diff options
Diffstat (limited to 'drivers/staging')
811 files changed, 206913 insertions, 11717 deletions
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index ef28a1cb64ae..554683912cff 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -24,6 +24,8 @@ menuconfig STAGING if STAGING +source "drivers/staging/irda/net/Kconfig" + source "drivers/staging/wlan-ng/Kconfig" source "drivers/staging/comedi/Kconfig" @@ -40,6 +42,8 @@ source "drivers/staging/rtl8712/Kconfig" source "drivers/staging/rtl8188eu/Kconfig" +source "drivers/staging/rtlwifi/Kconfig" + source "drivers/staging/rts5208/Kconfig" source "drivers/staging/octeon/Kconfig" @@ -112,4 +116,6 @@ source "drivers/staging/typec/Kconfig" source "drivers/staging/vboxvideo/Kconfig" +source "drivers/staging/pi433/Kconfig" + endif # STAGING diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 2918580bdb9e..8951c37d8d80 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -2,6 +2,8 @@ obj-y += media/ obj-y += typec/ +obj-$(CONFIG_IRDA) += irda/net/ +obj-$(CONFIG_IRDA) += irda/drivers/ obj-$(CONFIG_PRISM2_USB) += wlan-ng/ obj-$(CONFIG_COMEDI) += comedi/ obj-$(CONFIG_FB_OLPC_DCON) += olpc_dcon/ @@ -10,6 +12,7 @@ obj-$(CONFIG_RTL8192E) += rtl8192e/ obj-$(CONFIG_RTL8723BS) += rtl8723bs/ obj-$(CONFIG_R8712U) += rtl8712/ obj-$(CONFIG_R8188EU) += rtl8188eu/ +obj-$(CONFIG_R8822BE) += rtlwifi/ obj-$(CONFIG_RTS5208) += rts5208/ obj-$(CONFIG_NETLOGIC_XLR_NET) += netlogic/ obj-$(CONFIG_OCTEON_ETHERNET) += octeon/ @@ -45,3 +48,4 @@ obj-$(CONFIG_GREYBUS) += greybus/ obj-$(CONFIG_BCM2835_VCHIQ) += vc04_services/ obj-$(CONFIG_CRYPTO_DEV_CCREE) += ccree/ obj-$(CONFIG_DRM_VBOXVIDEO) += vboxvideo/ +obj-$(CONFIG_PI433) += pi433/ diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c index 6ba270e0494d..0f695df14c9d 100644 --- a/drivers/staging/android/ashmem.c +++ b/drivers/staging/android/ashmem.c @@ -294,19 +294,9 @@ static int ashmem_release(struct inode *ignored, struct file *file) return 0; } -/** - * ashmem_read() - Reads a set of bytes from an Ashmem-enabled file - * @file: The associated backing file. - * @buf: The buffer of data being written to - * @len: The number of bytes being read - * @pos: The position of the first byte to read. - * - * Return: 0 if successful, or another return code if not. - */ -static ssize_t ashmem_read(struct file *file, char __user *buf, - size_t len, loff_t *pos) +static ssize_t ashmem_read_iter(struct kiocb *iocb, struct iov_iter *iter) { - struct ashmem_area *asma = file->private_data; + struct ashmem_area *asma = iocb->ki_filp->private_data; int ret = 0; mutex_lock(&ashmem_mutex); @@ -320,20 +310,17 @@ static ssize_t ashmem_read(struct file *file, char __user *buf, goto out_unlock; } - mutex_unlock(&ashmem_mutex); - /* * asma and asma->file are used outside the lock here. We assume * once asma->file is set it will never be changed, and will not * be destroyed until all references to the file are dropped and * ashmem_release is called. */ - ret = __vfs_read(asma->file, buf, len, pos); - if (ret >= 0) - /** Update backing file pos, since f_ops->read() doesn't */ - asma->file->f_pos = *pos; - return ret; - + mutex_unlock(&ashmem_mutex); + ret = vfs_iter_read(asma->file, iter, &iocb->ki_pos, 0); + mutex_lock(&ashmem_mutex); + if (ret > 0) + asma->file->f_pos = iocb->ki_pos; out_unlock: mutex_unlock(&ashmem_mutex); return ret; @@ -834,7 +821,7 @@ static const struct file_operations ashmem_fops = { .owner = THIS_MODULE, .open = ashmem_open, .release = ashmem_release, - .read = ashmem_read, + .read_iter = ashmem_read_iter, .llseek = ashmem_llseek, .mmap = ashmem_mmap, .unlocked_ioctl = ashmem_ioctl, diff --git a/drivers/staging/android/ion/ion.h b/drivers/staging/android/ion/ion.h index fa9ed81ab972..621e5f7ceacb 100644 --- a/drivers/staging/android/ion/ion.h +++ b/drivers/staging/android/ion/ion.h @@ -135,7 +135,7 @@ struct ion_heap_ops { /** * heap flags - flags between the heaps and core ion code */ -#define ION_HEAP_FLAG_DEFER_FREE (1 << 0) +#define ION_HEAP_FLAG_DEFER_FREE BIT(0) /** * private flags - flags internal to ion @@ -146,7 +146,7 @@ struct ion_heap_ops { * any buffer storage that came from the system allocator will be * returned to the system allocator. */ -#define ION_PRIV_FLAG_SHRINKER_FREE (1 << 0) +#define ION_PRIV_FLAG_SHRINKER_FREE BIT(0) /** * struct ion_heap - represents a heap in the system @@ -226,8 +226,8 @@ int ion_heap_buffer_zero(struct ion_buffer *buffer); int ion_heap_pages_zero(struct page *page, size_t size, pgprot_t pgprot); int ion_alloc(size_t len, - unsigned int heap_id_mask, - unsigned int flags); + unsigned int heap_id_mask, + unsigned int flags); /** * ion_heap_init_shrinker @@ -291,7 +291,7 @@ size_t ion_heap_freelist_drain(struct ion_heap *heap, size_t size); * flag. */ size_t ion_heap_freelist_shrink(struct ion_heap *heap, - size_t size); + size_t size); /** * ion_heap_freelist_size - returns the size of the freelist in bytes @@ -352,7 +352,7 @@ void ion_page_pool_free(struct ion_page_pool *pool, struct page *page); * returns the number of items freed in pages */ int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask, - int nr_to_scan); + int nr_to_scan); long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); diff --git a/drivers/staging/android/ion/ion_cma_heap.c b/drivers/staging/android/ion/ion_cma_heap.c index a0949bc0dcf4..dd5545d9990a 100644 --- a/drivers/staging/android/ion/ion_cma_heap.c +++ b/drivers/staging/android/ion/ion_cma_heap.c @@ -31,7 +31,6 @@ struct ion_cma_heap { #define to_cma_heap(x) container_of(x, struct ion_cma_heap, heap) - /* ION CMA heap operations functions */ static int ion_cma_allocate(struct ion_heap *heap, struct ion_buffer *buffer, unsigned long len, @@ -46,7 +45,7 @@ static int ion_cma_allocate(struct ion_heap *heap, struct ion_buffer *buffer, if (!pages) return -ENOMEM; - table = kmalloc(sizeof(struct sg_table), GFP_KERNEL); + table = kmalloc(sizeof(*table), GFP_KERNEL); if (!table) goto err; @@ -106,7 +105,7 @@ static struct ion_heap *__ion_cma_heap_create(struct cma *cma) return &cma_heap->heap; } -int __ion_add_cma_heaps(struct cma *cma, void *data) +static int __ion_add_cma_heaps(struct cma *cma, void *data) { struct ion_heap *heap; diff --git a/drivers/staging/android/ion/ion_system_heap.c b/drivers/staging/android/ion/ion_system_heap.c index 5964bf21fd80..4dc5d7a589c2 100644 --- a/drivers/staging/android/ion/ion_system_heap.c +++ b/drivers/staging/android/ion/ion_system_heap.c @@ -98,7 +98,6 @@ static void free_buffer_page(struct ion_system_heap *heap, ion_page_pool_free(pool, page); } - static struct page *alloc_largest_available(struct ion_system_heap *heap, struct ion_buffer *buffer, unsigned long size, @@ -256,7 +255,6 @@ static struct ion_heap_ops system_heap_ops = { static int ion_system_heap_debug_show(struct ion_heap *heap, struct seq_file *s, void *unused) { - struct ion_system_heap *sys_heap = container_of(heap, struct ion_system_heap, heap); diff --git a/drivers/staging/ccree/Kconfig b/drivers/staging/ccree/Kconfig index 36a87c686a2a..0b3092ba2fcb 100644 --- a/drivers/staging/ccree/Kconfig +++ b/drivers/staging/ccree/Kconfig @@ -23,12 +23,3 @@ config CRYPTO_DEV_CCREE Choose this if you wish to use hardware acceleration of cryptographic operations on the system REE. If unsure say Y. - -config CCREE_FIPS_SUPPORT - bool "Turn on CryptoCell 7XX REE FIPS mode support" - depends on CRYPTO_DEV_CCREE - default n - help - Say 'Y' to enable support for FIPS compliant mode by the - CCREE driver. - If unsure say N. diff --git a/drivers/staging/ccree/Makefile b/drivers/staging/ccree/Makefile index 318c2b39acf6..ae702f3b5369 100644 --- a/drivers/staging/ccree/Makefile +++ b/drivers/staging/ccree/Makefile @@ -1,3 +1,3 @@ obj-$(CONFIG_CRYPTO_DEV_CCREE) := ccree.o ccree-y := ssi_driver.o ssi_sysfs.o ssi_buffer_mgr.o ssi_request_mgr.o ssi_cipher.o ssi_hash.o ssi_aead.o ssi_ivgen.o ssi_sram_mgr.o ssi_pm.o -ccree-$(CCREE_FIPS_SUPPORT) += ssi_fips.o ssi_fips_ll.o ssi_fips_ext.o ssi_fips_local.o +ccree-$(CONFIG_CRYPTO_FIPS) += ssi_fips.o diff --git a/drivers/staging/ccree/cc_hw_queue_defs.h b/drivers/staging/ccree/cc_hw_queue_defs.h index e6b8cea3f88d..2ae0f655e7a0 100644 --- a/drivers/staging/ccree/cc_hw_queue_defs.h +++ b/drivers/staging/ccree/cc_hw_queue_defs.h @@ -27,7 +27,8 @@ ******************************************************************************/ #define HW_DESC_SIZE_WORDS 6 -#define HW_QUEUE_SLOTS_MAX 15 /* Max. available slots in HW queue */ +/* Define max. available slots in HW queue */ +#define HW_QUEUE_SLOTS_MAX 15 #define CC_REG_NAME(word, name) DX_DSCRPTR_QUEUE_WORD ## word ## _ ## name diff --git a/drivers/staging/ccree/ssi_aead.c b/drivers/staging/ccree/ssi_aead.c index 1fc0b05ea0d5..5abe6b24ff8c 100644 --- a/drivers/staging/ccree/ssi_aead.c +++ b/drivers/staging/ccree/ssi_aead.c @@ -36,7 +36,6 @@ #include "ssi_hash.h" #include "ssi_sysfs.h" #include "ssi_sram_mgr.h" -#include "ssi_fips_local.h" #define template_aead template_u.aead @@ -57,22 +56,26 @@ struct ssi_aead_handle { struct list_head aead_list; }; +struct cc_hmac_s { + u8 *padded_authkey; + u8 *ipad_opad; /* IPAD, OPAD*/ + dma_addr_t padded_authkey_dma_addr; + dma_addr_t ipad_opad_dma_addr; +}; + +struct cc_xcbc_s { + u8 *xcbc_keys; /* K1,K2,K3 */ + dma_addr_t xcbc_keys_dma_addr; +}; + struct ssi_aead_ctx { struct ssi_drvdata *drvdata; u8 ctr_nonce[MAX_NONCE_SIZE]; /* used for ctr3686 iv and aes ccm */ u8 *enckey; dma_addr_t enckey_dma_addr; union { - struct { - u8 *padded_authkey; - u8 *ipad_opad; /* IPAD, OPAD*/ - dma_addr_t padded_authkey_dma_addr; - dma_addr_t ipad_opad_dma_addr; - } hmac; - struct { - u8 *xcbc_keys; /* K1,K2,K3 */ - dma_addr_t xcbc_keys_dma_addr; - } xcbc; + struct cc_hmac_s hmac; + struct cc_xcbc_s xcbc; } auth_state; unsigned int enc_keylen; unsigned int auth_keylen; @@ -93,46 +96,50 @@ static void ssi_aead_exit(struct crypto_aead *tfm) struct ssi_aead_ctx *ctx = crypto_aead_ctx(tfm); SSI_LOG_DEBUG("Clearing context @%p for %s\n", - crypto_aead_ctx(tfm), crypto_tfm_alg_name(&(tfm->base))); + crypto_aead_ctx(tfm), crypto_tfm_alg_name(&tfm->base)); dev = &ctx->drvdata->plat_dev->dev; /* Unmap enckey buffer */ if (ctx->enckey) { dma_free_coherent(dev, AES_MAX_KEY_SIZE, ctx->enckey, ctx->enckey_dma_addr); - SSI_LOG_DEBUG("Freed enckey DMA buffer enckey_dma_addr=0x%llX\n", - (unsigned long long)ctx->enckey_dma_addr); + SSI_LOG_DEBUG("Freed enckey DMA buffer enckey_dma_addr=%pad\n", + ctx->enckey_dma_addr); ctx->enckey_dma_addr = 0; ctx->enckey = NULL; } if (ctx->auth_mode == DRV_HASH_XCBC_MAC) { /* XCBC authetication */ - if (ctx->auth_state.xcbc.xcbc_keys) { + struct cc_xcbc_s *xcbc = &ctx->auth_state.xcbc; + + if (xcbc->xcbc_keys) { dma_free_coherent(dev, CC_AES_128_BIT_KEY_SIZE * 3, - ctx->auth_state.xcbc.xcbc_keys, - ctx->auth_state.xcbc.xcbc_keys_dma_addr); + xcbc->xcbc_keys, + xcbc->xcbc_keys_dma_addr); } - SSI_LOG_DEBUG("Freed xcbc_keys DMA buffer xcbc_keys_dma_addr=0x%llX\n", - (unsigned long long)ctx->auth_state.xcbc.xcbc_keys_dma_addr); - ctx->auth_state.xcbc.xcbc_keys_dma_addr = 0; - ctx->auth_state.xcbc.xcbc_keys = NULL; + SSI_LOG_DEBUG("Freed xcbc_keys DMA buffer xcbc_keys_dma_addr=%pad\n", + xcbc->xcbc_keys_dma_addr); + xcbc->xcbc_keys_dma_addr = 0; + xcbc->xcbc_keys = NULL; } else if (ctx->auth_mode != DRV_HASH_NULL) { /* HMAC auth. */ - if (ctx->auth_state.hmac.ipad_opad) { + struct cc_hmac_s *hmac = &ctx->auth_state.hmac; + + if (hmac->ipad_opad) { dma_free_coherent(dev, 2 * MAX_HMAC_DIGEST_SIZE, - ctx->auth_state.hmac.ipad_opad, - ctx->auth_state.hmac.ipad_opad_dma_addr); - SSI_LOG_DEBUG("Freed ipad_opad DMA buffer ipad_opad_dma_addr=0x%llX\n", - (unsigned long long)ctx->auth_state.hmac.ipad_opad_dma_addr); - ctx->auth_state.hmac.ipad_opad_dma_addr = 0; - ctx->auth_state.hmac.ipad_opad = NULL; + hmac->ipad_opad, + hmac->ipad_opad_dma_addr); + SSI_LOG_DEBUG("Freed ipad_opad DMA buffer ipad_opad_dma_addr=%pad\n", + hmac->ipad_opad_dma_addr); + hmac->ipad_opad_dma_addr = 0; + hmac->ipad_opad = NULL; } - if (ctx->auth_state.hmac.padded_authkey) { + if (hmac->padded_authkey) { dma_free_coherent(dev, MAX_HMAC_BLOCK_SIZE, - ctx->auth_state.hmac.padded_authkey, - ctx->auth_state.hmac.padded_authkey_dma_addr); - SSI_LOG_DEBUG("Freed padded_authkey DMA buffer padded_authkey_dma_addr=0x%llX\n", - (unsigned long long)ctx->auth_state.hmac.padded_authkey_dma_addr); - ctx->auth_state.hmac.padded_authkey_dma_addr = 0; - ctx->auth_state.hmac.padded_authkey = NULL; + hmac->padded_authkey, + hmac->padded_authkey_dma_addr); + SSI_LOG_DEBUG("Freed padded_authkey DMA buffer padded_authkey_dma_addr=%pad\n", + hmac->padded_authkey_dma_addr); + hmac->padded_authkey_dma_addr = 0; + hmac->padded_authkey = NULL; } } } @@ -144,9 +151,7 @@ static int ssi_aead_init(struct crypto_aead *tfm) struct ssi_aead_ctx *ctx = crypto_aead_ctx(tfm); struct ssi_crypto_alg *ssi_alg = container_of(alg, struct ssi_crypto_alg, aead_alg); - SSI_LOG_DEBUG("Initializing context @%p for %s\n", ctx, crypto_tfm_alg_name(&(tfm->base))); - - CHECK_AND_RETURN_UPON_FIPS_ERROR(); + SSI_LOG_DEBUG("Initializing context @%p for %s\n", ctx, crypto_tfm_alg_name(&tfm->base)); /* Initialize modes in instance */ ctx->cipher_mode = ssi_alg->cipher_mode; @@ -158,7 +163,7 @@ static int ssi_aead_init(struct crypto_aead *tfm) /* Allocate key buffer, cache line aligned */ ctx->enckey = dma_alloc_coherent(dev, AES_MAX_KEY_SIZE, - &ctx->enckey_dma_addr, GFP_KERNEL); + &ctx->enckey_dma_addr, GFP_KERNEL); if (!ctx->enckey) { SSI_LOG_ERR("Failed allocating key buffer\n"); goto init_failed; @@ -168,31 +173,42 @@ static int ssi_aead_init(struct crypto_aead *tfm) /* Set default authlen value */ if (ctx->auth_mode == DRV_HASH_XCBC_MAC) { /* XCBC authetication */ + struct cc_xcbc_s *xcbc = &ctx->auth_state.xcbc; + const unsigned int key_size = CC_AES_128_BIT_KEY_SIZE * 3; + /* Allocate dma-coherent buffer for XCBC's K1+K2+K3 */ /* (and temporary for user key - up to 256b) */ - ctx->auth_state.xcbc.xcbc_keys = dma_alloc_coherent(dev, - CC_AES_128_BIT_KEY_SIZE * 3, - &ctx->auth_state.xcbc.xcbc_keys_dma_addr, GFP_KERNEL); - if (!ctx->auth_state.xcbc.xcbc_keys) { + xcbc->xcbc_keys = dma_alloc_coherent(dev, key_size, + &xcbc->xcbc_keys_dma_addr, + GFP_KERNEL); + if (!xcbc->xcbc_keys) { SSI_LOG_ERR("Failed allocating buffer for XCBC keys\n"); goto init_failed; } } else if (ctx->auth_mode != DRV_HASH_NULL) { /* HMAC authentication */ + struct cc_hmac_s *hmac = &ctx->auth_state.hmac; + const unsigned int digest_size = 2 * MAX_HMAC_DIGEST_SIZE; + dma_addr_t *pkey_dma = &hmac->padded_authkey_dma_addr; + /* Allocate dma-coherent buffer for IPAD + OPAD */ - ctx->auth_state.hmac.ipad_opad = dma_alloc_coherent(dev, - 2 * MAX_HMAC_DIGEST_SIZE, - &ctx->auth_state.hmac.ipad_opad_dma_addr, GFP_KERNEL); - if (!ctx->auth_state.hmac.ipad_opad) { + hmac->ipad_opad = dma_alloc_coherent(dev, digest_size, + &hmac->ipad_opad_dma_addr, + GFP_KERNEL); + + if (!hmac->ipad_opad) { SSI_LOG_ERR("Failed allocating IPAD/OPAD buffer\n"); goto init_failed; } + SSI_LOG_DEBUG("Allocated authkey buffer in context ctx->authkey=@%p\n", - ctx->auth_state.hmac.ipad_opad); + hmac->ipad_opad); + + hmac->padded_authkey = dma_alloc_coherent(dev, + MAX_HMAC_BLOCK_SIZE, + pkey_dma, + GFP_KERNEL); - ctx->auth_state.hmac.padded_authkey = dma_alloc_coherent(dev, - MAX_HMAC_BLOCK_SIZE, - &ctx->auth_state.hmac.padded_authkey_dma_addr, GFP_KERNEL); - if (!ctx->auth_state.hmac.padded_authkey) { + if (!hmac->padded_authkey) { SSI_LOG_ERR("failed to allocate padded_authkey\n"); goto init_failed; } @@ -223,7 +239,7 @@ static void ssi_aead_complete(struct device *dev, void *ssi_req, void __iomem *c if (areq_ctx->gen_ctx.op_type == DRV_CRYPTO_DIRECTION_DECRYPT) { if (memcmp(areq_ctx->mac_buf, areq_ctx->icv_virt_addr, - ctx->authsize) != 0) { + ctx->authsize) != 0) { SSI_LOG_DEBUG("Payload authentication failure, " "(auth-size=%d, cipher=%d).\n", ctx->authsize, ctx->cipher_mode); @@ -236,8 +252,8 @@ static void ssi_aead_complete(struct device *dev, void *ssi_req, void __iomem *c } else { /*ENCRYPT*/ if (unlikely(areq_ctx->is_icv_fragmented)) ssi_buffer_mgr_copy_scatterlist_portion( - areq_ctx->mac_buf, areq_ctx->dstSgl, areq->cryptlen + areq_ctx->dstOffset, - areq->cryptlen + areq_ctx->dstOffset + ctx->authsize, SSI_SG_FROM_BUF); + areq_ctx->mac_buf, areq_ctx->dst_sgl, areq->cryptlen + areq_ctx->dst_offset, + areq->cryptlen + areq_ctx->dst_offset + ctx->authsize, SSI_SG_FROM_BUF); /* If an IV was generated, copy it back to the user provided buffer. */ if (areq_ctx->backup_giv) { @@ -292,12 +308,13 @@ static int xcbc_setkey(struct cc_hw_desc *desc, struct ssi_aead_ctx *ctx) static int hmac_setkey(struct cc_hw_desc *desc, struct ssi_aead_ctx *ctx) { - unsigned int hmacPadConst[2] = { HMAC_IPAD_CONST, HMAC_OPAD_CONST }; + unsigned int hmac_pad_const[2] = { HMAC_IPAD_CONST, HMAC_OPAD_CONST }; unsigned int digest_ofs = 0; unsigned int hash_mode = (ctx->auth_mode == DRV_HASH_SHA1) ? DRV_HASH_HW_SHA1 : DRV_HASH_HW_SHA256; unsigned int digest_size = (ctx->auth_mode == DRV_HASH_SHA1) ? CC_SHA1_DIGEST_SIZE : CC_SHA256_DIGEST_SIZE; + struct cc_hmac_s *hmac = &ctx->auth_state.hmac; int idx = 0; int i; @@ -325,7 +342,7 @@ static int hmac_setkey(struct cc_hw_desc *desc, struct ssi_aead_ctx *ctx) /* Prepare ipad key */ hw_desc_init(&desc[idx]); - set_xor_val(&desc[idx], hmacPadConst[i]); + set_xor_val(&desc[idx], hmac_pad_const[i]); set_cipher_mode(&desc[idx], hash_mode); set_flow_mode(&desc[idx], S_DIN_to_HASH); set_setup_mode(&desc[idx], SETUP_LOAD_STATE1); @@ -334,7 +351,7 @@ static int hmac_setkey(struct cc_hw_desc *desc, struct ssi_aead_ctx *ctx) /* Perform HASH update */ hw_desc_init(&desc[idx]); set_din_type(&desc[idx], DMA_DLLI, - ctx->auth_state.hmac.padded_authkey_dma_addr, + hmac->padded_authkey_dma_addr, SHA256_BLOCK_SIZE, NS_BIT); set_cipher_mode(&desc[idx], hash_mode); set_xor_active(&desc[idx]); @@ -345,8 +362,8 @@ static int hmac_setkey(struct cc_hw_desc *desc, struct ssi_aead_ctx *ctx) hw_desc_init(&desc[idx]); set_cipher_mode(&desc[idx], hash_mode); set_dout_dlli(&desc[idx], - (ctx->auth_state.hmac.ipad_opad_dma_addr + - digest_ofs), digest_size, NS_BIT, 0); + (hmac->ipad_opad_dma_addr + digest_ofs), + digest_size, NS_BIT, 0); set_flow_mode(&desc[idx], S_HASH_to_DOUT); set_setup_mode(&desc[idx], SETUP_WRITE_STATE0); set_cipher_config1(&desc[idx], HASH_PADDING_DISABLED); @@ -361,7 +378,7 @@ static int hmac_setkey(struct cc_hw_desc *desc, struct ssi_aead_ctx *ctx) static int validate_keys_sizes(struct ssi_aead_ctx *ctx) { SSI_LOG_DEBUG("enc_keylen=%u authkeylen=%u\n", - ctx->enc_keylen, ctx->auth_keylen); + ctx->enc_keylen, ctx->auth_keylen); switch (ctx->auth_mode) { case DRV_HASH_SHA1: @@ -385,7 +402,7 @@ static int validate_keys_sizes(struct ssi_aead_ctx *ctx) if (unlikely(ctx->flow_mode == S_DIN_to_DES)) { if (ctx->enc_keylen != DES3_EDE_KEY_SIZE) { SSI_LOG_ERR("Invalid cipher(3DES) key size: %u\n", - ctx->enc_keylen); + ctx->enc_keylen); return -EINVAL; } } else { /* Default assumed to be AES ciphers */ @@ -393,7 +410,7 @@ static int validate_keys_sizes(struct ssi_aead_ctx *ctx) (ctx->enc_keylen != AES_KEYSIZE_192) && (ctx->enc_keylen != AES_KEYSIZE_256)) { SSI_LOG_ERR("Invalid cipher(AES) key size: %u\n", - ctx->enc_keylen); + ctx->enc_keylen); return -EINVAL; } } @@ -536,9 +553,9 @@ ssi_aead_setkey(struct crypto_aead *tfm, const u8 *key, unsigned int keylen) int seq_len = 0, rc = -EINVAL; SSI_LOG_DEBUG("Setting key in context @%p for %s. key=%p keylen=%u\n", - ctx, crypto_tfm_alg_name(crypto_aead_tfm(tfm)), key, keylen); + ctx, crypto_tfm_alg_name(crypto_aead_tfm(tfm)), + key, keylen); - CHECK_AND_RETURN_UPON_FIPS_ERROR(); /* STAT_PHASE_0: Init and sanity checks */ if (ctx->auth_mode != DRV_HASH_NULL) { /* authenc() alg. */ @@ -654,7 +671,6 @@ static int ssi_aead_setauthsize( { struct ssi_aead_ctx *ctx = crypto_aead_ctx(authenc); - CHECK_AND_RETURN_UPON_FIPS_ERROR(); /* Unsupported auth. sizes */ if ((authsize == 0) || (authsize > crypto_aead_maxauthsize(authenc))) { @@ -669,7 +685,7 @@ static int ssi_aead_setauthsize( #if SSI_CC_HAS_AES_CCM static int ssi_rfc4309_ccm_setauthsize(struct crypto_aead *authenc, - unsigned int authsize) + unsigned int authsize) { switch (authsize) { case 8: @@ -684,7 +700,7 @@ static int ssi_rfc4309_ccm_setauthsize(struct crypto_aead *authenc, } static int ssi_ccm_setauthsize(struct crypto_aead *authenc, - unsigned int authsize) + unsigned int authsize) { switch (authsize) { case 4: @@ -762,11 +778,11 @@ ssi_aead_process_authenc_data_desc( { struct scatterlist *cipher = (direct == DRV_CRYPTO_DIRECTION_ENCRYPT) ? - areq_ctx->dstSgl : areq_ctx->srcSgl; + areq_ctx->dst_sgl : areq_ctx->src_sgl; unsigned int offset = (direct == DRV_CRYPTO_DIRECTION_ENCRYPT) ? - areq_ctx->dstOffset : areq_ctx->srcOffset; + areq_ctx->dst_offset : areq_ctx->src_offset; SSI_LOG_DEBUG("AUTHENC: SRC/DST buffer type DLLI\n"); hw_desc_init(&desc[idx]); set_din_type(&desc[idx], DMA_DLLI, @@ -828,11 +844,11 @@ ssi_aead_process_cipher_data_desc( SSI_LOG_DEBUG("CIPHER: SRC/DST buffer type DLLI\n"); hw_desc_init(&desc[idx]); set_din_type(&desc[idx], DMA_DLLI, - (sg_dma_address(areq_ctx->srcSgl) + - areq_ctx->srcOffset), areq_ctx->cryptlen, NS_BIT); + (sg_dma_address(areq_ctx->src_sgl) + + areq_ctx->src_offset), areq_ctx->cryptlen, NS_BIT); set_dout_dlli(&desc[idx], - (sg_dma_address(areq_ctx->dstSgl) + - areq_ctx->dstOffset), + (sg_dma_address(areq_ctx->dst_sgl) + + areq_ctx->dst_offset), areq_ctx->cryptlen, NS_BIT, 0); set_flow_mode(&desc[idx], flow_mode); break; @@ -1168,8 +1184,8 @@ static inline void ssi_aead_load_mlli_to_sram( (req_ctx->data_buff_type == SSI_DMA_BUF_MLLI) || !req_ctx->is_single_pass)) { SSI_LOG_DEBUG("Copy-to-sram: mlli_dma=%08x, mlli_size=%u\n", - (unsigned int)ctx->drvdata->mlli_sram_addr, - req_ctx->mlli_params.mlli_len); + (unsigned int)ctx->drvdata->mlli_sram_addr, + req_ctx->mlli_params.mlli_len); /* Copy MLLI table host-to-sram */ hw_desc_init(&desc[*seq_size]); set_din_type(&desc[*seq_size], DMA_DLLI, @@ -1313,7 +1329,8 @@ ssi_aead_xcbc_authenc( } static int validate_data_size(struct ssi_aead_ctx *ctx, - enum drv_crypto_direction direct, struct aead_request *req) + enum drv_crypto_direction direct, + struct aead_request *req) { struct aead_req_ctx *areq_ctx = aead_request_ctx(req); unsigned int assoclen = req->assoclen; @@ -1321,7 +1338,7 @@ static int validate_data_size(struct ssi_aead_ctx *ctx, (req->cryptlen - ctx->authsize) : req->cryptlen; if (unlikely((direct == DRV_CRYPTO_DIRECTION_DECRYPT) && - (req->cryptlen < ctx->authsize))) + (req->cryptlen < ctx->authsize))) goto data_size_err; areq_ctx->is_single_pass = true; /*defaulted to fast flow*/ @@ -1329,7 +1346,7 @@ static int validate_data_size(struct ssi_aead_ctx *ctx, switch (ctx->flow_mode) { case S_DIN_to_AES: if (unlikely((ctx->cipher_mode == DRV_CIPHER_CBC) && - !IS_ALIGNED(cipherlen, AES_BLOCK_SIZE))) + !IS_ALIGNED(cipherlen, AES_BLOCK_SIZE))) goto data_size_err; if (ctx->cipher_mode == DRV_CIPHER_CCM) break; @@ -1365,27 +1382,27 @@ data_size_err: } #if SSI_CC_HAS_AES_CCM -static unsigned int format_ccm_a0(u8 *pA0Buff, u32 headerSize) +static unsigned int format_ccm_a0(u8 *pa0_buff, u32 header_size) { unsigned int len = 0; - if (headerSize == 0) + if (header_size == 0) return 0; - if (headerSize < ((1UL << 16) - (1UL << 8))) { + if (header_size < ((1UL << 16) - (1UL << 8))) { len = 2; - pA0Buff[0] = (headerSize >> 8) & 0xFF; - pA0Buff[1] = headerSize & 0xFF; + pa0_buff[0] = (header_size >> 8) & 0xFF; + pa0_buff[1] = header_size & 0xFF; } else { len = 6; - pA0Buff[0] = 0xFF; - pA0Buff[1] = 0xFE; - pA0Buff[2] = (headerSize >> 24) & 0xFF; - pA0Buff[3] = (headerSize >> 16) & 0xFF; - pA0Buff[4] = (headerSize >> 8) & 0xFF; - pA0Buff[5] = headerSize & 0xFF; + pa0_buff[0] = 0xFF; + pa0_buff[1] = 0xFE; + pa0_buff[2] = (header_size >> 24) & 0xFF; + pa0_buff[3] = (header_size >> 16) & 0xFF; + pa0_buff[4] = (header_size >> 8) & 0xFF; + pa0_buff[5] = header_size & 0xFF; } return len; @@ -1557,7 +1574,7 @@ static int config_ccm_adata(struct aead_request *req) /* taken from crypto/ccm.c */ /* 2 <= L <= 8, so 1 <= L' <= 7. */ - if (2 > l || l > 8) { + if (l < 2 || l > 8) { SSI_LOG_ERR("illegal iv value %X\n", req->iv[0]); return -EINVAL; } @@ -1848,8 +1865,9 @@ static inline void ssi_aead_dump_gcm( SSI_LOG_DEBUG("%s\n", title); } - SSI_LOG_DEBUG("cipher_mode %d, authsize %d, enc_keylen %d, assoclen %d, cryptlen %d\n", \ - ctx->cipher_mode, ctx->authsize, ctx->enc_keylen, req->assoclen, req_ctx->cryptlen); + SSI_LOG_DEBUG("cipher_mode %d, authsize %d, enc_keylen %d, assoclen %d, cryptlen %d\n", + ctx->cipher_mode, ctx->authsize, ctx->enc_keylen, + req->assoclen, req_ctx->cryptlen); if (ctx->enckey) dump_byte_array("mac key", ctx->enckey, 16); @@ -1864,7 +1882,7 @@ static inline void ssi_aead_dump_gcm( dump_byte_array("mac_buf", req_ctx->mac_buf, AES_BLOCK_SIZE); - dump_byte_array("gcm_len_block", req_ctx->gcm_len_block.lenA, AES_BLOCK_SIZE); + dump_byte_array("gcm_len_block", req_ctx->gcm_len_block.len_a, AES_BLOCK_SIZE); if (req->src && req->cryptlen) dump_byte_array("req->src", sg_virt(req->src), req->cryptlen + req->assoclen); @@ -1886,7 +1904,7 @@ static int config_gcm_context(struct aead_request *req) (req->cryptlen - ctx->authsize); __be32 counter = cpu_to_be32(2); - SSI_LOG_DEBUG("config_gcm_context() cryptlen = %d, req->assoclen = %d ctx->authsize = %d\n", cryptlen, req->assoclen, ctx->authsize); + SSI_LOG_DEBUG("%s() cryptlen = %d, req->assoclen = %d ctx->authsize = %d\n", __func__, cryptlen, req->assoclen, ctx->authsize); memset(req_ctx->hkey, 0, AES_BLOCK_SIZE); @@ -1903,16 +1921,16 @@ static int config_gcm_context(struct aead_request *req) __be64 temp64; temp64 = cpu_to_be64(req->assoclen * 8); - memcpy(&req_ctx->gcm_len_block.lenA, &temp64, sizeof(temp64)); + memcpy(&req_ctx->gcm_len_block.len_a, &temp64, sizeof(temp64)); temp64 = cpu_to_be64(cryptlen * 8); - memcpy(&req_ctx->gcm_len_block.lenC, &temp64, 8); + memcpy(&req_ctx->gcm_len_block.len_c, &temp64, 8); } else { //rfc4543=> all data(AAD,IV,Plain) are considered additional data that is nothing is encrypted. __be64 temp64; temp64 = cpu_to_be64((req->assoclen + GCM_BLOCK_RFC4_IV_SIZE + cryptlen) * 8); - memcpy(&req_ctx->gcm_len_block.lenA, &temp64, sizeof(temp64)); + memcpy(&req_ctx->gcm_len_block.len_a, &temp64, sizeof(temp64)); temp64 = 0; - memcpy(&req_ctx->gcm_len_block.lenC, &temp64, 8); + memcpy(&req_ctx->gcm_len_block.len_c, &temp64, 8); } return 0; @@ -1944,16 +1962,16 @@ static int ssi_aead_process(struct aead_request *req, enum drv_crypto_direction struct ssi_crypto_req ssi_req = {}; SSI_LOG_DEBUG("%s context=%p req=%p iv=%p src=%p src_ofs=%d dst=%p dst_ofs=%d cryptolen=%d\n", - ((direct == DRV_CRYPTO_DIRECTION_ENCRYPT) ? "Encrypt" : "Decrypt"), ctx, req, req->iv, - sg_virt(req->src), req->src->offset, sg_virt(req->dst), req->dst->offset, req->cryptlen); - CHECK_AND_RETURN_UPON_FIPS_ERROR(); + ((direct == DRV_CRYPTO_DIRECTION_ENCRYPT) ? "Encrypt" : "Decrypt"), + ctx, req, req->iv, sg_virt(req->src), req->src->offset, + sg_virt(req->dst), req->dst->offset, req->cryptlen); /* STAT_PHASE_0: Init and sanity checks */ /* Check data length according to mode */ if (unlikely(validate_data_size(ctx, direct, req) != 0)) { SSI_LOG_ERR("Unsupported crypt/assoc len %d/%d.\n", - req->cryptlen, req->assoclen); + req->cryptlen, req->assoclen); crypto_aead_set_flags(tfm, CRYPTO_TFM_RES_BAD_BLOCK_LEN); return -EINVAL; } @@ -1976,7 +1994,7 @@ static int ssi_aead_process(struct aead_request *req, enum drv_crypto_direction memcpy(areq_ctx->ctr_iv, ctx->ctr_nonce, CTR_RFC3686_NONCE_SIZE); if (!areq_ctx->backup_giv) /*User none-generated IV*/ memcpy(areq_ctx->ctr_iv + CTR_RFC3686_NONCE_SIZE, - req->iv, CTR_RFC3686_IV_SIZE); + req->iv, CTR_RFC3686_IV_SIZE); /* Initialize counter portion of counter block */ *(__be32 *)(areq_ctx->ctr_iv + CTR_RFC3686_NONCE_SIZE + CTR_RFC3686_IV_SIZE) = cpu_to_be32(1); @@ -2198,7 +2216,7 @@ static int ssi_rfc4106_gcm_setkey(struct crypto_aead *tfm, const u8 *key, unsign struct ssi_aead_ctx *ctx = crypto_aead_ctx(tfm); int rc = 0; - SSI_LOG_DEBUG("ssi_rfc4106_gcm_setkey() keylen %d, key %p\n", keylen, key); + SSI_LOG_DEBUG("%s() keylen %d, key %p\n", __func__, keylen, key); if (keylen < 4) return -EINVAL; @@ -2216,7 +2234,7 @@ static int ssi_rfc4543_gcm_setkey(struct crypto_aead *tfm, const u8 *key, unsign struct ssi_aead_ctx *ctx = crypto_aead_ctx(tfm); int rc = 0; - SSI_LOG_DEBUG("ssi_rfc4543_gcm_setkey() keylen %d, key %p\n", keylen, key); + SSI_LOG_DEBUG("%s() keylen %d, key %p\n", __func__, keylen, key); if (keylen < 4) return -EINVAL; @@ -2230,7 +2248,7 @@ static int ssi_rfc4543_gcm_setkey(struct crypto_aead *tfm, const u8 *key, unsign } static int ssi_gcm_setauthsize(struct crypto_aead *authenc, - unsigned int authsize) + unsigned int authsize) { switch (authsize) { case 4: @@ -2249,9 +2267,9 @@ static int ssi_gcm_setauthsize(struct crypto_aead *authenc, } static int ssi_rfc4106_gcm_setauthsize(struct crypto_aead *authenc, - unsigned int authsize) + unsigned int authsize) { - SSI_LOG_DEBUG("ssi_rfc4106_gcm_setauthsize() authsize %d\n", authsize); + SSI_LOG_DEBUG("authsize %d\n", authsize); switch (authsize) { case 8: @@ -2268,7 +2286,7 @@ static int ssi_rfc4106_gcm_setauthsize(struct crypto_aead *authenc, static int ssi_rfc4543_gcm_setauthsize(struct crypto_aead *authenc, unsigned int authsize) { - SSI_LOG_DEBUG("ssi_rfc4543_gcm_setauthsize() authsize %d\n", authsize); + SSI_LOG_DEBUG("authsize %d\n", authsize); if (authsize != 16) return -EINVAL; @@ -2641,7 +2659,7 @@ static struct ssi_crypto_alg *ssi_aead_create_alg(struct ssi_alg_template *templ struct ssi_crypto_alg *t_alg; struct aead_alg *alg; - t_alg = kzalloc(sizeof(struct ssi_crypto_alg), GFP_KERNEL); + t_alg = kzalloc(sizeof(*t_alg), GFP_KERNEL); if (!t_alg) { SSI_LOG_ERR("failed to allocate t_alg\n"); return ERR_PTR(-ENOMEM); @@ -2696,7 +2714,7 @@ int ssi_aead_alloc(struct ssi_drvdata *drvdata) int rc = -ENOMEM; int alg; - aead_handle = kmalloc(sizeof(struct ssi_aead_handle), GFP_KERNEL); + aead_handle = kmalloc(sizeof(*aead_handle), GFP_KERNEL); if (!aead_handle) { rc = -ENOMEM; goto fail0; @@ -2720,14 +2738,14 @@ int ssi_aead_alloc(struct ssi_drvdata *drvdata) if (IS_ERR(t_alg)) { rc = PTR_ERR(t_alg); SSI_LOG_ERR("%s alg allocation failed\n", - aead_algs[alg].driver_name); + aead_algs[alg].driver_name); goto fail1; } t_alg->drvdata = drvdata; rc = crypto_register_aead(&t_alg->aead_alg); if (unlikely(rc != 0)) { SSI_LOG_ERR("%s alg registration failed\n", - t_alg->aead_alg.base.cra_driver_name); + t_alg->aead_alg.base.cra_driver_name); goto fail2; } else { list_add_tail(&t_alg->entry, &aead_handle->aead_list); diff --git a/drivers/staging/ccree/ssi_aead.h b/drivers/staging/ccree/ssi_aead.h index 39cc633a3ffa..e85bcd917e7b 100644 --- a/drivers/staging/ccree/ssi_aead.h +++ b/drivers/staging/ccree/ssi_aead.h @@ -69,8 +69,8 @@ struct aead_req_ctx { u8 gcm_iv_inc2[AES_BLOCK_SIZE] ____cacheline_aligned; u8 hkey[AES_BLOCK_SIZE] ____cacheline_aligned; struct { - u8 lenA[GCM_BLOCK_LEN_SIZE] ____cacheline_aligned; - u8 lenC[GCM_BLOCK_LEN_SIZE]; + u8 len_a[GCM_BLOCK_LEN_SIZE] ____cacheline_aligned; + u8 len_c[GCM_BLOCK_LEN_SIZE]; } gcm_len_block; u8 ccm_config[CCM_CONFIG_BUF_SIZE] ____cacheline_aligned; @@ -94,10 +94,10 @@ struct aead_req_ctx { struct ssi_mlli assoc; struct ssi_mlli src; struct ssi_mlli dst; - struct scatterlist *srcSgl; - struct scatterlist *dstSgl; - unsigned int srcOffset; - unsigned int dstOffset; + struct scatterlist *src_sgl; + struct scatterlist *dst_sgl; + unsigned int src_offset; + unsigned int dst_offset; enum ssi_req_dma_buf_type assoc_buff_type; enum ssi_req_dma_buf_type data_buff_type; struct mlli_params mlli_params; diff --git a/drivers/staging/ccree/ssi_buffer_mgr.c b/drivers/staging/ccree/ssi_buffer_mgr.c index b35871eeabd1..63936091d524 100644 --- a/drivers/staging/ccree/ssi_buffer_mgr.c +++ b/drivers/staging/ccree/ssi_buffer_mgr.c @@ -150,7 +150,7 @@ static inline int ssi_buffer_mgr_render_buff_to_mlli( u32 **mlli_entry_pp) { u32 *mlli_entry_p = *mlli_entry_pp; - u32 new_nents;; + u32 new_nents; /* Verify there is no memory overflow*/ new_nents = (*curr_nents + buff_size / CC_MAX_MLLI_ENTRY_SIZE + 1); @@ -162,8 +162,8 @@ static inline int ssi_buffer_mgr_render_buff_to_mlli( cc_lli_set_addr(mlli_entry_p, buff_dma); cc_lli_set_size(mlli_entry_p, CC_MAX_MLLI_ENTRY_SIZE); SSI_LOG_DEBUG("entry[%d]: single_buff=0x%08X size=%08X\n", *curr_nents, - mlli_entry_p[LLI_WORD0_OFFSET], - mlli_entry_p[LLI_WORD1_OFFSET]); + mlli_entry_p[LLI_WORD0_OFFSET], + mlli_entry_p[LLI_WORD1_OFFSET]); buff_dma += CC_MAX_MLLI_ENTRY_SIZE; buff_size -= CC_MAX_MLLI_ENTRY_SIZE; mlli_entry_p = mlli_entry_p + 2; @@ -173,8 +173,8 @@ static inline int ssi_buffer_mgr_render_buff_to_mlli( cc_lli_set_addr(mlli_entry_p, buff_dma); cc_lli_set_size(mlli_entry_p, buff_size); SSI_LOG_DEBUG("entry[%d]: single_buff=0x%08X size=%08X\n", *curr_nents, - mlli_entry_p[LLI_WORD0_OFFSET], - mlli_entry_p[LLI_WORD1_OFFSET]); + mlli_entry_p[LLI_WORD0_OFFSET], + mlli_entry_p[LLI_WORD1_OFFSET]); mlli_entry_p = mlli_entry_p + 2; *mlli_entry_pp = mlli_entry_p; (*curr_nents)++; @@ -182,8 +182,8 @@ static inline int ssi_buffer_mgr_render_buff_to_mlli( } static inline int ssi_buffer_mgr_render_scatterlist_to_mlli( - struct scatterlist *sgl, u32 sgl_data_len, u32 sglOffset, u32 *curr_nents, - u32 **mlli_entry_pp) + struct scatterlist *sgl, u32 sgl_data_len, u32 sgl_offset, + u32 *curr_nents, u32 **mlli_entry_pp) { struct scatterlist *curr_sgl = sgl; u32 *mlli_entry_p = *mlli_entry_pp; @@ -192,16 +192,17 @@ static inline int ssi_buffer_mgr_render_scatterlist_to_mlli( for ( ; (curr_sgl) && (sgl_data_len != 0); curr_sgl = sg_next(curr_sgl)) { u32 entry_data_len = - (sgl_data_len > sg_dma_len(curr_sgl) - sglOffset) ? - sg_dma_len(curr_sgl) - sglOffset : sgl_data_len; + (sgl_data_len > sg_dma_len(curr_sgl) - sgl_offset) ? + sg_dma_len(curr_sgl) - sgl_offset : + sgl_data_len; sgl_data_len -= entry_data_len; rc = ssi_buffer_mgr_render_buff_to_mlli( - sg_dma_address(curr_sgl) + sglOffset, entry_data_len, curr_nents, - &mlli_entry_p); + sg_dma_address(curr_sgl) + sgl_offset, entry_data_len, + curr_nents, &mlli_entry_p); if (rc != 0) return rc; - sglOffset = 0; + sgl_offset = 0; } *mlli_entry_pp = mlli_entry_p; return 0; @@ -221,7 +222,7 @@ static int ssi_buffer_mgr_generate_mlli( /* Allocate memory from the pointed pool */ mlli_params->mlli_virt_addr = dma_pool_alloc( mlli_params->curr_pool, GFP_KERNEL, - &(mlli_params->mlli_dma_addr)); + &mlli_params->mlli_dma_addr); if (unlikely(!mlli_params->mlli_virt_addr)) { SSI_LOG_ERR("dma_pool_alloc() failed\n"); rc = -ENOMEM; @@ -249,7 +250,7 @@ static int ssi_buffer_mgr_generate_mlli( /*Calculate the current MLLI table length for the *length field in the descriptor */ - *(sg_data->mlli_nents[i]) += + *sg_data->mlli_nents[i] += (total_nents - prev_total_nents); prev_total_nents = total_nents; } @@ -259,9 +260,9 @@ static int ssi_buffer_mgr_generate_mlli( mlli_params->mlli_len = (total_nents * LLI_ENTRY_BYTE_SIZE); SSI_LOG_DEBUG("MLLI params: " - "virt_addr=%pK dma_addr=0x%llX mlli_len=0x%X\n", + "virt_addr=%pK dma_addr=%pad mlli_len=0x%X\n", mlli_params->mlli_virt_addr, - (unsigned long long)mlli_params->mlli_dma_addr, + mlli_params->mlli_dma_addr, mlli_params->mlli_len); build_mlli_exit: @@ -275,9 +276,9 @@ static inline void ssi_buffer_mgr_add_buffer_entry( { unsigned int index = sgl_data->num_of_buffers; - SSI_LOG_DEBUG("index=%u single_buff=0x%llX " + SSI_LOG_DEBUG("index=%u single_buff=%pad " "buffer_len=0x%08X is_last=%d\n", - index, (unsigned long long)buffer_dma, buffer_len, is_last_entry); + index, buffer_dma, buffer_len, is_last_entry); sgl_data->nents[index] = 1; sgl_data->entry[index].buffer_dma = buffer_dma; sgl_data->offset[index] = 0; @@ -302,7 +303,7 @@ static inline void ssi_buffer_mgr_add_scatterlist_entry( unsigned int index = sgl_data->num_of_buffers; SSI_LOG_DEBUG("index=%u nents=%u sgl=%pK data_len=0x%08X is_last=%d\n", - index, nents, sgl, data_len, is_last_table); + index, nents, sgl, data_len, is_last_table); sgl_data->nents[index] = nents; sgl_data->entry[index].sgl = sgl; sgl_data->offset[index] = data_offset; @@ -317,7 +318,7 @@ static inline void ssi_buffer_mgr_add_scatterlist_entry( static int ssi_buffer_mgr_dma_map_sg(struct device *dev, struct scatterlist *sg, u32 nents, - enum dma_data_direction direction) + enum dma_data_direction direction) { u32 i, j; struct scatterlist *l_sg = sg; @@ -358,10 +359,10 @@ static int ssi_buffer_mgr_map_scatterlist( SSI_LOG_ERR("dma_map_sg() single buffer failed\n"); return -ENOMEM; } - SSI_LOG_DEBUG("Mapped sg: dma_address=0x%llX " + SSI_LOG_DEBUG("Mapped sg: dma_address=%pad " "page=%p addr=%pK offset=%u " "length=%u\n", - (unsigned long long)sg_dma_address(sg), + sg_dma_address(sg), sg_page(sg), sg_virt(sg), sg->offset, sg->length); @@ -370,11 +371,11 @@ static int ssi_buffer_mgr_map_scatterlist( *mapped_nents = 1; } else { /*sg_is_last*/ *nents = ssi_buffer_mgr_get_sgl_nents(sg, nbytes, lbytes, - &is_chained); + &is_chained); if (*nents > max_sg_nents) { *nents = 0; SSI_LOG_ERR("Too many fragments. current %d max %d\n", - *nents, max_sg_nents); + *nents, max_sg_nents); return -ENOMEM; } if (!is_chained) { @@ -392,9 +393,9 @@ static int ssi_buffer_mgr_map_scatterlist( * must have the same nents before and after map */ *mapped_nents = ssi_buffer_mgr_dma_map_sg(dev, - sg, - *nents, - direction); + sg, + *nents, + direction); if (unlikely(*mapped_nents != *nents)) { *nents = *mapped_nents; SSI_LOG_ERR("dma_map_sg() sg buffer failed\n"); @@ -408,10 +409,10 @@ static int ssi_buffer_mgr_map_scatterlist( static inline int ssi_aead_handle_config_buf(struct device *dev, - struct aead_req_ctx *areq_ctx, - u8 *config_data, - struct buffer_array *sg_data, - unsigned int assoclen) + struct aead_req_ctx *areq_ctx, + u8 *config_data, + struct buffer_array *sg_data, + unsigned int assoclen) { SSI_LOG_DEBUG(" handle additional data config set to DLLI\n"); /* create sg for the current buffer */ @@ -422,10 +423,10 @@ ssi_aead_handle_config_buf(struct device *dev, "config buffer failed\n"); return -ENOMEM; } - SSI_LOG_DEBUG("Mapped curr_buff: dma_address=0x%llX " + SSI_LOG_DEBUG("Mapped curr_buff: dma_address=%pad " "page=%p addr=%pK " "offset=%u length=%u\n", - (unsigned long long)sg_dma_address(&areq_ctx->ccm_adata_sg), + sg_dma_address(&areq_ctx->ccm_adata_sg), sg_page(&areq_ctx->ccm_adata_sg), sg_virt(&areq_ctx->ccm_adata_sg), areq_ctx->ccm_adata_sg.offset, @@ -433,19 +434,18 @@ ssi_aead_handle_config_buf(struct device *dev, /* prepare for case of MLLI */ if (assoclen > 0) { ssi_buffer_mgr_add_scatterlist_entry(sg_data, 1, - &areq_ctx->ccm_adata_sg, - (AES_BLOCK_SIZE + - areq_ctx->ccm_hdr_size), 0, - false, NULL); + &areq_ctx->ccm_adata_sg, + (AES_BLOCK_SIZE + areq_ctx->ccm_hdr_size), + 0, false, NULL); } return 0; } static inline int ssi_ahash_handle_curr_buf(struct device *dev, - struct ahash_req_ctx *areq_ctx, - u8 *curr_buff, - u32 curr_buff_cnt, - struct buffer_array *sg_data) + struct ahash_req_ctx *areq_ctx, + u8 *curr_buff, + u32 curr_buff_cnt, + struct buffer_array *sg_data) { SSI_LOG_DEBUG(" handle curr buff %x set to DLLI\n", curr_buff_cnt); /* create sg for the current buffer */ @@ -456,10 +456,10 @@ static inline int ssi_ahash_handle_curr_buf(struct device *dev, "src buffer failed\n"); return -ENOMEM; } - SSI_LOG_DEBUG("Mapped curr_buff: dma_address=0x%llX " + SSI_LOG_DEBUG("Mapped curr_buff: dma_address=%pad " "page=%p addr=%pK " "offset=%u length=%u\n", - (unsigned long long)sg_dma_address(areq_ctx->buff_sg), + sg_dma_address(areq_ctx->buff_sg), sg_page(areq_ctx->buff_sg), sg_virt(areq_ctx->buff_sg), areq_ctx->buff_sg->offset, @@ -469,7 +469,7 @@ static inline int ssi_ahash_handle_curr_buf(struct device *dev, areq_ctx->in_nents = 0; /* prepare for case of MLLI */ ssi_buffer_mgr_add_scatterlist_entry(sg_data, 1, areq_ctx->buff_sg, - curr_buff_cnt, 0, false, NULL); + curr_buff_cnt, 0, false, NULL); return 0; } @@ -483,9 +483,9 @@ void ssi_buffer_mgr_unmap_blkcipher_request( struct blkcipher_req_ctx *req_ctx = (struct blkcipher_req_ctx *)ctx; if (likely(req_ctx->gen_ctx.iv_dma_addr != 0)) { - SSI_LOG_DEBUG("Unmapped iv: iv_dma_addr=0x%llX iv_size=%u\n", - (unsigned long long)req_ctx->gen_ctx.iv_dma_addr, - ivsize); + SSI_LOG_DEBUG("Unmapped iv: iv_dma_addr=%pad iv_size=%u\n", + req_ctx->gen_ctx.iv_dma_addr, + ivsize); dma_unmap_single(dev, req_ctx->gen_ctx.iv_dma_addr, ivsize, req_ctx->is_giv ? DMA_BIDIRECTIONAL : @@ -498,16 +498,12 @@ void ssi_buffer_mgr_unmap_blkcipher_request( req_ctx->mlli_params.mlli_dma_addr); } - dma_unmap_sg(dev, src, req_ctx->in_nents, - DMA_BIDIRECTIONAL); - SSI_LOG_DEBUG("Unmapped req->src=%pK\n", - sg_virt(src)); + dma_unmap_sg(dev, src, req_ctx->in_nents, DMA_BIDIRECTIONAL); + SSI_LOG_DEBUG("Unmapped req->src=%pK\n", sg_virt(src)); if (src != dst) { - dma_unmap_sg(dev, dst, req_ctx->out_nents, - DMA_BIDIRECTIONAL); - SSI_LOG_DEBUG("Unmapped req->dst=%pK\n", - sg_virt(dst)); + dma_unmap_sg(dev, dst, req_ctx->out_nents, DMA_BIDIRECTIONAL); + SSI_LOG_DEBUG("Unmapped req->dst=%pK\n", sg_virt(dst)); } } @@ -542,22 +538,24 @@ int ssi_buffer_mgr_map_blkcipher_request( req_ctx->is_giv ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE); if (unlikely(dma_mapping_error(dev, - req_ctx->gen_ctx.iv_dma_addr))) { + req_ctx->gen_ctx.iv_dma_addr))) { SSI_LOG_ERR("Mapping iv %u B at va=%pK " "for DMA failed\n", ivsize, info); return -ENOMEM; } - SSI_LOG_DEBUG("Mapped iv %u B at va=%pK to dma=0x%llX\n", - ivsize, info, - (unsigned long long)req_ctx->gen_ctx.iv_dma_addr); + SSI_LOG_DEBUG("Mapped iv %u B at va=%pK to dma=%pad\n", + ivsize, info, + req_ctx->gen_ctx.iv_dma_addr); } else { req_ctx->gen_ctx.iv_dma_addr = 0; } /* Map the src SGL */ rc = ssi_buffer_mgr_map_scatterlist(dev, src, - nbytes, DMA_BIDIRECTIONAL, &req_ctx->in_nents, - LLI_MAX_NUM_OF_DATA_ENTRIES, &dummy, &mapped_nents); + nbytes, DMA_BIDIRECTIONAL, + &req_ctx->in_nents, + LLI_MAX_NUM_OF_DATA_ENTRIES, &dummy, + &mapped_nents); if (unlikely(rc != 0)) { rc = -ENOMEM; goto ablkcipher_exit; @@ -570,8 +568,10 @@ int ssi_buffer_mgr_map_blkcipher_request( if (unlikely(req_ctx->dma_buf_type == SSI_DMA_BUF_MLLI)) { req_ctx->out_nents = 0; ssi_buffer_mgr_add_scatterlist_entry(&sg_data, - req_ctx->in_nents, src, - nbytes, 0, true, &req_ctx->in_mlli_nents); + req_ctx->in_nents, + src, nbytes, 0, + true, + &req_ctx->in_mlli_nents); } } else { /* Map the dst sg */ @@ -588,13 +588,15 @@ int ssi_buffer_mgr_map_blkcipher_request( if (unlikely((req_ctx->dma_buf_type == SSI_DMA_BUF_MLLI))) { ssi_buffer_mgr_add_scatterlist_entry(&sg_data, - req_ctx->in_nents, src, - nbytes, 0, true, - &req_ctx->in_mlli_nents); + req_ctx->in_nents, + src, nbytes, 0, + true, + &req_ctx->in_mlli_nents); ssi_buffer_mgr_add_scatterlist_entry(&sg_data, - req_ctx->out_nents, dst, - nbytes, 0, true, - &req_ctx->out_mlli_nents); + req_ctx->out_nents, + dst, nbytes, 0, + true, + &req_ctx->out_mlli_nents); } } @@ -606,7 +608,7 @@ int ssi_buffer_mgr_map_blkcipher_request( } SSI_LOG_DEBUG("areq_ctx->dma_buf_type = %s\n", - GET_DMA_BUFFER_TYPE(req_ctx->dma_buf_type)); + GET_DMA_BUFFER_TYPE(req_ctx->dma_buf_type)); return 0; @@ -628,7 +630,7 @@ void ssi_buffer_mgr_unmap_aead_request( if (areq_ctx->mac_buf_dma_addr != 0) { dma_unmap_single(dev, areq_ctx->mac_buf_dma_addr, - MAX_MAC_SIZE, DMA_BIDIRECTIONAL); + MAX_MAC_SIZE, DMA_BIDIRECTIONAL); } #if SSI_CC_HAS_AES_GCM @@ -645,12 +647,12 @@ void ssi_buffer_mgr_unmap_aead_request( if (areq_ctx->gcm_iv_inc1_dma_addr != 0) { dma_unmap_single(dev, areq_ctx->gcm_iv_inc1_dma_addr, - AES_BLOCK_SIZE, DMA_TO_DEVICE); + AES_BLOCK_SIZE, DMA_TO_DEVICE); } if (areq_ctx->gcm_iv_inc2_dma_addr != 0) { dma_unmap_single(dev, areq_ctx->gcm_iv_inc2_dma_addr, - AES_BLOCK_SIZE, DMA_TO_DEVICE); + AES_BLOCK_SIZE, DMA_TO_DEVICE); } } #endif @@ -658,7 +660,7 @@ void ssi_buffer_mgr_unmap_aead_request( if (areq_ctx->ccm_hdr_size != ccm_header_size_null) { if (areq_ctx->ccm_iv0_dma_addr != 0) { dma_unmap_single(dev, areq_ctx->ccm_iv0_dma_addr, - AES_BLOCK_SIZE, DMA_TO_DEVICE); + AES_BLOCK_SIZE, DMA_TO_DEVICE); } dma_unmap_sg(dev, &areq_ctx->ccm_adata_sg, 1, DMA_TO_DEVICE); @@ -672,9 +674,9 @@ void ssi_buffer_mgr_unmap_aead_request( *allocated and should be released */ if (areq_ctx->mlli_params.curr_pool) { - SSI_LOG_DEBUG("free MLLI buffer: dma=0x%08llX virt=%pK\n", - (unsigned long long)areq_ctx->mlli_params.mlli_dma_addr, - areq_ctx->mlli_params.mlli_virt_addr); + SSI_LOG_DEBUG("free MLLI buffer: dma=%pad virt=%pK\n", + areq_ctx->mlli_params.mlli_dma_addr, + areq_ctx->mlli_params.mlli_virt_addr); dma_pool_free(areq_ctx->mlli_params.curr_pool, areq_ctx->mlli_params.mlli_virt_addr, areq_ctx->mlli_params.mlli_dma_addr); @@ -690,14 +692,17 @@ void ssi_buffer_mgr_unmap_aead_request( dma_unmap_sg(dev, req->src, ssi_buffer_mgr_get_sgl_nents(req->src, size_to_unmap, &dummy, &chained), DMA_BIDIRECTIONAL); if (unlikely(req->src != req->dst)) { SSI_LOG_DEBUG("Unmapping dst sgl: req->dst=%pK\n", - sg_virt(req->dst)); - dma_unmap_sg(dev, req->dst, ssi_buffer_mgr_get_sgl_nents(req->dst, size_to_unmap, &dummy, &chained), - DMA_BIDIRECTIONAL); + sg_virt(req->dst)); + dma_unmap_sg(dev, req->dst, + ssi_buffer_mgr_get_sgl_nents(req->dst, + size_to_unmap, + &dummy, + &chained), + DMA_BIDIRECTIONAL); } if (drvdata->coherent && (areq_ctx->gen_ctx.op_type == DRV_CRYPTO_DIRECTION_DECRYPT) && - likely(req->src == req->dst)) - { + likely(req->src == req->dst)) { u32 size_to_skip = req->assoclen; if (areq_ctx->is_gcm4543) @@ -753,11 +758,11 @@ static inline int ssi_buffer_mgr_get_aead_icv_nents( *is_icv_fragmented = true; } else { SSI_LOG_ERR("Unsupported num. of ICV fragments (> %d)\n", - MAX_ICV_NENTS_SUPPORTED); + MAX_ICV_NENTS_SUPPORTED); nents = -1; /*unsupported*/ } SSI_LOG_DEBUG("is_frag=%s icv_nents=%u\n", - (*is_icv_fragmented ? "true" : "false"), nents); + (*is_icv_fragmented ? "true" : "false"), nents); return nents; } @@ -778,18 +783,18 @@ static inline int ssi_buffer_mgr_aead_chain_iv( goto chain_iv_exit; } - areq_ctx->gen_ctx.iv_dma_addr = dma_map_single(dev, req->iv, - hw_iv_size, DMA_BIDIRECTIONAL); + areq_ctx->gen_ctx.iv_dma_addr = dma_map_single(dev, req->iv, hw_iv_size, + DMA_BIDIRECTIONAL); if (unlikely(dma_mapping_error(dev, areq_ctx->gen_ctx.iv_dma_addr))) { SSI_LOG_ERR("Mapping iv %u B at va=%pK for DMA failed\n", - hw_iv_size, req->iv); + hw_iv_size, req->iv); rc = -ENOMEM; goto chain_iv_exit; } - SSI_LOG_DEBUG("Mapped iv %u B at va=%pK to dma=0x%llX\n", - hw_iv_size, req->iv, - (unsigned long long)areq_ctx->gen_ctx.iv_dma_addr); + SSI_LOG_DEBUG("Mapped iv %u B at va=%pK to dma=%pad\n", + hw_iv_size, req->iv, + areq_ctx->gen_ctx.iv_dma_addr); if (do_chain && areq_ctx->plaintext_authenticate_only) { // TODO: what about CTR?? ask Ron struct crypto_aead *tfm = crypto_aead_reqtfm(req); unsigned int iv_size_to_authenc = crypto_aead_ivsize(tfm); @@ -833,8 +838,8 @@ static inline int ssi_buffer_mgr_aead_chain_assoc( areq_ctx->assoc.nents = 0; areq_ctx->assoc.mlli_nents = 0; SSI_LOG_DEBUG("Chain assoc of length 0: buff_type=%s nents=%u\n", - GET_DMA_BUFFER_TYPE(areq_ctx->assoc_buff_type), - areq_ctx->assoc.nents); + GET_DMA_BUFFER_TYPE(areq_ctx->assoc_buff_type), + areq_ctx->assoc.nents); goto chain_assoc_exit; } @@ -868,10 +873,9 @@ static inline int ssi_buffer_mgr_aead_chain_assoc( if (areq_ctx->ccm_hdr_size != ccm_header_size_null) { if (unlikely((mapped_nents + 1) > LLI_MAX_NUM_OF_ASSOC_DATA_ENTRIES)) { - SSI_LOG_ERR("CCM case.Too many fragments. " - "Current %d max %d\n", - (areq_ctx->assoc.nents + 1), - LLI_MAX_NUM_OF_ASSOC_DATA_ENTRIES); + SSI_LOG_ERR("CCM case.Too many fragments. Current %d max %d\n", + (areq_ctx->assoc.nents + 1), + LLI_MAX_NUM_OF_ASSOC_DATA_ENTRIES); rc = -ENOMEM; goto chain_assoc_exit; } @@ -884,10 +888,10 @@ static inline int ssi_buffer_mgr_aead_chain_assoc( areq_ctx->assoc_buff_type = SSI_DMA_BUF_MLLI; if (unlikely((do_chain) || - (areq_ctx->assoc_buff_type == SSI_DMA_BUF_MLLI))) { + (areq_ctx->assoc_buff_type == SSI_DMA_BUF_MLLI))) { SSI_LOG_DEBUG("Chain assoc: buff_type=%s nents=%u\n", - GET_DMA_BUFFER_TYPE(areq_ctx->assoc_buff_type), - areq_ctx->assoc.nents); + GET_DMA_BUFFER_TYPE(areq_ctx->assoc_buff_type), + areq_ctx->assoc.nents); ssi_buffer_mgr_add_scatterlist_entry( sg_data, areq_ctx->assoc.nents, req->src, req->assoclen, 0, is_last, @@ -911,26 +915,26 @@ static inline void ssi_buffer_mgr_prepare_aead_data_dlli( if (likely(req->src == req->dst)) { /*INPLACE*/ areq_ctx->icv_dma_addr = sg_dma_address( - areq_ctx->srcSgl) + + areq_ctx->src_sgl) + (*src_last_bytes - authsize); areq_ctx->icv_virt_addr = sg_virt( - areq_ctx->srcSgl) + + areq_ctx->src_sgl) + (*src_last_bytes - authsize); } else if (direct == DRV_CRYPTO_DIRECTION_DECRYPT) { /*NON-INPLACE and DECRYPT*/ areq_ctx->icv_dma_addr = sg_dma_address( - areq_ctx->srcSgl) + + areq_ctx->src_sgl) + (*src_last_bytes - authsize); areq_ctx->icv_virt_addr = sg_virt( - areq_ctx->srcSgl) + + areq_ctx->src_sgl) + (*src_last_bytes - authsize); } else { /*NON-INPLACE and ENCRYPT*/ areq_ctx->icv_dma_addr = sg_dma_address( - areq_ctx->dstSgl) + + areq_ctx->dst_sgl) + (*dst_last_bytes - authsize); areq_ctx->icv_virt_addr = sg_virt( - areq_ctx->dstSgl) + + areq_ctx->dst_sgl) + (*dst_last_bytes - authsize); } } @@ -951,13 +955,18 @@ static inline int ssi_buffer_mgr_prepare_aead_data_mlli( if (likely(req->src == req->dst)) { /*INPLACE*/ ssi_buffer_mgr_add_scatterlist_entry(sg_data, - areq_ctx->src.nents, areq_ctx->srcSgl, - areq_ctx->cryptlen, areq_ctx->srcOffset, is_last_table, - &areq_ctx->src.mlli_nents); - - icv_nents = ssi_buffer_mgr_get_aead_icv_nents(areq_ctx->srcSgl, - areq_ctx->src.nents, authsize, *src_last_bytes, - &areq_ctx->is_icv_fragmented); + areq_ctx->src.nents, + areq_ctx->src_sgl, + areq_ctx->cryptlen, + areq_ctx->src_offset, + is_last_table, + &areq_ctx->src.mlli_nents); + + icv_nents = ssi_buffer_mgr_get_aead_icv_nents(areq_ctx->src_sgl, + areq_ctx->src.nents, + authsize, + *src_last_bytes, + &areq_ctx->is_icv_fragmented); if (unlikely(icv_nents < 0)) { rc = -ENOTSUPP; goto prepare_data_mlli_exit; @@ -995,27 +1004,35 @@ static inline int ssi_buffer_mgr_prepare_aead_data_mlli( } else { /* Contig. ICV */ /*Should hanlde if the sg is not contig.*/ areq_ctx->icv_dma_addr = sg_dma_address( - &areq_ctx->srcSgl[areq_ctx->src.nents - 1]) + + &areq_ctx->src_sgl[areq_ctx->src.nents - 1]) + (*src_last_bytes - authsize); areq_ctx->icv_virt_addr = sg_virt( - &areq_ctx->srcSgl[areq_ctx->src.nents - 1]) + + &areq_ctx->src_sgl[areq_ctx->src.nents - 1]) + (*src_last_bytes - authsize); } } else if (direct == DRV_CRYPTO_DIRECTION_DECRYPT) { /*NON-INPLACE and DECRYPT*/ ssi_buffer_mgr_add_scatterlist_entry(sg_data, - areq_ctx->src.nents, areq_ctx->srcSgl, - areq_ctx->cryptlen, areq_ctx->srcOffset, is_last_table, - &areq_ctx->src.mlli_nents); + areq_ctx->src.nents, + areq_ctx->src_sgl, + areq_ctx->cryptlen, + areq_ctx->src_offset, + is_last_table, + &areq_ctx->src.mlli_nents); ssi_buffer_mgr_add_scatterlist_entry(sg_data, - areq_ctx->dst.nents, areq_ctx->dstSgl, - areq_ctx->cryptlen, areq_ctx->dstOffset, is_last_table, - &areq_ctx->dst.mlli_nents); - - icv_nents = ssi_buffer_mgr_get_aead_icv_nents(areq_ctx->srcSgl, - areq_ctx->src.nents, authsize, *src_last_bytes, - &areq_ctx->is_icv_fragmented); + areq_ctx->dst.nents, + areq_ctx->dst_sgl, + areq_ctx->cryptlen, + areq_ctx->dst_offset, + is_last_table, + &areq_ctx->dst.mlli_nents); + + icv_nents = ssi_buffer_mgr_get_aead_icv_nents(areq_ctx->src_sgl, + areq_ctx->src.nents, + authsize, + *src_last_bytes, + &areq_ctx->is_icv_fragmented); if (unlikely(icv_nents < 0)) { rc = -ENOTSUPP; goto prepare_data_mlli_exit; @@ -1039,26 +1056,34 @@ static inline int ssi_buffer_mgr_prepare_aead_data_mlli( } else { /* Contig. ICV */ /*Should hanlde if the sg is not contig.*/ areq_ctx->icv_dma_addr = sg_dma_address( - &areq_ctx->srcSgl[areq_ctx->src.nents - 1]) + + &areq_ctx->src_sgl[areq_ctx->src.nents - 1]) + (*src_last_bytes - authsize); areq_ctx->icv_virt_addr = sg_virt( - &areq_ctx->srcSgl[areq_ctx->src.nents - 1]) + + &areq_ctx->src_sgl[areq_ctx->src.nents - 1]) + (*src_last_bytes - authsize); } } else { /*NON-INPLACE and ENCRYPT*/ ssi_buffer_mgr_add_scatterlist_entry(sg_data, - areq_ctx->dst.nents, areq_ctx->dstSgl, - areq_ctx->cryptlen, areq_ctx->dstOffset, is_last_table, - &areq_ctx->dst.mlli_nents); + areq_ctx->dst.nents, + areq_ctx->dst_sgl, + areq_ctx->cryptlen, + areq_ctx->dst_offset, + is_last_table, + &areq_ctx->dst.mlli_nents); ssi_buffer_mgr_add_scatterlist_entry(sg_data, - areq_ctx->src.nents, areq_ctx->srcSgl, - areq_ctx->cryptlen, areq_ctx->srcOffset, is_last_table, - &areq_ctx->src.mlli_nents); - - icv_nents = ssi_buffer_mgr_get_aead_icv_nents(areq_ctx->dstSgl, - areq_ctx->dst.nents, authsize, *dst_last_bytes, + areq_ctx->src.nents, + areq_ctx->src_sgl, + areq_ctx->cryptlen, + areq_ctx->src_offset, + is_last_table, + &areq_ctx->src.mlli_nents); + + icv_nents = ssi_buffer_mgr_get_aead_icv_nents(areq_ctx->dst_sgl, + areq_ctx->dst.nents, + authsize, + *dst_last_bytes, &areq_ctx->is_icv_fragmented); if (unlikely(icv_nents < 0)) { rc = -ENOTSUPP; @@ -1068,10 +1093,10 @@ static inline int ssi_buffer_mgr_prepare_aead_data_mlli( if (likely(!areq_ctx->is_icv_fragmented)) { /* Contig. ICV */ areq_ctx->icv_dma_addr = sg_dma_address( - &areq_ctx->dstSgl[areq_ctx->dst.nents - 1]) + + &areq_ctx->dst_sgl[areq_ctx->dst.nents - 1]) + (*dst_last_bytes - authsize); areq_ctx->icv_virt_addr = sg_virt( - &areq_ctx->dstSgl[areq_ctx->dst.nents - 1]) + + &areq_ctx->dst_sgl[areq_ctx->dst.nents - 1]) + (*dst_last_bytes - authsize); } else { areq_ctx->icv_dma_addr = areq_ctx->mac_buf_dma_addr; @@ -1113,37 +1138,36 @@ static inline int ssi_buffer_mgr_aead_chain_data( rc = -EINVAL; goto chain_data_exit; } - areq_ctx->srcSgl = req->src; - areq_ctx->dstSgl = req->dst; + areq_ctx->src_sgl = req->src; + areq_ctx->dst_sgl = req->dst; if (is_gcm4543) size_for_map += crypto_aead_ivsize(tfm); size_for_map += (direct == DRV_CRYPTO_DIRECTION_ENCRYPT) ? authsize : 0; src_mapped_nents = ssi_buffer_mgr_get_sgl_nents(req->src, size_for_map, &src_last_bytes, &chained); - sg_index = areq_ctx->srcSgl->length; + sg_index = areq_ctx->src_sgl->length; //check where the data starts while (sg_index <= size_to_skip) { - offset -= areq_ctx->srcSgl->length; - areq_ctx->srcSgl = sg_next(areq_ctx->srcSgl); + offset -= areq_ctx->src_sgl->length; + areq_ctx->src_sgl = sg_next(areq_ctx->src_sgl); //if have reached the end of the sgl, then this is unexpected - if (!areq_ctx->srcSgl) { + if (!areq_ctx->src_sgl) { SSI_LOG_ERR("reached end of sg list. unexpected\n"); BUG(); } - sg_index += areq_ctx->srcSgl->length; + sg_index += areq_ctx->src_sgl->length; src_mapped_nents--; } - if (unlikely(src_mapped_nents > LLI_MAX_NUM_OF_DATA_ENTRIES)) - { + if (unlikely(src_mapped_nents > LLI_MAX_NUM_OF_DATA_ENTRIES)) { SSI_LOG_ERR("Too many fragments. current %d max %d\n", - src_mapped_nents, LLI_MAX_NUM_OF_DATA_ENTRIES); + src_mapped_nents, LLI_MAX_NUM_OF_DATA_ENTRIES); return -ENOMEM; } areq_ctx->src.nents = src_mapped_nents; - areq_ctx->srcOffset = offset; + areq_ctx->src_offset = offset; if (req->src != req->dst) { size_for_map = req->assoclen + req->cryptlen; @@ -1152,9 +1176,11 @@ static inline int ssi_buffer_mgr_aead_chain_data( size_for_map += crypto_aead_ivsize(tfm); rc = ssi_buffer_mgr_map_scatterlist(dev, req->dst, size_for_map, - DMA_BIDIRECTIONAL, &(areq_ctx->dst.nents), - LLI_MAX_NUM_OF_DATA_ENTRIES, &dst_last_bytes, - &dst_mapped_nents); + DMA_BIDIRECTIONAL, + &areq_ctx->dst.nents, + LLI_MAX_NUM_OF_DATA_ENTRIES, + &dst_last_bytes, + &dst_mapped_nents); if (unlikely(rc != 0)) { rc = -ENOMEM; goto chain_data_exit; @@ -1162,35 +1188,37 @@ static inline int ssi_buffer_mgr_aead_chain_data( } dst_mapped_nents = ssi_buffer_mgr_get_sgl_nents(req->dst, size_for_map, &dst_last_bytes, &chained); - sg_index = areq_ctx->dstSgl->length; + sg_index = areq_ctx->dst_sgl->length; offset = size_to_skip; //check where the data starts while (sg_index <= size_to_skip) { - offset -= areq_ctx->dstSgl->length; - areq_ctx->dstSgl = sg_next(areq_ctx->dstSgl); + offset -= areq_ctx->dst_sgl->length; + areq_ctx->dst_sgl = sg_next(areq_ctx->dst_sgl); //if have reached the end of the sgl, then this is unexpected - if (!areq_ctx->dstSgl) { + if (!areq_ctx->dst_sgl) { SSI_LOG_ERR("reached end of sg list. unexpected\n"); BUG(); } - sg_index += areq_ctx->dstSgl->length; + sg_index += areq_ctx->dst_sgl->length; dst_mapped_nents--; } - if (unlikely(dst_mapped_nents > LLI_MAX_NUM_OF_DATA_ENTRIES)) - { + if (unlikely(dst_mapped_nents > LLI_MAX_NUM_OF_DATA_ENTRIES)) { SSI_LOG_ERR("Too many fragments. current %d max %d\n", dst_mapped_nents, LLI_MAX_NUM_OF_DATA_ENTRIES); return -ENOMEM; } areq_ctx->dst.nents = dst_mapped_nents; - areq_ctx->dstOffset = offset; + areq_ctx->dst_offset = offset; if ((src_mapped_nents > 1) || (dst_mapped_nents > 1) || do_chain) { areq_ctx->data_buff_type = SSI_DMA_BUF_MLLI; - rc = ssi_buffer_mgr_prepare_aead_data_mlli(drvdata, req, sg_data, - &src_last_bytes, &dst_last_bytes, is_last_table); + rc = ssi_buffer_mgr_prepare_aead_data_mlli(drvdata, req, + sg_data, + &src_last_bytes, + &dst_last_bytes, + is_last_table); } else { areq_ctx->data_buff_type = SSI_DMA_BUF_DLLI; ssi_buffer_mgr_prepare_aead_data_dlli( @@ -1202,7 +1230,7 @@ chain_data_exit: } static void ssi_buffer_mgr_update_aead_mlli_nents(struct ssi_drvdata *drvdata, - struct aead_request *req) + struct aead_request *req) { struct aead_req_ctx *areq_ctx = aead_request_ctx(req); u32 curr_mlli_size = 0; @@ -1274,8 +1302,7 @@ int ssi_buffer_mgr_map_aead_request( if (drvdata->coherent && (areq_ctx->gen_ctx.op_type == DRV_CRYPTO_DIRECTION_DECRYPT) && - likely(req->src == req->dst)) - { + likely(req->src == req->dst)) { u32 size_to_skip = req->assoclen; if (is_gcm4543) @@ -1296,19 +1323,21 @@ int ssi_buffer_mgr_map_aead_request( req->cryptlen : (req->cryptlen - authsize); - areq_ctx->mac_buf_dma_addr = dma_map_single(dev, - areq_ctx->mac_buf, MAX_MAC_SIZE, DMA_BIDIRECTIONAL); + areq_ctx->mac_buf_dma_addr = dma_map_single(dev, areq_ctx->mac_buf, + MAX_MAC_SIZE, + DMA_BIDIRECTIONAL); if (unlikely(dma_mapping_error(dev, areq_ctx->mac_buf_dma_addr))) { SSI_LOG_ERR("Mapping mac_buf %u B at va=%pK for DMA failed\n", - MAX_MAC_SIZE, areq_ctx->mac_buf); + MAX_MAC_SIZE, areq_ctx->mac_buf); rc = -ENOMEM; goto aead_map_failure; } if (areq_ctx->ccm_hdr_size != ccm_header_size_null) { areq_ctx->ccm_iv0_dma_addr = dma_map_single(dev, - (areq_ctx->ccm_config + CCM_CTR_COUNT_0_OFFSET), - AES_BLOCK_SIZE, DMA_TO_DEVICE); + (areq_ctx->ccm_config + CCM_CTR_COUNT_0_OFFSET), + AES_BLOCK_SIZE, + DMA_TO_DEVICE); if (unlikely(dma_mapping_error(dev, areq_ctx->ccm_iv0_dma_addr))) { SSI_LOG_ERR("Mapping mac_buf %u B at va=%pK " @@ -1319,7 +1348,8 @@ int ssi_buffer_mgr_map_aead_request( goto aead_map_failure; } if (ssi_aead_handle_config_buf(dev, areq_ctx, - areq_ctx->ccm_config, &sg_data, req->assoclen) != 0) { + areq_ctx->ccm_config, &sg_data, + req->assoclen) != 0) { rc = -ENOMEM; goto aead_map_failure; } @@ -1328,26 +1358,31 @@ int ssi_buffer_mgr_map_aead_request( #if SSI_CC_HAS_AES_GCM if (areq_ctx->cipher_mode == DRV_CIPHER_GCTR) { areq_ctx->hkey_dma_addr = dma_map_single(dev, - areq_ctx->hkey, AES_BLOCK_SIZE, DMA_BIDIRECTIONAL); + areq_ctx->hkey, + AES_BLOCK_SIZE, + DMA_BIDIRECTIONAL); if (unlikely(dma_mapping_error(dev, areq_ctx->hkey_dma_addr))) { SSI_LOG_ERR("Mapping hkey %u B at va=%pK for DMA failed\n", - AES_BLOCK_SIZE, areq_ctx->hkey); + AES_BLOCK_SIZE, areq_ctx->hkey); rc = -ENOMEM; goto aead_map_failure; } areq_ctx->gcm_block_len_dma_addr = dma_map_single(dev, - &areq_ctx->gcm_len_block, AES_BLOCK_SIZE, DMA_TO_DEVICE); + &areq_ctx->gcm_len_block, + AES_BLOCK_SIZE, + DMA_TO_DEVICE); if (unlikely(dma_mapping_error(dev, areq_ctx->gcm_block_len_dma_addr))) { SSI_LOG_ERR("Mapping gcm_len_block %u B at va=%pK for DMA failed\n", - AES_BLOCK_SIZE, &areq_ctx->gcm_len_block); + AES_BLOCK_SIZE, &areq_ctx->gcm_len_block); rc = -ENOMEM; goto aead_map_failure; } areq_ctx->gcm_iv_inc1_dma_addr = dma_map_single(dev, - areq_ctx->gcm_iv_inc1, - AES_BLOCK_SIZE, DMA_TO_DEVICE); + areq_ctx->gcm_iv_inc1, + AES_BLOCK_SIZE, + DMA_TO_DEVICE); if (unlikely(dma_mapping_error(dev, areq_ctx->gcm_iv_inc1_dma_addr))) { SSI_LOG_ERR("Mapping gcm_iv_inc1 %u B at va=%pK " @@ -1359,8 +1394,9 @@ int ssi_buffer_mgr_map_aead_request( } areq_ctx->gcm_iv_inc2_dma_addr = dma_map_single(dev, - areq_ctx->gcm_iv_inc2, - AES_BLOCK_SIZE, DMA_TO_DEVICE); + areq_ctx->gcm_iv_inc2, + AES_BLOCK_SIZE, + DMA_TO_DEVICE); if (unlikely(dma_mapping_error(dev, areq_ctx->gcm_iv_inc2_dma_addr))) { SSI_LOG_ERR("Mapping gcm_iv_inc2 %u B at va=%pK " @@ -1380,7 +1416,7 @@ int ssi_buffer_mgr_map_aead_request( if (is_gcm4543) size_to_map += crypto_aead_ivsize(tfm); rc = ssi_buffer_mgr_map_scatterlist(dev, req->src, - size_to_map, DMA_BIDIRECTIONAL, &(areq_ctx->src.nents), + size_to_map, DMA_BIDIRECTIONAL, &areq_ctx->src.nents, LLI_MAX_NUM_OF_ASSOC_DATA_ENTRIES + LLI_MAX_NUM_OF_DATA_ENTRIES, &dummy, &mapped_nents); if (unlikely(rc != 0)) { rc = -ENOMEM; @@ -1491,18 +1527,18 @@ int ssi_buffer_mgr_map_hash_request_final( /* map the previous buffer */ if (*curr_buff_cnt != 0) { if (ssi_ahash_handle_curr_buf(dev, areq_ctx, curr_buff, - *curr_buff_cnt, &sg_data) != 0) { + *curr_buff_cnt, &sg_data) != 0) { return -ENOMEM; } } if (src && (nbytes > 0) && do_update) { - if (unlikely(ssi_buffer_mgr_map_scatterlist(dev, src, - nbytes, - DMA_TO_DEVICE, - &areq_ctx->in_nents, - LLI_MAX_NUM_OF_DATA_ENTRIES, - &dummy, &mapped_nents))){ + if (unlikely(ssi_buffer_mgr_map_scatterlist(dev, src, nbytes, + DMA_TO_DEVICE, + &areq_ctx->in_nents, + LLI_MAX_NUM_OF_DATA_ENTRIES, + &dummy, + &mapped_nents))){ goto unmap_curr_buff; } if (src && (mapped_nents == 1) @@ -1522,19 +1558,18 @@ int ssi_buffer_mgr_map_hash_request_final( mlli_params->curr_pool = buff_mgr->mlli_buffs_pool; /* add the src data to the sg_data */ ssi_buffer_mgr_add_scatterlist_entry(&sg_data, - areq_ctx->in_nents, - src, - nbytes, 0, - true, &areq_ctx->mlli_nents); + areq_ctx->in_nents, + src, nbytes, 0, true, + &areq_ctx->mlli_nents); if (unlikely(ssi_buffer_mgr_generate_mlli(dev, &sg_data, - mlli_params) != 0)) { + mlli_params) != 0)) { goto fail_unmap_din; } } /* change the buffer index for the unmap function */ areq_ctx->buff_index = (areq_ctx->buff_index ^ 1); SSI_LOG_DEBUG("areq_ctx->data_dma_buf_type = %s\n", - GET_DMA_BUFFER_TYPE(areq_ctx->data_dma_buf_type)); + GET_DMA_BUFFER_TYPE(areq_ctx->data_dma_buf_type)); return 0; fail_unmap_din: @@ -1588,8 +1623,8 @@ int ssi_buffer_mgr_map_hash_request_update( &curr_buff[*curr_buff_cnt]); areq_ctx->in_nents = ssi_buffer_mgr_get_sgl_nents(src, - nbytes, - &dummy, NULL); + nbytes, + &dummy, NULL); sg_copy_to_buffer(src, areq_ctx->in_nents, &curr_buff[*curr_buff_cnt], nbytes); *curr_buff_cnt += nbytes; @@ -1612,15 +1647,15 @@ int ssi_buffer_mgr_map_hash_request_update( (update_data_len - *curr_buff_cnt), *next_buff_cnt); ssi_buffer_mgr_copy_scatterlist_portion(next_buff, src, - (update_data_len - *curr_buff_cnt), - nbytes, SSI_SG_TO_BUF); + (update_data_len - *curr_buff_cnt), + nbytes, SSI_SG_TO_BUF); /* change the buffer index for next operation */ swap_index = 1; } if (*curr_buff_cnt != 0) { if (ssi_ahash_handle_curr_buf(dev, areq_ctx, curr_buff, - *curr_buff_cnt, &sg_data) != 0) { + *curr_buff_cnt, &sg_data) != 0) { return -ENOMEM; } /* change the buffer index for next operation */ @@ -1629,11 +1664,12 @@ int ssi_buffer_mgr_map_hash_request_update( if (update_data_len > *curr_buff_cnt) { if (unlikely(ssi_buffer_mgr_map_scatterlist(dev, src, - (update_data_len - *curr_buff_cnt), - DMA_TO_DEVICE, - &areq_ctx->in_nents, - LLI_MAX_NUM_OF_DATA_ENTRIES, - &dummy, &mapped_nents))){ + (update_data_len - *curr_buff_cnt), + DMA_TO_DEVICE, + &areq_ctx->in_nents, + LLI_MAX_NUM_OF_DATA_ENTRIES, + &dummy, + &mapped_nents))){ goto unmap_curr_buff; } if ((mapped_nents == 1) @@ -1653,12 +1689,14 @@ int ssi_buffer_mgr_map_hash_request_update( mlli_params->curr_pool = buff_mgr->mlli_buffs_pool; /* add the src data to the sg_data */ ssi_buffer_mgr_add_scatterlist_entry(&sg_data, - areq_ctx->in_nents, - src, - (update_data_len - *curr_buff_cnt), 0, - true, &areq_ctx->mlli_nents); + areq_ctx->in_nents, + src, + (update_data_len - *curr_buff_cnt), + 0, + true, + &areq_ctx->mlli_nents); if (unlikely(ssi_buffer_mgr_generate_mlli(dev, &sg_data, - mlli_params) != 0)) { + mlli_params) != 0)) { goto fail_unmap_din; } } @@ -1687,28 +1725,28 @@ void ssi_buffer_mgr_unmap_hash_request( *allocated and should be released */ if (areq_ctx->mlli_params.curr_pool) { - SSI_LOG_DEBUG("free MLLI buffer: dma=0x%llX virt=%pK\n", - (unsigned long long)areq_ctx->mlli_params.mlli_dma_addr, - areq_ctx->mlli_params.mlli_virt_addr); + SSI_LOG_DEBUG("free MLLI buffer: dma=%pad virt=%pK\n", + areq_ctx->mlli_params.mlli_dma_addr, + areq_ctx->mlli_params.mlli_virt_addr); dma_pool_free(areq_ctx->mlli_params.curr_pool, areq_ctx->mlli_params.mlli_virt_addr, areq_ctx->mlli_params.mlli_dma_addr); } if ((src) && likely(areq_ctx->in_nents != 0)) { - SSI_LOG_DEBUG("Unmapped sg src: virt=%pK dma=0x%llX len=0x%X\n", - sg_virt(src), - (unsigned long long)sg_dma_address(src), - sg_dma_len(src)); + SSI_LOG_DEBUG("Unmapped sg src: virt=%pK dma=%pad len=0x%X\n", + sg_virt(src), + sg_dma_address(src), + sg_dma_len(src)); dma_unmap_sg(dev, src, areq_ctx->in_nents, DMA_TO_DEVICE); } if (*prev_len != 0) { SSI_LOG_DEBUG("Unmapped buffer: areq_ctx->buff_sg=%pK" - " dma=0x%llX len 0x%X\n", + " dma=%pad len 0x%X\n", sg_virt(areq_ctx->buff_sg), - (unsigned long long)sg_dma_address(areq_ctx->buff_sg), + sg_dma_address(areq_ctx->buff_sg), sg_dma_len(areq_ctx->buff_sg)); dma_unmap_sg(dev, areq_ctx->buff_sg, 1, DMA_TO_DEVICE); if (!do_revert) { @@ -1725,8 +1763,7 @@ int ssi_buffer_mgr_init(struct ssi_drvdata *drvdata) struct buff_mgr_handle *buff_mgr_handle; struct device *dev = &drvdata->plat_dev->dev; - buff_mgr_handle = (struct buff_mgr_handle *) - kmalloc(sizeof(struct buff_mgr_handle), GFP_KERNEL); + buff_mgr_handle = kmalloc(sizeof(*buff_mgr_handle), GFP_KERNEL); if (!buff_mgr_handle) return -ENOMEM; diff --git a/drivers/staging/ccree/ssi_cipher.c b/drivers/staging/ccree/ssi_cipher.c index cd2eafc04232..8d31a93fd8b7 100644 --- a/drivers/staging/ccree/ssi_cipher.c +++ b/drivers/staging/ccree/ssi_cipher.c @@ -23,6 +23,8 @@ #include <crypto/aes.h> #include <crypto/ctr.h> #include <crypto/des.h> +#include <crypto/xts.h> +#include <crypto/scatterwalk.h> #include "ssi_config.h" #include "ssi_driver.h" @@ -31,7 +33,6 @@ #include "ssi_cipher.h" #include "ssi_request_mgr.h" #include "ssi_sysfs.h" -#include "ssi_fips_local.h" #define MAX_ABLKCIPHER_SEQ_LEN 6 @@ -68,7 +69,8 @@ struct ssi_ablkcipher_ctx { static void ssi_ablkcipher_complete(struct device *dev, void *ssi_req, void __iomem *cc_base); -static int validate_keys_sizes(struct ssi_ablkcipher_ctx *ctx_p, u32 size) { +static int validate_keys_sizes(struct ssi_ablkcipher_ctx *ctx_p, u32 size) +{ switch (ctx_p->flow_mode) { case S_DIN_to_AES: switch (size) { @@ -92,8 +94,7 @@ static int validate_keys_sizes(struct ssi_ablkcipher_ctx *ctx_p, u32 size) { break; } case S_DIN_to_DES: - if (likely(size == DES3_EDE_KEY_SIZE || - size == DES_KEY_SIZE)) + if (likely(size == DES3_EDE_KEY_SIZE || size == DES_KEY_SIZE)) return 0; break; #if SSI_CC_HAS_MULTI2 @@ -108,7 +109,8 @@ static int validate_keys_sizes(struct ssi_ablkcipher_ctx *ctx_p, u32 size) { return -EINVAL; } -static int validate_data_size(struct ssi_ablkcipher_ctx *ctx_p, unsigned int size) { +static int validate_data_size(struct ssi_ablkcipher_ctx *ctx_p, unsigned int size) +{ switch (ctx_p->flow_mode) { case S_DIN_to_AES: switch (ctx_p->cipher_mode) { @@ -183,10 +185,9 @@ static int ssi_blkcipher_init(struct crypto_tfm *tfm) int rc = 0; unsigned int max_key_buf_size = get_max_keysize(tfm); - SSI_LOG_DEBUG("Initializing context @%p for %s\n", ctx_p, - crypto_tfm_alg_name(tfm)); + SSI_LOG_DEBUG("Initializing context @%p for %s\n", + ctx_p, crypto_tfm_alg_name(tfm)); - CHECK_AND_RETURN_UPON_FIPS_ERROR(); ctx_p->cipher_mode = ssi_alg->cipher_mode; ctx_p->flow_mode = ssi_alg->flow_mode; ctx_p->drvdata = ssi_alg->drvdata; @@ -203,15 +204,16 @@ static int ssi_blkcipher_init(struct crypto_tfm *tfm) /* Map key buffer */ ctx_p->user.key_dma_addr = dma_map_single(dev, (void *)ctx_p->user.key, - max_key_buf_size, DMA_TO_DEVICE); + max_key_buf_size, + DMA_TO_DEVICE); if (dma_mapping_error(dev, ctx_p->user.key_dma_addr)) { SSI_LOG_ERR("Mapping Key %u B at va=%pK for DMA failed\n", - max_key_buf_size, ctx_p->user.key); + max_key_buf_size, ctx_p->user.key); return -ENOMEM; } - SSI_LOG_DEBUG("Mapped key %u B at va=%pK to dma=0x%llX\n", - max_key_buf_size, ctx_p->user.key, - (unsigned long long)ctx_p->user.key_dma_addr); + SSI_LOG_DEBUG("Mapped key %u B at va=%pK to dma=%pad\n", + max_key_buf_size, ctx_p->user.key, + ctx_p->user.key_dma_addr); if (ctx_p->cipher_mode == DRV_CIPHER_ESSIV) { /* Alloc hash tfm for essiv */ @@ -232,7 +234,7 @@ static void ssi_blkcipher_exit(struct crypto_tfm *tfm) unsigned int max_key_buf_size = get_max_keysize(tfm); SSI_LOG_DEBUG("Clearing context @%p for %s\n", - crypto_tfm_ctx(tfm), crypto_tfm_alg_name(tfm)); + crypto_tfm_ctx(tfm), crypto_tfm_alg_name(tfm)); if (ctx_p->cipher_mode == DRV_CIPHER_ESSIV) { /* Free hash tfm for essiv */ @@ -242,9 +244,9 @@ static void ssi_blkcipher_exit(struct crypto_tfm *tfm) /* Unmap key buffer */ dma_unmap_single(dev, ctx_p->user.key_dma_addr, max_key_buf_size, - DMA_TO_DEVICE); - SSI_LOG_DEBUG("Unmapped key buffer key_dma_addr=0x%llX\n", - (unsigned long long)ctx_p->user.key_dma_addr); + DMA_TO_DEVICE); + SSI_LOG_DEBUG("Unmapped key buffer key_dma_addr=%pad\n", + ctx_p->user.key_dma_addr); /* Free key buffer in context */ kfree(ctx_p->user.key); @@ -263,31 +265,15 @@ static const u8 zero_buff[] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; /* The function verifies that tdes keys are not weak.*/ -static int ssi_fips_verify_3des_keys(const u8 *key, unsigned int keylen) +static int ssi_verify_3des_keys(const u8 *key, unsigned int keylen) { -#ifdef CCREE_FIPS_SUPPORT struct tdes_keys *tdes_key = (struct tdes_keys *)key; /* verify key1 != key2 and key3 != key2*/ if (unlikely((memcmp((u8 *)tdes_key->key1, (u8 *)tdes_key->key2, sizeof(tdes_key->key1)) == 0) || - (memcmp((u8 *)tdes_key->key3, (u8 *)tdes_key->key2, sizeof(tdes_key->key3)) == 0))) { + (memcmp((u8 *)tdes_key->key3, (u8 *)tdes_key->key2, sizeof(tdes_key->key3)) == 0))) { return -ENOEXEC; } -#endif /* CCREE_FIPS_SUPPORT */ - - return 0; -} - -/* The function verifies that xts keys are not weak.*/ -static int ssi_fips_verify_xts_keys(const u8 *key, unsigned int keylen) -{ -#ifdef CCREE_FIPS_SUPPORT - /* Weak key is define as key that its first half (128/256 lsb) equals its second half (128/256 msb) */ - int singleKeySize = keylen >> 1; - - if (unlikely(memcmp(key, &key[singleKeySize], singleKeySize) == 0)) - return -ENOEXEC; -#endif /* CCREE_FIPS_SUPPORT */ return 0; } @@ -317,12 +303,10 @@ static int ssi_blkcipher_setkey(struct crypto_tfm *tfm, unsigned int max_key_buf_size = get_max_keysize(tfm); SSI_LOG_DEBUG("Setting key in context @%p for %s. keylen=%u\n", - ctx_p, crypto_tfm_alg_name(tfm), keylen); + ctx_p, crypto_tfm_alg_name(tfm), keylen); dump_byte_array("key", (u8 *)key, keylen); - CHECK_AND_RETURN_UPON_FIPS_ERROR(); - - SSI_LOG_DEBUG("ssi_blkcipher_setkey: after FIPS check"); + SSI_LOG_DEBUG("after FIPS check"); /* STAT_PHASE_0: Init and sanity checks */ @@ -368,7 +352,7 @@ static int ssi_blkcipher_setkey(struct crypto_tfm *tfm, } ctx_p->keylen = keylen; - SSI_LOG_DEBUG("ssi_blkcipher_setkey: ssi_is_hw_key ret 0"); + SSI_LOG_DEBUG("ssi_is_hw_key ret 0"); return 0; } @@ -378,25 +362,25 @@ static int ssi_blkcipher_setkey(struct crypto_tfm *tfm, if (unlikely(!des_ekey(tmp, key)) && (crypto_tfm_get_flags(tfm) & CRYPTO_TFM_REQ_WEAK_KEY)) { tfm->crt_flags |= CRYPTO_TFM_RES_WEAK_KEY; - SSI_LOG_DEBUG("ssi_blkcipher_setkey: weak DES key"); + SSI_LOG_DEBUG("weak DES key"); return -EINVAL; } } if ((ctx_p->cipher_mode == DRV_CIPHER_XTS) && - ssi_fips_verify_xts_keys(key, keylen) != 0) { - SSI_LOG_DEBUG("ssi_blkcipher_setkey: weak XTS key"); + xts_check_key(tfm, key, keylen) != 0) { + SSI_LOG_DEBUG("weak XTS key"); return -EINVAL; } if ((ctx_p->flow_mode == S_DIN_to_DES) && (keylen == DES3_EDE_KEY_SIZE) && - ssi_fips_verify_3des_keys(key, keylen) != 0) { - SSI_LOG_DEBUG("ssi_blkcipher_setkey: weak 3DES key"); + ssi_verify_3des_keys(key, keylen) != 0) { + SSI_LOG_DEBUG("weak 3DES key"); return -EINVAL; } /* STAT_PHASE_1: Copy key to ctx */ dma_sync_single_for_cpu(dev, ctx_p->user.key_dma_addr, - max_key_buf_size, DMA_TO_DEVICE); + max_key_buf_size, DMA_TO_DEVICE); if (ctx_p->flow_mode == S_DIN_to_MULTI2) { #if SSI_CC_HAS_MULTI2 @@ -405,7 +389,7 @@ static int ssi_blkcipher_setkey(struct crypto_tfm *tfm, if (ctx_p->key_round_number < CC_MULTI2_MIN_NUM_ROUNDS || ctx_p->key_round_number > CC_MULTI2_MAX_NUM_ROUNDS) { crypto_tfm_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); - SSI_LOG_DEBUG("ssi_blkcipher_setkey: SSI_CC_HAS_MULTI2 einval"); + SSI_LOG_DEBUG("SSI_CC_HAS_MULTI2 einval"); return -EINVAL; #endif /*SSI_CC_HAS_MULTI2*/ } else { @@ -429,10 +413,10 @@ static int ssi_blkcipher_setkey(struct crypto_tfm *tfm, } } dma_sync_single_for_device(dev, ctx_p->user.key_dma_addr, - max_key_buf_size, DMA_TO_DEVICE); + max_key_buf_size, DMA_TO_DEVICE); ctx_p->keylen = keylen; - SSI_LOG_DEBUG("ssi_blkcipher_setkey: return safely"); + SSI_LOG_DEBUG("return safely"); return 0; } @@ -632,17 +616,15 @@ ssi_blkcipher_create_data_desc( break; #endif /*SSI_CC_HAS_MULTI2*/ default: - SSI_LOG_ERR("invalid flow mode, flow_mode = %d \n", flow_mode); + SSI_LOG_ERR("invalid flow mode, flow_mode = %d\n", flow_mode); return; } /* Process */ if (likely(req_ctx->dma_buf_type == SSI_DMA_BUF_DLLI)) { - SSI_LOG_DEBUG(" data params addr 0x%llX length 0x%X \n", - (unsigned long long)sg_dma_address(src), - nbytes); - SSI_LOG_DEBUG(" data params addr 0x%llX length 0x%X \n", - (unsigned long long)sg_dma_address(dst), - nbytes); + SSI_LOG_DEBUG(" data params addr %pad length 0x%X\n", + sg_dma_address(src), nbytes); + SSI_LOG_DEBUG(" data params addr %pad length 0x%X\n", + sg_dma_address(dst), nbytes); hw_desc_init(&desc[*seq_size]); set_din_type(&desc[*seq_size], DMA_DLLI, sg_dma_address(src), nbytes, NS_BIT); @@ -655,9 +637,9 @@ ssi_blkcipher_create_data_desc( (*seq_size)++; } else { /* bypass */ - SSI_LOG_DEBUG(" bypass params addr 0x%llX " + SSI_LOG_DEBUG(" bypass params addr %pad " "length 0x%X addr 0x%08X\n", - (unsigned long long)req_ctx->mlli_params.mlli_dma_addr, + req_ctx->mlli_params.mlli_dma_addr, req_ctx->mlli_params.mlli_len, (unsigned int)ctx_p->drvdata->mlli_sram_addr); hw_desc_init(&desc[*seq_size]); @@ -706,16 +688,17 @@ ssi_blkcipher_create_data_desc( } static int ssi_blkcipher_complete(struct device *dev, - struct ssi_ablkcipher_ctx *ctx_p, - struct blkcipher_req_ctx *req_ctx, - struct scatterlist *dst, - struct scatterlist *src, - unsigned int ivsize, - void *areq, - void __iomem *cc_base) + struct ssi_ablkcipher_ctx *ctx_p, + struct blkcipher_req_ctx *req_ctx, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int ivsize, + void *areq, + void __iomem *cc_base) { int completion_error = 0; u32 inflight_counter; + struct ablkcipher_request *req = (struct ablkcipher_request *)areq; ssi_buffer_mgr_unmap_blkcipher_request(dev, req_ctx, ivsize, src, dst); @@ -726,6 +709,22 @@ static int ssi_blkcipher_complete(struct device *dev, ctx_p->drvdata->inflight_counter--; if (areq) { + /* + * The crypto API expects us to set the req->info to the last + * ciphertext block. For encrypt, simply copy from the result. + * For decrypt, we must copy from a saved buffer since this + * could be an in-place decryption operation and the src is + * lost by this point. + */ + if (req_ctx->gen_ctx.op_type == DRV_CRYPTO_DIRECTION_DECRYPT) { + memcpy(req->info, req_ctx->backup_info, ivsize); + kfree(req_ctx->backup_info); + } else { + scatterwalk_map_and_copy(req->info, req->dst, + (req->nbytes - ivsize), + ivsize, 0); + } + ablkcipher_request_complete(areq, completion_error); return 0; } @@ -749,21 +748,22 @@ static int ssi_blkcipher_process( int rc, seq_len = 0, cts_restore_flag = 0; SSI_LOG_DEBUG("%s areq=%p info=%p nbytes=%d\n", - ((direction == DRV_CRYPTO_DIRECTION_ENCRYPT) ? "Encrypt" : "Decrypt"), - areq, info, nbytes); + ((direction == DRV_CRYPTO_DIRECTION_ENCRYPT) ? "Encrypt" : "Decrypt"), + areq, info, nbytes); - CHECK_AND_RETURN_UPON_FIPS_ERROR(); /* STAT_PHASE_0: Init and sanity checks */ /* TODO: check data length according to mode */ if (unlikely(validate_data_size(ctx_p, nbytes))) { SSI_LOG_ERR("Unsupported data size %d.\n", nbytes); crypto_tfm_set_flags(tfm, CRYPTO_TFM_RES_BAD_BLOCK_LEN); - return -EINVAL; + rc = -EINVAL; + goto exit_process; } if (nbytes == 0) { /* No data to process is valid */ - return 0; + rc = 0; + goto exit_process; } /*For CTS in case of data size aligned to 16 use CBC mode*/ if (((nbytes % AES_BLOCK_SIZE) == 0) && (ctx_p->cipher_mode == DRV_CIPHER_CBC_CTS)) { @@ -804,12 +804,8 @@ static int ssi_blkcipher_process( ssi_blkcipher_create_setup_desc(tfm, req_ctx, ivsize, nbytes, desc, &seq_len); /* Data processing */ - ssi_blkcipher_create_data_desc(tfm, - req_ctx, - dst, src, - nbytes, - areq, - desc, &seq_len); + ssi_blkcipher_create_data_desc(tfm, req_ctx, dst, src, nbytes, areq, + desc, &seq_len); /* do we need to generate IV? */ if (req_ctx->is_giv) { @@ -842,6 +838,9 @@ exit_process: if (cts_restore_flag != 0) ctx_p->cipher_mode = DRV_CIPHER_CBC_CTS; + if (rc != -EINPROGRESS) + kfree(req_ctx->backup_info); + return rc; } @@ -853,8 +852,6 @@ static void ssi_ablkcipher_complete(struct device *dev, void *ssi_req, void __io struct ssi_ablkcipher_ctx *ctx_p = crypto_ablkcipher_ctx(tfm); unsigned int ivsize = crypto_ablkcipher_ivsize(tfm); - CHECK_AND_RETURN_VOID_UPON_FIPS_ERROR(); - ssi_blkcipher_complete(dev, ctx_p, req_ctx, areq->dst, areq->src, ivsize, areq, cc_base); } @@ -871,8 +868,8 @@ static int ssi_ablkcipher_init(struct crypto_tfm *tfm) } static int ssi_ablkcipher_setkey(struct crypto_ablkcipher *tfm, - const u8 *key, - unsigned int keylen) + const u8 *key, + unsigned int keylen) { return ssi_blkcipher_setkey(crypto_ablkcipher_tfm(tfm), key, keylen); } @@ -884,7 +881,6 @@ static int ssi_ablkcipher_encrypt(struct ablkcipher_request *req) struct blkcipher_req_ctx *req_ctx = ablkcipher_request_ctx(req); unsigned int ivsize = crypto_ablkcipher_ivsize(ablk_tfm); - req_ctx->backup_info = req->info; req_ctx->is_giv = false; return ssi_blkcipher_process(tfm, req_ctx, req->dst, req->src, req->nbytes, req->info, ivsize, (void *)req, DRV_CRYPTO_DIRECTION_ENCRYPT); @@ -897,8 +893,18 @@ static int ssi_ablkcipher_decrypt(struct ablkcipher_request *req) struct blkcipher_req_ctx *req_ctx = ablkcipher_request_ctx(req); unsigned int ivsize = crypto_ablkcipher_ivsize(ablk_tfm); - req_ctx->backup_info = req->info; + /* + * Allocate and save the last IV sized bytes of the source, which will + * be lost in case of in-place decryption and might be needed for CTS. + */ + req_ctx->backup_info = kmalloc(ivsize, GFP_KERNEL); + if (!req_ctx->backup_info) + return -ENOMEM; + + scatterwalk_map_and_copy(req_ctx->backup_info, req->src, + (req->nbytes - ivsize), ivsize, 0); req_ctx->is_giv = false; + return ssi_blkcipher_process(tfm, req_ctx, req->dst, req->src, req->nbytes, req->info, ivsize, (void *)req, DRV_CRYPTO_DIRECTION_DECRYPT); } @@ -1244,7 +1250,7 @@ struct ssi_crypto_alg *ssi_ablkcipher_create_alg(struct ssi_alg_template *templa struct ssi_crypto_alg *t_alg; struct crypto_alg *alg; - t_alg = kzalloc(sizeof(struct ssi_crypto_alg), GFP_KERNEL); + t_alg = kzalloc(sizeof(*t_alg), GFP_KERNEL); if (!t_alg) { SSI_LOG_ERR("failed to allocate t_alg\n"); return ERR_PTR(-ENOMEM); @@ -1286,7 +1292,7 @@ int ssi_ablkcipher_free(struct ssi_drvdata *drvdata) if (blkcipher_handle) { /* Remove registered algs */ list_for_each_entry_safe(t_alg, n, - &blkcipher_handle->blkcipher_alg_list, + &blkcipher_handle->blkcipher_alg_list, entry) { crypto_unregister_alg(&t_alg->crypto_alg); list_del(&t_alg->entry); @@ -1305,8 +1311,7 @@ int ssi_ablkcipher_alloc(struct ssi_drvdata *drvdata) int rc = -ENOMEM; int alg; - ablkcipher_handle = kmalloc(sizeof(struct ssi_blkcipher_handle), - GFP_KERNEL); + ablkcipher_handle = kmalloc(sizeof(*ablkcipher_handle), GFP_KERNEL); if (!ablkcipher_handle) return -ENOMEM; @@ -1322,7 +1327,7 @@ int ssi_ablkcipher_alloc(struct ssi_drvdata *drvdata) if (IS_ERR(t_alg)) { rc = PTR_ERR(t_alg); SSI_LOG_ERR("%s alg allocation failed\n", - blkcipher_algs[alg].driver_name); + blkcipher_algs[alg].driver_name); goto fail0; } t_alg->drvdata = drvdata; @@ -1330,17 +1335,17 @@ int ssi_ablkcipher_alloc(struct ssi_drvdata *drvdata) SSI_LOG_DEBUG("registering %s\n", blkcipher_algs[alg].driver_name); rc = crypto_register_alg(&t_alg->crypto_alg); SSI_LOG_DEBUG("%s alg registration rc = %x\n", - t_alg->crypto_alg.cra_driver_name, rc); + t_alg->crypto_alg.cra_driver_name, rc); if (unlikely(rc != 0)) { SSI_LOG_ERR("%s alg registration failed\n", - t_alg->crypto_alg.cra_driver_name); + t_alg->crypto_alg.cra_driver_name); kfree(t_alg); goto fail0; } else { list_add_tail(&t_alg->entry, &ablkcipher_handle->blkcipher_alg_list); SSI_LOG_DEBUG("Registered %s\n", - t_alg->crypto_alg.cra_driver_name); + t_alg->crypto_alg.cra_driver_name); } } return 0; diff --git a/drivers/staging/ccree/ssi_driver.c b/drivers/staging/ccree/ssi_driver.c index 78709b92736d..9c6f1200c130 100644 --- a/drivers/staging/ccree/ssi_driver.c +++ b/drivers/staging/ccree/ssi_driver.c @@ -71,7 +71,7 @@ #include "ssi_ivgen.h" #include "ssi_sram_mgr.h" #include "ssi_pm.h" -#include "ssi_fips_local.h" +#include "ssi_fips.h" #ifdef DX_DUMP_BYTES void dump_byte_array(const char *name, const u8 *the_array, unsigned long size) @@ -81,12 +81,11 @@ void dump_byte_array(const char *name, const u8 *the_array, unsigned long size) char line_buf[80]; if (!the_array) { - SSI_LOG_ERR("cannot dump_byte_array - NULL pointer\n"); + SSI_LOG_ERR("cannot dump array - NULL pointer\n"); return; } - ret = snprintf(line_buf, sizeof(line_buf), "%s[%lu]: ", - name, size); + ret = snprintf(line_buf, sizeof(line_buf), "%s[%lu]: ", name, size); if (ret < 0) { SSI_LOG_ERR("snprintf returned %d . aborting buffer array dump\n", ret); return; @@ -95,8 +94,8 @@ void dump_byte_array(const char *name, const u8 *the_array, unsigned long size) for (i = 0, cur_byte = the_array; (i < size) && (line_offset < sizeof(line_buf)); i++, cur_byte++) { ret = snprintf(line_buf + line_offset, - sizeof(line_buf) - line_offset, - "0x%02X ", *cur_byte); + sizeof(line_buf) - line_offset, + "0x%02X ", *cur_byte); if (ret < 0) { SSI_LOG_ERR("snprintf returned %d . aborting buffer array dump\n", ret); return; @@ -193,11 +192,11 @@ int init_cc_regs(struct ssi_drvdata *drvdata, bool is_probe) #ifdef DX_IRQ_DELAY /* Set CC IRQ delay */ CC_HAL_WRITE_REGISTER(CC_REG_OFFSET(HOST_RGF, HOST_IRQ_TIMER_INIT_VAL), - DX_IRQ_DELAY); + DX_IRQ_DELAY); #endif if (CC_HAL_READ_REGISTER(CC_REG_OFFSET(HOST_RGF, HOST_IRQ_TIMER_INIT_VAL)) > 0) { SSI_LOG_DEBUG("irq_delay=%d CC cycles\n", - CC_HAL_READ_REGISTER(CC_REG_OFFSET(HOST_RGF, HOST_IRQ_TIMER_INIT_VAL))); + CC_HAL_READ_REGISTER(CC_REG_OFFSET(HOST_RGF, HOST_IRQ_TIMER_INIT_VAL))); } #endif @@ -224,7 +223,8 @@ static int init_cc_resources(struct platform_device *plat_dev) struct resource *req_mem_cc_regs = NULL; void __iomem *cc_base = NULL; bool irq_registered = false; - struct ssi_drvdata *new_drvdata = kzalloc(sizeof(struct ssi_drvdata), GFP_KERNEL); + struct ssi_drvdata *new_drvdata = kzalloc(sizeof(*new_drvdata), + GFP_KERNEL); struct device *dev = &plat_dev->dev; struct device_node *np = dev->of_node; u32 signature_val; @@ -251,10 +251,10 @@ static int init_cc_resources(struct platform_device *plat_dev) rc = -ENODEV; goto init_cc_res_err; } - SSI_LOG_DEBUG("Got MEM resource (%s): start=0x%llX end=0x%llX\n", - new_drvdata->res_mem->name, - (unsigned long long)new_drvdata->res_mem->start, - (unsigned long long)new_drvdata->res_mem->end); + SSI_LOG_DEBUG("Got MEM resource (%s): start=%pad end=%pad\n", + new_drvdata->res_mem->name, + new_drvdata->res_mem->start, + new_drvdata->res_mem->end); /* Map registers space */ req_mem_cc_regs = request_mem_region(new_drvdata->res_mem->start, resource_size(new_drvdata->res_mem), "arm_cc7x_regs"); if (unlikely(!req_mem_cc_regs)) { @@ -266,7 +266,8 @@ static int init_cc_resources(struct platform_device *plat_dev) cc_base = ioremap(new_drvdata->res_mem->start, resource_size(new_drvdata->res_mem)); if (unlikely(!cc_base)) { SSI_LOG_ERR("ioremap[CC](0x%08X,0x%08X) failed\n", - (unsigned int)new_drvdata->res_mem->start, (unsigned int)resource_size(new_drvdata->res_mem)); + (unsigned int)new_drvdata->res_mem->start, + (unsigned int)resource_size(new_drvdata->res_mem)); rc = -ENOMEM; goto init_cc_res_err; } @@ -284,15 +285,15 @@ static int init_cc_resources(struct platform_device *plat_dev) IRQF_SHARED, "arm_cc7x", new_drvdata); if (unlikely(rc != 0)) { SSI_LOG_ERR("Could not register to interrupt %llu\n", - (unsigned long long)new_drvdata->res_irq->start); + (unsigned long long)new_drvdata->res_irq->start); goto init_cc_res_err; } init_completion(&new_drvdata->icache_setup_completion); irq_registered = true; SSI_LOG_DEBUG("Registered to IRQ (%s) %llu\n", - new_drvdata->res_irq->name, - (unsigned long long)new_drvdata->res_irq->start); + new_drvdata->res_irq->name, + (unsigned long long)new_drvdata->res_irq->start); new_drvdata->plat_dev = plat_dev; @@ -301,19 +302,16 @@ static int init_cc_resources(struct platform_device *plat_dev) goto init_cc_res_err; if (!new_drvdata->plat_dev->dev.dma_mask) - { new_drvdata->plat_dev->dev.dma_mask = &new_drvdata->plat_dev->dev.coherent_dma_mask; - } + if (!new_drvdata->plat_dev->dev.coherent_dma_mask) - { new_drvdata->plat_dev->dev.coherent_dma_mask = DMA_BIT_MASK(DMA_BIT_MASK_LEN); - } /* Verify correct mapping */ signature_val = CC_HAL_READ_REGISTER(CC_REG_OFFSET(HOST_RGF, HOST_SIGNATURE)); if (signature_val != DX_DEV_SIGNATURE) { SSI_LOG_ERR("Invalid CC signature: SIGNATURE=0x%08X != expected=0x%08X\n", - signature_val, (u32)DX_DEV_SIGNATURE); + signature_val, (u32)DX_DEV_SIGNATURE); rc = -EINVAL; goto init_cc_res_err; } @@ -330,7 +328,7 @@ static int init_cc_resources(struct platform_device *plat_dev) } #ifdef ENABLE_CC_SYSFS - rc = ssi_sysfs_init(&(plat_dev->dev.kobj), new_drvdata); + rc = ssi_sysfs_init(&plat_dev->dev.kobj, new_drvdata); if (unlikely(rc != 0)) { SSI_LOG_ERR("init_stat_db failed\n"); goto init_cc_res_err; @@ -401,6 +399,12 @@ static int init_cc_resources(struct platform_device *plat_dev) goto init_cc_res_err; } + /* If we got here and FIPS mode is enabled + * it means all FIPS test passed, so let TEE + * know we're good. + */ + cc_set_ree_fips_status(new_drvdata, true); + return 0; init_cc_res_err: @@ -428,7 +432,7 @@ init_cc_res_err: new_drvdata->cc_base = NULL; } release_mem_region(new_drvdata->res_mem->start, - resource_size(new_drvdata->res_mem)); + resource_size(new_drvdata->res_mem)); new_drvdata->res_mem = NULL; } kfree(new_drvdata); @@ -471,7 +475,7 @@ static void cleanup_cc_resources(struct platform_device *plat_dev) if (drvdata->cc_base) { iounmap(drvdata->cc_base); release_mem_region(drvdata->res_mem->start, - resource_size(drvdata->res_mem)); + resource_size(drvdata->res_mem)); drvdata->cc_base = NULL; drvdata->res_mem = NULL; } @@ -516,12 +520,12 @@ static int cc7x_probe(struct platform_device *plat_dev) asm volatile("mrc p15, 0, %0, c0, c0, 1" : "=r" (ctr)); cacheline_size = 4 << ((ctr >> 16) & 0xf); SSI_LOG_DEBUG("CP15(L1_CACHE_BYTES) = %u , Kconfig(L1_CACHE_BYTES) = %u\n", - cacheline_size, L1_CACHE_BYTES); + cacheline_size, L1_CACHE_BYTES); asm volatile("mrc p15, 0, %0, c0, c0, 0" : "=r" (ctr)); - SSI_LOG_DEBUG("Main ID register (MIDR): Implementer 0x%02X, Arch 0x%01X," - " Part 0x%03X, Rev r%dp%d\n", - (ctr >> 24), (ctr >> 16) & 0xF, (ctr >> 4) & 0xFFF, (ctr >> 20) & 0xF, ctr & 0xF); + SSI_LOG_DEBUG("Main ID register (MIDR): Implementer 0x%02X, Arch 0x%01X, Part 0x%03X, Rev r%dp%d\n", + (ctr >> 24), (ctr >> 16) & 0xF, (ctr >> 4) & 0xFFF, + (ctr >> 20) & 0xF, ctr & 0xF); #endif /* Map registers space */ @@ -546,7 +550,7 @@ static int cc7x_remove(struct platform_device *plat_dev) } #if defined(CONFIG_PM_RUNTIME) || defined(CONFIG_PM_SLEEP) -static struct dev_pm_ops arm_cc7x_driver_pm = { +static const struct dev_pm_ops arm_cc7x_driver_pm = { SET_RUNTIME_PM_OPS(ssi_power_mgr_runtime_suspend, ssi_power_mgr_runtime_resume, NULL) }; #endif diff --git a/drivers/staging/ccree/ssi_driver.h b/drivers/staging/ccree/ssi_driver.h index c1ed61f1a202..b6ad89ae9bee 100644 --- a/drivers/staging/ccree/ssi_driver.h +++ b/drivers/staging/ccree/ssi_driver.h @@ -48,7 +48,6 @@ #include "cc_crypto_ctx.h" #include "ssi_sysfs.h" #include "hash_defs.h" -#include "ssi_fips_local.h" #include "cc_hw_queue_defs.h" #include "ssi_sram_mgr.h" diff --git a/drivers/staging/ccree/ssi_fips.c b/drivers/staging/ccree/ssi_fips.c index fdc40f38332a..33d53d64603d 100644 --- a/drivers/staging/ccree/ssi_fips.c +++ b/drivers/staging/ccree/ssi_fips.c @@ -14,48 +14,115 @@ * along with this program; if not, see <http://www.gnu.org/licenses/>. */ -/************************************************************** - * This file defines the driver FIPS APIs * - **************************************************************/ +#include <linux/kernel.h> +#include <linux/fips.h> -#include <linux/module.h> +#include "ssi_config.h" +#include "ssi_driver.h" +#include "cc_hal.h" #include "ssi_fips.h" -extern int ssi_fips_ext_get_state(enum cc_fips_state_t *p_state); -extern int ssi_fips_ext_get_error(enum cc_fips_error *p_err); +static void fips_dsr(unsigned long devarg); + +struct ssi_fips_handle { + struct tasklet_struct tasklet; +}; + +/* The function called once at driver entry point to check + * whether TEE FIPS error occurred. + */ +static bool cc_get_tee_fips_status(struct ssi_drvdata *drvdata) +{ + u32 reg; + void __iomem *cc_base = drvdata->cc_base; + + reg = CC_HAL_READ_REGISTER(CC_REG_OFFSET(HOST_RGF, GPR_HOST)); + return (reg == (CC_FIPS_SYNC_TEE_STATUS | CC_FIPS_SYNC_MODULE_OK)); +} /* - * This function returns the REE FIPS state. - * It should be called by kernel module. + * This function should push the FIPS REE library status towards the TEE library + * by writing the error state to HOST_GPR0 register. */ -int ssi_fips_get_state(enum cc_fips_state_t *p_state) +void cc_set_ree_fips_status(struct ssi_drvdata *drvdata, bool status) +{ + void __iomem *cc_base = drvdata->cc_base; + int val = CC_FIPS_SYNC_REE_STATUS; + + val |= (status ? CC_FIPS_SYNC_MODULE_OK : CC_FIPS_SYNC_MODULE_ERROR); + + CC_HAL_WRITE_REGISTER(CC_REG_OFFSET(HOST_RGF, HOST_GPR0), val); +} + +void ssi_fips_fini(struct ssi_drvdata *drvdata) { - int rc = 0; + struct ssi_fips_handle *fips_h = drvdata->fips_handle; - if (!p_state) - return -EINVAL; + if (!fips_h) + return; /* Not allocated */ - rc = ssi_fips_ext_get_state(p_state); + /* Kill tasklet */ + tasklet_kill(&fips_h->tasklet); - return rc; + kfree(fips_h); + drvdata->fips_handle = NULL; } -EXPORT_SYMBOL(ssi_fips_get_state); +void fips_handler(struct ssi_drvdata *drvdata) +{ + struct ssi_fips_handle *fips_handle_ptr = + drvdata->fips_handle; -/* - * This function returns the REE FIPS error. - * It should be called by kernel module. - */ -int ssi_fips_get_error(enum cc_fips_error *p_err) + tasklet_schedule(&fips_handle_ptr->tasklet); +} + +static inline void tee_fips_error(void) { - int rc = 0; + if (fips_enabled) + panic("ccree: TEE reported cryptographic error in fips mode!\n"); + else + SSI_LOG_ERR("TEE reported error!\n"); +} - if (!p_err) - return -EINVAL; +/* Deferred service handler, run as interrupt-fired tasklet */ +static void fips_dsr(unsigned long devarg) +{ + struct ssi_drvdata *drvdata = (struct ssi_drvdata *)devarg; + void __iomem *cc_base = drvdata->cc_base; + u32 irq, state, val; - rc = ssi_fips_ext_get_error(p_err); + irq = (drvdata->irq & (SSI_GPR0_IRQ_MASK)); - return rc; + if (irq) { + state = CC_HAL_READ_REGISTER(CC_REG_OFFSET(HOST_RGF, GPR_HOST)); + + if (state != (CC_FIPS_SYNC_TEE_STATUS | CC_FIPS_SYNC_MODULE_OK)) + tee_fips_error(); + } + + /* after verifing that there is nothing to do, + * unmask AXI completion interrupt. + */ + val = (CC_REG_OFFSET(HOST_RGF, HOST_IMR) & ~irq); + CC_HAL_WRITE_REGISTER(CC_REG_OFFSET(HOST_RGF, HOST_IMR), val); } -EXPORT_SYMBOL(ssi_fips_get_error); +/* The function called once at driver entry point .*/ +int ssi_fips_init(struct ssi_drvdata *p_drvdata) +{ + struct ssi_fips_handle *fips_h; + + fips_h = kzalloc(sizeof(*fips_h), GFP_KERNEL); + if (!fips_h) + return -ENOMEM; + + p_drvdata->fips_handle = fips_h; + + SSI_LOG_DEBUG("Initializing fips tasklet\n"); + tasklet_init(&fips_h->tasklet, fips_dsr, (unsigned long)p_drvdata); + + if (!cc_get_tee_fips_status(p_drvdata)) + tee_fips_error(); + + return 0; +} diff --git a/drivers/staging/ccree/ssi_fips.h b/drivers/staging/ccree/ssi_fips.h index 4f5c6a9a8363..369ddf9478e7 100644 --- a/drivers/staging/ccree/ssi_fips.h +++ b/drivers/staging/ccree/ssi_fips.h @@ -17,45 +17,33 @@ #ifndef __SSI_FIPS_H__ #define __SSI_FIPS_H__ -/*! - * @file - * @brief This file contains FIPS related defintions and APIs. - */ +#ifdef CONFIG_CRYPTO_FIPS -enum cc_fips_state { - CC_FIPS_STATE_NOT_SUPPORTED = 0, - CC_FIPS_STATE_SUPPORTED, - CC_FIPS_STATE_ERROR, - CC_FIPS_STATE_RESERVE32B = S32_MAX +enum cc_fips_status { + CC_FIPS_SYNC_MODULE_OK = 0x0, + CC_FIPS_SYNC_MODULE_ERROR = 0x1, + CC_FIPS_SYNC_REE_STATUS = 0x4, + CC_FIPS_SYNC_TEE_STATUS = 0x8, + CC_FIPS_SYNC_STATUS_RESERVE32B = S32_MAX }; -enum cc_fips_error { - CC_REE_FIPS_ERROR_OK = 0, - CC_REE_FIPS_ERROR_GENERAL, - CC_REE_FIPS_ERROR_FROM_TEE, - CC_REE_FIPS_ERROR_AES_ECB_PUT, - CC_REE_FIPS_ERROR_AES_CBC_PUT, - CC_REE_FIPS_ERROR_AES_OFB_PUT, - CC_REE_FIPS_ERROR_AES_CTR_PUT, - CC_REE_FIPS_ERROR_AES_CBC_CTS_PUT, - CC_REE_FIPS_ERROR_AES_XTS_PUT, - CC_REE_FIPS_ERROR_AES_CMAC_PUT, - CC_REE_FIPS_ERROR_AESCCM_PUT, - CC_REE_FIPS_ERROR_AESGCM_PUT, - CC_REE_FIPS_ERROR_DES_ECB_PUT, - CC_REE_FIPS_ERROR_DES_CBC_PUT, - CC_REE_FIPS_ERROR_SHA1_PUT, - CC_REE_FIPS_ERROR_SHA256_PUT, - CC_REE_FIPS_ERROR_SHA512_PUT, - CC_REE_FIPS_ERROR_HMAC_SHA1_PUT, - CC_REE_FIPS_ERROR_HMAC_SHA256_PUT, - CC_REE_FIPS_ERROR_HMAC_SHA512_PUT, - CC_REE_FIPS_ERROR_ROM_CHECKSUM, - CC_REE_FIPS_ERROR_RESERVE32B = S32_MAX -}; +int ssi_fips_init(struct ssi_drvdata *p_drvdata); +void ssi_fips_fini(struct ssi_drvdata *drvdata); +void fips_handler(struct ssi_drvdata *drvdata); +void cc_set_ree_fips_status(struct ssi_drvdata *drvdata, bool ok); + +#else /* CONFIG_CRYPTO_FIPS */ + +static inline int ssi_fips_init(struct ssi_drvdata *p_drvdata) +{ + return 0; +} + +static inline void ssi_fips_fini(struct ssi_drvdata *drvdata) {} +void cc_set_ree_fips_status(struct ssi_drvdata *drvdata, bool ok) {} +void fips_handler(struct ssi_drvdata *drvdata) {} -int ssi_fips_get_state(enum cc_fips_state *p_state); -int ssi_fips_get_error(enum cc_fips_error *p_err); +#endif /* CONFIG_CRYPTO_FIPS */ #endif /*__SSI_FIPS_H__*/ diff --git a/drivers/staging/ccree/ssi_fips_data.h b/drivers/staging/ccree/ssi_fips_data.h deleted file mode 100644 index c41671dbee40..000000000000 --- a/drivers/staging/ccree/ssi_fips_data.h +++ /dev/null @@ -1,306 +0,0 @@ -/* - * Copyright (C) 2012-2017 ARM Limited or its affiliates. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -/* - * The test vectors were taken from: - * - * * AES - * NIST Special Publication 800-38A 2001 Edition - * Recommendation for Block Cipher Modes of Operation - * http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf - * Appendix F: Example Vectors for Modes of Operation of the AES - * - * * AES CTS - * Advanced Encryption Standard (AES) Encryption for Kerberos 5 - * February 2005 - * https://tools.ietf.org/html/rfc3962#appendix-B - * B. Sample Test Vectors - * - * * AES XTS - * http://csrc.nist.gov/groups/STM/cavp/#08 - * http://csrc.nist.gov/groups/STM/cavp/documents/aes/XTSTestVectors.zip - * - * * AES CMAC - * http://csrc.nist.gov/groups/STM/cavp/index.html#07 - * http://csrc.nist.gov/groups/STM/cavp/documents/mac/cmactestvectors.zip - * - * * AES-CCM - * http://csrc.nist.gov/groups/STM/cavp/#07 - * http://csrc.nist.gov/groups/STM/cavp/documents/mac/ccmtestvectors.zip - * - * * AES-GCM - * http://csrc.nist.gov/groups/STM/cavp/documents/mac/gcmtestvectors.zip - * - * * Triple-DES - * NIST Special Publication 800-67 January 2012 - * Recommendation for the Triple Data Encryption Algorithm (TDEA) Block Cipher - * http://csrc.nist.gov/publications/nistpubs/800-67-Rev1/SP-800-67-Rev1.pdf - * APPENDIX B: EXAMPLE OF TDEA FORWARD AND INVERSE CIPHER OPERATIONS - * and - * http://csrc.nist.gov/groups/STM/cavp/#01 - * http://csrc.nist.gov/groups/STM/cavp/documents/des/tdesmct_intermediate.zip - * - * * HASH - * http://csrc.nist.gov/groups/STM/cavp/#03 - * http://csrc.nist.gov/groups/STM/cavp/documents/shs/shabytetestvectors.zip - * - * * HMAC - * http://csrc.nist.gov/groups/STM/cavp/#07 - * http://csrc.nist.gov/groups/STM/cavp/documents/mac/hmactestvectors.zip - */ - -/* NIST AES */ -#define AES_128_BIT_KEY_SIZE 16 -#define AES_192_BIT_KEY_SIZE 24 -#define AES_256_BIT_KEY_SIZE 32 -#define AES_512_BIT_KEY_SIZE 64 - -#define NIST_AES_IV_SIZE 16 - -#define NIST_AES_128_KEY { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c } -#define NIST_AES_192_KEY { 0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52, 0xc8, 0x10, 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5, \ - 0x62, 0xf8, 0xea, 0xd2, 0x52, 0x2c, 0x6b, 0x7b } -#define NIST_AES_256_KEY { 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, \ - 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4 } -#define NIST_AES_VECTOR_SIZE 16 -#define NIST_AES_PLAIN_DATA { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a } - -#define NIST_AES_ECB_IV { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } -#define NIST_AES_128_ECB_CIPHER { 0x3a, 0xd7, 0x7b, 0xb4, 0x0d, 0x7a, 0x36, 0x60, 0xa8, 0x9e, 0xca, 0xf3, 0x24, 0x66, 0xef, 0x97 } -#define NIST_AES_192_ECB_CIPHER { 0xbd, 0x33, 0x4f, 0x1d, 0x6e, 0x45, 0xf2, 0x5f, 0xf7, 0x12, 0xa2, 0x14, 0x57, 0x1f, 0xa5, 0xcc } -#define NIST_AES_256_ECB_CIPHER { 0xf3, 0xee, 0xd1, 0xbd, 0xb5, 0xd2, 0xa0, 0x3c, 0x06, 0x4b, 0x5a, 0x7e, 0x3d, 0xb1, 0x81, 0xf8 } - -#define NIST_AES_CBC_IV { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f } -#define NIST_AES_128_CBC_CIPHER { 0x76, 0x49, 0xab, 0xac, 0x81, 0x19, 0xb2, 0x46, 0xce, 0xe9, 0x8e, 0x9b, 0x12, 0xe9, 0x19, 0x7d } -#define NIST_AES_192_CBC_CIPHER { 0x4f, 0x02, 0x1d, 0xb2, 0x43, 0xbc, 0x63, 0x3d, 0x71, 0x78, 0x18, 0x3a, 0x9f, 0xa0, 0x71, 0xe8 } -#define NIST_AES_256_CBC_CIPHER { 0xf5, 0x8c, 0x4c, 0x04, 0xd6, 0xe5, 0xf1, 0xba, 0x77, 0x9e, 0xab, 0xfb, 0x5f, 0x7b, 0xfb, 0xd6 } - -#define NIST_AES_OFB_IV { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f } -#define NIST_AES_128_OFB_CIPHER { 0x3b, 0x3f, 0xd9, 0x2e, 0xb7, 0x2d, 0xad, 0x20, 0x33, 0x34, 0x49, 0xf8, 0xe8, 0x3c, 0xfb, 0x4a } -#define NIST_AES_192_OFB_CIPHER { 0xcd, 0xc8, 0x0d, 0x6f, 0xdd, 0xf1, 0x8c, 0xab, 0x34, 0xc2, 0x59, 0x09, 0xc9, 0x9a, 0x41, 0x74 } -#define NIST_AES_256_OFB_CIPHER { 0xdc, 0x7e, 0x84, 0xbf, 0xda, 0x79, 0x16, 0x4b, 0x7e, 0xcd, 0x84, 0x86, 0x98, 0x5d, 0x38, 0x60 } - -#define NIST_AES_CTR_IV { 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff } -#define NIST_AES_128_CTR_CIPHER { 0x87, 0x4d, 0x61, 0x91, 0xb6, 0x20, 0xe3, 0x26, 0x1b, 0xef, 0x68, 0x64, 0x99, 0x0d, 0xb6, 0xce } -#define NIST_AES_192_CTR_CIPHER { 0x1a, 0xbc, 0x93, 0x24, 0x17, 0x52, 0x1c, 0xa2, 0x4f, 0x2b, 0x04, 0x59, 0xfe, 0x7e, 0x6e, 0x0b } -#define NIST_AES_256_CTR_CIPHER { 0x60, 0x1e, 0xc3, 0x13, 0x77, 0x57, 0x89, 0xa5, 0xb7, 0xa7, 0xf5, 0x04, 0xbb, 0xf3, 0xd2, 0x28 } - -#define RFC3962_AES_128_KEY { 0x63, 0x68, 0x69, 0x63, 0x6b, 0x65, 0x6e, 0x20, 0x74, 0x65, 0x72, 0x69, 0x79, 0x61, 0x6b, 0x69 } -#define RFC3962_AES_VECTOR_SIZE 17 -#define RFC3962_AES_PLAIN_DATA { 0x49, 0x20, 0x77, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6c, 0x69, 0x6b, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20 } -#define RFC3962_AES_CBC_CTS_IV { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } -#define RFC3962_AES_128_CBC_CTS_CIPHER { 0xc6, 0x35, 0x35, 0x68, 0xf2, 0xbf, 0x8c, 0xb4, 0xd8, 0xa5, 0x80, 0x36, 0x2d, 0xa7, 0xff, 0x7f, 0x97 } - -#define NIST_AES_256_XTS_KEY { 0xa1, 0xb9, 0x0c, 0xba, 0x3f, 0x06, 0xac, 0x35, 0x3b, 0x2c, 0x34, 0x38, 0x76, 0x08, 0x17, 0x62, \ - 0x09, 0x09, 0x23, 0x02, 0x6e, 0x91, 0x77, 0x18, 0x15, 0xf2, 0x9d, 0xab, 0x01, 0x93, 0x2f, 0x2f } -#define NIST_AES_256_XTS_IV { 0x4f, 0xae, 0xf7, 0x11, 0x7c, 0xda, 0x59, 0xc6, 0x6e, 0x4b, 0x92, 0x01, 0x3e, 0x76, 0x8a, 0xd5 } -#define NIST_AES_256_XTS_VECTOR_SIZE 16 -#define NIST_AES_256_XTS_PLAIN { 0xeb, 0xab, 0xce, 0x95, 0xb1, 0x4d, 0x3c, 0x8d, 0x6f, 0xb3, 0x50, 0x39, 0x07, 0x90, 0x31, 0x1c } -#define NIST_AES_256_XTS_CIPHER { 0x77, 0x8a, 0xe8, 0xb4, 0x3c, 0xb9, 0x8d, 0x5a, 0x82, 0x50, 0x81, 0xd5, 0xbe, 0x47, 0x1c, 0x63 } - -#define NIST_AES_512_XTS_KEY { 0x1e, 0xa6, 0x61, 0xc5, 0x8d, 0x94, 0x3a, 0x0e, 0x48, 0x01, 0xe4, 0x2f, 0x4b, 0x09, 0x47, 0x14, \ - 0x9e, 0x7f, 0x9f, 0x8e, 0x3e, 0x68, 0xd0, 0xc7, 0x50, 0x52, 0x10, 0xbd, 0x31, 0x1a, 0x0e, 0x7c, \ - 0xd6, 0xe1, 0x3f, 0xfd, 0xf2, 0x41, 0x8d, 0x8d, 0x19, 0x11, 0xc0, 0x04, 0xcd, 0xa5, 0x8d, 0xa3, \ - 0xd6, 0x19, 0xb7, 0xe2, 0xb9, 0x14, 0x1e, 0x58, 0x31, 0x8e, 0xea, 0x39, 0x2c, 0xf4, 0x1b, 0x08 } -#define NIST_AES_512_XTS_IV { 0xad, 0xf8, 0xd9, 0x26, 0x27, 0x46, 0x4a, 0xd2, 0xf0, 0x42, 0x8e, 0x84, 0xa9, 0xf8, 0x75, 0x64, } -#define NIST_AES_512_XTS_VECTOR_SIZE 32 -#define NIST_AES_512_XTS_PLAIN { 0x2e, 0xed, 0xea, 0x52, 0xcd, 0x82, 0x15, 0xe1, 0xac, 0xc6, 0x47, 0xe8, 0x10, 0xbb, 0xc3, 0x64, \ - 0x2e, 0x87, 0x28, 0x7f, 0x8d, 0x2e, 0x57, 0xe3, 0x6c, 0x0a, 0x24, 0xfb, 0xc1, 0x2a, 0x20, 0x2e } -#define NIST_AES_512_XTS_CIPHER { 0xcb, 0xaa, 0xd0, 0xe2, 0xf6, 0xce, 0xa3, 0xf5, 0x0b, 0x37, 0xf9, 0x34, 0xd4, 0x6a, 0x9b, 0x13, \ - 0x0b, 0x9d, 0x54, 0xf0, 0x7e, 0x34, 0xf3, 0x6a, 0xf7, 0x93, 0xe8, 0x6f, 0x73, 0xc6, 0xd7, 0xdb } - -/* NIST AES-CMAC */ -#define NIST_AES_128_CMAC_KEY { 0x67, 0x08, 0xc9, 0x88, 0x7b, 0x84, 0x70, 0x84, 0xf1, 0x23, 0xd3, 0xdd, 0x9c, 0x3a, 0x81, 0x36 } -#define NIST_AES_128_CMAC_PLAIN_DATA { 0xa8, 0xde, 0x55, 0x17, 0x0c, 0x6d, 0xc0, 0xd8, 0x0d, 0xe3, 0x2f, 0x50, 0x8b, 0xf4, 0x9b, 0x70 } -#define NIST_AES_128_CMAC_MAC { 0xcf, 0xef, 0x9b, 0x78, 0x39, 0x84, 0x1f, 0xdb, 0xcc, 0xbb, 0x6c, 0x2c, 0xf2, 0x38, 0xf7 } -#define NIST_AES_128_CMAC_VECTOR_SIZE 16 -#define NIST_AES_128_CMAC_OUTPUT_SIZE 15 - -#define NIST_AES_192_CMAC_KEY { 0x20, 0x51, 0xaf, 0x34, 0x76, 0x2e, 0xbe, 0x55, 0x6f, 0x72, 0xa5, 0xc6, 0xed, 0xc7, 0x77, 0x1e, \ - 0xb9, 0x24, 0x5f, 0xad, 0x76, 0xf0, 0x34, 0xbe } -#define NIST_AES_192_CMAC_PLAIN_DATA { 0xae, 0x8e, 0x93, 0xc9, 0xc9, 0x91, 0xcf, 0x89, 0x6a, 0x49, 0x1a, 0x89, 0x07, 0xdf, 0x4e, 0x4b, \ - 0xe5, 0x18, 0x6a, 0xe4, 0x96, 0xcd, 0x34, 0x0d, 0xc1, 0x9b, 0x23, 0x78, 0x21, 0xdb, 0x7b, 0x60 } -#define NIST_AES_192_CMAC_MAC { 0x74, 0xf7, 0x46, 0x08, 0xc0, 0x4f, 0x0f, 0x4e, 0x47, 0xfa, 0x64, 0x04, 0x33, 0xb6, 0xe6, 0xfb } -#define NIST_AES_192_CMAC_VECTOR_SIZE 32 -#define NIST_AES_192_CMAC_OUTPUT_SIZE 16 - -#define NIST_AES_256_CMAC_KEY { 0x3a, 0x75, 0xa9, 0xd2, 0xbd, 0xb8, 0xc8, 0x04, 0xba, 0x4a, 0xb4, 0x98, 0x35, 0x73, 0xa6, 0xb2, \ - 0x53, 0x16, 0x0d, 0xd9, 0x0f, 0x8e, 0xdd, 0xfb, 0x2f, 0xdc, 0x2a, 0xb1, 0x76, 0x04, 0xf5, 0xc5 } -#define NIST_AES_256_CMAC_PLAIN_DATA { 0x42, 0xf3, 0x5d, 0x5a, 0xa5, 0x33, 0xa7, 0xa0, 0xa5, 0xf7, 0x4e, 0x14, 0x4f, 0x2a, 0x5f, 0x20 } -#define NIST_AES_256_CMAC_MAC { 0xf1, 0x53, 0x2f, 0x87, 0x32, 0xd9, 0xf5, 0x90, 0x30, 0x07 } -#define NIST_AES_256_CMAC_VECTOR_SIZE 16 -#define NIST_AES_256_CMAC_OUTPUT_SIZE 10 - -/* NIST TDES */ -#define TDES_NUM_OF_KEYS 3 -#define NIST_TDES_VECTOR_SIZE 8 -#define NIST_TDES_IV_SIZE 8 - -#define NIST_TDES_ECB_IV { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } - -#define NIST_TDES_ECB3_KEY { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, \ - 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, \ - 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23 } -#define NIST_TDES_ECB3_PLAIN_DATA { 0x54, 0x68, 0x65, 0x20, 0x71, 0x75, 0x66, 0x63 } -#define NIST_TDES_ECB3_CIPHER { 0xa8, 0x26, 0xfd, 0x8c, 0xe5, 0x3b, 0x85, 0x5f } - -#define NIST_TDES_CBC3_IV { 0xf8, 0xee, 0xe1, 0x35, 0x9c, 0x6e, 0x54, 0x40 } -#define NIST_TDES_CBC3_KEY { 0xe9, 0xda, 0x37, 0xf8, 0xdc, 0x97, 0x6d, 0x5b, \ - 0xb6, 0x8c, 0x04, 0xe3, 0xec, 0x98, 0x20, 0x15, \ - 0xf4, 0x0e, 0x08, 0xb5, 0x97, 0x29, 0xf2, 0x8f } -#define NIST_TDES_CBC3_PLAIN_DATA { 0x3b, 0xb7, 0xa7, 0xdb, 0xa3, 0xd5, 0x92, 0x91 } -#define NIST_TDES_CBC3_CIPHER { 0x5b, 0x84, 0x24, 0xd2, 0x39, 0x3e, 0x55, 0xa2 } - -/* NIST AES-CCM */ -#define NIST_AESCCM_128_BIT_KEY_SIZE 16 -#define NIST_AESCCM_192_BIT_KEY_SIZE 24 -#define NIST_AESCCM_256_BIT_KEY_SIZE 32 - -#define NIST_AESCCM_B0_VAL 0x79 /* L'[0:2]=1 , M'[3-5]=7 , Adata[6]=1, reserved[7]=0 */ -#define NIST_AESCCM_NONCE_SIZE 13 -#define NIST_AESCCM_IV_SIZE 16 -#define NIST_AESCCM_ADATA_SIZE 32 -#define NIST_AESCCM_TEXT_SIZE 16 -#define NIST_AESCCM_TAG_SIZE 16 - -#define NIST_AESCCM_128_KEY { 0x70, 0x01, 0x0e, 0xd9, 0x0e, 0x61, 0x86, 0xec, 0xad, 0x41, 0xf0, 0xd3, 0xc7, 0xc4, 0x2f, 0xf8 } -#define NIST_AESCCM_128_NONCE { 0xa5, 0xf4, 0xf4, 0x98, 0x6e, 0x98, 0x47, 0x29, 0x65, 0xf5, 0xab, 0xcc, 0x4b } -#define NIST_AESCCM_128_ADATA { 0x3f, 0xec, 0x0e, 0x5c, 0xc2, 0x4d, 0x67, 0x13, 0x94, 0x37, 0xcb, 0xc8, 0x11, 0x24, 0x14, 0xfc, \ - 0x8d, 0xac, 0xcd, 0x1a, 0x94, 0xb4, 0x9a, 0x4c, 0x76, 0xe2, 0xd3, 0x93, 0x03, 0x54, 0x73, 0x17 } -#define NIST_AESCCM_128_PLAIN_TEXT { 0xbe, 0x32, 0x2f, 0x58, 0xef, 0xa7, 0xf8, 0xc6, 0x8a, 0x63, 0x5e, 0x0b, 0x9c, 0xce, 0x77, 0xf2 } -#define NIST_AESCCM_128_CIPHER { 0x8e, 0x44, 0x25, 0xae, 0x57, 0x39, 0x74, 0xf0, 0xf0, 0x69, 0x3a, 0x18, 0x8b, 0x52, 0x58, 0x12 } -#define NIST_AESCCM_128_MAC { 0xee, 0xf0, 0x8e, 0x3f, 0xb1, 0x5f, 0x42, 0x27, 0xe0, 0xd9, 0x89, 0xa4, 0xd5, 0x87, 0xa8, 0xcf } - -#define NIST_AESCCM_192_KEY { 0x68, 0x73, 0xf1, 0xc6, 0xc3, 0x09, 0x75, 0xaf, 0xf6, 0xf0, 0x84, 0x70, 0x26, 0x43, 0x21, 0x13, \ - 0x0a, 0x6e, 0x59, 0x84, 0xad, 0xe3, 0x24, 0xe9 } -#define NIST_AESCCM_192_NONCE { 0x7c, 0x4d, 0x2f, 0x7c, 0xec, 0x04, 0x36, 0x1f, 0x18, 0x7f, 0x07, 0x26, 0xd5 } -#define NIST_AESCCM_192_ADATA { 0x77, 0x74, 0x3b, 0x5d, 0x83, 0xa0, 0x0d, 0x2c, 0x8d, 0x5f, 0x7e, 0x10, 0x78, 0x15, 0x31, 0xb4, \ - 0x96, 0xe0, 0x9f, 0x3b, 0xc9, 0x29, 0x5d, 0x7a, 0xe9, 0x79, 0x9e, 0x64, 0x66, 0x8e, 0xf8, 0xc5 } -#define NIST_AESCCM_192_PLAIN_TEXT { 0x50, 0x51, 0xa0, 0xb0, 0xb6, 0x76, 0x6c, 0xd6, 0xea, 0x29, 0xa6, 0x72, 0x76, 0x9d, 0x40, 0xfe } -#define NIST_AESCCM_192_CIPHER { 0x0c, 0xe5, 0xac, 0x8d, 0x6b, 0x25, 0x6f, 0xb7, 0x58, 0x0b, 0xf6, 0xac, 0xc7, 0x64, 0x26, 0xaf } -#define NIST_AESCCM_192_MAC { 0x40, 0xbc, 0xe5, 0x8f, 0xd4, 0xcd, 0x65, 0x48, 0xdf, 0x90, 0xa0, 0x33, 0x7c, 0x84, 0x20, 0x04 } - -#define NIST_AESCCM_256_KEY { 0xee, 0x8c, 0xe1, 0x87, 0x16, 0x97, 0x79, 0xd1, 0x3e, 0x44, 0x3d, 0x64, 0x28, 0xe3, 0x8b, 0x38, \ - 0xb5, 0x5d, 0xfb, 0x90, 0xf0, 0x22, 0x8a, 0x8a, 0x4e, 0x62, 0xf8, 0xf5, 0x35, 0x80, 0x6e, 0x62 } -#define NIST_AESCCM_256_NONCE { 0x12, 0x16, 0x42, 0xc4, 0x21, 0x8b, 0x39, 0x1c, 0x98, 0xe6, 0x26, 0x9c, 0x8a } -#define NIST_AESCCM_256_ADATA { 0x71, 0x8d, 0x13, 0xe4, 0x75, 0x22, 0xac, 0x4c, 0xdf, 0x3f, 0x82, 0x80, 0x63, 0x98, 0x0b, 0x6d, \ - 0x45, 0x2f, 0xcd, 0xcd, 0x6e, 0x1a, 0x19, 0x04, 0xbf, 0x87, 0xf5, 0x48, 0xa5, 0xfd, 0x5a, 0x05 } -#define NIST_AESCCM_256_PLAIN_TEXT { 0xd1, 0x5f, 0x98, 0xf2, 0xc6, 0xd6, 0x70, 0xf5, 0x5c, 0x78, 0xa0, 0x66, 0x48, 0x33, 0x2b, 0xc9 } -#define NIST_AESCCM_256_CIPHER { 0xcc, 0x17, 0xbf, 0x87, 0x94, 0xc8, 0x43, 0x45, 0x7d, 0x89, 0x93, 0x91, 0x89, 0x8e, 0xd2, 0x2a } -#define NIST_AESCCM_256_MAC { 0x6f, 0x9d, 0x28, 0xfc, 0xb6, 0x42, 0x34, 0xe1, 0xcd, 0x79, 0x3c, 0x41, 0x44, 0xf1, 0xda, 0x50 } - -/* NIST AES-GCM */ -#define NIST_AESGCM_128_BIT_KEY_SIZE 16 -#define NIST_AESGCM_192_BIT_KEY_SIZE 24 -#define NIST_AESGCM_256_BIT_KEY_SIZE 32 - -#define NIST_AESGCM_IV_SIZE 12 -#define NIST_AESGCM_ADATA_SIZE 16 -#define NIST_AESGCM_TEXT_SIZE 16 -#define NIST_AESGCM_TAG_SIZE 16 - -#define NIST_AESGCM_128_KEY { 0x81, 0x6e, 0x39, 0x07, 0x04, 0x10, 0xcf, 0x21, 0x84, 0x90, 0x4d, 0xa0, 0x3e, 0xa5, 0x07, 0x5a } -#define NIST_AESGCM_128_IV { 0x32, 0xc3, 0x67, 0xa3, 0x36, 0x26, 0x13, 0xb2, 0x7f, 0xc3, 0xe6, 0x7e } -#define NIST_AESGCM_128_ADATA { 0xf2, 0xa3, 0x07, 0x28, 0xed, 0x87, 0x4e, 0xe0, 0x29, 0x83, 0xc2, 0x94, 0x43, 0x5d, 0x3c, 0x16 } -#define NIST_AESGCM_128_PLAIN_TEXT { 0xec, 0xaf, 0xe9, 0x6c, 0x67, 0xa1, 0x64, 0x67, 0x44, 0xf1, 0xc8, 0x91, 0xf5, 0xe6, 0x94, 0x27 } -#define NIST_AESGCM_128_CIPHER { 0x55, 0x2e, 0xbe, 0x01, 0x2e, 0x7b, 0xcf, 0x90, 0xfc, 0xef, 0x71, 0x2f, 0x83, 0x44, 0xe8, 0xf1 } -#define NIST_AESGCM_128_MAC { 0xec, 0xaa, 0xe9, 0xfc, 0x68, 0x27, 0x6a, 0x45, 0xab, 0x0c, 0xa3, 0xcb, 0x9d, 0xd9, 0x53, 0x9f } - -#define NIST_AESGCM_192_KEY { 0x0c, 0x44, 0xd6, 0xc9, 0x28, 0xee, 0x11, 0x2c, 0xe6, 0x65, 0xfe, 0x54, 0x7e, 0xbd, 0x38, 0x72, \ - 0x98, 0xa9, 0x54, 0xb4, 0x62, 0xf6, 0x95, 0xd8 } -#define NIST_AESGCM_192_IV { 0x18, 0xb8, 0xf3, 0x20, 0xfe, 0xf4, 0xae, 0x8c, 0xcb, 0xe8, 0xf9, 0x52 } -#define NIST_AESGCM_192_ADATA { 0x73, 0x41, 0xd4, 0x3f, 0x98, 0xcf, 0x38, 0x82, 0x21, 0x18, 0x09, 0x41, 0x97, 0x03, 0x76, 0xe8 } -#define NIST_AESGCM_192_PLAIN_TEXT { 0x96, 0xad, 0x07, 0xf9, 0xb6, 0x28, 0xb6, 0x52, 0xcf, 0x86, 0xcb, 0x73, 0x17, 0x88, 0x6f, 0x51 } -#define NIST_AESGCM_192_CIPHER { 0xa6, 0x64, 0x07, 0x81, 0x33, 0x40, 0x5e, 0xb9, 0x09, 0x4d, 0x36, 0xf7, 0xe0, 0x70, 0x19, 0x1f } -#define NIST_AESGCM_192_MAC { 0xe8, 0xf9, 0xc3, 0x17, 0x84, 0x7c, 0xe3, 0xf3, 0xc2, 0x39, 0x94, 0xa4, 0x02, 0xf0, 0x65, 0x81 } - -#define NIST_AESGCM_256_KEY { 0x54, 0xe3, 0x52, 0xea, 0x1d, 0x84, 0xbf, 0xe6, 0x4a, 0x10, 0x11, 0x09, 0x61, 0x11, 0xfb, 0xe7, \ - 0x66, 0x8a, 0xd2, 0x20, 0x3d, 0x90, 0x2a, 0x01, 0x45, 0x8c, 0x3b, 0xbd, 0x85, 0xbf, 0xce, 0x14 } -#define NIST_AESGCM_256_IV { 0xdf, 0x7c, 0x3b, 0xca, 0x00, 0x39, 0x6d, 0x0c, 0x01, 0x84, 0x95, 0xd9 } -#define NIST_AESGCM_256_ADATA { 0x7e, 0x96, 0x8d, 0x71, 0xb5, 0x0c, 0x1f, 0x11, 0xfd, 0x00, 0x1f, 0x3f, 0xef, 0x49, 0xd0, 0x45 } -#define NIST_AESGCM_256_PLAIN_TEXT { 0x85, 0xfc, 0x3d, 0xfa, 0xd9, 0xb5, 0xa8, 0xd3, 0x25, 0x8e, 0x4f, 0xc4, 0x45, 0x71, 0xbd, 0x3b } -#define NIST_AESGCM_256_CIPHER { 0x42, 0x6e, 0x0e, 0xfc, 0x69, 0x3b, 0x7b, 0xe1, 0xf3, 0x01, 0x8d, 0xb7, 0xdd, 0xbb, 0x7e, 0x4d } -#define NIST_AESGCM_256_MAC { 0xee, 0x82, 0x57, 0x79, 0x5b, 0xe6, 0xa1, 0x16, 0x4d, 0x7e, 0x1d, 0x2d, 0x6c, 0xac, 0x77, 0xa7 } - -/* NIST HASH */ -#define NIST_SHA_MSG_SIZE 16 - -#define NIST_SHA_1_MSG { 0x35, 0x52, 0x69, 0x4c, 0xdf, 0x66, 0x3f, 0xd9, 0x4b, 0x22, 0x47, 0x47, 0xac, 0x40, 0x6a, 0xaf } -#define NIST_SHA_1_MD { 0xa1, 0x50, 0xde, 0x92, 0x74, 0x54, 0x20, 0x2d, 0x94, 0xe6, 0x56, 0xde, 0x4c, 0x7c, 0x0c, 0xa6, \ - 0x91, 0xde, 0x95, 0x5d } - -#define NIST_SHA_256_MSG { 0x0a, 0x27, 0x84, 0x7c, 0xdc, 0x98, 0xbd, 0x6f, 0x62, 0x22, 0x0b, 0x04, 0x6e, 0xdd, 0x76, 0x2b } -#define NIST_SHA_256_MD { 0x80, 0xc2, 0x5e, 0xc1, 0x60, 0x05, 0x87, 0xe7, 0xf2, 0x8b, 0x18, 0xb1, 0xb1, 0x8e, 0x3c, 0xdc, \ - 0x89, 0x92, 0x8e, 0x39, 0xca, 0xb3, 0xbc, 0x25, 0xe4, 0xd4, 0xa4, 0xc1, 0x39, 0xbc, 0xed, 0xc4 } - -#define NIST_SHA_512_MSG { 0xcd, 0x67, 0xbd, 0x40, 0x54, 0xaa, 0xa3, 0xba, 0xa0, 0xdb, 0x17, 0x8c, 0xe2, 0x32, 0xfd, 0x5a } -#define NIST_SHA_512_MD { 0x0d, 0x85, 0x21, 0xf8, 0xf2, 0xf3, 0x90, 0x03, 0x32, 0xd1, 0xa1, 0xa5, 0x5c, 0x60, 0xba, 0x81, \ - 0xd0, 0x4d, 0x28, 0xdf, 0xe8, 0xc5, 0x04, 0xb6, 0x32, 0x8a, 0xe7, 0x87, 0x92, 0x5f, 0xe0, 0x18, \ - 0x8f, 0x2b, 0xa9, 0x1c, 0x3a, 0x9f, 0x0c, 0x16, 0x53, 0xc4, 0xbf, 0x0a, 0xda, 0x35, 0x64, 0x55, \ - 0xea, 0x36, 0xfd, 0x31, 0xf8, 0xe7, 0x3e, 0x39, 0x51, 0xca, 0xd4, 0xeb, 0xba, 0x8c, 0x6e, 0x04 } - -/* NIST HMAC */ -#define NIST_HMAC_MSG_SIZE 128 - -#define NIST_HMAC_SHA1_KEY_SIZE 10 -#define NIST_HMAC_SHA1_KEY { 0x59, 0x78, 0x59, 0x28, 0xd7, 0x25, 0x16, 0xe3, 0x12, 0x72 } -#define NIST_HMAC_SHA1_MSG { 0xa3, 0xce, 0x88, 0x99, 0xdf, 0x10, 0x22, 0xe8, 0xd2, 0xd5, 0x39, 0xb4, 0x7b, 0xf0, 0xe3, 0x09, \ - 0xc6, 0x6f, 0x84, 0x09, 0x5e, 0x21, 0x43, 0x8e, 0xc3, 0x55, 0xbf, 0x11, 0x9c, 0xe5, 0xfd, 0xcb, \ - 0x4e, 0x73, 0xa6, 0x19, 0xcd, 0xf3, 0x6f, 0x25, 0xb3, 0x69, 0xd8, 0xc3, 0x8f, 0xf4, 0x19, 0x99, \ - 0x7f, 0x0c, 0x59, 0x83, 0x01, 0x08, 0x22, 0x36, 0x06, 0xe3, 0x12, 0x23, 0x48, 0x3f, 0xd3, 0x9e, \ - 0xde, 0xaa, 0x4d, 0x3f, 0x0d, 0x21, 0x19, 0x88, 0x62, 0xd2, 0x39, 0xc9, 0xfd, 0x26, 0x07, 0x41, \ - 0x30, 0xff, 0x6c, 0x86, 0x49, 0x3f, 0x52, 0x27, 0xab, 0x89, 0x5c, 0x8f, 0x24, 0x4b, 0xd4, 0x2c, \ - 0x7a, 0xfc, 0xe5, 0xd1, 0x47, 0xa2, 0x0a, 0x59, 0x07, 0x98, 0xc6, 0x8e, 0x70, 0x8e, 0x96, 0x49, \ - 0x02, 0xd1, 0x24, 0xda, 0xde, 0xcd, 0xbd, 0xa9, 0xdb, 0xd0, 0x05, 0x1e, 0xd7, 0x10, 0xe9, 0xbf } -#define NIST_HMAC_SHA1_MD { 0x3c, 0x81, 0x62, 0x58, 0x9a, 0xaf, 0xae, 0xe0, 0x24, 0xfc, 0x9a, 0x5c, 0xa5, 0x0d, 0xd2, 0x33, \ - 0x6f, 0xe3, 0xeb, 0x28 } - -#define NIST_HMAC_SHA256_KEY_SIZE 40 -#define NIST_HMAC_SHA256_KEY { 0x97, 0x79, 0xd9, 0x12, 0x06, 0x42, 0x79, 0x7f, 0x17, 0x47, 0x02, 0x5d, 0x5b, 0x22, 0xb7, 0xac, \ - 0x60, 0x7c, 0xab, 0x08, 0xe1, 0x75, 0x8f, 0x2f, 0x3a, 0x46, 0xc8, 0xbe, 0x1e, 0x25, 0xc5, 0x3b, \ - 0x8c, 0x6a, 0x8f, 0x58, 0xff, 0xef, 0xa1, 0x76 } -#define NIST_HMAC_SHA256_MSG { 0xb1, 0x68, 0x9c, 0x25, 0x91, 0xea, 0xf3, 0xc9, 0xe6, 0x60, 0x70, 0xf8, 0xa7, 0x79, 0x54, 0xff, \ - 0xb8, 0x17, 0x49, 0xf1, 0xb0, 0x03, 0x46, 0xf9, 0xdf, 0xe0, 0xb2, 0xee, 0x90, 0x5d, 0xcc, 0x28, \ - 0x8b, 0xaf, 0x4a, 0x92, 0xde, 0x3f, 0x40, 0x01, 0xdd, 0x9f, 0x44, 0xc4, 0x68, 0xc3, 0xd0, 0x7d, \ - 0x6c, 0x6e, 0xe8, 0x2f, 0xac, 0xea, 0xfc, 0x97, 0xc2, 0xfc, 0x0f, 0xc0, 0x60, 0x17, 0x19, 0xd2, \ - 0xdc, 0xd0, 0xaa, 0x2a, 0xec, 0x92, 0xd1, 0xb0, 0xae, 0x93, 0x3c, 0x65, 0xeb, 0x06, 0xa0, 0x3c, \ - 0x9c, 0x93, 0x5c, 0x2b, 0xad, 0x04, 0x59, 0x81, 0x02, 0x41, 0x34, 0x7a, 0xb8, 0x7e, 0x9f, 0x11, \ - 0xad, 0xb3, 0x04, 0x15, 0x42, 0x4c, 0x6c, 0x7f, 0x5f, 0x22, 0xa0, 0x03, 0xb8, 0xab, 0x8d, 0xe5, \ - 0x4f, 0x6d, 0xed, 0x0e, 0x3a, 0xb9, 0x24, 0x5f, 0xa7, 0x95, 0x68, 0x45, 0x1d, 0xfa, 0x25, 0x8e } -#define NIST_HMAC_SHA256_MD { 0x76, 0x9f, 0x00, 0xd3, 0xe6, 0xa6, 0xcc, 0x1f, 0xb4, 0x26, 0xa1, 0x4a, 0x4f, 0x76, 0xc6, 0x46, \ - 0x2e, 0x61, 0x49, 0x72, 0x6e, 0x0d, 0xee, 0x0e, 0xc0, 0xcf, 0x97, 0xa1, 0x66, 0x05, 0xac, 0x8b } - -#define NIST_HMAC_SHA512_KEY_SIZE 100 -#define NIST_HMAC_SHA512_KEY { 0x57, 0xc2, 0xeb, 0x67, 0x7b, 0x50, 0x93, 0xb9, 0xe8, 0x29, 0xea, 0x4b, 0xab, 0xb5, 0x0b, 0xde, \ - 0x55, 0xd0, 0xad, 0x59, 0xfe, 0xc3, 0x4a, 0x61, 0x89, 0x73, 0x80, 0x2b, 0x2a, 0xd9, 0xb7, 0x8e, \ - 0x26, 0xb2, 0x04, 0x5d, 0xda, 0x78, 0x4d, 0xf3, 0xff, 0x90, 0xae, 0x0f, 0x2c, 0xc5, 0x1c, 0xe3, \ - 0x9c, 0xf5, 0x48, 0x67, 0x32, 0x0a, 0xc6, 0xf3, 0xba, 0x2c, 0x6f, 0x0d, 0x72, 0x36, 0x04, 0x80, \ - 0xc9, 0x66, 0x14, 0xae, 0x66, 0x58, 0x1f, 0x26, 0x6c, 0x35, 0xfb, 0x79, 0xfd, 0x28, 0x77, 0x4a, \ - 0xfd, 0x11, 0x3f, 0xa5, 0x18, 0x7e, 0xff, 0x92, 0x06, 0xd7, 0xcb, 0xe9, 0x0d, 0xd8, 0xbf, 0x67, \ - 0xc8, 0x44, 0xe2, 0x02 } -#define NIST_HMAC_SHA512_MSG { 0x24, 0x23, 0xdf, 0xf4, 0x8b, 0x31, 0x2b, 0xe8, 0x64, 0xcb, 0x34, 0x90, 0x64, 0x1f, 0x79, 0x3d, \ - 0x2b, 0x9f, 0xb6, 0x8a, 0x77, 0x63, 0xb8, 0xe2, 0x98, 0xc8, 0x6f, 0x42, 0x24, 0x5e, 0x45, 0x40, \ - 0xeb, 0x01, 0xae, 0x4d, 0x2d, 0x45, 0x00, 0x37, 0x0b, 0x18, 0x86, 0xf2, 0x3c, 0xa2, 0xcf, 0x97, \ - 0x01, 0x70, 0x4c, 0xad, 0x5b, 0xd2, 0x1b, 0xa8, 0x7b, 0x81, 0x1d, 0xaf, 0x7a, 0x85, 0x4e, 0xa2, \ - 0x4a, 0x56, 0x56, 0x5c, 0xed, 0x42, 0x5b, 0x35, 0xe4, 0x0e, 0x1a, 0xcb, 0xeb, 0xe0, 0x36, 0x03, \ - 0xe3, 0x5d, 0xcf, 0x4a, 0x10, 0x0e, 0x57, 0x21, 0x84, 0x08, 0xa1, 0xd8, 0xdb, 0xcc, 0x3b, 0x99, \ - 0x29, 0x6c, 0xfe, 0xa9, 0x31, 0xef, 0xe3, 0xeb, 0xd8, 0xf7, 0x19, 0xa6, 0xd9, 0xa1, 0x54, 0x87, \ - 0xb9, 0xad, 0x67, 0xea, 0xfe, 0xdf, 0x15, 0x55, 0x9c, 0xa4, 0x24, 0x45, 0xb0, 0xf9, 0xb4, 0x2e } -#define NIST_HMAC_SHA512_MD { 0x33, 0xc5, 0x11, 0xe9, 0xbc, 0x23, 0x07, 0xc6, 0x27, 0x58, 0xdf, 0x61, 0x12, 0x5a, 0x98, 0x0e, \ - 0xe6, 0x4c, 0xef, 0xeb, 0xd9, 0x09, 0x31, 0xcb, 0x91, 0xc1, 0x37, 0x42, 0xd4, 0x71, 0x4c, 0x06, \ - 0xde, 0x40, 0x03, 0xfa, 0xf3, 0xc4, 0x1c, 0x06, 0xae, 0xfc, 0x63, 0x8a, 0xd4, 0x7b, 0x21, 0x90, \ - 0x6e, 0x6b, 0x10, 0x48, 0x16, 0xb7, 0x2d, 0xe6, 0x26, 0x9e, 0x04, 0x5a, 0x1f, 0x44, 0x29, 0xd4 } - diff --git a/drivers/staging/ccree/ssi_fips_ext.c b/drivers/staging/ccree/ssi_fips_ext.c deleted file mode 100644 index e7bf1843f60c..000000000000 --- a/drivers/staging/ccree/ssi_fips_ext.c +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2012-2017 ARM Limited or its affiliates. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -/************************************************************** - * This file defines the driver FIPS functions that should be - * implemented by the driver user. Current implementation is sample code only. - ***************************************************************/ - -#include <linux/module.h> -#include "ssi_fips_local.h" -#include "ssi_driver.h" - -static bool tee_error; -module_param(tee_error, bool, 0644); -MODULE_PARM_DESC(tee_error, "Simulate TEE library failure flag: 0 - no error (default), 1 - TEE error occured "); - -static enum cc_fips_state_t fips_state = CC_FIPS_STATE_NOT_SUPPORTED; -static enum cc_fips_error fips_error = CC_REE_FIPS_ERROR_OK; - -/* - * This function returns the FIPS REE state. - * The function should be implemented by the driver user, depends on where - * the state value is stored. - * The reference code uses global variable. - */ -int ssi_fips_ext_get_state(enum cc_fips_state_t *p_state) -{ - int rc = 0; - - if (!p_state) - return -EINVAL; - - *p_state = fips_state; - - return rc; -} - -/* - * This function returns the FIPS REE error. - * The function should be implemented by the driver user, depends on where - * the error value is stored. - * The reference code uses global variable. - */ -int ssi_fips_ext_get_error(enum cc_fips_error *p_err) -{ - int rc = 0; - - if (!p_err) - return -EINVAL; - - *p_err = fips_error; - - return rc; -} - -/* - * This function sets the FIPS REE state. - * The function should be implemented by the driver user, depends on where - * the state value is stored. - * The reference code uses global variable. - */ -int ssi_fips_ext_set_state(enum cc_fips_state_t state) -{ - fips_state = state; - return 0; -} - -/* - * This function sets the FIPS REE error. - * The function should be implemented by the driver user, depends on where - * the error value is stored. - * The reference code uses global variable. - */ -int ssi_fips_ext_set_error(enum cc_fips_error err) -{ - fips_error = err; - return 0; -} - diff --git a/drivers/staging/ccree/ssi_fips_ll.c b/drivers/staging/ccree/ssi_fips_ll.c deleted file mode 100644 index 3557e20c9e36..000000000000 --- a/drivers/staging/ccree/ssi_fips_ll.c +++ /dev/null @@ -1,1649 +0,0 @@ -/* - * Copyright (C) 2012-2017 ARM Limited or its affiliates. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -/************************************************************** - * This file defines the driver FIPS Low Level implmentaion functions, - * that executes the KAT. - ***************************************************************/ -#include <linux/kernel.h> - -#include "ssi_driver.h" -#include "ssi_fips_local.h" -#include "ssi_fips_data.h" -#include "cc_crypto_ctx.h" -#include "ssi_hash.h" -#include "ssi_request_mgr.h" - -static const u32 digest_len_init[] = { - 0x00000040, 0x00000000, 0x00000000, 0x00000000 }; -static const u32 sha1_init[] = { - SHA1_H4, SHA1_H3, SHA1_H2, SHA1_H1, SHA1_H0 }; -static const u32 sha256_init[] = { - SHA256_H7, SHA256_H6, SHA256_H5, SHA256_H4, - SHA256_H3, SHA256_H2, SHA256_H1, SHA256_H0 }; -#if (CC_SUPPORT_SHA > 256) -static const u32 digest_len_sha512_init[] = { - 0x00000080, 0x00000000, 0x00000000, 0x00000000 }; -static const u64 sha512_init[] = { - SHA512_H7, SHA512_H6, SHA512_H5, SHA512_H4, - SHA512_H3, SHA512_H2, SHA512_H1, SHA512_H0 }; -#endif - -#define NIST_CIPHER_AES_MAX_VECTOR_SIZE 32 - -struct fips_cipher_ctx { - u8 iv[CC_AES_IV_SIZE]; - u8 key[AES_512_BIT_KEY_SIZE]; - u8 din[NIST_CIPHER_AES_MAX_VECTOR_SIZE]; - u8 dout[NIST_CIPHER_AES_MAX_VECTOR_SIZE]; -}; - -typedef struct _FipsCipherData { - u8 isAes; - u8 key[AES_512_BIT_KEY_SIZE]; - size_t keySize; - u8 iv[CC_AES_IV_SIZE]; - enum drv_crypto_direction direction; - enum drv_cipher_mode oprMode; - u8 dataIn[NIST_CIPHER_AES_MAX_VECTOR_SIZE]; - u8 dataOut[NIST_CIPHER_AES_MAX_VECTOR_SIZE]; - size_t dataInSize; -} FipsCipherData; - -struct fips_cmac_ctx { - u8 key[AES_256_BIT_KEY_SIZE]; - u8 din[NIST_CIPHER_AES_MAX_VECTOR_SIZE]; - u8 mac_res[CC_DIGEST_SIZE_MAX]; -}; - -typedef struct _FipsCmacData { - enum drv_crypto_direction direction; - u8 key[AES_256_BIT_KEY_SIZE]; - size_t key_size; - u8 data_in[NIST_CIPHER_AES_MAX_VECTOR_SIZE]; - size_t data_in_size; - u8 mac_res[CC_DIGEST_SIZE_MAX]; - size_t mac_res_size; -} FipsCmacData; - -struct fips_hash_ctx { - u8 initial_digest[CC_DIGEST_SIZE_MAX]; - u8 din[NIST_SHA_MSG_SIZE]; - u8 mac_res[CC_DIGEST_SIZE_MAX]; -}; - -typedef struct _FipsHashData { - enum drv_hash_mode hash_mode; - u8 data_in[NIST_SHA_MSG_SIZE]; - size_t data_in_size; - u8 mac_res[CC_DIGEST_SIZE_MAX]; -} FipsHashData; - -/* note that the hmac key length must be equal or less than block size (block size is 64 up to sha256 and 128 for sha384/512) */ -struct fips_hmac_ctx { - u8 initial_digest[CC_DIGEST_SIZE_MAX]; - u8 key[CC_HMAC_BLOCK_SIZE_MAX]; - u8 k0[CC_HMAC_BLOCK_SIZE_MAX]; - u8 digest_bytes_len[HASH_LEN_SIZE]; - u8 tmp_digest[CC_DIGEST_SIZE_MAX]; - u8 din[NIST_HMAC_MSG_SIZE]; - u8 mac_res[CC_DIGEST_SIZE_MAX]; -}; - -typedef struct _FipsHmacData { - enum drv_hash_mode hash_mode; - u8 key[CC_HMAC_BLOCK_SIZE_MAX]; - size_t key_size; - u8 data_in[NIST_HMAC_MSG_SIZE]; - size_t data_in_size; - u8 mac_res[CC_DIGEST_SIZE_MAX]; -} FipsHmacData; - -#define FIPS_CCM_B0_A0_ADATA_SIZE (NIST_AESCCM_IV_SIZE + NIST_AESCCM_IV_SIZE + NIST_AESCCM_ADATA_SIZE) - -struct fips_ccm_ctx { - u8 b0_a0_adata[FIPS_CCM_B0_A0_ADATA_SIZE]; - u8 iv[NIST_AESCCM_IV_SIZE]; - u8 ctr_cnt_0[NIST_AESCCM_IV_SIZE]; - u8 key[CC_AES_KEY_SIZE_MAX]; - u8 din[NIST_AESCCM_TEXT_SIZE]; - u8 dout[NIST_AESCCM_TEXT_SIZE]; - u8 mac_res[NIST_AESCCM_TAG_SIZE]; -}; - -typedef struct _FipsCcmData { - enum drv_crypto_direction direction; - u8 key[CC_AES_KEY_SIZE_MAX]; - size_t keySize; - u8 nonce[NIST_AESCCM_NONCE_SIZE]; - u8 adata[NIST_AESCCM_ADATA_SIZE]; - size_t adataSize; - u8 dataIn[NIST_AESCCM_TEXT_SIZE]; - size_t dataInSize; - u8 dataOut[NIST_AESCCM_TEXT_SIZE]; - u8 tagSize; - u8 macResOut[NIST_AESCCM_TAG_SIZE]; -} FipsCcmData; - -struct fips_gcm_ctx { - u8 adata[NIST_AESGCM_ADATA_SIZE]; - u8 key[CC_AES_KEY_SIZE_MAX]; - u8 hkey[CC_AES_KEY_SIZE_MAX]; - u8 din[NIST_AESGCM_TEXT_SIZE]; - u8 dout[NIST_AESGCM_TEXT_SIZE]; - u8 mac_res[NIST_AESGCM_TAG_SIZE]; - u8 len_block[AES_BLOCK_SIZE]; - u8 iv_inc1[AES_BLOCK_SIZE]; - u8 iv_inc2[AES_BLOCK_SIZE]; -}; - -typedef struct _FipsGcmData { - enum drv_crypto_direction direction; - u8 key[CC_AES_KEY_SIZE_MAX]; - size_t keySize; - u8 iv[NIST_AESGCM_IV_SIZE]; - u8 adata[NIST_AESGCM_ADATA_SIZE]; - size_t adataSize; - u8 dataIn[NIST_AESGCM_TEXT_SIZE]; - size_t dataInSize; - u8 dataOut[NIST_AESGCM_TEXT_SIZE]; - u8 tagSize; - u8 macResOut[NIST_AESGCM_TAG_SIZE]; -} FipsGcmData; - -typedef union _fips_ctx { - struct fips_cipher_ctx cipher; - struct fips_cmac_ctx cmac; - struct fips_hash_ctx hash; - struct fips_hmac_ctx hmac; - struct fips_ccm_ctx ccm; - struct fips_gcm_ctx gcm; -} fips_ctx; - -/* test data tables */ -static const FipsCipherData FipsCipherDataTable[] = { - /* AES */ - { 1, NIST_AES_128_KEY, CC_AES_128_BIT_KEY_SIZE, NIST_AES_ECB_IV, DRV_CRYPTO_DIRECTION_ENCRYPT, DRV_CIPHER_ECB, NIST_AES_PLAIN_DATA, NIST_AES_128_ECB_CIPHER, NIST_AES_VECTOR_SIZE }, - { 1, NIST_AES_128_KEY, CC_AES_128_BIT_KEY_SIZE, NIST_AES_ECB_IV, DRV_CRYPTO_DIRECTION_DECRYPT, DRV_CIPHER_ECB, NIST_AES_128_ECB_CIPHER, NIST_AES_PLAIN_DATA, NIST_AES_VECTOR_SIZE }, - { 1, NIST_AES_192_KEY, CC_AES_192_BIT_KEY_SIZE, NIST_AES_ECB_IV, DRV_CRYPTO_DIRECTION_ENCRYPT, DRV_CIPHER_ECB, NIST_AES_PLAIN_DATA, NIST_AES_192_ECB_CIPHER, NIST_AES_VECTOR_SIZE }, - { 1, NIST_AES_192_KEY, CC_AES_192_BIT_KEY_SIZE, NIST_AES_ECB_IV, DRV_CRYPTO_DIRECTION_DECRYPT, DRV_CIPHER_ECB, NIST_AES_192_ECB_CIPHER, NIST_AES_PLAIN_DATA, NIST_AES_VECTOR_SIZE }, - { 1, NIST_AES_256_KEY, CC_AES_256_BIT_KEY_SIZE, NIST_AES_ECB_IV, DRV_CRYPTO_DIRECTION_ENCRYPT, DRV_CIPHER_ECB, NIST_AES_PLAIN_DATA, NIST_AES_256_ECB_CIPHER, NIST_AES_VECTOR_SIZE }, - { 1, NIST_AES_256_KEY, CC_AES_256_BIT_KEY_SIZE, NIST_AES_ECB_IV, DRV_CRYPTO_DIRECTION_DECRYPT, DRV_CIPHER_ECB, NIST_AES_256_ECB_CIPHER, NIST_AES_PLAIN_DATA, NIST_AES_VECTOR_SIZE }, - { 1, NIST_AES_128_KEY, CC_AES_128_BIT_KEY_SIZE, NIST_AES_CBC_IV, DRV_CRYPTO_DIRECTION_ENCRYPT, DRV_CIPHER_CBC, NIST_AES_PLAIN_DATA, NIST_AES_128_CBC_CIPHER, NIST_AES_VECTOR_SIZE }, - { 1, NIST_AES_128_KEY, CC_AES_128_BIT_KEY_SIZE, NIST_AES_CBC_IV, DRV_CRYPTO_DIRECTION_DECRYPT, DRV_CIPHER_CBC, NIST_AES_128_CBC_CIPHER, NIST_AES_PLAIN_DATA, NIST_AES_VECTOR_SIZE }, - { 1, NIST_AES_192_KEY, CC_AES_192_BIT_KEY_SIZE, NIST_AES_CBC_IV, DRV_CRYPTO_DIRECTION_ENCRYPT, DRV_CIPHER_CBC, NIST_AES_PLAIN_DATA, NIST_AES_192_CBC_CIPHER, NIST_AES_VECTOR_SIZE }, - { 1, NIST_AES_192_KEY, CC_AES_192_BIT_KEY_SIZE, NIST_AES_CBC_IV, DRV_CRYPTO_DIRECTION_DECRYPT, DRV_CIPHER_CBC, NIST_AES_192_CBC_CIPHER, NIST_AES_PLAIN_DATA, NIST_AES_VECTOR_SIZE }, - { 1, NIST_AES_256_KEY, CC_AES_256_BIT_KEY_SIZE, NIST_AES_CBC_IV, DRV_CRYPTO_DIRECTION_ENCRYPT, DRV_CIPHER_CBC, NIST_AES_PLAIN_DATA, NIST_AES_256_CBC_CIPHER, NIST_AES_VECTOR_SIZE }, - { 1, NIST_AES_256_KEY, CC_AES_256_BIT_KEY_SIZE, NIST_AES_CBC_IV, DRV_CRYPTO_DIRECTION_DECRYPT, DRV_CIPHER_CBC, NIST_AES_256_CBC_CIPHER, NIST_AES_PLAIN_DATA, NIST_AES_VECTOR_SIZE }, - { 1, NIST_AES_128_KEY, CC_AES_128_BIT_KEY_SIZE, NIST_AES_OFB_IV, DRV_CRYPTO_DIRECTION_ENCRYPT, DRV_CIPHER_OFB, NIST_AES_PLAIN_DATA, NIST_AES_128_OFB_CIPHER, NIST_AES_VECTOR_SIZE }, - { 1, NIST_AES_128_KEY, CC_AES_128_BIT_KEY_SIZE, NIST_AES_OFB_IV, DRV_CRYPTO_DIRECTION_ENCRYPT, DRV_CIPHER_OFB, NIST_AES_128_OFB_CIPHER, NIST_AES_PLAIN_DATA, NIST_AES_VECTOR_SIZE }, - { 1, NIST_AES_192_KEY, CC_AES_192_BIT_KEY_SIZE, NIST_AES_OFB_IV, DRV_CRYPTO_DIRECTION_ENCRYPT, DRV_CIPHER_OFB, NIST_AES_PLAIN_DATA, NIST_AES_192_OFB_CIPHER, NIST_AES_VECTOR_SIZE }, - { 1, NIST_AES_192_KEY, CC_AES_192_BIT_KEY_SIZE, NIST_AES_OFB_IV, DRV_CRYPTO_DIRECTION_DECRYPT, DRV_CIPHER_OFB, NIST_AES_192_OFB_CIPHER, NIST_AES_PLAIN_DATA, NIST_AES_VECTOR_SIZE }, - { 1, NIST_AES_256_KEY, CC_AES_256_BIT_KEY_SIZE, NIST_AES_OFB_IV, DRV_CRYPTO_DIRECTION_ENCRYPT, DRV_CIPHER_OFB, NIST_AES_PLAIN_DATA, NIST_AES_256_OFB_CIPHER, NIST_AES_VECTOR_SIZE }, - { 1, NIST_AES_256_KEY, CC_AES_256_BIT_KEY_SIZE, NIST_AES_OFB_IV, DRV_CRYPTO_DIRECTION_DECRYPT, DRV_CIPHER_OFB, NIST_AES_256_OFB_CIPHER, NIST_AES_PLAIN_DATA, NIST_AES_VECTOR_SIZE }, - { 1, NIST_AES_128_KEY, CC_AES_128_BIT_KEY_SIZE, NIST_AES_CTR_IV, DRV_CRYPTO_DIRECTION_ENCRYPT, DRV_CIPHER_CTR, NIST_AES_PLAIN_DATA, NIST_AES_128_CTR_CIPHER, NIST_AES_VECTOR_SIZE }, - { 1, NIST_AES_128_KEY, CC_AES_128_BIT_KEY_SIZE, NIST_AES_CTR_IV, DRV_CRYPTO_DIRECTION_DECRYPT, DRV_CIPHER_CTR, NIST_AES_128_CTR_CIPHER, NIST_AES_PLAIN_DATA, NIST_AES_VECTOR_SIZE }, - { 1, NIST_AES_192_KEY, CC_AES_192_BIT_KEY_SIZE, NIST_AES_CTR_IV, DRV_CRYPTO_DIRECTION_ENCRYPT, DRV_CIPHER_CTR, NIST_AES_PLAIN_DATA, NIST_AES_192_CTR_CIPHER, NIST_AES_VECTOR_SIZE }, - { 1, NIST_AES_192_KEY, CC_AES_192_BIT_KEY_SIZE, NIST_AES_CTR_IV, DRV_CRYPTO_DIRECTION_DECRYPT, DRV_CIPHER_CTR, NIST_AES_192_CTR_CIPHER, NIST_AES_PLAIN_DATA, NIST_AES_VECTOR_SIZE }, - { 1, NIST_AES_256_KEY, CC_AES_256_BIT_KEY_SIZE, NIST_AES_CTR_IV, DRV_CRYPTO_DIRECTION_ENCRYPT, DRV_CIPHER_CTR, NIST_AES_PLAIN_DATA, NIST_AES_256_CTR_CIPHER, NIST_AES_VECTOR_SIZE }, - { 1, NIST_AES_256_KEY, CC_AES_256_BIT_KEY_SIZE, NIST_AES_CTR_IV, DRV_CRYPTO_DIRECTION_DECRYPT, DRV_CIPHER_CTR, NIST_AES_256_CTR_CIPHER, NIST_AES_PLAIN_DATA, NIST_AES_VECTOR_SIZE }, - { 1, RFC3962_AES_128_KEY, CC_AES_128_BIT_KEY_SIZE, RFC3962_AES_CBC_CTS_IV, DRV_CRYPTO_DIRECTION_ENCRYPT, DRV_CIPHER_CBC_CTS, RFC3962_AES_PLAIN_DATA, RFC3962_AES_128_CBC_CTS_CIPHER, RFC3962_AES_VECTOR_SIZE }, - { 1, RFC3962_AES_128_KEY, CC_AES_128_BIT_KEY_SIZE, RFC3962_AES_CBC_CTS_IV, DRV_CRYPTO_DIRECTION_DECRYPT, DRV_CIPHER_CBC_CTS, RFC3962_AES_128_CBC_CTS_CIPHER, RFC3962_AES_PLAIN_DATA, RFC3962_AES_VECTOR_SIZE }, - { 1, NIST_AES_256_XTS_KEY, CC_AES_256_BIT_KEY_SIZE, NIST_AES_256_XTS_IV, DRV_CRYPTO_DIRECTION_ENCRYPT, DRV_CIPHER_XTS, NIST_AES_256_XTS_PLAIN, NIST_AES_256_XTS_CIPHER, NIST_AES_256_XTS_VECTOR_SIZE }, - { 1, NIST_AES_256_XTS_KEY, CC_AES_256_BIT_KEY_SIZE, NIST_AES_256_XTS_IV, DRV_CRYPTO_DIRECTION_DECRYPT, DRV_CIPHER_XTS, NIST_AES_256_XTS_CIPHER, NIST_AES_256_XTS_PLAIN, NIST_AES_256_XTS_VECTOR_SIZE }, -#if (CC_SUPPORT_SHA > 256) - { 1, NIST_AES_512_XTS_KEY, 2 * CC_AES_256_BIT_KEY_SIZE, NIST_AES_512_XTS_IV, DRV_CRYPTO_DIRECTION_ENCRYPT, DRV_CIPHER_XTS, NIST_AES_512_XTS_PLAIN, NIST_AES_512_XTS_CIPHER, NIST_AES_512_XTS_VECTOR_SIZE }, - { 1, NIST_AES_512_XTS_KEY, 2 * CC_AES_256_BIT_KEY_SIZE, NIST_AES_512_XTS_IV, DRV_CRYPTO_DIRECTION_DECRYPT, DRV_CIPHER_XTS, NIST_AES_512_XTS_CIPHER, NIST_AES_512_XTS_PLAIN, NIST_AES_512_XTS_VECTOR_SIZE }, -#endif - /* DES */ - { 0, NIST_TDES_ECB3_KEY, CC_DRV_DES_TRIPLE_KEY_SIZE, NIST_TDES_ECB_IV, DRV_CRYPTO_DIRECTION_ENCRYPT, DRV_CIPHER_ECB, NIST_TDES_ECB3_PLAIN_DATA, NIST_TDES_ECB3_CIPHER, NIST_TDES_VECTOR_SIZE }, - { 0, NIST_TDES_ECB3_KEY, CC_DRV_DES_TRIPLE_KEY_SIZE, NIST_TDES_ECB_IV, DRV_CRYPTO_DIRECTION_DECRYPT, DRV_CIPHER_ECB, NIST_TDES_ECB3_CIPHER, NIST_TDES_ECB3_PLAIN_DATA, NIST_TDES_VECTOR_SIZE }, - { 0, NIST_TDES_CBC3_KEY, CC_DRV_DES_TRIPLE_KEY_SIZE, NIST_TDES_CBC3_IV, DRV_CRYPTO_DIRECTION_ENCRYPT, DRV_CIPHER_CBC, NIST_TDES_CBC3_PLAIN_DATA, NIST_TDES_CBC3_CIPHER, NIST_TDES_VECTOR_SIZE }, - { 0, NIST_TDES_CBC3_KEY, CC_DRV_DES_TRIPLE_KEY_SIZE, NIST_TDES_CBC3_IV, DRV_CRYPTO_DIRECTION_DECRYPT, DRV_CIPHER_CBC, NIST_TDES_CBC3_CIPHER, NIST_TDES_CBC3_PLAIN_DATA, NIST_TDES_VECTOR_SIZE }, -}; - -#define FIPS_CIPHER_NUM_OF_TESTS (sizeof(FipsCipherDataTable) / sizeof(FipsCipherData)) - -static const FipsCmacData FipsCmacDataTable[] = { - { DRV_CRYPTO_DIRECTION_ENCRYPT, NIST_AES_128_CMAC_KEY, AES_128_BIT_KEY_SIZE, NIST_AES_128_CMAC_PLAIN_DATA, NIST_AES_128_CMAC_VECTOR_SIZE, NIST_AES_128_CMAC_MAC, NIST_AES_128_CMAC_OUTPUT_SIZE }, - { DRV_CRYPTO_DIRECTION_ENCRYPT, NIST_AES_192_CMAC_KEY, AES_192_BIT_KEY_SIZE, NIST_AES_192_CMAC_PLAIN_DATA, NIST_AES_192_CMAC_VECTOR_SIZE, NIST_AES_192_CMAC_MAC, NIST_AES_192_CMAC_OUTPUT_SIZE }, - { DRV_CRYPTO_DIRECTION_ENCRYPT, NIST_AES_256_CMAC_KEY, AES_256_BIT_KEY_SIZE, NIST_AES_256_CMAC_PLAIN_DATA, NIST_AES_256_CMAC_VECTOR_SIZE, NIST_AES_256_CMAC_MAC, NIST_AES_256_CMAC_OUTPUT_SIZE }, -}; - -#define FIPS_CMAC_NUM_OF_TESTS (sizeof(FipsCmacDataTable) / sizeof(FipsCmacData)) - -static const FipsHashData FipsHashDataTable[] = { - { DRV_HASH_SHA1, NIST_SHA_1_MSG, NIST_SHA_MSG_SIZE, NIST_SHA_1_MD }, - { DRV_HASH_SHA256, NIST_SHA_256_MSG, NIST_SHA_MSG_SIZE, NIST_SHA_256_MD }, -#if (CC_SUPPORT_SHA > 256) -// { DRV_HASH_SHA512, NIST_SHA_512_MSG, NIST_SHA_MSG_SIZE, NIST_SHA_512_MD }, -#endif -}; - -#define FIPS_HASH_NUM_OF_TESTS (sizeof(FipsHashDataTable) / sizeof(FipsHashData)) - -static const FipsHmacData FipsHmacDataTable[] = { - { DRV_HASH_SHA1, NIST_HMAC_SHA1_KEY, NIST_HMAC_SHA1_KEY_SIZE, NIST_HMAC_SHA1_MSG, NIST_HMAC_MSG_SIZE, NIST_HMAC_SHA1_MD }, - { DRV_HASH_SHA256, NIST_HMAC_SHA256_KEY, NIST_HMAC_SHA256_KEY_SIZE, NIST_HMAC_SHA256_MSG, NIST_HMAC_MSG_SIZE, NIST_HMAC_SHA256_MD }, -#if (CC_SUPPORT_SHA > 256) -// { DRV_HASH_SHA512, NIST_HMAC_SHA512_KEY, NIST_HMAC_SHA512_KEY_SIZE, NIST_HMAC_SHA512_MSG, NIST_HMAC_MSG_SIZE, NIST_HMAC_SHA512_MD }, -#endif -}; - -#define FIPS_HMAC_NUM_OF_TESTS (sizeof(FipsHmacDataTable) / sizeof(FipsHmacData)) - -static const FipsCcmData FipsCcmDataTable[] = { - { DRV_CRYPTO_DIRECTION_ENCRYPT, NIST_AESCCM_128_KEY, NIST_AESCCM_128_BIT_KEY_SIZE, NIST_AESCCM_128_NONCE, NIST_AESCCM_128_ADATA, NIST_AESCCM_ADATA_SIZE, NIST_AESCCM_128_PLAIN_TEXT, NIST_AESCCM_TEXT_SIZE, NIST_AESCCM_128_CIPHER, NIST_AESCCM_TAG_SIZE, NIST_AESCCM_128_MAC }, - { DRV_CRYPTO_DIRECTION_DECRYPT, NIST_AESCCM_128_KEY, NIST_AESCCM_128_BIT_KEY_SIZE, NIST_AESCCM_128_NONCE, NIST_AESCCM_128_ADATA, NIST_AESCCM_ADATA_SIZE, NIST_AESCCM_128_CIPHER, NIST_AESCCM_TEXT_SIZE, NIST_AESCCM_128_PLAIN_TEXT, NIST_AESCCM_TAG_SIZE, NIST_AESCCM_128_MAC }, - { DRV_CRYPTO_DIRECTION_ENCRYPT, NIST_AESCCM_192_KEY, NIST_AESCCM_192_BIT_KEY_SIZE, NIST_AESCCM_192_NONCE, NIST_AESCCM_192_ADATA, NIST_AESCCM_ADATA_SIZE, NIST_AESCCM_192_PLAIN_TEXT, NIST_AESCCM_TEXT_SIZE, NIST_AESCCM_192_CIPHER, NIST_AESCCM_TAG_SIZE, NIST_AESCCM_192_MAC }, - { DRV_CRYPTO_DIRECTION_DECRYPT, NIST_AESCCM_192_KEY, NIST_AESCCM_192_BIT_KEY_SIZE, NIST_AESCCM_192_NONCE, NIST_AESCCM_192_ADATA, NIST_AESCCM_ADATA_SIZE, NIST_AESCCM_192_CIPHER, NIST_AESCCM_TEXT_SIZE, NIST_AESCCM_192_PLAIN_TEXT, NIST_AESCCM_TAG_SIZE, NIST_AESCCM_192_MAC }, - { DRV_CRYPTO_DIRECTION_ENCRYPT, NIST_AESCCM_256_KEY, NIST_AESCCM_256_BIT_KEY_SIZE, NIST_AESCCM_256_NONCE, NIST_AESCCM_256_ADATA, NIST_AESCCM_ADATA_SIZE, NIST_AESCCM_256_PLAIN_TEXT, NIST_AESCCM_TEXT_SIZE, NIST_AESCCM_256_CIPHER, NIST_AESCCM_TAG_SIZE, NIST_AESCCM_256_MAC }, - { DRV_CRYPTO_DIRECTION_DECRYPT, NIST_AESCCM_256_KEY, NIST_AESCCM_256_BIT_KEY_SIZE, NIST_AESCCM_256_NONCE, NIST_AESCCM_256_ADATA, NIST_AESCCM_ADATA_SIZE, NIST_AESCCM_256_CIPHER, NIST_AESCCM_TEXT_SIZE, NIST_AESCCM_256_PLAIN_TEXT, NIST_AESCCM_TAG_SIZE, NIST_AESCCM_256_MAC }, -}; - -#define FIPS_CCM_NUM_OF_TESTS (sizeof(FipsCcmDataTable) / sizeof(FipsCcmData)) - -static const FipsGcmData FipsGcmDataTable[] = { - { DRV_CRYPTO_DIRECTION_ENCRYPT, NIST_AESGCM_128_KEY, NIST_AESGCM_128_BIT_KEY_SIZE, NIST_AESGCM_128_IV, NIST_AESGCM_128_ADATA, NIST_AESGCM_ADATA_SIZE, NIST_AESGCM_128_PLAIN_TEXT, NIST_AESGCM_TEXT_SIZE, NIST_AESGCM_128_CIPHER, NIST_AESGCM_TAG_SIZE, NIST_AESGCM_128_MAC }, - { DRV_CRYPTO_DIRECTION_DECRYPT, NIST_AESGCM_128_KEY, NIST_AESGCM_128_BIT_KEY_SIZE, NIST_AESGCM_128_IV, NIST_AESGCM_128_ADATA, NIST_AESGCM_ADATA_SIZE, NIST_AESGCM_128_CIPHER, NIST_AESGCM_TEXT_SIZE, NIST_AESGCM_128_PLAIN_TEXT, NIST_AESGCM_TAG_SIZE, NIST_AESGCM_128_MAC }, - { DRV_CRYPTO_DIRECTION_ENCRYPT, NIST_AESGCM_192_KEY, NIST_AESGCM_192_BIT_KEY_SIZE, NIST_AESGCM_192_IV, NIST_AESGCM_192_ADATA, NIST_AESGCM_ADATA_SIZE, NIST_AESGCM_192_PLAIN_TEXT, NIST_AESGCM_TEXT_SIZE, NIST_AESGCM_192_CIPHER, NIST_AESGCM_TAG_SIZE, NIST_AESGCM_192_MAC }, - { DRV_CRYPTO_DIRECTION_DECRYPT, NIST_AESGCM_192_KEY, NIST_AESGCM_192_BIT_KEY_SIZE, NIST_AESGCM_192_IV, NIST_AESGCM_192_ADATA, NIST_AESGCM_ADATA_SIZE, NIST_AESGCM_192_CIPHER, NIST_AESGCM_TEXT_SIZE, NIST_AESGCM_192_PLAIN_TEXT, NIST_AESGCM_TAG_SIZE, NIST_AESGCM_192_MAC }, - { DRV_CRYPTO_DIRECTION_ENCRYPT, NIST_AESGCM_256_KEY, NIST_AESGCM_256_BIT_KEY_SIZE, NIST_AESGCM_256_IV, NIST_AESGCM_256_ADATA, NIST_AESGCM_ADATA_SIZE, NIST_AESGCM_256_PLAIN_TEXT, NIST_AESGCM_TEXT_SIZE, NIST_AESGCM_256_CIPHER, NIST_AESGCM_TAG_SIZE, NIST_AESGCM_256_MAC }, - { DRV_CRYPTO_DIRECTION_DECRYPT, NIST_AESGCM_256_KEY, NIST_AESGCM_256_BIT_KEY_SIZE, NIST_AESGCM_256_IV, NIST_AESGCM_256_ADATA, NIST_AESGCM_ADATA_SIZE, NIST_AESGCM_256_CIPHER, NIST_AESGCM_TEXT_SIZE, NIST_AESGCM_256_PLAIN_TEXT, NIST_AESGCM_TAG_SIZE, NIST_AESGCM_256_MAC }, -}; - -#define FIPS_GCM_NUM_OF_TESTS (sizeof(FipsGcmDataTable) / sizeof(FipsGcmData)) - -static inline enum cc_fips_error -FIPS_CipherToFipsError(enum drv_cipher_mode mode, bool is_aes) -{ - switch (mode) - { - case DRV_CIPHER_ECB: - return is_aes ? CC_REE_FIPS_ERROR_AES_ECB_PUT : CC_REE_FIPS_ERROR_DES_ECB_PUT; - case DRV_CIPHER_CBC: - return is_aes ? CC_REE_FIPS_ERROR_AES_CBC_PUT : CC_REE_FIPS_ERROR_DES_CBC_PUT; - case DRV_CIPHER_OFB: - return CC_REE_FIPS_ERROR_AES_OFB_PUT; - case DRV_CIPHER_CTR: - return CC_REE_FIPS_ERROR_AES_CTR_PUT; - case DRV_CIPHER_CBC_CTS: - return CC_REE_FIPS_ERROR_AES_CBC_CTS_PUT; - case DRV_CIPHER_XTS: - return CC_REE_FIPS_ERROR_AES_XTS_PUT; - default: - return CC_REE_FIPS_ERROR_GENERAL; - } - - return CC_REE_FIPS_ERROR_GENERAL; -} - -static inline int -ssi_cipher_fips_run_test(struct ssi_drvdata *drvdata, - bool is_aes, - int cipher_mode, - int direction, - dma_addr_t key_dma_addr, - size_t key_len, - dma_addr_t iv_dma_addr, - size_t iv_len, - dma_addr_t din_dma_addr, - dma_addr_t dout_dma_addr, - size_t data_size) -{ - /* max number of descriptors used for the flow */ - #define FIPS_CIPHER_MAX_SEQ_LEN 6 - - int rc; - struct ssi_crypto_req ssi_req = {0}; - struct cc_hw_desc desc[FIPS_CIPHER_MAX_SEQ_LEN]; - int idx = 0; - int s_flow_mode = is_aes ? S_DIN_to_AES : S_DIN_to_DES; - - /* create setup descriptors */ - switch (cipher_mode) { - case DRV_CIPHER_CBC: - case DRV_CIPHER_CBC_CTS: - case DRV_CIPHER_CTR: - case DRV_CIPHER_OFB: - /* Load cipher state */ - hw_desc_init(&desc[idx]); - set_din_type(&desc[idx], DMA_DLLI, - iv_dma_addr, iv_len, NS_BIT); - set_cipher_config0(&desc[idx], direction); - set_flow_mode(&desc[idx], s_flow_mode); - set_cipher_mode(&desc[idx], cipher_mode); - if ((cipher_mode == DRV_CIPHER_CTR) || - (cipher_mode == DRV_CIPHER_OFB)) { - set_setup_mode(&desc[idx], SETUP_LOAD_STATE1); - } else { - set_setup_mode(&desc[idx], SETUP_LOAD_STATE0); - } - idx++; - /*FALLTHROUGH*/ - case DRV_CIPHER_ECB: - /* Load key */ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], cipher_mode); - set_cipher_config0(&desc[idx], direction); - if (is_aes) { - set_din_type(&desc[idx], DMA_DLLI, key_dma_addr, - ((key_len == 24) ? AES_MAX_KEY_SIZE : - key_len), NS_BIT); - set_key_size_aes(&desc[idx], key_len); - } else {/*des*/ - set_din_type(&desc[idx], DMA_DLLI, key_dma_addr, - key_len, NS_BIT); - set_key_size_des(&desc[idx], key_len); - } - set_flow_mode(&desc[idx], s_flow_mode); - set_setup_mode(&desc[idx], SETUP_LOAD_KEY0); - idx++; - break; - case DRV_CIPHER_XTS: - /* Load AES key */ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], cipher_mode); - set_cipher_config0(&desc[idx], direction); - set_din_type(&desc[idx], DMA_DLLI, key_dma_addr, (key_len / 2), - NS_BIT); - set_key_size_aes(&desc[idx], (key_len / 2)); - set_flow_mode(&desc[idx], s_flow_mode); - set_setup_mode(&desc[idx], SETUP_LOAD_KEY0); - idx++; - - /* load XEX key */ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], cipher_mode); - set_cipher_config0(&desc[idx], direction); - set_din_type(&desc[idx], DMA_DLLI, - (key_dma_addr + (key_len / 2)), - (key_len / 2), NS_BIT); - set_xex_data_unit_size(&desc[idx], data_size); - set_flow_mode(&desc[idx], s_flow_mode); - set_key_size_aes(&desc[idx], (key_len / 2)); - set_setup_mode(&desc[idx], SETUP_LOAD_XEX_KEY); - idx++; - - /* Set state */ - hw_desc_init(&desc[idx]); - set_setup_mode(&desc[idx], SETUP_LOAD_STATE1); - set_cipher_mode(&desc[idx], cipher_mode); - set_cipher_config0(&desc[idx], direction); - set_key_size_aes(&desc[idx], (key_len / 2)); - set_flow_mode(&desc[idx], s_flow_mode); - set_din_type(&desc[idx], DMA_DLLI, iv_dma_addr, - CC_AES_BLOCK_SIZE, NS_BIT); - idx++; - break; - default: - FIPS_LOG("Unsupported cipher mode (%d)\n", cipher_mode); - BUG(); - } - - /* create data descriptor */ - hw_desc_init(&desc[idx]); - set_din_type(&desc[idx], DMA_DLLI, din_dma_addr, data_size, NS_BIT); - set_dout_dlli(&desc[idx], dout_dma_addr, data_size, NS_BIT, 0); - set_flow_mode(&desc[idx], is_aes ? DIN_AES_DOUT : DIN_DES_DOUT); - idx++; - - /* perform the operation - Lock HW and push sequence */ - BUG_ON(idx > FIPS_CIPHER_MAX_SEQ_LEN); - rc = send_request(drvdata, &ssi_req, desc, idx, false); - - // send_request returns error just in some corner cases which should not appear in this flow. - return rc; -} - -enum cc_fips_error -ssi_cipher_fips_power_up_tests(struct ssi_drvdata *drvdata, void *cpu_addr_buffer, dma_addr_t dma_coherent_buffer) -{ - enum cc_fips_error error = CC_REE_FIPS_ERROR_OK; - size_t i; - struct fips_cipher_ctx *virt_ctx = (struct fips_cipher_ctx *)cpu_addr_buffer; - - /* set the phisical pointers for iv, key, din, dout */ - dma_addr_t iv_dma_addr = dma_coherent_buffer + offsetof(struct fips_cipher_ctx, iv); - dma_addr_t key_dma_addr = dma_coherent_buffer + offsetof(struct fips_cipher_ctx, key); - dma_addr_t din_dma_addr = dma_coherent_buffer + offsetof(struct fips_cipher_ctx, din); - dma_addr_t dout_dma_addr = dma_coherent_buffer + offsetof(struct fips_cipher_ctx, dout); - - for (i = 0; i < FIPS_CIPHER_NUM_OF_TESTS; ++i) - { - FipsCipherData *cipherData = (FipsCipherData *)&FipsCipherDataTable[i]; - int rc = 0; - size_t iv_size = cipherData->isAes ? NIST_AES_IV_SIZE : NIST_TDES_IV_SIZE; - - memset(cpu_addr_buffer, 0, sizeof(struct fips_cipher_ctx)); - - /* copy into the allocated buffer */ - memcpy(virt_ctx->iv, cipherData->iv, iv_size); - memcpy(virt_ctx->key, cipherData->key, cipherData->keySize); - memcpy(virt_ctx->din, cipherData->dataIn, cipherData->dataInSize); - - FIPS_DBG("ssi_cipher_fips_run_test - (i = %d) \n", i); - rc = ssi_cipher_fips_run_test(drvdata, - cipherData->isAes, - cipherData->oprMode, - cipherData->direction, - key_dma_addr, - cipherData->keySize, - iv_dma_addr, - iv_size, - din_dma_addr, - dout_dma_addr, - cipherData->dataInSize); - if (rc != 0) - { - FIPS_LOG("ssi_cipher_fips_run_test %d returned error - rc = %d \n", i, rc); - error = FIPS_CipherToFipsError(cipherData->oprMode, cipherData->isAes); - break; - } - - /* compare actual dout to expected */ - if (memcmp(virt_ctx->dout, cipherData->dataOut, cipherData->dataInSize) != 0) - { - FIPS_LOG("dout comparison error %d - oprMode=%d, isAes=%d\n", i, cipherData->oprMode, cipherData->isAes); - FIPS_LOG(" i expected received \n"); - FIPS_LOG(" i 0x%08x 0x%08x (size=%d) \n", (size_t)cipherData->dataOut, (size_t)virt_ctx->dout, cipherData->dataInSize); - for (i = 0; i < cipherData->dataInSize; ++i) - { - FIPS_LOG(" %d 0x%02x 0x%02x \n", i, cipherData->dataOut[i], virt_ctx->dout[i]); - } - - error = FIPS_CipherToFipsError(cipherData->oprMode, cipherData->isAes); - break; - } - } - - return error; -} - -static inline int -ssi_cmac_fips_run_test(struct ssi_drvdata *drvdata, - dma_addr_t key_dma_addr, - size_t key_len, - dma_addr_t din_dma_addr, - size_t din_len, - dma_addr_t digest_dma_addr, - size_t digest_len) -{ - /* max number of descriptors used for the flow */ - #define FIPS_CMAC_MAX_SEQ_LEN 4 - - int rc; - struct ssi_crypto_req ssi_req = {0}; - struct cc_hw_desc desc[FIPS_CMAC_MAX_SEQ_LEN]; - int idx = 0; - - /* Setup CMAC Key */ - hw_desc_init(&desc[idx]); - set_din_type(&desc[idx], DMA_DLLI, key_dma_addr, - ((key_len == 24) ? AES_MAX_KEY_SIZE : key_len), NS_BIT); - set_setup_mode(&desc[idx], SETUP_LOAD_KEY0); - set_cipher_mode(&desc[idx], DRV_CIPHER_CMAC); - set_cipher_config0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT); - set_key_size_aes(&desc[idx], key_len); - set_flow_mode(&desc[idx], S_DIN_to_AES); - idx++; - - /* Load MAC state */ - hw_desc_init(&desc[idx]); - set_din_type(&desc[idx], DMA_DLLI, digest_dma_addr, CC_AES_BLOCK_SIZE, - NS_BIT); - set_setup_mode(&desc[idx], SETUP_LOAD_STATE0); - set_cipher_mode(&desc[idx], DRV_CIPHER_CMAC); - set_cipher_config0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT); - set_key_size_aes(&desc[idx], key_len); - set_flow_mode(&desc[idx], S_DIN_to_AES); - idx++; - - //ssi_hash_create_data_desc(state, ctx, DIN_AES_DOUT, desc, false, &idx); - hw_desc_init(&desc[idx]); - set_din_type(&desc[idx], DMA_DLLI, din_dma_addr, din_len, NS_BIT); - set_flow_mode(&desc[idx], DIN_AES_DOUT); - idx++; - - /* Get final MAC result */ - hw_desc_init(&desc[idx]); - set_dout_dlli(&desc[idx], digest_dma_addr, CC_AES_BLOCK_SIZE, NS_BIT, - 0); - set_flow_mode(&desc[idx], S_AES_to_DOUT); - set_setup_mode(&desc[idx], SETUP_WRITE_STATE0); - set_cipher_config0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT); - set_cipher_mode(&desc[idx], DRV_CIPHER_CMAC); - idx++; - - /* perform the operation - Lock HW and push sequence */ - BUG_ON(idx > FIPS_CMAC_MAX_SEQ_LEN); - rc = send_request(drvdata, &ssi_req, desc, idx, false); - - // send_request returns error just in some corner cases which should not appear in this flow. - return rc; -} - -enum cc_fips_error -ssi_cmac_fips_power_up_tests(struct ssi_drvdata *drvdata, void *cpu_addr_buffer, dma_addr_t dma_coherent_buffer) -{ - enum cc_fips_error error = CC_REE_FIPS_ERROR_OK; - size_t i; - struct fips_cmac_ctx *virt_ctx = (struct fips_cmac_ctx *)cpu_addr_buffer; - - /* set the phisical pointers for key, din, dout */ - dma_addr_t key_dma_addr = dma_coherent_buffer + offsetof(struct fips_cmac_ctx, key); - dma_addr_t din_dma_addr = dma_coherent_buffer + offsetof(struct fips_cmac_ctx, din); - dma_addr_t mac_res_dma_addr = dma_coherent_buffer + offsetof(struct fips_cmac_ctx, mac_res); - - for (i = 0; i < FIPS_CMAC_NUM_OF_TESTS; ++i) - { - FipsCmacData *cmac_data = (FipsCmacData *)&FipsCmacDataTable[i]; - int rc = 0; - - memset(cpu_addr_buffer, 0, sizeof(struct fips_cmac_ctx)); - - /* copy into the allocated buffer */ - memcpy(virt_ctx->key, cmac_data->key, cmac_data->key_size); - memcpy(virt_ctx->din, cmac_data->data_in, cmac_data->data_in_size); - - BUG_ON(cmac_data->direction != DRV_CRYPTO_DIRECTION_ENCRYPT); - - FIPS_DBG("ssi_cmac_fips_run_test - (i = %d) \n", i); - rc = ssi_cmac_fips_run_test(drvdata, - key_dma_addr, - cmac_data->key_size, - din_dma_addr, - cmac_data->data_in_size, - mac_res_dma_addr, - cmac_data->mac_res_size); - if (rc != 0) - { - FIPS_LOG("ssi_cmac_fips_run_test %d returned error - rc = %d \n", i, rc); - error = CC_REE_FIPS_ERROR_AES_CMAC_PUT; - break; - } - - /* compare actual mac result to expected */ - if (memcmp(virt_ctx->mac_res, cmac_data->mac_res, cmac_data->mac_res_size) != 0) - { - FIPS_LOG("comparison error %d - digest_size=%d \n", i, cmac_data->mac_res_size); - FIPS_LOG(" i expected received \n"); - FIPS_LOG(" i 0x%08x 0x%08x \n", (size_t)cmac_data->mac_res, (size_t)virt_ctx->mac_res); - for (i = 0; i < cmac_data->mac_res_size; ++i) - { - FIPS_LOG(" %d 0x%02x 0x%02x \n", i, cmac_data->mac_res[i], virt_ctx->mac_res[i]); - } - - error = CC_REE_FIPS_ERROR_AES_CMAC_PUT; - break; - } - } - - return error; -} - -static inline enum cc_fips_error -FIPS_HashToFipsError(enum drv_hash_mode hash_mode) -{ - switch (hash_mode) { - case DRV_HASH_SHA1: - return CC_REE_FIPS_ERROR_SHA1_PUT; - case DRV_HASH_SHA256: - return CC_REE_FIPS_ERROR_SHA256_PUT; -#if (CC_SUPPORT_SHA > 256) - case DRV_HASH_SHA512: - return CC_REE_FIPS_ERROR_SHA512_PUT; -#endif - default: - return CC_REE_FIPS_ERROR_GENERAL; - } - - return CC_REE_FIPS_ERROR_GENERAL; -} - -static inline int -ssi_hash_fips_run_test(struct ssi_drvdata *drvdata, - dma_addr_t initial_digest_dma_addr, - dma_addr_t din_dma_addr, - size_t data_in_size, - dma_addr_t mac_res_dma_addr, - enum drv_hash_mode hash_mode, - enum drv_hash_hw_mode hw_mode, - int digest_size, - int inter_digestsize) -{ - /* max number of descriptors used for the flow */ - #define FIPS_HASH_MAX_SEQ_LEN 4 - - int rc; - struct ssi_crypto_req ssi_req = {0}; - struct cc_hw_desc desc[FIPS_HASH_MAX_SEQ_LEN]; - int idx = 0; - - /* Load initial digest */ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], hw_mode); - set_din_type(&desc[idx], DMA_DLLI, initial_digest_dma_addr, - inter_digestsize, NS_BIT); - set_flow_mode(&desc[idx], S_DIN_to_HASH); - set_setup_mode(&desc[idx], SETUP_LOAD_STATE0); - idx++; - - /* Load the hash current length */ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], hw_mode); - set_din_const(&desc[idx], 0, HASH_LEN_SIZE); - set_cipher_config1(&desc[idx], HASH_PADDING_ENABLED); - set_flow_mode(&desc[idx], S_DIN_to_HASH); - set_setup_mode(&desc[idx], SETUP_LOAD_KEY0); - idx++; - - /* data descriptor */ - hw_desc_init(&desc[idx]); - set_din_type(&desc[idx], DMA_DLLI, din_dma_addr, data_in_size, NS_BIT); - set_flow_mode(&desc[idx], DIN_HASH); - idx++; - - /* Get final MAC result */ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], hw_mode); - set_dout_dlli(&desc[idx], mac_res_dma_addr, digest_size, NS_BIT, 0); - set_flow_mode(&desc[idx], S_HASH_to_DOUT); - set_setup_mode(&desc[idx], SETUP_WRITE_STATE0); - set_cipher_config1(&desc[idx], HASH_PADDING_DISABLED); - if (unlikely((hash_mode == DRV_HASH_MD5) || - (hash_mode == DRV_HASH_SHA384) || - (hash_mode == DRV_HASH_SHA512))) { - set_bytes_swap(&desc[idx], 1); - } else { - set_cipher_config0(&desc[idx], - HASH_DIGEST_RESULT_LITTLE_ENDIAN); - } - idx++; - - /* perform the operation - Lock HW and push sequence */ - BUG_ON(idx > FIPS_HASH_MAX_SEQ_LEN); - rc = send_request(drvdata, &ssi_req, desc, idx, false); - - return rc; -} - -enum cc_fips_error -ssi_hash_fips_power_up_tests(struct ssi_drvdata *drvdata, void *cpu_addr_buffer, dma_addr_t dma_coherent_buffer) -{ - enum cc_fips_error error = CC_REE_FIPS_ERROR_OK; - size_t i; - struct fips_hash_ctx *virt_ctx = (struct fips_hash_ctx *)cpu_addr_buffer; - - /* set the phisical pointers for initial_digest, din, mac_res */ - dma_addr_t initial_digest_dma_addr = dma_coherent_buffer + offsetof(struct fips_hash_ctx, initial_digest); - dma_addr_t din_dma_addr = dma_coherent_buffer + offsetof(struct fips_hash_ctx, din); - dma_addr_t mac_res_dma_addr = dma_coherent_buffer + offsetof(struct fips_hash_ctx, mac_res); - - for (i = 0; i < FIPS_HASH_NUM_OF_TESTS; ++i) - { - FipsHashData *hash_data = (FipsHashData *)&FipsHashDataTable[i]; - int rc = 0; - enum drv_hash_hw_mode hw_mode = 0; - int digest_size = 0; - int inter_digestsize = 0; - - memset(cpu_addr_buffer, 0, sizeof(struct fips_hash_ctx)); - - switch (hash_data->hash_mode) { - case DRV_HASH_SHA1: - hw_mode = DRV_HASH_HW_SHA1; - digest_size = CC_SHA1_DIGEST_SIZE; - inter_digestsize = CC_SHA1_DIGEST_SIZE; - /* copy the initial digest into the allocated cache coherent buffer */ - memcpy(virt_ctx->initial_digest, (void *)sha1_init, CC_SHA1_DIGEST_SIZE); - break; - case DRV_HASH_SHA256: - hw_mode = DRV_HASH_HW_SHA256; - digest_size = CC_SHA256_DIGEST_SIZE; - inter_digestsize = CC_SHA256_DIGEST_SIZE; - memcpy(virt_ctx->initial_digest, (void *)sha256_init, CC_SHA256_DIGEST_SIZE); - break; -#if (CC_SUPPORT_SHA > 256) - case DRV_HASH_SHA512: - hw_mode = DRV_HASH_HW_SHA512; - digest_size = CC_SHA512_DIGEST_SIZE; - inter_digestsize = CC_SHA512_DIGEST_SIZE; - memcpy(virt_ctx->initial_digest, (void *)sha512_init, CC_SHA512_DIGEST_SIZE); - break; -#endif - default: - error = FIPS_HashToFipsError(hash_data->hash_mode); - break; - } - - /* copy the din data into the allocated buffer */ - memcpy(virt_ctx->din, hash_data->data_in, hash_data->data_in_size); - - /* run the test on HW */ - FIPS_DBG("ssi_hash_fips_run_test - (i = %d) \n", i); - rc = ssi_hash_fips_run_test(drvdata, - initial_digest_dma_addr, - din_dma_addr, - hash_data->data_in_size, - mac_res_dma_addr, - hash_data->hash_mode, - hw_mode, - digest_size, - inter_digestsize); - if (rc != 0) - { - FIPS_LOG("ssi_hash_fips_run_test %d returned error - rc = %d \n", i, rc); - error = FIPS_HashToFipsError(hash_data->hash_mode); - break; - } - - /* compare actual mac result to expected */ - if (memcmp(virt_ctx->mac_res, hash_data->mac_res, digest_size) != 0) - { - FIPS_LOG("comparison error %d - hash_mode=%d digest_size=%d \n", i, hash_data->hash_mode, digest_size); - FIPS_LOG(" i expected received \n"); - FIPS_LOG(" i 0x%08x 0x%08x \n", (size_t)hash_data->mac_res, (size_t)virt_ctx->mac_res); - for (i = 0; i < digest_size; ++i) - { - FIPS_LOG(" %d 0x%02x 0x%02x \n", i, hash_data->mac_res[i], virt_ctx->mac_res[i]); - } - - error = FIPS_HashToFipsError(hash_data->hash_mode); - break; - } - } - - return error; -} - -static inline enum cc_fips_error -FIPS_HmacToFipsError(enum drv_hash_mode hash_mode) -{ - switch (hash_mode) { - case DRV_HASH_SHA1: - return CC_REE_FIPS_ERROR_HMAC_SHA1_PUT; - case DRV_HASH_SHA256: - return CC_REE_FIPS_ERROR_HMAC_SHA256_PUT; -#if (CC_SUPPORT_SHA > 256) - case DRV_HASH_SHA512: - return CC_REE_FIPS_ERROR_HMAC_SHA512_PUT; -#endif - default: - return CC_REE_FIPS_ERROR_GENERAL; - } - - return CC_REE_FIPS_ERROR_GENERAL; -} - -static inline int -ssi_hmac_fips_run_test(struct ssi_drvdata *drvdata, - dma_addr_t initial_digest_dma_addr, - dma_addr_t key_dma_addr, - size_t key_size, - dma_addr_t din_dma_addr, - size_t data_in_size, - dma_addr_t mac_res_dma_addr, - enum drv_hash_mode hash_mode, - enum drv_hash_hw_mode hw_mode, - size_t digest_size, - size_t inter_digestsize, - size_t block_size, - dma_addr_t k0_dma_addr, - dma_addr_t tmp_digest_dma_addr, - dma_addr_t digest_bytes_len_dma_addr) -{ - /* The implemented flow is not the same as the one implemented in ssi_hash.c (setkey + digest flows). - * In this flow, there is no need to store and reload some of the intermidiate results. - */ - - /* max number of descriptors used for the flow */ - #define FIPS_HMAC_MAX_SEQ_LEN 12 - - int rc; - struct ssi_crypto_req ssi_req = {0}; - struct cc_hw_desc desc[FIPS_HMAC_MAX_SEQ_LEN]; - int idx = 0; - int i; - /* calc the hash opad first and ipad only afterwards (unlike the flow in ssi_hash.c) */ - unsigned int hmacPadConst[2] = { HMAC_OPAD_CONST, HMAC_IPAD_CONST }; - - // assume (key_size <= block_size) - hw_desc_init(&desc[idx]); - set_din_type(&desc[idx], DMA_DLLI, key_dma_addr, key_size, NS_BIT); - set_flow_mode(&desc[idx], BYPASS); - set_dout_dlli(&desc[idx], k0_dma_addr, key_size, NS_BIT, 0); - idx++; - - // if needed, append Key with zeros to create K0 - if ((block_size - key_size) != 0) { - hw_desc_init(&desc[idx]); - set_din_const(&desc[idx], 0, (block_size - key_size)); - set_flow_mode(&desc[idx], BYPASS); - set_dout_dlli(&desc[idx], (k0_dma_addr + key_size), - (block_size - key_size), NS_BIT, 0); - idx++; - } - - BUG_ON(idx > FIPS_HMAC_MAX_SEQ_LEN); - rc = send_request(drvdata, &ssi_req, desc, idx, 0); - if (unlikely(rc != 0)) { - SSI_LOG_ERR("send_request() failed (rc=%d)\n", rc); - return rc; - } - idx = 0; - - /* calc derived HMAC key */ - for (i = 0; i < 2; i++) { - /* Load hash initial state */ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], hw_mode); - set_din_type(&desc[idx], DMA_DLLI, initial_digest_dma_addr, - inter_digestsize, NS_BIT); - set_flow_mode(&desc[idx], S_DIN_to_HASH); - set_setup_mode(&desc[idx], SETUP_LOAD_STATE0); - idx++; - - /* Load the hash current length*/ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], hw_mode); - set_din_const(&desc[idx], 0, HASH_LEN_SIZE); - set_flow_mode(&desc[idx], S_DIN_to_HASH); - set_setup_mode(&desc[idx], SETUP_LOAD_KEY0); - idx++; - - /* Prepare opad/ipad key */ - hw_desc_init(&desc[idx]); - set_xor_val(&desc[idx], hmacPadConst[i]); - set_cipher_mode(&desc[idx], hw_mode); - set_flow_mode(&desc[idx], S_DIN_to_HASH); - set_setup_mode(&desc[idx], SETUP_LOAD_STATE1); - idx++; - - /* Perform HASH update */ - hw_desc_init(&desc[idx]); - set_din_type(&desc[idx], DMA_DLLI, k0_dma_addr, block_size, - NS_BIT); - set_cipher_mode(&desc[idx], hw_mode); - set_xor_active(&desc[idx]); - set_flow_mode(&desc[idx], DIN_HASH); - idx++; - - if (i == 0) { - /* First iteration - calc H(K0^opad) into tmp_digest_dma_addr */ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], hw_mode); - set_dout_dlli(&desc[idx], tmp_digest_dma_addr, - inter_digestsize, NS_BIT, 0); - set_flow_mode(&desc[idx], S_HASH_to_DOUT); - set_setup_mode(&desc[idx], SETUP_WRITE_STATE0); - idx++; - - // is this needed?? or continue with current descriptors?? - BUG_ON(idx > FIPS_HMAC_MAX_SEQ_LEN); - rc = send_request(drvdata, &ssi_req, desc, idx, 0); - if (unlikely(rc != 0)) { - SSI_LOG_ERR("send_request() failed (rc=%d)\n", rc); - return rc; - } - idx = 0; - } - } - - /* data descriptor */ - hw_desc_init(&desc[idx]); - set_din_type(&desc[idx], DMA_DLLI, din_dma_addr, data_in_size, NS_BIT); - set_flow_mode(&desc[idx], DIN_HASH); - idx++; - - /* HW last hash block padding (aka. "DO_PAD") */ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], hw_mode); - set_dout_dlli(&desc[idx], k0_dma_addr, HASH_LEN_SIZE, NS_BIT, 0); - set_flow_mode(&desc[idx], S_HASH_to_DOUT); - set_setup_mode(&desc[idx], SETUP_WRITE_STATE1); - set_cipher_do(&desc[idx], DO_PAD); - idx++; - - /* store the hash digest result in the context */ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], hw_mode); - set_dout_dlli(&desc[idx], k0_dma_addr, digest_size, NS_BIT, 0); - set_flow_mode(&desc[idx], S_HASH_to_DOUT); - if (unlikely((hash_mode == DRV_HASH_MD5) || - (hash_mode == DRV_HASH_SHA384) || - (hash_mode == DRV_HASH_SHA512))) { - set_bytes_swap(&desc[idx], 1); - } else { - set_cipher_config0(&desc[idx], - HASH_DIGEST_RESULT_LITTLE_ENDIAN); - } - set_setup_mode(&desc[idx], SETUP_WRITE_STATE0); - idx++; - - /* at this point: - * tmp_digest = H(o_key_pad) - * k0 = H(i_key_pad || m) - */ - - /* Loading hash opad xor key state */ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], hw_mode); - set_din_type(&desc[idx], DMA_DLLI, tmp_digest_dma_addr, - inter_digestsize, NS_BIT); - set_flow_mode(&desc[idx], S_DIN_to_HASH); - set_setup_mode(&desc[idx], SETUP_LOAD_STATE0); - idx++; - - /* Load the hash current length */ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], hw_mode); - set_din_type(&desc[idx], DMA_DLLI, digest_bytes_len_dma_addr, - HASH_LEN_SIZE, NS_BIT); - set_cipher_config1(&desc[idx], HASH_PADDING_ENABLED); - set_flow_mode(&desc[idx], S_DIN_to_HASH); - set_setup_mode(&desc[idx], SETUP_LOAD_KEY0); - idx++; - - /* Memory Barrier: wait for IPAD/OPAD axi write to complete */ - hw_desc_init(&desc[idx]); - set_din_no_dma(&desc[idx], 0, 0xfffff0); - set_dout_no_dma(&desc[idx], 0, 0, 1); - idx++; - - /* Perform HASH update */ - hw_desc_init(&desc[idx]); - set_din_type(&desc[idx], DMA_DLLI, k0_dma_addr, digest_size, NS_BIT); - set_flow_mode(&desc[idx], DIN_HASH); - idx++; - - /* Get final MAC result */ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], hw_mode); - set_dout_dlli(&desc[idx], mac_res_dma_addr, digest_size, NS_BIT, 0); - set_flow_mode(&desc[idx], S_HASH_to_DOUT); - set_setup_mode(&desc[idx], SETUP_WRITE_STATE0); - set_cipher_config1(&desc[idx], HASH_PADDING_DISABLED); - if (unlikely((hash_mode == DRV_HASH_MD5) || - (hash_mode == DRV_HASH_SHA384) || - (hash_mode == DRV_HASH_SHA512))) { - set_bytes_swap(&desc[idx], 1); - } else { - set_cipher_config0(&desc[idx], - HASH_DIGEST_RESULT_LITTLE_ENDIAN); - } - idx++; - - /* perform the operation - Lock HW and push sequence */ - BUG_ON(idx > FIPS_HMAC_MAX_SEQ_LEN); - rc = send_request(drvdata, &ssi_req, desc, idx, false); - - return rc; -} - -enum cc_fips_error -ssi_hmac_fips_power_up_tests(struct ssi_drvdata *drvdata, void *cpu_addr_buffer, dma_addr_t dma_coherent_buffer) -{ - enum cc_fips_error error = CC_REE_FIPS_ERROR_OK; - size_t i; - struct fips_hmac_ctx *virt_ctx = (struct fips_hmac_ctx *)cpu_addr_buffer; - - /* set the phisical pointers */ - dma_addr_t initial_digest_dma_addr = dma_coherent_buffer + offsetof(struct fips_hmac_ctx, initial_digest); - dma_addr_t key_dma_addr = dma_coherent_buffer + offsetof(struct fips_hmac_ctx, key); - dma_addr_t k0_dma_addr = dma_coherent_buffer + offsetof(struct fips_hmac_ctx, k0); - dma_addr_t tmp_digest_dma_addr = dma_coherent_buffer + offsetof(struct fips_hmac_ctx, tmp_digest); - dma_addr_t digest_bytes_len_dma_addr = dma_coherent_buffer + offsetof(struct fips_hmac_ctx, digest_bytes_len); - dma_addr_t din_dma_addr = dma_coherent_buffer + offsetof(struct fips_hmac_ctx, din); - dma_addr_t mac_res_dma_addr = dma_coherent_buffer + offsetof(struct fips_hmac_ctx, mac_res); - - for (i = 0; i < FIPS_HMAC_NUM_OF_TESTS; ++i) - { - FipsHmacData *hmac_data = (FipsHmacData *)&FipsHmacDataTable[i]; - int rc = 0; - enum drv_hash_hw_mode hw_mode = 0; - int digest_size = 0; - int block_size = 0; - int inter_digestsize = 0; - - memset(cpu_addr_buffer, 0, sizeof(struct fips_hmac_ctx)); - - switch (hmac_data->hash_mode) { - case DRV_HASH_SHA1: - hw_mode = DRV_HASH_HW_SHA1; - digest_size = CC_SHA1_DIGEST_SIZE; - block_size = CC_SHA1_BLOCK_SIZE; - inter_digestsize = CC_SHA1_DIGEST_SIZE; - memcpy(virt_ctx->initial_digest, (void *)sha1_init, CC_SHA1_DIGEST_SIZE); - memcpy(virt_ctx->digest_bytes_len, digest_len_init, HASH_LEN_SIZE); - break; - case DRV_HASH_SHA256: - hw_mode = DRV_HASH_HW_SHA256; - digest_size = CC_SHA256_DIGEST_SIZE; - block_size = CC_SHA256_BLOCK_SIZE; - inter_digestsize = CC_SHA256_DIGEST_SIZE; - memcpy(virt_ctx->initial_digest, (void *)sha256_init, CC_SHA256_DIGEST_SIZE); - memcpy(virt_ctx->digest_bytes_len, digest_len_init, HASH_LEN_SIZE); - break; -#if (CC_SUPPORT_SHA > 256) - case DRV_HASH_SHA512: - hw_mode = DRV_HASH_HW_SHA512; - digest_size = CC_SHA512_DIGEST_SIZE; - block_size = CC_SHA512_BLOCK_SIZE; - inter_digestsize = CC_SHA512_DIGEST_SIZE; - memcpy(virt_ctx->initial_digest, (void *)sha512_init, CC_SHA512_DIGEST_SIZE); - memcpy(virt_ctx->digest_bytes_len, digest_len_sha512_init, HASH_LEN_SIZE); - break; -#endif - default: - error = FIPS_HmacToFipsError(hmac_data->hash_mode); - break; - } - - /* copy into the allocated buffer */ - memcpy(virt_ctx->key, hmac_data->key, hmac_data->key_size); - memcpy(virt_ctx->din, hmac_data->data_in, hmac_data->data_in_size); - - /* run the test on HW */ - FIPS_DBG("ssi_hmac_fips_run_test - (i = %d) \n", i); - rc = ssi_hmac_fips_run_test(drvdata, - initial_digest_dma_addr, - key_dma_addr, - hmac_data->key_size, - din_dma_addr, - hmac_data->data_in_size, - mac_res_dma_addr, - hmac_data->hash_mode, - hw_mode, - digest_size, - inter_digestsize, - block_size, - k0_dma_addr, - tmp_digest_dma_addr, - digest_bytes_len_dma_addr); - if (rc != 0) - { - FIPS_LOG("ssi_hmac_fips_run_test %d returned error - rc = %d \n", i, rc); - error = FIPS_HmacToFipsError(hmac_data->hash_mode); - break; - } - - /* compare actual mac result to expected */ - if (memcmp(virt_ctx->mac_res, hmac_data->mac_res, digest_size) != 0) - { - FIPS_LOG("comparison error %d - hash_mode=%d digest_size=%d \n", i, hmac_data->hash_mode, digest_size); - FIPS_LOG(" i expected received \n"); - FIPS_LOG(" i 0x%08x 0x%08x \n", (size_t)hmac_data->mac_res, (size_t)virt_ctx->mac_res); - for (i = 0; i < digest_size; ++i) - { - FIPS_LOG(" %d 0x%02x 0x%02x \n", i, hmac_data->mac_res[i], virt_ctx->mac_res[i]); - } - - error = FIPS_HmacToFipsError(hmac_data->hash_mode); - break; - } - } - - return error; -} - -static inline int -ssi_ccm_fips_run_test(struct ssi_drvdata *drvdata, - enum drv_crypto_direction direction, - dma_addr_t key_dma_addr, - size_t key_size, - dma_addr_t iv_dma_addr, - dma_addr_t ctr_cnt_0_dma_addr, - dma_addr_t b0_a0_adata_dma_addr, - size_t b0_a0_adata_size, - dma_addr_t din_dma_addr, - size_t din_size, - dma_addr_t dout_dma_addr, - dma_addr_t mac_res_dma_addr) -{ - /* max number of descriptors used for the flow */ - #define FIPS_CCM_MAX_SEQ_LEN 10 - - int rc; - struct ssi_crypto_req ssi_req = {0}; - struct cc_hw_desc desc[FIPS_CCM_MAX_SEQ_LEN]; - unsigned int idx = 0; - unsigned int cipher_flow_mode; - - if (direction == DRV_CRYPTO_DIRECTION_DECRYPT) { - cipher_flow_mode = AES_to_HASH_and_DOUT; - } else { /* Encrypt */ - cipher_flow_mode = AES_and_HASH; - } - - /* load key */ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], DRV_CIPHER_CTR); - set_din_type(&desc[idx], DMA_DLLI, key_dma_addr, - ((key_size == NIST_AESCCM_192_BIT_KEY_SIZE) ? - CC_AES_KEY_SIZE_MAX : key_size), NS_BIT) - set_key_size_aes(&desc[idx], key_size); - set_setup_mode(&desc[idx], SETUP_LOAD_KEY0); - set_cipher_config0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT); - set_flow_mode(&desc[idx], S_DIN_to_AES); - idx++; - - /* load ctr state */ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], DRV_CIPHER_CTR); - set_key_size_aes(&desc[idx], key_size); - set_din_type(&desc[idx], DMA_DLLI, iv_dma_addr, AES_BLOCK_SIZE, - NS_BIT); - set_cipher_config0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT); - set_setup_mode(&desc[idx], SETUP_LOAD_STATE1); - set_flow_mode(&desc[idx], S_DIN_to_AES); - idx++; - - /* load MAC key */ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], DRV_CIPHER_CBC_MAC); - set_din_type(&desc[idx], DMA_DLLI, key_dma_addr, - ((key_size == NIST_AESCCM_192_BIT_KEY_SIZE) ? - CC_AES_KEY_SIZE_MAX : key_size), NS_BIT); - set_key_size_aes(&desc[idx], key_size); - set_setup_mode(&desc[idx], SETUP_LOAD_KEY0); - set_cipher_config0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT); - set_flow_mode(&desc[idx], S_DIN_to_HASH); - set_aes_not_hash_mode(&desc[idx]); - idx++; - - /* load MAC state */ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], DRV_CIPHER_CBC_MAC); - set_key_size_aes(&desc[idx], key_size); - set_din_type(&desc[idx], DMA_DLLI, mac_res_dma_addr, - NIST_AESCCM_TAG_SIZE, NS_BIT); - set_cipher_config0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT); - set_setup_mode(&desc[idx], SETUP_LOAD_STATE0); - set_flow_mode(&desc[idx], S_DIN_to_HASH); - set_aes_not_hash_mode(&desc[idx]); - idx++; - - /* prcess assoc data */ - hw_desc_init(&desc[idx]); - set_din_type(&desc[idx], DMA_DLLI, b0_a0_adata_dma_addr, - b0_a0_adata_size, NS_BIT); - set_flow_mode(&desc[idx], DIN_HASH); - idx++; - - /* process the cipher */ - hw_desc_init(&desc[idx]); - set_din_type(&desc[idx], DMA_DLLI, din_dma_addr, din_size, NS_BIT); - set_dout_dlli(&desc[idx], dout_dma_addr, din_size, NS_BIT, 0); - set_flow_mode(&desc[idx], cipher_flow_mode); - idx++; - - /* Read temporal MAC */ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], DRV_CIPHER_CBC_MAC); - set_dout_dlli(&desc[idx], mac_res_dma_addr, NIST_AESCCM_TAG_SIZE, - NS_BIT, 0); - set_setup_mode(&desc[idx], SETUP_WRITE_STATE0); - set_cipher_config0(&desc[idx], HASH_DIGEST_RESULT_LITTLE_ENDIAN); - set_flow_mode(&desc[idx], S_HASH_to_DOUT); - set_aes_not_hash_mode(&desc[idx]); - idx++; - - /* load AES-CTR state (for last MAC calculation)*/ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], DRV_CIPHER_CTR); - set_cipher_config0(&desc[idx], DRV_CRYPTO_DIRECTION_ENCRYPT); - set_din_type(&desc[idx], DMA_DLLI, ctr_cnt_0_dma_addr, AES_BLOCK_SIZE, - NS_BIT); - set_key_size_aes(&desc[idx], key_size); - set_setup_mode(&desc[idx], SETUP_LOAD_STATE1); - set_flow_mode(&desc[idx], S_DIN_to_AES); - idx++; - - /* Memory Barrier */ - hw_desc_init(&desc[idx]); - set_din_no_dma(&desc[idx], 0, 0xfffff0); - set_dout_no_dma(&desc[idx], 0, 0, 1); - idx++; - - /* encrypt the "T" value and store MAC inplace */ - hw_desc_init(&desc[idx]); - set_din_type(&desc[idx], DMA_DLLI, mac_res_dma_addr, - NIST_AESCCM_TAG_SIZE, NS_BIT); - set_dout_dlli(&desc[idx], mac_res_dma_addr, NIST_AESCCM_TAG_SIZE, - NS_BIT, 0); - set_flow_mode(&desc[idx], DIN_AES_DOUT); - idx++; - - /* perform the operation - Lock HW and push sequence */ - BUG_ON(idx > FIPS_CCM_MAX_SEQ_LEN); - rc = send_request(drvdata, &ssi_req, desc, idx, false); - - return rc; -} - -enum cc_fips_error -ssi_ccm_fips_power_up_tests(struct ssi_drvdata *drvdata, void *cpu_addr_buffer, dma_addr_t dma_coherent_buffer) -{ - enum cc_fips_error error = CC_REE_FIPS_ERROR_OK; - size_t i; - struct fips_ccm_ctx *virt_ctx = (struct fips_ccm_ctx *)cpu_addr_buffer; - - /* set the phisical pointers */ - dma_addr_t b0_a0_adata_dma_addr = dma_coherent_buffer + offsetof(struct fips_ccm_ctx, b0_a0_adata); - dma_addr_t iv_dma_addr = dma_coherent_buffer + offsetof(struct fips_ccm_ctx, iv); - dma_addr_t ctr_cnt_0_dma_addr = dma_coherent_buffer + offsetof(struct fips_ccm_ctx, ctr_cnt_0); - dma_addr_t key_dma_addr = dma_coherent_buffer + offsetof(struct fips_ccm_ctx, key); - dma_addr_t din_dma_addr = dma_coherent_buffer + offsetof(struct fips_ccm_ctx, din); - dma_addr_t dout_dma_addr = dma_coherent_buffer + offsetof(struct fips_ccm_ctx, dout); - dma_addr_t mac_res_dma_addr = dma_coherent_buffer + offsetof(struct fips_ccm_ctx, mac_res); - - for (i = 0; i < FIPS_CCM_NUM_OF_TESTS; ++i) - { - FipsCcmData *ccmData = (FipsCcmData *)&FipsCcmDataTable[i]; - int rc = 0; - - memset(cpu_addr_buffer, 0, sizeof(struct fips_ccm_ctx)); - - /* copy the nonce, key, adata, din data into the allocated buffer */ - memcpy(virt_ctx->key, ccmData->key, ccmData->keySize); - memcpy(virt_ctx->din, ccmData->dataIn, ccmData->dataInSize); - { - /* build B0 -- B0, nonce, l(m) */ - __be16 data = cpu_to_be16(NIST_AESCCM_TEXT_SIZE); - - virt_ctx->b0_a0_adata[0] = NIST_AESCCM_B0_VAL; - memcpy(virt_ctx->b0_a0_adata + 1, ccmData->nonce, NIST_AESCCM_NONCE_SIZE); - memcpy(virt_ctx->b0_a0_adata + 14, (u8 *)&data, sizeof(__be16)); - /* build A0+ADATA */ - virt_ctx->b0_a0_adata[NIST_AESCCM_IV_SIZE + 0] = (ccmData->adataSize >> 8) & 0xFF; - virt_ctx->b0_a0_adata[NIST_AESCCM_IV_SIZE + 1] = ccmData->adataSize & 0xFF; - memcpy(virt_ctx->b0_a0_adata + NIST_AESCCM_IV_SIZE + 2, ccmData->adata, ccmData->adataSize); - /* iv */ - virt_ctx->iv[0] = 1; /* L' */ - memcpy(virt_ctx->iv + 1, ccmData->nonce, NIST_AESCCM_NONCE_SIZE); - virt_ctx->iv[15] = 1; - /* ctr_count_0 */ - memcpy(virt_ctx->ctr_cnt_0, virt_ctx->iv, NIST_AESCCM_IV_SIZE); - virt_ctx->ctr_cnt_0[15] = 0; - } - - FIPS_DBG("ssi_ccm_fips_run_test - (i = %d) \n", i); - rc = ssi_ccm_fips_run_test(drvdata, - ccmData->direction, - key_dma_addr, - ccmData->keySize, - iv_dma_addr, - ctr_cnt_0_dma_addr, - b0_a0_adata_dma_addr, - FIPS_CCM_B0_A0_ADATA_SIZE, - din_dma_addr, - ccmData->dataInSize, - dout_dma_addr, - mac_res_dma_addr); - if (rc != 0) - { - FIPS_LOG("ssi_ccm_fips_run_test %d returned error - rc = %d \n", i, rc); - error = CC_REE_FIPS_ERROR_AESCCM_PUT; - break; - } - - /* compare actual dout to expected */ - if (memcmp(virt_ctx->dout, ccmData->dataOut, ccmData->dataInSize) != 0) - { - FIPS_LOG("dout comparison error %d - size=%d \n", i, ccmData->dataInSize); - error = CC_REE_FIPS_ERROR_AESCCM_PUT; - break; - } - - /* compare actual mac result to expected */ - if (memcmp(virt_ctx->mac_res, ccmData->macResOut, ccmData->tagSize) != 0) - { - FIPS_LOG("mac_res comparison error %d - mac_size=%d \n", i, ccmData->tagSize); - FIPS_LOG(" i expected received \n"); - FIPS_LOG(" i 0x%08x 0x%08x \n", (size_t)ccmData->macResOut, (size_t)virt_ctx->mac_res); - for (i = 0; i < ccmData->tagSize; ++i) - { - FIPS_LOG(" %d 0x%02x 0x%02x \n", i, ccmData->macResOut[i], virt_ctx->mac_res[i]); - } - - error = CC_REE_FIPS_ERROR_AESCCM_PUT; - break; - } - } - - return error; -} - -static inline int -ssi_gcm_fips_run_test(struct ssi_drvdata *drvdata, - enum drv_crypto_direction direction, - dma_addr_t key_dma_addr, - size_t key_size, - dma_addr_t hkey_dma_addr, - dma_addr_t block_len_dma_addr, - dma_addr_t iv_inc1_dma_addr, - dma_addr_t iv_inc2_dma_addr, - dma_addr_t adata_dma_addr, - size_t adata_size, - dma_addr_t din_dma_addr, - size_t din_size, - dma_addr_t dout_dma_addr, - dma_addr_t mac_res_dma_addr) -{ - /* max number of descriptors used for the flow */ - #define FIPS_GCM_MAX_SEQ_LEN 15 - - int rc; - struct ssi_crypto_req ssi_req = {0}; - struct cc_hw_desc desc[FIPS_GCM_MAX_SEQ_LEN]; - unsigned int idx = 0; - unsigned int cipher_flow_mode; - - if (direction == DRV_CRYPTO_DIRECTION_DECRYPT) { - cipher_flow_mode = AES_and_HASH; - } else { /* Encrypt */ - cipher_flow_mode = AES_to_HASH_and_DOUT; - } - -///////////////////////////////// 1 //////////////////////////////////// -// ssi_aead_gcm_setup_ghash_desc(req, desc, seq_size); -///////////////////////////////// 1 //////////////////////////////////// - - /* load key to AES */ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], DRV_CIPHER_ECB); - set_cipher_config0(&desc[idx], DRV_CRYPTO_DIRECTION_ENCRYPT); - set_din_type(&desc[idx], DMA_DLLI, key_dma_addr, key_size, NS_BIT); - set_key_size_aes(&desc[idx], key_size); - set_setup_mode(&desc[idx], SETUP_LOAD_KEY0); - set_flow_mode(&desc[idx], S_DIN_to_AES); - idx++; - - /* process one zero block to generate hkey */ - hw_desc_init(&desc[idx]); - set_din_const(&desc[idx], 0x0, AES_BLOCK_SIZE); - set_dout_dlli(&desc[idx], hkey_dma_addr, AES_BLOCK_SIZE, NS_BIT, 0); - set_flow_mode(&desc[idx], DIN_AES_DOUT); - idx++; - - /* Memory Barrier */ - hw_desc_init(&desc[idx]); - set_din_no_dma(&desc[idx], 0, 0xfffff0); - set_dout_no_dma(&desc[idx], 0, 0, 1); - idx++; - - /* Load GHASH subkey */ - hw_desc_init(&desc[idx]); - set_din_type(&desc[idx], DMA_DLLI, hkey_dma_addr, AES_BLOCK_SIZE, - NS_BIT); - set_dout_no_dma(&desc[idx], 0, 0, 1); - set_flow_mode(&desc[idx], S_DIN_to_HASH); - set_aes_not_hash_mode(&desc[idx]); - set_cipher_mode(&desc[idx], DRV_HASH_HW_GHASH); - set_cipher_config1(&desc[idx], HASH_PADDING_ENABLED); - set_setup_mode(&desc[idx], SETUP_LOAD_KEY0); - idx++; - - /* Configure Hash Engine to work with GHASH. - * Since it was not possible to extend HASH submodes to add GHASH, - * The following command is necessary in order to - * select GHASH (according to HW designers) - */ - hw_desc_init(&desc[idx]); - set_din_no_dma(&desc[idx], 0, 0xfffff0); - set_dout_no_dma(&desc[idx], 0, 0, 1); - set_flow_mode(&desc[idx], S_DIN_to_HASH); - set_aes_not_hash_mode(&desc[idx]); - set_cipher_mode(&desc[idx], DRV_HASH_HW_GHASH); - set_cipher_do(&desc[idx], 1); //1=AES_SK RKEK - set_cipher_config0(&desc[idx], DRV_CRYPTO_DIRECTION_ENCRYPT); - set_cipher_config1(&desc[idx], HASH_PADDING_ENABLED); - set_setup_mode(&desc[idx], SETUP_LOAD_KEY0); - idx++; - - /* Load GHASH initial STATE (which is 0). (for any hash there is an initial state) */ - hw_desc_init(&desc[idx]); - set_din_const(&desc[idx], 0x0, AES_BLOCK_SIZE); - set_dout_no_dma(&desc[idx], 0, 0, 1); - set_flow_mode(&desc[idx], S_DIN_to_HASH); - set_aes_not_hash_mode(&desc[idx]); - set_cipher_mode(&desc[idx], DRV_HASH_HW_GHASH); - set_cipher_config1(&desc[idx], HASH_PADDING_ENABLED); - set_setup_mode(&desc[idx], SETUP_LOAD_STATE0); - idx++; - -///////////////////////////////// 2 //////////////////////////////////// - /* prcess(ghash) assoc data */ -// if (req->assoclen > 0) -// ssi_aead_create_assoc_desc(req, DIN_HASH, desc, seq_size); -///////////////////////////////// 2 //////////////////////////////////// - - hw_desc_init(&desc[idx]); - set_din_type(&desc[idx], DMA_DLLI, adata_dma_addr, adata_size, NS_BIT); - set_flow_mode(&desc[idx], DIN_HASH); - idx++; - -///////////////////////////////// 3 //////////////////////////////////// -// ssi_aead_gcm_setup_gctr_desc(req, desc, seq_size); -///////////////////////////////// 3 //////////////////////////////////// - - /* load key to AES*/ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], DRV_CIPHER_GCTR); - set_cipher_config0(&desc[idx], DRV_CRYPTO_DIRECTION_ENCRYPT); - set_din_type(&desc[idx], DMA_DLLI, key_dma_addr, key_size, NS_BIT); - set_key_size_aes(&desc[idx], key_size); - set_setup_mode(&desc[idx], SETUP_LOAD_KEY0); - set_flow_mode(&desc[idx], S_DIN_to_AES); - idx++; - - /* load AES/CTR initial CTR value inc by 2*/ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], DRV_CIPHER_GCTR); - set_key_size_aes(&desc[idx], key_size); - set_din_type(&desc[idx], DMA_DLLI, iv_inc2_dma_addr, AES_BLOCK_SIZE, - NS_BIT); - set_cipher_config0(&desc[idx], DRV_CRYPTO_DIRECTION_ENCRYPT); - set_setup_mode(&desc[idx], SETUP_LOAD_STATE1); - set_flow_mode(&desc[idx], S_DIN_to_AES); - idx++; - -///////////////////////////////// 4 //////////////////////////////////// - /* process(gctr+ghash) */ -// if (req_ctx->cryptlen != 0) -// ssi_aead_process_cipher_data_desc(req, cipher_flow_mode, desc, seq_size); -///////////////////////////////// 4 //////////////////////////////////// - - hw_desc_init(&desc[idx]); - set_din_type(&desc[idx], DMA_DLLI, din_dma_addr, din_size, NS_BIT); - set_dout_dlli(&desc[idx], dout_dma_addr, din_size, NS_BIT, 0); - set_flow_mode(&desc[idx], cipher_flow_mode); - idx++; - -///////////////////////////////// 5 //////////////////////////////////// -// ssi_aead_process_gcm_result_desc(req, desc, seq_size); -///////////////////////////////// 5 //////////////////////////////////// - - /* prcess(ghash) gcm_block_len */ - hw_desc_init(&desc[idx]); - set_din_type(&desc[idx], DMA_DLLI, block_len_dma_addr, AES_BLOCK_SIZE, - NS_BIT); - set_flow_mode(&desc[idx], DIN_HASH); - idx++; - - /* Store GHASH state after GHASH(Associated Data + Cipher +LenBlock) */ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], DRV_HASH_HW_GHASH); - set_din_no_dma(&desc[idx], 0, 0xfffff0); - set_dout_dlli(&desc[idx], mac_res_dma_addr, AES_BLOCK_SIZE, NS_BIT, 0); - set_setup_mode(&desc[idx], SETUP_WRITE_STATE0); - set_flow_mode(&desc[idx], S_HASH_to_DOUT); - set_aes_not_hash_mode(&desc[idx]); - idx++; - - /* load AES/CTR initial CTR value inc by 1*/ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], DRV_CIPHER_GCTR); - set_key_size_aes(&desc[idx], key_size); - set_din_type(&desc[idx], DMA_DLLI, iv_inc1_dma_addr, AES_BLOCK_SIZE, - NS_BIT); - set_cipher_config0(&desc[idx], DRV_CRYPTO_DIRECTION_ENCRYPT); - set_setup_mode(&desc[idx], SETUP_LOAD_STATE1); - set_flow_mode(&desc[idx], S_DIN_to_AES); - idx++; - - /* Memory Barrier */ - hw_desc_init(&desc[idx]); - set_din_no_dma(&desc[idx], 0, 0xfffff0); - set_dout_no_dma(&desc[idx], 0, 0, 1); - idx++; - - /* process GCTR on stored GHASH and store MAC inplace */ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], DRV_CIPHER_GCTR); - set_din_type(&desc[idx], DMA_DLLI, mac_res_dma_addr, AES_BLOCK_SIZE, - NS_BIT); - set_dout_dlli(&desc[idx], mac_res_dma_addr, AES_BLOCK_SIZE, NS_BIT, 0); - set_flow_mode(&desc[idx], DIN_AES_DOUT); - idx++; - - /* perform the operation - Lock HW and push sequence */ - BUG_ON(idx > FIPS_GCM_MAX_SEQ_LEN); - rc = send_request(drvdata, &ssi_req, desc, idx, false); - - return rc; -} - -enum cc_fips_error -ssi_gcm_fips_power_up_tests(struct ssi_drvdata *drvdata, void *cpu_addr_buffer, dma_addr_t dma_coherent_buffer) -{ - enum cc_fips_error error = CC_REE_FIPS_ERROR_OK; - size_t i; - struct fips_gcm_ctx *virt_ctx = (struct fips_gcm_ctx *)cpu_addr_buffer; - - /* set the phisical pointers */ - dma_addr_t adata_dma_addr = dma_coherent_buffer + offsetof(struct fips_gcm_ctx, adata); - dma_addr_t key_dma_addr = dma_coherent_buffer + offsetof(struct fips_gcm_ctx, key); - dma_addr_t hkey_dma_addr = dma_coherent_buffer + offsetof(struct fips_gcm_ctx, hkey); - dma_addr_t din_dma_addr = dma_coherent_buffer + offsetof(struct fips_gcm_ctx, din); - dma_addr_t dout_dma_addr = dma_coherent_buffer + offsetof(struct fips_gcm_ctx, dout); - dma_addr_t mac_res_dma_addr = dma_coherent_buffer + offsetof(struct fips_gcm_ctx, mac_res); - dma_addr_t len_block_dma_addr = dma_coherent_buffer + offsetof(struct fips_gcm_ctx, len_block); - dma_addr_t iv_inc1_dma_addr = dma_coherent_buffer + offsetof(struct fips_gcm_ctx, iv_inc1); - dma_addr_t iv_inc2_dma_addr = dma_coherent_buffer + offsetof(struct fips_gcm_ctx, iv_inc2); - - for (i = 0; i < FIPS_GCM_NUM_OF_TESTS; ++i) - { - FipsGcmData *gcmData = (FipsGcmData *)&FipsGcmDataTable[i]; - int rc = 0; - - memset(cpu_addr_buffer, 0, sizeof(struct fips_gcm_ctx)); - - /* copy the key, adata, din data - into the allocated buffer */ - memcpy(virt_ctx->key, gcmData->key, gcmData->keySize); - memcpy(virt_ctx->adata, gcmData->adata, gcmData->adataSize); - memcpy(virt_ctx->din, gcmData->dataIn, gcmData->dataInSize); - - /* len_block */ - { - __be64 len_bits; - - len_bits = cpu_to_be64(gcmData->adataSize * 8); - memcpy(virt_ctx->len_block, &len_bits, sizeof(len_bits)); - len_bits = cpu_to_be64(gcmData->dataInSize * 8); - memcpy(virt_ctx->len_block + 8, &len_bits, sizeof(len_bits)); - } - /* iv_inc1, iv_inc2 */ - { - __be32 counter = cpu_to_be32(1); - - memcpy(virt_ctx->iv_inc1, gcmData->iv, NIST_AESGCM_IV_SIZE); - memcpy(virt_ctx->iv_inc1 + NIST_AESGCM_IV_SIZE, &counter, sizeof(counter)); - counter = cpu_to_be32(2); - memcpy(virt_ctx->iv_inc2, gcmData->iv, NIST_AESGCM_IV_SIZE); - memcpy(virt_ctx->iv_inc2 + NIST_AESGCM_IV_SIZE, &counter, sizeof(counter)); - } - - FIPS_DBG("ssi_gcm_fips_run_test - (i = %d) \n", i); - rc = ssi_gcm_fips_run_test(drvdata, - gcmData->direction, - key_dma_addr, - gcmData->keySize, - hkey_dma_addr, - len_block_dma_addr, - iv_inc1_dma_addr, - iv_inc2_dma_addr, - adata_dma_addr, - gcmData->adataSize, - din_dma_addr, - gcmData->dataInSize, - dout_dma_addr, - mac_res_dma_addr); - if (rc != 0) - { - FIPS_LOG("ssi_gcm_fips_run_test %d returned error - rc = %d \n", i, rc); - error = CC_REE_FIPS_ERROR_AESGCM_PUT; - break; - } - - if (gcmData->direction == DRV_CRYPTO_DIRECTION_ENCRYPT) { - /* compare actual dout to expected */ - if (memcmp(virt_ctx->dout, gcmData->dataOut, gcmData->dataInSize) != 0) - { - FIPS_LOG("dout comparison error %d - size=%d \n", i, gcmData->dataInSize); - FIPS_LOG(" i expected received \n"); - FIPS_LOG(" i 0x%08x 0x%08x \n", (size_t)gcmData->dataOut, (size_t)virt_ctx->dout); - for (i = 0; i < gcmData->dataInSize; ++i) - { - FIPS_LOG(" %d 0x%02x 0x%02x \n", i, gcmData->dataOut[i], virt_ctx->dout[i]); - } - - error = CC_REE_FIPS_ERROR_AESGCM_PUT; - break; - } - } - - /* compare actual mac result to expected */ - if (memcmp(virt_ctx->mac_res, gcmData->macResOut, gcmData->tagSize) != 0) - { - FIPS_LOG("mac_res comparison error %d - mac_size=%d \n", i, gcmData->tagSize); - FIPS_LOG(" i expected received \n"); - FIPS_LOG(" i 0x%08x 0x%08x \n", (size_t)gcmData->macResOut, (size_t)virt_ctx->mac_res); - for (i = 0; i < gcmData->tagSize; ++i) - { - FIPS_LOG(" %d 0x%02x 0x%02x \n", i, gcmData->macResOut[i], virt_ctx->mac_res[i]); - } - - error = CC_REE_FIPS_ERROR_AESGCM_PUT; - break; - } - } - return error; -} - -size_t ssi_fips_max_mem_alloc_size(void) -{ - FIPS_DBG("sizeof(struct fips_cipher_ctx) %d \n", sizeof(struct fips_cipher_ctx)); - FIPS_DBG("sizeof(struct fips_cmac_ctx) %d \n", sizeof(struct fips_cmac_ctx)); - FIPS_DBG("sizeof(struct fips_hash_ctx) %d \n", sizeof(struct fips_hash_ctx)); - FIPS_DBG("sizeof(struct fips_hmac_ctx) %d \n", sizeof(struct fips_hmac_ctx)); - FIPS_DBG("sizeof(struct fips_ccm_ctx) %d \n", sizeof(struct fips_ccm_ctx)); - FIPS_DBG("sizeof(struct fips_gcm_ctx) %d \n", sizeof(struct fips_gcm_ctx)); - - return sizeof(fips_ctx); -} - diff --git a/drivers/staging/ccree/ssi_fips_local.c b/drivers/staging/ccree/ssi_fips_local.c deleted file mode 100644 index aefb71dc9e9a..000000000000 --- a/drivers/staging/ccree/ssi_fips_local.c +++ /dev/null @@ -1,357 +0,0 @@ -/* - * Copyright (C) 2012-2017 ARM Limited or its affiliates. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -/************************************************************** - * This file defines the driver FIPS internal function, used by the driver itself. - ***************************************************************/ -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <crypto/des.h> - -#include "ssi_config.h" -#include "ssi_driver.h" -#include "cc_hal.h" - -#define FIPS_POWER_UP_TEST_CIPHER 1 -#define FIPS_POWER_UP_TEST_CMAC 1 -#define FIPS_POWER_UP_TEST_HASH 1 -#define FIPS_POWER_UP_TEST_HMAC 1 -#define FIPS_POWER_UP_TEST_CCM 1 -#define FIPS_POWER_UP_TEST_GCM 1 - -static bool ssi_fips_support = 1; -module_param(ssi_fips_support, bool, 0644); -MODULE_PARM_DESC(ssi_fips_support, "FIPS supported flag: 0 - off , 1 - on (default)"); - -static void fips_dsr(unsigned long devarg); - -struct ssi_fips_handle { -#ifdef COMP_IN_WQ - struct workqueue_struct *workq; - struct delayed_work fipswork; -#else - struct tasklet_struct fipstask; -#endif -}; - -extern int ssi_fips_get_state(enum cc_fips_state_t *p_state); -extern int ssi_fips_get_error(enum cc_fips_error *p_err); -extern int ssi_fips_ext_set_state(enum cc_fips_state_t state); -extern int ssi_fips_ext_set_error(enum cc_fips_error err); - -/* FIPS power-up tests */ -extern enum cc_fips_error ssi_cipher_fips_power_up_tests(struct ssi_drvdata *drvdata, void *cpu_addr_buffer, dma_addr_t dma_coherent_buffer); -extern enum cc_fips_error ssi_cmac_fips_power_up_tests(struct ssi_drvdata *drvdata, void *cpu_addr_buffer, dma_addr_t dma_coherent_buffer); -extern enum cc_fips_error ssi_hash_fips_power_up_tests(struct ssi_drvdata *drvdata, void *cpu_addr_buffer, dma_addr_t dma_coherent_buffer); -extern enum cc_fips_error ssi_hmac_fips_power_up_tests(struct ssi_drvdata *drvdata, void *cpu_addr_buffer, dma_addr_t dma_coherent_buffer); -extern enum cc_fips_error ssi_ccm_fips_power_up_tests(struct ssi_drvdata *drvdata, void *cpu_addr_buffer, dma_addr_t dma_coherent_buffer); -extern enum cc_fips_error ssi_gcm_fips_power_up_tests(struct ssi_drvdata *drvdata, void *cpu_addr_buffer, dma_addr_t dma_coherent_buffer); -extern size_t ssi_fips_max_mem_alloc_size(void); - -/* The function called once at driver entry point to check whether TEE FIPS error occured.*/ -static enum ssi_fips_error ssi_fips_get_tee_error(struct ssi_drvdata *drvdata) -{ - u32 regVal; - void __iomem *cc_base = drvdata->cc_base; - - regVal = CC_HAL_READ_REGISTER(CC_REG_OFFSET(HOST_RGF, GPR_HOST)); - if (regVal == (CC_FIPS_SYNC_TEE_STATUS | CC_FIPS_SYNC_MODULE_OK)) - return CC_REE_FIPS_ERROR_OK; - - return CC_REE_FIPS_ERROR_FROM_TEE; -} - -/* - * This function should push the FIPS REE library status towards the TEE library. - * By writing the error state to HOST_GPR0 register. The function is called from - * driver entry point so no need to protect by mutex. - */ -static void ssi_fips_update_tee_upon_ree_status(struct ssi_drvdata *drvdata, enum cc_fips_error err) -{ - void __iomem *cc_base = drvdata->cc_base; - - if (err == CC_REE_FIPS_ERROR_OK) - CC_HAL_WRITE_REGISTER(CC_REG_OFFSET(HOST_RGF, HOST_GPR0), (CC_FIPS_SYNC_REE_STATUS | CC_FIPS_SYNC_MODULE_OK)); - else - CC_HAL_WRITE_REGISTER(CC_REG_OFFSET(HOST_RGF, HOST_GPR0), (CC_FIPS_SYNC_REE_STATUS | CC_FIPS_SYNC_MODULE_ERROR)); -} - -void ssi_fips_fini(struct ssi_drvdata *drvdata) -{ - struct ssi_fips_handle *fips_h = drvdata->fips_handle; - - if (!fips_h) - return; /* Not allocated */ - -#ifdef COMP_IN_WQ - if (fips_h->workq) { - flush_workqueue(fips_h->workq); - destroy_workqueue(fips_h->workq); - } -#else - /* Kill tasklet */ - tasklet_kill(&fips_h->fipstask); -#endif - memset(fips_h, 0, sizeof(struct ssi_fips_handle)); - kfree(fips_h); - drvdata->fips_handle = NULL; -} - -void fips_handler(struct ssi_drvdata *drvdata) -{ - struct ssi_fips_handle *fips_handle_ptr = - drvdata->fips_handle; -#ifdef COMP_IN_WQ - queue_delayed_work(fips_handle_ptr->workq, &fips_handle_ptr->fipswork, 0); -#else - tasklet_schedule(&fips_handle_ptr->fipstask); -#endif -} - -#ifdef COMP_IN_WQ -static void fips_wq_handler(struct work_struct *work) -{ - struct ssi_drvdata *drvdata = - container_of(work, struct ssi_drvdata, fipswork.work); - - fips_dsr((unsigned long)drvdata); -} -#endif - -/* Deferred service handler, run as interrupt-fired tasklet */ -static void fips_dsr(unsigned long devarg) -{ - struct ssi_drvdata *drvdata = (struct ssi_drvdata *)devarg; - void __iomem *cc_base = drvdata->cc_base; - u32 irq; - u32 teeFipsError = 0; - - irq = (drvdata->irq & (SSI_GPR0_IRQ_MASK)); - - if (irq & SSI_GPR0_IRQ_MASK) { - teeFipsError = CC_HAL_READ_REGISTER(CC_REG_OFFSET(HOST_RGF, GPR_HOST)); - if (teeFipsError != (CC_FIPS_SYNC_TEE_STATUS | CC_FIPS_SYNC_MODULE_OK)) - ssi_fips_set_error(drvdata, CC_REE_FIPS_ERROR_FROM_TEE); - } - - /* after verifing that there is nothing to do, Unmask AXI completion interrupt */ - CC_HAL_WRITE_REGISTER(CC_REG_OFFSET(HOST_RGF, HOST_IMR), - CC_HAL_READ_REGISTER( - CC_REG_OFFSET(HOST_RGF, HOST_IMR)) & ~irq); -} - -enum cc_fips_error cc_fips_run_power_up_tests(struct ssi_drvdata *drvdata) -{ - enum cc_fips_error fips_error = CC_REE_FIPS_ERROR_OK; - void *cpu_addr_buffer = NULL; - dma_addr_t dma_handle; - size_t alloc_buff_size = ssi_fips_max_mem_alloc_size(); - struct device *dev = &drvdata->plat_dev->dev; - - // allocate memory using dma_alloc_coherent - for phisical, consecutive and cache coherent buffer (memory map is not needed) - // the return value is the virtual address - use it to copy data into the buffer - // the dma_handle is the returned phy address - use it in the HW descriptor - FIPS_DBG("dma_alloc_coherent \n"); - cpu_addr_buffer = dma_alloc_coherent(dev, alloc_buff_size, &dma_handle, GFP_KERNEL); - if (!cpu_addr_buffer) - return CC_REE_FIPS_ERROR_GENERAL; - - FIPS_DBG("allocated coherent buffer - addr 0x%08X , size = %d \n", (size_t)cpu_addr_buffer, alloc_buff_size); - -#if FIPS_POWER_UP_TEST_CIPHER - FIPS_DBG("ssi_cipher_fips_power_up_tests ...\n"); - fips_error = ssi_cipher_fips_power_up_tests(drvdata, cpu_addr_buffer, dma_handle); - FIPS_DBG("ssi_cipher_fips_power_up_tests - done. (fips_error = %d) \n", fips_error); -#endif -#if FIPS_POWER_UP_TEST_CMAC - if (likely(fips_error == CC_REE_FIPS_ERROR_OK)) { - FIPS_DBG("ssi_cmac_fips_power_up_tests ...\n"); - fips_error = ssi_cmac_fips_power_up_tests(drvdata, cpu_addr_buffer, dma_handle); - FIPS_DBG("ssi_cmac_fips_power_up_tests - done. (fips_error = %d) \n", fips_error); - } -#endif -#if FIPS_POWER_UP_TEST_HASH - if (likely(fips_error == CC_REE_FIPS_ERROR_OK)) { - FIPS_DBG("ssi_hash_fips_power_up_tests ...\n"); - fips_error = ssi_hash_fips_power_up_tests(drvdata, cpu_addr_buffer, dma_handle); - FIPS_DBG("ssi_hash_fips_power_up_tests - done. (fips_error = %d) \n", fips_error); - } -#endif -#if FIPS_POWER_UP_TEST_HMAC - if (likely(fips_error == CC_REE_FIPS_ERROR_OK)) { - FIPS_DBG("ssi_hmac_fips_power_up_tests ...\n"); - fips_error = ssi_hmac_fips_power_up_tests(drvdata, cpu_addr_buffer, dma_handle); - FIPS_DBG("ssi_hmac_fips_power_up_tests - done. (fips_error = %d) \n", fips_error); - } -#endif -#if FIPS_POWER_UP_TEST_CCM - if (likely(fips_error == CC_REE_FIPS_ERROR_OK)) { - FIPS_DBG("ssi_ccm_fips_power_up_tests ...\n"); - fips_error = ssi_ccm_fips_power_up_tests(drvdata, cpu_addr_buffer, dma_handle); - FIPS_DBG("ssi_ccm_fips_power_up_tests - done. (fips_error = %d) \n", fips_error); - } -#endif -#if FIPS_POWER_UP_TEST_GCM - if (likely(fips_error == CC_REE_FIPS_ERROR_OK)) { - FIPS_DBG("ssi_gcm_fips_power_up_tests ...\n"); - fips_error = ssi_gcm_fips_power_up_tests(drvdata, cpu_addr_buffer, dma_handle); - FIPS_DBG("ssi_gcm_fips_power_up_tests - done. (fips_error = %d) \n", fips_error); - } -#endif - /* deallocate the buffer when all tests are done... */ - FIPS_DBG("dma_free_coherent \n"); - dma_free_coherent(dev, alloc_buff_size, cpu_addr_buffer, dma_handle); - - return fips_error; -} - -/* The function checks if FIPS supported and FIPS error exists.* - * It should be used in every driver API. - */ -int ssi_fips_check_fips_error(void) -{ - enum cc_fips_state_t fips_state; - - if (ssi_fips_get_state(&fips_state) != 0) { - FIPS_LOG("ssi_fips_get_state FAILED, returning.. \n"); - return -ENOEXEC; - } - if (fips_state == CC_FIPS_STATE_ERROR) { - FIPS_LOG("ssi_fips_get_state: fips_state is %d, returning.. \n", fips_state); - return -ENOEXEC; - } - return 0; -} - -/* The function sets the REE FIPS state.* - * It should be used while driver is being loaded. - */ -int ssi_fips_set_state(enum cc_fips_state_t state) -{ - return ssi_fips_ext_set_state(state); -} - -/* The function sets the REE FIPS error, and pushes the error to TEE library. * - * It should be used when any of the KAT tests fails. - */ -int ssi_fips_set_error(struct ssi_drvdata *p_drvdata, enum cc_fips_error err) -{ - int rc = 0; - enum cc_fips_error current_err; - - FIPS_LOG("ssi_fips_set_error - fips_error = %d \n", err); - - // setting no error is not allowed - if (err == CC_REE_FIPS_ERROR_OK) - return -ENOEXEC; - - // If error exists, do not set new error - if (ssi_fips_get_error(¤t_err) != 0) - return -ENOEXEC; - - if (current_err != CC_REE_FIPS_ERROR_OK) - return -ENOEXEC; - - // set REE internal error and state - rc = ssi_fips_ext_set_error(err); - if (rc != 0) - return -ENOEXEC; - - rc = ssi_fips_ext_set_state(CC_FIPS_STATE_ERROR); - if (rc != 0) - return -ENOEXEC; - - // push error towards TEE libraray, if it's not TEE error - if (err != CC_REE_FIPS_ERROR_FROM_TEE) - ssi_fips_update_tee_upon_ree_status(p_drvdata, err); - - return rc; -} - -/* The function called once at driver entry point .*/ -int ssi_fips_init(struct ssi_drvdata *p_drvdata) -{ - enum cc_fips_error rc = CC_REE_FIPS_ERROR_OK; - struct ssi_fips_handle *fips_h; - - FIPS_DBG("CC FIPS code .. (fips=%d) \n", ssi_fips_support); - - fips_h = kzalloc(sizeof(struct ssi_fips_handle), GFP_KERNEL); - if (!fips_h) { - ssi_fips_set_error(p_drvdata, CC_REE_FIPS_ERROR_GENERAL); - return -ENOMEM; - } - - p_drvdata->fips_handle = fips_h; - -#ifdef COMP_IN_WQ - SSI_LOG_DEBUG("Initializing fips workqueue\n"); - fips_h->workq = create_singlethread_workqueue("arm_cc7x_fips_wq"); - if (unlikely(!fips_h->workq)) { - SSI_LOG_ERR("Failed creating fips work queue\n"); - ssi_fips_set_error(p_drvdata, CC_REE_FIPS_ERROR_GENERAL); - rc = -ENOMEM; - goto ssi_fips_init_err; - } - INIT_DELAYED_WORK(&fips_h->fipswork, fips_wq_handler); -#else - SSI_LOG_DEBUG("Initializing fips tasklet\n"); - tasklet_init(&fips_h->fipstask, fips_dsr, (unsigned long)p_drvdata); -#endif - - /* init fips driver data */ - rc = ssi_fips_set_state((ssi_fips_support == 0) ? CC_FIPS_STATE_NOT_SUPPORTED : CC_FIPS_STATE_SUPPORTED); - if (unlikely(rc != 0)) { - ssi_fips_set_error(p_drvdata, CC_REE_FIPS_ERROR_GENERAL); - rc = -EAGAIN; - goto ssi_fips_init_err; - } - - /* Run power up tests (before registration and operating the HW engines) */ - FIPS_DBG("ssi_fips_get_tee_error \n"); - rc = ssi_fips_get_tee_error(p_drvdata); - if (unlikely(rc != CC_REE_FIPS_ERROR_OK)) { - ssi_fips_set_error(p_drvdata, CC_REE_FIPS_ERROR_FROM_TEE); - rc = -EAGAIN; - goto ssi_fips_init_err; - } - - FIPS_DBG("cc_fips_run_power_up_tests \n"); - rc = cc_fips_run_power_up_tests(p_drvdata); - if (unlikely(rc != CC_REE_FIPS_ERROR_OK)) { - ssi_fips_set_error(p_drvdata, rc); - rc = -EAGAIN; - goto ssi_fips_init_err; - } - FIPS_LOG("cc_fips_run_power_up_tests - done ... fips_error = %d \n", rc); - - /* when all tests passed, update TEE with fips OK status after power up tests */ - ssi_fips_update_tee_upon_ree_status(p_drvdata, CC_REE_FIPS_ERROR_OK); - - if (unlikely(rc != 0)) { - rc = -EAGAIN; - ssi_fips_set_error(p_drvdata, CC_REE_FIPS_ERROR_GENERAL); - goto ssi_fips_init_err; - } - - return 0; - -ssi_fips_init_err: - ssi_fips_fini(p_drvdata); - return rc; -} - diff --git a/drivers/staging/ccree/ssi_fips_local.h b/drivers/staging/ccree/ssi_fips_local.h deleted file mode 100644 index 8c7994fe9fae..000000000000 --- a/drivers/staging/ccree/ssi_fips_local.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2012-2017 ARM Limited or its affiliates. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef __SSI_FIPS_LOCAL_H__ -#define __SSI_FIPS_LOCAL_H__ - -#ifdef CONFIG_CCX7REE_FIPS_SUPPORT - -#include "ssi_fips.h" -struct ssi_drvdata; - -#define CHECK_AND_RETURN_UPON_FIPS_ERROR() {\ - if (ssi_fips_check_fips_error() != 0) {\ - return -ENOEXEC;\ - } \ -} - -#define CHECK_AND_RETURN_VOID_UPON_FIPS_ERROR() {\ - if (ssi_fips_check_fips_error() != 0) {\ - return;\ - } \ -} - -#define SSI_FIPS_INIT(p_drvData) (ssi_fips_init(p_drvData)) -#define SSI_FIPS_FINI(p_drvData) (ssi_fips_fini(p_drvData)) - -#define FIPS_LOG(...) SSI_LOG(KERN_INFO, __VA_ARGS__) -#define FIPS_DBG(...) //SSI_LOG(KERN_INFO, __VA_ARGS__) - -/* FIPS functions */ -int ssi_fips_init(struct ssi_drvdata *p_drvdata); -void ssi_fips_fini(struct ssi_drvdata *drvdata); -int ssi_fips_check_fips_error(void); -int ssi_fips_set_error(struct ssi_drvdata *p_drvdata, enum cc_fips_error err); -void fips_handler(struct ssi_drvdata *drvdata); - -#else /* CONFIG_CC7XXREE_FIPS_SUPPORT */ - -#define CHECK_AND_RETURN_UPON_FIPS_ERROR() -#define CHECK_AND_RETURN_VOID_UPON_FIPS_ERROR() - -static inline int ssi_fips_init(struct ssi_drvdata *p_drvdata) -{ - return 0; -} - -static inline void ssi_fips_fini(struct ssi_drvdata *drvdata) {} - -void fips_handler(struct ssi_drvdata *drvdata); - -#endif /* CONFIG_CC7XXREE_FIPS_SUPPORT */ - -#endif /*__SSI_FIPS_LOCAL_H__*/ - diff --git a/drivers/staging/ccree/ssi_hash.c b/drivers/staging/ccree/ssi_hash.c index ae8f36af3837..13291aeaf350 100644 --- a/drivers/staging/ccree/ssi_hash.c +++ b/drivers/staging/ccree/ssi_hash.c @@ -30,7 +30,6 @@ #include "ssi_sysfs.h" #include "ssi_hash.h" #include "ssi_sram_mgr.h" -#include "ssi_fips_local.h" #define SSI_MAX_AHASH_SEQ_LEN 12 #define SSI_MAX_HASH_OPAD_TMP_KEYS_SIZE MAX(SSI_MAX_HASH_BLCK_SIZE, 3 * AES_BLOCK_SIZE) @@ -71,8 +70,8 @@ static void ssi_hash_create_xcbc_setup( unsigned int *seq_size); static void ssi_hash_create_cmac_setup(struct ahash_request *areq, - struct cc_hw_desc desc[], - unsigned int *seq_size); + struct cc_hw_desc desc[], + unsigned int *seq_size); struct ssi_hash_alg { struct list_head entry; @@ -118,8 +117,8 @@ static void ssi_hash_create_data_desc( static inline void ssi_set_hash_endianity(u32 mode, struct cc_hw_desc *desc) { if (unlikely((mode == DRV_HASH_MD5) || - (mode == DRV_HASH_SHA384) || - (mode == DRV_HASH_SHA512))) { + (mode == DRV_HASH_SHA384) || + (mode == DRV_HASH_SHA512))) { set_bytes_swap(desc, 1); } else { set_cipher_config0(desc, HASH_DIGEST_RESULT_LITTLE_ENDIAN); @@ -136,13 +135,13 @@ static int ssi_hash_map_result(struct device *dev, DMA_BIDIRECTIONAL); if (unlikely(dma_mapping_error(dev, state->digest_result_dma_addr))) { SSI_LOG_ERR("Mapping digest result buffer %u B for DMA failed\n", - digestsize); + digestsize); return -ENOMEM; } SSI_LOG_DEBUG("Mapped digest result buffer %u B " - "at va=%pK to dma=0x%llX\n", + "at va=%pK to dma=%pad\n", digestsize, state->digest_result_buff, - (unsigned long long)state->digest_result_dma_addr); + state->digest_result_dma_addr); return 0; } @@ -201,12 +200,12 @@ static int ssi_hash_map_request(struct device *dev, state->digest_buff_dma_addr = dma_map_single(dev, (void *)state->digest_buff, ctx->inter_digestsize, DMA_BIDIRECTIONAL); if (dma_mapping_error(dev, state->digest_buff_dma_addr)) { SSI_LOG_ERR("Mapping digest len %d B at va=%pK for DMA failed\n", - ctx->inter_digestsize, state->digest_buff); + ctx->inter_digestsize, state->digest_buff); goto fail3; } - SSI_LOG_DEBUG("Mapped digest %d B at va=%pK to dma=0x%llX\n", - ctx->inter_digestsize, state->digest_buff, - (unsigned long long)state->digest_buff_dma_addr); + SSI_LOG_DEBUG("Mapped digest %d B at va=%pK to dma=%pad\n", + ctx->inter_digestsize, state->digest_buff, + state->digest_buff_dma_addr); if (is_hmac) { dma_sync_single_for_cpu(dev, ctx->digest_buff_dma_addr, ctx->inter_digestsize, DMA_BIDIRECTIONAL); @@ -250,12 +249,12 @@ static int ssi_hash_map_request(struct device *dev, state->digest_bytes_len_dma_addr = dma_map_single(dev, (void *)state->digest_bytes_len, HASH_LEN_SIZE, DMA_BIDIRECTIONAL); if (dma_mapping_error(dev, state->digest_bytes_len_dma_addr)) { SSI_LOG_ERR("Mapping digest len %u B at va=%pK for DMA failed\n", - HASH_LEN_SIZE, state->digest_bytes_len); + HASH_LEN_SIZE, state->digest_bytes_len); goto fail4; } - SSI_LOG_DEBUG("Mapped digest len %u B at va=%pK to dma=0x%llX\n", - HASH_LEN_SIZE, state->digest_bytes_len, - (unsigned long long)state->digest_bytes_len_dma_addr); + SSI_LOG_DEBUG("Mapped digest len %u B at va=%pK to dma=%pad\n", + HASH_LEN_SIZE, state->digest_bytes_len, + state->digest_bytes_len_dma_addr); } else { state->digest_bytes_len_dma_addr = 0; } @@ -264,12 +263,13 @@ static int ssi_hash_map_request(struct device *dev, state->opad_digest_dma_addr = dma_map_single(dev, (void *)state->opad_digest_buff, ctx->inter_digestsize, DMA_BIDIRECTIONAL); if (dma_mapping_error(dev, state->opad_digest_dma_addr)) { SSI_LOG_ERR("Mapping opad digest %d B at va=%pK for DMA failed\n", - ctx->inter_digestsize, state->opad_digest_buff); + ctx->inter_digestsize, + state->opad_digest_buff); goto fail5; } - SSI_LOG_DEBUG("Mapped opad digest %d B at va=%pK to dma=0x%llX\n", - ctx->inter_digestsize, state->opad_digest_buff, - (unsigned long long)state->opad_digest_dma_addr); + SSI_LOG_DEBUG("Mapped opad digest %d B at va=%pK to dma=%pad\n", + ctx->inter_digestsize, state->opad_digest_buff, + state->opad_digest_dma_addr); } else { state->opad_digest_dma_addr = 0; } @@ -297,20 +297,14 @@ fail2: fail1: kfree(state->digest_buff); fail_digest_result_buff: - if (state->digest_result_buff) { - kfree(state->digest_result_buff); - state->digest_result_buff = NULL; - } + kfree(state->digest_result_buff); + state->digest_result_buff = NULL; fail_buff1: - if (state->buff1) { - kfree(state->buff1); - state->buff1 = NULL; - } + kfree(state->buff1); + state->buff1 = NULL; fail_buff0: - if (state->buff0) { - kfree(state->buff0); - state->buff0 = NULL; - } + kfree(state->buff0); + state->buff0 = NULL; fail0: return rc; } @@ -322,22 +316,22 @@ static void ssi_hash_unmap_request(struct device *dev, if (state->digest_buff_dma_addr != 0) { dma_unmap_single(dev, state->digest_buff_dma_addr, ctx->inter_digestsize, DMA_BIDIRECTIONAL); - SSI_LOG_DEBUG("Unmapped digest-buffer: digest_buff_dma_addr=0x%llX\n", - (unsigned long long)state->digest_buff_dma_addr); + SSI_LOG_DEBUG("Unmapped digest-buffer: digest_buff_dma_addr=%pad\n", + state->digest_buff_dma_addr); state->digest_buff_dma_addr = 0; } if (state->digest_bytes_len_dma_addr != 0) { dma_unmap_single(dev, state->digest_bytes_len_dma_addr, HASH_LEN_SIZE, DMA_BIDIRECTIONAL); - SSI_LOG_DEBUG("Unmapped digest-bytes-len buffer: digest_bytes_len_dma_addr=0x%llX\n", - (unsigned long long)state->digest_bytes_len_dma_addr); + SSI_LOG_DEBUG("Unmapped digest-bytes-len buffer: digest_bytes_len_dma_addr=%pad\n", + state->digest_bytes_len_dma_addr); state->digest_bytes_len_dma_addr = 0; } if (state->opad_digest_dma_addr != 0) { dma_unmap_single(dev, state->opad_digest_dma_addr, ctx->inter_digestsize, DMA_BIDIRECTIONAL); - SSI_LOG_DEBUG("Unmapped opad-digest: opad_digest_dma_addr=0x%llX\n", - (unsigned long long)state->opad_digest_dma_addr); + SSI_LOG_DEBUG("Unmapped opad-digest: opad_digest_dma_addr=%pad\n", + state->opad_digest_dma_addr); state->opad_digest_dma_addr = 0; } @@ -359,9 +353,9 @@ static void ssi_hash_unmap_result(struct device *dev, digestsize, DMA_BIDIRECTIONAL); SSI_LOG_DEBUG("unmpa digest result buffer " - "va (%pK) pa (%llx) len %u\n", + "va (%pK) pa (%pad) len %u\n", state->digest_result_buff, - (unsigned long long)state->digest_result_dma_addr, + state->digest_result_dma_addr, digestsize); memcpy(result, state->digest_result_buff, @@ -431,8 +425,6 @@ static int ssi_hash_digest(struct ahash_req_ctx *state, SSI_LOG_DEBUG("===== %s-digest (%d) ====\n", is_hmac ? "hmac" : "hash", nbytes); - CHECK_AND_RETURN_UPON_FIPS_ERROR(); - if (unlikely(ssi_hash_map_request(dev, state, ctx) != 0)) { SSI_LOG_ERR("map_ahash_source() failed\n"); return -ENOMEM; @@ -596,16 +588,16 @@ static int ssi_hash_update(struct ahash_req_ctx *state, SSI_LOG_DEBUG("===== %s-update (%d) ====\n", ctx->is_hmac ? "hmac" : "hash", nbytes); - CHECK_AND_RETURN_UPON_FIPS_ERROR(); if (nbytes == 0) { /* no real updates required */ return 0; } - if (unlikely(rc = ssi_buffer_mgr_map_hash_request_update(ctx->drvdata, state, src, nbytes, block_size))) { + rc = ssi_buffer_mgr_map_hash_request_update(ctx->drvdata, state, src, nbytes, block_size); + if (unlikely(rc)) { if (rc == 1) { SSI_LOG_DEBUG(" data size not require HW update %x\n", - nbytes); + nbytes); /* No hardware updates are required */ return 0; } @@ -693,8 +685,6 @@ static int ssi_hash_finup(struct ahash_req_ctx *state, SSI_LOG_DEBUG("===== %s-finup (%d) ====\n", is_hmac ? "hmac" : "hash", nbytes); - CHECK_AND_RETURN_UPON_FIPS_ERROR(); - if (unlikely(ssi_buffer_mgr_map_hash_request_final(ctx->drvdata, state, src, nbytes, 1) != 0)) { SSI_LOG_ERR("map_ahash_request_final() failed\n"); return -ENOMEM; @@ -829,8 +819,6 @@ static int ssi_hash_final(struct ahash_req_ctx *state, SSI_LOG_DEBUG("===== %s-final (%d) ====\n", is_hmac ? "hmac" : "hash", nbytes); - CHECK_AND_RETURN_UPON_FIPS_ERROR(); - if (unlikely(ssi_buffer_mgr_map_hash_request_final(ctx->drvdata, state, src, nbytes, 0) != 0)) { SSI_LOG_ERR("map_ahash_request_final() failed\n"); return -ENOMEM; @@ -964,7 +952,6 @@ static int ssi_hash_init(struct ahash_req_ctx *state, struct ssi_hash_ctx *ctx) state->xcbc_count = 0; - CHECK_AND_RETURN_UPON_FIPS_ERROR(); ssi_hash_map_request(dev, state, ctx); return 0; @@ -975,7 +962,7 @@ static int ssi_hash_setkey(void *hash, unsigned int keylen, bool synchronize) { - unsigned int hmacPadConst[2] = { HMAC_IPAD_CONST, HMAC_OPAD_CONST }; + unsigned int hmac_pad_const[2] = { HMAC_IPAD_CONST, HMAC_OPAD_CONST }; struct ssi_crypto_req ssi_req = {}; struct ssi_hash_ctx *ctx = NULL; int blocksize = 0; @@ -984,9 +971,8 @@ static int ssi_hash_setkey(void *hash, struct cc_hw_desc desc[SSI_MAX_AHASH_SEQ_LEN]; ssi_sram_addr_t larval_addr; - SSI_LOG_DEBUG("ssi_hash_setkey: start keylen: %d", keylen); + SSI_LOG_DEBUG("start keylen: %d", keylen); - CHECK_AND_RETURN_UPON_FIPS_ERROR(); ctx = crypto_ahash_ctx(((struct crypto_ahash *)hash)); blocksize = crypto_tfm_alg_blocksize(&((struct crypto_ahash *)hash)->base); digestsize = crypto_ahash_digestsize(((struct crypto_ahash *)hash)); @@ -1012,9 +998,8 @@ static int ssi_hash_setkey(void *hash, " DMA failed\n", key, keylen); return -ENOMEM; } - SSI_LOG_DEBUG("mapping key-buffer: key_dma_addr=0x%llX " - "keylen=%u\n", - (unsigned long long)ctx->key_params.key_dma_addr, + SSI_LOG_DEBUG("mapping key-buffer: key_dma_addr=%pad " + "keylen=%u\n", ctx->key_params.key_dma_addr, ctx->key_params.keylen); if (keylen > blocksize) { @@ -1118,7 +1103,7 @@ static int ssi_hash_setkey(void *hash, /* Prepare ipad key */ hw_desc_init(&desc[idx]); - set_xor_val(&desc[idx], hmacPadConst[i]); + set_xor_val(&desc[idx], hmac_pad_const[i]); set_cipher_mode(&desc[idx], ctx->hw_mode); set_flow_mode(&desc[idx], S_DIN_to_HASH); set_setup_mode(&desc[idx], SETUP_LOAD_STATE1); @@ -1155,17 +1140,17 @@ out: if (ctx->key_params.key_dma_addr) { dma_unmap_single(&ctx->drvdata->plat_dev->dev, - ctx->key_params.key_dma_addr, - ctx->key_params.keylen, DMA_TO_DEVICE); - SSI_LOG_DEBUG("Unmapped key-buffer: key_dma_addr=0x%llX keylen=%u\n", - (unsigned long long)ctx->key_params.key_dma_addr, - ctx->key_params.keylen); + ctx->key_params.key_dma_addr, + ctx->key_params.keylen, DMA_TO_DEVICE); + SSI_LOG_DEBUG("Unmapped key-buffer: key_dma_addr=%pad keylen=%u\n", + ctx->key_params.key_dma_addr, + ctx->key_params.keylen); } return rc; } static int ssi_xcbc_setkey(struct crypto_ahash *ahash, - const u8 *key, unsigned int keylen) + const u8 *key, unsigned int keylen) { struct ssi_crypto_req ssi_req = {}; struct ssi_hash_ctx *ctx = crypto_ahash_ctx(ahash); @@ -1173,15 +1158,14 @@ static int ssi_xcbc_setkey(struct crypto_ahash *ahash, struct cc_hw_desc desc[SSI_MAX_AHASH_SEQ_LEN]; SSI_LOG_DEBUG("===== setkey (%d) ====\n", keylen); - CHECK_AND_RETURN_UPON_FIPS_ERROR(); switch (keylen) { - case AES_KEYSIZE_128: - case AES_KEYSIZE_192: - case AES_KEYSIZE_256: - break; - default: - return -EINVAL; + case AES_KEYSIZE_128: + case AES_KEYSIZE_192: + case AES_KEYSIZE_256: + break; + default: + return -EINVAL; } ctx->key_params.keylen = keylen; @@ -1196,9 +1180,9 @@ static int ssi_xcbc_setkey(struct crypto_ahash *ahash, " DMA failed\n", key, keylen); return -ENOMEM; } - SSI_LOG_DEBUG("mapping key-buffer: key_dma_addr=0x%llX " + SSI_LOG_DEBUG("mapping key-buffer: key_dma_addr=%pad " "keylen=%u\n", - (unsigned long long)ctx->key_params.key_dma_addr, + ctx->key_params.key_dma_addr, ctx->key_params.keylen); ctx->is_hmac = true; @@ -1243,33 +1227,32 @@ static int ssi_xcbc_setkey(struct crypto_ahash *ahash, crypto_ahash_set_flags(ahash, CRYPTO_TFM_RES_BAD_KEY_LEN); dma_unmap_single(&ctx->drvdata->plat_dev->dev, - ctx->key_params.key_dma_addr, - ctx->key_params.keylen, DMA_TO_DEVICE); - SSI_LOG_DEBUG("Unmapped key-buffer: key_dma_addr=0x%llX keylen=%u\n", - (unsigned long long)ctx->key_params.key_dma_addr, - ctx->key_params.keylen); + ctx->key_params.key_dma_addr, + ctx->key_params.keylen, DMA_TO_DEVICE); + SSI_LOG_DEBUG("Unmapped key-buffer: key_dma_addr=%pad keylen=%u\n", + ctx->key_params.key_dma_addr, + ctx->key_params.keylen); return rc; } #if SSI_CC_HAS_CMAC static int ssi_cmac_setkey(struct crypto_ahash *ahash, - const u8 *key, unsigned int keylen) + const u8 *key, unsigned int keylen) { struct ssi_hash_ctx *ctx = crypto_ahash_ctx(ahash); SSI_LOG_DEBUG("===== setkey (%d) ====\n", keylen); - CHECK_AND_RETURN_UPON_FIPS_ERROR(); ctx->is_hmac = true; switch (keylen) { - case AES_KEYSIZE_128: - case AES_KEYSIZE_192: - case AES_KEYSIZE_256: - break; - default: - return -EINVAL; + case AES_KEYSIZE_128: + case AES_KEYSIZE_192: + case AES_KEYSIZE_256: + break; + default: + return -EINVAL; } ctx->key_params.keylen = keylen; @@ -1302,8 +1285,8 @@ static void ssi_hash_free_ctx(struct ssi_hash_ctx *ctx) dma_unmap_single(dev, ctx->digest_buff_dma_addr, sizeof(ctx->digest_buff), DMA_BIDIRECTIONAL); SSI_LOG_DEBUG("Unmapped digest-buffer: " - "digest_buff_dma_addr=0x%llX\n", - (unsigned long long)ctx->digest_buff_dma_addr); + "digest_buff_dma_addr=%pad\n", + ctx->digest_buff_dma_addr); ctx->digest_buff_dma_addr = 0; } if (ctx->opad_tmp_keys_dma_addr != 0) { @@ -1311,8 +1294,8 @@ static void ssi_hash_free_ctx(struct ssi_hash_ctx *ctx) sizeof(ctx->opad_tmp_keys_buff), DMA_BIDIRECTIONAL); SSI_LOG_DEBUG("Unmapped opad-digest: " - "opad_tmp_keys_dma_addr=0x%llX\n", - (unsigned long long)ctx->opad_tmp_keys_dma_addr); + "opad_tmp_keys_dma_addr=%pad\n", + ctx->opad_tmp_keys_dma_addr); ctx->opad_tmp_keys_dma_addr = 0; } @@ -1328,23 +1311,23 @@ static int ssi_hash_alloc_ctx(struct ssi_hash_ctx *ctx) ctx->digest_buff_dma_addr = dma_map_single(dev, (void *)ctx->digest_buff, sizeof(ctx->digest_buff), DMA_BIDIRECTIONAL); if (dma_mapping_error(dev, ctx->digest_buff_dma_addr)) { SSI_LOG_ERR("Mapping digest len %zu B at va=%pK for DMA failed\n", - sizeof(ctx->digest_buff), ctx->digest_buff); + sizeof(ctx->digest_buff), ctx->digest_buff); goto fail; } - SSI_LOG_DEBUG("Mapped digest %zu B at va=%pK to dma=0x%llX\n", - sizeof(ctx->digest_buff), ctx->digest_buff, - (unsigned long long)ctx->digest_buff_dma_addr); + SSI_LOG_DEBUG("Mapped digest %zu B at va=%pK to dma=%pad\n", + sizeof(ctx->digest_buff), ctx->digest_buff, + ctx->digest_buff_dma_addr); ctx->opad_tmp_keys_dma_addr = dma_map_single(dev, (void *)ctx->opad_tmp_keys_buff, sizeof(ctx->opad_tmp_keys_buff), DMA_BIDIRECTIONAL); if (dma_mapping_error(dev, ctx->opad_tmp_keys_dma_addr)) { SSI_LOG_ERR("Mapping opad digest %zu B at va=%pK for DMA failed\n", - sizeof(ctx->opad_tmp_keys_buff), - ctx->opad_tmp_keys_buff); + sizeof(ctx->opad_tmp_keys_buff), + ctx->opad_tmp_keys_buff); goto fail; } - SSI_LOG_DEBUG("Mapped opad_tmp_keys %zu B at va=%pK to dma=0x%llX\n", - sizeof(ctx->opad_tmp_keys_buff), ctx->opad_tmp_keys_buff, - (unsigned long long)ctx->opad_tmp_keys_dma_addr); + SSI_LOG_DEBUG("Mapped opad_tmp_keys %zu B at va=%pK to dma=%pad\n", + sizeof(ctx->opad_tmp_keys_buff), ctx->opad_tmp_keys_buff, + ctx->opad_tmp_keys_dma_addr); ctx->is_hmac = false; return 0; @@ -1364,9 +1347,8 @@ static int ssi_ahash_cra_init(struct crypto_tfm *tfm) struct ssi_hash_alg *ssi_alg = container_of(ahash_alg, struct ssi_hash_alg, ahash_alg); - CHECK_AND_RETURN_UPON_FIPS_ERROR(); crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), - sizeof(struct ahash_req_ctx)); + sizeof(struct ahash_req_ctx)); ctx->hash_mode = ssi_alg->hash_mode; ctx->hw_mode = ssi_alg->hw_mode; @@ -1396,7 +1378,6 @@ static int ssi_mac_update(struct ahash_request *req) int rc; u32 idx = 0; - CHECK_AND_RETURN_UPON_FIPS_ERROR(); if (req->nbytes == 0) { /* no real updates required */ return 0; @@ -1404,10 +1385,11 @@ static int ssi_mac_update(struct ahash_request *req) state->xcbc_count++; - if (unlikely(rc = ssi_buffer_mgr_map_hash_request_update(ctx->drvdata, state, req->src, req->nbytes, block_size))) { + rc = ssi_buffer_mgr_map_hash_request_update(ctx->drvdata, state, req->src, req->nbytes, block_size); + if (unlikely(rc)) { if (rc == 1) { SSI_LOG_DEBUG(" data size not require HW update %x\n", - req->nbytes); + req->nbytes); /* No hardware updates are required */ return 0; } @@ -1454,19 +1436,19 @@ static int ssi_mac_final(struct ahash_request *req) struct cc_hw_desc desc[SSI_MAX_AHASH_SEQ_LEN]; int idx = 0; int rc = 0; - u32 keySize, keyLen; + u32 key_size, key_len; u32 digestsize = crypto_ahash_digestsize(tfm); u32 rem_cnt = state->buff_index ? state->buff1_cnt : state->buff0_cnt; - CHECK_AND_RETURN_UPON_FIPS_ERROR(); if (ctx->hw_mode == DRV_CIPHER_XCBC_MAC) { - keySize = CC_AES_128_BIT_KEY_SIZE; - keyLen = CC_AES_128_BIT_KEY_SIZE; + key_size = CC_AES_128_BIT_KEY_SIZE; + key_len = CC_AES_128_BIT_KEY_SIZE; } else { - keySize = (ctx->key_params.keylen == 24) ? AES_MAX_KEY_SIZE : ctx->key_params.keylen; - keyLen = ctx->key_params.keylen; + key_size = (ctx->key_params.keylen == 24) ? AES_MAX_KEY_SIZE : + ctx->key_params.keylen; + key_len = ctx->key_params.keylen; } SSI_LOG_DEBUG("===== final xcbc reminder (%d) ====\n", rem_cnt); @@ -1492,8 +1474,8 @@ static int ssi_mac_final(struct ahash_request *req) set_cipher_config0(&desc[idx], DRV_CRYPTO_DIRECTION_DECRYPT); set_din_type(&desc[idx], DMA_DLLI, (ctx->opad_tmp_keys_dma_addr + - XCBC_MAC_K1_OFFSET), keySize, NS_BIT); - set_key_size_aes(&desc[idx], keyLen); + XCBC_MAC_K1_OFFSET), key_size, NS_BIT); + set_key_size_aes(&desc[idx], key_len); set_flow_mode(&desc[idx], S_DIN_to_AES); set_setup_mode(&desc[idx], SETUP_LOAD_KEY0); idx++; @@ -1522,7 +1504,7 @@ static int ssi_mac_final(struct ahash_request *req) if (state->xcbc_count == 0) { hw_desc_init(&desc[idx]); set_cipher_mode(&desc[idx], ctx->hw_mode); - set_key_size_aes(&desc[idx], keyLen); + set_key_size_aes(&desc[idx], key_len); set_cmac_size0_mode(&desc[idx]); set_flow_mode(&desc[idx], S_DIN_to_AES); idx++; @@ -1569,9 +1551,8 @@ static int ssi_mac_finup(struct ahash_request *req) u32 digestsize = crypto_ahash_digestsize(tfm); SSI_LOG_DEBUG("===== finup xcbc(%d) ====\n", req->nbytes); - CHECK_AND_RETURN_UPON_FIPS_ERROR(); if (state->xcbc_count > 0 && req->nbytes == 0) { - SSI_LOG_DEBUG("No data to update. Call to fdx_mac_final \n"); + SSI_LOG_DEBUG("No data to update. Call to fdx_mac_final\n"); return ssi_mac_final(req); } @@ -1636,12 +1617,11 @@ static int ssi_mac_digest(struct ahash_request *req) u32 digestsize = crypto_ahash_digestsize(tfm); struct ssi_crypto_req ssi_req = {}; struct cc_hw_desc desc[SSI_MAX_AHASH_SEQ_LEN]; - u32 keyLen; + u32 key_len; int idx = 0; int rc; SSI_LOG_DEBUG("===== -digest mac (%d) ====\n", req->nbytes); - CHECK_AND_RETURN_UPON_FIPS_ERROR(); if (unlikely(ssi_hash_map_request(dev, state, ctx) != 0)) { SSI_LOG_ERR("map_ahash_source() failed\n"); @@ -1662,17 +1642,17 @@ static int ssi_mac_digest(struct ahash_request *req) ssi_req.user_arg = (void *)req; if (ctx->hw_mode == DRV_CIPHER_XCBC_MAC) { - keyLen = CC_AES_128_BIT_KEY_SIZE; + key_len = CC_AES_128_BIT_KEY_SIZE; ssi_hash_create_xcbc_setup(req, desc, &idx); } else { - keyLen = ctx->key_params.keylen; + key_len = ctx->key_params.keylen; ssi_hash_create_cmac_setup(req, desc, &idx); } if (req->nbytes == 0) { hw_desc_init(&desc[idx]); set_cipher_mode(&desc[idx], ctx->hw_mode); - set_key_size_aes(&desc[idx], keyLen); + set_key_size_aes(&desc[idx], key_len); set_cmac_size0_mode(&desc[idx]); set_flow_mode(&desc[idx], S_DIN_to_AES); idx++; @@ -1764,8 +1744,6 @@ static int ssi_ahash_export(struct ahash_request *req, void *out) state->buff0_cnt; const u32 tmp = CC_EXPORT_MAGIC; - CHECK_AND_RETURN_UPON_FIPS_ERROR(); - memcpy(out, &tmp, sizeof(u32)); out += sizeof(u32); @@ -1805,8 +1783,6 @@ static int ssi_ahash_import(struct ahash_request *req, const void *in) u32 tmp; int rc; - CHECK_AND_RETURN_UPON_FIPS_ERROR(); - memcpy(&tmp, in, sizeof(u32)); if (tmp != CC_EXPORT_MAGIC) { rc = -EINVAL; @@ -1856,7 +1832,7 @@ out: } static int ssi_ahash_setkey(struct crypto_ahash *ahash, - const u8 *key, unsigned int keylen) + const u8 *key, unsigned int keylen) { return ssi_hash_setkey((void *)ahash, key, keylen, false); } @@ -2084,9 +2060,9 @@ ssi_hash_create_alg(struct ssi_hash_template *template, bool keyed) struct crypto_alg *alg; struct ahash_alg *halg; - t_crypto_alg = kzalloc(sizeof(struct ssi_hash_alg), GFP_KERNEL); + t_crypto_alg = kzalloc(sizeof(*t_crypto_alg), GFP_KERNEL); if (!t_crypto_alg) { - SSI_LOG_ERR("failed to allocate t_alg\n"); + SSI_LOG_ERR("failed to allocate t_crypto_alg\n"); return ERR_PTR(-ENOMEM); } @@ -2138,7 +2114,8 @@ int ssi_hash_init_sram_digest_consts(struct ssi_drvdata *drvdata) /* Copy-to-sram digest-len */ ssi_sram_mgr_const2sram_desc(digest_len_init, sram_buff_ofs, - ARRAY_SIZE(digest_len_init), larval_seq, &larval_seq_len); + ARRAY_SIZE(digest_len_init), + larval_seq, &larval_seq_len); rc = send_request_init(drvdata, larval_seq, larval_seq_len); if (unlikely(rc != 0)) goto init_digest_const_err; @@ -2149,7 +2126,8 @@ int ssi_hash_init_sram_digest_consts(struct ssi_drvdata *drvdata) #if (DX_DEV_SHA_MAX > 256) /* Copy-to-sram digest-len for sha384/512 */ ssi_sram_mgr_const2sram_desc(digest_len_sha512_init, sram_buff_ofs, - ARRAY_SIZE(digest_len_sha512_init), larval_seq, &larval_seq_len); + ARRAY_SIZE(digest_len_sha512_init), + larval_seq, &larval_seq_len); rc = send_request_init(drvdata, larval_seq, larval_seq_len); if (unlikely(rc != 0)) goto init_digest_const_err; @@ -2163,7 +2141,8 @@ int ssi_hash_init_sram_digest_consts(struct ssi_drvdata *drvdata) /* Copy-to-sram initial SHA* digests */ ssi_sram_mgr_const2sram_desc(md5_init, sram_buff_ofs, - ARRAY_SIZE(md5_init), larval_seq, &larval_seq_len); + ARRAY_SIZE(md5_init), larval_seq, + &larval_seq_len); rc = send_request_init(drvdata, larval_seq, larval_seq_len); if (unlikely(rc != 0)) goto init_digest_const_err; @@ -2171,7 +2150,8 @@ int ssi_hash_init_sram_digest_consts(struct ssi_drvdata *drvdata) larval_seq_len = 0; ssi_sram_mgr_const2sram_desc(sha1_init, sram_buff_ofs, - ARRAY_SIZE(sha1_init), larval_seq, &larval_seq_len); + ARRAY_SIZE(sha1_init), larval_seq, + &larval_seq_len); rc = send_request_init(drvdata, larval_seq, larval_seq_len); if (unlikely(rc != 0)) goto init_digest_const_err; @@ -2179,7 +2159,8 @@ int ssi_hash_init_sram_digest_consts(struct ssi_drvdata *drvdata) larval_seq_len = 0; ssi_sram_mgr_const2sram_desc(sha224_init, sram_buff_ofs, - ARRAY_SIZE(sha224_init), larval_seq, &larval_seq_len); + ARRAY_SIZE(sha224_init), larval_seq, + &larval_seq_len); rc = send_request_init(drvdata, larval_seq, larval_seq_len); if (unlikely(rc != 0)) goto init_digest_const_err; @@ -2187,7 +2168,8 @@ int ssi_hash_init_sram_digest_consts(struct ssi_drvdata *drvdata) larval_seq_len = 0; ssi_sram_mgr_const2sram_desc(sha256_init, sram_buff_ofs, - ARRAY_SIZE(sha256_init), larval_seq, &larval_seq_len); + ARRAY_SIZE(sha256_init), larval_seq, + &larval_seq_len); rc = send_request_init(drvdata, larval_seq, larval_seq_len); if (unlikely(rc != 0)) goto init_digest_const_err; @@ -2201,10 +2183,10 @@ int ssi_hash_init_sram_digest_consts(struct ssi_drvdata *drvdata) const u32 const1 = ((u32 *)((u64 *)&sha384_init[i]))[0]; ssi_sram_mgr_const2sram_desc(&const0, sram_buff_ofs, 1, - larval_seq, &larval_seq_len); + larval_seq, &larval_seq_len); sram_buff_ofs += sizeof(u32); ssi_sram_mgr_const2sram_desc(&const1, sram_buff_ofs, 1, - larval_seq, &larval_seq_len); + larval_seq, &larval_seq_len); sram_buff_ofs += sizeof(u32); } rc = send_request_init(drvdata, larval_seq, larval_seq_len); @@ -2219,10 +2201,10 @@ int ssi_hash_init_sram_digest_consts(struct ssi_drvdata *drvdata) const u32 const1 = ((u32 *)((u64 *)&sha512_init[i]))[0]; ssi_sram_mgr_const2sram_desc(&const0, sram_buff_ofs, 1, - larval_seq, &larval_seq_len); + larval_seq, &larval_seq_len); sram_buff_ofs += sizeof(u32); ssi_sram_mgr_const2sram_desc(&const1, sram_buff_ofs, 1, - larval_seq, &larval_seq_len); + larval_seq, &larval_seq_len); sram_buff_ofs += sizeof(u32); } rc = send_request_init(drvdata, larval_seq, larval_seq_len); @@ -2244,10 +2226,10 @@ int ssi_hash_alloc(struct ssi_drvdata *drvdata) int rc = 0; int alg; - hash_handle = kzalloc(sizeof(struct ssi_hash_handle), GFP_KERNEL); + hash_handle = kzalloc(sizeof(*hash_handle), GFP_KERNEL); if (!hash_handle) { SSI_LOG_ERR("kzalloc failed to allocate %zu B\n", - sizeof(struct ssi_hash_handle)); + sizeof(*hash_handle)); rc = -ENOMEM; goto fail; } @@ -2319,7 +2301,7 @@ int ssi_hash_alloc(struct ssi_drvdata *drvdata) if (IS_ERR(t_alg)) { rc = PTR_ERR(t_alg); SSI_LOG_ERR("%s alg allocation failed\n", - driver_hash[alg].driver_name); + driver_hash[alg].driver_name); goto fail; } t_alg->drvdata = drvdata; @@ -2338,11 +2320,8 @@ int ssi_hash_alloc(struct ssi_drvdata *drvdata) return 0; fail: - - if (drvdata->hash_handle) { - kfree(drvdata->hash_handle); - drvdata->hash_handle = NULL; - } + kfree(drvdata->hash_handle); + drvdata->hash_handle = NULL; return rc; } @@ -2365,8 +2344,9 @@ int ssi_hash_free(struct ssi_drvdata *drvdata) } static void ssi_hash_create_xcbc_setup(struct ahash_request *areq, - struct cc_hw_desc desc[], - unsigned int *seq_size) { + struct cc_hw_desc desc[], + unsigned int *seq_size) +{ unsigned int idx = *seq_size; struct ahash_req_ctx *state = ahash_request_ctx(areq); struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq); @@ -2422,8 +2402,8 @@ static void ssi_hash_create_xcbc_setup(struct ahash_request *areq, } static void ssi_hash_create_cmac_setup(struct ahash_request *areq, - struct cc_hw_desc desc[], - unsigned int *seq_size) + struct cc_hw_desc desc[], + unsigned int *seq_size) { unsigned int idx = *seq_size; struct ahash_req_ctx *state = ahash_request_ctx(areq); diff --git a/drivers/staging/ccree/ssi_ivgen.c b/drivers/staging/ccree/ssi_ivgen.c index 5ff3368c04d9..b01e03231947 100644 --- a/drivers/staging/ccree/ssi_ivgen.c +++ b/drivers/staging/ccree/ssi_ivgen.c @@ -158,7 +158,7 @@ int ssi_ivgen_init_sram_pool(struct ssi_drvdata *drvdata) void ssi_ivgen_fini(struct ssi_drvdata *drvdata) { struct ssi_ivgen_ctx *ivgen_ctx = drvdata->ivgen_handle; - struct device *device = &(drvdata->plat_dev->dev); + struct device *device = &drvdata->plat_dev->dev; if (!ivgen_ctx) return; @@ -166,7 +166,8 @@ void ssi_ivgen_fini(struct ssi_drvdata *drvdata) if (ivgen_ctx->pool_meta) { memset(ivgen_ctx->pool_meta, 0, SSI_IVPOOL_META_SIZE); dma_free_coherent(device, SSI_IVPOOL_META_SIZE, - ivgen_ctx->pool_meta, ivgen_ctx->pool_meta_dma); + ivgen_ctx->pool_meta, + ivgen_ctx->pool_meta_dma); } ivgen_ctx->pool = NULL_SRAM_ADDR; @@ -190,10 +191,11 @@ int ssi_ivgen_init(struct ssi_drvdata *drvdata) int rc; /* Allocate "this" context */ - drvdata->ivgen_handle = kzalloc(sizeof(struct ssi_ivgen_ctx), GFP_KERNEL); + drvdata->ivgen_handle = kzalloc(sizeof(*drvdata->ivgen_handle), + GFP_KERNEL); if (!drvdata->ivgen_handle) { SSI_LOG_ERR("Not enough memory to allocate IVGEN context " - "(%zu B)\n", sizeof(struct ssi_ivgen_ctx)); + "(%zu B)\n", sizeof(*drvdata->ivgen_handle)); rc = -ENOMEM; goto out; } @@ -201,7 +203,8 @@ int ssi_ivgen_init(struct ssi_drvdata *drvdata) /* Allocate pool's header for intial enc. key/IV */ ivgen_ctx->pool_meta = dma_alloc_coherent(device, SSI_IVPOOL_META_SIZE, - &ivgen_ctx->pool_meta_dma, GFP_KERNEL); + &ivgen_ctx->pool_meta_dma, + GFP_KERNEL); if (!ivgen_ctx->pool_meta) { SSI_LOG_ERR("Not enough memory to allocate DMA of pool_meta " "(%u B)\n", SSI_IVPOOL_META_SIZE); diff --git a/drivers/staging/ccree/ssi_pm.c b/drivers/staging/ccree/ssi_pm.c index 52a8ed579177..31325e6cd4b4 100644 --- a/drivers/staging/ccree/ssi_pm.c +++ b/drivers/staging/ccree/ssi_pm.c @@ -40,7 +40,7 @@ int ssi_power_mgr_runtime_suspend(struct device *dev) (struct ssi_drvdata *)dev_get_drvdata(dev); int rc; - SSI_LOG_DEBUG("ssi_power_mgr_runtime_suspend: set HOST_POWER_DOWN_EN\n"); + SSI_LOG_DEBUG("set HOST_POWER_DOWN_EN\n"); WRITE_REGISTER(drvdata->cc_base + CC_REG_OFFSET(HOST_RGF, HOST_POWER_DOWN_EN), POWER_DOWN_ENABLE); rc = ssi_request_mgr_runtime_suspend_queue(drvdata); if (rc != 0) { @@ -58,7 +58,7 @@ int ssi_power_mgr_runtime_resume(struct device *dev) struct ssi_drvdata *drvdata = (struct ssi_drvdata *)dev_get_drvdata(dev); - SSI_LOG_DEBUG("ssi_power_mgr_runtime_resume , unset HOST_POWER_DOWN_EN\n"); + SSI_LOG_DEBUG("unset HOST_POWER_DOWN_EN\n"); WRITE_REGISTER(drvdata->cc_base + CC_REG_OFFSET(HOST_RGF, HOST_POWER_DOWN_EN), POWER_DOWN_DISABLE); rc = cc_clk_on(drvdata); diff --git a/drivers/staging/ccree/ssi_request_mgr.c b/drivers/staging/ccree/ssi_request_mgr.c index 46d9396f9ff9..e5c2f92857f6 100644 --- a/drivers/staging/ccree/ssi_request_mgr.c +++ b/drivers/staging/ccree/ssi_request_mgr.c @@ -30,8 +30,6 @@ #include "ssi_sysfs.h" #include "ssi_ivgen.h" #include "ssi_pm.h" -#include "ssi_fips.h" -#include "ssi_fips_local.h" #define SSI_MAX_POLL_ITER 10 @@ -102,7 +100,7 @@ int request_mgr_init(struct ssi_drvdata *drvdata) struct ssi_request_mgr_handle *req_mgr_h; int rc = 0; - req_mgr_h = kzalloc(sizeof(struct ssi_request_mgr_handle), GFP_KERNEL); + req_mgr_h = kzalloc(sizeof(*req_mgr_h), GFP_KERNEL); if (!req_mgr_h) { rc = -ENOMEM; goto req_mgr_init_err; @@ -129,7 +127,7 @@ int request_mgr_init(struct ssi_drvdata *drvdata) SSI_LOG_DEBUG("hw_queue_size=0x%08X\n", req_mgr_h->hw_queue_size); if (req_mgr_h->hw_queue_size < MIN_HW_QUEUE_SIZE) { SSI_LOG_ERR("Invalid HW queue size = %u (Min. required is %u)\n", - req_mgr_h->hw_queue_size, MIN_HW_QUEUE_SIZE); + req_mgr_h->hw_queue_size, MIN_HW_QUEUE_SIZE); rc = -ENOMEM; goto req_mgr_init_err; } @@ -138,7 +136,9 @@ int request_mgr_init(struct ssi_drvdata *drvdata) /* Allocate DMA word for "dummy" completion descriptor use */ req_mgr_h->dummy_comp_buff = dma_alloc_coherent(&drvdata->plat_dev->dev, - sizeof(u32), &req_mgr_h->dummy_comp_buff_dma, GFP_KERNEL); + sizeof(u32), + &req_mgr_h->dummy_comp_buff_dma, + GFP_KERNEL); if (!req_mgr_h->dummy_comp_buff) { SSI_LOG_ERR("Not enough memory to allocate DMA (%zu) dropped " "buffer\n", sizeof(u32)); @@ -177,7 +177,8 @@ static inline void enqueue_seq( writel_relaxed(seq[i].word[5], (volatile void __iomem *)(cc_base + CC_REG_OFFSET(CRY_KERNEL, DSCRPTR_QUEUE_WORD0))); #ifdef DX_DUMP_DESCS SSI_LOG_DEBUG("desc[%02d]: 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n", i, - seq[i].word[0], seq[i].word[1], seq[i].word[2], seq[i].word[3], seq[i].word[4], seq[i].word[5]); + seq[i].word[0], seq[i].word[1], seq[i].word[2], + seq[i].word[3], seq[i].word[4], seq[i].word[5]); #endif } } @@ -211,7 +212,7 @@ static inline int request_mgr_queues_status_check( (MAX_REQUEST_QUEUE_SIZE - 1)) == req_mgr_h->req_queue_tail)) { SSI_LOG_ERR("SW FIFO is full. req_queue_head=%d sw_fifo_len=%d\n", - req_mgr_h->req_queue_head, MAX_REQUEST_QUEUE_SIZE); + req_mgr_h->req_queue_head, MAX_REQUEST_QUEUE_SIZE); return -EBUSY; } @@ -221,9 +222,8 @@ static inline int request_mgr_queues_status_check( /* Wait for space in HW queue. Poll constant num of iterations. */ for (poll_queue = 0; poll_queue < SSI_MAX_POLL_ITER ; poll_queue++) { req_mgr_h->q_free_slots = - CC_HAL_READ_REGISTER( - CC_REG_OFFSET(CRY_KERNEL, - DSCRPTR_QUEUE_CONTENT)); + CC_HAL_READ_REGISTER(CC_REG_OFFSET(CRY_KERNEL, + DSCRPTR_QUEUE_CONTENT)); if (unlikely(req_mgr_h->q_free_slots < req_mgr_h->min_free_hw_slots)) { req_mgr_h->min_free_hw_slots = req_mgr_h->q_free_slots; @@ -235,7 +235,7 @@ static inline int request_mgr_queues_status_check( } SSI_LOG_DEBUG("HW FIFO is full. q_free_slots=%d total_seq_len=%d\n", - req_mgr_h->q_free_slots, total_seq_len); + req_mgr_h->q_free_slots, total_seq_len); } /* No room in the HW queue try again later */ SSI_LOG_DEBUG("HW FIFO full, timeout. req_queue_head=%d " @@ -291,9 +291,8 @@ int send_request( * in case iv gen add the max size and in case of no dout add 1 * for the internal completion descriptor */ - rc = request_mgr_queues_status_check(req_mgr_h, - cc_base, - max_required_seq_len); + rc = request_mgr_queues_status_check(req_mgr_h, cc_base, + max_required_seq_len); if (likely(rc == 0)) /* There is enough place in the queue */ break; @@ -320,21 +319,22 @@ int send_request( if (!is_dout) { init_completion(&ssi_req->seq_compl); ssi_req->user_cb = request_mgr_complete; - ssi_req->user_arg = &(ssi_req->seq_compl); + ssi_req->user_arg = &ssi_req->seq_compl; total_seq_len++; } if (ssi_req->ivgen_dma_addr_len > 0) { - SSI_LOG_DEBUG("Acquire IV from pool into %d DMA addresses 0x%llX, 0x%llX, 0x%llX, IV-size=%u\n", - ssi_req->ivgen_dma_addr_len, - (unsigned long long)ssi_req->ivgen_dma_addr[0], - (unsigned long long)ssi_req->ivgen_dma_addr[1], - (unsigned long long)ssi_req->ivgen_dma_addr[2], - ssi_req->ivgen_size); + SSI_LOG_DEBUG("Acquire IV from pool into %d DMA addresses %pad, %pad, %pad, IV-size=%u\n", + ssi_req->ivgen_dma_addr_len, + ssi_req->ivgen_dma_addr[0], + ssi_req->ivgen_dma_addr[1], + ssi_req->ivgen_dma_addr[2], + ssi_req->ivgen_size); /* Acquire IV from pool */ - rc = ssi_ivgen_getiv(drvdata, ssi_req->ivgen_dma_addr, ssi_req->ivgen_dma_addr_len, - ssi_req->ivgen_size, iv_seq, &iv_seq_len); + rc = ssi_ivgen_getiv(drvdata, ssi_req->ivgen_dma_addr, + ssi_req->ivgen_dma_addr_len, + ssi_req->ivgen_size, iv_seq, &iv_seq_len); if (unlikely(rc != 0)) { SSI_LOG_ERR("Failed to generate IV (rc=%d)\n", rc); @@ -418,9 +418,8 @@ int send_request_init( enqueue_seq(cc_base, desc, len); /* Update the free slots in HW queue */ - req_mgr_h->q_free_slots = CC_HAL_READ_REGISTER( - CC_REG_OFFSET(CRY_KERNEL, - DSCRPTR_QUEUE_CONTENT)); + req_mgr_h->q_free_slots = CC_HAL_READ_REGISTER(CC_REG_OFFSET(CRY_KERNEL, + DSCRPTR_QUEUE_CONTENT)); return 0; } @@ -545,8 +544,7 @@ static void comp_handler(unsigned long devarg) } /* after verifing that there is nothing to do, Unmask AXI completion interrupt */ CC_HAL_WRITE_REGISTER(CC_REG_OFFSET(HOST_RGF, HOST_IMR), - CC_HAL_READ_REGISTER( - CC_REG_OFFSET(HOST_RGF, HOST_IMR)) & ~irq); + CC_HAL_READ_REGISTER(CC_REG_OFFSET(HOST_RGF, HOST_IMR)) & ~irq); } /* diff --git a/drivers/staging/ccree/ssi_sram_mgr.c b/drivers/staging/ccree/ssi_sram_mgr.c index e05c0c13c2eb..f11116afe89a 100644 --- a/drivers/staging/ccree/ssi_sram_mgr.c +++ b/drivers/staging/ccree/ssi_sram_mgr.c @@ -58,7 +58,7 @@ int ssi_sram_mgr_init(struct ssi_drvdata *drvdata) sizeof(struct ssi_sram_mgr_ctx), GFP_KERNEL); if (!drvdata->sram_mgr_handle) { SSI_LOG_ERR("Not enough memory to allocate SRAM_MGR ctx (%zu)\n", - sizeof(struct ssi_sram_mgr_ctx)); + sizeof(struct ssi_sram_mgr_ctx)); rc = -ENOMEM; goto out; } @@ -90,12 +90,12 @@ ssi_sram_addr_t ssi_sram_mgr_alloc(struct ssi_drvdata *drvdata, u32 size) if (unlikely((size & 0x3) != 0)) { SSI_LOG_ERR("Requested buffer size (%u) is not multiple of 4", - size); + size); return NULL_SRAM_ADDR; } if (unlikely(size > (SSI_CC_SRAM_SIZE - smgr_ctx->sram_free_offset))) { SSI_LOG_ERR("Not enough space to allocate %u B (at offset %llu)\n", - size, smgr_ctx->sram_free_offset); + size, smgr_ctx->sram_free_offset); return NULL_SRAM_ADDR; } diff --git a/drivers/staging/ccree/ssi_sysfs.c b/drivers/staging/ccree/ssi_sysfs.c index dbcd1634aad1..0655658bba4d 100644 --- a/drivers/staging/ccree/ssi_sysfs.c +++ b/drivers/staging/ccree/ssi_sysfs.c @@ -40,8 +40,7 @@ struct stat_name { const char *stat_phase_name[MAX_STAT_PHASES]; }; -static struct stat_name stat_name_db[MAX_STAT_OP_TYPES] = -{ +static struct stat_name stat_name_db[MAX_STAT_OP_TYPES] = { { /* STAT_OP_TYPE_NULL */ .op_type_name = "NULL", @@ -144,8 +143,12 @@ static void display_db(struct stat_item item[MAX_STAT_OP_TYPES][MAX_STAT_PHASES] avg = (u64)item[i][j].sum; do_div(avg, item[i][j].count); SSI_LOG_ERR("%s, %s: min=%d avg=%d max=%d sum=%lld count=%d\n", - stat_name_db[i].op_type_name, stat_name_db[i].stat_phase_name[j], - item[i][j].min, (int)avg, item[i][j].max, (long long)item[i][j].sum, item[i][j].count); + stat_name_db[i].op_type_name, + stat_name_db[i].stat_phase_name[j], + item[i][j].min, (int)avg, + item[i][j].max, + (long long)item[i][j].sum, + item[i][j].count); } } } @@ -156,21 +159,23 @@ static void display_db(struct stat_item item[MAX_STAT_OP_TYPES][MAX_STAT_PHASES] **************************************/ static ssize_t ssi_sys_stats_host_db_clear(struct kobject *kobj, - struct kobj_attribute *attr, const char *buf, size_t count) + struct kobj_attribute *attr, + const char *buf, size_t count) { init_db(stat_host_db); return count; } static ssize_t ssi_sys_stats_cc_db_clear(struct kobject *kobj, - struct kobj_attribute *attr, const char *buf, size_t count) + struct kobj_attribute *attr, + const char *buf, size_t count) { init_db(stat_cc_db); return count; } static ssize_t ssi_sys_stat_host_db_show(struct kobject *kobj, - struct kobj_attribute *attr, char *buf) + struct kobj_attribute *attr, char *buf) { int i, j; char line[512]; @@ -179,7 +184,7 @@ static ssize_t ssi_sys_stat_host_db_show(struct kobject *kobj, ssize_t buf_len, tmp_len = 0; buf_len = scnprintf(buf, PAGE_SIZE, - "phase\t\t\t\t\t\t\tmin[cy]\tavg[cy]\tmax[cy]\t#samples\n"); + "phase\t\t\t\t\t\t\tmin[cy]\tavg[cy]\tmax[cy]\t#samples\n"); if (buf_len < 0)/* scnprintf shouldn't return negative value according to its implementation*/ return buf_len; for (i = STAT_OP_TYPE_ENCODE; i < MAX_STAT_OP_TYPES; i++) { @@ -193,11 +198,11 @@ static ssize_t ssi_sys_stat_host_db_show(struct kobject *kobj, avg = min_cyc = max_cyc = 0; } tmp_len = scnprintf(line, 512, - "%s::%s\t\t\t\t\t%6u\t%6u\t%6u\t%7u\n", - stat_name_db[i].op_type_name, - stat_name_db[i].stat_phase_name[j], - min_cyc, (unsigned int)avg, max_cyc, - stat_host_db[i][j].count); + "%s::%s\t\t\t\t\t%6u\t%6u\t%6u\t%7u\n", + stat_name_db[i].op_type_name, + stat_name_db[i].stat_phase_name[j], + min_cyc, (unsigned int)avg, max_cyc, + stat_host_db[i][j].count); if (tmp_len < 0)/* scnprintf shouldn't return negative value according to its implementation*/ return buf_len; if (buf_len + tmp_len >= PAGE_SIZE) @@ -210,7 +215,7 @@ static ssize_t ssi_sys_stat_host_db_show(struct kobject *kobj, } static ssize_t ssi_sys_stat_cc_db_show(struct kobject *kobj, - struct kobj_attribute *attr, char *buf) + struct kobj_attribute *attr, char *buf) { int i; char line[256]; @@ -219,7 +224,7 @@ static ssize_t ssi_sys_stat_cc_db_show(struct kobject *kobj, ssize_t buf_len, tmp_len = 0; buf_len = scnprintf(buf, PAGE_SIZE, - "phase\tmin[cy]\tavg[cy]\tmax[cy]\t#samples\n"); + "phase\tmin[cy]\tavg[cy]\tmax[cy]\t#samples\n"); if (buf_len < 0)/* scnprintf shouldn't return negative value according to its implementation*/ return buf_len; for (i = STAT_OP_TYPE_ENCODE; i < MAX_STAT_OP_TYPES; i++) { @@ -231,13 +236,10 @@ static ssize_t ssi_sys_stat_cc_db_show(struct kobject *kobj, } else { avg = min_cyc = max_cyc = 0; } - tmp_len = scnprintf(line, 256, - "%s\t%6u\t%6u\t%6u\t%7u\n", - stat_name_db[i].op_type_name, - min_cyc, - (unsigned int)avg, - max_cyc, - stat_cc_db[i][STAT_PHASE_6].count); + tmp_len = scnprintf(line, 256, "%s\t%6u\t%6u\t%6u\t%7u\n", + stat_name_db[i].op_type_name, min_cyc, + (unsigned int)avg, max_cyc, + stat_cc_db[i][STAT_PHASE_6].count); if (tmp_len < 0)/* scnprintf shouldn't return negative value according to its implementation*/ return buf_len; @@ -255,7 +257,7 @@ void update_host_stat(unsigned int op_type, unsigned int phase, cycles_t result) unsigned long flags; spin_lock_irqsave(&stat_lock, flags); - update_db(&(stat_host_db[op_type][phase]), (unsigned int)result); + update_db(&stat_host_db[op_type][phase], (unsigned int)result); spin_unlock_irqrestore(&stat_lock, flags); } @@ -264,7 +266,7 @@ void update_cc_stat( unsigned int phase, unsigned int elapsed_cycles) { - update_db(&(stat_cc_db[op_type][phase]), elapsed_cycles); + update_db(&stat_cc_db[op_type][phase], elapsed_cycles); } void display_all_stat_db(void) @@ -277,7 +279,7 @@ void display_all_stat_db(void) #endif /*CC_CYCLE_COUNT*/ static ssize_t ssi_sys_regdump_show(struct kobject *kobj, - struct kobj_attribute *attr, char *buf) + struct kobj_attribute *attr, char *buf) { struct ssi_drvdata *drvdata = sys_get_drvdata(); u32 register_value; @@ -285,20 +287,20 @@ static ssize_t ssi_sys_regdump_show(struct kobject *kobj, int offset = 0; register_value = CC_HAL_READ_REGISTER(CC_REG_OFFSET(HOST_RGF, HOST_SIGNATURE)); - offset += scnprintf(buf + offset, PAGE_SIZE - offset, "%s \t(0x%lX)\t 0x%08X \n", "HOST_SIGNATURE ", DX_HOST_SIGNATURE_REG_OFFSET, register_value); + offset += scnprintf(buf + offset, PAGE_SIZE - offset, "%s \t(0x%lX)\t 0x%08X\n", "HOST_SIGNATURE ", DX_HOST_SIGNATURE_REG_OFFSET, register_value); register_value = CC_HAL_READ_REGISTER(CC_REG_OFFSET(HOST_RGF, HOST_IRR)); - offset += scnprintf(buf + offset, PAGE_SIZE - offset, "%s \t(0x%lX)\t 0x%08X \n", "HOST_IRR ", DX_HOST_IRR_REG_OFFSET, register_value); + offset += scnprintf(buf + offset, PAGE_SIZE - offset, "%s \t(0x%lX)\t 0x%08X\n", "HOST_IRR ", DX_HOST_IRR_REG_OFFSET, register_value); register_value = CC_HAL_READ_REGISTER(CC_REG_OFFSET(HOST_RGF, HOST_POWER_DOWN_EN)); - offset += scnprintf(buf + offset, PAGE_SIZE - offset, "%s \t(0x%lX)\t 0x%08X \n", "HOST_POWER_DOWN_EN ", DX_HOST_POWER_DOWN_EN_REG_OFFSET, register_value); + offset += scnprintf(buf + offset, PAGE_SIZE - offset, "%s \t(0x%lX)\t 0x%08X\n", "HOST_POWER_DOWN_EN ", DX_HOST_POWER_DOWN_EN_REG_OFFSET, register_value); register_value = CC_HAL_READ_REGISTER(CC_REG_OFFSET(CRY_KERNEL, AXIM_MON_ERR)); - offset += scnprintf(buf + offset, PAGE_SIZE - offset, "%s \t(0x%lX)\t 0x%08X \n", "AXIM_MON_ERR ", DX_AXIM_MON_ERR_REG_OFFSET, register_value); + offset += scnprintf(buf + offset, PAGE_SIZE - offset, "%s \t(0x%lX)\t 0x%08X\n", "AXIM_MON_ERR ", DX_AXIM_MON_ERR_REG_OFFSET, register_value); register_value = CC_HAL_READ_REGISTER(CC_REG_OFFSET(CRY_KERNEL, DSCRPTR_QUEUE_CONTENT)); - offset += scnprintf(buf + offset, PAGE_SIZE - offset, "%s \t(0x%lX)\t 0x%08X \n", "DSCRPTR_QUEUE_CONTENT", DX_DSCRPTR_QUEUE_CONTENT_REG_OFFSET, register_value); + offset += scnprintf(buf + offset, PAGE_SIZE - offset, "%s \t(0x%lX)\t 0x%08X\n", "DSCRPTR_QUEUE_CONTENT", DX_DSCRPTR_QUEUE_CONTENT_REG_OFFSET, register_value); return offset; } static ssize_t ssi_sys_help_show(struct kobject *kobj, - struct kobj_attribute *attr, char *buf) + struct kobj_attribute *attr, char *buf) { char *help_str[] = { "cat reg_dump ", "Print several of CC register values", @@ -357,8 +359,8 @@ static struct ssi_drvdata *sys_get_drvdata(void) } static int sys_init_dir(struct sys_dir *sys_dir, struct ssi_drvdata *drvdata, - struct kobject *parent_dir_kobj, const char *dir_name, - struct kobj_attribute *attrs, u32 num_of_attrs) + struct kobject *parent_dir_kobj, const char *dir_name, + struct kobj_attribute *attrs, u32 num_of_attrs) { int i; @@ -375,7 +377,7 @@ static int sys_init_dir(struct sys_dir *sys_dir, struct ssi_drvdata *drvdata, /* allocate memory for directory's attributes list */ sys_dir->sys_dir_attr_list = kzalloc(sizeof(struct attribute *) * (num_of_attrs + 1), - GFP_KERNEL); + GFP_KERNEL); if (!(sys_dir->sys_dir_attr_list)) { kobject_put(sys_dir->sys_dir_kobj); @@ -386,7 +388,7 @@ static int sys_init_dir(struct sys_dir *sys_dir, struct ssi_drvdata *drvdata, /* initialize attributes list */ for (i = 0; i < num_of_attrs; ++i) - sys_dir->sys_dir_attr_list[i] = &(attrs[i].attr); + sys_dir->sys_dir_attr_list[i] = &attrs[i].attr; /* last list entry should be NULL */ sys_dir->sys_dir_attr_list[num_of_attrs] = NULL; @@ -394,7 +396,7 @@ static int sys_init_dir(struct sys_dir *sys_dir, struct ssi_drvdata *drvdata, sys_dir->sys_dir_attr_group.attrs = sys_dir->sys_dir_attr_list; return sysfs_create_group(sys_dir->sys_dir_kobj, - &(sys_dir->sys_dir_attr_group)); + &sys_dir->sys_dir_attr_group); } static void sys_free_dir(struct sys_dir *sys_dir) @@ -421,9 +423,9 @@ int ssi_sysfs_init(struct kobject *sys_dev_obj, struct ssi_drvdata *drvdata) SSI_LOG_ERR("setup sysfs under %s\n", sys_dev_obj->name); /* Initialize top directory */ - retval = sys_init_dir(&sys_top_dir, drvdata, sys_dev_obj, - "cc_info", ssi_sys_top_level_attrs, - ARRAY_SIZE(ssi_sys_top_level_attrs)); + retval = sys_init_dir(&sys_top_dir, drvdata, sys_dev_obj, "cc_info", + ssi_sys_top_level_attrs, + ARRAY_SIZE(ssi_sys_top_level_attrs)); return retval; } diff --git a/drivers/staging/comedi/comedi_buf.c b/drivers/staging/comedi/comedi_buf.c index 8e9b30b26810..b455ff6714eb 100644 --- a/drivers/staging/comedi/comedi_buf.c +++ b/drivers/staging/comedi/comedi_buf.c @@ -165,7 +165,7 @@ int comedi_buf_map_put(struct comedi_buf_map *bm) int comedi_buf_map_access(struct comedi_buf_map *bm, unsigned long offset, void *buf, int len, int write) { - unsigned int pgoff = offset & ~PAGE_MASK; + unsigned int pgoff = offset_in_page(offset); unsigned long pg = offset >> PAGE_SHIFT; int done = 0; diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index 34ca7823255d..e19e395b0e44 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c @@ -745,7 +745,7 @@ static void do_become_nonbusy(struct comedi_device *dev, wake_up_interruptible_all(&async->wait_head); } else { dev_err(dev->class_dev, - "BUG: (?) do_become_nonbusy called with async=NULL\n"); + "BUG: (?) %s called with async=NULL\n", __func__); s->busy = NULL; } } diff --git a/drivers/staging/comedi/drivers.c b/drivers/staging/comedi/drivers.c index a5bf2cc165c0..0b43db6371c6 100644 --- a/drivers/staging/comedi/drivers.c +++ b/drivers/staging/comedi/drivers.c @@ -995,12 +995,12 @@ int comedi_auto_config(struct device *hardware_device, int ret; if (!hardware_device) { - pr_warn("BUG! comedi_auto_config called with NULL hardware_device\n"); + pr_warn("BUG! %s called with NULL hardware_device\n", __func__); return -EINVAL; } if (!driver) { dev_warn(hardware_device, - "BUG! comedi_auto_config called with NULL comedi driver\n"); + "BUG! %s called with NULL comedi driver\n", __func__); return -EINVAL; } diff --git a/drivers/staging/comedi/drivers/ni_mio_common.c b/drivers/staging/comedi/drivers/ni_mio_common.c index 2f7bfc1c59e5..398347fedc47 100644 --- a/drivers/staging/comedi/drivers/ni_mio_common.c +++ b/drivers/staging/comedi/drivers/ni_mio_common.c @@ -1962,7 +1962,8 @@ static unsigned int ni_timer_to_ns(const struct comedi_device *dev, int timer) static void ni_cmd_set_mite_transfer(struct mite_ring *ring, struct comedi_subdevice *sdev, const struct comedi_cmd *cmd, - unsigned int max_count) { + unsigned int max_count) +{ #ifdef PCIDMA unsigned int nbytes = max_count; diff --git a/drivers/staging/comedi/drivers/serial2002.c b/drivers/staging/comedi/drivers/serial2002.c index 0d33e520f635..cc18e25103ca 100644 --- a/drivers/staging/comedi/drivers/serial2002.c +++ b/drivers/staging/comedi/drivers/serial2002.c @@ -106,16 +106,8 @@ static long serial2002_tty_ioctl(struct file *f, unsigned int op, static int serial2002_tty_write(struct file *f, unsigned char *buf, int count) { - const char __user *p = (__force const char __user *)buf; - int result; - loff_t offset = 0; - mm_segment_t oldfs; - - oldfs = get_fs(); - set_fs(KERNEL_DS); - result = __vfs_write(f, p, count, &offset); - set_fs(oldfs); - return result; + loff_t pos = 0; + return kernel_write(f, buf, count, &pos); } static void serial2002_tty_read_poll_wait(struct file *f, int timeout) @@ -148,19 +140,14 @@ static int serial2002_tty_read(struct file *f, int timeout) { unsigned char ch; int result; + loff_t pos = 0; result = -1; if (!IS_ERR(f)) { - mm_segment_t oldfs; - char __user *p = (__force char __user *)&ch; - loff_t offset = 0; - - oldfs = get_fs(); - set_fs(KERNEL_DS); if (f->f_op->poll) { serial2002_tty_read_poll_wait(f, timeout); - if (__vfs_read(f, p, 1, &offset) == 1) + if (kernel_read(f, &ch, 1, &pos) == 1) result = ch; } else { /* Device does not support poll, busy wait */ @@ -171,14 +158,13 @@ static int serial2002_tty_read(struct file *f, int timeout) if (retries >= timeout) break; - if (__vfs_read(f, p, 1, &offset) == 1) { + if (kernel_read(f, &ch, 1, &pos) == 1) { result = ch; break; } usleep_range(100, 1000); } } - set_fs(oldfs); } return result; } diff --git a/drivers/staging/fbtft/fb_st7789v.c b/drivers/staging/fbtft/fb_st7789v.c index 8935a97ec048..a5d7c87557f8 100644 --- a/drivers/staging/fbtft/fb_st7789v.c +++ b/drivers/staging/fbtft/fb_st7789v.c @@ -189,7 +189,7 @@ static int set_gamma(struct fbtft_par *par, u32 *curves) * The masks are the same for both positive and negative voltage * gamma curves. */ - const u8 gamma_par_mask[] = { + static const u8 gamma_par_mask[] = { 0xFF, /* V63[3:0], V0[3:0]*/ 0x3F, /* V1[5:0] */ 0x3F, /* V2[5:0] */ diff --git a/drivers/staging/fbtft/fbtft-core.c b/drivers/staging/fbtft/fbtft-core.c index b742ee786615..6d0363deba61 100644 --- a/drivers/staging/fbtft/fbtft-core.c +++ b/drivers/staging/fbtft/fbtft-core.c @@ -84,7 +84,7 @@ static unsigned long fbtft_request_gpios_match(struct fbtft_par *par, const struct fbtft_gpio *gpio) { int ret; - long val; + unsigned int val; fbtft_par_dbg(DEBUG_REQUEST_GPIOS_MATCH, par, "%s('%s')\n", __func__, gpio->name); @@ -108,7 +108,7 @@ static unsigned long fbtft_request_gpios_match(struct fbtft_par *par, par->gpio.latch = gpio->gpio; return GPIOF_OUT_INIT_LOW; } else if (gpio->name[0] == 'd' && gpio->name[1] == 'b') { - ret = kstrtol(&gpio->name[2], 10, &val); + ret = kstrtouint(&gpio->name[2], 10, &val); if (ret == 0 && val < 16) { par->gpio.db[val] = gpio->gpio; return GPIOF_OUT_INIT_LOW; diff --git a/drivers/staging/fsl-dpaa2/Kconfig b/drivers/staging/fsl-dpaa2/Kconfig index 730fd6d4db33..dfff675b3055 100644 --- a/drivers/staging/fsl-dpaa2/Kconfig +++ b/drivers/staging/fsl-dpaa2/Kconfig @@ -4,7 +4,7 @@ config FSL_DPAA2 bool "Freescale DPAA2 devices" - depends on FSL_MC_BUS + depends on FSL_MC_BUS && ARCH_LAYERSCAPE ---help--- Build drivers for Freescale DataPath Acceleration Architecture (DPAA2) family of SoCs. diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c index b9a0a315e6fb..26017fe9df93 100644 --- a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c +++ b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c @@ -616,7 +616,7 @@ static netdev_tx_t dpaa2_eth_tx(struct sk_buff *skb, struct net_device *net_dev) free_tx_fd(priv, &fd, NULL); } else { percpu_stats->tx_packets++; - percpu_stats->tx_bytes += skb->len; + percpu_stats->tx_bytes += dpaa2_fd_get_len(&fd); } return NETDEV_TX_OK; @@ -656,7 +656,7 @@ static void dpaa2_eth_tx_conf(struct dpaa2_eth_priv *priv, has_fas_errors = (fd_errors & DPAA2_FD_CTRL_FAERR) && !!(dpaa2_fd_get_frc(fd) & DPAA2_FD_FRC_FASV); if (net_ratelimit()) - netdev_dbg(priv->net_dev, "TX frame FD error: %x08\n", + netdev_dbg(priv->net_dev, "TX frame FD error: 0x%08x\n", fd_errors); } @@ -670,7 +670,7 @@ static void dpaa2_eth_tx_conf(struct dpaa2_eth_priv *priv, percpu_stats->tx_errors++; if (has_fas_errors && net_ratelimit()) - netdev_dbg(priv->net_dev, "TX frame FAS error: %x08\n", + netdev_dbg(priv->net_dev, "TX frame FAS error: 0x%08x\n", status & DPAA2_FAS_TX_ERR_MASK); } diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h index e6d28a249fc1..bfbabae1aad8 100644 --- a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h +++ b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h @@ -123,8 +123,8 @@ struct dpaa2_eth_swa { /* Error bits in FD CTRL */ #define DPAA2_FD_CTRL_UFD 0x00000004 #define DPAA2_FD_CTRL_SBE 0x00000008 -#define DPAA2_FD_CTRL_FSE 0x00000010 -#define DPAA2_FD_CTRL_FAERR 0x00000020 +#define DPAA2_FD_CTRL_FSE 0x00000020 +#define DPAA2_FD_CTRL_FAERR 0x00000040 #define DPAA2_FD_RX_ERR_MASK (DPAA2_FD_CTRL_SBE | \ DPAA2_FD_CTRL_FAERR) diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-ethtool.c b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-ethtool.c index 5312edc26f01..031179ab3a22 100644 --- a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-ethtool.c +++ b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-ethtool.c @@ -217,8 +217,6 @@ static void dpaa2_eth_get_ethtool_stats(struct net_device *net_dev, case 2: num_cnt = sizeof(dpni_stats.page_2) / sizeof(u64); break; - default: - break; } for (k = 0; k < num_cnt; k++) *(data + i++) = dpni_stats.raw.counter[k]; diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpni.c b/drivers/staging/fsl-dpaa2/ethernet/dpni.c index 5b9d4424e4fb..04a5b14bc1c5 100644 --- a/drivers/staging/fsl-dpaa2/ethernet/dpni.c +++ b/drivers/staging/fsl-dpaa2/ethernet/dpni.c @@ -1443,7 +1443,7 @@ int dpni_get_queue(struct fsl_mc_io *mc_io, queue->destination.id = le32_to_cpu(rsp_params->dest_id); queue->destination.priority = rsp_params->dest_prio; queue->destination.type = dpni_get_field(rsp_params->flags, - DEST_TYPE); + DEST_TYPE); queue->flc.stash_control = dpni_get_field(rsp_params->flags, STASH_CTRL); queue->destination.hold_active = dpni_get_field(rsp_params->flags, diff --git a/drivers/staging/fsl-mc/bus/Kconfig b/drivers/staging/fsl-mc/bus/Kconfig index a10aaf03f314..504c987447f2 100644 --- a/drivers/staging/fsl-mc/bus/Kconfig +++ b/drivers/staging/fsl-mc/bus/Kconfig @@ -8,7 +8,7 @@ config FSL_MC_BUS bool "QorIQ DPAA2 fsl-mc bus driver" - depends on OF && ARCH_LAYERSCAPE + depends on OF && (ARCH_LAYERSCAPE || (COMPILE_TEST && (ARM || ARM64 || X86 || PPC))) select GENERIC_MSI_IRQ_DOMAIN help Driver to enable the bus infrastructure for the QorIQ DPAA2 @@ -18,7 +18,7 @@ config FSL_MC_BUS config FSL_MC_DPIO tristate "QorIQ DPAA2 DPIO driver" - depends on FSL_MC_BUS + depends on FSL_MC_BUS && ARCH_LAYERSCAPE help Driver for the DPAA2 DPIO object. A DPIO provides queue and buffer management facilities for software to interact with diff --git a/drivers/staging/fsl-mc/bus/dpio/qbman-portal.c b/drivers/staging/fsl-mc/bus/dpio/qbman-portal.c index 7988612aaecf..163bdac6b051 100644 --- a/drivers/staging/fsl-mc/bus/dpio/qbman-portal.c +++ b/drivers/staging/fsl-mc/bus/dpio/qbman-portal.c @@ -136,18 +136,18 @@ static inline u32 qbman_set_swp_cfg(u8 max_fill, u8 wn, u8 est, u8 rpm, u8 dcm, u8 epm, int sd, int sp, int se, int dp, int de, int ep) { - return cpu_to_le32 (max_fill << SWP_CFG_DQRR_MF_SHIFT | - est << SWP_CFG_EST_SHIFT | - wn << SWP_CFG_WN_SHIFT | - rpm << SWP_CFG_RPM_SHIFT | - dcm << SWP_CFG_DCM_SHIFT | - epm << SWP_CFG_EPM_SHIFT | - sd << SWP_CFG_SD_SHIFT | - sp << SWP_CFG_SP_SHIFT | - se << SWP_CFG_SE_SHIFT | - dp << SWP_CFG_DP_SHIFT | - de << SWP_CFG_DE_SHIFT | - ep << SWP_CFG_EP_SHIFT); + return (max_fill << SWP_CFG_DQRR_MF_SHIFT | + est << SWP_CFG_EST_SHIFT | + wn << SWP_CFG_WN_SHIFT | + rpm << SWP_CFG_RPM_SHIFT | + dcm << SWP_CFG_DCM_SHIFT | + epm << SWP_CFG_EPM_SHIFT | + sd << SWP_CFG_SD_SHIFT | + sp << SWP_CFG_SP_SHIFT | + se << SWP_CFG_SE_SHIFT | + dp << SWP_CFG_DP_SHIFT | + de << SWP_CFG_DE_SHIFT | + ep << SWP_CFG_EP_SHIFT); } /** diff --git a/drivers/staging/fsl-mc/bus/dprc-driver.c b/drivers/staging/fsl-mc/bus/dprc-driver.c index 4cdd190a338b..06df528f4cfc 100644 --- a/drivers/staging/fsl-mc/bus/dprc-driver.c +++ b/drivers/staging/fsl-mc/bus/dprc-driver.c @@ -29,7 +29,7 @@ static bool fsl_mc_device_match(struct fsl_mc_device *mc_dev, struct fsl_mc_obj_desc *obj_desc) { return mc_dev->obj_desc.id == obj_desc->id && - !strcmp(mc_dev->obj_desc.type, obj_desc->type); + strcmp(mc_dev->obj_desc.type, obj_desc->type) == 0; } @@ -617,8 +617,7 @@ static int dprc_probe(struct fsl_mc_device *mc_dev) if (WARN_ON(mc_dev->obj_desc.region_count == 0)) return -EINVAL; - region_size = mc_dev->regions[0].end - - mc_dev->regions[0].start + 1; + region_size = resource_size(mc_dev->regions); error = fsl_create_mc_io(&mc_dev->dev, mc_dev->regions[0].start, diff --git a/drivers/staging/fsl-mc/bus/fsl-mc-allocator.c b/drivers/staging/fsl-mc/bus/fsl-mc-allocator.c index b37a6f48225f..8ea3920400a0 100644 --- a/drivers/staging/fsl-mc/bus/fsl-mc-allocator.c +++ b/drivers/staging/fsl-mc/bus/fsl-mc-allocator.c @@ -16,9 +16,9 @@ static bool __must_check fsl_mc_is_allocatable(const char *obj_type) { - return strcmp(obj_type, "dpbp") || - strcmp(obj_type, "dpmcp") || - strcmp(obj_type, "dpcon"); + return strcmp(obj_type, "dpbp") == 0 || + strcmp(obj_type, "dpmcp") == 0 || + strcmp(obj_type, "dpcon") == 0; } /** diff --git a/drivers/staging/fsl-mc/bus/fsl-mc-bus.c b/drivers/staging/fsl-mc/bus/fsl-mc-bus.c index 19606e8d25dd..409f2b9e70ff 100644 --- a/drivers/staging/fsl-mc/bus/fsl-mc-bus.c +++ b/drivers/staging/fsl-mc/bus/fsl-mc-bus.c @@ -757,8 +757,8 @@ static int fsl_mc_bus_probe(struct platform_device *pdev) error = of_address_to_resource(pdev->dev.of_node, 0, &res); if (error < 0) { dev_err(&pdev->dev, - "of_address_to_resource() failed for %s\n", - pdev->dev.of_node->full_name); + "of_address_to_resource() failed for %pOF\n", + pdev->dev.of_node); return error; } diff --git a/drivers/staging/fsl-mc/bus/fsl-mc-msi.c b/drivers/staging/fsl-mc/bus/fsl-mc-msi.c index c04a2f2b3409..038da4d1ebd0 100644 --- a/drivers/staging/fsl-mc/bus/fsl-mc-msi.c +++ b/drivers/staging/fsl-mc/bus/fsl-mc-msi.c @@ -11,13 +11,13 @@ #include <linux/of_device.h> #include <linux/of_address.h> -#include <linux/irqchip/arm-gic-v3.h> #include <linux/of_irq.h> #include <linux/irq.h> #include <linux/irqdomain.h> #include <linux/msi.h> #include "fsl-mc-private.h" +#ifdef GENERIC_MSI_DOMAIN_OPS /* * Generate a unique ID identifying the interrupt (only used within the MSI * irqdomain. Combine the icid with the interrupt index. @@ -39,6 +39,9 @@ static void fsl_mc_msi_set_desc(msi_alloc_info_t *arg, arg->hwirq = fsl_mc_domain_calc_hwirq(to_fsl_mc_device(desc->dev), desc); } +#else +#define fsl_mc_msi_set_desc NULL +#endif static void fsl_mc_msi_update_dom_ops(struct msi_domain_info *info) { @@ -183,8 +186,8 @@ int fsl_mc_find_msi_domain(struct device *mc_platform_dev, msi_domain = of_msi_get_domain(mc_platform_dev, mc_of_node, DOMAIN_BUS_FSL_MC_MSI); if (!msi_domain) { - pr_err("Unable to find fsl-mc MSI domain for %s\n", - mc_of_node->full_name); + pr_err("Unable to find fsl-mc MSI domain for %pOF\n", + mc_of_node); return -ENOENT; } diff --git a/drivers/staging/fsl-mc/bus/irq-gic-v3-its-fsl-mc-msi.c b/drivers/staging/fsl-mc/bus/irq-gic-v3-its-fsl-mc-msi.c index 865d38517508..123e4af58408 100644 --- a/drivers/staging/fsl-mc/bus/irq-gic-v3-its-fsl-mc-msi.c +++ b/drivers/staging/fsl-mc/bus/irq-gic-v3-its-fsl-mc-msi.c @@ -11,7 +11,6 @@ #include <linux/of_device.h> #include <linux/of_address.h> -#include <linux/irqchip/arm-gic-v3.h> #include <linux/irq.h> #include <linux/msi.h> #include <linux/of.h> @@ -46,7 +45,9 @@ static int its_fsl_mc_msi_prepare(struct irq_domain *msi_domain, * NOTE: This device id corresponds to the IOMMU stream ID * associated with the DPRC object (ICID). */ +#ifdef GENERIC_MSI_DOMAIN_OPS info->scratchpad[0].ul = mc_bus_dev->icid; +#endif msi_info = msi_get_domain_info(msi_domain->parent); return msi_info->ops->msi_prepare(msi_domain->parent, dev, nvec, info); } @@ -79,8 +80,7 @@ int __init its_fsl_mc_msi_init(void) parent = irq_find_matching_host(np, DOMAIN_BUS_NEXUS); if (!parent || !msi_get_domain_info(parent)) { - pr_err("%s: unable to locate ITS domain\n", - np->full_name); + pr_err("%pOF: unable to locate ITS domain\n", np); continue; } @@ -89,15 +89,14 @@ int __init its_fsl_mc_msi_init(void) &its_fsl_mc_msi_domain_info, parent); if (!mc_msi_domain) { - pr_err("%s: unable to create fsl-mc domain\n", - np->full_name); + pr_err("%pOF: unable to create fsl-mc domain\n", np); continue; } WARN_ON(mc_msi_domain->host_data != &its_fsl_mc_msi_domain_info); - pr_info("fsl-mc MSI: %s domain created\n", np->full_name); + pr_info("fsl-mc MSI: %pOF domain created\n", np); } return 0; diff --git a/drivers/staging/fsl-mc/bus/mc-io.c b/drivers/staging/fsl-mc/bus/mc-io.c index 35221a17858b..f65c23ce83f1 100644 --- a/drivers/staging/fsl-mc/bus/mc-io.c +++ b/drivers/staging/fsl-mc/bus/mc-io.c @@ -129,8 +129,8 @@ int __must_check fsl_create_mc_io(struct device *dev, "mc_portal"); if (!res) { dev_err(dev, - "devm_request_mem_region failed for MC portal %#llx\n", - mc_portal_phys_addr); + "devm_request_mem_region failed for MC portal %pa\n", + &mc_portal_phys_addr); return -EBUSY; } @@ -139,8 +139,8 @@ int __must_check fsl_create_mc_io(struct device *dev, mc_portal_size); if (!mc_portal_virt_addr) { dev_err(dev, - "devm_ioremap_nocache failed for MC portal %#llx\n", - mc_portal_phys_addr); + "devm_ioremap_nocache failed for MC portal %pa\n", + &mc_portal_phys_addr); return -ENXIO; } @@ -242,8 +242,7 @@ int __must_check fsl_mc_portal_allocate(struct fsl_mc_device *mc_dev, goto error_cleanup_resource; mc_portal_phys_addr = dpmcp_dev->regions[0].start; - mc_portal_size = dpmcp_dev->regions[0].end - - dpmcp_dev->regions[0].start + 1; + mc_portal_size = resource_size(dpmcp_dev->regions); if (WARN_ON(mc_portal_size != mc_bus_dev->mc_io->portal_size)) goto error_cleanup_resource; diff --git a/drivers/staging/fsl-mc/bus/mc-sys.c b/drivers/staging/fsl-mc/bus/mc-sys.c index a1704c3a6a78..7ce105bd3977 100644 --- a/drivers/staging/fsl-mc/bus/mc-sys.c +++ b/drivers/staging/fsl-mc/bus/mc-sys.c @@ -37,6 +37,7 @@ #include <linux/ioport.h> #include <linux/device.h> #include <linux/io.h> +#include <linux/io-64-nonatomic-hi-lo.h> #include "../include/mc.h" #include "dpmcp.h" @@ -126,11 +127,15 @@ static inline void mc_write_command(struct mc_command __iomem *portal, /* copy command parameters into the portal */ for (i = 0; i < MC_CMD_NUM_OF_PARAMS; i++) - __raw_writeq(cmd->params[i], &portal->params[i]); - __iowmb(); + /* + * Data is already in the expected LE byte-order. Do an + * extra LE -> CPU conversion so that the CPU -> LE done in + * the device io write api puts it back in the right order. + */ + writeq_relaxed(le64_to_cpu(cmd->params[i]), &portal->params[i]); /* submit the command by writing the header */ - __raw_writeq(cmd->header, &portal->header); + writeq(le64_to_cpu(cmd->header), &portal->header); } /** @@ -150,17 +155,20 @@ static inline enum mc_cmd_status mc_read_response(struct mc_command __iomem * enum mc_cmd_status status; /* Copy command response header from MC portal: */ - __iormb(); - resp->header = __raw_readq(&portal->header); - __iormb(); + resp->header = cpu_to_le64(readq_relaxed(&portal->header)); status = mc_cmd_hdr_read_status(resp); if (status != MC_CMD_STATUS_OK) return status; /* Copy command response data from MC portal: */ for (i = 0; i < MC_CMD_NUM_OF_PARAMS; i++) - resp->params[i] = __raw_readq(&portal->params[i]); - __iormb(); + /* + * Data is expected to be in LE byte-order. Do an + * extra CPU -> LE to revert the LE -> CPU done in + * the device io read api. + */ + resp->params[i] = + cpu_to_le64(readq_relaxed(&portal->params[i])); return status; } @@ -198,8 +206,8 @@ static int mc_polling_wait_preemptible(struct fsl_mc_io *mc_io, if (time_after_eq(jiffies, jiffies_until_timeout)) { dev_dbg(mc_io->dev, - "MC command timed out (portal: %#llx, dprc handle: %#x, command: %#x)\n", - mc_io->portal_phys_addr, + "MC command timed out (portal: %pa, dprc handle: %#x, command: %#x)\n", + &mc_io->portal_phys_addr, (unsigned int)mc_cmd_hdr_read_token(cmd), (unsigned int)mc_cmd_hdr_read_cmdid(cmd)); @@ -238,8 +246,8 @@ static int mc_polling_wait_atomic(struct fsl_mc_io *mc_io, timeout_usecs -= MC_CMD_COMPLETION_POLLING_MAX_SLEEP_USECS; if (timeout_usecs == 0) { dev_dbg(mc_io->dev, - "MC command timed out (portal: %#llx, dprc handle: %#x, command: %#x)\n", - mc_io->portal_phys_addr, + "MC command timed out (portal: %pa, dprc handle: %#x, command: %#x)\n", + &mc_io->portal_phys_addr, (unsigned int)mc_cmd_hdr_read_token(cmd), (unsigned int)mc_cmd_hdr_read_cmdid(cmd)); @@ -292,8 +300,8 @@ int mc_send_command(struct fsl_mc_io *mc_io, struct mc_command *cmd) if (status != MC_CMD_STATUS_OK) { dev_dbg(mc_io->dev, - "MC command failed: portal: %#llx, dprc handle: %#x, command: %#x, status: %s (%#x)\n", - mc_io->portal_phys_addr, + "MC command failed: portal: %pa, dprc handle: %#x, command: %#x, status: %s (%#x)\n", + &mc_io->portal_phys_addr, (unsigned int)mc_cmd_hdr_read_token(cmd), (unsigned int)mc_cmd_hdr_read_cmdid(cmd), mc_status_to_string(status), diff --git a/drivers/staging/fsl-mc/include/dpaa2-io.h b/drivers/staging/fsl-mc/include/dpaa2-io.h index 002829cecd75..c5646096c5d4 100644 --- a/drivers/staging/fsl-mc/include/dpaa2-io.h +++ b/drivers/staging/fsl-mc/include/dpaa2-io.h @@ -34,6 +34,7 @@ #include <linux/types.h> #include <linux/cpumask.h> +#include <linux/irqreturn.h> #include "dpaa2-fd.h" #include "dpaa2-global.h" diff --git a/drivers/staging/goldfish/goldfish_nand.c b/drivers/staging/goldfish/goldfish_nand.c index 8f92ff4ba4b8..52cc1363993e 100644 --- a/drivers/staging/goldfish/goldfish_nand.c +++ b/drivers/staging/goldfish/goldfish_nand.c @@ -153,12 +153,12 @@ static int goldfish_nand_read_oob(struct mtd_info *mtd, loff_t ofs, ofs += mtd->writesize + ops->ooboffs; if (ops->oobbuf) ops->oobretlen = goldfish_nand_cmd(mtd, NAND_CMD_READ, ofs, - ops->ooblen, ops->oobbuf); + ops->ooblen, ops->oobbuf); return 0; invalid_arg: - pr_err("goldfish_nand_read_oob: invalid read, start %llx, len %zx, ooblen %zx, dev_size %llx, write_size %x\n", - ofs, ops->len, ops->ooblen, mtd->size, mtd->writesize); + pr_err("%s: invalid read, start %llx, len %zx, ooblen %zx, dev_size %llx, write_size %x\n", + __func__, ofs, ops->len, ops->ooblen, mtd->size, mtd->writesize); return -EINVAL; } @@ -185,12 +185,12 @@ static int goldfish_nand_write_oob(struct mtd_info *mtd, loff_t ofs, ofs += mtd->writesize + ops->ooboffs; if (ops->oobbuf) ops->oobretlen = goldfish_nand_cmd(mtd, NAND_CMD_WRITE, ofs, - ops->ooblen, ops->oobbuf); + ops->ooblen, ops->oobbuf); return 0; invalid_arg: - pr_err("goldfish_nand_write_oob: invalid write, start %llx, len %zx, ooblen %zx, dev_size %llx, write_size %x\n", - ofs, ops->len, ops->ooblen, mtd->size, mtd->writesize); + pr_err("%s: invalid write, start %llx, len %zx, ooblen %zx, dev_size %llx, write_size %x\n", + __func__, ofs, ops->len, ops->ooblen, mtd->size, mtd->writesize); return -EINVAL; } @@ -211,8 +211,8 @@ static int goldfish_nand_read(struct mtd_info *mtd, loff_t from, size_t len, return 0; invalid_arg: - pr_err("goldfish_nand_read: invalid read, start %llx, len %zx, dev_size %llx, write_size %x\n", - from, len, mtd->size, mtd->writesize); + pr_err("%s: invalid read, start %llx, len %zx, dev_size %llx, write_size %x\n", + __func__, from, len, mtd->size, mtd->writesize); return -EINVAL; } @@ -233,8 +233,8 @@ static int goldfish_nand_write(struct mtd_info *mtd, loff_t to, size_t len, return 0; invalid_arg: - pr_err("goldfish_nand_write: invalid write, start %llx, len %zx, dev_size %llx, write_size %x\n", - to, len, mtd->size, mtd->writesize); + pr_err("%s: invalid write, start %llx, len %zx, dev_size %llx, write_size %x\n", + __func__, to, len, mtd->size, mtd->writesize); return -EINVAL; } @@ -340,8 +340,8 @@ static int goldfish_nand_init_device(struct platform_device *pdev, name); if (result != name_len) { dev_err(&pdev->dev, - "goldfish_nand_init_device failed to get dev name %d != %d\n", - result, name_len); + "%s: failed to get dev name %d != %d\n", + __func__, result, name_len); return -ENODEV; } ((char *)mtd->name)[name_len] = '\0'; diff --git a/drivers/staging/greybus/arche-platform.c b/drivers/staging/greybus/arche-platform.c index eced2d26467b..21ac92d0f533 100644 --- a/drivers/staging/greybus/arche-platform.c +++ b/drivers/staging/greybus/arche-platform.c @@ -176,7 +176,10 @@ static irqreturn_t arche_platform_wd_irq(int irq, void *devid) arche_platform_set_wake_detect_state(arche_pdata, WD_STATE_IDLE); } else { - /* Check we are not in middle of irq thread already */ + /* + * Check we are not in middle of irq thread + * already + */ if (arche_pdata->wake_detect_state != WD_STATE_COLDBOOT_START) { arche_platform_set_wake_detect_state(arche_pdata, @@ -193,7 +196,7 @@ static irqreturn_t arche_platform_wd_irq(int irq, void *devid) if (arche_pdata->wake_detect_state == WD_STATE_IDLE) { arche_pdata->wake_detect_start = jiffies; /* - * In the begining, when wake/detect goes low + * In the beginning, when wake/detect goes low * (first time), we assume it is meant for coldboot * and set the flag. If wake/detect line stays low * beyond 30msec, then it is coldboot else fallback @@ -607,7 +610,6 @@ static int arche_platform_remove(struct platform_device *pdev) device_remove_file(&pdev->dev, &dev_attr_state); device_for_each_child(&pdev->dev, NULL, arche_remove_child); arche_platform_poweroff_seq(arche_pdata); - platform_set_drvdata(pdev, NULL); if (usb3613_hub_mode_ctrl(false)) dev_warn(arche_pdata->dev, "failed to control hub device\n"); @@ -657,12 +659,14 @@ static SIMPLE_DEV_PM_OPS(arche_platform_pm_ops, arche_platform_resume); static const struct of_device_id arche_platform_of_match[] = { - { .compatible = "google,arche-platform", }, /* Use PID/VID of SVC device */ + /* Use PID/VID of SVC device */ + { .compatible = "google,arche-platform", }, { }, }; static const struct of_device_id arche_combined_id[] = { - { .compatible = "google,arche-platform", }, /* Use PID/VID of SVC device */ + /* Use PID/VID of SVC device */ + { .compatible = "google,arche-platform", }, { .compatible = "usbffff,2", }, { }, }; diff --git a/drivers/staging/greybus/audio_codec.c b/drivers/staging/greybus/audio_codec.c index 25c8bb4cb0de..a6d01f0761f3 100644 --- a/drivers/staging/greybus/audio_codec.c +++ b/drivers/staging/greybus/audio_codec.c @@ -674,7 +674,7 @@ static int gbcodec_mute_stream(struct snd_soc_dai *dai, int mute, int stream) return ret; } -static struct snd_soc_dai_ops gbcodec_dai_ops = { +static const struct snd_soc_dai_ops gbcodec_dai_ops = { .startup = gbcodec_startup, .shutdown = gbcodec_shutdown, .hw_params = gbcodec_hw_params, diff --git a/drivers/staging/greybus/gbphy.c b/drivers/staging/greybus/gbphy.c index 603de6f21fd1..80c1da8224e6 100644 --- a/drivers/staging/greybus/gbphy.c +++ b/drivers/staging/greybus/gbphy.c @@ -66,7 +66,7 @@ static const struct dev_pm_ops gb_gbphy_pm_ops = { gb_gbphy_idle) }; -static struct device_type greybus_gbphy_dev_type = { +static const struct device_type greybus_gbphy_dev_type = { .name = "gbphy_device", .release = gbphy_dev_release, .pm = &gb_gbphy_pm_ops, diff --git a/drivers/staging/greybus/interface.c b/drivers/staging/greybus/interface.c index a4fd51632232..71e5cc234e78 100644 --- a/drivers/staging/greybus/interface.c +++ b/drivers/staging/greybus/interface.c @@ -47,7 +47,7 @@ static int gb_interface_hibernate_link(struct gb_interface *intf); static int gb_interface_refclk_set(struct gb_interface *intf, bool enable); static int gb_interface_dme_attr_get(struct gb_interface *intf, - u16 attr, u32 *val) + u16 attr, u32 *val) { return gb_svc_dme_peer_get(intf->hd->svc, intf->interface_id, attr, DME_SELECTOR_INDEX_NULL, val); @@ -64,7 +64,7 @@ static int gb_interface_read_ara_dme(struct gb_interface *intf) */ if (intf->ddbl1_manufacturer_id != TOSHIBA_DMID) { dev_err(&intf->dev, "unknown manufacturer %08x\n", - intf->ddbl1_manufacturer_id); + intf->ddbl1_manufacturer_id); return -ENODEV; } @@ -110,7 +110,7 @@ static int gb_interface_read_dme(struct gb_interface *intf) return ret; if (intf->ddbl1_manufacturer_id == TOSHIBA_DMID && - intf->ddbl1_product_id == TOSHIBA_ES2_BRIDGE_DPID) { + intf->ddbl1_product_id == TOSHIBA_ES2_BRIDGE_DPID) { intf->quirks |= GB_INTERFACE_QUIRK_NO_GMP_IDS; intf->quirks |= GB_INTERFACE_QUIRK_NO_INIT_STATUS; } @@ -144,7 +144,7 @@ static int gb_interface_route_create(struct gb_interface *intf) ret = gb_svc_intf_device_id(svc, intf_id, device_id); if (ret) { dev_err(&intf->dev, "failed to set device id %u: %d\n", - device_id, ret); + device_id, ret); goto err_ida_remove; } @@ -205,21 +205,21 @@ static int gb_interface_legacy_mode_switch(struct gb_interface *intf) } void gb_interface_mailbox_event(struct gb_interface *intf, u16 result, - u32 mailbox) + u32 mailbox) { mutex_lock(&intf->mutex); if (result) { dev_warn(&intf->dev, - "mailbox event with UniPro error: 0x%04x\n", - result); + "mailbox event with UniPro error: 0x%04x\n", + result); goto err_disable; } if (mailbox != GB_SVC_INTF_MAILBOX_GREYBUS) { dev_warn(&intf->dev, - "mailbox event with unexpected value: 0x%08x\n", - mailbox); + "mailbox event with unexpected value: 0x%08x\n", + mailbox); goto err_disable; } @@ -230,7 +230,7 @@ void gb_interface_mailbox_event(struct gb_interface *intf, u16 result, if (!intf->mode_switch) { dev_warn(&intf->dev, "unexpected mailbox event: 0x%08x\n", - mailbox); + mailbox); goto err_disable; } @@ -299,7 +299,7 @@ static void gb_interface_mode_switch_work(struct work_struct *work) ret = gb_interface_enable(intf); if (ret) { dev_err(&intf->dev, "failed to re-enable interface: %d\n", - ret); + ret); gb_interface_deactivate(intf); } } @@ -619,7 +619,7 @@ static struct attribute *interface_common_attrs[] = { }; static umode_t interface_unipro_is_visible(struct kobject *kobj, - struct attribute *attr, int n) + struct attribute *attr, int n) { struct device *dev = container_of(kobj, struct device, kobj); struct gb_interface *intf = to_gb_interface(dev); @@ -634,7 +634,7 @@ static umode_t interface_unipro_is_visible(struct kobject *kobj, } static umode_t interface_greybus_is_visible(struct kobject *kobj, - struct attribute *attr, int n) + struct attribute *attr, int n) { struct device *dev = container_of(kobj, struct device, kobj); struct gb_interface *intf = to_gb_interface(dev); @@ -648,7 +648,7 @@ static umode_t interface_greybus_is_visible(struct kobject *kobj, } static umode_t interface_power_is_visible(struct kobject *kobj, - struct attribute *attr, int n) + struct attribute *attr, int n) { struct device *dev = container_of(kobj, struct device, kobj); struct gb_interface *intf = to_gb_interface(dev); @@ -813,7 +813,7 @@ struct gb_interface *gb_interface_create(struct gb_module *module, intf->dev.dma_mask = module->dev.dma_mask; device_initialize(&intf->dev); dev_set_name(&intf->dev, "%s.%u", dev_name(&module->dev), - interface_id); + interface_id); pm_runtime_set_autosuspend_delay(&intf->dev, GB_INTERFACE_AUTOSUSPEND_MS); @@ -1083,7 +1083,7 @@ int gb_interface_enable(struct gb_interface *intf) control = gb_control_create(intf); if (IS_ERR(control)) { dev_err(&intf->dev, "failed to create control device: %ld\n", - PTR_ERR(control)); + PTR_ERR(control)); return PTR_ERR(control); } intf->control = control; @@ -1228,17 +1228,17 @@ int gb_interface_add(struct gb_interface *intf) trace_gb_interface_add(intf); dev_info(&intf->dev, "Interface added (%s)\n", - gb_interface_type_string(intf)); + gb_interface_type_string(intf)); switch (intf->type) { case GB_INTERFACE_TYPE_GREYBUS: dev_info(&intf->dev, "GMP VID=0x%08x, PID=0x%08x\n", - intf->vendor_id, intf->product_id); + intf->vendor_id, intf->product_id); /* fall-through */ case GB_INTERFACE_TYPE_UNIPRO: dev_info(&intf->dev, "DDBL1 Manufacturer=0x%08x, Product=0x%08x\n", - intf->ddbl1_manufacturer_id, - intf->ddbl1_product_id); + intf->ddbl1_manufacturer_id, + intf->ddbl1_product_id); break; default: break; diff --git a/drivers/staging/greybus/light.c b/drivers/staging/greybus/light.c index 861a249e6ef1..3f4148c92308 100644 --- a/drivers/staging/greybus/light.c +++ b/drivers/staging/greybus/light.c @@ -58,6 +58,7 @@ struct gb_light { bool ready; #if IS_REACHABLE(CONFIG_V4L2_FLASH_LED_CLASS) struct v4l2_flash *v4l2_flash; + struct v4l2_flash *v4l2_flash_ind; #endif }; @@ -534,26 +535,21 @@ static int gb_lights_light_v4l2_register(struct gb_light *light) { struct gb_connection *connection = get_conn_from_light(light); struct device *dev = &connection->bundle->dev; - struct v4l2_flash_config *sd_cfg; + struct v4l2_flash_config sd_cfg = { {0} }, sd_cfg_ind = { {0} }; struct led_classdev_flash *fled; - struct led_classdev_flash *iled = NULL; + struct led_classdev *iled = NULL; struct gb_channel *channel_torch, *channel_ind, *channel_flash; - int ret = 0; - - sd_cfg = kcalloc(1, sizeof(*sd_cfg), GFP_KERNEL); - if (!sd_cfg) - return -ENOMEM; channel_torch = get_channel_from_mode(light, GB_CHANNEL_MODE_TORCH); if (channel_torch) __gb_lights_channel_v4l2_config(&channel_torch->intensity_uA, - &sd_cfg->torch_intensity); + &sd_cfg.intensity); channel_ind = get_channel_from_mode(light, GB_CHANNEL_MODE_INDICATOR); if (channel_ind) { __gb_lights_channel_v4l2_config(&channel_ind->intensity_uA, - &sd_cfg->indicator_intensity); - iled = &channel_ind->fled; + &sd_cfg_ind.intensity); + iled = &channel_ind->fled.led_cdev; } channel_flash = get_channel_from_mode(light, GB_CHANNEL_MODE_FLASH); @@ -561,31 +557,37 @@ static int gb_lights_light_v4l2_register(struct gb_light *light) fled = &channel_flash->fled; - snprintf(sd_cfg->dev_name, sizeof(sd_cfg->dev_name), "%s", light->name); + snprintf(sd_cfg.dev_name, sizeof(sd_cfg.dev_name), "%s", light->name); + snprintf(sd_cfg_ind.dev_name, sizeof(sd_cfg_ind.dev_name), + "%s indicator", light->name); /* Set the possible values to faults, in our case all faults */ - sd_cfg->flash_faults = LED_FAULT_OVER_VOLTAGE | LED_FAULT_TIMEOUT | + sd_cfg.flash_faults = LED_FAULT_OVER_VOLTAGE | LED_FAULT_TIMEOUT | LED_FAULT_OVER_TEMPERATURE | LED_FAULT_SHORT_CIRCUIT | LED_FAULT_OVER_CURRENT | LED_FAULT_INDICATOR | LED_FAULT_UNDER_VOLTAGE | LED_FAULT_INPUT_VOLTAGE | LED_FAULT_LED_OVER_TEMPERATURE; - light->v4l2_flash = v4l2_flash_init(dev, NULL, fled, iled, - &v4l2_flash_ops, sd_cfg); - if (IS_ERR_OR_NULL(light->v4l2_flash)) { - ret = PTR_ERR(light->v4l2_flash); - goto out_free; - } + light->v4l2_flash = v4l2_flash_init(dev, NULL, fled, &v4l2_flash_ops, + &sd_cfg); + if (IS_ERR(light->v4l2_flash)) + return PTR_ERR(light->v4l2_flash); - return ret; + if (channel_ind) { + light->v4l2_flash_ind = + v4l2_flash_indicator_init(dev, NULL, iled, &sd_cfg_ind); + if (IS_ERR(light->v4l2_flash_ind)) { + v4l2_flash_release(light->v4l2_flash); + return PTR_ERR(light->v4l2_flash_ind); + } + } -out_free: - kfree(sd_cfg); - return ret; + return 0; } static void gb_lights_light_v4l2_unregister(struct gb_light *light) { + v4l2_flash_release(light->v4l2_flash_ind); v4l2_flash_release(light->v4l2_flash); } #else diff --git a/drivers/staging/greybus/spilib.h b/drivers/staging/greybus/spilib.h index 566d0dde7f79..cb6092578a92 100644 --- a/drivers/staging/greybus/spilib.h +++ b/drivers/staging/greybus/spilib.h @@ -18,7 +18,8 @@ struct spilib_ops { void (*unprepare_transfer_hardware)(struct device *dev); }; -int gb_spilib_master_init(struct gb_connection *connection, struct device *dev, struct spilib_ops *ops); +int gb_spilib_master_init(struct gb_connection *connection, + struct device *dev, struct spilib_ops *ops); void gb_spilib_master_exit(struct gb_connection *connection); #endif /* __SPILIB_H */ diff --git a/drivers/staging/greybus/tools/loopback_test.c b/drivers/staging/greybus/tools/loopback_test.c index 32a43693181c..fbe589fca840 100644 --- a/drivers/staging/greybus/tools/loopback_test.c +++ b/drivers/staging/greybus/tools/loopback_test.c @@ -420,10 +420,10 @@ void log_csv_error(int len, int err) } int format_output(struct loopback_test *t, - struct loopback_results *r, - const char *dev_name, - char *buf, int buf_len, - struct tm *tm) + struct loopback_results *r, + const char *dev_name, + char *buf, int buf_len, + struct tm *tm) { int len = 0; @@ -528,14 +528,14 @@ static int log_results(struct loopback_test *t) tm = *localtime(&local_time); /* - * file name will test_name_size_iteration_max.csv - * every time the same test with the same parameters is run we will then - * append to the same CSV with datestamp - representing each test - * dataset. - */ + * file name will test_name_size_iteration_max.csv + * every time the same test with the same parameters is run we will then + * append to the same CSV with datestamp - representing each test + * dataset. + */ if (t->file_output && !t->porcelain) { snprintf(file_name, sizeof(file_name), "%s_%d_%d.csv", - t->test_name, t->size, t->iteration_max); + t->test_name, t->size, t->iteration_max); fd = open(file_name, O_WRONLY | O_CREAT | O_APPEND, 0644); if (fd < 0) { @@ -549,8 +549,8 @@ static int log_results(struct loopback_test *t) continue; len = format_output(t, &t->devices[i].results, - t->devices[i].name, - data, sizeof(data), &tm); + t->devices[i].name, + data, sizeof(data), &tm); if (t->file_output && !t->porcelain) { ret = write(fd, data, len); if (ret == -1) @@ -562,7 +562,7 @@ static int log_results(struct loopback_test *t) if (t->aggregate_output) { len = format_output(t, &t->aggregate_results, "aggregate", - data, sizeof(data), &tm); + data, sizeof(data), &tm); if (t->file_output && !t->porcelain) { ret = write(fd, data, len); if (ret == -1) @@ -623,14 +623,13 @@ int find_loopback_devices(struct loopback_test *t) snprintf(d->name, MAX_STR_LEN, "gb_loopback%u", dev_id); snprintf(d->sysfs_entry, MAX_SYSFS_PATH, "%s%s/", - t->sysfs_prefix, d->name); + t->sysfs_prefix, d->name); snprintf(d->debugfs_entry, MAX_SYSFS_PATH, "%sraw_latency_%s", - t->debugfs_prefix, d->name); + t->debugfs_prefix, d->name); if (t->debug) - printf("add %s %s\n", d->sysfs_entry, - d->debugfs_entry); + printf("add %s %s\n", d->sysfs_entry, d->debugfs_entry); } ret = 0; @@ -779,7 +778,8 @@ static void prepare_devices(struct loopback_test *t) { int i; - /* Cancel any running tests on enabled devices. If + /* + * Cancel any running tests on enabled devices. If * stop_all option is given, stop test on all devices. */ for (i = 0; i < t->device_count; i++) @@ -802,16 +802,14 @@ static void prepare_devices(struct loopback_test *t) t->iteration_max); if (t->use_async) { + write_sysfs_val(t->devices[i].sysfs_entry, "async", 1); write_sysfs_val(t->devices[i].sysfs_entry, - "async", 1); + "timeout", t->async_timeout); write_sysfs_val(t->devices[i].sysfs_entry, - "timeout", t->async_timeout); - write_sysfs_val(t->devices[i].sysfs_entry, - "outstanding_operations_max", - t->async_outstanding_operations); + "outstanding_operations_max", + t->async_outstanding_operations); } else - write_sysfs_val(t->devices[i].sysfs_entry, - "async", 0); + write_sysfs_val(t->devices[i].sysfs_entry, "async", 0); } } diff --git a/drivers/staging/greybus/usb.c b/drivers/staging/greybus/usb.c index ccadda084b76..f93a76d02de6 100644 --- a/drivers/staging/greybus/usb.c +++ b/drivers/staging/greybus/usb.c @@ -139,7 +139,7 @@ out: return ret; } -static struct hc_driver usb_gb_hc_driver = { +static const struct hc_driver usb_gb_hc_driver = { .description = "greybus-hcd", .product_desc = "Greybus USB Host Controller", .hcd_priv_size = sizeof(struct gb_usb_device), diff --git a/drivers/staging/greybus/vibrator.c b/drivers/staging/greybus/vibrator.c index 77a2365a55e6..5cd8a50d41ad 100644 --- a/drivers/staging/greybus/vibrator.c +++ b/drivers/staging/greybus/vibrator.c @@ -34,7 +34,7 @@ static int turn_off(struct gb_vibrator_device *vib) int ret; ret = gb_operation_sync(vib->connection, GB_VIBRATOR_TYPE_OFF, - NULL, 0, NULL, 0); + NULL, 0, NULL, 0); gb_pm_runtime_put_autosuspend(bundle); @@ -55,7 +55,7 @@ static int turn_on(struct gb_vibrator_device *vib, u16 timeout_ms) turn_off(vib); ret = gb_operation_sync(vib->connection, GB_VIBRATOR_TYPE_ON, - NULL, 0, NULL, 0); + NULL, 0, NULL, 0); if (ret) { gb_pm_runtime_put_autosuspend(bundle); return ret; @@ -116,7 +116,7 @@ static struct class vibrator_class = { static DEFINE_IDA(minors); static int gb_vibrator_probe(struct gb_bundle *bundle, - const struct greybus_bundle_id *id) + const struct greybus_bundle_id *id) { struct greybus_descriptor_cport *cport_desc; struct gb_connection *connection; @@ -136,7 +136,7 @@ static int gb_vibrator_probe(struct gb_bundle *bundle, return -ENOMEM; connection = gb_connection_create(bundle, le16_to_cpu(cport_desc->id), - NULL); + NULL); if (IS_ERR(connection)) { retval = PTR_ERR(connection); goto err_free_vib; diff --git a/drivers/staging/gs_fpgaboot/gs_fpgaboot.c b/drivers/staging/gs_fpgaboot/gs_fpgaboot.c index 19b550fff04b..bcbdc7340b55 100644 --- a/drivers/staging/gs_fpgaboot/gs_fpgaboot.c +++ b/drivers/staging/gs_fpgaboot/gs_fpgaboot.c @@ -23,6 +23,7 @@ #include <linux/delay.h> #include <linux/io.h> #include <linux/firmware.h> +#include <asm/unaligned.h> #include "gs_fpgaboot.h" #include "io.h" @@ -41,16 +42,16 @@ static char *file = "xlinx_fpga_firmware.bit"; module_param(file, charp, 0444); MODULE_PARM_DESC(file, "Xilinx FPGA firmware file."); -static void read_bitstream(char *bitdata, char *buf, int *offset, int rdsize) +static void read_bitstream(u8 *bitdata, u8 *buf, int *offset, int rdsize) { memcpy(buf, bitdata + *offset, rdsize); *offset += rdsize; } -static void readinfo_bitstream(char *bitdata, char *buf, int *offset) +static int readinfo_bitstream(u8 *bitdata, u8 *buf, int size, int *offset) { - char tbuf[64]; - s32 len; + u8 tbuf[2]; + u16 len; /* read section char */ read_bitstream(bitdata, tbuf, offset, 1); @@ -58,18 +59,24 @@ static void readinfo_bitstream(char *bitdata, char *buf, int *offset) /* read length */ read_bitstream(bitdata, tbuf, offset, 2); - len = tbuf[0] << 8 | tbuf[1]; + len = get_unaligned_be16(tbuf); + if (len >= size) { + pr_err("error: readinfo buffer too small\n"); + return -EINVAL; + } read_bitstream(bitdata, buf, offset, len); buf[len] = '\0'; + + return 0; } /* * read bitdata length */ -static int readlength_bitstream(char *bitdata, int *lendata, int *offset) +static int readlength_bitstream(u8 *bitdata, int *lendata, int *offset) { - char tbuf[64]; + u8 tbuf[4]; /* read section char */ read_bitstream(bitdata, tbuf, offset, 1); @@ -77,14 +84,13 @@ static int readlength_bitstream(char *bitdata, int *lendata, int *offset) /* make sure it is section 'e' */ if (tbuf[0] != 'e') { pr_err("error: length section is not 'e', but %c\n", tbuf[0]); - return -1; + return -EINVAL; } /* read 4bytes length */ read_bitstream(bitdata, tbuf, offset, 4); - *lendata = tbuf[0] << 24 | tbuf[1] << 16 | - tbuf[2] << 8 | tbuf[3]; + *lendata = get_unaligned_be32(tbuf); return 0; } @@ -92,16 +98,16 @@ static int readlength_bitstream(char *bitdata, int *lendata, int *offset) /* * read first 13 bytes to check bitstream magic number */ -static int readmagic_bitstream(char *bitdata, int *offset) +static int readmagic_bitstream(u8 *bitdata, int *offset) { - char buf[13]; + u8 buf[13]; int r; read_bitstream(bitdata, buf, offset, 13); r = memcmp(buf, bits_magic, 13); if (r) { pr_err("error: corrupted header"); - return -1; + return -EINVAL; } pr_info("bitstream file magic number Ok\n"); @@ -113,7 +119,7 @@ static int readmagic_bitstream(char *bitdata, int *offset) /* * NOTE: supports only bitstream format */ -static enum fmt_image get_imageformat(struct fpgaimage *fimage) +static enum fmt_image get_imageformat(void) { return f_bit; } @@ -127,38 +133,58 @@ static void gs_print_header(struct fpgaimage *fimage) pr_info("lendata: %d\n", fimage->lendata); } -static void gs_read_bitstream(struct fpgaimage *fimage) +static int gs_read_bitstream(struct fpgaimage *fimage) { - char *bitdata; + u8 *bitdata; int offset; + int err; offset = 0; - bitdata = (char *)fimage->fw_entry->data; + bitdata = (u8 *)fimage->fw_entry->data; + + err = readmagic_bitstream(bitdata, &offset); + if (err) + return err; + + err = readinfo_bitstream(bitdata, fimage->filename, MAX_STR, &offset); + if (err) + return err; + err = readinfo_bitstream(bitdata, fimage->part, MAX_STR, &offset); + if (err) + return err; + err = readinfo_bitstream(bitdata, fimage->date, MAX_STR, &offset); + if (err) + return err; + err = readinfo_bitstream(bitdata, fimage->time, MAX_STR, &offset); + if (err) + return err; - readmagic_bitstream(bitdata, &offset); - readinfo_bitstream(bitdata, fimage->filename, &offset); - readinfo_bitstream(bitdata, fimage->part, &offset); - readinfo_bitstream(bitdata, fimage->date, &offset); - readinfo_bitstream(bitdata, fimage->time, &offset); - readlength_bitstream(bitdata, &fimage->lendata, &offset); + err = readlength_bitstream(bitdata, &fimage->lendata, &offset); + if (err) + return err; fimage->fpgadata = bitdata + offset; + + return 0; } static int gs_read_image(struct fpgaimage *fimage) { int img_fmt; + int err; - img_fmt = get_imageformat(fimage); + img_fmt = get_imageformat(); switch (img_fmt) { case f_bit: pr_info("image is bitstream format\n"); - gs_read_bitstream(fimage); + err = gs_read_bitstream(fimage); + if (err) + return err; break; default: pr_err("unsupported fpga image format\n"); - return -1; + return -EINVAL; } gs_print_header(fimage); @@ -183,11 +209,11 @@ static int gs_load_image(struct fpgaimage *fimage, char *fw_file) static int gs_download_image(struct fpgaimage *fimage, enum wbus bus_bytes) { - char *bitdata; + u8 *bitdata; int size, i, cnt; cnt = 0; - bitdata = (char *)fimage->fpgadata; + bitdata = (u8 *)fimage->fpgadata; size = fimage->lendata; #ifdef DEBUG_FPGA @@ -197,7 +223,7 @@ static int gs_download_image(struct fpgaimage *fimage, enum wbus bus_bytes) if (!xl_supported_prog_bus_width(bus_bytes)) { pr_err("unsupported program bus width %d\n", bus_bytes); - return -1; + return -EINVAL; } /* Bring csi_b, rdwr_b Low and program_b High */ @@ -224,7 +250,7 @@ static int gs_download_image(struct fpgaimage *fimage, enum wbus bus_bytes) /* Check INIT_B */ if (xl_get_init_b() == 0) { pr_err("init_b 0\n"); - return -1; + return -EIO; } while (xl_get_done_b() == 0) { @@ -236,7 +262,7 @@ static int gs_download_image(struct fpgaimage *fimage, enum wbus bus_bytes) if (cnt > MAX_WAIT_DONE) { pr_err("fpga download fail\n"); - return -1; + return -EIO; } pr_info("download fpgaimage\n"); @@ -325,7 +351,7 @@ err_out2: err_out1: kfree(fimage); - return -1; + return err; } static int __init gs_fpgaboot_init(void) diff --git a/drivers/staging/gs_fpgaboot/gs_fpgaboot.h b/drivers/staging/gs_fpgaboot/gs_fpgaboot.h index cd1eb2c4c940..986e841f6b5e 100644 --- a/drivers/staging/gs_fpgaboot/gs_fpgaboot.h +++ b/drivers/staging/gs_fpgaboot/gs_fpgaboot.h @@ -47,5 +47,5 @@ struct fpgaimage { char date[MAX_STR]; char time[MAX_STR]; int lendata; - char *fpgadata; + u8 *fpgadata; }; diff --git a/drivers/staging/gs_fpgaboot/io.c b/drivers/staging/gs_fpgaboot/io.c index c9391198fbfb..83a13ca7259a 100644 --- a/drivers/staging/gs_fpgaboot/io.c +++ b/drivers/staging/gs_fpgaboot/io.c @@ -9,10 +9,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <linux/kernel.h> diff --git a/drivers/staging/iio/adc/ad7280a.c b/drivers/staging/iio/adc/ad7280a.c index d5ab83f0236d..f85dde9805e0 100644 --- a/drivers/staging/iio/adc/ad7280a.c +++ b/drivers/staging/iio/adc/ad7280a.c @@ -99,9 +99,14 @@ #define AD7280A_DEVADDR_MASTER 0 #define AD7280A_DEVADDR_ALL 0x1F /* 5-bit device address is sent LSB first */ -#define AD7280A_DEVADDR(addr) (((addr & 0x1) << 4) | ((addr & 0x2) << 3) | \ - (addr & 0x4) | ((addr & 0x8) >> 3) | \ - ((addr & 0x10) >> 4)) +static unsigned int ad7280a_devaddr(unsigned int addr) +{ + return ((addr & 0x1) << 4) | + ((addr & 0x2) << 3) | + (addr & 0x4) | + ((addr & 0x8) >> 3) | + ((addr & 0x10) >> 4); +} /* During a read a valid write is mandatory. * So writing to the highest available address (Address 0x1F) @@ -372,7 +377,7 @@ static int ad7280_chain_setup(struct ad7280_state *st) if (ad7280_check_crc(st, val)) return -EIO; - if (n != AD7280A_DEVADDR(val >> 27)) + if (n != ad7280a_devaddr(val >> 27)) return -EIO; } @@ -511,7 +516,7 @@ static int ad7280_channel_init(struct ad7280_state *st) st->channels[cnt].info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE); st->channels[cnt].address = - AD7280A_DEVADDR(dev) << 8 | ch; + ad7280a_devaddr(dev) << 8 | ch; st->channels[cnt].scan_index = cnt; st->channels[cnt].scan_type.sign = 'u'; st->channels[cnt].scan_type.realbits = 12; @@ -558,7 +563,7 @@ static int ad7280_attr_init(struct ad7280_state *st) for (ch = AD7280A_CELL_VOLTAGE_1; ch <= AD7280A_CELL_VOLTAGE_6; ch++, cnt++) { st->iio_attr[cnt].address = - AD7280A_DEVADDR(dev) << 8 | ch; + ad7280a_devaddr(dev) << 8 | ch; st->iio_attr[cnt].dev_attr.attr.mode = 0644; st->iio_attr[cnt].dev_attr.show = @@ -574,7 +579,7 @@ static int ad7280_attr_init(struct ad7280_state *st) &st->iio_attr[cnt].dev_attr.attr; cnt++; st->iio_attr[cnt].address = - AD7280A_DEVADDR(dev) << 8 | + ad7280a_devaddr(dev) << 8 | (AD7280A_CB1_TIMER + ch); st->iio_attr[cnt].dev_attr.attr.mode = 0644; @@ -918,7 +923,7 @@ static int ad7280_probe(struct spi_device *spi) if (ret) goto error_unregister; - ret = ad7280_write(st, AD7280A_DEVADDR(st->slave_num), + ret = ad7280_write(st, ad7280a_devaddr(st->slave_num), AD7280A_ALERT, 0, AD7280A_ALERT_GEN_STATIC_HIGH | (pdata->chain_last_alert_ignore & 0xF)); diff --git a/drivers/staging/iio/adc/ad7606_par.c b/drivers/staging/iio/adc/ad7606_par.c index cd6c410c0484..3eb6f8f312dd 100644 --- a/drivers/staging/iio/adc/ad7606_par.c +++ b/drivers/staging/iio/adc/ad7606_par.c @@ -57,8 +57,8 @@ static int ad7606_par_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) { - dev_err(&pdev->dev, "no irq\n"); - return -ENODEV; + dev_err(&pdev->dev, "no irq: %d\n", irq); + return irq; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); diff --git a/drivers/staging/iio/light/tsl2x7x.c b/drivers/staging/iio/light/tsl2x7x.c index 146719928fb3..786e93f16ce9 100644 --- a/drivers/staging/iio/light/tsl2x7x.c +++ b/drivers/staging/iio/light/tsl2x7x.c @@ -285,35 +285,6 @@ static const u8 device_channel_config[] = { }; /** - * tsl2x7x_i2c_read() - Read a byte from a register. - * @client: i2c client - * @reg: device register to read from - * @*val: pointer to location to store register contents. - * - */ -static int -tsl2x7x_i2c_read(struct i2c_client *client, u8 reg, u8 *val) -{ - int ret; - - /* select register to write */ - ret = i2c_smbus_write_byte(client, (TSL2X7X_CMD_REG | reg)); - if (ret < 0) { - dev_err(&client->dev, "failed to write register %x\n", reg); - return ret; - } - - /* read the data */ - ret = i2c_smbus_read_byte(client); - if (ret >= 0) - *val = (u8)ret; - else - dev_err(&client->dev, "failed to read register %x\n", reg); - - return ret; -} - -/** * tsl2x7x_get_lux() - Reads and calculates current lux value. * @indio_dev: pointer to IIO device * @@ -352,15 +323,15 @@ static int tsl2x7x_get_lux(struct iio_dev *indio_dev) goto out_unlock; } - ret = tsl2x7x_i2c_read(chip->client, - (TSL2X7X_CMD_REG | TSL2X7X_STATUS), &buf[0]); + ret = i2c_smbus_read_byte_data(chip->client, + TSL2X7X_CMD_REG | TSL2X7X_STATUS); if (ret < 0) { dev_err(&chip->client->dev, "%s: Failed to read STATUS Reg\n", __func__); goto out_unlock; } /* is data new & valid */ - if (!(buf[0] & TSL2X7X_STA_ADC_VALID)) { + if (!(ret & TSL2X7X_STA_ADC_VALID)) { dev_err(&chip->client->dev, "%s: data not valid yet\n", __func__); ret = chip->als_cur_info.lux; /* return LAST VALUE */ @@ -368,14 +339,16 @@ static int tsl2x7x_get_lux(struct iio_dev *indio_dev) } for (i = 0; i < 4; i++) { - ret = tsl2x7x_i2c_read(chip->client, - (TSL2X7X_CMD_REG | - (TSL2X7X_ALS_CHAN0LO + i)), &buf[i]); + int reg = TSL2X7X_CMD_REG | (TSL2X7X_ALS_CHAN0LO + i); + + ret = i2c_smbus_read_byte_data(chip->client, reg); if (ret < 0) { dev_err(&chip->client->dev, "failed to read. err=%x\n", ret); goto out_unlock; } + + buf[i] = ret; } /* clear any existing interrupt status */ @@ -475,7 +448,6 @@ static int tsl2x7x_get_prox(struct iio_dev *indio_dev) { int i; int ret; - u8 status; u8 chdata[2]; struct tsl2X7X_chip *chip = iio_priv(indio_dev); @@ -485,8 +457,8 @@ static int tsl2x7x_get_prox(struct iio_dev *indio_dev) return -EBUSY; } - ret = tsl2x7x_i2c_read(chip->client, - (TSL2X7X_CMD_REG | TSL2X7X_STATUS), &status); + ret = i2c_smbus_read_byte_data(chip->client, + TSL2X7X_CMD_REG | TSL2X7X_STATUS); if (ret < 0) { dev_err(&chip->client->dev, "i2c err=%d\n", ret); goto prox_poll_err; @@ -498,7 +470,7 @@ static int tsl2x7x_get_prox(struct iio_dev *indio_dev) case tmd2671: case tsl2771: case tmd2771: - if (!(status & TSL2X7X_STA_ADC_VALID)) + if (!(ret & TSL2X7X_STA_ADC_VALID)) goto prox_poll_err; break; case tsl2572: @@ -506,17 +478,19 @@ static int tsl2x7x_get_prox(struct iio_dev *indio_dev) case tmd2672: case tsl2772: case tmd2772: - if (!(status & TSL2X7X_STA_PRX_VALID)) + if (!(ret & TSL2X7X_STA_PRX_VALID)) goto prox_poll_err; break; } for (i = 0; i < 2; i++) { - ret = tsl2x7x_i2c_read(chip->client, - (TSL2X7X_CMD_REG | - (TSL2X7X_PRX_LO + i)), &chdata[i]); + int reg = TSL2X7X_CMD_REG | (TSL2X7X_PRX_LO + i); + + ret = i2c_smbus_read_byte_data(chip->client, reg); if (ret < 0) goto prox_poll_err; + + chdata[i] = ret; } chip->prox_data = @@ -568,39 +542,29 @@ static void tsl2x7x_defaults(struct tsl2X7X_chip *chip) static int tsl2x7x_als_calibrate(struct iio_dev *indio_dev) { struct tsl2X7X_chip *chip = iio_priv(indio_dev); - u8 reg_val; int gain_trim_val; int ret; int lux_val; - ret = i2c_smbus_write_byte(chip->client, - (TSL2X7X_CMD_REG | TSL2X7X_CNTRL)); + ret = i2c_smbus_read_byte_data(chip->client, + TSL2X7X_CMD_REG | TSL2X7X_CNTRL); if (ret < 0) { dev_err(&chip->client->dev, - "failed to write CNTRL register, ret=%d\n", ret); + "%s: failed to read from the CNTRL register\n", + __func__); return ret; } - reg_val = i2c_smbus_read_byte(chip->client); - if ((reg_val & (TSL2X7X_CNTL_ADC_ENBL | TSL2X7X_CNTL_PWR_ON)) - != (TSL2X7X_CNTL_ADC_ENBL | TSL2X7X_CNTL_PWR_ON)) { - dev_err(&chip->client->dev, - "%s: failed: ADC not enabled\n", __func__); - return -1; - } - - ret = i2c_smbus_write_byte(chip->client, - (TSL2X7X_CMD_REG | TSL2X7X_CNTRL)); - if (ret < 0) { + if ((ret & (TSL2X7X_CNTL_ADC_ENBL | TSL2X7X_CNTL_PWR_ON)) + != (TSL2X7X_CNTL_ADC_ENBL | TSL2X7X_CNTL_PWR_ON)) { dev_err(&chip->client->dev, - "failed to write ctrl reg: ret=%d\n", ret); - return ret; - } - - reg_val = i2c_smbus_read_byte(chip->client); - if ((reg_val & TSL2X7X_STA_ADC_VALID) != TSL2X7X_STA_ADC_VALID) { + "%s: Device is not powered on and/or ADC is not enabled\n", + __func__); + return -EINVAL; + } else if ((ret & TSL2X7X_STA_ADC_VALID) != TSL2X7X_STA_ADC_VALID) { dev_err(&chip->client->dev, - "%s: failed: STATUS - ADC not valid.\n", __func__); + "%s: The two ADC channels have not completed an integration cycle\n", + __func__); return -ENODATA; } @@ -722,7 +686,8 @@ static int tsl2x7x_chip_on(struct iio_dev *indio_dev) } } - mdelay(3); /* Power-on settling time */ + /* Power-on settling time */ + usleep_range(3000, 3500); /* * NOW enable the ADC @@ -806,22 +771,24 @@ int tsl2x7x_invoke_change(struct iio_dev *indio_dev) { struct tsl2X7X_chip *chip = iio_priv(indio_dev); int device_status = chip->tsl2x7x_chip_status; + int ret; mutex_lock(&chip->als_mutex); mutex_lock(&chip->prox_mutex); - if (device_status == TSL2X7X_CHIP_WORKING) - tsl2x7x_chip_off(indio_dev); - - tsl2x7x_chip_on(indio_dev); + if (device_status == TSL2X7X_CHIP_WORKING) { + ret = tsl2x7x_chip_off(indio_dev); + if (ret < 0) + goto unlock; + } - if (device_status != TSL2X7X_CHIP_WORKING) - tsl2x7x_chip_off(indio_dev); + ret = tsl2x7x_chip_on(indio_dev); +unlock: mutex_unlock(&chip->prox_mutex); mutex_unlock(&chip->als_mutex); - return 0; + return ret; } static @@ -889,7 +856,7 @@ static void tsl2x7x_prox_cal(struct iio_dev *indio_dev) /*gather the samples*/ for (i = 0; i < chip->tsl2x7x_settings.prox_max_samples_cal; i++) { - mdelay(15); + usleep_range(15000, 17500); tsl2x7x_get_prox(indio_dev); prox_history[i] = chip->prox_data; dev_info(&chip->client->dev, "2 i=%d prox data= %d\n", @@ -915,33 +882,6 @@ static void tsl2x7x_prox_cal(struct iio_dev *indio_dev) tsl2x7x_chip_on(indio_dev); } -static ssize_t power_state_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev)); - - return snprintf(buf, PAGE_SIZE, "%d\n", chip->tsl2x7x_chip_status); -} - -static ssize_t power_state_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - bool value; - - if (strtobool(buf, &value)) - return -EINVAL; - - if (value) - tsl2x7x_chip_on(indio_dev); - else - tsl2x7x_chip_off(indio_dev); - - return len; -} - static ssize_t in_illuminance0_calibscale_available_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -1027,6 +967,7 @@ static ssize_t in_illuminance0_target_input_store(struct device *dev, struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct tsl2X7X_chip *chip = iio_priv(indio_dev); unsigned long value; + int ret; if (kstrtoul(buf, 0, &value)) return -EINVAL; @@ -1034,7 +975,9 @@ static ssize_t in_illuminance0_target_input_store(struct device *dev, if (value) chip->tsl2x7x_settings.als_cal_target = value; - tsl2x7x_invoke_change(indio_dev); + ret = tsl2x7x_invoke_change(indio_dev); + if (ret < 0) + return ret; return len; } @@ -1083,7 +1026,9 @@ static ssize_t in_intensity0_thresh_period_store(struct device *dev, dev_info(&chip->client->dev, "%s: als persistence = %d", __func__, filter_delay); - tsl2x7x_invoke_change(indio_dev); + ret = tsl2x7x_invoke_change(indio_dev); + if (ret < 0) + return ret; return IIO_VAL_INT_PLUS_MICRO; } @@ -1131,7 +1076,10 @@ static ssize_t in_proximity0_thresh_period_store(struct device *dev, dev_info(&chip->client->dev, "%s: prox persistence = %d", __func__, filter_delay); - tsl2x7x_invoke_change(indio_dev); + ret = tsl2x7x_invoke_change(indio_dev); + if (ret < 0) + return ret; + return IIO_VAL_INT_PLUS_MICRO; } @@ -1142,6 +1090,7 @@ static ssize_t in_illuminance0_calibrate_store(struct device *dev, { struct iio_dev *indio_dev = dev_to_iio_dev(dev); bool value; + int ret; if (strtobool(buf, &value)) return -EINVAL; @@ -1149,7 +1098,9 @@ static ssize_t in_illuminance0_calibrate_store(struct device *dev, if (value) tsl2x7x_als_calibrate(indio_dev); - tsl2x7x_invoke_change(indio_dev); + ret = tsl2x7x_invoke_change(indio_dev); + if (ret < 0) + return ret; return len; } @@ -1189,7 +1140,7 @@ static ssize_t in_illuminance0_lux_table_store(struct device *dev, struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct tsl2X7X_chip *chip = iio_priv(indio_dev); int value[ARRAY_SIZE(chip->tsl2x7x_device_lux) * 3 + 1]; - int n; + int n, ret; get_options(buf, ARRAY_SIZE(value), value); @@ -1217,7 +1168,9 @@ static ssize_t in_illuminance0_lux_table_store(struct device *dev, memset(chip->tsl2x7x_device_lux, 0, sizeof(chip->tsl2x7x_device_lux)); memcpy(chip->tsl2x7x_device_lux, &value[1], (value[0] * 4)); - tsl2x7x_invoke_change(indio_dev); + ret = tsl2x7x_invoke_change(indio_dev); + if (ret < 0) + return ret; return len; } @@ -1228,6 +1181,7 @@ static ssize_t in_proximity0_calibrate_store(struct device *dev, { struct iio_dev *indio_dev = dev_to_iio_dev(dev); bool value; + int ret; if (strtobool(buf, &value)) return -EINVAL; @@ -1235,7 +1189,9 @@ static ssize_t in_proximity0_calibrate_store(struct device *dev, if (value) tsl2x7x_prox_cal(indio_dev); - tsl2x7x_invoke_change(indio_dev); + ret = tsl2x7x_invoke_change(indio_dev); + if (ret < 0) + return ret; return len; } @@ -1263,6 +1219,7 @@ static int tsl2x7x_write_interrupt_config(struct iio_dev *indio_dev, int val) { struct tsl2X7X_chip *chip = iio_priv(indio_dev); + int ret; if (chan->type == IIO_INTENSITY) { if (val) @@ -1276,83 +1233,108 @@ static int tsl2x7x_write_interrupt_config(struct iio_dev *indio_dev, chip->tsl2x7x_settings.interrupts_en &= 0x10; } - tsl2x7x_invoke_change(indio_dev); + ret = tsl2x7x_invoke_change(indio_dev); + if (ret < 0) + return ret; return 0; } -static int tsl2x7x_write_thresh(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, - enum iio_event_type type, - enum iio_event_direction dir, - enum iio_event_info info, - int val, int val2) +static int tsl2x7x_write_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int val, int val2) { struct tsl2X7X_chip *chip = iio_priv(indio_dev); + int ret = -EINVAL; - if (chan->type == IIO_INTENSITY) { - switch (dir) { - case IIO_EV_DIR_RISING: - chip->tsl2x7x_settings.als_thresh_high = val; - break; - case IIO_EV_DIR_FALLING: - chip->tsl2x7x_settings.als_thresh_low = val; - break; - default: - return -EINVAL; - } - } else { - switch (dir) { - case IIO_EV_DIR_RISING: - chip->tsl2x7x_settings.prox_thres_high = val; - break; - case IIO_EV_DIR_FALLING: - chip->tsl2x7x_settings.prox_thres_low = val; - break; - default: - return -EINVAL; + switch (info) { + case IIO_EV_INFO_VALUE: + if (chan->type == IIO_INTENSITY) { + switch (dir) { + case IIO_EV_DIR_RISING: + chip->tsl2x7x_settings.als_thresh_high = val; + ret = 0; + break; + case IIO_EV_DIR_FALLING: + chip->tsl2x7x_settings.als_thresh_low = val; + ret = 0; + break; + default: + break; + } + } else { + switch (dir) { + case IIO_EV_DIR_RISING: + chip->tsl2x7x_settings.prox_thres_high = val; + ret = 0; + break; + case IIO_EV_DIR_FALLING: + chip->tsl2x7x_settings.prox_thres_low = val; + ret = 0; + break; + default: + break; + } } + break; + default: + break; } - tsl2x7x_invoke_change(indio_dev); + if (ret < 0) + return ret; - return 0; + return tsl2x7x_invoke_change(indio_dev); } -static int tsl2x7x_read_thresh(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, - enum iio_event_type type, - enum iio_event_direction dir, - enum iio_event_info info, - int *val, int *val2) +static int tsl2x7x_read_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int *val, int *val2) { struct tsl2X7X_chip *chip = iio_priv(indio_dev); + int ret = -EINVAL; - if (chan->type == IIO_INTENSITY) { - switch (dir) { - case IIO_EV_DIR_RISING: - *val = chip->tsl2x7x_settings.als_thresh_high; - break; - case IIO_EV_DIR_FALLING: - *val = chip->tsl2x7x_settings.als_thresh_low; - break; - default: - return -EINVAL; - } - } else { - switch (dir) { - case IIO_EV_DIR_RISING: - *val = chip->tsl2x7x_settings.prox_thres_high; - break; - case IIO_EV_DIR_FALLING: - *val = chip->tsl2x7x_settings.prox_thres_low; - break; - default: - return -EINVAL; + switch (info) { + case IIO_EV_INFO_VALUE: + if (chan->type == IIO_INTENSITY) { + switch (dir) { + case IIO_EV_DIR_RISING: + *val = chip->tsl2x7x_settings.als_thresh_high; + ret = IIO_VAL_INT; + break; + case IIO_EV_DIR_FALLING: + *val = chip->tsl2x7x_settings.als_thresh_low; + ret = IIO_VAL_INT; + break; + default: + break; + } + } else { + switch (dir) { + case IIO_EV_DIR_RISING: + *val = chip->tsl2x7x_settings.prox_thres_high; + ret = IIO_VAL_INT; + break; + case IIO_EV_DIR_FALLING: + *val = chip->tsl2x7x_settings.prox_thres_low; + ret = IIO_VAL_INT; + break; + default: + break; + } } + break; + default: + break; } - return IIO_VAL_INT; + return ret; } static int tsl2x7x_read_raw(struct iio_dev *indio_dev, @@ -1489,13 +1471,9 @@ static int tsl2x7x_write_raw(struct iio_dev *indio_dev, return -EINVAL; } - tsl2x7x_invoke_change(indio_dev); - - return 0; + return tsl2x7x_invoke_change(indio_dev); } -static DEVICE_ATTR_RW(power_state); - static DEVICE_ATTR_RO(in_proximity0_calibscale_available); static DEVICE_ATTR_RO(in_illuminance0_calibscale_available); @@ -1515,7 +1493,7 @@ static DEVICE_ATTR_RW(in_intensity0_thresh_period); static DEVICE_ATTR_RW(in_proximity0_thresh_period); /* Use the default register values to identify the Taos device */ -static int tsl2x7x_device_id(unsigned char *id, int target) +static int tsl2x7x_device_id(int *id, int target) { switch (target) { case tsl2571: @@ -1580,7 +1558,6 @@ static irqreturn_t tsl2x7x_event_handler(int irq, void *private) } static struct attribute *tsl2x7x_ALS_device_attrs[] = { - &dev_attr_power_state.attr, &dev_attr_in_illuminance0_calibscale_available.attr, &dev_attr_in_illuminance0_integration_time.attr, &iio_const_attr_in_illuminance0_integration_time_available.dev_attr.attr, @@ -1591,13 +1568,11 @@ static struct attribute *tsl2x7x_ALS_device_attrs[] = { }; static struct attribute *tsl2x7x_PRX_device_attrs[] = { - &dev_attr_power_state.attr, &dev_attr_in_proximity0_calibrate.attr, NULL }; static struct attribute *tsl2x7x_ALSPRX_device_attrs[] = { - &dev_attr_power_state.attr, &dev_attr_in_illuminance0_calibscale_available.attr, &dev_attr_in_illuminance0_integration_time.attr, &iio_const_attr_in_illuminance0_integration_time_available.dev_attr.attr, @@ -1609,14 +1584,12 @@ static struct attribute *tsl2x7x_ALSPRX_device_attrs[] = { }; static struct attribute *tsl2x7x_PRX2_device_attrs[] = { - &dev_attr_power_state.attr, &dev_attr_in_proximity0_calibrate.attr, &dev_attr_in_proximity0_calibscale_available.attr, NULL }; static struct attribute *tsl2x7x_ALSPRX2_device_attrs[] = { - &dev_attr_power_state.attr, &dev_attr_in_illuminance0_calibscale_available.attr, &dev_attr_in_illuminance0_integration_time.attr, &iio_const_attr_in_illuminance0_integration_time_available.dev_attr.attr, @@ -1684,8 +1657,8 @@ static const struct iio_info tsl2X7X_device_info[] = { .driver_module = THIS_MODULE, .read_raw = &tsl2x7x_read_raw, .write_raw = &tsl2x7x_write_raw, - .read_event_value = &tsl2x7x_read_thresh, - .write_event_value = &tsl2x7x_write_thresh, + .read_event_value = &tsl2x7x_read_event_value, + .write_event_value = &tsl2x7x_write_event_value, .read_event_config = &tsl2x7x_read_interrupt_config, .write_event_config = &tsl2x7x_write_interrupt_config, }, @@ -1695,8 +1668,8 @@ static const struct iio_info tsl2X7X_device_info[] = { .driver_module = THIS_MODULE, .read_raw = &tsl2x7x_read_raw, .write_raw = &tsl2x7x_write_raw, - .read_event_value = &tsl2x7x_read_thresh, - .write_event_value = &tsl2x7x_write_thresh, + .read_event_value = &tsl2x7x_read_event_value, + .write_event_value = &tsl2x7x_write_event_value, .read_event_config = &tsl2x7x_read_interrupt_config, .write_event_config = &tsl2x7x_write_interrupt_config, }, @@ -1706,8 +1679,8 @@ static const struct iio_info tsl2X7X_device_info[] = { .driver_module = THIS_MODULE, .read_raw = &tsl2x7x_read_raw, .write_raw = &tsl2x7x_write_raw, - .read_event_value = &tsl2x7x_read_thresh, - .write_event_value = &tsl2x7x_write_thresh, + .read_event_value = &tsl2x7x_read_event_value, + .write_event_value = &tsl2x7x_write_event_value, .read_event_config = &tsl2x7x_read_interrupt_config, .write_event_config = &tsl2x7x_write_interrupt_config, }, @@ -1717,8 +1690,8 @@ static const struct iio_info tsl2X7X_device_info[] = { .driver_module = THIS_MODULE, .read_raw = &tsl2x7x_read_raw, .write_raw = &tsl2x7x_write_raw, - .read_event_value = &tsl2x7x_read_thresh, - .write_event_value = &tsl2x7x_write_thresh, + .read_event_value = &tsl2x7x_read_event_value, + .write_event_value = &tsl2x7x_write_event_value, .read_event_config = &tsl2x7x_read_interrupt_config, .write_event_config = &tsl2x7x_write_interrupt_config, }, @@ -1728,8 +1701,8 @@ static const struct iio_info tsl2X7X_device_info[] = { .driver_module = THIS_MODULE, .read_raw = &tsl2x7x_read_raw, .write_raw = &tsl2x7x_write_raw, - .read_event_value = &tsl2x7x_read_thresh, - .write_event_value = &tsl2x7x_write_thresh, + .read_event_value = &tsl2x7x_read_event_value, + .write_event_value = &tsl2x7x_write_event_value, .read_event_config = &tsl2x7x_read_interrupt_config, .write_event_config = &tsl2x7x_write_interrupt_config, }, @@ -1877,7 +1850,6 @@ static int tsl2x7x_probe(struct i2c_client *clientp, const struct i2c_device_id *id) { int ret; - unsigned char device_id; struct iio_dev *indio_dev; struct tsl2X7X_chip *chip; @@ -1889,13 +1861,13 @@ static int tsl2x7x_probe(struct i2c_client *clientp, chip->client = clientp; i2c_set_clientdata(clientp, indio_dev); - ret = tsl2x7x_i2c_read(chip->client, - TSL2X7X_CHIPID, &device_id); + ret = i2c_smbus_read_byte_data(chip->client, + TSL2X7X_CMD_REG | TSL2X7X_CHIPID); if (ret < 0) return ret; - if ((!tsl2x7x_device_id(&device_id, id->driver_data)) || - (tsl2x7x_device_id(&device_id, id->driver_data) == -EINVAL)) { + if ((!tsl2x7x_device_id(&ret, id->driver_data)) || + (tsl2x7x_device_id(&ret, id->driver_data) == -EINVAL)) { dev_info(&chip->client->dev, "%s: i2c device found does not match expected id\n", __func__); @@ -2026,6 +1998,21 @@ static struct i2c_device_id tsl2x7x_idtable[] = { MODULE_DEVICE_TABLE(i2c, tsl2x7x_idtable); +static const struct of_device_id tsl2x7x_of_match[] = { + { .compatible = "amstaos,tsl2571" }, + { .compatible = "amstaos,tsl2671" }, + { .compatible = "amstaos,tmd2671" }, + { .compatible = "amstaos,tsl2771" }, + { .compatible = "amstaos,tmd2771" }, + { .compatible = "amstaos,tsl2572" }, + { .compatible = "amstaos,tsl2672" }, + { .compatible = "amstaos,tmd2672" }, + { .compatible = "amstaos,tsl2772" }, + { .compatible = "amstaos,tmd2772" }, + {} +}; +MODULE_DEVICE_TABLE(of, tsl2x7x_of_match); + static const struct dev_pm_ops tsl2x7x_pm_ops = { .suspend = tsl2x7x_suspend, .resume = tsl2x7x_resume, @@ -2035,6 +2022,7 @@ static const struct dev_pm_ops tsl2x7x_pm_ops = { static struct i2c_driver tsl2x7x_driver = { .driver = { .name = "tsl2x7x", + .of_match_table = tsl2x7x_of_match, .pm = &tsl2x7x_pm_ops, }, .id_table = tsl2x7x_idtable, diff --git a/drivers/staging/irda/TODO b/drivers/staging/irda/TODO new file mode 100644 index 000000000000..7d98a5cffaff --- /dev/null +++ b/drivers/staging/irda/TODO @@ -0,0 +1,4 @@ +The irda code will be removed soon from the kernel tree as it is old and +obsolete and broken. + +Don't worry about fixing up anything here, it's not needed. diff --git a/drivers/staging/irda/drivers/Kconfig b/drivers/staging/irda/drivers/Kconfig new file mode 100644 index 000000000000..e070e1222733 --- /dev/null +++ b/drivers/staging/irda/drivers/Kconfig @@ -0,0 +1,398 @@ +menu "Infrared-port device drivers" + depends on IRDA!=n + +comment "SIR device drivers" + +config IRTTY_SIR + tristate "IrTTY (uses Linux serial driver)" + depends on IRDA && TTY + help + Say Y here if you want to build support for the IrTTY line + discipline. To compile it as a module, choose M here: the module + will be called irtty-sir. IrTTY makes it possible to use Linux's + own serial driver for all IrDA ports that are 16550 compatible. + Most IrDA chips are 16550 compatible so you should probably say Y + to this option. Using IrTTY will however limit the speed of the + connection to 115200 bps (IrDA SIR mode). + + If unsure, say Y. + +config BFIN_SIR + tristate "Blackfin SIR on UART" + depends on BLACKFIN && IRDA + default n + help + Say Y here if your want to enable SIR function on Blackfin UART + devices. + + To activate this driver you can start irattach like: + "irattach irda0 -s" + + Saying M, it will be built as a module named bfin_sir. + + Note that you need to turn off one of the serial drivers for SIR + to use that UART. + +config BFIN_SIR0 + bool "Blackfin SIR on UART0" + depends on BFIN_SIR && !SERIAL_BFIN_UART0 + +config BFIN_SIR1 + bool "Blackfin SIR on UART1" + depends on BFIN_SIR && !SERIAL_BFIN_UART1 && (!BF531 && !BF532 && !BF533 && !BF561) + +config BFIN_SIR2 + bool "Blackfin SIR on UART2" + depends on BFIN_SIR && !SERIAL_BFIN_UART2 && (BF54x || BF538 || BF539) + +config BFIN_SIR3 + bool "Blackfin SIR on UART3" + depends on BFIN_SIR && !SERIAL_BFIN_UART3 && (BF54x) + +choice + prompt "SIR Mode" + depends on BFIN_SIR + default SIR_BFIN_DMA + +config SIR_BFIN_DMA + bool "DMA mode" + depends on !DMA_UNCACHED_NONE + +config SIR_BFIN_PIO + bool "PIO mode" +endchoice + +config SH_SIR + tristate "SuperH SIR on UART" + depends on IRDA && SUPERH && \ + (CPU_SUBTYPE_SH7722 || CPU_SUBTYPE_SH7723 || \ + CPU_SUBTYPE_SH7724) + default n + help + Say Y here if your want to enable SIR function on SuperH UART + devices. + +comment "Dongle support" + +config DONGLE + bool "Serial dongle support" + depends on IRTTY_SIR + help + Say Y here if you have an infrared device that connects to your + computer's serial port. These devices are called dongles. Then say Y + or M to the driver for your particular dongle below. + + Note that the answer to this question won't directly affect the + kernel: saying N will just cause the configurator to skip all + the questions about serial dongles. + +config ESI_DONGLE + tristate "ESI JetEye PC dongle" + depends on IRTTY_SIR && DONGLE && IRDA + help + Say Y here if you want to build support for the Extended Systems + JetEye PC dongle. To compile it as a module, choose M here. The ESI + dongle attaches to the normal 9-pin serial port connector, and can + currently only be used by IrTTY. To activate support for ESI + dongles you will have to start irattach like this: + "irattach -d esi". + +config ACTISYS_DONGLE + tristate "ACTiSYS IR-220L and IR220L+ dongle" + depends on IRTTY_SIR && DONGLE && IRDA + help + Say Y here if you want to build support for the ACTiSYS IR-220L and + IR220L+ dongles. To compile it as a module, choose M here. The + ACTiSYS dongles attaches to the normal 9-pin serial port connector, + and can currently only be used by IrTTY. To activate support for + ACTiSYS dongles you will have to start irattach like this: + "irattach -d actisys" or "irattach -d actisys+". + +config TEKRAM_DONGLE + tristate "Tekram IrMate 210B dongle" + depends on IRTTY_SIR && DONGLE && IRDA + help + Say Y here if you want to build support for the Tekram IrMate 210B + dongle. To compile it as a module, choose M here. The Tekram dongle + attaches to the normal 9-pin serial port connector, and can + currently only be used by IrTTY. To activate support for Tekram + dongles you will have to start irattach like this: + "irattach -d tekram". + +config TOIM3232_DONGLE + tristate "TOIM3232 IrDa dongle" + depends on IRTTY_SIR && DONGLE && IRDA + help + Say Y here if you want to build support for the Vishay/Temic + TOIM3232 and TOIM4232 based dongles. + To compile it as a module, choose M here. + +config LITELINK_DONGLE + tristate "Parallax LiteLink dongle" + depends on IRTTY_SIR && DONGLE && IRDA + help + Say Y here if you want to build support for the Parallax Litelink + dongle. To compile it as a module, choose M here. The Parallax + dongle attaches to the normal 9-pin serial port connector, and can + currently only be used by IrTTY. To activate support for Parallax + dongles you will have to start irattach like this: + "irattach -d litelink". + +config MA600_DONGLE + tristate "Mobile Action MA600 dongle" + depends on IRTTY_SIR && DONGLE && IRDA + help + Say Y here if you want to build support for the Mobile Action MA600 + dongle. To compile it as a module, choose M here. The MA600 dongle + attaches to the normal 9-pin serial port connector, and can + currently only be used by IrTTY. The driver should also support + the MA620 USB version of the dongle, if the integrated USB-to-RS232 + converter is supported by usbserial. To activate support for + MA600 dongle you will have to start irattach like this: + "irattach -d ma600". + +config GIRBIL_DONGLE + tristate "Greenwich GIrBIL dongle" + depends on IRTTY_SIR && DONGLE && IRDA + help + Say Y here if you want to build support for the Greenwich GIrBIL + dongle. If you want to compile it as a module, choose M here. + The Greenwich dongle attaches to the normal 9-pin serial port + connector, and can currently only be used by IrTTY. To activate + support for Greenwich dongles you will have to start irattach + like this: "irattach -d girbil". + +config MCP2120_DONGLE + tristate "Microchip MCP2120" + depends on IRTTY_SIR && DONGLE && IRDA + help + Say Y here if you want to build support for the Microchip MCP2120 + dongle. If you want to compile it as a module, choose M here. + The MCP2120 dongle attaches to the normal 9-pin serial port + connector, and can currently only be used by IrTTY. To activate + support for MCP2120 dongles you will have to start irattach + like this: "irattach -d mcp2120". + + You must build this dongle yourself. For more information see: + <http://www.eyetap.org/~tangf/irda_sir_linux.html> + +config OLD_BELKIN_DONGLE + tristate "Old Belkin dongle" + depends on IRTTY_SIR && DONGLE && IRDA + help + Say Y here if you want to build support for the Adaptec Airport 1000 + and 2000 dongles. If you want to compile it as a module, choose + M here. Some information is contained in the comments + at the top of <file:drivers/net/irda/old_belkin-sir.c>. + +config ACT200L_DONGLE + tristate "ACTiSYS IR-200L dongle" + depends on IRTTY_SIR && DONGLE && IRDA + help + Say Y here if you want to build support for the ACTiSYS IR-200L + dongle. If you want to compile it as a module, choose M here. + The ACTiSYS IR-200L dongle attaches to the normal 9-pin serial + port connector, and can currently only be used by IrTTY. + To activate support for ACTiSYS IR-200L dongle you will have to + start irattach like this: "irattach -d act200l". + +config KINGSUN_DONGLE + tristate "KingSun/DonShine DS-620 IrDA-USB dongle" + depends on IRDA && USB + help + Say Y or M here if you want to build support for the KingSun/DonShine + DS-620 IrDA-USB bridge device driver. + + This USB bridge does not conform to the IrDA-USB device class + specification, and therefore needs its own specific driver. This + dongle supports SIR speed only (9600 bps). + + To compile it as a module, choose M here: the module will be called + kingsun-sir. + +config KSDAZZLE_DONGLE + tristate "KingSun Dazzle IrDA-USB dongle" + depends on IRDA && USB + help + Say Y or M here if you want to build support for the KingSun Dazzle + IrDA-USB bridge device driver. + + This USB bridge does not conform to the IrDA-USB device class + specification, and therefore needs its own specific driver. This + dongle supports SIR speeds only (9600 through 115200 bps). + + To compile it as a module, choose M here: the module will be called + ksdazzle-sir. + +config KS959_DONGLE + tristate "KingSun KS-959 IrDA-USB dongle" + depends on IRDA && USB + help + Say Y or M here if you want to build support for the KingSun KS-959 + IrDA-USB bridge device driver. + + This USB bridge does not conform to the IrDA-USB device class + specification, and therefore needs its own specific driver. This + dongle supports SIR speeds only (9600 through 57600 bps). + + To compile it as a module, choose M here: the module will be called + ks959-sir. + +comment "FIR device drivers" + +config USB_IRDA + tristate "IrDA USB dongles" + depends on IRDA && USB + select FW_LOADER + ---help--- + Say Y here if you want to build support for the USB IrDA FIR Dongle + device driver. To compile it as a module, choose M here: the module + will be called irda-usb. IrDA-USB support the various IrDA USB + dongles available and most of their peculiarities. Those dongles + plug in the USB port of your computer, are plug and play, and + support SIR and FIR (4Mbps) speeds. On the other hand, those + dongles tend to be less efficient than a FIR chipset. + + Please note that the driver is still experimental. And of course, + you will need both USB and IrDA support in your kernel... + +config SIGMATEL_FIR + tristate "SigmaTel STIr4200 bridge" + depends on IRDA && USB + select CRC32 + ---help--- + Say Y here if you want to build support for the SigmaTel STIr4200 + USB IrDA FIR bridge device driver. + + USB bridge based on the SigmaTel STIr4200 don't conform to the + IrDA-USB device class specification, and therefore need their + own specific driver. Those dongles support SIR and FIR (4Mbps) + speeds. + + To compile it as a module, choose M here: the module will be called + stir4200. + +config NSC_FIR + tristate "NSC PC87108/PC87338" + depends on IRDA && ISA_DMA_API + help + Say Y here if you want to build support for the NSC PC87108 and + PC87338 IrDA chipsets. This driver supports SIR, + MIR and FIR (4Mbps) speeds. + + To compile it as a module, choose M here: the module will be called + nsc-ircc. + +config WINBOND_FIR + tristate "Winbond W83977AF (IR)" + depends on IRDA && ISA_DMA_API + help + Say Y here if you want to build IrDA support for the Winbond + W83977AF super-io chipset. This driver should be used for the IrDA + chipset in the Corel NetWinder. The driver supports SIR, MIR and + FIR (4Mbps) speeds. + + To compile it as a module, choose M here: the module will be called + w83977af_ir. + +config TOSHIBA_FIR + tristate "Toshiba Type-O IR Port" + depends on IRDA && PCI && !64BIT && VIRT_TO_BUS + help + Say Y here if you want to build support for the Toshiba Type-O IR + and Donau oboe chipsets. These chipsets are used by the Toshiba + Libretto 100/110CT, Tecra 8100, Portege 7020 and many more laptops. + To compile it as a module, choose M here: the module will be called + donauboe. + +config AU1000_FIR + tristate "Alchemy IrDA SIR/FIR" + depends on IRDA && MIPS_ALCHEMY + help + Say Y/M here to build support the IrDA peripheral on the + Alchemy Au1000 and Au1100 SoCs. + Say M to build a module; it will be called au1k_ir.ko + +config SMC_IRCC_FIR + tristate "SMSC IrCC" + depends on IRDA && ISA_DMA_API + help + Say Y here if you want to build support for the SMC Infrared + Communications Controller. It is used in a wide variety of + laptops (Fujitsu, Sony, Compaq and some Toshiba). + To compile it as a module, choose M here: the module will be called + smsc-ircc2.o. + +config ALI_FIR + tristate "ALi M5123 FIR" + depends on IRDA && ISA_DMA_API + help + Say Y here if you want to build support for the ALi M5123 FIR + Controller. The ALi M5123 FIR Controller is embedded in ALi M1543C, + M1535, M1535D, M1535+, M1535D South Bridge. This driver supports + SIR, MIR and FIR (4Mbps) speeds. + + To compile it as a module, choose M here: the module will be called + ali-ircc. + +config VLSI_FIR + tristate "VLSI 82C147 SIR/MIR/FIR" + depends on IRDA && PCI + help + Say Y here if you want to build support for the VLSI 82C147 + PCI-IrDA Controller. This controller is used by the HP OmniBook 800 + and 5500 notebooks. The driver provides support for SIR, MIR and + FIR (4Mbps) speeds. + + To compile it as a module, choose M here: the module will be called + vlsi_ir. + +config SA1100_FIR + tristate "SA1100 Internal IR" + depends on ARCH_SA1100 && IRDA && DMA_SA11X0 + +config VIA_FIR + tristate "VIA VT8231/VT1211 SIR/MIR/FIR" + depends on IRDA && ISA_DMA_API + help + Say Y here if you want to build support for the VIA VT8231 + and VIA VT1211 IrDA controllers, found on the motherboards using + those VIA chipsets. To use this controller, you will need + to plug a specific 5 pins FIR IrDA dongle in the specific + motherboard connector. The driver provides support for SIR, MIR + and FIR (4Mbps) speeds. + + You will need to specify the 'dongle_id' module parameter to + indicate the FIR dongle attached to the controller. + + To compile it as a module, choose M here: the module will be called + via-ircc. + +config PXA_FICP + tristate "Intel PXA2xx Internal FICP" + depends on ARCH_PXA && IRDA + help + Say Y or M here if you want to build support for the PXA2xx + built-in IRDA interface which can support both SIR and FIR. + This driver relies on platform specific helper routines so + available capabilities may vary from one PXA2xx target to + another. + +config MCS_FIR + tristate "MosChip MCS7780 IrDA-USB dongle" + depends on IRDA && USB + select CRC32 + help + Say Y or M here if you want to build support for the MosChip + MCS7780 IrDA-USB bridge device driver. + + USB bridge based on the MosChip MCS7780 don't conform to the + IrDA-USB device class specification, and therefore need their + own specific driver. Those dongles support SIR and FIR (4Mbps) + speeds. + + To compile it as a module, choose M here: the module will be called + mcs7780. + +endmenu + diff --git a/drivers/staging/irda/drivers/Makefile b/drivers/staging/irda/drivers/Makefile new file mode 100644 index 000000000000..e2901b135528 --- /dev/null +++ b/drivers/staging/irda/drivers/Makefile @@ -0,0 +1,44 @@ +# +# Makefile for the Linux IrDA infrared port device drivers. +# +# 9 Aug 2000, Christoph Hellwig <hch@infradead.org> +# Rewritten to use lists instead of if-statements. +# + +subdir-ccflags-y += -I$(srctree)/drivers/staging/irda/include + +# FIR drivers +obj-$(CONFIG_USB_IRDA) += irda-usb.o +obj-$(CONFIG_SIGMATEL_FIR) += stir4200.o +obj-$(CONFIG_NSC_FIR) += nsc-ircc.o +obj-$(CONFIG_WINBOND_FIR) += w83977af_ir.o +obj-$(CONFIG_SA1100_FIR) += sa1100_ir.o +obj-$(CONFIG_TOSHIBA_FIR) += donauboe.o +obj-$(CONFIG_SMC_IRCC_FIR) += smsc-ircc2.o +obj-$(CONFIG_ALI_FIR) += ali-ircc.o +obj-$(CONFIG_VLSI_FIR) += vlsi_ir.o +obj-$(CONFIG_VIA_FIR) += via-ircc.o +obj-$(CONFIG_PXA_FICP) += pxaficp_ir.o +obj-$(CONFIG_MCS_FIR) += mcs7780.o +obj-$(CONFIG_AU1000_FIR) += au1k_ir.o +# SIR drivers +obj-$(CONFIG_IRTTY_SIR) += irtty-sir.o sir-dev.o +obj-$(CONFIG_BFIN_SIR) += bfin_sir.o +obj-$(CONFIG_SH_SIR) += sh_sir.o +# dongle drivers for SIR drivers +obj-$(CONFIG_ESI_DONGLE) += esi-sir.o +obj-$(CONFIG_TEKRAM_DONGLE) += tekram-sir.o +obj-$(CONFIG_ACTISYS_DONGLE) += actisys-sir.o +obj-$(CONFIG_LITELINK_DONGLE) += litelink-sir.o +obj-$(CONFIG_GIRBIL_DONGLE) += girbil-sir.o +obj-$(CONFIG_OLD_BELKIN_DONGLE) += old_belkin-sir.o +obj-$(CONFIG_MCP2120_DONGLE) += mcp2120-sir.o +obj-$(CONFIG_ACT200L_DONGLE) += act200l-sir.o +obj-$(CONFIG_MA600_DONGLE) += ma600-sir.o +obj-$(CONFIG_TOIM3232_DONGLE) += toim3232-sir.o +obj-$(CONFIG_KINGSUN_DONGLE) += kingsun-sir.o +obj-$(CONFIG_KSDAZZLE_DONGLE) += ksdazzle-sir.o +obj-$(CONFIG_KS959_DONGLE) += ks959-sir.o + +# The SIR helper module +sir-dev-objs := sir_dev.o sir_dongle.o diff --git a/drivers/staging/irda/drivers/act200l-sir.c b/drivers/staging/irda/drivers/act200l-sir.c new file mode 100644 index 000000000000..e8917511e1aa --- /dev/null +++ b/drivers/staging/irda/drivers/act200l-sir.c @@ -0,0 +1,250 @@ +/********************************************************************* + * + * Filename: act200l.c + * Version: 0.8 + * Description: Implementation for the ACTiSYS ACT-IR200L dongle + * Status: Experimental. + * Author: SHIMIZU Takuya <tshimizu@ga2.so-net.ne.jp> + * Created at: Fri Aug 3 17:35:42 2001 + * Modified at: Fri Aug 17 10:22:40 2001 + * Modified by: SHIMIZU Takuya <tshimizu@ga2.so-net.ne.jp> + * + * Copyright (c) 2001 SHIMIZU Takuya, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + ********************************************************************/ + +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/init.h> + +#include <net/irda/irda.h> + +#include "sir-dev.h" + +static int act200l_reset(struct sir_dev *dev); +static int act200l_open(struct sir_dev *dev); +static int act200l_close(struct sir_dev *dev); +static int act200l_change_speed(struct sir_dev *dev, unsigned speed); + +/* Regsiter 0: Control register #1 */ +#define ACT200L_REG0 0x00 +#define ACT200L_TXEN 0x01 /* Enable transmitter */ +#define ACT200L_RXEN 0x02 /* Enable receiver */ + +/* Register 1: Control register #2 */ +#define ACT200L_REG1 0x10 +#define ACT200L_LODB 0x01 /* Load new baud rate count value */ +#define ACT200L_WIDE 0x04 /* Expand the maximum allowable pulse */ + +/* Register 4: Output Power register */ +#define ACT200L_REG4 0x40 +#define ACT200L_OP0 0x01 /* Enable LED1C output */ +#define ACT200L_OP1 0x02 /* Enable LED2C output */ +#define ACT200L_BLKR 0x04 + +/* Register 5: Receive Mode register */ +#define ACT200L_REG5 0x50 +#define ACT200L_RWIDL 0x01 /* fixed 1.6us pulse mode */ + +/* Register 6: Receive Sensitivity register #1 */ +#define ACT200L_REG6 0x60 +#define ACT200L_RS0 0x01 /* receive threshold bit 0 */ +#define ACT200L_RS1 0x02 /* receive threshold bit 1 */ + +/* Register 7: Receive Sensitivity register #2 */ +#define ACT200L_REG7 0x70 +#define ACT200L_ENPOS 0x04 /* Ignore the falling edge */ + +/* Register 8,9: Baud Rate Dvider register #1,#2 */ +#define ACT200L_REG8 0x80 +#define ACT200L_REG9 0x90 + +#define ACT200L_2400 0x5f +#define ACT200L_9600 0x17 +#define ACT200L_19200 0x0b +#define ACT200L_38400 0x05 +#define ACT200L_57600 0x03 +#define ACT200L_115200 0x01 + +/* Register 13: Control register #3 */ +#define ACT200L_REG13 0xd0 +#define ACT200L_SHDW 0x01 /* Enable access to shadow registers */ + +/* Register 15: Status register */ +#define ACT200L_REG15 0xf0 + +/* Register 21: Control register #4 */ +#define ACT200L_REG21 0x50 +#define ACT200L_EXCK 0x02 /* Disable clock output driver */ +#define ACT200L_OSCL 0x04 /* oscillator in low power, medium accuracy mode */ + +static struct dongle_driver act200l = { + .owner = THIS_MODULE, + .driver_name = "ACTiSYS ACT-IR200L", + .type = IRDA_ACT200L_DONGLE, + .open = act200l_open, + .close = act200l_close, + .reset = act200l_reset, + .set_speed = act200l_change_speed, +}; + +static int __init act200l_sir_init(void) +{ + return irda_register_dongle(&act200l); +} + +static void __exit act200l_sir_cleanup(void) +{ + irda_unregister_dongle(&act200l); +} + +static int act200l_open(struct sir_dev *dev) +{ + struct qos_info *qos = &dev->qos; + + /* Power on the dongle */ + sirdev_set_dtr_rts(dev, TRUE, TRUE); + + /* Set the speeds we can accept */ + qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200; + qos->min_turn_time.bits = 0x03; + irda_qos_bits_to_value(qos); + + /* irda thread waits 50 msec for power settling */ + + return 0; +} + +static int act200l_close(struct sir_dev *dev) +{ + /* Power off the dongle */ + sirdev_set_dtr_rts(dev, FALSE, FALSE); + + return 0; +} + +/* + * Function act200l_change_speed (dev, speed) + * + * Set the speed for the ACTiSYS ACT-IR200L type dongle. + * + */ +static int act200l_change_speed(struct sir_dev *dev, unsigned speed) +{ + u8 control[3]; + int ret = 0; + + /* Clear DTR and set RTS to enter command mode */ + sirdev_set_dtr_rts(dev, FALSE, TRUE); + + switch (speed) { + default: + ret = -EINVAL; + /* fall through */ + case 9600: + control[0] = ACT200L_REG8 | (ACT200L_9600 & 0x0f); + control[1] = ACT200L_REG9 | ((ACT200L_9600 >> 4) & 0x0f); + break; + case 19200: + control[0] = ACT200L_REG8 | (ACT200L_19200 & 0x0f); + control[1] = ACT200L_REG9 | ((ACT200L_19200 >> 4) & 0x0f); + break; + case 38400: + control[0] = ACT200L_REG8 | (ACT200L_38400 & 0x0f); + control[1] = ACT200L_REG9 | ((ACT200L_38400 >> 4) & 0x0f); + break; + case 57600: + control[0] = ACT200L_REG8 | (ACT200L_57600 & 0x0f); + control[1] = ACT200L_REG9 | ((ACT200L_57600 >> 4) & 0x0f); + break; + case 115200: + control[0] = ACT200L_REG8 | (ACT200L_115200 & 0x0f); + control[1] = ACT200L_REG9 | ((ACT200L_115200 >> 4) & 0x0f); + break; + } + control[2] = ACT200L_REG1 | ACT200L_LODB | ACT200L_WIDE; + + /* Write control bytes */ + sirdev_raw_write(dev, control, 3); + msleep(5); + + /* Go back to normal mode */ + sirdev_set_dtr_rts(dev, TRUE, TRUE); + + dev->speed = speed; + return ret; +} + +/* + * Function act200l_reset (driver) + * + * Reset the ACTiSYS ACT-IR200L type dongle. + */ + +#define ACT200L_STATE_WAIT1_RESET (SIRDEV_STATE_DONGLE_RESET+1) +#define ACT200L_STATE_WAIT2_RESET (SIRDEV_STATE_DONGLE_RESET+2) + +static int act200l_reset(struct sir_dev *dev) +{ + unsigned state = dev->fsm.substate; + unsigned delay = 0; + static const u8 control[9] = { + ACT200L_REG15, + ACT200L_REG13 | ACT200L_SHDW, + ACT200L_REG21 | ACT200L_EXCK | ACT200L_OSCL, + ACT200L_REG13, + ACT200L_REG7 | ACT200L_ENPOS, + ACT200L_REG6 | ACT200L_RS0 | ACT200L_RS1, + ACT200L_REG5 | ACT200L_RWIDL, + ACT200L_REG4 | ACT200L_OP0 | ACT200L_OP1 | ACT200L_BLKR, + ACT200L_REG0 | ACT200L_TXEN | ACT200L_RXEN + }; + int ret = 0; + + switch (state) { + case SIRDEV_STATE_DONGLE_RESET: + /* Reset the dongle : set RTS low for 25 ms */ + sirdev_set_dtr_rts(dev, TRUE, FALSE); + state = ACT200L_STATE_WAIT1_RESET; + delay = 50; + break; + + case ACT200L_STATE_WAIT1_RESET: + /* Clear DTR and set RTS to enter command mode */ + sirdev_set_dtr_rts(dev, FALSE, TRUE); + + udelay(25); /* better wait for some short while */ + + /* Write control bytes */ + sirdev_raw_write(dev, control, sizeof(control)); + state = ACT200L_STATE_WAIT2_RESET; + delay = 15; + break; + + case ACT200L_STATE_WAIT2_RESET: + /* Go back to normal mode */ + sirdev_set_dtr_rts(dev, TRUE, TRUE); + dev->speed = 9600; + break; + default: + net_err_ratelimited("%s(), unknown state %d\n", + __func__, state); + ret = -1; + break; + } + dev->fsm.substate = state; + return (delay > 0) ? delay : ret; +} + +MODULE_AUTHOR("SHIMIZU Takuya <tshimizu@ga2.so-net.ne.jp>"); +MODULE_DESCRIPTION("ACTiSYS ACT-IR200L dongle driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("irda-dongle-10"); /* IRDA_ACT200L_DONGLE */ + +module_init(act200l_sir_init); +module_exit(act200l_sir_cleanup); diff --git a/drivers/staging/irda/drivers/actisys-sir.c b/drivers/staging/irda/drivers/actisys-sir.c new file mode 100644 index 000000000000..e224b8b99517 --- /dev/null +++ b/drivers/staging/irda/drivers/actisys-sir.c @@ -0,0 +1,245 @@ +/********************************************************************* + * + * Filename: actisys.c + * Version: 1.1 + * Description: Implementation for the ACTiSYS IR-220L and IR-220L+ + * dongles + * Status: Beta. + * Authors: Dag Brattli <dagb@cs.uit.no> (initially) + * Jean Tourrilhes <jt@hpl.hp.com> (new version) + * Martin Diehl <mad@mdiehl.de> (new version for sir_dev) + * Created at: Wed Oct 21 20:02:35 1998 + * Modified at: Sun Oct 27 22:02:13 2002 + * Modified by: Martin Diehl <mad@mdiehl.de> + * + * Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved. + * Copyright (c) 1999 Jean Tourrilhes + * Copyright (c) 2002 Martin Diehl + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +/* + * Changelog + * + * 0.8 -> 0.9999 - Jean + * o New initialisation procedure : much safer and correct + * o New procedure the change speed : much faster and simpler + * o Other cleanups & comments + * Thanks to Lichen Wang @ Actisys for his excellent help... + * + * 1.0 -> 1.1 - Martin Diehl + * modified for new sir infrastructure + */ + +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/init.h> + +#include <net/irda/irda.h> + +#include "sir-dev.h" + +/* + * Define the timing of the pulses we send to the dongle (to reset it, and + * to toggle speeds). Basically, the limit here is the propagation speed of + * the signals through the serial port, the dongle being much faster. Any + * serial port support 115 kb/s, so we are sure that pulses 8.5 us wide can + * go through cleanly . If you are on the wild side, you can try to lower + * this value (Actisys recommended me 2 us, and 0 us work for me on a P233!) + */ +#define MIN_DELAY 10 /* 10 us to be on the conservative side */ + +static int actisys_open(struct sir_dev *); +static int actisys_close(struct sir_dev *); +static int actisys_change_speed(struct sir_dev *, unsigned); +static int actisys_reset(struct sir_dev *); + +/* These are the baudrates supported, in the order available */ +/* Note : the 220L doesn't support 38400, but we will fix that below */ +static unsigned baud_rates[] = { 9600, 19200, 57600, 115200, 38400 }; + +#define MAX_SPEEDS ARRAY_SIZE(baud_rates) + +static struct dongle_driver act220l = { + .owner = THIS_MODULE, + .driver_name = "Actisys ACT-220L", + .type = IRDA_ACTISYS_DONGLE, + .open = actisys_open, + .close = actisys_close, + .reset = actisys_reset, + .set_speed = actisys_change_speed, +}; + +static struct dongle_driver act220l_plus = { + .owner = THIS_MODULE, + .driver_name = "Actisys ACT-220L+", + .type = IRDA_ACTISYS_PLUS_DONGLE, + .open = actisys_open, + .close = actisys_close, + .reset = actisys_reset, + .set_speed = actisys_change_speed, +}; + +static int __init actisys_sir_init(void) +{ + int ret; + + /* First, register an Actisys 220L dongle */ + ret = irda_register_dongle(&act220l); + if (ret < 0) + return ret; + + /* Now, register an Actisys 220L+ dongle */ + ret = irda_register_dongle(&act220l_plus); + if (ret < 0) { + irda_unregister_dongle(&act220l); + return ret; + } + return 0; +} + +static void __exit actisys_sir_cleanup(void) +{ + /* We have to remove both dongles */ + irda_unregister_dongle(&act220l_plus); + irda_unregister_dongle(&act220l); +} + +static int actisys_open(struct sir_dev *dev) +{ + struct qos_info *qos = &dev->qos; + + sirdev_set_dtr_rts(dev, TRUE, TRUE); + + /* Set the speeds we can accept */ + qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200; + + /* Remove support for 38400 if this is not a 220L+ dongle */ + if (dev->dongle_drv->type == IRDA_ACTISYS_DONGLE) + qos->baud_rate.bits &= ~IR_38400; + + qos->min_turn_time.bits = 0x7f; /* Needs 0.01 ms */ + irda_qos_bits_to_value(qos); + + /* irda thread waits 50 msec for power settling */ + + return 0; +} + +static int actisys_close(struct sir_dev *dev) +{ + /* Power off the dongle */ + sirdev_set_dtr_rts(dev, FALSE, FALSE); + + return 0; +} + +/* + * Function actisys_change_speed (task) + * + * Change speed of the ACTiSYS IR-220L and IR-220L+ type IrDA dongles. + * To cycle through the available baud rates, pulse RTS low for a few us. + * + * First, we reset the dongle to always start from a known state. + * Then, we cycle through the speeds by pulsing RTS low and then up. + * The dongle allow us to pulse quite fast, se we can set speed in one go, + * which is must faster ( < 100 us) and less complex than what is found + * in some other dongle drivers... + * Note that even if the new speed is the same as the current speed, + * we reassert the speed. This make sure that things are all right, + * and it's fast anyway... + * By the way, this function will work for both type of dongles, + * because the additional speed is at the end of the sequence... + */ +static int actisys_change_speed(struct sir_dev *dev, unsigned speed) +{ + int ret = 0; + int i = 0; + + pr_debug("%s(), speed=%d (was %d)\n", __func__, speed, dev->speed); + + /* dongle was already resetted from irda_request state machine, + * we are in known state (dongle default) + */ + + /* + * Now, we can set the speed requested. Send RTS pulses until we + * reach the target speed + */ + for (i = 0; i < MAX_SPEEDS; i++) { + if (speed == baud_rates[i]) { + dev->speed = speed; + break; + } + /* Set RTS low for 10 us */ + sirdev_set_dtr_rts(dev, TRUE, FALSE); + udelay(MIN_DELAY); + + /* Set RTS high for 10 us */ + sirdev_set_dtr_rts(dev, TRUE, TRUE); + udelay(MIN_DELAY); + } + + /* Check if life is sweet... */ + if (i >= MAX_SPEEDS) { + actisys_reset(dev); + ret = -EINVAL; /* This should not happen */ + } + + /* Basta lavoro, on se casse d'ici... */ + return ret; +} + +/* + * Function actisys_reset (task) + * + * Reset the Actisys type dongle. Warning, this function must only be + * called with a process context! + * + * We need to do two things in this function : + * o first make sure that the dongle is in a state where it can operate + * o second put the dongle in a know state + * + * The dongle is powered of the RTS and DTR lines. In the dongle, there + * is a big capacitor to accommodate the current spikes. This capacitor + * takes a least 50 ms to be charged. In theory, the Bios set those lines + * up, so by the time we arrive here we should be set. It doesn't hurt + * to be on the conservative side, so we will wait... + * <Martin : move above comment to irda_config_fsm> + * Then, we set the speed to 9600 b/s to get in a known state (see in + * change_speed for details). It is needed because the IrDA stack + * has tried to set the speed immediately after our first return, + * so before we can be sure the dongle is up and running. + */ + +static int actisys_reset(struct sir_dev *dev) +{ + /* Reset the dongle : set DTR low for 10 us */ + sirdev_set_dtr_rts(dev, FALSE, TRUE); + udelay(MIN_DELAY); + + /* Go back to normal mode */ + sirdev_set_dtr_rts(dev, TRUE, TRUE); + + dev->speed = 9600; /* That's the default */ + + return 0; +} + +MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no> - Jean Tourrilhes <jt@hpl.hp.com>"); +MODULE_DESCRIPTION("ACTiSYS IR-220L and IR-220L+ dongle driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("irda-dongle-2"); /* IRDA_ACTISYS_DONGLE */ +MODULE_ALIAS("irda-dongle-3"); /* IRDA_ACTISYS_PLUS_DONGLE */ + +module_init(actisys_sir_init); +module_exit(actisys_sir_cleanup); diff --git a/drivers/staging/irda/drivers/ali-ircc.c b/drivers/staging/irda/drivers/ali-ircc.c new file mode 100644 index 000000000000..35f198d83701 --- /dev/null +++ b/drivers/staging/irda/drivers/ali-ircc.c @@ -0,0 +1,2218 @@ +/********************************************************************* + * + * Filename: ali-ircc.h + * Version: 0.5 + * Description: Driver for the ALI M1535D and M1543C FIR Controller + * Status: Experimental. + * Author: Benjamin Kong <benjamin_kong@ali.com.tw> + * Created at: 2000/10/16 03:46PM + * Modified at: 2001/1/3 02:55PM + * Modified by: Benjamin Kong <benjamin_kong@ali.com.tw> + * Modified at: 2003/11/6 and support for ALi south-bridge chipsets M1563 + * Modified by: Clear Zhang <clear_zhang@ali.com.tw> + * + * Copyright (c) 2000 Benjamin Kong <benjamin_kong@ali.com.tw> + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + ********************************************************************/ + +#include <linux/module.h> +#include <linux/gfp.h> + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/skbuff.h> +#include <linux/netdevice.h> +#include <linux/ioport.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/rtnetlink.h> +#include <linux/serial_reg.h> +#include <linux/dma-mapping.h> +#include <linux/platform_device.h> + +#include <asm/io.h> +#include <asm/dma.h> +#include <asm/byteorder.h> + +#include <net/irda/wrapper.h> +#include <net/irda/irda.h> +#include <net/irda/irda_device.h> + +#include "ali-ircc.h" + +#define CHIP_IO_EXTENT 8 +#define BROKEN_DONGLE_ID + +#define ALI_IRCC_DRIVER_NAME "ali-ircc" + +/* Power Management */ +static int ali_ircc_suspend(struct platform_device *dev, pm_message_t state); +static int ali_ircc_resume(struct platform_device *dev); + +static struct platform_driver ali_ircc_driver = { + .suspend = ali_ircc_suspend, + .resume = ali_ircc_resume, + .driver = { + .name = ALI_IRCC_DRIVER_NAME, + }, +}; + +/* Module parameters */ +static int qos_mtt_bits = 0x07; /* 1 ms or more */ + +/* Use BIOS settions by default, but user may supply module parameters */ +static unsigned int io[] = { ~0, ~0, ~0, ~0 }; +static unsigned int irq[] = { 0, 0, 0, 0 }; +static unsigned int dma[] = { 0, 0, 0, 0 }; + +static int ali_ircc_probe_53(ali_chip_t *chip, chipio_t *info); +static int ali_ircc_init_43(ali_chip_t *chip, chipio_t *info); +static int ali_ircc_init_53(ali_chip_t *chip, chipio_t *info); + +/* These are the currently known ALi south-bridge chipsets, the only one difference + * is that M1543C doesn't support HP HDSL-3600 + */ +static ali_chip_t chips[] = +{ + { "M1543", { 0x3f0, 0x370 }, 0x51, 0x23, 0x20, 0x43, ali_ircc_probe_53, ali_ircc_init_43 }, + { "M1535", { 0x3f0, 0x370 }, 0x51, 0x23, 0x20, 0x53, ali_ircc_probe_53, ali_ircc_init_53 }, + { "M1563", { 0x3f0, 0x370 }, 0x51, 0x23, 0x20, 0x63, ali_ircc_probe_53, ali_ircc_init_53 }, + { NULL } +}; + +/* Max 4 instances for now */ +static struct ali_ircc_cb *dev_self[] = { NULL, NULL, NULL, NULL }; + +/* Dongle Types */ +static char *dongle_types[] = { + "TFDS6000", + "HP HSDL-3600", + "HP HSDL-1100", + "No dongle connected", +}; + +/* Some prototypes */ +static int ali_ircc_open(int i, chipio_t *info); + +static int ali_ircc_close(struct ali_ircc_cb *self); + +static int ali_ircc_setup(chipio_t *info); +static int ali_ircc_is_receiving(struct ali_ircc_cb *self); +static int ali_ircc_net_open(struct net_device *dev); +static int ali_ircc_net_close(struct net_device *dev); +static int ali_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +static void ali_ircc_change_speed(struct ali_ircc_cb *self, __u32 baud); + +/* SIR function */ +static netdev_tx_t ali_ircc_sir_hard_xmit(struct sk_buff *skb, + struct net_device *dev); +static irqreturn_t ali_ircc_sir_interrupt(struct ali_ircc_cb *self); +static void ali_ircc_sir_receive(struct ali_ircc_cb *self); +static void ali_ircc_sir_write_wakeup(struct ali_ircc_cb *self); +static int ali_ircc_sir_write(int iobase, int fifo_size, __u8 *buf, int len); +static void ali_ircc_sir_change_speed(struct ali_ircc_cb *priv, __u32 speed); + +/* FIR function */ +static netdev_tx_t ali_ircc_fir_hard_xmit(struct sk_buff *skb, + struct net_device *dev); +static void ali_ircc_fir_change_speed(struct ali_ircc_cb *priv, __u32 speed); +static irqreturn_t ali_ircc_fir_interrupt(struct ali_ircc_cb *self); +static int ali_ircc_dma_receive(struct ali_ircc_cb *self); +static int ali_ircc_dma_receive_complete(struct ali_ircc_cb *self); +static int ali_ircc_dma_xmit_complete(struct ali_ircc_cb *self); +static void ali_ircc_dma_xmit(struct ali_ircc_cb *self); + +/* My Function */ +static int ali_ircc_read_dongle_id (int i, chipio_t *info); +static void ali_ircc_change_dongle_speed(struct ali_ircc_cb *priv, int speed); + +/* ALi chip function */ +static void SIR2FIR(int iobase); +static void FIR2SIR(int iobase); +static void SetCOMInterrupts(struct ali_ircc_cb *self , unsigned char enable); + +/* + * Function ali_ircc_init () + * + * Initialize chip. Find out whay kinds of chips we are dealing with + * and their configuration registers address + */ +static int __init ali_ircc_init(void) +{ + ali_chip_t *chip; + chipio_t info; + int ret; + int cfg, cfg_base; + int reg, revision; + int i = 0; + + ret = platform_driver_register(&ali_ircc_driver); + if (ret) { + net_err_ratelimited("%s, Can't register driver!\n", + ALI_IRCC_DRIVER_NAME); + return ret; + } + + ret = -ENODEV; + + /* Probe for all the ALi chipsets we know about */ + for (chip= chips; chip->name; chip++, i++) + { + pr_debug("%s(), Probing for %s ...\n", __func__, chip->name); + + /* Try all config registers for this chip */ + for (cfg=0; cfg<2; cfg++) + { + cfg_base = chip->cfg[cfg]; + if (!cfg_base) + continue; + + memset(&info, 0, sizeof(chipio_t)); + info.cfg_base = cfg_base; + info.fir_base = io[i]; + info.dma = dma[i]; + info.irq = irq[i]; + + + /* Enter Configuration */ + outb(chip->entr1, cfg_base); + outb(chip->entr2, cfg_base); + + /* Select Logical Device 5 Registers (UART2) */ + outb(0x07, cfg_base); + outb(0x05, cfg_base+1); + + /* Read Chip Identification Register */ + outb(chip->cid_index, cfg_base); + reg = inb(cfg_base+1); + + if (reg == chip->cid_value) + { + pr_debug("%s(), Chip found at 0x%03x\n", + __func__, cfg_base); + + outb(0x1F, cfg_base); + revision = inb(cfg_base+1); + pr_debug("%s(), Found %s chip, revision=%d\n", + __func__, chip->name, revision); + + /* + * If the user supplies the base address, then + * we init the chip, if not we probe the values + * set by the BIOS + */ + if (io[i] < 2000) + { + chip->init(chip, &info); + } + else + { + chip->probe(chip, &info); + } + + if (ali_ircc_open(i, &info) == 0) + ret = 0; + i++; + } + else + { + pr_debug("%s(), No %s chip at 0x%03x\n", + __func__, chip->name, cfg_base); + } + /* Exit configuration */ + outb(0xbb, cfg_base); + } + } + + if (ret) + platform_driver_unregister(&ali_ircc_driver); + + return ret; +} + +/* + * Function ali_ircc_cleanup () + * + * Close all configured chips + * + */ +static void __exit ali_ircc_cleanup(void) +{ + int i; + + for (i=0; i < ARRAY_SIZE(dev_self); i++) { + if (dev_self[i]) + ali_ircc_close(dev_self[i]); + } + + platform_driver_unregister(&ali_ircc_driver); + +} + +static const struct net_device_ops ali_ircc_sir_ops = { + .ndo_open = ali_ircc_net_open, + .ndo_stop = ali_ircc_net_close, + .ndo_start_xmit = ali_ircc_sir_hard_xmit, + .ndo_do_ioctl = ali_ircc_net_ioctl, +}; + +static const struct net_device_ops ali_ircc_fir_ops = { + .ndo_open = ali_ircc_net_open, + .ndo_stop = ali_ircc_net_close, + .ndo_start_xmit = ali_ircc_fir_hard_xmit, + .ndo_do_ioctl = ali_ircc_net_ioctl, +}; + +/* + * Function ali_ircc_open (int i, chipio_t *inf) + * + * Open driver instance + * + */ +static int ali_ircc_open(int i, chipio_t *info) +{ + struct net_device *dev; + struct ali_ircc_cb *self; + int dongle_id; + int err; + + if (i >= ARRAY_SIZE(dev_self)) { + net_err_ratelimited("%s(), maximum number of supported chips reached!\n", + __func__); + return -ENOMEM; + } + + /* Set FIR FIFO and DMA Threshold */ + if ((ali_ircc_setup(info)) == -1) + return -1; + + dev = alloc_irdadev(sizeof(*self)); + if (dev == NULL) { + net_err_ratelimited("%s(), can't allocate memory for control block!\n", + __func__); + return -ENOMEM; + } + + self = netdev_priv(dev); + self->netdev = dev; + spin_lock_init(&self->lock); + + /* Need to store self somewhere */ + dev_self[i] = self; + self->index = i; + + /* Initialize IO */ + self->io.cfg_base = info->cfg_base; /* In ali_ircc_probe_53 assign */ + self->io.fir_base = info->fir_base; /* info->sir_base = info->fir_base */ + self->io.sir_base = info->sir_base; /* ALi SIR and FIR use the same address */ + self->io.irq = info->irq; + self->io.fir_ext = CHIP_IO_EXTENT; + self->io.dma = info->dma; + self->io.fifo_size = 16; /* SIR: 16, FIR: 32 Benjamin 2000/11/1 */ + + /* Reserve the ioports that we need */ + if (!request_region(self->io.fir_base, self->io.fir_ext, + ALI_IRCC_DRIVER_NAME)) { + net_warn_ratelimited("%s(), can't get iobase of 0x%03x\n", + __func__, self->io.fir_base); + err = -ENODEV; + goto err_out1; + } + + /* Initialize QoS for this device */ + irda_init_max_qos_capabilies(&self->qos); + + /* The only value we must override it the baudrate */ + self->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600| + IR_115200|IR_576000|IR_1152000|(IR_4000000 << 8); // benjamin 2000/11/8 05:27PM + + self->qos.min_turn_time.bits = qos_mtt_bits; + + irda_qos_bits_to_value(&self->qos); + + /* Max DMA buffer size needed = (data_size + 6) * (window_size) + 6; */ + self->rx_buff.truesize = 14384; + self->tx_buff.truesize = 14384; + + /* Allocate memory if needed */ + self->rx_buff.head = + dma_zalloc_coherent(NULL, self->rx_buff.truesize, + &self->rx_buff_dma, GFP_KERNEL); + if (self->rx_buff.head == NULL) { + err = -ENOMEM; + goto err_out2; + } + + self->tx_buff.head = + dma_zalloc_coherent(NULL, self->tx_buff.truesize, + &self->tx_buff_dma, GFP_KERNEL); + if (self->tx_buff.head == NULL) { + err = -ENOMEM; + goto err_out3; + } + + self->rx_buff.in_frame = FALSE; + self->rx_buff.state = OUTSIDE_FRAME; + self->tx_buff.data = self->tx_buff.head; + self->rx_buff.data = self->rx_buff.head; + + /* Reset Tx queue info */ + self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0; + self->tx_fifo.tail = self->tx_buff.head; + + /* Override the network functions we need to use */ + dev->netdev_ops = &ali_ircc_sir_ops; + + err = register_netdev(dev); + if (err) { + net_err_ratelimited("%s(), register_netdev() failed!\n", + __func__); + goto err_out4; + } + net_info_ratelimited("IrDA: Registered device %s\n", dev->name); + + /* Check dongle id */ + dongle_id = ali_ircc_read_dongle_id(i, info); + net_info_ratelimited("%s(), %s, Found dongle: %s\n", + __func__, ALI_IRCC_DRIVER_NAME, + dongle_types[dongle_id]); + + self->io.dongle_id = dongle_id; + + + return 0; + + err_out4: + dma_free_coherent(NULL, self->tx_buff.truesize, + self->tx_buff.head, self->tx_buff_dma); + err_out3: + dma_free_coherent(NULL, self->rx_buff.truesize, + self->rx_buff.head, self->rx_buff_dma); + err_out2: + release_region(self->io.fir_base, self->io.fir_ext); + err_out1: + dev_self[i] = NULL; + free_netdev(dev); + return err; +} + + +/* + * Function ali_ircc_close (self) + * + * Close driver instance + * + */ +static int __exit ali_ircc_close(struct ali_ircc_cb *self) +{ + int iobase; + + IRDA_ASSERT(self != NULL, return -1;); + + iobase = self->io.fir_base; + + /* Remove netdevice */ + unregister_netdev(self->netdev); + + /* Release the PORT that this driver is using */ + pr_debug("%s(), Releasing Region %03x\n", __func__, self->io.fir_base); + release_region(self->io.fir_base, self->io.fir_ext); + + if (self->tx_buff.head) + dma_free_coherent(NULL, self->tx_buff.truesize, + self->tx_buff.head, self->tx_buff_dma); + + if (self->rx_buff.head) + dma_free_coherent(NULL, self->rx_buff.truesize, + self->rx_buff.head, self->rx_buff_dma); + + dev_self[self->index] = NULL; + free_netdev(self->netdev); + + + return 0; +} + +/* + * Function ali_ircc_init_43 (chip, info) + * + * Initialize the ALi M1543 chip. + */ +static int ali_ircc_init_43(ali_chip_t *chip, chipio_t *info) +{ + /* All controller information like I/O address, DMA channel, IRQ + * are set by BIOS + */ + + return 0; +} + +/* + * Function ali_ircc_init_53 (chip, info) + * + * Initialize the ALi M1535 chip. + */ +static int ali_ircc_init_53(ali_chip_t *chip, chipio_t *info) +{ + /* All controller information like I/O address, DMA channel, IRQ + * are set by BIOS + */ + + return 0; +} + +/* + * Function ali_ircc_probe_53 (chip, info) + * + * Probes for the ALi M1535D or M1535 + */ +static int ali_ircc_probe_53(ali_chip_t *chip, chipio_t *info) +{ + int cfg_base = info->cfg_base; + int hi, low, reg; + + + /* Enter Configuration */ + outb(chip->entr1, cfg_base); + outb(chip->entr2, cfg_base); + + /* Select Logical Device 5 Registers (UART2) */ + outb(0x07, cfg_base); + outb(0x05, cfg_base+1); + + /* Read address control register */ + outb(0x60, cfg_base); + hi = inb(cfg_base+1); + outb(0x61, cfg_base); + low = inb(cfg_base+1); + info->fir_base = (hi<<8) + low; + + info->sir_base = info->fir_base; + + pr_debug("%s(), probing fir_base=0x%03x\n", __func__, info->fir_base); + + /* Read IRQ control register */ + outb(0x70, cfg_base); + reg = inb(cfg_base+1); + info->irq = reg & 0x0f; + pr_debug("%s(), probing irq=%d\n", __func__, info->irq); + + /* Read DMA channel */ + outb(0x74, cfg_base); + reg = inb(cfg_base+1); + info->dma = reg & 0x07; + + if(info->dma == 0x04) + net_warn_ratelimited("%s(), No DMA channel assigned !\n", + __func__); + else + pr_debug("%s(), probing dma=%d\n", __func__, info->dma); + + /* Read Enabled Status */ + outb(0x30, cfg_base); + reg = inb(cfg_base+1); + info->enabled = (reg & 0x80) && (reg & 0x01); + pr_debug("%s(), probing enabled=%d\n", __func__, info->enabled); + + /* Read Power Status */ + outb(0x22, cfg_base); + reg = inb(cfg_base+1); + info->suspended = (reg & 0x20); + pr_debug("%s(), probing suspended=%d\n", __func__, info->suspended); + + /* Exit configuration */ + outb(0xbb, cfg_base); + + + return 0; +} + +/* + * Function ali_ircc_setup (info) + * + * Set FIR FIFO and DMA Threshold + * Returns non-negative on success. + * + */ +static int ali_ircc_setup(chipio_t *info) +{ + unsigned char tmp; + int version; + int iobase = info->fir_base; + + + /* Locking comments : + * Most operations here need to be protected. We are called before + * the device instance is created in ali_ircc_open(), therefore + * nobody can bother us - Jean II */ + + /* Switch to FIR space */ + SIR2FIR(iobase); + + /* Master Reset */ + outb(0x40, iobase+FIR_MCR); // benjamin 2000/11/30 11:45AM + + /* Read FIR ID Version Register */ + switch_bank(iobase, BANK3); + version = inb(iobase+FIR_ID_VR); + + /* Should be 0x00 in the M1535/M1535D */ + if(version != 0x00) + { + net_err_ratelimited("%s, Wrong chip version %02x\n", + ALI_IRCC_DRIVER_NAME, version); + return -1; + } + + /* Set FIR FIFO Threshold Register */ + switch_bank(iobase, BANK1); + outb(RX_FIFO_Threshold, iobase+FIR_FIFO_TR); + + /* Set FIR DMA Threshold Register */ + outb(RX_DMA_Threshold, iobase+FIR_DMA_TR); + + /* CRC enable */ + switch_bank(iobase, BANK2); + outb(inb(iobase+FIR_IRDA_CR) | IRDA_CR_CRC, iobase+FIR_IRDA_CR); + + /* NDIS driver set TX Length here BANK2 Alias 3, Alias4*/ + + /* Switch to Bank 0 */ + switch_bank(iobase, BANK0); + + tmp = inb(iobase+FIR_LCR_B); + tmp &=~0x20; // disable SIP + tmp |= 0x80; // these two steps make RX mode + tmp &= 0xbf; + outb(tmp, iobase+FIR_LCR_B); + + /* Disable Interrupt */ + outb(0x00, iobase+FIR_IER); + + + /* Switch to SIR space */ + FIR2SIR(iobase); + + net_info_ratelimited("%s, driver loaded (Benjamin Kong)\n", + ALI_IRCC_DRIVER_NAME); + + /* Enable receive interrupts */ + // outb(UART_IER_RDI, iobase+UART_IER); //benjamin 2000/11/23 01:25PM + // Turn on the interrupts in ali_ircc_net_open + + + return 0; +} + +/* + * Function ali_ircc_read_dongle_id (int index, info) + * + * Try to read dongle identification. This procedure needs to be executed + * once after power-on/reset. It also needs to be used whenever you suspect + * that the user may have plugged/unplugged the IrDA Dongle. + */ +static int ali_ircc_read_dongle_id (int i, chipio_t *info) +{ + int dongle_id, reg; + int cfg_base = info->cfg_base; + + + /* Enter Configuration */ + outb(chips[i].entr1, cfg_base); + outb(chips[i].entr2, cfg_base); + + /* Select Logical Device 5 Registers (UART2) */ + outb(0x07, cfg_base); + outb(0x05, cfg_base+1); + + /* Read Dongle ID */ + outb(0xf0, cfg_base); + reg = inb(cfg_base+1); + dongle_id = ((reg>>6)&0x02) | ((reg>>5)&0x01); + pr_debug("%s(), probing dongle_id=%d, dongle_types=%s\n", + __func__, dongle_id, dongle_types[dongle_id]); + + /* Exit configuration */ + outb(0xbb, cfg_base); + + + return dongle_id; +} + +/* + * Function ali_ircc_interrupt (irq, dev_id, regs) + * + * An interrupt from the chip has arrived. Time to do some work + * + */ +static irqreturn_t ali_ircc_interrupt(int irq, void *dev_id) +{ + struct net_device *dev = dev_id; + struct ali_ircc_cb *self; + int ret; + + + self = netdev_priv(dev); + + spin_lock(&self->lock); + + /* Dispatch interrupt handler for the current speed */ + if (self->io.speed > 115200) + ret = ali_ircc_fir_interrupt(self); + else + ret = ali_ircc_sir_interrupt(self); + + spin_unlock(&self->lock); + + return ret; +} +/* + * Function ali_ircc_fir_interrupt(irq, struct ali_ircc_cb *self) + * + * Handle MIR/FIR interrupt + * + */ +static irqreturn_t ali_ircc_fir_interrupt(struct ali_ircc_cb *self) +{ + __u8 eir, OldMessageCount; + int iobase, tmp; + + + iobase = self->io.fir_base; + + switch_bank(iobase, BANK0); + self->InterruptID = inb(iobase+FIR_IIR); + self->BusStatus = inb(iobase+FIR_BSR); + + OldMessageCount = (self->LineStatus + 1) & 0x07; + self->LineStatus = inb(iobase+FIR_LSR); + //self->ier = inb(iobase+FIR_IER); 2000/12/1 04:32PM + eir = self->InterruptID & self->ier; /* Mask out the interesting ones */ + + pr_debug("%s(), self->InterruptID = %x\n", __func__, self->InterruptID); + pr_debug("%s(), self->LineStatus = %x\n", __func__, self->LineStatus); + pr_debug("%s(), self->ier = %x\n", __func__, self->ier); + pr_debug("%s(), eir = %x\n", __func__, eir); + + /* Disable interrupts */ + SetCOMInterrupts(self, FALSE); + + /* Tx or Rx Interrupt */ + + if (eir & IIR_EOM) + { + if (self->io.direction == IO_XMIT) /* TX */ + { + pr_debug("%s(), ******* IIR_EOM (Tx) *******\n", + __func__); + + if(ali_ircc_dma_xmit_complete(self)) + { + if (irda_device_txqueue_empty(self->netdev)) + { + /* Prepare for receive */ + ali_ircc_dma_receive(self); + self->ier = IER_EOM; + } + } + else + { + self->ier = IER_EOM; + } + + } + else /* RX */ + { + pr_debug("%s(), ******* IIR_EOM (Rx) *******\n", + __func__); + + if(OldMessageCount > ((self->LineStatus+1) & 0x07)) + { + self->rcvFramesOverflow = TRUE; + pr_debug("%s(), ******* self->rcvFramesOverflow = TRUE ********\n", + __func__); + } + + if (ali_ircc_dma_receive_complete(self)) + { + pr_debug("%s(), ******* receive complete ********\n", + __func__); + + self->ier = IER_EOM; + } + else + { + pr_debug("%s(), ******* Not receive complete ********\n", + __func__); + + self->ier = IER_EOM | IER_TIMER; + } + + } + } + /* Timer Interrupt */ + else if (eir & IIR_TIMER) + { + if(OldMessageCount > ((self->LineStatus+1) & 0x07)) + { + self->rcvFramesOverflow = TRUE; + pr_debug("%s(), ******* self->rcvFramesOverflow = TRUE *******\n", + __func__); + } + /* Disable Timer */ + switch_bank(iobase, BANK1); + tmp = inb(iobase+FIR_CR); + outb( tmp& ~CR_TIMER_EN, iobase+FIR_CR); + + /* Check if this is a Tx timer interrupt */ + if (self->io.direction == IO_XMIT) + { + ali_ircc_dma_xmit(self); + + /* Interrupt on EOM */ + self->ier = IER_EOM; + + } + else /* Rx */ + { + if(ali_ircc_dma_receive_complete(self)) + { + self->ier = IER_EOM; + } + else + { + self->ier = IER_EOM | IER_TIMER; + } + } + } + + /* Restore Interrupt */ + SetCOMInterrupts(self, TRUE); + + return IRQ_RETVAL(eir); +} + +/* + * Function ali_ircc_sir_interrupt (irq, self, eir) + * + * Handle SIR interrupt + * + */ +static irqreturn_t ali_ircc_sir_interrupt(struct ali_ircc_cb *self) +{ + int iobase; + int iir, lsr; + + + iobase = self->io.sir_base; + + iir = inb(iobase+UART_IIR) & UART_IIR_ID; + if (iir) { + /* Clear interrupt */ + lsr = inb(iobase+UART_LSR); + + pr_debug("%s(), iir=%02x, lsr=%02x, iobase=%#x\n", + __func__, iir, lsr, iobase); + + switch (iir) + { + case UART_IIR_RLSI: + pr_debug("%s(), RLSI\n", __func__); + break; + case UART_IIR_RDI: + /* Receive interrupt */ + ali_ircc_sir_receive(self); + break; + case UART_IIR_THRI: + if (lsr & UART_LSR_THRE) + { + /* Transmitter ready for data */ + ali_ircc_sir_write_wakeup(self); + } + break; + default: + pr_debug("%s(), unhandled IIR=%#x\n", + __func__, iir); + break; + } + + } + + + return IRQ_RETVAL(iir); +} + + +/* + * Function ali_ircc_sir_receive (self) + * + * Receive one frame from the infrared port + * + */ +static void ali_ircc_sir_receive(struct ali_ircc_cb *self) +{ + int boguscount = 0; + int iobase; + + IRDA_ASSERT(self != NULL, return;); + + iobase = self->io.sir_base; + + /* + * Receive all characters in Rx FIFO, unwrap and unstuff them. + * async_unwrap_char will deliver all found frames + */ + do { + async_unwrap_char(self->netdev, &self->netdev->stats, &self->rx_buff, + inb(iobase+UART_RX)); + + /* Make sure we don't stay here too long */ + if (boguscount++ > 32) { + pr_debug("%s(), breaking!\n", __func__); + break; + } + } while (inb(iobase+UART_LSR) & UART_LSR_DR); + +} + +/* + * Function ali_ircc_sir_write_wakeup (tty) + * + * Called by the driver when there's room for more data. If we have + * more packets to send, we send them here. + * + */ +static void ali_ircc_sir_write_wakeup(struct ali_ircc_cb *self) +{ + int actual = 0; + int iobase; + + IRDA_ASSERT(self != NULL, return;); + + + iobase = self->io.sir_base; + + /* Finished with frame? */ + if (self->tx_buff.len > 0) + { + /* Write data left in transmit buffer */ + actual = ali_ircc_sir_write(iobase, self->io.fifo_size, + self->tx_buff.data, self->tx_buff.len); + self->tx_buff.data += actual; + self->tx_buff.len -= actual; + } + else + { + if (self->new_speed) + { + /* We must wait until all data are gone */ + while(!(inb(iobase+UART_LSR) & UART_LSR_TEMT)) + pr_debug("%s(), UART_LSR_THRE\n", __func__); + + pr_debug("%s(), Changing speed! self->new_speed = %d\n", + __func__, self->new_speed); + ali_ircc_change_speed(self, self->new_speed); + self->new_speed = 0; + + // benjamin 2000/11/10 06:32PM + if (self->io.speed > 115200) + { + pr_debug("%s(), ali_ircc_change_speed from UART_LSR_TEMT\n", + __func__); + + self->ier = IER_EOM; + // SetCOMInterrupts(self, TRUE); + return; + } + } + else + { + netif_wake_queue(self->netdev); + } + + self->netdev->stats.tx_packets++; + + /* Turn on receive interrupts */ + outb(UART_IER_RDI, iobase+UART_IER); + } + +} + +static void ali_ircc_change_speed(struct ali_ircc_cb *self, __u32 baud) +{ + struct net_device *dev = self->netdev; + int iobase; + + + pr_debug("%s(), setting speed = %d\n", __func__, baud); + + /* This function *must* be called with irq off and spin-lock. + * - Jean II */ + + iobase = self->io.fir_base; + + SetCOMInterrupts(self, FALSE); // 2000/11/24 11:43AM + + /* Go to MIR, FIR Speed */ + if (baud > 115200) + { + + + ali_ircc_fir_change_speed(self, baud); + + /* Install FIR xmit handler*/ + dev->netdev_ops = &ali_ircc_fir_ops; + + /* Enable Interuupt */ + self->ier = IER_EOM; // benjamin 2000/11/20 07:24PM + + /* Be ready for incoming frames */ + ali_ircc_dma_receive(self); // benajmin 2000/11/8 07:46PM not complete + } + /* Go to SIR Speed */ + else + { + ali_ircc_sir_change_speed(self, baud); + + /* Install SIR xmit handler*/ + dev->netdev_ops = &ali_ircc_sir_ops; + } + + + SetCOMInterrupts(self, TRUE); // 2000/11/24 11:43AM + + netif_wake_queue(self->netdev); + +} + +static void ali_ircc_fir_change_speed(struct ali_ircc_cb *priv, __u32 baud) +{ + + int iobase; + struct ali_ircc_cb *self = priv; + struct net_device *dev; + + + IRDA_ASSERT(self != NULL, return;); + + dev = self->netdev; + iobase = self->io.fir_base; + + pr_debug("%s(), self->io.speed = %d, change to speed = %d\n", + __func__, self->io.speed, baud); + + /* Come from SIR speed */ + if(self->io.speed <=115200) + { + SIR2FIR(iobase); + } + + /* Update accounting for new speed */ + self->io.speed = baud; + + // Set Dongle Speed mode + ali_ircc_change_dongle_speed(self, baud); + +} + +/* + * Function ali_sir_change_speed (self, speed) + * + * Set speed of IrDA port to specified baudrate + * + */ +static void ali_ircc_sir_change_speed(struct ali_ircc_cb *priv, __u32 speed) +{ + struct ali_ircc_cb *self = priv; + int iobase; + int fcr; /* FIFO control reg */ + int lcr; /* Line control reg */ + int divisor; + + + pr_debug("%s(), Setting speed to: %d\n", __func__, speed); + + IRDA_ASSERT(self != NULL, return;); + + iobase = self->io.sir_base; + + /* Come from MIR or FIR speed */ + if(self->io.speed >115200) + { + // Set Dongle Speed mode first + ali_ircc_change_dongle_speed(self, speed); + + FIR2SIR(iobase); + } + + // Clear Line and Auxiluary status registers 2000/11/24 11:47AM + + inb(iobase+UART_LSR); + inb(iobase+UART_SCR); + + /* Update accounting for new speed */ + self->io.speed = speed; + + divisor = 115200/speed; + + fcr = UART_FCR_ENABLE_FIFO; + + /* + * Use trigger level 1 to avoid 3 ms. timeout delay at 9600 bps, and + * almost 1,7 ms at 19200 bps. At speeds above that we can just forget + * about this timeout since it will always be fast enough. + */ + if (self->io.speed < 38400) + fcr |= UART_FCR_TRIGGER_1; + else + fcr |= UART_FCR_TRIGGER_14; + + /* IrDA ports use 8N1 */ + lcr = UART_LCR_WLEN8; + + outb(UART_LCR_DLAB | lcr, iobase+UART_LCR); /* Set DLAB */ + outb(divisor & 0xff, iobase+UART_DLL); /* Set speed */ + outb(divisor >> 8, iobase+UART_DLM); + outb(lcr, iobase+UART_LCR); /* Set 8N1 */ + outb(fcr, iobase+UART_FCR); /* Enable FIFO's */ + + /* without this, the connection will be broken after come back from FIR speed, + but with this, the SIR connection is harder to established */ + outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase+UART_MCR); +} + +static void ali_ircc_change_dongle_speed(struct ali_ircc_cb *priv, int speed) +{ + + struct ali_ircc_cb *self = priv; + int iobase,dongle_id; + int tmp = 0; + + + iobase = self->io.fir_base; /* or iobase = self->io.sir_base; */ + dongle_id = self->io.dongle_id; + + /* We are already locked, no need to do it again */ + + pr_debug("%s(), Set Speed for %s , Speed = %d\n", + __func__, dongle_types[dongle_id], speed); + + switch_bank(iobase, BANK2); + tmp = inb(iobase+FIR_IRDA_CR); + + /* IBM type dongle */ + if(dongle_id == 0) + { + if(speed == 4000000) + { + // __ __ + // SD/MODE __| |__ __ + // __ __ + // IRTX __ __| |__ + // T1 T2 T3 T4 T5 + + tmp &= ~IRDA_CR_HDLC; // HDLC=0 + tmp |= IRDA_CR_CRC; // CRC=1 + + switch_bank(iobase, BANK2); + outb(tmp, iobase+FIR_IRDA_CR); + + // T1 -> SD/MODE:0 IRTX:0 + tmp &= ~0x09; + tmp |= 0x02; + outb(tmp, iobase+FIR_IRDA_CR); + udelay(2); + + // T2 -> SD/MODE:1 IRTX:0 + tmp &= ~0x01; + tmp |= 0x0a; + outb(tmp, iobase+FIR_IRDA_CR); + udelay(2); + + // T3 -> SD/MODE:1 IRTX:1 + tmp |= 0x0b; + outb(tmp, iobase+FIR_IRDA_CR); + udelay(2); + + // T4 -> SD/MODE:0 IRTX:1 + tmp &= ~0x08; + tmp |= 0x03; + outb(tmp, iobase+FIR_IRDA_CR); + udelay(2); + + // T5 -> SD/MODE:0 IRTX:0 + tmp &= ~0x09; + tmp |= 0x02; + outb(tmp, iobase+FIR_IRDA_CR); + udelay(2); + + // reset -> Normal TX output Signal + outb(tmp & ~0x02, iobase+FIR_IRDA_CR); + } + else /* speed <=1152000 */ + { + // __ + // SD/MODE __| |__ + // + // IRTX ________ + // T1 T2 T3 + + /* MIR 115200, 57600 */ + if (speed==1152000) + { + tmp |= 0xA0; //HDLC=1, 1.152Mbps=1 + } + else + { + tmp &=~0x80; //HDLC 0.576Mbps + tmp |= 0x20; //HDLC=1, + } + + tmp |= IRDA_CR_CRC; // CRC=1 + + switch_bank(iobase, BANK2); + outb(tmp, iobase+FIR_IRDA_CR); + + /* MIR 115200, 57600 */ + + //switch_bank(iobase, BANK2); + // T1 -> SD/MODE:0 IRTX:0 + tmp &= ~0x09; + tmp |= 0x02; + outb(tmp, iobase+FIR_IRDA_CR); + udelay(2); + + // T2 -> SD/MODE:1 IRTX:0 + tmp &= ~0x01; + tmp |= 0x0a; + outb(tmp, iobase+FIR_IRDA_CR); + + // T3 -> SD/MODE:0 IRTX:0 + tmp &= ~0x09; + tmp |= 0x02; + outb(tmp, iobase+FIR_IRDA_CR); + udelay(2); + + // reset -> Normal TX output Signal + outb(tmp & ~0x02, iobase+FIR_IRDA_CR); + } + } + else if (dongle_id == 1) /* HP HDSL-3600 */ + { + switch(speed) + { + case 4000000: + tmp &= ~IRDA_CR_HDLC; // HDLC=0 + break; + + case 1152000: + tmp |= 0xA0; // HDLC=1, 1.152Mbps=1 + break; + + case 576000: + tmp &=~0x80; // HDLC 0.576Mbps + tmp |= 0x20; // HDLC=1, + break; + } + + tmp |= IRDA_CR_CRC; // CRC=1 + + switch_bank(iobase, BANK2); + outb(tmp, iobase+FIR_IRDA_CR); + } + else /* HP HDSL-1100 */ + { + if(speed <= 115200) /* SIR */ + { + + tmp &= ~IRDA_CR_FIR_SIN; // HP sin select = 0 + + switch_bank(iobase, BANK2); + outb(tmp, iobase+FIR_IRDA_CR); + } + else /* MIR FIR */ + { + + switch(speed) + { + case 4000000: + tmp &= ~IRDA_CR_HDLC; // HDLC=0 + break; + + case 1152000: + tmp |= 0xA0; // HDLC=1, 1.152Mbps=1 + break; + + case 576000: + tmp &=~0x80; // HDLC 0.576Mbps + tmp |= 0x20; // HDLC=1, + break; + } + + tmp |= IRDA_CR_CRC; // CRC=1 + tmp |= IRDA_CR_FIR_SIN; // HP sin select = 1 + + switch_bank(iobase, BANK2); + outb(tmp, iobase+FIR_IRDA_CR); + } + } + + switch_bank(iobase, BANK0); + +} + +/* + * Function ali_ircc_sir_write (driver) + * + * Fill Tx FIFO with transmit data + * + */ +static int ali_ircc_sir_write(int iobase, int fifo_size, __u8 *buf, int len) +{ + int actual = 0; + + + /* Tx FIFO should be empty! */ + if (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) { + pr_debug("%s(), failed, fifo not empty!\n", __func__); + return 0; + } + + /* Fill FIFO with current frame */ + while ((fifo_size-- > 0) && (actual < len)) { + /* Transmit next byte */ + outb(buf[actual], iobase+UART_TX); + + actual++; + } + + return actual; +} + +/* + * Function ali_ircc_net_open (dev) + * + * Start the device + * + */ +static int ali_ircc_net_open(struct net_device *dev) +{ + struct ali_ircc_cb *self; + int iobase; + char hwname[32]; + + + IRDA_ASSERT(dev != NULL, return -1;); + + self = netdev_priv(dev); + + IRDA_ASSERT(self != NULL, return 0;); + + iobase = self->io.fir_base; + + /* Request IRQ and install Interrupt Handler */ + if (request_irq(self->io.irq, ali_ircc_interrupt, 0, dev->name, dev)) + { + net_warn_ratelimited("%s, unable to allocate irq=%d\n", + ALI_IRCC_DRIVER_NAME, self->io.irq); + return -EAGAIN; + } + + /* + * Always allocate the DMA channel after the IRQ, and clean up on + * failure. + */ + if (request_dma(self->io.dma, dev->name)) { + net_warn_ratelimited("%s, unable to allocate dma=%d\n", + ALI_IRCC_DRIVER_NAME, self->io.dma); + free_irq(self->io.irq, dev); + return -EAGAIN; + } + + /* Turn on interrups */ + outb(UART_IER_RDI , iobase+UART_IER); + + /* Ready to play! */ + netif_start_queue(dev); //benjamin by irport + + /* Give self a hardware name */ + sprintf(hwname, "ALI-FIR @ 0x%03x", self->io.fir_base); + + /* + * Open new IrLAP layer instance, now that everything should be + * initialized properly + */ + self->irlap = irlap_open(dev, &self->qos, hwname); + + + return 0; +} + +/* + * Function ali_ircc_net_close (dev) + * + * Stop the device + * + */ +static int ali_ircc_net_close(struct net_device *dev) +{ + + struct ali_ircc_cb *self; + //int iobase; + + + IRDA_ASSERT(dev != NULL, return -1;); + + self = netdev_priv(dev); + IRDA_ASSERT(self != NULL, return 0;); + + /* Stop device */ + netif_stop_queue(dev); + + /* Stop and remove instance of IrLAP */ + if (self->irlap) + irlap_close(self->irlap); + self->irlap = NULL; + + disable_dma(self->io.dma); + + /* Disable interrupts */ + SetCOMInterrupts(self, FALSE); + + free_irq(self->io.irq, dev); + free_dma(self->io.dma); + + + return 0; +} + +/* + * Function ali_ircc_fir_hard_xmit (skb, dev) + * + * Transmit the frame + * + */ +static netdev_tx_t ali_ircc_fir_hard_xmit(struct sk_buff *skb, + struct net_device *dev) +{ + struct ali_ircc_cb *self; + unsigned long flags; + int iobase; + __u32 speed; + int mtt, diff; + + + self = netdev_priv(dev); + iobase = self->io.fir_base; + + netif_stop_queue(dev); + + /* Make sure tests *& speed change are atomic */ + spin_lock_irqsave(&self->lock, flags); + + /* Note : you should make sure that speed changes are not going + * to corrupt any outgoing frame. Look at nsc-ircc for the gory + * details - Jean II */ + + /* Check if we need to change the speed */ + speed = irda_get_next_speed(skb); + if ((speed != self->io.speed) && (speed != -1)) { + /* Check for empty frame */ + if (!skb->len) { + ali_ircc_change_speed(self, speed); + netif_trans_update(dev); + spin_unlock_irqrestore(&self->lock, flags); + dev_kfree_skb(skb); + return NETDEV_TX_OK; + } else + self->new_speed = speed; + } + + /* Register and copy this frame to DMA memory */ + self->tx_fifo.queue[self->tx_fifo.free].start = self->tx_fifo.tail; + self->tx_fifo.queue[self->tx_fifo.free].len = skb->len; + self->tx_fifo.tail += skb->len; + + dev->stats.tx_bytes += skb->len; + + skb_copy_from_linear_data(skb, self->tx_fifo.queue[self->tx_fifo.free].start, + skb->len); + self->tx_fifo.len++; + self->tx_fifo.free++; + + /* Start transmit only if there is currently no transmit going on */ + if (self->tx_fifo.len == 1) + { + /* Check if we must wait the min turn time or not */ + mtt = irda_get_mtt(skb); + + if (mtt) + { + /* Check how much time we have used already */ + diff = ktime_us_delta(ktime_get(), self->stamp); + /* self->stamp is set from ali_ircc_dma_receive_complete() */ + + pr_debug("%s(), ******* diff = %d *******\n", + __func__, diff); + + /* Check if the mtt is larger than the time we have + * already used by all the protocol processing + */ + if (mtt > diff) + { + mtt -= diff; + + /* + * Use timer if delay larger than 1000 us, and + * use udelay for smaller values which should + * be acceptable + */ + if (mtt > 500) + { + /* Adjust for timer resolution */ + mtt = (mtt+250) / 500; /* 4 discard, 5 get advanced, Let's round off */ + + pr_debug("%s(), ************** mtt = %d ***********\n", + __func__, mtt); + + /* Setup timer */ + if (mtt == 1) /* 500 us */ + { + switch_bank(iobase, BANK1); + outb(TIMER_IIR_500, iobase+FIR_TIMER_IIR); + } + else if (mtt == 2) /* 1 ms */ + { + switch_bank(iobase, BANK1); + outb(TIMER_IIR_1ms, iobase+FIR_TIMER_IIR); + } + else /* > 2ms -> 4ms */ + { + switch_bank(iobase, BANK1); + outb(TIMER_IIR_2ms, iobase+FIR_TIMER_IIR); + } + + + /* Start timer */ + outb(inb(iobase+FIR_CR) | CR_TIMER_EN, iobase+FIR_CR); + self->io.direction = IO_XMIT; + + /* Enable timer interrupt */ + self->ier = IER_TIMER; + SetCOMInterrupts(self, TRUE); + + /* Timer will take care of the rest */ + goto out; + } + else + udelay(mtt); + } // if (if (mtt > diff) + }// if (mtt) + + /* Enable EOM interrupt */ + self->ier = IER_EOM; + SetCOMInterrupts(self, TRUE); + + /* Transmit frame */ + ali_ircc_dma_xmit(self); + } // if (self->tx_fifo.len == 1) + + out: + + /* Not busy transmitting anymore if window is not full */ + if (self->tx_fifo.free < MAX_TX_WINDOW) + netif_wake_queue(self->netdev); + + /* Restore bank register */ + switch_bank(iobase, BANK0); + + netif_trans_update(dev); + spin_unlock_irqrestore(&self->lock, flags); + dev_kfree_skb(skb); + + return NETDEV_TX_OK; +} + + +static void ali_ircc_dma_xmit(struct ali_ircc_cb *self) +{ + int iobase, tmp; + unsigned char FIFO_OPTI, Hi, Lo; + + + + iobase = self->io.fir_base; + + /* FIFO threshold , this method comes from NDIS5 code */ + + if(self->tx_fifo.queue[self->tx_fifo.ptr].len < TX_FIFO_Threshold) + FIFO_OPTI = self->tx_fifo.queue[self->tx_fifo.ptr].len-1; + else + FIFO_OPTI = TX_FIFO_Threshold; + + /* Disable DMA */ + switch_bank(iobase, BANK1); + outb(inb(iobase+FIR_CR) & ~CR_DMA_EN, iobase+FIR_CR); + + self->io.direction = IO_XMIT; + + irda_setup_dma(self->io.dma, + ((u8 *)self->tx_fifo.queue[self->tx_fifo.ptr].start - + self->tx_buff.head) + self->tx_buff_dma, + self->tx_fifo.queue[self->tx_fifo.ptr].len, + DMA_TX_MODE); + + /* Reset Tx FIFO */ + switch_bank(iobase, BANK0); + outb(LCR_A_FIFO_RESET, iobase+FIR_LCR_A); + + /* Set Tx FIFO threshold */ + if (self->fifo_opti_buf!=FIFO_OPTI) + { + switch_bank(iobase, BANK1); + outb(FIFO_OPTI, iobase+FIR_FIFO_TR) ; + self->fifo_opti_buf=FIFO_OPTI; + } + + /* Set Tx DMA threshold */ + switch_bank(iobase, BANK1); + outb(TX_DMA_Threshold, iobase+FIR_DMA_TR); + + /* Set max Tx frame size */ + Hi = (self->tx_fifo.queue[self->tx_fifo.ptr].len >> 8) & 0x0f; + Lo = self->tx_fifo.queue[self->tx_fifo.ptr].len & 0xff; + switch_bank(iobase, BANK2); + outb(Hi, iobase+FIR_TX_DSR_HI); + outb(Lo, iobase+FIR_TX_DSR_LO); + + /* Disable SIP , Disable Brick Wall (we don't support in TX mode), Change to TX mode */ + switch_bank(iobase, BANK0); + tmp = inb(iobase+FIR_LCR_B); + tmp &= ~0x20; // Disable SIP + outb(((unsigned char)(tmp & 0x3f) | LCR_B_TX_MODE) & ~LCR_B_BW, iobase+FIR_LCR_B); + pr_debug("%s(), *** Change to TX mode: FIR_LCR_B = 0x%x ***\n", + __func__, inb(iobase + FIR_LCR_B)); + + outb(0, iobase+FIR_LSR); + + /* Enable DMA and Burst Mode */ + switch_bank(iobase, BANK1); + outb(inb(iobase+FIR_CR) | CR_DMA_EN | CR_DMA_BURST, iobase+FIR_CR); + + switch_bank(iobase, BANK0); + +} + +static int ali_ircc_dma_xmit_complete(struct ali_ircc_cb *self) +{ + int iobase; + int ret = TRUE; + + + iobase = self->io.fir_base; + + /* Disable DMA */ + switch_bank(iobase, BANK1); + outb(inb(iobase+FIR_CR) & ~CR_DMA_EN, iobase+FIR_CR); + + /* Check for underrun! */ + switch_bank(iobase, BANK0); + if((inb(iobase+FIR_LSR) & LSR_FRAME_ABORT) == LSR_FRAME_ABORT) + + { + net_err_ratelimited("%s(), ********* LSR_FRAME_ABORT *********\n", + __func__); + self->netdev->stats.tx_errors++; + self->netdev->stats.tx_fifo_errors++; + } + else + { + self->netdev->stats.tx_packets++; + } + + /* Check if we need to change the speed */ + if (self->new_speed) + { + ali_ircc_change_speed(self, self->new_speed); + self->new_speed = 0; + } + + /* Finished with this frame, so prepare for next */ + self->tx_fifo.ptr++; + self->tx_fifo.len--; + + /* Any frames to be sent back-to-back? */ + if (self->tx_fifo.len) + { + ali_ircc_dma_xmit(self); + + /* Not finished yet! */ + ret = FALSE; + } + else + { /* Reset Tx FIFO info */ + self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0; + self->tx_fifo.tail = self->tx_buff.head; + } + + /* Make sure we have room for more frames */ + if (self->tx_fifo.free < MAX_TX_WINDOW) { + /* Not busy transmitting anymore */ + /* Tell the network layer, that we can accept more frames */ + netif_wake_queue(self->netdev); + } + + switch_bank(iobase, BANK0); + + return ret; +} + +/* + * Function ali_ircc_dma_receive (self) + * + * Get ready for receiving a frame. The device will initiate a DMA + * if it starts to receive a frame. + * + */ +static int ali_ircc_dma_receive(struct ali_ircc_cb *self) +{ + int iobase, tmp; + + + iobase = self->io.fir_base; + + /* Reset Tx FIFO info */ + self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0; + self->tx_fifo.tail = self->tx_buff.head; + + /* Disable DMA */ + switch_bank(iobase, BANK1); + outb(inb(iobase+FIR_CR) & ~CR_DMA_EN, iobase+FIR_CR); + + /* Reset Message Count */ + switch_bank(iobase, BANK0); + outb(0x07, iobase+FIR_LSR); + + self->rcvFramesOverflow = FALSE; + + self->LineStatus = inb(iobase+FIR_LSR) ; + + /* Reset Rx FIFO info */ + self->io.direction = IO_RECV; + self->rx_buff.data = self->rx_buff.head; + + /* Reset Rx FIFO */ + // switch_bank(iobase, BANK0); + outb(LCR_A_FIFO_RESET, iobase+FIR_LCR_A); + + self->st_fifo.len = self->st_fifo.pending_bytes = 0; + self->st_fifo.tail = self->st_fifo.head = 0; + + irda_setup_dma(self->io.dma, self->rx_buff_dma, self->rx_buff.truesize, + DMA_RX_MODE); + + /* Set Receive Mode,Brick Wall */ + //switch_bank(iobase, BANK0); + tmp = inb(iobase+FIR_LCR_B); + outb((unsigned char)(tmp &0x3f) | LCR_B_RX_MODE | LCR_B_BW , iobase + FIR_LCR_B); // 2000/12/1 05:16PM + pr_debug("%s(), *** Change To RX mode: FIR_LCR_B = 0x%x ***\n", + __func__, inb(iobase + FIR_LCR_B)); + + /* Set Rx Threshold */ + switch_bank(iobase, BANK1); + outb(RX_FIFO_Threshold, iobase+FIR_FIFO_TR); + outb(RX_DMA_Threshold, iobase+FIR_DMA_TR); + + /* Enable DMA and Burst Mode */ + // switch_bank(iobase, BANK1); + outb(CR_DMA_EN | CR_DMA_BURST, iobase+FIR_CR); + + switch_bank(iobase, BANK0); + return 0; +} + +static int ali_ircc_dma_receive_complete(struct ali_ircc_cb *self) +{ + struct st_fifo *st_fifo; + struct sk_buff *skb; + __u8 status, MessageCount; + int len, i, iobase, val; + + st_fifo = &self->st_fifo; + iobase = self->io.fir_base; + + switch_bank(iobase, BANK0); + MessageCount = inb(iobase+ FIR_LSR)&0x07; + + if (MessageCount > 0) + pr_debug("%s(), Message count = %d\n", __func__, MessageCount); + + for (i=0; i<=MessageCount; i++) + { + /* Bank 0 */ + switch_bank(iobase, BANK0); + status = inb(iobase+FIR_LSR); + + switch_bank(iobase, BANK2); + len = inb(iobase+FIR_RX_DSR_HI) & 0x0f; + len = len << 8; + len |= inb(iobase+FIR_RX_DSR_LO); + + pr_debug("%s(), RX Length = 0x%.2x,\n", __func__ , len); + pr_debug("%s(), RX Status = 0x%.2x,\n", __func__ , status); + + if (st_fifo->tail >= MAX_RX_WINDOW) { + pr_debug("%s(), window is full!\n", __func__); + continue; + } + + st_fifo->entries[st_fifo->tail].status = status; + st_fifo->entries[st_fifo->tail].len = len; + st_fifo->pending_bytes += len; + st_fifo->tail++; + st_fifo->len++; + } + + for (i=0; i<=MessageCount; i++) + { + /* Get first entry */ + status = st_fifo->entries[st_fifo->head].status; + len = st_fifo->entries[st_fifo->head].len; + st_fifo->pending_bytes -= len; + st_fifo->head++; + st_fifo->len--; + + /* Check for errors */ + if ((status & 0xd8) || self->rcvFramesOverflow || (len==0)) + { + pr_debug("%s(), ************* RX Errors ************\n", + __func__); + + /* Skip frame */ + self->netdev->stats.rx_errors++; + + self->rx_buff.data += len; + + if (status & LSR_FIFO_UR) + { + self->netdev->stats.rx_frame_errors++; + pr_debug("%s(), ************* FIFO Errors ************\n", + __func__); + } + if (status & LSR_FRAME_ERROR) + { + self->netdev->stats.rx_frame_errors++; + pr_debug("%s(), ************* FRAME Errors ************\n", + __func__); + } + + if (status & LSR_CRC_ERROR) + { + self->netdev->stats.rx_crc_errors++; + pr_debug("%s(), ************* CRC Errors ************\n", + __func__); + } + + if(self->rcvFramesOverflow) + { + self->netdev->stats.rx_frame_errors++; + pr_debug("%s(), ************* Overran DMA buffer ************\n", + __func__); + } + if(len == 0) + { + self->netdev->stats.rx_frame_errors++; + pr_debug("%s(), ********** Receive Frame Size = 0 *********\n", + __func__); + } + } + else + { + + if (st_fifo->pending_bytes < 32) + { + switch_bank(iobase, BANK0); + val = inb(iobase+FIR_BSR); + if ((val& BSR_FIFO_NOT_EMPTY)== 0x80) + { + pr_debug("%s(), ************* BSR_FIFO_NOT_EMPTY ************\n", + __func__); + + /* Put this entry back in fifo */ + st_fifo->head--; + st_fifo->len++; + st_fifo->pending_bytes += len; + st_fifo->entries[st_fifo->head].status = status; + st_fifo->entries[st_fifo->head].len = len; + + /* + * DMA not finished yet, so try again + * later, set timer value, resolution + * 500 us + */ + + switch_bank(iobase, BANK1); + outb(TIMER_IIR_500, iobase+FIR_TIMER_IIR); // 2001/1/2 05:07PM + + /* Enable Timer */ + outb(inb(iobase+FIR_CR) | CR_TIMER_EN, iobase+FIR_CR); + + return FALSE; /* I'll be back! */ + } + } + + /* + * Remember the time we received this frame, so we can + * reduce the min turn time a bit since we will know + * how much time we have used for protocol processing + */ + self->stamp = ktime_get(); + + skb = dev_alloc_skb(len+1); + if (skb == NULL) + { + self->netdev->stats.rx_dropped++; + + return FALSE; + } + + /* Make sure IP header gets aligned */ + skb_reserve(skb, 1); + + /* Copy frame without CRC, CRC is removed by hardware*/ + skb_put(skb, len); + skb_copy_to_linear_data(skb, self->rx_buff.data, len); + + /* Move to next frame */ + self->rx_buff.data += len; + self->netdev->stats.rx_bytes += len; + self->netdev->stats.rx_packets++; + + skb->dev = self->netdev; + skb_reset_mac_header(skb); + skb->protocol = htons(ETH_P_IRDA); + netif_rx(skb); + } + } + + switch_bank(iobase, BANK0); + + return TRUE; +} + + + +/* + * Function ali_ircc_sir_hard_xmit (skb, dev) + * + * Transmit the frame! + * + */ +static netdev_tx_t ali_ircc_sir_hard_xmit(struct sk_buff *skb, + struct net_device *dev) +{ + struct ali_ircc_cb *self; + unsigned long flags; + int iobase; + __u32 speed; + + + IRDA_ASSERT(dev != NULL, return NETDEV_TX_OK;); + + self = netdev_priv(dev); + IRDA_ASSERT(self != NULL, return NETDEV_TX_OK;); + + iobase = self->io.sir_base; + + netif_stop_queue(dev); + + /* Make sure tests *& speed change are atomic */ + spin_lock_irqsave(&self->lock, flags); + + /* Note : you should make sure that speed changes are not going + * to corrupt any outgoing frame. Look at nsc-ircc for the gory + * details - Jean II */ + + /* Check if we need to change the speed */ + speed = irda_get_next_speed(skb); + if ((speed != self->io.speed) && (speed != -1)) { + /* Check for empty frame */ + if (!skb->len) { + ali_ircc_change_speed(self, speed); + netif_trans_update(dev); + spin_unlock_irqrestore(&self->lock, flags); + dev_kfree_skb(skb); + return NETDEV_TX_OK; + } else + self->new_speed = speed; + } + + /* Init tx buffer */ + self->tx_buff.data = self->tx_buff.head; + + /* Copy skb to tx_buff while wrapping, stuffing and making CRC */ + self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data, + self->tx_buff.truesize); + + self->netdev->stats.tx_bytes += self->tx_buff.len; + + /* Turn on transmit finished interrupt. Will fire immediately! */ + outb(UART_IER_THRI, iobase+UART_IER); + + netif_trans_update(dev); + spin_unlock_irqrestore(&self->lock, flags); + + dev_kfree_skb(skb); + + + return NETDEV_TX_OK; +} + + +/* + * Function ali_ircc_net_ioctl (dev, rq, cmd) + * + * Process IOCTL commands for this device + * + */ +static int ali_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct if_irda_req *irq = (struct if_irda_req *) rq; + struct ali_ircc_cb *self; + unsigned long flags; + int ret = 0; + + + IRDA_ASSERT(dev != NULL, return -1;); + + self = netdev_priv(dev); + + IRDA_ASSERT(self != NULL, return -1;); + + pr_debug("%s(), %s, (cmd=0x%X)\n", __func__ , dev->name, cmd); + + switch (cmd) { + case SIOCSBANDWIDTH: /* Set bandwidth */ + pr_debug("%s(), SIOCSBANDWIDTH\n", __func__); + /* + * This function will also be used by IrLAP to change the + * speed, so we still must allow for speed change within + * interrupt context. + */ + if (!in_interrupt() && !capable(CAP_NET_ADMIN)) + return -EPERM; + + spin_lock_irqsave(&self->lock, flags); + ali_ircc_change_speed(self, irq->ifr_baudrate); + spin_unlock_irqrestore(&self->lock, flags); + break; + case SIOCSMEDIABUSY: /* Set media busy */ + pr_debug("%s(), SIOCSMEDIABUSY\n", __func__); + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + irda_device_set_media_busy(self->netdev, TRUE); + break; + case SIOCGRECEIVING: /* Check if we are receiving right now */ + pr_debug("%s(), SIOCGRECEIVING\n", __func__); + /* This is protected */ + irq->ifr_receiving = ali_ircc_is_receiving(self); + break; + default: + ret = -EOPNOTSUPP; + } + + + return ret; +} + +/* + * Function ali_ircc_is_receiving (self) + * + * Return TRUE is we are currently receiving a frame + * + */ +static int ali_ircc_is_receiving(struct ali_ircc_cb *self) +{ + unsigned long flags; + int status = FALSE; + int iobase; + + + IRDA_ASSERT(self != NULL, return FALSE;); + + spin_lock_irqsave(&self->lock, flags); + + if (self->io.speed > 115200) + { + iobase = self->io.fir_base; + + switch_bank(iobase, BANK1); + if((inb(iobase+FIR_FIFO_FR) & 0x3f) != 0) + { + /* We are receiving something */ + pr_debug("%s(), We are receiving something\n", + __func__); + status = TRUE; + } + switch_bank(iobase, BANK0); + } + else + { + status = (self->rx_buff.state != OUTSIDE_FRAME); + } + + spin_unlock_irqrestore(&self->lock, flags); + + + return status; +} + +static int ali_ircc_suspend(struct platform_device *dev, pm_message_t state) +{ + struct ali_ircc_cb *self = platform_get_drvdata(dev); + + net_info_ratelimited("%s, Suspending\n", ALI_IRCC_DRIVER_NAME); + + if (self->io.suspended) + return 0; + + ali_ircc_net_close(self->netdev); + + self->io.suspended = 1; + + return 0; +} + +static int ali_ircc_resume(struct platform_device *dev) +{ + struct ali_ircc_cb *self = platform_get_drvdata(dev); + + if (!self->io.suspended) + return 0; + + ali_ircc_net_open(self->netdev); + + net_info_ratelimited("%s, Waking up\n", ALI_IRCC_DRIVER_NAME); + + self->io.suspended = 0; + + return 0; +} + +/* ALi Chip Function */ + +static void SetCOMInterrupts(struct ali_ircc_cb *self , unsigned char enable) +{ + + unsigned char newMask; + + int iobase = self->io.fir_base; /* or sir_base */ + + pr_debug("%s(), -------- Start -------- ( Enable = %d )\n", + __func__, enable); + + /* Enable the interrupt which we wish to */ + if (enable){ + if (self->io.direction == IO_XMIT) + { + if (self->io.speed > 115200) /* FIR, MIR */ + { + newMask = self->ier; + } + else /* SIR */ + { + newMask = UART_IER_THRI | UART_IER_RDI; + } + } + else { + if (self->io.speed > 115200) /* FIR, MIR */ + { + newMask = self->ier; + } + else /* SIR */ + { + newMask = UART_IER_RDI; + } + } + } + else /* Disable all the interrupts */ + { + newMask = 0x00; + + } + + //SIR and FIR has different registers + if (self->io.speed > 115200) + { + switch_bank(iobase, BANK0); + outb(newMask, iobase+FIR_IER); + } + else + outb(newMask, iobase+UART_IER); + +} + +static void SIR2FIR(int iobase) +{ + //unsigned char tmp; + + + /* Already protected (change_speed() or setup()), no need to lock. + * Jean II */ + + outb(0x28, iobase+UART_MCR); + outb(0x68, iobase+UART_MCR); + outb(0x88, iobase+UART_MCR); + + outb(0x60, iobase+FIR_MCR); /* Master Reset */ + outb(0x20, iobase+FIR_MCR); /* Master Interrupt Enable */ + + //tmp = inb(iobase+FIR_LCR_B); /* SIP enable */ + //tmp |= 0x20; + //outb(tmp, iobase+FIR_LCR_B); + +} + +static void FIR2SIR(int iobase) +{ + unsigned char val; + + + /* Already protected (change_speed() or setup()), no need to lock. + * Jean II */ + + outb(0x20, iobase+FIR_MCR); /* IRQ to low */ + outb(0x00, iobase+UART_IER); + + outb(0xA0, iobase+FIR_MCR); /* Don't set master reset */ + outb(0x00, iobase+UART_FCR); + outb(0x07, iobase+UART_FCR); + + val = inb(iobase+UART_RX); + val = inb(iobase+UART_LSR); + val = inb(iobase+UART_MSR); + +} + +MODULE_AUTHOR("Benjamin Kong <benjamin_kong@ali.com.tw>"); +MODULE_DESCRIPTION("ALi FIR Controller Driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" ALI_IRCC_DRIVER_NAME); + + +module_param_hw_array(io, int, ioport, NULL, 0); +MODULE_PARM_DESC(io, "Base I/O addresses"); +module_param_hw_array(irq, int, irq, NULL, 0); +MODULE_PARM_DESC(irq, "IRQ lines"); +module_param_hw_array(dma, int, dma, NULL, 0); +MODULE_PARM_DESC(dma, "DMA channels"); + +module_init(ali_ircc_init); +module_exit(ali_ircc_cleanup); diff --git a/drivers/staging/irda/drivers/ali-ircc.h b/drivers/staging/irda/drivers/ali-ircc.h new file mode 100644 index 000000000000..c2d9747a5108 --- /dev/null +++ b/drivers/staging/irda/drivers/ali-ircc.h @@ -0,0 +1,227 @@ +/********************************************************************* + * + * Filename: ali-ircc.h + * Version: 0.5 + * Description: Driver for the ALI M1535D and M1543C FIR Controller + * Status: Experimental. + * Author: Benjamin Kong <benjamin_kong@ali.com.tw> + * Created at: 2000/10/16 03:46PM + * Modified at: 2001/1/3 02:56PM + * Modified by: Benjamin Kong <benjamin_kong@ali.com.tw> + * + * Copyright (c) 2000 Benjamin Kong <benjamin_kong@ali.com.tw> + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + ********************************************************************/ + +#ifndef ALI_IRCC_H +#define ALI_IRCC_H + +#include <linux/ktime.h> + +#include <linux/spinlock.h> +#include <linux/pm.h> +#include <linux/types.h> +#include <asm/io.h> + +/* SIR Register */ +/* Usr definition of linux/serial_reg.h */ + +/* FIR Register */ +#define BANK0 0x20 +#define BANK1 0x21 +#define BANK2 0x22 +#define BANK3 0x23 + +#define FIR_MCR 0x07 /* Master Control Register */ + +/* Bank 0 */ +#define FIR_DR 0x00 /* Alias 0, FIR Data Register (R/W) */ +#define FIR_IER 0x01 /* Alias 1, FIR Interrupt Enable Register (R/W) */ +#define FIR_IIR 0x02 /* Alias 2, FIR Interrupt Identification Register (Read only) */ +#define FIR_LCR_A 0x03 /* Alias 3, FIR Line Control Register A (R/W) */ +#define FIR_LCR_B 0x04 /* Alias 4, FIR Line Control Register B (R/W) */ +#define FIR_LSR 0x05 /* Alias 5, FIR Line Status Register (R/W) */ +#define FIR_BSR 0x06 /* Alias 6, FIR Bus Status Register (Read only) */ + + + /* Alias 1 */ + #define IER_FIFO 0x10 /* FIR FIFO Interrupt Enable */ + #define IER_TIMER 0x20 /* Timer Interrupt Enable */ + #define IER_EOM 0x40 /* End of Message Interrupt Enable */ + #define IER_ACT 0x80 /* Active Frame Interrupt Enable */ + + /* Alias 2 */ + #define IIR_FIFO 0x10 /* FIR FIFO Interrupt */ + #define IIR_TIMER 0x20 /* Timer Interrupt */ + #define IIR_EOM 0x40 /* End of Message Interrupt */ + #define IIR_ACT 0x80 /* Active Frame Interrupt */ + + /* Alias 3 */ + #define LCR_A_FIFO_RESET 0x80 /* FIFO Reset */ + + /* Alias 4 */ + #define LCR_B_BW 0x10 /* Brick Wall */ + #define LCR_B_SIP 0x20 /* SIP Enable */ + #define LCR_B_TX_MODE 0x40 /* Transmit Mode */ + #define LCR_B_RX_MODE 0x80 /* Receive Mode */ + + /* Alias 5 */ + #define LSR_FIR_LSA 0x00 /* FIR Line Status Address */ + #define LSR_FRAME_ABORT 0x08 /* Frame Abort */ + #define LSR_CRC_ERROR 0x10 /* CRC Error */ + #define LSR_SIZE_ERROR 0x20 /* Size Error */ + #define LSR_FRAME_ERROR 0x40 /* Frame Error */ + #define LSR_FIFO_UR 0x80 /* FIFO Underrun */ + #define LSR_FIFO_OR 0x80 /* FIFO Overrun */ + + /* Alias 6 */ + #define BSR_FIFO_NOT_EMPTY 0x80 /* FIFO Not Empty */ + +/* Bank 1 */ +#define FIR_CR 0x00 /* Alias 0, FIR Configuration Register (R/W) */ +#define FIR_FIFO_TR 0x01 /* Alias 1, FIR FIFO Threshold Register (R/W) */ +#define FIR_DMA_TR 0x02 /* Alias 2, FIR DMA Threshold Register (R/W) */ +#define FIR_TIMER_IIR 0x03 /* Alias 3, FIR Timer interrupt interval register (W/O) */ +#define FIR_FIFO_FR 0x03 /* Alias 3, FIR FIFO Flag register (R/O) */ +#define FIR_FIFO_RAR 0x04 /* Alias 4, FIR FIFO Read Address register (R/O) */ +#define FIR_FIFO_WAR 0x05 /* Alias 5, FIR FIFO Write Address register (R/O) */ +#define FIR_TR 0x06 /* Alias 6, Test REgister (W/O) */ + + /* Alias 0 */ + #define CR_DMA_EN 0x01 /* DMA Enable */ + #define CR_DMA_BURST 0x02 /* DMA Burst Mode */ + #define CR_TIMER_EN 0x08 /* Timer Enable */ + + /* Alias 3 */ + #define TIMER_IIR_500 0x00 /* 500 us */ + #define TIMER_IIR_1ms 0x01 /* 1 ms */ + #define TIMER_IIR_2ms 0x02 /* 2 ms */ + #define TIMER_IIR_4ms 0x03 /* 4 ms */ + +/* Bank 2 */ +#define FIR_IRDA_CR 0x00 /* Alias 0, IrDA Control Register (R/W) */ +#define FIR_BOF_CR 0x01 /* Alias 1, BOF Count Register (R/W) */ +#define FIR_BW_CR 0x02 /* Alias 2, Brick Wall Count Register (R/W) */ +#define FIR_TX_DSR_HI 0x03 /* Alias 3, TX Data Size Register (high) (R/W) */ +#define FIR_TX_DSR_LO 0x04 /* Alias 4, TX Data Size Register (low) (R/W) */ +#define FIR_RX_DSR_HI 0x05 /* Alias 5, RX Data Size Register (high) (R/W) */ +#define FIR_RX_DSR_LO 0x06 /* Alias 6, RX Data Size Register (low) (R/W) */ + + /* Alias 0 */ + #define IRDA_CR_HDLC1152 0x80 /* 1.152Mbps HDLC Select */ + #define IRDA_CR_CRC 0X40 /* CRC Select. */ + #define IRDA_CR_HDLC 0x20 /* HDLC select. */ + #define IRDA_CR_HP_MODE 0x10 /* HP mode (read only) */ + #define IRDA_CR_SD_ST 0x08 /* SD/MODE State. */ + #define IRDA_CR_FIR_SIN 0x04 /* FIR SIN Select. */ + #define IRDA_CR_ITTX_0 0x02 /* SOUT State. IRTX force to 0 */ + #define IRDA_CR_ITTX_1 0x03 /* SOUT State. IRTX force to 1 */ + +/* Bank 3 */ +#define FIR_ID_VR 0x00 /* Alias 0, FIR ID Version Register (R/O) */ +#define FIR_MODULE_CR 0x01 /* Alias 1, FIR Module Control Register (R/W) */ +#define FIR_IO_BASE_HI 0x02 /* Alias 2, FIR Higher I/O Base Address Register (R/O) */ +#define FIR_IO_BASE_LO 0x03 /* Alias 3, FIR Lower I/O Base Address Register (R/O) */ +#define FIR_IRQ_CR 0x04 /* Alias 4, FIR IRQ Channel Register (R/O) */ +#define FIR_DMA_CR 0x05 /* Alias 5, FIR DMA Channel Register (R/O) */ + +struct ali_chip { + char *name; + int cfg[2]; + unsigned char entr1; + unsigned char entr2; + unsigned char cid_index; + unsigned char cid_value; + int (*probe)(struct ali_chip *chip, chipio_t *info); + int (*init)(struct ali_chip *chip, chipio_t *info); +}; +typedef struct ali_chip ali_chip_t; + + +/* DMA modes needed */ +#define DMA_TX_MODE 0x08 /* Mem to I/O, ++, demand. */ +#define DMA_RX_MODE 0x04 /* I/O to mem, ++, demand. */ + +#define MAX_TX_WINDOW 7 +#define MAX_RX_WINDOW 7 + +#define TX_FIFO_Threshold 8 +#define RX_FIFO_Threshold 1 +#define TX_DMA_Threshold 1 +#define RX_DMA_Threshold 1 + +/* For storing entries in the status FIFO */ + +struct st_fifo_entry { + int status; + int len; +}; + +struct st_fifo { + struct st_fifo_entry entries[MAX_RX_WINDOW]; + int pending_bytes; + int head; + int tail; + int len; +}; + +struct frame_cb { + void *start; /* Start of frame in DMA mem */ + int len; /* Length of frame in DMA mem */ +}; + +struct tx_fifo { + struct frame_cb queue[MAX_TX_WINDOW]; /* Info about frames in queue */ + int ptr; /* Currently being sent */ + int len; /* Length of queue */ + int free; /* Next free slot */ + void *tail; /* Next free start in DMA mem */ +}; + +/* Private data for each instance */ +struct ali_ircc_cb { + + struct st_fifo st_fifo; /* Info about received frames */ + struct tx_fifo tx_fifo; /* Info about frames to be transmitted */ + + struct net_device *netdev; /* Yes! we are some kind of netdevice */ + + struct irlap_cb *irlap; /* The link layer we are binded to */ + struct qos_info qos; /* QoS capabilities for this device */ + + chipio_t io; /* IrDA controller information */ + iobuff_t tx_buff; /* Transmit buffer */ + iobuff_t rx_buff; /* Receive buffer */ + dma_addr_t tx_buff_dma; + dma_addr_t rx_buff_dma; + + __u8 ier; /* Interrupt enable register */ + + __u8 InterruptID; /* Interrupt ID */ + __u8 BusStatus; /* Bus Status */ + __u8 LineStatus; /* Line Status */ + + unsigned char rcvFramesOverflow; + + ktime_t stamp; + + spinlock_t lock; /* For serializing operations */ + + __u32 new_speed; + int index; /* Instance index */ + + unsigned char fifo_opti_buf; +}; + +static inline void switch_bank(int iobase, int bank) +{ + outb(bank, iobase+FIR_MCR); +} + +#endif /* ALI_IRCC_H */ diff --git a/drivers/staging/irda/drivers/au1k_ir.c b/drivers/staging/irda/drivers/au1k_ir.c new file mode 100644 index 000000000000..be4ea6aa57a9 --- /dev/null +++ b/drivers/staging/irda/drivers/au1k_ir.c @@ -0,0 +1,989 @@ +/* + * Alchemy Semi Au1000 IrDA driver + * + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or source@mvista.com + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/clk.h> +#include <linux/module.h> +#include <linux/netdevice.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/types.h> + +#include <net/irda/irda.h> +#include <net/irda/irmod.h> +#include <net/irda/wrapper.h> +#include <net/irda/irda_device.h> +#include <asm/mach-au1x00/au1000.h> + +/* registers */ +#define IR_RING_PTR_STATUS 0x00 +#define IR_RING_BASE_ADDR_H 0x04 +#define IR_RING_BASE_ADDR_L 0x08 +#define IR_RING_SIZE 0x0C +#define IR_RING_PROMPT 0x10 +#define IR_RING_ADDR_CMPR 0x14 +#define IR_INT_CLEAR 0x18 +#define IR_CONFIG_1 0x20 +#define IR_SIR_FLAGS 0x24 +#define IR_STATUS 0x28 +#define IR_READ_PHY_CONFIG 0x2C +#define IR_WRITE_PHY_CONFIG 0x30 +#define IR_MAX_PKT_LEN 0x34 +#define IR_RX_BYTE_CNT 0x38 +#define IR_CONFIG_2 0x3C +#define IR_ENABLE 0x40 + +/* Config1 */ +#define IR_RX_INVERT_LED (1 << 0) +#define IR_TX_INVERT_LED (1 << 1) +#define IR_ST (1 << 2) +#define IR_SF (1 << 3) +#define IR_SIR (1 << 4) +#define IR_MIR (1 << 5) +#define IR_FIR (1 << 6) +#define IR_16CRC (1 << 7) +#define IR_TD (1 << 8) +#define IR_RX_ALL (1 << 9) +#define IR_DMA_ENABLE (1 << 10) +#define IR_RX_ENABLE (1 << 11) +#define IR_TX_ENABLE (1 << 12) +#define IR_LOOPBACK (1 << 14) +#define IR_SIR_MODE (IR_SIR | IR_DMA_ENABLE | \ + IR_RX_ALL | IR_RX_ENABLE | IR_SF | \ + IR_16CRC) + +/* ir_status */ +#define IR_RX_STATUS (1 << 9) +#define IR_TX_STATUS (1 << 10) +#define IR_PHYEN (1 << 15) + +/* ir_write_phy_config */ +#define IR_BR(x) (((x) & 0x3f) << 10) /* baud rate */ +#define IR_PW(x) (((x) & 0x1f) << 5) /* pulse width */ +#define IR_P(x) ((x) & 0x1f) /* preamble bits */ + +/* Config2 */ +#define IR_MODE_INV (1 << 0) +#define IR_ONE_PIN (1 << 1) +#define IR_PHYCLK_40MHZ (0 << 2) +#define IR_PHYCLK_48MHZ (1 << 2) +#define IR_PHYCLK_56MHZ (2 << 2) +#define IR_PHYCLK_64MHZ (3 << 2) +#define IR_DP (1 << 4) +#define IR_DA (1 << 5) +#define IR_FLT_HIGH (0 << 6) +#define IR_FLT_MEDHI (1 << 6) +#define IR_FLT_MEDLO (2 << 6) +#define IR_FLT_LO (3 << 6) +#define IR_IEN (1 << 8) + +/* ir_enable */ +#define IR_HC (1 << 3) /* divide SBUS clock by 2 */ +#define IR_CE (1 << 2) /* clock enable */ +#define IR_C (1 << 1) /* coherency bit */ +#define IR_BE (1 << 0) /* set in big endian mode */ + +#define NUM_IR_DESC 64 +#define RING_SIZE_4 0x0 +#define RING_SIZE_16 0x3 +#define RING_SIZE_64 0xF +#define MAX_NUM_IR_DESC 64 +#define MAX_BUF_SIZE 2048 + +/* Ring descriptor flags */ +#define AU_OWN (1 << 7) /* tx,rx */ +#define IR_DIS_CRC (1 << 6) /* tx */ +#define IR_BAD_CRC (1 << 5) /* tx */ +#define IR_NEED_PULSE (1 << 4) /* tx */ +#define IR_FORCE_UNDER (1 << 3) /* tx */ +#define IR_DISABLE_TX (1 << 2) /* tx */ +#define IR_HW_UNDER (1 << 0) /* tx */ +#define IR_TX_ERROR (IR_DIS_CRC | IR_BAD_CRC | IR_HW_UNDER) + +#define IR_PHY_ERROR (1 << 6) /* rx */ +#define IR_CRC_ERROR (1 << 5) /* rx */ +#define IR_MAX_LEN (1 << 4) /* rx */ +#define IR_FIFO_OVER (1 << 3) /* rx */ +#define IR_SIR_ERROR (1 << 2) /* rx */ +#define IR_RX_ERROR (IR_PHY_ERROR | IR_CRC_ERROR | \ + IR_MAX_LEN | IR_FIFO_OVER | IR_SIR_ERROR) + +struct db_dest { + struct db_dest *pnext; + volatile u32 *vaddr; + dma_addr_t dma_addr; +}; + +struct ring_dest { + u8 count_0; /* 7:0 */ + u8 count_1; /* 12:8 */ + u8 reserved; + u8 flags; + u8 addr_0; /* 7:0 */ + u8 addr_1; /* 15:8 */ + u8 addr_2; /* 23:16 */ + u8 addr_3; /* 31:24 */ +}; + +/* Private data for each instance */ +struct au1k_private { + void __iomem *iobase; + int irq_rx, irq_tx; + + struct db_dest *pDBfree; + struct db_dest db[2 * NUM_IR_DESC]; + volatile struct ring_dest *rx_ring[NUM_IR_DESC]; + volatile struct ring_dest *tx_ring[NUM_IR_DESC]; + struct db_dest *rx_db_inuse[NUM_IR_DESC]; + struct db_dest *tx_db_inuse[NUM_IR_DESC]; + u32 rx_head; + u32 tx_head; + u32 tx_tail; + u32 tx_full; + + iobuff_t rx_buff; + + struct net_device *netdev; + struct qos_info qos; + struct irlap_cb *irlap; + + u8 open; + u32 speed; + u32 newspeed; + + struct resource *ioarea; + struct au1k_irda_platform_data *platdata; + struct clk *irda_clk; +}; + +static int qos_mtt_bits = 0x07; /* 1 ms or more */ + +static void au1k_irda_plat_set_phy_mode(struct au1k_private *p, int mode) +{ + if (p->platdata && p->platdata->set_phy_mode) + p->platdata->set_phy_mode(mode); +} + +static inline unsigned long irda_read(struct au1k_private *p, + unsigned long ofs) +{ + /* + * IrDA peripheral bug. You have to read the register + * twice to get the right value. + */ + (void)__raw_readl(p->iobase + ofs); + return __raw_readl(p->iobase + ofs); +} + +static inline void irda_write(struct au1k_private *p, unsigned long ofs, + unsigned long val) +{ + __raw_writel(val, p->iobase + ofs); + wmb(); +} + +/* + * Buffer allocation/deallocation routines. The buffer descriptor returned + * has the virtual and dma address of a buffer suitable for + * both, receive and transmit operations. + */ +static struct db_dest *GetFreeDB(struct au1k_private *aup) +{ + struct db_dest *db; + db = aup->pDBfree; + + if (db) + aup->pDBfree = db->pnext; + return db; +} + +/* + DMA memory allocation, derived from pci_alloc_consistent. + However, the Au1000 data cache is coherent (when programmed + so), therefore we return KSEG0 address, not KSEG1. +*/ +static void *dma_alloc(size_t size, dma_addr_t *dma_handle) +{ + void *ret; + int gfp = GFP_ATOMIC | GFP_DMA; + + ret = (void *)__get_free_pages(gfp, get_order(size)); + + if (ret != NULL) { + memset(ret, 0, size); + *dma_handle = virt_to_bus(ret); + ret = (void *)KSEG0ADDR(ret); + } + return ret; +} + +static void dma_free(void *vaddr, size_t size) +{ + vaddr = (void *)KSEG0ADDR(vaddr); + free_pages((unsigned long) vaddr, get_order(size)); +} + + +static void setup_hw_rings(struct au1k_private *aup, u32 rx_base, u32 tx_base) +{ + int i; + for (i = 0; i < NUM_IR_DESC; i++) { + aup->rx_ring[i] = (volatile struct ring_dest *) + (rx_base + sizeof(struct ring_dest) * i); + } + for (i = 0; i < NUM_IR_DESC; i++) { + aup->tx_ring[i] = (volatile struct ring_dest *) + (tx_base + sizeof(struct ring_dest) * i); + } +} + +static int au1k_irda_init_iobuf(iobuff_t *io, int size) +{ + io->head = kmalloc(size, GFP_KERNEL); + if (io->head != NULL) { + io->truesize = size; + io->in_frame = FALSE; + io->state = OUTSIDE_FRAME; + io->data = io->head; + } + return io->head ? 0 : -ENOMEM; +} + +/* + * Set the IrDA communications speed. + */ +static int au1k_irda_set_speed(struct net_device *dev, int speed) +{ + struct au1k_private *aup = netdev_priv(dev); + volatile struct ring_dest *ptxd; + unsigned long control; + int ret = 0, timeout = 10, i; + + if (speed == aup->speed) + return ret; + + /* disable PHY first */ + au1k_irda_plat_set_phy_mode(aup, AU1000_IRDA_PHY_MODE_OFF); + irda_write(aup, IR_STATUS, irda_read(aup, IR_STATUS) & ~IR_PHYEN); + + /* disable RX/TX */ + irda_write(aup, IR_CONFIG_1, + irda_read(aup, IR_CONFIG_1) & ~(IR_RX_ENABLE | IR_TX_ENABLE)); + msleep(20); + while (irda_read(aup, IR_STATUS) & (IR_RX_STATUS | IR_TX_STATUS)) { + msleep(20); + if (!timeout--) { + printk(KERN_ERR "%s: rx/tx disable timeout\n", + dev->name); + break; + } + } + + /* disable DMA */ + irda_write(aup, IR_CONFIG_1, + irda_read(aup, IR_CONFIG_1) & ~IR_DMA_ENABLE); + msleep(20); + + /* After we disable tx/rx. the index pointers go back to zero. */ + aup->tx_head = aup->tx_tail = aup->rx_head = 0; + for (i = 0; i < NUM_IR_DESC; i++) { + ptxd = aup->tx_ring[i]; + ptxd->flags = 0; + ptxd->count_0 = 0; + ptxd->count_1 = 0; + } + + for (i = 0; i < NUM_IR_DESC; i++) { + ptxd = aup->rx_ring[i]; + ptxd->count_0 = 0; + ptxd->count_1 = 0; + ptxd->flags = AU_OWN; + } + + if (speed == 4000000) + au1k_irda_plat_set_phy_mode(aup, AU1000_IRDA_PHY_MODE_FIR); + else + au1k_irda_plat_set_phy_mode(aup, AU1000_IRDA_PHY_MODE_SIR); + + switch (speed) { + case 9600: + irda_write(aup, IR_WRITE_PHY_CONFIG, IR_BR(11) | IR_PW(12)); + irda_write(aup, IR_CONFIG_1, IR_SIR_MODE); + break; + case 19200: + irda_write(aup, IR_WRITE_PHY_CONFIG, IR_BR(5) | IR_PW(12)); + irda_write(aup, IR_CONFIG_1, IR_SIR_MODE); + break; + case 38400: + irda_write(aup, IR_WRITE_PHY_CONFIG, IR_BR(2) | IR_PW(12)); + irda_write(aup, IR_CONFIG_1, IR_SIR_MODE); + break; + case 57600: + irda_write(aup, IR_WRITE_PHY_CONFIG, IR_BR(1) | IR_PW(12)); + irda_write(aup, IR_CONFIG_1, IR_SIR_MODE); + break; + case 115200: + irda_write(aup, IR_WRITE_PHY_CONFIG, IR_PW(12)); + irda_write(aup, IR_CONFIG_1, IR_SIR_MODE); + break; + case 4000000: + irda_write(aup, IR_WRITE_PHY_CONFIG, IR_P(15)); + irda_write(aup, IR_CONFIG_1, IR_FIR | IR_DMA_ENABLE | + IR_RX_ENABLE); + break; + default: + printk(KERN_ERR "%s unsupported speed %x\n", dev->name, speed); + ret = -EINVAL; + break; + } + + aup->speed = speed; + irda_write(aup, IR_STATUS, irda_read(aup, IR_STATUS) | IR_PHYEN); + + control = irda_read(aup, IR_STATUS); + irda_write(aup, IR_RING_PROMPT, 0); + + if (control & (1 << 14)) { + printk(KERN_ERR "%s: configuration error\n", dev->name); + } else { + if (control & (1 << 11)) + printk(KERN_DEBUG "%s Valid SIR config\n", dev->name); + if (control & (1 << 12)) + printk(KERN_DEBUG "%s Valid MIR config\n", dev->name); + if (control & (1 << 13)) + printk(KERN_DEBUG "%s Valid FIR config\n", dev->name); + if (control & (1 << 10)) + printk(KERN_DEBUG "%s TX enabled\n", dev->name); + if (control & (1 << 9)) + printk(KERN_DEBUG "%s RX enabled\n", dev->name); + } + + return ret; +} + +static void update_rx_stats(struct net_device *dev, u32 status, u32 count) +{ + struct net_device_stats *ps = &dev->stats; + + ps->rx_packets++; + + if (status & IR_RX_ERROR) { + ps->rx_errors++; + if (status & (IR_PHY_ERROR | IR_FIFO_OVER)) + ps->rx_missed_errors++; + if (status & IR_MAX_LEN) + ps->rx_length_errors++; + if (status & IR_CRC_ERROR) + ps->rx_crc_errors++; + } else + ps->rx_bytes += count; +} + +static void update_tx_stats(struct net_device *dev, u32 status, u32 pkt_len) +{ + struct net_device_stats *ps = &dev->stats; + + ps->tx_packets++; + ps->tx_bytes += pkt_len; + + if (status & IR_TX_ERROR) { + ps->tx_errors++; + ps->tx_aborted_errors++; + } +} + +static void au1k_tx_ack(struct net_device *dev) +{ + struct au1k_private *aup = netdev_priv(dev); + volatile struct ring_dest *ptxd; + + ptxd = aup->tx_ring[aup->tx_tail]; + while (!(ptxd->flags & AU_OWN) && (aup->tx_tail != aup->tx_head)) { + update_tx_stats(dev, ptxd->flags, + (ptxd->count_1 << 8) | ptxd->count_0); + ptxd->count_0 = 0; + ptxd->count_1 = 0; + wmb(); + aup->tx_tail = (aup->tx_tail + 1) & (NUM_IR_DESC - 1); + ptxd = aup->tx_ring[aup->tx_tail]; + + if (aup->tx_full) { + aup->tx_full = 0; + netif_wake_queue(dev); + } + } + + if (aup->tx_tail == aup->tx_head) { + if (aup->newspeed) { + au1k_irda_set_speed(dev, aup->newspeed); + aup->newspeed = 0; + } else { + irda_write(aup, IR_CONFIG_1, + irda_read(aup, IR_CONFIG_1) & ~IR_TX_ENABLE); + irda_write(aup, IR_CONFIG_1, + irda_read(aup, IR_CONFIG_1) | IR_RX_ENABLE); + irda_write(aup, IR_RING_PROMPT, 0); + } + } +} + +static int au1k_irda_rx(struct net_device *dev) +{ + struct au1k_private *aup = netdev_priv(dev); + volatile struct ring_dest *prxd; + struct sk_buff *skb; + struct db_dest *pDB; + u32 flags, count; + + prxd = aup->rx_ring[aup->rx_head]; + flags = prxd->flags; + + while (!(flags & AU_OWN)) { + pDB = aup->rx_db_inuse[aup->rx_head]; + count = (prxd->count_1 << 8) | prxd->count_0; + if (!(flags & IR_RX_ERROR)) { + /* good frame */ + update_rx_stats(dev, flags, count); + skb = alloc_skb(count + 1, GFP_ATOMIC); + if (skb == NULL) { + dev->stats.rx_dropped++; + continue; + } + skb_reserve(skb, 1); + if (aup->speed == 4000000) + skb_put(skb, count); + else + skb_put(skb, count - 2); + skb_copy_to_linear_data(skb, (void *)pDB->vaddr, + count - 2); + skb->dev = dev; + skb_reset_mac_header(skb); + skb->protocol = htons(ETH_P_IRDA); + netif_rx(skb); + prxd->count_0 = 0; + prxd->count_1 = 0; + } + prxd->flags |= AU_OWN; + aup->rx_head = (aup->rx_head + 1) & (NUM_IR_DESC - 1); + irda_write(aup, IR_RING_PROMPT, 0); + + /* next descriptor */ + prxd = aup->rx_ring[aup->rx_head]; + flags = prxd->flags; + + } + return 0; +} + +static irqreturn_t au1k_irda_interrupt(int dummy, void *dev_id) +{ + struct net_device *dev = dev_id; + struct au1k_private *aup = netdev_priv(dev); + + irda_write(aup, IR_INT_CLEAR, 0); /* ack irda interrupts */ + + au1k_irda_rx(dev); + au1k_tx_ack(dev); + + return IRQ_HANDLED; +} + +static int au1k_init(struct net_device *dev) +{ + struct au1k_private *aup = netdev_priv(dev); + u32 enable, ring_address, phyck; + struct clk *c; + int i; + + c = clk_get(NULL, "irda_clk"); + if (IS_ERR(c)) + return PTR_ERR(c); + i = clk_prepare_enable(c); + if (i) { + clk_put(c); + return i; + } + + switch (clk_get_rate(c)) { + case 40000000: + phyck = IR_PHYCLK_40MHZ; + break; + case 48000000: + phyck = IR_PHYCLK_48MHZ; + break; + case 56000000: + phyck = IR_PHYCLK_56MHZ; + break; + case 64000000: + phyck = IR_PHYCLK_64MHZ; + break; + default: + clk_disable_unprepare(c); + clk_put(c); + return -EINVAL; + } + aup->irda_clk = c; + + enable = IR_HC | IR_CE | IR_C; +#ifndef CONFIG_CPU_LITTLE_ENDIAN + enable |= IR_BE; +#endif + aup->tx_head = 0; + aup->tx_tail = 0; + aup->rx_head = 0; + + for (i = 0; i < NUM_IR_DESC; i++) + aup->rx_ring[i]->flags = AU_OWN; + + irda_write(aup, IR_ENABLE, enable); + msleep(20); + + /* disable PHY */ + au1k_irda_plat_set_phy_mode(aup, AU1000_IRDA_PHY_MODE_OFF); + irda_write(aup, IR_STATUS, irda_read(aup, IR_STATUS) & ~IR_PHYEN); + msleep(20); + + irda_write(aup, IR_MAX_PKT_LEN, MAX_BUF_SIZE); + + ring_address = (u32)virt_to_phys((void *)aup->rx_ring[0]); + irda_write(aup, IR_RING_BASE_ADDR_H, ring_address >> 26); + irda_write(aup, IR_RING_BASE_ADDR_L, (ring_address >> 10) & 0xffff); + + irda_write(aup, IR_RING_SIZE, + (RING_SIZE_64 << 8) | (RING_SIZE_64 << 12)); + + irda_write(aup, IR_CONFIG_2, phyck | IR_ONE_PIN); + irda_write(aup, IR_RING_ADDR_CMPR, 0); + + au1k_irda_set_speed(dev, 9600); + return 0; +} + +static int au1k_irda_start(struct net_device *dev) +{ + struct au1k_private *aup = netdev_priv(dev); + char hwname[32]; + int retval; + + retval = au1k_init(dev); + if (retval) { + printk(KERN_ERR "%s: error in au1k_init\n", dev->name); + return retval; + } + + retval = request_irq(aup->irq_tx, &au1k_irda_interrupt, 0, + dev->name, dev); + if (retval) { + printk(KERN_ERR "%s: unable to get IRQ %d\n", + dev->name, dev->irq); + return retval; + } + retval = request_irq(aup->irq_rx, &au1k_irda_interrupt, 0, + dev->name, dev); + if (retval) { + free_irq(aup->irq_tx, dev); + printk(KERN_ERR "%s: unable to get IRQ %d\n", + dev->name, dev->irq); + return retval; + } + + /* Give self a hardware name */ + sprintf(hwname, "Au1000 SIR/FIR"); + aup->irlap = irlap_open(dev, &aup->qos, hwname); + netif_start_queue(dev); + + /* int enable */ + irda_write(aup, IR_CONFIG_2, irda_read(aup, IR_CONFIG_2) | IR_IEN); + + /* power up */ + au1k_irda_plat_set_phy_mode(aup, AU1000_IRDA_PHY_MODE_SIR); + + return 0; +} + +static int au1k_irda_stop(struct net_device *dev) +{ + struct au1k_private *aup = netdev_priv(dev); + + au1k_irda_plat_set_phy_mode(aup, AU1000_IRDA_PHY_MODE_OFF); + + /* disable interrupts */ + irda_write(aup, IR_CONFIG_2, irda_read(aup, IR_CONFIG_2) & ~IR_IEN); + irda_write(aup, IR_CONFIG_1, 0); + irda_write(aup, IR_ENABLE, 0); /* disable clock */ + + if (aup->irlap) { + irlap_close(aup->irlap); + aup->irlap = NULL; + } + + netif_stop_queue(dev); + + /* disable the interrupt */ + free_irq(aup->irq_tx, dev); + free_irq(aup->irq_rx, dev); + + clk_disable_unprepare(aup->irda_clk); + clk_put(aup->irda_clk); + + return 0; +} + +/* + * Au1000 transmit routine. + */ +static int au1k_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct au1k_private *aup = netdev_priv(dev); + int speed = irda_get_next_speed(skb); + volatile struct ring_dest *ptxd; + struct db_dest *pDB; + u32 len, flags; + + if (speed != aup->speed && speed != -1) + aup->newspeed = speed; + + if ((skb->len == 0) && (aup->newspeed)) { + if (aup->tx_tail == aup->tx_head) { + au1k_irda_set_speed(dev, speed); + aup->newspeed = 0; + } + dev_kfree_skb(skb); + return NETDEV_TX_OK; + } + + ptxd = aup->tx_ring[aup->tx_head]; + flags = ptxd->flags; + + if (flags & AU_OWN) { + printk(KERN_DEBUG "%s: tx_full\n", dev->name); + netif_stop_queue(dev); + aup->tx_full = 1; + return 1; + } else if (((aup->tx_head + 1) & (NUM_IR_DESC - 1)) == aup->tx_tail) { + printk(KERN_DEBUG "%s: tx_full\n", dev->name); + netif_stop_queue(dev); + aup->tx_full = 1; + return 1; + } + + pDB = aup->tx_db_inuse[aup->tx_head]; + +#if 0 + if (irda_read(aup, IR_RX_BYTE_CNT) != 0) { + printk(KERN_DEBUG "tx warning: rx byte cnt %x\n", + irda_read(aup, IR_RX_BYTE_CNT)); + } +#endif + + if (aup->speed == 4000000) { + /* FIR */ + skb_copy_from_linear_data(skb, (void *)pDB->vaddr, skb->len); + ptxd->count_0 = skb->len & 0xff; + ptxd->count_1 = (skb->len >> 8) & 0xff; + } else { + /* SIR */ + len = async_wrap_skb(skb, (u8 *)pDB->vaddr, MAX_BUF_SIZE); + ptxd->count_0 = len & 0xff; + ptxd->count_1 = (len >> 8) & 0xff; + ptxd->flags |= IR_DIS_CRC; + } + ptxd->flags |= AU_OWN; + wmb(); + + irda_write(aup, IR_CONFIG_1, + irda_read(aup, IR_CONFIG_1) | IR_TX_ENABLE); + irda_write(aup, IR_RING_PROMPT, 0); + + dev_kfree_skb(skb); + aup->tx_head = (aup->tx_head + 1) & (NUM_IR_DESC - 1); + return NETDEV_TX_OK; +} + +/* + * The Tx ring has been full longer than the watchdog timeout + * value. The transmitter must be hung? + */ +static void au1k_tx_timeout(struct net_device *dev) +{ + u32 speed; + struct au1k_private *aup = netdev_priv(dev); + + printk(KERN_ERR "%s: tx timeout\n", dev->name); + speed = aup->speed; + aup->speed = 0; + au1k_irda_set_speed(dev, speed); + aup->tx_full = 0; + netif_wake_queue(dev); +} + +static int au1k_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd) +{ + struct if_irda_req *rq = (struct if_irda_req *)ifreq; + struct au1k_private *aup = netdev_priv(dev); + int ret = -EOPNOTSUPP; + + switch (cmd) { + case SIOCSBANDWIDTH: + if (capable(CAP_NET_ADMIN)) { + /* + * We are unable to set the speed if the + * device is not running. + */ + if (aup->open) + ret = au1k_irda_set_speed(dev, + rq->ifr_baudrate); + else { + printk(KERN_ERR "%s ioctl: !netif_running\n", + dev->name); + ret = 0; + } + } + break; + + case SIOCSMEDIABUSY: + ret = -EPERM; + if (capable(CAP_NET_ADMIN)) { + irda_device_set_media_busy(dev, TRUE); + ret = 0; + } + break; + + case SIOCGRECEIVING: + rq->ifr_receiving = 0; + break; + default: + break; + } + return ret; +} + +static const struct net_device_ops au1k_irda_netdev_ops = { + .ndo_open = au1k_irda_start, + .ndo_stop = au1k_irda_stop, + .ndo_start_xmit = au1k_irda_hard_xmit, + .ndo_tx_timeout = au1k_tx_timeout, + .ndo_do_ioctl = au1k_irda_ioctl, +}; + +static int au1k_irda_net_init(struct net_device *dev) +{ + struct au1k_private *aup = netdev_priv(dev); + struct db_dest *pDB, *pDBfree; + int i, err, retval = 0; + dma_addr_t temp; + + err = au1k_irda_init_iobuf(&aup->rx_buff, 14384); + if (err) + goto out1; + + dev->netdev_ops = &au1k_irda_netdev_ops; + + irda_init_max_qos_capabilies(&aup->qos); + + /* The only value we must override it the baudrate */ + aup->qos.baud_rate.bits = IR_9600 | IR_19200 | IR_38400 | + IR_57600 | IR_115200 | IR_576000 | (IR_4000000 << 8); + + aup->qos.min_turn_time.bits = qos_mtt_bits; + irda_qos_bits_to_value(&aup->qos); + + retval = -ENOMEM; + + /* Tx ring follows rx ring + 512 bytes */ + /* we need a 1k aligned buffer */ + aup->rx_ring[0] = (struct ring_dest *) + dma_alloc(2 * MAX_NUM_IR_DESC * (sizeof(struct ring_dest)), + &temp); + if (!aup->rx_ring[0]) + goto out2; + + /* allocate the data buffers */ + aup->db[0].vaddr = + dma_alloc(MAX_BUF_SIZE * 2 * NUM_IR_DESC, &temp); + if (!aup->db[0].vaddr) + goto out3; + + setup_hw_rings(aup, (u32)aup->rx_ring[0], (u32)aup->rx_ring[0] + 512); + + pDBfree = NULL; + pDB = aup->db; + for (i = 0; i < (2 * NUM_IR_DESC); i++) { + pDB->pnext = pDBfree; + pDBfree = pDB; + pDB->vaddr = + (u32 *)((unsigned)aup->db[0].vaddr + (MAX_BUF_SIZE * i)); + pDB->dma_addr = (dma_addr_t)virt_to_bus(pDB->vaddr); + pDB++; + } + aup->pDBfree = pDBfree; + + /* attach a data buffer to each descriptor */ + for (i = 0; i < NUM_IR_DESC; i++) { + pDB = GetFreeDB(aup); + if (!pDB) + goto out3; + aup->rx_ring[i]->addr_0 = (u8)(pDB->dma_addr & 0xff); + aup->rx_ring[i]->addr_1 = (u8)((pDB->dma_addr >> 8) & 0xff); + aup->rx_ring[i]->addr_2 = (u8)((pDB->dma_addr >> 16) & 0xff); + aup->rx_ring[i]->addr_3 = (u8)((pDB->dma_addr >> 24) & 0xff); + aup->rx_db_inuse[i] = pDB; + } + for (i = 0; i < NUM_IR_DESC; i++) { + pDB = GetFreeDB(aup); + if (!pDB) + goto out3; + aup->tx_ring[i]->addr_0 = (u8)(pDB->dma_addr & 0xff); + aup->tx_ring[i]->addr_1 = (u8)((pDB->dma_addr >> 8) & 0xff); + aup->tx_ring[i]->addr_2 = (u8)((pDB->dma_addr >> 16) & 0xff); + aup->tx_ring[i]->addr_3 = (u8)((pDB->dma_addr >> 24) & 0xff); + aup->tx_ring[i]->count_0 = 0; + aup->tx_ring[i]->count_1 = 0; + aup->tx_ring[i]->flags = 0; + aup->tx_db_inuse[i] = pDB; + } + + return 0; + +out3: + dma_free((void *)aup->rx_ring[0], + 2 * MAX_NUM_IR_DESC * (sizeof(struct ring_dest))); +out2: + kfree(aup->rx_buff.head); +out1: + printk(KERN_ERR "au1k_irda_net_init() failed. Returns %d\n", retval); + return retval; +} + +static int au1k_irda_probe(struct platform_device *pdev) +{ + struct au1k_private *aup; + struct net_device *dev; + struct resource *r; + struct clk *c; + int err; + + dev = alloc_irdadev(sizeof(struct au1k_private)); + if (!dev) + return -ENOMEM; + + aup = netdev_priv(dev); + + aup->platdata = pdev->dev.platform_data; + + err = -EINVAL; + r = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!r) + goto out; + + aup->irq_tx = r->start; + + r = platform_get_resource(pdev, IORESOURCE_IRQ, 1); + if (!r) + goto out; + + aup->irq_rx = r->start; + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!r) + goto out; + + err = -EBUSY; + aup->ioarea = request_mem_region(r->start, resource_size(r), + pdev->name); + if (!aup->ioarea) + goto out; + + /* bail out early if clock doesn't exist */ + c = clk_get(NULL, "irda_clk"); + if (IS_ERR(c)) { + err = PTR_ERR(c); + goto out; + } + clk_put(c); + + aup->iobase = ioremap_nocache(r->start, resource_size(r)); + if (!aup->iobase) + goto out2; + + dev->irq = aup->irq_rx; + + err = au1k_irda_net_init(dev); + if (err) + goto out3; + err = register_netdev(dev); + if (err) + goto out4; + + platform_set_drvdata(pdev, dev); + + printk(KERN_INFO "IrDA: Registered device %s\n", dev->name); + return 0; + +out4: + dma_free((void *)aup->db[0].vaddr, + MAX_BUF_SIZE * 2 * NUM_IR_DESC); + dma_free((void *)aup->rx_ring[0], + 2 * MAX_NUM_IR_DESC * (sizeof(struct ring_dest))); + kfree(aup->rx_buff.head); +out3: + iounmap(aup->iobase); +out2: + release_resource(aup->ioarea); + kfree(aup->ioarea); +out: + free_netdev(dev); + return err; +} + +static int au1k_irda_remove(struct platform_device *pdev) +{ + struct net_device *dev = platform_get_drvdata(pdev); + struct au1k_private *aup = netdev_priv(dev); + + unregister_netdev(dev); + + dma_free((void *)aup->db[0].vaddr, + MAX_BUF_SIZE * 2 * NUM_IR_DESC); + dma_free((void *)aup->rx_ring[0], + 2 * MAX_NUM_IR_DESC * (sizeof(struct ring_dest))); + kfree(aup->rx_buff.head); + + iounmap(aup->iobase); + release_resource(aup->ioarea); + kfree(aup->ioarea); + + free_netdev(dev); + + return 0; +} + +static struct platform_driver au1k_irda_driver = { + .driver = { + .name = "au1000-irda", + }, + .probe = au1k_irda_probe, + .remove = au1k_irda_remove, +}; + +module_platform_driver(au1k_irda_driver); + +MODULE_AUTHOR("Pete Popov <ppopov@mvista.com>"); +MODULE_DESCRIPTION("Au1000 IrDA Device Driver"); diff --git a/drivers/staging/irda/drivers/bfin_sir.c b/drivers/staging/irda/drivers/bfin_sir.c new file mode 100644 index 000000000000..3151b580dbd6 --- /dev/null +++ b/drivers/staging/irda/drivers/bfin_sir.c @@ -0,0 +1,817 @@ +/* + * Blackfin Infra-red Driver + * + * Copyright 2006-2009 Analog Devices Inc. + * + * Enter bugs at http://blackfin.uclinux.org/ + * + * Licensed under the GPL-2 or later. + * + */ +#include "bfin_sir.h" + +#ifdef CONFIG_SIR_BFIN_DMA +#define DMA_SIR_RX_XCNT 10 +#define DMA_SIR_RX_YCNT (PAGE_SIZE / DMA_SIR_RX_XCNT) +#define DMA_SIR_RX_FLUSH_JIFS (HZ * 4 / 250) +#endif + +#if ANOMALY_05000447 +static int max_rate = 57600; +#else +static int max_rate = 115200; +#endif + +static void turnaround_delay(int mtt) +{ + long ticks; + + mtt = mtt < 10000 ? 10000 : mtt; + ticks = 1 + mtt / (USEC_PER_SEC / HZ); + schedule_timeout_uninterruptible(ticks); +} + +static void bfin_sir_init_ports(struct bfin_sir_port *sp, struct platform_device *pdev) +{ + int i; + struct resource *res; + + for (i = 0; i < pdev->num_resources; i++) { + res = &pdev->resource[i]; + switch (res->flags) { + case IORESOURCE_MEM: + sp->membase = (void __iomem *)res->start; + break; + case IORESOURCE_IRQ: + sp->irq = res->start; + break; + case IORESOURCE_DMA: + sp->rx_dma_channel = res->start; + sp->tx_dma_channel = res->end; + break; + default: + break; + } + } + + sp->clk = get_sclk(); +#ifdef CONFIG_SIR_BFIN_DMA + sp->tx_done = 1; + init_timer(&(sp->rx_dma_timer)); +#endif +} + +static void bfin_sir_stop_tx(struct bfin_sir_port *port) +{ +#ifdef CONFIG_SIR_BFIN_DMA + disable_dma(port->tx_dma_channel); +#endif + + while (!(UART_GET_LSR(port) & THRE)) { + cpu_relax(); + continue; + } + + UART_CLEAR_IER(port, ETBEI); +} + +static void bfin_sir_enable_tx(struct bfin_sir_port *port) +{ + UART_SET_IER(port, ETBEI); +} + +static void bfin_sir_stop_rx(struct bfin_sir_port *port) +{ + UART_CLEAR_IER(port, ERBFI); +} + +static void bfin_sir_enable_rx(struct bfin_sir_port *port) +{ + UART_SET_IER(port, ERBFI); +} + +static int bfin_sir_set_speed(struct bfin_sir_port *port, int speed) +{ + int ret = -EINVAL; + unsigned int quot; + unsigned short val, lsr, lcr; + static int utime; + int count = 10; + + lcr = WLS(8); + + switch (speed) { + case 9600: + case 19200: + case 38400: + case 57600: + case 115200: + + /* + * IRDA is not affected by anomaly 05000230, so there is no + * need to tweak the divisor like he UART driver (which will + * slightly speed up the baud rate on us). + */ + quot = (port->clk + (8 * speed)) / (16 * speed); + + do { + udelay(utime); + lsr = UART_GET_LSR(port); + } while (!(lsr & TEMT) && count--); + + /* The useconds for 1 bits to transmit */ + utime = 1000000 / speed + 1; + + /* Clear UCEN bit to reset the UART state machine + * and control registers + */ + val = UART_GET_GCTL(port); + val &= ~UCEN; + UART_PUT_GCTL(port, val); + + /* Set DLAB in LCR to Access THR RBR IER */ + UART_SET_DLAB(port); + SSYNC(); + + UART_PUT_DLL(port, quot & 0xFF); + UART_PUT_DLH(port, (quot >> 8) & 0xFF); + SSYNC(); + + /* Clear DLAB in LCR */ + UART_CLEAR_DLAB(port); + SSYNC(); + + UART_PUT_LCR(port, lcr); + + val = UART_GET_GCTL(port); + val |= UCEN; + UART_PUT_GCTL(port, val); + + ret = 0; + break; + default: + printk(KERN_WARNING "bfin_sir: Invalid speed %d\n", speed); + break; + } + + val = UART_GET_GCTL(port); + /* If not add the 'RPOLC', we can't catch the receive interrupt. + * It's related with the HW layout and the IR transiver. + */ + val |= UMOD_IRDA | RPOLC; + UART_PUT_GCTL(port, val); + return ret; +} + +static int bfin_sir_is_receiving(struct net_device *dev) +{ + struct bfin_sir_self *self = netdev_priv(dev); + struct bfin_sir_port *port = self->sir_port; + + if (!(UART_GET_IER(port) & ERBFI)) + return 0; + return self->rx_buff.state != OUTSIDE_FRAME; +} + +#ifdef CONFIG_SIR_BFIN_PIO +static void bfin_sir_tx_chars(struct net_device *dev) +{ + unsigned int chr; + struct bfin_sir_self *self = netdev_priv(dev); + struct bfin_sir_port *port = self->sir_port; + + if (self->tx_buff.len != 0) { + chr = *(self->tx_buff.data); + UART_PUT_CHAR(port, chr); + self->tx_buff.data++; + self->tx_buff.len--; + } else { + self->stats.tx_packets++; + self->stats.tx_bytes += self->tx_buff.data - self->tx_buff.head; + if (self->newspeed) { + bfin_sir_set_speed(port, self->newspeed); + self->speed = self->newspeed; + self->newspeed = 0; + } + bfin_sir_stop_tx(port); + bfin_sir_enable_rx(port); + /* I'm hungry! */ + netif_wake_queue(dev); + } +} + +static void bfin_sir_rx_chars(struct net_device *dev) +{ + struct bfin_sir_self *self = netdev_priv(dev); + struct bfin_sir_port *port = self->sir_port; + unsigned char ch; + + UART_CLEAR_LSR(port); + ch = UART_GET_CHAR(port); + async_unwrap_char(dev, &self->stats, &self->rx_buff, ch); +} + +static irqreturn_t bfin_sir_rx_int(int irq, void *dev_id) +{ + struct net_device *dev = dev_id; + struct bfin_sir_self *self = netdev_priv(dev); + struct bfin_sir_port *port = self->sir_port; + + spin_lock(&self->lock); + while ((UART_GET_LSR(port) & DR)) + bfin_sir_rx_chars(dev); + spin_unlock(&self->lock); + + return IRQ_HANDLED; +} + +static irqreturn_t bfin_sir_tx_int(int irq, void *dev_id) +{ + struct net_device *dev = dev_id; + struct bfin_sir_self *self = netdev_priv(dev); + struct bfin_sir_port *port = self->sir_port; + + spin_lock(&self->lock); + if (UART_GET_LSR(port) & THRE) + bfin_sir_tx_chars(dev); + spin_unlock(&self->lock); + + return IRQ_HANDLED; +} +#endif /* CONFIG_SIR_BFIN_PIO */ + +#ifdef CONFIG_SIR_BFIN_DMA +static void bfin_sir_dma_tx_chars(struct net_device *dev) +{ + struct bfin_sir_self *self = netdev_priv(dev); + struct bfin_sir_port *port = self->sir_port; + + if (!port->tx_done) + return; + port->tx_done = 0; + + if (self->tx_buff.len == 0) { + self->stats.tx_packets++; + if (self->newspeed) { + bfin_sir_set_speed(port, self->newspeed); + self->speed = self->newspeed; + self->newspeed = 0; + } + bfin_sir_enable_rx(port); + port->tx_done = 1; + netif_wake_queue(dev); + return; + } + + blackfin_dcache_flush_range((unsigned long)(self->tx_buff.data), + (unsigned long)(self->tx_buff.data+self->tx_buff.len)); + set_dma_config(port->tx_dma_channel, + set_bfin_dma_config(DIR_READ, DMA_FLOW_STOP, + INTR_ON_BUF, DIMENSION_LINEAR, DATA_SIZE_8, + DMA_SYNC_RESTART)); + set_dma_start_addr(port->tx_dma_channel, + (unsigned long)(self->tx_buff.data)); + set_dma_x_count(port->tx_dma_channel, self->tx_buff.len); + set_dma_x_modify(port->tx_dma_channel, 1); + enable_dma(port->tx_dma_channel); +} + +static irqreturn_t bfin_sir_dma_tx_int(int irq, void *dev_id) +{ + struct net_device *dev = dev_id; + struct bfin_sir_self *self = netdev_priv(dev); + struct bfin_sir_port *port = self->sir_port; + + spin_lock(&self->lock); + if (!(get_dma_curr_irqstat(port->tx_dma_channel) & DMA_RUN)) { + clear_dma_irqstat(port->tx_dma_channel); + bfin_sir_stop_tx(port); + + self->stats.tx_packets++; + self->stats.tx_bytes += self->tx_buff.len; + self->tx_buff.len = 0; + if (self->newspeed) { + bfin_sir_set_speed(port, self->newspeed); + self->speed = self->newspeed; + self->newspeed = 0; + } + bfin_sir_enable_rx(port); + /* I'm hungry! */ + netif_wake_queue(dev); + port->tx_done = 1; + } + spin_unlock(&self->lock); + + return IRQ_HANDLED; +} + +static void bfin_sir_dma_rx_chars(struct net_device *dev) +{ + struct bfin_sir_self *self = netdev_priv(dev); + struct bfin_sir_port *port = self->sir_port; + int i; + + UART_CLEAR_LSR(port); + + for (i = port->rx_dma_buf.head; i < port->rx_dma_buf.tail; i++) + async_unwrap_char(dev, &self->stats, &self->rx_buff, port->rx_dma_buf.buf[i]); +} + +void bfin_sir_rx_dma_timeout(struct net_device *dev) +{ + struct bfin_sir_self *self = netdev_priv(dev); + struct bfin_sir_port *port = self->sir_port; + int x_pos, pos; + unsigned long flags; + + spin_lock_irqsave(&self->lock, flags); + x_pos = DMA_SIR_RX_XCNT - get_dma_curr_xcount(port->rx_dma_channel); + if (x_pos == DMA_SIR_RX_XCNT) + x_pos = 0; + + pos = port->rx_dma_nrows * DMA_SIR_RX_XCNT + x_pos; + + if (pos > port->rx_dma_buf.tail) { + port->rx_dma_buf.tail = pos; + bfin_sir_dma_rx_chars(dev); + port->rx_dma_buf.head = port->rx_dma_buf.tail; + } + spin_unlock_irqrestore(&self->lock, flags); +} + +static irqreturn_t bfin_sir_dma_rx_int(int irq, void *dev_id) +{ + struct net_device *dev = dev_id; + struct bfin_sir_self *self = netdev_priv(dev); + struct bfin_sir_port *port = self->sir_port; + unsigned short irqstat; + + spin_lock(&self->lock); + + port->rx_dma_nrows++; + port->rx_dma_buf.tail = DMA_SIR_RX_XCNT * port->rx_dma_nrows; + bfin_sir_dma_rx_chars(dev); + if (port->rx_dma_nrows >= DMA_SIR_RX_YCNT) { + port->rx_dma_nrows = 0; + port->rx_dma_buf.tail = 0; + } + port->rx_dma_buf.head = port->rx_dma_buf.tail; + + irqstat = get_dma_curr_irqstat(port->rx_dma_channel); + clear_dma_irqstat(port->rx_dma_channel); + spin_unlock(&self->lock); + + mod_timer(&port->rx_dma_timer, jiffies + DMA_SIR_RX_FLUSH_JIFS); + return IRQ_HANDLED; +} +#endif /* CONFIG_SIR_BFIN_DMA */ + +static int bfin_sir_startup(struct bfin_sir_port *port, struct net_device *dev) +{ +#ifdef CONFIG_SIR_BFIN_DMA + dma_addr_t dma_handle; +#endif /* CONFIG_SIR_BFIN_DMA */ + + if (request_dma(port->rx_dma_channel, "BFIN_UART_RX") < 0) { + dev_warn(&dev->dev, "Unable to attach SIR RX DMA channel\n"); + return -EBUSY; + } + + if (request_dma(port->tx_dma_channel, "BFIN_UART_TX") < 0) { + dev_warn(&dev->dev, "Unable to attach SIR TX DMA channel\n"); + free_dma(port->rx_dma_channel); + return -EBUSY; + } + +#ifdef CONFIG_SIR_BFIN_DMA + + set_dma_callback(port->rx_dma_channel, bfin_sir_dma_rx_int, dev); + set_dma_callback(port->tx_dma_channel, bfin_sir_dma_tx_int, dev); + + port->rx_dma_buf.buf = dma_alloc_coherent(NULL, PAGE_SIZE, + &dma_handle, GFP_DMA); + port->rx_dma_buf.head = 0; + port->rx_dma_buf.tail = 0; + port->rx_dma_nrows = 0; + + set_dma_config(port->rx_dma_channel, + set_bfin_dma_config(DIR_WRITE, DMA_FLOW_AUTO, + INTR_ON_ROW, DIMENSION_2D, + DATA_SIZE_8, DMA_SYNC_RESTART)); + set_dma_x_count(port->rx_dma_channel, DMA_SIR_RX_XCNT); + set_dma_x_modify(port->rx_dma_channel, 1); + set_dma_y_count(port->rx_dma_channel, DMA_SIR_RX_YCNT); + set_dma_y_modify(port->rx_dma_channel, 1); + set_dma_start_addr(port->rx_dma_channel, (unsigned long)port->rx_dma_buf.buf); + enable_dma(port->rx_dma_channel); + + port->rx_dma_timer.data = (unsigned long)(dev); + port->rx_dma_timer.function = (void *)bfin_sir_rx_dma_timeout; + +#else + + if (request_irq(port->irq, bfin_sir_rx_int, 0, "BFIN_SIR_RX", dev)) { + dev_warn(&dev->dev, "Unable to attach SIR RX interrupt\n"); + return -EBUSY; + } + + if (request_irq(port->irq+1, bfin_sir_tx_int, 0, "BFIN_SIR_TX", dev)) { + dev_warn(&dev->dev, "Unable to attach SIR TX interrupt\n"); + free_irq(port->irq, dev); + return -EBUSY; + } +#endif + + return 0; +} + +static void bfin_sir_shutdown(struct bfin_sir_port *port, struct net_device *dev) +{ + unsigned short val; + + bfin_sir_stop_rx(port); + + val = UART_GET_GCTL(port); + val &= ~(UCEN | UMOD_MASK | RPOLC); + UART_PUT_GCTL(port, val); + +#ifdef CONFIG_SIR_BFIN_DMA + disable_dma(port->tx_dma_channel); + disable_dma(port->rx_dma_channel); + del_timer(&(port->rx_dma_timer)); + dma_free_coherent(NULL, PAGE_SIZE, port->rx_dma_buf.buf, 0); +#else + free_irq(port->irq+1, dev); + free_irq(port->irq, dev); +#endif + free_dma(port->tx_dma_channel); + free_dma(port->rx_dma_channel); +} + +#ifdef CONFIG_PM +static int bfin_sir_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct bfin_sir_port *sir_port; + struct net_device *dev; + struct bfin_sir_self *self; + + sir_port = platform_get_drvdata(pdev); + if (!sir_port) + return 0; + + dev = sir_port->dev; + self = netdev_priv(dev); + if (self->open) { + flush_work(&self->work); + bfin_sir_shutdown(self->sir_port, dev); + netif_device_detach(dev); + } + + return 0; +} +static int bfin_sir_resume(struct platform_device *pdev) +{ + struct bfin_sir_port *sir_port; + struct net_device *dev; + struct bfin_sir_self *self; + struct bfin_sir_port *port; + + sir_port = platform_get_drvdata(pdev); + if (!sir_port) + return 0; + + dev = sir_port->dev; + self = netdev_priv(dev); + port = self->sir_port; + if (self->open) { + if (self->newspeed) { + self->speed = self->newspeed; + self->newspeed = 0; + } + bfin_sir_startup(port, dev); + bfin_sir_set_speed(port, 9600); + bfin_sir_enable_rx(port); + netif_device_attach(dev); + } + return 0; +} +#else +#define bfin_sir_suspend NULL +#define bfin_sir_resume NULL +#endif + +static void bfin_sir_send_work(struct work_struct *work) +{ + struct bfin_sir_self *self = container_of(work, struct bfin_sir_self, work); + struct net_device *dev = self->sir_port->dev; + struct bfin_sir_port *port = self->sir_port; + unsigned short val; + int tx_cnt = 10; + + while (bfin_sir_is_receiving(dev) && --tx_cnt) + turnaround_delay(self->mtt); + + bfin_sir_stop_rx(port); + + /* To avoid losting RX interrupt, we reset IR function before + * sending data. We also can set the speed, which will + * reset all the UART. + */ + val = UART_GET_GCTL(port); + val &= ~(UMOD_MASK | RPOLC); + UART_PUT_GCTL(port, val); + SSYNC(); + val |= UMOD_IRDA | RPOLC; + UART_PUT_GCTL(port, val); + SSYNC(); + /* bfin_sir_set_speed(port, self->speed); */ + +#ifdef CONFIG_SIR_BFIN_DMA + bfin_sir_dma_tx_chars(dev); +#endif + bfin_sir_enable_tx(port); + netif_trans_update(dev); +} + +static int bfin_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct bfin_sir_self *self = netdev_priv(dev); + int speed = irda_get_next_speed(skb); + + netif_stop_queue(dev); + + self->mtt = irda_get_mtt(skb); + + if (speed != self->speed && speed != -1) + self->newspeed = speed; + + self->tx_buff.data = self->tx_buff.head; + if (skb->len == 0) + self->tx_buff.len = 0; + else + self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data, self->tx_buff.truesize); + + schedule_work(&self->work); + dev_kfree_skb(skb); + + return 0; +} + +static int bfin_sir_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd) +{ + struct if_irda_req *rq = (struct if_irda_req *)ifreq; + struct bfin_sir_self *self = netdev_priv(dev); + struct bfin_sir_port *port = self->sir_port; + int ret = 0; + + switch (cmd) { + case SIOCSBANDWIDTH: + if (capable(CAP_NET_ADMIN)) { + if (self->open) { + ret = bfin_sir_set_speed(port, rq->ifr_baudrate); + bfin_sir_enable_rx(port); + } else { + dev_warn(&dev->dev, "SIOCSBANDWIDTH: !netif_running\n"); + ret = 0; + } + } + break; + + case SIOCSMEDIABUSY: + ret = -EPERM; + if (capable(CAP_NET_ADMIN)) { + irda_device_set_media_busy(dev, TRUE); + ret = 0; + } + break; + + case SIOCGRECEIVING: + rq->ifr_receiving = bfin_sir_is_receiving(dev); + break; + + default: + ret = -EOPNOTSUPP; + break; + } + + return ret; +} + +static struct net_device_stats *bfin_sir_stats(struct net_device *dev) +{ + struct bfin_sir_self *self = netdev_priv(dev); + + return &self->stats; +} + +static int bfin_sir_open(struct net_device *dev) +{ + struct bfin_sir_self *self = netdev_priv(dev); + struct bfin_sir_port *port = self->sir_port; + int err; + + self->newspeed = 0; + self->speed = 9600; + + spin_lock_init(&self->lock); + + err = bfin_sir_startup(port, dev); + if (err) + goto err_startup; + + bfin_sir_set_speed(port, 9600); + + self->irlap = irlap_open(dev, &self->qos, DRIVER_NAME); + if (!self->irlap) { + err = -ENOMEM; + goto err_irlap; + } + + INIT_WORK(&self->work, bfin_sir_send_work); + + /* + * Now enable the interrupt then start the queue + */ + self->open = 1; + bfin_sir_enable_rx(port); + + netif_start_queue(dev); + + return 0; + +err_irlap: + self->open = 0; + bfin_sir_shutdown(port, dev); +err_startup: + return err; +} + +static int bfin_sir_stop(struct net_device *dev) +{ + struct bfin_sir_self *self = netdev_priv(dev); + + flush_work(&self->work); + bfin_sir_shutdown(self->sir_port, dev); + + if (self->rxskb) { + dev_kfree_skb(self->rxskb); + self->rxskb = NULL; + } + + /* Stop IrLAP */ + if (self->irlap) { + irlap_close(self->irlap); + self->irlap = NULL; + } + + netif_stop_queue(dev); + self->open = 0; + + return 0; +} + +static int bfin_sir_init_iobuf(iobuff_t *io, int size) +{ + io->head = kmalloc(size, GFP_KERNEL); + if (!io->head) + return -ENOMEM; + io->truesize = size; + io->in_frame = FALSE; + io->state = OUTSIDE_FRAME; + io->data = io->head; + return 0; +} + +static const struct net_device_ops bfin_sir_ndo = { + .ndo_open = bfin_sir_open, + .ndo_stop = bfin_sir_stop, + .ndo_start_xmit = bfin_sir_hard_xmit, + .ndo_do_ioctl = bfin_sir_ioctl, + .ndo_get_stats = bfin_sir_stats, +}; + +static int bfin_sir_probe(struct platform_device *pdev) +{ + struct net_device *dev; + struct bfin_sir_self *self; + unsigned int baudrate_mask; + struct bfin_sir_port *sir_port; + int err; + + if (pdev->id >= 0 && pdev->id < ARRAY_SIZE(per) && \ + per[pdev->id][3] == pdev->id) { + err = peripheral_request_list(per[pdev->id], DRIVER_NAME); + if (err) + return err; + } else { + dev_err(&pdev->dev, "Invalid pdev id, please check board file\n"); + return -ENODEV; + } + + err = -ENOMEM; + sir_port = kmalloc(sizeof(*sir_port), GFP_KERNEL); + if (!sir_port) + goto err_mem_0; + + bfin_sir_init_ports(sir_port, pdev); + + dev = alloc_irdadev(sizeof(*self)); + if (!dev) + goto err_mem_1; + + self = netdev_priv(dev); + self->dev = &pdev->dev; + self->sir_port = sir_port; + sir_port->dev = dev; + + err = bfin_sir_init_iobuf(&self->rx_buff, IRDA_SKB_MAX_MTU); + if (err) + goto err_mem_2; + err = bfin_sir_init_iobuf(&self->tx_buff, IRDA_SIR_MAX_FRAME); + if (err) + goto err_mem_3; + + dev->netdev_ops = &bfin_sir_ndo; + dev->irq = sir_port->irq; + + irda_init_max_qos_capabilies(&self->qos); + + baudrate_mask = IR_9600; + + switch (max_rate) { + case 115200: + baudrate_mask |= IR_115200; + case 57600: + baudrate_mask |= IR_57600; + case 38400: + baudrate_mask |= IR_38400; + case 19200: + baudrate_mask |= IR_19200; + case 9600: + break; + default: + dev_warn(&pdev->dev, "Invalid maximum baud rate, using 9600\n"); + } + + self->qos.baud_rate.bits &= baudrate_mask; + + self->qos.min_turn_time.bits = 1; /* 10 ms or more */ + + irda_qos_bits_to_value(&self->qos); + + err = register_netdev(dev); + + if (err) { + kfree(self->tx_buff.head); +err_mem_3: + kfree(self->rx_buff.head); +err_mem_2: + free_netdev(dev); +err_mem_1: + kfree(sir_port); +err_mem_0: + peripheral_free_list(per[pdev->id]); + } else + platform_set_drvdata(pdev, sir_port); + + return err; +} + +static int bfin_sir_remove(struct platform_device *pdev) +{ + struct bfin_sir_port *sir_port; + struct net_device *dev = NULL; + struct bfin_sir_self *self; + + sir_port = platform_get_drvdata(pdev); + if (!sir_port) + return 0; + dev = sir_port->dev; + self = netdev_priv(dev); + unregister_netdev(dev); + kfree(self->tx_buff.head); + kfree(self->rx_buff.head); + free_netdev(dev); + kfree(sir_port); + + return 0; +} + +static struct platform_driver bfin_ir_driver = { + .probe = bfin_sir_probe, + .remove = bfin_sir_remove, + .suspend = bfin_sir_suspend, + .resume = bfin_sir_resume, + .driver = { + .name = DRIVER_NAME, + }, +}; + +module_platform_driver(bfin_ir_driver); + +module_param(max_rate, int, 0); +MODULE_PARM_DESC(max_rate, "Maximum baud rate (115200, 57600, 38400, 19200, 9600)"); + +MODULE_AUTHOR("Graf Yang <graf.yang@analog.com>"); +MODULE_DESCRIPTION("Blackfin IrDA driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/irda/drivers/bfin_sir.h b/drivers/staging/irda/drivers/bfin_sir.h new file mode 100644 index 000000000000..d47cf14bb4a5 --- /dev/null +++ b/drivers/staging/irda/drivers/bfin_sir.h @@ -0,0 +1,93 @@ +/* + * Blackfin Infra-red Driver + * + * Copyright 2006-2009 Analog Devices Inc. + * + * Enter bugs at http://blackfin.uclinux.org/ + * + * Licensed under the GPL-2 or later. + * + */ + +#include <linux/serial.h> +#include <linux/module.h> +#include <linux/netdevice.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/dma-mapping.h> +#include <linux/slab.h> + +#include <net/irda/irda.h> +#include <net/irda/wrapper.h> +#include <net/irda/irda_device.h> + +#include <asm/irq.h> +#include <asm/cacheflush.h> +#include <asm/dma.h> +#include <asm/portmux.h> +#undef DRIVER_NAME + +#ifdef CONFIG_SIR_BFIN_DMA +struct dma_rx_buf { + char *buf; + int head; + int tail; +}; +#endif + +struct bfin_sir_port { + unsigned char __iomem *membase; + unsigned int irq; + unsigned int lsr; + unsigned long clk; + struct net_device *dev; +#ifdef CONFIG_SIR_BFIN_DMA + int tx_done; + struct dma_rx_buf rx_dma_buf; + struct timer_list rx_dma_timer; + int rx_dma_nrows; +#endif + unsigned int tx_dma_channel; + unsigned int rx_dma_channel; +}; + +struct bfin_sir_port_res { + unsigned long base_addr; + int irq; + unsigned int rx_dma_channel; + unsigned int tx_dma_channel; +}; + +struct bfin_sir_self { + struct bfin_sir_port *sir_port; + spinlock_t lock; + unsigned int open; + int speed; + int newspeed; + + struct sk_buff *txskb; + struct sk_buff *rxskb; + struct net_device_stats stats; + struct device *dev; + struct irlap_cb *irlap; + struct qos_info qos; + + iobuff_t tx_buff; + iobuff_t rx_buff; + + struct work_struct work; + int mtt; +}; + +#define DRIVER_NAME "bfin_sir" + +#include <asm/bfin_serial.h> + +static const unsigned short per[][4] = { + /* rx pin tx pin NULL uart_number */ + {P_UART0_RX, P_UART0_TX, 0, 0}, + {P_UART1_RX, P_UART1_TX, 0, 1}, + {P_UART2_RX, P_UART2_TX, 0, 2}, + {P_UART3_RX, P_UART3_TX, 0, 3}, +}; diff --git a/drivers/staging/irda/drivers/donauboe.c b/drivers/staging/irda/drivers/donauboe.c new file mode 100644 index 000000000000..b337e6d23a88 --- /dev/null +++ b/drivers/staging/irda/drivers/donauboe.c @@ -0,0 +1,1732 @@ +/***************************************************************** + * + * Filename: donauboe.c + * Version: 2.17 + * Description: Driver for the Toshiba OBOE (or type-O or 701) + * FIR Chipset, also supports the DONAUOBOE (type-DO + * or d01) FIR chipset which as far as I know is + * register compatible. + * Documentation: http://libxg.free.fr/irda/lib-irda.html + * Status: Experimental. + * Author: James McKenzie <james@fishsoup.dhs.org> + * Created at: Sat May 8 12:35:27 1999 + * Modified: Paul Bristow <paul.bristow@technologist.com> + * Modified: Mon Nov 11 19:10:05 1999 + * Modified: James McKenzie <james@fishsoup.dhs.org> + * Modified: Thu Mar 16 12:49:00 2000 (Substantial rewrite) + * Modified: Sat Apr 29 00:23:03 2000 (Added DONAUOBOE support) + * Modified: Wed May 24 23:45:02 2000 (Fixed chipio_t structure) + * Modified: 2.13 Christian Gennerat <christian.gennerat@polytechnique.org> + * Modified: 2.13 dim jan 07 21:57:39 2001 (tested with kernel 2.4 & irnet/ppp) + * Modified: 2.14 Christian Gennerat <christian.gennerat@polytechnique.org> + * Modified: 2.14 lun fev 05 17:55:59 2001 (adapted to patch-2.4.1-pre8-irda1) + * Modified: 2.15 Martin Lucina <mato@kotelna.sk> + * Modified: 2.15 Fri Jun 21 20:40:59 2002 (sync with 2.4.18, substantial fixes) + * Modified: 2.16 Martin Lucina <mato@kotelna.sk> + * Modified: 2.16 Sat Jun 22 18:54:29 2002 (fix freeregion, default to verbose) + * Modified: 2.17 Christian Gennerat <christian.gennerat@polytechnique.org> + * Modified: 2.17 jeu sep 12 08:50:20 2002 (save_flags();cli(); replaced by spinlocks) + * Modified: 2.18 Christian Gennerat <christian.gennerat@polytechnique.org> + * Modified: 2.18 ven jan 10 03:14:16 2003 Change probe default options + * + * Copyright (c) 1999 James McKenzie, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither James McKenzie nor Cambridge University admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + * Applicable Models : Libretto 100/110CT and many more. + * Toshiba refers to this chip as the type-O IR port, + * or the type-DO IR port. + * + ********************************************************************/ + +/* Look at toshoboe.h (currently in include/net/irda) for details of */ +/* Where to get documentation on the chip */ + +/* See below for a description of the logic in this driver */ + +/* User servicable parts */ +/* USE_PROBE Create the code which probes the chip and does a few tests */ +/* do_probe module parameter Enable this code */ +/* Probe code is very useful for understanding how the hardware works */ +/* Use it with various combinations of TT_LEN, RX_LEN */ +/* Strongly recommended, disable if the probe fails on your machine */ +/* and send me <james@fishsoup.dhs.org> the output of dmesg */ +#define USE_PROBE 1 +#undef USE_PROBE + +/* Trace Transmit ring, interrupts, Receive ring or not ? */ +#define PROBE_VERBOSE 1 + +/* Debug option, examine sent and received raw data */ +/* Irdadump is better, but does not see all packets. enable it if you want. */ +#undef DUMP_PACKETS + +/* MIR mode has not been tested. Some behaviour is different */ +/* Seems to work against an Ericsson R520 for me. -Martin */ +#define USE_MIR + +/* Schedule back to back hardware transmits wherever possible, otherwise */ +/* we need an interrupt for every frame, unset if oboe works for a bit and */ +/* then hangs */ +#define OPTIMIZE_TX + +/* Set the number of slots in the rings */ +/* If you get rx/tx fifo overflows at high bitrates, you can try increasing */ +/* these */ + +#define RING_SIZE (OBOE_RING_SIZE_RX8 | OBOE_RING_SIZE_TX8) +#define TX_SLOTS 8 +#define RX_SLOTS 8 + + +/* Less user servicable parts below here */ + +/* Test, Transmit and receive buffer sizes, adjust at your peril */ +/* remarks: nfs usually needs 1k blocks */ +/* remarks: in SIR mode, CRC is received, -> RX_LEN=TX_LEN+2 */ +/* remarks: test accepts large blocks. Standard is 0x80 */ +/* When TT_LEN > RX_LEN (SIR mode) data is stored in successive slots. */ +/* When 3 or more slots are needed for each test packet, */ +/* data received in the first slots is overwritten, even */ +/* if OBOE_CTL_RX_HW_OWNS is not set, without any error! */ +#define TT_LEN 0x80 +#define TX_LEN 0xc00 +#define RX_LEN 0xc04 +/* Real transmitted length (SIR mode) is about 14+(2%*TX_LEN) more */ +/* long than user-defined length (see async_wrap_skb) and is less then 4K */ +/* Real received length is (max RX_LEN) differs from user-defined */ +/* length only b the CRC (2 or 4 bytes) */ +#define BUF_SAFETY 0x7a +#define RX_BUF_SZ (RX_LEN) +#define TX_BUF_SZ (TX_LEN+BUF_SAFETY) + + +/* Logic of the netdev part of this driver */ + +/* The RX ring is filled with buffers, when a packet arrives */ +/* it is DMA'd into the buffer which is marked used and RxDone called */ +/* RxDone forms an skb (and checks the CRC if in SIR mode) and ships */ +/* the packet off upstairs */ + +/* The transmitter on the oboe chip can work in one of two modes */ +/* for each ring->tx[] the transmitter can either */ +/* a) transmit the packet, leave the trasmitter enabled and proceed to */ +/* the next ring */ +/* OR */ +/* b) transmit the packet, switch off the transmitter and issue TxDone */ + +/* All packets are entered into the ring in mode b), if the ring was */ +/* empty the transmitter is started. */ + +/* If OPTIMIZE_TX is defined then in TxDone if the ring contains */ +/* more than one packet, all but the last are set to mode a) [HOWEVER */ +/* the hardware may not notice this, this is why we start in mode b) ] */ +/* then restart the transmitter */ + +/* If OPTIMIZE_TX is not defined then we just restart the transmitter */ +/* if the ring isn't empty */ + +/* Speed changes are delayed until the TxRing is empty */ +/* mtt is handled by generating packets with bad CRCs, before the data */ + +/* TODO: */ +/* check the mtt works ok */ +/* finish the watchdog */ + +/* No user servicable parts below here */ + +#include <linux/module.h> + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/skbuff.h> +#include <linux/netdevice.h> +#include <linux/ioport.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/pci.h> +#include <linux/rtnetlink.h> + +#include <asm/io.h> + +#include <net/irda/wrapper.h> +#include <net/irda/irda.h> +//#include <net/irda/irmod.h> +//#include <net/irda/irlap_frame.h> +#include <net/irda/irda_device.h> +#include <net/irda/crc.h> + +#include "donauboe.h" + +#define INB(port) inb_p(port) +#define OUTB(val,port) outb_p(val,port) +#define OUTBP(val,port) outb_p(val,port) + +#define PROMPT OUTB(OBOE_PROMPT_BIT,OBOE_PROMPT); + +#if PROBE_VERBOSE +#define PROBE_DEBUG(args...) (printk (args)) +#else +#define PROBE_DEBUG(args...) ; +#endif + +/* Set the DMA to be byte at a time */ +#define CONFIG0H_DMA_OFF OBOE_CONFIG0H_RCVANY +#define CONFIG0H_DMA_ON_NORX CONFIG0H_DMA_OFF| OBOE_CONFIG0H_ENDMAC +#define CONFIG0H_DMA_ON CONFIG0H_DMA_ON_NORX | OBOE_CONFIG0H_ENRX + +static const struct pci_device_id toshoboe_pci_tbl[] = { + { PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_FIR701, PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_FIRD01, PCI_ANY_ID, PCI_ANY_ID, }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(pci, toshoboe_pci_tbl); + +#define DRIVER_NAME "toshoboe" +static char *driver_name = DRIVER_NAME; + +static int max_baud = 4000000; +#ifdef USE_PROBE +static bool do_probe = false; +#endif + + +/**********************************************************************/ +static int +toshoboe_checkfcs (unsigned char *buf, int len) +{ + int i; + union + { + __u16 value; + __u8 bytes[2]; + } + fcs; + + fcs.value = INIT_FCS; + + for (i = 0; i < len; ++i) + fcs.value = irda_fcs (fcs.value, *(buf++)); + + return fcs.value == GOOD_FCS; +} + +/***********************************************************************/ +/* Generic chip handling code */ +#ifdef DUMP_PACKETS +static unsigned char dump[50]; +static void +_dumpbufs (unsigned char *data, int len, char tete) +{ +int i,j; +char head=tete; +for (i=0;i<len;i+=16) { + for (j=0;j<16 && i+j<len;j++) { sprintf(&dump[3*j],"%02x.",data[i+j]); } + dump [3*j]=0; + pr_debug("%c%s\n", head, dump); + head='+'; + } +} +#endif + +#ifdef USE_PROBE +/* Dump the registers */ +static void +toshoboe_dumpregs (struct toshoboe_cb *self) +{ + __u32 ringbase; + + ringbase = INB (OBOE_RING_BASE0) << 10; + ringbase |= INB (OBOE_RING_BASE1) << 18; + ringbase |= INB (OBOE_RING_BASE2) << 26; + + printk (KERN_ERR DRIVER_NAME ": Register dump:\n"); + printk (KERN_ERR "Interrupts: Tx:%d Rx:%d TxUnder:%d RxOver:%d Sip:%d\n", + self->int_tx, self->int_rx, self->int_txunder, self->int_rxover, + self->int_sip); + printk (KERN_ERR "RX %02x TX %02x RingBase %08x\n", + INB (OBOE_RXSLOT), INB (OBOE_TXSLOT), ringbase); + printk (KERN_ERR "RING_SIZE %02x IER %02x ISR %02x\n", + INB (OBOE_RING_SIZE), INB (OBOE_IER), INB (OBOE_ISR)); + printk (KERN_ERR "CONFIG1 %02x STATUS %02x\n", + INB (OBOE_CONFIG1), INB (OBOE_STATUS)); + printk (KERN_ERR "CONFIG0 %02x%02x ENABLE %02x%02x\n", + INB (OBOE_CONFIG0H), INB (OBOE_CONFIG0L), + INB (OBOE_ENABLEH), INB (OBOE_ENABLEL)); + printk (KERN_ERR "NEW_PCONFIG %02x%02x CURR_PCONFIG %02x%02x\n", + INB (OBOE_NEW_PCONFIGH), INB (OBOE_NEW_PCONFIGL), + INB (OBOE_CURR_PCONFIGH), INB (OBOE_CURR_PCONFIGL)); + printk (KERN_ERR "MAXLEN %02x%02x RXCOUNT %02x%02x\n", + INB (OBOE_MAXLENH), INB (OBOE_MAXLENL), + INB (OBOE_RXCOUNTL), INB (OBOE_RXCOUNTH)); + + if (self->ring) + { + int i; + ringbase = virt_to_bus (self->ring); + printk (KERN_ERR "Ring at %08x:\n", ringbase); + printk (KERN_ERR "RX:"); + for (i = 0; i < RX_SLOTS; ++i) + printk (" (%d,%02x)",self->ring->rx[i].len,self->ring->rx[i].control); + printk ("\n"); + printk (KERN_ERR "TX:"); + for (i = 0; i < RX_SLOTS; ++i) + printk (" (%d,%02x)",self->ring->tx[i].len,self->ring->tx[i].control); + printk ("\n"); + } +} +#endif + +/*Don't let the chip look at memory */ +static void +toshoboe_disablebm (struct toshoboe_cb *self) +{ + __u8 command; + pci_read_config_byte (self->pdev, PCI_COMMAND, &command); + command &= ~PCI_COMMAND_MASTER; + pci_write_config_byte (self->pdev, PCI_COMMAND, command); + +} + +/* Shutdown the chip and point the taskfile reg somewhere else */ +static void +toshoboe_stopchip (struct toshoboe_cb *self) +{ + /*Disable interrupts */ + OUTB (0x0, OBOE_IER); + /*Disable DMA, Disable Rx, Disable Tx */ + OUTB (CONFIG0H_DMA_OFF, OBOE_CONFIG0H); + /*Disable SIR MIR FIR, Tx and Rx */ + OUTB (0x00, OBOE_ENABLEH); + /*Point the ring somewhere safe */ + OUTB (0x3f, OBOE_RING_BASE2); + OUTB (0xff, OBOE_RING_BASE1); + OUTB (0xff, OBOE_RING_BASE0); + + OUTB (RX_LEN >> 8, OBOE_MAXLENH); + OUTB (RX_LEN & 0xff, OBOE_MAXLENL); + + /*Acknoledge any pending interrupts */ + OUTB (0xff, OBOE_ISR); + + /*Why */ + OUTB (OBOE_ENABLEH_PHYANDCLOCK, OBOE_ENABLEH); + + /*switch it off */ + OUTB (OBOE_CONFIG1_OFF, OBOE_CONFIG1); + + toshoboe_disablebm (self); +} + +/* Transmitter initialization */ +static void +toshoboe_start_DMA (struct toshoboe_cb *self, int opts) +{ + OUTB (0x0, OBOE_ENABLEH); + OUTB (CONFIG0H_DMA_ON | opts, OBOE_CONFIG0H); + OUTB (OBOE_ENABLEH_PHYANDCLOCK, OBOE_ENABLEH); + PROMPT; +} + +/*Set the baud rate */ +static void +toshoboe_setbaud (struct toshoboe_cb *self) +{ + __u16 pconfig = 0; + __u8 config0l = 0; + + pr_debug("%s(%d/%d)\n", __func__, self->speed, self->io.speed); + + switch (self->speed) + { + case 2400: + case 4800: + case 9600: + case 19200: + case 38400: + case 57600: + case 115200: +#ifdef USE_MIR + case 1152000: +#endif + case 4000000: + break; + default: + + printk (KERN_ERR DRIVER_NAME ": switch to unsupported baudrate %d\n", + self->speed); + return; + } + + switch (self->speed) + { + /* For SIR the preamble is done by adding XBOFs */ + /* to the packet */ + /* set to filtered SIR mode, filter looks for BOF and EOF */ + case 2400: + pconfig |= 47 << OBOE_PCONFIG_BAUDSHIFT; + pconfig |= 25 << OBOE_PCONFIG_WIDTHSHIFT; + break; + case 4800: + pconfig |= 23 << OBOE_PCONFIG_BAUDSHIFT; + pconfig |= 25 << OBOE_PCONFIG_WIDTHSHIFT; + break; + case 9600: + pconfig |= 11 << OBOE_PCONFIG_BAUDSHIFT; + pconfig |= 25 << OBOE_PCONFIG_WIDTHSHIFT; + break; + case 19200: + pconfig |= 5 << OBOE_PCONFIG_BAUDSHIFT; + pconfig |= 25 << OBOE_PCONFIG_WIDTHSHIFT; + break; + case 38400: + pconfig |= 2 << OBOE_PCONFIG_BAUDSHIFT; + pconfig |= 25 << OBOE_PCONFIG_WIDTHSHIFT; + break; + case 57600: + pconfig |= 1 << OBOE_PCONFIG_BAUDSHIFT; + pconfig |= 25 << OBOE_PCONFIG_WIDTHSHIFT; + break; + case 115200: + pconfig |= 0 << OBOE_PCONFIG_BAUDSHIFT; + pconfig |= 25 << OBOE_PCONFIG_WIDTHSHIFT; + break; + default: + /*Set to packet based reception */ + OUTB (RX_LEN >> 8, OBOE_MAXLENH); + OUTB (RX_LEN & 0xff, OBOE_MAXLENL); + break; + } + + switch (self->speed) + { + case 2400: + case 4800: + case 9600: + case 19200: + case 38400: + case 57600: + case 115200: + config0l = OBOE_CONFIG0L_ENSIR; + if (self->async) + { + /*Set to character based reception */ + /*System will lock if MAXLEN=0 */ + /*so have to be careful */ + OUTB (0x01, OBOE_MAXLENH); + OUTB (0x01, OBOE_MAXLENL); + OUTB (0x00, OBOE_MAXLENH); + } + else + { + /*Set to packet based reception */ + config0l |= OBOE_CONFIG0L_ENSIRF; + OUTB (RX_LEN >> 8, OBOE_MAXLENH); + OUTB (RX_LEN & 0xff, OBOE_MAXLENL); + } + break; + +#ifdef USE_MIR + /* MIR mode */ + /* Set for 16 bit CRC and enable MIR */ + /* Preamble now handled by the chip */ + case 1152000: + pconfig |= 0 << OBOE_PCONFIG_BAUDSHIFT; + pconfig |= 8 << OBOE_PCONFIG_WIDTHSHIFT; + pconfig |= 1 << OBOE_PCONFIG_PREAMBLESHIFT; + config0l = OBOE_CONFIG0L_CRC16 | OBOE_CONFIG0L_ENMIR; + break; +#endif + /* FIR mode */ + /* Set for 32 bit CRC and enable FIR */ + /* Preamble handled by the chip */ + case 4000000: + pconfig |= 0 << OBOE_PCONFIG_BAUDSHIFT; + /* Documentation says 14, but toshiba use 15 in their drivers */ + pconfig |= 15 << OBOE_PCONFIG_PREAMBLESHIFT; + config0l = OBOE_CONFIG0L_ENFIR; + break; + } + + /* Copy into new PHY config buffer */ + OUTBP (pconfig >> 8, OBOE_NEW_PCONFIGH); + OUTB (pconfig & 0xff, OBOE_NEW_PCONFIGL); + OUTB (config0l, OBOE_CONFIG0L); + + /* Now make OBOE copy from new PHY to current PHY */ + OUTB (0x0, OBOE_ENABLEH); + OUTB (OBOE_ENABLEH_PHYANDCLOCK, OBOE_ENABLEH); + PROMPT; + + /* speed change executed */ + self->new_speed = 0; + self->io.speed = self->speed; +} + +/*Let the chip look at memory */ +static void +toshoboe_enablebm (struct toshoboe_cb *self) +{ + pci_set_master (self->pdev); +} + +/*setup the ring */ +static void +toshoboe_initring (struct toshoboe_cb *self) +{ + int i; + + for (i = 0; i < TX_SLOTS; ++i) + { + self->ring->tx[i].len = 0; + self->ring->tx[i].control = 0x00; + self->ring->tx[i].address = virt_to_bus (self->tx_bufs[i]); + } + + for (i = 0; i < RX_SLOTS; ++i) + { + self->ring->rx[i].len = RX_LEN; + self->ring->rx[i].len = 0; + self->ring->rx[i].address = virt_to_bus (self->rx_bufs[i]); + self->ring->rx[i].control = OBOE_CTL_RX_HW_OWNS; + } +} + +static void +toshoboe_resetptrs (struct toshoboe_cb *self) +{ + /* Can reset pointers by twidling DMA */ + OUTB (0x0, OBOE_ENABLEH); + OUTBP (CONFIG0H_DMA_OFF, OBOE_CONFIG0H); + OUTB (OBOE_ENABLEH_PHYANDCLOCK, OBOE_ENABLEH); + + self->rxs = inb_p (OBOE_RXSLOT) & OBOE_SLOT_MASK; + self->txs = inb_p (OBOE_TXSLOT) & OBOE_SLOT_MASK; +} + +/* Called in locked state */ +static void +toshoboe_initptrs (struct toshoboe_cb *self) +{ + + /* spin_lock_irqsave(self->spinlock, flags); */ + /* save_flags (flags); */ + + /* Can reset pointers by twidling DMA */ + toshoboe_resetptrs (self); + + OUTB (0x0, OBOE_ENABLEH); + OUTB (CONFIG0H_DMA_ON, OBOE_CONFIG0H); + OUTB (OBOE_ENABLEH_PHYANDCLOCK, OBOE_ENABLEH); + + self->txpending = 0; + + /* spin_unlock_irqrestore(self->spinlock, flags); */ + /* restore_flags (flags); */ +} + +/* Wake the chip up and get it looking at the rings */ +/* Called in locked state */ +static void +toshoboe_startchip (struct toshoboe_cb *self) +{ + __u32 physaddr; + + toshoboe_initring (self); + toshoboe_enablebm (self); + OUTBP (OBOE_CONFIG1_RESET, OBOE_CONFIG1); + OUTBP (OBOE_CONFIG1_ON, OBOE_CONFIG1); + + /* Stop the clocks */ + OUTB (0, OBOE_ENABLEH); + + /*Set size of rings */ + OUTB (RING_SIZE, OBOE_RING_SIZE); + + /*Acknoledge any pending interrupts */ + OUTB (0xff, OBOE_ISR); + + /*Enable ints */ + OUTB (OBOE_INT_TXDONE | OBOE_INT_RXDONE | + OBOE_INT_TXUNDER | OBOE_INT_RXOVER | OBOE_INT_SIP , OBOE_IER); + + /*Acknoledge any pending interrupts */ + OUTB (0xff, OBOE_ISR); + + /*Set the maximum packet length to 0xfff (4095) */ + OUTB (RX_LEN >> 8, OBOE_MAXLENH); + OUTB (RX_LEN & 0xff, OBOE_MAXLENL); + + /*Shutdown DMA */ + OUTB (CONFIG0H_DMA_OFF, OBOE_CONFIG0H); + + /*Find out where the rings live */ + physaddr = virt_to_bus (self->ring); + + IRDA_ASSERT ((physaddr & 0x3ff) == 0, + printk (KERN_ERR DRIVER_NAME "ring not correctly aligned\n"); + return;); + + OUTB ((physaddr >> 10) & 0xff, OBOE_RING_BASE0); + OUTB ((physaddr >> 18) & 0xff, OBOE_RING_BASE1); + OUTB ((physaddr >> 26) & 0x3f, OBOE_RING_BASE2); + + /*Enable DMA controller in byte mode and RX */ + OUTB (CONFIG0H_DMA_ON, OBOE_CONFIG0H); + + /* Start up the clocks */ + OUTB (OBOE_ENABLEH_PHYANDCLOCK, OBOE_ENABLEH); + + /*set to sensible speed */ + self->speed = 9600; + toshoboe_setbaud (self); + toshoboe_initptrs (self); +} + +static void +toshoboe_isntstuck (struct toshoboe_cb *self) +{ +} + +static void +toshoboe_checkstuck (struct toshoboe_cb *self) +{ + unsigned long flags; + + if (0) + { + spin_lock_irqsave(&self->spinlock, flags); + + /* This will reset the chip completely */ + printk (KERN_ERR DRIVER_NAME ": Resetting chip\n"); + + toshoboe_stopchip (self); + toshoboe_startchip (self); + spin_unlock_irqrestore(&self->spinlock, flags); + } +} + +/*Generate packet of about mtt us long */ +static int +toshoboe_makemttpacket (struct toshoboe_cb *self, void *buf, int mtt) +{ + int xbofs; + + xbofs = ((int) (mtt/100)) * (int) (self->speed); + xbofs=xbofs/80000; /*Eight bits per byte, and mtt is in us*/ + xbofs++; + + pr_debug(DRIVER_NAME ": generated mtt of %d bytes for %d us at %d baud\n", + xbofs, mtt, self->speed); + + if (xbofs > TX_LEN) + { + printk (KERN_ERR DRIVER_NAME ": wanted %d bytes MTT but TX_LEN is %d\n", + xbofs, TX_LEN); + xbofs = TX_LEN; + } + + /*xbofs will do for SIR, MIR and FIR,SIR mode doesn't generate a checksum anyway */ + memset (buf, XBOF, xbofs); + + return xbofs; +} + +#ifdef USE_PROBE +/***********************************************************************/ +/* Probe code */ + +static void +toshoboe_dumptx (struct toshoboe_cb *self) +{ + int i; + PROBE_DEBUG(KERN_WARNING "TX:"); + for (i = 0; i < RX_SLOTS; ++i) + PROBE_DEBUG(" (%d,%02x)",self->ring->tx[i].len,self->ring->tx[i].control); + PROBE_DEBUG(" [%d]\n",self->speed); +} + +static void +toshoboe_dumprx (struct toshoboe_cb *self, int score) +{ + int i; + PROBE_DEBUG(" %d\nRX:",score); + for (i = 0; i < RX_SLOTS; ++i) + PROBE_DEBUG(" (%d,%02x)",self->ring->rx[i].len,self->ring->rx[i].control); + PROBE_DEBUG("\n"); +} + +static inline int +stuff_byte (__u8 byte, __u8 * buf) +{ + switch (byte) + { + case BOF: /* FALLTHROUGH */ + case EOF: /* FALLTHROUGH */ + case CE: + /* Insert transparently coded */ + buf[0] = CE; /* Send link escape */ + buf[1] = byte ^ IRDA_TRANS; /* Complement bit 5 */ + return 2; + /* break; */ + default: + /* Non-special value, no transparency required */ + buf[0] = byte; + return 1; + /* break; */ + } +} + +static irqreturn_t +toshoboe_probeinterrupt (int irq, void *dev_id) +{ + struct toshoboe_cb *self = dev_id; + __u8 irqstat; + + irqstat = INB (OBOE_ISR); + +/* was it us */ + if (!(irqstat & OBOE_INT_MASK)) + return IRQ_NONE; + +/* Ack all the interrupts */ + OUTB (irqstat, OBOE_ISR); + + if (irqstat & OBOE_INT_TXDONE) + { + int txp; + + self->int_tx++; + PROBE_DEBUG("T"); + + txp = INB (OBOE_TXSLOT) & OBOE_SLOT_MASK; + if (self->ring->tx[txp].control & OBOE_CTL_TX_HW_OWNS) + { + self->int_tx+=100; + PROBE_DEBUG("S"); + toshoboe_start_DMA(self, OBOE_CONFIG0H_ENTX | OBOE_CONFIG0H_LOOP); + } + } + + if (irqstat & OBOE_INT_RXDONE) { + self->int_rx++; + PROBE_DEBUG("R"); } + if (irqstat & OBOE_INT_TXUNDER) { + self->int_txunder++; + PROBE_DEBUG("U"); } + if (irqstat & OBOE_INT_RXOVER) { + self->int_rxover++; + PROBE_DEBUG("O"); } + if (irqstat & OBOE_INT_SIP) { + self->int_sip++; + PROBE_DEBUG("I"); } + return IRQ_HANDLED; +} + +static int +toshoboe_maketestpacket (unsigned char *buf, int badcrc, int fir) +{ + int i; + int len = 0; + union + { + __u16 value; + __u8 bytes[2]; + } + fcs; + + if (fir) + { + memset (buf, 0, TT_LEN); + return TT_LEN; + } + + fcs.value = INIT_FCS; + + memset (buf, XBOF, 10); + len += 10; + buf[len++] = BOF; + + for (i = 0; i < TT_LEN; ++i) + { + len += stuff_byte (i, buf + len); + fcs.value = irda_fcs (fcs.value, i); + } + + len += stuff_byte (fcs.bytes[0] ^ badcrc, buf + len); + len += stuff_byte (fcs.bytes[1] ^ badcrc, buf + len); + buf[len++] = EOF; + len++; + return len; +} + +static int +toshoboe_probefail (struct toshoboe_cb *self, char *msg) +{ + printk (KERN_ERR DRIVER_NAME "probe(%d) failed %s\n",self-> speed, msg); + toshoboe_dumpregs (self); + toshoboe_stopchip (self); + free_irq (self->io.irq, (void *) self); + return 0; +} + +static int +toshoboe_numvalidrcvs (struct toshoboe_cb *self) +{ + int i, ret = 0; + for (i = 0; i < RX_SLOTS; ++i) + if ((self->ring->rx[i].control & 0xe0) == 0) + ret++; + + return ret; +} + +static int +toshoboe_numrcvs (struct toshoboe_cb *self) +{ + int i, ret = 0; + for (i = 0; i < RX_SLOTS; ++i) + if (!(self->ring->rx[i].control & OBOE_CTL_RX_HW_OWNS)) + ret++; + + return ret; +} + +static int +toshoboe_probe (struct toshoboe_cb *self) +{ + int i, j, n; +#ifdef USE_MIR + static const int bauds[] = { 9600, 115200, 4000000, 1152000 }; +#else + static const int bauds[] = { 9600, 115200, 4000000 }; +#endif + unsigned long flags; + + if (request_irq (self->io.irq, toshoboe_probeinterrupt, + self->io.irqflags, "toshoboe", (void *) self)) + { + printk (KERN_ERR DRIVER_NAME ": probe failed to allocate irq %d\n", + self->io.irq); + return 0; + } + + /* test 1: SIR filter and back to back */ + + for (j = 0; j < ARRAY_SIZE(bauds); ++j) + { + int fir = (j > 1); + toshoboe_stopchip (self); + + + spin_lock_irqsave(&self->spinlock, flags); + /*Address is already setup */ + toshoboe_startchip (self); + self->int_rx = self->int_tx = 0; + self->speed = bauds[j]; + toshoboe_setbaud (self); + toshoboe_initptrs (self); + spin_unlock_irqrestore(&self->spinlock, flags); + + self->ring->tx[self->txs].control = +/* (FIR only) OBOE_CTL_TX_SIP needed for switching to next slot */ +/* MIR: all received data is stored in one slot */ + (fir) ? OBOE_CTL_TX_HW_OWNS | OBOE_CTL_TX_RTCENTX + : OBOE_CTL_TX_HW_OWNS ; + self->ring->tx[self->txs].len = + toshoboe_maketestpacket (self->tx_bufs[self->txs], 0, fir); + self->txs++; + self->txs %= TX_SLOTS; + + self->ring->tx[self->txs].control = + (fir) ? OBOE_CTL_TX_HW_OWNS | OBOE_CTL_TX_SIP + : OBOE_CTL_TX_HW_OWNS | OBOE_CTL_TX_RTCENTX ; + self->ring->tx[self->txs].len = + toshoboe_maketestpacket (self->tx_bufs[self->txs], 0, fir); + self->txs++; + self->txs %= TX_SLOTS; + + self->ring->tx[self->txs].control = + (fir) ? OBOE_CTL_TX_HW_OWNS | OBOE_CTL_TX_RTCENTX + : OBOE_CTL_TX_HW_OWNS ; + self->ring->tx[self->txs].len = + toshoboe_maketestpacket (self->tx_bufs[self->txs], 0, fir); + self->txs++; + self->txs %= TX_SLOTS; + + self->ring->tx[self->txs].control = + (fir) ? OBOE_CTL_TX_HW_OWNS | OBOE_CTL_TX_RTCENTX + | OBOE_CTL_TX_SIP | OBOE_CTL_TX_BAD_CRC + : OBOE_CTL_TX_HW_OWNS | OBOE_CTL_TX_RTCENTX ; + self->ring->tx[self->txs].len = + toshoboe_maketestpacket (self->tx_bufs[self->txs], 0, fir); + self->txs++; + self->txs %= TX_SLOTS; + + toshoboe_dumptx (self); + /* Turn on TX and RX and loopback */ + toshoboe_start_DMA(self, OBOE_CONFIG0H_ENTX | OBOE_CONFIG0H_LOOP); + + i = 0; + n = fir ? 1 : 4; + while (toshoboe_numvalidrcvs (self) != n) + { + if (i > 4800) + return toshoboe_probefail (self, "filter test"); + udelay ((9600*(TT_LEN+16))/self->speed); + i++; + } + + n = fir ? 203 : 102; + while ((toshoboe_numrcvs(self) != self->int_rx) || (self->int_tx != n)) + { + if (i > 4800) + return toshoboe_probefail (self, "interrupt test"); + udelay ((9600*(TT_LEN+16))/self->speed); + i++; + } + toshoboe_dumprx (self,i); + + } + + /* test 2: SIR in char at a time */ + + toshoboe_stopchip (self); + self->int_rx = self->int_tx = 0; + + spin_lock_irqsave(&self->spinlock, flags); + toshoboe_startchip (self); + spin_unlock_irqrestore(&self->spinlock, flags); + + self->async = 1; + self->speed = 115200; + toshoboe_setbaud (self); + self->ring->tx[self->txs].control = + OBOE_CTL_TX_RTCENTX | OBOE_CTL_TX_HW_OWNS; + self->ring->tx[self->txs].len = 4; + + ((unsigned char *) self->tx_bufs[self->txs])[0] = 'f'; + ((unsigned char *) self->tx_bufs[self->txs])[1] = 'i'; + ((unsigned char *) self->tx_bufs[self->txs])[2] = 's'; + ((unsigned char *) self->tx_bufs[self->txs])[3] = 'h'; + toshoboe_dumptx (self); + toshoboe_start_DMA(self, OBOE_CONFIG0H_ENTX | OBOE_CONFIG0H_LOOP); + + i = 0; + while (toshoboe_numvalidrcvs (self) != 4) + { + if (i > 100) + return toshoboe_probefail (self, "Async test"); + udelay (100); + i++; + } + + while ((toshoboe_numrcvs (self) != self->int_rx) || (self->int_tx != 1)) + { + if (i > 100) + return toshoboe_probefail (self, "Async interrupt test"); + udelay (100); + i++; + } + toshoboe_dumprx (self,i); + + self->async = 0; + self->speed = 9600; + toshoboe_setbaud (self); + toshoboe_stopchip (self); + + free_irq (self->io.irq, (void *) self); + + printk (KERN_WARNING DRIVER_NAME ": Self test passed ok\n"); + + return 1; +} +#endif + +/******************************************************************/ +/* Netdev style code */ + +/* Transmit something */ +static netdev_tx_t +toshoboe_hard_xmit (struct sk_buff *skb, struct net_device *dev) +{ + struct toshoboe_cb *self; + __s32 speed; + int mtt, len, ctl; + unsigned long flags; + struct irda_skb_cb *cb = (struct irda_skb_cb *) skb->cb; + + self = netdev_priv(dev); + + IRDA_ASSERT (self != NULL, return NETDEV_TX_OK; ); + + pr_debug("%s.tx:%x(%x)%x\n", + __func__, skb->len, self->txpending, INB(OBOE_ENABLEH)); + if (!cb->magic) { + pr_debug("%s.Not IrLAP:%x\n", __func__, cb->magic); +#ifdef DUMP_PACKETS + _dumpbufs(skb->data,skb->len,'>'); +#endif + } + + /* change speed pending, wait for its execution */ + if (self->new_speed) + return NETDEV_TX_BUSY; + + /* device stopped (apm) wait for restart */ + if (self->stopped) + return NETDEV_TX_BUSY; + + toshoboe_checkstuck (self); + + /* Check if we need to change the speed */ + /* But not now. Wait after transmission if mtt not required */ + speed=irda_get_next_speed(skb); + if ((speed != self->io.speed) && (speed != -1)) + { + spin_lock_irqsave(&self->spinlock, flags); + + if (self->txpending || skb->len) + { + self->new_speed = speed; + pr_debug("%s: Queued TxDone scheduled speed change %d\n" , + __func__, speed); + /* if no data, that's all! */ + if (!skb->len) + { + spin_unlock_irqrestore(&self->spinlock, flags); + dev_kfree_skb (skb); + return NETDEV_TX_OK; + } + /* True packet, go on, but */ + /* do not accept anything before change speed execution */ + netif_stop_queue(dev); + /* ready to process TxDone interrupt */ + spin_unlock_irqrestore(&self->spinlock, flags); + } + else + { + /* idle and no data, change speed now */ + self->speed = speed; + toshoboe_setbaud (self); + spin_unlock_irqrestore(&self->spinlock, flags); + dev_kfree_skb (skb); + return NETDEV_TX_OK; + } + + } + + if ((mtt = irda_get_mtt(skb))) + { + /* This is fair since the queue should be empty anyway */ + spin_lock_irqsave(&self->spinlock, flags); + + if (self->txpending) + { + spin_unlock_irqrestore(&self->spinlock, flags); + return NETDEV_TX_BUSY; + } + + /* If in SIR mode we need to generate a string of XBOFs */ + /* In MIR and FIR we need to generate a string of data */ + /* which we will add a wrong checksum to */ + + mtt = toshoboe_makemttpacket (self, self->tx_bufs[self->txs], mtt); + pr_debug("%s.mtt:%x(%x)%d\n", __func__, skb->len, mtt, self->txpending); + if (mtt) + { + self->ring->tx[self->txs].len = mtt & 0xfff; + + ctl = OBOE_CTL_TX_HW_OWNS | OBOE_CTL_TX_RTCENTX; + if (INB (OBOE_ENABLEH) & OBOE_ENABLEH_FIRON) + { + ctl |= OBOE_CTL_TX_BAD_CRC | OBOE_CTL_TX_SIP ; + } +#ifdef USE_MIR + else if (INB (OBOE_ENABLEH) & OBOE_ENABLEH_MIRON) + { + ctl |= OBOE_CTL_TX_BAD_CRC; + } +#endif + self->ring->tx[self->txs].control = ctl; + + OUTB (0x0, OBOE_ENABLEH); + /* It is only a timer. Do not send mtt packet outside! */ + toshoboe_start_DMA(self, OBOE_CONFIG0H_ENTX | OBOE_CONFIG0H_LOOP); + + self->txpending++; + + self->txs++; + self->txs %= TX_SLOTS; + + } + else + { + printk(KERN_ERR DRIVER_NAME ": problem with mtt packet - ignored\n"); + } + spin_unlock_irqrestore(&self->spinlock, flags); + } + +#ifdef DUMP_PACKETS +dumpbufs(skb->data,skb->len,'>'); +#endif + + spin_lock_irqsave(&self->spinlock, flags); + + if (self->ring->tx[self->txs].control & OBOE_CTL_TX_HW_OWNS) + { + pr_debug("%s.ful:%x(%x)%x\n", + __func__, skb->len, self->ring->tx[self->txs].control, + self->txpending); + toshoboe_start_DMA(self, OBOE_CONFIG0H_ENTX); + spin_unlock_irqrestore(&self->spinlock, flags); + return NETDEV_TX_BUSY; + } + + if (INB (OBOE_ENABLEH) & OBOE_ENABLEH_SIRON) + { + len = async_wrap_skb (skb, self->tx_bufs[self->txs], TX_BUF_SZ); + } + else + { + len = skb->len; + skb_copy_from_linear_data(skb, self->tx_bufs[self->txs], len); + } + self->ring->tx[self->txs].len = len & 0x0fff; + + /*Sometimes the HW doesn't see us assert RTCENTX in the interrupt code */ + /*later this plays safe, we garuntee the last packet to be transmitted */ + /*has RTCENTX set */ + + ctl = OBOE_CTL_TX_HW_OWNS | OBOE_CTL_TX_RTCENTX; + if (INB (OBOE_ENABLEH) & OBOE_ENABLEH_FIRON) + { + ctl |= OBOE_CTL_TX_SIP ; + } + self->ring->tx[self->txs].control = ctl; + + /* If transmitter is idle start in one-shot mode */ + + if (!self->txpending) + toshoboe_start_DMA(self, OBOE_CONFIG0H_ENTX); + + self->txpending++; + + self->txs++; + self->txs %= TX_SLOTS; + + spin_unlock_irqrestore(&self->spinlock, flags); + dev_kfree_skb (skb); + + return NETDEV_TX_OK; +} + +/*interrupt handler */ +static irqreturn_t +toshoboe_interrupt (int irq, void *dev_id) +{ + struct toshoboe_cb *self = dev_id; + __u8 irqstat; + struct sk_buff *skb = NULL; + + irqstat = INB (OBOE_ISR); + +/* was it us */ + if (!(irqstat & OBOE_INT_MASK)) + return IRQ_NONE; + +/* Ack all the interrupts */ + OUTB (irqstat, OBOE_ISR); + + toshoboe_isntstuck (self); + +/* Txdone */ + if (irqstat & OBOE_INT_TXDONE) + { + int txp, txpc; + int i; + + txp = self->txpending; + self->txpending = 0; + + for (i = 0; i < TX_SLOTS; ++i) + { + if (self->ring->tx[i].control & OBOE_CTL_TX_HW_OWNS) + self->txpending++; + } + pr_debug("%s.txd(%x)%x/%x\n", __func__, irqstat, txp, self->txpending); + + txp = INB (OBOE_TXSLOT) & OBOE_SLOT_MASK; + + /* Got anything queued ? start it together */ + if (self->ring->tx[txp].control & OBOE_CTL_TX_HW_OWNS) + { + txpc = txp; +#ifdef OPTIMIZE_TX + while (self->ring->tx[txpc].control & OBOE_CTL_TX_HW_OWNS) + { + txp = txpc; + txpc++; + txpc %= TX_SLOTS; + self->netdev->stats.tx_packets++; + if (self->ring->tx[txpc].control & OBOE_CTL_TX_HW_OWNS) + self->ring->tx[txp].control &= ~OBOE_CTL_TX_RTCENTX; + } + self->netdev->stats.tx_packets--; +#else + self->netdev->stats.tx_packets++; +#endif + toshoboe_start_DMA(self, OBOE_CONFIG0H_ENTX); + } + + if ((!self->txpending) && (self->new_speed)) + { + self->speed = self->new_speed; + pr_debug("%s: Executed TxDone scheduled speed change %d\n", + __func__, self->speed); + toshoboe_setbaud (self); + } + + /* Tell network layer that we want more frames */ + if (!self->new_speed) + netif_wake_queue(self->netdev); + } + + if (irqstat & OBOE_INT_RXDONE) + { + while (!(self->ring->rx[self->rxs].control & OBOE_CTL_RX_HW_OWNS)) + { + int len = self->ring->rx[self->rxs].len; + skb = NULL; + pr_debug("%s.rcv:%x(%x)\n", __func__ + , len, self->ring->rx[self->rxs].control); + +#ifdef DUMP_PACKETS +dumpbufs(self->rx_bufs[self->rxs],len,'<'); +#endif + + if (self->ring->rx[self->rxs].control == 0) + { + __u8 enable = INB (OBOE_ENABLEH); + + /* In SIR mode we need to check the CRC as this */ + /* hasn't been done by the hardware */ + if (enable & OBOE_ENABLEH_SIRON) + { + if (!toshoboe_checkfcs (self->rx_bufs[self->rxs], len)) + len = 0; + /*Trim off the CRC */ + if (len > 1) + len -= 2; + else + len = 0; + pr_debug("%s.SIR:%x(%x)\n", __func__, len, enable); + } + +#ifdef USE_MIR + else if (enable & OBOE_ENABLEH_MIRON) + { + if (len > 1) + len -= 2; + else + len = 0; + pr_debug("%s.MIR:%x(%x)\n", __func__, len, enable); + } +#endif + else if (enable & OBOE_ENABLEH_FIRON) + { + if (len > 3) + len -= 4; /*FIXME: check this */ + else + len = 0; + pr_debug("%s.FIR:%x(%x)\n", __func__, len, enable); + } + else + pr_debug("%s.?IR:%x(%x)\n", __func__, len, enable); + + if (len) + { + skb = dev_alloc_skb (len + 1); + if (skb) + { + skb_reserve (skb, 1); + + skb_put (skb, len); + skb_copy_to_linear_data(skb, self->rx_bufs[self->rxs], + len); + self->netdev->stats.rx_packets++; + skb->dev = self->netdev; + skb_reset_mac_header(skb); + skb->protocol = htons (ETH_P_IRDA); + } + else + { + printk (KERN_INFO + "%s(), memory squeeze, dropping frame.\n", + __func__); + } + } + } + else + { + /* TODO: =========================================== */ + /* if OBOE_CTL_RX_LENGTH, our buffers are too small */ + /* (MIR or FIR) data is lost. */ + /* (SIR) data is splitted in several slots. */ + /* we have to join all the received buffers received */ + /*in a large buffer before checking CRC. */ + pr_debug("%s.err:%x(%x)\n", __func__ + , len, self->ring->rx[self->rxs].control); + } + + self->ring->rx[self->rxs].len = 0x0; + self->ring->rx[self->rxs].control = OBOE_CTL_RX_HW_OWNS; + + self->rxs++; + self->rxs %= RX_SLOTS; + + if (skb) + netif_rx (skb); + + } + } + + if (irqstat & OBOE_INT_TXUNDER) + { + printk (KERN_WARNING DRIVER_NAME ": tx fifo underflow\n"); + } + if (irqstat & OBOE_INT_RXOVER) + { + printk (KERN_WARNING DRIVER_NAME ": rx fifo overflow\n"); + } +/* This must be useful for something... */ + if (irqstat & OBOE_INT_SIP) + { + self->int_sip++; + pr_debug("%s.sip:%x(%x)%x\n", + __func__, self->int_sip, irqstat, self->txpending); + } + return IRQ_HANDLED; +} + + +static int +toshoboe_net_open (struct net_device *dev) +{ + struct toshoboe_cb *self; + unsigned long flags; + int rc; + + self = netdev_priv(dev); + + if (self->async) + return -EBUSY; + + if (self->stopped) + return 0; + + rc = request_irq (self->io.irq, toshoboe_interrupt, + IRQF_SHARED, dev->name, self); + if (rc) + return rc; + + spin_lock_irqsave(&self->spinlock, flags); + toshoboe_startchip (self); + spin_unlock_irqrestore(&self->spinlock, flags); + + /* Ready to play! */ + netif_start_queue(dev); + + /* + * Open new IrLAP layer instance, now that everything should be + * initialized properly + */ + self->irlap = irlap_open (dev, &self->qos, driver_name); + + self->irdad = 1; + + return 0; +} + +static int +toshoboe_net_close (struct net_device *dev) +{ + struct toshoboe_cb *self; + + IRDA_ASSERT (dev != NULL, return -1; ); + self = netdev_priv(dev); + + /* Stop device */ + netif_stop_queue(dev); + + /* Stop and remove instance of IrLAP */ + if (self->irlap) + irlap_close (self->irlap); + self->irlap = NULL; + + self->irdad = 0; + + free_irq (self->io.irq, (void *) self); + + if (!self->stopped) + { + toshoboe_stopchip (self); + } + + return 0; +} + +/* + * Function toshoboe_net_ioctl (dev, rq, cmd) + * + * Process IOCTL commands for this device + * + */ +static int +toshoboe_net_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct if_irda_req *irq = (struct if_irda_req *) rq; + struct toshoboe_cb *self; + unsigned long flags; + int ret = 0; + + IRDA_ASSERT (dev != NULL, return -1; ); + + self = netdev_priv(dev); + + IRDA_ASSERT (self != NULL, return -1; ); + + pr_debug("%s(), %s, (cmd=0x%X)\n", __func__, dev->name, cmd); + + /* Disable interrupts & save flags */ + spin_lock_irqsave(&self->spinlock, flags); + + switch (cmd) + { + case SIOCSBANDWIDTH: /* Set bandwidth */ + /* This function will also be used by IrLAP to change the + * speed, so we still must allow for speed change within + * interrupt context. + */ + pr_debug("%s(BANDWIDTH), %s, (%X/%ld\n", + __func__, dev->name, INB(OBOE_STATUS), irq->ifr_baudrate); + if (!in_interrupt () && !capable (CAP_NET_ADMIN)) { + ret = -EPERM; + goto out; + } + + /* self->speed=irq->ifr_baudrate; */ + /* toshoboe_setbaud(self); */ + /* Just change speed once - inserted by Paul Bristow */ + self->new_speed = irq->ifr_baudrate; + break; + case SIOCSMEDIABUSY: /* Set media busy */ + pr_debug("%s(MEDIABUSY), %s, (%X/%x)\n", + __func__, dev->name, + INB(OBOE_STATUS), capable(CAP_NET_ADMIN)); + if (!capable (CAP_NET_ADMIN)) { + ret = -EPERM; + goto out; + } + irda_device_set_media_busy (self->netdev, TRUE); + break; + case SIOCGRECEIVING: /* Check if we are receiving right now */ + irq->ifr_receiving = (INB (OBOE_STATUS) & OBOE_STATUS_RXBUSY) ? 1 : 0; + pr_debug("%s(RECEIVING), %s, (%X/%x)\n", + __func__, dev->name, INB(OBOE_STATUS), irq->ifr_receiving); + break; + default: + pr_debug("%s(?), %s, (cmd=0x%X)\n", __func__, dev->name, cmd); + ret = -EOPNOTSUPP; + } +out: + spin_unlock_irqrestore(&self->spinlock, flags); + return ret; + +} + +MODULE_DESCRIPTION("Toshiba OBOE IrDA Device Driver"); +MODULE_AUTHOR("James McKenzie <james@fishsoup.dhs.org>"); +MODULE_LICENSE("GPL"); + +module_param (max_baud, int, 0); +MODULE_PARM_DESC(max_baud, "Maximum baud rate"); + +#ifdef USE_PROBE +module_param (do_probe, bool, 0); +MODULE_PARM_DESC(do_probe, "Enable/disable chip probing and self-test"); +#endif + +static void +toshoboe_close (struct pci_dev *pci_dev) +{ + int i; + struct toshoboe_cb *self = pci_get_drvdata(pci_dev); + + IRDA_ASSERT (self != NULL, return; ); + + if (!self->stopped) + { + toshoboe_stopchip (self); + } + + release_region (self->io.fir_base, self->io.fir_ext); + + for (i = 0; i < TX_SLOTS; ++i) + { + kfree (self->tx_bufs[i]); + self->tx_bufs[i] = NULL; + } + + for (i = 0; i < RX_SLOTS; ++i) + { + kfree (self->rx_bufs[i]); + self->rx_bufs[i] = NULL; + } + + unregister_netdev(self->netdev); + + kfree (self->ringbuf); + self->ringbuf = NULL; + self->ring = NULL; + + free_netdev(self->netdev); +} + +static const struct net_device_ops toshoboe_netdev_ops = { + .ndo_open = toshoboe_net_open, + .ndo_stop = toshoboe_net_close, + .ndo_start_xmit = toshoboe_hard_xmit, + .ndo_do_ioctl = toshoboe_net_ioctl, +}; + +static int +toshoboe_open (struct pci_dev *pci_dev, const struct pci_device_id *pdid) +{ + struct toshoboe_cb *self; + struct net_device *dev; + int i = 0; + int ok = 0; + int err; + + if ((err=pci_enable_device(pci_dev))) + return err; + + dev = alloc_irdadev(sizeof (struct toshoboe_cb)); + if (dev == NULL) + { + printk (KERN_ERR DRIVER_NAME ": can't allocate memory for " + "IrDA control block\n"); + return -ENOMEM; + } + + self = netdev_priv(dev); + self->netdev = dev; + self->pdev = pci_dev; + self->base = pci_resource_start(pci_dev,0); + + self->io.fir_base = self->base; + self->io.fir_ext = OBOE_IO_EXTENT; + self->io.irq = pci_dev->irq; + self->io.irqflags = IRQF_SHARED; + + self->speed = self->io.speed = 9600; + self->async = 0; + + /* Lock the port that we need */ + if (NULL==request_region (self->io.fir_base, self->io.fir_ext, driver_name)) + { + printk (KERN_ERR DRIVER_NAME ": can't get iobase of 0x%03x\n" + ,self->io.fir_base); + err = -EBUSY; + goto freeself; + } + + spin_lock_init(&self->spinlock); + + irda_init_max_qos_capabilies (&self->qos); + self->qos.baud_rate.bits = 0; + + if (max_baud >= 2400) + self->qos.baud_rate.bits |= IR_2400; + /*if (max_baud>=4800) idev->qos.baud_rate.bits|=IR_4800; */ + if (max_baud >= 9600) + self->qos.baud_rate.bits |= IR_9600; + if (max_baud >= 19200) + self->qos.baud_rate.bits |= IR_19200; + if (max_baud >= 115200) + self->qos.baud_rate.bits |= IR_115200; +#ifdef USE_MIR + if (max_baud >= 1152000) + { + self->qos.baud_rate.bits |= IR_1152000; + } +#endif + if (max_baud >= 4000000) + { + self->qos.baud_rate.bits |= (IR_4000000 << 8); + } + + /*FIXME: work this out... */ + self->qos.min_turn_time.bits = 0xff; + + irda_qos_bits_to_value (&self->qos); + + /* Allocate twice the size to guarantee alignment */ + self->ringbuf = kmalloc(OBOE_RING_LEN << 1, GFP_KERNEL); + if (!self->ringbuf) + { + err = -ENOMEM; + goto freeregion; + } + +#if (BITS_PER_LONG == 64) +#error broken on 64-bit: casts pointer to 32-bit, and then back to pointer. +#endif + + /*We need to align the taskfile on a taskfile size boundary */ + { + unsigned long addr; + + addr = (__u32) self->ringbuf; + addr &= ~(OBOE_RING_LEN - 1); + addr += OBOE_RING_LEN; + self->ring = (struct OboeRing *) addr; + } + + memset (self->ring, 0, OBOE_RING_LEN); + self->io.mem_base = (__u32) self->ring; + + ok = 1; + for (i = 0; i < TX_SLOTS; ++i) + { + self->tx_bufs[i] = kmalloc (TX_BUF_SZ, GFP_KERNEL); + if (!self->tx_bufs[i]) + ok = 0; + } + + for (i = 0; i < RX_SLOTS; ++i) + { + self->rx_bufs[i] = kmalloc (RX_BUF_SZ, GFP_KERNEL); + if (!self->rx_bufs[i]) + ok = 0; + } + + if (!ok) + { + err = -ENOMEM; + goto freebufs; + } + + +#ifdef USE_PROBE + if (do_probe) + if (!toshoboe_probe (self)) + { + err = -ENODEV; + goto freebufs; + } +#endif + + SET_NETDEV_DEV(dev, &pci_dev->dev); + dev->netdev_ops = &toshoboe_netdev_ops; + + err = register_netdev(dev); + if (err) + { + printk (KERN_ERR DRIVER_NAME ": register_netdev() failed\n"); + err = -ENOMEM; + goto freebufs; + } + printk (KERN_INFO "IrDA: Registered device %s\n", dev->name); + + pci_set_drvdata(pci_dev,self); + + printk (KERN_INFO DRIVER_NAME ": Using multiple tasks\n"); + + return 0; + +freebufs: + for (i = 0; i < TX_SLOTS; ++i) + kfree (self->tx_bufs[i]); + for (i = 0; i < RX_SLOTS; ++i) + kfree (self->rx_bufs[i]); + kfree(self->ringbuf); + +freeregion: + release_region (self->io.fir_base, self->io.fir_ext); + +freeself: + free_netdev(dev); + + return err; +} + +static int +toshoboe_gotosleep (struct pci_dev *pci_dev, pm_message_t crap) +{ + struct toshoboe_cb *self = pci_get_drvdata(pci_dev); + unsigned long flags; + int i = 10; + + if (!self || self->stopped) + return 0; + + if ((!self->irdad) && (!self->async)) + return 0; + +/* Flush all packets */ + while ((i--) && (self->txpending)) + msleep(10); + + spin_lock_irqsave(&self->spinlock, flags); + + toshoboe_stopchip (self); + self->stopped = 1; + self->txpending = 0; + + spin_unlock_irqrestore(&self->spinlock, flags); + return 0; +} + +static int +toshoboe_wakeup (struct pci_dev *pci_dev) +{ + struct toshoboe_cb *self = pci_get_drvdata(pci_dev); + unsigned long flags; + + if (!self || !self->stopped) + return 0; + + if ((!self->irdad) && (!self->async)) + return 0; + + spin_lock_irqsave(&self->spinlock, flags); + + toshoboe_startchip (self); + self->stopped = 0; + + netif_wake_queue(self->netdev); + spin_unlock_irqrestore(&self->spinlock, flags); + return 0; +} + +static struct pci_driver donauboe_pci_driver = { + .name = "donauboe", + .id_table = toshoboe_pci_tbl, + .probe = toshoboe_open, + .remove = toshoboe_close, + .suspend = toshoboe_gotosleep, + .resume = toshoboe_wakeup +}; + +module_pci_driver(donauboe_pci_driver); diff --git a/drivers/staging/irda/drivers/donauboe.h b/drivers/staging/irda/drivers/donauboe.h new file mode 100644 index 000000000000..d92d54e839b9 --- /dev/null +++ b/drivers/staging/irda/drivers/donauboe.h @@ -0,0 +1,362 @@ +/********************************************************************* + * + * Filename: toshoboe.h + * Version: 2.16 + * Description: Driver for the Toshiba OBOE (or type-O or 701) + * FIR Chipset, also supports the DONAUOBOE (type-DO + * or d01) FIR chipset which as far as I know is + * register compatible. + * Status: Experimental. + * Author: James McKenzie <james@fishsoup.dhs.org> + * Created at: Sat May 8 12:35:27 1999 + * Modified: 2.16 Martin Lucina <mato@kotelna.sk> + * Modified: 2.16 Sat Jun 22 18:54:29 2002 (sync headers) + * Modified: 2.17 Christian Gennerat <christian.gennerat@polytechnique.org> + * Modified: 2.17 jeu sep 12 08:50:20 2002 (add lock to be used by spinlocks) + * + * Copyright (c) 1999 James McKenzie, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither James McKenzie nor Cambridge University admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + * Applicable Models : Libretto 100/110CT and many more. + * Toshiba refers to this chip as the type-O IR port, + * or the type-DO IR port. + * + * IrDA chip set list from Toshiba Computer Engineering Corp. + * model method maker controller Version + * Portege 320CT FIR,SIR Toshiba Oboe(Triangle) + * Portege 3010CT FIR,SIR Toshiba Oboe(Sydney) + * Portege 3015CT FIR,SIR Toshiba Oboe(Sydney) + * Portege 3020CT FIR,SIR Toshiba Oboe(Sydney) + * Portege 7020CT FIR,SIR ? ? + * + * Satell. 4090XCDT FIR,SIR ? ? + * + * Libretto 100CT FIR,SIR Toshiba Oboe + * Libretto 1000CT FIR,SIR Toshiba Oboe + * + * TECRA750DVD FIR,SIR Toshiba Oboe(Triangle) REV ID=14h + * TECRA780 FIR,SIR Toshiba Oboe(Sandlot) REV ID=32h,33h + * TECRA750CDT FIR,SIR Toshiba Oboe(Triangle) REV ID=13h,14h + * TECRA8000 FIR,SIR Toshiba Oboe(ISKUR) REV ID=23h + * + ********************************************************************/ + +/* The documentation for this chip is allegedly released */ +/* However I have not seen it, not have I managed to contact */ +/* anyone who has. HOWEVER the chip bears a striking resemblance */ +/* to the IrDA controller in the Toshiba RISC TMPR3922 chip */ +/* the documentation for this is freely available at */ +/* http://www.madingley.org/james/resources/toshoboe/TMPR3922.pdf */ +/* The mapping between the registers in that document and the */ +/* Registers in the 701 oboe chip are as follows */ + + +/* 3922 reg 701 regs, by bit numbers */ +/* 7- 0 15- 8 24-16 31-25 */ +/* $28 0x0 0x1 */ +/* $2c SEE NOTE 1 */ +/* $30 0x6 0x7 */ +/* $34 0x8 0x9 SEE NOTE 2 */ +/* $38 0x10 0x11 */ +/* $3C 0xe SEE NOTE 3 */ +/* $40 0x12 0x13 */ +/* $44 0x14 0x15 */ +/* $48 0x16 0x17 */ +/* $4c 0x18 0x19 */ +/* $50 0x1a 0x1b */ + +/* FIXME: could be 0x1b 0x1a here */ + +/* $54 0x1d 0x1c */ +/* $5C 0xf SEE NOTE 4 */ +/* $130 SEE NOTE 5 */ +/* $134 SEE NOTE 6 */ +/* */ +/* NOTES: */ +/* 1. The pointer to ring is packed in most unceremoniusly */ +/* 701 Register Address bits (A9-A0 must be zero) */ +/* 0x4: A17 A16 A15 A14 A13 A12 A11 A10 */ +/* 0x5: A25 A24 A23 A22 A21 A20 A19 A18 */ +/* 0x2: 0 0 A31 A30 A29 A28 A27 A26 */ +/* */ +/* 2. The M$ drivers do a write 0x1 to 0x9, however the 3922 */ +/* documentation would suggest that a write of 0x1 to 0x8 */ +/* would be more appropriate. */ +/* */ +/* 3. This assignment is tenuous at best, register 0xe seems to */ +/* have bits arranged 0 0 0 R/W R/W R/W R/W R/W */ +/* if either of the lower two bits are set the chip seems to */ +/* switch off */ +/* */ +/* 4. Bits 7-4 seem to be different 4 seems just to be generic */ +/* receiver busy flag */ +/* */ +/* 5. and 6. The IER and ISR have a different bit assignment */ +/* The lower three bits of both read back as ones */ +/* ISR is register 0xc, IER is register 0xd */ +/* 7 6 5 4 3 2 1 0 */ +/* 0xc: TxDone RxDone TxUndr RxOver SipRcv 1 1 1 */ +/* 0xd: TxDone RxDone TxUndr RxOver SipRcv 1 1 1 */ +/* TxDone xmitt done (generated only if generate interrupt bit */ +/* is set in the ring) */ +/* RxDone recv completed (or other recv condition if you set it */ +/* up */ +/* TxUnder underflow in Transmit FIFO */ +/* RxOver overflow in Recv FIFO */ +/* SipRcv received serial gap (or other condition you set) */ +/* Interrupts are enabled by writing a one to the IER register */ +/* Interrupts are cleared by writing a one to the ISR register */ +/* */ +/* 6. The remaining registers: 0x6 and 0x3 appear to be */ +/* reserved parts of 16 or 32 bit registersthe remainder */ +/* 0xa 0xb 0x1e 0x1f could possibly be (by their behaviour) */ +/* the Unicast Filter register at $58. */ +/* */ +/* 7. While the core obviously expects 32 bit accesses all the */ +/* M$ drivers do 8 bit accesses, infact the Miniport ones */ +/* write and read back the byte serveral times (why?) */ + + +#ifndef TOSHOBOE_H +#define TOSHOBOE_H + +/* Registers */ + +#define OBOE_IO_EXTENT 0x1f + +/*Receive and transmit slot pointers */ +#define OBOE_REG(i) (i+(self->base)) +#define OBOE_RXSLOT OBOE_REG(0x0) +#define OBOE_TXSLOT OBOE_REG(0x1) +#define OBOE_SLOT_MASK 0x3f + +#define OBOE_TXRING_OFFSET 0x200 +#define OBOE_TXRING_OFFSET_IN_SLOTS 0x40 + +/*pointer to the ring */ +#define OBOE_RING_BASE0 OBOE_REG(0x4) +#define OBOE_RING_BASE1 OBOE_REG(0x5) +#define OBOE_RING_BASE2 OBOE_REG(0x2) +#define OBOE_RING_BASE3 OBOE_REG(0x3) + +/*Number of slots in the ring */ +#define OBOE_RING_SIZE OBOE_REG(0x7) +#define OBOE_RING_SIZE_RX4 0x00 +#define OBOE_RING_SIZE_RX8 0x01 +#define OBOE_RING_SIZE_RX16 0x03 +#define OBOE_RING_SIZE_RX32 0x07 +#define OBOE_RING_SIZE_RX64 0x0f +#define OBOE_RING_SIZE_TX4 0x00 +#define OBOE_RING_SIZE_TX8 0x10 +#define OBOE_RING_SIZE_TX16 0x30 +#define OBOE_RING_SIZE_TX32 0x70 +#define OBOE_RING_SIZE_TX64 0xf0 + +#define OBOE_RING_MAX_SIZE 64 + +/*Causes the gubbins to re-examine the ring */ +#define OBOE_PROMPT OBOE_REG(0x9) +#define OBOE_PROMPT_BIT 0x1 + +/* Interrupt Status Register */ +#define OBOE_ISR OBOE_REG(0xc) +/* Interrupt Enable Register */ +#define OBOE_IER OBOE_REG(0xd) +/* Interrupt bits for IER and ISR */ +#define OBOE_INT_TXDONE 0x80 +#define OBOE_INT_RXDONE 0x40 +#define OBOE_INT_TXUNDER 0x20 +#define OBOE_INT_RXOVER 0x10 +#define OBOE_INT_SIP 0x08 +#define OBOE_INT_MASK 0xf8 + +/*Reset Register */ +#define OBOE_CONFIG1 OBOE_REG(0xe) +#define OBOE_CONFIG1_RST 0x01 +#define OBOE_CONFIG1_DISABLE 0x02 +#define OBOE_CONFIG1_4 0x08 +#define OBOE_CONFIG1_8 0x08 + +#define OBOE_CONFIG1_ON 0x8 +#define OBOE_CONFIG1_RESET 0xf +#define OBOE_CONFIG1_OFF 0xe + +#define OBOE_STATUS OBOE_REG(0xf) +#define OBOE_STATUS_RXBUSY 0x10 +#define OBOE_STATUS_FIRRX 0x04 +#define OBOE_STATUS_MIRRX 0x02 +#define OBOE_STATUS_SIRRX 0x01 + + +/*Speed control registers */ +#define OBOE_CONFIG0L OBOE_REG(0x10) +#define OBOE_CONFIG0H OBOE_REG(0x11) + +#define OBOE_CONFIG0H_TXONLOOP 0x80 /*Transmit when looping (dangerous) */ +#define OBOE_CONFIG0H_LOOP 0x40 /*Loopback Tx->Rx */ +#define OBOE_CONFIG0H_ENTX 0x10 /*Enable Tx */ +#define OBOE_CONFIG0H_ENRX 0x08 /*Enable Rx */ +#define OBOE_CONFIG0H_ENDMAC 0x04 /*Enable/reset* the DMA controller */ +#define OBOE_CONFIG0H_RCVANY 0x02 /*DMA mode 1=bytes, 0=dwords */ + +#define OBOE_CONFIG0L_CRC16 0x80 /*CRC 1=16 bit 0=32 bit */ +#define OBOE_CONFIG0L_ENFIR 0x40 /*Enable FIR */ +#define OBOE_CONFIG0L_ENMIR 0x20 /*Enable MIR */ +#define OBOE_CONFIG0L_ENSIR 0x10 /*Enable SIR */ +#define OBOE_CONFIG0L_ENSIRF 0x08 /*Enable SIR framer */ +#define OBOE_CONFIG0L_SIRTEST 0x04 /*Enable SIR framer in MIR and FIR */ +#define OBOE_CONFIG0L_INVERTTX 0x02 /*Invert Tx Line */ +#define OBOE_CONFIG0L_INVERTRX 0x01 /*Invert Rx Line */ + +#define OBOE_BOF OBOE_REG(0x12) +#define OBOE_EOF OBOE_REG(0x13) + +#define OBOE_ENABLEL OBOE_REG(0x14) +#define OBOE_ENABLEH OBOE_REG(0x15) + +#define OBOE_ENABLEH_PHYANDCLOCK 0x80 /*Toggle low to copy config in */ +#define OBOE_ENABLEH_CONFIGERR 0x40 +#define OBOE_ENABLEH_FIRON 0x20 +#define OBOE_ENABLEH_MIRON 0x10 +#define OBOE_ENABLEH_SIRON 0x08 +#define OBOE_ENABLEH_ENTX 0x04 +#define OBOE_ENABLEH_ENRX 0x02 +#define OBOE_ENABLEH_CRC16 0x01 + +#define OBOE_ENABLEL_BROADCAST 0x01 + +#define OBOE_CURR_PCONFIGL OBOE_REG(0x16) /*Current config */ +#define OBOE_CURR_PCONFIGH OBOE_REG(0x17) + +#define OBOE_NEW_PCONFIGL OBOE_REG(0x18) +#define OBOE_NEW_PCONFIGH OBOE_REG(0x19) + +#define OBOE_PCONFIGH_BAUDMASK 0xfc +#define OBOE_PCONFIGH_WIDTHMASK 0x04 +#define OBOE_PCONFIGL_WIDTHMASK 0xe0 +#define OBOE_PCONFIGL_PREAMBLEMASK 0x1f + +#define OBOE_PCONFIG_BAUDMASK 0xfc00 +#define OBOE_PCONFIG_BAUDSHIFT 10 +#define OBOE_PCONFIG_WIDTHMASK 0x04e0 +#define OBOE_PCONFIG_WIDTHSHIFT 5 +#define OBOE_PCONFIG_PREAMBLEMASK 0x001f +#define OBOE_PCONFIG_PREAMBLESHIFT 0 + +#define OBOE_MAXLENL OBOE_REG(0x1a) +#define OBOE_MAXLENH OBOE_REG(0x1b) + +#define OBOE_RXCOUNTH OBOE_REG(0x1c) /*Reset on recipt */ +#define OBOE_RXCOUNTL OBOE_REG(0x1d) /*of whole packet */ + +/* The PCI ID of the OBOE chip */ +#ifndef PCI_DEVICE_ID_FIR701 +#define PCI_DEVICE_ID_FIR701 0x0701 +#endif + +#ifndef PCI_DEVICE_ID_FIRD01 +#define PCI_DEVICE_ID_FIRD01 0x0d01 +#endif + +struct OboeSlot +{ + __u16 len; /*Tweleve bits of packet length */ + __u8 unused; + __u8 control; /*Slot control/status see below */ + __u32 address; /*Slot buffer address */ +} +__packed; + +#define OBOE_NTASKS OBOE_TXRING_OFFSET_IN_SLOTS + +struct OboeRing +{ + struct OboeSlot rx[OBOE_NTASKS]; + struct OboeSlot tx[OBOE_NTASKS]; +}; + +#define OBOE_RING_LEN (sizeof(struct OboeRing)) + + +#define OBOE_CTL_TX_HW_OWNS 0x80 /*W/R This slot owned by the hardware */ +#define OBOE_CTL_TX_DISTX_CRC 0x40 /*W Disable CRC generation for [FM]IR */ +#define OBOE_CTL_TX_BAD_CRC 0x20 /*W Generate bad CRC */ +#define OBOE_CTL_TX_SIP 0x10 /*W Generate an SIP after xmittion */ +#define OBOE_CTL_TX_MKUNDER 0x08 /*W Generate an underrun error */ +#define OBOE_CTL_TX_RTCENTX 0x04 /*W Enable receiver and generate TXdone */ + /* After this slot is processed */ +#define OBOE_CTL_TX_UNDER 0x01 /*R Set by hardware to indicate underrun */ + + +#define OBOE_CTL_RX_HW_OWNS 0x80 /*W/R This slot owned by hardware */ +#define OBOE_CTL_RX_PHYERR 0x40 /*R Decoder error on receiption */ +#define OBOE_CTL_RX_CRCERR 0x20 /*R CRC error only set for [FM]IR */ +#define OBOE_CTL_RX_LENGTH 0x10 /*R Packet > max Rx length */ +#define OBOE_CTL_RX_OVER 0x08 /*R set to indicate an overflow */ +#define OBOE_CTL_RX_SIRBAD 0x04 /*R SIR had BOF in packet or ABORT sequence */ +#define OBOE_CTL_RX_RXEOF 0x02 /*R Finished receiving on this slot */ + + +struct toshoboe_cb +{ + struct net_device *netdev; /* Yes! we are some kind of netdevice */ + struct tty_driver ttydev; + + struct irlap_cb *irlap; /* The link layer we are binded to */ + + chipio_t io; /* IrDA controller information */ + struct qos_info qos; /* QoS capabilities for this device */ + + __u32 flags; /* Interface flags */ + + struct pci_dev *pdev; /*PCI device */ + int base; /*IO base */ + + + int txpending; /*how many tx's are pending */ + int txs, rxs; /*Which slots are we at */ + + int irdad; /*Driver under control of netdev end */ + int async; /*Driver under control of async end */ + + + int stopped; /*Stopped by some or other APM stuff */ + + int filter; /*In SIR mode do we want to receive + frames or byte ranges */ + + void *ringbuf; /*The ring buffer */ + struct OboeRing *ring; /*The ring */ + + void *tx_bufs[OBOE_RING_MAX_SIZE]; /*The buffers */ + void *rx_bufs[OBOE_RING_MAX_SIZE]; + + + int speed; /*Current setting of the speed */ + int new_speed; /*Set to request a speed change */ + +/* The spinlock protect critical parts of the driver. + * Locking is done like this : + * spin_lock_irqsave(&self->spinlock, flags); + * Releasing the lock : + * spin_unlock_irqrestore(&self->spinlock, flags); + */ + spinlock_t spinlock; + /* Used for the probe and diagnostics code */ + int int_rx; + int int_tx; + int int_txunder; + int int_rxover; + int int_sip; +}; + + +#endif diff --git a/drivers/staging/irda/drivers/esi-sir.c b/drivers/staging/irda/drivers/esi-sir.c new file mode 100644 index 000000000000..019a3e848bcb --- /dev/null +++ b/drivers/staging/irda/drivers/esi-sir.c @@ -0,0 +1,157 @@ +/********************************************************************* + * + * Filename: esi.c + * Version: 1.6 + * Description: Driver for the Extended Systems JetEye PC dongle + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Sat Feb 21 18:54:38 1998 + * Modified at: Sun Oct 27 22:01:04 2002 + * Modified by: Martin Diehl <mad@mdiehl.de> + * + * Copyright (c) 1999 Dag Brattli, <dagb@cs.uit.no>, + * Copyright (c) 1998 Thomas Davis, <ratbert@radiks.net>, + * Copyright (c) 2002 Martin Diehl, <mad@mdiehl.de>, + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + ********************************************************************/ + +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/init.h> + +#include <net/irda/irda.h> + +#include "sir-dev.h" + +static int esi_open(struct sir_dev *); +static int esi_close(struct sir_dev *); +static int esi_change_speed(struct sir_dev *, unsigned); +static int esi_reset(struct sir_dev *); + +static struct dongle_driver esi = { + .owner = THIS_MODULE, + .driver_name = "JetEye PC ESI-9680 PC", + .type = IRDA_ESI_DONGLE, + .open = esi_open, + .close = esi_close, + .reset = esi_reset, + .set_speed = esi_change_speed, +}; + +static int __init esi_sir_init(void) +{ + return irda_register_dongle(&esi); +} + +static void __exit esi_sir_cleanup(void) +{ + irda_unregister_dongle(&esi); +} + +static int esi_open(struct sir_dev *dev) +{ + struct qos_info *qos = &dev->qos; + + /* Power up and set dongle to 9600 baud */ + sirdev_set_dtr_rts(dev, FALSE, TRUE); + + qos->baud_rate.bits &= IR_9600|IR_19200|IR_115200; + qos->min_turn_time.bits = 0x01; /* Needs at least 10 ms */ + irda_qos_bits_to_value(qos); + + /* irda thread waits 50 msec for power settling */ + + return 0; +} + +static int esi_close(struct sir_dev *dev) +{ + /* Power off dongle */ + sirdev_set_dtr_rts(dev, FALSE, FALSE); + + return 0; +} + +/* + * Function esi_change_speed (task) + * + * Set the speed for the Extended Systems JetEye PC ESI-9680 type dongle + * Apparently (see old esi-driver) no delays are needed here... + * + */ +static int esi_change_speed(struct sir_dev *dev, unsigned speed) +{ + int ret = 0; + int dtr, rts; + + switch (speed) { + case 19200: + dtr = TRUE; + rts = FALSE; + break; + case 115200: + dtr = rts = TRUE; + break; + default: + ret = -EINVAL; + speed = 9600; + /* fall through */ + case 9600: + dtr = FALSE; + rts = TRUE; + break; + } + + /* Change speed of dongle */ + sirdev_set_dtr_rts(dev, dtr, rts); + dev->speed = speed; + + return ret; +} + +/* + * Function esi_reset (task) + * + * Reset dongle; + * + */ +static int esi_reset(struct sir_dev *dev) +{ + sirdev_set_dtr_rts(dev, FALSE, FALSE); + + /* Hm, the old esi-driver left the dongle unpowered relying on + * the following speed change to repower. This might work for + * the esi because we only need the modem lines. However, now the + * general rule is reset must bring the dongle to some working + * well-known state because speed change might write to registers. + * The old esi-driver didn't any delay here - let's hope it' fine. + */ + + sirdev_set_dtr_rts(dev, FALSE, TRUE); + dev->speed = 9600; + + return 0; +} + +MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>"); +MODULE_DESCRIPTION("Extended Systems JetEye PC dongle driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("irda-dongle-1"); /* IRDA_ESI_DONGLE */ + +module_init(esi_sir_init); +module_exit(esi_sir_cleanup); + diff --git a/drivers/staging/irda/drivers/girbil-sir.c b/drivers/staging/irda/drivers/girbil-sir.c new file mode 100644 index 000000000000..7e0a5b8c6d53 --- /dev/null +++ b/drivers/staging/irda/drivers/girbil-sir.c @@ -0,0 +1,252 @@ +/********************************************************************* + * + * Filename: girbil.c + * Version: 1.2 + * Description: Implementation for the Greenwich GIrBIL dongle + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Sat Feb 6 21:02:33 1999 + * Modified at: Fri Dec 17 09:13:20 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1999 Dag Brattli, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/init.h> + +#include <net/irda/irda.h> + +#include "sir-dev.h" + +static int girbil_reset(struct sir_dev *dev); +static int girbil_open(struct sir_dev *dev); +static int girbil_close(struct sir_dev *dev); +static int girbil_change_speed(struct sir_dev *dev, unsigned speed); + +/* Control register 1 */ +#define GIRBIL_TXEN 0x01 /* Enable transmitter */ +#define GIRBIL_RXEN 0x02 /* Enable receiver */ +#define GIRBIL_ECAN 0x04 /* Cancel self emitted data */ +#define GIRBIL_ECHO 0x08 /* Echo control characters */ + +/* LED Current Register (0x2) */ +#define GIRBIL_HIGH 0x20 +#define GIRBIL_MEDIUM 0x21 +#define GIRBIL_LOW 0x22 + +/* Baud register (0x3) */ +#define GIRBIL_2400 0x30 +#define GIRBIL_4800 0x31 +#define GIRBIL_9600 0x32 +#define GIRBIL_19200 0x33 +#define GIRBIL_38400 0x34 +#define GIRBIL_57600 0x35 +#define GIRBIL_115200 0x36 + +/* Mode register (0x4) */ +#define GIRBIL_IRDA 0x40 +#define GIRBIL_ASK 0x41 + +/* Control register 2 (0x5) */ +#define GIRBIL_LOAD 0x51 /* Load the new baud rate value */ + +static struct dongle_driver girbil = { + .owner = THIS_MODULE, + .driver_name = "Greenwich GIrBIL", + .type = IRDA_GIRBIL_DONGLE, + .open = girbil_open, + .close = girbil_close, + .reset = girbil_reset, + .set_speed = girbil_change_speed, +}; + +static int __init girbil_sir_init(void) +{ + return irda_register_dongle(&girbil); +} + +static void __exit girbil_sir_cleanup(void) +{ + irda_unregister_dongle(&girbil); +} + +static int girbil_open(struct sir_dev *dev) +{ + struct qos_info *qos = &dev->qos; + + /* Power on dongle */ + sirdev_set_dtr_rts(dev, TRUE, TRUE); + + qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200; + qos->min_turn_time.bits = 0x03; + irda_qos_bits_to_value(qos); + + /* irda thread waits 50 msec for power settling */ + + return 0; +} + +static int girbil_close(struct sir_dev *dev) +{ + /* Power off dongle */ + sirdev_set_dtr_rts(dev, FALSE, FALSE); + + return 0; +} + +/* + * Function girbil_change_speed (dev, speed) + * + * Set the speed for the Girbil type dongle. + * + */ + +#define GIRBIL_STATE_WAIT_SPEED (SIRDEV_STATE_DONGLE_SPEED + 1) + +static int girbil_change_speed(struct sir_dev *dev, unsigned speed) +{ + unsigned state = dev->fsm.substate; + unsigned delay = 0; + u8 control[2]; + static int ret = 0; + + /* dongle alread reset - port and dongle at default speed */ + + switch(state) { + + case SIRDEV_STATE_DONGLE_SPEED: + + /* Set DTR and Clear RTS to enter command mode */ + sirdev_set_dtr_rts(dev, FALSE, TRUE); + + udelay(25); /* better wait a little while */ + + ret = 0; + switch (speed) { + default: + ret = -EINVAL; + /* fall through */ + case 9600: + control[0] = GIRBIL_9600; + break; + case 19200: + control[0] = GIRBIL_19200; + break; + case 34800: + control[0] = GIRBIL_38400; + break; + case 57600: + control[0] = GIRBIL_57600; + break; + case 115200: + control[0] = GIRBIL_115200; + break; + } + control[1] = GIRBIL_LOAD; + + /* Write control bytes */ + sirdev_raw_write(dev, control, 2); + + dev->speed = speed; + + state = GIRBIL_STATE_WAIT_SPEED; + delay = 100; + break; + + case GIRBIL_STATE_WAIT_SPEED: + /* Go back to normal mode */ + sirdev_set_dtr_rts(dev, TRUE, TRUE); + + udelay(25); /* better wait a little while */ + break; + + default: + net_err_ratelimited("%s - undefined state %d\n", + __func__, state); + ret = -EINVAL; + break; + } + dev->fsm.substate = state; + return (delay > 0) ? delay : ret; +} + +/* + * Function girbil_reset (driver) + * + * This function resets the girbil dongle. + * + * Algorithm: + * 0. set RTS, and wait at least 5 ms + * 1. clear RTS + */ + + +#define GIRBIL_STATE_WAIT1_RESET (SIRDEV_STATE_DONGLE_RESET + 1) +#define GIRBIL_STATE_WAIT2_RESET (SIRDEV_STATE_DONGLE_RESET + 2) +#define GIRBIL_STATE_WAIT3_RESET (SIRDEV_STATE_DONGLE_RESET + 3) + +static int girbil_reset(struct sir_dev *dev) +{ + unsigned state = dev->fsm.substate; + unsigned delay = 0; + u8 control = GIRBIL_TXEN | GIRBIL_RXEN; + int ret = 0; + + switch (state) { + case SIRDEV_STATE_DONGLE_RESET: + /* Reset dongle */ + sirdev_set_dtr_rts(dev, TRUE, FALSE); + /* Sleep at least 5 ms */ + delay = 20; + state = GIRBIL_STATE_WAIT1_RESET; + break; + + case GIRBIL_STATE_WAIT1_RESET: + /* Set DTR and clear RTS to enter command mode */ + sirdev_set_dtr_rts(dev, FALSE, TRUE); + delay = 20; + state = GIRBIL_STATE_WAIT2_RESET; + break; + + case GIRBIL_STATE_WAIT2_RESET: + /* Write control byte */ + sirdev_raw_write(dev, &control, 1); + delay = 20; + state = GIRBIL_STATE_WAIT3_RESET; + break; + + case GIRBIL_STATE_WAIT3_RESET: + /* Go back to normal mode */ + sirdev_set_dtr_rts(dev, TRUE, TRUE); + dev->speed = 9600; + break; + + default: + net_err_ratelimited("%s(), undefined state %d\n", + __func__, state); + ret = -1; + break; + } + dev->fsm.substate = state; + return (delay > 0) ? delay : ret; +} + +MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>"); +MODULE_DESCRIPTION("Greenwich GIrBIL dongle driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("irda-dongle-4"); /* IRDA_GIRBIL_DONGLE */ + +module_init(girbil_sir_init); +module_exit(girbil_sir_cleanup); diff --git a/drivers/staging/irda/drivers/irda-usb.c b/drivers/staging/irda/drivers/irda-usb.c new file mode 100644 index 000000000000..723e49bc4baa --- /dev/null +++ b/drivers/staging/irda/drivers/irda-usb.c @@ -0,0 +1,1914 @@ +/***************************************************************************** + * + * Filename: irda-usb.c + * Version: 0.10 + * Description: IrDA-USB Driver + * Status: Experimental + * Author: Dag Brattli <dag@brattli.net> + * + * Copyright (C) 2000, Roman Weissgaerber <weissg@vienna.at> + * Copyright (C) 2001, Dag Brattli <dag@brattli.net> + * Copyright (C) 2001, Jean Tourrilhes <jt@hpl.hp.com> + * Copyright (C) 2004, SigmaTel, Inc. <irquality@sigmatel.com> + * Copyright (C) 2005, Milan Beno <beno@pobox.sk> + * Copyright (C) 2006, Nick Fedchik <nick@fedchik.org.ua> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + *****************************************************************************/ + +/* + * IMPORTANT NOTE + * -------------- + * + * As of kernel 2.5.20, this is the state of compliance and testing of + * this driver (irda-usb) with regards to the USB low level drivers... + * + * This driver has been tested SUCCESSFULLY with the following drivers : + * o usb-uhci-hcd (For Intel/Via USB controllers) + * o uhci-hcd (Alternate/JE driver for Intel/Via USB controllers) + * o ohci-hcd (For other USB controllers) + * + * This driver has NOT been tested with the following drivers : + * o ehci-hcd (USB 2.0 controllers) + * + * Note that all HCD drivers do URB_ZERO_PACKET and timeout properly, + * so we don't have to worry about that anymore. + * One common problem is the failure to set the address on the dongle, + * but this happens before the driver gets loaded... + * + * Jean II + */ + +/*------------------------------------------------------------------*/ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/skbuff.h> +#include <linux/netdevice.h> +#include <linux/slab.h> +#include <linux/rtnetlink.h> +#include <linux/usb.h> +#include <linux/firmware.h> + +#include "irda-usb.h" + +/*------------------------------------------------------------------*/ + +static int qos_mtt_bits = 0; + +/* These are the currently known IrDA USB dongles. Add new dongles here */ +static const struct usb_device_id dongles[] = { + /* ACTiSYS Corp., ACT-IR2000U FIR-USB Adapter */ + { USB_DEVICE(0x9c4, 0x011), .driver_info = IUC_SPEED_BUG | IUC_NO_WINDOW }, + /* Look like ACTiSYS, Report : IBM Corp., IBM UltraPort IrDA */ + { USB_DEVICE(0x4428, 0x012), .driver_info = IUC_SPEED_BUG | IUC_NO_WINDOW }, + /* KC Technology Inc., KC-180 USB IrDA Device */ + { USB_DEVICE(0x50f, 0x180), .driver_info = IUC_SPEED_BUG | IUC_NO_WINDOW }, + /* Extended Systems, Inc., XTNDAccess IrDA USB (ESI-9685) */ + { USB_DEVICE(0x8e9, 0x100), .driver_info = IUC_SPEED_BUG | IUC_NO_WINDOW }, + /* SigmaTel STIR4210/4220/4116 USB IrDA (VFIR) Bridge */ + { USB_DEVICE(0x66f, 0x4210), .driver_info = IUC_STIR421X | IUC_SPEED_BUG }, + { USB_DEVICE(0x66f, 0x4220), .driver_info = IUC_STIR421X | IUC_SPEED_BUG }, + { USB_DEVICE(0x66f, 0x4116), .driver_info = IUC_STIR421X | IUC_SPEED_BUG }, + { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS | + USB_DEVICE_ID_MATCH_INT_SUBCLASS, + .bInterfaceClass = USB_CLASS_APP_SPEC, + .bInterfaceSubClass = USB_CLASS_IRDA, + .driver_info = IUC_DEFAULT, }, + { }, /* The end */ +}; + +/* + * Important note : + * Devices based on the SigmaTel chipset (0x66f, 0x4200) are not designed + * using the "USB-IrDA specification" (yes, there exist such a thing), and + * therefore not supported by this driver (don't add them above). + * There is a Linux driver, stir4200, that support those USB devices. + * Jean II + */ + +MODULE_DEVICE_TABLE(usb, dongles); + +/*------------------------------------------------------------------*/ + +static void irda_usb_init_qos(struct irda_usb_cb *self) ; +static struct irda_class_desc *irda_usb_find_class_desc(struct usb_interface *intf); +static void irda_usb_disconnect(struct usb_interface *intf); +static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self); +static netdev_tx_t irda_usb_hard_xmit(struct sk_buff *skb, + struct net_device *dev); +static int irda_usb_open(struct irda_usb_cb *self); +static void irda_usb_close(struct irda_usb_cb *self); +static void speed_bulk_callback(struct urb *urb); +static void write_bulk_callback(struct urb *urb); +static void irda_usb_receive(struct urb *urb); +static void irda_usb_rx_defer_expired(unsigned long data); +static int irda_usb_net_open(struct net_device *dev); +static int irda_usb_net_close(struct net_device *dev); +static int irda_usb_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +static void irda_usb_net_timeout(struct net_device *dev); + +/************************ TRANSMIT ROUTINES ************************/ +/* + * Receive packets from the IrDA stack and send them on the USB pipe. + * Handle speed change, timeout and lot's of ugliness... + */ + +/*------------------------------------------------------------------*/ +/* + * Function irda_usb_build_header(self, skb, header) + * + * Builds USB-IrDA outbound header + * + * When we send an IrDA frame over an USB pipe, we add to it a 1 byte + * header. This function create this header with the proper values. + * + * Important note : the USB-IrDA spec 1.0 say very clearly in chapter 5.4.2.2 + * that the setting of the link speed and xbof number in this outbound header + * should be applied *AFTER* the frame has been sent. + * Unfortunately, some devices are not compliant with that... It seems that + * reading the spec is far too difficult... + * Jean II + */ +static void irda_usb_build_header(struct irda_usb_cb *self, + __u8 *header, + int force) +{ + /* Here we check if we have an STIR421x chip, + * and if either speed or xbofs (or both) needs + * to be changed. + */ + if (self->capability & IUC_STIR421X && + ((self->new_speed != -1) || (self->new_xbofs != -1))) { + + /* With STIR421x, speed and xBOFs must be set at the same + * time, even if only one of them changes. + */ + if (self->new_speed == -1) + self->new_speed = self->speed ; + + if (self->new_xbofs == -1) + self->new_xbofs = self->xbofs ; + } + + /* Set the link speed */ + if (self->new_speed != -1) { + /* Hum... Ugly hack :-( + * Some device are not compliant with the spec and change + * parameters *before* sending the frame. - Jean II + */ + if ((self->capability & IUC_SPEED_BUG) && + (!force) && (self->speed != -1)) { + /* No speed and xbofs change here + * (we'll do it later in the write callback) */ + pr_debug("%s(), not changing speed yet\n", __func__); + *header = 0; + return; + } + + pr_debug("%s(), changing speed to %d\n", + __func__, self->new_speed); + self->speed = self->new_speed; + /* We will do ` self->new_speed = -1; ' in the completion + * handler just in case the current URB fail - Jean II */ + + switch (self->speed) { + case 2400: + *header = SPEED_2400; + break; + default: + case 9600: + *header = SPEED_9600; + break; + case 19200: + *header = SPEED_19200; + break; + case 38400: + *header = SPEED_38400; + break; + case 57600: + *header = SPEED_57600; + break; + case 115200: + *header = SPEED_115200; + break; + case 576000: + *header = SPEED_576000; + break; + case 1152000: + *header = SPEED_1152000; + break; + case 4000000: + *header = SPEED_4000000; + self->new_xbofs = 0; + break; + case 16000000: + *header = SPEED_16000000; + self->new_xbofs = 0; + break; + } + } else + /* No change */ + *header = 0; + + /* Set the negotiated additional XBOFS */ + if (self->new_xbofs != -1) { + pr_debug("%s(), changing xbofs to %d\n", + __func__, self->new_xbofs); + self->xbofs = self->new_xbofs; + /* We will do ` self->new_xbofs = -1; ' in the completion + * handler just in case the current URB fail - Jean II */ + + switch (self->xbofs) { + case 48: + *header |= 0x10; + break; + case 28: + case 24: /* USB spec 1.0 says 24 */ + *header |= 0x20; + break; + default: + case 12: + *header |= 0x30; + break; + case 5: /* Bug in IrLAP spec? (should be 6) */ + case 6: + *header |= 0x40; + break; + case 3: + *header |= 0x50; + break; + case 2: + *header |= 0x60; + break; + case 1: + *header |= 0x70; + break; + case 0: + *header |= 0x80; + break; + } + } +} + +/* +* calculate turnaround time for SigmaTel header +*/ +static __u8 get_turnaround_time(struct sk_buff *skb) +{ + int turnaround_time = irda_get_mtt(skb); + + if ( turnaround_time == 0 ) + return 0; + else if ( turnaround_time <= 10 ) + return 1; + else if ( turnaround_time <= 50 ) + return 2; + else if ( turnaround_time <= 100 ) + return 3; + else if ( turnaround_time <= 500 ) + return 4; + else if ( turnaround_time <= 1000 ) + return 5; + else if ( turnaround_time <= 5000 ) + return 6; + else + return 7; +} + + +/*------------------------------------------------------------------*/ +/* + * Send a command to change the speed of the dongle + * Need to be called with spinlock on. + */ +static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self) +{ + __u8 *frame; + struct urb *urb; + int ret; + + pr_debug("%s(), speed=%d, xbofs=%d\n", __func__, + self->new_speed, self->new_xbofs); + + /* Grab the speed URB */ + urb = self->speed_urb; + if (urb->status != 0) { + net_warn_ratelimited("%s(), URB still in use!\n", __func__); + return; + } + + /* Allocate the fake frame */ + frame = self->speed_buff; + + /* Set the new speed and xbofs in this fake frame */ + irda_usb_build_header(self, frame, 1); + + if (self->capability & IUC_STIR421X) { + if (frame[0] == 0) return ; // do nothing if no change + frame[1] = 0; // other parameters don't change here + frame[2] = 0; + } + + /* Submit the 0 length IrDA frame to trigger new speed settings */ + usb_fill_bulk_urb(urb, self->usbdev, + usb_sndbulkpipe(self->usbdev, self->bulk_out_ep), + frame, IRDA_USB_SPEED_MTU, + speed_bulk_callback, self); + urb->transfer_buffer_length = self->header_length; + urb->transfer_flags = 0; + + /* Irq disabled -> GFP_ATOMIC */ + if ((ret = usb_submit_urb(urb, GFP_ATOMIC))) { + net_warn_ratelimited("%s(), failed Speed URB\n", __func__); + } +} + +/*------------------------------------------------------------------*/ +/* + * Speed URB callback + * Now, we can only get called for the speed URB. + */ +static void speed_bulk_callback(struct urb *urb) +{ + struct irda_usb_cb *self = urb->context; + + /* We should always have a context */ + IRDA_ASSERT(self != NULL, return;); + /* We should always be called for the speed URB */ + IRDA_ASSERT(urb == self->speed_urb, return;); + + /* Check for timeout and other USB nasties */ + if (urb->status != 0) { + /* I get a lot of -ECONNABORTED = -103 here - Jean II */ + pr_debug("%s(), URB complete status %d, transfer_flags 0x%04X\n", + __func__, urb->status, urb->transfer_flags); + + /* Don't do anything here, that might confuse the USB layer. + * Instead, we will wait for irda_usb_net_timeout(), the + * network layer watchdog, to fix the situation. + * Jean II */ + /* A reset of the dongle might be welcomed here - Jean II */ + return; + } + + /* urb is now available */ + //urb->status = 0; -> tested above + + /* New speed and xbof is now committed in hardware */ + self->new_speed = -1; + self->new_xbofs = -1; + + /* Allow the stack to send more packets */ + netif_wake_queue(self->netdev); +} + +/*------------------------------------------------------------------*/ +/* + * Send an IrDA frame to the USB dongle (for transmission) + */ +static netdev_tx_t irda_usb_hard_xmit(struct sk_buff *skb, + struct net_device *netdev) +{ + struct irda_usb_cb *self = netdev_priv(netdev); + struct urb *urb = self->tx_urb; + unsigned long flags; + s32 speed; + s16 xbofs; + int res, mtt; + + pr_debug("%s() on %s\n", __func__, netdev->name); + + netif_stop_queue(netdev); + + /* Protect us from USB callbacks, net watchdog and else. */ + spin_lock_irqsave(&self->lock, flags); + + /* Check if the device is still there. + * We need to check self->present under the spinlock because + * of irda_usb_disconnect() is synchronous - Jean II */ + if (!self->present) { + pr_debug("%s(), Device is gone...\n", __func__); + goto drop; + } + + /* Check if we need to change the number of xbofs */ + xbofs = irda_get_next_xbofs(skb); + if ((xbofs != self->xbofs) && (xbofs != -1)) { + self->new_xbofs = xbofs; + } + + /* Check if we need to change the speed */ + speed = irda_get_next_speed(skb); + if ((speed != self->speed) && (speed != -1)) { + /* Set the desired speed */ + self->new_speed = speed; + + /* Check for empty frame */ + if (!skb->len) { + /* IrLAP send us an empty frame to make us change the + * speed. Changing speed with the USB adapter is in + * fact sending an empty frame to the adapter, so we + * could just let the present function do its job. + * However, we would wait for min turn time, + * do an extra memcpy and increment packet counters... + * Jean II */ + irda_usb_change_speed_xbofs(self); + netif_trans_update(netdev); + /* Will netif_wake_queue() in callback */ + goto drop; + } + } + + if (urb->status != 0) { + net_warn_ratelimited("%s(), URB still in use!\n", __func__); + goto drop; + } + + skb_copy_from_linear_data(skb, self->tx_buff + self->header_length, skb->len); + + /* Change setting for next frame */ + if (self->capability & IUC_STIR421X) { + __u8 turnaround_time; + __u8* frame = self->tx_buff; + turnaround_time = get_turnaround_time( skb ); + irda_usb_build_header(self, frame, 0); + frame[2] = turnaround_time; + if ((skb->len != 0) && + ((skb->len % 128) == 0) && + ((skb->len % 512) != 0)) { + /* add extra byte for special SigmaTel feature */ + frame[1] = 1; + skb_put(skb, 1); + } else { + frame[1] = 0; + } + } else { + irda_usb_build_header(self, self->tx_buff, 0); + } + + /* FIXME: Make macro out of this one */ + ((struct irda_skb_cb *)skb->cb)->context = self; + + usb_fill_bulk_urb(urb, self->usbdev, + usb_sndbulkpipe(self->usbdev, self->bulk_out_ep), + self->tx_buff, skb->len + self->header_length, + write_bulk_callback, skb); + + /* This flag (URB_ZERO_PACKET) indicates that what we send is not + * a continuous stream of data but separate packets. + * In this case, the USB layer will insert an empty USB frame (TD) + * after each of our packets that is exact multiple of the frame size. + * This is how the dongle will detect the end of packet - Jean II */ + urb->transfer_flags = URB_ZERO_PACKET; + + /* Generate min turn time. FIXME: can we do better than this? */ + /* Trying to a turnaround time at this level is trying to measure + * processor clock cycle with a wrist-watch, approximate at best... + * + * What we know is the last time we received a frame over USB. + * Due to latency over USB that depend on the USB load, we don't + * know when this frame was received over IrDA (a few ms before ?) + * Then, same story for our outgoing frame... + * + * In theory, the USB dongle is supposed to handle the turnaround + * by itself (spec 1.0, chater 4, page 6). Who knows ??? That's + * why this code is enabled only for dongles that doesn't meet + * the spec. + * Jean II */ + if (self->capability & IUC_NO_TURN) { + mtt = irda_get_mtt(skb); + if (mtt) { + int diff; + diff = ktime_us_delta(ktime_get(), self->stamp); +#ifdef IU_USB_MIN_RTT + /* Factor in USB delays -> Get rid of udelay() that + * would be lost in the noise - Jean II */ + diff += IU_USB_MIN_RTT; +#endif /* IU_USB_MIN_RTT */ + + /* Check if the mtt is larger than the time we have + * already used by all the protocol processing + */ + if (mtt > diff) { + mtt -= diff; + if (mtt > 1000) + mdelay(mtt/1000); + else + udelay(mtt); + } + } + } + + /* Ask USB to send the packet - Irq disabled -> GFP_ATOMIC */ + if ((res = usb_submit_urb(urb, GFP_ATOMIC))) { + net_warn_ratelimited("%s(), failed Tx URB\n", __func__); + netdev->stats.tx_errors++; + /* Let USB recover : We will catch that in the watchdog */ + /*netif_start_queue(netdev);*/ + } else { + /* Increment packet stats */ + netdev->stats.tx_packets++; + netdev->stats.tx_bytes += skb->len; + + netif_trans_update(netdev); + } + spin_unlock_irqrestore(&self->lock, flags); + + return NETDEV_TX_OK; + +drop: + /* Drop silently the skb and exit */ + dev_kfree_skb(skb); + spin_unlock_irqrestore(&self->lock, flags); + return NETDEV_TX_OK; +} + +/*------------------------------------------------------------------*/ +/* + * Note : this function will be called only for tx_urb... + */ +static void write_bulk_callback(struct urb *urb) +{ + unsigned long flags; + struct sk_buff *skb = urb->context; + struct irda_usb_cb *self = ((struct irda_skb_cb *) skb->cb)->context; + + /* We should always have a context */ + IRDA_ASSERT(self != NULL, return;); + /* We should always be called for the speed URB */ + IRDA_ASSERT(urb == self->tx_urb, return;); + + /* Free up the skb */ + dev_kfree_skb_any(skb); + urb->context = NULL; + + /* Check for timeout and other USB nasties */ + if (urb->status != 0) { + /* I get a lot of -ECONNABORTED = -103 here - Jean II */ + pr_debug("%s(), URB complete status %d, transfer_flags 0x%04X\n", + __func__, urb->status, urb->transfer_flags); + + /* Don't do anything here, that might confuse the USB layer, + * and we could go in recursion and blow the kernel stack... + * Instead, we will wait for irda_usb_net_timeout(), the + * network layer watchdog, to fix the situation. + * Jean II */ + /* A reset of the dongle might be welcomed here - Jean II */ + return; + } + + /* urb is now available */ + //urb->status = 0; -> tested above + + /* Make sure we read self->present properly */ + spin_lock_irqsave(&self->lock, flags); + + /* If the network is closed, stop everything */ + if ((!self->netopen) || (!self->present)) { + pr_debug("%s(), Network is gone...\n", __func__); + spin_unlock_irqrestore(&self->lock, flags); + return; + } + + /* If changes to speed or xbofs is pending... */ + if ((self->new_speed != -1) || (self->new_xbofs != -1)) { + if ((self->new_speed != self->speed) || + (self->new_xbofs != self->xbofs)) { + /* We haven't changed speed yet (because of + * IUC_SPEED_BUG), so do it now - Jean II */ + pr_debug("%s(), Changing speed now...\n", __func__); + irda_usb_change_speed_xbofs(self); + } else { + /* New speed and xbof is now committed in hardware */ + self->new_speed = -1; + self->new_xbofs = -1; + /* Done, waiting for next packet */ + netif_wake_queue(self->netdev); + } + } else { + /* Otherwise, allow the stack to send more packets */ + netif_wake_queue(self->netdev); + } + spin_unlock_irqrestore(&self->lock, flags); +} + +/*------------------------------------------------------------------*/ +/* + * Watchdog timer from the network layer. + * After a predetermined timeout, if we don't give confirmation that + * the packet has been sent (i.e. no call to netif_wake_queue()), + * the network layer will call this function. + * Note that URB that we submit have also a timeout. When the URB timeout + * expire, the normal URB callback is called (write_bulk_callback()). + */ +static void irda_usb_net_timeout(struct net_device *netdev) +{ + unsigned long flags; + struct irda_usb_cb *self = netdev_priv(netdev); + struct urb *urb; + int done = 0; /* If we have made any progress */ + + pr_debug("%s(), Network layer thinks we timed out!\n", __func__); + IRDA_ASSERT(self != NULL, return;); + + /* Protect us from USB callbacks, net Tx and else. */ + spin_lock_irqsave(&self->lock, flags); + + /* self->present *MUST* be read under spinlock */ + if (!self->present) { + net_warn_ratelimited("%s(), device not present!\n", __func__); + netif_stop_queue(netdev); + spin_unlock_irqrestore(&self->lock, flags); + return; + } + + /* Check speed URB */ + urb = self->speed_urb; + if (urb->status != 0) { + pr_debug("%s: Speed change timed out, urb->status=%d, urb->transfer_flags=0x%04X\n", + netdev->name, urb->status, urb->transfer_flags); + + switch (urb->status) { + case -EINPROGRESS: + usb_unlink_urb(urb); + /* Note : above will *NOT* call netif_wake_queue() + * in completion handler, we will come back here. + * Jean II */ + done = 1; + break; + case -ECONNRESET: + case -ENOENT: /* urb unlinked by us */ + default: /* ??? - Play safe */ + urb->status = 0; + netif_wake_queue(self->netdev); + done = 1; + break; + } + } + + /* Check Tx URB */ + urb = self->tx_urb; + if (urb->status != 0) { + struct sk_buff *skb = urb->context; + + pr_debug("%s: Tx timed out, urb->status=%d, urb->transfer_flags=0x%04X\n", + netdev->name, urb->status, urb->transfer_flags); + + /* Increase error count */ + netdev->stats.tx_errors++; + +#ifdef IU_BUG_KICK_TIMEOUT + /* Can't be a bad idea to reset the speed ;-) - Jean II */ + if(self->new_speed == -1) + self->new_speed = self->speed; + if(self->new_xbofs == -1) + self->new_xbofs = self->xbofs; + irda_usb_change_speed_xbofs(self); +#endif /* IU_BUG_KICK_TIMEOUT */ + + switch (urb->status) { + case -EINPROGRESS: + usb_unlink_urb(urb); + /* Note : above will *NOT* call netif_wake_queue() + * in completion handler, because urb->status will + * be -ENOENT. We will fix that at the next watchdog, + * leaving more time to USB to recover... + * Jean II */ + done = 1; + break; + case -ECONNRESET: + case -ENOENT: /* urb unlinked by us */ + default: /* ??? - Play safe */ + if(skb != NULL) { + dev_kfree_skb_any(skb); + urb->context = NULL; + } + urb->status = 0; + netif_wake_queue(self->netdev); + done = 1; + break; + } + } + spin_unlock_irqrestore(&self->lock, flags); + + /* Maybe we need a reset */ + /* Note : Some drivers seem to use a usb_set_interface() when they + * need to reset the hardware. Hum... + */ + + /* if(done == 0) */ +} + +/************************* RECEIVE ROUTINES *************************/ +/* + * Receive packets from the USB layer stack and pass them to the IrDA stack. + * Try to work around USB failures... + */ + +/* + * Note : + * Some of you may have noticed that most dongle have an interrupt in pipe + * that we don't use. Here is the little secret... + * When we hang a Rx URB on the bulk in pipe, it generates some USB traffic + * in every USB frame. This is unnecessary overhead. + * The interrupt in pipe will generate an event every time a packet is + * received. Reading an interrupt pipe adds minimal overhead, but has some + * latency (~1ms). + * If we are connected (speed != 9600), we want to minimise latency, so + * we just always hang the Rx URB and ignore the interrupt. + * If we are not connected (speed == 9600), there is usually no Rx traffic, + * and we want to minimise the USB overhead. In this case we should wait + * on the interrupt pipe and hang the Rx URB only when an interrupt is + * received. + * Jean II + * + * Note : don't read the above as what we are currently doing, but as + * something we could do with KC dongle. Also don't forget that the + * interrupt pipe is not part of the original standard, so this would + * need to be optional... + * Jean II + */ + +/*------------------------------------------------------------------*/ +/* + * Submit a Rx URB to the USB layer to handle reception of a frame + * Mostly called by the completion callback of the previous URB. + * + * Jean II + */ +static void irda_usb_submit(struct irda_usb_cb *self, struct sk_buff *skb, struct urb *urb) +{ + struct irda_skb_cb *cb; + int ret; + + /* This should never happen */ + IRDA_ASSERT(skb != NULL, return;); + IRDA_ASSERT(urb != NULL, return;); + + /* Save ourselves in the skb */ + cb = (struct irda_skb_cb *) skb->cb; + cb->context = self; + + /* Reinitialize URB */ + usb_fill_bulk_urb(urb, self->usbdev, + usb_rcvbulkpipe(self->usbdev, self->bulk_in_ep), + skb->data, IRDA_SKB_MAX_MTU, + irda_usb_receive, skb); + urb->status = 0; + + /* Can be called from irda_usb_receive (irq handler) -> GFP_ATOMIC */ + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (ret) { + /* If this ever happen, we are in deep s***. + * Basically, the Rx path will stop... */ + net_warn_ratelimited("%s(), Failed to submit Rx URB %d\n", + __func__, ret); + } +} + +/*------------------------------------------------------------------*/ +/* + * Function irda_usb_receive(urb) + * + * Called by the USB subsystem when a frame has been received + * + */ +static void irda_usb_receive(struct urb *urb) +{ + struct sk_buff *skb = (struct sk_buff *) urb->context; + struct irda_usb_cb *self; + struct irda_skb_cb *cb; + struct sk_buff *newskb; + struct sk_buff *dataskb; + struct urb *next_urb; + unsigned int len, docopy; + + pr_debug("%s(), len=%d\n", __func__, urb->actual_length); + + /* Find ourselves */ + cb = (struct irda_skb_cb *) skb->cb; + IRDA_ASSERT(cb != NULL, return;); + self = (struct irda_usb_cb *) cb->context; + IRDA_ASSERT(self != NULL, return;); + + /* If the network is closed or the device gone, stop everything */ + if ((!self->netopen) || (!self->present)) { + pr_debug("%s(), Network is gone!\n", __func__); + /* Don't re-submit the URB : will stall the Rx path */ + return; + } + + /* Check the status */ + if (urb->status != 0) { + switch (urb->status) { + case -EILSEQ: + self->netdev->stats.rx_crc_errors++; + /* Also precursor to a hot-unplug on UHCI. */ + /* Fallthrough... */ + case -ECONNRESET: + /* Random error, if I remember correctly */ + /* uhci_cleanup_unlink() is going to kill the Rx + * URB just after we return. No problem, at this + * point the URB will be idle ;-) - Jean II */ + case -ESHUTDOWN: + /* That's usually a hot-unplug. Submit will fail... */ + case -ETIME: + /* Usually precursor to a hot-unplug on OHCI. */ + default: + self->netdev->stats.rx_errors++; + pr_debug("%s(), RX status %d, transfer_flags 0x%04X\n", + __func__, urb->status, urb->transfer_flags); + break; + } + /* If we received an error, we don't want to resubmit the + * Rx URB straight away but to give the USB layer a little + * bit of breathing room. + * We are in the USB thread context, therefore there is a + * danger of recursion (new URB we submit fails, we come + * back here). + * With recent USB stack (2.6.15+), I'm seeing that on + * hot unplug of the dongle... + * Lowest effective timer is 10ms... + * Jean II */ + self->rx_defer_timer.function = irda_usb_rx_defer_expired; + self->rx_defer_timer.data = (unsigned long) urb; + mod_timer(&self->rx_defer_timer, + jiffies + msecs_to_jiffies(10)); + + return; + } + + /* Check for empty frames */ + if (urb->actual_length <= self->header_length) { + net_warn_ratelimited("%s(), empty frame!\n", __func__); + goto done; + } + + /* + * Remember the time we received this frame, so we can + * reduce the min turn time a bit since we will know + * how much time we have used for protocol processing + */ + self->stamp = ktime_get(); + + /* Check if we need to copy the data to a new skb or not. + * For most frames, we use ZeroCopy and pass the already + * allocated skb up the stack. + * If the frame is small, it is more efficient to copy it + * to save memory (copy will be fast anyway - that's + * called Rx-copy-break). Jean II */ + docopy = (urb->actual_length < IRDA_RX_COPY_THRESHOLD); + + /* Allocate a new skb */ + if (self->capability & IUC_STIR421X) + newskb = dev_alloc_skb(docopy ? urb->actual_length : + IRDA_SKB_MAX_MTU + + USB_IRDA_STIR421X_HEADER); + else + newskb = dev_alloc_skb(docopy ? urb->actual_length : + IRDA_SKB_MAX_MTU); + + if (!newskb) { + self->netdev->stats.rx_dropped++; + /* We could deliver the current skb, but this would stall + * the Rx path. Better drop the packet... Jean II */ + goto done; + } + + /* Make sure IP header get aligned (IrDA header is 5 bytes) */ + /* But IrDA-USB header is 1 byte. Jean II */ + //skb_reserve(newskb, USB_IRDA_HEADER - 1); + + if(docopy) { + /* Copy packet, so we can recycle the original */ + skb_copy_from_linear_data(skb, newskb->data, urb->actual_length); + /* Deliver this new skb */ + dataskb = newskb; + /* And hook the old skb to the URB + * Note : we don't need to "clean up" the old skb, + * as we never touched it. Jean II */ + } else { + /* We are using ZeroCopy. Deliver old skb */ + dataskb = skb; + /* And hook the new skb to the URB */ + skb = newskb; + } + + /* Set proper length on skb & remove USB-IrDA header */ + skb_put(dataskb, urb->actual_length); + skb_pull(dataskb, self->header_length); + + /* Ask the networking layer to queue the packet for the IrDA stack */ + dataskb->dev = self->netdev; + skb_reset_mac_header(dataskb); + dataskb->protocol = htons(ETH_P_IRDA); + len = dataskb->len; + netif_rx(dataskb); + + /* Keep stats up to date */ + self->netdev->stats.rx_bytes += len; + self->netdev->stats.rx_packets++; + +done: + /* Note : at this point, the URB we've just received (urb) + * is still referenced by the USB layer. For example, if we + * have received a -ECONNRESET, uhci_cleanup_unlink() will + * continue to process it (in fact, cleaning it up). + * If we were to submit this URB, disaster would ensue. + * Therefore, we submit our idle URB, and put this URB in our + * idle slot.... + * Jean II */ + /* Note : with this scheme, we could submit the idle URB before + * processing the Rx URB. I don't think it would buy us anything as + * we are running in the USB thread context. Jean II */ + next_urb = self->idle_rx_urb; + + /* Recycle Rx URB : Now, the idle URB is the present one */ + urb->context = NULL; + self->idle_rx_urb = urb; + + /* Submit the idle URB to replace the URB we've just received. + * Do it last to avoid race conditions... Jean II */ + irda_usb_submit(self, skb, next_urb); +} + +/*------------------------------------------------------------------*/ +/* + * In case of errors, we want the USB layer to have time to recover. + * Now, it is time to resubmit ouur Rx URB... + */ +static void irda_usb_rx_defer_expired(unsigned long data) +{ + struct urb *urb = (struct urb *) data; + struct sk_buff *skb = (struct sk_buff *) urb->context; + struct irda_usb_cb *self; + struct irda_skb_cb *cb; + struct urb *next_urb; + + /* Find ourselves */ + cb = (struct irda_skb_cb *) skb->cb; + IRDA_ASSERT(cb != NULL, return;); + self = (struct irda_usb_cb *) cb->context; + IRDA_ASSERT(self != NULL, return;); + + /* Same stuff as when Rx is done, see above... */ + next_urb = self->idle_rx_urb; + urb->context = NULL; + self->idle_rx_urb = urb; + irda_usb_submit(self, skb, next_urb); +} + +/*------------------------------------------------------------------*/ +/* + * Callbak from IrDA layer. IrDA wants to know if we have + * started receiving anything. + */ +static int irda_usb_is_receiving(struct irda_usb_cb *self) +{ + /* Note : because of the way UHCI works, it's almost impossible + * to get this info. The Controller DMA directly to memory and + * signal only when the whole frame is finished. To know if the + * first TD of the URB has been filled or not seems hard work... + * + * The other solution would be to use the "receiving" command + * on the default decriptor with a usb_control_msg(), but that + * would add USB traffic and would return result only in the + * next USB frame (~1ms). + * + * I've been told that current dongles send status info on their + * interrupt endpoint, and that's what the Windows driver uses + * to know this info. Unfortunately, this is not yet in the spec... + * + * Jean II + */ + + return 0; /* For now */ +} + +#define STIR421X_PATCH_PRODUCT_VER "Product Version: " +#define STIR421X_PATCH_STMP_TAG "STMP" +#define STIR421X_PATCH_CODE_OFFSET 512 /* patch image starts before here */ +/* marks end of patch file header (PC DOS text file EOF character) */ +#define STIR421X_PATCH_END_OF_HDR_TAG 0x1A +#define STIR421X_PATCH_BLOCK_SIZE 1023 + +/* + * Function stir421x_fwupload (struct irda_usb_cb *self, + * unsigned char *patch, + * const unsigned int patch_len) + * + * Upload firmware code to SigmaTel 421X IRDA-USB dongle + */ +static int stir421x_fw_upload(struct irda_usb_cb *self, + const unsigned char *patch, + const unsigned int patch_len) +{ + int ret = -ENOMEM; + int actual_len = 0; + unsigned int i; + unsigned int block_size = 0; + unsigned char *patch_block; + + patch_block = kzalloc(STIR421X_PATCH_BLOCK_SIZE, GFP_KERNEL); + if (patch_block == NULL) + return -ENOMEM; + + /* break up patch into 1023-byte sections */ + for (i = 0; i < patch_len; i += block_size) { + block_size = patch_len - i; + + if (block_size > STIR421X_PATCH_BLOCK_SIZE) + block_size = STIR421X_PATCH_BLOCK_SIZE; + + /* upload the patch section */ + memcpy(patch_block, patch + i, block_size); + + ret = usb_bulk_msg(self->usbdev, + usb_sndbulkpipe(self->usbdev, + self->bulk_out_ep), + patch_block, block_size, + &actual_len, msecs_to_jiffies(500)); + pr_debug("%s(): Bulk send %u bytes, ret=%d\n", + __func__, actual_len, ret); + + if (ret < 0) + break; + + mdelay(10); + } + + kfree(patch_block); + + return ret; + } + +/* + * Function stir421x_patch_device(struct irda_usb_cb *self) + * + * Get a firmware code from userspase using hotplug request_firmware() call + */ +static int stir421x_patch_device(struct irda_usb_cb *self) +{ + unsigned int i; + int ret; + char stir421x_fw_name[12]; + const struct firmware *fw; + const unsigned char *fw_version_ptr; /* pointer to version string */ + unsigned long fw_version = 0; + + /* + * Known firmware patch file names for STIR421x dongles + * are "42101001.sb" or "42101002.sb" + */ + sprintf(stir421x_fw_name, "4210%4X.sb", + le16_to_cpu(self->usbdev->descriptor.bcdDevice)); + ret = request_firmware(&fw, stir421x_fw_name, &self->usbdev->dev); + if (ret < 0) + return ret; + + /* We get a patch from userspace */ + net_info_ratelimited("%s(): Received firmware %s (%zu bytes)\n", + __func__, stir421x_fw_name, fw->size); + + ret = -EINVAL; + + /* Get the bcd product version */ + if (!memcmp(fw->data, STIR421X_PATCH_PRODUCT_VER, + sizeof(STIR421X_PATCH_PRODUCT_VER) - 1)) { + fw_version_ptr = fw->data + + sizeof(STIR421X_PATCH_PRODUCT_VER) - 1; + + /* Let's check if the product version is dotted */ + if (fw_version_ptr[3] == '.' && + fw_version_ptr[7] == '.') { + unsigned long major, minor, build; + major = simple_strtoul(fw_version_ptr, NULL, 10); + minor = simple_strtoul(fw_version_ptr + 4, NULL, 10); + build = simple_strtoul(fw_version_ptr + 8, NULL, 10); + + fw_version = (major << 12) + + (minor << 8) + + ((build / 10) << 4) + + (build % 10); + + pr_debug("%s(): Firmware Product version %ld\n", + __func__, fw_version); + } + } + + if (self->usbdev->descriptor.bcdDevice == cpu_to_le16(fw_version)) { + /* + * If we're here, we've found a correct patch + * The actual image starts after the "STMP" keyword + * so forward to the firmware header tag + */ + for (i = 0; i < fw->size && fw->data[i] != + STIR421X_PATCH_END_OF_HDR_TAG; i++) ; + /* here we check for the out of buffer case */ + if (i < STIR421X_PATCH_CODE_OFFSET && i < fw->size && + STIR421X_PATCH_END_OF_HDR_TAG == fw->data[i]) { + if (!memcmp(fw->data + i + 1, STIR421X_PATCH_STMP_TAG, + sizeof(STIR421X_PATCH_STMP_TAG) - 1)) { + + /* We can upload the patch to the target */ + i += sizeof(STIR421X_PATCH_STMP_TAG); + ret = stir421x_fw_upload(self, &fw->data[i], + fw->size - i); + } + } + } + + release_firmware(fw); + + return ret; +} + + +/********************** IRDA DEVICE CALLBACKS **********************/ +/* + * Main calls from the IrDA/Network subsystem. + * Mostly registering a new irda-usb device and removing it.... + * We only deal with the IrDA side of the business, the USB side will + * be dealt with below... + */ + + +/*------------------------------------------------------------------*/ +/* + * Function irda_usb_net_open (dev) + * + * Network device is taken up. Usually this is done by "ifconfig irda0 up" + * + * Note : don't mess with self->netopen - Jean II + */ +static int irda_usb_net_open(struct net_device *netdev) +{ + struct irda_usb_cb *self; + unsigned long flags; + char hwname[16]; + int i; + + IRDA_ASSERT(netdev != NULL, return -1;); + self = netdev_priv(netdev); + IRDA_ASSERT(self != NULL, return -1;); + + spin_lock_irqsave(&self->lock, flags); + /* Can only open the device if it's there */ + if(!self->present) { + spin_unlock_irqrestore(&self->lock, flags); + net_warn_ratelimited("%s(), device not present!\n", __func__); + return -1; + } + + if(self->needspatch) { + spin_unlock_irqrestore(&self->lock, flags); + net_warn_ratelimited("%s(), device needs patch\n", __func__); + return -EIO ; + } + + /* Initialise default speed and xbofs value + * (IrLAP will change that soon) */ + self->speed = -1; + self->xbofs = -1; + self->new_speed = -1; + self->new_xbofs = -1; + + /* To do *before* submitting Rx urbs and starting net Tx queue + * Jean II */ + self->netopen = 1; + spin_unlock_irqrestore(&self->lock, flags); + + /* + * Now that everything should be initialized properly, + * Open new IrLAP layer instance to take care of us... + * Note : will send immediately a speed change... + */ + sprintf(hwname, "usb#%d", self->usbdev->devnum); + self->irlap = irlap_open(netdev, &self->qos, hwname); + IRDA_ASSERT(self->irlap != NULL, return -1;); + + /* Allow IrLAP to send data to us */ + netif_start_queue(netdev); + + /* We submit all the Rx URB except for one that we keep idle. + * Need to be initialised before submitting other USBs, because + * in some cases as soon as we submit the URBs the USB layer + * will trigger a dummy receive - Jean II */ + self->idle_rx_urb = self->rx_urb[IU_MAX_ACTIVE_RX_URBS]; + self->idle_rx_urb->context = NULL; + + /* Now that we can pass data to IrLAP, allow the USB layer + * to send us some data... */ + for (i = 0; i < IU_MAX_ACTIVE_RX_URBS; i++) { + struct sk_buff *skb = dev_alloc_skb(IRDA_SKB_MAX_MTU); + if (!skb) { + /* If this ever happen, we are in deep s***. + * Basically, we can't start the Rx path... */ + return -1; + } + //skb_reserve(newskb, USB_IRDA_HEADER - 1); + irda_usb_submit(self, skb, self->rx_urb[i]); + } + + /* Ready to play !!! */ + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * Function irda_usb_net_close (self) + * + * Network device is taken down. Usually this is done by + * "ifconfig irda0 down" + */ +static int irda_usb_net_close(struct net_device *netdev) +{ + struct irda_usb_cb *self; + int i; + + IRDA_ASSERT(netdev != NULL, return -1;); + self = netdev_priv(netdev); + IRDA_ASSERT(self != NULL, return -1;); + + /* Clear this flag *before* unlinking the urbs and *before* + * stopping the network Tx queue - Jean II */ + self->netopen = 0; + + /* Stop network Tx queue */ + netif_stop_queue(netdev); + + /* Kill defered Rx URB */ + del_timer(&self->rx_defer_timer); + + /* Deallocate all the Rx path buffers (URBs and skb) */ + for (i = 0; i < self->max_rx_urb; i++) { + struct urb *urb = self->rx_urb[i]; + struct sk_buff *skb = (struct sk_buff *) urb->context; + /* Cancel the receive command */ + usb_kill_urb(urb); + /* The skb is ours, free it */ + if(skb) { + dev_kfree_skb(skb); + urb->context = NULL; + } + } + /* Cancel Tx and speed URB - need to be synchronous to avoid races */ + usb_kill_urb(self->tx_urb); + usb_kill_urb(self->speed_urb); + + /* Stop and remove instance of IrLAP */ + if (self->irlap) + irlap_close(self->irlap); + self->irlap = NULL; + + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * IOCTLs : Extra out-of-band network commands... + */ +static int irda_usb_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + unsigned long flags; + struct if_irda_req *irq = (struct if_irda_req *) rq; + struct irda_usb_cb *self; + int ret = 0; + + IRDA_ASSERT(dev != NULL, return -1;); + self = netdev_priv(dev); + IRDA_ASSERT(self != NULL, return -1;); + + pr_debug("%s(), %s, (cmd=0x%X)\n", __func__, dev->name, cmd); + + switch (cmd) { + case SIOCSBANDWIDTH: /* Set bandwidth */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + /* Protect us from USB callbacks, net watchdog and else. */ + spin_lock_irqsave(&self->lock, flags); + /* Check if the device is still there */ + if(self->present) { + /* Set the desired speed */ + self->new_speed = irq->ifr_baudrate; + irda_usb_change_speed_xbofs(self); + } + spin_unlock_irqrestore(&self->lock, flags); + break; + case SIOCSMEDIABUSY: /* Set media busy */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + /* Check if the IrDA stack is still there */ + if(self->netopen) + irda_device_set_media_busy(self->netdev, TRUE); + break; + case SIOCGRECEIVING: /* Check if we are receiving right now */ + irq->ifr_receiving = irda_usb_is_receiving(self); + break; + default: + ret = -EOPNOTSUPP; + } + + return ret; +} + +/*------------------------------------------------------------------*/ + +/********************* IRDA CONFIG SUBROUTINES *********************/ +/* + * Various subroutines dealing with IrDA and network stuff we use to + * configure and initialise each irda-usb instance. + * These functions are used below in the main calls of the driver... + */ + +/*------------------------------------------------------------------*/ +/* + * Set proper values in the IrDA QOS structure + */ +static inline void irda_usb_init_qos(struct irda_usb_cb *self) +{ + struct irda_class_desc *desc; + + + desc = self->irda_desc; + + /* Initialize QoS for this device */ + irda_init_max_qos_capabilies(&self->qos); + + /* See spec section 7.2 for meaning. + * Values are little endian (as most USB stuff), the IrDA stack + * use it in native order (see parameters.c). - Jean II */ + self->qos.baud_rate.bits = le16_to_cpu(desc->wBaudRate); + self->qos.min_turn_time.bits = desc->bmMinTurnaroundTime; + self->qos.additional_bofs.bits = desc->bmAdditionalBOFs; + self->qos.window_size.bits = desc->bmWindowSize; + self->qos.data_size.bits = desc->bmDataSize; + + pr_debug("%s(), dongle says speed=0x%X, size=0x%X, window=0x%X, bofs=0x%X, turn=0x%X\n", + __func__, self->qos.baud_rate.bits, self->qos.data_size.bits, + self->qos.window_size.bits, self->qos.additional_bofs.bits, + self->qos.min_turn_time.bits); + + /* Don't always trust what the dongle tell us */ + if(self->capability & IUC_SIR_ONLY) + self->qos.baud_rate.bits &= 0x00ff; + if(self->capability & IUC_SMALL_PKT) + self->qos.data_size.bits = 0x07; + if(self->capability & IUC_NO_WINDOW) + self->qos.window_size.bits = 0x01; + if(self->capability & IUC_MAX_WINDOW) + self->qos.window_size.bits = 0x7f; + if(self->capability & IUC_MAX_XBOFS) + self->qos.additional_bofs.bits = 0x01; + +#if 1 + /* Module parameter can override the rx window size */ + if (qos_mtt_bits) + self->qos.min_turn_time.bits = qos_mtt_bits; +#endif + /* + * Note : most of those values apply only for the receive path, + * the transmit path will be set differently - Jean II + */ + irda_qos_bits_to_value(&self->qos); +} + +/*------------------------------------------------------------------*/ +static const struct net_device_ops irda_usb_netdev_ops = { + .ndo_open = irda_usb_net_open, + .ndo_stop = irda_usb_net_close, + .ndo_do_ioctl = irda_usb_net_ioctl, + .ndo_start_xmit = irda_usb_hard_xmit, + .ndo_tx_timeout = irda_usb_net_timeout, +}; + +/* + * Initialise the network side of the irda-usb instance + * Called when a new USB instance is registered in irda_usb_probe() + */ +static inline int irda_usb_open(struct irda_usb_cb *self) +{ + struct net_device *netdev = self->netdev; + + netdev->netdev_ops = &irda_usb_netdev_ops; + + irda_usb_init_qos(self); + + return register_netdev(netdev); +} + +/*------------------------------------------------------------------*/ +/* + * Cleanup the network side of the irda-usb instance + * Called when a USB instance is removed in irda_usb_disconnect() + */ +static inline void irda_usb_close(struct irda_usb_cb *self) +{ + /* Remove netdevice */ + unregister_netdev(self->netdev); + + /* Remove the speed buffer */ + kfree(self->speed_buff); + self->speed_buff = NULL; + + kfree(self->tx_buff); + self->tx_buff = NULL; +} + +/********************** USB CONFIG SUBROUTINES **********************/ +/* + * Various subroutines dealing with USB stuff we use to configure and + * initialise each irda-usb instance. + * These functions are used below in the main calls of the driver... + */ + +/*------------------------------------------------------------------*/ +/* + * Function irda_usb_parse_endpoints(dev, ifnum) + * + * Parse the various endpoints and find the one we need. + * + * The endpoint are the pipes used to communicate with the USB device. + * The spec defines 2 endpoints of type bulk transfer, one in, and one out. + * These are used to pass frames back and forth with the dongle. + * Most dongle have also an interrupt endpoint, that will be probably + * documented in the next spec... + */ +static inline int irda_usb_parse_endpoints(struct irda_usb_cb *self, struct usb_host_endpoint *endpoint, int ennum) +{ + int i; /* Endpoint index in table */ + + /* Init : no endpoints */ + self->bulk_in_ep = 0; + self->bulk_out_ep = 0; + self->bulk_int_ep = 0; + + /* Let's look at all those endpoints */ + for(i = 0; i < ennum; i++) { + /* All those variables will get optimised by the compiler, + * so let's aim for clarity... - Jean II */ + __u8 ep; /* Endpoint address */ + __u8 dir; /* Endpoint direction */ + __u8 attr; /* Endpoint attribute */ + __u16 psize; /* Endpoint max packet size in bytes */ + + /* Get endpoint address, direction and attribute */ + ep = endpoint[i].desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; + dir = endpoint[i].desc.bEndpointAddress & USB_ENDPOINT_DIR_MASK; + attr = endpoint[i].desc.bmAttributes; + psize = le16_to_cpu(endpoint[i].desc.wMaxPacketSize); + + /* Is it a bulk endpoint ??? */ + if(attr == USB_ENDPOINT_XFER_BULK) { + /* We need to find an IN and an OUT */ + if(dir == USB_DIR_IN) { + /* This is our Rx endpoint */ + self->bulk_in_ep = ep; + } else { + /* This is our Tx endpoint */ + self->bulk_out_ep = ep; + self->bulk_out_mtu = psize; + } + } else { + if((attr == USB_ENDPOINT_XFER_INT) && + (dir == USB_DIR_IN)) { + /* This is our interrupt endpoint */ + self->bulk_int_ep = ep; + } else { + net_err_ratelimited("%s(), Unrecognised endpoint %02X\n", + __func__, ep); + } + } + } + + pr_debug("%s(), And our endpoints are : in=%02X, out=%02X (%d), int=%02X\n", + __func__, self->bulk_in_ep, self->bulk_out_ep, + self->bulk_out_mtu, self->bulk_int_ep); + + return (self->bulk_in_ep != 0) && (self->bulk_out_ep != 0); +} + +#ifdef IU_DUMP_CLASS_DESC +/*------------------------------------------------------------------*/ +/* + * Function usb_irda_dump_class_desc(desc) + * + * Prints out the contents of the IrDA class descriptor + * + */ +static inline void irda_usb_dump_class_desc(struct irda_class_desc *desc) +{ + /* Values are little endian */ + printk("bLength=%x\n", desc->bLength); + printk("bDescriptorType=%x\n", desc->bDescriptorType); + printk("bcdSpecRevision=%x\n", le16_to_cpu(desc->bcdSpecRevision)); + printk("bmDataSize=%x\n", desc->bmDataSize); + printk("bmWindowSize=%x\n", desc->bmWindowSize); + printk("bmMinTurnaroundTime=%d\n", desc->bmMinTurnaroundTime); + printk("wBaudRate=%x\n", le16_to_cpu(desc->wBaudRate)); + printk("bmAdditionalBOFs=%x\n", desc->bmAdditionalBOFs); + printk("bIrdaRateSniff=%x\n", desc->bIrdaRateSniff); + printk("bMaxUnicastList=%x\n", desc->bMaxUnicastList); +} +#endif /* IU_DUMP_CLASS_DESC */ + +/*------------------------------------------------------------------*/ +/* + * Function irda_usb_find_class_desc(intf) + * + * Returns instance of IrDA class descriptor, or NULL if not found + * + * The class descriptor is some extra info that IrDA USB devices will + * offer to us, describing their IrDA characteristics. We will use that in + * irda_usb_init_qos() + */ +static inline struct irda_class_desc *irda_usb_find_class_desc(struct usb_interface *intf) +{ + struct usb_device *dev = interface_to_usbdev (intf); + struct irda_class_desc *desc; + int ret; + + desc = kzalloc(sizeof(*desc), GFP_KERNEL); + if (!desc) + return NULL; + + /* USB-IrDA class spec 1.0: + * 6.1.3: Standard "Get Descriptor" Device Request is not + * appropriate to retrieve class-specific descriptor + * 6.2.5: Class Specific "Get Class Descriptor" Interface Request + * is mandatory and returns the USB-IrDA class descriptor + */ + + ret = usb_control_msg(dev, usb_rcvctrlpipe(dev,0), + IU_REQ_GET_CLASS_DESC, + USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, + 0, intf->altsetting->desc.bInterfaceNumber, desc, + sizeof(*desc), 500); + + pr_debug("%s(), ret=%d\n", __func__, ret); + if (ret < sizeof(*desc)) { + net_warn_ratelimited("usb-irda: class_descriptor read %s (%d)\n", + ret < 0 ? "failed" : "too short", ret); + } + else if (desc->bDescriptorType != USB_DT_IRDA) { + net_warn_ratelimited("usb-irda: bad class_descriptor type\n"); + } + else { +#ifdef IU_DUMP_CLASS_DESC + irda_usb_dump_class_desc(desc); +#endif /* IU_DUMP_CLASS_DESC */ + + return desc; + } + kfree(desc); + return NULL; +} + +/*********************** USB DEVICE CALLBACKS ***********************/ +/* + * Main calls from the USB subsystem. + * Mostly registering a new irda-usb device and removing it.... + */ + +/*------------------------------------------------------------------*/ +/* + * This routine is called by the USB subsystem for each new device + * in the system. We need to check if the device is ours, and in + * this case start handling it. + * The USB layer protect us from reentrancy (via BKL), so we don't need + * to spinlock in there... Jean II + */ +static int irda_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct net_device *net; + struct usb_device *dev = interface_to_usbdev(intf); + struct irda_usb_cb *self; + struct usb_host_interface *interface; + struct irda_class_desc *irda_desc; + int ret = -ENOMEM; + int i; /* Driver instance index / Rx URB index */ + + /* Note : the probe make sure to call us only for devices that + * matches the list of dongle (top of the file). So, we + * don't need to check if the dongle is really ours. + * Jean II */ + + net_info_ratelimited("IRDA-USB found at address %d, Vendor: %x, Product: %x\n", + dev->devnum, le16_to_cpu(dev->descriptor.idVendor), + le16_to_cpu(dev->descriptor.idProduct)); + + net = alloc_irdadev(sizeof(*self)); + if (!net) + goto err_out; + + SET_NETDEV_DEV(net, &intf->dev); + self = netdev_priv(net); + self->netdev = net; + spin_lock_init(&self->lock); + init_timer(&self->rx_defer_timer); + + self->capability = id->driver_info; + self->needspatch = ((self->capability & IUC_STIR421X) != 0); + + /* Create all of the needed urbs */ + if (self->capability & IUC_STIR421X) { + self->max_rx_urb = IU_SIGMATEL_MAX_RX_URBS; + self->header_length = USB_IRDA_STIR421X_HEADER; + } else { + self->max_rx_urb = IU_MAX_RX_URBS; + self->header_length = USB_IRDA_HEADER; + } + + self->rx_urb = kcalloc(self->max_rx_urb, sizeof(struct urb *), + GFP_KERNEL); + if (!self->rx_urb) + goto err_free_net; + + for (i = 0; i < self->max_rx_urb; i++) { + self->rx_urb[i] = usb_alloc_urb(0, GFP_KERNEL); + if (!self->rx_urb[i]) { + goto err_out_1; + } + } + self->tx_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!self->tx_urb) { + goto err_out_1; + } + self->speed_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!self->speed_urb) { + goto err_out_2; + } + + /* Is this really necessary? (no, except maybe for broken devices) */ + if (usb_reset_configuration (dev) < 0) { + dev_err(&intf->dev, "reset_configuration failed\n"); + ret = -EIO; + goto err_out_3; + } + + /* Is this really necessary? */ + /* Note : some driver do hardcode the interface number, some others + * specify an alternate, but very few driver do like this. + * Jean II */ + ret = usb_set_interface(dev, intf->altsetting->desc.bInterfaceNumber, 0); + pr_debug("usb-irda: set interface %d result %d\n", + intf->altsetting->desc.bInterfaceNumber, ret); + switch (ret) { + case 0: + break; + case -EPIPE: /* -EPIPE = -32 */ + /* Martin Diehl says if we get a -EPIPE we should + * be fine and we don't need to do a usb_clear_halt(). + * - Jean II */ + pr_debug("%s(), Received -EPIPE, ignoring...\n", + __func__); + break; + default: + pr_debug("%s(), Unknown error %d\n", __func__, ret); + ret = -EIO; + goto err_out_3; + } + + /* Find our endpoints */ + interface = intf->cur_altsetting; + if(!irda_usb_parse_endpoints(self, interface->endpoint, + interface->desc.bNumEndpoints)) { + net_err_ratelimited("%s(), Bogus endpoints...\n", __func__); + ret = -EIO; + goto err_out_3; + } + + self->usbdev = dev; + + /* Find IrDA class descriptor */ + irda_desc = irda_usb_find_class_desc(intf); + ret = -ENODEV; + if (!irda_desc) + goto err_out_3; + + if (self->needspatch) { + ret = usb_control_msg (self->usbdev, usb_sndctrlpipe (self->usbdev, 0), + 0x02, 0x40, 0, 0, NULL, 0, 500); + if (ret < 0) { + pr_debug("usb_control_msg failed %d\n", ret); + goto err_out_3; + } else { + mdelay(10); + } + } + + self->irda_desc = irda_desc; + self->present = 1; + self->netopen = 0; + self->usbintf = intf; + + /* Allocate the buffer for speed changes */ + /* Don't change this buffer size and allocation without doing + * some heavy and complete testing. Don't ask why :-( + * Jean II */ + ret = -ENOMEM; + self->speed_buff = kzalloc(IRDA_USB_SPEED_MTU, GFP_KERNEL); + if (!self->speed_buff) + goto err_out_3; + + self->tx_buff = kzalloc(IRDA_SKB_MAX_MTU + self->header_length, + GFP_KERNEL); + if (!self->tx_buff) + goto err_out_4; + + ret = irda_usb_open(self); + if (ret) + goto err_out_5; + + net_info_ratelimited("IrDA: Registered device %s\n", net->name); + usb_set_intfdata(intf, self); + + if (self->needspatch) { + /* Now we fetch and upload the firmware patch */ + ret = stir421x_patch_device(self); + self->needspatch = (ret < 0); + if (self->needspatch) { + net_err_ratelimited("STIR421X: Couldn't upload patch\n"); + goto err_out_6; + } + + /* replace IrDA class descriptor with what patched device is now reporting */ + irda_desc = irda_usb_find_class_desc (self->usbintf); + if (!irda_desc) { + ret = -ENODEV; + goto err_out_6; + } + kfree(self->irda_desc); + self->irda_desc = irda_desc; + irda_usb_init_qos(self); + } + + return 0; +err_out_6: + unregister_netdev(self->netdev); +err_out_5: + kfree(self->tx_buff); +err_out_4: + kfree(self->speed_buff); +err_out_3: + /* Free all urbs that we may have created */ + usb_free_urb(self->speed_urb); +err_out_2: + usb_free_urb(self->tx_urb); +err_out_1: + for (i = 0; i < self->max_rx_urb; i++) + usb_free_urb(self->rx_urb[i]); + kfree(self->rx_urb); +err_free_net: + free_netdev(net); +err_out: + return ret; +} + +/*------------------------------------------------------------------*/ +/* + * The current irda-usb device is removed, the USB layer tell us + * to shut it down... + * One of the constraints is that when we exit this function, + * we cannot use the usb_device no more. Gone. Destroyed. kfree(). + * Most other subsystem allow you to destroy the instance at a time + * when it's convenient to you, to postpone it to a later date, but + * not the USB subsystem. + * So, we must make bloody sure that everything gets deactivated. + * Jean II + */ +static void irda_usb_disconnect(struct usb_interface *intf) +{ + unsigned long flags; + struct irda_usb_cb *self = usb_get_intfdata(intf); + int i; + + usb_set_intfdata(intf, NULL); + if (!self) + return; + + /* Make sure that the Tx path is not executing. - Jean II */ + spin_lock_irqsave(&self->lock, flags); + + /* Oups ! We are not there any more. + * This will stop/desactivate the Tx path. - Jean II */ + self->present = 0; + + /* Kill defered Rx URB */ + del_timer(&self->rx_defer_timer); + + /* We need to have irq enabled to unlink the URBs. That's OK, + * at this point the Tx path is gone - Jean II */ + spin_unlock_irqrestore(&self->lock, flags); + + /* Hum... Check if networking is still active (avoid races) */ + if((self->netopen) || (self->irlap)) { + /* Accept no more transmissions */ + /*netif_device_detach(self->netdev);*/ + netif_stop_queue(self->netdev); + /* Stop all the receive URBs. Must be synchronous. */ + for (i = 0; i < self->max_rx_urb; i++) + usb_kill_urb(self->rx_urb[i]); + /* Cancel Tx and speed URB. + * Make sure it's synchronous to avoid races. */ + usb_kill_urb(self->tx_urb); + usb_kill_urb(self->speed_urb); + } + + /* Cleanup the device stuff */ + irda_usb_close(self); + /* No longer attached to USB bus */ + self->usbdev = NULL; + self->usbintf = NULL; + + /* Clean up our urbs */ + for (i = 0; i < self->max_rx_urb; i++) + usb_free_urb(self->rx_urb[i]); + kfree(self->rx_urb); + /* Clean up Tx and speed URB */ + usb_free_urb(self->tx_urb); + usb_free_urb(self->speed_urb); + + /* Free self and network device */ + free_netdev(self->netdev); + pr_debug("%s(), USB IrDA Disconnected\n", __func__); +} + +#ifdef CONFIG_PM +/* USB suspend, so power off the transmitter/receiver */ +static int irda_usb_suspend(struct usb_interface *intf, pm_message_t message) +{ + struct irda_usb_cb *self = usb_get_intfdata(intf); + int i; + + netif_device_detach(self->netdev); + + if (self->tx_urb != NULL) + usb_kill_urb(self->tx_urb); + if (self->speed_urb != NULL) + usb_kill_urb(self->speed_urb); + for (i = 0; i < self->max_rx_urb; i++) { + if (self->rx_urb[i] != NULL) + usb_kill_urb(self->rx_urb[i]); + } + return 0; +} + +/* Coming out of suspend, so reset hardware */ +static int irda_usb_resume(struct usb_interface *intf) +{ + struct irda_usb_cb *self = usb_get_intfdata(intf); + int i; + + for (i = 0; i < self->max_rx_urb; i++) { + if (self->rx_urb[i] != NULL) + usb_submit_urb(self->rx_urb[i], GFP_KERNEL); + } + + netif_device_attach(self->netdev); + return 0; +} +#endif + +/*------------------------------------------------------------------*/ +/* + * USB device callbacks + */ +static struct usb_driver irda_driver = { + .name = "irda-usb", + .probe = irda_usb_probe, + .disconnect = irda_usb_disconnect, + .id_table = dongles, +#ifdef CONFIG_PM + .suspend = irda_usb_suspend, + .resume = irda_usb_resume, +#endif +}; + +module_usb_driver(irda_driver); + +/* + * Module parameters + */ +module_param(qos_mtt_bits, int, 0); +MODULE_PARM_DESC(qos_mtt_bits, "Minimum Turn Time"); +MODULE_AUTHOR("Roman Weissgaerber <weissg@vienna.at>, Dag Brattli <dag@brattli.net>, Jean Tourrilhes <jt@hpl.hp.com> and Nick Fedchik <nick@fedchik.org.ua>"); +MODULE_DESCRIPTION("IrDA-USB Dongle Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/irda/drivers/irda-usb.h b/drivers/staging/irda/drivers/irda-usb.h new file mode 100644 index 000000000000..8ac389fa9348 --- /dev/null +++ b/drivers/staging/irda/drivers/irda-usb.h @@ -0,0 +1,174 @@ +/***************************************************************************** + * + * Filename: irda-usb.h + * Version: 0.10 + * Description: IrDA-USB Driver + * Status: Experimental + * Author: Dag Brattli <dag@brattli.net> + * + * Copyright (C) 2001, Roman Weissgaerber <weissg@vienna.at> + * Copyright (C) 2000, Dag Brattli <dag@brattli.net> + * Copyright (C) 2001, Jean Tourrilhes <jt@hpl.hp.com> + * Copyright (C) 2004, SigmaTel, Inc. <irquality@sigmatel.com> + * Copyright (C) 2005, Milan Beno <beno@pobox.sk> + * Copyright (C) 2006, Nick FEdchik <nick@fedchik.org.ua> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + *****************************************************************************/ + +#include <linux/ktime.h> + +#include <net/irda/irda.h> +#include <net/irda/irda_device.h> /* struct irlap_cb */ + +#define RX_COPY_THRESHOLD 200 +#define IRDA_USB_MAX_MTU 2051 +#define IRDA_USB_SPEED_MTU 64 /* Weird, but work like this */ + +/* Maximum number of active URB on the Rx path + * This is the amount of buffers the we keep between the USB harware and the + * IrDA stack. + * + * Note : the network layer does also queue the packets between us and the + * IrDA stack, and is actually pretty fast and efficient in doing that. + * Therefore, we don't need to have a large number of URBs, and we can + * perfectly live happy with only one. We certainly don't need to keep the + * full IrTTP window around here... + * I repeat for those who have trouble to understand : 1 URB is plenty + * good enough to handle back-to-back (brickwalled) frames. I tried it, + * it works (it's the hardware that has trouble doing it). + * + * Having 2 URBs would allow the USB stack to process one URB while we take + * care of the other and then swap the URBs... + * On the other hand, increasing the number of URB will have penalities + * in term of latency and will interact with the link management in IrLAP... + * Jean II */ +#define IU_MAX_ACTIVE_RX_URBS 1 /* Don't touch !!! */ + +/* When a Rx URB is passed back to us, we can't reuse it immediately, + * because it may still be referenced by the USB layer. Therefore we + * need to keep one extra URB in the Rx path. + * Jean II */ +#define IU_MAX_RX_URBS (IU_MAX_ACTIVE_RX_URBS + 1) + +/* Various ugly stuff to try to workaround generic problems */ +/* Send speed command in case of timeout, just for trying to get things sane */ +#define IU_BUG_KICK_TIMEOUT +/* Show the USB class descriptor */ +#undef IU_DUMP_CLASS_DESC +/* Assume a minimum round trip latency for USB transfer (in us)... + * USB transfer are done in the next USB slot if there is no traffic + * (1/19 msec) and is done at 12 Mb/s : + * Waiting for slot + tx = (53us + 16us) * 2 = 137us minimum. + * Rx notification will only be done at the end of the USB frame period : + * OHCI : frame period = 1ms + * UHCI : frame period = 1ms, but notification can take 2 or 3 ms :-( + * EHCI : frame period = 125us */ +#define IU_USB_MIN_RTT 500 /* This should be safe in most cases */ + +/* Inbound header */ +#define MEDIA_BUSY 0x80 + +#define SPEED_2400 0x01 +#define SPEED_9600 0x02 +#define SPEED_19200 0x03 +#define SPEED_38400 0x04 +#define SPEED_57600 0x05 +#define SPEED_115200 0x06 +#define SPEED_576000 0x07 +#define SPEED_1152000 0x08 +#define SPEED_4000000 0x09 +#define SPEED_16000000 0x0a + +/* Basic capabilities */ +#define IUC_DEFAULT 0x00 /* Basic device compliant with 1.0 spec */ +/* Main bugs */ +#define IUC_SPEED_BUG 0x01 /* Device doesn't set speed after the frame */ +#define IUC_NO_WINDOW 0x02 /* Device doesn't behave with big Rx window */ +#define IUC_NO_TURN 0x04 /* Device doesn't do turnaround by itself */ +/* Not currently used */ +#define IUC_SIR_ONLY 0x08 /* Device doesn't behave at FIR speeds */ +#define IUC_SMALL_PKT 0x10 /* Device doesn't behave with big Rx packets */ +#define IUC_MAX_WINDOW 0x20 /* Device underestimate the Rx window */ +#define IUC_MAX_XBOFS 0x40 /* Device need more xbofs than advertised */ +#define IUC_STIR421X 0x80 /* SigmaTel 4210/4220/4116 VFIR */ + +/* USB class definitions */ +#define USB_IRDA_HEADER 0x01 +#define USB_CLASS_IRDA 0x02 /* USB_CLASS_APP_SPEC subclass */ +#define USB_DT_IRDA 0x21 +#define USB_IRDA_STIR421X_HEADER 0x03 +#define IU_SIGMATEL_MAX_RX_URBS (IU_MAX_ACTIVE_RX_URBS + \ + USB_IRDA_STIR421X_HEADER) + +struct irda_class_desc { + __u8 bLength; + __u8 bDescriptorType; + __le16 bcdSpecRevision; + __u8 bmDataSize; + __u8 bmWindowSize; + __u8 bmMinTurnaroundTime; + __le16 wBaudRate; + __u8 bmAdditionalBOFs; + __u8 bIrdaRateSniff; + __u8 bMaxUnicastList; +} __packed; + +/* class specific interface request to get the IrDA-USB class descriptor + * (6.2.5, USB-IrDA class spec 1.0) */ + +#define IU_REQ_GET_CLASS_DESC 0x06 +#define STIR421X_MAX_PATCH_DOWNLOAD_SIZE 1023 + +struct irda_usb_cb { + struct irda_class_desc *irda_desc; + struct usb_device *usbdev; /* init: probe_irda */ + struct usb_interface *usbintf; /* init: probe_irda */ + int netopen; /* Device is active for network */ + int present; /* Device is present on the bus */ + __u32 capability; /* Capability of the hardware */ + __u8 bulk_in_ep; /* Rx Endpoint assignments */ + __u8 bulk_out_ep; /* Tx Endpoint assignments */ + __u16 bulk_out_mtu; /* Max Tx packet size in bytes */ + __u8 bulk_int_ep; /* Interrupt Endpoint assignments */ + + __u8 max_rx_urb; + struct urb **rx_urb; /* URBs used to receive data frames */ + struct urb *idle_rx_urb; /* Pointer to idle URB in Rx path */ + struct urb *tx_urb; /* URB used to send data frames */ + struct urb *speed_urb; /* URB used to send speed commands */ + + struct net_device *netdev; /* Yes! we are some kind of netdev. */ + struct irlap_cb *irlap; /* The link layer we are binded to */ + struct qos_info qos; + char *speed_buff; /* Buffer for speed changes */ + char *tx_buff; + + ktime_t stamp; + + spinlock_t lock; /* For serializing Tx operations */ + + __u16 xbofs; /* Current xbofs setting */ + __s16 new_xbofs; /* xbofs we need to set */ + __u32 speed; /* Current speed */ + __s32 new_speed; /* speed we need to set */ + + __u8 header_length; /* USB-IrDA frame header size */ + int needspatch; /* device needs firmware patch */ + + struct timer_list rx_defer_timer; /* Wait for Rx error to clear */ +}; + diff --git a/drivers/staging/irda/drivers/irtty-sir.c b/drivers/staging/irda/drivers/irtty-sir.c new file mode 100644 index 000000000000..7a20a9a4663a --- /dev/null +++ b/drivers/staging/irda/drivers/irtty-sir.c @@ -0,0 +1,570 @@ +/********************************************************************* + * + * Filename: irtty-sir.c + * Version: 2.0 + * Description: IrDA line discipline implementation + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Tue Dec 9 21:18:38 1997 + * Modified at: Sun Oct 27 22:13:30 2002 + * Modified by: Martin Diehl <mad@mdiehl.de> + * Sources: slip.c by Laurence Culhane, <loz@holmes.demon.co.uk> + * Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org> + * + * Copyright (c) 1998-2000 Dag Brattli, + * Copyright (c) 2002 Martin Diehl, + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/tty.h> +#include <linux/init.h> +#include <linux/uaccess.h> +#include <linux/delay.h> +#include <linux/mutex.h> + +#include <net/irda/irda.h> +#include <net/irda/irda_device.h> + +#include "sir-dev.h" +#include "irtty-sir.h" + +static int qos_mtt_bits = 0x03; /* 5 ms or more */ + +module_param(qos_mtt_bits, int, 0); +MODULE_PARM_DESC(qos_mtt_bits, "Minimum Turn Time"); + +/* ------------------------------------------------------- */ + +/* device configuration callbacks always invoked with irda-thread context */ + +/* find out, how many chars we have in buffers below us + * this is allowed to lie, i.e. return less chars than we + * actually have. The returned value is used to determine + * how long the irdathread should wait before doing the + * real blocking wait_until_sent() + */ + +static int irtty_chars_in_buffer(struct sir_dev *dev) +{ + struct sirtty_cb *priv = dev->priv; + + IRDA_ASSERT(priv != NULL, return -1;); + IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return -1;); + + return tty_chars_in_buffer(priv->tty); +} + +/* Wait (sleep) until underlaying hardware finished transmission + * i.e. hardware buffers are drained + * this must block and not return before all characters are really sent + * + * If the tty sits on top of a 16550A-like uart, there are typically + * up to 16 bytes in the fifo - f.e. 9600 bps 8N1 needs 16.7 msec + * + * With usbserial the uart-fifo is basically replaced by the converter's + * outgoing endpoint buffer, which can usually hold 64 bytes (at least). + * With pl2303 it appears we are safe with 60msec here. + * + * I really wish all serial drivers would provide + * correct implementation of wait_until_sent() + */ + +#define USBSERIAL_TX_DONE_DELAY 60 + +static void irtty_wait_until_sent(struct sir_dev *dev) +{ + struct sirtty_cb *priv = dev->priv; + struct tty_struct *tty; + + IRDA_ASSERT(priv != NULL, return;); + IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return;); + + tty = priv->tty; + if (tty->ops->wait_until_sent) { + tty->ops->wait_until_sent(tty, msecs_to_jiffies(100)); + } + else { + msleep(USBSERIAL_TX_DONE_DELAY); + } +} + +/* + * Function irtty_change_speed (dev, speed) + * + * Change the speed of the serial port. + * + * This may sleep in set_termios (usbserial driver f.e.) and must + * not be called from interrupt/timer/tasklet therefore. + * All such invocations are deferred to kIrDAd now so we can sleep there. + */ + +static int irtty_change_speed(struct sir_dev *dev, unsigned speed) +{ + struct sirtty_cb *priv = dev->priv; + struct tty_struct *tty; + struct ktermios old_termios; + int cflag; + + IRDA_ASSERT(priv != NULL, return -1;); + IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return -1;); + + tty = priv->tty; + + down_write(&tty->termios_rwsem); + old_termios = tty->termios; + cflag = tty->termios.c_cflag; + tty_encode_baud_rate(tty, speed, speed); + if (tty->ops->set_termios) + tty->ops->set_termios(tty, &old_termios); + priv->io.speed = speed; + up_write(&tty->termios_rwsem); + + return 0; +} + +/* + * Function irtty_set_dtr_rts (dev, dtr, rts) + * + * This function can be used by dongles etc. to set or reset the status + * of the dtr and rts lines + */ + +static int irtty_set_dtr_rts(struct sir_dev *dev, int dtr, int rts) +{ + struct sirtty_cb *priv = dev->priv; + int set = 0; + int clear = 0; + + IRDA_ASSERT(priv != NULL, return -1;); + IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return -1;); + + if (rts) + set |= TIOCM_RTS; + else + clear |= TIOCM_RTS; + if (dtr) + set |= TIOCM_DTR; + else + clear |= TIOCM_DTR; + + /* + * We can't use ioctl() because it expects a non-null file structure, + * and we don't have that here. + * This function is not yet defined for all tty driver, so + * let's be careful... Jean II + */ + IRDA_ASSERT(priv->tty->ops->tiocmset != NULL, return -1;); + priv->tty->ops->tiocmset(priv->tty, set, clear); + + return 0; +} + +/* ------------------------------------------------------- */ + +/* called from sir_dev when there is more data to send + * context is either netdev->hard_xmit or some transmit-completion bh + * i.e. we are under spinlock here and must not sleep. + */ + +static int irtty_do_write(struct sir_dev *dev, const unsigned char *ptr, size_t len) +{ + struct sirtty_cb *priv = dev->priv; + struct tty_struct *tty; + int writelen; + + IRDA_ASSERT(priv != NULL, return -1;); + IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return -1;); + + tty = priv->tty; + if (!tty->ops->write) + return 0; + set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); + writelen = tty_write_room(tty); + if (writelen > len) + writelen = len; + return tty->ops->write(tty, ptr, writelen); +} + +/* ------------------------------------------------------- */ + +/* irda line discipline callbacks */ + +/* + * Function irtty_receive_buf( tty, cp, count) + * + * Handle the 'receiver data ready' interrupt. This function is called + * by the 'tty_io' module in the kernel when a block of IrDA data has + * been received, which can now be decapsulated and delivered for + * further processing + * + * calling context depends on underlying driver and tty->port->low_latency! + * for example (low_latency: 1 / 0): + * serial.c: uart-interrupt / softint + * usbserial: urb-complete-interrupt / softint + */ + +static void irtty_receive_buf(struct tty_struct *tty, const unsigned char *cp, + char *fp, int count) +{ + struct sir_dev *dev; + struct sirtty_cb *priv = tty->disc_data; + int i; + + IRDA_ASSERT(priv != NULL, return;); + IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return;); + + if (unlikely(count==0)) /* yes, this happens */ + return; + + dev = priv->dev; + if (!dev) { + net_warn_ratelimited("%s(), not ready yet!\n", __func__); + return; + } + + for (i = 0; i < count; i++) { + /* + * Characters received with a parity error, etc? + */ + if (fp && *fp++) { + pr_debug("Framing or parity error!\n"); + sirdev_receive(dev, NULL, 0); /* notify sir_dev (updating stats) */ + return; + } + } + + sirdev_receive(dev, cp, count); +} + +/* + * Function irtty_write_wakeup (tty) + * + * Called by the driver when there's room for more data. If we have + * more packets to send, we send them here. + * + */ +static void irtty_write_wakeup(struct tty_struct *tty) +{ + struct sirtty_cb *priv = tty->disc_data; + + IRDA_ASSERT(priv != NULL, return;); + IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return;); + + clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); + if (priv->dev) + sirdev_write_complete(priv->dev); +} + +/* ------------------------------------------------------- */ + +/* + * Function irtty_stop_receiver (tty, stop) + * + */ + +static inline void irtty_stop_receiver(struct tty_struct *tty, int stop) +{ + struct ktermios old_termios; + int cflag; + + down_write(&tty->termios_rwsem); + old_termios = tty->termios; + cflag = tty->termios.c_cflag; + + if (stop) + cflag &= ~CREAD; + else + cflag |= CREAD; + + tty->termios.c_cflag = cflag; + if (tty->ops->set_termios) + tty->ops->set_termios(tty, &old_termios); + up_write(&tty->termios_rwsem); +} + +/*****************************************************************/ + +/* serialize ldisc open/close with sir_dev */ +static DEFINE_MUTEX(irtty_mutex); + +/* notifier from sir_dev when irda% device gets opened (ifup) */ + +static int irtty_start_dev(struct sir_dev *dev) +{ + struct sirtty_cb *priv; + struct tty_struct *tty; + + /* serialize with ldisc open/close */ + mutex_lock(&irtty_mutex); + + priv = dev->priv; + if (unlikely(!priv || priv->magic!=IRTTY_MAGIC)) { + mutex_unlock(&irtty_mutex); + return -ESTALE; + } + + tty = priv->tty; + + if (tty->ops->start) + tty->ops->start(tty); + /* Make sure we can receive more data */ + irtty_stop_receiver(tty, FALSE); + + mutex_unlock(&irtty_mutex); + return 0; +} + +/* notifier from sir_dev when irda% device gets closed (ifdown) */ + +static int irtty_stop_dev(struct sir_dev *dev) +{ + struct sirtty_cb *priv; + struct tty_struct *tty; + + /* serialize with ldisc open/close */ + mutex_lock(&irtty_mutex); + + priv = dev->priv; + if (unlikely(!priv || priv->magic!=IRTTY_MAGIC)) { + mutex_unlock(&irtty_mutex); + return -ESTALE; + } + + tty = priv->tty; + + /* Make sure we don't receive more data */ + irtty_stop_receiver(tty, TRUE); + if (tty->ops->stop) + tty->ops->stop(tty); + + mutex_unlock(&irtty_mutex); + + return 0; +} + +/* ------------------------------------------------------- */ + +static struct sir_driver sir_tty_drv = { + .owner = THIS_MODULE, + .driver_name = "sir_tty", + .start_dev = irtty_start_dev, + .stop_dev = irtty_stop_dev, + .do_write = irtty_do_write, + .chars_in_buffer = irtty_chars_in_buffer, + .wait_until_sent = irtty_wait_until_sent, + .set_speed = irtty_change_speed, + .set_dtr_rts = irtty_set_dtr_rts, +}; + +/* ------------------------------------------------------- */ + +/* + * Function irtty_ioctl (tty, file, cmd, arg) + * + * The Swiss army knife of system calls :-) + * + */ +static int irtty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) +{ + struct irtty_info { char name[6]; } info; + struct sir_dev *dev; + struct sirtty_cb *priv = tty->disc_data; + int err = 0; + + IRDA_ASSERT(priv != NULL, return -ENODEV;); + IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return -EBADR;); + + pr_debug("%s(cmd=0x%X)\n", __func__, cmd); + + dev = priv->dev; + IRDA_ASSERT(dev != NULL, return -1;); + + switch (cmd) { + case IRTTY_IOCTDONGLE: + /* this call blocks for completion */ + err = sirdev_set_dongle(dev, (IRDA_DONGLE) arg); + break; + + case IRTTY_IOCGET: + IRDA_ASSERT(dev->netdev != NULL, return -1;); + + memset(&info, 0, sizeof(info)); + strncpy(info.name, dev->netdev->name, sizeof(info.name)-1); + + if (copy_to_user((void __user *)arg, &info, sizeof(info))) + err = -EFAULT; + break; + default: + err = tty_mode_ioctl(tty, file, cmd, arg); + break; + } + return err; +} + + +/* + * Function irtty_open(tty) + * + * This function is called by the TTY module when the IrDA line + * discipline is called for. Because we are sure the tty line exists, + * we only have to link it to a free IrDA channel. + */ +static int irtty_open(struct tty_struct *tty) +{ + struct sir_dev *dev; + struct sirtty_cb *priv; + int ret = 0; + + /* Module stuff handled via irda_ldisc.owner - Jean II */ + + /* stop the underlying driver */ + irtty_stop_receiver(tty, TRUE); + if (tty->ops->stop) + tty->ops->stop(tty); + + tty_driver_flush_buffer(tty); + + /* apply mtt override */ + sir_tty_drv.qos_mtt_bits = qos_mtt_bits; + + /* get a sir device instance for this driver */ + dev = sirdev_get_instance(&sir_tty_drv, tty->name); + if (!dev) { + ret = -ENODEV; + goto out; + } + + /* allocate private device info block */ + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) { + ret = -ENOMEM; + goto out_put; + } + + priv->magic = IRTTY_MAGIC; + priv->tty = tty; + priv->dev = dev; + + /* serialize with start_dev - in case we were racing with ifup */ + mutex_lock(&irtty_mutex); + + dev->priv = priv; + tty->disc_data = priv; + tty->receive_room = 65536; + + mutex_unlock(&irtty_mutex); + + pr_debug("%s - %s: irda line discipline opened\n", __func__, tty->name); + + return 0; + +out_put: + sirdev_put_instance(dev); +out: + return ret; +} + +/* + * Function irtty_close (tty) + * + * Close down a IrDA channel. This means flushing out any pending queues, + * and then restoring the TTY line discipline to what it was before it got + * hooked to IrDA (which usually is TTY again). + */ +static void irtty_close(struct tty_struct *tty) +{ + struct sirtty_cb *priv = tty->disc_data; + + IRDA_ASSERT(priv != NULL, return;); + IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return;); + + /* Hm, with a dongle attached the dongle driver wants + * to close the dongle - which requires the use of + * some tty write and/or termios or ioctl operations. + * Are we allowed to call those when already requested + * to shutdown the ldisc? + * If not, we should somehow mark the dev being staled. + * Question remains, how to close the dongle in this case... + * For now let's assume we are granted to issue tty driver calls + * until we return here from the ldisc close. I'm just wondering + * how this behaves with hotpluggable serial hardware like + * rs232-pcmcia card or usb-serial... + * + * priv->tty = NULL?; + */ + + /* we are dead now */ + tty->disc_data = NULL; + + sirdev_put_instance(priv->dev); + + /* Stop tty */ + clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); + if (tty->ops->stop) + tty->ops->stop(tty); + + kfree(priv); + + pr_debug("%s - %s: irda line discipline closed\n", __func__, tty->name); +} + +/* ------------------------------------------------------- */ + +static struct tty_ldisc_ops irda_ldisc = { + .magic = TTY_LDISC_MAGIC, + .name = "irda", + .flags = 0, + .open = irtty_open, + .close = irtty_close, + .read = NULL, + .write = NULL, + .ioctl = irtty_ioctl, + .poll = NULL, + .receive_buf = irtty_receive_buf, + .write_wakeup = irtty_write_wakeup, + .owner = THIS_MODULE, +}; + +/* ------------------------------------------------------- */ + +static int __init irtty_sir_init(void) +{ + int err; + + if ((err = tty_register_ldisc(N_IRDA, &irda_ldisc)) != 0) + net_err_ratelimited("IrDA: can't register line discipline (err = %d)\n", + err); + return err; +} + +static void __exit irtty_sir_cleanup(void) +{ + int err; + + if ((err = tty_unregister_ldisc(N_IRDA))) { + net_err_ratelimited("%s(), can't unregister line discipline (err = %d)\n", + __func__, err); + } +} + +module_init(irtty_sir_init); +module_exit(irtty_sir_cleanup); + +MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>"); +MODULE_DESCRIPTION("IrDA TTY device driver"); +MODULE_ALIAS_LDISC(N_IRDA); +MODULE_LICENSE("GPL"); + diff --git a/drivers/staging/irda/drivers/irtty-sir.h b/drivers/staging/irda/drivers/irtty-sir.h new file mode 100644 index 000000000000..b132d8f6eb13 --- /dev/null +++ b/drivers/staging/irda/drivers/irtty-sir.h @@ -0,0 +1,34 @@ +/********************************************************************* + * + * sir_tty.h: definitions for the irtty_sir client driver (former irtty) + * + * Copyright (c) 2002 Martin Diehl + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + ********************************************************************/ + +#ifndef IRTTYSIR_H +#define IRTTYSIR_H + +#include <net/irda/irda.h> +#include <net/irda/irda_device.h> // chipio_t + +#define IRTTY_IOC_MAGIC 'e' +#define IRTTY_IOCTDONGLE _IO(IRTTY_IOC_MAGIC, 1) +#define IRTTY_IOCGET _IOR(IRTTY_IOC_MAGIC, 2, struct irtty_info) +#define IRTTY_IOC_MAXNR 2 + +struct sirtty_cb { + magic_t magic; + + struct sir_dev *dev; + struct tty_struct *tty; + + chipio_t io; /* IrDA controller information */ +}; + +#endif diff --git a/drivers/staging/irda/drivers/kingsun-sir.c b/drivers/staging/irda/drivers/kingsun-sir.c new file mode 100644 index 000000000000..4fd4ac2fe09f --- /dev/null +++ b/drivers/staging/irda/drivers/kingsun-sir.c @@ -0,0 +1,634 @@ +/***************************************************************************** +* +* Filename: kingsun-sir.c +* Version: 0.1.1 +* Description: Irda KingSun/DonShine USB Dongle +* Status: Experimental +* Author: Alex VillacĂs Lasso <a_villacis@palosanto.com> +* +* Based on stir4200 and mcs7780 drivers, with (strange?) differences +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + +/* + * This is my current (2007-04-25) understanding of how this dongle is supposed + * to work. This is based on reverse-engineering and examination of the packet + * data sent and received by the WinXP driver using USBSnoopy. Feel free to + * update here as more of this dongle is known: + * + * General: Unlike the other USB IrDA dongles, this particular dongle exposes, + * not two bulk (in and out) endpoints, but two *interrupt* ones. This dongle, + * like the bulk based ones (stir4200.c and mcs7780.c), requires polling in + * order to receive data. + * Transmission: Just like stir4200, this dongle uses a raw stream of data, + * which needs to be wrapped and escaped in a similar way as in stir4200.c. + * Reception: Poll-based, as in stir4200. Each read returns the contents of a + * 8-byte buffer, of which the first byte (LSB) indicates the number of bytes + * (1-7) of valid data contained within the remaining 7 bytes. For example, if + * the buffer had the following contents: + * 06 ff ff ff c0 01 04 aa + * This means that (06) there are 6 bytes of valid data. The byte 0xaa at the + * end is garbage (left over from a previous reception) and is discarded. + * If a read returns an "impossible" value as the length of valid data (such as + * 0x36) in the first byte, then the buffer is uninitialized (as is the case of + * first plug-in) and its contents should be discarded. There is currently no + * evidence that the top 5 bits of the 1st byte of the buffer can have values + * other than 0 once reception begins. + * Once valid bytes are collected, the assembled stream is a sequence of + * wrapped IrDA frames that is unwrapped and unescaped as in stir4200.c. + * BIG FAT WARNING: the dongle does *not* reset the RX buffer in any way after + * a successful read from the host, which means that in absence of further + * reception, repeated reads from the dongle will return the exact same + * contents repeatedly. Attempts to be smart and cache a previous read seem + * to result in corrupted packets, so this driver depends on the unwrap logic + * to sort out any repeated reads. + * Speed change: no commands observed so far to change speed, assumed fixed + * 9600bps (SIR). + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/slab.h> +#include <linux/usb.h> +#include <linux/device.h> +#include <linux/crc32.h> + +#include <asm/unaligned.h> +#include <asm/byteorder.h> +#include <linux/uaccess.h> + +#include <net/irda/irda.h> +#include <net/irda/wrapper.h> +#include <net/irda/crc.h> + +/* + * According to lsusb, 0x07c0 is assigned to + * "Code Mercenaries Hard- und Software GmbH" + */ +#define KING_VENDOR_ID 0x07c0 +#define KING_PRODUCT_ID 0x4200 + +/* These are the currently known USB ids */ +static const struct usb_device_id dongles[] = { + /* KingSun Co,Ltd IrDA/USB Bridge */ + { USB_DEVICE(KING_VENDOR_ID, KING_PRODUCT_ID) }, + { } +}; + +MODULE_DEVICE_TABLE(usb, dongles); + +#define KINGSUN_MTT 0x07 + +#define KINGSUN_FIFO_SIZE 4096 +#define KINGSUN_EP_IN 0 +#define KINGSUN_EP_OUT 1 + +struct kingsun_cb { + struct usb_device *usbdev; /* init: probe_irda */ + struct net_device *netdev; /* network layer */ + struct irlap_cb *irlap; /* The link layer we are binded to */ + + struct qos_info qos; + + __u8 *in_buf; /* receive buffer */ + __u8 *out_buf; /* transmit buffer */ + __u8 max_rx; /* max. atomic read from dongle + (usually 8), also size of in_buf */ + __u8 max_tx; /* max. atomic write to dongle + (usually 8) */ + + iobuff_t rx_buff; /* receive unwrap state machine */ + spinlock_t lock; + int receiving; + + __u8 ep_in; + __u8 ep_out; + + struct urb *tx_urb; + struct urb *rx_urb; +}; + +/* Callback transmission routine */ +static void kingsun_send_irq(struct urb *urb) +{ + struct kingsun_cb *kingsun = urb->context; + struct net_device *netdev = kingsun->netdev; + + /* in process of stopping, just drop data */ + if (!netif_running(kingsun->netdev)) { + dev_err(&kingsun->usbdev->dev, + "kingsun_send_irq: Network not running!\n"); + return; + } + + /* unlink, shutdown, unplug, other nasties */ + if (urb->status != 0) { + dev_err(&kingsun->usbdev->dev, + "kingsun_send_irq: urb asynchronously failed - %d\n", + urb->status); + } + netif_wake_queue(netdev); +} + +/* + * Called from net/core when new frame is available. + */ +static netdev_tx_t kingsun_hard_xmit(struct sk_buff *skb, + struct net_device *netdev) +{ + struct kingsun_cb *kingsun; + int wraplen; + int ret = 0; + + netif_stop_queue(netdev); + + /* the IRDA wrapping routines don't deal with non linear skb */ + SKB_LINEAR_ASSERT(skb); + + kingsun = netdev_priv(netdev); + + spin_lock(&kingsun->lock); + + /* Append data to the end of whatever data remains to be transmitted */ + wraplen = async_wrap_skb(skb, + kingsun->out_buf, + KINGSUN_FIFO_SIZE); + + /* Calculate how much data can be transmitted in this urb */ + usb_fill_int_urb(kingsun->tx_urb, kingsun->usbdev, + usb_sndintpipe(kingsun->usbdev, kingsun->ep_out), + kingsun->out_buf, wraplen, kingsun_send_irq, + kingsun, 1); + + if ((ret = usb_submit_urb(kingsun->tx_urb, GFP_ATOMIC))) { + dev_err(&kingsun->usbdev->dev, + "kingsun_hard_xmit: failed tx_urb submit: %d\n", ret); + switch (ret) { + case -ENODEV: + case -EPIPE: + break; + default: + netdev->stats.tx_errors++; + netif_start_queue(netdev); + } + } else { + netdev->stats.tx_packets++; + netdev->stats.tx_bytes += skb->len; + } + + dev_kfree_skb(skb); + spin_unlock(&kingsun->lock); + + return NETDEV_TX_OK; +} + +/* Receive callback function */ +static void kingsun_rcv_irq(struct urb *urb) +{ + struct kingsun_cb *kingsun = urb->context; + int ret; + + /* in process of stopping, just drop data */ + if (!netif_running(kingsun->netdev)) { + kingsun->receiving = 0; + return; + } + + /* unlink, shutdown, unplug, other nasties */ + if (urb->status != 0) { + dev_err(&kingsun->usbdev->dev, + "kingsun_rcv_irq: urb asynchronously failed - %d\n", + urb->status); + kingsun->receiving = 0; + return; + } + + if (urb->actual_length == kingsun->max_rx) { + __u8 *bytes = urb->transfer_buffer; + int i; + + /* The very first byte in the buffer indicates the length of + valid data in the read. This byte must be in the range + 1..kingsun->max_rx -1 . Values outside this range indicate + an uninitialized Rx buffer when the dongle has just been + plugged in. */ + if (bytes[0] >= 1 && bytes[0] < kingsun->max_rx) { + for (i = 1; i <= bytes[0]; i++) { + async_unwrap_char(kingsun->netdev, + &kingsun->netdev->stats, + &kingsun->rx_buff, bytes[i]); + } + kingsun->receiving = + (kingsun->rx_buff.state != OUTSIDE_FRAME) + ? 1 : 0; + } + } else if (urb->actual_length > 0) { + dev_err(&kingsun->usbdev->dev, + "%s(): Unexpected response length, expected %d got %d\n", + __func__, kingsun->max_rx, urb->actual_length); + } + /* This urb has already been filled in kingsun_net_open */ + ret = usb_submit_urb(urb, GFP_ATOMIC); +} + +/* + * Function kingsun_net_open (dev) + * + * Network device is taken up. Usually this is done by "ifconfig irda0 up" + */ +static int kingsun_net_open(struct net_device *netdev) +{ + struct kingsun_cb *kingsun = netdev_priv(netdev); + int err = -ENOMEM; + char hwname[16]; + + /* At this point, urbs are NULL, and skb is NULL (see kingsun_probe) */ + kingsun->receiving = 0; + + /* Initialize for SIR to copy data directly into skb. */ + kingsun->rx_buff.in_frame = FALSE; + kingsun->rx_buff.state = OUTSIDE_FRAME; + kingsun->rx_buff.truesize = IRDA_SKB_MAX_MTU; + kingsun->rx_buff.skb = dev_alloc_skb(IRDA_SKB_MAX_MTU); + if (!kingsun->rx_buff.skb) + goto free_mem; + + skb_reserve(kingsun->rx_buff.skb, 1); + kingsun->rx_buff.head = kingsun->rx_buff.skb->data; + + kingsun->rx_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!kingsun->rx_urb) + goto free_mem; + + kingsun->tx_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!kingsun->tx_urb) + goto free_mem; + + /* + * Now that everything should be initialized properly, + * Open new IrLAP layer instance to take care of us... + */ + sprintf(hwname, "usb#%d", kingsun->usbdev->devnum); + kingsun->irlap = irlap_open(netdev, &kingsun->qos, hwname); + if (!kingsun->irlap) { + dev_err(&kingsun->usbdev->dev, "irlap_open failed\n"); + goto free_mem; + } + + /* Start first reception */ + usb_fill_int_urb(kingsun->rx_urb, kingsun->usbdev, + usb_rcvintpipe(kingsun->usbdev, kingsun->ep_in), + kingsun->in_buf, kingsun->max_rx, + kingsun_rcv_irq, kingsun, 1); + kingsun->rx_urb->status = 0; + err = usb_submit_urb(kingsun->rx_urb, GFP_KERNEL); + if (err) { + dev_err(&kingsun->usbdev->dev, + "first urb-submit failed: %d\n", err); + goto close_irlap; + } + + netif_start_queue(netdev); + + /* Situation at this point: + - all work buffers allocated + - urbs allocated and ready to fill + - max rx packet known (in max_rx) + - unwrap state machine initialized, in state outside of any frame + - receive request in progress + - IrLAP layer started, about to hand over packets to send + */ + + return 0; + + close_irlap: + irlap_close(kingsun->irlap); + free_mem: + if (kingsun->tx_urb) { + usb_free_urb(kingsun->tx_urb); + kingsun->tx_urb = NULL; + } + if (kingsun->rx_urb) { + usb_free_urb(kingsun->rx_urb); + kingsun->rx_urb = NULL; + } + if (kingsun->rx_buff.skb) { + kfree_skb(kingsun->rx_buff.skb); + kingsun->rx_buff.skb = NULL; + kingsun->rx_buff.head = NULL; + } + return err; +} + +/* + * Function kingsun_net_close (kingsun) + * + * Network device is taken down. Usually this is done by + * "ifconfig irda0 down" + */ +static int kingsun_net_close(struct net_device *netdev) +{ + struct kingsun_cb *kingsun = netdev_priv(netdev); + + /* Stop transmit processing */ + netif_stop_queue(netdev); + + /* Mop up receive && transmit urb's */ + usb_kill_urb(kingsun->tx_urb); + usb_kill_urb(kingsun->rx_urb); + + usb_free_urb(kingsun->tx_urb); + usb_free_urb(kingsun->rx_urb); + + kingsun->tx_urb = NULL; + kingsun->rx_urb = NULL; + + kfree_skb(kingsun->rx_buff.skb); + kingsun->rx_buff.skb = NULL; + kingsun->rx_buff.head = NULL; + kingsun->rx_buff.in_frame = FALSE; + kingsun->rx_buff.state = OUTSIDE_FRAME; + kingsun->receiving = 0; + + /* Stop and remove instance of IrLAP */ + if (kingsun->irlap) + irlap_close(kingsun->irlap); + + kingsun->irlap = NULL; + + return 0; +} + +/* + * IOCTLs : Extra out-of-band network commands... + */ +static int kingsun_net_ioctl(struct net_device *netdev, struct ifreq *rq, + int cmd) +{ + struct if_irda_req *irq = (struct if_irda_req *) rq; + struct kingsun_cb *kingsun = netdev_priv(netdev); + int ret = 0; + + switch (cmd) { + case SIOCSBANDWIDTH: /* Set bandwidth */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + /* Check if the device is still there */ + if (netif_device_present(kingsun->netdev)) + /* No observed commands for speed change */ + ret = -EOPNOTSUPP; + break; + + case SIOCSMEDIABUSY: /* Set media busy */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + /* Check if the IrDA stack is still there */ + if (netif_running(kingsun->netdev)) + irda_device_set_media_busy(kingsun->netdev, TRUE); + break; + + case SIOCGRECEIVING: + /* Only approximately true */ + irq->ifr_receiving = kingsun->receiving; + break; + + default: + ret = -EOPNOTSUPP; + } + + return ret; +} + +static const struct net_device_ops kingsun_ops = { + .ndo_start_xmit = kingsun_hard_xmit, + .ndo_open = kingsun_net_open, + .ndo_stop = kingsun_net_close, + .ndo_do_ioctl = kingsun_net_ioctl, +}; + +/* + * This routine is called by the USB subsystem for each new device + * in the system. We need to check if the device is ours, and in + * this case start handling it. + */ +static int kingsun_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_host_interface *interface; + struct usb_endpoint_descriptor *endpoint; + + struct usb_device *dev = interface_to_usbdev(intf); + struct kingsun_cb *kingsun = NULL; + struct net_device *net = NULL; + int ret = -ENOMEM; + int pipe, maxp_in, maxp_out; + __u8 ep_in; + __u8 ep_out; + + /* Check that there really are two interrupt endpoints. + Check based on the one in drivers/usb/input/usbmouse.c + */ + interface = intf->cur_altsetting; + if (interface->desc.bNumEndpoints != 2) { + dev_err(&intf->dev, + "kingsun-sir: expected 2 endpoints, found %d\n", + interface->desc.bNumEndpoints); + return -ENODEV; + } + endpoint = &interface->endpoint[KINGSUN_EP_IN].desc; + if (!usb_endpoint_is_int_in(endpoint)) { + dev_err(&intf->dev, + "kingsun-sir: endpoint 0 is not interrupt IN\n"); + return -ENODEV; + } + + ep_in = endpoint->bEndpointAddress; + pipe = usb_rcvintpipe(dev, ep_in); + maxp_in = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); + if (maxp_in > 255 || maxp_in <= 1) { + dev_err(&intf->dev, + "endpoint 0 has max packet size %d not in range\n", + maxp_in); + return -ENODEV; + } + + endpoint = &interface->endpoint[KINGSUN_EP_OUT].desc; + if (!usb_endpoint_is_int_out(endpoint)) { + dev_err(&intf->dev, + "kingsun-sir: endpoint 1 is not interrupt OUT\n"); + return -ENODEV; + } + + ep_out = endpoint->bEndpointAddress; + pipe = usb_sndintpipe(dev, ep_out); + maxp_out = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); + + /* Allocate network device container. */ + net = alloc_irdadev(sizeof(*kingsun)); + if(!net) + goto err_out1; + + SET_NETDEV_DEV(net, &intf->dev); + kingsun = netdev_priv(net); + kingsun->irlap = NULL; + kingsun->tx_urb = NULL; + kingsun->rx_urb = NULL; + kingsun->ep_in = ep_in; + kingsun->ep_out = ep_out; + kingsun->in_buf = NULL; + kingsun->out_buf = NULL; + kingsun->max_rx = (__u8)maxp_in; + kingsun->max_tx = (__u8)maxp_out; + kingsun->netdev = net; + kingsun->usbdev = dev; + kingsun->rx_buff.in_frame = FALSE; + kingsun->rx_buff.state = OUTSIDE_FRAME; + kingsun->rx_buff.skb = NULL; + kingsun->receiving = 0; + spin_lock_init(&kingsun->lock); + + /* Allocate input buffer */ + kingsun->in_buf = kmalloc(kingsun->max_rx, GFP_KERNEL); + if (!kingsun->in_buf) + goto free_mem; + + /* Allocate output buffer */ + kingsun->out_buf = kmalloc(KINGSUN_FIFO_SIZE, GFP_KERNEL); + if (!kingsun->out_buf) + goto free_mem; + + printk(KERN_INFO "KingSun/DonShine IRDA/USB found at address %d, " + "Vendor: %x, Product: %x\n", + dev->devnum, le16_to_cpu(dev->descriptor.idVendor), + le16_to_cpu(dev->descriptor.idProduct)); + + /* Initialize QoS for this device */ + irda_init_max_qos_capabilies(&kingsun->qos); + + /* That's the Rx capability. */ + kingsun->qos.baud_rate.bits &= IR_9600; + kingsun->qos.min_turn_time.bits &= KINGSUN_MTT; + irda_qos_bits_to_value(&kingsun->qos); + + /* Override the network functions we need to use */ + net->netdev_ops = &kingsun_ops; + + ret = register_netdev(net); + if (ret != 0) + goto free_mem; + + dev_info(&net->dev, "IrDA: Registered KingSun/DonShine device %s\n", + net->name); + + usb_set_intfdata(intf, kingsun); + + /* Situation at this point: + - all work buffers allocated + - urbs not allocated, set to NULL + - max rx packet known (in max_rx) + - unwrap state machine (partially) initialized, but skb == NULL + */ + + return 0; + +free_mem: + kfree(kingsun->out_buf); + kfree(kingsun->in_buf); + free_netdev(net); +err_out1: + return ret; +} + +/* + * The current device is removed, the USB layer tell us to shut it down... + */ +static void kingsun_disconnect(struct usb_interface *intf) +{ + struct kingsun_cb *kingsun = usb_get_intfdata(intf); + + if (!kingsun) + return; + + unregister_netdev(kingsun->netdev); + + /* Mop up receive && transmit urb's */ + if (kingsun->tx_urb != NULL) { + usb_kill_urb(kingsun->tx_urb); + usb_free_urb(kingsun->tx_urb); + kingsun->tx_urb = NULL; + } + if (kingsun->rx_urb != NULL) { + usb_kill_urb(kingsun->rx_urb); + usb_free_urb(kingsun->rx_urb); + kingsun->rx_urb = NULL; + } + + kfree(kingsun->out_buf); + kfree(kingsun->in_buf); + free_netdev(kingsun->netdev); + + usb_set_intfdata(intf, NULL); +} + +#ifdef CONFIG_PM +/* USB suspend, so power off the transmitter/receiver */ +static int kingsun_suspend(struct usb_interface *intf, pm_message_t message) +{ + struct kingsun_cb *kingsun = usb_get_intfdata(intf); + + netif_device_detach(kingsun->netdev); + if (kingsun->tx_urb != NULL) usb_kill_urb(kingsun->tx_urb); + if (kingsun->rx_urb != NULL) usb_kill_urb(kingsun->rx_urb); + return 0; +} + +/* Coming out of suspend, so reset hardware */ +static int kingsun_resume(struct usb_interface *intf) +{ + struct kingsun_cb *kingsun = usb_get_intfdata(intf); + + if (kingsun->rx_urb != NULL) + usb_submit_urb(kingsun->rx_urb, GFP_KERNEL); + netif_device_attach(kingsun->netdev); + + return 0; +} +#endif + +/* + * USB device callbacks + */ +static struct usb_driver irda_driver = { + .name = "kingsun-sir", + .probe = kingsun_probe, + .disconnect = kingsun_disconnect, + .id_table = dongles, +#ifdef CONFIG_PM + .suspend = kingsun_suspend, + .resume = kingsun_resume, +#endif +}; + +module_usb_driver(irda_driver); + +MODULE_AUTHOR("Alex VillacĂs Lasso <a_villacis@palosanto.com>"); +MODULE_DESCRIPTION("IrDA-USB Dongle Driver for KingSun/DonShine"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/irda/drivers/ks959-sir.c b/drivers/staging/irda/drivers/ks959-sir.c new file mode 100644 index 000000000000..8025741e7586 --- /dev/null +++ b/drivers/staging/irda/drivers/ks959-sir.c @@ -0,0 +1,912 @@ +/***************************************************************************** +* +* Filename: ks959-sir.c +* Version: 0.1.2 +* Description: Irda KingSun KS-959 USB Dongle +* Status: Experimental +* Author: Alex VillacĂs Lasso <a_villacis@palosanto.com> +* with help from Domen Puncer <domen@coderock.org> +* +* Based on stir4200, mcs7780, kingsun-sir drivers. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + +/* + * Following is my most current (2007-07-17) understanding of how the Kingsun + * KS-959 dongle is supposed to work. This information was deduced by + * reverse-engineering and examining the USB traffic captured with USBSnoopy + * from the WinXP driver. Feel free to update here as more of the dongle is + * known. + * + * My most sincere thanks must go to Domen Puncer <domen@coderock.org> for + * invaluable help in cracking the obfuscation and padding required for this + * dongle. + * + * General: This dongle exposes one interface with one interrupt IN endpoint. + * However, the interrupt endpoint is NOT used at all for this dongle. Instead, + * this dongle uses control transfers for everything, including sending and + * receiving the IrDA frame data. Apparently the interrupt endpoint is just a + * dummy to ensure the dongle has a valid interface to present to the PC.And I + * thought the DonShine dongle was weird... In addition, this dongle uses + * obfuscation (?!?!), applied at the USB level, to hide the traffic, both sent + * and received, from the dongle. I call it obfuscation because the XOR keying + * and padding required to produce an USB traffic acceptable for the dongle can + * not be explained by any other technical requirement. + * + * Transmission: To transmit an IrDA frame, the driver must prepare a control + * URB with the following as a setup packet: + * bRequestType USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE + * bRequest 0x09 + * wValue <length of valid data before padding, little endian> + * wIndex 0x0000 + * wLength <length of padded data> + * The payload packet must be manually wrapped and escaped (as in stir4200.c), + * then padded and obfuscated before being sent. Both padding and obfuscation + * are implemented in the procedure obfuscate_tx_buffer(). Suffice to say, the + * designer/programmer of the dongle used his name as a source for the + * obfuscation. WTF?! + * Apparently the dongle cannot handle payloads larger than 256 bytes. The + * driver has to perform fragmentation in order to send anything larger than + * this limit. + * + * Reception: To receive data, the driver must poll the dongle regularly (like + * kingsun-sir.c) with control URBs and the following as a setup packet: + * bRequestType USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE + * bRequest 0x01 + * wValue 0x0200 + * wIndex 0x0000 + * wLength 0x0800 (size of available buffer) + * If there is data to be read, it will be returned as the response payload. + * This data is (apparently) not padded, but it is obfuscated. To de-obfuscate + * it, the driver must XOR every byte, in sequence, with a value that starts at + * 1 and is incremented with each byte processed, and then with 0x55. The value + * incremented with each byte processed overflows as an unsigned char. The + * resulting bytes form a wrapped SIR frame that is unwrapped and unescaped + * as in stir4200.c The incremented value is NOT reset with each frame, but is + * kept across the entire session with the dongle. Also, the dongle inserts an + * extra garbage byte with value 0x95 (after decoding) every 0xff bytes, which + * must be skipped. + * + * Speed change: To change the speed of the dongle, the driver prepares a + * control URB with the following as a setup packet: + * bRequestType USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE + * bRequest 0x09 + * wValue 0x0200 + * wIndex 0x0001 + * wLength 0x0008 (length of the payload) + * The payload is a 8-byte record, apparently identical to the one used in + * drivers/usb/serial/cypress_m8.c to change speed: + * __u32 baudSpeed; + * unsigned int dataBits : 2; // 0 - 5 bits 3 - 8 bits + * unsigned int : 1; + * unsigned int stopBits : 1; + * unsigned int parityEnable : 1; + * unsigned int parityType : 1; + * unsigned int : 1; + * unsigned int reset : 1; + * unsigned char reserved[3]; // set to 0 + * + * For now only SIR speeds have been observed with this dongle. Therefore, + * nothing is known on what changes (if any) must be done to frame wrapping / + * unwrapping for higher than SIR speeds. This driver assumes no change is + * necessary and announces support for all the way to 57600 bps. Although the + * package announces support for up to 4MBps, tests with a Sony Ericcson K300 + * phone show corruption when receiving large frames at 115200 bps, the highest + * speed announced by the phone. However, transmission at 115200 bps is OK. Go + * figure. Since I don't know whether the phone or the dongle is at fault, max + * announced speed is 57600 bps until someone produces a device that can run + * at higher speeds with this dongle. + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/slab.h> +#include <linux/usb.h> +#include <linux/device.h> +#include <linux/crc32.h> + +#include <asm/unaligned.h> +#include <asm/byteorder.h> +#include <linux/uaccess.h> + +#include <net/irda/irda.h> +#include <net/irda/wrapper.h> +#include <net/irda/crc.h> + +#define KS959_VENDOR_ID 0x07d0 +#define KS959_PRODUCT_ID 0x4959 + +/* These are the currently known USB ids */ +static const struct usb_device_id dongles[] = { + /* KingSun Co,Ltd IrDA/USB Bridge */ + {USB_DEVICE(KS959_VENDOR_ID, KS959_PRODUCT_ID)}, + {} +}; + +MODULE_DEVICE_TABLE(usb, dongles); + +#define KINGSUN_MTT 0x07 +#define KINGSUN_REQ_RECV 0x01 +#define KINGSUN_REQ_SEND 0x09 + +#define KINGSUN_RCV_FIFO_SIZE 2048 /* Max length we can receive */ +#define KINGSUN_SND_FIFO_SIZE 2048 /* Max packet we can send */ +#define KINGSUN_SND_PACKET_SIZE 256 /* Max packet dongle can handle */ + +struct ks959_speedparams { + __le32 baudrate; /* baud rate, little endian */ + __u8 flags; + __u8 reserved[3]; +} __packed; + +#define KS_DATA_5_BITS 0x00 +#define KS_DATA_6_BITS 0x01 +#define KS_DATA_7_BITS 0x02 +#define KS_DATA_8_BITS 0x03 + +#define KS_STOP_BITS_1 0x00 +#define KS_STOP_BITS_2 0x08 + +#define KS_PAR_DISABLE 0x00 +#define KS_PAR_EVEN 0x10 +#define KS_PAR_ODD 0x30 +#define KS_RESET 0x80 + +struct ks959_cb { + struct usb_device *usbdev; /* init: probe_irda */ + struct net_device *netdev; /* network layer */ + struct irlap_cb *irlap; /* The link layer we are binded to */ + + struct qos_info qos; + + struct usb_ctrlrequest *tx_setuprequest; + struct urb *tx_urb; + __u8 *tx_buf_clear; + unsigned int tx_buf_clear_used; + unsigned int tx_buf_clear_sent; + __u8 *tx_buf_xored; + + struct usb_ctrlrequest *rx_setuprequest; + struct urb *rx_urb; + __u8 *rx_buf; + __u8 rx_variable_xormask; + iobuff_t rx_unwrap_buff; + + struct usb_ctrlrequest *speed_setuprequest; + struct urb *speed_urb; + struct ks959_speedparams speedparams; + unsigned int new_speed; + + spinlock_t lock; + int receiving; +}; + +/* Procedure to perform the obfuscation/padding expected by the dongle + * + * buf_cleartext (IN) Cleartext version of the IrDA frame to transmit + * len_cleartext (IN) Length of the cleartext version of IrDA frame + * buf_xoredtext (OUT) Obfuscated version of frame built by proc + * len_maxbuf (OUT) Maximum space available at buf_xoredtext + * + * (return) length of obfuscated frame with padding + * + * If not enough space (as indicated by len_maxbuf vs. required padding), + * zero is returned + * + * The value of lookup_string is actually a required portion of the algorithm. + * Seems the designer of the dongle wanted to state who exactly is responsible + * for implementing obfuscation. Send your best (or other) wishes to him ]:-) + */ +static unsigned int obfuscate_tx_buffer(const __u8 * buf_cleartext, + unsigned int len_cleartext, + __u8 * buf_xoredtext, + unsigned int len_maxbuf) +{ + unsigned int len_xoredtext; + + /* Calculate required length with padding, check for necessary space */ + len_xoredtext = ((len_cleartext + 7) & ~0x7) + 0x10; + if (len_xoredtext <= len_maxbuf) { + static const __u8 lookup_string[] = "wangshuofei19710"; + __u8 xor_mask; + + /* Unlike the WinXP driver, we *do* clear out the padding */ + memset(buf_xoredtext, 0, len_xoredtext); + + xor_mask = lookup_string[(len_cleartext & 0x0f) ^ 0x06] ^ 0x55; + + while (len_cleartext-- > 0) { + *buf_xoredtext++ = *buf_cleartext++ ^ xor_mask; + } + } else { + len_xoredtext = 0; + } + return len_xoredtext; +} + +/* Callback transmission routine */ +static void ks959_speed_irq(struct urb *urb) +{ + /* unlink, shutdown, unplug, other nasties */ + if (urb->status != 0) { + dev_err(&urb->dev->dev, + "ks959_speed_irq: urb asynchronously failed - %d\n", + urb->status); + } +} + +/* Send a control request to change speed of the dongle */ +static int ks959_change_speed(struct ks959_cb *kingsun, unsigned speed) +{ + static unsigned int supported_speeds[] = { 2400, 9600, 19200, 38400, + 57600, 115200, 576000, 1152000, 4000000, 0 + }; + int err; + unsigned int i; + + if (kingsun->speed_setuprequest == NULL || kingsun->speed_urb == NULL) + return -ENOMEM; + + /* Check that requested speed is among the supported ones */ + for (i = 0; supported_speeds[i] && supported_speeds[i] != speed; i++) ; + if (supported_speeds[i] == 0) + return -EOPNOTSUPP; + + memset(&(kingsun->speedparams), 0, sizeof(struct ks959_speedparams)); + kingsun->speedparams.baudrate = cpu_to_le32(speed); + kingsun->speedparams.flags = KS_DATA_8_BITS; + + /* speed_setuprequest pre-filled in ks959_probe */ + usb_fill_control_urb(kingsun->speed_urb, kingsun->usbdev, + usb_sndctrlpipe(kingsun->usbdev, 0), + (unsigned char *)kingsun->speed_setuprequest, + &(kingsun->speedparams), + sizeof(struct ks959_speedparams), ks959_speed_irq, + kingsun); + kingsun->speed_urb->status = 0; + err = usb_submit_urb(kingsun->speed_urb, GFP_ATOMIC); + + return err; +} + +/* Submit one fragment of an IrDA frame to the dongle */ +static void ks959_send_irq(struct urb *urb); +static int ks959_submit_tx_fragment(struct ks959_cb *kingsun) +{ + unsigned int padlen; + unsigned int wraplen; + int ret; + + /* Check whether current plaintext can produce a padded buffer that fits + within the range handled by the dongle */ + wraplen = (KINGSUN_SND_PACKET_SIZE & ~0x7) - 0x10; + if (wraplen > kingsun->tx_buf_clear_used) + wraplen = kingsun->tx_buf_clear_used; + + /* Perform dongle obfuscation. Also remove the portion of the frame that + was just obfuscated and will now be sent to the dongle. */ + padlen = obfuscate_tx_buffer(kingsun->tx_buf_clear, wraplen, + kingsun->tx_buf_xored, + KINGSUN_SND_PACKET_SIZE); + + /* Calculate how much data can be transmitted in this urb */ + kingsun->tx_setuprequest->wValue = cpu_to_le16(wraplen); + kingsun->tx_setuprequest->wLength = cpu_to_le16(padlen); + /* Rest of the fields were filled in ks959_probe */ + usb_fill_control_urb(kingsun->tx_urb, kingsun->usbdev, + usb_sndctrlpipe(kingsun->usbdev, 0), + (unsigned char *)kingsun->tx_setuprequest, + kingsun->tx_buf_xored, padlen, + ks959_send_irq, kingsun); + kingsun->tx_urb->status = 0; + ret = usb_submit_urb(kingsun->tx_urb, GFP_ATOMIC); + + /* Remember how much data was sent, in order to update at callback */ + kingsun->tx_buf_clear_sent = (ret == 0) ? wraplen : 0; + return ret; +} + +/* Callback transmission routine */ +static void ks959_send_irq(struct urb *urb) +{ + struct ks959_cb *kingsun = urb->context; + struct net_device *netdev = kingsun->netdev; + int ret = 0; + + /* in process of stopping, just drop data */ + if (!netif_running(kingsun->netdev)) { + dev_err(&kingsun->usbdev->dev, + "ks959_send_irq: Network not running!\n"); + return; + } + + /* unlink, shutdown, unplug, other nasties */ + if (urb->status != 0) { + dev_err(&kingsun->usbdev->dev, + "ks959_send_irq: urb asynchronously failed - %d\n", + urb->status); + return; + } + + if (kingsun->tx_buf_clear_used > 0) { + /* Update data remaining to be sent */ + if (kingsun->tx_buf_clear_sent < kingsun->tx_buf_clear_used) { + memmove(kingsun->tx_buf_clear, + kingsun->tx_buf_clear + + kingsun->tx_buf_clear_sent, + kingsun->tx_buf_clear_used - + kingsun->tx_buf_clear_sent); + } + kingsun->tx_buf_clear_used -= kingsun->tx_buf_clear_sent; + kingsun->tx_buf_clear_sent = 0; + + if (kingsun->tx_buf_clear_used > 0) { + /* There is more data to be sent */ + if ((ret = ks959_submit_tx_fragment(kingsun)) != 0) { + dev_err(&kingsun->usbdev->dev, + "ks959_send_irq: failed tx_urb submit: %d\n", + ret); + switch (ret) { + case -ENODEV: + case -EPIPE: + break; + default: + netdev->stats.tx_errors++; + netif_start_queue(netdev); + } + } + } else { + /* All data sent, send next speed && wake network queue */ + if (kingsun->new_speed != -1 && + cpu_to_le32(kingsun->new_speed) != + kingsun->speedparams.baudrate) + ks959_change_speed(kingsun, kingsun->new_speed); + + netif_wake_queue(netdev); + } + } +} + +/* + * Called from net/core when new frame is available. + */ +static netdev_tx_t ks959_hard_xmit(struct sk_buff *skb, + struct net_device *netdev) +{ + struct ks959_cb *kingsun; + unsigned int wraplen; + int ret = 0; + + netif_stop_queue(netdev); + + /* the IRDA wrapping routines don't deal with non linear skb */ + SKB_LINEAR_ASSERT(skb); + + kingsun = netdev_priv(netdev); + + spin_lock(&kingsun->lock); + kingsun->new_speed = irda_get_next_speed(skb); + + /* Append data to the end of whatever data remains to be transmitted */ + wraplen = + async_wrap_skb(skb, kingsun->tx_buf_clear, KINGSUN_SND_FIFO_SIZE); + kingsun->tx_buf_clear_used = wraplen; + + if ((ret = ks959_submit_tx_fragment(kingsun)) != 0) { + dev_err(&kingsun->usbdev->dev, + "ks959_hard_xmit: failed tx_urb submit: %d\n", ret); + switch (ret) { + case -ENODEV: + case -EPIPE: + break; + default: + netdev->stats.tx_errors++; + netif_start_queue(netdev); + } + } else { + netdev->stats.tx_packets++; + netdev->stats.tx_bytes += skb->len; + + } + + dev_kfree_skb(skb); + spin_unlock(&kingsun->lock); + + return NETDEV_TX_OK; +} + +/* Receive callback function */ +static void ks959_rcv_irq(struct urb *urb) +{ + struct ks959_cb *kingsun = urb->context; + int ret; + + /* in process of stopping, just drop data */ + if (!netif_running(kingsun->netdev)) { + kingsun->receiving = 0; + return; + } + + /* unlink, shutdown, unplug, other nasties */ + if (urb->status != 0) { + dev_err(&kingsun->usbdev->dev, + "kingsun_rcv_irq: urb asynchronously failed - %d\n", + urb->status); + kingsun->receiving = 0; + return; + } + + if (urb->actual_length > 0) { + __u8 *bytes = urb->transfer_buffer; + unsigned int i; + + for (i = 0; i < urb->actual_length; i++) { + /* De-obfuscation implemented here: variable portion of + xormask is incremented, and then used with the encoded + byte for the XOR. The result of the operation is used + to unwrap the SIR frame. */ + kingsun->rx_variable_xormask++; + bytes[i] = + bytes[i] ^ kingsun->rx_variable_xormask ^ 0x55u; + + /* rx_variable_xormask doubles as an index counter so we + can skip the byte at 0xff (wrapped around to 0). + */ + if (kingsun->rx_variable_xormask != 0) { + async_unwrap_char(kingsun->netdev, + &kingsun->netdev->stats, + &kingsun->rx_unwrap_buff, + bytes[i]); + } + } + kingsun->receiving = + (kingsun->rx_unwrap_buff.state != OUTSIDE_FRAME) ? 1 : 0; + } + + /* This urb has already been filled in kingsun_net_open. Setup + packet must be re-filled, but it is assumed that urb keeps the + pointer to the initial setup packet, as well as the payload buffer. + Setup packet is already pre-filled at ks959_probe. + */ + urb->status = 0; + ret = usb_submit_urb(urb, GFP_ATOMIC); +} + +/* + * Function kingsun_net_open (dev) + * + * Network device is taken up. Usually this is done by "ifconfig irda0 up" + */ +static int ks959_net_open(struct net_device *netdev) +{ + struct ks959_cb *kingsun = netdev_priv(netdev); + int err = -ENOMEM; + char hwname[16]; + + /* At this point, urbs are NULL, and skb is NULL (see kingsun_probe) */ + kingsun->receiving = 0; + + /* Initialize for SIR to copy data directly into skb. */ + kingsun->rx_unwrap_buff.in_frame = FALSE; + kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME; + kingsun->rx_unwrap_buff.truesize = IRDA_SKB_MAX_MTU; + kingsun->rx_unwrap_buff.skb = dev_alloc_skb(IRDA_SKB_MAX_MTU); + if (!kingsun->rx_unwrap_buff.skb) + goto free_mem; + + skb_reserve(kingsun->rx_unwrap_buff.skb, 1); + kingsun->rx_unwrap_buff.head = kingsun->rx_unwrap_buff.skb->data; + + kingsun->rx_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!kingsun->rx_urb) + goto free_mem; + + kingsun->tx_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!kingsun->tx_urb) + goto free_mem; + + kingsun->speed_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!kingsun->speed_urb) + goto free_mem; + + /* Initialize speed for dongle */ + kingsun->new_speed = 9600; + err = ks959_change_speed(kingsun, 9600); + if (err < 0) + goto free_mem; + + /* + * Now that everything should be initialized properly, + * Open new IrLAP layer instance to take care of us... + */ + sprintf(hwname, "usb#%d", kingsun->usbdev->devnum); + kingsun->irlap = irlap_open(netdev, &kingsun->qos, hwname); + if (!kingsun->irlap) { + err = -ENOMEM; + dev_err(&kingsun->usbdev->dev, "irlap_open failed\n"); + goto free_mem; + } + + /* Start reception. Setup request already pre-filled in ks959_probe */ + usb_fill_control_urb(kingsun->rx_urb, kingsun->usbdev, + usb_rcvctrlpipe(kingsun->usbdev, 0), + (unsigned char *)kingsun->rx_setuprequest, + kingsun->rx_buf, KINGSUN_RCV_FIFO_SIZE, + ks959_rcv_irq, kingsun); + kingsun->rx_urb->status = 0; + err = usb_submit_urb(kingsun->rx_urb, GFP_KERNEL); + if (err) { + dev_err(&kingsun->usbdev->dev, + "first urb-submit failed: %d\n", err); + goto close_irlap; + } + + netif_start_queue(netdev); + + /* Situation at this point: + - all work buffers allocated + - urbs allocated and ready to fill + - max rx packet known (in max_rx) + - unwrap state machine initialized, in state outside of any frame + - receive request in progress + - IrLAP layer started, about to hand over packets to send + */ + + return 0; + + close_irlap: + irlap_close(kingsun->irlap); + free_mem: + usb_free_urb(kingsun->speed_urb); + kingsun->speed_urb = NULL; + usb_free_urb(kingsun->tx_urb); + kingsun->tx_urb = NULL; + usb_free_urb(kingsun->rx_urb); + kingsun->rx_urb = NULL; + if (kingsun->rx_unwrap_buff.skb) { + kfree_skb(kingsun->rx_unwrap_buff.skb); + kingsun->rx_unwrap_buff.skb = NULL; + kingsun->rx_unwrap_buff.head = NULL; + } + return err; +} + +/* + * Function kingsun_net_close (kingsun) + * + * Network device is taken down. Usually this is done by + * "ifconfig irda0 down" + */ +static int ks959_net_close(struct net_device *netdev) +{ + struct ks959_cb *kingsun = netdev_priv(netdev); + + /* Stop transmit processing */ + netif_stop_queue(netdev); + + /* Mop up receive && transmit urb's */ + usb_kill_urb(kingsun->tx_urb); + usb_free_urb(kingsun->tx_urb); + kingsun->tx_urb = NULL; + + usb_kill_urb(kingsun->speed_urb); + usb_free_urb(kingsun->speed_urb); + kingsun->speed_urb = NULL; + + usb_kill_urb(kingsun->rx_urb); + usb_free_urb(kingsun->rx_urb); + kingsun->rx_urb = NULL; + + kfree_skb(kingsun->rx_unwrap_buff.skb); + kingsun->rx_unwrap_buff.skb = NULL; + kingsun->rx_unwrap_buff.head = NULL; + kingsun->rx_unwrap_buff.in_frame = FALSE; + kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME; + kingsun->receiving = 0; + + /* Stop and remove instance of IrLAP */ + if (kingsun->irlap) + irlap_close(kingsun->irlap); + + kingsun->irlap = NULL; + + return 0; +} + +/* + * IOCTLs : Extra out-of-band network commands... + */ +static int ks959_net_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) +{ + struct if_irda_req *irq = (struct if_irda_req *)rq; + struct ks959_cb *kingsun = netdev_priv(netdev); + int ret = 0; + + switch (cmd) { + case SIOCSBANDWIDTH: /* Set bandwidth */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + /* Check if the device is still there */ + if (netif_device_present(kingsun->netdev)) + return ks959_change_speed(kingsun, irq->ifr_baudrate); + break; + + case SIOCSMEDIABUSY: /* Set media busy */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + /* Check if the IrDA stack is still there */ + if (netif_running(kingsun->netdev)) + irda_device_set_media_busy(kingsun->netdev, TRUE); + break; + + case SIOCGRECEIVING: + /* Only approximately true */ + irq->ifr_receiving = kingsun->receiving; + break; + + default: + ret = -EOPNOTSUPP; + } + + return ret; +} + +static const struct net_device_ops ks959_ops = { + .ndo_start_xmit = ks959_hard_xmit, + .ndo_open = ks959_net_open, + .ndo_stop = ks959_net_close, + .ndo_do_ioctl = ks959_net_ioctl, +}; +/* + * This routine is called by the USB subsystem for each new device + * in the system. We need to check if the device is ours, and in + * this case start handling it. + */ +static int ks959_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *dev = interface_to_usbdev(intf); + struct ks959_cb *kingsun = NULL; + struct net_device *net = NULL; + int ret = -ENOMEM; + + /* Allocate network device container. */ + net = alloc_irdadev(sizeof(*kingsun)); + if (!net) + goto err_out1; + + SET_NETDEV_DEV(net, &intf->dev); + kingsun = netdev_priv(net); + kingsun->netdev = net; + kingsun->usbdev = dev; + kingsun->irlap = NULL; + kingsun->tx_setuprequest = NULL; + kingsun->tx_urb = NULL; + kingsun->tx_buf_clear = NULL; + kingsun->tx_buf_xored = NULL; + kingsun->tx_buf_clear_used = 0; + kingsun->tx_buf_clear_sent = 0; + + kingsun->rx_setuprequest = NULL; + kingsun->rx_urb = NULL; + kingsun->rx_buf = NULL; + kingsun->rx_variable_xormask = 0; + kingsun->rx_unwrap_buff.in_frame = FALSE; + kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME; + kingsun->rx_unwrap_buff.skb = NULL; + kingsun->receiving = 0; + spin_lock_init(&kingsun->lock); + + kingsun->speed_setuprequest = NULL; + kingsun->speed_urb = NULL; + kingsun->speedparams.baudrate = 0; + + /* Allocate input buffer */ + kingsun->rx_buf = kmalloc(KINGSUN_RCV_FIFO_SIZE, GFP_KERNEL); + if (!kingsun->rx_buf) + goto free_mem; + + /* Allocate input setup packet */ + kingsun->rx_setuprequest = + kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL); + if (!kingsun->rx_setuprequest) + goto free_mem; + kingsun->rx_setuprequest->bRequestType = + USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE; + kingsun->rx_setuprequest->bRequest = KINGSUN_REQ_RECV; + kingsun->rx_setuprequest->wValue = cpu_to_le16(0x0200); + kingsun->rx_setuprequest->wIndex = 0; + kingsun->rx_setuprequest->wLength = cpu_to_le16(KINGSUN_RCV_FIFO_SIZE); + + /* Allocate output buffer */ + kingsun->tx_buf_clear = kmalloc(KINGSUN_SND_FIFO_SIZE, GFP_KERNEL); + if (!kingsun->tx_buf_clear) + goto free_mem; + kingsun->tx_buf_xored = kmalloc(KINGSUN_SND_PACKET_SIZE, GFP_KERNEL); + if (!kingsun->tx_buf_xored) + goto free_mem; + + /* Allocate and initialize output setup packet */ + kingsun->tx_setuprequest = + kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL); + if (!kingsun->tx_setuprequest) + goto free_mem; + kingsun->tx_setuprequest->bRequestType = + USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE; + kingsun->tx_setuprequest->bRequest = KINGSUN_REQ_SEND; + kingsun->tx_setuprequest->wValue = 0; + kingsun->tx_setuprequest->wIndex = 0; + kingsun->tx_setuprequest->wLength = 0; + + /* Allocate and initialize speed setup packet */ + kingsun->speed_setuprequest = + kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL); + if (!kingsun->speed_setuprequest) + goto free_mem; + kingsun->speed_setuprequest->bRequestType = + USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE; + kingsun->speed_setuprequest->bRequest = KINGSUN_REQ_SEND; + kingsun->speed_setuprequest->wValue = cpu_to_le16(0x0200); + kingsun->speed_setuprequest->wIndex = cpu_to_le16(0x0001); + kingsun->speed_setuprequest->wLength = + cpu_to_le16(sizeof(struct ks959_speedparams)); + + printk(KERN_INFO "KingSun KS-959 IRDA/USB found at address %d, " + "Vendor: %x, Product: %x\n", + dev->devnum, le16_to_cpu(dev->descriptor.idVendor), + le16_to_cpu(dev->descriptor.idProduct)); + + /* Initialize QoS for this device */ + irda_init_max_qos_capabilies(&kingsun->qos); + + /* Baud rates known to be supported. Please uncomment if devices (other + than a SonyEriccson K300 phone) can be shown to support higher speed + with this dongle. + */ + kingsun->qos.baud_rate.bits = + IR_2400 | IR_9600 | IR_19200 | IR_38400 | IR_57600; + kingsun->qos.min_turn_time.bits &= KINGSUN_MTT; + irda_qos_bits_to_value(&kingsun->qos); + + /* Override the network functions we need to use */ + net->netdev_ops = &ks959_ops; + + ret = register_netdev(net); + if (ret != 0) + goto free_mem; + + dev_info(&net->dev, "IrDA: Registered KingSun KS-959 device %s\n", + net->name); + + usb_set_intfdata(intf, kingsun); + + /* Situation at this point: + - all work buffers allocated + - setup requests pre-filled + - urbs not allocated, set to NULL + - max rx packet known (is KINGSUN_FIFO_SIZE) + - unwrap state machine (partially) initialized, but skb == NULL + */ + + return 0; + + free_mem: + kfree(kingsun->speed_setuprequest); + kfree(kingsun->tx_setuprequest); + kfree(kingsun->tx_buf_xored); + kfree(kingsun->tx_buf_clear); + kfree(kingsun->rx_setuprequest); + kfree(kingsun->rx_buf); + free_netdev(net); + err_out1: + return ret; +} + +/* + * The current device is removed, the USB layer tell us to shut it down... + */ +static void ks959_disconnect(struct usb_interface *intf) +{ + struct ks959_cb *kingsun = usb_get_intfdata(intf); + + if (!kingsun) + return; + + unregister_netdev(kingsun->netdev); + + /* Mop up receive && transmit urb's */ + if (kingsun->speed_urb != NULL) { + usb_kill_urb(kingsun->speed_urb); + usb_free_urb(kingsun->speed_urb); + kingsun->speed_urb = NULL; + } + if (kingsun->tx_urb != NULL) { + usb_kill_urb(kingsun->tx_urb); + usb_free_urb(kingsun->tx_urb); + kingsun->tx_urb = NULL; + } + if (kingsun->rx_urb != NULL) { + usb_kill_urb(kingsun->rx_urb); + usb_free_urb(kingsun->rx_urb); + kingsun->rx_urb = NULL; + } + + kfree(kingsun->speed_setuprequest); + kfree(kingsun->tx_setuprequest); + kfree(kingsun->tx_buf_xored); + kfree(kingsun->tx_buf_clear); + kfree(kingsun->rx_setuprequest); + kfree(kingsun->rx_buf); + free_netdev(kingsun->netdev); + + usb_set_intfdata(intf, NULL); +} + +#ifdef CONFIG_PM +/* USB suspend, so power off the transmitter/receiver */ +static int ks959_suspend(struct usb_interface *intf, pm_message_t message) +{ + struct ks959_cb *kingsun = usb_get_intfdata(intf); + + netif_device_detach(kingsun->netdev); + if (kingsun->speed_urb != NULL) + usb_kill_urb(kingsun->speed_urb); + if (kingsun->tx_urb != NULL) + usb_kill_urb(kingsun->tx_urb); + if (kingsun->rx_urb != NULL) + usb_kill_urb(kingsun->rx_urb); + return 0; +} + +/* Coming out of suspend, so reset hardware */ +static int ks959_resume(struct usb_interface *intf) +{ + struct ks959_cb *kingsun = usb_get_intfdata(intf); + + if (kingsun->rx_urb != NULL) { + /* Setup request already filled in ks959_probe */ + usb_submit_urb(kingsun->rx_urb, GFP_KERNEL); + } + netif_device_attach(kingsun->netdev); + + return 0; +} +#endif + +/* + * USB device callbacks + */ +static struct usb_driver irda_driver = { + .name = "ks959-sir", + .probe = ks959_probe, + .disconnect = ks959_disconnect, + .id_table = dongles, +#ifdef CONFIG_PM + .suspend = ks959_suspend, + .resume = ks959_resume, +#endif +}; + +module_usb_driver(irda_driver); + +MODULE_AUTHOR("Alex VillacĂs Lasso <a_villacis@palosanto.com>"); +MODULE_DESCRIPTION("IrDA-USB Dongle Driver for KingSun KS-959"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/irda/drivers/ksdazzle-sir.c b/drivers/staging/irda/drivers/ksdazzle-sir.c new file mode 100644 index 000000000000..d2a0755df596 --- /dev/null +++ b/drivers/staging/irda/drivers/ksdazzle-sir.c @@ -0,0 +1,813 @@ +/***************************************************************************** +* +* Filename: ksdazzle.c +* Version: 0.1.2 +* Description: Irda KingSun Dazzle USB Dongle +* Status: Experimental +* Author: Alex VillacĂs Lasso <a_villacis@palosanto.com> +* +* Based on stir4200, mcs7780, kingsun-sir drivers. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + +/* + * Following is my most current (2007-07-26) understanding of how the Kingsun + * 07D0:4100 dongle (sometimes known as the MA-660) is supposed to work. This + * information was deduced by examining the USB traffic captured with USBSnoopy + * from the WinXP driver. Feel free to update here as more of the dongle is + * known. + * + * General: This dongle exposes one interface with two interrupt endpoints, one + * IN and one OUT. In this regard, it is similar to what the Kingsun/Donshine + * dongle (07c0:4200) exposes. Traffic is raw and needs to be wrapped and + * unwrapped manually as in stir4200, kingsun-sir, and ks959-sir. + * + * Transmission: To transmit an IrDA frame, it is necessary to wrap it, then + * split it into multiple segments of up to 7 bytes each, and transmit each in + * sequence. It seems that sending a single big block (like kingsun-sir does) + * won't work with this dongle. Each segment needs to be prefixed with a value + * equal to (unsigned char)0xF8 + <number of bytes in segment>, inside a payload + * of exactly 8 bytes. For example, a segment of 1 byte gets prefixed by 0xF9, + * and one of 7 bytes gets prefixed by 0xFF. The bytes at the end of the + * payload, not considered by the prefix, are ignored (set to 0 by this + * implementation). + * + * Reception: To receive data, the driver must poll the dongle regularly (like + * kingsun-sir.c) with interrupt URBs. If data is available, it will be returned + * in payloads from 0 to 8 bytes long. When concatenated, these payloads form + * a raw IrDA stream that needs to be unwrapped as in stir4200 and kingsun-sir + * + * Speed change: To change the speed of the dongle, the driver prepares a + * control URB with the following as a setup packet: + * bRequestType USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE + * bRequest 0x09 + * wValue 0x0200 + * wIndex 0x0001 + * wLength 0x0008 (length of the payload) + * The payload is a 8-byte record, apparently identical to the one used in + * drivers/usb/serial/cypress_m8.c to change speed: + * __u32 baudSpeed; + * unsigned int dataBits : 2; // 0 - 5 bits 3 - 8 bits + * unsigned int : 1; + * unsigned int stopBits : 1; + * unsigned int parityEnable : 1; + * unsigned int parityType : 1; + * unsigned int : 1; + * unsigned int reset : 1; + * unsigned char reserved[3]; // set to 0 + * + * For now only SIR speeds have been observed with this dongle. Therefore, + * nothing is known on what changes (if any) must be done to frame wrapping / + * unwrapping for higher than SIR speeds. This driver assumes no change is + * necessary and announces support for all the way to 115200 bps. + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/slab.h> +#include <linux/usb.h> +#include <linux/device.h> +#include <linux/crc32.h> + +#include <asm/unaligned.h> +#include <asm/byteorder.h> +#include <linux/uaccess.h> + +#include <net/irda/irda.h> +#include <net/irda/wrapper.h> +#include <net/irda/crc.h> + +#define KSDAZZLE_VENDOR_ID 0x07d0 +#define KSDAZZLE_PRODUCT_ID 0x4100 + +/* These are the currently known USB ids */ +static const struct usb_device_id dongles[] = { + /* KingSun Co,Ltd IrDA/USB Bridge */ + {USB_DEVICE(KSDAZZLE_VENDOR_ID, KSDAZZLE_PRODUCT_ID)}, + {} +}; + +MODULE_DEVICE_TABLE(usb, dongles); + +#define KINGSUN_MTT 0x07 +#define KINGSUN_REQ_RECV 0x01 +#define KINGSUN_REQ_SEND 0x09 + +#define KINGSUN_SND_FIFO_SIZE 2048 /* Max packet we can send */ +#define KINGSUN_RCV_MAX 2048 /* Max transfer we can receive */ + +struct ksdazzle_speedparams { + __le32 baudrate; /* baud rate, little endian */ + __u8 flags; + __u8 reserved[3]; +} __packed; + +#define KS_DATA_5_BITS 0x00 +#define KS_DATA_6_BITS 0x01 +#define KS_DATA_7_BITS 0x02 +#define KS_DATA_8_BITS 0x03 + +#define KS_STOP_BITS_1 0x00 +#define KS_STOP_BITS_2 0x08 + +#define KS_PAR_DISABLE 0x00 +#define KS_PAR_EVEN 0x10 +#define KS_PAR_ODD 0x30 +#define KS_RESET 0x80 + +#define KINGSUN_EP_IN 0 +#define KINGSUN_EP_OUT 1 + +struct ksdazzle_cb { + struct usb_device *usbdev; /* init: probe_irda */ + struct net_device *netdev; /* network layer */ + struct irlap_cb *irlap; /* The link layer we are binded to */ + + struct qos_info qos; + + struct urb *tx_urb; + __u8 *tx_buf_clear; + unsigned int tx_buf_clear_used; + unsigned int tx_buf_clear_sent; + __u8 tx_payload[8]; + + struct urb *rx_urb; + __u8 *rx_buf; + iobuff_t rx_unwrap_buff; + + struct usb_ctrlrequest *speed_setuprequest; + struct urb *speed_urb; + struct ksdazzle_speedparams speedparams; + unsigned int new_speed; + + __u8 ep_in; + __u8 ep_out; + + spinlock_t lock; + int receiving; +}; + +/* Callback transmission routine */ +static void ksdazzle_speed_irq(struct urb *urb) +{ + /* unlink, shutdown, unplug, other nasties */ + if (urb->status != 0) + dev_err(&urb->dev->dev, + "ksdazzle_speed_irq: urb asynchronously failed - %d\n", + urb->status); +} + +/* Send a control request to change speed of the dongle */ +static int ksdazzle_change_speed(struct ksdazzle_cb *kingsun, unsigned speed) +{ + static unsigned int supported_speeds[] = { 2400, 9600, 19200, 38400, + 57600, 115200, 576000, 1152000, 4000000, 0 + }; + int err; + unsigned int i; + + if (kingsun->speed_setuprequest == NULL || kingsun->speed_urb == NULL) + return -ENOMEM; + + /* Check that requested speed is among the supported ones */ + for (i = 0; supported_speeds[i] && supported_speeds[i] != speed; i++) ; + if (supported_speeds[i] == 0) + return -EOPNOTSUPP; + + memset(&(kingsun->speedparams), 0, sizeof(struct ksdazzle_speedparams)); + kingsun->speedparams.baudrate = cpu_to_le32(speed); + kingsun->speedparams.flags = KS_DATA_8_BITS; + + /* speed_setuprequest pre-filled in ksdazzle_probe */ + usb_fill_control_urb(kingsun->speed_urb, kingsun->usbdev, + usb_sndctrlpipe(kingsun->usbdev, 0), + (unsigned char *)kingsun->speed_setuprequest, + &(kingsun->speedparams), + sizeof(struct ksdazzle_speedparams), + ksdazzle_speed_irq, kingsun); + kingsun->speed_urb->status = 0; + err = usb_submit_urb(kingsun->speed_urb, GFP_ATOMIC); + + return err; +} + +/* Submit one fragment of an IrDA frame to the dongle */ +static void ksdazzle_send_irq(struct urb *urb); +static int ksdazzle_submit_tx_fragment(struct ksdazzle_cb *kingsun) +{ + unsigned int wraplen; + int ret; + + /* We can send at most 7 bytes of payload at a time */ + wraplen = 7; + if (wraplen > kingsun->tx_buf_clear_used) + wraplen = kingsun->tx_buf_clear_used; + + /* Prepare payload prefix with used length */ + memset(kingsun->tx_payload, 0, 8); + kingsun->tx_payload[0] = (unsigned char)0xf8 + wraplen; + memcpy(kingsun->tx_payload + 1, kingsun->tx_buf_clear, wraplen); + + usb_fill_int_urb(kingsun->tx_urb, kingsun->usbdev, + usb_sndintpipe(kingsun->usbdev, kingsun->ep_out), + kingsun->tx_payload, 8, ksdazzle_send_irq, kingsun, 1); + kingsun->tx_urb->status = 0; + ret = usb_submit_urb(kingsun->tx_urb, GFP_ATOMIC); + + /* Remember how much data was sent, in order to update at callback */ + kingsun->tx_buf_clear_sent = (ret == 0) ? wraplen : 0; + return ret; +} + +/* Callback transmission routine */ +static void ksdazzle_send_irq(struct urb *urb) +{ + struct ksdazzle_cb *kingsun = urb->context; + struct net_device *netdev = kingsun->netdev; + int ret = 0; + + /* in process of stopping, just drop data */ + if (!netif_running(kingsun->netdev)) { + dev_err(&kingsun->usbdev->dev, + "ksdazzle_send_irq: Network not running!\n"); + return; + } + + /* unlink, shutdown, unplug, other nasties */ + if (urb->status != 0) { + dev_err(&kingsun->usbdev->dev, + "ksdazzle_send_irq: urb asynchronously failed - %d\n", + urb->status); + return; + } + + if (kingsun->tx_buf_clear_used > 0) { + /* Update data remaining to be sent */ + if (kingsun->tx_buf_clear_sent < kingsun->tx_buf_clear_used) { + memmove(kingsun->tx_buf_clear, + kingsun->tx_buf_clear + + kingsun->tx_buf_clear_sent, + kingsun->tx_buf_clear_used - + kingsun->tx_buf_clear_sent); + } + kingsun->tx_buf_clear_used -= kingsun->tx_buf_clear_sent; + kingsun->tx_buf_clear_sent = 0; + + if (kingsun->tx_buf_clear_used > 0) { + /* There is more data to be sent */ + if ((ret = ksdazzle_submit_tx_fragment(kingsun)) != 0) { + dev_err(&kingsun->usbdev->dev, + "ksdazzle_send_irq: failed tx_urb submit: %d\n", + ret); + switch (ret) { + case -ENODEV: + case -EPIPE: + break; + default: + netdev->stats.tx_errors++; + netif_start_queue(netdev); + } + } + } else { + /* All data sent, send next speed && wake network queue */ + if (kingsun->new_speed != -1 && + cpu_to_le32(kingsun->new_speed) != + kingsun->speedparams.baudrate) + ksdazzle_change_speed(kingsun, + kingsun->new_speed); + + netif_wake_queue(netdev); + } + } +} + +/* + * Called from net/core when new frame is available. + */ +static netdev_tx_t ksdazzle_hard_xmit(struct sk_buff *skb, + struct net_device *netdev) +{ + struct ksdazzle_cb *kingsun; + unsigned int wraplen; + int ret = 0; + + netif_stop_queue(netdev); + + /* the IRDA wrapping routines don't deal with non linear skb */ + SKB_LINEAR_ASSERT(skb); + + kingsun = netdev_priv(netdev); + + spin_lock(&kingsun->lock); + kingsun->new_speed = irda_get_next_speed(skb); + + /* Append data to the end of whatever data remains to be transmitted */ + wraplen = + async_wrap_skb(skb, kingsun->tx_buf_clear, KINGSUN_SND_FIFO_SIZE); + kingsun->tx_buf_clear_used = wraplen; + + if ((ret = ksdazzle_submit_tx_fragment(kingsun)) != 0) { + dev_err(&kingsun->usbdev->dev, + "ksdazzle_hard_xmit: failed tx_urb submit: %d\n", ret); + switch (ret) { + case -ENODEV: + case -EPIPE: + break; + default: + netdev->stats.tx_errors++; + netif_start_queue(netdev); + } + } else { + netdev->stats.tx_packets++; + netdev->stats.tx_bytes += skb->len; + + } + + dev_kfree_skb(skb); + spin_unlock(&kingsun->lock); + + return NETDEV_TX_OK; +} + +/* Receive callback function */ +static void ksdazzle_rcv_irq(struct urb *urb) +{ + struct ksdazzle_cb *kingsun = urb->context; + struct net_device *netdev = kingsun->netdev; + + /* in process of stopping, just drop data */ + if (!netif_running(netdev)) { + kingsun->receiving = 0; + return; + } + + /* unlink, shutdown, unplug, other nasties */ + if (urb->status != 0) { + dev_err(&kingsun->usbdev->dev, + "ksdazzle_rcv_irq: urb asynchronously failed - %d\n", + urb->status); + kingsun->receiving = 0; + return; + } + + if (urb->actual_length > 0) { + __u8 *bytes = urb->transfer_buffer; + unsigned int i; + + for (i = 0; i < urb->actual_length; i++) { + async_unwrap_char(netdev, &netdev->stats, + &kingsun->rx_unwrap_buff, bytes[i]); + } + kingsun->receiving = + (kingsun->rx_unwrap_buff.state != OUTSIDE_FRAME) ? 1 : 0; + } + + /* This urb has already been filled in ksdazzle_net_open. It is assumed that + urb keeps the pointer to the payload buffer. + */ + urb->status = 0; + usb_submit_urb(urb, GFP_ATOMIC); +} + +/* + * Function ksdazzle_net_open (dev) + * + * Network device is taken up. Usually this is done by "ifconfig irda0 up" + */ +static int ksdazzle_net_open(struct net_device *netdev) +{ + struct ksdazzle_cb *kingsun = netdev_priv(netdev); + int err = -ENOMEM; + char hwname[16]; + + /* At this point, urbs are NULL, and skb is NULL (see ksdazzle_probe) */ + kingsun->receiving = 0; + + /* Initialize for SIR to copy data directly into skb. */ + kingsun->rx_unwrap_buff.in_frame = FALSE; + kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME; + kingsun->rx_unwrap_buff.truesize = IRDA_SKB_MAX_MTU; + kingsun->rx_unwrap_buff.skb = dev_alloc_skb(IRDA_SKB_MAX_MTU); + if (!kingsun->rx_unwrap_buff.skb) + goto free_mem; + + skb_reserve(kingsun->rx_unwrap_buff.skb, 1); + kingsun->rx_unwrap_buff.head = kingsun->rx_unwrap_buff.skb->data; + + kingsun->rx_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!kingsun->rx_urb) + goto free_mem; + + kingsun->tx_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!kingsun->tx_urb) + goto free_mem; + + kingsun->speed_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!kingsun->speed_urb) + goto free_mem; + + /* Initialize speed for dongle */ + kingsun->new_speed = 9600; + err = ksdazzle_change_speed(kingsun, 9600); + if (err < 0) + goto free_mem; + + /* + * Now that everything should be initialized properly, + * Open new IrLAP layer instance to take care of us... + */ + sprintf(hwname, "usb#%d", kingsun->usbdev->devnum); + kingsun->irlap = irlap_open(netdev, &kingsun->qos, hwname); + if (!kingsun->irlap) { + err = -ENOMEM; + dev_err(&kingsun->usbdev->dev, "irlap_open failed\n"); + goto free_mem; + } + + /* Start reception. */ + usb_fill_int_urb(kingsun->rx_urb, kingsun->usbdev, + usb_rcvintpipe(kingsun->usbdev, kingsun->ep_in), + kingsun->rx_buf, KINGSUN_RCV_MAX, ksdazzle_rcv_irq, + kingsun, 1); + kingsun->rx_urb->status = 0; + err = usb_submit_urb(kingsun->rx_urb, GFP_KERNEL); + if (err) { + dev_err(&kingsun->usbdev->dev, "first urb-submit failed: %d\n", err); + goto close_irlap; + } + + netif_start_queue(netdev); + + /* Situation at this point: + - all work buffers allocated + - urbs allocated and ready to fill + - max rx packet known (in max_rx) + - unwrap state machine initialized, in state outside of any frame + - receive request in progress + - IrLAP layer started, about to hand over packets to send + */ + + return 0; + + close_irlap: + irlap_close(kingsun->irlap); + free_mem: + usb_free_urb(kingsun->speed_urb); + kingsun->speed_urb = NULL; + usb_free_urb(kingsun->tx_urb); + kingsun->tx_urb = NULL; + usb_free_urb(kingsun->rx_urb); + kingsun->rx_urb = NULL; + if (kingsun->rx_unwrap_buff.skb) { + kfree_skb(kingsun->rx_unwrap_buff.skb); + kingsun->rx_unwrap_buff.skb = NULL; + kingsun->rx_unwrap_buff.head = NULL; + } + return err; +} + +/* + * Function ksdazzle_net_close (dev) + * + * Network device is taken down. Usually this is done by + * "ifconfig irda0 down" + */ +static int ksdazzle_net_close(struct net_device *netdev) +{ + struct ksdazzle_cb *kingsun = netdev_priv(netdev); + + /* Stop transmit processing */ + netif_stop_queue(netdev); + + /* Mop up receive && transmit urb's */ + usb_kill_urb(kingsun->tx_urb); + usb_free_urb(kingsun->tx_urb); + kingsun->tx_urb = NULL; + + usb_kill_urb(kingsun->speed_urb); + usb_free_urb(kingsun->speed_urb); + kingsun->speed_urb = NULL; + + usb_kill_urb(kingsun->rx_urb); + usb_free_urb(kingsun->rx_urb); + kingsun->rx_urb = NULL; + + kfree_skb(kingsun->rx_unwrap_buff.skb); + kingsun->rx_unwrap_buff.skb = NULL; + kingsun->rx_unwrap_buff.head = NULL; + kingsun->rx_unwrap_buff.in_frame = FALSE; + kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME; + kingsun->receiving = 0; + + /* Stop and remove instance of IrLAP */ + irlap_close(kingsun->irlap); + + kingsun->irlap = NULL; + + return 0; +} + +/* + * IOCTLs : Extra out-of-band network commands... + */ +static int ksdazzle_net_ioctl(struct net_device *netdev, struct ifreq *rq, + int cmd) +{ + struct if_irda_req *irq = (struct if_irda_req *)rq; + struct ksdazzle_cb *kingsun = netdev_priv(netdev); + int ret = 0; + + switch (cmd) { + case SIOCSBANDWIDTH: /* Set bandwidth */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + /* Check if the device is still there */ + if (netif_device_present(kingsun->netdev)) + return ksdazzle_change_speed(kingsun, + irq->ifr_baudrate); + break; + + case SIOCSMEDIABUSY: /* Set media busy */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + /* Check if the IrDA stack is still there */ + if (netif_running(kingsun->netdev)) + irda_device_set_media_busy(kingsun->netdev, TRUE); + break; + + case SIOCGRECEIVING: + /* Only approximately true */ + irq->ifr_receiving = kingsun->receiving; + break; + + default: + ret = -EOPNOTSUPP; + } + + return ret; +} + +static const struct net_device_ops ksdazzle_ops = { + .ndo_start_xmit = ksdazzle_hard_xmit, + .ndo_open = ksdazzle_net_open, + .ndo_stop = ksdazzle_net_close, + .ndo_do_ioctl = ksdazzle_net_ioctl, +}; + +/* + * This routine is called by the USB subsystem for each new device + * in the system. We need to check if the device is ours, and in + * this case start handling it. + */ +static int ksdazzle_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_host_interface *interface; + struct usb_endpoint_descriptor *endpoint; + + struct usb_device *dev = interface_to_usbdev(intf); + struct ksdazzle_cb *kingsun = NULL; + struct net_device *net = NULL; + int ret = -ENOMEM; + int pipe, maxp_in, maxp_out; + __u8 ep_in; + __u8 ep_out; + + /* Check that there really are two interrupt endpoints. Check based on the + one in drivers/usb/input/usbmouse.c + */ + interface = intf->cur_altsetting; + if (interface->desc.bNumEndpoints != 2) { + dev_err(&intf->dev, "ksdazzle: expected 2 endpoints, found %d\n", + interface->desc.bNumEndpoints); + return -ENODEV; + } + endpoint = &interface->endpoint[KINGSUN_EP_IN].desc; + if (!usb_endpoint_is_int_in(endpoint)) { + dev_err(&intf->dev, + "ksdazzle: endpoint 0 is not interrupt IN\n"); + return -ENODEV; + } + + ep_in = endpoint->bEndpointAddress; + pipe = usb_rcvintpipe(dev, ep_in); + maxp_in = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); + if (maxp_in > 255 || maxp_in <= 1) { + dev_err(&intf->dev, + "ksdazzle: endpoint 0 has max packet size %d not in range [2..255]\n", + maxp_in); + return -ENODEV; + } + + endpoint = &interface->endpoint[KINGSUN_EP_OUT].desc; + if (!usb_endpoint_is_int_out(endpoint)) { + dev_err(&intf->dev, + "ksdazzle: endpoint 1 is not interrupt OUT\n"); + return -ENODEV; + } + + ep_out = endpoint->bEndpointAddress; + pipe = usb_sndintpipe(dev, ep_out); + maxp_out = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); + + /* Allocate network device container. */ + net = alloc_irdadev(sizeof(*kingsun)); + if (!net) + goto err_out1; + + SET_NETDEV_DEV(net, &intf->dev); + kingsun = netdev_priv(net); + kingsun->netdev = net; + kingsun->usbdev = dev; + kingsun->ep_in = ep_in; + kingsun->ep_out = ep_out; + kingsun->irlap = NULL; + kingsun->tx_urb = NULL; + kingsun->tx_buf_clear = NULL; + kingsun->tx_buf_clear_used = 0; + kingsun->tx_buf_clear_sent = 0; + + kingsun->rx_urb = NULL; + kingsun->rx_buf = NULL; + kingsun->rx_unwrap_buff.in_frame = FALSE; + kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME; + kingsun->rx_unwrap_buff.skb = NULL; + kingsun->receiving = 0; + spin_lock_init(&kingsun->lock); + + kingsun->speed_setuprequest = NULL; + kingsun->speed_urb = NULL; + kingsun->speedparams.baudrate = 0; + + /* Allocate input buffer */ + kingsun->rx_buf = kmalloc(KINGSUN_RCV_MAX, GFP_KERNEL); + if (!kingsun->rx_buf) + goto free_mem; + + /* Allocate output buffer */ + kingsun->tx_buf_clear = kmalloc(KINGSUN_SND_FIFO_SIZE, GFP_KERNEL); + if (!kingsun->tx_buf_clear) + goto free_mem; + + /* Allocate and initialize speed setup packet */ + kingsun->speed_setuprequest = + kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL); + if (!kingsun->speed_setuprequest) + goto free_mem; + kingsun->speed_setuprequest->bRequestType = + USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE; + kingsun->speed_setuprequest->bRequest = KINGSUN_REQ_SEND; + kingsun->speed_setuprequest->wValue = cpu_to_le16(0x0200); + kingsun->speed_setuprequest->wIndex = cpu_to_le16(0x0001); + kingsun->speed_setuprequest->wLength = + cpu_to_le16(sizeof(struct ksdazzle_speedparams)); + + printk(KERN_INFO "KingSun/Dazzle IRDA/USB found at address %d, " + "Vendor: %x, Product: %x\n", + dev->devnum, le16_to_cpu(dev->descriptor.idVendor), + le16_to_cpu(dev->descriptor.idProduct)); + + /* Initialize QoS for this device */ + irda_init_max_qos_capabilies(&kingsun->qos); + + /* Baud rates known to be supported. Please uncomment if devices (other + than a SonyEriccson K300 phone) can be shown to support higher speeds + with this dongle. + */ + kingsun->qos.baud_rate.bits = + IR_2400 | IR_9600 | IR_19200 | IR_38400 | IR_57600 | IR_115200; + kingsun->qos.min_turn_time.bits &= KINGSUN_MTT; + irda_qos_bits_to_value(&kingsun->qos); + + /* Override the network functions we need to use */ + net->netdev_ops = &ksdazzle_ops; + + ret = register_netdev(net); + if (ret != 0) + goto free_mem; + + dev_info(&net->dev, "IrDA: Registered KingSun/Dazzle device %s\n", + net->name); + + usb_set_intfdata(intf, kingsun); + + /* Situation at this point: + - all work buffers allocated + - setup requests pre-filled + - urbs not allocated, set to NULL + - max rx packet known (is KINGSUN_FIFO_SIZE) + - unwrap state machine (partially) initialized, but skb == NULL + */ + + return 0; + + free_mem: + kfree(kingsun->speed_setuprequest); + kfree(kingsun->tx_buf_clear); + kfree(kingsun->rx_buf); + free_netdev(net); + err_out1: + return ret; +} + +/* + * The current device is removed, the USB layer tell us to shut it down... + */ +static void ksdazzle_disconnect(struct usb_interface *intf) +{ + struct ksdazzle_cb *kingsun = usb_get_intfdata(intf); + + if (!kingsun) + return; + + unregister_netdev(kingsun->netdev); + + /* Mop up receive && transmit urb's */ + usb_kill_urb(kingsun->speed_urb); + usb_free_urb(kingsun->speed_urb); + kingsun->speed_urb = NULL; + + usb_kill_urb(kingsun->tx_urb); + usb_free_urb(kingsun->tx_urb); + kingsun->tx_urb = NULL; + + usb_kill_urb(kingsun->rx_urb); + usb_free_urb(kingsun->rx_urb); + kingsun->rx_urb = NULL; + + kfree(kingsun->speed_setuprequest); + kfree(kingsun->tx_buf_clear); + kfree(kingsun->rx_buf); + free_netdev(kingsun->netdev); + + usb_set_intfdata(intf, NULL); +} + +#ifdef CONFIG_PM +/* USB suspend, so power off the transmitter/receiver */ +static int ksdazzle_suspend(struct usb_interface *intf, pm_message_t message) +{ + struct ksdazzle_cb *kingsun = usb_get_intfdata(intf); + + netif_device_detach(kingsun->netdev); + if (kingsun->speed_urb != NULL) + usb_kill_urb(kingsun->speed_urb); + if (kingsun->tx_urb != NULL) + usb_kill_urb(kingsun->tx_urb); + if (kingsun->rx_urb != NULL) + usb_kill_urb(kingsun->rx_urb); + return 0; +} + +/* Coming out of suspend, so reset hardware */ +static int ksdazzle_resume(struct usb_interface *intf) +{ + struct ksdazzle_cb *kingsun = usb_get_intfdata(intf); + + if (kingsun->rx_urb != NULL) { + /* Setup request already filled in ksdazzle_probe */ + usb_submit_urb(kingsun->rx_urb, GFP_KERNEL); + } + netif_device_attach(kingsun->netdev); + + return 0; +} +#endif + +/* + * USB device callbacks + */ +static struct usb_driver irda_driver = { + .name = "ksdazzle-sir", + .probe = ksdazzle_probe, + .disconnect = ksdazzle_disconnect, + .id_table = dongles, +#ifdef CONFIG_PM + .suspend = ksdazzle_suspend, + .resume = ksdazzle_resume, +#endif +}; + +module_usb_driver(irda_driver); + +MODULE_AUTHOR("Alex VillacĂs Lasso <a_villacis@palosanto.com>"); +MODULE_DESCRIPTION("IrDA-USB Dongle Driver for KingSun Dazzle"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/irda/drivers/litelink-sir.c b/drivers/staging/irda/drivers/litelink-sir.c new file mode 100644 index 000000000000..8eefcb44bac3 --- /dev/null +++ b/drivers/staging/irda/drivers/litelink-sir.c @@ -0,0 +1,199 @@ +/********************************************************************* + * + * Filename: litelink.c + * Version: 1.1 + * Description: Driver for the Parallax LiteLink dongle + * Status: Stable + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Fri May 7 12:50:33 1999 + * Modified at: Fri Dec 17 09:14:23 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1999 Dag Brattli, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + ********************************************************************/ + +/* + * Modified at: Thu Jan 15 2003 + * Modified by: Eugene Crosser <crosser@average.org> + * + * Convert to "new" IRDA infrastructure for kernel 2.6 + */ + +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/init.h> + +#include <net/irda/irda.h> + +#include "sir-dev.h" + +#define MIN_DELAY 25 /* 15 us, but wait a little more to be sure */ +#define MAX_DELAY 10000 /* 1 ms */ + +static int litelink_open(struct sir_dev *dev); +static int litelink_close(struct sir_dev *dev); +static int litelink_change_speed(struct sir_dev *dev, unsigned speed); +static int litelink_reset(struct sir_dev *dev); + +/* These are the baudrates supported - 9600 must be last one! */ +static unsigned baud_rates[] = { 115200, 57600, 38400, 19200, 9600 }; + +static struct dongle_driver litelink = { + .owner = THIS_MODULE, + .driver_name = "Parallax LiteLink", + .type = IRDA_LITELINK_DONGLE, + .open = litelink_open, + .close = litelink_close, + .reset = litelink_reset, + .set_speed = litelink_change_speed, +}; + +static int __init litelink_sir_init(void) +{ + return irda_register_dongle(&litelink); +} + +static void __exit litelink_sir_cleanup(void) +{ + irda_unregister_dongle(&litelink); +} + +static int litelink_open(struct sir_dev *dev) +{ + struct qos_info *qos = &dev->qos; + + /* Power up dongle */ + sirdev_set_dtr_rts(dev, TRUE, TRUE); + + /* Set the speeds we can accept */ + qos->baud_rate.bits &= IR_115200|IR_57600|IR_38400|IR_19200|IR_9600; + qos->min_turn_time.bits = 0x7f; /* Needs 0.01 ms */ + irda_qos_bits_to_value(qos); + + /* irda thread waits 50 msec for power settling */ + + return 0; +} + +static int litelink_close(struct sir_dev *dev) +{ + /* Power off dongle */ + sirdev_set_dtr_rts(dev, FALSE, FALSE); + + return 0; +} + +/* + * Function litelink_change_speed (task) + * + * Change speed of the Litelink dongle. To cycle through the available + * baud rates, pulse RTS low for a few ms. + */ +static int litelink_change_speed(struct sir_dev *dev, unsigned speed) +{ + int i; + + /* dongle already reset by irda-thread - current speed (dongle and + * port) is the default speed (115200 for litelink!) + */ + + /* Cycle through avaiable baudrates until we reach the correct one */ + for (i = 0; baud_rates[i] != speed; i++) { + + /* end-of-list reached due to invalid speed request */ + if (baud_rates[i] == 9600) + break; + + /* Set DTR, clear RTS */ + sirdev_set_dtr_rts(dev, FALSE, TRUE); + + /* Sleep a minimum of 15 us */ + udelay(MIN_DELAY); + + /* Set DTR, Set RTS */ + sirdev_set_dtr_rts(dev, TRUE, TRUE); + + /* Sleep a minimum of 15 us */ + udelay(MIN_DELAY); + } + + dev->speed = baud_rates[i]; + + /* invalid baudrate should not happen - but if, we return -EINVAL and + * the dongle configured for 9600 so the stack has a chance to recover + */ + + return (dev->speed == speed) ? 0 : -EINVAL; +} + +/* + * Function litelink_reset (task) + * + * Reset the Litelink type dongle. + * + */ +static int litelink_reset(struct sir_dev *dev) +{ + /* probably the power-up can be dropped here, but with only + * 15 usec delay it's not worth the risk unless somebody with + * the hardware confirms it doesn't break anything... + */ + + /* Power on dongle */ + sirdev_set_dtr_rts(dev, TRUE, TRUE); + + /* Sleep a minimum of 15 us */ + udelay(MIN_DELAY); + + /* Clear RTS to reset dongle */ + sirdev_set_dtr_rts(dev, TRUE, FALSE); + + /* Sleep a minimum of 15 us */ + udelay(MIN_DELAY); + + /* Go back to normal mode */ + sirdev_set_dtr_rts(dev, TRUE, TRUE); + + /* Sleep a minimum of 15 us */ + udelay(MIN_DELAY); + + /* This dongles speed defaults to 115200 bps */ + dev->speed = 115200; + + return 0; +} + +MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>"); +MODULE_DESCRIPTION("Parallax Litelink dongle driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("irda-dongle-5"); /* IRDA_LITELINK_DONGLE */ + +/* + * Function init_module (void) + * + * Initialize Litelink module + * + */ +module_init(litelink_sir_init); + +/* + * Function cleanup_module (void) + * + * Cleanup Litelink module + * + */ +module_exit(litelink_sir_cleanup); diff --git a/drivers/staging/irda/drivers/ma600-sir.c b/drivers/staging/irda/drivers/ma600-sir.c new file mode 100644 index 000000000000..a764817b47f1 --- /dev/null +++ b/drivers/staging/irda/drivers/ma600-sir.c @@ -0,0 +1,253 @@ +/********************************************************************* + * + * Filename: ma600.c + * Version: 0.1 + * Description: Implementation of the MA600 dongle + * Status: Experimental. + * Author: Leung <95Etwl@alumni.ee.ust.hk> http://www.engsvr.ust/~eetwl95 + * Created at: Sat Jun 10 20:02:35 2000 + * Modified at: Sat Aug 16 09:34:13 2003 + * Modified by: Martin Diehl <mad@mdiehl.de> (modified for new sir_dev) + * + * Note: very thanks to Mr. Maru Wang <maru@mobileaction.com.tw> for providing + * information on the MA600 dongle + * + * Copyright (c) 2000 Leung, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + ********************************************************************/ + +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/init.h> + +#include <net/irda/irda.h> + +#include "sir-dev.h" + +static int ma600_open(struct sir_dev *); +static int ma600_close(struct sir_dev *); +static int ma600_change_speed(struct sir_dev *, unsigned); +static int ma600_reset(struct sir_dev *); + +/* control byte for MA600 */ +#define MA600_9600 0x00 +#define MA600_19200 0x01 +#define MA600_38400 0x02 +#define MA600_57600 0x03 +#define MA600_115200 0x04 +#define MA600_DEV_ID1 0x05 +#define MA600_DEV_ID2 0x06 +#define MA600_2400 0x08 + +static struct dongle_driver ma600 = { + .owner = THIS_MODULE, + .driver_name = "MA600", + .type = IRDA_MA600_DONGLE, + .open = ma600_open, + .close = ma600_close, + .reset = ma600_reset, + .set_speed = ma600_change_speed, +}; + + +static int __init ma600_sir_init(void) +{ + return irda_register_dongle(&ma600); +} + +static void __exit ma600_sir_cleanup(void) +{ + irda_unregister_dongle(&ma600); +} + +/* + Power on: + (0) Clear RTS and DTR for 1 second + (1) Set RTS and DTR for 1 second + (2) 9600 bps now + Note: assume RTS, DTR are clear before +*/ +static int ma600_open(struct sir_dev *dev) +{ + struct qos_info *qos = &dev->qos; + + sirdev_set_dtr_rts(dev, TRUE, TRUE); + + /* Explicitly set the speeds we can accept */ + qos->baud_rate.bits &= IR_2400|IR_9600|IR_19200|IR_38400 + |IR_57600|IR_115200; + /* Hm, 0x01 means 10ms - for >= 1ms we would need 0x07 */ + qos->min_turn_time.bits = 0x01; /* Needs at least 1 ms */ + irda_qos_bits_to_value(qos); + + /* irda thread waits 50 msec for power settling */ + + return 0; +} + +static int ma600_close(struct sir_dev *dev) +{ + /* Power off dongle */ + sirdev_set_dtr_rts(dev, FALSE, FALSE); + + return 0; +} + +static __u8 get_control_byte(__u32 speed) +{ + __u8 byte; + + switch (speed) { + default: + case 115200: + byte = MA600_115200; + break; + case 57600: + byte = MA600_57600; + break; + case 38400: + byte = MA600_38400; + break; + case 19200: + byte = MA600_19200; + break; + case 9600: + byte = MA600_9600; + break; + case 2400: + byte = MA600_2400; + break; + } + + return byte; +} + +/* + * Function ma600_change_speed (dev, speed) + * + * Set the speed for the MA600 type dongle. + * + * The dongle has already been reset to a known state (dongle default) + * We cycle through speeds by pulsing RTS low and then high. + */ + +/* + * Function ma600_change_speed (dev, speed) + * + * Set the speed for the MA600 type dongle. + * + * Algorithm + * 1. Reset (already done by irda thread state machine) + * 2. clear RTS, set DTR and wait for 1ms + * 3. send Control Byte to the MA600 through TXD to set new baud rate + * wait until the stop bit of Control Byte is sent (for 9600 baud rate, + * it takes about 10 msec) + * 4. set RTS, set DTR (return to NORMAL Operation) + * 5. wait at least 10 ms, new setting (baud rate, etc) takes effect here + * after + */ + +/* total delays are only about 20ms - let's just sleep for now to + * avoid the state machine complexity before we get things working + */ + +static int ma600_change_speed(struct sir_dev *dev, unsigned speed) +{ + u8 byte; + + pr_debug("%s(), speed=%d (was %d)\n", __func__, + speed, dev->speed); + + /* dongle already reset, dongle and port at default speed (9600) */ + + /* Set RTS low for 1 ms */ + sirdev_set_dtr_rts(dev, TRUE, FALSE); + mdelay(1); + + /* Write control byte */ + byte = get_control_byte(speed); + sirdev_raw_write(dev, &byte, sizeof(byte)); + + /* Wait at least 10ms: fake wait_until_sent - 10 bits at 9600 baud*/ + msleep(15); /* old ma600 uses 15ms */ + +#if 1 + /* read-back of the control byte. ma600 is the first dongle driver + * which uses this so there might be some unidentified issues. + * Disable this in case of problems with readback. + */ + + sirdev_raw_read(dev, &byte, sizeof(byte)); + if (byte != get_control_byte(speed)) { + net_warn_ratelimited("%s(): bad control byte read-back %02x != %02x\n", + __func__, (unsigned)byte, + (unsigned)get_control_byte(speed)); + return -1; + } + else + pr_debug("%s() control byte write read OK\n", __func__); +#endif + + /* Set DTR, Set RTS */ + sirdev_set_dtr_rts(dev, TRUE, TRUE); + + /* Wait at least 10ms */ + msleep(10); + + /* dongle is now switched to the new speed */ + dev->speed = speed; + + return 0; +} + +/* + * Function ma600_reset (dev) + * + * This function resets the ma600 dongle. + * + * Algorithm: + * 0. DTR=0, RTS=1 and wait 10 ms + * 1. DTR=1, RTS=1 and wait 10 ms + * 2. 9600 bps now + */ + +/* total delays are only about 20ms - let's just sleep for now to + * avoid the state machine complexity before we get things working + */ + +static int ma600_reset(struct sir_dev *dev) +{ + /* Reset the dongle : set DTR low for 10 ms */ + sirdev_set_dtr_rts(dev, FALSE, TRUE); + msleep(10); + + /* Go back to normal mode */ + sirdev_set_dtr_rts(dev, TRUE, TRUE); + msleep(10); + + dev->speed = 9600; /* That's the dongle-default */ + + return 0; +} + +MODULE_AUTHOR("Leung <95Etwl@alumni.ee.ust.hk> http://www.engsvr.ust/~eetwl95"); +MODULE_DESCRIPTION("MA600 dongle driver version 0.1"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("irda-dongle-11"); /* IRDA_MA600_DONGLE */ + +module_init(ma600_sir_init); +module_exit(ma600_sir_cleanup); + diff --git a/drivers/staging/irda/drivers/mcp2120-sir.c b/drivers/staging/irda/drivers/mcp2120-sir.c new file mode 100644 index 000000000000..2e33f91bfe8f --- /dev/null +++ b/drivers/staging/irda/drivers/mcp2120-sir.c @@ -0,0 +1,224 @@ +/********************************************************************* + * + * + * Filename: mcp2120.c + * Version: 1.0 + * Description: Implementation for the MCP2120 (Microchip) + * Status: Experimental. + * Author: Felix Tang (tangf@eyetap.org) + * Created at: Sun Mar 31 19:32:12 EST 2002 + * Based on code by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 2002 Felix Tang, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + ********************************************************************/ + +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/init.h> + +#include <net/irda/irda.h> + +#include "sir-dev.h" + +static int mcp2120_reset(struct sir_dev *dev); +static int mcp2120_open(struct sir_dev *dev); +static int mcp2120_close(struct sir_dev *dev); +static int mcp2120_change_speed(struct sir_dev *dev, unsigned speed); + +#define MCP2120_9600 0x87 +#define MCP2120_19200 0x8B +#define MCP2120_38400 0x85 +#define MCP2120_57600 0x83 +#define MCP2120_115200 0x81 + +#define MCP2120_COMMIT 0x11 + +static struct dongle_driver mcp2120 = { + .owner = THIS_MODULE, + .driver_name = "Microchip MCP2120", + .type = IRDA_MCP2120_DONGLE, + .open = mcp2120_open, + .close = mcp2120_close, + .reset = mcp2120_reset, + .set_speed = mcp2120_change_speed, +}; + +static int __init mcp2120_sir_init(void) +{ + return irda_register_dongle(&mcp2120); +} + +static void __exit mcp2120_sir_cleanup(void) +{ + irda_unregister_dongle(&mcp2120); +} + +static int mcp2120_open(struct sir_dev *dev) +{ + struct qos_info *qos = &dev->qos; + + /* seems no explicit power-on required here and reset switching it on anyway */ + + qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200; + qos->min_turn_time.bits = 0x01; + irda_qos_bits_to_value(qos); + + return 0; +} + +static int mcp2120_close(struct sir_dev *dev) +{ + /* Power off dongle */ + /* reset and inhibit mcp2120 */ + sirdev_set_dtr_rts(dev, TRUE, TRUE); + // sirdev_set_dtr_rts(dev, FALSE, FALSE); + + return 0; +} + +/* + * Function mcp2120_change_speed (dev, speed) + * + * Set the speed for the MCP2120. + * + */ + +#define MCP2120_STATE_WAIT_SPEED (SIRDEV_STATE_DONGLE_SPEED+1) + +static int mcp2120_change_speed(struct sir_dev *dev, unsigned speed) +{ + unsigned state = dev->fsm.substate; + unsigned delay = 0; + u8 control[2]; + static int ret = 0; + + switch (state) { + case SIRDEV_STATE_DONGLE_SPEED: + /* Set DTR to enter command mode */ + sirdev_set_dtr_rts(dev, TRUE, FALSE); + udelay(500); + + ret = 0; + switch (speed) { + default: + speed = 9600; + ret = -EINVAL; + /* fall through */ + case 9600: + control[0] = MCP2120_9600; + //printk("mcp2120 9600\n"); + break; + case 19200: + control[0] = MCP2120_19200; + //printk("mcp2120 19200\n"); + break; + case 34800: + control[0] = MCP2120_38400; + //printk("mcp2120 38400\n"); + break; + case 57600: + control[0] = MCP2120_57600; + //printk("mcp2120 57600\n"); + break; + case 115200: + control[0] = MCP2120_115200; + //printk("mcp2120 115200\n"); + break; + } + control[1] = MCP2120_COMMIT; + + /* Write control bytes */ + sirdev_raw_write(dev, control, 2); + dev->speed = speed; + + state = MCP2120_STATE_WAIT_SPEED; + delay = 100; + //printk("mcp2120_change_speed: dongle_speed\n"); + break; + + case MCP2120_STATE_WAIT_SPEED: + /* Go back to normal mode */ + sirdev_set_dtr_rts(dev, FALSE, FALSE); + //printk("mcp2120_change_speed: mcp_wait\n"); + break; + + default: + net_err_ratelimited("%s(), undefine state %d\n", + __func__, state); + ret = -EINVAL; + break; + } + dev->fsm.substate = state; + return (delay > 0) ? delay : ret; +} + +/* + * Function mcp2120_reset (driver) + * + * This function resets the mcp2120 dongle. + * + * Info: -set RTS to reset mcp2120 + * -set DTR to set mcp2120 software command mode + * -mcp2120 defaults to 9600 baud after reset + * + * Algorithm: + * 0. Set RTS to reset mcp2120. + * 1. Clear RTS and wait for device reset timer of 30 ms (max). + * + */ + +#define MCP2120_STATE_WAIT1_RESET (SIRDEV_STATE_DONGLE_RESET+1) +#define MCP2120_STATE_WAIT2_RESET (SIRDEV_STATE_DONGLE_RESET+2) + +static int mcp2120_reset(struct sir_dev *dev) +{ + unsigned state = dev->fsm.substate; + unsigned delay = 0; + int ret = 0; + + switch (state) { + case SIRDEV_STATE_DONGLE_RESET: + //printk("mcp2120_reset: dongle_reset\n"); + /* Reset dongle by setting RTS*/ + sirdev_set_dtr_rts(dev, TRUE, TRUE); + state = MCP2120_STATE_WAIT1_RESET; + delay = 50; + break; + + case MCP2120_STATE_WAIT1_RESET: + //printk("mcp2120_reset: mcp2120_wait1\n"); + /* clear RTS and wait for at least 30 ms. */ + sirdev_set_dtr_rts(dev, FALSE, FALSE); + state = MCP2120_STATE_WAIT2_RESET; + delay = 50; + break; + + case MCP2120_STATE_WAIT2_RESET: + //printk("mcp2120_reset mcp2120_wait2\n"); + /* Go back to normal mode */ + sirdev_set_dtr_rts(dev, FALSE, FALSE); + break; + + default: + net_err_ratelimited("%s(), undefined state %d\n", + __func__, state); + ret = -EINVAL; + break; + } + dev->fsm.substate = state; + return (delay > 0) ? delay : ret; +} + +MODULE_AUTHOR("Felix Tang <tangf@eyetap.org>"); +MODULE_DESCRIPTION("Microchip MCP2120"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("irda-dongle-9"); /* IRDA_MCP2120_DONGLE */ + +module_init(mcp2120_sir_init); +module_exit(mcp2120_sir_cleanup); diff --git a/drivers/staging/irda/drivers/mcs7780.c b/drivers/staging/irda/drivers/mcs7780.c new file mode 100644 index 000000000000..c3f0b254b344 --- /dev/null +++ b/drivers/staging/irda/drivers/mcs7780.c @@ -0,0 +1,987 @@ +/***************************************************************************** +* +* Filename: mcs7780.c +* Version: 0.4-alpha +* Description: Irda MosChip USB Dongle Driver +* Authors: Lukasz Stelmach <stlman@poczta.fm> +* Brian Pugh <bpugh@cs.pdx.edu> +* Judy Fischbach <jfisch@cs.pdx.edu> +* +* Based on stir4200 driver, but some things done differently. +* Based on earlier driver by Paul Stewart <stewart@parc.com> +* +* Copyright (C) 2000, Roman Weissgaerber <weissg@vienna.at> +* Copyright (C) 2001, Dag Brattli <dag@brattli.net> +* Copyright (C) 2001, Jean Tourrilhes <jt@hpl.hp.com> +* Copyright (C) 2004, Stephen Hemminger <shemminger@osdl.org> +* Copyright (C) 2005, Lukasz Stelmach <stlman@poczta.fm> +* Copyright (C) 2005, Brian Pugh <bpugh@cs.pdx.edu> +* Copyright (C) 2005, Judy Fischbach <jfisch@cs.pdx.edu> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + +/* + * MCS7780 is a simple USB to IrDA bridge by MosChip. It is neither + * compatibile with irda-usb nor with stir4200. Although it is quite + * similar to the later as far as general idea of operation is concerned. + * That is it requires the software to do all the framing job at SIR speeds. + * The hardware does take care of the framing at MIR and FIR speeds. + * It supports all speeds from 2400 through 4Mbps + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/slab.h> +#include <linux/usb.h> +#include <linux/device.h> +#include <linux/crc32.h> + +#include <asm/unaligned.h> +#include <asm/byteorder.h> +#include <linux/uaccess.h> + +#include <net/irda/irda.h> +#include <net/irda/wrapper.h> +#include <net/irda/crc.h> + +#include "mcs7780.h" + +#define MCS_VENDOR_ID 0x9710 +#define MCS_PRODUCT_ID 0x7780 + +static const struct usb_device_id mcs_table[] = { + /* MosChip Corp., MCS7780 FIR-USB Adapter */ + {USB_DEVICE(MCS_VENDOR_ID, MCS_PRODUCT_ID)}, + {}, +}; + +MODULE_AUTHOR("Brian Pugh <bpugh@cs.pdx.edu>"); +MODULE_DESCRIPTION("IrDA-USB Dongle Driver for MosChip MCS7780"); +MODULE_VERSION("0.3alpha"); +MODULE_LICENSE("GPL"); + +MODULE_DEVICE_TABLE(usb, mcs_table); + +static int qos_mtt_bits = 0x07 /* > 1ms */ ; +module_param(qos_mtt_bits, int, 0); +MODULE_PARM_DESC(qos_mtt_bits, "Minimum Turn Time"); + +static int receive_mode = 0x1; +module_param(receive_mode, int, 0); +MODULE_PARM_DESC(receive_mode, + "Receive mode of the device (1:fast, 0:slow, default:1)"); + +static int sir_tweak = 1; +module_param(sir_tweak, int, 0444); +MODULE_PARM_DESC(sir_tweak, + "Default pulse width (1:1.6us, 0:3/16 bit, default:1)."); + +static int transceiver_type = MCS_TSC_VISHAY; +module_param(transceiver_type, int, 0444); +MODULE_PARM_DESC(transceiver_type, "IR transceiver type, see mcs7780.h."); + +static struct usb_driver mcs_driver = { + .name = "mcs7780", + .probe = mcs_probe, + .disconnect = mcs_disconnect, + .id_table = mcs_table, +}; + +/* speed flag selection by direct addressing. +addr = (speed >> 8) & 0x0f + +0x1 57600 0x2 115200 0x4 1152000 0x5 9600 +0x6 38400 0x9 2400 0xa 576000 0xb 19200 + +4Mbps (or 2400) must be checked separately. Since it also has +to be programmed in a different manner that is not a big problem. +*/ +static __u16 mcs_speed_set[16] = { 0, + MCS_SPEED_57600, + MCS_SPEED_115200, + 0, + MCS_SPEED_1152000, + MCS_SPEED_9600, + MCS_SPEED_38400, + 0, 0, + MCS_SPEED_2400, + MCS_SPEED_576000, + MCS_SPEED_19200, + 0, 0, 0, +}; + +/* Set given 16 bit register with a 16 bit value. Send control message + * to set dongle register. */ +static int mcs_set_reg(struct mcs_cb *mcs, __u16 reg, __u16 val) +{ + struct usb_device *dev = mcs->usbdev; + return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), MCS_WRREQ, + MCS_WR_RTYPE, val, reg, NULL, 0, + msecs_to_jiffies(MCS_CTRL_TIMEOUT)); +} + +/* Get 16 bit register value. Send contol message to read dongle register. */ +static int mcs_get_reg(struct mcs_cb *mcs, __u16 reg, __u16 * val) +{ + struct usb_device *dev = mcs->usbdev; + void *dmabuf; + int ret; + + dmabuf = kmalloc(sizeof(__u16), GFP_KERNEL); + if (!dmabuf) + return -ENOMEM; + + ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), MCS_RDREQ, + MCS_RD_RTYPE, 0, reg, dmabuf, 2, + msecs_to_jiffies(MCS_CTRL_TIMEOUT)); + + memcpy(val, dmabuf, sizeof(__u16)); + kfree(dmabuf); + + return ret; +} + +/* Setup a communication between mcs7780 and TFDU chips. It is described + * in more detail in the data sheet. The setup sequence puts the the + * vishay tranceiver into high speed mode. It will also receive SIR speed + * packets but at reduced sensitivity. + */ + +/* 0: OK 1:ERROR */ +static inline int mcs_setup_transceiver_vishay(struct mcs_cb *mcs) +{ + int ret = 0; + __u16 rval; + + /* mcs_get_reg should read exactly two bytes from the dongle */ + ret = mcs_get_reg(mcs, MCS_XCVR_REG, &rval); + if (unlikely(ret != 2)) { + ret = -EIO; + goto error; + } + + /* The MCS_XCVR_CONF bit puts the transceiver into configuration + * mode. The MCS_MODE0 bit must start out high (1) and then + * transition to low and the MCS_STFIR and MCS_MODE1 bits must + * be low. + */ + rval |= (MCS_MODE0 | MCS_XCVR_CONF); + rval &= ~MCS_STFIR; + rval &= ~MCS_MODE1; + ret = mcs_set_reg(mcs, MCS_XCVR_REG, rval); + if (unlikely(ret)) + goto error; + + rval &= ~MCS_MODE0; + ret = mcs_set_reg(mcs, MCS_XCVR_REG, rval); + if (unlikely(ret)) + goto error; + + rval &= ~MCS_XCVR_CONF; + ret = mcs_set_reg(mcs, MCS_XCVR_REG, rval); + if (unlikely(ret)) + goto error; + + ret = 0; +error: + return ret; +} + +/* Setup a communication between mcs7780 and agilent chip. */ +static inline int mcs_setup_transceiver_agilent(struct mcs_cb *mcs) +{ + net_warn_ratelimited("This transceiver type is not supported yet\n"); + return 1; +} + +/* Setup a communication between mcs7780 and sharp chip. */ +static inline int mcs_setup_transceiver_sharp(struct mcs_cb *mcs) +{ + net_warn_ratelimited("This transceiver type is not supported yet\n"); + return 1; +} + +/* Common setup for all transceivers */ +static inline int mcs_setup_transceiver(struct mcs_cb *mcs) +{ + int ret = 0; + __u16 rval; + const char *msg; + + msg = "Basic transceiver setup error"; + + /* read value of MODE Register, set the DRIVER and RESET bits + * and write value back out to MODE Register + */ + ret = mcs_get_reg(mcs, MCS_MODE_REG, &rval); + if(unlikely(ret != 2)) + goto error; + rval |= MCS_DRIVER; /* put the mcs7780 into configuration mode. */ + ret = mcs_set_reg(mcs, MCS_MODE_REG, rval); + if(unlikely(ret)) + goto error; + + rval = 0; /* set min pulse width to 0 initially. */ + ret = mcs_set_reg(mcs, MCS_MINRXPW_REG, rval); + if(unlikely(ret)) + goto error; + + ret = mcs_get_reg(mcs, MCS_MODE_REG, &rval); + if(unlikely(ret != 2)) + goto error; + + rval &= ~MCS_FIR; /* turn off fir mode. */ + if(mcs->sir_tweak) + rval |= MCS_SIR16US; /* 1.6us pulse width */ + else + rval &= ~MCS_SIR16US; /* 3/16 bit time pulse width */ + + /* make sure ask mode and back to back packets are off. */ + rval &= ~(MCS_BBTG | MCS_ASK); + + rval &= ~MCS_SPEED_MASK; + rval |= MCS_SPEED_9600; /* make sure initial speed is 9600. */ + mcs->speed = 9600; + mcs->new_speed = 0; /* new_speed is set to 0 */ + rval &= ~MCS_PLLPWDN; /* disable power down. */ + + /* make sure device determines direction and that the auto send sip + * pulse are on. + */ + rval |= MCS_DTD | MCS_SIPEN; + + ret = mcs_set_reg(mcs, MCS_MODE_REG, rval); + if(unlikely(ret)) + goto error; + + msg = "transceiver model specific setup error"; + switch (mcs->transceiver_type) { + case MCS_TSC_VISHAY: + ret = mcs_setup_transceiver_vishay(mcs); + break; + + case MCS_TSC_SHARP: + ret = mcs_setup_transceiver_sharp(mcs); + break; + + case MCS_TSC_AGILENT: + ret = mcs_setup_transceiver_agilent(mcs); + break; + + default: + net_warn_ratelimited("Unknown transceiver type: %d\n", + mcs->transceiver_type); + ret = 1; + } + if (unlikely(ret)) + goto error; + + /* If transceiver is not SHARP, then if receive mode set + * on the RXFAST bit in the XCVR Register otherwise unset it + */ + if (mcs->transceiver_type != MCS_TSC_SHARP) { + + ret = mcs_get_reg(mcs, MCS_XCVR_REG, &rval); + if (unlikely(ret != 2)) + goto error; + if (mcs->receive_mode) + rval |= MCS_RXFAST; + else + rval &= ~MCS_RXFAST; + ret = mcs_set_reg(mcs, MCS_XCVR_REG, rval); + if (unlikely(ret)) + goto error; + } + + msg = "transceiver reset"; + + ret = mcs_get_reg(mcs, MCS_MODE_REG, &rval); + if (unlikely(ret != 2)) + goto error; + + /* reset the mcs7780 so all changes take effect. */ + rval &= ~MCS_RESET; + ret = mcs_set_reg(mcs, MCS_MODE_REG, rval); + if (unlikely(ret)) + goto error; + else + return ret; + +error: + net_err_ratelimited("%s\n", msg); + return ret; +} + +/* Wraps the data in format for SIR */ +static inline int mcs_wrap_sir_skb(struct sk_buff *skb, __u8 * buf) +{ + int wraplen; + + /* 2: full frame length, including "the length" */ + wraplen = async_wrap_skb(skb, buf + 2, 4094); + + wraplen += 2; + buf[0] = wraplen & 0xff; + buf[1] = (wraplen >> 8) & 0xff; + + return wraplen; +} + +/* Wraps the data in format for FIR */ +static unsigned mcs_wrap_fir_skb(const struct sk_buff *skb, __u8 *buf) +{ + unsigned int len = 0; + __u32 fcs = ~(crc32_le(~0, skb->data, skb->len)); + + /* add 2 bytes for length value and 4 bytes for fcs. */ + len = skb->len + 6; + + /* The mcs7780 requires that the first two bytes are the packet + * length in little endian order. Note: the length value includes + * the two bytes for the length value itself. + */ + buf[0] = len & 0xff; + buf[1] = (len >> 8) & 0xff; + /* copy the data into the tx buffer. */ + skb_copy_from_linear_data(skb, buf + 2, skb->len); + /* put the fcs in the last four bytes in little endian order. */ + buf[len - 4] = fcs & 0xff; + buf[len - 3] = (fcs >> 8) & 0xff; + buf[len - 2] = (fcs >> 16) & 0xff; + buf[len - 1] = (fcs >> 24) & 0xff; + + return len; +} + +/* Wraps the data in format for MIR */ +static unsigned mcs_wrap_mir_skb(const struct sk_buff *skb, __u8 *buf) +{ + __u16 fcs = 0; + int len = skb->len + 4; + + fcs = ~(irda_calc_crc16(~fcs, skb->data, skb->len)); + /* put the total packet length in first. Note: packet length + * value includes the two bytes that hold the packet length + * itself. + */ + buf[0] = len & 0xff; + buf[1] = (len >> 8) & 0xff; + /* copy the data */ + skb_copy_from_linear_data(skb, buf + 2, skb->len); + /* put the fcs in last two bytes in little endian order. */ + buf[len - 2] = fcs & 0xff; + buf[len - 1] = (fcs >> 8) & 0xff; + + return len; +} + +/* Unwrap received packets at MIR speed. A 16 bit crc_ccitt checksum is + * used for the fcs. When performed over the entire packet the result + * should be GOOD_FCS = 0xf0b8. Hands the unwrapped data off to the IrDA + * layer via a sk_buff. + */ +static void mcs_unwrap_mir(struct mcs_cb *mcs, __u8 *buf, int len) +{ + __u16 fcs; + int new_len; + struct sk_buff *skb; + + /* Assume that the frames are going to fill a single packet + * rather than span multiple packets. + */ + + new_len = len - 2; + if(unlikely(new_len <= 0)) { + net_err_ratelimited("%s short frame length %d\n", + mcs->netdev->name, new_len); + ++mcs->netdev->stats.rx_errors; + ++mcs->netdev->stats.rx_length_errors; + return; + } + fcs = 0; + fcs = irda_calc_crc16(~fcs, buf, len); + + if(fcs != GOOD_FCS) { + net_err_ratelimited("crc error calc 0x%x len %d\n", + fcs, new_len); + mcs->netdev->stats.rx_errors++; + mcs->netdev->stats.rx_crc_errors++; + return; + } + + skb = dev_alloc_skb(new_len + 1); + if(unlikely(!skb)) { + ++mcs->netdev->stats.rx_dropped; + return; + } + + skb_reserve(skb, 1); + skb_copy_to_linear_data(skb, buf, new_len); + skb_put(skb, new_len); + skb_reset_mac_header(skb); + skb->protocol = htons(ETH_P_IRDA); + skb->dev = mcs->netdev; + + netif_rx(skb); + + mcs->netdev->stats.rx_packets++; + mcs->netdev->stats.rx_bytes += new_len; +} + +/* Unwrap received packets at FIR speed. A 32 bit crc_ccitt checksum is + * used for the fcs. Hands the unwrapped data off to the IrDA + * layer via a sk_buff. + */ +static void mcs_unwrap_fir(struct mcs_cb *mcs, __u8 *buf, int len) +{ + __u32 fcs; + int new_len; + struct sk_buff *skb; + + /* Assume that the frames are going to fill a single packet + * rather than span multiple packets. This is most likely a false + * assumption. + */ + + new_len = len - 4; + if(unlikely(new_len <= 0)) { + net_err_ratelimited("%s short frame length %d\n", + mcs->netdev->name, new_len); + ++mcs->netdev->stats.rx_errors; + ++mcs->netdev->stats.rx_length_errors; + return; + } + + fcs = ~(crc32_le(~0, buf, new_len)); + if(fcs != get_unaligned_le32(buf + new_len)) { + net_err_ratelimited("crc error calc 0x%x len %d\n", + fcs, new_len); + mcs->netdev->stats.rx_errors++; + mcs->netdev->stats.rx_crc_errors++; + return; + } + + skb = dev_alloc_skb(new_len + 1); + if(unlikely(!skb)) { + ++mcs->netdev->stats.rx_dropped; + return; + } + + skb_reserve(skb, 1); + skb_copy_to_linear_data(skb, buf, new_len); + skb_put(skb, new_len); + skb_reset_mac_header(skb); + skb->protocol = htons(ETH_P_IRDA); + skb->dev = mcs->netdev; + + netif_rx(skb); + + mcs->netdev->stats.rx_packets++; + mcs->netdev->stats.rx_bytes += new_len; +} + + +/* Allocates urbs for both receive and transmit. + * If alloc fails return error code 0 (fail) otherwise + * return error code 1 (success). + */ +static inline int mcs_setup_urbs(struct mcs_cb *mcs) +{ + mcs->rx_urb = NULL; + + mcs->tx_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!mcs->tx_urb) + return 0; + + mcs->rx_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!mcs->rx_urb) { + usb_free_urb(mcs->tx_urb); + mcs->tx_urb = NULL; + return 0; + } + + return 1; +} + +/* Sets up state to be initially outside frame, gets receive urb, + * sets status to successful and then submits the urb to start + * receiving the data. + */ +static inline int mcs_receive_start(struct mcs_cb *mcs) +{ + mcs->rx_buff.in_frame = FALSE; + mcs->rx_buff.state = OUTSIDE_FRAME; + + usb_fill_bulk_urb(mcs->rx_urb, mcs->usbdev, + usb_rcvbulkpipe(mcs->usbdev, mcs->ep_in), + mcs->in_buf, 4096, mcs_receive_irq, mcs); + + mcs->rx_urb->status = 0; + return usb_submit_urb(mcs->rx_urb, GFP_KERNEL); +} + +/* Finds the in and out endpoints for the mcs control block */ +static inline int mcs_find_endpoints(struct mcs_cb *mcs, + struct usb_host_endpoint *ep, int epnum) +{ + int i; + int ret = 0; + + /* If no place to store the endpoints just return */ + if (!ep) + return ret; + + /* cycle through all endpoints, find the first two that are DIR_IN */ + for (i = 0; i < epnum; i++) { + if (ep[i].desc.bEndpointAddress & USB_DIR_IN) + mcs->ep_in = ep[i].desc.bEndpointAddress; + else + mcs->ep_out = ep[i].desc.bEndpointAddress; + + /* MosChip says that the chip has only two bulk + * endpoints. Find one for each direction and move on. + */ + if ((mcs->ep_in != 0) && (mcs->ep_out != 0)) { + ret = 1; + break; + } + } + + return ret; +} + +static void mcs_speed_work(struct work_struct *work) +{ + struct mcs_cb *mcs = container_of(work, struct mcs_cb, work); + struct net_device *netdev = mcs->netdev; + + mcs_speed_change(mcs); + netif_wake_queue(netdev); +} + +/* Function to change the speed of the mcs7780. Fully supports SIR, + * MIR, and FIR speeds. + */ +static int mcs_speed_change(struct mcs_cb *mcs) +{ + int ret = 0; + int rst = 0; + int cnt = 0; + __u16 nspeed; + __u16 rval; + + nspeed = mcs_speed_set[(mcs->new_speed >> 8) & 0x0f]; + + do { + mcs_get_reg(mcs, MCS_RESV_REG, &rval); + } while(cnt++ < 100 && (rval & MCS_IRINTX)); + + if (cnt > 100) { + net_err_ratelimited("unable to change speed\n"); + ret = -EIO; + goto error; + } + + mcs_get_reg(mcs, MCS_MODE_REG, &rval); + + /* MINRXPW values recommended by MosChip */ + if (mcs->new_speed <= 115200) { + rval &= ~MCS_FIR; + + if ((rst = (mcs->speed > 115200))) + mcs_set_reg(mcs, MCS_MINRXPW_REG, 0); + + } else if (mcs->new_speed <= 1152000) { + rval &= ~MCS_FIR; + + if ((rst = !(mcs->speed == 576000 || mcs->speed == 1152000))) + mcs_set_reg(mcs, MCS_MINRXPW_REG, 5); + + } else { + rval |= MCS_FIR; + + if ((rst = (mcs->speed != 4000000))) + mcs_set_reg(mcs, MCS_MINRXPW_REG, 5); + + } + + rval &= ~MCS_SPEED_MASK; + rval |= nspeed; + + ret = mcs_set_reg(mcs, MCS_MODE_REG, rval); + if (unlikely(ret)) + goto error; + + if (rst) + switch (mcs->transceiver_type) { + case MCS_TSC_VISHAY: + ret = mcs_setup_transceiver_vishay(mcs); + break; + + case MCS_TSC_SHARP: + ret = mcs_setup_transceiver_sharp(mcs); + break; + + case MCS_TSC_AGILENT: + ret = mcs_setup_transceiver_agilent(mcs); + break; + + default: + ret = 1; + net_warn_ratelimited("Unknown transceiver type: %d\n", + mcs->transceiver_type); + } + if (unlikely(ret)) + goto error; + + mcs_get_reg(mcs, MCS_MODE_REG, &rval); + rval &= ~MCS_RESET; + ret = mcs_set_reg(mcs, MCS_MODE_REG, rval); + + mcs->speed = mcs->new_speed; +error: + mcs->new_speed = 0; + return ret; +} + +/* Ioctl calls not supported at this time. Can be an area of future work. */ +static int mcs_net_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) +{ + /* struct if_irda_req *irq = (struct if_irda_req *)rq; */ + /* struct mcs_cb *mcs = netdev_priv(netdev); */ + int ret = 0; + + switch (cmd) { + default: + ret = -EOPNOTSUPP; + } + + return ret; +} + +/* Network device is taken down, done by "ifconfig irda0 down" */ +static int mcs_net_close(struct net_device *netdev) +{ + int ret = 0; + struct mcs_cb *mcs = netdev_priv(netdev); + + /* Stop transmit processing */ + netif_stop_queue(netdev); + + kfree_skb(mcs->rx_buff.skb); + + /* kill and free the receive and transmit URBs */ + usb_kill_urb(mcs->rx_urb); + usb_free_urb(mcs->rx_urb); + usb_kill_urb(mcs->tx_urb); + usb_free_urb(mcs->tx_urb); + + /* Stop and remove instance of IrLAP */ + if (mcs->irlap) + irlap_close(mcs->irlap); + + mcs->irlap = NULL; + return ret; +} + +/* Network device is taken up, done by "ifconfig irda0 up" */ +static int mcs_net_open(struct net_device *netdev) +{ + struct mcs_cb *mcs = netdev_priv(netdev); + char hwname[16]; + int ret = 0; + + ret = usb_clear_halt(mcs->usbdev, + usb_sndbulkpipe(mcs->usbdev, mcs->ep_in)); + if (ret) + goto error1; + ret = usb_clear_halt(mcs->usbdev, + usb_rcvbulkpipe(mcs->usbdev, mcs->ep_out)); + if (ret) + goto error1; + + ret = mcs_setup_transceiver(mcs); + if (ret) + goto error1; + + ret = -ENOMEM; + + /* Initialize for SIR/FIR to copy data directly into skb. */ + mcs->receiving = 0; + mcs->rx_buff.truesize = IRDA_SKB_MAX_MTU; + mcs->rx_buff.skb = dev_alloc_skb(IRDA_SKB_MAX_MTU); + if (!mcs->rx_buff.skb) + goto error1; + + skb_reserve(mcs->rx_buff.skb, 1); + mcs->rx_buff.head = mcs->rx_buff.skb->data; + + /* + * Now that everything should be initialized properly, + * Open new IrLAP layer instance to take care of us... + * Note : will send immediately a speed change... + */ + sprintf(hwname, "usb#%d", mcs->usbdev->devnum); + mcs->irlap = irlap_open(netdev, &mcs->qos, hwname); + if (!mcs->irlap) { + net_err_ratelimited("mcs7780: irlap_open failed\n"); + goto error2; + } + + if (!mcs_setup_urbs(mcs)) + goto error3; + + ret = mcs_receive_start(mcs); + if (ret) + goto error4; + + netif_start_queue(netdev); + return 0; + +error4: + usb_free_urb(mcs->rx_urb); + usb_free_urb(mcs->tx_urb); +error3: + irlap_close(mcs->irlap); +error2: + kfree_skb(mcs->rx_buff.skb); +error1: + return ret; +} + +/* Receive callback function. */ +static void mcs_receive_irq(struct urb *urb) +{ + __u8 *bytes; + struct mcs_cb *mcs = urb->context; + int i; + int ret; + + if (!netif_running(mcs->netdev)) + return; + + if (urb->status) + return; + + if (urb->actual_length > 0) { + bytes = urb->transfer_buffer; + + /* MCS returns frames without BOF and EOF + * I assume it returns whole frames. + */ + /* SIR speed */ + if(mcs->speed < 576000) { + async_unwrap_char(mcs->netdev, &mcs->netdev->stats, + &mcs->rx_buff, 0xc0); + + for (i = 0; i < urb->actual_length; i++) + async_unwrap_char(mcs->netdev, &mcs->netdev->stats, + &mcs->rx_buff, bytes[i]); + + async_unwrap_char(mcs->netdev, &mcs->netdev->stats, + &mcs->rx_buff, 0xc1); + } + /* MIR speed */ + else if(mcs->speed == 576000 || mcs->speed == 1152000) { + mcs_unwrap_mir(mcs, urb->transfer_buffer, + urb->actual_length); + } + /* FIR speed */ + else { + mcs_unwrap_fir(mcs, urb->transfer_buffer, + urb->actual_length); + } + } + + ret = usb_submit_urb(urb, GFP_ATOMIC); +} + +/* Transmit callback function. */ +static void mcs_send_irq(struct urb *urb) +{ + struct mcs_cb *mcs = urb->context; + struct net_device *ndev = mcs->netdev; + + if (unlikely(mcs->new_speed)) + schedule_work(&mcs->work); + else + netif_wake_queue(ndev); +} + +/* Transmit callback function. */ +static netdev_tx_t mcs_hard_xmit(struct sk_buff *skb, + struct net_device *ndev) +{ + unsigned long flags; + struct mcs_cb *mcs; + int wraplen; + int ret = 0; + + netif_stop_queue(ndev); + mcs = netdev_priv(ndev); + + spin_lock_irqsave(&mcs->lock, flags); + + mcs->new_speed = irda_get_next_speed(skb); + if (likely(mcs->new_speed == mcs->speed)) + mcs->new_speed = 0; + + /* SIR speed */ + if(mcs->speed < 576000) { + wraplen = mcs_wrap_sir_skb(skb, mcs->out_buf); + } + /* MIR speed */ + else if(mcs->speed == 576000 || mcs->speed == 1152000) { + wraplen = mcs_wrap_mir_skb(skb, mcs->out_buf); + } + /* FIR speed */ + else { + wraplen = mcs_wrap_fir_skb(skb, mcs->out_buf); + } + usb_fill_bulk_urb(mcs->tx_urb, mcs->usbdev, + usb_sndbulkpipe(mcs->usbdev, mcs->ep_out), + mcs->out_buf, wraplen, mcs_send_irq, mcs); + + if ((ret = usb_submit_urb(mcs->tx_urb, GFP_ATOMIC))) { + net_err_ratelimited("failed tx_urb: %d\n", ret); + switch (ret) { + case -ENODEV: + case -EPIPE: + break; + default: + mcs->netdev->stats.tx_errors++; + netif_start_queue(ndev); + } + } else { + mcs->netdev->stats.tx_packets++; + mcs->netdev->stats.tx_bytes += skb->len; + } + + dev_kfree_skb(skb); + spin_unlock_irqrestore(&mcs->lock, flags); + return NETDEV_TX_OK; +} + +static const struct net_device_ops mcs_netdev_ops = { + .ndo_open = mcs_net_open, + .ndo_stop = mcs_net_close, + .ndo_start_xmit = mcs_hard_xmit, + .ndo_do_ioctl = mcs_net_ioctl, +}; + +/* + * This function is called by the USB subsystem for each new device in the + * system. Need to verify the device and if it is, then start handling it. + */ +static int mcs_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(intf); + struct net_device *ndev = NULL; + struct mcs_cb *mcs; + int ret = -ENOMEM; + + ndev = alloc_irdadev(sizeof(*mcs)); + if (!ndev) + goto error1; + + pr_debug("MCS7780 USB-IrDA bridge found at %d.\n", udev->devnum); + + SET_NETDEV_DEV(ndev, &intf->dev); + + ret = usb_reset_configuration(udev); + if (ret != 0) { + net_err_ratelimited("mcs7780: usb reset configuration failed\n"); + goto error2; + } + + mcs = netdev_priv(ndev); + mcs->usbdev = udev; + mcs->netdev = ndev; + spin_lock_init(&mcs->lock); + + /* Initialize QoS for this device */ + irda_init_max_qos_capabilies(&mcs->qos); + + /* That's the Rx capability. */ + mcs->qos.baud_rate.bits &= + IR_2400 | IR_9600 | IR_19200 | IR_38400 | IR_57600 | IR_115200 + | IR_576000 | IR_1152000 | (IR_4000000 << 8); + + + mcs->qos.min_turn_time.bits &= qos_mtt_bits; + irda_qos_bits_to_value(&mcs->qos); + + /* Speed change work initialisation*/ + INIT_WORK(&mcs->work, mcs_speed_work); + + ndev->netdev_ops = &mcs_netdev_ops; + + if (!intf->cur_altsetting) { + ret = -ENOMEM; + goto error2; + } + + ret = mcs_find_endpoints(mcs, intf->cur_altsetting->endpoint, + intf->cur_altsetting->desc.bNumEndpoints); + if (!ret) { + ret = -ENODEV; + goto error2; + } + + ret = register_netdev(ndev); + if (ret != 0) + goto error2; + + pr_debug("IrDA: Registered MosChip MCS7780 device as %s\n", + ndev->name); + + mcs->transceiver_type = transceiver_type; + mcs->sir_tweak = sir_tweak; + mcs->receive_mode = receive_mode; + + usb_set_intfdata(intf, mcs); + return 0; + +error2: + free_netdev(ndev); + +error1: + return ret; +} + +/* The current device is removed, the USB layer tells us to shut down. */ +static void mcs_disconnect(struct usb_interface *intf) +{ + struct mcs_cb *mcs = usb_get_intfdata(intf); + + if (!mcs) + return; + + cancel_work_sync(&mcs->work); + + unregister_netdev(mcs->netdev); + free_netdev(mcs->netdev); + + usb_set_intfdata(intf, NULL); + pr_debug("MCS7780 now disconnected.\n"); +} + +module_usb_driver(mcs_driver); diff --git a/drivers/staging/irda/drivers/mcs7780.h b/drivers/staging/irda/drivers/mcs7780.h new file mode 100644 index 000000000000..a6e8f7dbafc9 --- /dev/null +++ b/drivers/staging/irda/drivers/mcs7780.h @@ -0,0 +1,165 @@ +/***************************************************************************** +* +* Filename: mcs7780.h +* Version: 0.2-alpha +* Description: Irda MosChip USB Dongle +* Status: Experimental +* Authors: Lukasz Stelmach <stlman@poczta.fm> +* Brian Pugh <bpugh@cs.pdx.edu> +* +* Copyright (C) 2005, Lukasz Stelmach <stlman@poczta.fm> +* Copyright (C) 2005, Brian Pugh <bpugh@cs.pdx.edu> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ +#ifndef _MCS7780_H +#define _MCS7780_H + +#define MCS_MODE_SIR 0 +#define MCS_MODE_MIR 1 +#define MCS_MODE_FIR 2 + +#define MCS_CTRL_TIMEOUT 500 +#define MCS_XMIT_TIMEOUT 500 +/* Possible transceiver types */ +#define MCS_TSC_VISHAY 0 /* Vishay TFD, default choice */ +#define MCS_TSC_AGILENT 1 /* Agilent 3602/3600 */ +#define MCS_TSC_SHARP 2 /* Sharp GP2W1000YP */ + +/* Requests */ +#define MCS_RD_RTYPE 0xC0 +#define MCS_WR_RTYPE 0x40 +#define MCS_RDREQ 0x0F +#define MCS_WRREQ 0x0E + +/* Register 0x00 */ +#define MCS_MODE_REG 0 +#define MCS_FIR ((__u16)0x0001) +#define MCS_SIR16US ((__u16)0x0002) +#define MCS_BBTG ((__u16)0x0004) +#define MCS_ASK ((__u16)0x0008) +#define MCS_PARITY ((__u16)0x0010) + +/* SIR/MIR speed constants */ +#define MCS_SPEED_SHIFT 5 +#define MCS_SPEED_MASK ((__u16)0x00E0) +#define MCS_SPEED(x) ((x & MCS_SPEED_MASK) >> MCS_SPEED_SHIFT) +#define MCS_SPEED_2400 ((0 << MCS_SPEED_SHIFT) & MCS_SPEED_MASK) +#define MCS_SPEED_9600 ((1 << MCS_SPEED_SHIFT) & MCS_SPEED_MASK) +#define MCS_SPEED_19200 ((2 << MCS_SPEED_SHIFT) & MCS_SPEED_MASK) +#define MCS_SPEED_38400 ((3 << MCS_SPEED_SHIFT) & MCS_SPEED_MASK) +#define MCS_SPEED_57600 ((4 << MCS_SPEED_SHIFT) & MCS_SPEED_MASK) +#define MCS_SPEED_115200 ((5 << MCS_SPEED_SHIFT) & MCS_SPEED_MASK) +#define MCS_SPEED_576000 ((6 << MCS_SPEED_SHIFT) & MCS_SPEED_MASK) +#define MCS_SPEED_1152000 ((7 << MCS_SPEED_SHIFT) & MCS_SPEED_MASK) + +#define MCS_PLLPWDN ((__u16)0x0100) +#define MCS_DRIVER ((__u16)0x0200) +#define MCS_DTD ((__u16)0x0400) +#define MCS_DIR ((__u16)0x0800) +#define MCS_SIPEN ((__u16)0x1000) +#define MCS_SENDSIP ((__u16)0x2000) +#define MCS_CHGDIR ((__u16)0x4000) +#define MCS_RESET ((__u16)0x8000) + +/* Register 0x02 */ +#define MCS_XCVR_REG 2 +#define MCS_MODE0 ((__u16)0x0001) +#define MCS_STFIR ((__u16)0x0002) +#define MCS_XCVR_CONF ((__u16)0x0004) +#define MCS_RXFAST ((__u16)0x0008) +/* TXCUR [6:4] */ +#define MCS_TXCUR_SHIFT 4 +#define MCS_TXCUR_MASK ((__u16)0x0070) +#define MCS_TXCUR(x) ((x & MCS_TXCUR_MASK) >> MCS_TXCUR_SHIFT) +#define MCS_SETTXCUR(x,y) \ + ((x & ~MCS_TXCUR_MASK) | (y << MCS_TXCUR_SHIFT) & MCS_TXCUR_MASK) + +#define MCS_MODE1 ((__u16)0x0080) +#define MCS_SMODE0 ((__u16)0x0100) +#define MCS_SMODE1 ((__u16)0x0200) +#define MCS_INVTX ((__u16)0x0400) +#define MCS_INVRX ((__u16)0x0800) + +#define MCS_MINRXPW_REG 4 + +#define MCS_RESV_REG 7 +#define MCS_IRINTX ((__u16)0x0001) +#define MCS_IRINRX ((__u16)0x0002) + +struct mcs_cb { + struct usb_device *usbdev; /* init: probe_irda */ + struct net_device *netdev; /* network layer */ + struct irlap_cb *irlap; /* The link layer we are binded to */ + struct qos_info qos; + unsigned int speed; /* Current speed */ + unsigned int new_speed; /* new speed */ + + struct work_struct work; /* Change speed work */ + + struct sk_buff *tx_pending; + char in_buf[4096]; /* transmit/receive buffer */ + char out_buf[4096]; /* transmit/receive buffer */ + __u8 *fifo_status; + + iobuff_t rx_buff; /* receive unwrap state machine */ + spinlock_t lock; + int receiving; + + __u8 ep_in; + __u8 ep_out; + + struct urb *rx_urb; + struct urb *tx_urb; + + int transceiver_type; + int sir_tweak; + int receive_mode; +}; + +static int mcs_set_reg(struct mcs_cb *mcs, __u16 reg, __u16 val); +static int mcs_get_reg(struct mcs_cb *mcs, __u16 reg, __u16 * val); + +static inline int mcs_setup_transceiver_vishay(struct mcs_cb *mcs); +static inline int mcs_setup_transceiver_agilent(struct mcs_cb *mcs); +static inline int mcs_setup_transceiver_sharp(struct mcs_cb *mcs); +static inline int mcs_setup_transceiver(struct mcs_cb *mcs); +static inline int mcs_wrap_sir_skb(struct sk_buff *skb, __u8 * buf); +static unsigned mcs_wrap_fir_skb(const struct sk_buff *skb, __u8 *buf); +static unsigned mcs_wrap_mir_skb(const struct sk_buff *skb, __u8 *buf); +static void mcs_unwrap_mir(struct mcs_cb *mcs, __u8 *buf, int len); +static void mcs_unwrap_fir(struct mcs_cb *mcs, __u8 *buf, int len); +static inline int mcs_setup_urbs(struct mcs_cb *mcs); +static inline int mcs_receive_start(struct mcs_cb *mcs); +static inline int mcs_find_endpoints(struct mcs_cb *mcs, + struct usb_host_endpoint *ep, int epnum); + +static int mcs_speed_change(struct mcs_cb *mcs); + +static int mcs_net_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd); +static int mcs_net_close(struct net_device *netdev); +static int mcs_net_open(struct net_device *netdev); + +static void mcs_receive_irq(struct urb *urb); +static void mcs_send_irq(struct urb *urb); +static netdev_tx_t mcs_hard_xmit(struct sk_buff *skb, + struct net_device *netdev); + +static int mcs_probe(struct usb_interface *intf, + const struct usb_device_id *id); +static void mcs_disconnect(struct usb_interface *intf); + +#endif /* _MCS7780_H */ diff --git a/drivers/staging/irda/drivers/nsc-ircc.c b/drivers/staging/irda/drivers/nsc-ircc.c new file mode 100644 index 000000000000..7beae147be11 --- /dev/null +++ b/drivers/staging/irda/drivers/nsc-ircc.c @@ -0,0 +1,2410 @@ +/********************************************************************* + * + * Filename: nsc-ircc.c + * Version: 1.0 + * Description: Driver for the NSC PC'108 and PC'338 IrDA chipsets + * Status: Stable. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Sat Nov 7 21:43:15 1998 + * Modified at: Wed Mar 1 11:29:34 2000 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no> + * Copyright (c) 1998 Lichen Wang, <lwang@actisys.com> + * Copyright (c) 1998 Actisys Corp., www.actisys.com + * Copyright (c) 2000-2004 Jean Tourrilhes <jt@hpl.hp.com> + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + * Notice that all functions that needs to access the chip in _any_ + * way, must save BSR register on entry, and restore it on exit. + * It is _very_ important to follow this policy! + * + * __u8 bank; + * + * bank = inb(iobase+BSR); + * + * do_your_stuff_here(); + * + * outb(bank, iobase+BSR); + * + * If you find bugs in this file, its very likely that the same bug + * will also be in w83977af_ir.c since the implementations are quite + * similar. + * + ********************************************************************/ + +#include <linux/module.h> +#include <linux/gfp.h> + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/skbuff.h> +#include <linux/netdevice.h> +#include <linux/ioport.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/rtnetlink.h> +#include <linux/dma-mapping.h> +#include <linux/pnp.h> +#include <linux/platform_device.h> + +#include <asm/io.h> +#include <asm/dma.h> +#include <asm/byteorder.h> + +#include <net/irda/wrapper.h> +#include <net/irda/irda.h> +#include <net/irda/irda_device.h> + +#include "nsc-ircc.h" + +#define CHIP_IO_EXTENT 8 +#define BROKEN_DONGLE_ID + +static char *driver_name = "nsc-ircc"; + +/* Power Management */ +#define NSC_IRCC_DRIVER_NAME "nsc-ircc" +static int nsc_ircc_suspend(struct platform_device *dev, pm_message_t state); +static int nsc_ircc_resume(struct platform_device *dev); + +static struct platform_driver nsc_ircc_driver = { + .suspend = nsc_ircc_suspend, + .resume = nsc_ircc_resume, + .driver = { + .name = NSC_IRCC_DRIVER_NAME, + }, +}; + +/* Module parameters */ +static int qos_mtt_bits = 0x07; /* 1 ms or more */ +static int dongle_id; + +/* Use BIOS settions by default, but user may supply module parameters */ +static unsigned int io[] = { ~0, ~0, ~0, ~0, ~0 }; +static unsigned int irq[] = { 0, 0, 0, 0, 0 }; +static unsigned int dma[] = { 0, 0, 0, 0, 0 }; + +static int nsc_ircc_probe_108(nsc_chip_t *chip, chipio_t *info); +static int nsc_ircc_probe_338(nsc_chip_t *chip, chipio_t *info); +static int nsc_ircc_probe_39x(nsc_chip_t *chip, chipio_t *info); +static int nsc_ircc_init_108(nsc_chip_t *chip, chipio_t *info); +static int nsc_ircc_init_338(nsc_chip_t *chip, chipio_t *info); +static int nsc_ircc_init_39x(nsc_chip_t *chip, chipio_t *info); +#ifdef CONFIG_PNP +static int nsc_ircc_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *id); +#endif + +/* These are the known NSC chips */ +static nsc_chip_t chips[] = { +/* Name, {cfg registers}, chip id index reg, chip id expected value, revision mask */ + { "PC87108", { 0x150, 0x398, 0xea }, 0x05, 0x10, 0xf0, + nsc_ircc_probe_108, nsc_ircc_init_108 }, + { "PC87338", { 0x398, 0x15c, 0x2e }, 0x08, 0xb0, 0xf8, + nsc_ircc_probe_338, nsc_ircc_init_338 }, + /* Contributed by Steffen Pingel - IBM X40 */ + { "PC8738x", { 0x164e, 0x4e, 0x2e }, 0x20, 0xf4, 0xff, + nsc_ircc_probe_39x, nsc_ircc_init_39x }, + /* Contributed by Jan Frey - IBM A30/A31 */ + { "PC8739x", { 0x2e, 0x4e, 0x0 }, 0x20, 0xea, 0xff, + nsc_ircc_probe_39x, nsc_ircc_init_39x }, + /* IBM ThinkPads using PC8738x (T60/X60/Z60) */ + { "IBM-PC8738x", { 0x2e, 0x4e, 0x0 }, 0x20, 0xf4, 0xff, + nsc_ircc_probe_39x, nsc_ircc_init_39x }, + /* IBM ThinkPads using PC8394T (T43/R52/?) */ + { "IBM-PC8394T", { 0x2e, 0x4e, 0x0 }, 0x20, 0xf9, 0xff, + nsc_ircc_probe_39x, nsc_ircc_init_39x }, + { NULL } +}; + +static struct nsc_ircc_cb *dev_self[] = { NULL, NULL, NULL, NULL, NULL }; + +static char *dongle_types[] = { + "Differential serial interface", + "Differential serial interface", + "Reserved", + "Reserved", + "Sharp RY5HD01", + "Reserved", + "Single-ended serial interface", + "Consumer-IR only", + "HP HSDL-2300, HP HSDL-3600/HSDL-3610", + "IBM31T1100 or Temic TFDS6000/TFDS6500", + "Reserved", + "Reserved", + "HP HSDL-1100/HSDL-2100", + "HP HSDL-1100/HSDL-2100", + "Supports SIR Mode only", + "No dongle connected", +}; + +/* PNP probing */ +static chipio_t pnp_info; +static const struct pnp_device_id nsc_ircc_pnp_table[] = { + { .id = "NSC6001", .driver_data = 0 }, + { .id = "HWPC224", .driver_data = 0 }, + { .id = "IBM0071", .driver_data = NSC_FORCE_DONGLE_TYPE9 }, + { } +}; + +MODULE_DEVICE_TABLE(pnp, nsc_ircc_pnp_table); + +static struct pnp_driver nsc_ircc_pnp_driver = { +#ifdef CONFIG_PNP + .name = "nsc-ircc", + .id_table = nsc_ircc_pnp_table, + .probe = nsc_ircc_pnp_probe, +#endif +}; + +/* Some prototypes */ +static int nsc_ircc_open(chipio_t *info); +static int nsc_ircc_close(struct nsc_ircc_cb *self); +static int nsc_ircc_setup(chipio_t *info); +static void nsc_ircc_pio_receive(struct nsc_ircc_cb *self); +static int nsc_ircc_dma_receive(struct nsc_ircc_cb *self); +static int nsc_ircc_dma_receive_complete(struct nsc_ircc_cb *self, int iobase); +static netdev_tx_t nsc_ircc_hard_xmit_sir(struct sk_buff *skb, + struct net_device *dev); +static netdev_tx_t nsc_ircc_hard_xmit_fir(struct sk_buff *skb, + struct net_device *dev); +static int nsc_ircc_pio_write(int iobase, __u8 *buf, int len, int fifo_size); +static void nsc_ircc_dma_xmit(struct nsc_ircc_cb *self, int iobase); +static __u8 nsc_ircc_change_speed(struct nsc_ircc_cb *self, __u32 baud); +static int nsc_ircc_is_receiving(struct nsc_ircc_cb *self); +static int nsc_ircc_read_dongle_id (int iobase); +static void nsc_ircc_init_dongle_interface (int iobase, int dongle_id); + +static int nsc_ircc_net_open(struct net_device *dev); +static int nsc_ircc_net_close(struct net_device *dev); +static int nsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); + +/* Globals */ +static int pnp_registered; +static int pnp_succeeded; + +/* + * Function nsc_ircc_init () + * + * Initialize chip. Just try to find out how many chips we are dealing with + * and where they are + */ +static int __init nsc_ircc_init(void) +{ + chipio_t info; + nsc_chip_t *chip; + int ret; + int cfg_base; + int cfg, id; + int reg; + int i = 0; + + ret = platform_driver_register(&nsc_ircc_driver); + if (ret) { + net_err_ratelimited("%s, Can't register driver!\n", + driver_name); + return ret; + } + + /* Register with PnP subsystem to detect disable ports */ + ret = pnp_register_driver(&nsc_ircc_pnp_driver); + + if (!ret) + pnp_registered = 1; + + ret = -ENODEV; + + /* Probe for all the NSC chipsets we know about */ + for (chip = chips; chip->name ; chip++) { + pr_debug("%s(), Probing for %s ...\n", __func__, + chip->name); + + /* Try all config registers for this chip */ + for (cfg = 0; cfg < ARRAY_SIZE(chip->cfg); cfg++) { + cfg_base = chip->cfg[cfg]; + if (!cfg_base) + continue; + + /* Read index register */ + reg = inb(cfg_base); + if (reg == 0xff) { + pr_debug("%s() no chip at 0x%03x\n", + __func__, cfg_base); + continue; + } + + /* Read chip identification register */ + outb(chip->cid_index, cfg_base); + id = inb(cfg_base+1); + if ((id & chip->cid_mask) == chip->cid_value) { + pr_debug("%s() Found %s chip, revision=%d\n", + __func__, chip->name, + id & ~chip->cid_mask); + + /* + * If we found a correct PnP setting, + * we first try it. + */ + if (pnp_succeeded) { + memset(&info, 0, sizeof(chipio_t)); + info.cfg_base = cfg_base; + info.fir_base = pnp_info.fir_base; + info.dma = pnp_info.dma; + info.irq = pnp_info.irq; + + if (info.fir_base < 0x2000) { + net_info_ratelimited("%s, chip->init\n", + driver_name); + chip->init(chip, &info); + } else + chip->probe(chip, &info); + + if (nsc_ircc_open(&info) >= 0) + ret = 0; + } + + /* + * Opening based on PnP values failed. + * Let's fallback to user values, or probe + * the chip. + */ + if (ret) { + pr_debug("%s, PnP init failed\n", + driver_name); + memset(&info, 0, sizeof(chipio_t)); + info.cfg_base = cfg_base; + info.fir_base = io[i]; + info.dma = dma[i]; + info.irq = irq[i]; + + /* + * If the user supplies the base address, then + * we init the chip, if not we probe the values + * set by the BIOS + */ + if (io[i] < 0x2000) { + chip->init(chip, &info); + } else + chip->probe(chip, &info); + + if (nsc_ircc_open(&info) >= 0) + ret = 0; + } + i++; + } else { + pr_debug("%s(), Wrong chip id=0x%02x\n", + __func__, id); + } + } + } + + if (ret) { + platform_driver_unregister(&nsc_ircc_driver); + pnp_unregister_driver(&nsc_ircc_pnp_driver); + pnp_registered = 0; + } + + return ret; +} + +/* + * Function nsc_ircc_cleanup () + * + * Close all configured chips + * + */ +static void __exit nsc_ircc_cleanup(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(dev_self); i++) { + if (dev_self[i]) + nsc_ircc_close(dev_self[i]); + } + + platform_driver_unregister(&nsc_ircc_driver); + + if (pnp_registered) + pnp_unregister_driver(&nsc_ircc_pnp_driver); + + pnp_registered = 0; +} + +static const struct net_device_ops nsc_ircc_sir_ops = { + .ndo_open = nsc_ircc_net_open, + .ndo_stop = nsc_ircc_net_close, + .ndo_start_xmit = nsc_ircc_hard_xmit_sir, + .ndo_do_ioctl = nsc_ircc_net_ioctl, +}; + +static const struct net_device_ops nsc_ircc_fir_ops = { + .ndo_open = nsc_ircc_net_open, + .ndo_stop = nsc_ircc_net_close, + .ndo_start_xmit = nsc_ircc_hard_xmit_fir, + .ndo_do_ioctl = nsc_ircc_net_ioctl, +}; + +/* + * Function nsc_ircc_open (iobase, irq) + * + * Open driver instance + * + */ +static int __init nsc_ircc_open(chipio_t *info) +{ + struct net_device *dev; + struct nsc_ircc_cb *self; + void *ret; + int err, chip_index; + + for (chip_index = 0; chip_index < ARRAY_SIZE(dev_self); chip_index++) { + if (!dev_self[chip_index]) + break; + } + + if (chip_index == ARRAY_SIZE(dev_self)) { + net_err_ratelimited("%s(), maximum number of supported chips reached!\n", + __func__); + return -ENOMEM; + } + + net_info_ratelimited("%s, Found chip at base=0x%03x\n", + driver_name, info->cfg_base); + + if ((nsc_ircc_setup(info)) == -1) + return -1; + + net_info_ratelimited("%s, driver loaded (Dag Brattli)\n", driver_name); + + dev = alloc_irdadev(sizeof(struct nsc_ircc_cb)); + if (dev == NULL) { + net_err_ratelimited("%s(), can't allocate memory for control block!\n", + __func__); + return -ENOMEM; + } + + self = netdev_priv(dev); + self->netdev = dev; + spin_lock_init(&self->lock); + + /* Need to store self somewhere */ + dev_self[chip_index] = self; + self->index = chip_index; + + /* Initialize IO */ + self->io.cfg_base = info->cfg_base; + self->io.fir_base = info->fir_base; + self->io.irq = info->irq; + self->io.fir_ext = CHIP_IO_EXTENT; + self->io.dma = info->dma; + self->io.fifo_size = 32; + + /* Reserve the ioports that we need */ + ret = request_region(self->io.fir_base, self->io.fir_ext, driver_name); + if (!ret) { + net_warn_ratelimited("%s(), can't get iobase of 0x%03x\n", + __func__, self->io.fir_base); + err = -ENODEV; + goto out1; + } + + /* Initialize QoS for this device */ + irda_init_max_qos_capabilies(&self->qos); + + /* The only value we must override it the baudrate */ + self->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600| + IR_115200|IR_576000|IR_1152000 |(IR_4000000 << 8); + + self->qos.min_turn_time.bits = qos_mtt_bits; + irda_qos_bits_to_value(&self->qos); + + /* Max DMA buffer size needed = (data_size + 6) * (window_size) + 6; */ + self->rx_buff.truesize = 14384; + self->tx_buff.truesize = 14384; + + /* Allocate memory if needed */ + self->rx_buff.head = + dma_zalloc_coherent(NULL, self->rx_buff.truesize, + &self->rx_buff_dma, GFP_KERNEL); + if (self->rx_buff.head == NULL) { + err = -ENOMEM; + goto out2; + + } + + self->tx_buff.head = + dma_zalloc_coherent(NULL, self->tx_buff.truesize, + &self->tx_buff_dma, GFP_KERNEL); + if (self->tx_buff.head == NULL) { + err = -ENOMEM; + goto out3; + } + + self->rx_buff.in_frame = FALSE; + self->rx_buff.state = OUTSIDE_FRAME; + self->tx_buff.data = self->tx_buff.head; + self->rx_buff.data = self->rx_buff.head; + + /* Reset Tx queue info */ + self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0; + self->tx_fifo.tail = self->tx_buff.head; + + /* Override the network functions we need to use */ + dev->netdev_ops = &nsc_ircc_sir_ops; + + err = register_netdev(dev); + if (err) { + net_err_ratelimited("%s(), register_netdev() failed!\n", + __func__); + goto out4; + } + net_info_ratelimited("IrDA: Registered device %s\n", dev->name); + + /* Check if user has supplied a valid dongle id or not */ + if ((dongle_id <= 0) || + (dongle_id >= ARRAY_SIZE(dongle_types))) { + dongle_id = nsc_ircc_read_dongle_id(self->io.fir_base); + + net_info_ratelimited("%s, Found dongle: %s\n", + driver_name, dongle_types[dongle_id]); + } else { + net_info_ratelimited("%s, Using dongle: %s\n", + driver_name, dongle_types[dongle_id]); + } + + self->io.dongle_id = dongle_id; + nsc_ircc_init_dongle_interface(self->io.fir_base, dongle_id); + + self->pldev = platform_device_register_simple(NSC_IRCC_DRIVER_NAME, + self->index, NULL, 0); + if (IS_ERR(self->pldev)) { + err = PTR_ERR(self->pldev); + goto out5; + } + platform_set_drvdata(self->pldev, self); + + return chip_index; + + out5: + unregister_netdev(dev); + out4: + dma_free_coherent(NULL, self->tx_buff.truesize, + self->tx_buff.head, self->tx_buff_dma); + out3: + dma_free_coherent(NULL, self->rx_buff.truesize, + self->rx_buff.head, self->rx_buff_dma); + out2: + release_region(self->io.fir_base, self->io.fir_ext); + out1: + free_netdev(dev); + dev_self[chip_index] = NULL; + return err; +} + +/* + * Function nsc_ircc_close (self) + * + * Close driver instance + * + */ +static int __exit nsc_ircc_close(struct nsc_ircc_cb *self) +{ + int iobase; + + IRDA_ASSERT(self != NULL, return -1;); + + iobase = self->io.fir_base; + + platform_device_unregister(self->pldev); + + /* Remove netdevice */ + unregister_netdev(self->netdev); + + /* Release the PORT that this driver is using */ + pr_debug("%s(), Releasing Region %03x\n", + __func__, self->io.fir_base); + release_region(self->io.fir_base, self->io.fir_ext); + + if (self->tx_buff.head) + dma_free_coherent(NULL, self->tx_buff.truesize, + self->tx_buff.head, self->tx_buff_dma); + + if (self->rx_buff.head) + dma_free_coherent(NULL, self->rx_buff.truesize, + self->rx_buff.head, self->rx_buff_dma); + + dev_self[self->index] = NULL; + free_netdev(self->netdev); + + return 0; +} + +/* + * Function nsc_ircc_init_108 (iobase, cfg_base, irq, dma) + * + * Initialize the NSC '108 chip + * + */ +static int nsc_ircc_init_108(nsc_chip_t *chip, chipio_t *info) +{ + int cfg_base = info->cfg_base; + __u8 temp=0; + + outb(2, cfg_base); /* Mode Control Register (MCTL) */ + outb(0x00, cfg_base+1); /* Disable device */ + + /* Base Address and Interrupt Control Register (BAIC) */ + outb(CFG_108_BAIC, cfg_base); + switch (info->fir_base) { + case 0x3e8: outb(0x14, cfg_base+1); break; + case 0x2e8: outb(0x15, cfg_base+1); break; + case 0x3f8: outb(0x16, cfg_base+1); break; + case 0x2f8: outb(0x17, cfg_base+1); break; + default: net_err_ratelimited("%s(), invalid base_address\n", __func__); + } + + /* Control Signal Routing Register (CSRT) */ + switch (info->irq) { + case 3: temp = 0x01; break; + case 4: temp = 0x02; break; + case 5: temp = 0x03; break; + case 7: temp = 0x04; break; + case 9: temp = 0x05; break; + case 11: temp = 0x06; break; + case 15: temp = 0x07; break; + default: net_err_ratelimited("%s(), invalid irq\n", __func__); + } + outb(CFG_108_CSRT, cfg_base); + + switch (info->dma) { + case 0: outb(0x08+temp, cfg_base+1); break; + case 1: outb(0x10+temp, cfg_base+1); break; + case 3: outb(0x18+temp, cfg_base+1); break; + default: net_err_ratelimited("%s(), invalid dma\n", __func__); + } + + outb(CFG_108_MCTL, cfg_base); /* Mode Control Register (MCTL) */ + outb(0x03, cfg_base+1); /* Enable device */ + + return 0; +} + +/* + * Function nsc_ircc_probe_108 (chip, info) + * + * + * + */ +static int nsc_ircc_probe_108(nsc_chip_t *chip, chipio_t *info) +{ + int cfg_base = info->cfg_base; + int reg; + + /* Read address and interrupt control register (BAIC) */ + outb(CFG_108_BAIC, cfg_base); + reg = inb(cfg_base+1); + + switch (reg & 0x03) { + case 0: + info->fir_base = 0x3e8; + break; + case 1: + info->fir_base = 0x2e8; + break; + case 2: + info->fir_base = 0x3f8; + break; + case 3: + info->fir_base = 0x2f8; + break; + } + info->sir_base = info->fir_base; + pr_debug("%s(), probing fir_base=0x%03x\n", __func__, + info->fir_base); + + /* Read control signals routing register (CSRT) */ + outb(CFG_108_CSRT, cfg_base); + reg = inb(cfg_base+1); + + switch (reg & 0x07) { + case 0: + info->irq = -1; + break; + case 1: + info->irq = 3; + break; + case 2: + info->irq = 4; + break; + case 3: + info->irq = 5; + break; + case 4: + info->irq = 7; + break; + case 5: + info->irq = 9; + break; + case 6: + info->irq = 11; + break; + case 7: + info->irq = 15; + break; + } + pr_debug("%s(), probing irq=%d\n", __func__, info->irq); + + /* Currently we only read Rx DMA but it will also be used for Tx */ + switch ((reg >> 3) & 0x03) { + case 0: + info->dma = -1; + break; + case 1: + info->dma = 0; + break; + case 2: + info->dma = 1; + break; + case 3: + info->dma = 3; + break; + } + pr_debug("%s(), probing dma=%d\n", __func__, info->dma); + + /* Read mode control register (MCTL) */ + outb(CFG_108_MCTL, cfg_base); + reg = inb(cfg_base+1); + + info->enabled = reg & 0x01; + info->suspended = !((reg >> 1) & 0x01); + + return 0; +} + +/* + * Function nsc_ircc_init_338 (chip, info) + * + * Initialize the NSC '338 chip. Remember that the 87338 needs two + * consecutive writes to the data registers while CPU interrupts are + * disabled. The 97338 does not require this, but shouldn't be any + * harm if we do it anyway. + */ +static int nsc_ircc_init_338(nsc_chip_t *chip, chipio_t *info) +{ + /* No init yet */ + + return 0; +} + +/* + * Function nsc_ircc_probe_338 (chip, info) + * + * + * + */ +static int nsc_ircc_probe_338(nsc_chip_t *chip, chipio_t *info) +{ + int cfg_base = info->cfg_base; + int reg, com = 0; + int pnp; + + /* Read function enable register (FER) */ + outb(CFG_338_FER, cfg_base); + reg = inb(cfg_base+1); + + info->enabled = (reg >> 2) & 0x01; + + /* Check if we are in Legacy or PnP mode */ + outb(CFG_338_PNP0, cfg_base); + reg = inb(cfg_base+1); + + pnp = (reg >> 3) & 0x01; + if (pnp) { + pr_debug("(), Chip is in PnP mode\n"); + outb(0x46, cfg_base); + reg = (inb(cfg_base+1) & 0xfe) << 2; + + outb(0x47, cfg_base); + reg |= ((inb(cfg_base+1) & 0xfc) << 8); + + info->fir_base = reg; + } else { + /* Read function address register (FAR) */ + outb(CFG_338_FAR, cfg_base); + reg = inb(cfg_base+1); + + switch ((reg >> 4) & 0x03) { + case 0: + info->fir_base = 0x3f8; + break; + case 1: + info->fir_base = 0x2f8; + break; + case 2: + com = 3; + break; + case 3: + com = 4; + break; + } + + if (com) { + switch ((reg >> 6) & 0x03) { + case 0: + if (com == 3) + info->fir_base = 0x3e8; + else + info->fir_base = 0x2e8; + break; + case 1: + if (com == 3) + info->fir_base = 0x338; + else + info->fir_base = 0x238; + break; + case 2: + if (com == 3) + info->fir_base = 0x2e8; + else + info->fir_base = 0x2e0; + break; + case 3: + if (com == 3) + info->fir_base = 0x220; + else + info->fir_base = 0x228; + break; + } + } + } + info->sir_base = info->fir_base; + + /* Read PnP register 1 (PNP1) */ + outb(CFG_338_PNP1, cfg_base); + reg = inb(cfg_base+1); + + info->irq = reg >> 4; + + /* Read PnP register 3 (PNP3) */ + outb(CFG_338_PNP3, cfg_base); + reg = inb(cfg_base+1); + + info->dma = (reg & 0x07) - 1; + + /* Read power and test register (PTR) */ + outb(CFG_338_PTR, cfg_base); + reg = inb(cfg_base+1); + + info->suspended = reg & 0x01; + + return 0; +} + + +/* + * Function nsc_ircc_init_39x (chip, info) + * + * Now that we know it's a '39x (see probe below), we need to + * configure it so we can use it. + * + * The NSC '338 chip is a Super I/O chip with a "bank" architecture, + * the configuration of the different functionality (serial, parallel, + * floppy...) are each in a different bank (Logical Device Number). + * The base address, irq and dma configuration registers are common + * to all functionalities (index 0x30 to 0x7F). + * There is only one configuration register specific to the + * serial port, CFG_39X_SPC. + * JeanII + * + * Note : this code was written by Jan Frey <janfrey@web.de> + */ +static int nsc_ircc_init_39x(nsc_chip_t *chip, chipio_t *info) +{ + int cfg_base = info->cfg_base; + int enabled; + + /* User is sure about his config... accept it. */ + pr_debug("%s(): nsc_ircc_init_39x (user settings): io=0x%04x, irq=%d, dma=%d\n", + __func__, info->fir_base, info->irq, info->dma); + + /* Access bank for SP2 */ + outb(CFG_39X_LDN, cfg_base); + outb(0x02, cfg_base+1); + + /* Configure SP2 */ + + /* We want to enable the device if not enabled */ + outb(CFG_39X_ACT, cfg_base); + enabled = inb(cfg_base+1) & 0x01; + + if (!enabled) { + /* Enable the device */ + outb(CFG_39X_SIOCF1, cfg_base); + outb(0x01, cfg_base+1); + /* May want to update info->enabled. Jean II */ + } + + /* Enable UART bank switching (bit 7) ; Sets the chip to normal + * power mode (wake up from sleep mode) (bit 1) */ + outb(CFG_39X_SPC, cfg_base); + outb(0x82, cfg_base+1); + + return 0; +} + +/* + * Function nsc_ircc_probe_39x (chip, info) + * + * Test if we really have a '39x chip at the given address + * + * Note : this code was written by Jan Frey <janfrey@web.de> + */ +static int nsc_ircc_probe_39x(nsc_chip_t *chip, chipio_t *info) +{ + int cfg_base = info->cfg_base; + int reg1, reg2, irq, irqt, dma1, dma2; + int enabled, susp; + + pr_debug("%s(), nsc_ircc_probe_39x, base=%d\n", + __func__, cfg_base); + + /* This function should be executed with irq off to avoid + * another driver messing with the Super I/O bank - Jean II */ + + /* Access bank for SP2 */ + outb(CFG_39X_LDN, cfg_base); + outb(0x02, cfg_base+1); + + /* Read infos about SP2 ; store in info struct */ + outb(CFG_39X_BASEH, cfg_base); + reg1 = inb(cfg_base+1); + outb(CFG_39X_BASEL, cfg_base); + reg2 = inb(cfg_base+1); + info->fir_base = (reg1 << 8) | reg2; + + outb(CFG_39X_IRQNUM, cfg_base); + irq = inb(cfg_base+1); + outb(CFG_39X_IRQSEL, cfg_base); + irqt = inb(cfg_base+1); + info->irq = irq; + + outb(CFG_39X_DMA0, cfg_base); + dma1 = inb(cfg_base+1); + outb(CFG_39X_DMA1, cfg_base); + dma2 = inb(cfg_base+1); + info->dma = dma1 -1; + + outb(CFG_39X_ACT, cfg_base); + info->enabled = enabled = inb(cfg_base+1) & 0x01; + + outb(CFG_39X_SPC, cfg_base); + susp = 1 - ((inb(cfg_base+1) & 0x02) >> 1); + + pr_debug("%s(): io=0x%02x%02x, irq=%d (type %d), rxdma=%d, txdma=%d, enabled=%d (suspended=%d)\n", + __func__, reg1, reg2, irq, irqt, dma1, dma2, enabled, susp); + + /* Configure SP2 */ + + /* We want to enable the device if not enabled */ + outb(CFG_39X_ACT, cfg_base); + enabled = inb(cfg_base+1) & 0x01; + + if (!enabled) { + /* Enable the device */ + outb(CFG_39X_SIOCF1, cfg_base); + outb(0x01, cfg_base+1); + /* May want to update info->enabled. Jean II */ + } + + /* Enable UART bank switching (bit 7) ; Sets the chip to normal + * power mode (wake up from sleep mode) (bit 1) */ + outb(CFG_39X_SPC, cfg_base); + outb(0x82, cfg_base+1); + + return 0; +} + +#ifdef CONFIG_PNP +/* PNP probing */ +static int nsc_ircc_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *id) +{ + memset(&pnp_info, 0, sizeof(chipio_t)); + pnp_info.irq = -1; + pnp_info.dma = -1; + pnp_succeeded = 1; + + if (id->driver_data & NSC_FORCE_DONGLE_TYPE9) + dongle_id = 0x9; + + /* There doesn't seem to be any way of getting the cfg_base. + * On my box, cfg_base is in the PnP descriptor of the + * motherboard. Oh well... Jean II */ + + if (pnp_port_valid(dev, 0) && + !(pnp_port_flags(dev, 0) & IORESOURCE_DISABLED)) + pnp_info.fir_base = pnp_port_start(dev, 0); + + if (pnp_irq_valid(dev, 0) && + !(pnp_irq_flags(dev, 0) & IORESOURCE_DISABLED)) + pnp_info.irq = pnp_irq(dev, 0); + + if (pnp_dma_valid(dev, 0) && + !(pnp_dma_flags(dev, 0) & IORESOURCE_DISABLED)) + pnp_info.dma = pnp_dma(dev, 0); + + pr_debug("%s() : From PnP, found firbase 0x%03X ; irq %d ; dma %d.\n", + __func__, pnp_info.fir_base, pnp_info.irq, pnp_info.dma); + + if((pnp_info.fir_base == 0) || + (pnp_info.irq == -1) || (pnp_info.dma == -1)) { + /* Returning an error will disable the device. Yuck ! */ + //return -EINVAL; + pnp_succeeded = 0; + } + + return 0; +} +#endif + +/* + * Function nsc_ircc_setup (info) + * + * Returns non-negative on success. + * + */ +static int nsc_ircc_setup(chipio_t *info) +{ + int version; + int iobase = info->fir_base; + + /* Read the Module ID */ + switch_bank(iobase, BANK3); + version = inb(iobase+MID); + + pr_debug("%s() Driver %s Found chip version %02x\n", + __func__, driver_name, version); + + /* Should be 0x2? */ + if (0x20 != (version & 0xf0)) { + net_err_ratelimited("%s, Wrong chip version %02x\n", + driver_name, version); + return -1; + } + + /* Switch to advanced mode */ + switch_bank(iobase, BANK2); + outb(ECR1_EXT_SL, iobase+ECR1); + switch_bank(iobase, BANK0); + + /* Set FIFO threshold to TX17, RX16, reset and enable FIFO's */ + switch_bank(iobase, BANK0); + outb(FCR_RXTH|FCR_TXTH|FCR_TXSR|FCR_RXSR|FCR_FIFO_EN, iobase+FCR); + + outb(0x03, iobase+LCR); /* 8 bit word length */ + outb(MCR_SIR, iobase+MCR); /* Start at SIR-mode, also clears LSR*/ + + /* Set FIFO size to 32 */ + switch_bank(iobase, BANK2); + outb(EXCR2_RFSIZ|EXCR2_TFSIZ, iobase+EXCR2); + + /* IRCR2: FEND_MD is not set */ + switch_bank(iobase, BANK5); + outb(0x02, iobase+4); + + /* Make sure that some defaults are OK */ + switch_bank(iobase, BANK6); + outb(0x20, iobase+0); /* Set 32 bits FIR CRC */ + outb(0x0a, iobase+1); /* Set MIR pulse width */ + outb(0x0d, iobase+2); /* Set SIR pulse width to 1.6us */ + outb(0x2a, iobase+4); /* Set beginning frag, and preamble length */ + + /* Enable receive interrupts */ + switch_bank(iobase, BANK0); + outb(IER_RXHDL_IE, iobase+IER); + + return 0; +} + +/* + * Function nsc_ircc_read_dongle_id (void) + * + * Try to read dongle identification. This procedure needs to be executed + * once after power-on/reset. It also needs to be used whenever you suspect + * that the user may have plugged/unplugged the IrDA Dongle. + */ +static int nsc_ircc_read_dongle_id (int iobase) +{ + int dongle_id; + __u8 bank; + + bank = inb(iobase+BSR); + + /* Select Bank 7 */ + switch_bank(iobase, BANK7); + + /* IRCFG4: IRSL0_DS and IRSL21_DS are cleared */ + outb(0x00, iobase+7); + + /* ID0, 1, and 2 are pulled up/down very slowly */ + udelay(50); + + /* IRCFG1: read the ID bits */ + dongle_id = inb(iobase+4) & 0x0f; + +#ifdef BROKEN_DONGLE_ID + if (dongle_id == 0x0a) + dongle_id = 0x09; +#endif + /* Go back to bank 0 before returning */ + switch_bank(iobase, BANK0); + + outb(bank, iobase+BSR); + + return dongle_id; +} + +/* + * Function nsc_ircc_init_dongle_interface (iobase, dongle_id) + * + * This function initializes the dongle for the transceiver that is + * used. This procedure needs to be executed once after + * power-on/reset. It also needs to be used whenever you suspect that + * the dongle is changed. + */ +static void nsc_ircc_init_dongle_interface (int iobase, int dongle_id) +{ + int bank; + + /* Save current bank */ + bank = inb(iobase+BSR); + + /* Select Bank 7 */ + switch_bank(iobase, BANK7); + + /* IRCFG4: set according to dongle_id */ + switch (dongle_id) { + case 0x00: /* same as */ + case 0x01: /* Differential serial interface */ + pr_debug("%s(), %s not defined by irda yet\n", + __func__, dongle_types[dongle_id]); + break; + case 0x02: /* same as */ + case 0x03: /* Reserved */ + pr_debug("%s(), %s not defined by irda yet\n", + __func__, dongle_types[dongle_id]); + break; + case 0x04: /* Sharp RY5HD01 */ + break; + case 0x05: /* Reserved, but this is what the Thinkpad reports */ + pr_debug("%s(), %s not defined by irda yet\n", + __func__, dongle_types[dongle_id]); + break; + case 0x06: /* Single-ended serial interface */ + pr_debug("%s(), %s not defined by irda yet\n", + __func__, dongle_types[dongle_id]); + break; + case 0x07: /* Consumer-IR only */ + pr_debug("%s(), %s is not for IrDA mode\n", + __func__, dongle_types[dongle_id]); + break; + case 0x08: /* HP HSDL-2300, HP HSDL-3600/HSDL-3610 */ + pr_debug("%s(), %s\n", + __func__, dongle_types[dongle_id]); + break; + case 0x09: /* IBM31T1100 or Temic TFDS6000/TFDS6500 */ + outb(0x28, iobase+7); /* Set irsl[0-2] as output */ + break; + case 0x0A: /* same as */ + case 0x0B: /* Reserved */ + pr_debug("%s(), %s not defined by irda yet\n", + __func__, dongle_types[dongle_id]); + break; + case 0x0C: /* same as */ + case 0x0D: /* HP HSDL-1100/HSDL-2100 */ + /* + * Set irsl0 as input, irsl[1-2] as output, and separate + * inputs are used for SIR and MIR/FIR + */ + outb(0x48, iobase+7); + break; + case 0x0E: /* Supports SIR Mode only */ + outb(0x28, iobase+7); /* Set irsl[0-2] as output */ + break; + case 0x0F: /* No dongle connected */ + pr_debug("%s(), %s\n", + __func__, dongle_types[dongle_id]); + + switch_bank(iobase, BANK0); + outb(0x62, iobase+MCR); + break; + default: + pr_debug("%s(), invalid dongle_id %#x", + __func__, dongle_id); + } + + /* IRCFG1: IRSL1 and 2 are set to IrDA mode */ + outb(0x00, iobase+4); + + /* Restore bank register */ + outb(bank, iobase+BSR); + +} /* set_up_dongle_interface */ + +/* + * Function nsc_ircc_change_dongle_speed (iobase, speed, dongle_id) + * + * Change speed of the attach dongle + * + */ +static void nsc_ircc_change_dongle_speed(int iobase, int speed, int dongle_id) +{ + __u8 bank; + + /* Save current bank */ + bank = inb(iobase+BSR); + + /* Select Bank 7 */ + switch_bank(iobase, BANK7); + + /* IRCFG1: set according to dongle_id */ + switch (dongle_id) { + case 0x00: /* same as */ + case 0x01: /* Differential serial interface */ + pr_debug("%s(), %s not defined by irda yet\n", + __func__, dongle_types[dongle_id]); + break; + case 0x02: /* same as */ + case 0x03: /* Reserved */ + pr_debug("%s(), %s not defined by irda yet\n", + __func__, dongle_types[dongle_id]); + break; + case 0x04: /* Sharp RY5HD01 */ + break; + case 0x05: /* Reserved */ + pr_debug("%s(), %s not defined by irda yet\n", + __func__, dongle_types[dongle_id]); + break; + case 0x06: /* Single-ended serial interface */ + pr_debug("%s(), %s not defined by irda yet\n", + __func__, dongle_types[dongle_id]); + break; + case 0x07: /* Consumer-IR only */ + pr_debug("%s(), %s is not for IrDA mode\n", + __func__, dongle_types[dongle_id]); + break; + case 0x08: /* HP HSDL-2300, HP HSDL-3600/HSDL-3610 */ + pr_debug("%s(), %s\n", + __func__, dongle_types[dongle_id]); + outb(0x00, iobase+4); + if (speed > 115200) + outb(0x01, iobase+4); + break; + case 0x09: /* IBM31T1100 or Temic TFDS6000/TFDS6500 */ + outb(0x01, iobase+4); + + if (speed == 4000000) { + /* There was a cli() there, but we now are already + * under spin_lock_irqsave() - JeanII */ + outb(0x81, iobase+4); + outb(0x80, iobase+4); + } else + outb(0x00, iobase+4); + break; + case 0x0A: /* same as */ + case 0x0B: /* Reserved */ + pr_debug("%s(), %s not defined by irda yet\n", + __func__, dongle_types[dongle_id]); + break; + case 0x0C: /* same as */ + case 0x0D: /* HP HSDL-1100/HSDL-2100 */ + break; + case 0x0E: /* Supports SIR Mode only */ + break; + case 0x0F: /* No dongle connected */ + pr_debug("%s(), %s is not for IrDA mode\n", + __func__, dongle_types[dongle_id]); + + switch_bank(iobase, BANK0); + outb(0x62, iobase+MCR); + break; + default: + pr_debug("%s(), invalid data_rate\n", __func__); + } + /* Restore bank register */ + outb(bank, iobase+BSR); +} + +/* + * Function nsc_ircc_change_speed (self, baud) + * + * Change the speed of the device + * + * This function *must* be called with irq off and spin-lock. + */ +static __u8 nsc_ircc_change_speed(struct nsc_ircc_cb *self, __u32 speed) +{ + struct net_device *dev; + __u8 mcr = MCR_SIR; + int iobase; + __u8 bank; + __u8 ier; /* Interrupt enable register */ + + pr_debug("%s(), speed=%d\n", __func__, speed); + + IRDA_ASSERT(self != NULL, return 0;); + + dev = self->netdev; + iobase = self->io.fir_base; + + /* Update accounting for new speed */ + self->io.speed = speed; + + /* Save current bank */ + bank = inb(iobase+BSR); + + /* Disable interrupts */ + switch_bank(iobase, BANK0); + outb(0, iobase+IER); + + /* Select Bank 2 */ + switch_bank(iobase, BANK2); + + outb(0x00, iobase+BGDH); + switch (speed) { + case 9600: outb(0x0c, iobase+BGDL); break; + case 19200: outb(0x06, iobase+BGDL); break; + case 38400: outb(0x03, iobase+BGDL); break; + case 57600: outb(0x02, iobase+BGDL); break; + case 115200: outb(0x01, iobase+BGDL); break; + case 576000: + switch_bank(iobase, BANK5); + + /* IRCR2: MDRS is set */ + outb(inb(iobase+4) | 0x04, iobase+4); + + mcr = MCR_MIR; + pr_debug("%s(), handling baud of 576000\n", __func__); + break; + case 1152000: + mcr = MCR_MIR; + pr_debug("%s(), handling baud of 1152000\n", __func__); + break; + case 4000000: + mcr = MCR_FIR; + pr_debug("%s(), handling baud of 4000000\n", __func__); + break; + default: + mcr = MCR_FIR; + pr_debug("%s(), unknown baud rate of %d\n", + __func__, speed); + break; + } + + /* Set appropriate speed mode */ + switch_bank(iobase, BANK0); + outb(mcr | MCR_TX_DFR, iobase+MCR); + + /* Give some hits to the transceiver */ + nsc_ircc_change_dongle_speed(iobase, speed, self->io.dongle_id); + + /* Set FIFO threshold to TX17, RX16 */ + switch_bank(iobase, BANK0); + outb(0x00, iobase+FCR); + outb(FCR_FIFO_EN, iobase+FCR); + outb(FCR_RXTH| /* Set Rx FIFO threshold */ + FCR_TXTH| /* Set Tx FIFO threshold */ + FCR_TXSR| /* Reset Tx FIFO */ + FCR_RXSR| /* Reset Rx FIFO */ + FCR_FIFO_EN, /* Enable FIFOs */ + iobase+FCR); + + /* Set FIFO size to 32 */ + switch_bank(iobase, BANK2); + outb(EXCR2_RFSIZ|EXCR2_TFSIZ, iobase+EXCR2); + + /* Enable some interrupts so we can receive frames */ + switch_bank(iobase, BANK0); + if (speed > 115200) { + /* Install FIR xmit handler */ + dev->netdev_ops = &nsc_ircc_fir_ops; + ier = IER_SFIF_IE; + nsc_ircc_dma_receive(self); + } else { + /* Install SIR xmit handler */ + dev->netdev_ops = &nsc_ircc_sir_ops; + ier = IER_RXHDL_IE; + } + /* Set our current interrupt mask */ + outb(ier, iobase+IER); + + /* Restore BSR */ + outb(bank, iobase+BSR); + + /* Make sure interrupt handlers keep the proper interrupt mask */ + return ier; +} + +/* + * Function nsc_ircc_hard_xmit (skb, dev) + * + * Transmit the frame! + * + */ +static netdev_tx_t nsc_ircc_hard_xmit_sir(struct sk_buff *skb, + struct net_device *dev) +{ + struct nsc_ircc_cb *self; + unsigned long flags; + int iobase; + __s32 speed; + __u8 bank; + + self = netdev_priv(dev); + + IRDA_ASSERT(self != NULL, return NETDEV_TX_OK;); + + iobase = self->io.fir_base; + + netif_stop_queue(dev); + + /* Make sure tests *& speed change are atomic */ + spin_lock_irqsave(&self->lock, flags); + + /* Check if we need to change the speed */ + speed = irda_get_next_speed(skb); + if ((speed != self->io.speed) && (speed != -1)) { + /* Check for empty frame. */ + if (!skb->len) { + /* If we just sent a frame, we get called before + * the last bytes get out (because of the SIR FIFO). + * If this is the case, let interrupt handler change + * the speed itself... Jean II */ + if (self->io.direction == IO_RECV) { + nsc_ircc_change_speed(self, speed); + /* TODO : For SIR->SIR, the next packet + * may get corrupted - Jean II */ + netif_wake_queue(dev); + } else { + self->new_speed = speed; + /* Queue will be restarted after speed change + * to make sure packets gets through the + * proper xmit handler - Jean II */ + } + netif_trans_update(dev); + spin_unlock_irqrestore(&self->lock, flags); + dev_kfree_skb(skb); + return NETDEV_TX_OK; + } else + self->new_speed = speed; + } + + /* Save current bank */ + bank = inb(iobase+BSR); + + self->tx_buff.data = self->tx_buff.head; + + self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data, + self->tx_buff.truesize); + + dev->stats.tx_bytes += self->tx_buff.len; + + /* Add interrupt on tx low level (will fire immediately) */ + switch_bank(iobase, BANK0); + outb(IER_TXLDL_IE, iobase+IER); + + /* Restore bank register */ + outb(bank, iobase+BSR); + + netif_trans_update(dev); + spin_unlock_irqrestore(&self->lock, flags); + + dev_kfree_skb(skb); + + return NETDEV_TX_OK; +} + +static netdev_tx_t nsc_ircc_hard_xmit_fir(struct sk_buff *skb, + struct net_device *dev) +{ + struct nsc_ircc_cb *self; + unsigned long flags; + int iobase; + __s32 speed; + __u8 bank; + int mtt, diff; + + self = netdev_priv(dev); + iobase = self->io.fir_base; + + netif_stop_queue(dev); + + /* Make sure tests *& speed change are atomic */ + spin_lock_irqsave(&self->lock, flags); + + /* Check if we need to change the speed */ + speed = irda_get_next_speed(skb); + if ((speed != self->io.speed) && (speed != -1)) { + /* Check for empty frame. */ + if (!skb->len) { + /* If we are currently transmitting, defer to + * interrupt handler. - Jean II */ + if(self->tx_fifo.len == 0) { + nsc_ircc_change_speed(self, speed); + netif_wake_queue(dev); + } else { + self->new_speed = speed; + /* Keep queue stopped : + * the speed change operation may change the + * xmit handler, and we want to make sure + * the next packet get through the proper + * Tx path, so block the Tx queue until + * the speed change has been done. + * Jean II */ + } + netif_trans_update(dev); + spin_unlock_irqrestore(&self->lock, flags); + dev_kfree_skb(skb); + return NETDEV_TX_OK; + } else { + /* Change speed after current frame */ + self->new_speed = speed; + } + } + + /* Save current bank */ + bank = inb(iobase+BSR); + + /* Register and copy this frame to DMA memory */ + self->tx_fifo.queue[self->tx_fifo.free].start = self->tx_fifo.tail; + self->tx_fifo.queue[self->tx_fifo.free].len = skb->len; + self->tx_fifo.tail += skb->len; + + dev->stats.tx_bytes += skb->len; + + skb_copy_from_linear_data(skb, self->tx_fifo.queue[self->tx_fifo.free].start, + skb->len); + self->tx_fifo.len++; + self->tx_fifo.free++; + + /* Start transmit only if there is currently no transmit going on */ + if (self->tx_fifo.len == 1) { + /* Check if we must wait the min turn time or not */ + mtt = irda_get_mtt(skb); + if (mtt) { + /* Check how much time we have used already */ + diff = ktime_us_delta(ktime_get(), self->stamp); + + /* Check if the mtt is larger than the time we have + * already used by all the protocol processing + */ + if (mtt > diff) { + mtt -= diff; + + /* + * Use timer if delay larger than 125 us, and + * use udelay for smaller values which should + * be acceptable + */ + if (mtt > 125) { + /* Adjust for timer resolution */ + mtt = mtt / 125; + + /* Setup timer */ + switch_bank(iobase, BANK4); + outb(mtt & 0xff, iobase+TMRL); + outb((mtt >> 8) & 0x0f, iobase+TMRH); + + /* Start timer */ + outb(IRCR1_TMR_EN, iobase+IRCR1); + self->io.direction = IO_XMIT; + + /* Enable timer interrupt */ + switch_bank(iobase, BANK0); + outb(IER_TMR_IE, iobase+IER); + + /* Timer will take care of the rest */ + goto out; + } else + udelay(mtt); + } + } + /* Enable DMA interrupt */ + switch_bank(iobase, BANK0); + outb(IER_DMA_IE, iobase+IER); + + /* Transmit frame */ + nsc_ircc_dma_xmit(self, iobase); + } + out: + /* Not busy transmitting anymore if window is not full, + * and if we don't need to change speed */ + if ((self->tx_fifo.free < MAX_TX_WINDOW) && (self->new_speed == 0)) + netif_wake_queue(self->netdev); + + /* Restore bank register */ + outb(bank, iobase+BSR); + + netif_trans_update(dev); + spin_unlock_irqrestore(&self->lock, flags); + dev_kfree_skb(skb); + + return NETDEV_TX_OK; +} + +/* + * Function nsc_ircc_dma_xmit (self, iobase) + * + * Transmit data using DMA + * + */ +static void nsc_ircc_dma_xmit(struct nsc_ircc_cb *self, int iobase) +{ + int bsr; + + /* Save current bank */ + bsr = inb(iobase+BSR); + + /* Disable DMA */ + switch_bank(iobase, BANK0); + outb(inb(iobase+MCR) & ~MCR_DMA_EN, iobase+MCR); + + self->io.direction = IO_XMIT; + + /* Choose transmit DMA channel */ + switch_bank(iobase, BANK2); + outb(ECR1_DMASWP|ECR1_DMANF|ECR1_EXT_SL, iobase+ECR1); + + irda_setup_dma(self->io.dma, + ((u8 *)self->tx_fifo.queue[self->tx_fifo.ptr].start - + self->tx_buff.head) + self->tx_buff_dma, + self->tx_fifo.queue[self->tx_fifo.ptr].len, + DMA_TX_MODE); + + /* Enable DMA and SIR interaction pulse */ + switch_bank(iobase, BANK0); + outb(inb(iobase+MCR)|MCR_TX_DFR|MCR_DMA_EN|MCR_IR_PLS, iobase+MCR); + + /* Restore bank register */ + outb(bsr, iobase+BSR); +} + +/* + * Function nsc_ircc_pio_xmit (self, iobase) + * + * Transmit data using PIO. Returns the number of bytes that actually + * got transferred + * + */ +static int nsc_ircc_pio_write(int iobase, __u8 *buf, int len, int fifo_size) +{ + int actual = 0; + __u8 bank; + + /* Save current bank */ + bank = inb(iobase+BSR); + + switch_bank(iobase, BANK0); + if (!(inb_p(iobase+LSR) & LSR_TXEMP)) { + pr_debug("%s(), warning, FIFO not empty yet!\n", + __func__); + + /* FIFO may still be filled to the Tx interrupt threshold */ + fifo_size -= 17; + } + + /* Fill FIFO with current frame */ + while ((fifo_size-- > 0) && (actual < len)) { + /* Transmit next byte */ + outb(buf[actual++], iobase+TXD); + } + + pr_debug("%s(), fifo_size %d ; %d sent of %d\n", + __func__, fifo_size, actual, len); + + /* Restore bank */ + outb(bank, iobase+BSR); + + return actual; +} + +/* + * Function nsc_ircc_dma_xmit_complete (self) + * + * The transfer of a frame in finished. This function will only be called + * by the interrupt handler + * + */ +static int nsc_ircc_dma_xmit_complete(struct nsc_ircc_cb *self) +{ + int iobase; + __u8 bank; + int ret = TRUE; + + iobase = self->io.fir_base; + + /* Save current bank */ + bank = inb(iobase+BSR); + + /* Disable DMA */ + switch_bank(iobase, BANK0); + outb(inb(iobase+MCR) & ~MCR_DMA_EN, iobase+MCR); + + /* Check for underrun! */ + if (inb(iobase+ASCR) & ASCR_TXUR) { + self->netdev->stats.tx_errors++; + self->netdev->stats.tx_fifo_errors++; + + /* Clear bit, by writing 1 into it */ + outb(ASCR_TXUR, iobase+ASCR); + } else { + self->netdev->stats.tx_packets++; + } + + /* Finished with this frame, so prepare for next */ + self->tx_fifo.ptr++; + self->tx_fifo.len--; + + /* Any frames to be sent back-to-back? */ + if (self->tx_fifo.len) { + nsc_ircc_dma_xmit(self, iobase); + + /* Not finished yet! */ + ret = FALSE; + } else { + /* Reset Tx FIFO info */ + self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0; + self->tx_fifo.tail = self->tx_buff.head; + } + + /* Make sure we have room for more frames and + * that we don't need to change speed */ + if ((self->tx_fifo.free < MAX_TX_WINDOW) && (self->new_speed == 0)) { + /* Not busy transmitting anymore */ + /* Tell the network layer, that we can accept more frames */ + netif_wake_queue(self->netdev); + } + + /* Restore bank */ + outb(bank, iobase+BSR); + + return ret; +} + +/* + * Function nsc_ircc_dma_receive (self) + * + * Get ready for receiving a frame. The device will initiate a DMA + * if it starts to receive a frame. + * + */ +static int nsc_ircc_dma_receive(struct nsc_ircc_cb *self) +{ + int iobase; + __u8 bsr; + + iobase = self->io.fir_base; + + /* Reset Tx FIFO info */ + self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0; + self->tx_fifo.tail = self->tx_buff.head; + + /* Save current bank */ + bsr = inb(iobase+BSR); + + /* Disable DMA */ + switch_bank(iobase, BANK0); + outb(inb(iobase+MCR) & ~MCR_DMA_EN, iobase+MCR); + + /* Choose DMA Rx, DMA Fairness, and Advanced mode */ + switch_bank(iobase, BANK2); + outb(ECR1_DMANF|ECR1_EXT_SL, iobase+ECR1); + + self->io.direction = IO_RECV; + self->rx_buff.data = self->rx_buff.head; + + /* Reset Rx FIFO. This will also flush the ST_FIFO */ + switch_bank(iobase, BANK0); + outb(FCR_RXSR|FCR_FIFO_EN, iobase+FCR); + + self->st_fifo.len = self->st_fifo.pending_bytes = 0; + self->st_fifo.tail = self->st_fifo.head = 0; + + irda_setup_dma(self->io.dma, self->rx_buff_dma, self->rx_buff.truesize, + DMA_RX_MODE); + + /* Enable DMA */ + switch_bank(iobase, BANK0); + outb(inb(iobase+MCR)|MCR_DMA_EN, iobase+MCR); + + /* Restore bank register */ + outb(bsr, iobase+BSR); + + return 0; +} + +/* + * Function nsc_ircc_dma_receive_complete (self) + * + * Finished with receiving frames + * + * + */ +static int nsc_ircc_dma_receive_complete(struct nsc_ircc_cb *self, int iobase) +{ + struct st_fifo *st_fifo; + struct sk_buff *skb; + __u8 status; + __u8 bank; + int len; + + st_fifo = &self->st_fifo; + + /* Save current bank */ + bank = inb(iobase+BSR); + + /* Read all entries in status FIFO */ + switch_bank(iobase, BANK5); + while ((status = inb(iobase+FRM_ST)) & FRM_ST_VLD) { + /* We must empty the status FIFO no matter what */ + len = inb(iobase+RFLFL) | ((inb(iobase+RFLFH) & 0x1f) << 8); + + if (st_fifo->tail >= MAX_RX_WINDOW) { + pr_debug("%s(), window is full!\n", __func__); + continue; + } + + st_fifo->entries[st_fifo->tail].status = status; + st_fifo->entries[st_fifo->tail].len = len; + st_fifo->pending_bytes += len; + st_fifo->tail++; + st_fifo->len++; + } + /* Try to process all entries in status FIFO */ + while (st_fifo->len > 0) { + /* Get first entry */ + status = st_fifo->entries[st_fifo->head].status; + len = st_fifo->entries[st_fifo->head].len; + st_fifo->pending_bytes -= len; + st_fifo->head++; + st_fifo->len--; + + /* Check for errors */ + if (status & FRM_ST_ERR_MSK) { + if (status & FRM_ST_LOST_FR) { + /* Add number of lost frames to stats */ + self->netdev->stats.rx_errors += len; + } else { + /* Skip frame */ + self->netdev->stats.rx_errors++; + + self->rx_buff.data += len; + + if (status & FRM_ST_MAX_LEN) + self->netdev->stats.rx_length_errors++; + + if (status & FRM_ST_PHY_ERR) + self->netdev->stats.rx_frame_errors++; + + if (status & FRM_ST_BAD_CRC) + self->netdev->stats.rx_crc_errors++; + } + /* The errors below can be reported in both cases */ + if (status & FRM_ST_OVR1) + self->netdev->stats.rx_fifo_errors++; + + if (status & FRM_ST_OVR2) + self->netdev->stats.rx_fifo_errors++; + } else { + /* + * First we must make sure that the frame we + * want to deliver is all in main memory. If we + * cannot tell, then we check if the Rx FIFO is + * empty. If not then we will have to take a nap + * and try again later. + */ + if (st_fifo->pending_bytes < self->io.fifo_size) { + switch_bank(iobase, BANK0); + if (inb(iobase+LSR) & LSR_RXDA) { + /* Put this entry back in fifo */ + st_fifo->head--; + st_fifo->len++; + st_fifo->pending_bytes += len; + st_fifo->entries[st_fifo->head].status = status; + st_fifo->entries[st_fifo->head].len = len; + /* + * DMA not finished yet, so try again + * later, set timer value, resolution + * 125 us + */ + switch_bank(iobase, BANK4); + outb(0x02, iobase+TMRL); /* x 125 us */ + outb(0x00, iobase+TMRH); + + /* Start timer */ + outb(IRCR1_TMR_EN, iobase+IRCR1); + + /* Restore bank register */ + outb(bank, iobase+BSR); + + return FALSE; /* I'll be back! */ + } + } + + /* + * Remember the time we received this frame, so we can + * reduce the min turn time a bit since we will know + * how much time we have used for protocol processing + */ + self->stamp = ktime_get(); + + skb = dev_alloc_skb(len+1); + if (skb == NULL) { + self->netdev->stats.rx_dropped++; + + /* Restore bank register */ + outb(bank, iobase+BSR); + + return FALSE; + } + + /* Make sure IP header gets aligned */ + skb_reserve(skb, 1); + + /* Copy frame without CRC */ + if (self->io.speed < 4000000) { + skb_put(skb, len-2); + skb_copy_to_linear_data(skb, + self->rx_buff.data, + len - 2); + } else { + skb_put(skb, len-4); + skb_copy_to_linear_data(skb, + self->rx_buff.data, + len - 4); + } + + /* Move to next frame */ + self->rx_buff.data += len; + self->netdev->stats.rx_bytes += len; + self->netdev->stats.rx_packets++; + + skb->dev = self->netdev; + skb_reset_mac_header(skb); + skb->protocol = htons(ETH_P_IRDA); + netif_rx(skb); + } + } + /* Restore bank register */ + outb(bank, iobase+BSR); + + return TRUE; +} + +/* + * Function nsc_ircc_pio_receive (self) + * + * Receive all data in receiver FIFO + * + */ +static void nsc_ircc_pio_receive(struct nsc_ircc_cb *self) +{ + __u8 byte; + int iobase; + + iobase = self->io.fir_base; + + /* Receive all characters in Rx FIFO */ + do { + byte = inb(iobase+RXD); + async_unwrap_char(self->netdev, &self->netdev->stats, + &self->rx_buff, byte); + } while (inb(iobase+LSR) & LSR_RXDA); /* Data available */ +} + +/* + * Function nsc_ircc_sir_interrupt (self, eir) + * + * Handle SIR interrupt + * + */ +static void nsc_ircc_sir_interrupt(struct nsc_ircc_cb *self, int eir) +{ + int actual; + + /* Check if transmit FIFO is low on data */ + if (eir & EIR_TXLDL_EV) { + /* Write data left in transmit buffer */ + actual = nsc_ircc_pio_write(self->io.fir_base, + self->tx_buff.data, + self->tx_buff.len, + self->io.fifo_size); + self->tx_buff.data += actual; + self->tx_buff.len -= actual; + + self->io.direction = IO_XMIT; + + /* Check if finished */ + if (self->tx_buff.len > 0) + self->ier = IER_TXLDL_IE; + else { + + self->netdev->stats.tx_packets++; + netif_wake_queue(self->netdev); + self->ier = IER_TXEMP_IE; + } + + } + /* Check if transmission has completed */ + if (eir & EIR_TXEMP_EV) { + /* Turn around and get ready to receive some data */ + self->io.direction = IO_RECV; + self->ier = IER_RXHDL_IE; + /* Check if we need to change the speed? + * Need to be after self->io.direction to avoid race with + * nsc_ircc_hard_xmit_sir() - Jean II */ + if (self->new_speed) { + pr_debug("%s(), Changing speed!\n", __func__); + self->ier = nsc_ircc_change_speed(self, + self->new_speed); + self->new_speed = 0; + netif_wake_queue(self->netdev); + + /* Check if we are going to FIR */ + if (self->io.speed > 115200) { + /* No need to do anymore SIR stuff */ + return; + } + } + } + + /* Rx FIFO threshold or timeout */ + if (eir & EIR_RXHDL_EV) { + nsc_ircc_pio_receive(self); + + /* Keep receiving */ + self->ier = IER_RXHDL_IE; + } +} + +/* + * Function nsc_ircc_fir_interrupt (self, eir) + * + * Handle MIR/FIR interrupt + * + */ +static void nsc_ircc_fir_interrupt(struct nsc_ircc_cb *self, int iobase, + int eir) +{ + __u8 bank; + + bank = inb(iobase+BSR); + + /* Status FIFO event*/ + if (eir & EIR_SFIF_EV) { + /* Check if DMA has finished */ + if (nsc_ircc_dma_receive_complete(self, iobase)) { + /* Wait for next status FIFO interrupt */ + self->ier = IER_SFIF_IE; + } else { + self->ier = IER_SFIF_IE | IER_TMR_IE; + } + } else if (eir & EIR_TMR_EV) { /* Timer finished */ + /* Disable timer */ + switch_bank(iobase, BANK4); + outb(0, iobase+IRCR1); + + /* Clear timer event */ + switch_bank(iobase, BANK0); + outb(ASCR_CTE, iobase+ASCR); + + /* Check if this is a Tx timer interrupt */ + if (self->io.direction == IO_XMIT) { + nsc_ircc_dma_xmit(self, iobase); + + /* Interrupt on DMA */ + self->ier = IER_DMA_IE; + } else { + /* Check (again) if DMA has finished */ + if (nsc_ircc_dma_receive_complete(self, iobase)) { + self->ier = IER_SFIF_IE; + } else { + self->ier = IER_SFIF_IE | IER_TMR_IE; + } + } + } else if (eir & EIR_DMA_EV) { + /* Finished with all transmissions? */ + if (nsc_ircc_dma_xmit_complete(self)) { + if(self->new_speed != 0) { + /* As we stop the Tx queue, the speed change + * need to be done when the Tx fifo is + * empty. Ask for a Tx done interrupt */ + self->ier = IER_TXEMP_IE; + } else { + /* Check if there are more frames to be + * transmitted */ + if (irda_device_txqueue_empty(self->netdev)) { + /* Prepare for receive */ + nsc_ircc_dma_receive(self); + self->ier = IER_SFIF_IE; + } else + net_warn_ratelimited("%s(), potential Tx queue lockup !\n", + __func__); + } + } else { + /* Not finished yet, so interrupt on DMA again */ + self->ier = IER_DMA_IE; + } + } else if (eir & EIR_TXEMP_EV) { + /* The Tx FIFO has totally drained out, so now we can change + * the speed... - Jean II */ + self->ier = nsc_ircc_change_speed(self, self->new_speed); + self->new_speed = 0; + netif_wake_queue(self->netdev); + /* Note : nsc_ircc_change_speed() restarted Rx fifo */ + } + + outb(bank, iobase+BSR); +} + +/* + * Function nsc_ircc_interrupt (irq, dev_id, regs) + * + * An interrupt from the chip has arrived. Time to do some work + * + */ +static irqreturn_t nsc_ircc_interrupt(int irq, void *dev_id) +{ + struct net_device *dev = dev_id; + struct nsc_ircc_cb *self; + __u8 bsr, eir; + int iobase; + + self = netdev_priv(dev); + + spin_lock(&self->lock); + + iobase = self->io.fir_base; + + bsr = inb(iobase+BSR); /* Save current bank */ + + switch_bank(iobase, BANK0); + self->ier = inb(iobase+IER); + eir = inb(iobase+EIR) & self->ier; /* Mask out the interesting ones */ + + outb(0, iobase+IER); /* Disable interrupts */ + + if (eir) { + /* Dispatch interrupt handler for the current speed */ + if (self->io.speed > 115200) + nsc_ircc_fir_interrupt(self, iobase, eir); + else + nsc_ircc_sir_interrupt(self, eir); + } + + outb(self->ier, iobase+IER); /* Restore interrupts */ + outb(bsr, iobase+BSR); /* Restore bank register */ + + spin_unlock(&self->lock); + return IRQ_RETVAL(eir); +} + +/* + * Function nsc_ircc_is_receiving (self) + * + * Return TRUE is we are currently receiving a frame + * + */ +static int nsc_ircc_is_receiving(struct nsc_ircc_cb *self) +{ + unsigned long flags; + int status = FALSE; + int iobase; + __u8 bank; + + IRDA_ASSERT(self != NULL, return FALSE;); + + spin_lock_irqsave(&self->lock, flags); + + if (self->io.speed > 115200) { + iobase = self->io.fir_base; + + /* Check if rx FIFO is not empty */ + bank = inb(iobase+BSR); + switch_bank(iobase, BANK2); + if ((inb(iobase+RXFLV) & 0x3f) != 0) { + /* We are receiving something */ + status = TRUE; + } + outb(bank, iobase+BSR); + } else + status = (self->rx_buff.state != OUTSIDE_FRAME); + + spin_unlock_irqrestore(&self->lock, flags); + + return status; +} + +/* + * Function nsc_ircc_net_open (dev) + * + * Start the device + * + */ +static int nsc_ircc_net_open(struct net_device *dev) +{ + struct nsc_ircc_cb *self; + int iobase; + char hwname[32]; + __u8 bank; + + + IRDA_ASSERT(dev != NULL, return -1;); + self = netdev_priv(dev); + + IRDA_ASSERT(self != NULL, return 0;); + + iobase = self->io.fir_base; + + if (request_irq(self->io.irq, nsc_ircc_interrupt, 0, dev->name, dev)) { + net_warn_ratelimited("%s, unable to allocate irq=%d\n", + driver_name, self->io.irq); + return -EAGAIN; + } + /* + * Always allocate the DMA channel after the IRQ, and clean up on + * failure. + */ + if (request_dma(self->io.dma, dev->name)) { + net_warn_ratelimited("%s, unable to allocate dma=%d\n", + driver_name, self->io.dma); + free_irq(self->io.irq, dev); + return -EAGAIN; + } + + /* Save current bank */ + bank = inb(iobase+BSR); + + /* turn on interrupts */ + switch_bank(iobase, BANK0); + outb(IER_LS_IE | IER_RXHDL_IE, iobase+IER); + + /* Restore bank register */ + outb(bank, iobase+BSR); + + /* Ready to play! */ + netif_start_queue(dev); + + /* Give self a hardware name */ + sprintf(hwname, "NSC-FIR @ 0x%03x", self->io.fir_base); + + /* + * Open new IrLAP layer instance, now that everything should be + * initialized properly + */ + self->irlap = irlap_open(dev, &self->qos, hwname); + + return 0; +} + +/* + * Function nsc_ircc_net_close (dev) + * + * Stop the device + * + */ +static int nsc_ircc_net_close(struct net_device *dev) +{ + struct nsc_ircc_cb *self; + int iobase; + __u8 bank; + + + IRDA_ASSERT(dev != NULL, return -1;); + + self = netdev_priv(dev); + IRDA_ASSERT(self != NULL, return 0;); + + /* Stop device */ + netif_stop_queue(dev); + + /* Stop and remove instance of IrLAP */ + if (self->irlap) + irlap_close(self->irlap); + self->irlap = NULL; + + iobase = self->io.fir_base; + + disable_dma(self->io.dma); + + /* Save current bank */ + bank = inb(iobase+BSR); + + /* Disable interrupts */ + switch_bank(iobase, BANK0); + outb(0, iobase+IER); + + free_irq(self->io.irq, dev); + free_dma(self->io.dma); + + /* Restore bank register */ + outb(bank, iobase+BSR); + + return 0; +} + +/* + * Function nsc_ircc_net_ioctl (dev, rq, cmd) + * + * Process IOCTL commands for this device + * + */ +static int nsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct if_irda_req *irq = (struct if_irda_req *) rq; + struct nsc_ircc_cb *self; + unsigned long flags; + int ret = 0; + + IRDA_ASSERT(dev != NULL, return -1;); + + self = netdev_priv(dev); + + IRDA_ASSERT(self != NULL, return -1;); + + pr_debug("%s(), %s, (cmd=0x%X)\n", __func__, dev->name, cmd); + + switch (cmd) { + case SIOCSBANDWIDTH: /* Set bandwidth */ + if (!capable(CAP_NET_ADMIN)) { + ret = -EPERM; + break; + } + spin_lock_irqsave(&self->lock, flags); + nsc_ircc_change_speed(self, irq->ifr_baudrate); + spin_unlock_irqrestore(&self->lock, flags); + break; + case SIOCSMEDIABUSY: /* Set media busy */ + if (!capable(CAP_NET_ADMIN)) { + ret = -EPERM; + break; + } + irda_device_set_media_busy(self->netdev, TRUE); + break; + case SIOCGRECEIVING: /* Check if we are receiving right now */ + /* This is already protected */ + irq->ifr_receiving = nsc_ircc_is_receiving(self); + break; + default: + ret = -EOPNOTSUPP; + } + return ret; +} + +static int nsc_ircc_suspend(struct platform_device *dev, pm_message_t state) +{ + struct nsc_ircc_cb *self = platform_get_drvdata(dev); + int bank; + unsigned long flags; + int iobase = self->io.fir_base; + + if (self->io.suspended) + return 0; + + pr_debug("%s, Suspending\n", driver_name); + + rtnl_lock(); + if (netif_running(self->netdev)) { + netif_device_detach(self->netdev); + spin_lock_irqsave(&self->lock, flags); + /* Save current bank */ + bank = inb(iobase+BSR); + + /* Disable interrupts */ + switch_bank(iobase, BANK0); + outb(0, iobase+IER); + + /* Restore bank register */ + outb(bank, iobase+BSR); + + spin_unlock_irqrestore(&self->lock, flags); + free_irq(self->io.irq, self->netdev); + disable_dma(self->io.dma); + } + self->io.suspended = 1; + rtnl_unlock(); + + return 0; +} + +static int nsc_ircc_resume(struct platform_device *dev) +{ + struct nsc_ircc_cb *self = platform_get_drvdata(dev); + unsigned long flags; + + if (!self->io.suspended) + return 0; + + pr_debug("%s, Waking up\n", driver_name); + + rtnl_lock(); + nsc_ircc_setup(&self->io); + nsc_ircc_init_dongle_interface(self->io.fir_base, self->io.dongle_id); + + if (netif_running(self->netdev)) { + if (request_irq(self->io.irq, nsc_ircc_interrupt, 0, + self->netdev->name, self->netdev)) { + net_warn_ratelimited("%s, unable to allocate irq=%d\n", + driver_name, self->io.irq); + + /* + * Don't fail resume process, just kill this + * network interface + */ + unregister_netdevice(self->netdev); + } else { + spin_lock_irqsave(&self->lock, flags); + nsc_ircc_change_speed(self, self->io.speed); + spin_unlock_irqrestore(&self->lock, flags); + netif_device_attach(self->netdev); + } + + } else { + spin_lock_irqsave(&self->lock, flags); + nsc_ircc_change_speed(self, 9600); + spin_unlock_irqrestore(&self->lock, flags); + } + self->io.suspended = 0; + rtnl_unlock(); + + return 0; +} + +MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>"); +MODULE_DESCRIPTION("NSC IrDA Device Driver"); +MODULE_LICENSE("GPL"); + + +module_param(qos_mtt_bits, int, 0); +MODULE_PARM_DESC(qos_mtt_bits, "Minimum Turn Time"); +module_param_hw_array(io, int, ioport, NULL, 0); +MODULE_PARM_DESC(io, "Base I/O addresses"); +module_param_hw_array(irq, int, irq, NULL, 0); +MODULE_PARM_DESC(irq, "IRQ lines"); +module_param_hw_array(dma, int, dma, NULL, 0); +MODULE_PARM_DESC(dma, "DMA channels"); +module_param(dongle_id, int, 0); +MODULE_PARM_DESC(dongle_id, "Type-id of used dongle"); + +module_init(nsc_ircc_init); +module_exit(nsc_ircc_cleanup); + diff --git a/drivers/staging/irda/drivers/nsc-ircc.h b/drivers/staging/irda/drivers/nsc-ircc.h new file mode 100644 index 000000000000..7be5acb56532 --- /dev/null +++ b/drivers/staging/irda/drivers/nsc-ircc.h @@ -0,0 +1,281 @@ +/********************************************************************* + * + * Filename: nsc-ircc.h + * Version: + * Description: + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Fri Nov 13 14:37:40 1998 + * Modified at: Sun Jan 23 17:47:00 2000 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no> + * Copyright (c) 1998 Lichen Wang, <lwang@actisys.com> + * Copyright (c) 1998 Actisys Corp., www.actisys.com + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#ifndef NSC_IRCC_H +#define NSC_IRCC_H + +#include <linux/ktime.h> + +#include <linux/spinlock.h> +#include <linux/pm.h> +#include <linux/types.h> +#include <asm/io.h> + +/* Features for chips (set in driver_data) */ +#define NSC_FORCE_DONGLE_TYPE9 0x00000001 + +/* DMA modes needed */ +#define DMA_TX_MODE 0x08 /* Mem to I/O, ++, demand. */ +#define DMA_RX_MODE 0x04 /* I/O to mem, ++, demand. */ + +/* Config registers for the '108 */ +#define CFG_108_BAIC 0x00 +#define CFG_108_CSRT 0x01 +#define CFG_108_MCTL 0x02 + +/* Config registers for the '338 */ +#define CFG_338_FER 0x00 +#define CFG_338_FAR 0x01 +#define CFG_338_PTR 0x02 +#define CFG_338_PNP0 0x1b +#define CFG_338_PNP1 0x1c +#define CFG_338_PNP3 0x4f + +/* Config registers for the '39x (in the logical device bank) */ +#define CFG_39X_LDN 0x07 /* Logical device number (Super I/O bank) */ +#define CFG_39X_SIOCF1 0x21 /* SuperI/O Config */ +#define CFG_39X_ACT 0x30 /* Device activation */ +#define CFG_39X_BASEH 0x60 /* Device base address (high bits) */ +#define CFG_39X_BASEL 0x61 /* Device base address (low bits) */ +#define CFG_39X_IRQNUM 0x70 /* Interrupt number & wake up enable */ +#define CFG_39X_IRQSEL 0x71 /* Interrupt select (edge/level + polarity) */ +#define CFG_39X_DMA0 0x74 /* DMA 0 configuration */ +#define CFG_39X_DMA1 0x75 /* DMA 1 configuration */ +#define CFG_39X_SPC 0xF0 /* Serial port configuration register */ + +/* Flags for configuration register CRF0 */ +#define APEDCRC 0x02 +#define ENBNKSEL 0x01 + +/* Set 0 */ +#define TXD 0x00 /* Transmit data port */ +#define RXD 0x00 /* Receive data port */ + +/* Register 1 */ +#define IER 0x01 /* Interrupt Enable Register*/ +#define IER_RXHDL_IE 0x01 /* Receiver high data level interrupt */ +#define IER_TXLDL_IE 0x02 /* Transeiver low data level interrupt */ +#define IER_LS_IE 0x04//* Link Status Interrupt */ +#define IER_ETXURI 0x04 /* Tx underrun */ +#define IER_DMA_IE 0x10 /* DMA finished interrupt */ +#define IER_TXEMP_IE 0x20 +#define IER_SFIF_IE 0x40 /* Frame status FIFO intr */ +#define IER_TMR_IE 0x80 /* Timer event */ + +#define FCR 0x02 /* (write only) */ +#define FCR_FIFO_EN 0x01 /* Enable FIFO's */ +#define FCR_RXSR 0x02 /* Rx FIFO soft reset */ +#define FCR_TXSR 0x04 /* Tx FIFO soft reset */ +#define FCR_RXTH 0x40 /* Rx FIFO threshold (set to 16) */ +#define FCR_TXTH 0x20 /* Tx FIFO threshold (set to 17) */ + +#define EIR 0x02 /* (read only) */ +#define EIR_RXHDL_EV 0x01 +#define EIR_TXLDL_EV 0x02 +#define EIR_LS_EV 0x04 +#define EIR_DMA_EV 0x10 +#define EIR_TXEMP_EV 0x20 +#define EIR_SFIF_EV 0x40 +#define EIR_TMR_EV 0x80 + +#define LCR 0x03 /* Link control register */ +#define LCR_WLS_8 0x03 /* 8 bits */ + +#define BSR 0x03 /* Bank select register */ +#define BSR_BKSE 0x80 +#define BANK0 LCR_WLS_8 /* Must make sure that we set 8N1 */ +#define BANK1 0x80 +#define BANK2 0xe0 +#define BANK3 0xe4 +#define BANK4 0xe8 +#define BANK5 0xec +#define BANK6 0xf0 +#define BANK7 0xf4 + +#define MCR 0x04 /* Mode Control Register */ +#define MCR_MODE_MASK ~(0xd0) +#define MCR_UART 0x00 +#define MCR_RESERVED 0x20 +#define MCR_SHARP_IR 0x40 +#define MCR_SIR 0x60 +#define MCR_MIR 0x80 +#define MCR_FIR 0xa0 +#define MCR_CEIR 0xb0 +#define MCR_IR_PLS 0x10 +#define MCR_DMA_EN 0x04 +#define MCR_EN_IRQ 0x08 +#define MCR_TX_DFR 0x08 + +#define LSR 0x05 /* Link status register */ +#define LSR_RXDA 0x01 /* Receiver data available */ +#define LSR_TXRDY 0x20 /* Transmitter ready */ +#define LSR_TXEMP 0x40 /* Transmitter empty */ + +#define ASCR 0x07 /* Auxiliary Status and Control Register */ +#define ASCR_RXF_TOUT 0x01 /* Rx FIFO timeout */ +#define ASCR_FEND_INF 0x02 /* Frame end bytes in rx FIFO */ +#define ASCR_S_EOT 0x04 /* Set end of transmission */ +#define ASCT_RXBSY 0x20 /* Rx busy */ +#define ASCR_TXUR 0x40 /* Transeiver underrun */ +#define ASCR_CTE 0x80 /* Clear timer event */ + +/* Bank 2 */ +#define BGDL 0x00 /* Baud Generator Divisor Port (Low Byte) */ +#define BGDH 0x01 /* Baud Generator Divisor Port (High Byte) */ + +#define ECR1 0x02 /* Extended Control Register 1 */ +#define ECR1_EXT_SL 0x01 /* Extended Mode Select */ +#define ECR1_DMANF 0x02 /* DMA Fairness */ +#define ECR1_DMATH 0x04 /* DMA Threshold */ +#define ECR1_DMASWP 0x08 /* DMA Swap */ + +#define EXCR2 0x04 +#define EXCR2_TFSIZ 0x01 /* Rx FIFO size = 32 */ +#define EXCR2_RFSIZ 0x04 /* Tx FIFO size = 32 */ + +#define TXFLV 0x06 /* Tx FIFO level */ +#define RXFLV 0x07 /* Rx FIFO level */ + +/* Bank 3 */ +#define MID 0x00 + +/* Bank 4 */ +#define TMRL 0x00 /* Timer low byte */ +#define TMRH 0x01 /* Timer high byte */ +#define IRCR1 0x02 /* Infrared control register 1 */ +#define IRCR1_TMR_EN 0x01 /* Timer enable */ + +#define TFRLL 0x04 +#define TFRLH 0x05 +#define RFRLL 0x06 +#define RFRLH 0x07 + +/* Bank 5 */ +#define IRCR2 0x04 /* Infrared control register 2 */ +#define IRCR2_MDRS 0x04 /* MIR data rate select */ +#define IRCR2_FEND_MD 0x20 /* */ + +#define FRM_ST 0x05 /* Frame status FIFO */ +#define FRM_ST_VLD 0x80 /* Frame status FIFO data valid */ +#define FRM_ST_ERR_MSK 0x5f +#define FRM_ST_LOST_FR 0x40 /* Frame lost */ +#define FRM_ST_MAX_LEN 0x10 /* Max frame len exceeded */ +#define FRM_ST_PHY_ERR 0x08 /* Physical layer error */ +#define FRM_ST_BAD_CRC 0x04 +#define FRM_ST_OVR1 0x02 /* Rx FIFO overrun */ +#define FRM_ST_OVR2 0x01 /* Frame status FIFO overrun */ + +#define RFLFL 0x06 +#define RFLFH 0x07 + +/* Bank 6 */ +#define IR_CFG2 0x00 +#define IR_CFG2_DIS_CRC 0x02 + +/* Bank 7 */ +#define IRM_CR 0x07 /* Infrared module control register */ +#define IRM_CR_IRX_MSL 0x40 +#define IRM_CR_AF_MNT 0x80 /* Automatic format */ + +/* NSC chip information */ +struct nsc_chip { + char *name; /* Name of chipset */ + int cfg[3]; /* Config registers */ + u_int8_t cid_index; /* Chip identification index reg */ + u_int8_t cid_value; /* Chip identification expected value */ + u_int8_t cid_mask; /* Chip identification revision mask */ + + /* Functions for probing and initializing the specific chip */ + int (*probe)(struct nsc_chip *chip, chipio_t *info); + int (*init)(struct nsc_chip *chip, chipio_t *info); +}; +typedef struct nsc_chip nsc_chip_t; + +/* For storing entries in the status FIFO */ +struct st_fifo_entry { + int status; + int len; +}; + +#define MAX_TX_WINDOW 7 +#define MAX_RX_WINDOW 7 + +struct st_fifo { + struct st_fifo_entry entries[MAX_RX_WINDOW]; + int pending_bytes; + int head; + int tail; + int len; +}; + +struct frame_cb { + void *start; /* Start of frame in DMA mem */ + int len; /* Length of frame in DMA mem */ +}; + +struct tx_fifo { + struct frame_cb queue[MAX_TX_WINDOW]; /* Info about frames in queue */ + int ptr; /* Currently being sent */ + int len; /* Length of queue */ + int free; /* Next free slot */ + void *tail; /* Next free start in DMA mem */ +}; + +/* Private data for each instance */ +struct nsc_ircc_cb { + struct st_fifo st_fifo; /* Info about received frames */ + struct tx_fifo tx_fifo; /* Info about frames to be transmitted */ + + struct net_device *netdev; /* Yes! we are some kind of netdevice */ + + struct irlap_cb *irlap; /* The link layer we are binded to */ + struct qos_info qos; /* QoS capabilities for this device */ + + chipio_t io; /* IrDA controller information */ + iobuff_t tx_buff; /* Transmit buffer */ + iobuff_t rx_buff; /* Receive buffer */ + dma_addr_t tx_buff_dma; + dma_addr_t rx_buff_dma; + + __u8 ier; /* Interrupt enable register */ + + ktime_t stamp; + + spinlock_t lock; /* For serializing operations */ + + __u32 new_speed; + int index; /* Instance index */ + + struct platform_device *pldev; +}; + +static inline void switch_bank(int iobase, int bank) +{ + outb(bank, iobase+BSR); +} + +#endif /* NSC_IRCC_H */ diff --git a/drivers/staging/irda/drivers/old_belkin-sir.c b/drivers/staging/irda/drivers/old_belkin-sir.c new file mode 100644 index 000000000000..a7c2e990ae69 --- /dev/null +++ b/drivers/staging/irda/drivers/old_belkin-sir.c @@ -0,0 +1,146 @@ +/********************************************************************* + * + * Filename: old_belkin.c + * Version: 1.1 + * Description: Driver for the Belkin (old) SmartBeam dongle + * Status: Experimental... + * Author: Jean Tourrilhes <jt@hpl.hp.com> + * Created at: 22/11/99 + * Modified at: Fri Dec 17 09:13:32 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1999 Jean Tourrilhes, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + ********************************************************************/ + +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/init.h> + +#include <net/irda/irda.h> +// #include <net/irda/irda_device.h> + +#include "sir-dev.h" + +/* + * Belkin is selling a dongle called the SmartBeam. + * In fact, there is two hardware version of this dongle, of course with + * the same name and looking the exactly same (grrr...). + * I guess that I've got the old one, because inside I don't have + * a jumper for IrDA/ASK... + * + * As far as I can make it from info on their web site, the old dongle + * support only 9600 b/s, which make our life much simpler as far as + * the driver is concerned, but you might not like it very much ;-) + * The new SmartBeam does 115 kb/s, and I've not tested it... + * + * Belkin claim that the correct driver for the old dongle (in Windows) + * is the generic Parallax 9500a driver, but the Linux LiteLink driver + * fails for me (probably because Linux-IrDA doesn't rate fallback), + * so I created this really dumb driver... + * + * In fact, this driver doesn't do much. The only thing it does is to + * prevent Linux-IrDA to use any other speed than 9600 b/s ;-) This + * driver is called "old_belkin" so that when the new SmartBeam is supported + * its driver can be called "belkin" instead of "new_belkin". + * + * Note : this driver was written without any info/help from Belkin, + * so a lot of info here might be totally wrong. Blame me ;-) + */ + +static int old_belkin_open(struct sir_dev *dev); +static int old_belkin_close(struct sir_dev *dev); +static int old_belkin_change_speed(struct sir_dev *dev, unsigned speed); +static int old_belkin_reset(struct sir_dev *dev); + +static struct dongle_driver old_belkin = { + .owner = THIS_MODULE, + .driver_name = "Old Belkin SmartBeam", + .type = IRDA_OLD_BELKIN_DONGLE, + .open = old_belkin_open, + .close = old_belkin_close, + .reset = old_belkin_reset, + .set_speed = old_belkin_change_speed, +}; + +static int __init old_belkin_sir_init(void) +{ + return irda_register_dongle(&old_belkin); +} + +static void __exit old_belkin_sir_cleanup(void) +{ + irda_unregister_dongle(&old_belkin); +} + +static int old_belkin_open(struct sir_dev *dev) +{ + struct qos_info *qos = &dev->qos; + + /* Power on dongle */ + sirdev_set_dtr_rts(dev, TRUE, TRUE); + + /* Not too fast, please... */ + qos->baud_rate.bits &= IR_9600; + /* Needs at least 10 ms (totally wild guess, can do probably better) */ + qos->min_turn_time.bits = 0x01; + irda_qos_bits_to_value(qos); + + /* irda thread waits 50 msec for power settling */ + + return 0; +} + +static int old_belkin_close(struct sir_dev *dev) +{ + /* Power off dongle */ + sirdev_set_dtr_rts(dev, FALSE, FALSE); + + return 0; +} + +/* + * Function old_belkin_change_speed (task) + * + * With only one speed available, not much to do... + */ +static int old_belkin_change_speed(struct sir_dev *dev, unsigned speed) +{ + dev->speed = 9600; + return (speed==dev->speed) ? 0 : -EINVAL; +} + +/* + * Function old_belkin_reset (task) + * + * Reset the Old-Belkin type dongle. + * + */ +static int old_belkin_reset(struct sir_dev *dev) +{ + /* This dongles speed "defaults" to 9600 bps ;-) */ + dev->speed = 9600; + + return 0; +} + +MODULE_AUTHOR("Jean Tourrilhes <jt@hpl.hp.com>"); +MODULE_DESCRIPTION("Belkin (old) SmartBeam dongle driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("irda-dongle-7"); /* IRDA_OLD_BELKIN_DONGLE */ + +module_init(old_belkin_sir_init); +module_exit(old_belkin_sir_cleanup); diff --git a/drivers/staging/irda/drivers/pxaficp_ir.c b/drivers/staging/irda/drivers/pxaficp_ir.c new file mode 100644 index 000000000000..1dba16bc7f8d --- /dev/null +++ b/drivers/staging/irda/drivers/pxaficp_ir.c @@ -0,0 +1,1076 @@ +/* + * linux/drivers/net/irda/pxaficp_ir.c + * + * Based on sa1100_ir.c by Russell King + * + * Changes copyright (C) 2003-2005 MontaVista Software, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Infra-red driver (SIR/FIR) for the PXA2xx embedded microprocessor + * + */ +#include <linux/dma-mapping.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/dmaengine.h> +#include <linux/dma-mapping.h> +#include <linux/dma/pxa-dma.h> +#include <linux/gpio.h> +#include <linux/slab.h> +#include <linux/sched/clock.h> + +#include <net/irda/irda.h> +#include <net/irda/irmod.h> +#include <net/irda/wrapper.h> +#include <net/irda/irda_device.h> + +#include <linux/platform_data/irda-pxaficp.h> +#undef __REG +#define __REG(x) ((x) & 0xffff) +#include <mach/regs-uart.h> + +#define ICCR0 0x0000 /* ICP Control Register 0 */ +#define ICCR1 0x0004 /* ICP Control Register 1 */ +#define ICCR2 0x0008 /* ICP Control Register 2 */ +#define ICDR 0x000c /* ICP Data Register */ +#define ICSR0 0x0014 /* ICP Status Register 0 */ +#define ICSR1 0x0018 /* ICP Status Register 1 */ + +#define ICCR0_AME (1 << 7) /* Address match enable */ +#define ICCR0_TIE (1 << 6) /* Transmit FIFO interrupt enable */ +#define ICCR0_RIE (1 << 5) /* Receive FIFO interrupt enable */ +#define ICCR0_RXE (1 << 4) /* Receive enable */ +#define ICCR0_TXE (1 << 3) /* Transmit enable */ +#define ICCR0_TUS (1 << 2) /* Transmit FIFO underrun select */ +#define ICCR0_LBM (1 << 1) /* Loopback mode */ +#define ICCR0_ITR (1 << 0) /* IrDA transmission */ + +#define ICCR2_RXP (1 << 3) /* Receive Pin Polarity select */ +#define ICCR2_TXP (1 << 2) /* Transmit Pin Polarity select */ +#define ICCR2_TRIG (3 << 0) /* Receive FIFO Trigger threshold */ +#define ICCR2_TRIG_8 (0 << 0) /* >= 8 bytes */ +#define ICCR2_TRIG_16 (1 << 0) /* >= 16 bytes */ +#define ICCR2_TRIG_32 (2 << 0) /* >= 32 bytes */ + +#define ICSR0_EOC (1 << 6) /* DMA End of Descriptor Chain */ +#define ICSR0_FRE (1 << 5) /* Framing error */ +#define ICSR0_RFS (1 << 4) /* Receive FIFO service request */ +#define ICSR0_TFS (1 << 3) /* Transnit FIFO service request */ +#define ICSR0_RAB (1 << 2) /* Receiver abort */ +#define ICSR0_TUR (1 << 1) /* Trunsmit FIFO underun */ +#define ICSR0_EIF (1 << 0) /* End/Error in FIFO */ + +#define ICSR1_ROR (1 << 6) /* Receiver FIFO underrun */ +#define ICSR1_CRE (1 << 5) /* CRC error */ +#define ICSR1_EOF (1 << 4) /* End of frame */ +#define ICSR1_TNF (1 << 3) /* Transmit FIFO not full */ +#define ICSR1_RNE (1 << 2) /* Receive FIFO not empty */ +#define ICSR1_TBY (1 << 1) /* Tramsmiter busy flag */ +#define ICSR1_RSY (1 << 0) /* Recevier synchronized flag */ + +#define IrSR_RXPL_NEG_IS_ZERO (1<<4) +#define IrSR_RXPL_POS_IS_ZERO 0x0 +#define IrSR_TXPL_NEG_IS_ZERO (1<<3) +#define IrSR_TXPL_POS_IS_ZERO 0x0 +#define IrSR_XMODE_PULSE_1_6 (1<<2) +#define IrSR_XMODE_PULSE_3_16 0x0 +#define IrSR_RCVEIR_IR_MODE (1<<1) +#define IrSR_RCVEIR_UART_MODE 0x0 +#define IrSR_XMITIR_IR_MODE (1<<0) +#define IrSR_XMITIR_UART_MODE 0x0 + +#define IrSR_IR_RECEIVE_ON (\ + IrSR_RXPL_NEG_IS_ZERO | \ + IrSR_TXPL_POS_IS_ZERO | \ + IrSR_XMODE_PULSE_3_16 | \ + IrSR_RCVEIR_IR_MODE | \ + IrSR_XMITIR_UART_MODE) + +#define IrSR_IR_TRANSMIT_ON (\ + IrSR_RXPL_NEG_IS_ZERO | \ + IrSR_TXPL_POS_IS_ZERO | \ + IrSR_XMODE_PULSE_3_16 | \ + IrSR_RCVEIR_UART_MODE | \ + IrSR_XMITIR_IR_MODE) + +/* macros for registers read/write */ +#define ficp_writel(irda, val, off) \ + do { \ + dev_vdbg(irda->dev, \ + "%s():%d ficp_writel(0x%x, %s)\n", \ + __func__, __LINE__, (val), #off); \ + writel_relaxed((val), (irda)->irda_base + (off)); \ + } while (0) + +#define ficp_readl(irda, off) \ + ({ \ + unsigned int _v; \ + _v = readl_relaxed((irda)->irda_base + (off)); \ + dev_vdbg(irda->dev, \ + "%s():%d ficp_readl(%s): 0x%x\n", \ + __func__, __LINE__, #off, _v); \ + _v; \ + }) + +#define stuart_writel(irda, val, off) \ + do { \ + dev_vdbg(irda->dev, \ + "%s():%d stuart_writel(0x%x, %s)\n", \ + __func__, __LINE__, (val), #off); \ + writel_relaxed((val), (irda)->stuart_base + (off)); \ + } while (0) + +#define stuart_readl(irda, off) \ + ({ \ + unsigned int _v; \ + _v = readl_relaxed((irda)->stuart_base + (off)); \ + dev_vdbg(irda->dev, \ + "%s():%d stuart_readl(%s): 0x%x\n", \ + __func__, __LINE__, #off, _v); \ + _v; \ + }) + +struct pxa_irda { + int speed; + int newspeed; + unsigned long long last_clk; + + void __iomem *stuart_base; + void __iomem *irda_base; + unsigned char *dma_rx_buff; + unsigned char *dma_tx_buff; + dma_addr_t dma_rx_buff_phy; + dma_addr_t dma_tx_buff_phy; + unsigned int dma_tx_buff_len; + struct dma_chan *txdma; + struct dma_chan *rxdma; + dma_cookie_t rx_cookie; + dma_cookie_t tx_cookie; + int drcmr_rx; + int drcmr_tx; + + int uart_irq; + int icp_irq; + + struct irlap_cb *irlap; + struct qos_info qos; + + iobuff_t tx_buff; + iobuff_t rx_buff; + + struct device *dev; + struct pxaficp_platform_data *pdata; + struct clk *fir_clk; + struct clk *sir_clk; + struct clk *cur_clk; +}; + +static int pxa_irda_set_speed(struct pxa_irda *si, int speed); + +static inline void pxa_irda_disable_clk(struct pxa_irda *si) +{ + if (si->cur_clk) + clk_disable_unprepare(si->cur_clk); + si->cur_clk = NULL; +} + +static inline void pxa_irda_enable_firclk(struct pxa_irda *si) +{ + si->cur_clk = si->fir_clk; + clk_prepare_enable(si->fir_clk); +} + +static inline void pxa_irda_enable_sirclk(struct pxa_irda *si) +{ + si->cur_clk = si->sir_clk; + clk_prepare_enable(si->sir_clk); +} + + +#define IS_FIR(si) ((si)->speed >= 4000000) +#define IRDA_FRAME_SIZE_LIMIT 2047 + +static void pxa_irda_fir_dma_rx_irq(void *data); +static void pxa_irda_fir_dma_tx_irq(void *data); + +inline static void pxa_irda_fir_dma_rx_start(struct pxa_irda *si) +{ + struct dma_async_tx_descriptor *tx; + + tx = dmaengine_prep_slave_single(si->rxdma, si->dma_rx_buff_phy, + IRDA_FRAME_SIZE_LIMIT, DMA_FROM_DEVICE, + DMA_PREP_INTERRUPT); + if (!tx) { + dev_err(si->dev, "prep_slave_sg() failed\n"); + return; + } + tx->callback = pxa_irda_fir_dma_rx_irq; + tx->callback_param = si; + si->rx_cookie = dmaengine_submit(tx); + dma_async_issue_pending(si->rxdma); +} + +inline static void pxa_irda_fir_dma_tx_start(struct pxa_irda *si) +{ + struct dma_async_tx_descriptor *tx; + + tx = dmaengine_prep_slave_single(si->txdma, si->dma_tx_buff_phy, + si->dma_tx_buff_len, DMA_TO_DEVICE, + DMA_PREP_INTERRUPT); + if (!tx) { + dev_err(si->dev, "prep_slave_sg() failed\n"); + return; + } + tx->callback = pxa_irda_fir_dma_tx_irq; + tx->callback_param = si; + si->tx_cookie = dmaengine_submit(tx); + dma_async_issue_pending(si->rxdma); +} + +/* + * Set the IrDA communications mode. + */ +static void pxa_irda_set_mode(struct pxa_irda *si, int mode) +{ + if (si->pdata->transceiver_mode) + si->pdata->transceiver_mode(si->dev, mode); + else { + if (gpio_is_valid(si->pdata->gpio_pwdown)) + gpio_set_value(si->pdata->gpio_pwdown, + !(mode & IR_OFF) ^ + !si->pdata->gpio_pwdown_inverted); + pxa2xx_transceiver_mode(si->dev, mode); + } +} + +/* + * Set the IrDA communications speed. + */ +static int pxa_irda_set_speed(struct pxa_irda *si, int speed) +{ + unsigned long flags; + unsigned int divisor; + + switch (speed) { + case 9600: case 19200: case 38400: + case 57600: case 115200: + + /* refer to PXA250/210 Developer's Manual 10-7 */ + /* BaudRate = 14.7456 MHz / (16*Divisor) */ + divisor = 14745600 / (16 * speed); + + local_irq_save(flags); + + if (IS_FIR(si)) { + /* stop RX DMA */ + dmaengine_terminate_all(si->rxdma); + /* disable FICP */ + ficp_writel(si, 0, ICCR0); + pxa_irda_disable_clk(si); + + /* set board transceiver to SIR mode */ + pxa_irda_set_mode(si, IR_SIRMODE); + + /* enable the STUART clock */ + pxa_irda_enable_sirclk(si); + } + + /* disable STUART first */ + stuart_writel(si, 0, STIER); + + /* access DLL & DLH */ + stuart_writel(si, stuart_readl(si, STLCR) | LCR_DLAB, STLCR); + stuart_writel(si, divisor & 0xff, STDLL); + stuart_writel(si, divisor >> 8, STDLH); + stuart_writel(si, stuart_readl(si, STLCR) & ~LCR_DLAB, STLCR); + + si->speed = speed; + stuart_writel(si, IrSR_IR_RECEIVE_ON | IrSR_XMODE_PULSE_1_6, + STISR); + stuart_writel(si, IER_UUE | IER_RLSE | IER_RAVIE | IER_RTIOE, + STIER); + + local_irq_restore(flags); + break; + + case 4000000: + local_irq_save(flags); + + /* disable STUART */ + stuart_writel(si, 0, STIER); + stuart_writel(si, 0, STISR); + pxa_irda_disable_clk(si); + + /* disable FICP first */ + ficp_writel(si, 0, ICCR0); + + /* set board transceiver to FIR mode */ + pxa_irda_set_mode(si, IR_FIRMODE); + + /* enable the FICP clock */ + pxa_irda_enable_firclk(si); + + si->speed = speed; + pxa_irda_fir_dma_rx_start(si); + ficp_writel(si, ICCR0_ITR | ICCR0_RXE, ICCR0); + + local_irq_restore(flags); + break; + + default: + return -EINVAL; + } + + return 0; +} + +/* SIR interrupt service routine. */ +static irqreturn_t pxa_irda_sir_irq(int irq, void *dev_id) +{ + struct net_device *dev = dev_id; + struct pxa_irda *si = netdev_priv(dev); + int iir, lsr, data; + + iir = stuart_readl(si, STIIR); + + switch (iir & 0x0F) { + case 0x06: /* Receiver Line Status */ + lsr = stuart_readl(si, STLSR); + while (lsr & LSR_FIFOE) { + data = stuart_readl(si, STRBR); + if (lsr & (LSR_OE | LSR_PE | LSR_FE | LSR_BI)) { + printk(KERN_DEBUG "pxa_ir: sir receiving error\n"); + dev->stats.rx_errors++; + if (lsr & LSR_FE) + dev->stats.rx_frame_errors++; + if (lsr & LSR_OE) + dev->stats.rx_fifo_errors++; + } else { + dev->stats.rx_bytes++; + async_unwrap_char(dev, &dev->stats, + &si->rx_buff, data); + } + lsr = stuart_readl(si, STLSR); + } + si->last_clk = sched_clock(); + break; + + case 0x04: /* Received Data Available */ + /* forth through */ + + case 0x0C: /* Character Timeout Indication */ + do { + dev->stats.rx_bytes++; + async_unwrap_char(dev, &dev->stats, &si->rx_buff, + stuart_readl(si, STRBR)); + } while (stuart_readl(si, STLSR) & LSR_DR); + si->last_clk = sched_clock(); + break; + + case 0x02: /* Transmit FIFO Data Request */ + while ((si->tx_buff.len) && + (stuart_readl(si, STLSR) & LSR_TDRQ)) { + stuart_writel(si, *si->tx_buff.data++, STTHR); + si->tx_buff.len -= 1; + } + + if (si->tx_buff.len == 0) { + dev->stats.tx_packets++; + dev->stats.tx_bytes += si->tx_buff.data - si->tx_buff.head; + + /* We need to ensure that the transmitter has finished. */ + while ((stuart_readl(si, STLSR) & LSR_TEMT) == 0) + cpu_relax(); + si->last_clk = sched_clock(); + + /* + * Ok, we've finished transmitting. Now enable + * the receiver. Sometimes we get a receive IRQ + * immediately after a transmit... + */ + if (si->newspeed) { + pxa_irda_set_speed(si, si->newspeed); + si->newspeed = 0; + } else { + /* enable IR Receiver, disable IR Transmitter */ + stuart_writel(si, IrSR_IR_RECEIVE_ON | + IrSR_XMODE_PULSE_1_6, STISR); + /* enable STUART and receive interrupts */ + stuart_writel(si, IER_UUE | IER_RLSE | + IER_RAVIE | IER_RTIOE, STIER); + } + /* I'm hungry! */ + netif_wake_queue(dev); + } + break; + } + + return IRQ_HANDLED; +} + +/* FIR Receive DMA interrupt handler */ +static void pxa_irda_fir_dma_rx_irq(void *data) +{ + struct net_device *dev = data; + struct pxa_irda *si = netdev_priv(dev); + + dmaengine_terminate_all(si->rxdma); + netdev_dbg(dev, "pxa_ir: fir rx dma bus error\n"); +} + +/* FIR Transmit DMA interrupt handler */ +static void pxa_irda_fir_dma_tx_irq(void *data) +{ + struct net_device *dev = data; + struct pxa_irda *si = netdev_priv(dev); + + dmaengine_terminate_all(si->txdma); + if (dmaengine_tx_status(si->txdma, si->tx_cookie, NULL) == DMA_ERROR) { + dev->stats.tx_errors++; + } else { + dev->stats.tx_packets++; + dev->stats.tx_bytes += si->dma_tx_buff_len; + } + + while (ficp_readl(si, ICSR1) & ICSR1_TBY) + cpu_relax(); + si->last_clk = sched_clock(); + + /* + * HACK: It looks like the TBY bit is dropped too soon. + * Without this delay things break. + */ + udelay(120); + + if (si->newspeed) { + pxa_irda_set_speed(si, si->newspeed); + si->newspeed = 0; + } else { + int i = 64; + + ficp_writel(si, 0, ICCR0); + pxa_irda_fir_dma_rx_start(si); + while ((ficp_readl(si, ICSR1) & ICSR1_RNE) && i--) + ficp_readl(si, ICDR); + ficp_writel(si, ICCR0_ITR | ICCR0_RXE, ICCR0); + + if (i < 0) + printk(KERN_ERR "pxa_ir: cannot clear Rx FIFO!\n"); + } + netif_wake_queue(dev); +} + +/* EIF(Error in FIFO/End in Frame) handler for FIR */ +static void pxa_irda_fir_irq_eif(struct pxa_irda *si, struct net_device *dev, int icsr0) +{ + unsigned int len, stat, data; + struct dma_tx_state state; + + /* Get the current data position. */ + + dmaengine_tx_status(si->rxdma, si->rx_cookie, &state); + len = IRDA_FRAME_SIZE_LIMIT - state.residue; + + do { + /* Read Status, and then Data. */ + stat = ficp_readl(si, ICSR1); + rmb(); + data = ficp_readl(si, ICDR); + + if (stat & (ICSR1_CRE | ICSR1_ROR)) { + dev->stats.rx_errors++; + if (stat & ICSR1_CRE) { + printk(KERN_DEBUG "pxa_ir: fir receive CRC error\n"); + dev->stats.rx_crc_errors++; + } + if (stat & ICSR1_ROR) { + printk(KERN_DEBUG "pxa_ir: fir receive overrun\n"); + dev->stats.rx_over_errors++; + } + } else { + si->dma_rx_buff[len++] = data; + } + /* If we hit the end of frame, there's no point in continuing. */ + if (stat & ICSR1_EOF) + break; + } while (ficp_readl(si, ICSR0) & ICSR0_EIF); + + if (stat & ICSR1_EOF) { + /* end of frame. */ + struct sk_buff *skb; + + if (icsr0 & ICSR0_FRE) { + printk(KERN_ERR "pxa_ir: dropping erroneous frame\n"); + dev->stats.rx_dropped++; + return; + } + + skb = alloc_skb(len+1,GFP_ATOMIC); + if (!skb) { + printk(KERN_ERR "pxa_ir: fir out of memory for receive skb\n"); + dev->stats.rx_dropped++; + return; + } + + /* Align IP header to 20 bytes */ + skb_reserve(skb, 1); + skb_copy_to_linear_data(skb, si->dma_rx_buff, len); + skb_put(skb, len); + + /* Feed it to IrLAP */ + skb->dev = dev; + skb_reset_mac_header(skb); + skb->protocol = htons(ETH_P_IRDA); + netif_rx(skb); + + dev->stats.rx_packets++; + dev->stats.rx_bytes += len; + } +} + +/* FIR interrupt handler */ +static irqreturn_t pxa_irda_fir_irq(int irq, void *dev_id) +{ + struct net_device *dev = dev_id; + struct pxa_irda *si = netdev_priv(dev); + int icsr0, i = 64; + + /* stop RX DMA */ + dmaengine_terminate_all(si->rxdma); + si->last_clk = sched_clock(); + icsr0 = ficp_readl(si, ICSR0); + + if (icsr0 & (ICSR0_FRE | ICSR0_RAB)) { + if (icsr0 & ICSR0_FRE) { + printk(KERN_DEBUG "pxa_ir: fir receive frame error\n"); + dev->stats.rx_frame_errors++; + } else { + printk(KERN_DEBUG "pxa_ir: fir receive abort\n"); + dev->stats.rx_errors++; + } + ficp_writel(si, icsr0 & (ICSR0_FRE | ICSR0_RAB), ICSR0); + } + + if (icsr0 & ICSR0_EIF) { + /* An error in FIFO occurred, or there is a end of frame */ + pxa_irda_fir_irq_eif(si, dev, icsr0); + } + + ficp_writel(si, 0, ICCR0); + pxa_irda_fir_dma_rx_start(si); + while ((ficp_readl(si, ICSR1) & ICSR1_RNE) && i--) + ficp_readl(si, ICDR); + ficp_writel(si, ICCR0_ITR | ICCR0_RXE, ICCR0); + + if (i < 0) + printk(KERN_ERR "pxa_ir: cannot clear Rx FIFO!\n"); + + return IRQ_HANDLED; +} + +/* hard_xmit interface of irda device */ +static int pxa_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct pxa_irda *si = netdev_priv(dev); + int speed = irda_get_next_speed(skb); + + /* + * Does this packet contain a request to change the interface + * speed? If so, remember it until we complete the transmission + * of this frame. + */ + if (speed != si->speed && speed != -1) + si->newspeed = speed; + + /* + * If this is an empty frame, we can bypass a lot. + */ + if (skb->len == 0) { + if (si->newspeed) { + si->newspeed = 0; + pxa_irda_set_speed(si, speed); + } + dev_kfree_skb(skb); + return NETDEV_TX_OK; + } + + netif_stop_queue(dev); + + if (!IS_FIR(si)) { + si->tx_buff.data = si->tx_buff.head; + si->tx_buff.len = async_wrap_skb(skb, si->tx_buff.data, si->tx_buff.truesize); + + /* Disable STUART interrupts and switch to transmit mode. */ + stuart_writel(si, 0, STIER); + stuart_writel(si, IrSR_IR_TRANSMIT_ON | IrSR_XMODE_PULSE_1_6, + STISR); + + /* enable STUART and transmit interrupts */ + stuart_writel(si, IER_UUE | IER_TIE, STIER); + } else { + unsigned long mtt = irda_get_mtt(skb); + + si->dma_tx_buff_len = skb->len; + skb_copy_from_linear_data(skb, si->dma_tx_buff, skb->len); + + if (mtt) + while ((sched_clock() - si->last_clk) * 1000 < mtt) + cpu_relax(); + + /* stop RX DMA, disable FICP */ + dmaengine_terminate_all(si->rxdma); + ficp_writel(si, 0, ICCR0); + + pxa_irda_fir_dma_tx_start(si); + ficp_writel(si, ICCR0_ITR | ICCR0_TXE, ICCR0); + } + + dev_kfree_skb(skb); + return NETDEV_TX_OK; +} + +static int pxa_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd) +{ + struct if_irda_req *rq = (struct if_irda_req *)ifreq; + struct pxa_irda *si = netdev_priv(dev); + int ret; + + switch (cmd) { + case SIOCSBANDWIDTH: + ret = -EPERM; + if (capable(CAP_NET_ADMIN)) { + /* + * We are unable to set the speed if the + * device is not running. + */ + if (netif_running(dev)) { + ret = pxa_irda_set_speed(si, + rq->ifr_baudrate); + } else { + printk(KERN_INFO "pxa_ir: SIOCSBANDWIDTH: !netif_running\n"); + ret = 0; + } + } + break; + + case SIOCSMEDIABUSY: + ret = -EPERM; + if (capable(CAP_NET_ADMIN)) { + irda_device_set_media_busy(dev, TRUE); + ret = 0; + } + break; + + case SIOCGRECEIVING: + ret = 0; + rq->ifr_receiving = IS_FIR(si) ? 0 + : si->rx_buff.state != OUTSIDE_FRAME; + break; + + default: + ret = -EOPNOTSUPP; + break; + } + + return ret; +} + +static void pxa_irda_startup(struct pxa_irda *si) +{ + /* Disable STUART interrupts */ + stuart_writel(si, 0, STIER); + /* enable STUART interrupt to the processor */ + stuart_writel(si, MCR_OUT2, STMCR); + /* configure SIR frame format: StartBit - Data 7 ... Data 0 - Stop Bit */ + stuart_writel(si, LCR_WLS0 | LCR_WLS1, STLCR); + /* enable FIFO, we use FIFO to improve performance */ + stuart_writel(si, FCR_TRFIFOE | FCR_ITL_32, STFCR); + + /* disable FICP */ + ficp_writel(si, 0, ICCR0); + /* configure FICP ICCR2 */ + ficp_writel(si, ICCR2_TXP | ICCR2_TRIG_32, ICCR2); + + /* force SIR reinitialization */ + si->speed = 4000000; + pxa_irda_set_speed(si, 9600); + + printk(KERN_DEBUG "pxa_ir: irda startup\n"); +} + +static void pxa_irda_shutdown(struct pxa_irda *si) +{ + unsigned long flags; + + local_irq_save(flags); + + /* disable STUART and interrupt */ + stuart_writel(si, 0, STIER); + /* disable STUART SIR mode */ + stuart_writel(si, 0, STISR); + + /* disable DMA */ + dmaengine_terminate_all(si->rxdma); + dmaengine_terminate_all(si->txdma); + /* disable FICP */ + ficp_writel(si, 0, ICCR0); + + /* disable the STUART or FICP clocks */ + pxa_irda_disable_clk(si); + + local_irq_restore(flags); + + /* power off board transceiver */ + pxa_irda_set_mode(si, IR_OFF); + + printk(KERN_DEBUG "pxa_ir: irda shutdown\n"); +} + +static int pxa_irda_start(struct net_device *dev) +{ + struct pxa_irda *si = netdev_priv(dev); + dma_cap_mask_t mask; + struct dma_slave_config config; + struct pxad_param param; + int err; + + si->speed = 9600; + + err = request_irq(si->uart_irq, pxa_irda_sir_irq, 0, dev->name, dev); + if (err) + goto err_irq1; + + err = request_irq(si->icp_irq, pxa_irda_fir_irq, 0, dev->name, dev); + if (err) + goto err_irq2; + + /* + * The interrupt must remain disabled for now. + */ + disable_irq(si->uart_irq); + disable_irq(si->icp_irq); + + err = -EBUSY; + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + param.prio = PXAD_PRIO_LOWEST; + + memset(&config, 0, sizeof(config)); + config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + config.src_addr = (dma_addr_t)si->irda_base + ICDR; + config.dst_addr = (dma_addr_t)si->irda_base + ICDR; + config.src_maxburst = 32; + config.dst_maxburst = 32; + + param.drcmr = si->drcmr_rx; + si->rxdma = dma_request_slave_channel_compat(mask, pxad_filter_fn, + ¶m, &dev->dev, "rx"); + if (!si->rxdma) + goto err_rx_dma; + + param.drcmr = si->drcmr_tx; + si->txdma = dma_request_slave_channel_compat(mask, pxad_filter_fn, + ¶m, &dev->dev, "tx"); + if (!si->txdma) + goto err_tx_dma; + + err = dmaengine_slave_config(si->rxdma, &config); + if (err) + goto err_dma_rx_buff; + err = dmaengine_slave_config(si->txdma, &config); + if (err) + goto err_dma_rx_buff; + + err = -ENOMEM; + si->dma_rx_buff = dma_alloc_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT, + &si->dma_rx_buff_phy, GFP_KERNEL); + if (!si->dma_rx_buff) + goto err_dma_rx_buff; + + si->dma_tx_buff = dma_alloc_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT, + &si->dma_tx_buff_phy, GFP_KERNEL); + if (!si->dma_tx_buff) + goto err_dma_tx_buff; + + /* Setup the serial port for the initial speed. */ + pxa_irda_startup(si); + + /* + * Open a new IrLAP layer instance. + */ + si->irlap = irlap_open(dev, &si->qos, "pxa"); + err = -ENOMEM; + if (!si->irlap) + goto err_irlap; + + /* + * Now enable the interrupt and start the queue + */ + enable_irq(si->uart_irq); + enable_irq(si->icp_irq); + netif_start_queue(dev); + + printk(KERN_DEBUG "pxa_ir: irda driver opened\n"); + + return 0; + +err_irlap: + pxa_irda_shutdown(si); + dma_free_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT, si->dma_tx_buff, si->dma_tx_buff_phy); +err_dma_tx_buff: + dma_free_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT, si->dma_rx_buff, si->dma_rx_buff_phy); +err_dma_rx_buff: + dma_release_channel(si->txdma); +err_tx_dma: + dma_release_channel(si->rxdma); +err_rx_dma: + free_irq(si->icp_irq, dev); +err_irq2: + free_irq(si->uart_irq, dev); +err_irq1: + + return err; +} + +static int pxa_irda_stop(struct net_device *dev) +{ + struct pxa_irda *si = netdev_priv(dev); + + netif_stop_queue(dev); + + pxa_irda_shutdown(si); + + /* Stop IrLAP */ + if (si->irlap) { + irlap_close(si->irlap); + si->irlap = NULL; + } + + free_irq(si->uart_irq, dev); + free_irq(si->icp_irq, dev); + + dmaengine_terminate_all(si->rxdma); + dmaengine_terminate_all(si->txdma); + dma_release_channel(si->rxdma); + dma_release_channel(si->txdma); + + if (si->dma_rx_buff) + dma_free_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT, si->dma_tx_buff, si->dma_tx_buff_phy); + if (si->dma_tx_buff) + dma_free_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT, si->dma_rx_buff, si->dma_rx_buff_phy); + + printk(KERN_DEBUG "pxa_ir: irda driver closed\n"); + return 0; +} + +static int pxa_irda_suspend(struct platform_device *_dev, pm_message_t state) +{ + struct net_device *dev = platform_get_drvdata(_dev); + struct pxa_irda *si; + + if (dev && netif_running(dev)) { + si = netdev_priv(dev); + netif_device_detach(dev); + pxa_irda_shutdown(si); + } + + return 0; +} + +static int pxa_irda_resume(struct platform_device *_dev) +{ + struct net_device *dev = platform_get_drvdata(_dev); + struct pxa_irda *si; + + if (dev && netif_running(dev)) { + si = netdev_priv(dev); + pxa_irda_startup(si); + netif_device_attach(dev); + netif_wake_queue(dev); + } + + return 0; +} + + +static int pxa_irda_init_iobuf(iobuff_t *io, int size) +{ + io->head = kmalloc(size, GFP_KERNEL | GFP_DMA); + if (io->head != NULL) { + io->truesize = size; + io->in_frame = FALSE; + io->state = OUTSIDE_FRAME; + io->data = io->head; + } + return io->head ? 0 : -ENOMEM; +} + +static const struct net_device_ops pxa_irda_netdev_ops = { + .ndo_open = pxa_irda_start, + .ndo_stop = pxa_irda_stop, + .ndo_start_xmit = pxa_irda_hard_xmit, + .ndo_do_ioctl = pxa_irda_ioctl, +}; + +static int pxa_irda_probe(struct platform_device *pdev) +{ + struct net_device *dev; + struct resource *res; + struct pxa_irda *si; + void __iomem *ficp, *stuart; + unsigned int baudrate_mask; + int err; + + if (!pdev->dev.platform_data) + return -ENODEV; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + ficp = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(ficp)) { + dev_err(&pdev->dev, "resource ficp not defined\n"); + return PTR_ERR(ficp); + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + stuart = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(stuart)) { + dev_err(&pdev->dev, "resource stuart not defined\n"); + return PTR_ERR(stuart); + } + + dev = alloc_irdadev(sizeof(struct pxa_irda)); + if (!dev) { + err = -ENOMEM; + goto err_mem_1; + } + + SET_NETDEV_DEV(dev, &pdev->dev); + si = netdev_priv(dev); + si->dev = &pdev->dev; + si->pdata = pdev->dev.platform_data; + + si->irda_base = ficp; + si->stuart_base = stuart; + si->uart_irq = platform_get_irq(pdev, 0); + si->icp_irq = platform_get_irq(pdev, 1); + + si->sir_clk = devm_clk_get(&pdev->dev, "UARTCLK"); + si->fir_clk = devm_clk_get(&pdev->dev, "FICPCLK"); + if (IS_ERR(si->sir_clk) || IS_ERR(si->fir_clk)) { + err = PTR_ERR(IS_ERR(si->sir_clk) ? si->sir_clk : si->fir_clk); + goto err_mem_4; + } + + res = platform_get_resource(pdev, IORESOURCE_DMA, 0); + if (res) + si->drcmr_rx = res->start; + res = platform_get_resource(pdev, IORESOURCE_DMA, 1); + if (res) + si->drcmr_tx = res->start; + + /* + * Initialise the SIR buffers + */ + err = pxa_irda_init_iobuf(&si->rx_buff, 14384); + if (err) + goto err_mem_4; + err = pxa_irda_init_iobuf(&si->tx_buff, 4000); + if (err) + goto err_mem_5; + + if (gpio_is_valid(si->pdata->gpio_pwdown)) { + err = gpio_request(si->pdata->gpio_pwdown, "IrDA switch"); + if (err) + goto err_startup; + err = gpio_direction_output(si->pdata->gpio_pwdown, + !si->pdata->gpio_pwdown_inverted); + if (err) { + gpio_free(si->pdata->gpio_pwdown); + goto err_startup; + } + } + + if (si->pdata->startup) { + err = si->pdata->startup(si->dev); + if (err) + goto err_startup; + } + + if (gpio_is_valid(si->pdata->gpio_pwdown) && si->pdata->startup) + dev_warn(si->dev, "gpio_pwdown and startup() both defined!\n"); + + dev->netdev_ops = &pxa_irda_netdev_ops; + + irda_init_max_qos_capabilies(&si->qos); + + baudrate_mask = 0; + if (si->pdata->transceiver_cap & IR_SIRMODE) + baudrate_mask |= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200; + if (si->pdata->transceiver_cap & IR_FIRMODE) + baudrate_mask |= IR_4000000 << 8; + + si->qos.baud_rate.bits &= baudrate_mask; + si->qos.min_turn_time.bits = 7; /* 1ms or more */ + + irda_qos_bits_to_value(&si->qos); + + err = register_netdev(dev); + + if (err == 0) + platform_set_drvdata(pdev, dev); + + if (err) { + if (si->pdata->shutdown) + si->pdata->shutdown(si->dev); +err_startup: + kfree(si->tx_buff.head); +err_mem_5: + kfree(si->rx_buff.head); +err_mem_4: + free_netdev(dev); + } +err_mem_1: + return err; +} + +static int pxa_irda_remove(struct platform_device *_dev) +{ + struct net_device *dev = platform_get_drvdata(_dev); + + if (dev) { + struct pxa_irda *si = netdev_priv(dev); + unregister_netdev(dev); + if (gpio_is_valid(si->pdata->gpio_pwdown)) + gpio_free(si->pdata->gpio_pwdown); + if (si->pdata->shutdown) + si->pdata->shutdown(si->dev); + kfree(si->tx_buff.head); + kfree(si->rx_buff.head); + free_netdev(dev); + } + + return 0; +} + +static struct platform_driver pxa_ir_driver = { + .driver = { + .name = "pxa2xx-ir", + }, + .probe = pxa_irda_probe, + .remove = pxa_irda_remove, + .suspend = pxa_irda_suspend, + .resume = pxa_irda_resume, +}; + +module_platform_driver(pxa_ir_driver); + +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:pxa2xx-ir"); diff --git a/drivers/staging/irda/drivers/sa1100_ir.c b/drivers/staging/irda/drivers/sa1100_ir.c new file mode 100644 index 000000000000..b6e44ff4e373 --- /dev/null +++ b/drivers/staging/irda/drivers/sa1100_ir.c @@ -0,0 +1,1150 @@ +/* + * linux/drivers/net/irda/sa1100_ir.c + * + * Copyright (C) 2000-2001 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Infra-red driver for the StrongARM SA1100 embedded microprocessor + * + * Note that we don't have to worry about the SA1111's DMA bugs in here, + * so we use the straight forward dma_map_* functions with a null pointer. + * + * This driver takes one kernel command line parameter, sa1100ir=, with + * the following options: + * max_rate:baudrate - set the maximum baud rate + * power_level:level - set the transmitter power level + * tx_lpm:0|1 - set transmit low power mode + */ +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/types.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/netdevice.h> +#include <linux/slab.h> +#include <linux/rtnetlink.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/dma-mapping.h> +#include <linux/dmaengine.h> +#include <linux/sa11x0-dma.h> + +#include <net/irda/irda.h> +#include <net/irda/wrapper.h> +#include <net/irda/irda_device.h> + +#include <mach/hardware.h> +#include <linux/platform_data/irda-sa11x0.h> + +static int power_level = 3; +static int tx_lpm; +static int max_rate = 4000000; + +struct sa1100_buf { + struct device *dev; + struct sk_buff *skb; + struct scatterlist sg; + struct dma_chan *chan; + dma_cookie_t cookie; +}; + +struct sa1100_irda { + unsigned char utcr4; + unsigned char power; + unsigned char open; + + int speed; + int newspeed; + + struct sa1100_buf dma_rx; + struct sa1100_buf dma_tx; + + struct device *dev; + struct irda_platform_data *pdata; + struct irlap_cb *irlap; + struct qos_info qos; + + iobuff_t tx_buff; + iobuff_t rx_buff; + + int (*tx_start)(struct sk_buff *, struct net_device *, struct sa1100_irda *); + irqreturn_t (*irq)(struct net_device *, struct sa1100_irda *); +}; + +static int sa1100_irda_set_speed(struct sa1100_irda *, int); + +#define IS_FIR(si) ((si)->speed >= 4000000) + +#define HPSIR_MAX_RXLEN 2047 + +static struct dma_slave_config sa1100_irda_sir_tx = { + .direction = DMA_TO_DEVICE, + .dst_addr = __PREG(Ser2UTDR), + .dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE, + .dst_maxburst = 4, +}; + +static struct dma_slave_config sa1100_irda_fir_rx = { + .direction = DMA_FROM_DEVICE, + .src_addr = __PREG(Ser2HSDR), + .src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE, + .src_maxburst = 8, +}; + +static struct dma_slave_config sa1100_irda_fir_tx = { + .direction = DMA_TO_DEVICE, + .dst_addr = __PREG(Ser2HSDR), + .dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE, + .dst_maxburst = 8, +}; + +static unsigned sa1100_irda_dma_xferred(struct sa1100_buf *buf) +{ + struct dma_chan *chan = buf->chan; + struct dma_tx_state state; + enum dma_status status; + + status = chan->device->device_tx_status(chan, buf->cookie, &state); + if (status != DMA_PAUSED) + return 0; + + return sg_dma_len(&buf->sg) - state.residue; +} + +static int sa1100_irda_dma_request(struct device *dev, struct sa1100_buf *buf, + const char *name, struct dma_slave_config *cfg) +{ + dma_cap_mask_t m; + int ret; + + dma_cap_zero(m); + dma_cap_set(DMA_SLAVE, m); + + buf->chan = dma_request_channel(m, sa11x0_dma_filter_fn, (void *)name); + if (!buf->chan) { + dev_err(dev, "unable to request DMA channel for %s\n", + name); + return -ENOENT; + } + + ret = dmaengine_slave_config(buf->chan, cfg); + if (ret) + dev_warn(dev, "DMA slave_config for %s returned %d\n", + name, ret); + + buf->dev = buf->chan->device->dev; + + return 0; +} + +static void sa1100_irda_dma_start(struct sa1100_buf *buf, + enum dma_transfer_direction dir, dma_async_tx_callback cb, void *cb_p) +{ + struct dma_async_tx_descriptor *desc; + struct dma_chan *chan = buf->chan; + + desc = dmaengine_prep_slave_sg(chan, &buf->sg, 1, dir, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (desc) { + desc->callback = cb; + desc->callback_param = cb_p; + buf->cookie = dmaengine_submit(desc); + dma_async_issue_pending(chan); + } +} + +/* + * Allocate and map the receive buffer, unless it is already allocated. + */ +static int sa1100_irda_rx_alloc(struct sa1100_irda *si) +{ + if (si->dma_rx.skb) + return 0; + + si->dma_rx.skb = alloc_skb(HPSIR_MAX_RXLEN + 1, GFP_ATOMIC); + if (!si->dma_rx.skb) { + printk(KERN_ERR "sa1100_ir: out of memory for RX SKB\n"); + return -ENOMEM; + } + + /* + * Align any IP headers that may be contained + * within the frame. + */ + skb_reserve(si->dma_rx.skb, 1); + + sg_set_buf(&si->dma_rx.sg, si->dma_rx.skb->data, HPSIR_MAX_RXLEN); + if (dma_map_sg(si->dma_rx.dev, &si->dma_rx.sg, 1, DMA_FROM_DEVICE) == 0) { + dev_kfree_skb_any(si->dma_rx.skb); + return -ENOMEM; + } + + return 0; +} + +/* + * We want to get here as soon as possible, and get the receiver setup. + * We use the existing buffer. + */ +static void sa1100_irda_rx_dma_start(struct sa1100_irda *si) +{ + if (!si->dma_rx.skb) { + printk(KERN_ERR "sa1100_ir: rx buffer went missing\n"); + return; + } + + /* + * First empty receive FIFO + */ + Ser2HSCR0 = HSCR0_HSSP; + + /* + * Enable the DMA, receiver and receive interrupt. + */ + dmaengine_terminate_all(si->dma_rx.chan); + sa1100_irda_dma_start(&si->dma_rx, DMA_DEV_TO_MEM, NULL, NULL); + + Ser2HSCR0 = HSCR0_HSSP | HSCR0_RXE; +} + +static void sa1100_irda_check_speed(struct sa1100_irda *si) +{ + if (si->newspeed) { + sa1100_irda_set_speed(si, si->newspeed); + si->newspeed = 0; + } +} + +/* + * HP-SIR format support. + */ +static void sa1100_irda_sirtxdma_irq(void *id) +{ + struct net_device *dev = id; + struct sa1100_irda *si = netdev_priv(dev); + + dma_unmap_sg(si->dma_tx.dev, &si->dma_tx.sg, 1, DMA_TO_DEVICE); + dev_kfree_skb(si->dma_tx.skb); + si->dma_tx.skb = NULL; + + dev->stats.tx_packets++; + dev->stats.tx_bytes += sg_dma_len(&si->dma_tx.sg); + + /* We need to ensure that the transmitter has finished. */ + do + rmb(); + while (Ser2UTSR1 & UTSR1_TBY); + + /* + * Ok, we've finished transmitting. Now enable the receiver. + * Sometimes we get a receive IRQ immediately after a transmit... + */ + Ser2UTSR0 = UTSR0_REB | UTSR0_RBB | UTSR0_RID; + Ser2UTCR3 = UTCR3_RIE | UTCR3_RXE | UTCR3_TXE; + + sa1100_irda_check_speed(si); + + /* I'm hungry! */ + netif_wake_queue(dev); +} + +static int sa1100_irda_sir_tx_start(struct sk_buff *skb, struct net_device *dev, + struct sa1100_irda *si) +{ + si->tx_buff.data = si->tx_buff.head; + si->tx_buff.len = async_wrap_skb(skb, si->tx_buff.data, + si->tx_buff.truesize); + + si->dma_tx.skb = skb; + sg_set_buf(&si->dma_tx.sg, si->tx_buff.data, si->tx_buff.len); + if (dma_map_sg(si->dma_tx.dev, &si->dma_tx.sg, 1, DMA_TO_DEVICE) == 0) { + si->dma_tx.skb = NULL; + netif_wake_queue(dev); + dev->stats.tx_dropped++; + return NETDEV_TX_OK; + } + + sa1100_irda_dma_start(&si->dma_tx, DMA_MEM_TO_DEV, sa1100_irda_sirtxdma_irq, dev); + + /* + * The mean turn-around time is enforced by XBOF padding, + * so we don't have to do anything special here. + */ + Ser2UTCR3 = UTCR3_TXE; + + return NETDEV_TX_OK; +} + +static irqreturn_t sa1100_irda_sir_irq(struct net_device *dev, struct sa1100_irda *si) +{ + int status; + + status = Ser2UTSR0; + + /* + * Deal with any receive errors first. The bytes in error may be + * the only bytes in the receive FIFO, so we do this first. + */ + while (status & UTSR0_EIF) { + int stat, data; + + stat = Ser2UTSR1; + data = Ser2UTDR; + + if (stat & (UTSR1_FRE | UTSR1_ROR)) { + dev->stats.rx_errors++; + if (stat & UTSR1_FRE) + dev->stats.rx_frame_errors++; + if (stat & UTSR1_ROR) + dev->stats.rx_fifo_errors++; + } else + async_unwrap_char(dev, &dev->stats, &si->rx_buff, data); + + status = Ser2UTSR0; + } + + /* + * We must clear certain bits. + */ + Ser2UTSR0 = status & (UTSR0_RID | UTSR0_RBB | UTSR0_REB); + + if (status & UTSR0_RFS) { + /* + * There are at least 4 bytes in the FIFO. Read 3 bytes + * and leave the rest to the block below. + */ + async_unwrap_char(dev, &dev->stats, &si->rx_buff, Ser2UTDR); + async_unwrap_char(dev, &dev->stats, &si->rx_buff, Ser2UTDR); + async_unwrap_char(dev, &dev->stats, &si->rx_buff, Ser2UTDR); + } + + if (status & (UTSR0_RFS | UTSR0_RID)) { + /* + * Fifo contains more than 1 character. + */ + do { + async_unwrap_char(dev, &dev->stats, &si->rx_buff, + Ser2UTDR); + } while (Ser2UTSR1 & UTSR1_RNE); + + } + + return IRQ_HANDLED; +} + +/* + * FIR format support. + */ +static void sa1100_irda_firtxdma_irq(void *id) +{ + struct net_device *dev = id; + struct sa1100_irda *si = netdev_priv(dev); + struct sk_buff *skb; + + /* + * Wait for the transmission to complete. Unfortunately, + * the hardware doesn't give us an interrupt to indicate + * "end of frame". + */ + do + rmb(); + while (!(Ser2HSSR0 & HSSR0_TUR) || Ser2HSSR1 & HSSR1_TBY); + + /* + * Clear the transmit underrun bit. + */ + Ser2HSSR0 = HSSR0_TUR; + + /* + * Do we need to change speed? Note that we're lazy + * here - we don't free the old dma_rx.skb. We don't need + * to allocate a buffer either. + */ + sa1100_irda_check_speed(si); + + /* + * Start reception. This disables the transmitter for + * us. This will be using the existing RX buffer. + */ + sa1100_irda_rx_dma_start(si); + + /* Account and free the packet. */ + skb = si->dma_tx.skb; + if (skb) { + dma_unmap_sg(si->dma_tx.dev, &si->dma_tx.sg, 1, + DMA_TO_DEVICE); + dev->stats.tx_packets ++; + dev->stats.tx_bytes += skb->len; + dev_kfree_skb_irq(skb); + si->dma_tx.skb = NULL; + } + + /* + * Make sure that the TX queue is available for sending + * (for retries). TX has priority over RX at all times. + */ + netif_wake_queue(dev); +} + +static int sa1100_irda_fir_tx_start(struct sk_buff *skb, struct net_device *dev, + struct sa1100_irda *si) +{ + int mtt = irda_get_mtt(skb); + + si->dma_tx.skb = skb; + sg_set_buf(&si->dma_tx.sg, skb->data, skb->len); + if (dma_map_sg(si->dma_tx.dev, &si->dma_tx.sg, 1, DMA_TO_DEVICE) == 0) { + si->dma_tx.skb = NULL; + netif_wake_queue(dev); + dev->stats.tx_dropped++; + dev_kfree_skb(skb); + return NETDEV_TX_OK; + } + + sa1100_irda_dma_start(&si->dma_tx, DMA_MEM_TO_DEV, sa1100_irda_firtxdma_irq, dev); + + /* + * If we have a mean turn-around time, impose the specified + * specified delay. We could shorten this by timing from + * the point we received the packet. + */ + if (mtt) + udelay(mtt); + + Ser2HSCR0 = HSCR0_HSSP | HSCR0_TXE; + + return NETDEV_TX_OK; +} + +static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev) +{ + struct sk_buff *skb = si->dma_rx.skb; + unsigned int len, stat, data; + + if (!skb) { + printk(KERN_ERR "sa1100_ir: SKB is NULL!\n"); + return; + } + + /* + * Get the current data position. + */ + len = sa1100_irda_dma_xferred(&si->dma_rx); + if (len > HPSIR_MAX_RXLEN) + len = HPSIR_MAX_RXLEN; + dma_unmap_sg(si->dma_rx.dev, &si->dma_rx.sg, 1, DMA_FROM_DEVICE); + + do { + /* + * Read Status, and then Data. + */ + stat = Ser2HSSR1; + rmb(); + data = Ser2HSDR; + + if (stat & (HSSR1_CRE | HSSR1_ROR)) { + dev->stats.rx_errors++; + if (stat & HSSR1_CRE) + dev->stats.rx_crc_errors++; + if (stat & HSSR1_ROR) + dev->stats.rx_frame_errors++; + } else + skb->data[len++] = data; + + /* + * If we hit the end of frame, there's + * no point in continuing. + */ + if (stat & HSSR1_EOF) + break; + } while (Ser2HSSR0 & HSSR0_EIF); + + if (stat & HSSR1_EOF) { + si->dma_rx.skb = NULL; + + skb_put(skb, len); + skb->dev = dev; + skb_reset_mac_header(skb); + skb->protocol = htons(ETH_P_IRDA); + dev->stats.rx_packets++; + dev->stats.rx_bytes += len; + + /* + * Before we pass the buffer up, allocate a new one. + */ + sa1100_irda_rx_alloc(si); + + netif_rx(skb); + } else { + /* + * Remap the buffer - it was previously mapped, and we + * hope that this succeeds. + */ + dma_map_sg(si->dma_rx.dev, &si->dma_rx.sg, 1, DMA_FROM_DEVICE); + } +} + +/* + * We only have to handle RX events here; transmit events go via the TX + * DMA handler. We disable RX, process, and the restart RX. + */ +static irqreturn_t sa1100_irda_fir_irq(struct net_device *dev, struct sa1100_irda *si) +{ + /* + * Stop RX DMA + */ + dmaengine_pause(si->dma_rx.chan); + + /* + * Framing error - we throw away the packet completely. + * Clearing RXE flushes the error conditions and data + * from the fifo. + */ + if (Ser2HSSR0 & (HSSR0_FRE | HSSR0_RAB)) { + dev->stats.rx_errors++; + + if (Ser2HSSR0 & HSSR0_FRE) + dev->stats.rx_frame_errors++; + + /* + * Clear out the DMA... + */ + Ser2HSCR0 = HSCR0_HSSP; + + /* + * Clear selected status bits now, so we + * don't miss them next time around. + */ + Ser2HSSR0 = HSSR0_FRE | HSSR0_RAB; + } + + /* + * Deal with any receive errors. The any of the lowest + * 8 bytes in the FIFO may contain an error. We must read + * them one by one. The "error" could even be the end of + * packet! + */ + if (Ser2HSSR0 & HSSR0_EIF) + sa1100_irda_fir_error(si, dev); + + /* + * No matter what happens, we must restart reception. + */ + sa1100_irda_rx_dma_start(si); + + return IRQ_HANDLED; +} + +/* + * Set the IrDA communications speed. + */ +static int sa1100_irda_set_speed(struct sa1100_irda *si, int speed) +{ + unsigned long flags; + int brd, ret = -EINVAL; + + switch (speed) { + case 9600: case 19200: case 38400: + case 57600: case 115200: + brd = 3686400 / (16 * speed) - 1; + + /* Stop the receive DMA, and configure transmit. */ + if (IS_FIR(si)) { + dmaengine_terminate_all(si->dma_rx.chan); + dmaengine_slave_config(si->dma_tx.chan, + &sa1100_irda_sir_tx); + } + + local_irq_save(flags); + + Ser2UTCR3 = 0; + Ser2HSCR0 = HSCR0_UART; + + Ser2UTCR1 = brd >> 8; + Ser2UTCR2 = brd; + + /* + * Clear status register + */ + Ser2UTSR0 = UTSR0_REB | UTSR0_RBB | UTSR0_RID; + Ser2UTCR3 = UTCR3_RIE | UTCR3_RXE | UTCR3_TXE; + + if (si->pdata->set_speed) + si->pdata->set_speed(si->dev, speed); + + si->speed = speed; + si->tx_start = sa1100_irda_sir_tx_start; + si->irq = sa1100_irda_sir_irq; + + local_irq_restore(flags); + ret = 0; + break; + + case 4000000: + if (!IS_FIR(si)) + dmaengine_slave_config(si->dma_tx.chan, + &sa1100_irda_fir_tx); + + local_irq_save(flags); + + Ser2HSSR0 = 0xff; + Ser2HSCR0 = HSCR0_HSSP; + Ser2UTCR3 = 0; + + si->speed = speed; + si->tx_start = sa1100_irda_fir_tx_start; + si->irq = sa1100_irda_fir_irq; + + if (si->pdata->set_speed) + si->pdata->set_speed(si->dev, speed); + + sa1100_irda_rx_alloc(si); + sa1100_irda_rx_dma_start(si); + + local_irq_restore(flags); + + break; + + default: + break; + } + + return ret; +} + +/* + * Control the power state of the IrDA transmitter. + * State: + * 0 - off + * 1 - short range, lowest power + * 2 - medium range, medium power + * 3 - maximum range, high power + * + * Currently, only assabet is known to support this. + */ +static int +__sa1100_irda_set_power(struct sa1100_irda *si, unsigned int state) +{ + int ret = 0; + if (si->pdata->set_power) + ret = si->pdata->set_power(si->dev, state); + return ret; +} + +static inline int +sa1100_set_power(struct sa1100_irda *si, unsigned int state) +{ + int ret; + + ret = __sa1100_irda_set_power(si, state); + if (ret == 0) + si->power = state; + + return ret; +} + +static irqreturn_t sa1100_irda_irq(int irq, void *dev_id) +{ + struct net_device *dev = dev_id; + struct sa1100_irda *si = netdev_priv(dev); + + return si->irq(dev, si); +} + +static int sa1100_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct sa1100_irda *si = netdev_priv(dev); + int speed = irda_get_next_speed(skb); + + /* + * Does this packet contain a request to change the interface + * speed? If so, remember it until we complete the transmission + * of this frame. + */ + if (speed != si->speed && speed != -1) + si->newspeed = speed; + + /* If this is an empty frame, we can bypass a lot. */ + if (skb->len == 0) { + sa1100_irda_check_speed(si); + dev_kfree_skb(skb); + return NETDEV_TX_OK; + } + + netif_stop_queue(dev); + + /* We must not already have a skb to transmit... */ + BUG_ON(si->dma_tx.skb); + + return si->tx_start(skb, dev, si); +} + +static int +sa1100_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd) +{ + struct if_irda_req *rq = (struct if_irda_req *)ifreq; + struct sa1100_irda *si = netdev_priv(dev); + int ret = -EOPNOTSUPP; + + switch (cmd) { + case SIOCSBANDWIDTH: + if (capable(CAP_NET_ADMIN)) { + /* + * We are unable to set the speed if the + * device is not running. + */ + if (si->open) { + ret = sa1100_irda_set_speed(si, + rq->ifr_baudrate); + } else { + printk("sa1100_irda_ioctl: SIOCSBANDWIDTH: !netif_running\n"); + ret = 0; + } + } + break; + + case SIOCSMEDIABUSY: + ret = -EPERM; + if (capable(CAP_NET_ADMIN)) { + irda_device_set_media_busy(dev, TRUE); + ret = 0; + } + break; + + case SIOCGRECEIVING: + rq->ifr_receiving = IS_FIR(si) ? 0 + : si->rx_buff.state != OUTSIDE_FRAME; + break; + + default: + break; + } + + return ret; +} + +static int sa1100_irda_startup(struct sa1100_irda *si) +{ + int ret; + + /* + * Ensure that the ports for this device are setup correctly. + */ + if (si->pdata->startup) { + ret = si->pdata->startup(si->dev); + if (ret) + return ret; + } + + /* + * Configure PPC for IRDA - we want to drive TXD2 low. + * We also want to drive this pin low during sleep. + */ + PPSR &= ~PPC_TXD2; + PSDR &= ~PPC_TXD2; + PPDR |= PPC_TXD2; + + /* + * Enable HP-SIR modulation, and ensure that the port is disabled. + */ + Ser2UTCR3 = 0; + Ser2HSCR0 = HSCR0_UART; + Ser2UTCR4 = si->utcr4; + Ser2UTCR0 = UTCR0_8BitData; + Ser2HSCR2 = HSCR2_TrDataH | HSCR2_RcDataL; + + /* + * Clear status register + */ + Ser2UTSR0 = UTSR0_REB | UTSR0_RBB | UTSR0_RID; + + ret = sa1100_irda_set_speed(si, si->speed = 9600); + if (ret) { + Ser2UTCR3 = 0; + Ser2HSCR0 = 0; + + if (si->pdata->shutdown) + si->pdata->shutdown(si->dev); + } + + return ret; +} + +static void sa1100_irda_shutdown(struct sa1100_irda *si) +{ + /* + * Stop all DMA activity. + */ + dmaengine_terminate_all(si->dma_rx.chan); + dmaengine_terminate_all(si->dma_tx.chan); + + /* Disable the port. */ + Ser2UTCR3 = 0; + Ser2HSCR0 = 0; + + if (si->pdata->shutdown) + si->pdata->shutdown(si->dev); +} + +static int sa1100_irda_start(struct net_device *dev) +{ + struct sa1100_irda *si = netdev_priv(dev); + int err; + + si->speed = 9600; + + err = sa1100_irda_dma_request(si->dev, &si->dma_rx, "Ser2ICPRc", + &sa1100_irda_fir_rx); + if (err) + goto err_rx_dma; + + err = sa1100_irda_dma_request(si->dev, &si->dma_tx, "Ser2ICPTr", + &sa1100_irda_sir_tx); + if (err) + goto err_tx_dma; + + /* + * Setup the serial port for the specified speed. + */ + err = sa1100_irda_startup(si); + if (err) + goto err_startup; + + /* + * Open a new IrLAP layer instance. + */ + si->irlap = irlap_open(dev, &si->qos, "sa1100"); + err = -ENOMEM; + if (!si->irlap) + goto err_irlap; + + err = request_irq(dev->irq, sa1100_irda_irq, 0, dev->name, dev); + if (err) + goto err_irq; + + /* + * Now enable the interrupt and start the queue + */ + si->open = 1; + sa1100_set_power(si, power_level); /* low power mode */ + + netif_start_queue(dev); + return 0; + +err_irq: + irlap_close(si->irlap); +err_irlap: + si->open = 0; + sa1100_irda_shutdown(si); +err_startup: + dma_release_channel(si->dma_tx.chan); +err_tx_dma: + dma_release_channel(si->dma_rx.chan); +err_rx_dma: + return err; +} + +static int sa1100_irda_stop(struct net_device *dev) +{ + struct sa1100_irda *si = netdev_priv(dev); + struct sk_buff *skb; + + netif_stop_queue(dev); + + si->open = 0; + sa1100_irda_shutdown(si); + + /* + * If we have been doing any DMA activity, make sure we + * tidy that up cleanly. + */ + skb = si->dma_rx.skb; + if (skb) { + dma_unmap_sg(si->dma_rx.dev, &si->dma_rx.sg, 1, + DMA_FROM_DEVICE); + dev_kfree_skb(skb); + si->dma_rx.skb = NULL; + } + + skb = si->dma_tx.skb; + if (skb) { + dma_unmap_sg(si->dma_tx.dev, &si->dma_tx.sg, 1, + DMA_TO_DEVICE); + dev_kfree_skb(skb); + si->dma_tx.skb = NULL; + } + + /* Stop IrLAP */ + if (si->irlap) { + irlap_close(si->irlap); + si->irlap = NULL; + } + + /* + * Free resources + */ + dma_release_channel(si->dma_tx.chan); + dma_release_channel(si->dma_rx.chan); + free_irq(dev->irq, dev); + + sa1100_set_power(si, 0); + + return 0; +} + +static int sa1100_irda_init_iobuf(iobuff_t *io, int size) +{ + io->head = kmalloc(size, GFP_KERNEL | GFP_DMA); + if (io->head != NULL) { + io->truesize = size; + io->in_frame = FALSE; + io->state = OUTSIDE_FRAME; + io->data = io->head; + } + return io->head ? 0 : -ENOMEM; +} + +static const struct net_device_ops sa1100_irda_netdev_ops = { + .ndo_open = sa1100_irda_start, + .ndo_stop = sa1100_irda_stop, + .ndo_start_xmit = sa1100_irda_hard_xmit, + .ndo_do_ioctl = sa1100_irda_ioctl, +}; + +static int sa1100_irda_probe(struct platform_device *pdev) +{ + struct net_device *dev; + struct sa1100_irda *si; + unsigned int baudrate_mask; + int err, irq; + + if (!pdev->dev.platform_data) + return -EINVAL; + + irq = platform_get_irq(pdev, 0); + if (irq <= 0) + return irq < 0 ? irq : -ENXIO; + + err = request_mem_region(__PREG(Ser2UTCR0), 0x24, "IrDA") ? 0 : -EBUSY; + if (err) + goto err_mem_1; + err = request_mem_region(__PREG(Ser2HSCR0), 0x1c, "IrDA") ? 0 : -EBUSY; + if (err) + goto err_mem_2; + err = request_mem_region(__PREG(Ser2HSCR2), 0x04, "IrDA") ? 0 : -EBUSY; + if (err) + goto err_mem_3; + + dev = alloc_irdadev(sizeof(struct sa1100_irda)); + if (!dev) { + err = -ENOMEM; + goto err_mem_4; + } + + SET_NETDEV_DEV(dev, &pdev->dev); + + si = netdev_priv(dev); + si->dev = &pdev->dev; + si->pdata = pdev->dev.platform_data; + + sg_init_table(&si->dma_rx.sg, 1); + sg_init_table(&si->dma_tx.sg, 1); + + /* + * Initialise the HP-SIR buffers + */ + err = sa1100_irda_init_iobuf(&si->rx_buff, 14384); + if (err) + goto err_mem_5; + err = sa1100_irda_init_iobuf(&si->tx_buff, IRDA_SIR_MAX_FRAME); + if (err) + goto err_mem_5; + + dev->netdev_ops = &sa1100_irda_netdev_ops; + dev->irq = irq; + + irda_init_max_qos_capabilies(&si->qos); + + /* + * We support original IRDA up to 115k2. (we don't currently + * support 4Mbps). Min Turn Time set to 1ms or greater. + */ + baudrate_mask = IR_9600; + + switch (max_rate) { + case 4000000: baudrate_mask |= IR_4000000 << 8; + case 115200: baudrate_mask |= IR_115200; + case 57600: baudrate_mask |= IR_57600; + case 38400: baudrate_mask |= IR_38400; + case 19200: baudrate_mask |= IR_19200; + } + + si->qos.baud_rate.bits &= baudrate_mask; + si->qos.min_turn_time.bits = 7; + + irda_qos_bits_to_value(&si->qos); + + si->utcr4 = UTCR4_HPSIR; + if (tx_lpm) + si->utcr4 |= UTCR4_Z1_6us; + + /* + * Initially enable HP-SIR modulation, and ensure that the port + * is disabled. + */ + Ser2UTCR3 = 0; + Ser2UTCR4 = si->utcr4; + Ser2HSCR0 = HSCR0_UART; + + err = register_netdev(dev); + if (err == 0) + platform_set_drvdata(pdev, dev); + + if (err) { + err_mem_5: + kfree(si->tx_buff.head); + kfree(si->rx_buff.head); + free_netdev(dev); + err_mem_4: + release_mem_region(__PREG(Ser2HSCR2), 0x04); + err_mem_3: + release_mem_region(__PREG(Ser2HSCR0), 0x1c); + err_mem_2: + release_mem_region(__PREG(Ser2UTCR0), 0x24); + } + err_mem_1: + return err; +} + +static int sa1100_irda_remove(struct platform_device *pdev) +{ + struct net_device *dev = platform_get_drvdata(pdev); + + if (dev) { + struct sa1100_irda *si = netdev_priv(dev); + unregister_netdev(dev); + kfree(si->tx_buff.head); + kfree(si->rx_buff.head); + free_netdev(dev); + } + + release_mem_region(__PREG(Ser2HSCR2), 0x04); + release_mem_region(__PREG(Ser2HSCR0), 0x1c); + release_mem_region(__PREG(Ser2UTCR0), 0x24); + + return 0; +} + +#ifdef CONFIG_PM +/* + * Suspend the IrDA interface. + */ +static int sa1100_irda_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct net_device *dev = platform_get_drvdata(pdev); + struct sa1100_irda *si; + + if (!dev) + return 0; + + si = netdev_priv(dev); + if (si->open) { + /* + * Stop the transmit queue + */ + netif_device_detach(dev); + disable_irq(dev->irq); + sa1100_irda_shutdown(si); + __sa1100_irda_set_power(si, 0); + } + + return 0; +} + +/* + * Resume the IrDA interface. + */ +static int sa1100_irda_resume(struct platform_device *pdev) +{ + struct net_device *dev = platform_get_drvdata(pdev); + struct sa1100_irda *si; + + if (!dev) + return 0; + + si = netdev_priv(dev); + if (si->open) { + /* + * If we missed a speed change, initialise at the new speed + * directly. It is debatable whether this is actually + * required, but in the interests of continuing from where + * we left off it is desirable. The converse argument is + * that we should re-negotiate at 9600 baud again. + */ + if (si->newspeed) { + si->speed = si->newspeed; + si->newspeed = 0; + } + + sa1100_irda_startup(si); + __sa1100_irda_set_power(si, si->power); + enable_irq(dev->irq); + + /* + * This automatically wakes up the queue + */ + netif_device_attach(dev); + } + + return 0; +} +#else +#define sa1100_irda_suspend NULL +#define sa1100_irda_resume NULL +#endif + +static struct platform_driver sa1100ir_driver = { + .probe = sa1100_irda_probe, + .remove = sa1100_irda_remove, + .suspend = sa1100_irda_suspend, + .resume = sa1100_irda_resume, + .driver = { + .name = "sa11x0-ir", + }, +}; + +static int __init sa1100_irda_init(void) +{ + /* + * Limit power level a sensible range. + */ + if (power_level < 1) + power_level = 1; + if (power_level > 3) + power_level = 3; + + return platform_driver_register(&sa1100ir_driver); +} + +static void __exit sa1100_irda_exit(void) +{ + platform_driver_unregister(&sa1100ir_driver); +} + +module_init(sa1100_irda_init); +module_exit(sa1100_irda_exit); +module_param(power_level, int, 0); +module_param(tx_lpm, int, 0); +module_param(max_rate, int, 0); + +MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>"); +MODULE_DESCRIPTION("StrongARM SA1100 IrDA driver"); +MODULE_LICENSE("GPL"); +MODULE_PARM_DESC(power_level, "IrDA power level, 1 (low) to 3 (high)"); +MODULE_PARM_DESC(tx_lpm, "Enable transmitter low power (1.6us) mode"); +MODULE_PARM_DESC(max_rate, "Maximum baud rate (4000000, 115200, 57600, 38400, 19200, 9600)"); +MODULE_ALIAS("platform:sa11x0-ir"); diff --git a/drivers/staging/irda/drivers/sh_sir.c b/drivers/staging/irda/drivers/sh_sir.c new file mode 100644 index 000000000000..fede6864c737 --- /dev/null +++ b/drivers/staging/irda/drivers/sh_sir.c @@ -0,0 +1,810 @@ +/* + * SuperH IrDA Driver + * + * Copyright (C) 2009 Renesas Solutions Corp. + * Kuninori Morimoto <morimoto.kuninori@renesas.com> + * + * Based on bfin_sir.c + * Copyright 2006-2009 Analog Devices Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/io.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <net/irda/wrapper.h> +#include <net/irda/irda_device.h> +#include <asm/clock.h> + +#define DRIVER_NAME "sh_sir" + +#define RX_PHASE (1 << 0) +#define TX_PHASE (1 << 1) +#define TX_COMP_PHASE (1 << 2) /* tx complete */ +#define NONE_PHASE (1 << 31) + +#define IRIF_RINTCLR 0x0016 /* DMA rx interrupt source clear */ +#define IRIF_TINTCLR 0x0018 /* DMA tx interrupt source clear */ +#define IRIF_SIR0 0x0020 /* IrDA-SIR10 control */ +#define IRIF_SIR1 0x0022 /* IrDA-SIR10 baudrate error correction */ +#define IRIF_SIR2 0x0024 /* IrDA-SIR10 baudrate count */ +#define IRIF_SIR3 0x0026 /* IrDA-SIR10 status */ +#define IRIF_SIR_FRM 0x0028 /* Hardware frame processing set */ +#define IRIF_SIR_EOF 0x002A /* EOF value */ +#define IRIF_SIR_FLG 0x002C /* Flag clear */ +#define IRIF_UART_STS2 0x002E /* UART status 2 */ +#define IRIF_UART0 0x0030 /* UART control */ +#define IRIF_UART1 0x0032 /* UART status */ +#define IRIF_UART2 0x0034 /* UART mode */ +#define IRIF_UART3 0x0036 /* UART transmit data */ +#define IRIF_UART4 0x0038 /* UART receive data */ +#define IRIF_UART5 0x003A /* UART interrupt mask */ +#define IRIF_UART6 0x003C /* UART baud rate error correction */ +#define IRIF_UART7 0x003E /* UART baud rate count set */ +#define IRIF_CRC0 0x0040 /* CRC engine control */ +#define IRIF_CRC1 0x0042 /* CRC engine input data */ +#define IRIF_CRC2 0x0044 /* CRC engine calculation */ +#define IRIF_CRC3 0x0046 /* CRC engine output data 1 */ +#define IRIF_CRC4 0x0048 /* CRC engine output data 2 */ + +/* IRIF_SIR0 */ +#define IRTPW (1 << 1) /* transmit pulse width select */ +#define IRERRC (1 << 0) /* Clear receive pulse width error */ + +/* IRIF_SIR3 */ +#define IRERR (1 << 0) /* received pulse width Error */ + +/* IRIF_SIR_FRM */ +#define EOFD (1 << 9) /* EOF detection flag */ +#define FRER (1 << 8) /* Frame Error bit */ +#define FRP (1 << 0) /* Frame processing set */ + +/* IRIF_UART_STS2 */ +#define IRSME (1 << 6) /* Receive Sum Error flag */ +#define IROVE (1 << 5) /* Receive Overrun Error flag */ +#define IRFRE (1 << 4) /* Receive Framing Error flag */ +#define IRPRE (1 << 3) /* Receive Parity Error flag */ + +/* IRIF_UART0_*/ +#define TBEC (1 << 2) /* Transmit Data Clear */ +#define RIE (1 << 1) /* Receive Enable */ +#define TIE (1 << 0) /* Transmit Enable */ + +/* IRIF_UART1 */ +#define URSME (1 << 6) /* Receive Sum Error Flag */ +#define UROVE (1 << 5) /* Receive Overrun Error Flag */ +#define URFRE (1 << 4) /* Receive Framing Error Flag */ +#define URPRE (1 << 3) /* Receive Parity Error Flag */ +#define RBF (1 << 2) /* Receive Buffer Full Flag */ +#define TSBE (1 << 1) /* Transmit Shift Buffer Empty Flag */ +#define TBE (1 << 0) /* Transmit Buffer Empty flag */ +#define TBCOMP (TSBE | TBE) + +/* IRIF_UART5 */ +#define RSEIM (1 << 6) /* Receive Sum Error Flag IRQ Mask */ +#define RBFIM (1 << 2) /* Receive Buffer Full Flag IRQ Mask */ +#define TSBEIM (1 << 1) /* Transmit Shift Buffer Empty Flag IRQ Mask */ +#define TBEIM (1 << 0) /* Transmit Buffer Empty Flag IRQ Mask */ +#define RX_MASK (RSEIM | RBFIM) + +/* IRIF_CRC0 */ +#define CRC_RST (1 << 15) /* CRC Engine Reset */ +#define CRC_CT_MASK 0x0FFF + +/************************************************************************ + + + structure + + +************************************************************************/ +struct sh_sir_self { + void __iomem *membase; + unsigned int irq; + struct clk *clk; + + struct net_device *ndev; + + struct irlap_cb *irlap; + struct qos_info qos; + + iobuff_t tx_buff; + iobuff_t rx_buff; +}; + +/************************************************************************ + + + common function + + +************************************************************************/ +static void sh_sir_write(struct sh_sir_self *self, u32 offset, u16 data) +{ + iowrite16(data, self->membase + offset); +} + +static u16 sh_sir_read(struct sh_sir_self *self, u32 offset) +{ + return ioread16(self->membase + offset); +} + +static void sh_sir_update_bits(struct sh_sir_self *self, u32 offset, + u16 mask, u16 data) +{ + u16 old, new; + + old = sh_sir_read(self, offset); + new = (old & ~mask) | data; + if (old != new) + sh_sir_write(self, offset, new); +} + +/************************************************************************ + + + CRC function + + +************************************************************************/ +static void sh_sir_crc_reset(struct sh_sir_self *self) +{ + sh_sir_write(self, IRIF_CRC0, CRC_RST); +} + +static void sh_sir_crc_add(struct sh_sir_self *self, u8 data) +{ + sh_sir_write(self, IRIF_CRC1, (u16)data); +} + +static u16 sh_sir_crc_cnt(struct sh_sir_self *self) +{ + return CRC_CT_MASK & sh_sir_read(self, IRIF_CRC0); +} + +static u16 sh_sir_crc_out(struct sh_sir_self *self) +{ + return sh_sir_read(self, IRIF_CRC4); +} + +static int sh_sir_crc_init(struct sh_sir_self *self) +{ + struct device *dev = &self->ndev->dev; + int ret = -EIO; + u16 val; + + sh_sir_crc_reset(self); + + sh_sir_crc_add(self, 0xCC); + sh_sir_crc_add(self, 0xF5); + sh_sir_crc_add(self, 0xF1); + sh_sir_crc_add(self, 0xA7); + + val = sh_sir_crc_cnt(self); + if (4 != val) { + dev_err(dev, "CRC count error %x\n", val); + goto crc_init_out; + } + + val = sh_sir_crc_out(self); + if (0x51DF != val) { + dev_err(dev, "CRC result error%x\n", val); + goto crc_init_out; + } + + ret = 0; + +crc_init_out: + + sh_sir_crc_reset(self); + return ret; +} + +/************************************************************************ + + + baud rate functions + + +************************************************************************/ +#define SCLK_BASE 1843200 /* 1.8432MHz */ + +static u32 sh_sir_find_sclk(struct clk *irda_clk) +{ + struct cpufreq_frequency_table *freq_table = irda_clk->freq_table; + struct cpufreq_frequency_table *pos; + struct clk *pclk = clk_get(NULL, "peripheral_clk"); + u32 limit, min = 0xffffffff, tmp; + int index = 0; + + limit = clk_get_rate(pclk); + clk_put(pclk); + + /* IrDA can not set over peripheral_clk */ + cpufreq_for_each_valid_entry(pos, freq_table) { + u32 freq = pos->frequency; + + /* IrDA should not over peripheral_clk */ + if (freq > limit) + continue; + + tmp = freq % SCLK_BASE; + if (tmp < min) { + min = tmp; + index = pos - freq_table; + } + } + + return freq_table[index].frequency; +} + +#define ERR_ROUNDING(a) ((a + 5000) / 10000) +static int sh_sir_set_baudrate(struct sh_sir_self *self, u32 baudrate) +{ + struct clk *clk; + struct device *dev = &self->ndev->dev; + u32 rate; + u16 uabca, uabc; + u16 irbca, irbc; + u32 min, rerr, tmp; + int i; + + /* Baud Rate Error Correction x 10000 */ + u32 rate_err_array[] = { + 0, 625, 1250, 1875, + 2500, 3125, 3750, 4375, + 5000, 5625, 6250, 6875, + 7500, 8125, 8750, 9375, + }; + + /* + * FIXME + * + * it support 9600 only now + */ + switch (baudrate) { + case 9600: + break; + default: + dev_err(dev, "un-supported baudrate %d\n", baudrate); + return -EIO; + } + + clk = clk_get(NULL, "irda_clk"); + if (IS_ERR(clk)) { + dev_err(dev, "can not get irda_clk\n"); + return -EIO; + } + + clk_set_rate(clk, sh_sir_find_sclk(clk)); + rate = clk_get_rate(clk); + clk_put(clk); + + dev_dbg(dev, "selected sclk = %d\n", rate); + + /* + * CALCULATION + * + * 1843200 = system rate / (irbca + (irbc + 1)) + */ + + irbc = rate / SCLK_BASE; + + tmp = rate - (SCLK_BASE * irbc); + tmp *= 10000; + + rerr = tmp / SCLK_BASE; + + min = 0xffffffff; + irbca = 0; + for (i = 0; i < ARRAY_SIZE(rate_err_array); i++) { + tmp = abs(rate_err_array[i] - rerr); + if (min > tmp) { + min = tmp; + irbca = i; + } + } + + tmp = rate / (irbc + ERR_ROUNDING(rate_err_array[irbca])); + if ((SCLK_BASE / 100) < abs(tmp - SCLK_BASE)) + dev_warn(dev, "IrDA freq error margin over %d\n", tmp); + + dev_dbg(dev, "target = %d, result = %d, infrared = %d.%d\n", + SCLK_BASE, tmp, irbc, rate_err_array[irbca]); + + irbca = (irbca & 0xF) << 4; + irbc = (irbc - 1) & 0xF; + + if (!irbc) { + dev_err(dev, "sh_sir can not set 0 in IRIF_SIR2\n"); + return -EIO; + } + + sh_sir_write(self, IRIF_SIR0, IRTPW | IRERRC); + sh_sir_write(self, IRIF_SIR1, irbca); + sh_sir_write(self, IRIF_SIR2, irbc); + + /* + * CALCULATION + * + * BaudRate[bps] = system rate / (uabca + (uabc + 1) x 16) + */ + + uabc = rate / baudrate; + uabc = (uabc / 16) - 1; + uabc = (uabc + 1) * 16; + + tmp = rate - (uabc * baudrate); + tmp *= 10000; + + rerr = tmp / baudrate; + + min = 0xffffffff; + uabca = 0; + for (i = 0; i < ARRAY_SIZE(rate_err_array); i++) { + tmp = abs(rate_err_array[i] - rerr); + if (min > tmp) { + min = tmp; + uabca = i; + } + } + + tmp = rate / (uabc + ERR_ROUNDING(rate_err_array[uabca])); + if ((baudrate / 100) < abs(tmp - baudrate)) + dev_warn(dev, "UART freq error margin over %d\n", tmp); + + dev_dbg(dev, "target = %d, result = %d, uart = %d.%d\n", + baudrate, tmp, + uabc, rate_err_array[uabca]); + + uabca = (uabca & 0xF) << 4; + uabc = (uabc / 16) - 1; + + sh_sir_write(self, IRIF_UART6, uabca); + sh_sir_write(self, IRIF_UART7, uabc); + + return 0; +} + +/************************************************************************ + + + iobuf function + + +************************************************************************/ +static int __sh_sir_init_iobuf(iobuff_t *io, int size) +{ + io->head = kmalloc(size, GFP_KERNEL); + if (!io->head) + return -ENOMEM; + + io->truesize = size; + io->in_frame = FALSE; + io->state = OUTSIDE_FRAME; + io->data = io->head; + + return 0; +} + +static void sh_sir_remove_iobuf(struct sh_sir_self *self) +{ + kfree(self->rx_buff.head); + kfree(self->tx_buff.head); + + self->rx_buff.head = NULL; + self->tx_buff.head = NULL; +} + +static int sh_sir_init_iobuf(struct sh_sir_self *self, int rxsize, int txsize) +{ + int err = -ENOMEM; + + if (self->rx_buff.head || + self->tx_buff.head) { + dev_err(&self->ndev->dev, "iobuff has already existed."); + return err; + } + + err = __sh_sir_init_iobuf(&self->rx_buff, rxsize); + if (err) + goto iobuf_err; + + err = __sh_sir_init_iobuf(&self->tx_buff, txsize); + +iobuf_err: + if (err) + sh_sir_remove_iobuf(self); + + return err; +} + +/************************************************************************ + + + status function + + +************************************************************************/ +static void sh_sir_clear_all_err(struct sh_sir_self *self) +{ + /* Clear error flag for receive pulse width */ + sh_sir_update_bits(self, IRIF_SIR0, IRERRC, IRERRC); + + /* Clear frame / EOF error flag */ + sh_sir_write(self, IRIF_SIR_FLG, 0xffff); + + /* Clear all status error */ + sh_sir_write(self, IRIF_UART_STS2, 0); +} + +static void sh_sir_set_phase(struct sh_sir_self *self, int phase) +{ + u16 uart5 = 0; + u16 uart0 = 0; + + switch (phase) { + case TX_PHASE: + uart5 = TBEIM; + uart0 = TBEC | TIE; + break; + case TX_COMP_PHASE: + uart5 = TSBEIM; + uart0 = TIE; + break; + case RX_PHASE: + uart5 = RX_MASK; + uart0 = RIE; + break; + default: + break; + } + + sh_sir_write(self, IRIF_UART5, uart5); + sh_sir_write(self, IRIF_UART0, uart0); +} + +static int sh_sir_is_which_phase(struct sh_sir_self *self) +{ + u16 val = sh_sir_read(self, IRIF_UART5); + + if (val & TBEIM) + return TX_PHASE; + + if (val & TSBEIM) + return TX_COMP_PHASE; + + if (val & RX_MASK) + return RX_PHASE; + + return NONE_PHASE; +} + +static void sh_sir_tx(struct sh_sir_self *self, int phase) +{ + switch (phase) { + case TX_PHASE: + if (0 >= self->tx_buff.len) { + sh_sir_set_phase(self, TX_COMP_PHASE); + } else { + sh_sir_write(self, IRIF_UART3, self->tx_buff.data[0]); + self->tx_buff.len--; + self->tx_buff.data++; + } + break; + case TX_COMP_PHASE: + sh_sir_set_phase(self, RX_PHASE); + netif_wake_queue(self->ndev); + break; + default: + dev_err(&self->ndev->dev, "should not happen\n"); + break; + } +} + +static int sh_sir_read_data(struct sh_sir_self *self) +{ + u16 val = 0; + int timeout = 1024; + + while (timeout--) { + val = sh_sir_read(self, IRIF_UART1); + + /* data get */ + if (val & RBF) { + if (val & (URSME | UROVE | URFRE | URPRE)) + break; + + return (int)sh_sir_read(self, IRIF_UART4); + } + + udelay(1); + } + + dev_err(&self->ndev->dev, "UART1 %04x : STATUS %04x\n", + val, sh_sir_read(self, IRIF_UART_STS2)); + + /* read data register for clear error */ + sh_sir_read(self, IRIF_UART4); + + return -1; +} + +static void sh_sir_rx(struct sh_sir_self *self) +{ + int timeout = 1024; + int data; + + while (timeout--) { + data = sh_sir_read_data(self); + if (data < 0) + break; + + async_unwrap_char(self->ndev, &self->ndev->stats, + &self->rx_buff, (u8)data); + + if (EOFD & sh_sir_read(self, IRIF_SIR_FRM)) + continue; + + break; + } +} + +static irqreturn_t sh_sir_irq(int irq, void *dev_id) +{ + struct sh_sir_self *self = dev_id; + struct device *dev = &self->ndev->dev; + int phase = sh_sir_is_which_phase(self); + + switch (phase) { + case TX_COMP_PHASE: + case TX_PHASE: + sh_sir_tx(self, phase); + break; + case RX_PHASE: + if (sh_sir_read(self, IRIF_SIR3)) + dev_err(dev, "rcv pulse width error occurred\n"); + + sh_sir_rx(self); + sh_sir_clear_all_err(self); + break; + default: + dev_err(dev, "unknown interrupt\n"); + } + + return IRQ_HANDLED; +} + +/************************************************************************ + + + net_device_ops function + + +************************************************************************/ +static int sh_sir_hard_xmit(struct sk_buff *skb, struct net_device *ndev) +{ + struct sh_sir_self *self = netdev_priv(ndev); + int speed = irda_get_next_speed(skb); + + if ((0 < speed) && + (9600 != speed)) { + dev_err(&ndev->dev, "support 9600 only (%d)\n", speed); + return -EIO; + } + + netif_stop_queue(ndev); + + self->tx_buff.data = self->tx_buff.head; + self->tx_buff.len = 0; + if (skb->len) + self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data, + self->tx_buff.truesize); + + sh_sir_set_phase(self, TX_PHASE); + dev_kfree_skb(skb); + + return 0; +} + +static int sh_sir_ioctl(struct net_device *ndev, struct ifreq *ifreq, int cmd) +{ + /* + * FIXME + * + * This function is needed for irda framework. + * But nothing to do now + */ + return 0; +} + +static struct net_device_stats *sh_sir_stats(struct net_device *ndev) +{ + struct sh_sir_self *self = netdev_priv(ndev); + + return &self->ndev->stats; +} + +static int sh_sir_open(struct net_device *ndev) +{ + struct sh_sir_self *self = netdev_priv(ndev); + int err; + + clk_enable(self->clk); + err = sh_sir_crc_init(self); + if (err) + goto open_err; + + sh_sir_set_baudrate(self, 9600); + + self->irlap = irlap_open(ndev, &self->qos, DRIVER_NAME); + if (!self->irlap) { + err = -ENODEV; + goto open_err; + } + + /* + * Now enable the interrupt then start the queue + */ + sh_sir_update_bits(self, IRIF_SIR_FRM, FRP, FRP); + sh_sir_read(self, IRIF_UART1); /* flag clear */ + sh_sir_read(self, IRIF_UART4); /* flag clear */ + sh_sir_set_phase(self, RX_PHASE); + + netif_start_queue(ndev); + + dev_info(&self->ndev->dev, "opened\n"); + + return 0; + +open_err: + clk_disable(self->clk); + + return err; +} + +static int sh_sir_stop(struct net_device *ndev) +{ + struct sh_sir_self *self = netdev_priv(ndev); + + /* Stop IrLAP */ + if (self->irlap) { + irlap_close(self->irlap); + self->irlap = NULL; + } + + netif_stop_queue(ndev); + + dev_info(&ndev->dev, "stopped\n"); + + return 0; +} + +static const struct net_device_ops sh_sir_ndo = { + .ndo_open = sh_sir_open, + .ndo_stop = sh_sir_stop, + .ndo_start_xmit = sh_sir_hard_xmit, + .ndo_do_ioctl = sh_sir_ioctl, + .ndo_get_stats = sh_sir_stats, +}; + +/************************************************************************ + + + platform_driver function + + +************************************************************************/ +static int sh_sir_probe(struct platform_device *pdev) +{ + struct net_device *ndev; + struct sh_sir_self *self; + struct resource *res; + char clk_name[8]; + int irq; + int err = -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + irq = platform_get_irq(pdev, 0); + if (!res || irq < 0) { + dev_err(&pdev->dev, "Not enough platform resources.\n"); + goto exit; + } + + ndev = alloc_irdadev(sizeof(*self)); + if (!ndev) + goto exit; + + self = netdev_priv(ndev); + self->membase = ioremap_nocache(res->start, resource_size(res)); + if (!self->membase) { + err = -ENXIO; + dev_err(&pdev->dev, "Unable to ioremap.\n"); + goto err_mem_1; + } + + err = sh_sir_init_iobuf(self, IRDA_SKB_MAX_MTU, IRDA_SIR_MAX_FRAME); + if (err) + goto err_mem_2; + + snprintf(clk_name, sizeof(clk_name), "irda%d", pdev->id); + self->clk = clk_get(&pdev->dev, clk_name); + if (IS_ERR(self->clk)) { + dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name); + err = -ENODEV; + goto err_mem_3; + } + + irda_init_max_qos_capabilies(&self->qos); + + ndev->netdev_ops = &sh_sir_ndo; + ndev->irq = irq; + + self->ndev = ndev; + self->qos.baud_rate.bits &= IR_9600; /* FIXME */ + self->qos.min_turn_time.bits = 1; /* 10 ms or more */ + + irda_qos_bits_to_value(&self->qos); + + err = register_netdev(ndev); + if (err) + goto err_mem_4; + + platform_set_drvdata(pdev, ndev); + err = devm_request_irq(&pdev->dev, irq, sh_sir_irq, 0, "sh_sir", self); + if (err) { + dev_warn(&pdev->dev, "Unable to attach sh_sir interrupt\n"); + goto err_mem_4; + } + + dev_info(&pdev->dev, "SuperH IrDA probed\n"); + + goto exit; + +err_mem_4: + clk_put(self->clk); +err_mem_3: + sh_sir_remove_iobuf(self); +err_mem_2: + iounmap(self->membase); +err_mem_1: + free_netdev(ndev); +exit: + return err; +} + +static int sh_sir_remove(struct platform_device *pdev) +{ + struct net_device *ndev = platform_get_drvdata(pdev); + struct sh_sir_self *self = netdev_priv(ndev); + + if (!self) + return 0; + + unregister_netdev(ndev); + clk_put(self->clk); + sh_sir_remove_iobuf(self); + iounmap(self->membase); + free_netdev(ndev); + + return 0; +} + +static struct platform_driver sh_sir_driver = { + .probe = sh_sir_probe, + .remove = sh_sir_remove, + .driver = { + .name = DRIVER_NAME, + }, +}; + +module_platform_driver(sh_sir_driver); + +MODULE_AUTHOR("Kuninori Morimoto <morimoto.kuninori@renesas.com>"); +MODULE_DESCRIPTION("SuperH IrDA driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/irda/drivers/sir-dev.h b/drivers/staging/irda/drivers/sir-dev.h new file mode 100644 index 000000000000..f50b9c1c0639 --- /dev/null +++ b/drivers/staging/irda/drivers/sir-dev.h @@ -0,0 +1,191 @@ +/********************************************************************* + * + * sir.h: include file for irda-sir device abstraction layer + * + * Copyright (c) 2002 Martin Diehl + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + ********************************************************************/ + +#ifndef IRDA_SIR_H +#define IRDA_SIR_H + +#include <linux/netdevice.h> +#include <linux/workqueue.h> + +#include <net/irda/irda.h> +#include <net/irda/irda_device.h> // iobuff_t + +struct sir_fsm { + struct semaphore sem; + struct delayed_work work; + unsigned state, substate; + int param; + int result; +}; + +#define SIRDEV_STATE_WAIT_TX_COMPLETE 0x0100 + +/* substates for wait_tx_complete */ +#define SIRDEV_STATE_WAIT_XMIT 0x0101 +#define SIRDEV_STATE_WAIT_UNTIL_SENT 0x0102 +#define SIRDEV_STATE_TX_DONE 0x0103 + +#define SIRDEV_STATE_DONGLE_OPEN 0x0300 + +/* 0x0301-0x03ff reserved for individual dongle substates */ + +#define SIRDEV_STATE_DONGLE_CLOSE 0x0400 + +/* 0x0401-0x04ff reserved for individual dongle substates */ + +#define SIRDEV_STATE_SET_DTR_RTS 0x0500 + +#define SIRDEV_STATE_SET_SPEED 0x0700 +#define SIRDEV_STATE_DONGLE_CHECK 0x0800 +#define SIRDEV_STATE_DONGLE_RESET 0x0900 + +/* 0x0901-0x09ff reserved for individual dongle substates */ + +#define SIRDEV_STATE_DONGLE_SPEED 0x0a00 +/* 0x0a01-0x0aff reserved for individual dongle substates */ + +#define SIRDEV_STATE_PORT_SPEED 0x0b00 +#define SIRDEV_STATE_DONE 0x0c00 +#define SIRDEV_STATE_ERROR 0x0d00 +#define SIRDEV_STATE_COMPLETE 0x0e00 + +#define SIRDEV_STATE_DEAD 0xffff + + +struct sir_dev; + +struct dongle_driver { + + struct module *owner; + + const char *driver_name; + + IRDA_DONGLE type; + + int (*open)(struct sir_dev *dev); + int (*close)(struct sir_dev *dev); + int (*reset)(struct sir_dev *dev); + int (*set_speed)(struct sir_dev *dev, unsigned speed); + + struct list_head dongle_list; +}; + +struct sir_driver { + + struct module *owner; + + const char *driver_name; + + int qos_mtt_bits; + + int (*chars_in_buffer)(struct sir_dev *dev); + void (*wait_until_sent)(struct sir_dev *dev); + int (*set_speed)(struct sir_dev *dev, unsigned speed); + int (*set_dtr_rts)(struct sir_dev *dev, int dtr, int rts); + + int (*do_write)(struct sir_dev *dev, const unsigned char *ptr, size_t len); + + int (*start_dev)(struct sir_dev *dev); + int (*stop_dev)(struct sir_dev *dev); +}; + + +/* exported */ + +int irda_register_dongle(struct dongle_driver *new); +int irda_unregister_dongle(struct dongle_driver *drv); + +struct sir_dev *sirdev_get_instance(const struct sir_driver *drv, + const char *name); +int sirdev_put_instance(struct sir_dev *self); + +int sirdev_set_dongle(struct sir_dev *dev, IRDA_DONGLE type); +void sirdev_write_complete(struct sir_dev *dev); +int sirdev_receive(struct sir_dev *dev, const unsigned char *cp, size_t count); + +/* low level helpers for SIR device/dongle setup */ +int sirdev_raw_write(struct sir_dev *dev, const char *buf, int len); +int sirdev_raw_read(struct sir_dev *dev, char *buf, int len); +int sirdev_set_dtr_rts(struct sir_dev *dev, int dtr, int rts); + +/* not exported */ + +int sirdev_get_dongle(struct sir_dev *self, IRDA_DONGLE type); +int sirdev_put_dongle(struct sir_dev *self); + +void sirdev_enable_rx(struct sir_dev *dev); +int sirdev_schedule_request(struct sir_dev *dev, int state, unsigned param); + +/* inline helpers */ + +static inline int sirdev_schedule_speed(struct sir_dev *dev, unsigned speed) +{ + return sirdev_schedule_request(dev, SIRDEV_STATE_SET_SPEED, speed); +} + +static inline int sirdev_schedule_dongle_open(struct sir_dev *dev, int dongle_id) +{ + return sirdev_schedule_request(dev, SIRDEV_STATE_DONGLE_OPEN, dongle_id); +} + +static inline int sirdev_schedule_dongle_close(struct sir_dev *dev) +{ + return sirdev_schedule_request(dev, SIRDEV_STATE_DONGLE_CLOSE, 0); +} + +static inline int sirdev_schedule_dtr_rts(struct sir_dev *dev, int dtr, int rts) +{ + int dtrrts; + + dtrrts = ((dtr) ? 0x02 : 0x00) | ((rts) ? 0x01 : 0x00); + return sirdev_schedule_request(dev, SIRDEV_STATE_SET_DTR_RTS, dtrrts); +} + +#if 0 +static inline int sirdev_schedule_mode(struct sir_dev *dev, int mode) +{ + return sirdev_schedule_request(dev, SIRDEV_STATE_SET_MODE, mode); +} +#endif + + +struct sir_dev { + struct net_device *netdev; + + struct irlap_cb *irlap; + + struct qos_info qos; + + char hwname[32]; + + struct sir_fsm fsm; + atomic_t enable_rx; + int raw_tx; + spinlock_t tx_lock; + + u32 new_speed; + u32 flags; + + unsigned speed; + + iobuff_t tx_buff; /* Transmit buffer */ + iobuff_t rx_buff; /* Receive buffer */ + struct sk_buff *tx_skb; + + const struct dongle_driver * dongle_drv; + const struct sir_driver * drv; + void *priv; + +}; + +#endif /* IRDA_SIR_H */ diff --git a/drivers/staging/irda/drivers/sir_dev.c b/drivers/staging/irda/drivers/sir_dev.c new file mode 100644 index 000000000000..6af26a7d787c --- /dev/null +++ b/drivers/staging/irda/drivers/sir_dev.c @@ -0,0 +1,987 @@ +/********************************************************************* + * + * sir_dev.c: irda sir network device + * + * Copyright (c) 2002 Martin Diehl + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + ********************************************************************/ + +#include <linux/hardirq.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/init.h> +#include <linux/delay.h> + +#include <net/irda/irda.h> +#include <net/irda/wrapper.h> +#include <net/irda/irda_device.h> + +#include "sir-dev.h" + + +static struct workqueue_struct *irda_sir_wq; + +/* STATE MACHINE */ + +/* substate handler of the config-fsm to handle the cases where we want + * to wait for transmit completion before changing the port configuration + */ + +static int sirdev_tx_complete_fsm(struct sir_dev *dev) +{ + struct sir_fsm *fsm = &dev->fsm; + unsigned next_state, delay; + unsigned bytes_left; + + do { + next_state = fsm->substate; /* default: stay in current substate */ + delay = 0; + + switch(fsm->substate) { + + case SIRDEV_STATE_WAIT_XMIT: + if (dev->drv->chars_in_buffer) + bytes_left = dev->drv->chars_in_buffer(dev); + else + bytes_left = 0; + if (!bytes_left) { + next_state = SIRDEV_STATE_WAIT_UNTIL_SENT; + break; + } + + if (dev->speed > 115200) + delay = (bytes_left*8*10000) / (dev->speed/100); + else if (dev->speed > 0) + delay = (bytes_left*10*10000) / (dev->speed/100); + else + delay = 0; + /* expected delay (usec) until remaining bytes are sent */ + if (delay < 100) { + udelay(delay); + delay = 0; + break; + } + /* sleep some longer delay (msec) */ + delay = (delay+999) / 1000; + break; + + case SIRDEV_STATE_WAIT_UNTIL_SENT: + /* block until underlaying hardware buffer are empty */ + if (dev->drv->wait_until_sent) + dev->drv->wait_until_sent(dev); + next_state = SIRDEV_STATE_TX_DONE; + break; + + case SIRDEV_STATE_TX_DONE: + return 0; + + default: + net_err_ratelimited("%s - undefined state\n", __func__); + return -EINVAL; + } + fsm->substate = next_state; + } while (delay == 0); + return delay; +} + +/* + * Function sirdev_config_fsm + * + * State machine to handle the configuration of the device (and attached dongle, if any). + * This handler is scheduled for execution in kIrDAd context, so we can sleep. + * however, kIrDAd is shared by all sir_dev devices so we better don't sleep there too + * long. Instead, for longer delays we start a timer to reschedule us later. + * On entry, fsm->sem is always locked and the netdev xmit queue stopped. + * Both must be unlocked/restarted on completion - but only on final exit. + */ + +static void sirdev_config_fsm(struct work_struct *work) +{ + struct sir_dev *dev = container_of(work, struct sir_dev, fsm.work.work); + struct sir_fsm *fsm = &dev->fsm; + int next_state; + int ret = -1; + unsigned delay; + + pr_debug("%s(), <%ld>\n", __func__, jiffies); + + do { + pr_debug("%s - state=0x%04x / substate=0x%04x\n", + __func__, fsm->state, fsm->substate); + + next_state = fsm->state; + delay = 0; + + switch(fsm->state) { + + case SIRDEV_STATE_DONGLE_OPEN: + if (dev->dongle_drv != NULL) { + ret = sirdev_put_dongle(dev); + if (ret) { + fsm->result = -EINVAL; + next_state = SIRDEV_STATE_ERROR; + break; + } + } + + /* Initialize dongle */ + ret = sirdev_get_dongle(dev, fsm->param); + if (ret) { + fsm->result = ret; + next_state = SIRDEV_STATE_ERROR; + break; + } + + /* Dongles are powered through the modem control lines which + * were just set during open. Before resetting, let's wait for + * the power to stabilize. This is what some dongle drivers did + * in open before, while others didn't - should be safe anyway. + */ + + delay = 50; + fsm->substate = SIRDEV_STATE_DONGLE_RESET; + next_state = SIRDEV_STATE_DONGLE_RESET; + + fsm->param = 9600; + + break; + + case SIRDEV_STATE_DONGLE_CLOSE: + /* shouldn't we just treat this as success=? */ + if (dev->dongle_drv == NULL) { + fsm->result = -EINVAL; + next_state = SIRDEV_STATE_ERROR; + break; + } + + ret = sirdev_put_dongle(dev); + if (ret) { + fsm->result = ret; + next_state = SIRDEV_STATE_ERROR; + break; + } + next_state = SIRDEV_STATE_DONE; + break; + + case SIRDEV_STATE_SET_DTR_RTS: + ret = sirdev_set_dtr_rts(dev, + (fsm->param&0x02) ? TRUE : FALSE, + (fsm->param&0x01) ? TRUE : FALSE); + next_state = SIRDEV_STATE_DONE; + break; + + case SIRDEV_STATE_SET_SPEED: + fsm->substate = SIRDEV_STATE_WAIT_XMIT; + next_state = SIRDEV_STATE_DONGLE_CHECK; + break; + + case SIRDEV_STATE_DONGLE_CHECK: + ret = sirdev_tx_complete_fsm(dev); + if (ret < 0) { + fsm->result = ret; + next_state = SIRDEV_STATE_ERROR; + break; + } + if ((delay=ret) != 0) + break; + + if (dev->dongle_drv) { + fsm->substate = SIRDEV_STATE_DONGLE_RESET; + next_state = SIRDEV_STATE_DONGLE_RESET; + } + else { + dev->speed = fsm->param; + next_state = SIRDEV_STATE_PORT_SPEED; + } + break; + + case SIRDEV_STATE_DONGLE_RESET: + if (dev->dongle_drv->reset) { + ret = dev->dongle_drv->reset(dev); + if (ret < 0) { + fsm->result = ret; + next_state = SIRDEV_STATE_ERROR; + break; + } + } + else + ret = 0; + if ((delay=ret) == 0) { + /* set serial port according to dongle default speed */ + if (dev->drv->set_speed) + dev->drv->set_speed(dev, dev->speed); + fsm->substate = SIRDEV_STATE_DONGLE_SPEED; + next_state = SIRDEV_STATE_DONGLE_SPEED; + } + break; + + case SIRDEV_STATE_DONGLE_SPEED: + if (dev->dongle_drv->set_speed) { + ret = dev->dongle_drv->set_speed(dev, fsm->param); + if (ret < 0) { + fsm->result = ret; + next_state = SIRDEV_STATE_ERROR; + break; + } + } + else + ret = 0; + if ((delay=ret) == 0) + next_state = SIRDEV_STATE_PORT_SPEED; + break; + + case SIRDEV_STATE_PORT_SPEED: + /* Finally we are ready to change the serial port speed */ + if (dev->drv->set_speed) + dev->drv->set_speed(dev, dev->speed); + dev->new_speed = 0; + next_state = SIRDEV_STATE_DONE; + break; + + case SIRDEV_STATE_DONE: + /* Signal network layer so it can send more frames */ + netif_wake_queue(dev->netdev); + next_state = SIRDEV_STATE_COMPLETE; + break; + + default: + net_err_ratelimited("%s - undefined state\n", __func__); + fsm->result = -EINVAL; + /* fall thru */ + + case SIRDEV_STATE_ERROR: + net_err_ratelimited("%s - error: %d\n", + __func__, fsm->result); + +#if 0 /* don't enable this before we have netdev->tx_timeout to recover */ + netif_stop_queue(dev->netdev); +#else + netif_wake_queue(dev->netdev); +#endif + /* fall thru */ + + case SIRDEV_STATE_COMPLETE: + /* config change finished, so we are not busy any longer */ + sirdev_enable_rx(dev); + up(&fsm->sem); + return; + } + fsm->state = next_state; + } while(!delay); + + queue_delayed_work(irda_sir_wq, &fsm->work, msecs_to_jiffies(delay)); +} + +/* schedule some device configuration task for execution by kIrDAd + * on behalf of the above state machine. + * can be called from process or interrupt/tasklet context. + */ + +int sirdev_schedule_request(struct sir_dev *dev, int initial_state, unsigned param) +{ + struct sir_fsm *fsm = &dev->fsm; + + pr_debug("%s - state=0x%04x / param=%u\n", __func__, + initial_state, param); + + if (down_trylock(&fsm->sem)) { + if (in_interrupt() || in_atomic() || irqs_disabled()) { + pr_debug("%s(), state machine busy!\n", __func__); + return -EWOULDBLOCK; + } else + down(&fsm->sem); + } + + if (fsm->state == SIRDEV_STATE_DEAD) { + /* race with sirdev_close should never happen */ + net_err_ratelimited("%s(), instance staled!\n", __func__); + up(&fsm->sem); + return -ESTALE; /* or better EPIPE? */ + } + + netif_stop_queue(dev->netdev); + atomic_set(&dev->enable_rx, 0); + + fsm->state = initial_state; + fsm->param = param; + fsm->result = 0; + + INIT_DELAYED_WORK(&fsm->work, sirdev_config_fsm); + queue_delayed_work(irda_sir_wq, &fsm->work, 0); + return 0; +} + + +/***************************************************************************/ + +void sirdev_enable_rx(struct sir_dev *dev) +{ + if (unlikely(atomic_read(&dev->enable_rx))) + return; + + /* flush rx-buffer - should also help in case of problems with echo cancelation */ + dev->rx_buff.data = dev->rx_buff.head; + dev->rx_buff.len = 0; + dev->rx_buff.in_frame = FALSE; + dev->rx_buff.state = OUTSIDE_FRAME; + atomic_set(&dev->enable_rx, 1); +} + +static int sirdev_is_receiving(struct sir_dev *dev) +{ + if (!atomic_read(&dev->enable_rx)) + return 0; + + return dev->rx_buff.state != OUTSIDE_FRAME; +} + +int sirdev_set_dongle(struct sir_dev *dev, IRDA_DONGLE type) +{ + int err; + + pr_debug("%s : requesting dongle %d.\n", __func__, type); + + err = sirdev_schedule_dongle_open(dev, type); + if (unlikely(err)) + return err; + down(&dev->fsm.sem); /* block until config change completed */ + err = dev->fsm.result; + up(&dev->fsm.sem); + return err; +} +EXPORT_SYMBOL(sirdev_set_dongle); + +/* used by dongle drivers for dongle programming */ + +int sirdev_raw_write(struct sir_dev *dev, const char *buf, int len) +{ + unsigned long flags; + int ret; + + if (unlikely(len > dev->tx_buff.truesize)) + return -ENOSPC; + + spin_lock_irqsave(&dev->tx_lock, flags); /* serialize with other tx operations */ + while (dev->tx_buff.len > 0) { /* wait until tx idle */ + spin_unlock_irqrestore(&dev->tx_lock, flags); + msleep(10); + spin_lock_irqsave(&dev->tx_lock, flags); + } + + dev->tx_buff.data = dev->tx_buff.head; + memcpy(dev->tx_buff.data, buf, len); + dev->tx_buff.len = len; + + ret = dev->drv->do_write(dev, dev->tx_buff.data, dev->tx_buff.len); + if (ret > 0) { + pr_debug("%s(), raw-tx started\n", __func__); + + dev->tx_buff.data += ret; + dev->tx_buff.len -= ret; + dev->raw_tx = 1; + ret = len; /* all data is going to be sent */ + } + spin_unlock_irqrestore(&dev->tx_lock, flags); + return ret; +} +EXPORT_SYMBOL(sirdev_raw_write); + +/* seems some dongle drivers may need this */ + +int sirdev_raw_read(struct sir_dev *dev, char *buf, int len) +{ + int count; + + if (atomic_read(&dev->enable_rx)) + return -EIO; /* fail if we expect irda-frames */ + + count = (len < dev->rx_buff.len) ? len : dev->rx_buff.len; + + if (count > 0) { + memcpy(buf, dev->rx_buff.data, count); + dev->rx_buff.data += count; + dev->rx_buff.len -= count; + } + + /* remaining stuff gets flushed when re-enabling normal rx */ + + return count; +} +EXPORT_SYMBOL(sirdev_raw_read); + +int sirdev_set_dtr_rts(struct sir_dev *dev, int dtr, int rts) +{ + int ret = -ENXIO; + if (dev->drv->set_dtr_rts) + ret = dev->drv->set_dtr_rts(dev, dtr, rts); + return ret; +} +EXPORT_SYMBOL(sirdev_set_dtr_rts); + +/**********************************************************************/ + +/* called from client driver - likely with bh-context - to indicate + * it made some progress with transmission. Hence we send the next + * chunk, if any, or complete the skb otherwise + */ + +void sirdev_write_complete(struct sir_dev *dev) +{ + unsigned long flags; + struct sk_buff *skb; + int actual = 0; + int err; + + spin_lock_irqsave(&dev->tx_lock, flags); + + pr_debug("%s() - dev->tx_buff.len = %d\n", + __func__, dev->tx_buff.len); + + if (likely(dev->tx_buff.len > 0)) { + /* Write data left in transmit buffer */ + actual = dev->drv->do_write(dev, dev->tx_buff.data, dev->tx_buff.len); + + if (likely(actual>0)) { + dev->tx_buff.data += actual; + dev->tx_buff.len -= actual; + } + else if (unlikely(actual<0)) { + /* could be dropped later when we have tx_timeout to recover */ + net_err_ratelimited("%s: drv->do_write failed (%d)\n", + __func__, actual); + if ((skb=dev->tx_skb) != NULL) { + dev->tx_skb = NULL; + dev_kfree_skb_any(skb); + dev->netdev->stats.tx_errors++; + dev->netdev->stats.tx_dropped++; + } + dev->tx_buff.len = 0; + } + if (dev->tx_buff.len > 0) + goto done; /* more data to send later */ + } + + if (unlikely(dev->raw_tx != 0)) { + /* in raw mode we are just done now after the buffer was sent + * completely. Since this was requested by some dongle driver + * running under the control of the irda-thread we must take + * care here not to re-enable the queue. The queue will be + * restarted when the irda-thread has completed the request. + */ + + pr_debug("%s(), raw-tx done\n", __func__); + dev->raw_tx = 0; + goto done; /* no post-frame handling in raw mode */ + } + + /* we have finished now sending this skb. + * update statistics and free the skb. + * finally we check and trigger a pending speed change, if any. + * if not we switch to rx mode and wake the queue for further + * packets. + * note the scheduled speed request blocks until the lower + * client driver and the corresponding hardware has really + * finished sending all data (xmit fifo drained f.e.) + * before the speed change gets finally done and the queue + * re-activated. + */ + + pr_debug("%s(), finished with frame!\n", __func__); + + if ((skb=dev->tx_skb) != NULL) { + dev->tx_skb = NULL; + dev->netdev->stats.tx_packets++; + dev->netdev->stats.tx_bytes += skb->len; + dev_kfree_skb_any(skb); + } + + if (unlikely(dev->new_speed > 0)) { + pr_debug("%s(), Changing speed!\n", __func__); + err = sirdev_schedule_speed(dev, dev->new_speed); + if (unlikely(err)) { + /* should never happen + * forget the speed change and hope the stack recovers + */ + net_err_ratelimited("%s - schedule speed change failed: %d\n", + __func__, err); + netif_wake_queue(dev->netdev); + } + /* else: success + * speed change in progress now + * on completion dev->new_speed gets cleared, + * rx-reenabled and the queue restarted + */ + } + else { + sirdev_enable_rx(dev); + netif_wake_queue(dev->netdev); + } + +done: + spin_unlock_irqrestore(&dev->tx_lock, flags); +} +EXPORT_SYMBOL(sirdev_write_complete); + +/* called from client driver - likely with bh-context - to give us + * some more received bytes. We put them into the rx-buffer, + * normally unwrapping and building LAP-skb's (unless rx disabled) + */ + +int sirdev_receive(struct sir_dev *dev, const unsigned char *cp, size_t count) +{ + if (!dev || !dev->netdev) { + net_warn_ratelimited("%s(), not ready yet!\n", __func__); + return -1; + } + + if (!dev->irlap) { + net_warn_ratelimited("%s - too early: %p / %zd!\n", + __func__, cp, count); + return -1; + } + + if (cp==NULL) { + /* error already at lower level receive + * just update stats and set media busy + */ + irda_device_set_media_busy(dev->netdev, TRUE); + dev->netdev->stats.rx_dropped++; + pr_debug("%s; rx-drop: %zd\n", __func__, count); + return 0; + } + + /* Read the characters into the buffer */ + if (likely(atomic_read(&dev->enable_rx))) { + while (count--) + /* Unwrap and destuff one byte */ + async_unwrap_char(dev->netdev, &dev->netdev->stats, + &dev->rx_buff, *cp++); + } else { + while (count--) { + /* rx not enabled: save the raw bytes and never + * trigger any netif_rx. The received bytes are flushed + * later when we re-enable rx but might be read meanwhile + * by the dongle driver. + */ + dev->rx_buff.data[dev->rx_buff.len++] = *cp++; + + /* What should we do when the buffer is full? */ + if (unlikely(dev->rx_buff.len == dev->rx_buff.truesize)) + dev->rx_buff.len = 0; + } + } + + return 0; +} +EXPORT_SYMBOL(sirdev_receive); + +/**********************************************************************/ + +/* callbacks from network layer */ + +static netdev_tx_t sirdev_hard_xmit(struct sk_buff *skb, + struct net_device *ndev) +{ + struct sir_dev *dev = netdev_priv(ndev); + unsigned long flags; + int actual = 0; + int err; + s32 speed; + + IRDA_ASSERT(dev != NULL, return NETDEV_TX_OK;); + + netif_stop_queue(ndev); + + pr_debug("%s(), skb->len = %d\n", __func__, skb->len); + + speed = irda_get_next_speed(skb); + if ((speed != dev->speed) && (speed != -1)) { + if (!skb->len) { + err = sirdev_schedule_speed(dev, speed); + if (unlikely(err == -EWOULDBLOCK)) { + /* Failed to initiate the speed change, likely the fsm + * is still busy (pretty unlikely, but...) + * We refuse to accept the skb and return with the queue + * stopped so the network layer will retry after the + * fsm completes and wakes the queue. + */ + return NETDEV_TX_BUSY; + } + else if (unlikely(err)) { + /* other fatal error - forget the speed change and + * hope the stack will recover somehow + */ + netif_start_queue(ndev); + } + /* else: success + * speed change in progress now + * on completion the queue gets restarted + */ + + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } else + dev->new_speed = speed; + } + + /* Init tx buffer*/ + dev->tx_buff.data = dev->tx_buff.head; + + /* Check problems */ + if(spin_is_locked(&dev->tx_lock)) { + pr_debug("%s(), write not completed\n", __func__); + } + + /* serialize with write completion */ + spin_lock_irqsave(&dev->tx_lock, flags); + + /* Copy skb to tx_buff while wrapping, stuffing and making CRC */ + dev->tx_buff.len = async_wrap_skb(skb, dev->tx_buff.data, dev->tx_buff.truesize); + + /* transmission will start now - disable receive. + * if we are just in the middle of an incoming frame, + * treat it as collision. probably it's a good idea to + * reset the rx_buf OUTSIDE_FRAME in this case too? + */ + atomic_set(&dev->enable_rx, 0); + if (unlikely(sirdev_is_receiving(dev))) + dev->netdev->stats.collisions++; + + actual = dev->drv->do_write(dev, dev->tx_buff.data, dev->tx_buff.len); + + if (likely(actual > 0)) { + dev->tx_skb = skb; + dev->tx_buff.data += actual; + dev->tx_buff.len -= actual; + } + else if (unlikely(actual < 0)) { + /* could be dropped later when we have tx_timeout to recover */ + net_err_ratelimited("%s: drv->do_write failed (%d)\n", + __func__, actual); + dev_kfree_skb_any(skb); + dev->netdev->stats.tx_errors++; + dev->netdev->stats.tx_dropped++; + netif_wake_queue(ndev); + } + spin_unlock_irqrestore(&dev->tx_lock, flags); + + return NETDEV_TX_OK; +} + +/* called from network layer with rtnl hold */ + +static int sirdev_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) +{ + struct if_irda_req *irq = (struct if_irda_req *) rq; + struct sir_dev *dev = netdev_priv(ndev); + int ret = 0; + + IRDA_ASSERT(dev != NULL, return -1;); + + pr_debug("%s(), %s, (cmd=0x%X)\n", __func__, ndev->name, cmd); + + switch (cmd) { + case SIOCSBANDWIDTH: /* Set bandwidth */ + if (!capable(CAP_NET_ADMIN)) + ret = -EPERM; + else + ret = sirdev_schedule_speed(dev, irq->ifr_baudrate); + /* cannot sleep here for completion + * we are called from network layer with rtnl hold + */ + break; + + case SIOCSDONGLE: /* Set dongle */ + if (!capable(CAP_NET_ADMIN)) + ret = -EPERM; + else + ret = sirdev_schedule_dongle_open(dev, irq->ifr_dongle); + /* cannot sleep here for completion + * we are called from network layer with rtnl hold + */ + break; + + case SIOCSMEDIABUSY: /* Set media busy */ + if (!capable(CAP_NET_ADMIN)) + ret = -EPERM; + else + irda_device_set_media_busy(dev->netdev, TRUE); + break; + + case SIOCGRECEIVING: /* Check if we are receiving right now */ + irq->ifr_receiving = sirdev_is_receiving(dev); + break; + + case SIOCSDTRRTS: + if (!capable(CAP_NET_ADMIN)) + ret = -EPERM; + else + ret = sirdev_schedule_dtr_rts(dev, irq->ifr_dtr, irq->ifr_rts); + /* cannot sleep here for completion + * we are called from network layer with rtnl hold + */ + break; + + case SIOCSMODE: +#if 0 + if (!capable(CAP_NET_ADMIN)) + ret = -EPERM; + else + ret = sirdev_schedule_mode(dev, irq->ifr_mode); + /* cannot sleep here for completion + * we are called from network layer with rtnl hold + */ + break; +#endif + default: + ret = -EOPNOTSUPP; + } + + return ret; +} + +/* ----------------------------------------------------------------------------- */ + +#define SIRBUF_ALLOCSIZE 4269 /* worst case size of a wrapped IrLAP frame */ + +static int sirdev_alloc_buffers(struct sir_dev *dev) +{ + dev->tx_buff.truesize = SIRBUF_ALLOCSIZE; + dev->rx_buff.truesize = IRDA_SKB_MAX_MTU; + + /* Bootstrap ZeroCopy Rx */ + dev->rx_buff.skb = __netdev_alloc_skb(dev->netdev, dev->rx_buff.truesize, + GFP_KERNEL); + if (dev->rx_buff.skb == NULL) + return -ENOMEM; + skb_reserve(dev->rx_buff.skb, 1); + dev->rx_buff.head = dev->rx_buff.skb->data; + + dev->tx_buff.head = kmalloc(dev->tx_buff.truesize, GFP_KERNEL); + if (dev->tx_buff.head == NULL) { + kfree_skb(dev->rx_buff.skb); + dev->rx_buff.skb = NULL; + dev->rx_buff.head = NULL; + return -ENOMEM; + } + + dev->tx_buff.data = dev->tx_buff.head; + dev->rx_buff.data = dev->rx_buff.head; + dev->tx_buff.len = 0; + dev->rx_buff.len = 0; + + dev->rx_buff.in_frame = FALSE; + dev->rx_buff.state = OUTSIDE_FRAME; + return 0; +}; + +static void sirdev_free_buffers(struct sir_dev *dev) +{ + kfree_skb(dev->rx_buff.skb); + kfree(dev->tx_buff.head); + dev->rx_buff.head = dev->tx_buff.head = NULL; + dev->rx_buff.skb = NULL; +} + +static int sirdev_open(struct net_device *ndev) +{ + struct sir_dev *dev = netdev_priv(ndev); + const struct sir_driver *drv = dev->drv; + + if (!drv) + return -ENODEV; + + /* increase the reference count of the driver module before doing serious stuff */ + if (!try_module_get(drv->owner)) + return -ESTALE; + + if (sirdev_alloc_buffers(dev)) + goto errout_dec; + + if (!dev->drv->start_dev || dev->drv->start_dev(dev)) + goto errout_free; + + sirdev_enable_rx(dev); + dev->raw_tx = 0; + + netif_start_queue(ndev); + dev->irlap = irlap_open(ndev, &dev->qos, dev->hwname); + if (!dev->irlap) + goto errout_stop; + + netif_wake_queue(ndev); + + pr_debug("%s - done, speed = %d\n", __func__, dev->speed); + + return 0; + +errout_stop: + atomic_set(&dev->enable_rx, 0); + if (dev->drv->stop_dev) + dev->drv->stop_dev(dev); +errout_free: + sirdev_free_buffers(dev); +errout_dec: + module_put(drv->owner); + return -EAGAIN; +} + +static int sirdev_close(struct net_device *ndev) +{ + struct sir_dev *dev = netdev_priv(ndev); + const struct sir_driver *drv; + +/* pr_debug("%s\n", __func__); */ + + netif_stop_queue(ndev); + + down(&dev->fsm.sem); /* block on pending config completion */ + + atomic_set(&dev->enable_rx, 0); + + if (unlikely(!dev->irlap)) + goto out; + irlap_close(dev->irlap); + dev->irlap = NULL; + + drv = dev->drv; + if (unlikely(!drv || !dev->priv)) + goto out; + + if (drv->stop_dev) + drv->stop_dev(dev); + + sirdev_free_buffers(dev); + module_put(drv->owner); + +out: + dev->speed = 0; + up(&dev->fsm.sem); + return 0; +} + +static const struct net_device_ops sirdev_ops = { + .ndo_start_xmit = sirdev_hard_xmit, + .ndo_open = sirdev_open, + .ndo_stop = sirdev_close, + .ndo_do_ioctl = sirdev_ioctl, +}; +/* ----------------------------------------------------------------------------- */ + +struct sir_dev * sirdev_get_instance(const struct sir_driver *drv, const char *name) +{ + struct net_device *ndev; + struct sir_dev *dev; + + pr_debug("%s - %s\n", __func__, name); + + /* instead of adding tests to protect against drv->do_write==NULL + * at several places we refuse to create a sir_dev instance for + * drivers which don't implement do_write. + */ + if (!drv || !drv->do_write) + return NULL; + + /* + * Allocate new instance of the device + */ + ndev = alloc_irdadev(sizeof(*dev)); + if (ndev == NULL) { + net_err_ratelimited("%s - Can't allocate memory for IrDA control block!\n", + __func__); + goto out; + } + dev = netdev_priv(ndev); + + irda_init_max_qos_capabilies(&dev->qos); + dev->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|IR_115200; + dev->qos.min_turn_time.bits = drv->qos_mtt_bits; + irda_qos_bits_to_value(&dev->qos); + + strncpy(dev->hwname, name, sizeof(dev->hwname)-1); + + atomic_set(&dev->enable_rx, 0); + dev->tx_skb = NULL; + + spin_lock_init(&dev->tx_lock); + sema_init(&dev->fsm.sem, 1); + + dev->drv = drv; + dev->netdev = ndev; + + /* Override the network functions we need to use */ + ndev->netdev_ops = &sirdev_ops; + + if (register_netdev(ndev)) { + net_err_ratelimited("%s(), register_netdev() failed!\n", + __func__); + goto out_freenetdev; + } + + return dev; + +out_freenetdev: + free_netdev(ndev); +out: + return NULL; +} +EXPORT_SYMBOL(sirdev_get_instance); + +int sirdev_put_instance(struct sir_dev *dev) +{ + int err = 0; + + pr_debug("%s\n", __func__); + + atomic_set(&dev->enable_rx, 0); + + netif_carrier_off(dev->netdev); + netif_device_detach(dev->netdev); + + if (dev->dongle_drv) + err = sirdev_schedule_dongle_close(dev); + if (err) + net_err_ratelimited("%s - error %d\n", __func__, err); + + sirdev_close(dev->netdev); + + down(&dev->fsm.sem); + dev->fsm.state = SIRDEV_STATE_DEAD; /* mark staled */ + dev->dongle_drv = NULL; + dev->priv = NULL; + up(&dev->fsm.sem); + + /* Remove netdevice */ + unregister_netdev(dev->netdev); + + free_netdev(dev->netdev); + + return 0; +} +EXPORT_SYMBOL(sirdev_put_instance); + +static int __init sir_wq_init(void) +{ + irda_sir_wq = create_singlethread_workqueue("irda_sir_wq"); + if (!irda_sir_wq) + return -ENOMEM; + return 0; +} + +static void __exit sir_wq_exit(void) +{ + destroy_workqueue(irda_sir_wq); +} + +module_init(sir_wq_init); +module_exit(sir_wq_exit); + +MODULE_AUTHOR("Martin Diehl <info@mdiehl.de>"); +MODULE_DESCRIPTION("IrDA SIR core"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/irda/drivers/sir_dongle.c b/drivers/staging/irda/drivers/sir_dongle.c new file mode 100644 index 000000000000..7436f73ff1bb --- /dev/null +++ b/drivers/staging/irda/drivers/sir_dongle.c @@ -0,0 +1,133 @@ +/********************************************************************* + * + * sir_dongle.c: manager for serial dongle protocol drivers + * + * Copyright (c) 2002 Martin Diehl + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + ********************************************************************/ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/kmod.h> +#include <linux/mutex.h> + +#include <net/irda/irda.h> + +#include "sir-dev.h" + +/************************************************************************** + * + * dongle registration and attachment + * + */ + +static LIST_HEAD(dongle_list); /* list of registered dongle drivers */ +static DEFINE_MUTEX(dongle_list_lock); /* protects the list */ + +int irda_register_dongle(struct dongle_driver *new) +{ + struct list_head *entry; + struct dongle_driver *drv; + + pr_debug("%s : registering dongle \"%s\" (%d).\n", + __func__, new->driver_name, new->type); + + mutex_lock(&dongle_list_lock); + list_for_each(entry, &dongle_list) { + drv = list_entry(entry, struct dongle_driver, dongle_list); + if (new->type == drv->type) { + mutex_unlock(&dongle_list_lock); + return -EEXIST; + } + } + list_add(&new->dongle_list, &dongle_list); + mutex_unlock(&dongle_list_lock); + return 0; +} +EXPORT_SYMBOL(irda_register_dongle); + +int irda_unregister_dongle(struct dongle_driver *drv) +{ + mutex_lock(&dongle_list_lock); + list_del(&drv->dongle_list); + mutex_unlock(&dongle_list_lock); + return 0; +} +EXPORT_SYMBOL(irda_unregister_dongle); + +int sirdev_get_dongle(struct sir_dev *dev, IRDA_DONGLE type) +{ + struct list_head *entry; + const struct dongle_driver *drv = NULL; + int err = -EINVAL; + + request_module("irda-dongle-%d", type); + + if (dev->dongle_drv != NULL) + return -EBUSY; + + /* serialize access to the list of registered dongles */ + mutex_lock(&dongle_list_lock); + + list_for_each(entry, &dongle_list) { + drv = list_entry(entry, struct dongle_driver, dongle_list); + if (drv->type == type) + break; + else + drv = NULL; + } + + if (!drv) { + err = -ENODEV; + goto out_unlock; /* no such dongle */ + } + + /* handling of SMP races with dongle module removal - three cases: + * 1) dongle driver was already unregistered - then we haven't found the + * requested dongle above and are already out here + * 2) the module is already marked deleted but the driver is still + * registered - then the try_module_get() below will fail + * 3) the try_module_get() below succeeds before the module is marked + * deleted - then sys_delete_module() fails and prevents the removal + * because the module is in use. + */ + + if (!try_module_get(drv->owner)) { + err = -ESTALE; + goto out_unlock; /* rmmod already pending */ + } + dev->dongle_drv = drv; + + if (!drv->open || (err=drv->open(dev))!=0) + goto out_reject; /* failed to open driver */ + + mutex_unlock(&dongle_list_lock); + return 0; + +out_reject: + dev->dongle_drv = NULL; + module_put(drv->owner); +out_unlock: + mutex_unlock(&dongle_list_lock); + return err; +} + +int sirdev_put_dongle(struct sir_dev *dev) +{ + const struct dongle_driver *drv = dev->dongle_drv; + + if (drv) { + if (drv->close) + drv->close(dev); /* close this dongle instance */ + + dev->dongle_drv = NULL; /* unlink the dongle driver */ + module_put(drv->owner);/* decrement driver's module refcount */ + } + + return 0; +} diff --git a/drivers/staging/irda/drivers/smsc-ircc2.c b/drivers/staging/irda/drivers/smsc-ircc2.c new file mode 100644 index 000000000000..19a55cba6beb --- /dev/null +++ b/drivers/staging/irda/drivers/smsc-ircc2.c @@ -0,0 +1,3026 @@ +/********************************************************************* + * + * Description: Driver for the SMC Infrared Communications Controller + * Author: Daniele Peri (peri@csai.unipa.it) + * Created at: + * Modified at: + * Modified by: + * + * Copyright (c) 2002 Daniele Peri + * All Rights Reserved. + * Copyright (c) 2002 Jean Tourrilhes + * Copyright (c) 2006 Linus Walleij + * + * + * Based on smc-ircc.c: + * + * Copyright (c) 2001 Stefani Seibold + * Copyright (c) 1999-2001 Dag Brattli + * Copyright (c) 1998-1999 Thomas Davis, + * + * and irport.c: + * + * Copyright (c) 1997, 1998, 1999-2000 Dag Brattli, All Rights Reserved. + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + ********************************************************************/ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/skbuff.h> +#include <linux/netdevice.h> +#include <linux/ioport.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/rtnetlink.h> +#include <linux/serial_reg.h> +#include <linux/dma-mapping.h> +#include <linux/pnp.h> +#include <linux/platform_device.h> +#include <linux/gfp.h> + +#include <asm/io.h> +#include <asm/dma.h> +#include <asm/byteorder.h> + +#include <linux/spinlock.h> +#include <linux/pm.h> +#ifdef CONFIG_PCI +#include <linux/pci.h> +#endif + +#include <net/irda/wrapper.h> +#include <net/irda/irda.h> +#include <net/irda/irda_device.h> + +#include "smsc-ircc2.h" +#include "smsc-sio.h" + + +MODULE_AUTHOR("Daniele Peri <peri@csai.unipa.it>"); +MODULE_DESCRIPTION("SMC IrCC SIR/FIR controller driver"); +MODULE_LICENSE("GPL"); + +static bool smsc_nopnp = true; +module_param_named(nopnp, smsc_nopnp, bool, 0); +MODULE_PARM_DESC(nopnp, "Do not use PNP to detect controller settings, defaults to true"); + +#define DMA_INVAL 255 +static int ircc_dma = DMA_INVAL; +module_param_hw(ircc_dma, int, dma, 0); +MODULE_PARM_DESC(ircc_dma, "DMA channel"); + +#define IRQ_INVAL 255 +static int ircc_irq = IRQ_INVAL; +module_param_hw(ircc_irq, int, irq, 0); +MODULE_PARM_DESC(ircc_irq, "IRQ line"); + +static int ircc_fir; +module_param_hw(ircc_fir, int, ioport, 0); +MODULE_PARM_DESC(ircc_fir, "FIR Base Address"); + +static int ircc_sir; +module_param_hw(ircc_sir, int, ioport, 0); +MODULE_PARM_DESC(ircc_sir, "SIR Base Address"); + +static int ircc_cfg; +module_param_hw(ircc_cfg, int, ioport, 0); +MODULE_PARM_DESC(ircc_cfg, "Configuration register base address"); + +static int ircc_transceiver; +module_param(ircc_transceiver, int, 0); +MODULE_PARM_DESC(ircc_transceiver, "Transceiver type"); + +/* Types */ + +#ifdef CONFIG_PCI +struct smsc_ircc_subsystem_configuration { + unsigned short vendor; /* PCI vendor ID */ + unsigned short device; /* PCI vendor ID */ + unsigned short subvendor; /* PCI subsystem vendor ID */ + unsigned short subdevice; /* PCI subsystem device ID */ + unsigned short sir_io; /* I/O port for SIR */ + unsigned short fir_io; /* I/O port for FIR */ + unsigned char fir_irq; /* FIR IRQ */ + unsigned char fir_dma; /* FIR DMA */ + unsigned short cfg_base; /* I/O port for chip configuration */ + int (*preconfigure)(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf); /* Preconfig function */ + const char *name; /* name shown as info */ +}; +#endif + +struct smsc_transceiver { + char *name; + void (*set_for_speed)(int fir_base, u32 speed); + int (*probe)(int fir_base); +}; + +struct smsc_chip { + char *name; + #if 0 + u8 type; + #endif + u16 flags; + u8 devid; + u8 rev; +}; + +struct smsc_chip_address { + unsigned int cfg_base; + unsigned int type; +}; + +/* Private data for each instance */ +struct smsc_ircc_cb { + struct net_device *netdev; /* Yes! we are some kind of netdevice */ + struct irlap_cb *irlap; /* The link layer we are binded to */ + + chipio_t io; /* IrDA controller information */ + iobuff_t tx_buff; /* Transmit buffer */ + iobuff_t rx_buff; /* Receive buffer */ + dma_addr_t tx_buff_dma; + dma_addr_t rx_buff_dma; + + struct qos_info qos; /* QoS capabilities for this device */ + + spinlock_t lock; /* For serializing operations */ + + __u32 new_speed; + __u32 flags; /* Interface flags */ + + int tx_buff_offsets[10]; /* Offsets between frames in tx_buff */ + int tx_len; /* Number of frames in tx_buff */ + + int transceiver; + struct platform_device *pldev; +}; + +/* Constants */ + +#define SMSC_IRCC2_DRIVER_NAME "smsc-ircc2" + +#define SMSC_IRCC2_C_IRDA_FALLBACK_SPEED 9600 +#define SMSC_IRCC2_C_DEFAULT_TRANSCEIVER 1 +#define SMSC_IRCC2_C_NET_TIMEOUT 0 +#define SMSC_IRCC2_C_SIR_STOP 0 + +static const char *driver_name = SMSC_IRCC2_DRIVER_NAME; + +/* Prototypes */ + +static int smsc_ircc_open(unsigned int firbase, unsigned int sirbase, u8 dma, u8 irq); +static int smsc_ircc_present(unsigned int fir_base, unsigned int sir_base); +static void smsc_ircc_setup_io(struct smsc_ircc_cb *self, unsigned int fir_base, unsigned int sir_base, u8 dma, u8 irq); +static void smsc_ircc_setup_qos(struct smsc_ircc_cb *self); +static void smsc_ircc_init_chip(struct smsc_ircc_cb *self); +static int __exit smsc_ircc_close(struct smsc_ircc_cb *self); +static int smsc_ircc_dma_receive(struct smsc_ircc_cb *self); +static void smsc_ircc_dma_receive_complete(struct smsc_ircc_cb *self); +static void smsc_ircc_sir_receive(struct smsc_ircc_cb *self); +static netdev_tx_t smsc_ircc_hard_xmit_sir(struct sk_buff *skb, + struct net_device *dev); +static netdev_tx_t smsc_ircc_hard_xmit_fir(struct sk_buff *skb, + struct net_device *dev); +static void smsc_ircc_dma_xmit(struct smsc_ircc_cb *self, int bofs); +static void smsc_ircc_dma_xmit_complete(struct smsc_ircc_cb *self); +static void smsc_ircc_change_speed(struct smsc_ircc_cb *self, u32 speed); +static void smsc_ircc_set_sir_speed(struct smsc_ircc_cb *self, u32 speed); +static irqreturn_t smsc_ircc_interrupt(int irq, void *dev_id); +static irqreturn_t smsc_ircc_interrupt_sir(struct net_device *dev); +static void smsc_ircc_sir_start(struct smsc_ircc_cb *self); +#if SMSC_IRCC2_C_SIR_STOP +static void smsc_ircc_sir_stop(struct smsc_ircc_cb *self); +#endif +static void smsc_ircc_sir_write_wakeup(struct smsc_ircc_cb *self); +static int smsc_ircc_sir_write(int iobase, int fifo_size, __u8 *buf, int len); +static int smsc_ircc_net_open(struct net_device *dev); +static int smsc_ircc_net_close(struct net_device *dev); +static int smsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +#if SMSC_IRCC2_C_NET_TIMEOUT +static void smsc_ircc_timeout(struct net_device *dev); +#endif +static int smsc_ircc_is_receiving(struct smsc_ircc_cb *self); +static void smsc_ircc_probe_transceiver(struct smsc_ircc_cb *self); +static void smsc_ircc_set_transceiver_for_speed(struct smsc_ircc_cb *self, u32 speed); +static void smsc_ircc_sir_wait_hw_transmitter_finish(struct smsc_ircc_cb *self); + +/* Probing */ +static int __init smsc_ircc_look_for_chips(void); +static const struct smsc_chip * __init smsc_ircc_probe(unsigned short cfg_base, u8 reg, const struct smsc_chip *chip, char *type); +static int __init smsc_superio_flat(const struct smsc_chip *chips, unsigned short cfg_base, char *type); +static int __init smsc_superio_paged(const struct smsc_chip *chips, unsigned short cfg_base, char *type); +static int __init smsc_superio_fdc(unsigned short cfg_base); +static int __init smsc_superio_lpc(unsigned short cfg_base); +#ifdef CONFIG_PCI +static int __init preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuration *conf); +static int __init preconfigure_through_82801(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf); +static void __init preconfigure_ali_port(struct pci_dev *dev, + unsigned short port); +static int __init preconfigure_through_ali(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf); +static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, + unsigned short ircc_fir, + unsigned short ircc_sir, + unsigned char ircc_dma, + unsigned char ircc_irq); +#endif + +/* Transceivers specific functions */ + +static void smsc_ircc_set_transceiver_toshiba_sat1800(int fir_base, u32 speed); +static int smsc_ircc_probe_transceiver_toshiba_sat1800(int fir_base); +static void smsc_ircc_set_transceiver_smsc_ircc_fast_pin_select(int fir_base, u32 speed); +static int smsc_ircc_probe_transceiver_smsc_ircc_fast_pin_select(int fir_base); +static void smsc_ircc_set_transceiver_smsc_ircc_atc(int fir_base, u32 speed); +static int smsc_ircc_probe_transceiver_smsc_ircc_atc(int fir_base); + +/* Power Management */ + +static int smsc_ircc_suspend(struct platform_device *dev, pm_message_t state); +static int smsc_ircc_resume(struct platform_device *dev); + +static struct platform_driver smsc_ircc_driver = { + .suspend = smsc_ircc_suspend, + .resume = smsc_ircc_resume, + .driver = { + .name = SMSC_IRCC2_DRIVER_NAME, + }, +}; + +/* Transceivers for SMSC-ircc */ + +static struct smsc_transceiver smsc_transceivers[] = +{ + { "Toshiba Satellite 1800 (GP data pin select)", smsc_ircc_set_transceiver_toshiba_sat1800, smsc_ircc_probe_transceiver_toshiba_sat1800 }, + { "Fast pin select", smsc_ircc_set_transceiver_smsc_ircc_fast_pin_select, smsc_ircc_probe_transceiver_smsc_ircc_fast_pin_select }, + { "ATC IRMode", smsc_ircc_set_transceiver_smsc_ircc_atc, smsc_ircc_probe_transceiver_smsc_ircc_atc }, + { NULL, NULL } +}; +#define SMSC_IRCC2_C_NUMBER_OF_TRANSCEIVERS (ARRAY_SIZE(smsc_transceivers) - 1) + +/* SMC SuperIO chipsets definitions */ + +#define KEY55_1 0 /* SuperIO Configuration mode with Key <0x55> */ +#define KEY55_2 1 /* SuperIO Configuration mode with Key <0x55,0x55> */ +#define NoIRDA 2 /* SuperIO Chip has no IRDA Port */ +#define SIR 0 /* SuperIO Chip has only slow IRDA */ +#define FIR 4 /* SuperIO Chip has fast IRDA */ +#define SERx4 8 /* SuperIO Chip supports 115,2 KBaud * 4=460,8 KBaud */ + +static struct smsc_chip __initdata fdc_chips_flat[] = +{ + /* Base address 0x3f0 or 0x370 */ + { "37C44", KEY55_1|NoIRDA, 0x00, 0x00 }, /* This chip cannot be detected */ + { "37C665GT", KEY55_2|NoIRDA, 0x65, 0x01 }, + { "37C665GT", KEY55_2|NoIRDA, 0x66, 0x01 }, + { "37C669", KEY55_2|SIR|SERx4, 0x03, 0x02 }, + { "37C669", KEY55_2|SIR|SERx4, 0x04, 0x02 }, /* ID? */ + { "37C78", KEY55_2|NoIRDA, 0x78, 0x00 }, + { "37N769", KEY55_1|FIR|SERx4, 0x28, 0x00 }, + { "37N869", KEY55_1|FIR|SERx4, 0x29, 0x00 }, + { NULL } +}; + +static struct smsc_chip __initdata fdc_chips_paged[] = +{ + /* Base address 0x3f0 or 0x370 */ + { "37B72X", KEY55_1|SIR|SERx4, 0x4c, 0x00 }, + { "37B77X", KEY55_1|SIR|SERx4, 0x43, 0x00 }, + { "37B78X", KEY55_1|SIR|SERx4, 0x44, 0x00 }, + { "37B80X", KEY55_1|SIR|SERx4, 0x42, 0x00 }, + { "37C67X", KEY55_1|FIR|SERx4, 0x40, 0x00 }, + { "37C93X", KEY55_2|SIR|SERx4, 0x02, 0x01 }, + { "37C93XAPM", KEY55_1|SIR|SERx4, 0x30, 0x01 }, + { "37C93XFR", KEY55_2|FIR|SERx4, 0x03, 0x01 }, + { "37M707", KEY55_1|SIR|SERx4, 0x42, 0x00 }, + { "37M81X", KEY55_1|SIR|SERx4, 0x4d, 0x00 }, + { "37N958FR", KEY55_1|FIR|SERx4, 0x09, 0x04 }, + { "37N971", KEY55_1|FIR|SERx4, 0x0a, 0x00 }, + { "37N972", KEY55_1|FIR|SERx4, 0x0b, 0x00 }, + { NULL } +}; + +static struct smsc_chip __initdata lpc_chips_flat[] = +{ + /* Base address 0x2E or 0x4E */ + { "47N227", KEY55_1|FIR|SERx4, 0x5a, 0x00 }, + { "47N227", KEY55_1|FIR|SERx4, 0x7a, 0x00 }, + { "47N267", KEY55_1|FIR|SERx4, 0x5e, 0x00 }, + { NULL } +}; + +static struct smsc_chip __initdata lpc_chips_paged[] = +{ + /* Base address 0x2E or 0x4E */ + { "47B27X", KEY55_1|SIR|SERx4, 0x51, 0x00 }, + { "47B37X", KEY55_1|SIR|SERx4, 0x52, 0x00 }, + { "47M10X", KEY55_1|SIR|SERx4, 0x59, 0x00 }, + { "47M120", KEY55_1|NoIRDA|SERx4, 0x5c, 0x00 }, + { "47M13X", KEY55_1|SIR|SERx4, 0x59, 0x00 }, + { "47M14X", KEY55_1|SIR|SERx4, 0x5f, 0x00 }, + { "47N252", KEY55_1|FIR|SERx4, 0x0e, 0x00 }, + { "47S42X", KEY55_1|SIR|SERx4, 0x57, 0x00 }, + { NULL } +}; + +#define SMSCSIO_TYPE_FDC 1 +#define SMSCSIO_TYPE_LPC 2 +#define SMSCSIO_TYPE_FLAT 4 +#define SMSCSIO_TYPE_PAGED 8 + +static struct smsc_chip_address __initdata possible_addresses[] = +{ + { 0x3f0, SMSCSIO_TYPE_FDC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED }, + { 0x370, SMSCSIO_TYPE_FDC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED }, + { 0xe0, SMSCSIO_TYPE_FDC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED }, + { 0x2e, SMSCSIO_TYPE_LPC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED }, + { 0x4e, SMSCSIO_TYPE_LPC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED }, + { 0, 0 } +}; + +/* Globals */ + +static struct smsc_ircc_cb *dev_self[] = { NULL, NULL }; +static unsigned short dev_count; + +static inline void register_bank(int iobase, int bank) +{ + outb(((inb(iobase + IRCC_MASTER) & 0xf0) | (bank & 0x07)), + iobase + IRCC_MASTER); +} + +/* PNP hotplug support */ +static const struct pnp_device_id smsc_ircc_pnp_table[] = { + { .id = "SMCf010", .driver_data = 0 }, + /* and presumably others */ + { } +}; +MODULE_DEVICE_TABLE(pnp, smsc_ircc_pnp_table); + +static int pnp_driver_registered; + +#ifdef CONFIG_PNP +static int smsc_ircc_pnp_probe(struct pnp_dev *dev, + const struct pnp_device_id *dev_id) +{ + unsigned int firbase, sirbase; + u8 dma, irq; + + if (!(pnp_port_valid(dev, 0) && pnp_port_valid(dev, 1) && + pnp_dma_valid(dev, 0) && pnp_irq_valid(dev, 0))) + return -EINVAL; + + sirbase = pnp_port_start(dev, 0); + firbase = pnp_port_start(dev, 1); + dma = pnp_dma(dev, 0); + irq = pnp_irq(dev, 0); + + if (smsc_ircc_open(firbase, sirbase, dma, irq)) + return -ENODEV; + + return 0; +} + +static struct pnp_driver smsc_ircc_pnp_driver = { + .name = "smsc-ircc2", + .id_table = smsc_ircc_pnp_table, + .probe = smsc_ircc_pnp_probe, +}; +#else /* CONFIG_PNP */ +static struct pnp_driver smsc_ircc_pnp_driver; +#endif + +/******************************************************************************* + * + * + * SMSC-ircc stuff + * + * + *******************************************************************************/ + +static int __init smsc_ircc_legacy_probe(void) +{ + int ret = 0; + +#ifdef CONFIG_PCI + if (smsc_ircc_preconfigure_subsystems(ircc_cfg, ircc_fir, ircc_sir, ircc_dma, ircc_irq) < 0) { + /* Ignore errors from preconfiguration */ + net_err_ratelimited("%s, Preconfiguration failed !\n", + driver_name); + } +#endif + + if (ircc_fir > 0 && ircc_sir > 0) { + net_info_ratelimited(" Overriding FIR address 0x%04x\n", + ircc_fir); + net_info_ratelimited(" Overriding SIR address 0x%04x\n", + ircc_sir); + + if (smsc_ircc_open(ircc_fir, ircc_sir, ircc_dma, ircc_irq)) + ret = -ENODEV; + } else { + ret = -ENODEV; + + /* try user provided configuration register base address */ + if (ircc_cfg > 0) { + net_info_ratelimited(" Overriding configuration address 0x%04x\n", + ircc_cfg); + if (!smsc_superio_fdc(ircc_cfg)) + ret = 0; + if (!smsc_superio_lpc(ircc_cfg)) + ret = 0; + } + + if (smsc_ircc_look_for_chips() > 0) + ret = 0; + } + return ret; +} + +/* + * Function smsc_ircc_init () + * + * Initialize chip. Just try to find out how many chips we are dealing with + * and where they are + */ +static int __init smsc_ircc_init(void) +{ + int ret; + + pr_debug("%s\n", __func__); + + ret = platform_driver_register(&smsc_ircc_driver); + if (ret) { + net_err_ratelimited("%s, Can't register driver!\n", + driver_name); + return ret; + } + + dev_count = 0; + + if (smsc_nopnp || !pnp_platform_devices || + ircc_cfg || ircc_fir || ircc_sir || + ircc_dma != DMA_INVAL || ircc_irq != IRQ_INVAL) { + ret = smsc_ircc_legacy_probe(); + } else { + if (pnp_register_driver(&smsc_ircc_pnp_driver) == 0) + pnp_driver_registered = 1; + } + + if (ret) { + if (pnp_driver_registered) + pnp_unregister_driver(&smsc_ircc_pnp_driver); + platform_driver_unregister(&smsc_ircc_driver); + } + + return ret; +} + +static netdev_tx_t smsc_ircc_net_xmit(struct sk_buff *skb, + struct net_device *dev) +{ + struct smsc_ircc_cb *self = netdev_priv(dev); + + if (self->io.speed > 115200) + return smsc_ircc_hard_xmit_fir(skb, dev); + else + return smsc_ircc_hard_xmit_sir(skb, dev); +} + +static const struct net_device_ops smsc_ircc_netdev_ops = { + .ndo_open = smsc_ircc_net_open, + .ndo_stop = smsc_ircc_net_close, + .ndo_do_ioctl = smsc_ircc_net_ioctl, + .ndo_start_xmit = smsc_ircc_net_xmit, +#if SMSC_IRCC2_C_NET_TIMEOUT + .ndo_tx_timeout = smsc_ircc_timeout, +#endif +}; + +/* + * Function smsc_ircc_open (firbase, sirbase, dma, irq) + * + * Try to open driver instance + * + */ +static int smsc_ircc_open(unsigned int fir_base, unsigned int sir_base, u8 dma, u8 irq) +{ + struct smsc_ircc_cb *self; + struct net_device *dev; + int err; + + pr_debug("%s\n", __func__); + + err = smsc_ircc_present(fir_base, sir_base); + if (err) + goto err_out; + + err = -ENOMEM; + if (dev_count >= ARRAY_SIZE(dev_self)) { + net_warn_ratelimited("%s(), too many devices!\n", __func__); + goto err_out1; + } + + /* + * Allocate new instance of the driver + */ + dev = alloc_irdadev(sizeof(struct smsc_ircc_cb)); + if (!dev) { + net_warn_ratelimited("%s() can't allocate net device\n", + __func__); + goto err_out1; + } + +#if SMSC_IRCC2_C_NET_TIMEOUT + dev->watchdog_timeo = HZ * 2; /* Allow enough time for speed change */ +#endif + dev->netdev_ops = &smsc_ircc_netdev_ops; + + self = netdev_priv(dev); + self->netdev = dev; + + /* Make ifconfig display some details */ + dev->base_addr = self->io.fir_base = fir_base; + dev->irq = self->io.irq = irq; + + /* Need to store self somewhere */ + dev_self[dev_count] = self; + spin_lock_init(&self->lock); + + self->rx_buff.truesize = SMSC_IRCC2_RX_BUFF_TRUESIZE; + self->tx_buff.truesize = SMSC_IRCC2_TX_BUFF_TRUESIZE; + + self->rx_buff.head = + dma_zalloc_coherent(NULL, self->rx_buff.truesize, + &self->rx_buff_dma, GFP_KERNEL); + if (self->rx_buff.head == NULL) + goto err_out2; + + self->tx_buff.head = + dma_zalloc_coherent(NULL, self->tx_buff.truesize, + &self->tx_buff_dma, GFP_KERNEL); + if (self->tx_buff.head == NULL) + goto err_out3; + + self->rx_buff.in_frame = FALSE; + self->rx_buff.state = OUTSIDE_FRAME; + self->tx_buff.data = self->tx_buff.head; + self->rx_buff.data = self->rx_buff.head; + + smsc_ircc_setup_io(self, fir_base, sir_base, dma, irq); + smsc_ircc_setup_qos(self); + smsc_ircc_init_chip(self); + + if (ircc_transceiver > 0 && + ircc_transceiver < SMSC_IRCC2_C_NUMBER_OF_TRANSCEIVERS) + self->transceiver = ircc_transceiver; + else + smsc_ircc_probe_transceiver(self); + + err = register_netdev(self->netdev); + if (err) { + net_err_ratelimited("%s, Network device registration failed!\n", + driver_name); + goto err_out4; + } + + self->pldev = platform_device_register_simple(SMSC_IRCC2_DRIVER_NAME, + dev_count, NULL, 0); + if (IS_ERR(self->pldev)) { + err = PTR_ERR(self->pldev); + goto err_out5; + } + platform_set_drvdata(self->pldev, self); + + net_info_ratelimited("IrDA: Registered device %s\n", dev->name); + dev_count++; + + return 0; + + err_out5: + unregister_netdev(self->netdev); + + err_out4: + dma_free_coherent(NULL, self->tx_buff.truesize, + self->tx_buff.head, self->tx_buff_dma); + err_out3: + dma_free_coherent(NULL, self->rx_buff.truesize, + self->rx_buff.head, self->rx_buff_dma); + err_out2: + free_netdev(self->netdev); + dev_self[dev_count] = NULL; + err_out1: + release_region(fir_base, SMSC_IRCC2_FIR_CHIP_IO_EXTENT); + release_region(sir_base, SMSC_IRCC2_SIR_CHIP_IO_EXTENT); + err_out: + return err; +} + +/* + * Function smsc_ircc_present(fir_base, sir_base) + * + * Check the smsc-ircc chip presence + * + */ +static int smsc_ircc_present(unsigned int fir_base, unsigned int sir_base) +{ + unsigned char low, high, chip, config, dma, irq, version; + + if (!request_region(fir_base, SMSC_IRCC2_FIR_CHIP_IO_EXTENT, + driver_name)) { + net_warn_ratelimited("%s: can't get fir_base of 0x%03x\n", + __func__, fir_base); + goto out1; + } + + if (!request_region(sir_base, SMSC_IRCC2_SIR_CHIP_IO_EXTENT, + driver_name)) { + net_warn_ratelimited("%s: can't get sir_base of 0x%03x\n", + __func__, sir_base); + goto out2; + } + + register_bank(fir_base, 3); + + high = inb(fir_base + IRCC_ID_HIGH); + low = inb(fir_base + IRCC_ID_LOW); + chip = inb(fir_base + IRCC_CHIP_ID); + version = inb(fir_base + IRCC_VERSION); + config = inb(fir_base + IRCC_INTERFACE); + dma = config & IRCC_INTERFACE_DMA_MASK; + irq = (config & IRCC_INTERFACE_IRQ_MASK) >> 4; + + if (high != 0x10 || low != 0xb8 || (chip != 0xf1 && chip != 0xf2)) { + net_warn_ratelimited("%s(), addr 0x%04x - no device found!\n", + __func__, fir_base); + goto out3; + } + net_info_ratelimited("SMsC IrDA Controller found\n IrCC version %d.%d, firport 0x%03x, sirport 0x%03x dma=%d, irq=%d\n", + chip & 0x0f, version, + fir_base, sir_base, dma, irq); + + return 0; + + out3: + release_region(sir_base, SMSC_IRCC2_SIR_CHIP_IO_EXTENT); + out2: + release_region(fir_base, SMSC_IRCC2_FIR_CHIP_IO_EXTENT); + out1: + return -ENODEV; +} + +/* + * Function smsc_ircc_setup_io(self, fir_base, sir_base, dma, irq) + * + * Setup I/O + * + */ +static void smsc_ircc_setup_io(struct smsc_ircc_cb *self, + unsigned int fir_base, unsigned int sir_base, + u8 dma, u8 irq) +{ + unsigned char config, chip_dma, chip_irq; + + register_bank(fir_base, 3); + config = inb(fir_base + IRCC_INTERFACE); + chip_dma = config & IRCC_INTERFACE_DMA_MASK; + chip_irq = (config & IRCC_INTERFACE_IRQ_MASK) >> 4; + + self->io.fir_base = fir_base; + self->io.sir_base = sir_base; + self->io.fir_ext = SMSC_IRCC2_FIR_CHIP_IO_EXTENT; + self->io.sir_ext = SMSC_IRCC2_SIR_CHIP_IO_EXTENT; + self->io.fifo_size = SMSC_IRCC2_FIFO_SIZE; + self->io.speed = SMSC_IRCC2_C_IRDA_FALLBACK_SPEED; + + if (irq != IRQ_INVAL) { + if (irq != chip_irq) + net_info_ratelimited("%s, Overriding IRQ - chip says %d, using %d\n", + driver_name, chip_irq, irq); + self->io.irq = irq; + } else + self->io.irq = chip_irq; + + if (dma != DMA_INVAL) { + if (dma != chip_dma) + net_info_ratelimited("%s, Overriding DMA - chip says %d, using %d\n", + driver_name, chip_dma, dma); + self->io.dma = dma; + } else + self->io.dma = chip_dma; + +} + +/* + * Function smsc_ircc_setup_qos(self) + * + * Setup qos + * + */ +static void smsc_ircc_setup_qos(struct smsc_ircc_cb *self) +{ + /* Initialize QoS for this device */ + irda_init_max_qos_capabilies(&self->qos); + + self->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600| + IR_115200|IR_576000|IR_1152000|(IR_4000000 << 8); + + self->qos.min_turn_time.bits = SMSC_IRCC2_MIN_TURN_TIME; + self->qos.window_size.bits = SMSC_IRCC2_WINDOW_SIZE; + irda_qos_bits_to_value(&self->qos); +} + +/* + * Function smsc_ircc_init_chip(self) + * + * Init chip + * + */ +static void smsc_ircc_init_chip(struct smsc_ircc_cb *self) +{ + int iobase = self->io.fir_base; + + register_bank(iobase, 0); + outb(IRCC_MASTER_RESET, iobase + IRCC_MASTER); + outb(0x00, iobase + IRCC_MASTER); + + register_bank(iobase, 1); + outb(((inb(iobase + IRCC_SCE_CFGA) & 0x87) | IRCC_CFGA_IRDA_SIR_A), + iobase + IRCC_SCE_CFGA); + +#ifdef smsc_669 /* Uses pin 88/89 for Rx/Tx */ + outb(((inb(iobase + IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_COM), + iobase + IRCC_SCE_CFGB); +#else + outb(((inb(iobase + IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_IR), + iobase + IRCC_SCE_CFGB); +#endif + (void) inb(iobase + IRCC_FIFO_THRESHOLD); + outb(SMSC_IRCC2_FIFO_THRESHOLD, iobase + IRCC_FIFO_THRESHOLD); + + register_bank(iobase, 4); + outb((inb(iobase + IRCC_CONTROL) & 0x30), iobase + IRCC_CONTROL); + + register_bank(iobase, 0); + outb(0, iobase + IRCC_LCR_A); + + smsc_ircc_set_sir_speed(self, SMSC_IRCC2_C_IRDA_FALLBACK_SPEED); + + /* Power on device */ + outb(0x00, iobase + IRCC_MASTER); +} + +/* + * Function smsc_ircc_net_ioctl (dev, rq, cmd) + * + * Process IOCTL commands for this device + * + */ +static int smsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct if_irda_req *irq = (struct if_irda_req *) rq; + struct smsc_ircc_cb *self; + unsigned long flags; + int ret = 0; + + IRDA_ASSERT(dev != NULL, return -1;); + + self = netdev_priv(dev); + + IRDA_ASSERT(self != NULL, return -1;); + + pr_debug("%s(), %s, (cmd=0x%X)\n", __func__, dev->name, cmd); + + switch (cmd) { + case SIOCSBANDWIDTH: /* Set bandwidth */ + if (!capable(CAP_NET_ADMIN)) + ret = -EPERM; + else { + /* Make sure we are the only one touching + * self->io.speed and the hardware - Jean II */ + spin_lock_irqsave(&self->lock, flags); + smsc_ircc_change_speed(self, irq->ifr_baudrate); + spin_unlock_irqrestore(&self->lock, flags); + } + break; + case SIOCSMEDIABUSY: /* Set media busy */ + if (!capable(CAP_NET_ADMIN)) { + ret = -EPERM; + break; + } + + irda_device_set_media_busy(self->netdev, TRUE); + break; + case SIOCGRECEIVING: /* Check if we are receiving right now */ + irq->ifr_receiving = smsc_ircc_is_receiving(self); + break; + #if 0 + case SIOCSDTRRTS: + if (!capable(CAP_NET_ADMIN)) { + ret = -EPERM; + break; + } + smsc_ircc_sir_set_dtr_rts(dev, irq->ifr_dtr, irq->ifr_rts); + break; + #endif + default: + ret = -EOPNOTSUPP; + } + + return ret; +} + +#if SMSC_IRCC2_C_NET_TIMEOUT +/* + * Function smsc_ircc_timeout (struct net_device *dev) + * + * The networking timeout management. + * + */ + +static void smsc_ircc_timeout(struct net_device *dev) +{ + struct smsc_ircc_cb *self = netdev_priv(dev); + unsigned long flags; + + net_warn_ratelimited("%s: transmit timed out, changing speed to: %d\n", + dev->name, self->io.speed); + spin_lock_irqsave(&self->lock, flags); + smsc_ircc_sir_start(self); + smsc_ircc_change_speed(self, self->io.speed); + netif_trans_update(dev); /* prevent tx timeout */ + netif_wake_queue(dev); + spin_unlock_irqrestore(&self->lock, flags); +} +#endif + +/* + * Function smsc_ircc_hard_xmit_sir (struct sk_buff *skb, struct net_device *dev) + * + * Transmits the current frame until FIFO is full, then + * waits until the next transmit interrupt, and continues until the + * frame is transmitted. + */ +static netdev_tx_t smsc_ircc_hard_xmit_sir(struct sk_buff *skb, + struct net_device *dev) +{ + struct smsc_ircc_cb *self; + unsigned long flags; + s32 speed; + + pr_debug("%s\n", __func__); + + IRDA_ASSERT(dev != NULL, return NETDEV_TX_OK;); + + self = netdev_priv(dev); + IRDA_ASSERT(self != NULL, return NETDEV_TX_OK;); + + netif_stop_queue(dev); + + /* Make sure test of self->io.speed & speed change are atomic */ + spin_lock_irqsave(&self->lock, flags); + + /* Check if we need to change the speed */ + speed = irda_get_next_speed(skb); + if (speed != self->io.speed && speed != -1) { + /* Check for empty frame */ + if (!skb->len) { + /* + * We send frames one by one in SIR mode (no + * pipelining), so at this point, if we were sending + * a previous frame, we just received the interrupt + * telling us it is finished (UART_IIR_THRI). + * Therefore, waiting for the transmitter to really + * finish draining the fifo won't take too long. + * And the interrupt handler is not expected to run. + * - Jean II */ + smsc_ircc_sir_wait_hw_transmitter_finish(self); + smsc_ircc_change_speed(self, speed); + spin_unlock_irqrestore(&self->lock, flags); + dev_kfree_skb(skb); + return NETDEV_TX_OK; + } + self->new_speed = speed; + } + + /* Init tx buffer */ + self->tx_buff.data = self->tx_buff.head; + + /* Copy skb to tx_buff while wrapping, stuffing and making CRC */ + self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data, + self->tx_buff.truesize); + + dev->stats.tx_bytes += self->tx_buff.len; + + /* Turn on transmit finished interrupt. Will fire immediately! */ + outb(UART_IER_THRI, self->io.sir_base + UART_IER); + + spin_unlock_irqrestore(&self->lock, flags); + + dev_kfree_skb(skb); + + return NETDEV_TX_OK; +} + +/* + * Function smsc_ircc_set_fir_speed (self, baud) + * + * Change the speed of the device + * + */ +static void smsc_ircc_set_fir_speed(struct smsc_ircc_cb *self, u32 speed) +{ + int fir_base, ir_mode, ctrl, fast; + + IRDA_ASSERT(self != NULL, return;); + fir_base = self->io.fir_base; + + self->io.speed = speed; + + switch (speed) { + default: + case 576000: + ir_mode = IRCC_CFGA_IRDA_HDLC; + ctrl = IRCC_CRC; + fast = 0; + pr_debug("%s(), handling baud of 576000\n", __func__); + break; + case 1152000: + ir_mode = IRCC_CFGA_IRDA_HDLC; + ctrl = IRCC_1152 | IRCC_CRC; + fast = IRCC_LCR_A_FAST | IRCC_LCR_A_GP_DATA; + pr_debug("%s(), handling baud of 1152000\n", + __func__); + break; + case 4000000: + ir_mode = IRCC_CFGA_IRDA_4PPM; + ctrl = IRCC_CRC; + fast = IRCC_LCR_A_FAST; + pr_debug("%s(), handling baud of 4000000\n", + __func__); + break; + } + #if 0 + Now in tranceiver! + /* This causes an interrupt */ + register_bank(fir_base, 0); + outb((inb(fir_base + IRCC_LCR_A) & 0xbf) | fast, fir_base + IRCC_LCR_A); + #endif + + register_bank(fir_base, 1); + outb(((inb(fir_base + IRCC_SCE_CFGA) & IRCC_SCE_CFGA_BLOCK_CTRL_BITS_MASK) | ir_mode), fir_base + IRCC_SCE_CFGA); + + register_bank(fir_base, 4); + outb((inb(fir_base + IRCC_CONTROL) & 0x30) | ctrl, fir_base + IRCC_CONTROL); +} + +/* + * Function smsc_ircc_fir_start(self) + * + * Change the speed of the device + * + */ +static void smsc_ircc_fir_start(struct smsc_ircc_cb *self) +{ + struct net_device *dev; + int fir_base; + + pr_debug("%s\n", __func__); + + IRDA_ASSERT(self != NULL, return;); + dev = self->netdev; + IRDA_ASSERT(dev != NULL, return;); + + fir_base = self->io.fir_base; + + /* Reset everything */ + + /* Clear FIFO */ + outb(inb(fir_base + IRCC_LCR_A) | IRCC_LCR_A_FIFO_RESET, fir_base + IRCC_LCR_A); + + /* Enable interrupt */ + /*outb(IRCC_IER_ACTIVE_FRAME|IRCC_IER_EOM, fir_base + IRCC_IER);*/ + + register_bank(fir_base, 1); + + /* Select the TX/RX interface */ +#ifdef SMSC_669 /* Uses pin 88/89 for Rx/Tx */ + outb(((inb(fir_base + IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_COM), + fir_base + IRCC_SCE_CFGB); +#else + outb(((inb(fir_base + IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_IR), + fir_base + IRCC_SCE_CFGB); +#endif + (void) inb(fir_base + IRCC_FIFO_THRESHOLD); + + /* Enable SCE interrupts */ + outb(0, fir_base + IRCC_MASTER); + register_bank(fir_base, 0); + outb(IRCC_IER_ACTIVE_FRAME | IRCC_IER_EOM, fir_base + IRCC_IER); + outb(IRCC_MASTER_INT_EN, fir_base + IRCC_MASTER); +} + +/* + * Function smsc_ircc_fir_stop(self, baud) + * + * Change the speed of the device + * + */ +static void smsc_ircc_fir_stop(struct smsc_ircc_cb *self) +{ + int fir_base; + + pr_debug("%s\n", __func__); + + IRDA_ASSERT(self != NULL, return;); + + fir_base = self->io.fir_base; + register_bank(fir_base, 0); + /*outb(IRCC_MASTER_RESET, fir_base + IRCC_MASTER);*/ + outb(inb(fir_base + IRCC_LCR_B) & IRCC_LCR_B_SIP_ENABLE, fir_base + IRCC_LCR_B); +} + + +/* + * Function smsc_ircc_change_speed(self, baud) + * + * Change the speed of the device + * + * This function *must* be called with spinlock held, because it may + * be called from the irq handler. - Jean II + */ +static void smsc_ircc_change_speed(struct smsc_ircc_cb *self, u32 speed) +{ + struct net_device *dev; + int last_speed_was_sir; + + pr_debug("%s() changing speed to: %d\n", __func__, speed); + + IRDA_ASSERT(self != NULL, return;); + dev = self->netdev; + + last_speed_was_sir = self->io.speed <= SMSC_IRCC2_MAX_SIR_SPEED; + + #if 0 + /* Temp Hack */ + speed= 1152000; + self->io.speed = speed; + last_speed_was_sir = 0; + smsc_ircc_fir_start(self); + #endif + + if (self->io.speed == 0) + smsc_ircc_sir_start(self); + + #if 0 + if (!last_speed_was_sir) speed = self->io.speed; + #endif + + if (self->io.speed != speed) + smsc_ircc_set_transceiver_for_speed(self, speed); + + self->io.speed = speed; + + if (speed <= SMSC_IRCC2_MAX_SIR_SPEED) { + if (!last_speed_was_sir) { + smsc_ircc_fir_stop(self); + smsc_ircc_sir_start(self); + } + smsc_ircc_set_sir_speed(self, speed); + } else { + if (last_speed_was_sir) { + #if SMSC_IRCC2_C_SIR_STOP + smsc_ircc_sir_stop(self); + #endif + smsc_ircc_fir_start(self); + } + smsc_ircc_set_fir_speed(self, speed); + + #if 0 + self->tx_buff.len = 10; + self->tx_buff.data = self->tx_buff.head; + + smsc_ircc_dma_xmit(self, 4000); + #endif + /* Be ready for incoming frames */ + smsc_ircc_dma_receive(self); + } + + netif_wake_queue(dev); +} + +/* + * Function smsc_ircc_set_sir_speed (self, speed) + * + * Set speed of IrDA port to specified baudrate + * + */ +static void smsc_ircc_set_sir_speed(struct smsc_ircc_cb *self, __u32 speed) +{ + int iobase; + int fcr; /* FIFO control reg */ + int lcr; /* Line control reg */ + int divisor; + + pr_debug("%s(), Setting speed to: %d\n", __func__, speed); + + IRDA_ASSERT(self != NULL, return;); + iobase = self->io.sir_base; + + /* Update accounting for new speed */ + self->io.speed = speed; + + /* Turn off interrupts */ + outb(0, iobase + UART_IER); + + divisor = SMSC_IRCC2_MAX_SIR_SPEED / speed; + + fcr = UART_FCR_ENABLE_FIFO; + + /* + * Use trigger level 1 to avoid 3 ms. timeout delay at 9600 bps, and + * almost 1,7 ms at 19200 bps. At speeds above that we can just forget + * about this timeout since it will always be fast enough. + */ + fcr |= self->io.speed < 38400 ? + UART_FCR_TRIGGER_1 : UART_FCR_TRIGGER_14; + + /* IrDA ports use 8N1 */ + lcr = UART_LCR_WLEN8; + + outb(UART_LCR_DLAB | lcr, iobase + UART_LCR); /* Set DLAB */ + outb(divisor & 0xff, iobase + UART_DLL); /* Set speed */ + outb(divisor >> 8, iobase + UART_DLM); + outb(lcr, iobase + UART_LCR); /* Set 8N1 */ + outb(fcr, iobase + UART_FCR); /* Enable FIFO's */ + + /* Turn on interrups */ + outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER); + + pr_debug("%s() speed changed to: %d\n", __func__, speed); +} + + +/* + * Function smsc_ircc_hard_xmit_fir (skb, dev) + * + * Transmit the frame! + * + */ +static netdev_tx_t smsc_ircc_hard_xmit_fir(struct sk_buff *skb, + struct net_device *dev) +{ + struct smsc_ircc_cb *self; + unsigned long flags; + s32 speed; + int mtt; + + IRDA_ASSERT(dev != NULL, return NETDEV_TX_OK;); + self = netdev_priv(dev); + IRDA_ASSERT(self != NULL, return NETDEV_TX_OK;); + + netif_stop_queue(dev); + + /* Make sure test of self->io.speed & speed change are atomic */ + spin_lock_irqsave(&self->lock, flags); + + /* Check if we need to change the speed after this frame */ + speed = irda_get_next_speed(skb); + if (speed != self->io.speed && speed != -1) { + /* Check for empty frame */ + if (!skb->len) { + /* Note : you should make sure that speed changes + * are not going to corrupt any outgoing frame. + * Look at nsc-ircc for the gory details - Jean II */ + smsc_ircc_change_speed(self, speed); + spin_unlock_irqrestore(&self->lock, flags); + dev_kfree_skb(skb); + return NETDEV_TX_OK; + } + + self->new_speed = speed; + } + + skb_copy_from_linear_data(skb, self->tx_buff.head, skb->len); + + self->tx_buff.len = skb->len; + self->tx_buff.data = self->tx_buff.head; + + mtt = irda_get_mtt(skb); + if (mtt) { + int bofs; + + /* + * Compute how many BOFs (STA or PA's) we need to waste the + * min turn time given the speed of the link. + */ + bofs = mtt * (self->io.speed / 1000) / 8000; + if (bofs > 4095) + bofs = 4095; + + smsc_ircc_dma_xmit(self, bofs); + } else { + /* Transmit frame */ + smsc_ircc_dma_xmit(self, 0); + } + + spin_unlock_irqrestore(&self->lock, flags); + dev_kfree_skb(skb); + + return NETDEV_TX_OK; +} + +/* + * Function smsc_ircc_dma_xmit (self, bofs) + * + * Transmit data using DMA + * + */ +static void smsc_ircc_dma_xmit(struct smsc_ircc_cb *self, int bofs) +{ + int iobase = self->io.fir_base; + u8 ctrl; + + pr_debug("%s\n", __func__); +#if 1 + /* Disable Rx */ + register_bank(iobase, 0); + outb(0x00, iobase + IRCC_LCR_B); +#endif + register_bank(iobase, 1); + outb(inb(iobase + IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE, + iobase + IRCC_SCE_CFGB); + + self->io.direction = IO_XMIT; + + /* Set BOF additional count for generating the min turn time */ + register_bank(iobase, 4); + outb(bofs & 0xff, iobase + IRCC_BOF_COUNT_LO); + ctrl = inb(iobase + IRCC_CONTROL) & 0xf0; + outb(ctrl | ((bofs >> 8) & 0x0f), iobase + IRCC_BOF_COUNT_HI); + + /* Set max Tx frame size */ + outb(self->tx_buff.len >> 8, iobase + IRCC_TX_SIZE_HI); + outb(self->tx_buff.len & 0xff, iobase + IRCC_TX_SIZE_LO); + + /*outb(UART_MCR_OUT2, self->io.sir_base + UART_MCR);*/ + + /* Enable burst mode chip Tx DMA */ + register_bank(iobase, 1); + outb(inb(iobase + IRCC_SCE_CFGB) | IRCC_CFGB_DMA_ENABLE | + IRCC_CFGB_DMA_BURST, iobase + IRCC_SCE_CFGB); + + /* Setup DMA controller (must be done after enabling chip DMA) */ + irda_setup_dma(self->io.dma, self->tx_buff_dma, self->tx_buff.len, + DMA_TX_MODE); + + /* Enable interrupt */ + + register_bank(iobase, 0); + outb(IRCC_IER_ACTIVE_FRAME | IRCC_IER_EOM, iobase + IRCC_IER); + outb(IRCC_MASTER_INT_EN, iobase + IRCC_MASTER); + + /* Enable transmit */ + outb(IRCC_LCR_B_SCE_TRANSMIT | IRCC_LCR_B_SIP_ENABLE, iobase + IRCC_LCR_B); +} + +/* + * Function smsc_ircc_dma_xmit_complete (self) + * + * The transfer of a frame in finished. This function will only be called + * by the interrupt handler + * + */ +static void smsc_ircc_dma_xmit_complete(struct smsc_ircc_cb *self) +{ + int iobase = self->io.fir_base; + + pr_debug("%s\n", __func__); +#if 0 + /* Disable Tx */ + register_bank(iobase, 0); + outb(0x00, iobase + IRCC_LCR_B); +#endif + register_bank(iobase, 1); + outb(inb(iobase + IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE, + iobase + IRCC_SCE_CFGB); + + /* Check for underrun! */ + register_bank(iobase, 0); + if (inb(iobase + IRCC_LSR) & IRCC_LSR_UNDERRUN) { + self->netdev->stats.tx_errors++; + self->netdev->stats.tx_fifo_errors++; + + /* Reset error condition */ + register_bank(iobase, 0); + outb(IRCC_MASTER_ERROR_RESET, iobase + IRCC_MASTER); + outb(0x00, iobase + IRCC_MASTER); + } else { + self->netdev->stats.tx_packets++; + self->netdev->stats.tx_bytes += self->tx_buff.len; + } + + /* Check if it's time to change the speed */ + if (self->new_speed) { + smsc_ircc_change_speed(self, self->new_speed); + self->new_speed = 0; + } + + netif_wake_queue(self->netdev); +} + +/* + * Function smsc_ircc_dma_receive(self) + * + * Get ready for receiving a frame. The device will initiate a DMA + * if it starts to receive a frame. + * + */ +static int smsc_ircc_dma_receive(struct smsc_ircc_cb *self) +{ + int iobase = self->io.fir_base; +#if 0 + /* Turn off chip DMA */ + register_bank(iobase, 1); + outb(inb(iobase + IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE, + iobase + IRCC_SCE_CFGB); +#endif + + /* Disable Tx */ + register_bank(iobase, 0); + outb(0x00, iobase + IRCC_LCR_B); + + /* Turn off chip DMA */ + register_bank(iobase, 1); + outb(inb(iobase + IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE, + iobase + IRCC_SCE_CFGB); + + self->io.direction = IO_RECV; + self->rx_buff.data = self->rx_buff.head; + + /* Set max Rx frame size */ + register_bank(iobase, 4); + outb((2050 >> 8) & 0x0f, iobase + IRCC_RX_SIZE_HI); + outb(2050 & 0xff, iobase + IRCC_RX_SIZE_LO); + + /* Setup DMA controller */ + irda_setup_dma(self->io.dma, self->rx_buff_dma, self->rx_buff.truesize, + DMA_RX_MODE); + + /* Enable burst mode chip Rx DMA */ + register_bank(iobase, 1); + outb(inb(iobase + IRCC_SCE_CFGB) | IRCC_CFGB_DMA_ENABLE | + IRCC_CFGB_DMA_BURST, iobase + IRCC_SCE_CFGB); + + /* Enable interrupt */ + register_bank(iobase, 0); + outb(IRCC_IER_ACTIVE_FRAME | IRCC_IER_EOM, iobase + IRCC_IER); + outb(IRCC_MASTER_INT_EN, iobase + IRCC_MASTER); + + /* Enable receiver */ + register_bank(iobase, 0); + outb(IRCC_LCR_B_SCE_RECEIVE | IRCC_LCR_B_SIP_ENABLE, + iobase + IRCC_LCR_B); + + return 0; +} + +/* + * Function smsc_ircc_dma_receive_complete(self) + * + * Finished with receiving frames + * + */ +static void smsc_ircc_dma_receive_complete(struct smsc_ircc_cb *self) +{ + struct sk_buff *skb; + int len, msgcnt, lsr; + int iobase = self->io.fir_base; + + register_bank(iobase, 0); + + pr_debug("%s\n", __func__); +#if 0 + /* Disable Rx */ + register_bank(iobase, 0); + outb(0x00, iobase + IRCC_LCR_B); +#endif + register_bank(iobase, 0); + outb(inb(iobase + IRCC_LSAR) & ~IRCC_LSAR_ADDRESS_MASK, iobase + IRCC_LSAR); + lsr= inb(iobase + IRCC_LSR); + msgcnt = inb(iobase + IRCC_LCR_B) & 0x08; + + pr_debug("%s: dma count = %d\n", __func__, + get_dma_residue(self->io.dma)); + + len = self->rx_buff.truesize - get_dma_residue(self->io.dma); + + /* Look for errors */ + if (lsr & (IRCC_LSR_FRAME_ERROR | IRCC_LSR_CRC_ERROR | IRCC_LSR_SIZE_ERROR)) { + self->netdev->stats.rx_errors++; + if (lsr & IRCC_LSR_FRAME_ERROR) + self->netdev->stats.rx_frame_errors++; + if (lsr & IRCC_LSR_CRC_ERROR) + self->netdev->stats.rx_crc_errors++; + if (lsr & IRCC_LSR_SIZE_ERROR) + self->netdev->stats.rx_length_errors++; + if (lsr & (IRCC_LSR_UNDERRUN | IRCC_LSR_OVERRUN)) + self->netdev->stats.rx_length_errors++; + return; + } + + /* Remove CRC */ + len -= self->io.speed < 4000000 ? 2 : 4; + + if (len < 2 || len > 2050) { + net_warn_ratelimited("%s(), bogus len=%d\n", __func__, len); + return; + } + pr_debug("%s: msgcnt = %d, len=%d\n", __func__, msgcnt, len); + + skb = dev_alloc_skb(len + 1); + if (!skb) + return; + + /* Make sure IP header gets aligned */ + skb_reserve(skb, 1); + + skb_put_data(skb, self->rx_buff.data, len); + self->netdev->stats.rx_packets++; + self->netdev->stats.rx_bytes += len; + + skb->dev = self->netdev; + skb_reset_mac_header(skb); + skb->protocol = htons(ETH_P_IRDA); + netif_rx(skb); +} + +/* + * Function smsc_ircc_sir_receive (self) + * + * Receive one frame from the infrared port + * + */ +static void smsc_ircc_sir_receive(struct smsc_ircc_cb *self) +{ + int boguscount = 0; + int iobase; + + IRDA_ASSERT(self != NULL, return;); + + iobase = self->io.sir_base; + + /* + * Receive all characters in Rx FIFO, unwrap and unstuff them. + * async_unwrap_char will deliver all found frames + */ + do { + async_unwrap_char(self->netdev, &self->netdev->stats, &self->rx_buff, + inb(iobase + UART_RX)); + + /* Make sure we don't stay here to long */ + if (boguscount++ > 32) { + pr_debug("%s(), breaking!\n", __func__); + break; + } + } while (inb(iobase + UART_LSR) & UART_LSR_DR); +} + + +/* + * Function smsc_ircc_interrupt (irq, dev_id, regs) + * + * An interrupt from the chip has arrived. Time to do some work + * + */ +static irqreturn_t smsc_ircc_interrupt(int dummy, void *dev_id) +{ + struct net_device *dev = dev_id; + struct smsc_ircc_cb *self = netdev_priv(dev); + int iobase, iir, lcra, lsr; + irqreturn_t ret = IRQ_NONE; + + /* Serialise the interrupt handler in various CPUs, stop Tx path */ + spin_lock(&self->lock); + + /* Check if we should use the SIR interrupt handler */ + if (self->io.speed <= SMSC_IRCC2_MAX_SIR_SPEED) { + ret = smsc_ircc_interrupt_sir(dev); + goto irq_ret_unlock; + } + + iobase = self->io.fir_base; + + register_bank(iobase, 0); + iir = inb(iobase + IRCC_IIR); + if (iir == 0) + goto irq_ret_unlock; + ret = IRQ_HANDLED; + + /* Disable interrupts */ + outb(0, iobase + IRCC_IER); + lcra = inb(iobase + IRCC_LCR_A); + lsr = inb(iobase + IRCC_LSR); + + pr_debug("%s(), iir = 0x%02x\n", __func__, iir); + + if (iir & IRCC_IIR_EOM) { + if (self->io.direction == IO_RECV) + smsc_ircc_dma_receive_complete(self); + else + smsc_ircc_dma_xmit_complete(self); + + smsc_ircc_dma_receive(self); + } + + if (iir & IRCC_IIR_ACTIVE_FRAME) { + /*printk(KERN_WARNING "%s(): Active Frame\n", __func__);*/ + } + + /* Enable interrupts again */ + + register_bank(iobase, 0); + outb(IRCC_IER_ACTIVE_FRAME | IRCC_IER_EOM, iobase + IRCC_IER); + + irq_ret_unlock: + spin_unlock(&self->lock); + + return ret; +} + +/* + * Function irport_interrupt_sir (irq, dev_id) + * + * Interrupt handler for SIR modes + */ +static irqreturn_t smsc_ircc_interrupt_sir(struct net_device *dev) +{ + struct smsc_ircc_cb *self = netdev_priv(dev); + int boguscount = 0; + int iobase; + int iir, lsr; + + /* Already locked coming here in smsc_ircc_interrupt() */ + /*spin_lock(&self->lock);*/ + + iobase = self->io.sir_base; + + iir = inb(iobase + UART_IIR) & UART_IIR_ID; + if (iir == 0) + return IRQ_NONE; + while (iir) { + /* Clear interrupt */ + lsr = inb(iobase + UART_LSR); + + pr_debug("%s(), iir=%02x, lsr=%02x, iobase=%#x\n", + __func__, iir, lsr, iobase); + + switch (iir) { + case UART_IIR_RLSI: + pr_debug("%s(), RLSI\n", __func__); + break; + case UART_IIR_RDI: + /* Receive interrupt */ + smsc_ircc_sir_receive(self); + break; + case UART_IIR_THRI: + if (lsr & UART_LSR_THRE) + /* Transmitter ready for data */ + smsc_ircc_sir_write_wakeup(self); + break; + default: + pr_debug("%s(), unhandled IIR=%#x\n", + __func__, iir); + break; + } + + /* Make sure we don't stay here to long */ + if (boguscount++ > 100) + break; + + iir = inb(iobase + UART_IIR) & UART_IIR_ID; + } + /*spin_unlock(&self->lock);*/ + return IRQ_HANDLED; +} + + +#if 0 /* unused */ +/* + * Function ircc_is_receiving (self) + * + * Return TRUE is we are currently receiving a frame + * + */ +static int ircc_is_receiving(struct smsc_ircc_cb *self) +{ + int status = FALSE; + /* int iobase; */ + + pr_debug("%s\n", __func__); + + IRDA_ASSERT(self != NULL, return FALSE;); + + pr_debug("%s: dma count = %d\n", __func__, + get_dma_residue(self->io.dma)); + + status = (self->rx_buff.state != OUTSIDE_FRAME); + + return status; +} +#endif /* unused */ + +static int smsc_ircc_request_irq(struct smsc_ircc_cb *self) +{ + int error; + + error = request_irq(self->io.irq, smsc_ircc_interrupt, 0, + self->netdev->name, self->netdev); + if (error) + pr_debug("%s(), unable to allocate irq=%d, err=%d\n", + __func__, self->io.irq, error); + + return error; +} + +static void smsc_ircc_start_interrupts(struct smsc_ircc_cb *self) +{ + unsigned long flags; + + spin_lock_irqsave(&self->lock, flags); + + self->io.speed = 0; + smsc_ircc_change_speed(self, SMSC_IRCC2_C_IRDA_FALLBACK_SPEED); + + spin_unlock_irqrestore(&self->lock, flags); +} + +static void smsc_ircc_stop_interrupts(struct smsc_ircc_cb *self) +{ + int iobase = self->io.fir_base; + unsigned long flags; + + spin_lock_irqsave(&self->lock, flags); + + register_bank(iobase, 0); + outb(0, iobase + IRCC_IER); + outb(IRCC_MASTER_RESET, iobase + IRCC_MASTER); + outb(0x00, iobase + IRCC_MASTER); + + spin_unlock_irqrestore(&self->lock, flags); +} + + +/* + * Function smsc_ircc_net_open (dev) + * + * Start the device + * + */ +static int smsc_ircc_net_open(struct net_device *dev) +{ + struct smsc_ircc_cb *self; + char hwname[16]; + + pr_debug("%s\n", __func__); + + IRDA_ASSERT(dev != NULL, return -1;); + self = netdev_priv(dev); + IRDA_ASSERT(self != NULL, return 0;); + + if (self->io.suspended) { + pr_debug("%s(), device is suspended\n", __func__); + return -EAGAIN; + } + + if (request_irq(self->io.irq, smsc_ircc_interrupt, 0, dev->name, + (void *) dev)) { + pr_debug("%s(), unable to allocate irq=%d\n", + __func__, self->io.irq); + return -EAGAIN; + } + + smsc_ircc_start_interrupts(self); + + /* Give self a hardware name */ + /* It would be cool to offer the chip revision here - Jean II */ + sprintf(hwname, "SMSC @ 0x%03x", self->io.fir_base); + + /* + * Open new IrLAP layer instance, now that everything should be + * initialized properly + */ + self->irlap = irlap_open(dev, &self->qos, hwname); + + /* + * Always allocate the DMA channel after the IRQ, + * and clean up on failure. + */ + if (request_dma(self->io.dma, dev->name)) { + smsc_ircc_net_close(dev); + + net_warn_ratelimited("%s(), unable to allocate DMA=%d\n", + __func__, self->io.dma); + return -EAGAIN; + } + + netif_start_queue(dev); + + return 0; +} + +/* + * Function smsc_ircc_net_close (dev) + * + * Stop the device + * + */ +static int smsc_ircc_net_close(struct net_device *dev) +{ + struct smsc_ircc_cb *self; + + pr_debug("%s\n", __func__); + + IRDA_ASSERT(dev != NULL, return -1;); + self = netdev_priv(dev); + IRDA_ASSERT(self != NULL, return 0;); + + /* Stop device */ + netif_stop_queue(dev); + + /* Stop and remove instance of IrLAP */ + if (self->irlap) + irlap_close(self->irlap); + self->irlap = NULL; + + smsc_ircc_stop_interrupts(self); + + /* if we are called from smsc_ircc_resume we don't have IRQ reserved */ + if (!self->io.suspended) + free_irq(self->io.irq, dev); + + disable_dma(self->io.dma); + free_dma(self->io.dma); + + return 0; +} + +static int smsc_ircc_suspend(struct platform_device *dev, pm_message_t state) +{ + struct smsc_ircc_cb *self = platform_get_drvdata(dev); + + if (!self->io.suspended) { + pr_debug("%s, Suspending\n", driver_name); + + rtnl_lock(); + if (netif_running(self->netdev)) { + netif_device_detach(self->netdev); + smsc_ircc_stop_interrupts(self); + free_irq(self->io.irq, self->netdev); + disable_dma(self->io.dma); + } + self->io.suspended = 1; + rtnl_unlock(); + } + + return 0; +} + +static int smsc_ircc_resume(struct platform_device *dev) +{ + struct smsc_ircc_cb *self = platform_get_drvdata(dev); + + if (self->io.suspended) { + pr_debug("%s, Waking up\n", driver_name); + + rtnl_lock(); + smsc_ircc_init_chip(self); + if (netif_running(self->netdev)) { + if (smsc_ircc_request_irq(self)) { + /* + * Don't fail resume process, just kill this + * network interface + */ + unregister_netdevice(self->netdev); + } else { + enable_dma(self->io.dma); + smsc_ircc_start_interrupts(self); + netif_device_attach(self->netdev); + } + } + self->io.suspended = 0; + rtnl_unlock(); + } + return 0; +} + +/* + * Function smsc_ircc_close (self) + * + * Close driver instance + * + */ +static int __exit smsc_ircc_close(struct smsc_ircc_cb *self) +{ + pr_debug("%s\n", __func__); + + IRDA_ASSERT(self != NULL, return -1;); + + platform_device_unregister(self->pldev); + + /* Remove netdevice */ + unregister_netdev(self->netdev); + + smsc_ircc_stop_interrupts(self); + + /* Release the PORTS that this driver is using */ + pr_debug("%s(), releasing 0x%03x\n", __func__, + self->io.fir_base); + + release_region(self->io.fir_base, self->io.fir_ext); + + pr_debug("%s(), releasing 0x%03x\n", __func__, + self->io.sir_base); + + release_region(self->io.sir_base, self->io.sir_ext); + + if (self->tx_buff.head) + dma_free_coherent(NULL, self->tx_buff.truesize, + self->tx_buff.head, self->tx_buff_dma); + + if (self->rx_buff.head) + dma_free_coherent(NULL, self->rx_buff.truesize, + self->rx_buff.head, self->rx_buff_dma); + + free_netdev(self->netdev); + + return 0; +} + +static void __exit smsc_ircc_cleanup(void) +{ + int i; + + pr_debug("%s\n", __func__); + + for (i = 0; i < 2; i++) { + if (dev_self[i]) + smsc_ircc_close(dev_self[i]); + } + + if (pnp_driver_registered) + pnp_unregister_driver(&smsc_ircc_pnp_driver); + + platform_driver_unregister(&smsc_ircc_driver); +} + +/* + * Start SIR operations + * + * This function *must* be called with spinlock held, because it may + * be called from the irq handler (via smsc_ircc_change_speed()). - Jean II + */ +static void smsc_ircc_sir_start(struct smsc_ircc_cb *self) +{ + struct net_device *dev; + int fir_base, sir_base; + + pr_debug("%s\n", __func__); + + IRDA_ASSERT(self != NULL, return;); + dev = self->netdev; + IRDA_ASSERT(dev != NULL, return;); + + fir_base = self->io.fir_base; + sir_base = self->io.sir_base; + + /* Reset everything */ + outb(IRCC_MASTER_RESET, fir_base + IRCC_MASTER); + + #if SMSC_IRCC2_C_SIR_STOP + /*smsc_ircc_sir_stop(self);*/ + #endif + + register_bank(fir_base, 1); + outb(((inb(fir_base + IRCC_SCE_CFGA) & IRCC_SCE_CFGA_BLOCK_CTRL_BITS_MASK) | IRCC_CFGA_IRDA_SIR_A), fir_base + IRCC_SCE_CFGA); + + /* Initialize UART */ + outb(UART_LCR_WLEN8, sir_base + UART_LCR); /* Reset DLAB */ + outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), sir_base + UART_MCR); + + /* Turn on interrups */ + outb(UART_IER_RLSI | UART_IER_RDI |UART_IER_THRI, sir_base + UART_IER); + + pr_debug("%s() - exit\n", __func__); + + outb(0x00, fir_base + IRCC_MASTER); +} + +#if SMSC_IRCC2_C_SIR_STOP +void smsc_ircc_sir_stop(struct smsc_ircc_cb *self) +{ + int iobase; + + pr_debug("%s\n", __func__); + iobase = self->io.sir_base; + + /* Reset UART */ + outb(0, iobase + UART_MCR); + + /* Turn off interrupts */ + outb(0, iobase + UART_IER); +} +#endif + +/* + * Function smsc_sir_write_wakeup (self) + * + * Called by the SIR interrupt handler when there's room for more data. + * If we have more packets to send, we send them here. + * + */ +static void smsc_ircc_sir_write_wakeup(struct smsc_ircc_cb *self) +{ + int actual = 0; + int iobase; + int fcr; + + IRDA_ASSERT(self != NULL, return;); + + pr_debug("%s\n", __func__); + + iobase = self->io.sir_base; + + /* Finished with frame? */ + if (self->tx_buff.len > 0) { + /* Write data left in transmit buffer */ + actual = smsc_ircc_sir_write(iobase, self->io.fifo_size, + self->tx_buff.data, self->tx_buff.len); + self->tx_buff.data += actual; + self->tx_buff.len -= actual; + } else { + + /*if (self->tx_buff.len ==0) {*/ + + /* + * Now serial buffer is almost free & we can start + * transmission of another packet. But first we must check + * if we need to change the speed of the hardware + */ + if (self->new_speed) { + pr_debug("%s(), Changing speed to %d.\n", + __func__, self->new_speed); + smsc_ircc_sir_wait_hw_transmitter_finish(self); + smsc_ircc_change_speed(self, self->new_speed); + self->new_speed = 0; + } else { + /* Tell network layer that we want more frames */ + netif_wake_queue(self->netdev); + } + self->netdev->stats.tx_packets++; + + if (self->io.speed <= 115200) { + /* + * Reset Rx FIFO to make sure that all reflected transmit data + * is discarded. This is needed for half duplex operation + */ + fcr = UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR; + fcr |= self->io.speed < 38400 ? + UART_FCR_TRIGGER_1 : UART_FCR_TRIGGER_14; + + outb(fcr, iobase + UART_FCR); + + /* Turn on receive interrupts */ + outb(UART_IER_RDI, iobase + UART_IER); + } + } +} + +/* + * Function smsc_ircc_sir_write (iobase, fifo_size, buf, len) + * + * Fill Tx FIFO with transmit data + * + */ +static int smsc_ircc_sir_write(int iobase, int fifo_size, __u8 *buf, int len) +{ + int actual = 0; + + /* Tx FIFO should be empty! */ + if (!(inb(iobase + UART_LSR) & UART_LSR_THRE)) { + net_warn_ratelimited("%s(), failed, fifo not empty!\n", + __func__); + return 0; + } + + /* Fill FIFO with current frame */ + while (fifo_size-- > 0 && actual < len) { + /* Transmit next byte */ + outb(buf[actual], iobase + UART_TX); + actual++; + } + return actual; +} + +/* + * Function smsc_ircc_is_receiving (self) + * + * Returns true is we are currently receiving data + * + */ +static int smsc_ircc_is_receiving(struct smsc_ircc_cb *self) +{ + return self->rx_buff.state != OUTSIDE_FRAME; +} + + +/* + * Function smsc_ircc_probe_transceiver(self) + * + * Tries to find the used Transceiver + * + */ +static void smsc_ircc_probe_transceiver(struct smsc_ircc_cb *self) +{ + unsigned int i; + + IRDA_ASSERT(self != NULL, return;); + + for (i = 0; smsc_transceivers[i].name != NULL; i++) + if (smsc_transceivers[i].probe(self->io.fir_base)) { + net_info_ratelimited(" %s transceiver found\n", + smsc_transceivers[i].name); + self->transceiver= i + 1; + return; + } + + net_info_ratelimited("No transceiver found. Defaulting to %s\n", + smsc_transceivers[SMSC_IRCC2_C_DEFAULT_TRANSCEIVER].name); + + self->transceiver = SMSC_IRCC2_C_DEFAULT_TRANSCEIVER; +} + + +/* + * Function smsc_ircc_set_transceiver_for_speed(self, speed) + * + * Set the transceiver according to the speed + * + */ +static void smsc_ircc_set_transceiver_for_speed(struct smsc_ircc_cb *self, u32 speed) +{ + unsigned int trx; + + trx = self->transceiver; + if (trx > 0) + smsc_transceivers[trx - 1].set_for_speed(self->io.fir_base, speed); +} + +/* + * Function smsc_ircc_wait_hw_transmitter_finish () + * + * Wait for the real end of HW transmission + * + * The UART is a strict FIFO, and we get called only when we have finished + * pushing data to the FIFO, so the maximum amount of time we must wait + * is only for the FIFO to drain out. + * + * We use a simple calibrated loop. We may need to adjust the loop + * delay (udelay) to balance I/O traffic and latency. And we also need to + * adjust the maximum timeout. + * It would probably be better to wait for the proper interrupt, + * but it doesn't seem to be available. + * + * We can't use jiffies or kernel timers because : + * 1) We are called from the interrupt handler, which disable softirqs, + * so jiffies won't be increased + * 2) Jiffies granularity is usually very coarse (10ms), and we don't + * want to wait that long to detect stuck hardware. + * Jean II + */ + +static void smsc_ircc_sir_wait_hw_transmitter_finish(struct smsc_ircc_cb *self) +{ + int iobase = self->io.sir_base; + int count = SMSC_IRCC2_HW_TRANSMITTER_TIMEOUT_US; + + /* Calibrated busy loop */ + while (count-- > 0 && !(inb(iobase + UART_LSR) & UART_LSR_TEMT)) + udelay(1); + + if (count < 0) + pr_debug("%s(): stuck transmitter\n", __func__); +} + + +/* PROBING + * + * REVISIT we can be told about the device by PNP, and should use that info + * instead of probing hardware and creating a platform_device ... + */ + +static int __init smsc_ircc_look_for_chips(void) +{ + struct smsc_chip_address *address; + char *type; + unsigned int cfg_base, found; + + found = 0; + address = possible_addresses; + + while (address->cfg_base) { + cfg_base = address->cfg_base; + + /*printk(KERN_WARNING "%s(): probing: 0x%02x for: 0x%02x\n", __func__, cfg_base, address->type);*/ + + if (address->type & SMSCSIO_TYPE_FDC) { + type = "FDC"; + if (address->type & SMSCSIO_TYPE_FLAT) + if (!smsc_superio_flat(fdc_chips_flat, cfg_base, type)) + found++; + + if (address->type & SMSCSIO_TYPE_PAGED) + if (!smsc_superio_paged(fdc_chips_paged, cfg_base, type)) + found++; + } + if (address->type & SMSCSIO_TYPE_LPC) { + type = "LPC"; + if (address->type & SMSCSIO_TYPE_FLAT) + if (!smsc_superio_flat(lpc_chips_flat, cfg_base, type)) + found++; + + if (address->type & SMSCSIO_TYPE_PAGED) + if (!smsc_superio_paged(lpc_chips_paged, cfg_base, type)) + found++; + } + address++; + } + return found; +} + +/* + * Function smsc_superio_flat (chip, base, type) + * + * Try to get configuration of a smc SuperIO chip with flat register model + * + */ +static int __init smsc_superio_flat(const struct smsc_chip *chips, unsigned short cfgbase, char *type) +{ + unsigned short firbase, sirbase; + u8 mode, dma, irq; + int ret = -ENODEV; + + pr_debug("%s\n", __func__); + + if (smsc_ircc_probe(cfgbase, SMSCSIOFLAT_DEVICEID_REG, chips, type) == NULL) + return ret; + + outb(SMSCSIOFLAT_UARTMODE0C_REG, cfgbase); + mode = inb(cfgbase + 1); + + /*printk(KERN_WARNING "%s(): mode: 0x%02x\n", __func__, mode);*/ + + if (!(mode & SMSCSIOFLAT_UART2MODE_VAL_IRDA)) + net_warn_ratelimited("%s(): IrDA not enabled\n", __func__); + + outb(SMSCSIOFLAT_UART2BASEADDR_REG, cfgbase); + sirbase = inb(cfgbase + 1) << 2; + + /* FIR iobase */ + outb(SMSCSIOFLAT_FIRBASEADDR_REG, cfgbase); + firbase = inb(cfgbase + 1) << 3; + + /* DMA */ + outb(SMSCSIOFLAT_FIRDMASELECT_REG, cfgbase); + dma = inb(cfgbase + 1) & SMSCSIOFLAT_FIRDMASELECT_MASK; + + /* IRQ */ + outb(SMSCSIOFLAT_UARTIRQSELECT_REG, cfgbase); + irq = inb(cfgbase + 1) & SMSCSIOFLAT_UART2IRQSELECT_MASK; + + net_info_ratelimited("%s(): fir: 0x%02x, sir: 0x%02x, dma: %02d, irq: %d, mode: 0x%02x\n", + __func__, firbase, sirbase, dma, irq, mode); + + if (firbase && smsc_ircc_open(firbase, sirbase, dma, irq) == 0) + ret = 0; + + /* Exit configuration */ + outb(SMSCSIO_CFGEXITKEY, cfgbase); + + return ret; +} + +/* + * Function smsc_superio_paged (chip, base, type) + * + * Try to get configuration of a smc SuperIO chip with paged register model + * + */ +static int __init smsc_superio_paged(const struct smsc_chip *chips, unsigned short cfg_base, char *type) +{ + unsigned short fir_io, sir_io; + int ret = -ENODEV; + + pr_debug("%s\n", __func__); + + if (smsc_ircc_probe(cfg_base, 0x20, chips, type) == NULL) + return ret; + + /* Select logical device (UART2) */ + outb(0x07, cfg_base); + outb(0x05, cfg_base + 1); + + /* SIR iobase */ + outb(0x60, cfg_base); + sir_io = inb(cfg_base + 1) << 8; + outb(0x61, cfg_base); + sir_io |= inb(cfg_base + 1); + + /* Read FIR base */ + outb(0x62, cfg_base); + fir_io = inb(cfg_base + 1) << 8; + outb(0x63, cfg_base); + fir_io |= inb(cfg_base + 1); + outb(0x2b, cfg_base); /* ??? */ + + if (fir_io && smsc_ircc_open(fir_io, sir_io, ircc_dma, ircc_irq) == 0) + ret = 0; + + /* Exit configuration */ + outb(SMSCSIO_CFGEXITKEY, cfg_base); + + return ret; +} + + +static int __init smsc_access(unsigned short cfg_base, unsigned char reg) +{ + pr_debug("%s\n", __func__); + + outb(reg, cfg_base); + return inb(cfg_base) != reg ? -1 : 0; +} + +static const struct smsc_chip * __init smsc_ircc_probe(unsigned short cfg_base, u8 reg, const struct smsc_chip *chip, char *type) +{ + u8 devid, xdevid, rev; + + pr_debug("%s\n", __func__); + + /* Leave configuration */ + + outb(SMSCSIO_CFGEXITKEY, cfg_base); + + if (inb(cfg_base) == SMSCSIO_CFGEXITKEY) /* not a smc superio chip */ + return NULL; + + outb(reg, cfg_base); + + xdevid = inb(cfg_base + 1); + + /* Enter configuration */ + + outb(SMSCSIO_CFGACCESSKEY, cfg_base); + + #if 0 + if (smsc_access(cfg_base,0x55)) /* send second key and check */ + return NULL; + #endif + + /* probe device ID */ + + if (smsc_access(cfg_base, reg)) + return NULL; + + devid = inb(cfg_base + 1); + + if (devid == 0 || devid == 0xff) /* typical values for unused port */ + return NULL; + + /* probe revision ID */ + + if (smsc_access(cfg_base, reg + 1)) + return NULL; + + rev = inb(cfg_base + 1); + + if (rev >= 128) /* i think this will make no sense */ + return NULL; + + if (devid == xdevid) /* protection against false positives */ + return NULL; + + /* Check for expected device ID; are there others? */ + + while (chip->devid != devid) { + + chip++; + + if (chip->name == NULL) + return NULL; + } + + net_info_ratelimited("found SMC SuperIO Chip (devid=0x%02x rev=%02X base=0x%04x): %s%s\n", + devid, rev, cfg_base, type, chip->name); + + if (chip->rev > rev) { + net_info_ratelimited("Revision higher than expected\n"); + return NULL; + } + + if (chip->flags & NoIRDA) + net_info_ratelimited("chipset does not support IRDA\n"); + + return chip; +} + +static int __init smsc_superio_fdc(unsigned short cfg_base) +{ + int ret = -1; + + if (!request_region(cfg_base, 2, driver_name)) { + net_warn_ratelimited("%s: can't get cfg_base of 0x%03x\n", + __func__, cfg_base); + } else { + if (!smsc_superio_flat(fdc_chips_flat, cfg_base, "FDC") || + !smsc_superio_paged(fdc_chips_paged, cfg_base, "FDC")) + ret = 0; + + release_region(cfg_base, 2); + } + + return ret; +} + +static int __init smsc_superio_lpc(unsigned short cfg_base) +{ + int ret = -1; + + if (!request_region(cfg_base, 2, driver_name)) { + net_warn_ratelimited("%s: can't get cfg_base of 0x%03x\n", + __func__, cfg_base); + } else { + if (!smsc_superio_flat(lpc_chips_flat, cfg_base, "LPC") || + !smsc_superio_paged(lpc_chips_paged, cfg_base, "LPC")) + ret = 0; + + release_region(cfg_base, 2); + } + return ret; +} + +/* + * Look for some specific subsystem setups that need + * pre-configuration not properly done by the BIOS (especially laptops) + * This code is based in part on smcinit.c, tosh1800-smcinit.c + * and tosh2450-smcinit.c. The table lists the device entries + * for ISA bridges with an LPC (Low Pin Count) controller which + * handles the communication with the SMSC device. After the LPC + * controller is initialized through PCI, the SMSC device is initialized + * through a dedicated port in the ISA port-mapped I/O area, this latter + * area is used to configure the SMSC device with default + * SIR and FIR I/O ports, DMA and IRQ. Different vendors have + * used different sets of parameters and different control port + * addresses making a subsystem device table necessary. + */ +#ifdef CONFIG_PCI +static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __initdata = { + /* + * Subsystems needing entries: + * 0x10b9:0x1533 0x103c:0x0850 HP nx9010 family + * 0x10b9:0x1533 0x0e11:0x005a Compaq nc4000 family + * 0x8086:0x24cc 0x0e11:0x002a HP nx9000 family + */ + { + /* Guessed entry */ + .vendor = PCI_VENDOR_ID_INTEL, /* Intel 82801DBM LPC bridge */ + .device = 0x24cc, + .subvendor = 0x103c, + .subdevice = 0x08bc, + .sir_io = 0x02f8, + .fir_io = 0x0130, + .fir_irq = 0x05, + .fir_dma = 0x03, + .cfg_base = 0x004e, + .preconfigure = preconfigure_through_82801, + .name = "HP nx5000 family", + }, + { + .vendor = PCI_VENDOR_ID_INTEL, /* Intel 82801DBM LPC bridge */ + .device = 0x24cc, + .subvendor = 0x103c, + .subdevice = 0x088c, + /* Quite certain these are the same for nc8000 as for nc6000 */ + .sir_io = 0x02f8, + .fir_io = 0x0130, + .fir_irq = 0x05, + .fir_dma = 0x03, + .cfg_base = 0x004e, + .preconfigure = preconfigure_through_82801, + .name = "HP nc8000 family", + }, + { + .vendor = PCI_VENDOR_ID_INTEL, /* Intel 82801DBM LPC bridge */ + .device = 0x24cc, + .subvendor = 0x103c, + .subdevice = 0x0890, + .sir_io = 0x02f8, + .fir_io = 0x0130, + .fir_irq = 0x05, + .fir_dma = 0x03, + .cfg_base = 0x004e, + .preconfigure = preconfigure_through_82801, + .name = "HP nc6000 family", + }, + { + .vendor = PCI_VENDOR_ID_INTEL, /* Intel 82801DBM LPC bridge */ + .device = 0x24cc, + .subvendor = 0x0e11, + .subdevice = 0x0860, + /* I assume these are the same for x1000 as for the others */ + .sir_io = 0x02e8, + .fir_io = 0x02f8, + .fir_irq = 0x07, + .fir_dma = 0x03, + .cfg_base = 0x002e, + .preconfigure = preconfigure_through_82801, + .name = "Compaq x1000 family", + }, + { + /* Intel 82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge */ + .vendor = PCI_VENDOR_ID_INTEL, + .device = 0x24c0, + .subvendor = 0x1179, + .subdevice = 0xffff, /* 0xffff is "any" */ + .sir_io = 0x03f8, + .fir_io = 0x0130, + .fir_irq = 0x07, + .fir_dma = 0x01, + .cfg_base = 0x002e, + .preconfigure = preconfigure_through_82801, + .name = "Toshiba laptop with Intel 82801DB/DBL LPC bridge", + }, + { + .vendor = PCI_VENDOR_ID_INTEL, /* Intel 82801CAM ISA bridge */ + .device = 0x248c, + .subvendor = 0x1179, + .subdevice = 0xffff, /* 0xffff is "any" */ + .sir_io = 0x03f8, + .fir_io = 0x0130, + .fir_irq = 0x03, + .fir_dma = 0x03, + .cfg_base = 0x002e, + .preconfigure = preconfigure_through_82801, + .name = "Toshiba laptop with Intel 82801CAM ISA bridge", + }, + { + /* 82801DBM (ICH4-M) LPC Interface Bridge */ + .vendor = PCI_VENDOR_ID_INTEL, + .device = 0x24cc, + .subvendor = 0x1179, + .subdevice = 0xffff, /* 0xffff is "any" */ + .sir_io = 0x03f8, + .fir_io = 0x0130, + .fir_irq = 0x03, + .fir_dma = 0x03, + .cfg_base = 0x002e, + .preconfigure = preconfigure_through_82801, + .name = "Toshiba laptop with Intel 8281DBM LPC bridge", + }, + { + /* ALi M1533/M1535 PCI to ISA Bridge [Aladdin IV/V/V+] */ + .vendor = PCI_VENDOR_ID_AL, + .device = 0x1533, + .subvendor = 0x1179, + .subdevice = 0xffff, /* 0xffff is "any" */ + .sir_io = 0x02e8, + .fir_io = 0x02f8, + .fir_irq = 0x07, + .fir_dma = 0x03, + .cfg_base = 0x002e, + .preconfigure = preconfigure_through_ali, + .name = "Toshiba laptop with ALi ISA bridge", + }, + { } // Terminator +}; + + +/* + * This sets up the basic SMSC parameters + * (FIR port, SIR port, FIR DMA, FIR IRQ) + * through the chip configuration port. + */ +static int __init preconfigure_smsc_chip(struct + smsc_ircc_subsystem_configuration + *conf) +{ + unsigned short iobase = conf->cfg_base; + unsigned char tmpbyte; + + outb(LPC47N227_CFGACCESSKEY, iobase); // enter configuration state + outb(SMSCSIOFLAT_DEVICEID_REG, iobase); // set for device ID + tmpbyte = inb(iobase +1); // Read device ID + pr_debug("Detected Chip id: 0x%02x, setting up registers...\n", + tmpbyte); + + /* Disable UART1 and set up SIR I/O port */ + outb(0x24, iobase); // select CR24 - UART1 base addr + outb(0x00, iobase + 1); // disable UART1 + outb(SMSCSIOFLAT_UART2BASEADDR_REG, iobase); // select CR25 - UART2 base addr + outb( (conf->sir_io >> 2), iobase + 1); // bits 2-9 of 0x3f8 + tmpbyte = inb(iobase + 1); + if (tmpbyte != (conf->sir_io >> 2) ) { + net_warn_ratelimited("ERROR: could not configure SIR ioport\n"); + net_warn_ratelimited("Try to supply ircc_cfg argument\n"); + return -ENXIO; + } + + /* Set up FIR IRQ channel for UART2 */ + outb(SMSCSIOFLAT_UARTIRQSELECT_REG, iobase); // select CR28 - UART1,2 IRQ select + tmpbyte = inb(iobase + 1); + tmpbyte &= SMSCSIOFLAT_UART1IRQSELECT_MASK; // Do not touch the UART1 portion + tmpbyte |= (conf->fir_irq & SMSCSIOFLAT_UART2IRQSELECT_MASK); + outb(tmpbyte, iobase + 1); + tmpbyte = inb(iobase + 1) & SMSCSIOFLAT_UART2IRQSELECT_MASK; + if (tmpbyte != conf->fir_irq) { + net_warn_ratelimited("ERROR: could not configure FIR IRQ channel\n"); + return -ENXIO; + } + + /* Set up FIR I/O port */ + outb(SMSCSIOFLAT_FIRBASEADDR_REG, iobase); // CR2B - SCE (FIR) base addr + outb((conf->fir_io >> 3), iobase + 1); + tmpbyte = inb(iobase + 1); + if (tmpbyte != (conf->fir_io >> 3) ) { + net_warn_ratelimited("ERROR: could not configure FIR I/O port\n"); + return -ENXIO; + } + + /* Set up FIR DMA channel */ + outb(SMSCSIOFLAT_FIRDMASELECT_REG, iobase); // CR2C - SCE (FIR) DMA select + outb((conf->fir_dma & LPC47N227_FIRDMASELECT_MASK), iobase + 1); // DMA + tmpbyte = inb(iobase + 1) & LPC47N227_FIRDMASELECT_MASK; + if (tmpbyte != (conf->fir_dma & LPC47N227_FIRDMASELECT_MASK)) { + net_warn_ratelimited("ERROR: could not configure FIR DMA channel\n"); + return -ENXIO; + } + + outb(SMSCSIOFLAT_UARTMODE0C_REG, iobase); // CR0C - UART mode + tmpbyte = inb(iobase + 1); + tmpbyte &= ~SMSCSIOFLAT_UART2MODE_MASK | + SMSCSIOFLAT_UART2MODE_VAL_IRDA; + outb(tmpbyte, iobase + 1); // enable IrDA (HPSIR) mode, high speed + + outb(LPC47N227_APMBOOTDRIVE_REG, iobase); // CR07 - Auto Pwr Mgt/boot drive sel + tmpbyte = inb(iobase + 1); + outb(tmpbyte | LPC47N227_UART2AUTOPWRDOWN_MASK, iobase + 1); // enable UART2 autopower down + + /* This one was not part of tosh1800 */ + outb(0x0a, iobase); // CR0a - ecp fifo / ir mux + tmpbyte = inb(iobase + 1); + outb(tmpbyte | 0x40, iobase + 1); // send active device to ir port + + outb(LPC47N227_UART12POWER_REG, iobase); // CR02 - UART 1,2 power + tmpbyte = inb(iobase + 1); + outb(tmpbyte | LPC47N227_UART2POWERDOWN_MASK, iobase + 1); // UART2 power up mode, UART1 power down + + outb(LPC47N227_FDCPOWERVALIDCONF_REG, iobase); // CR00 - FDC Power/valid config cycle + tmpbyte = inb(iobase + 1); + outb(tmpbyte | LPC47N227_VALID_MASK, iobase + 1); // valid config cycle done + + outb(LPC47N227_CFGEXITKEY, iobase); // Exit configuration + + return 0; +} + +/* 82801CAM generic registers */ +#define VID 0x00 +#define DID 0x02 +#define PIRQ_A_D_ROUT 0x60 +#define SIRQ_CNTL 0x64 +#define PIRQ_E_H_ROUT 0x68 +#define PCI_DMA_C 0x90 +/* LPC-specific registers */ +#define COM_DEC 0xe0 +#define GEN1_DEC 0xe4 +#define LPC_EN 0xe6 +#define GEN2_DEC 0xec +/* + * Sets up the I/O range using the 82801CAM ISA bridge, 82801DBM LPC bridge + * or Intel 82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge. + * They all work the same way! + */ +static int __init preconfigure_through_82801(struct pci_dev *dev, + struct + smsc_ircc_subsystem_configuration + *conf) +{ + unsigned short tmpword; + unsigned char tmpbyte; + + net_info_ratelimited("Setting up Intel 82801 controller and SMSC device\n"); + /* + * Select the range for the COMA COM port (SIR) + * Register COM_DEC: + * Bit 7: reserved + * Bit 6-4, COMB decode range + * Bit 3: reserved + * Bit 2-0, COMA decode range + * + * Decode ranges: + * 000 = 0x3f8-0x3ff (COM1) + * 001 = 0x2f8-0x2ff (COM2) + * 010 = 0x220-0x227 + * 011 = 0x228-0x22f + * 100 = 0x238-0x23f + * 101 = 0x2e8-0x2ef (COM4) + * 110 = 0x338-0x33f + * 111 = 0x3e8-0x3ef (COM3) + */ + pci_read_config_byte(dev, COM_DEC, &tmpbyte); + tmpbyte &= 0xf8; /* mask COMA bits */ + switch(conf->sir_io) { + case 0x3f8: + tmpbyte |= 0x00; + break; + case 0x2f8: + tmpbyte |= 0x01; + break; + case 0x220: + tmpbyte |= 0x02; + break; + case 0x228: + tmpbyte |= 0x03; + break; + case 0x238: + tmpbyte |= 0x04; + break; + case 0x2e8: + tmpbyte |= 0x05; + break; + case 0x338: + tmpbyte |= 0x06; + break; + case 0x3e8: + tmpbyte |= 0x07; + break; + default: + tmpbyte |= 0x01; /* COM2 default */ + } + pr_debug("COM_DEC (write): 0x%02x\n", tmpbyte); + pci_write_config_byte(dev, COM_DEC, tmpbyte); + + /* Enable Low Pin Count interface */ + pci_read_config_word(dev, LPC_EN, &tmpword); + /* These seem to be set up at all times, + * just make sure it is properly set. + */ + switch(conf->cfg_base) { + case 0x04e: + tmpword |= 0x2000; + break; + case 0x02e: + tmpword |= 0x1000; + break; + case 0x062: + tmpword |= 0x0800; + break; + case 0x060: + tmpword |= 0x0400; + break; + default: + net_warn_ratelimited("Uncommon I/O base address: 0x%04x\n", + conf->cfg_base); + break; + } + tmpword &= 0xfffd; /* disable LPC COMB */ + tmpword |= 0x0001; /* set bit 0 : enable LPC COMA addr range (GEN2) */ + pr_debug("LPC_EN (write): 0x%04x\n", tmpword); + pci_write_config_word(dev, LPC_EN, tmpword); + + /* + * Configure LPC DMA channel + * PCI_DMA_C bits: + * Bit 15-14: DMA channel 7 select + * Bit 13-12: DMA channel 6 select + * Bit 11-10: DMA channel 5 select + * Bit 9-8: Reserved + * Bit 7-6: DMA channel 3 select + * Bit 5-4: DMA channel 2 select + * Bit 3-2: DMA channel 1 select + * Bit 1-0: DMA channel 0 select + * 00 = Reserved value + * 01 = PC/PCI DMA + * 10 = Reserved value + * 11 = LPC I/F DMA + */ + pci_read_config_word(dev, PCI_DMA_C, &tmpword); + switch(conf->fir_dma) { + case 0x07: + tmpword |= 0xc000; + break; + case 0x06: + tmpword |= 0x3000; + break; + case 0x05: + tmpword |= 0x0c00; + break; + case 0x03: + tmpword |= 0x00c0; + break; + case 0x02: + tmpword |= 0x0030; + break; + case 0x01: + tmpword |= 0x000c; + break; + case 0x00: + tmpword |= 0x0003; + break; + default: + break; /* do not change settings */ + } + pr_debug("PCI_DMA_C (write): 0x%04x\n", tmpword); + pci_write_config_word(dev, PCI_DMA_C, tmpword); + + /* + * GEN2_DEC bits: + * Bit 15-4: Generic I/O range + * Bit 3-1: reserved (read as 0) + * Bit 0: enable GEN2 range on LPC I/F + */ + tmpword = conf->fir_io & 0xfff8; + tmpword |= 0x0001; + pr_debug("GEN2_DEC (write): 0x%04x\n", tmpword); + pci_write_config_word(dev, GEN2_DEC, tmpword); + + /* Pre-configure chip */ + return preconfigure_smsc_chip(conf); +} + +/* + * Pre-configure a certain port on the ALi 1533 bridge. + * This is based on reverse-engineering since ALi does not + * provide any data sheet for the 1533 chip. + */ +static void __init preconfigure_ali_port(struct pci_dev *dev, + unsigned short port) +{ + unsigned char reg; + /* These bits obviously control the different ports */ + unsigned char mask; + unsigned char tmpbyte; + + switch(port) { + case 0x0130: + case 0x0178: + reg = 0xb0; + mask = 0x80; + break; + case 0x03f8: + reg = 0xb4; + mask = 0x80; + break; + case 0x02f8: + reg = 0xb4; + mask = 0x30; + break; + case 0x02e8: + reg = 0xb4; + mask = 0x08; + break; + default: + net_err_ratelimited("Failed to configure unsupported port on ALi 1533 bridge: 0x%04x\n", + port); + return; + } + + pci_read_config_byte(dev, reg, &tmpbyte); + /* Turn on the right bits */ + tmpbyte |= mask; + pci_write_config_byte(dev, reg, tmpbyte); + net_info_ratelimited("Activated ALi 1533 ISA bridge port 0x%04x\n", + port); +} + +static int __init preconfigure_through_ali(struct pci_dev *dev, + struct + smsc_ircc_subsystem_configuration + *conf) +{ + /* Configure the two ports on the ALi 1533 */ + preconfigure_ali_port(dev, conf->sir_io); + preconfigure_ali_port(dev, conf->fir_io); + + /* Pre-configure chip */ + return preconfigure_smsc_chip(conf); +} + +static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, + unsigned short ircc_fir, + unsigned short ircc_sir, + unsigned char ircc_dma, + unsigned char ircc_irq) +{ + struct pci_dev *dev = NULL; + unsigned short ss_vendor = 0x0000; + unsigned short ss_device = 0x0000; + int ret = 0; + + for_each_pci_dev(dev) { + struct smsc_ircc_subsystem_configuration *conf; + + /* + * Cache the subsystem vendor/device: + * some manufacturers fail to set this for all components, + * so we save it in case there is just 0x0000 0x0000 on the + * device we want to check. + */ + if (dev->subsystem_vendor != 0x0000U) { + ss_vendor = dev->subsystem_vendor; + ss_device = dev->subsystem_device; + } + conf = subsystem_configurations; + for( ; conf->subvendor; conf++) { + if(conf->vendor == dev->vendor && + conf->device == dev->device && + conf->subvendor == ss_vendor && + /* Sometimes these are cached values */ + (conf->subdevice == ss_device || + conf->subdevice == 0xffff)) { + struct smsc_ircc_subsystem_configuration + tmpconf; + + memcpy(&tmpconf, conf, + sizeof(struct smsc_ircc_subsystem_configuration)); + + /* + * Override the default values with anything + * passed in as parameter + */ + if (ircc_cfg != 0) + tmpconf.cfg_base = ircc_cfg; + if (ircc_fir != 0) + tmpconf.fir_io = ircc_fir; + if (ircc_sir != 0) + tmpconf.sir_io = ircc_sir; + if (ircc_dma != DMA_INVAL) + tmpconf.fir_dma = ircc_dma; + if (ircc_irq != IRQ_INVAL) + tmpconf.fir_irq = ircc_irq; + + net_info_ratelimited("Detected unconfigured %s SMSC IrDA chip, pre-configuring device\n", + conf->name); + if (conf->preconfigure) + ret = conf->preconfigure(dev, &tmpconf); + else + ret = -ENODEV; + } + } + } + + return ret; +} +#endif // CONFIG_PCI + +/************************************************ + * + * Transceivers specific functions + * + ************************************************/ + + +/* + * Function smsc_ircc_set_transceiver_smsc_ircc_atc(fir_base, speed) + * + * Program transceiver through smsc-ircc ATC circuitry + * + */ + +static void smsc_ircc_set_transceiver_smsc_ircc_atc(int fir_base, u32 speed) +{ + unsigned long jiffies_now, jiffies_timeout; + u8 val; + + jiffies_now = jiffies; + jiffies_timeout = jiffies + SMSC_IRCC2_ATC_PROGRAMMING_TIMEOUT_JIFFIES; + + /* ATC */ + register_bank(fir_base, 4); + outb((inb(fir_base + IRCC_ATC) & IRCC_ATC_MASK) | IRCC_ATC_nPROGREADY|IRCC_ATC_ENABLE, + fir_base + IRCC_ATC); + + while ((val = (inb(fir_base + IRCC_ATC) & IRCC_ATC_nPROGREADY)) && + !time_after(jiffies, jiffies_timeout)) + /* empty */; + + if (val) + net_warn_ratelimited("%s(): ATC: 0x%02x\n", + __func__, inb(fir_base + IRCC_ATC)); +} + +/* + * Function smsc_ircc_probe_transceiver_smsc_ircc_atc(fir_base) + * + * Probe transceiver smsc-ircc ATC circuitry + * + */ + +static int smsc_ircc_probe_transceiver_smsc_ircc_atc(int fir_base) +{ + return 0; +} + +/* + * Function smsc_ircc_set_transceiver_smsc_ircc_fast_pin_select(self, speed) + * + * Set transceiver + * + */ + +static void smsc_ircc_set_transceiver_smsc_ircc_fast_pin_select(int fir_base, u32 speed) +{ + u8 fast_mode; + + switch (speed) { + default: + case 576000 : + fast_mode = 0; + break; + case 1152000 : + case 4000000 : + fast_mode = IRCC_LCR_A_FAST; + break; + } + register_bank(fir_base, 0); + outb((inb(fir_base + IRCC_LCR_A) & 0xbf) | fast_mode, fir_base + IRCC_LCR_A); +} + +/* + * Function smsc_ircc_probe_transceiver_smsc_ircc_fast_pin_select(fir_base) + * + * Probe transceiver + * + */ + +static int smsc_ircc_probe_transceiver_smsc_ircc_fast_pin_select(int fir_base) +{ + return 0; +} + +/* + * Function smsc_ircc_set_transceiver_toshiba_sat1800(fir_base, speed) + * + * Set transceiver + * + */ + +static void smsc_ircc_set_transceiver_toshiba_sat1800(int fir_base, u32 speed) +{ + u8 fast_mode; + + switch (speed) { + default: + case 576000 : + fast_mode = 0; + break; + case 1152000 : + case 4000000 : + fast_mode = /*IRCC_LCR_A_FAST |*/ IRCC_LCR_A_GP_DATA; + break; + + } + /* This causes an interrupt */ + register_bank(fir_base, 0); + outb((inb(fir_base + IRCC_LCR_A) & 0xbf) | fast_mode, fir_base + IRCC_LCR_A); +} + +/* + * Function smsc_ircc_probe_transceiver_toshiba_sat1800(fir_base) + * + * Probe transceiver + * + */ + +static int smsc_ircc_probe_transceiver_toshiba_sat1800(int fir_base) +{ + return 0; +} + + +module_init(smsc_ircc_init); +module_exit(smsc_ircc_cleanup); diff --git a/drivers/staging/irda/drivers/smsc-ircc2.h b/drivers/staging/irda/drivers/smsc-ircc2.h new file mode 100644 index 000000000000..4829fa22cb29 --- /dev/null +++ b/drivers/staging/irda/drivers/smsc-ircc2.h @@ -0,0 +1,191 @@ +/********************************************************************* + * + * Description: Definitions for the SMC IrCC chipset + * Status: Experimental. + * Author: Daniele Peri (peri@csai.unipa.it) + * + * Copyright (c) 2002 Daniele Peri + * All Rights Reserved. + * + * Based on smc-ircc.h: + * + * Copyright (c) 1999-2000, Dag Brattli <dagb@cs.uit.no> + * Copyright (c) 1998-1999, Thomas Davis (tadavis@jps.net> + * All Rights Reserved + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + ********************************************************************/ + +#ifndef SMSC_IRCC2_H +#define SMSC_IRCC2_H + +/* DMA modes needed */ +#define DMA_TX_MODE 0x08 /* Mem to I/O, ++, demand. */ +#define DMA_RX_MODE 0x04 /* I/O to mem, ++, demand. */ + +/* Master Control Register */ +#define IRCC_MASTER 0x07 +#define IRCC_MASTER_POWERDOWN 0x80 +#define IRCC_MASTER_RESET 0x40 +#define IRCC_MASTER_INT_EN 0x20 +#define IRCC_MASTER_ERROR_RESET 0x10 + +/* Register block 0 */ + +/* Interrupt Identification */ +#define IRCC_IIR 0x01 +#define IRCC_IIR_ACTIVE_FRAME 0x80 +#define IRCC_IIR_EOM 0x40 +#define IRCC_IIR_RAW_MODE 0x20 +#define IRCC_IIR_FIFO 0x10 + +/* Interrupt Enable */ +#define IRCC_IER 0x02 +#define IRCC_IER_ACTIVE_FRAME 0x80 +#define IRCC_IER_EOM 0x40 +#define IRCC_IER_RAW_MODE 0x20 +#define IRCC_IER_FIFO 0x10 + +/* Line Status Register */ +#define IRCC_LSR 0x03 +#define IRCC_LSR_UNDERRUN 0x80 +#define IRCC_LSR_OVERRUN 0x40 +#define IRCC_LSR_FRAME_ERROR 0x20 +#define IRCC_LSR_SIZE_ERROR 0x10 +#define IRCC_LSR_CRC_ERROR 0x80 +#define IRCC_LSR_FRAME_ABORT 0x40 + +/* Line Status Address Register */ +#define IRCC_LSAR 0x03 +#define IRCC_LSAR_ADDRESS_MASK 0x07 + +/* Line Control Register A */ +#define IRCC_LCR_A 0x04 +#define IRCC_LCR_A_FIFO_RESET 0x80 +#define IRCC_LCR_A_FAST 0x40 +#define IRCC_LCR_A_GP_DATA 0x20 +#define IRCC_LCR_A_RAW_TX 0x10 +#define IRCC_LCR_A_RAW_RX 0x08 +#define IRCC_LCR_A_ABORT 0x04 +#define IRCC_LCR_A_DATA_DONE 0x02 + +/* Line Control Register B */ +#define IRCC_LCR_B 0x05 +#define IRCC_LCR_B_SCE_DISABLED 0x00 +#define IRCC_LCR_B_SCE_TRANSMIT 0x40 +#define IRCC_LCR_B_SCE_RECEIVE 0x80 +#define IRCC_LCR_B_SCE_UNDEFINED 0xc0 +#define IRCC_LCR_B_SIP_ENABLE 0x20 +#define IRCC_LCR_B_BRICK_WALL 0x10 + +/* Bus Status Register */ +#define IRCC_BSR 0x06 +#define IRCC_BSR_NOT_EMPTY 0x80 +#define IRCC_BSR_FIFO_FULL 0x40 +#define IRCC_BSR_TIMEOUT 0x20 + +/* Register block 1 */ + +#define IRCC_FIFO_THRESHOLD 0x02 + +#define IRCC_SCE_CFGA 0x00 +#define IRCC_CFGA_AUX_IR 0x80 +#define IRCC_CFGA_HALF_DUPLEX 0x04 +#define IRCC_CFGA_TX_POLARITY 0x02 +#define IRCC_CFGA_RX_POLARITY 0x01 + +#define IRCC_CFGA_COM 0x00 +#define IRCC_SCE_CFGA_BLOCK_CTRL_BITS_MASK 0x87 +#define IRCC_CFGA_IRDA_SIR_A 0x08 +#define IRCC_CFGA_ASK_SIR 0x10 +#define IRCC_CFGA_IRDA_SIR_B 0x18 +#define IRCC_CFGA_IRDA_HDLC 0x20 +#define IRCC_CFGA_IRDA_4PPM 0x28 +#define IRCC_CFGA_CONSUMER 0x30 +#define IRCC_CFGA_RAW_IR 0x38 +#define IRCC_CFGA_OTHER 0x40 + +#define IRCC_IR_HDLC 0x04 +#define IRCC_IR_4PPM 0x01 +#define IRCC_IR_CONSUMER 0x02 + +#define IRCC_SCE_CFGB 0x01 +#define IRCC_CFGB_LOOPBACK 0x20 +#define IRCC_CFGB_LPBCK_TX_CRC 0x10 +#define IRCC_CFGB_NOWAIT 0x08 +#define IRCC_CFGB_STRING_MOVE 0x04 +#define IRCC_CFGB_DMA_BURST 0x02 +#define IRCC_CFGB_DMA_ENABLE 0x01 + +#define IRCC_CFGB_MUX_COM 0x00 +#define IRCC_CFGB_MUX_IR 0x40 +#define IRCC_CFGB_MUX_AUX 0x80 +#define IRCC_CFGB_MUX_INACTIVE 0xc0 + +/* Register block 3 - Identification Registers! */ +#define IRCC_ID_HIGH 0x00 /* 0x10 */ +#define IRCC_ID_LOW 0x01 /* 0xB8 */ +#define IRCC_CHIP_ID 0x02 /* 0xF1 */ +#define IRCC_VERSION 0x03 /* 0x01 */ +#define IRCC_INTERFACE 0x04 /* low 4 = DMA, high 4 = IRQ */ +#define IRCC_INTERFACE_DMA_MASK 0x0F /* low 4 = DMA, high 4 = IRQ */ +#define IRCC_INTERFACE_IRQ_MASK 0xF0 /* low 4 = DMA, high 4 = IRQ */ + +/* Register block 4 - IrDA */ +#define IRCC_CONTROL 0x00 +#define IRCC_BOF_COUNT_LO 0x01 /* Low byte */ +#define IRCC_BOF_COUNT_HI 0x00 /* High nibble (bit 0-3) */ +#define IRCC_BRICKWALL_CNT_LO 0x02 /* Low byte */ +#define IRCC_BRICKWALL_CNT_HI 0x03 /* High nibble (bit 4-7) */ +#define IRCC_TX_SIZE_LO 0x04 /* Low byte */ +#define IRCC_TX_SIZE_HI 0x03 /* High nibble (bit 0-3) */ +#define IRCC_RX_SIZE_HI 0x05 /* High nibble (bit 0-3) */ +#define IRCC_RX_SIZE_LO 0x06 /* Low byte */ + +#define IRCC_1152 0x80 +#define IRCC_CRC 0x40 + +/* Register block 5 - IrDA */ +#define IRCC_ATC 0x00 +#define IRCC_ATC_nPROGREADY 0x80 +#define IRCC_ATC_SPEED 0x40 +#define IRCC_ATC_ENABLE 0x20 +#define IRCC_ATC_MASK 0xE0 + + +#define IRCC_IRHALFDUPLEX_TIMEOUT 0x01 + +#define IRCC_SCE_TX_DELAY_TIMER 0x02 + +/* + * Other definitions + */ + +#define SMSC_IRCC2_MAX_SIR_SPEED 115200 +#define SMSC_IRCC2_FIR_CHIP_IO_EXTENT 8 +#define SMSC_IRCC2_SIR_CHIP_IO_EXTENT 8 +#define SMSC_IRCC2_FIFO_SIZE 16 +#define SMSC_IRCC2_FIFO_THRESHOLD 64 +/* Max DMA buffer size needed = (data_size + 6) * (window_size) + 6; */ +#define SMSC_IRCC2_RX_BUFF_TRUESIZE 14384 +#define SMSC_IRCC2_TX_BUFF_TRUESIZE 14384 +#define SMSC_IRCC2_MIN_TURN_TIME 0x07 +#define SMSC_IRCC2_WINDOW_SIZE 0x07 +/* Maximum wait for hw transmitter to finish */ +#define SMSC_IRCC2_HW_TRANSMITTER_TIMEOUT_US 1000 /* 1 ms */ +/* Maximum wait for ATC transceiver programming to finish */ +#define SMSC_IRCC2_ATC_PROGRAMMING_TIMEOUT_JIFFIES 1 +#endif /* SMSC_IRCC2_H */ diff --git a/drivers/staging/irda/drivers/smsc-sio.h b/drivers/staging/irda/drivers/smsc-sio.h new file mode 100644 index 000000000000..59e20e653ebe --- /dev/null +++ b/drivers/staging/irda/drivers/smsc-sio.h @@ -0,0 +1,100 @@ +#ifndef SMSC_SIO_H +#define SMSC_SIO_H + +/****************************************** + Keys. They should work with every SMsC SIO + ******************************************/ + +#define SMSCSIO_CFGACCESSKEY 0x55 +#define SMSCSIO_CFGEXITKEY 0xaa + +/***************************** + * Generic SIO Flat (!?) * + *****************************/ + +/* Register 0x0d */ +#define SMSCSIOFLAT_DEVICEID_REG 0x0d + +/* Register 0x0c */ +#define SMSCSIOFLAT_UARTMODE0C_REG 0x0c +#define SMSCSIOFLAT_UART2MODE_MASK 0x38 +#define SMSCSIOFLAT_UART2MODE_VAL_COM 0x00 +#define SMSCSIOFLAT_UART2MODE_VAL_IRDA 0x08 +#define SMSCSIOFLAT_UART2MODE_VAL_ASKIR 0x10 + +/* Register 0x25 */ +#define SMSCSIOFLAT_UART2BASEADDR_REG 0x25 + +/* Register 0x2b */ +#define SMSCSIOFLAT_FIRBASEADDR_REG 0x2b + +/* Register 0x2c */ +#define SMSCSIOFLAT_FIRDMASELECT_REG 0x2c +#define SMSCSIOFLAT_FIRDMASELECT_MASK 0x0f + +/* Register 0x28 */ +#define SMSCSIOFLAT_UARTIRQSELECT_REG 0x28 +#define SMSCSIOFLAT_UART2IRQSELECT_MASK 0x0f +#define SMSCSIOFLAT_UART1IRQSELECT_MASK 0xf0 +#define SMSCSIOFLAT_UARTIRQSELECT_VAL_NONE 0x00 + + +/********************* + * LPC47N227 * + *********************/ + +#define LPC47N227_CFGACCESSKEY 0x55 +#define LPC47N227_CFGEXITKEY 0xaa + +/* Register 0x00 */ +#define LPC47N227_FDCPOWERVALIDCONF_REG 0x00 +#define LPC47N227_FDCPOWER_MASK 0x08 +#define LPC47N227_VALID_MASK 0x80 + +/* Register 0x02 */ +#define LPC47N227_UART12POWER_REG 0x02 +#define LPC47N227_UART1POWERDOWN_MASK 0x08 +#define LPC47N227_UART2POWERDOWN_MASK 0x80 + +/* Register 0x07 */ +#define LPC47N227_APMBOOTDRIVE_REG 0x07 +#define LPC47N227_PARPORT2AUTOPWRDOWN_MASK 0x10 /* auto power down on if set */ +#define LPC47N227_UART2AUTOPWRDOWN_MASK 0x20 /* auto power down on if set */ +#define LPC47N227_UART1AUTOPWRDOWN_MASK 0x40 /* auto power down on if set */ + +/* Register 0x0c */ +#define LPC47N227_UARTMODE0C_REG 0x0c +#define LPC47N227_UART2MODE_MASK 0x38 +#define LPC47N227_UART2MODE_VAL_COM 0x00 +#define LPC47N227_UART2MODE_VAL_IRDA 0x08 +#define LPC47N227_UART2MODE_VAL_ASKIR 0x10 + +/* Register 0x0d */ +#define LPC47N227_DEVICEID_REG 0x0d +#define LPC47N227_DEVICEID_DEFVAL 0x5a + +/* Register 0x0e */ +#define LPC47N227_REVISIONID_REG 0x0e + +/* Register 0x25 */ +#define LPC47N227_UART2BASEADDR_REG 0x25 + +/* Register 0x28 */ +#define LPC47N227_UARTIRQSELECT_REG 0x28 +#define LPC47N227_UART2IRQSELECT_MASK 0x0f +#define LPC47N227_UART1IRQSELECT_MASK 0xf0 +#define LPC47N227_UARTIRQSELECT_VAL_NONE 0x00 + +/* Register 0x2b */ +#define LPC47N227_FIRBASEADDR_REG 0x2b + +/* Register 0x2c */ +#define LPC47N227_FIRDMASELECT_REG 0x2c +#define LPC47N227_FIRDMASELECT_MASK 0x0f +#define LPC47N227_FIRDMASELECT_VAL_DMA1 0x01 /* 47n227 has three dma channels */ +#define LPC47N227_FIRDMASELECT_VAL_DMA2 0x02 +#define LPC47N227_FIRDMASELECT_VAL_DMA3 0x03 +#define LPC47N227_FIRDMASELECT_VAL_NONE 0x0f + + +#endif diff --git a/drivers/staging/irda/drivers/stir4200.c b/drivers/staging/irda/drivers/stir4200.c new file mode 100644 index 000000000000..ee2cb70b688d --- /dev/null +++ b/drivers/staging/irda/drivers/stir4200.c @@ -0,0 +1,1134 @@ +/***************************************************************************** +* +* Filename: stir4200.c +* Version: 0.4 +* Description: Irda SigmaTel USB Dongle +* Status: Experimental +* Author: Stephen Hemminger <shemminger@osdl.org> +* +* Based on earlier driver by Paul Stewart <stewart@parc.com> +* +* Copyright (C) 2000, Roman Weissgaerber <weissg@vienna.at> +* Copyright (C) 2001, Dag Brattli <dag@brattli.net> +* Copyright (C) 2001, Jean Tourrilhes <jt@hpl.hp.com> +* Copyright (C) 2004, Stephen Hemminger <shemminger@osdl.org> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + +/* + * This dongle does no framing, and requires polling to receive the + * data. The STIr4200 has bulk in and out endpoints just like + * usr-irda devices, but the data it sends and receives is raw; like + * irtty, it needs to call the wrap and unwrap functions to add and + * remove SOF/BOF and escape characters to/from the frame. + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> + +#include <linux/kernel.h> +#include <linux/sched/signal.h> +#include <linux/ktime.h> +#include <linux/types.h> +#include <linux/time.h> +#include <linux/skbuff.h> +#include <linux/netdevice.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/usb.h> +#include <linux/crc32.h> +#include <linux/kthread.h> +#include <linux/freezer.h> +#include <net/irda/irda.h> +#include <net/irda/irda_device.h> +#include <net/irda/wrapper.h> +#include <net/irda/crc.h> +#include <asm/byteorder.h> +#include <asm/unaligned.h> + +MODULE_AUTHOR("Stephen Hemminger <shemminger@linux-foundation.org>"); +MODULE_DESCRIPTION("IrDA-USB Dongle Driver for SigmaTel STIr4200"); +MODULE_LICENSE("GPL"); + +static int qos_mtt_bits = 0x07; /* 1 ms or more */ +module_param(qos_mtt_bits, int, 0); +MODULE_PARM_DESC(qos_mtt_bits, "Minimum Turn Time"); + +static int rx_sensitivity = 1; /* FIR 0..4, SIR 0..6 */ +module_param(rx_sensitivity, int, 0); +MODULE_PARM_DESC(rx_sensitivity, "Set Receiver sensitivity (0-6, 0 is most sensitive)"); + +static int tx_power = 0; /* 0 = highest ... 3 = lowest */ +module_param(tx_power, int, 0); +MODULE_PARM_DESC(tx_power, "Set Transmitter power (0-3, 0 is highest power)"); + +#define STIR_IRDA_HEADER 4 +#define CTRL_TIMEOUT 100 /* milliseconds */ +#define TRANSMIT_TIMEOUT 200 /* milliseconds */ +#define STIR_FIFO_SIZE 4096 +#define FIFO_REGS_SIZE 3 + +enum FirChars { + FIR_CE = 0x7d, + FIR_XBOF = 0x7f, + FIR_EOF = 0x7e, +}; + +enum StirRequests { + REQ_WRITE_REG = 0x00, + REQ_READ_REG = 0x01, + REQ_READ_ROM = 0x02, + REQ_WRITE_SINGLE = 0x03, +}; + +/* Register offsets */ +enum StirRegs { + REG_RSVD=0, + REG_MODE, + REG_PDCLK, + REG_CTRL1, + REG_CTRL2, + REG_FIFOCTL, + REG_FIFOLSB, + REG_FIFOMSB, + REG_DPLL, + REG_IRDIG, + REG_TEST=15, +}; + +enum StirModeMask { + MODE_FIR = 0x80, + MODE_SIR = 0x20, + MODE_ASK = 0x10, + MODE_FASTRX = 0x08, + MODE_FFRSTEN = 0x04, + MODE_NRESET = 0x02, + MODE_2400 = 0x01, +}; + +enum StirPdclkMask { + PDCLK_4000000 = 0x02, + PDCLK_115200 = 0x09, + PDCLK_57600 = 0x13, + PDCLK_38400 = 0x1D, + PDCLK_19200 = 0x3B, + PDCLK_9600 = 0x77, + PDCLK_2400 = 0xDF, +}; + +enum StirCtrl1Mask { + CTRL1_SDMODE = 0x80, + CTRL1_RXSLOW = 0x40, + CTRL1_TXPWD = 0x10, + CTRL1_RXPWD = 0x08, + CTRL1_SRESET = 0x01, +}; + +enum StirCtrl2Mask { + CTRL2_SPWIDTH = 0x08, + CTRL2_REVID = 0x03, +}; + +enum StirFifoCtlMask { + FIFOCTL_DIR = 0x10, + FIFOCTL_CLR = 0x08, + FIFOCTL_EMPTY = 0x04, +}; + +enum StirDiagMask { + IRDIG_RXHIGH = 0x80, + IRDIG_RXLOW = 0x40, +}; + +enum StirTestMask { + TEST_PLLDOWN = 0x80, + TEST_LOOPIR = 0x40, + TEST_LOOPUSB = 0x20, + TEST_TSTENA = 0x10, + TEST_TSTOSC = 0x0F, +}; + +struct stir_cb { + struct usb_device *usbdev; /* init: probe_irda */ + struct net_device *netdev; /* network layer */ + struct irlap_cb *irlap; /* The link layer we are binded to */ + + struct qos_info qos; + unsigned speed; /* Current speed */ + + struct task_struct *thread; /* transmit thread */ + + struct sk_buff *tx_pending; + void *io_buf; /* transmit/receive buffer */ + __u8 *fifo_status; + + iobuff_t rx_buff; /* receive unwrap state machine */ + ktime_t rx_time; + int receiving; + struct urb *rx_urb; +}; + + +/* These are the currently known USB ids */ +static const struct usb_device_id dongles[] = { + /* SigmaTel, Inc, STIr4200 IrDA/USB Bridge */ + { USB_DEVICE(0x066f, 0x4200) }, + { } +}; + +MODULE_DEVICE_TABLE(usb, dongles); + +/* Send control message to set dongle register */ +static int write_reg(struct stir_cb *stir, __u16 reg, __u8 value) +{ + struct usb_device *dev = stir->usbdev; + + pr_debug("%s: write reg %d = 0x%x\n", + stir->netdev->name, reg, value); + return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + REQ_WRITE_SINGLE, + USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_DEVICE, + value, reg, NULL, 0, + CTRL_TIMEOUT); +} + +/* Send control message to read multiple registers */ +static inline int read_reg(struct stir_cb *stir, __u16 reg, + __u8 *data, __u16 count) +{ + struct usb_device *dev = stir->usbdev; + + return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + REQ_READ_REG, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, reg, data, count, + CTRL_TIMEOUT); +} + +static inline int isfir(u32 speed) +{ + return speed == 4000000; +} + +/* + * Prepare a FIR IrDA frame for transmission to the USB dongle. The + * FIR transmit frame is documented in the datasheet. It consists of + * a two byte 0x55 0xAA sequence, two little-endian length bytes, a + * sequence of exactly 16 XBOF bytes of 0x7E, two BOF bytes of 0x7E, + * then the data escaped as follows: + * + * 0x7D -> 0x7D 0x5D + * 0x7E -> 0x7D 0x5E + * 0x7F -> 0x7D 0x5F + * + * Then, 4 bytes of little endian (stuffed) FCS follow, then two + * trailing EOF bytes of 0x7E. + */ +static inline __u8 *stuff_fir(__u8 *p, __u8 c) +{ + switch(c) { + case 0x7d: + case 0x7e: + case 0x7f: + *p++ = 0x7d; + c ^= IRDA_TRANS; + /* fall through */ + default: + *p++ = c; + } + return p; +} + +/* Take raw data in skb and put it wrapped into buf */ +static unsigned wrap_fir_skb(const struct sk_buff *skb, __u8 *buf) +{ + __u8 *ptr = buf; + __u32 fcs = ~(crc32_le(~0, skb->data, skb->len)); + __u16 wraplen; + int i; + + /* Header */ + buf[0] = 0x55; + buf[1] = 0xAA; + + ptr = buf + STIR_IRDA_HEADER; + memset(ptr, 0x7f, 16); + ptr += 16; + + /* BOF */ + *ptr++ = 0x7e; + *ptr++ = 0x7e; + + /* Address / Control / Information */ + for (i = 0; i < skb->len; i++) + ptr = stuff_fir(ptr, skb->data[i]); + + /* FCS */ + ptr = stuff_fir(ptr, fcs & 0xff); + ptr = stuff_fir(ptr, (fcs >> 8) & 0xff); + ptr = stuff_fir(ptr, (fcs >> 16) & 0xff); + ptr = stuff_fir(ptr, (fcs >> 24) & 0xff); + + /* EOFs */ + *ptr++ = 0x7e; + *ptr++ = 0x7e; + + /* Total length, minus the header */ + wraplen = (ptr - buf) - STIR_IRDA_HEADER; + buf[2] = wraplen & 0xff; + buf[3] = (wraplen >> 8) & 0xff; + + return wraplen + STIR_IRDA_HEADER; +} + +static unsigned wrap_sir_skb(struct sk_buff *skb, __u8 *buf) +{ + __u16 wraplen; + + wraplen = async_wrap_skb(skb, buf + STIR_IRDA_HEADER, + STIR_FIFO_SIZE - STIR_IRDA_HEADER); + buf[0] = 0x55; + buf[1] = 0xAA; + buf[2] = wraplen & 0xff; + buf[3] = (wraplen >> 8) & 0xff; + + return wraplen + STIR_IRDA_HEADER; +} + +/* + * Frame is fully formed in the rx_buff so check crc + * and pass up to irlap + * setup for next receive + */ +static void fir_eof(struct stir_cb *stir) +{ + iobuff_t *rx_buff = &stir->rx_buff; + int len = rx_buff->len - 4; + struct sk_buff *skb, *nskb; + __u32 fcs; + + if (unlikely(len <= 0)) { + pr_debug("%s: short frame len %d\n", + stir->netdev->name, len); + + ++stir->netdev->stats.rx_errors; + ++stir->netdev->stats.rx_length_errors; + return; + } + + fcs = ~(crc32_le(~0, rx_buff->data, len)); + if (fcs != get_unaligned_le32(rx_buff->data + len)) { + pr_debug("crc error calc 0x%x len %d\n", fcs, len); + stir->netdev->stats.rx_errors++; + stir->netdev->stats.rx_crc_errors++; + return; + } + + /* if frame is short then just copy it */ + if (len < IRDA_RX_COPY_THRESHOLD) { + nskb = dev_alloc_skb(len + 1); + if (unlikely(!nskb)) { + ++stir->netdev->stats.rx_dropped; + return; + } + skb_reserve(nskb, 1); + skb = nskb; + skb_copy_to_linear_data(nskb, rx_buff->data, len); + } else { + nskb = dev_alloc_skb(rx_buff->truesize); + if (unlikely(!nskb)) { + ++stir->netdev->stats.rx_dropped; + return; + } + skb_reserve(nskb, 1); + skb = rx_buff->skb; + rx_buff->skb = nskb; + rx_buff->head = nskb->data; + } + + skb_put(skb, len); + + skb_reset_mac_header(skb); + skb->protocol = htons(ETH_P_IRDA); + skb->dev = stir->netdev; + + netif_rx(skb); + + stir->netdev->stats.rx_packets++; + stir->netdev->stats.rx_bytes += len; + + rx_buff->data = rx_buff->head; + rx_buff->len = 0; +} + +/* Unwrap FIR stuffed data and bump it to IrLAP */ +static void stir_fir_chars(struct stir_cb *stir, + const __u8 *bytes, int len) +{ + iobuff_t *rx_buff = &stir->rx_buff; + int i; + + for (i = 0; i < len; i++) { + __u8 byte = bytes[i]; + + switch(rx_buff->state) { + case OUTSIDE_FRAME: + /* ignore garbage till start of frame */ + if (unlikely(byte != FIR_EOF)) + continue; + /* Now receiving frame */ + rx_buff->state = BEGIN_FRAME; + + /* Time to initialize receive buffer */ + rx_buff->data = rx_buff->head; + rx_buff->len = 0; + continue; + + case LINK_ESCAPE: + if (byte == FIR_EOF) { + pr_debug("%s: got EOF after escape\n", + stir->netdev->name); + goto frame_error; + } + rx_buff->state = INSIDE_FRAME; + byte ^= IRDA_TRANS; + break; + + case BEGIN_FRAME: + /* ignore multiple BOF/EOF */ + if (byte == FIR_EOF) + continue; + rx_buff->state = INSIDE_FRAME; + rx_buff->in_frame = TRUE; + + /* fall through */ + case INSIDE_FRAME: + switch(byte) { + case FIR_CE: + rx_buff->state = LINK_ESCAPE; + continue; + case FIR_XBOF: + /* 0x7f is not used in this framing */ + pr_debug("%s: got XBOF without escape\n", + stir->netdev->name); + goto frame_error; + case FIR_EOF: + rx_buff->state = OUTSIDE_FRAME; + rx_buff->in_frame = FALSE; + fir_eof(stir); + continue; + } + break; + } + + /* add byte to rx buffer */ + if (unlikely(rx_buff->len >= rx_buff->truesize)) { + pr_debug("%s: fir frame exceeds %d\n", + stir->netdev->name, rx_buff->truesize); + ++stir->netdev->stats.rx_over_errors; + goto error_recovery; + } + + rx_buff->data[rx_buff->len++] = byte; + continue; + + frame_error: + ++stir->netdev->stats.rx_frame_errors; + + error_recovery: + ++stir->netdev->stats.rx_errors; + rx_buff->state = OUTSIDE_FRAME; + rx_buff->in_frame = FALSE; + } +} + +/* Unwrap SIR stuffed data and bump it up to IrLAP */ +static void stir_sir_chars(struct stir_cb *stir, + const __u8 *bytes, int len) +{ + int i; + + for (i = 0; i < len; i++) + async_unwrap_char(stir->netdev, &stir->netdev->stats, + &stir->rx_buff, bytes[i]); +} + +static inline void unwrap_chars(struct stir_cb *stir, + const __u8 *bytes, int length) +{ + if (isfir(stir->speed)) + stir_fir_chars(stir, bytes, length); + else + stir_sir_chars(stir, bytes, length); +} + +/* Mode parameters for each speed */ +static const struct { + unsigned speed; + __u8 pdclk; +} stir_modes[] = { + { 2400, PDCLK_2400 }, + { 9600, PDCLK_9600 }, + { 19200, PDCLK_19200 }, + { 38400, PDCLK_38400 }, + { 57600, PDCLK_57600 }, + { 115200, PDCLK_115200 }, + { 4000000, PDCLK_4000000 }, +}; + + +/* + * Setup chip for speed. + * Called at startup to initialize the chip + * and on speed changes. + * + * Note: Write multiple registers doesn't appear to work + */ +static int change_speed(struct stir_cb *stir, unsigned speed) +{ + int i, err; + __u8 mode; + + for (i = 0; i < ARRAY_SIZE(stir_modes); ++i) { + if (speed == stir_modes[i].speed) + goto found; + } + + dev_warn(&stir->netdev->dev, "invalid speed %d\n", speed); + return -EINVAL; + + found: + pr_debug("speed change from %d to %d\n", stir->speed, speed); + + /* Reset modulator */ + err = write_reg(stir, REG_CTRL1, CTRL1_SRESET); + if (err) + goto out; + + /* Undocumented magic to tweak the DPLL */ + err = write_reg(stir, REG_DPLL, 0x15); + if (err) + goto out; + + /* Set clock */ + err = write_reg(stir, REG_PDCLK, stir_modes[i].pdclk); + if (err) + goto out; + + mode = MODE_NRESET | MODE_FASTRX; + if (isfir(speed)) + mode |= MODE_FIR | MODE_FFRSTEN; + else + mode |= MODE_SIR; + + if (speed == 2400) + mode |= MODE_2400; + + err = write_reg(stir, REG_MODE, mode); + if (err) + goto out; + + /* This resets TEMIC style transceiver if any. */ + err = write_reg(stir, REG_CTRL1, + CTRL1_SDMODE | (tx_power & 3) << 1); + if (err) + goto out; + + err = write_reg(stir, REG_CTRL1, (tx_power & 3) << 1); + if (err) + goto out; + + /* Reset sensitivity */ + err = write_reg(stir, REG_CTRL2, (rx_sensitivity & 7) << 5); + out: + stir->speed = speed; + return err; +} + +/* + * Called from net/core when new frame is available. + */ +static netdev_tx_t stir_hard_xmit(struct sk_buff *skb, + struct net_device *netdev) +{ + struct stir_cb *stir = netdev_priv(netdev); + + netif_stop_queue(netdev); + + /* the IRDA wrapping routines don't deal with non linear skb */ + SKB_LINEAR_ASSERT(skb); + + skb = xchg(&stir->tx_pending, skb); + wake_up_process(stir->thread); + + /* this should never happen unless stop/wakeup problem */ + if (unlikely(skb)) { + WARN_ON(1); + dev_kfree_skb(skb); + } + + return NETDEV_TX_OK; +} + +/* + * Wait for the transmit FIFO to have space for next data + * + * If space < 0 then wait till FIFO completely drains. + * FYI: can take up to 13 seconds at 2400baud. + */ +static int fifo_txwait(struct stir_cb *stir, int space) +{ + int err; + unsigned long count, status; + unsigned long prev_count = 0x1fff; + + /* Read FIFO status and count */ + for (;; prev_count = count) { + err = read_reg(stir, REG_FIFOCTL, stir->fifo_status, + FIFO_REGS_SIZE); + if (unlikely(err != FIFO_REGS_SIZE)) { + dev_warn(&stir->netdev->dev, + "FIFO register read error: %d\n", err); + + return err; + } + + status = stir->fifo_status[0]; + count = (unsigned)(stir->fifo_status[2] & 0x1f) << 8 + | stir->fifo_status[1]; + + pr_debug("fifo status 0x%lx count %lu\n", status, count); + + /* is fifo receiving already, or empty */ + if (!(status & FIFOCTL_DIR) || + (status & FIFOCTL_EMPTY)) + return 0; + + if (signal_pending(current)) + return -EINTR; + + /* shutting down? */ + if (!netif_running(stir->netdev) || + !netif_device_present(stir->netdev)) + return -ESHUTDOWN; + + /* only waiting for some space */ + if (space >= 0 && STIR_FIFO_SIZE - 4 > space + count) + return 0; + + /* queue confused */ + if (prev_count < count) + break; + + /* estimate transfer time for remaining chars */ + msleep((count * 8000) / stir->speed); + } + + err = write_reg(stir, REG_FIFOCTL, FIFOCTL_CLR); + if (err) + return err; + err = write_reg(stir, REG_FIFOCTL, 0); + if (err) + return err; + + return 0; +} + + +/* Wait for turnaround delay before starting transmit. */ +static void turnaround_delay(const struct stir_cb *stir, long us) +{ + long ticks; + + if (us <= 0) + return; + + us -= ktime_us_delta(ktime_get(), stir->rx_time); + + if (us < 10) + return; + + ticks = us / (1000000 / HZ); + if (ticks > 0) + schedule_timeout_interruptible(1 + ticks); + else + udelay(us); +} + +/* + * Start receiver by submitting a request to the receive pipe. + * If nothing is available it will return after rx_interval. + */ +static int receive_start(struct stir_cb *stir) +{ + /* reset state */ + stir->receiving = 1; + + stir->rx_buff.in_frame = FALSE; + stir->rx_buff.state = OUTSIDE_FRAME; + + stir->rx_urb->status = 0; + return usb_submit_urb(stir->rx_urb, GFP_KERNEL); +} + +/* Stop all pending receive Urb's */ +static void receive_stop(struct stir_cb *stir) +{ + stir->receiving = 0; + usb_kill_urb(stir->rx_urb); + + if (stir->rx_buff.in_frame) + stir->netdev->stats.collisions++; +} +/* + * Wrap data in socket buffer and send it. + */ +static void stir_send(struct stir_cb *stir, struct sk_buff *skb) +{ + unsigned wraplen; + int first_frame = 0; + + /* if receiving, need to turnaround */ + if (stir->receiving) { + receive_stop(stir); + turnaround_delay(stir, irda_get_mtt(skb)); + first_frame = 1; + } + + if (isfir(stir->speed)) + wraplen = wrap_fir_skb(skb, stir->io_buf); + else + wraplen = wrap_sir_skb(skb, stir->io_buf); + + /* check for space available in fifo */ + if (!first_frame) + fifo_txwait(stir, wraplen); + + stir->netdev->stats.tx_packets++; + stir->netdev->stats.tx_bytes += skb->len; + netif_trans_update(stir->netdev); + pr_debug("send %d (%d)\n", skb->len, wraplen); + + if (usb_bulk_msg(stir->usbdev, usb_sndbulkpipe(stir->usbdev, 1), + stir->io_buf, wraplen, + NULL, TRANSMIT_TIMEOUT)) + stir->netdev->stats.tx_errors++; +} + +/* + * Transmit state machine thread + */ +static int stir_transmit_thread(void *arg) +{ + struct stir_cb *stir = arg; + struct net_device *dev = stir->netdev; + struct sk_buff *skb; + + while (!kthread_should_stop()) { +#ifdef CONFIG_PM + /* if suspending, then power off and wait */ + if (unlikely(freezing(current))) { + if (stir->receiving) + receive_stop(stir); + else + fifo_txwait(stir, -1); + + write_reg(stir, REG_CTRL1, CTRL1_TXPWD|CTRL1_RXPWD); + + try_to_freeze(); + + if (change_speed(stir, stir->speed)) + break; + } +#endif + + /* if something to send? */ + skb = xchg(&stir->tx_pending, NULL); + if (skb) { + unsigned new_speed = irda_get_next_speed(skb); + netif_wake_queue(dev); + + if (skb->len > 0) + stir_send(stir, skb); + dev_kfree_skb(skb); + + if ((new_speed != -1) && (stir->speed != new_speed)) { + if (fifo_txwait(stir, -1) || + change_speed(stir, new_speed)) + break; + } + continue; + } + + /* nothing to send? start receiving */ + if (!stir->receiving && + irda_device_txqueue_empty(dev)) { + /* Wait otherwise chip gets confused. */ + if (fifo_txwait(stir, -1)) + break; + + if (unlikely(receive_start(stir))) { + if (net_ratelimit()) + dev_info(&dev->dev, + "%s: receive usb submit failed\n", + stir->netdev->name); + stir->receiving = 0; + msleep(10); + continue; + } + } + + /* sleep if nothing to send */ + set_current_state(TASK_INTERRUPTIBLE); + schedule(); + + } + return 0; +} + + +/* + * USB bulk receive completion callback. + * Wakes up every ms (usb round trip) with wrapped + * data. + */ +static void stir_rcv_irq(struct urb *urb) +{ + struct stir_cb *stir = urb->context; + int err; + + /* in process of stopping, just drop data */ + if (!netif_running(stir->netdev)) + return; + + /* unlink, shutdown, unplug, other nasties */ + if (urb->status != 0) + return; + + if (urb->actual_length > 0) { + pr_debug("receive %d\n", urb->actual_length); + unwrap_chars(stir, urb->transfer_buffer, + urb->actual_length); + + stir->rx_time = ktime_get(); + } + + /* kernel thread is stopping receiver don't resubmit */ + if (!stir->receiving) + return; + + /* resubmit existing urb */ + err = usb_submit_urb(urb, GFP_ATOMIC); + + /* in case of error, the kernel thread will restart us */ + if (err) { + dev_warn(&stir->netdev->dev, "usb receive submit error: %d\n", + err); + stir->receiving = 0; + wake_up_process(stir->thread); + } +} + +/* + * Function stir_net_open (dev) + * + * Network device is taken up. Usually this is done by "ifconfig irda0 up" + */ +static int stir_net_open(struct net_device *netdev) +{ + struct stir_cb *stir = netdev_priv(netdev); + int err; + char hwname[16]; + + err = usb_clear_halt(stir->usbdev, usb_sndbulkpipe(stir->usbdev, 1)); + if (err) + goto err_out1; + err = usb_clear_halt(stir->usbdev, usb_rcvbulkpipe(stir->usbdev, 2)); + if (err) + goto err_out1; + + err = change_speed(stir, 9600); + if (err) + goto err_out1; + + err = -ENOMEM; + + /* Initialize for SIR/FIR to copy data directly into skb. */ + stir->receiving = 0; + stir->rx_buff.truesize = IRDA_SKB_MAX_MTU; + stir->rx_buff.skb = dev_alloc_skb(IRDA_SKB_MAX_MTU); + if (!stir->rx_buff.skb) + goto err_out1; + + skb_reserve(stir->rx_buff.skb, 1); + stir->rx_buff.head = stir->rx_buff.skb->data; + stir->rx_time = ktime_get(); + + stir->rx_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!stir->rx_urb) + goto err_out2; + + stir->io_buf = kmalloc(STIR_FIFO_SIZE, GFP_KERNEL); + if (!stir->io_buf) + goto err_out3; + + usb_fill_bulk_urb(stir->rx_urb, stir->usbdev, + usb_rcvbulkpipe(stir->usbdev, 2), + stir->io_buf, STIR_FIFO_SIZE, + stir_rcv_irq, stir); + + stir->fifo_status = kmalloc(FIFO_REGS_SIZE, GFP_KERNEL); + if (!stir->fifo_status) + goto err_out4; + + /* + * Now that everything should be initialized properly, + * Open new IrLAP layer instance to take care of us... + * Note : will send immediately a speed change... + */ + sprintf(hwname, "usb#%d", stir->usbdev->devnum); + stir->irlap = irlap_open(netdev, &stir->qos, hwname); + if (!stir->irlap) { + dev_err(&stir->usbdev->dev, "irlap_open failed\n"); + goto err_out5; + } + + /** Start kernel thread for transmit. */ + stir->thread = kthread_run(stir_transmit_thread, stir, + "%s", stir->netdev->name); + if (IS_ERR(stir->thread)) { + err = PTR_ERR(stir->thread); + dev_err(&stir->usbdev->dev, "unable to start kernel thread\n"); + goto err_out6; + } + + netif_start_queue(netdev); + + return 0; + + err_out6: + irlap_close(stir->irlap); + err_out5: + kfree(stir->fifo_status); + err_out4: + kfree(stir->io_buf); + err_out3: + usb_free_urb(stir->rx_urb); + err_out2: + kfree_skb(stir->rx_buff.skb); + err_out1: + return err; +} + +/* + * Function stir_net_close (stir) + * + * Network device is taken down. Usually this is done by + * "ifconfig irda0 down" + */ +static int stir_net_close(struct net_device *netdev) +{ + struct stir_cb *stir = netdev_priv(netdev); + + /* Stop transmit processing */ + netif_stop_queue(netdev); + + /* Kill transmit thread */ + kthread_stop(stir->thread); + kfree(stir->fifo_status); + + /* Mop up receive urb's */ + usb_kill_urb(stir->rx_urb); + + kfree(stir->io_buf); + usb_free_urb(stir->rx_urb); + kfree_skb(stir->rx_buff.skb); + + /* Stop and remove instance of IrLAP */ + if (stir->irlap) + irlap_close(stir->irlap); + + stir->irlap = NULL; + + return 0; +} + +/* + * IOCTLs : Extra out-of-band network commands... + */ +static int stir_net_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) +{ + struct if_irda_req *irq = (struct if_irda_req *) rq; + struct stir_cb *stir = netdev_priv(netdev); + int ret = 0; + + switch (cmd) { + case SIOCSBANDWIDTH: /* Set bandwidth */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + /* Check if the device is still there */ + if (netif_device_present(stir->netdev)) + ret = change_speed(stir, irq->ifr_baudrate); + break; + + case SIOCSMEDIABUSY: /* Set media busy */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + /* Check if the IrDA stack is still there */ + if (netif_running(stir->netdev)) + irda_device_set_media_busy(stir->netdev, TRUE); + break; + + case SIOCGRECEIVING: + /* Only approximately true */ + irq->ifr_receiving = stir->receiving; + break; + + default: + ret = -EOPNOTSUPP; + } + + return ret; +} + +static const struct net_device_ops stir_netdev_ops = { + .ndo_open = stir_net_open, + .ndo_stop = stir_net_close, + .ndo_start_xmit = stir_hard_xmit, + .ndo_do_ioctl = stir_net_ioctl, +}; + +/* + * This routine is called by the USB subsystem for each new device + * in the system. We need to check if the device is ours, and in + * this case start handling it. + * Note : it might be worth protecting this function by a global + * spinlock... Or not, because maybe USB already deal with that... + */ +static int stir_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *dev = interface_to_usbdev(intf); + struct stir_cb *stir = NULL; + struct net_device *net; + int ret = -ENOMEM; + + /* Allocate network device container. */ + net = alloc_irdadev(sizeof(*stir)); + if(!net) + goto err_out1; + + SET_NETDEV_DEV(net, &intf->dev); + stir = netdev_priv(net); + stir->netdev = net; + stir->usbdev = dev; + + ret = usb_reset_configuration(dev); + if (ret != 0) { + dev_err(&intf->dev, "usb reset configuration failed\n"); + goto err_out2; + } + + printk(KERN_INFO "SigmaTel STIr4200 IRDA/USB found at address %d, " + "Vendor: %x, Product: %x\n", + dev->devnum, le16_to_cpu(dev->descriptor.idVendor), + le16_to_cpu(dev->descriptor.idProduct)); + + /* Initialize QoS for this device */ + irda_init_max_qos_capabilies(&stir->qos); + + /* That's the Rx capability. */ + stir->qos.baud_rate.bits &= IR_2400 | IR_9600 | IR_19200 | + IR_38400 | IR_57600 | IR_115200 | + (IR_4000000 << 8); + stir->qos.min_turn_time.bits &= qos_mtt_bits; + irda_qos_bits_to_value(&stir->qos); + + /* Override the network functions we need to use */ + net->netdev_ops = &stir_netdev_ops; + + ret = register_netdev(net); + if (ret != 0) + goto err_out2; + + dev_info(&intf->dev, "IrDA: Registered SigmaTel device %s\n", + net->name); + + usb_set_intfdata(intf, stir); + + return 0; + +err_out2: + free_netdev(net); +err_out1: + return ret; +} + +/* + * The current device is removed, the USB layer tell us to shut it down... + */ +static void stir_disconnect(struct usb_interface *intf) +{ + struct stir_cb *stir = usb_get_intfdata(intf); + + if (!stir) + return; + + unregister_netdev(stir->netdev); + free_netdev(stir->netdev); + + usb_set_intfdata(intf, NULL); +} + +#ifdef CONFIG_PM +/* USB suspend, so power off the transmitter/receiver */ +static int stir_suspend(struct usb_interface *intf, pm_message_t message) +{ + struct stir_cb *stir = usb_get_intfdata(intf); + + netif_device_detach(stir->netdev); + return 0; +} + +/* Coming out of suspend, so reset hardware */ +static int stir_resume(struct usb_interface *intf) +{ + struct stir_cb *stir = usb_get_intfdata(intf); + + netif_device_attach(stir->netdev); + + /* receiver restarted when send thread wakes up */ + return 0; +} +#endif + +/* + * USB device callbacks + */ +static struct usb_driver irda_driver = { + .name = "stir4200", + .probe = stir_probe, + .disconnect = stir_disconnect, + .id_table = dongles, +#ifdef CONFIG_PM + .suspend = stir_suspend, + .resume = stir_resume, +#endif +}; + +module_usb_driver(irda_driver); diff --git a/drivers/staging/irda/drivers/tekram-sir.c b/drivers/staging/irda/drivers/tekram-sir.c new file mode 100644 index 000000000000..9dcf0c103b9d --- /dev/null +++ b/drivers/staging/irda/drivers/tekram-sir.c @@ -0,0 +1,225 @@ +/********************************************************************* + * + * Filename: tekram.c + * Version: 1.3 + * Description: Implementation of the Tekram IrMate IR-210B dongle + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Wed Oct 21 20:02:35 1998 + * Modified at: Sun Oct 27 22:02:38 2002 + * Modified by: Martin Diehl <mad@mdiehl.de> + * + * Copyright (c) 1998-1999 Dag Brattli, + * Copyright (c) 2002 Martin Diehl, + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/init.h> + +#include <net/irda/irda.h> + +#include "sir-dev.h" + +static int tekram_delay = 150; /* default is 150 ms */ +module_param(tekram_delay, int, 0); +MODULE_PARM_DESC(tekram_delay, "tekram dongle write complete delay"); + +static int tekram_open(struct sir_dev *); +static int tekram_close(struct sir_dev *); +static int tekram_change_speed(struct sir_dev *, unsigned); +static int tekram_reset(struct sir_dev *); + +#define TEKRAM_115200 0x00 +#define TEKRAM_57600 0x01 +#define TEKRAM_38400 0x02 +#define TEKRAM_19200 0x03 +#define TEKRAM_9600 0x04 + +#define TEKRAM_PW 0x10 /* Pulse select bit */ + +static struct dongle_driver tekram = { + .owner = THIS_MODULE, + .driver_name = "Tekram IR-210B", + .type = IRDA_TEKRAM_DONGLE, + .open = tekram_open, + .close = tekram_close, + .reset = tekram_reset, + .set_speed = tekram_change_speed, +}; + +static int __init tekram_sir_init(void) +{ + if (tekram_delay < 1 || tekram_delay > 500) + tekram_delay = 200; + pr_debug("%s - using %d ms delay\n", + tekram.driver_name, tekram_delay); + return irda_register_dongle(&tekram); +} + +static void __exit tekram_sir_cleanup(void) +{ + irda_unregister_dongle(&tekram); +} + +static int tekram_open(struct sir_dev *dev) +{ + struct qos_info *qos = &dev->qos; + + sirdev_set_dtr_rts(dev, TRUE, TRUE); + + qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200; + qos->min_turn_time.bits = 0x01; /* Needs at least 10 ms */ + irda_qos_bits_to_value(qos); + + /* irda thread waits 50 msec for power settling */ + + return 0; +} + +static int tekram_close(struct sir_dev *dev) +{ + /* Power off dongle */ + sirdev_set_dtr_rts(dev, FALSE, FALSE); + + return 0; +} + +/* + * Function tekram_change_speed (dev, state, speed) + * + * Set the speed for the Tekram IRMate 210 type dongle. Warning, this + * function must be called with a process context! + * + * Algorithm + * 1. clear DTR + * 2. set RTS, and wait at least 7 us + * 3. send Control Byte to the IR-210 through TXD to set new baud rate + * wait until the stop bit of Control Byte is sent (for 9600 baud rate, + * it takes about 100 msec) + * + * [oops, why 100 msec? sending 1 byte (10 bits) takes 1.05 msec + * - is this probably to compensate for delays in tty layer?] + * + * 5. clear RTS (return to NORMAL Operation) + * 6. wait at least 50 us, new setting (baud rate, etc) takes effect here + * after + */ + +#define TEKRAM_STATE_WAIT_SPEED (SIRDEV_STATE_DONGLE_SPEED + 1) + +static int tekram_change_speed(struct sir_dev *dev, unsigned speed) +{ + unsigned state = dev->fsm.substate; + unsigned delay = 0; + u8 byte; + static int ret = 0; + + switch(state) { + case SIRDEV_STATE_DONGLE_SPEED: + + switch (speed) { + default: + speed = 9600; + ret = -EINVAL; + /* fall thru */ + case 9600: + byte = TEKRAM_PW|TEKRAM_9600; + break; + case 19200: + byte = TEKRAM_PW|TEKRAM_19200; + break; + case 38400: + byte = TEKRAM_PW|TEKRAM_38400; + break; + case 57600: + byte = TEKRAM_PW|TEKRAM_57600; + break; + case 115200: + byte = TEKRAM_115200; + break; + } + + /* Set DTR, Clear RTS */ + sirdev_set_dtr_rts(dev, TRUE, FALSE); + + /* Wait at least 7us */ + udelay(14); + + /* Write control byte */ + sirdev_raw_write(dev, &byte, 1); + + dev->speed = speed; + + state = TEKRAM_STATE_WAIT_SPEED; + delay = tekram_delay; + break; + + case TEKRAM_STATE_WAIT_SPEED: + /* Set DTR, Set RTS */ + sirdev_set_dtr_rts(dev, TRUE, TRUE); + udelay(50); + break; + + default: + net_err_ratelimited("%s - undefined state %d\n", + __func__, state); + ret = -EINVAL; + break; + } + + dev->fsm.substate = state; + return (delay > 0) ? delay : ret; +} + +/* + * Function tekram_reset (driver) + * + * This function resets the tekram dongle. Warning, this function + * must be called with a process context!! + * + * Algorithm: + * 0. Clear RTS and DTR, and wait 50 ms (power off the IR-210 ) + * 1. clear RTS + * 2. set DTR, and wait at least 1 ms + * 3. clear DTR to SPACE state, wait at least 50 us for further + * operation + */ + +static int tekram_reset(struct sir_dev *dev) +{ + /* Clear DTR, Set RTS */ + sirdev_set_dtr_rts(dev, FALSE, TRUE); + + /* Should sleep 1 ms */ + msleep(1); + + /* Set DTR, Set RTS */ + sirdev_set_dtr_rts(dev, TRUE, TRUE); + + /* Wait at least 50 us */ + udelay(75); + + dev->speed = 9600; + + return 0; +} + +MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>"); +MODULE_DESCRIPTION("Tekram IrMate IR-210B dongle driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("irda-dongle-0"); /* IRDA_TEKRAM_DONGLE */ + +module_init(tekram_sir_init); +module_exit(tekram_sir_cleanup); diff --git a/drivers/staging/irda/drivers/toim3232-sir.c b/drivers/staging/irda/drivers/toim3232-sir.c new file mode 100644 index 000000000000..b977d6d33e74 --- /dev/null +++ b/drivers/staging/irda/drivers/toim3232-sir.c @@ -0,0 +1,358 @@ +/********************************************************************* + * + * Filename: toim3232-sir.c + * Version: 1.0 + * Description: Implementation of dongles based on the Vishay/Temic + * TOIM3232 SIR Endec chipset. Currently only the + * IRWave IR320ST-2 is tested, although it should work + * with any TOIM3232 or TOIM4232 chipset based RS232 + * dongle with minimal modification. + * Based heavily on the Tekram driver (tekram.c), + * with thanks to Dag Brattli and Martin Diehl. + * Status: Experimental. + * Author: David Basden <davidb-irda@rcpt.to> + * Created at: Thu Feb 09 23:47:32 2006 + * + * Copyright (c) 2006 David Basden. + * Copyright (c) 1998-1999 Dag Brattli, + * Copyright (c) 2002 Martin Diehl, + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +/* + * This driver has currently only been tested on the IRWave IR320ST-2 + * + * PROTOCOL: + * + * The protocol for talking to the TOIM3232 is quite easy, and is + * designed to interface with RS232 with only level convertors. The + * BR/~D line on the chip is brought high to signal 'command mode', + * where a command byte is sent to select the baudrate of the RS232 + * interface and the pulse length of the IRDA output. When BR/~D + * is brought low, the dongle then changes to the selected baudrate, + * and the RS232 interface is used for data until BR/~D is brought + * high again. The initial speed for the TOIMx323 after RESET is + * 9600 baud. The baudrate for command-mode is the last selected + * baud-rate, or 9600 after a RESET. + * + * The dongle I have (below) adds some extra hardware on the front end, + * but this is mostly directed towards pariasitic power from the RS232 + * line rather than changing very much about how to communicate with + * the TOIM3232. + * + * The protocol to talk to the TOIM4232 chipset seems to be almost + * identical to the TOIM3232 (and the 4232 datasheet is more detailed) + * so this code will probably work on that as well, although I haven't + * tested it on that hardware. + * + * Target dongle variations that might be common: + * + * DTR and RTS function: + * The data sheet for the 4232 has a sample implementation that hooks the + * DTR and RTS lines to the RESET and BaudRate/~Data lines of the + * chip (through line-converters). Given both DTR and RTS would have to + * be held low in normal operation, and the TOIMx232 requires +5V to + * signal ground, most dongle designers would almost certainly choose + * an implementation that kept at least one of DTR or RTS high in + * normal operation to provide power to the dongle, but will likely + * vary between designs. + * + * User specified command bits: + * There are two user-controllable output lines from the TOIMx232 that + * can be set low or high by setting the appropriate bits in the + * high-nibble of the command byte (when setting speed and pulse length). + * These might be used to switch on and off added hardware or extra + * dongle features. + * + * + * Target hardware: IRWave IR320ST-2 + * + * The IRWave IR320ST-2 is a simple dongle based on the Vishay/Temic + * TOIM3232 SIR Endec and the Vishay/Temic TFDS4500 SIR IRDA transceiver. + * It uses a hex inverter and some discrete components to buffer and + * line convert the RS232 down to 5V. + * + * The dongle is powered through a voltage regulator, fed by a large + * capacitor. To switch the dongle on, DTR is brought high to charge + * the capacitor and drive the voltage regulator. DTR isn't associated + * with any control lines on the TOIM3232. Parisitic power is also taken + * from the RTS, TD and RD lines when brought high, but through resistors. + * When DTR is low, the circuit might lose power even with RTS high. + * + * RTS is inverted and attached to the BR/~D input pin. When RTS + * is high, BR/~D is low, and the TOIM3232 is in the normal 'data' mode. + * RTS is brought low, BR/~D is high, and the TOIM3232 is in 'command + * mode'. + * + * For some unknown reason, the RESET line isn't actually connected + * to anything. This means to reset the dongle to get it to a known + * state (9600 baud) you must drop DTR and RTS low, wait for the power + * capacitor to discharge, and then bring DTR (and RTS for data mode) + * high again, and wait for the capacitor to charge, the power supply + * to stabilise, and the oscillator clock to stabilise. + * + * Fortunately, if the current baudrate is known, the chipset can + * easily change speed by entering command mode without having to + * reset the dongle first. + * + * Major Components: + * + * - Vishay/Temic TOIM3232 SIR Endec to change RS232 pulse timings + * to IRDA pulse timings + * - 3.6864MHz crystal to drive TOIM3232 clock oscillator + * - DM74lS04M Inverting Hex line buffer for RS232 input buffering + * and level conversion + * - PJ2951AC 150mA voltage regulator + * - Vishay/Temic TFDS4500 SIR IRDA front-end transceiver + * + */ + +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/sched.h> + +#include <net/irda/irda.h> + +#include "sir-dev.h" + +static int toim3232delay = 150; /* default is 150 ms */ +module_param(toim3232delay, int, 0); +MODULE_PARM_DESC(toim3232delay, "toim3232 dongle write complete delay"); + +static int toim3232_open(struct sir_dev *); +static int toim3232_close(struct sir_dev *); +static int toim3232_change_speed(struct sir_dev *, unsigned); +static int toim3232_reset(struct sir_dev *); + +#define TOIM3232_115200 0x00 +#define TOIM3232_57600 0x01 +#define TOIM3232_38400 0x02 +#define TOIM3232_19200 0x03 +#define TOIM3232_9600 0x06 +#define TOIM3232_2400 0x0A + +#define TOIM3232_PW 0x10 /* Pulse select bit */ + +static struct dongle_driver toim3232 = { + .owner = THIS_MODULE, + .driver_name = "Vishay TOIM3232", + .type = IRDA_TOIM3232_DONGLE, + .open = toim3232_open, + .close = toim3232_close, + .reset = toim3232_reset, + .set_speed = toim3232_change_speed, +}; + +static int __init toim3232_sir_init(void) +{ + if (toim3232delay < 1 || toim3232delay > 500) + toim3232delay = 200; + pr_debug("%s - using %d ms delay\n", + toim3232.driver_name, toim3232delay); + return irda_register_dongle(&toim3232); +} + +static void __exit toim3232_sir_cleanup(void) +{ + irda_unregister_dongle(&toim3232); +} + +static int toim3232_open(struct sir_dev *dev) +{ + struct qos_info *qos = &dev->qos; + + /* Pull the lines high to start with. + * + * For the IR320ST-2, we need to charge the main supply capacitor to + * switch the device on. We keep DTR high throughout to do this. + * When RTS, TD and RD are high, they will also trickle-charge the + * cap. RTS is high for data transmission, and low for baud rate select. + * -- DGB + */ + sirdev_set_dtr_rts(dev, TRUE, TRUE); + + /* The TOI3232 supports many speeds between 1200bps and 115000bps. + * We really only care about those supported by the IRDA spec, but + * 38400 seems to be implemented in many places */ + qos->baud_rate.bits &= IR_2400|IR_9600|IR_19200|IR_38400|IR_57600|IR_115200; + + /* From the tekram driver. Not sure what a reasonable value is -- DGB */ + qos->min_turn_time.bits = 0x01; /* Needs at least 10 ms */ + irda_qos_bits_to_value(qos); + + /* irda thread waits 50 msec for power settling */ + + return 0; +} + +static int toim3232_close(struct sir_dev *dev) +{ + /* Power off dongle */ + sirdev_set_dtr_rts(dev, FALSE, FALSE); + + return 0; +} + +/* + * Function toim3232change_speed (dev, state, speed) + * + * Set the speed for the TOIM3232 based dongle. Warning, this + * function must be called with a process context! + * + * Algorithm + * 1. keep DTR high but clear RTS to bring into baud programming mode + * 2. wait at least 7us to enter programming mode + * 3. send control word to set baud rate and timing + * 4. wait at least 1us + * 5. bring RTS high to enter DATA mode (RS232 is passed through to transceiver) + * 6. should take effect immediately (although probably worth waiting) + */ + +#define TOIM3232_STATE_WAIT_SPEED (SIRDEV_STATE_DONGLE_SPEED + 1) + +static int toim3232_change_speed(struct sir_dev *dev, unsigned speed) +{ + unsigned state = dev->fsm.substate; + unsigned delay = 0; + u8 byte; + static int ret = 0; + + switch(state) { + case SIRDEV_STATE_DONGLE_SPEED: + + /* Figure out what we are going to send as a control byte */ + switch (speed) { + case 2400: + byte = TOIM3232_PW|TOIM3232_2400; + break; + default: + speed = 9600; + ret = -EINVAL; + /* fall thru */ + case 9600: + byte = TOIM3232_PW|TOIM3232_9600; + break; + case 19200: + byte = TOIM3232_PW|TOIM3232_19200; + break; + case 38400: + byte = TOIM3232_PW|TOIM3232_38400; + break; + case 57600: + byte = TOIM3232_PW|TOIM3232_57600; + break; + case 115200: + byte = TOIM3232_115200; + break; + } + + /* Set DTR, Clear RTS: Go into baud programming mode */ + sirdev_set_dtr_rts(dev, TRUE, FALSE); + + /* Wait at least 7us */ + udelay(14); + + /* Write control byte */ + sirdev_raw_write(dev, &byte, 1); + + dev->speed = speed; + + state = TOIM3232_STATE_WAIT_SPEED; + delay = toim3232delay; + break; + + case TOIM3232_STATE_WAIT_SPEED: + /* Have transmitted control byte * Wait for 'at least 1us' */ + udelay(14); + + /* Set DTR, Set RTS: Go into normal data mode */ + sirdev_set_dtr_rts(dev, TRUE, TRUE); + + /* Wait (TODO: check this is needed) */ + udelay(50); + break; + + default: + printk(KERN_ERR "%s - undefined state %d\n", __func__, state); + ret = -EINVAL; + break; + } + + dev->fsm.substate = state; + return (delay > 0) ? delay : ret; +} + +/* + * Function toim3232reset (driver) + * + * This function resets the toim3232 dongle. Warning, this function + * must be called with a process context!! + * + * What we should do is: + * 0. Pull RESET high + * 1. Wait for at least 7us + * 2. Pull RESET low + * 3. Wait for at least 7us + * 4. Pull BR/~D high + * 5. Wait for at least 7us + * 6. Send control byte to set baud rate + * 7. Wait at least 1us after stop bit + * 8. Pull BR/~D low + * 9. Should then be in data mode + * + * Because the IR320ST-2 doesn't have the RESET line connected for some reason, + * we'll have to do something else. + * + * The default speed after a RESET is 9600, so lets try just bringing it up in + * data mode after switching it off, waiting for the supply capacitor to + * discharge, and then switch it back on. This isn't actually pulling RESET + * high, but it seems to have the same effect. + * + * This behaviour will probably work on dongles that have the RESET line connected, + * but if not, add a flag for the IR320ST-2, and implment the above-listed proper + * behaviour. + * + * RTS is inverted and then fed to BR/~D, so to put it in programming mode, we + * need to have pull RTS low + */ + +static int toim3232_reset(struct sir_dev *dev) +{ + /* Switch off both DTR and RTS to switch off dongle */ + sirdev_set_dtr_rts(dev, FALSE, FALSE); + + /* Should sleep a while. This might be evil doing it this way.*/ + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(msecs_to_jiffies(50)); + + /* Set DTR, Set RTS (data mode) */ + sirdev_set_dtr_rts(dev, TRUE, TRUE); + + /* Wait at least 10 ms for power to stabilize again */ + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(msecs_to_jiffies(10)); + + /* Speed should now be 9600 */ + dev->speed = 9600; + + return 0; +} + +MODULE_AUTHOR("David Basden <davidb-linux@rcpt.to>"); +MODULE_DESCRIPTION("Vishay/Temic TOIM3232 based dongle driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("irda-dongle-12"); /* IRDA_TOIM3232_DONGLE */ + +module_init(toim3232_sir_init); +module_exit(toim3232_sir_cleanup); diff --git a/drivers/staging/irda/drivers/via-ircc.c b/drivers/staging/irda/drivers/via-ircc.c new file mode 100644 index 000000000000..ca4442a9d631 --- /dev/null +++ b/drivers/staging/irda/drivers/via-ircc.c @@ -0,0 +1,1593 @@ +/******************************************************************** + Filename: via-ircc.c + Version: 1.0 + Description: Driver for the VIA VT8231/VT8233 IrDA chipsets + Author: VIA Technologies,inc + Date : 08/06/2003 + +Copyright (c) 1998-2003 VIA Technologies, Inc. + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTIES OR REPRESENTATIONS; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program; if not, see <http://www.gnu.org/licenses/>. + +F01 Oct/02/02: Modify code for V0.11(move out back to back transfer) +F02 Oct/28/02: Add SB device ID for 3147 and 3177. + Comment : + jul/09/2002 : only implement two kind of dongle currently. + Oct/02/2002 : work on VT8231 and VT8233 . + Aug/06/2003 : change driver format to pci driver . + +2004-02-16: <sda@bdit.de> +- Removed unneeded 'legacy' pci stuff. +- Make sure SIR mode is set (hw_init()) before calling mode-dependent stuff. +- On speed change from core, don't send SIR frame with new speed. + Use current speed and change speeds later. +- Make module-param dongle_id actually work. +- New dongle_id 17 (0x11): TDFS4500. Single-ended SIR only. + Tested with home-grown PCB on EPIA boards. +- Code cleanup. + + ********************************************************************/ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/skbuff.h> +#include <linux/netdevice.h> +#include <linux/ioport.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/rtnetlink.h> +#include <linux/pci.h> +#include <linux/dma-mapping.h> +#include <linux/gfp.h> + +#include <asm/io.h> +#include <asm/dma.h> +#include <asm/byteorder.h> + +#include <linux/pm.h> + +#include <net/irda/wrapper.h> +#include <net/irda/irda.h> +#include <net/irda/irda_device.h> + +#include "via-ircc.h" + +#define VIA_MODULE_NAME "via-ircc" +#define CHIP_IO_EXTENT 0x40 + +static char *driver_name = VIA_MODULE_NAME; + +/* Module parameters */ +static int qos_mtt_bits = 0x07; /* 1 ms or more */ +static int dongle_id = 0; /* default: probe */ + +/* We can't guess the type of connected dongle, user *must* supply it. */ +module_param(dongle_id, int, 0); + +/* Some prototypes */ +static int via_ircc_open(struct pci_dev *pdev, chipio_t *info, + unsigned int id); +static int via_ircc_dma_receive(struct via_ircc_cb *self); +static int via_ircc_dma_receive_complete(struct via_ircc_cb *self, + int iobase); +static netdev_tx_t via_ircc_hard_xmit_sir(struct sk_buff *skb, + struct net_device *dev); +static netdev_tx_t via_ircc_hard_xmit_fir(struct sk_buff *skb, + struct net_device *dev); +static void via_hw_init(struct via_ircc_cb *self); +static void via_ircc_change_speed(struct via_ircc_cb *self, __u32 baud); +static irqreturn_t via_ircc_interrupt(int irq, void *dev_id); +static int via_ircc_is_receiving(struct via_ircc_cb *self); +static int via_ircc_read_dongle_id(int iobase); + +static int via_ircc_net_open(struct net_device *dev); +static int via_ircc_net_close(struct net_device *dev); +static int via_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, + int cmd); +static void via_ircc_change_dongle_speed(int iobase, int speed, + int dongle_id); +static int RxTimerHandler(struct via_ircc_cb *self, int iobase); +static void hwreset(struct via_ircc_cb *self); +static int via_ircc_dma_xmit(struct via_ircc_cb *self, u16 iobase); +static int upload_rxdata(struct via_ircc_cb *self, int iobase); +static int via_init_one(struct pci_dev *pcidev, const struct pci_device_id *id); +static void via_remove_one(struct pci_dev *pdev); + +/* FIXME : Should use udelay() instead, even if we are x86 only - Jean II */ +static void iodelay(int udelay) +{ + u8 data; + int i; + + for (i = 0; i < udelay; i++) { + data = inb(0x80); + } +} + +static const struct pci_device_id via_pci_tbl[] = { + { PCI_VENDOR_ID_VIA, 0x8231, PCI_ANY_ID, PCI_ANY_ID,0,0,0 }, + { PCI_VENDOR_ID_VIA, 0x3109, PCI_ANY_ID, PCI_ANY_ID,0,0,1 }, + { PCI_VENDOR_ID_VIA, 0x3074, PCI_ANY_ID, PCI_ANY_ID,0,0,2 }, + { PCI_VENDOR_ID_VIA, 0x3147, PCI_ANY_ID, PCI_ANY_ID,0,0,3 }, + { PCI_VENDOR_ID_VIA, 0x3177, PCI_ANY_ID, PCI_ANY_ID,0,0,4 }, + { 0, } +}; + +MODULE_DEVICE_TABLE(pci,via_pci_tbl); + + +static struct pci_driver via_driver = { + .name = VIA_MODULE_NAME, + .id_table = via_pci_tbl, + .probe = via_init_one, + .remove = via_remove_one, +}; + + +/* + * Function via_ircc_init () + * + * Initialize chip. Just find out chip type and resource. + */ +static int __init via_ircc_init(void) +{ + int rc; + + rc = pci_register_driver(&via_driver); + if (rc < 0) { + pr_debug("%s(): error rc = %d, returning -ENODEV...\n", + __func__, rc); + return -ENODEV; + } + return 0; +} + +static int via_init_one(struct pci_dev *pcidev, const struct pci_device_id *id) +{ + int rc; + u8 temp,oldPCI_40,oldPCI_44,bTmp,bTmp1; + u16 Chipset,FirDRQ1,FirDRQ0,FirIRQ,FirIOBase; + chipio_t info; + + pr_debug("%s(): Device ID=(0X%X)\n", __func__, id->device); + + rc = pci_enable_device (pcidev); + if (rc) { + pr_debug("%s(): error rc = %d\n", __func__, rc); + return -ENODEV; + } + + // South Bridge exist + if ( ReadLPCReg(0x20) != 0x3C ) + Chipset=0x3096; + else + Chipset=0x3076; + + if (Chipset==0x3076) { + pr_debug("%s(): Chipset = 3076\n", __func__); + + WriteLPCReg(7,0x0c ); + temp=ReadLPCReg(0x30);//check if BIOS Enable Fir + if((temp&0x01)==1) { // BIOS close or no FIR + WriteLPCReg(0x1d, 0x82 ); + WriteLPCReg(0x23,0x18); + temp=ReadLPCReg(0xF0); + if((temp&0x01)==0) { + temp=(ReadLPCReg(0x74)&0x03); //DMA + FirDRQ0=temp + 4; + temp=(ReadLPCReg(0x74)&0x0C) >> 2; + FirDRQ1=temp + 4; + } else { + temp=(ReadLPCReg(0x74)&0x0C) >> 2; //DMA + FirDRQ0=temp + 4; + FirDRQ1=FirDRQ0; + } + FirIRQ=(ReadLPCReg(0x70)&0x0f); //IRQ + FirIOBase=ReadLPCReg(0x60 ) << 8; //IO Space :high byte + FirIOBase=FirIOBase| ReadLPCReg(0x61) ; //low byte + FirIOBase=FirIOBase ; + info.fir_base=FirIOBase; + info.irq=FirIRQ; + info.dma=FirDRQ1; + info.dma2=FirDRQ0; + pci_read_config_byte(pcidev,0x40,&bTmp); + pci_write_config_byte(pcidev,0x40,((bTmp | 0x08) & 0xfe)); + pci_read_config_byte(pcidev,0x42,&bTmp); + pci_write_config_byte(pcidev,0x42,(bTmp | 0xf0)); + pci_write_config_byte(pcidev,0x5a,0xc0); + WriteLPCReg(0x28, 0x70 ); + rc = via_ircc_open(pcidev, &info, 0x3076); + } else + rc = -ENODEV; //IR not turn on + } else { //Not VT1211 + pr_debug("%s(): Chipset = 3096\n", __func__); + + pci_read_config_byte(pcidev,0x67,&bTmp);//check if BIOS Enable Fir + if((bTmp&0x01)==1) { // BIOS enable FIR + //Enable Double DMA clock + pci_read_config_byte(pcidev,0x42,&oldPCI_40); + pci_write_config_byte(pcidev,0x42,oldPCI_40 | 0x80); + pci_read_config_byte(pcidev,0x40,&oldPCI_40); + pci_write_config_byte(pcidev,0x40,oldPCI_40 & 0xf7); + pci_read_config_byte(pcidev,0x44,&oldPCI_44); + pci_write_config_byte(pcidev,0x44,0x4e); + //---------- read configuration from Function0 of south bridge + if((bTmp&0x02)==0) { + pci_read_config_byte(pcidev,0x44,&bTmp1); //DMA + FirDRQ0 = (bTmp1 & 0x30) >> 4; + pci_read_config_byte(pcidev,0x44,&bTmp1); + FirDRQ1 = (bTmp1 & 0xc0) >> 6; + } else { + pci_read_config_byte(pcidev,0x44,&bTmp1); //DMA + FirDRQ0 = (bTmp1 & 0x30) >> 4 ; + FirDRQ1=0; + } + pci_read_config_byte(pcidev,0x47,&bTmp1); //IRQ + FirIRQ = bTmp1 & 0x0f; + + pci_read_config_byte(pcidev,0x69,&bTmp); + FirIOBase = bTmp << 8;//hight byte + pci_read_config_byte(pcidev,0x68,&bTmp); + FirIOBase = (FirIOBase | bTmp ) & 0xfff0; + //------------------------- + info.fir_base=FirIOBase; + info.irq=FirIRQ; + info.dma=FirDRQ1; + info.dma2=FirDRQ0; + rc = via_ircc_open(pcidev, &info, 0x3096); + } else + rc = -ENODEV; //IR not turn on !!!!! + }//Not VT1211 + + pr_debug("%s(): End - rc = %d\n", __func__, rc); + return rc; +} + +static void __exit via_ircc_cleanup(void) +{ + /* Cleanup all instances of the driver */ + pci_unregister_driver (&via_driver); +} + +static const struct net_device_ops via_ircc_sir_ops = { + .ndo_start_xmit = via_ircc_hard_xmit_sir, + .ndo_open = via_ircc_net_open, + .ndo_stop = via_ircc_net_close, + .ndo_do_ioctl = via_ircc_net_ioctl, +}; +static const struct net_device_ops via_ircc_fir_ops = { + .ndo_start_xmit = via_ircc_hard_xmit_fir, + .ndo_open = via_ircc_net_open, + .ndo_stop = via_ircc_net_close, + .ndo_do_ioctl = via_ircc_net_ioctl, +}; + +/* + * Function via_ircc_open(pdev, iobase, irq) + * + * Open driver instance + * + */ +static int via_ircc_open(struct pci_dev *pdev, chipio_t *info, unsigned int id) +{ + struct net_device *dev; + struct via_ircc_cb *self; + int err; + + /* Allocate new instance of the driver */ + dev = alloc_irdadev(sizeof(struct via_ircc_cb)); + if (dev == NULL) + return -ENOMEM; + + self = netdev_priv(dev); + self->netdev = dev; + spin_lock_init(&self->lock); + + pci_set_drvdata(pdev, self); + + /* Initialize Resource */ + self->io.cfg_base = info->cfg_base; + self->io.fir_base = info->fir_base; + self->io.irq = info->irq; + self->io.fir_ext = CHIP_IO_EXTENT; + self->io.dma = info->dma; + self->io.dma2 = info->dma2; + self->io.fifo_size = 32; + self->chip_id = id; + self->st_fifo.len = 0; + self->RxDataReady = 0; + + /* Reserve the ioports that we need */ + if (!request_region(self->io.fir_base, self->io.fir_ext, driver_name)) { + pr_debug("%s(), can't get iobase of 0x%03x\n", + __func__, self->io.fir_base); + err = -ENODEV; + goto err_out1; + } + + /* Initialize QoS for this device */ + irda_init_max_qos_capabilies(&self->qos); + + /* Check if user has supplied the dongle id or not */ + if (!dongle_id) + dongle_id = via_ircc_read_dongle_id(self->io.fir_base); + self->io.dongle_id = dongle_id; + + /* The only value we must override it the baudrate */ + /* Maximum speeds and capabilities are dongle-dependent. */ + switch( self->io.dongle_id ){ + case 0x0d: + self->qos.baud_rate.bits = + IR_9600 | IR_19200 | IR_38400 | IR_57600 | IR_115200 | + IR_576000 | IR_1152000 | (IR_4000000 << 8); + break; + default: + self->qos.baud_rate.bits = + IR_9600 | IR_19200 | IR_38400 | IR_57600 | IR_115200; + break; + } + + /* Following was used for testing: + * + * self->qos.baud_rate.bits = IR_9600; + * + * Is is no good, as it prohibits (error-prone) speed-changes. + */ + + self->qos.min_turn_time.bits = qos_mtt_bits; + irda_qos_bits_to_value(&self->qos); + + /* Max DMA buffer size needed = (data_size + 6) * (window_size) + 6; */ + self->rx_buff.truesize = 14384 + 2048; + self->tx_buff.truesize = 14384 + 2048; + + /* Allocate memory if needed */ + self->rx_buff.head = + dma_zalloc_coherent(&pdev->dev, self->rx_buff.truesize, + &self->rx_buff_dma, GFP_KERNEL); + if (self->rx_buff.head == NULL) { + err = -ENOMEM; + goto err_out2; + } + + self->tx_buff.head = + dma_zalloc_coherent(&pdev->dev, self->tx_buff.truesize, + &self->tx_buff_dma, GFP_KERNEL); + if (self->tx_buff.head == NULL) { + err = -ENOMEM; + goto err_out3; + } + + self->rx_buff.in_frame = FALSE; + self->rx_buff.state = OUTSIDE_FRAME; + self->tx_buff.data = self->tx_buff.head; + self->rx_buff.data = self->rx_buff.head; + + /* Reset Tx queue info */ + self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0; + self->tx_fifo.tail = self->tx_buff.head; + + /* Override the network functions we need to use */ + dev->netdev_ops = &via_ircc_sir_ops; + + err = register_netdev(dev); + if (err) + goto err_out4; + + net_info_ratelimited("IrDA: Registered device %s (via-ircc)\n", + dev->name); + + /* Initialise the hardware.. + */ + self->io.speed = 9600; + via_hw_init(self); + return 0; + err_out4: + dma_free_coherent(&pdev->dev, self->tx_buff.truesize, + self->tx_buff.head, self->tx_buff_dma); + err_out3: + dma_free_coherent(&pdev->dev, self->rx_buff.truesize, + self->rx_buff.head, self->rx_buff_dma); + err_out2: + release_region(self->io.fir_base, self->io.fir_ext); + err_out1: + free_netdev(dev); + return err; +} + +/* + * Function via_remove_one(pdev) + * + * Close driver instance + * + */ +static void via_remove_one(struct pci_dev *pdev) +{ + struct via_ircc_cb *self = pci_get_drvdata(pdev); + int iobase; + + iobase = self->io.fir_base; + + ResetChip(iobase, 5); //hardware reset. + /* Remove netdevice */ + unregister_netdev(self->netdev); + + /* Release the PORT that this driver is using */ + pr_debug("%s(), Releasing Region %03x\n", + __func__, self->io.fir_base); + release_region(self->io.fir_base, self->io.fir_ext); + if (self->tx_buff.head) + dma_free_coherent(&pdev->dev, self->tx_buff.truesize, + self->tx_buff.head, self->tx_buff_dma); + if (self->rx_buff.head) + dma_free_coherent(&pdev->dev, self->rx_buff.truesize, + self->rx_buff.head, self->rx_buff_dma); + + free_netdev(self->netdev); + + pci_disable_device(pdev); +} + +/* + * Function via_hw_init(self) + * + * Returns non-negative on success. + * + * Formerly via_ircc_setup + */ +static void via_hw_init(struct via_ircc_cb *self) +{ + int iobase = self->io.fir_base; + + SetMaxRxPacketSize(iobase, 0x0fff); //set to max:4095 + // FIFO Init + EnRXFIFOReadyInt(iobase, OFF); + EnRXFIFOHalfLevelInt(iobase, OFF); + EnTXFIFOHalfLevelInt(iobase, OFF); + EnTXFIFOUnderrunEOMInt(iobase, ON); + EnTXFIFOReadyInt(iobase, OFF); + InvertTX(iobase, OFF); + InvertRX(iobase, OFF); + + if (ReadLPCReg(0x20) == 0x3c) + WriteLPCReg(0xF0, 0); // for VT1211 + /* Int Init */ + EnRXSpecInt(iobase, ON); + + /* The following is basically hwreset */ + /* If this is the case, why not just call hwreset() ? Jean II */ + ResetChip(iobase, 5); + EnableDMA(iobase, OFF); + EnableTX(iobase, OFF); + EnableRX(iobase, OFF); + EnRXDMA(iobase, OFF); + EnTXDMA(iobase, OFF); + RXStart(iobase, OFF); + TXStart(iobase, OFF); + InitCard(iobase); + CommonInit(iobase); + SIRFilter(iobase, ON); + SetSIR(iobase, ON); + CRC16(iobase, ON); + EnTXCRC(iobase, 0); + WriteReg(iobase, I_ST_CT_0, 0x00); + SetBaudRate(iobase, 9600); + SetPulseWidth(iobase, 12); + SetSendPreambleCount(iobase, 0); + + self->io.speed = 9600; + self->st_fifo.len = 0; + + via_ircc_change_dongle_speed(iobase, self->io.speed, + self->io.dongle_id); + + WriteReg(iobase, I_ST_CT_0, 0x80); +} + +/* + * Function via_ircc_read_dongle_id (void) + * + */ +static int via_ircc_read_dongle_id(int iobase) +{ + net_err_ratelimited("via-ircc: dongle probing not supported, please specify dongle_id module parameter\n"); + return 9; /* Default to IBM */ +} + +/* + * Function via_ircc_change_dongle_speed (iobase, speed, dongle_id) + * Change speed of the attach dongle + * only implement two type of dongle currently. + */ +static void via_ircc_change_dongle_speed(int iobase, int speed, + int dongle_id) +{ + u8 mode = 0; + + /* speed is unused, as we use IsSIROn()/IsMIROn() */ + speed = speed; + + pr_debug("%s(): change_dongle_speed to %d for 0x%x, %d\n", + __func__, speed, iobase, dongle_id); + + switch (dongle_id) { + + /* Note: The dongle_id's listed here are derived from + * nsc-ircc.c */ + + case 0x08: /* HP HSDL-2300, HP HSDL-3600/HSDL-3610 */ + UseOneRX(iobase, ON); // use one RX pin RX1,RX2 + InvertTX(iobase, OFF); + InvertRX(iobase, OFF); + + EnRX2(iobase, ON); //sir to rx2 + EnGPIOtoRX2(iobase, OFF); + + if (IsSIROn(iobase)) { //sir + // Mode select Off + SlowIRRXLowActive(iobase, ON); + udelay(1000); + SlowIRRXLowActive(iobase, OFF); + } else { + if (IsMIROn(iobase)) { //mir + // Mode select On + SlowIRRXLowActive(iobase, OFF); + udelay(20); + } else { // fir + if (IsFIROn(iobase)) { //fir + // Mode select On + SlowIRRXLowActive(iobase, OFF); + udelay(20); + } + } + } + break; + + case 0x09: /* IBM31T1100 or Temic TFDS6000/TFDS6500 */ + UseOneRX(iobase, ON); //use ONE RX....RX1 + InvertTX(iobase, OFF); + InvertRX(iobase, OFF); // invert RX pin + + EnRX2(iobase, ON); + EnGPIOtoRX2(iobase, OFF); + if (IsSIROn(iobase)) { //sir + // Mode select On + SlowIRRXLowActive(iobase, ON); + udelay(20); + // Mode select Off + SlowIRRXLowActive(iobase, OFF); + } + if (IsMIROn(iobase)) { //mir + // Mode select On + SlowIRRXLowActive(iobase, OFF); + udelay(20); + // Mode select Off + SlowIRRXLowActive(iobase, ON); + } else { // fir + if (IsFIROn(iobase)) { //fir + // Mode select On + SlowIRRXLowActive(iobase, OFF); + // TX On + WriteTX(iobase, ON); + udelay(20); + // Mode select OFF + SlowIRRXLowActive(iobase, ON); + udelay(20); + // TX Off + WriteTX(iobase, OFF); + } + } + break; + + case 0x0d: + UseOneRX(iobase, OFF); // use two RX pin RX1,RX2 + InvertTX(iobase, OFF); + InvertRX(iobase, OFF); + SlowIRRXLowActive(iobase, OFF); + if (IsSIROn(iobase)) { //sir + EnGPIOtoRX2(iobase, OFF); + WriteGIO(iobase, OFF); + EnRX2(iobase, OFF); //sir to rx2 + } else { // fir mir + EnGPIOtoRX2(iobase, OFF); + WriteGIO(iobase, OFF); + EnRX2(iobase, OFF); //fir to rx + } + break; + + case 0x11: /* Temic TFDS4500 */ + + pr_debug("%s: Temic TFDS4500: One RX pin, TX normal, RX inverted\n", + __func__); + + UseOneRX(iobase, ON); //use ONE RX....RX1 + InvertTX(iobase, OFF); + InvertRX(iobase, ON); // invert RX pin + + EnRX2(iobase, ON); //sir to rx2 + EnGPIOtoRX2(iobase, OFF); + + if( IsSIROn(iobase) ){ //sir + + // Mode select On + SlowIRRXLowActive(iobase, ON); + udelay(20); + // Mode select Off + SlowIRRXLowActive(iobase, OFF); + + } else{ + pr_debug("%s: Warning: TFDS4500 not running in SIR mode !\n", + __func__); + } + break; + + case 0x0ff: /* Vishay */ + if (IsSIROn(iobase)) + mode = 0; + else if (IsMIROn(iobase)) + mode = 1; + else if (IsFIROn(iobase)) + mode = 2; + else if (IsVFIROn(iobase)) + mode = 5; //VFIR-16 + SI_SetMode(iobase, mode); + break; + + default: + net_err_ratelimited("%s: Error: dongle_id %d unsupported !\n", + __func__, dongle_id); + } +} + +/* + * Function via_ircc_change_speed (self, baud) + * + * Change the speed of the device + * + */ +static void via_ircc_change_speed(struct via_ircc_cb *self, __u32 speed) +{ + struct net_device *dev = self->netdev; + u16 iobase; + u8 value = 0, bTmp; + + iobase = self->io.fir_base; + /* Update accounting for new speed */ + self->io.speed = speed; + pr_debug("%s: change_speed to %d bps.\n", __func__, speed); + + WriteReg(iobase, I_ST_CT_0, 0x0); + + /* Controller mode sellection */ + switch (speed) { + case 2400: + case 9600: + case 19200: + case 38400: + case 57600: + case 115200: + value = (115200/speed)-1; + SetSIR(iobase, ON); + CRC16(iobase, ON); + break; + case 576000: + /* FIXME: this can't be right, as it's the same as 115200, + * and 576000 is MIR, not SIR. */ + value = 0; + SetSIR(iobase, ON); + CRC16(iobase, ON); + break; + case 1152000: + value = 0; + SetMIR(iobase, ON); + /* FIXME: CRC ??? */ + break; + case 4000000: + value = 0; + SetFIR(iobase, ON); + SetPulseWidth(iobase, 0); + SetSendPreambleCount(iobase, 14); + CRC16(iobase, OFF); + EnTXCRC(iobase, ON); + break; + case 16000000: + value = 0; + SetVFIR(iobase, ON); + /* FIXME: CRC ??? */ + break; + default: + value = 0; + break; + } + + /* Set baudrate to 0x19[2..7] */ + bTmp = (ReadReg(iobase, I_CF_H_1) & 0x03); + bTmp |= value << 2; + WriteReg(iobase, I_CF_H_1, bTmp); + + /* Some dongles may need to be informed about speed changes. */ + via_ircc_change_dongle_speed(iobase, speed, self->io.dongle_id); + + /* Set FIFO size to 64 */ + SetFIFO(iobase, 64); + + /* Enable IR */ + WriteReg(iobase, I_ST_CT_0, 0x80); + + // EnTXFIFOHalfLevelInt(iobase,ON); + + /* Enable some interrupts so we can receive frames */ + //EnAllInt(iobase,ON); + + if (IsSIROn(iobase)) { + SIRFilter(iobase, ON); + SIRRecvAny(iobase, ON); + } else { + SIRFilter(iobase, OFF); + SIRRecvAny(iobase, OFF); + } + + if (speed > 115200) { + /* Install FIR xmit handler */ + dev->netdev_ops = &via_ircc_fir_ops; + via_ircc_dma_receive(self); + } else { + /* Install SIR xmit handler */ + dev->netdev_ops = &via_ircc_sir_ops; + } + netif_wake_queue(dev); +} + +/* + * Function via_ircc_hard_xmit (skb, dev) + * + * Transmit the frame! + * + */ +static netdev_tx_t via_ircc_hard_xmit_sir(struct sk_buff *skb, + struct net_device *dev) +{ + struct via_ircc_cb *self; + unsigned long flags; + u16 iobase; + __u32 speed; + + self = netdev_priv(dev); + IRDA_ASSERT(self != NULL, return NETDEV_TX_OK;); + iobase = self->io.fir_base; + + netif_stop_queue(dev); + /* Check if we need to change the speed */ + speed = irda_get_next_speed(skb); + if ((speed != self->io.speed) && (speed != -1)) { + /* Check for empty frame */ + if (!skb->len) { + via_ircc_change_speed(self, speed); + netif_trans_update(dev); + dev_kfree_skb(skb); + return NETDEV_TX_OK; + } else + self->new_speed = speed; + } + InitCard(iobase); + CommonInit(iobase); + SIRFilter(iobase, ON); + SetSIR(iobase, ON); + CRC16(iobase, ON); + EnTXCRC(iobase, 0); + WriteReg(iobase, I_ST_CT_0, 0x00); + + spin_lock_irqsave(&self->lock, flags); + self->tx_buff.data = self->tx_buff.head; + self->tx_buff.len = + async_wrap_skb(skb, self->tx_buff.data, + self->tx_buff.truesize); + + dev->stats.tx_bytes += self->tx_buff.len; + /* Send this frame with old speed */ + SetBaudRate(iobase, self->io.speed); + SetPulseWidth(iobase, 12); + SetSendPreambleCount(iobase, 0); + WriteReg(iobase, I_ST_CT_0, 0x80); + + EnableTX(iobase, ON); + EnableRX(iobase, OFF); + + ResetChip(iobase, 0); + ResetChip(iobase, 1); + ResetChip(iobase, 2); + ResetChip(iobase, 3); + ResetChip(iobase, 4); + + EnAllInt(iobase, ON); + EnTXDMA(iobase, ON); + EnRXDMA(iobase, OFF); + + irda_setup_dma(self->io.dma, self->tx_buff_dma, self->tx_buff.len, + DMA_TX_MODE); + + SetSendByte(iobase, self->tx_buff.len); + RXStart(iobase, OFF); + TXStart(iobase, ON); + + netif_trans_update(dev); + spin_unlock_irqrestore(&self->lock, flags); + dev_kfree_skb(skb); + return NETDEV_TX_OK; +} + +static netdev_tx_t via_ircc_hard_xmit_fir(struct sk_buff *skb, + struct net_device *dev) +{ + struct via_ircc_cb *self; + u16 iobase; + __u32 speed; + unsigned long flags; + + self = netdev_priv(dev); + iobase = self->io.fir_base; + + if (self->st_fifo.len) + return NETDEV_TX_OK; + if (self->chip_id == 0x3076) + iodelay(1500); + else + udelay(1500); + netif_stop_queue(dev); + speed = irda_get_next_speed(skb); + if ((speed != self->io.speed) && (speed != -1)) { + if (!skb->len) { + via_ircc_change_speed(self, speed); + netif_trans_update(dev); + dev_kfree_skb(skb); + return NETDEV_TX_OK; + } else + self->new_speed = speed; + } + spin_lock_irqsave(&self->lock, flags); + self->tx_fifo.queue[self->tx_fifo.free].start = self->tx_fifo.tail; + self->tx_fifo.queue[self->tx_fifo.free].len = skb->len; + + self->tx_fifo.tail += skb->len; + dev->stats.tx_bytes += skb->len; + skb_copy_from_linear_data(skb, + self->tx_fifo.queue[self->tx_fifo.free].start, skb->len); + self->tx_fifo.len++; + self->tx_fifo.free++; +//F01 if (self->tx_fifo.len == 1) { + via_ircc_dma_xmit(self, iobase); +//F01 } +//F01 if (self->tx_fifo.free < (MAX_TX_WINDOW -1 )) netif_wake_queue(self->netdev); + netif_trans_update(dev); + dev_kfree_skb(skb); + spin_unlock_irqrestore(&self->lock, flags); + return NETDEV_TX_OK; + +} + +static int via_ircc_dma_xmit(struct via_ircc_cb *self, u16 iobase) +{ + EnTXDMA(iobase, OFF); + self->io.direction = IO_XMIT; + EnPhys(iobase, ON); + EnableTX(iobase, ON); + EnableRX(iobase, OFF); + ResetChip(iobase, 0); + ResetChip(iobase, 1); + ResetChip(iobase, 2); + ResetChip(iobase, 3); + ResetChip(iobase, 4); + EnAllInt(iobase, ON); + EnTXDMA(iobase, ON); + EnRXDMA(iobase, OFF); + irda_setup_dma(self->io.dma, + ((u8 *)self->tx_fifo.queue[self->tx_fifo.ptr].start - + self->tx_buff.head) + self->tx_buff_dma, + self->tx_fifo.queue[self->tx_fifo.ptr].len, DMA_TX_MODE); + pr_debug("%s: tx_fifo.ptr=%x,len=%x,tx_fifo.len=%x..\n", + __func__, self->tx_fifo.ptr, + self->tx_fifo.queue[self->tx_fifo.ptr].len, + self->tx_fifo.len); + + SetSendByte(iobase, self->tx_fifo.queue[self->tx_fifo.ptr].len); + RXStart(iobase, OFF); + TXStart(iobase, ON); + return 0; + +} + +/* + * Function via_ircc_dma_xmit_complete (self) + * + * The transfer of a frame in finished. This function will only be called + * by the interrupt handler + * + */ +static int via_ircc_dma_xmit_complete(struct via_ircc_cb *self) +{ + int iobase; + u8 Tx_status; + + iobase = self->io.fir_base; + /* Disable DMA */ +// DisableDmaChannel(self->io.dma); + /* Check for underrun! */ + /* Clear bit, by writing 1 into it */ + Tx_status = GetTXStatus(iobase); + if (Tx_status & 0x08) { + self->netdev->stats.tx_errors++; + self->netdev->stats.tx_fifo_errors++; + hwreset(self); + /* how to clear underrun? */ + } else { + self->netdev->stats.tx_packets++; + ResetChip(iobase, 3); + ResetChip(iobase, 4); + } + /* Check if we need to change the speed */ + if (self->new_speed) { + via_ircc_change_speed(self, self->new_speed); + self->new_speed = 0; + } + + /* Finished with this frame, so prepare for next */ + if (IsFIROn(iobase)) { + if (self->tx_fifo.len) { + self->tx_fifo.len--; + self->tx_fifo.ptr++; + } + } + pr_debug("%s: tx_fifo.len=%x ,tx_fifo.ptr=%x,tx_fifo.free=%x...\n", + __func__, + self->tx_fifo.len, self->tx_fifo.ptr, self->tx_fifo.free); +/* F01_S + // Any frames to be sent back-to-back? + if (self->tx_fifo.len) { + // Not finished yet! + via_ircc_dma_xmit(self, iobase); + ret = FALSE; + } else { +F01_E*/ + // Reset Tx FIFO info + self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0; + self->tx_fifo.tail = self->tx_buff.head; +//F01 } + + // Make sure we have room for more frames +//F01 if (self->tx_fifo.free < (MAX_TX_WINDOW -1 )) { + // Not busy transmitting anymore + // Tell the network layer, that we can accept more frames + netif_wake_queue(self->netdev); +//F01 } + return TRUE; +} + +/* + * Function via_ircc_dma_receive (self) + * + * Set configuration for receive a frame. + * + */ +static int via_ircc_dma_receive(struct via_ircc_cb *self) +{ + int iobase; + + iobase = self->io.fir_base; + + self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0; + self->tx_fifo.tail = self->tx_buff.head; + self->RxDataReady = 0; + self->io.direction = IO_RECV; + self->rx_buff.data = self->rx_buff.head; + self->st_fifo.len = self->st_fifo.pending_bytes = 0; + self->st_fifo.tail = self->st_fifo.head = 0; + + EnPhys(iobase, ON); + EnableTX(iobase, OFF); + EnableRX(iobase, ON); + + ResetChip(iobase, 0); + ResetChip(iobase, 1); + ResetChip(iobase, 2); + ResetChip(iobase, 3); + ResetChip(iobase, 4); + + EnAllInt(iobase, ON); + EnTXDMA(iobase, OFF); + EnRXDMA(iobase, ON); + irda_setup_dma(self->io.dma2, self->rx_buff_dma, + self->rx_buff.truesize, DMA_RX_MODE); + TXStart(iobase, OFF); + RXStart(iobase, ON); + + return 0; +} + +/* + * Function via_ircc_dma_receive_complete (self) + * + * Controller Finished with receiving frames, + * and this routine is call by ISR + * + */ +static int via_ircc_dma_receive_complete(struct via_ircc_cb *self, + int iobase) +{ + struct st_fifo *st_fifo; + struct sk_buff *skb; + int len, i; + u8 status = 0; + + iobase = self->io.fir_base; + st_fifo = &self->st_fifo; + + if (self->io.speed < 4000000) { //Speed below FIR + len = GetRecvByte(iobase, self); + skb = dev_alloc_skb(len + 1); + if (skb == NULL) + return FALSE; + // Make sure IP header gets aligned + skb_reserve(skb, 1); + skb_put(skb, len - 2); + if (self->chip_id == 0x3076) { + for (i = 0; i < len - 2; i++) + skb->data[i] = self->rx_buff.data[i * 2]; + } else { + if (self->chip_id == 0x3096) { + for (i = 0; i < len - 2; i++) + skb->data[i] = + self->rx_buff.data[i]; + } + } + // Move to next frame + self->rx_buff.data += len; + self->netdev->stats.rx_bytes += len; + self->netdev->stats.rx_packets++; + skb->dev = self->netdev; + skb_reset_mac_header(skb); + skb->protocol = htons(ETH_P_IRDA); + netif_rx(skb); + return TRUE; + } + + else { //FIR mode + len = GetRecvByte(iobase, self); + if (len == 0) + return TRUE; //interrupt only, data maybe move by RxT + if (((len - 4) < 2) || ((len - 4) > 2048)) { + pr_debug("%s(): Trouble:len=%x,CurCount=%x,LastCount=%x\n", + __func__, len, RxCurCount(iobase, self), + self->RxLastCount); + hwreset(self); + return FALSE; + } + pr_debug("%s(): fifo.len=%x,len=%x,CurCount=%x..\n", + __func__, + st_fifo->len, len - 4, RxCurCount(iobase, self)); + + st_fifo->entries[st_fifo->tail].status = status; + st_fifo->entries[st_fifo->tail].len = len; + st_fifo->pending_bytes += len; + st_fifo->tail++; + st_fifo->len++; + if (st_fifo->tail > MAX_RX_WINDOW) + st_fifo->tail = 0; + self->RxDataReady = 0; + + // It maybe have MAX_RX_WINDOW package receive by + // receive_complete before Timer IRQ +/* F01_S + if (st_fifo->len < (MAX_RX_WINDOW+2 )) { + RXStart(iobase,ON); + SetTimer(iobase,4); + } + else { +F01_E */ + EnableRX(iobase, OFF); + EnRXDMA(iobase, OFF); + RXStart(iobase, OFF); +//F01_S + // Put this entry back in fifo + if (st_fifo->head > MAX_RX_WINDOW) + st_fifo->head = 0; + status = st_fifo->entries[st_fifo->head].status; + len = st_fifo->entries[st_fifo->head].len; + st_fifo->head++; + st_fifo->len--; + + skb = dev_alloc_skb(len + 1 - 4); + /* + * if frame size, data ptr, or skb ptr are wrong, then get next + * entry. + */ + if ((skb == NULL) || (skb->data == NULL) || + (self->rx_buff.data == NULL) || (len < 6)) { + self->netdev->stats.rx_dropped++; + kfree_skb(skb); + return TRUE; + } + skb_reserve(skb, 1); + skb_put(skb, len - 4); + + skb_copy_to_linear_data(skb, self->rx_buff.data, len - 4); + pr_debug("%s(): len=%x.rx_buff=%p\n", __func__, + len - 4, self->rx_buff.data); + + // Move to next frame + self->rx_buff.data += len; + self->netdev->stats.rx_bytes += len; + self->netdev->stats.rx_packets++; + skb->dev = self->netdev; + skb_reset_mac_header(skb); + skb->protocol = htons(ETH_P_IRDA); + netif_rx(skb); + +//F01_E + } //FIR + return TRUE; + +} + +/* + * if frame is received , but no INT ,then use this routine to upload frame. + */ +static int upload_rxdata(struct via_ircc_cb *self, int iobase) +{ + struct sk_buff *skb; + int len; + struct st_fifo *st_fifo; + st_fifo = &self->st_fifo; + + len = GetRecvByte(iobase, self); + + pr_debug("%s(): len=%x\n", __func__, len); + + if ((len - 4) < 2) { + self->netdev->stats.rx_dropped++; + return FALSE; + } + + skb = dev_alloc_skb(len + 1); + if (skb == NULL) { + self->netdev->stats.rx_dropped++; + return FALSE; + } + skb_reserve(skb, 1); + skb_put(skb, len - 4 + 1); + skb_copy_to_linear_data(skb, self->rx_buff.data, len - 4 + 1); + st_fifo->tail++; + st_fifo->len++; + if (st_fifo->tail > MAX_RX_WINDOW) + st_fifo->tail = 0; + // Move to next frame + self->rx_buff.data += len; + self->netdev->stats.rx_bytes += len; + self->netdev->stats.rx_packets++; + skb->dev = self->netdev; + skb_reset_mac_header(skb); + skb->protocol = htons(ETH_P_IRDA); + netif_rx(skb); + if (st_fifo->len < (MAX_RX_WINDOW + 2)) { + RXStart(iobase, ON); + } else { + EnableRX(iobase, OFF); + EnRXDMA(iobase, OFF); + RXStart(iobase, OFF); + } + return TRUE; +} + +/* + * Implement back to back receive , use this routine to upload data. + */ + +static int RxTimerHandler(struct via_ircc_cb *self, int iobase) +{ + struct st_fifo *st_fifo; + struct sk_buff *skb; + int len; + u8 status; + + st_fifo = &self->st_fifo; + + if (CkRxRecv(iobase, self)) { + // if still receiving ,then return ,don't upload frame + self->RetryCount = 0; + SetTimer(iobase, 20); + self->RxDataReady++; + return FALSE; + } else + self->RetryCount++; + + if ((self->RetryCount >= 1) || + ((st_fifo->pending_bytes + 2048) > self->rx_buff.truesize) || + (st_fifo->len >= (MAX_RX_WINDOW))) { + while (st_fifo->len > 0) { //upload frame + // Put this entry back in fifo + if (st_fifo->head > MAX_RX_WINDOW) + st_fifo->head = 0; + status = st_fifo->entries[st_fifo->head].status; + len = st_fifo->entries[st_fifo->head].len; + st_fifo->head++; + st_fifo->len--; + + skb = dev_alloc_skb(len + 1 - 4); + /* + * if frame size, data ptr, or skb ptr are wrong, + * then get next entry. + */ + if ((skb == NULL) || (skb->data == NULL) || + (self->rx_buff.data == NULL) || (len < 6)) { + self->netdev->stats.rx_dropped++; + continue; + } + skb_reserve(skb, 1); + skb_put(skb, len - 4); + skb_copy_to_linear_data(skb, self->rx_buff.data, len - 4); + + pr_debug("%s(): len=%x.head=%x\n", __func__, + len - 4, st_fifo->head); + + // Move to next frame + self->rx_buff.data += len; + self->netdev->stats.rx_bytes += len; + self->netdev->stats.rx_packets++; + skb->dev = self->netdev; + skb_reset_mac_header(skb); + skb->protocol = htons(ETH_P_IRDA); + netif_rx(skb); + } //while + self->RetryCount = 0; + + pr_debug("%s(): End of upload HostStatus=%x,RxStatus=%x\n", + __func__, GetHostStatus(iobase), GetRXStatus(iobase)); + + /* + * if frame is receive complete at this routine ,then upload + * frame. + */ + if ((GetRXStatus(iobase) & 0x10) && + (RxCurCount(iobase, self) != self->RxLastCount)) { + upload_rxdata(self, iobase); + if (irda_device_txqueue_empty(self->netdev)) + via_ircc_dma_receive(self); + } + } // timer detect complete + else + SetTimer(iobase, 4); + return TRUE; + +} + + + +/* + * Function via_ircc_interrupt (irq, dev_id) + * + * An interrupt from the chip has arrived. Time to do some work + * + */ +static irqreturn_t via_ircc_interrupt(int dummy, void *dev_id) +{ + struct net_device *dev = dev_id; + struct via_ircc_cb *self = netdev_priv(dev); + int iobase; + u8 iHostIntType, iRxIntType, iTxIntType; + + iobase = self->io.fir_base; + spin_lock(&self->lock); + iHostIntType = GetHostStatus(iobase); + + pr_debug("%s(): iHostIntType %02x: %s %s %s %02x\n", + __func__, iHostIntType, + (iHostIntType & 0x40) ? "Timer" : "", + (iHostIntType & 0x20) ? "Tx" : "", + (iHostIntType & 0x10) ? "Rx" : "", + (iHostIntType & 0x0e) >> 1); + + if ((iHostIntType & 0x40) != 0) { //Timer Event + self->EventFlag.TimeOut++; + ClearTimerInt(iobase, 1); + if (self->io.direction == IO_XMIT) { + via_ircc_dma_xmit(self, iobase); + } + if (self->io.direction == IO_RECV) { + /* + * frame ready hold too long, must reset. + */ + if (self->RxDataReady > 30) { + hwreset(self); + if (irda_device_txqueue_empty(self->netdev)) { + via_ircc_dma_receive(self); + } + } else { // call this to upload frame. + RxTimerHandler(self, iobase); + } + } //RECV + } //Timer Event + if ((iHostIntType & 0x20) != 0) { //Tx Event + iTxIntType = GetTXStatus(iobase); + + pr_debug("%s(): iTxIntType %02x: %s %s %s %s\n", + __func__, iTxIntType, + (iTxIntType & 0x08) ? "FIFO underr." : "", + (iTxIntType & 0x04) ? "EOM" : "", + (iTxIntType & 0x02) ? "FIFO ready" : "", + (iTxIntType & 0x01) ? "Early EOM" : ""); + + if (iTxIntType & 0x4) { + self->EventFlag.EOMessage++; // read and will auto clean + if (via_ircc_dma_xmit_complete(self)) { + if (irda_device_txqueue_empty + (self->netdev)) { + via_ircc_dma_receive(self); + } + } else { + self->EventFlag.Unknown++; + } + } //EOP + } //Tx Event + //---------------------------------------- + if ((iHostIntType & 0x10) != 0) { //Rx Event + /* Check if DMA has finished */ + iRxIntType = GetRXStatus(iobase); + + pr_debug("%s(): iRxIntType %02x: %s %s %s %s %s %s %s\n", + __func__, iRxIntType, + (iRxIntType & 0x80) ? "PHY err." : "", + (iRxIntType & 0x40) ? "CRC err" : "", + (iRxIntType & 0x20) ? "FIFO overr." : "", + (iRxIntType & 0x10) ? "EOF" : "", + (iRxIntType & 0x08) ? "RxData" : "", + (iRxIntType & 0x02) ? "RxMaxLen" : "", + (iRxIntType & 0x01) ? "SIR bad" : ""); + if (!iRxIntType) + pr_debug("%s(): RxIRQ =0\n", __func__); + + if (iRxIntType & 0x10) { + if (via_ircc_dma_receive_complete(self, iobase)) { +//F01 if(!(IsFIROn(iobase))) via_ircc_dma_receive(self); + via_ircc_dma_receive(self); + } + } // No ERR + else { //ERR + pr_debug("%s(): RxIRQ ERR:iRxIntType=%x,HostIntType=%x,CurCount=%x,RxLastCount=%x_____\n", + __func__, iRxIntType, iHostIntType, + RxCurCount(iobase, self), self->RxLastCount); + + if (iRxIntType & 0x20) { //FIFO OverRun ERR + ResetChip(iobase, 0); + ResetChip(iobase, 1); + } else { //PHY,CRC ERR + + if (iRxIntType != 0x08) + hwreset(self); //F01 + } + via_ircc_dma_receive(self); + } //ERR + + } //Rx Event + spin_unlock(&self->lock); + return IRQ_RETVAL(iHostIntType); +} + +static void hwreset(struct via_ircc_cb *self) +{ + int iobase; + iobase = self->io.fir_base; + + ResetChip(iobase, 5); + EnableDMA(iobase, OFF); + EnableTX(iobase, OFF); + EnableRX(iobase, OFF); + EnRXDMA(iobase, OFF); + EnTXDMA(iobase, OFF); + RXStart(iobase, OFF); + TXStart(iobase, OFF); + InitCard(iobase); + CommonInit(iobase); + SIRFilter(iobase, ON); + SetSIR(iobase, ON); + CRC16(iobase, ON); + EnTXCRC(iobase, 0); + WriteReg(iobase, I_ST_CT_0, 0x00); + SetBaudRate(iobase, 9600); + SetPulseWidth(iobase, 12); + SetSendPreambleCount(iobase, 0); + WriteReg(iobase, I_ST_CT_0, 0x80); + + /* Restore speed. */ + via_ircc_change_speed(self, self->io.speed); + + self->st_fifo.len = 0; +} + +/* + * Function via_ircc_is_receiving (self) + * + * Return TRUE is we are currently receiving a frame + * + */ +static int via_ircc_is_receiving(struct via_ircc_cb *self) +{ + int status = FALSE; + int iobase; + + IRDA_ASSERT(self != NULL, return FALSE;); + + iobase = self->io.fir_base; + if (CkRxRecv(iobase, self)) + status = TRUE; + + pr_debug("%s(): status=%x....\n", __func__, status); + + return status; +} + + +/* + * Function via_ircc_net_open (dev) + * + * Start the device + * + */ +static int via_ircc_net_open(struct net_device *dev) +{ + struct via_ircc_cb *self; + int iobase; + char hwname[32]; + + IRDA_ASSERT(dev != NULL, return -1;); + self = netdev_priv(dev); + dev->stats.rx_packets = 0; + IRDA_ASSERT(self != NULL, return 0;); + iobase = self->io.fir_base; + if (request_irq(self->io.irq, via_ircc_interrupt, 0, dev->name, dev)) { + net_warn_ratelimited("%s, unable to allocate irq=%d\n", + driver_name, self->io.irq); + return -EAGAIN; + } + /* + * Always allocate the DMA channel after the IRQ, and clean up on + * failure. + */ + if (request_dma(self->io.dma, dev->name)) { + net_warn_ratelimited("%s, unable to allocate dma=%d\n", + driver_name, self->io.dma); + free_irq(self->io.irq, dev); + return -EAGAIN; + } + if (self->io.dma2 != self->io.dma) { + if (request_dma(self->io.dma2, dev->name)) { + net_warn_ratelimited("%s, unable to allocate dma2=%d\n", + driver_name, self->io.dma2); + free_irq(self->io.irq, dev); + free_dma(self->io.dma); + return -EAGAIN; + } + } + + + /* turn on interrupts */ + EnAllInt(iobase, ON); + EnInternalLoop(iobase, OFF); + EnExternalLoop(iobase, OFF); + + /* */ + via_ircc_dma_receive(self); + + /* Ready to play! */ + netif_start_queue(dev); + + /* + * Open new IrLAP layer instance, now that everything should be + * initialized properly + */ + sprintf(hwname, "VIA @ 0x%x", iobase); + self->irlap = irlap_open(dev, &self->qos, hwname); + + self->RxLastCount = 0; + + return 0; +} + +/* + * Function via_ircc_net_close (dev) + * + * Stop the device + * + */ +static int via_ircc_net_close(struct net_device *dev) +{ + struct via_ircc_cb *self; + int iobase; + + IRDA_ASSERT(dev != NULL, return -1;); + self = netdev_priv(dev); + IRDA_ASSERT(self != NULL, return 0;); + + /* Stop device */ + netif_stop_queue(dev); + /* Stop and remove instance of IrLAP */ + if (self->irlap) + irlap_close(self->irlap); + self->irlap = NULL; + iobase = self->io.fir_base; + EnTXDMA(iobase, OFF); + EnRXDMA(iobase, OFF); + DisableDmaChannel(self->io.dma); + + /* Disable interrupts */ + EnAllInt(iobase, OFF); + free_irq(self->io.irq, dev); + free_dma(self->io.dma); + if (self->io.dma2 != self->io.dma) + free_dma(self->io.dma2); + + return 0; +} + +/* + * Function via_ircc_net_ioctl (dev, rq, cmd) + * + * Process IOCTL commands for this device + * + */ +static int via_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, + int cmd) +{ + struct if_irda_req *irq = (struct if_irda_req *) rq; + struct via_ircc_cb *self; + unsigned long flags; + int ret = 0; + + IRDA_ASSERT(dev != NULL, return -1;); + self = netdev_priv(dev); + IRDA_ASSERT(self != NULL, return -1;); + pr_debug("%s(), %s, (cmd=0x%X)\n", __func__, dev->name, + cmd); + /* Disable interrupts & save flags */ + spin_lock_irqsave(&self->lock, flags); + switch (cmd) { + case SIOCSBANDWIDTH: /* Set bandwidth */ + if (!capable(CAP_NET_ADMIN)) { + ret = -EPERM; + goto out; + } + via_ircc_change_speed(self, irq->ifr_baudrate); + break; + case SIOCSMEDIABUSY: /* Set media busy */ + if (!capable(CAP_NET_ADMIN)) { + ret = -EPERM; + goto out; + } + irda_device_set_media_busy(self->netdev, TRUE); + break; + case SIOCGRECEIVING: /* Check if we are receiving right now */ + irq->ifr_receiving = via_ircc_is_receiving(self); + break; + default: + ret = -EOPNOTSUPP; + } + out: + spin_unlock_irqrestore(&self->lock, flags); + return ret; +} + +MODULE_AUTHOR("VIA Technologies,inc"); +MODULE_DESCRIPTION("VIA IrDA Device Driver"); +MODULE_LICENSE("GPL"); + +module_init(via_ircc_init); +module_exit(via_ircc_cleanup); diff --git a/drivers/staging/irda/drivers/via-ircc.h b/drivers/staging/irda/drivers/via-ircc.h new file mode 100644 index 000000000000..ac1525573398 --- /dev/null +++ b/drivers/staging/irda/drivers/via-ircc.h @@ -0,0 +1,846 @@ +/********************************************************************* + * + * Filename: via-ircc.h + * Version: 1.0 + * Description: Driver for the VIA VT8231/VT8233 IrDA chipsets + * Author: VIA Technologies, inc + * Date : 08/06/2003 + +Copyright (c) 1998-2003 VIA Technologies, Inc. + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTIES OR REPRESENTATIONS; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program; if not, see <http://www.gnu.org/licenses/>. + + * Comment: + * jul/08/2002 : Rx buffer length should use Rx ring ptr. + * Oct/28/2002 : Add SB id for 3147 and 3177. + * jul/09/2002 : only implement two kind of dongle currently. + * Oct/02/2002 : work on VT8231 and VT8233 . + * Aug/06/2003 : change driver format to pci driver . + ********************************************************************/ +#ifndef via_IRCC_H +#define via_IRCC_H +#include <linux/spinlock.h> +#include <linux/pm.h> +#include <linux/types.h> +#include <asm/io.h> + +#define MAX_TX_WINDOW 7 +#define MAX_RX_WINDOW 7 + +struct st_fifo_entry { + int status; + int len; +}; + +struct st_fifo { + struct st_fifo_entry entries[MAX_RX_WINDOW + 2]; + int pending_bytes; + int head; + int tail; + int len; +}; + +struct frame_cb { + void *start; /* Start of frame in DMA mem */ + int len; /* Length of frame in DMA mem */ +}; + +struct tx_fifo { + struct frame_cb queue[MAX_TX_WINDOW + 2]; /* Info about frames in queue */ + int ptr; /* Currently being sent */ + int len; /* Length of queue */ + int free; /* Next free slot */ + void *tail; /* Next free start in DMA mem */ +}; + + +struct eventflag // for keeping track of Interrupt Events +{ + //--------tx part + unsigned char TxFIFOUnderRun; + unsigned char EOMessage; + unsigned char TxFIFOReady; + unsigned char EarlyEOM; + //--------rx part + unsigned char PHYErr; + unsigned char CRCErr; + unsigned char RxFIFOOverRun; + unsigned char EOPacket; + unsigned char RxAvail; + unsigned char TooLargePacket; + unsigned char SIRBad; + //--------unknown + unsigned char Unknown; + //---------- + unsigned char TimeOut; + unsigned char RxDMATC; + unsigned char TxDMATC; +}; + +/* Private data for each instance */ +struct via_ircc_cb { + struct st_fifo st_fifo; /* Info about received frames */ + struct tx_fifo tx_fifo; /* Info about frames to be transmitted */ + + struct net_device *netdev; /* Yes! we are some kind of netdevice */ + + struct irlap_cb *irlap; /* The link layer we are binded to */ + struct qos_info qos; /* QoS capabilities for this device */ + + chipio_t io; /* IrDA controller information */ + iobuff_t tx_buff; /* Transmit buffer */ + iobuff_t rx_buff; /* Receive buffer */ + dma_addr_t tx_buff_dma; + dma_addr_t rx_buff_dma; + + __u8 ier; /* Interrupt enable register */ + + spinlock_t lock; /* For serializing operations */ + + __u32 flags; /* Interface flags */ + __u32 new_speed; + int index; /* Instance index */ + + struct eventflag EventFlag; + unsigned int chip_id; /* to remember chip id */ + unsigned int RetryCount; + unsigned int RxDataReady; + unsigned int RxLastCount; +}; + + +//---------I=Infrared, H=Host, M=Misc, T=Tx, R=Rx, ST=Status, +// CF=Config, CT=Control, L=Low, H=High, C=Count +#define I_CF_L_0 0x10 +#define I_CF_H_0 0x11 +#define I_SIR_BOF 0x12 +#define I_SIR_EOF 0x13 +#define I_ST_CT_0 0x15 +#define I_ST_L_1 0x16 +#define I_ST_H_1 0x17 +#define I_CF_L_1 0x18 +#define I_CF_H_1 0x19 +#define I_CF_L_2 0x1a +#define I_CF_H_2 0x1b +#define I_CF_3 0x1e +#define H_CT 0x20 +#define H_ST 0x21 +#define M_CT 0x22 +#define TX_CT_1 0x23 +#define TX_CT_2 0x24 +#define TX_ST 0x25 +#define RX_CT 0x26 +#define RX_ST 0x27 +#define RESET 0x28 +#define P_ADDR 0x29 +#define RX_C_L 0x2a +#define RX_C_H 0x2b +#define RX_P_L 0x2c +#define RX_P_H 0x2d +#define TX_C_L 0x2e +#define TX_C_H 0x2f +#define TIMER 0x32 +#define I_CF_4 0x33 +#define I_T_C_L 0x34 +#define I_T_C_H 0x35 +#define VERSION 0x3f +//------------------------------- +#define StartAddr 0x10 // the first register address +#define EndAddr 0x3f // the last register address +#define GetBit(val,bit) val = (unsigned char) ((val>>bit) & 0x1) + // Returns the bit +#define SetBit(val,bit) val= (unsigned char ) (val | (0x1 << bit)) + // Sets bit to 1 +#define ResetBit(val,bit) val= (unsigned char ) (val & ~(0x1 << bit)) + // Sets bit to 0 + +#define OFF 0 +#define ON 1 +#define DMA_TX_MODE 0x08 +#define DMA_RX_MODE 0x04 + +#define DMA1 0 +#define DMA2 0xc0 +#define MASK1 DMA1+0x0a +#define MASK2 DMA2+0x14 + +#define Clk_bit 0x40 +#define Tx_bit 0x01 +#define Rd_Valid 0x08 +#define RxBit 0x08 + +static void DisableDmaChannel(unsigned int channel) +{ + switch (channel) { // 8 Bit DMA channels DMAC1 + case 0: + outb(4, MASK1); //mask channel 0 + break; + case 1: + outb(5, MASK1); //Mask channel 1 + break; + case 2: + outb(6, MASK1); //Mask channel 2 + break; + case 3: + outb(7, MASK1); //Mask channel 3 + break; + case 5: + outb(5, MASK2); //Mask channel 5 + break; + case 6: + outb(6, MASK2); //Mask channel 6 + break; + case 7: + outb(7, MASK2); //Mask channel 7 + break; + default: + break; + } +} + +static unsigned char ReadLPCReg(int iRegNum) +{ + unsigned char iVal; + + outb(0x87, 0x2e); + outb(0x87, 0x2e); + outb(iRegNum, 0x2e); + iVal = inb(0x2f); + outb(0xaa, 0x2e); + + return iVal; +} + +static void WriteLPCReg(int iRegNum, unsigned char iVal) +{ + + outb(0x87, 0x2e); + outb(0x87, 0x2e); + outb(iRegNum, 0x2e); + outb(iVal, 0x2f); + outb(0xAA, 0x2e); +} + +static __u8 ReadReg(unsigned int BaseAddr, int iRegNum) +{ + return (__u8) inb(BaseAddr + iRegNum); +} + +static void WriteReg(unsigned int BaseAddr, int iRegNum, unsigned char iVal) +{ + outb(iVal, BaseAddr + iRegNum); +} + +static int WriteRegBit(unsigned int BaseAddr, unsigned char RegNum, + unsigned char BitPos, unsigned char value) +{ + __u8 Rtemp, Wtemp; + + if (BitPos > 7) { + return -1; + } + if ((RegNum < StartAddr) || (RegNum > EndAddr)) + return -1; + Rtemp = ReadReg(BaseAddr, RegNum); + if (value == 0) + Wtemp = ResetBit(Rtemp, BitPos); + else { + if (value == 1) + Wtemp = SetBit(Rtemp, BitPos); + else + return -1; + } + WriteReg(BaseAddr, RegNum, Wtemp); + return 0; +} + +static __u8 CheckRegBit(unsigned int BaseAddr, unsigned char RegNum, + unsigned char BitPos) +{ + __u8 temp; + + if (BitPos > 7) + return 0xff; + if ((RegNum < StartAddr) || (RegNum > EndAddr)) { +// printf("what is the register %x!\n",RegNum); + } + temp = ReadReg(BaseAddr, RegNum); + return GetBit(temp, BitPos); +} + +static void SetMaxRxPacketSize(__u16 iobase, __u16 size) +{ + __u16 low, high; + if ((size & 0xe000) == 0) { + low = size & 0x00ff; + high = (size & 0x1f00) >> 8; + WriteReg(iobase, I_CF_L_2, low); + WriteReg(iobase, I_CF_H_2, high); + + } + +} + +//for both Rx and Tx + +static void SetFIFO(__u16 iobase, __u16 value) +{ + switch (value) { + case 128: + WriteRegBit(iobase, 0x11, 0, 0); + WriteRegBit(iobase, 0x11, 7, 1); + break; + case 64: + WriteRegBit(iobase, 0x11, 0, 0); + WriteRegBit(iobase, 0x11, 7, 0); + break; + case 32: + WriteRegBit(iobase, 0x11, 0, 1); + WriteRegBit(iobase, 0x11, 7, 0); + break; + default: + WriteRegBit(iobase, 0x11, 0, 0); + WriteRegBit(iobase, 0x11, 7, 0); + } + +} + +#define CRC16(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_L_0,7,val) //0 for 32 CRC +/* +#define SetVFIR(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_H_0,5,val) +#define SetFIR(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_L_0,6,val) +#define SetMIR(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_L_0,5,val) +#define SetSIR(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_L_0,4,val) +*/ +#define SIRFilter(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_L_0,3,val) +#define Filter(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_L_0,2,val) +#define InvertTX(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_L_0,1,val) +#define InvertRX(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_L_0,0,val) +//****************************I_CF_H_0 +#define EnableTX(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_H_0,4,val) +#define EnableRX(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_H_0,3,val) +#define EnableDMA(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_H_0,2,val) +#define SIRRecvAny(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_H_0,1,val) +#define DiableTrans(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_H_0,0,val) +//***************************I_SIR_BOF,I_SIR_EOF +#define SetSIRBOF(BaseAddr,val) WriteReg(BaseAddr,I_SIR_BOF,val) +#define SetSIREOF(BaseAddr,val) WriteReg(BaseAddr,I_SIR_EOF,val) +#define GetSIRBOF(BaseAddr) ReadReg(BaseAddr,I_SIR_BOF) +#define GetSIREOF(BaseAddr) ReadReg(BaseAddr,I_SIR_EOF) +//*******************I_ST_CT_0 +#define EnPhys(BaseAddr,val) WriteRegBit(BaseAddr,I_ST_CT_0,7,val) +#define IsModeError(BaseAddr) CheckRegBit(BaseAddr,I_ST_CT_0,6) //RO +#define IsVFIROn(BaseAddr) CheckRegBit(BaseAddr,0x14,0) //RO for VT1211 only +#define IsFIROn(BaseAddr) CheckRegBit(BaseAddr,I_ST_CT_0,5) //RO +#define IsMIROn(BaseAddr) CheckRegBit(BaseAddr,I_ST_CT_0,4) //RO +#define IsSIROn(BaseAddr) CheckRegBit(BaseAddr,I_ST_CT_0,3) //RO +#define IsEnableTX(BaseAddr) CheckRegBit(BaseAddr,I_ST_CT_0,2) //RO +#define IsEnableRX(BaseAddr) CheckRegBit(BaseAddr,I_ST_CT_0,1) //RO +#define Is16CRC(BaseAddr) CheckRegBit(BaseAddr,I_ST_CT_0,0) //RO +//***************************I_CF_3 +#define DisableAdjacentPulseWidth(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_3,5,val) //1 disable +#define DisablePulseWidthAdjust(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_3,4,val) //1 disable +#define UseOneRX(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_3,1,val) //0 use two RX +#define SlowIRRXLowActive(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_3,0,val) //0 show RX high=1 in SIR +//***************************H_CT +#define EnAllInt(BaseAddr,val) WriteRegBit(BaseAddr,H_CT,7,val) +#define TXStart(BaseAddr,val) WriteRegBit(BaseAddr,H_CT,6,val) +#define RXStart(BaseAddr,val) WriteRegBit(BaseAddr,H_CT,5,val) +#define ClearRXInt(BaseAddr,val) WriteRegBit(BaseAddr,H_CT,4,val) // 1 clear +//*****************H_ST +#define IsRXInt(BaseAddr) CheckRegBit(BaseAddr,H_ST,4) +#define GetIntIndentify(BaseAddr) ((ReadReg(BaseAddr,H_ST)&0xf1) >>1) +#define IsHostBusy(BaseAddr) CheckRegBit(BaseAddr,H_ST,0) +#define GetHostStatus(BaseAddr) ReadReg(BaseAddr,H_ST) //RO +//**************************M_CT +#define EnTXDMA(BaseAddr,val) WriteRegBit(BaseAddr,M_CT,7,val) +#define EnRXDMA(BaseAddr,val) WriteRegBit(BaseAddr,M_CT,6,val) +#define SwapDMA(BaseAddr,val) WriteRegBit(BaseAddr,M_CT,5,val) +#define EnInternalLoop(BaseAddr,val) WriteRegBit(BaseAddr,M_CT,4,val) +#define EnExternalLoop(BaseAddr,val) WriteRegBit(BaseAddr,M_CT,3,val) +//**************************TX_CT_1 +#define EnTXFIFOHalfLevelInt(BaseAddr,val) WriteRegBit(BaseAddr,TX_CT_1,4,val) //half empty int (1 half) +#define EnTXFIFOUnderrunEOMInt(BaseAddr,val) WriteRegBit(BaseAddr,TX_CT_1,5,val) +#define EnTXFIFOReadyInt(BaseAddr,val) WriteRegBit(BaseAddr,TX_CT_1,6,val) //int when reach it threshold (setting by bit 4) +//**************************TX_CT_2 +#define ForceUnderrun(BaseAddr,val) WriteRegBit(BaseAddr,TX_CT_2,7,val) // force an underrun int +#define EnTXCRC(BaseAddr,val) WriteRegBit(BaseAddr,TX_CT_2,6,val) //1 for FIR,MIR...0 (not SIR) +#define ForceBADCRC(BaseAddr,val) WriteRegBit(BaseAddr,TX_CT_2,5,val) //force an bad CRC +#define SendSIP(BaseAddr,val) WriteRegBit(BaseAddr,TX_CT_2,4,val) //send indication pulse for prevent SIR disturb +#define ClearEnTX(BaseAddr,val) WriteRegBit(BaseAddr,TX_CT_2,3,val) // opposite to EnTX +//*****************TX_ST +#define GetTXStatus(BaseAddr) ReadReg(BaseAddr,TX_ST) //RO +//**************************RX_CT +#define EnRXSpecInt(BaseAddr,val) WriteRegBit(BaseAddr,RX_CT,0,val) +#define EnRXFIFOReadyInt(BaseAddr,val) WriteRegBit(BaseAddr,RX_CT,1,val) //enable int when reach it threshold (setting by bit 7) +#define EnRXFIFOHalfLevelInt(BaseAddr,val) WriteRegBit(BaseAddr,RX_CT,7,val) //enable int when (1) half full...or (0) just not full +//*****************RX_ST +#define GetRXStatus(BaseAddr) ReadReg(BaseAddr,RX_ST) //RO +//***********************P_ADDR +#define SetPacketAddr(BaseAddr,addr) WriteReg(BaseAddr,P_ADDR,addr) +//***********************I_CF_4 +#define EnGPIOtoRX2(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_4,7,val) +#define EnTimerInt(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_4,1,val) +#define ClearTimerInt(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_4,0,val) +//***********************I_T_C_L +#define WriteGIO(BaseAddr,val) WriteRegBit(BaseAddr,I_T_C_L,7,val) +#define ReadGIO(BaseAddr) CheckRegBit(BaseAddr,I_T_C_L,7) +#define ReadRX(BaseAddr) CheckRegBit(BaseAddr,I_T_C_L,3) //RO +#define WriteTX(BaseAddr,val) WriteRegBit(BaseAddr,I_T_C_L,0,val) +//***********************I_T_C_H +#define EnRX2(BaseAddr,val) WriteRegBit(BaseAddr,I_T_C_H,7,val) +#define ReadRX2(BaseAddr) CheckRegBit(BaseAddr,I_T_C_H,7) +//**********************Version +#define GetFIRVersion(BaseAddr) ReadReg(BaseAddr,VERSION) + + +static void SetTimer(__u16 iobase, __u8 count) +{ + EnTimerInt(iobase, OFF); + WriteReg(iobase, TIMER, count); + EnTimerInt(iobase, ON); +} + + +static void SetSendByte(__u16 iobase, __u32 count) +{ + __u32 low, high; + + if ((count & 0xf000) == 0) { + low = count & 0x00ff; + high = (count & 0x0f00) >> 8; + WriteReg(iobase, TX_C_L, low); + WriteReg(iobase, TX_C_H, high); + } +} + +static void ResetChip(__u16 iobase, __u8 type) +{ + __u8 value; + + value = (type + 2) << 4; + WriteReg(iobase, RESET, type); +} + +static int CkRxRecv(__u16 iobase, struct via_ircc_cb *self) +{ + __u8 low, high; + __u16 wTmp = 0, wTmp1 = 0, wTmp_new = 0; + + low = ReadReg(iobase, RX_C_L); + high = ReadReg(iobase, RX_C_H); + wTmp1 = high; + wTmp = (wTmp1 << 8) | low; + udelay(10); + low = ReadReg(iobase, RX_C_L); + high = ReadReg(iobase, RX_C_H); + wTmp1 = high; + wTmp_new = (wTmp1 << 8) | low; + if (wTmp_new != wTmp) + return 1; + else + return 0; + +} + +static __u16 RxCurCount(__u16 iobase, struct via_ircc_cb * self) +{ + __u8 low, high; + __u16 wTmp = 0, wTmp1 = 0; + + low = ReadReg(iobase, RX_P_L); + high = ReadReg(iobase, RX_P_H); + wTmp1 = high; + wTmp = (wTmp1 << 8) | low; + return wTmp; +} + +/* This Routine can only use in recevie_complete + * for it will update last count. + */ + +static __u16 GetRecvByte(__u16 iobase, struct via_ircc_cb * self) +{ + __u8 low, high; + __u16 wTmp, wTmp1, ret; + + low = ReadReg(iobase, RX_P_L); + high = ReadReg(iobase, RX_P_H); + wTmp1 = high; + wTmp = (wTmp1 << 8) | low; + + + if (wTmp >= self->RxLastCount) + ret = wTmp - self->RxLastCount; + else + ret = (0x8000 - self->RxLastCount) + wTmp; + self->RxLastCount = wTmp; + +/* RX_P is more actually the RX_C + low=ReadReg(iobase,RX_C_L); + high=ReadReg(iobase,RX_C_H); + + if(!(high&0xe000)) { + temp=(high<<8)+low; + return temp; + } + else return 0; +*/ + return ret; +} + +static void Sdelay(__u16 scale) +{ + __u8 bTmp; + int i, j; + + for (j = 0; j < scale; j++) { + for (i = 0; i < 0x20; i++) { + bTmp = inb(0xeb); + outb(bTmp, 0xeb); + } + } +} + +static void Tdelay(__u16 scale) +{ + __u8 bTmp; + int i, j; + + for (j = 0; j < scale; j++) { + for (i = 0; i < 0x50; i++) { + bTmp = inb(0xeb); + outb(bTmp, 0xeb); + } + } +} + + +static void ActClk(__u16 iobase, __u8 value) +{ + __u8 bTmp; + bTmp = ReadReg(iobase, 0x34); + if (value) + WriteReg(iobase, 0x34, bTmp | Clk_bit); + else + WriteReg(iobase, 0x34, bTmp & ~Clk_bit); +} + +static void ClkTx(__u16 iobase, __u8 Clk, __u8 Tx) +{ + __u8 bTmp; + + bTmp = ReadReg(iobase, 0x34); + if (Clk == 0) + bTmp &= ~Clk_bit; + else { + if (Clk == 1) + bTmp |= Clk_bit; + } + WriteReg(iobase, 0x34, bTmp); + Sdelay(1); + if (Tx == 0) + bTmp &= ~Tx_bit; + else { + if (Tx == 1) + bTmp |= Tx_bit; + } + WriteReg(iobase, 0x34, bTmp); +} + +static void Wr_Byte(__u16 iobase, __u8 data) +{ + __u8 bData = data; +// __u8 btmp; + int i; + + ClkTx(iobase, 0, 1); + + Tdelay(2); + ActClk(iobase, 1); + Tdelay(1); + + for (i = 0; i < 8; i++) { //LDN + + if ((bData >> i) & 0x01) { + ClkTx(iobase, 0, 1); //bit data = 1; + } else { + ClkTx(iobase, 0, 0); //bit data = 1; + } + Tdelay(2); + Sdelay(1); + ActClk(iobase, 1); //clk hi + Tdelay(1); + } +} + +static __u8 Rd_Indx(__u16 iobase, __u8 addr, __u8 index) +{ + __u8 data = 0, bTmp, data_bit; + int i; + + bTmp = addr | (index << 1) | 0; + ClkTx(iobase, 0, 0); + Tdelay(2); + ActClk(iobase, 1); + udelay(1); + Wr_Byte(iobase, bTmp); + Sdelay(1); + ClkTx(iobase, 0, 0); + Tdelay(2); + for (i = 0; i < 10; i++) { + ActClk(iobase, 1); + Tdelay(1); + ActClk(iobase, 0); + Tdelay(1); + ClkTx(iobase, 0, 1); + Tdelay(1); + bTmp = ReadReg(iobase, 0x34); + if (!(bTmp & Rd_Valid)) + break; + } + if (!(bTmp & Rd_Valid)) { + for (i = 0; i < 8; i++) { + ActClk(iobase, 1); + Tdelay(1); + ActClk(iobase, 0); + bTmp = ReadReg(iobase, 0x34); + data_bit = 1 << i; + if (bTmp & RxBit) + data |= data_bit; + else + data &= ~data_bit; + Tdelay(2); + } + } else { + for (i = 0; i < 2; i++) { + ActClk(iobase, 1); + Tdelay(1); + ActClk(iobase, 0); + Tdelay(2); + } + bTmp = ReadReg(iobase, 0x34); + } + for (i = 0; i < 1; i++) { + ActClk(iobase, 1); + Tdelay(1); + ActClk(iobase, 0); + Tdelay(2); + } + ClkTx(iobase, 0, 0); + Tdelay(1); + for (i = 0; i < 3; i++) { + ActClk(iobase, 1); + Tdelay(1); + ActClk(iobase, 0); + Tdelay(2); + } + return data; +} + +static void Wr_Indx(__u16 iobase, __u8 addr, __u8 index, __u8 data) +{ + int i; + __u8 bTmp; + + ClkTx(iobase, 0, 0); + udelay(2); + ActClk(iobase, 1); + udelay(1); + bTmp = addr | (index << 1) | 1; + Wr_Byte(iobase, bTmp); + Wr_Byte(iobase, data); + for (i = 0; i < 2; i++) { + ClkTx(iobase, 0, 0); + Tdelay(2); + ActClk(iobase, 1); + Tdelay(1); + } + ActClk(iobase, 0); +} + +static void ResetDongle(__u16 iobase) +{ + int i; + ClkTx(iobase, 0, 0); + Tdelay(1); + for (i = 0; i < 30; i++) { + ActClk(iobase, 1); + Tdelay(1); + ActClk(iobase, 0); + Tdelay(1); + } + ActClk(iobase, 0); +} + +static void SetSITmode(__u16 iobase) +{ + + __u8 bTmp; + + bTmp = ReadLPCReg(0x28); + WriteLPCReg(0x28, bTmp | 0x10); //select ITMOFF + bTmp = ReadReg(iobase, 0x35); + WriteReg(iobase, 0x35, bTmp | 0x40); // Driver ITMOFF + WriteReg(iobase, 0x28, bTmp | 0x80); // enable All interrupt +} + +static void SI_SetMode(__u16 iobase, int mode) +{ + //__u32 dTmp; + __u8 bTmp; + + WriteLPCReg(0x28, 0x70); // S/W Reset + SetSITmode(iobase); + ResetDongle(iobase); + udelay(10); + Wr_Indx(iobase, 0x40, 0x0, 0x17); //RX ,APEN enable,Normal power + Wr_Indx(iobase, 0x40, 0x1, mode); //Set Mode + Wr_Indx(iobase, 0x40, 0x2, 0xff); //Set power to FIR VFIR > 1m + bTmp = Rd_Indx(iobase, 0x40, 1); +} + +static void InitCard(__u16 iobase) +{ + ResetChip(iobase, 5); + WriteReg(iobase, I_ST_CT_0, 0x00); // open CHIP on + SetSIRBOF(iobase, 0xc0); // hardware default value + SetSIREOF(iobase, 0xc1); +} + +static void CommonInit(__u16 iobase) +{ +// EnTXCRC(iobase,0); + SwapDMA(iobase, OFF); + SetMaxRxPacketSize(iobase, 0x0fff); //set to max:4095 + EnRXFIFOReadyInt(iobase, OFF); + EnRXFIFOHalfLevelInt(iobase, OFF); + EnTXFIFOHalfLevelInt(iobase, OFF); + EnTXFIFOUnderrunEOMInt(iobase, ON); +// EnTXFIFOReadyInt(iobase,ON); + InvertTX(iobase, OFF); + InvertRX(iobase, OFF); +// WriteLPCReg(0xF0,0); //(if VT1211 then do this) + if (IsSIROn(iobase)) { + SIRFilter(iobase, ON); + SIRRecvAny(iobase, ON); + } else { + SIRFilter(iobase, OFF); + SIRRecvAny(iobase, OFF); + } + EnRXSpecInt(iobase, ON); + WriteReg(iobase, I_ST_CT_0, 0x80); + EnableDMA(iobase, ON); +} + +static void SetBaudRate(__u16 iobase, __u32 rate) +{ + __u8 value = 11, temp; + + if (IsSIROn(iobase)) { + switch (rate) { + case (__u32) (2400L): + value = 47; + break; + case (__u32) (9600L): + value = 11; + break; + case (__u32) (19200L): + value = 5; + break; + case (__u32) (38400L): + value = 2; + break; + case (__u32) (57600L): + value = 1; + break; + case (__u32) (115200L): + value = 0; + break; + default: + break; + } + } else if (IsMIROn(iobase)) { + value = 0; // will automatically be fixed in 1.152M + } else if (IsFIROn(iobase)) { + value = 0; // will automatically be fixed in 4M + } + temp = (ReadReg(iobase, I_CF_H_1) & 0x03); + temp |= value << 2; + WriteReg(iobase, I_CF_H_1, temp); +} + +static void SetPulseWidth(__u16 iobase, __u8 width) +{ + __u8 temp, temp1, temp2; + + temp = (ReadReg(iobase, I_CF_L_1) & 0x1f); + temp1 = (ReadReg(iobase, I_CF_H_1) & 0xfc); + temp2 = (width & 0x07) << 5; + temp |= temp2; + temp2 = (width & 0x18) >> 3; + temp1 |= temp2; + WriteReg(iobase, I_CF_L_1, temp); + WriteReg(iobase, I_CF_H_1, temp1); +} + +static void SetSendPreambleCount(__u16 iobase, __u8 count) +{ + __u8 temp; + + temp = ReadReg(iobase, I_CF_L_1) & 0xe0; + temp |= count; + WriteReg(iobase, I_CF_L_1, temp); + +} + +static void SetVFIR(__u16 BaseAddr, __u8 val) +{ + __u8 tmp; + + tmp = ReadReg(BaseAddr, I_CF_L_0); + WriteReg(BaseAddr, I_CF_L_0, tmp & 0x8f); + WriteRegBit(BaseAddr, I_CF_H_0, 5, val); +} + +static void SetFIR(__u16 BaseAddr, __u8 val) +{ + __u8 tmp; + + WriteRegBit(BaseAddr, I_CF_H_0, 5, 0); + tmp = ReadReg(BaseAddr, I_CF_L_0); + WriteReg(BaseAddr, I_CF_L_0, tmp & 0x8f); + WriteRegBit(BaseAddr, I_CF_L_0, 6, val); +} + +static void SetMIR(__u16 BaseAddr, __u8 val) +{ + __u8 tmp; + + WriteRegBit(BaseAddr, I_CF_H_0, 5, 0); + tmp = ReadReg(BaseAddr, I_CF_L_0); + WriteReg(BaseAddr, I_CF_L_0, tmp & 0x8f); + WriteRegBit(BaseAddr, I_CF_L_0, 5, val); +} + +static void SetSIR(__u16 BaseAddr, __u8 val) +{ + __u8 tmp; + + WriteRegBit(BaseAddr, I_CF_H_0, 5, 0); + tmp = ReadReg(BaseAddr, I_CF_L_0); + WriteReg(BaseAddr, I_CF_L_0, tmp & 0x8f); + WriteRegBit(BaseAddr, I_CF_L_0, 4, val); +} + +#endif /* via_IRCC_H */ diff --git a/drivers/staging/irda/drivers/vlsi_ir.c b/drivers/staging/irda/drivers/vlsi_ir.c new file mode 100644 index 000000000000..6638784c082e --- /dev/null +++ b/drivers/staging/irda/drivers/vlsi_ir.c @@ -0,0 +1,1872 @@ +/********************************************************************* + * + * vlsi_ir.c: VLSI82C147 PCI IrDA controller driver for Linux + * + * Copyright (c) 2001-2003 Martin Diehl + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + ********************************************************************/ + +#include <linux/module.h> + +#define DRIVER_NAME "vlsi_ir" +#define DRIVER_VERSION "v0.5" +#define DRIVER_DESCRIPTION "IrDA SIR/MIR/FIR driver for VLSI 82C147" +#define DRIVER_AUTHOR "Martin Diehl <info@mdiehl.de>" + +MODULE_DESCRIPTION(DRIVER_DESCRIPTION); +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_LICENSE("GPL"); + +/********************************************************/ + +#include <linux/kernel.h> +#include <linux/ktime.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/pci.h> +#include <linux/slab.h> +#include <linux/netdevice.h> +#include <linux/skbuff.h> +#include <linux/delay.h> +#include <linux/proc_fs.h> +#include <linux/seq_file.h> +#include <linux/math64.h> +#include <linux/mutex.h> +#include <linux/uaccess.h> +#include <asm/byteorder.h> + +#include <net/irda/irda.h> +#include <net/irda/irda_device.h> +#include <net/irda/wrapper.h> +#include <net/irda/crc.h> + +#include "vlsi_ir.h" + +/********************************************************/ + +static /* const */ char drivername[] = DRIVER_NAME; + +static const struct pci_device_id vlsi_irda_table[] = { + { + .class = PCI_CLASS_WIRELESS_IRDA << 8, + .class_mask = PCI_CLASS_SUBCLASS_MASK << 8, + .vendor = PCI_VENDOR_ID_VLSI, + .device = PCI_DEVICE_ID_VLSI_82C147, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { /* all zeroes */ } +}; + +MODULE_DEVICE_TABLE(pci, vlsi_irda_table); + +/********************************************************/ + +/* clksrc: which clock source to be used + * 0: auto - try PLL, fallback to 40MHz XCLK + * 1: on-chip 48MHz PLL + * 2: external 48MHz XCLK + * 3: external 40MHz XCLK (HP OB-800) + */ + +static int clksrc = 0; /* default is 0(auto) */ +module_param(clksrc, int, 0); +MODULE_PARM_DESC(clksrc, "clock input source selection"); + +/* ringsize: size of the tx and rx descriptor rings + * independent for tx and rx + * specify as ringsize=tx[,rx] + * allowed values: 4, 8, 16, 32, 64 + * Due to the IrDA 1.x max. allowed window size=7, + * there should be no gain when using rings larger than 8 + */ + +static int ringsize[] = {8,8}; /* default is tx=8 / rx=8 */ +module_param_array(ringsize, int, NULL, 0); +MODULE_PARM_DESC(ringsize, "TX, RX ring descriptor size"); + +/* sirpulse: tuning of the SIR pulse width within IrPHY 1.3 limits + * 0: very short, 1.5us (exception: 6us at 2.4 kbaud) + * 1: nominal 3/16 bittime width + * note: IrDA compliant peer devices should be happy regardless + * which one is used. Primary goal is to save some power + * on the sender's side - at 9.6kbaud for example the short + * pulse width saves more than 90% of the transmitted IR power. + */ + +static int sirpulse = 1; /* default is 3/16 bittime */ +module_param(sirpulse, int, 0); +MODULE_PARM_DESC(sirpulse, "SIR pulse width tuning"); + +/* qos_mtt_bits: encoded min-turn-time value we require the peer device + * to use before transmitting to us. "Type 1" (per-station) + * bitfield according to IrLAP definition (section 6.6.8) + * Don't know which transceiver is used by my OB800 - the + * pretty common HP HDLS-1100 requires 1 msec - so lets use this. + */ + +static int qos_mtt_bits = 0x07; /* default is 1 ms or more */ +module_param(qos_mtt_bits, int, 0); +MODULE_PARM_DESC(qos_mtt_bits, "IrLAP bitfield representing min-turn-time"); + +/********************************************************/ + +static void vlsi_reg_debug(unsigned iobase, const char *s) +{ + int i; + + printk(KERN_DEBUG "%s: ", s); + for (i = 0; i < 0x20; i++) + printk("%02x", (unsigned)inb((iobase+i))); + printk("\n"); +} + +static void vlsi_ring_debug(struct vlsi_ring *r) +{ + struct ring_descr *rd; + unsigned i; + + printk(KERN_DEBUG "%s - ring %p / size %u / mask 0x%04x / len %u / dir %d / hw %p\n", + __func__, r, r->size, r->mask, r->len, r->dir, r->rd[0].hw); + printk(KERN_DEBUG "%s - head = %d / tail = %d\n", __func__, + atomic_read(&r->head) & r->mask, atomic_read(&r->tail) & r->mask); + for (i = 0; i < r->size; i++) { + rd = &r->rd[i]; + printk(KERN_DEBUG "%s - ring descr %u: ", __func__, i); + printk("skb=%p data=%p hw=%p\n", rd->skb, rd->buf, rd->hw); + printk(KERN_DEBUG "%s - hw: status=%02x count=%u addr=0x%08x\n", + __func__, (unsigned) rd_get_status(rd), + (unsigned) rd_get_count(rd), (unsigned) rd_get_addr(rd)); + } +} + +/********************************************************/ + +/* needed regardless of CONFIG_PROC_FS */ +static struct proc_dir_entry *vlsi_proc_root = NULL; + +#ifdef CONFIG_PROC_FS + +static void vlsi_proc_pdev(struct seq_file *seq, struct pci_dev *pdev) +{ + unsigned iobase = pci_resource_start(pdev, 0); + unsigned i; + + seq_printf(seq, "\n%s (vid/did: [%04x:%04x])\n", + pci_name(pdev), (int)pdev->vendor, (int)pdev->device); + seq_printf(seq, "pci-power-state: %u\n", (unsigned) pdev->current_state); + seq_printf(seq, "resources: irq=%u / io=0x%04x / dma_mask=0x%016Lx\n", + pdev->irq, (unsigned)pci_resource_start(pdev, 0), (unsigned long long)pdev->dma_mask); + seq_printf(seq, "hw registers: "); + for (i = 0; i < 0x20; i++) + seq_printf(seq, "%02x", (unsigned)inb((iobase+i))); + seq_printf(seq, "\n"); +} + +static void vlsi_proc_ndev(struct seq_file *seq, struct net_device *ndev) +{ + vlsi_irda_dev_t *idev = netdev_priv(ndev); + u8 byte; + u16 word; + s32 sec, usec; + unsigned iobase = ndev->base_addr; + + seq_printf(seq, "\n%s link state: %s / %s / %s / %s\n", ndev->name, + netif_device_present(ndev) ? "attached" : "detached", + netif_running(ndev) ? "running" : "not running", + netif_carrier_ok(ndev) ? "carrier ok" : "no carrier", + netif_queue_stopped(ndev) ? "queue stopped" : "queue running"); + + if (!netif_running(ndev)) + return; + + seq_printf(seq, "\nhw-state:\n"); + pci_read_config_byte(idev->pdev, VLSI_PCI_IRMISC, &byte); + seq_printf(seq, "IRMISC:%s%s%s uart%s", + (byte&IRMISC_IRRAIL) ? " irrail" : "", + (byte&IRMISC_IRPD) ? " irpd" : "", + (byte&IRMISC_UARTTST) ? " uarttest" : "", + (byte&IRMISC_UARTEN) ? "@" : " disabled\n"); + if (byte&IRMISC_UARTEN) { + seq_printf(seq, "0x%s\n", + (byte&2) ? ((byte&1) ? "3e8" : "2e8") + : ((byte&1) ? "3f8" : "2f8")); + } + pci_read_config_byte(idev->pdev, VLSI_PCI_CLKCTL, &byte); + seq_printf(seq, "CLKCTL: PLL %s%s%s / clock %s / wakeup %s\n", + (byte&CLKCTL_PD_INV) ? "powered" : "down", + (byte&CLKCTL_LOCK) ? " locked" : "", + (byte&CLKCTL_EXTCLK) ? ((byte&CLKCTL_XCKSEL)?" / 40 MHz XCLK":" / 48 MHz XCLK") : "", + (byte&CLKCTL_CLKSTP) ? "stopped" : "running", + (byte&CLKCTL_WAKE) ? "enabled" : "disabled"); + pci_read_config_byte(idev->pdev, VLSI_PCI_MSTRPAGE, &byte); + seq_printf(seq, "MSTRPAGE: 0x%02x\n", (unsigned)byte); + + byte = inb(iobase+VLSI_PIO_IRINTR); + seq_printf(seq, "IRINTR:%s%s%s%s%s%s%s%s\n", + (byte&IRINTR_ACTEN) ? " ACTEN" : "", + (byte&IRINTR_RPKTEN) ? " RPKTEN" : "", + (byte&IRINTR_TPKTEN) ? " TPKTEN" : "", + (byte&IRINTR_OE_EN) ? " OE_EN" : "", + (byte&IRINTR_ACTIVITY) ? " ACTIVITY" : "", + (byte&IRINTR_RPKTINT) ? " RPKTINT" : "", + (byte&IRINTR_TPKTINT) ? " TPKTINT" : "", + (byte&IRINTR_OE_INT) ? " OE_INT" : ""); + word = inw(iobase+VLSI_PIO_RINGPTR); + seq_printf(seq, "RINGPTR: rx=%u / tx=%u\n", RINGPTR_GET_RX(word), RINGPTR_GET_TX(word)); + word = inw(iobase+VLSI_PIO_RINGBASE); + seq_printf(seq, "RINGBASE: busmap=0x%08x\n", + ((unsigned)word << 10)|(MSTRPAGE_VALUE<<24)); + word = inw(iobase+VLSI_PIO_RINGSIZE); + seq_printf(seq, "RINGSIZE: rx=%u / tx=%u\n", RINGSIZE_TO_RXSIZE(word), + RINGSIZE_TO_TXSIZE(word)); + + word = inw(iobase+VLSI_PIO_IRCFG); + seq_printf(seq, "IRCFG:%s%s%s%s%s%s%s%s%s%s%s%s%s\n", + (word&IRCFG_LOOP) ? " LOOP" : "", + (word&IRCFG_ENTX) ? " ENTX" : "", + (word&IRCFG_ENRX) ? " ENRX" : "", + (word&IRCFG_MSTR) ? " MSTR" : "", + (word&IRCFG_RXANY) ? " RXANY" : "", + (word&IRCFG_CRC16) ? " CRC16" : "", + (word&IRCFG_FIR) ? " FIR" : "", + (word&IRCFG_MIR) ? " MIR" : "", + (word&IRCFG_SIR) ? " SIR" : "", + (word&IRCFG_SIRFILT) ? " SIRFILT" : "", + (word&IRCFG_SIRTEST) ? " SIRTEST" : "", + (word&IRCFG_TXPOL) ? " TXPOL" : "", + (word&IRCFG_RXPOL) ? " RXPOL" : ""); + word = inw(iobase+VLSI_PIO_IRENABLE); + seq_printf(seq, "IRENABLE:%s%s%s%s%s%s%s%s\n", + (word&IRENABLE_PHYANDCLOCK) ? " PHYANDCLOCK" : "", + (word&IRENABLE_CFGER) ? " CFGERR" : "", + (word&IRENABLE_FIR_ON) ? " FIR_ON" : "", + (word&IRENABLE_MIR_ON) ? " MIR_ON" : "", + (word&IRENABLE_SIR_ON) ? " SIR_ON" : "", + (word&IRENABLE_ENTXST) ? " ENTXST" : "", + (word&IRENABLE_ENRXST) ? " ENRXST" : "", + (word&IRENABLE_CRC16_ON) ? " CRC16_ON" : ""); + word = inw(iobase+VLSI_PIO_PHYCTL); + seq_printf(seq, "PHYCTL: baud-divisor=%u / pulsewidth=%u / preamble=%u\n", + (unsigned)PHYCTL_TO_BAUD(word), + (unsigned)PHYCTL_TO_PLSWID(word), + (unsigned)PHYCTL_TO_PREAMB(word)); + word = inw(iobase+VLSI_PIO_NPHYCTL); + seq_printf(seq, "NPHYCTL: baud-divisor=%u / pulsewidth=%u / preamble=%u\n", + (unsigned)PHYCTL_TO_BAUD(word), + (unsigned)PHYCTL_TO_PLSWID(word), + (unsigned)PHYCTL_TO_PREAMB(word)); + word = inw(iobase+VLSI_PIO_MAXPKT); + seq_printf(seq, "MAXPKT: max. rx packet size = %u\n", word); + word = inw(iobase+VLSI_PIO_RCVBCNT) & RCVBCNT_MASK; + seq_printf(seq, "RCVBCNT: rx-fifo filling level = %u\n", word); + + seq_printf(seq, "\nsw-state:\n"); + seq_printf(seq, "IrPHY setup: %d baud - %s encoding\n", idev->baud, + (idev->mode==IFF_SIR)?"SIR":((idev->mode==IFF_MIR)?"MIR":"FIR")); + sec = div_s64_rem(ktime_us_delta(ktime_get(), idev->last_rx), + USEC_PER_SEC, &usec); + seq_printf(seq, "last rx: %ul.%06u sec\n", sec, usec); + + seq_printf(seq, "RX: packets=%lu / bytes=%lu / errors=%lu / dropped=%lu", + ndev->stats.rx_packets, ndev->stats.rx_bytes, ndev->stats.rx_errors, + ndev->stats.rx_dropped); + seq_printf(seq, " / overrun=%lu / length=%lu / frame=%lu / crc=%lu\n", + ndev->stats.rx_over_errors, ndev->stats.rx_length_errors, + ndev->stats.rx_frame_errors, ndev->stats.rx_crc_errors); + seq_printf(seq, "TX: packets=%lu / bytes=%lu / errors=%lu / dropped=%lu / fifo=%lu\n", + ndev->stats.tx_packets, ndev->stats.tx_bytes, ndev->stats.tx_errors, + ndev->stats.tx_dropped, ndev->stats.tx_fifo_errors); + +} + +static void vlsi_proc_ring(struct seq_file *seq, struct vlsi_ring *r) +{ + struct ring_descr *rd; + unsigned i, j; + int h, t; + + seq_printf(seq, "size %u / mask 0x%04x / len %u / dir %d / hw %p\n", + r->size, r->mask, r->len, r->dir, r->rd[0].hw); + h = atomic_read(&r->head) & r->mask; + t = atomic_read(&r->tail) & r->mask; + seq_printf(seq, "head = %d / tail = %d ", h, t); + if (h == t) + seq_printf(seq, "(empty)\n"); + else { + if (((t+1)&r->mask) == h) + seq_printf(seq, "(full)\n"); + else + seq_printf(seq, "(level = %d)\n", ((unsigned)(t-h) & r->mask)); + rd = &r->rd[h]; + j = (unsigned) rd_get_count(rd); + seq_printf(seq, "current: rd = %d / status = %02x / len = %u\n", + h, (unsigned)rd_get_status(rd), j); + if (j > 0) { + seq_printf(seq, " data: %*ph\n", + min_t(unsigned, j, 20), rd->buf); + } + } + for (i = 0; i < r->size; i++) { + rd = &r->rd[i]; + seq_printf(seq, "> ring descr %u: ", i); + seq_printf(seq, "skb=%p data=%p hw=%p\n", rd->skb, rd->buf, rd->hw); + seq_printf(seq, " hw: status=%02x count=%u busaddr=0x%08x\n", + (unsigned) rd_get_status(rd), + (unsigned) rd_get_count(rd), (unsigned) rd_get_addr(rd)); + } +} + +static int vlsi_seq_show(struct seq_file *seq, void *v) +{ + struct net_device *ndev = seq->private; + vlsi_irda_dev_t *idev = netdev_priv(ndev); + unsigned long flags; + + seq_printf(seq, "\n%s %s\n\n", DRIVER_NAME, DRIVER_VERSION); + seq_printf(seq, "clksrc: %s\n", + (clksrc>=2) ? ((clksrc==3)?"40MHz XCLK":"48MHz XCLK") + : ((clksrc==1)?"48MHz PLL":"autodetect")); + seq_printf(seq, "ringsize: tx=%d / rx=%d\n", + ringsize[0], ringsize[1]); + seq_printf(seq, "sirpulse: %s\n", (sirpulse)?"3/16 bittime":"short"); + seq_printf(seq, "qos_mtt_bits: 0x%02x\n", (unsigned)qos_mtt_bits); + + spin_lock_irqsave(&idev->lock, flags); + if (idev->pdev != NULL) { + vlsi_proc_pdev(seq, idev->pdev); + + if (idev->pdev->current_state == 0) + vlsi_proc_ndev(seq, ndev); + else + seq_printf(seq, "\nPCI controller down - resume_ok = %d\n", + idev->resume_ok); + if (netif_running(ndev) && idev->rx_ring && idev->tx_ring) { + seq_printf(seq, "\n--------- RX ring -----------\n\n"); + vlsi_proc_ring(seq, idev->rx_ring); + seq_printf(seq, "\n--------- TX ring -----------\n\n"); + vlsi_proc_ring(seq, idev->tx_ring); + } + } + seq_printf(seq, "\n"); + spin_unlock_irqrestore(&idev->lock, flags); + + return 0; +} + +static int vlsi_seq_open(struct inode *inode, struct file *file) +{ + return single_open(file, vlsi_seq_show, PDE_DATA(inode)); +} + +static const struct file_operations vlsi_proc_fops = { + .owner = THIS_MODULE, + .open = vlsi_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +#define VLSI_PROC_FOPS (&vlsi_proc_fops) + +#else /* CONFIG_PROC_FS */ +#define VLSI_PROC_FOPS NULL +#endif + +/********************************************************/ + +static struct vlsi_ring *vlsi_alloc_ring(struct pci_dev *pdev, struct ring_descr_hw *hwmap, + unsigned size, unsigned len, int dir) +{ + struct vlsi_ring *r; + struct ring_descr *rd; + unsigned i, j; + dma_addr_t busaddr; + + if (!size || ((size-1)&size)!=0) /* must be >0 and power of 2 */ + return NULL; + + r = kmalloc(sizeof(*r) + size * sizeof(struct ring_descr), GFP_KERNEL); + if (!r) + return NULL; + memset(r, 0, sizeof(*r)); + + r->pdev = pdev; + r->dir = dir; + r->len = len; + r->rd = (struct ring_descr *)(r+1); + r->mask = size - 1; + r->size = size; + atomic_set(&r->head, 0); + atomic_set(&r->tail, 0); + + for (i = 0; i < size; i++) { + rd = r->rd + i; + memset(rd, 0, sizeof(*rd)); + rd->hw = hwmap + i; + rd->buf = kmalloc(len, GFP_KERNEL|GFP_DMA); + if (rd->buf) + busaddr = pci_map_single(pdev, rd->buf, len, dir); + if (rd->buf == NULL || pci_dma_mapping_error(pdev, busaddr)) { + if (rd->buf) { + net_err_ratelimited("%s: failed to create PCI-MAP for %p\n", + __func__, rd->buf); + kfree(rd->buf); + rd->buf = NULL; + } + for (j = 0; j < i; j++) { + rd = r->rd + j; + busaddr = rd_get_addr(rd); + rd_set_addr_status(rd, 0, 0); + pci_unmap_single(pdev, busaddr, len, dir); + kfree(rd->buf); + rd->buf = NULL; + } + kfree(r); + return NULL; + } + rd_set_addr_status(rd, busaddr, 0); + /* initially, the dma buffer is owned by the CPU */ + rd->skb = NULL; + } + return r; +} + +static int vlsi_free_ring(struct vlsi_ring *r) +{ + struct ring_descr *rd; + unsigned i; + dma_addr_t busaddr; + + for (i = 0; i < r->size; i++) { + rd = r->rd + i; + if (rd->skb) + dev_kfree_skb_any(rd->skb); + busaddr = rd_get_addr(rd); + rd_set_addr_status(rd, 0, 0); + if (busaddr) + pci_unmap_single(r->pdev, busaddr, r->len, r->dir); + kfree(rd->buf); + } + kfree(r); + return 0; +} + +static int vlsi_create_hwif(vlsi_irda_dev_t *idev) +{ + char *ringarea; + struct ring_descr_hw *hwmap; + + idev->virtaddr = NULL; + idev->busaddr = 0; + + ringarea = pci_zalloc_consistent(idev->pdev, HW_RING_AREA_SIZE, + &idev->busaddr); + if (!ringarea) + goto out; + + hwmap = (struct ring_descr_hw *)ringarea; + idev->rx_ring = vlsi_alloc_ring(idev->pdev, hwmap, ringsize[1], + XFER_BUF_SIZE, PCI_DMA_FROMDEVICE); + if (idev->rx_ring == NULL) + goto out_unmap; + + hwmap += MAX_RING_DESCR; + idev->tx_ring = vlsi_alloc_ring(idev->pdev, hwmap, ringsize[0], + XFER_BUF_SIZE, PCI_DMA_TODEVICE); + if (idev->tx_ring == NULL) + goto out_free_rx; + + idev->virtaddr = ringarea; + return 0; + +out_free_rx: + vlsi_free_ring(idev->rx_ring); +out_unmap: + idev->rx_ring = idev->tx_ring = NULL; + pci_free_consistent(idev->pdev, HW_RING_AREA_SIZE, ringarea, idev->busaddr); + idev->busaddr = 0; +out: + return -ENOMEM; +} + +static int vlsi_destroy_hwif(vlsi_irda_dev_t *idev) +{ + vlsi_free_ring(idev->rx_ring); + vlsi_free_ring(idev->tx_ring); + idev->rx_ring = idev->tx_ring = NULL; + + if (idev->busaddr) + pci_free_consistent(idev->pdev,HW_RING_AREA_SIZE,idev->virtaddr,idev->busaddr); + + idev->virtaddr = NULL; + idev->busaddr = 0; + + return 0; +} + +/********************************************************/ + +static int vlsi_process_rx(struct vlsi_ring *r, struct ring_descr *rd) +{ + u16 status; + int crclen, len = 0; + struct sk_buff *skb; + int ret = 0; + struct net_device *ndev = pci_get_drvdata(r->pdev); + vlsi_irda_dev_t *idev = netdev_priv(ndev); + + pci_dma_sync_single_for_cpu(r->pdev, rd_get_addr(rd), r->len, r->dir); + /* dma buffer now owned by the CPU */ + status = rd_get_status(rd); + if (status & RD_RX_ERROR) { + if (status & RD_RX_OVER) + ret |= VLSI_RX_OVER; + if (status & RD_RX_LENGTH) + ret |= VLSI_RX_LENGTH; + if (status & RD_RX_PHYERR) + ret |= VLSI_RX_FRAME; + if (status & RD_RX_CRCERR) + ret |= VLSI_RX_CRC; + goto done; + } + + len = rd_get_count(rd); + crclen = (idev->mode==IFF_FIR) ? sizeof(u32) : sizeof(u16); + len -= crclen; /* remove trailing CRC */ + if (len <= 0) { + pr_debug("%s: strange frame (len=%d)\n", __func__, len); + ret |= VLSI_RX_DROP; + goto done; + } + + if (idev->mode == IFF_SIR) { /* hw checks CRC in MIR, FIR mode */ + + /* rd->buf is a streaming PCI_DMA_FROMDEVICE map. Doing the + * endian-adjustment there just in place will dirty a cache line + * which belongs to the map and thus we must be sure it will + * get flushed before giving the buffer back to hardware. + * vlsi_fill_rx() will do this anyway - but here we rely on. + */ + le16_to_cpus(rd->buf+len); + if (irda_calc_crc16(INIT_FCS,rd->buf,len+crclen) != GOOD_FCS) { + pr_debug("%s: crc error\n", __func__); + ret |= VLSI_RX_CRC; + goto done; + } + } + + if (!rd->skb) { + net_warn_ratelimited("%s: rx packet lost\n", __func__); + ret |= VLSI_RX_DROP; + goto done; + } + + skb = rd->skb; + rd->skb = NULL; + skb->dev = ndev; + skb_put_data(skb, rd->buf, len); + skb_reset_mac_header(skb); + if (in_interrupt()) + netif_rx(skb); + else + netif_rx_ni(skb); + +done: + rd_set_status(rd, 0); + rd_set_count(rd, 0); + /* buffer still owned by CPU */ + + return (ret) ? -ret : len; +} + +static void vlsi_fill_rx(struct vlsi_ring *r) +{ + struct ring_descr *rd; + + for (rd = ring_last(r); rd != NULL; rd = ring_put(r)) { + if (rd_is_active(rd)) { + net_warn_ratelimited("%s: driver bug: rx descr race with hw\n", + __func__); + vlsi_ring_debug(r); + break; + } + if (!rd->skb) { + rd->skb = dev_alloc_skb(IRLAP_SKB_ALLOCSIZE); + if (rd->skb) { + skb_reserve(rd->skb,1); + rd->skb->protocol = htons(ETH_P_IRDA); + } + else + break; /* probably not worth logging? */ + } + /* give dma buffer back to busmaster */ + pci_dma_sync_single_for_device(r->pdev, rd_get_addr(rd), r->len, r->dir); + rd_activate(rd); + } +} + +static void vlsi_rx_interrupt(struct net_device *ndev) +{ + vlsi_irda_dev_t *idev = netdev_priv(ndev); + struct vlsi_ring *r = idev->rx_ring; + struct ring_descr *rd; + int ret; + + for (rd = ring_first(r); rd != NULL; rd = ring_get(r)) { + + if (rd_is_active(rd)) + break; + + ret = vlsi_process_rx(r, rd); + + if (ret < 0) { + ret = -ret; + ndev->stats.rx_errors++; + if (ret & VLSI_RX_DROP) + ndev->stats.rx_dropped++; + if (ret & VLSI_RX_OVER) + ndev->stats.rx_over_errors++; + if (ret & VLSI_RX_LENGTH) + ndev->stats.rx_length_errors++; + if (ret & VLSI_RX_FRAME) + ndev->stats.rx_frame_errors++; + if (ret & VLSI_RX_CRC) + ndev->stats.rx_crc_errors++; + } + else if (ret > 0) { + ndev->stats.rx_packets++; + ndev->stats.rx_bytes += ret; + } + } + + idev->last_rx = ktime_get(); /* remember "now" for later mtt delay */ + + vlsi_fill_rx(r); + + if (ring_first(r) == NULL) { + /* we are in big trouble, if this should ever happen */ + net_err_ratelimited("%s: rx ring exhausted!\n", __func__); + vlsi_ring_debug(r); + } + else + outw(0, ndev->base_addr+VLSI_PIO_PROMPT); +} + +/* caller must have stopped the controller from busmastering */ + +static void vlsi_unarm_rx(vlsi_irda_dev_t *idev) +{ + struct net_device *ndev = pci_get_drvdata(idev->pdev); + struct vlsi_ring *r = idev->rx_ring; + struct ring_descr *rd; + int ret; + + for (rd = ring_first(r); rd != NULL; rd = ring_get(r)) { + + ret = 0; + if (rd_is_active(rd)) { + rd_set_status(rd, 0); + if (rd_get_count(rd)) { + pr_debug("%s - dropping rx packet\n", __func__); + ret = -VLSI_RX_DROP; + } + rd_set_count(rd, 0); + pci_dma_sync_single_for_cpu(r->pdev, rd_get_addr(rd), r->len, r->dir); + if (rd->skb) { + dev_kfree_skb_any(rd->skb); + rd->skb = NULL; + } + } + else + ret = vlsi_process_rx(r, rd); + + if (ret < 0) { + ret = -ret; + ndev->stats.rx_errors++; + if (ret & VLSI_RX_DROP) + ndev->stats.rx_dropped++; + if (ret & VLSI_RX_OVER) + ndev->stats.rx_over_errors++; + if (ret & VLSI_RX_LENGTH) + ndev->stats.rx_length_errors++; + if (ret & VLSI_RX_FRAME) + ndev->stats.rx_frame_errors++; + if (ret & VLSI_RX_CRC) + ndev->stats.rx_crc_errors++; + } + else if (ret > 0) { + ndev->stats.rx_packets++; + ndev->stats.rx_bytes += ret; + } + } +} + +/********************************************************/ + +static int vlsi_process_tx(struct vlsi_ring *r, struct ring_descr *rd) +{ + u16 status; + int len; + int ret; + + pci_dma_sync_single_for_cpu(r->pdev, rd_get_addr(rd), r->len, r->dir); + /* dma buffer now owned by the CPU */ + status = rd_get_status(rd); + if (status & RD_TX_UNDRN) + ret = VLSI_TX_FIFO; + else + ret = 0; + rd_set_status(rd, 0); + + if (rd->skb) { + len = rd->skb->len; + dev_kfree_skb_any(rd->skb); + rd->skb = NULL; + } + else /* tx-skb already freed? - should never happen */ + len = rd_get_count(rd); /* incorrect for SIR! (due to wrapping) */ + + rd_set_count(rd, 0); + /* dma buffer still owned by the CPU */ + + return (ret) ? -ret : len; +} + +static int vlsi_set_baud(vlsi_irda_dev_t *idev, unsigned iobase) +{ + u16 nphyctl; + u16 config; + unsigned mode; + int ret; + int baudrate; + int fifocnt; + + baudrate = idev->new_baud; + pr_debug("%s: %d -> %d\n", __func__, idev->baud, idev->new_baud); + if (baudrate == 4000000) { + mode = IFF_FIR; + config = IRCFG_FIR; + nphyctl = PHYCTL_FIR; + } + else if (baudrate == 1152000) { + mode = IFF_MIR; + config = IRCFG_MIR | IRCFG_CRC16; + nphyctl = PHYCTL_MIR(clksrc==3); + } + else { + mode = IFF_SIR; + config = IRCFG_SIR | IRCFG_SIRFILT | IRCFG_RXANY; + switch(baudrate) { + default: + net_warn_ratelimited("%s: undefined baudrate %d - fallback to 9600!\n", + __func__, baudrate); + baudrate = 9600; + /* fallthru */ + case 2400: + case 9600: + case 19200: + case 38400: + case 57600: + case 115200: + nphyctl = PHYCTL_SIR(baudrate,sirpulse,clksrc==3); + break; + } + } + config |= IRCFG_MSTR | IRCFG_ENRX; + + fifocnt = inw(iobase+VLSI_PIO_RCVBCNT) & RCVBCNT_MASK; + if (fifocnt != 0) { + pr_debug("%s: rx fifo not empty(%d)\n", __func__, fifocnt); + } + + outw(0, iobase+VLSI_PIO_IRENABLE); + outw(config, iobase+VLSI_PIO_IRCFG); + outw(nphyctl, iobase+VLSI_PIO_NPHYCTL); + wmb(); + outw(IRENABLE_PHYANDCLOCK, iobase+VLSI_PIO_IRENABLE); + mb(); + + udelay(1); /* chip applies IRCFG on next rising edge of its 8MHz clock */ + + /* read back settings for validation */ + + config = inw(iobase+VLSI_PIO_IRENABLE) & IRENABLE_MASK; + + if (mode == IFF_FIR) + config ^= IRENABLE_FIR_ON; + else if (mode == IFF_MIR) + config ^= (IRENABLE_MIR_ON|IRENABLE_CRC16_ON); + else + config ^= IRENABLE_SIR_ON; + + if (config != (IRENABLE_PHYANDCLOCK|IRENABLE_ENRXST)) { + net_warn_ratelimited("%s: failed to set %s mode!\n", + __func__, + mode == IFF_SIR ? "SIR" : + mode == IFF_MIR ? "MIR" : "FIR"); + ret = -1; + } + else { + if (inw(iobase+VLSI_PIO_PHYCTL) != nphyctl) { + net_warn_ratelimited("%s: failed to apply baudrate %d\n", + __func__, baudrate); + ret = -1; + } + else { + idev->mode = mode; + idev->baud = baudrate; + idev->new_baud = 0; + ret = 0; + } + } + + if (ret) + vlsi_reg_debug(iobase,__func__); + + return ret; +} + +static netdev_tx_t vlsi_hard_start_xmit(struct sk_buff *skb, + struct net_device *ndev) +{ + vlsi_irda_dev_t *idev = netdev_priv(ndev); + struct vlsi_ring *r = idev->tx_ring; + struct ring_descr *rd; + unsigned long flags; + unsigned iobase = ndev->base_addr; + u8 status; + u16 config; + int mtt, diff; + int len, speed; + char *msg = NULL; + + speed = irda_get_next_speed(skb); + spin_lock_irqsave(&idev->lock, flags); + if (speed != -1 && speed != idev->baud) { + netif_stop_queue(ndev); + idev->new_baud = speed; + status = RD_TX_CLRENTX; /* stop tx-ring after this frame */ + } + else + status = 0; + + if (skb->len == 0) { + /* handle zero packets - should be speed change */ + if (status == 0) { + msg = "bogus zero-length packet"; + goto drop_unlock; + } + + /* due to the completely asynch tx operation we might have + * IrLAP racing with the hardware here, f.e. if the controller + * is just sending the last packet with current speed while + * the LAP is already switching the speed using synchronous + * len=0 packet. Immediate execution would lead to hw lockup + * requiring a powercycle to reset. Good candidate to trigger + * this is the final UA:RSP packet after receiving a DISC:CMD + * when getting the LAP down. + * Note that we are not protected by the queue_stop approach + * because the final UA:RSP arrives _without_ request to apply + * new-speed-after-this-packet - hence the driver doesn't know + * this was the last packet and doesn't stop the queue. So the + * forced switch to default speed from LAP gets through as fast + * as only some 10 usec later while the UA:RSP is still processed + * by the hardware and we would get screwed. + */ + + if (ring_first(idev->tx_ring) == NULL) { + /* no race - tx-ring already empty */ + vlsi_set_baud(idev, iobase); + netif_wake_queue(ndev); + } + else + ; + /* keep the speed change pending like it would + * for any len>0 packet. tx completion interrupt + * will apply it when the tx ring becomes empty. + */ + spin_unlock_irqrestore(&idev->lock, flags); + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + + /* sanity checks - simply drop the packet */ + + rd = ring_last(r); + if (!rd) { + msg = "ring full, but queue wasn't stopped"; + goto drop_unlock; + } + + if (rd_is_active(rd)) { + msg = "entry still owned by hw"; + goto drop_unlock; + } + + if (!rd->buf) { + msg = "tx ring entry without pci buffer"; + goto drop_unlock; + } + + if (rd->skb) { + msg = "ring entry with old skb still attached"; + goto drop_unlock; + } + + /* no need for serialization or interrupt disable during mtt */ + spin_unlock_irqrestore(&idev->lock, flags); + + if ((mtt = irda_get_mtt(skb)) > 0) { + diff = ktime_us_delta(ktime_get(), idev->last_rx); + if (mtt > diff) + udelay(mtt - diff); + /* must not sleep here - called under netif_tx_lock! */ + } + + /* tx buffer already owned by CPU due to pci_dma_sync_single_for_cpu() + * after subsequent tx-completion + */ + + if (idev->mode == IFF_SIR) { + status |= RD_TX_DISCRC; /* no hw-crc creation */ + len = async_wrap_skb(skb, rd->buf, r->len); + + /* Some rare worst case situation in SIR mode might lead to + * potential buffer overflow. The wrapper detects this, returns + * with a shortened frame (without FCS/EOF) but doesn't provide + * any error indication about the invalid packet which we are + * going to transmit. + * Therefore we log if the buffer got filled to the point, where the + * wrapper would abort, i.e. when there are less than 5 bytes left to + * allow appending the FCS/EOF. + */ + + if (len >= r->len-5) + net_warn_ratelimited("%s: possible buffer overflow with SIR wrapping!\n", + __func__); + } + else { + /* hw deals with MIR/FIR mode wrapping */ + status |= RD_TX_PULSE; /* send 2 us highspeed indication pulse */ + len = skb->len; + if (len > r->len) { + msg = "frame exceeds tx buffer length"; + goto drop; + } + else + skb_copy_from_linear_data(skb, rd->buf, len); + } + + rd->skb = skb; /* remember skb for tx-complete stats */ + + rd_set_count(rd, len); + rd_set_status(rd, status); /* not yet active! */ + + /* give dma buffer back to busmaster-hw (flush caches to make + * CPU-driven changes visible from the pci bus). + */ + + pci_dma_sync_single_for_device(r->pdev, rd_get_addr(rd), r->len, r->dir); + +/* Switching to TX mode here races with the controller + * which may stop TX at any time when fetching an inactive descriptor + * or one with CLR_ENTX set. So we switch on TX only, if TX was not running + * _after_ the new descriptor was activated on the ring. This ensures + * we will either find TX already stopped or we can be sure, there + * will be a TX-complete interrupt even if the chip stopped doing + * TX just after we found it still running. The ISR will then find + * the non-empty ring and restart TX processing. The enclosing + * spinlock provides the correct serialization to prevent race with isr. + */ + + spin_lock_irqsave(&idev->lock,flags); + + rd_activate(rd); + + if (!(inw(iobase+VLSI_PIO_IRENABLE) & IRENABLE_ENTXST)) { + int fifocnt; + + fifocnt = inw(ndev->base_addr+VLSI_PIO_RCVBCNT) & RCVBCNT_MASK; + if (fifocnt != 0) { + pr_debug("%s: rx fifo not empty(%d)\n", + __func__, fifocnt); + } + + config = inw(iobase+VLSI_PIO_IRCFG); + mb(); + outw(config | IRCFG_ENTX, iobase+VLSI_PIO_IRCFG); + wmb(); + outw(0, iobase+VLSI_PIO_PROMPT); + } + + if (ring_put(r) == NULL) { + netif_stop_queue(ndev); + pr_debug("%s: tx ring full - queue stopped\n", __func__); + } + spin_unlock_irqrestore(&idev->lock, flags); + + return NETDEV_TX_OK; + +drop_unlock: + spin_unlock_irqrestore(&idev->lock, flags); +drop: + net_warn_ratelimited("%s: dropping packet - %s\n", __func__, msg); + dev_kfree_skb_any(skb); + ndev->stats.tx_errors++; + ndev->stats.tx_dropped++; + /* Don't even think about returning NET_XMIT_DROP (=1) here! + * In fact any retval!=0 causes the packet scheduler to requeue the + * packet for later retry of transmission - which isn't exactly + * what we want after we've just called dev_kfree_skb_any ;-) + */ + return NETDEV_TX_OK; +} + +static void vlsi_tx_interrupt(struct net_device *ndev) +{ + vlsi_irda_dev_t *idev = netdev_priv(ndev); + struct vlsi_ring *r = idev->tx_ring; + struct ring_descr *rd; + unsigned iobase; + int ret; + u16 config; + + for (rd = ring_first(r); rd != NULL; rd = ring_get(r)) { + + if (rd_is_active(rd)) + break; + + ret = vlsi_process_tx(r, rd); + + if (ret < 0) { + ret = -ret; + ndev->stats.tx_errors++; + if (ret & VLSI_TX_DROP) + ndev->stats.tx_dropped++; + if (ret & VLSI_TX_FIFO) + ndev->stats.tx_fifo_errors++; + } + else if (ret > 0){ + ndev->stats.tx_packets++; + ndev->stats.tx_bytes += ret; + } + } + + iobase = ndev->base_addr; + + if (idev->new_baud && rd == NULL) /* tx ring empty and speed change pending */ + vlsi_set_baud(idev, iobase); + + config = inw(iobase+VLSI_PIO_IRCFG); + if (rd == NULL) /* tx ring empty: re-enable rx */ + outw((config & ~IRCFG_ENTX) | IRCFG_ENRX, iobase+VLSI_PIO_IRCFG); + + else if (!(inw(iobase+VLSI_PIO_IRENABLE) & IRENABLE_ENTXST)) { + int fifocnt; + + fifocnt = inw(iobase+VLSI_PIO_RCVBCNT) & RCVBCNT_MASK; + if (fifocnt != 0) { + pr_debug("%s: rx fifo not empty(%d)\n", + __func__, fifocnt); + } + outw(config | IRCFG_ENTX, iobase+VLSI_PIO_IRCFG); + } + + outw(0, iobase+VLSI_PIO_PROMPT); + + if (netif_queue_stopped(ndev) && !idev->new_baud) { + netif_wake_queue(ndev); + pr_debug("%s: queue awoken\n", __func__); + } +} + +/* caller must have stopped the controller from busmastering */ + +static void vlsi_unarm_tx(vlsi_irda_dev_t *idev) +{ + struct net_device *ndev = pci_get_drvdata(idev->pdev); + struct vlsi_ring *r = idev->tx_ring; + struct ring_descr *rd; + int ret; + + for (rd = ring_first(r); rd != NULL; rd = ring_get(r)) { + + ret = 0; + if (rd_is_active(rd)) { + rd_set_status(rd, 0); + rd_set_count(rd, 0); + pci_dma_sync_single_for_cpu(r->pdev, rd_get_addr(rd), r->len, r->dir); + if (rd->skb) { + dev_kfree_skb_any(rd->skb); + rd->skb = NULL; + } + pr_debug("%s - dropping tx packet\n", __func__); + ret = -VLSI_TX_DROP; + } + else + ret = vlsi_process_tx(r, rd); + + if (ret < 0) { + ret = -ret; + ndev->stats.tx_errors++; + if (ret & VLSI_TX_DROP) + ndev->stats.tx_dropped++; + if (ret & VLSI_TX_FIFO) + ndev->stats.tx_fifo_errors++; + } + else if (ret > 0){ + ndev->stats.tx_packets++; + ndev->stats.tx_bytes += ret; + } + } + +} + +/********************************************************/ + +static int vlsi_start_clock(struct pci_dev *pdev) +{ + u8 clkctl, lock; + int i, count; + + if (clksrc < 2) { /* auto or PLL: try PLL */ + clkctl = CLKCTL_PD_INV | CLKCTL_CLKSTP; + pci_write_config_byte(pdev, VLSI_PCI_CLKCTL, clkctl); + + /* procedure to detect PLL lock synchronisation: + * after 0.5 msec initial delay we expect to find 3 PLL lock + * indications within 10 msec for successful PLL detection. + */ + udelay(500); + count = 0; + for (i = 500; i <= 10000; i += 50) { /* max 10 msec */ + pci_read_config_byte(pdev, VLSI_PCI_CLKCTL, &lock); + if (lock&CLKCTL_LOCK) { + if (++count >= 3) + break; + } + udelay(50); + } + if (count < 3) { + if (clksrc == 1) { /* explicitly asked for PLL hence bail out */ + net_err_ratelimited("%s: no PLL or failed to lock!\n", + __func__); + clkctl = CLKCTL_CLKSTP; + pci_write_config_byte(pdev, VLSI_PCI_CLKCTL, clkctl); + return -1; + } + else /* was: clksrc=0(auto) */ + clksrc = 3; /* fallback to 40MHz XCLK (OB800) */ + + pr_debug("%s: PLL not locked, fallback to clksrc=%d\n", + __func__, clksrc); + } + else + clksrc = 1; /* got successful PLL lock */ + } + + if (clksrc != 1) { + /* we get here if either no PLL detected in auto-mode or + an external clock source was explicitly specified */ + + clkctl = CLKCTL_EXTCLK | CLKCTL_CLKSTP; + if (clksrc == 3) + clkctl |= CLKCTL_XCKSEL; + pci_write_config_byte(pdev, VLSI_PCI_CLKCTL, clkctl); + + /* no way to test for working XCLK */ + } + else + pci_read_config_byte(pdev, VLSI_PCI_CLKCTL, &clkctl); + + /* ok, now going to connect the chip with the clock source */ + + clkctl &= ~CLKCTL_CLKSTP; + pci_write_config_byte(pdev, VLSI_PCI_CLKCTL, clkctl); + + return 0; +} + +static void vlsi_stop_clock(struct pci_dev *pdev) +{ + u8 clkctl; + + /* disconnect chip from clock source */ + pci_read_config_byte(pdev, VLSI_PCI_CLKCTL, &clkctl); + clkctl |= CLKCTL_CLKSTP; + pci_write_config_byte(pdev, VLSI_PCI_CLKCTL, clkctl); + + /* disable all clock sources */ + clkctl &= ~(CLKCTL_EXTCLK | CLKCTL_PD_INV); + pci_write_config_byte(pdev, VLSI_PCI_CLKCTL, clkctl); +} + +/********************************************************/ + +/* writing all-zero to the VLSI PCI IO register area seems to prevent + * some occasional situations where the hardware fails (symptoms are + * what appears as stalled tx/rx state machines, i.e. everything ok for + * receive or transmit but hw makes no progress or is unable to access + * the bus memory locations). + * Best place to call this is immediately after/before the internal clock + * gets started/stopped. + */ + +static inline void vlsi_clear_regs(unsigned iobase) +{ + unsigned i; + const unsigned chip_io_extent = 32; + + for (i = 0; i < chip_io_extent; i += sizeof(u16)) + outw(0, iobase + i); +} + +static int vlsi_init_chip(struct pci_dev *pdev) +{ + struct net_device *ndev = pci_get_drvdata(pdev); + vlsi_irda_dev_t *idev = netdev_priv(ndev); + unsigned iobase; + u16 ptr; + + /* start the clock and clean the registers */ + + if (vlsi_start_clock(pdev)) { + net_err_ratelimited("%s: no valid clock source\n", __func__); + return -1; + } + iobase = ndev->base_addr; + vlsi_clear_regs(iobase); + + outb(IRINTR_INT_MASK, iobase+VLSI_PIO_IRINTR); /* w/c pending IRQ, disable all INT */ + + outw(0, iobase+VLSI_PIO_IRENABLE); /* disable IrPHY-interface */ + + /* disable everything, particularly IRCFG_MSTR - (also resetting the RING_PTR) */ + + outw(0, iobase+VLSI_PIO_IRCFG); + wmb(); + + outw(MAX_PACKET_LENGTH, iobase+VLSI_PIO_MAXPKT); /* max possible value=0x0fff */ + + outw(BUS_TO_RINGBASE(idev->busaddr), iobase+VLSI_PIO_RINGBASE); + + outw(TX_RX_TO_RINGSIZE(idev->tx_ring->size, idev->rx_ring->size), + iobase+VLSI_PIO_RINGSIZE); + + ptr = inw(iobase+VLSI_PIO_RINGPTR); + atomic_set(&idev->rx_ring->head, RINGPTR_GET_RX(ptr)); + atomic_set(&idev->rx_ring->tail, RINGPTR_GET_RX(ptr)); + atomic_set(&idev->tx_ring->head, RINGPTR_GET_TX(ptr)); + atomic_set(&idev->tx_ring->tail, RINGPTR_GET_TX(ptr)); + + vlsi_set_baud(idev, iobase); /* idev->new_baud used as provided by caller */ + + outb(IRINTR_INT_MASK, iobase+VLSI_PIO_IRINTR); /* just in case - w/c pending IRQ's */ + wmb(); + + /* DO NOT BLINDLY ENABLE IRINTR_ACTEN! + * basically every received pulse fires an ACTIVITY-INT + * leading to >>1000 INT's per second instead of few 10 + */ + + outb(IRINTR_RPKTEN|IRINTR_TPKTEN, iobase+VLSI_PIO_IRINTR); + + return 0; +} + +static int vlsi_start_hw(vlsi_irda_dev_t *idev) +{ + struct pci_dev *pdev = idev->pdev; + struct net_device *ndev = pci_get_drvdata(pdev); + unsigned iobase = ndev->base_addr; + u8 byte; + + /* we don't use the legacy UART, disable its address decoding */ + + pci_read_config_byte(pdev, VLSI_PCI_IRMISC, &byte); + byte &= ~(IRMISC_UARTEN | IRMISC_UARTTST); + pci_write_config_byte(pdev, VLSI_PCI_IRMISC, byte); + + /* enable PCI busmaster access to our 16MB page */ + + pci_write_config_byte(pdev, VLSI_PCI_MSTRPAGE, MSTRPAGE_VALUE); + pci_set_master(pdev); + + if (vlsi_init_chip(pdev) < 0) { + pci_disable_device(pdev); + return -1; + } + + vlsi_fill_rx(idev->rx_ring); + + idev->last_rx = ktime_get(); /* first mtt may start from now on */ + + outw(0, iobase+VLSI_PIO_PROMPT); /* kick hw state machine */ + + return 0; +} + +static int vlsi_stop_hw(vlsi_irda_dev_t *idev) +{ + struct pci_dev *pdev = idev->pdev; + struct net_device *ndev = pci_get_drvdata(pdev); + unsigned iobase = ndev->base_addr; + unsigned long flags; + + spin_lock_irqsave(&idev->lock,flags); + outw(0, iobase+VLSI_PIO_IRENABLE); + outw(0, iobase+VLSI_PIO_IRCFG); /* disable everything */ + + /* disable and w/c irqs */ + outb(0, iobase+VLSI_PIO_IRINTR); + wmb(); + outb(IRINTR_INT_MASK, iobase+VLSI_PIO_IRINTR); + spin_unlock_irqrestore(&idev->lock,flags); + + vlsi_unarm_tx(idev); + vlsi_unarm_rx(idev); + + vlsi_clear_regs(iobase); + vlsi_stop_clock(pdev); + + pci_disable_device(pdev); + + return 0; +} + +/**************************************************************/ + +static void vlsi_tx_timeout(struct net_device *ndev) +{ + vlsi_irda_dev_t *idev = netdev_priv(ndev); + + + vlsi_reg_debug(ndev->base_addr, __func__); + vlsi_ring_debug(idev->tx_ring); + + if (netif_running(ndev)) + netif_stop_queue(ndev); + + vlsi_stop_hw(idev); + + /* now simply restart the whole thing */ + + if (!idev->new_baud) + idev->new_baud = idev->baud; /* keep current baudrate */ + + if (vlsi_start_hw(idev)) + net_err_ratelimited("%s: failed to restart hw - %s(%s) unusable!\n", + __func__, pci_name(idev->pdev), ndev->name); + else + netif_start_queue(ndev); +} + +static int vlsi_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) +{ + vlsi_irda_dev_t *idev = netdev_priv(ndev); + struct if_irda_req *irq = (struct if_irda_req *) rq; + unsigned long flags; + u16 fifocnt; + int ret = 0; + + switch (cmd) { + case SIOCSBANDWIDTH: + if (!capable(CAP_NET_ADMIN)) { + ret = -EPERM; + break; + } + spin_lock_irqsave(&idev->lock, flags); + idev->new_baud = irq->ifr_baudrate; + /* when called from userland there might be a minor race window here + * if the stack tries to change speed concurrently - which would be + * pretty strange anyway with the userland having full control... + */ + vlsi_set_baud(idev, ndev->base_addr); + spin_unlock_irqrestore(&idev->lock, flags); + break; + case SIOCSMEDIABUSY: + if (!capable(CAP_NET_ADMIN)) { + ret = -EPERM; + break; + } + irda_device_set_media_busy(ndev, TRUE); + break; + case SIOCGRECEIVING: + /* the best we can do: check whether there are any bytes in rx fifo. + * The trustable window (in case some data arrives just afterwards) + * may be as short as 1usec or so at 4Mbps. + */ + fifocnt = inw(ndev->base_addr+VLSI_PIO_RCVBCNT) & RCVBCNT_MASK; + irq->ifr_receiving = (fifocnt!=0) ? 1 : 0; + break; + default: + net_warn_ratelimited("%s: notsupp - cmd=%04x\n", + __func__, cmd); + ret = -EOPNOTSUPP; + } + + return ret; +} + +/********************************************************/ + +static irqreturn_t vlsi_interrupt(int irq, void *dev_instance) +{ + struct net_device *ndev = dev_instance; + vlsi_irda_dev_t *idev = netdev_priv(ndev); + unsigned iobase; + u8 irintr; + int boguscount = 5; + unsigned long flags; + int handled = 0; + + iobase = ndev->base_addr; + spin_lock_irqsave(&idev->lock,flags); + do { + irintr = inb(iobase+VLSI_PIO_IRINTR); + mb(); + outb(irintr, iobase+VLSI_PIO_IRINTR); /* acknowledge asap */ + + if (!(irintr&=IRINTR_INT_MASK)) /* not our INT - probably shared */ + break; + + handled = 1; + + if (unlikely(!(irintr & ~IRINTR_ACTIVITY))) + break; /* nothing todo if only activity */ + + if (irintr&IRINTR_RPKTINT) + vlsi_rx_interrupt(ndev); + + if (irintr&IRINTR_TPKTINT) + vlsi_tx_interrupt(ndev); + + } while (--boguscount > 0); + spin_unlock_irqrestore(&idev->lock,flags); + + if (boguscount <= 0) + net_info_ratelimited("%s: too much work in interrupt!\n", + __func__); + return IRQ_RETVAL(handled); +} + +/********************************************************/ + +static int vlsi_open(struct net_device *ndev) +{ + vlsi_irda_dev_t *idev = netdev_priv(ndev); + int err = -EAGAIN; + char hwname[32]; + + if (pci_request_regions(idev->pdev, drivername)) { + net_warn_ratelimited("%s: io resource busy\n", __func__); + goto errout; + } + ndev->base_addr = pci_resource_start(idev->pdev,0); + ndev->irq = idev->pdev->irq; + + /* under some rare occasions the chip apparently comes up with + * IRQ's pending. We better w/c pending IRQ and disable them all + */ + + outb(IRINTR_INT_MASK, ndev->base_addr+VLSI_PIO_IRINTR); + + if (request_irq(ndev->irq, vlsi_interrupt, IRQF_SHARED, + drivername, ndev)) { + net_warn_ratelimited("%s: couldn't get IRQ: %d\n", + __func__, ndev->irq); + goto errout_io; + } + + if ((err = vlsi_create_hwif(idev)) != 0) + goto errout_irq; + + sprintf(hwname, "VLSI-FIR @ 0x%04x", (unsigned)ndev->base_addr); + idev->irlap = irlap_open(ndev,&idev->qos,hwname); + if (!idev->irlap) + goto errout_free_ring; + + idev->last_rx = ktime_get(); /* first mtt may start from now on */ + + idev->new_baud = 9600; /* start with IrPHY using 9600(SIR) mode */ + + if ((err = vlsi_start_hw(idev)) != 0) + goto errout_close_irlap; + + netif_start_queue(ndev); + + net_info_ratelimited("%s: device %s operational\n", + __func__, ndev->name); + + return 0; + +errout_close_irlap: + irlap_close(idev->irlap); +errout_free_ring: + vlsi_destroy_hwif(idev); +errout_irq: + free_irq(ndev->irq,ndev); +errout_io: + pci_release_regions(idev->pdev); +errout: + return err; +} + +static int vlsi_close(struct net_device *ndev) +{ + vlsi_irda_dev_t *idev = netdev_priv(ndev); + + netif_stop_queue(ndev); + + if (idev->irlap) + irlap_close(idev->irlap); + idev->irlap = NULL; + + vlsi_stop_hw(idev); + + vlsi_destroy_hwif(idev); + + free_irq(ndev->irq,ndev); + + pci_release_regions(idev->pdev); + + net_info_ratelimited("%s: device %s stopped\n", __func__, ndev->name); + + return 0; +} + +static const struct net_device_ops vlsi_netdev_ops = { + .ndo_open = vlsi_open, + .ndo_stop = vlsi_close, + .ndo_start_xmit = vlsi_hard_start_xmit, + .ndo_do_ioctl = vlsi_ioctl, + .ndo_tx_timeout = vlsi_tx_timeout, +}; + +static int vlsi_irda_init(struct net_device *ndev) +{ + vlsi_irda_dev_t *idev = netdev_priv(ndev); + struct pci_dev *pdev = idev->pdev; + + ndev->irq = pdev->irq; + ndev->base_addr = pci_resource_start(pdev,0); + + /* PCI busmastering + * see include file for details why we need these 2 masks, in this order! + */ + + if (pci_set_dma_mask(pdev,DMA_MASK_USED_BY_HW) || + pci_set_dma_mask(pdev,DMA_MASK_MSTRPAGE)) { + net_err_ratelimited("%s: aborting due to PCI BM-DMA address limitations\n", + __func__); + return -1; + } + + irda_init_max_qos_capabilies(&idev->qos); + + /* the VLSI82C147 does not support 576000! */ + + idev->qos.baud_rate.bits = IR_2400 | IR_9600 + | IR_19200 | IR_38400 | IR_57600 | IR_115200 + | IR_1152000 | (IR_4000000 << 8); + + idev->qos.min_turn_time.bits = qos_mtt_bits; + + irda_qos_bits_to_value(&idev->qos); + + /* currently no public media definitions for IrDA */ + + ndev->flags |= IFF_PORTSEL | IFF_AUTOMEDIA; + ndev->if_port = IF_PORT_UNKNOWN; + + ndev->netdev_ops = &vlsi_netdev_ops; + ndev->watchdog_timeo = 500*HZ/1000; /* max. allowed turn time for IrLAP */ + + SET_NETDEV_DEV(ndev, &pdev->dev); + + return 0; +} + +/**************************************************************/ + +static int +vlsi_irda_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct net_device *ndev; + vlsi_irda_dev_t *idev; + + if (pci_enable_device(pdev)) + goto out; + else + pdev->current_state = 0; /* hw must be running now */ + + net_info_ratelimited("%s: IrDA PCI controller %s detected\n", + drivername, pci_name(pdev)); + + if ( !pci_resource_start(pdev,0) || + !(pci_resource_flags(pdev,0) & IORESOURCE_IO) ) { + net_err_ratelimited("%s: bar 0 invalid", __func__); + goto out_disable; + } + + ndev = alloc_irdadev(sizeof(*idev)); + if (ndev==NULL) { + net_err_ratelimited("%s: Unable to allocate device memory.\n", + __func__); + goto out_disable; + } + + idev = netdev_priv(ndev); + + spin_lock_init(&idev->lock); + mutex_init(&idev->mtx); + mutex_lock(&idev->mtx); + idev->pdev = pdev; + + if (vlsi_irda_init(ndev) < 0) + goto out_freedev; + + if (register_netdev(ndev) < 0) { + net_err_ratelimited("%s: register_netdev failed\n", __func__); + goto out_freedev; + } + + if (vlsi_proc_root != NULL) { + struct proc_dir_entry *ent; + + ent = proc_create_data(ndev->name, S_IFREG|S_IRUGO, + vlsi_proc_root, VLSI_PROC_FOPS, ndev); + if (!ent) { + net_warn_ratelimited("%s: failed to create proc entry\n", + __func__); + } else { + proc_set_size(ent, 0); + } + idev->proc_entry = ent; + } + net_info_ratelimited("%s: registered device %s\n", + drivername, ndev->name); + + pci_set_drvdata(pdev, ndev); + mutex_unlock(&idev->mtx); + + return 0; + +out_freedev: + mutex_unlock(&idev->mtx); + free_netdev(ndev); +out_disable: + pci_disable_device(pdev); +out: + return -ENODEV; +} + +static void vlsi_irda_remove(struct pci_dev *pdev) +{ + struct net_device *ndev = pci_get_drvdata(pdev); + vlsi_irda_dev_t *idev; + + if (!ndev) { + net_err_ratelimited("%s: lost netdevice?\n", drivername); + return; + } + + unregister_netdev(ndev); + + idev = netdev_priv(ndev); + mutex_lock(&idev->mtx); + if (idev->proc_entry) { + remove_proc_entry(ndev->name, vlsi_proc_root); + idev->proc_entry = NULL; + } + mutex_unlock(&idev->mtx); + + free_netdev(ndev); + + net_info_ratelimited("%s: %s removed\n", drivername, pci_name(pdev)); +} + +#ifdef CONFIG_PM + +/* The Controller doesn't provide PCI PM capabilities as defined by PCI specs. + * Some of the Linux PCI-PM code however depends on this, for example in + * pci_set_power_state(). So we have to take care to perform the required + * operations on our own (particularly reflecting the pdev->current_state) + * otherwise we might get cheated by pci-pm. + */ + + +static int vlsi_irda_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct net_device *ndev = pci_get_drvdata(pdev); + vlsi_irda_dev_t *idev; + + if (!ndev) { + net_err_ratelimited("%s - %s: no netdevice\n", + __func__, pci_name(pdev)); + return 0; + } + idev = netdev_priv(ndev); + mutex_lock(&idev->mtx); + if (pdev->current_state != 0) { /* already suspended */ + if (state.event > pdev->current_state) { /* simply go deeper */ + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + pdev->current_state = state.event; + } + else + net_err_ratelimited("%s - %s: invalid suspend request %u -> %u\n", + __func__, pci_name(pdev), + pdev->current_state, state.event); + mutex_unlock(&idev->mtx); + return 0; + } + + if (netif_running(ndev)) { + netif_device_detach(ndev); + vlsi_stop_hw(idev); + pci_save_state(pdev); + if (!idev->new_baud) + /* remember speed settings to restore on resume */ + idev->new_baud = idev->baud; + } + + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + pdev->current_state = state.event; + idev->resume_ok = 1; + mutex_unlock(&idev->mtx); + return 0; +} + +static int vlsi_irda_resume(struct pci_dev *pdev) +{ + struct net_device *ndev = pci_get_drvdata(pdev); + vlsi_irda_dev_t *idev; + + if (!ndev) { + net_err_ratelimited("%s - %s: no netdevice\n", + __func__, pci_name(pdev)); + return 0; + } + idev = netdev_priv(ndev); + mutex_lock(&idev->mtx); + if (pdev->current_state == 0) { + mutex_unlock(&idev->mtx); + net_warn_ratelimited("%s - %s: already resumed\n", + __func__, pci_name(pdev)); + return 0; + } + + pci_set_power_state(pdev, PCI_D0); + pdev->current_state = PM_EVENT_ON; + + if (!idev->resume_ok) { + /* should be obsolete now - but used to happen due to: + * - pci layer initially setting pdev->current_state = 4 (unknown) + * - pci layer did not walk the save_state-tree (might be APM problem) + * so we could not refuse to suspend from undefined state + * - vlsi_irda_suspend detected invalid state and refused to save + * configuration for resume - but was too late to stop suspending + * - vlsi_irda_resume got screwed when trying to resume from garbage + * + * now we explicitly set pdev->current_state = 0 after enabling the + * device and independently resume_ok should catch any garbage config. + */ + net_warn_ratelimited("%s - hm, nothing to resume?\n", __func__); + mutex_unlock(&idev->mtx); + return 0; + } + + if (netif_running(ndev)) { + pci_restore_state(pdev); + vlsi_start_hw(idev); + netif_device_attach(ndev); + } + idev->resume_ok = 0; + mutex_unlock(&idev->mtx); + return 0; +} + +#endif /* CONFIG_PM */ + +/*********************************************************/ + +static struct pci_driver vlsi_irda_driver = { + .name = drivername, + .id_table = vlsi_irda_table, + .probe = vlsi_irda_probe, + .remove = vlsi_irda_remove, +#ifdef CONFIG_PM + .suspend = vlsi_irda_suspend, + .resume = vlsi_irda_resume, +#endif +}; + +#define PROC_DIR ("driver/" DRIVER_NAME) + +static int __init vlsi_mod_init(void) +{ + int i, ret; + + if (clksrc < 0 || clksrc > 3) { + net_err_ratelimited("%s: invalid clksrc=%d\n", + drivername, clksrc); + return -1; + } + + for (i = 0; i < 2; i++) { + switch(ringsize[i]) { + case 4: + case 8: + case 16: + case 32: + case 64: + break; + default: + net_warn_ratelimited("%s: invalid %s ringsize %d, using default=8\n", + drivername, + i ? "rx" : "tx", + ringsize[i]); + ringsize[i] = 8; + break; + } + } + + sirpulse = !!sirpulse; + + /* proc_mkdir returns NULL if !CONFIG_PROC_FS. + * Failure to create the procfs entry is handled like running + * without procfs - it's not required for the driver to work. + */ + vlsi_proc_root = proc_mkdir(PROC_DIR, NULL); + + ret = pci_register_driver(&vlsi_irda_driver); + + if (ret && vlsi_proc_root) + remove_proc_entry(PROC_DIR, NULL); + return ret; + +} + +static void __exit vlsi_mod_exit(void) +{ + pci_unregister_driver(&vlsi_irda_driver); + if (vlsi_proc_root) + remove_proc_entry(PROC_DIR, NULL); +} + +module_init(vlsi_mod_init); +module_exit(vlsi_mod_exit); diff --git a/drivers/staging/irda/drivers/vlsi_ir.h b/drivers/staging/irda/drivers/vlsi_ir.h new file mode 100644 index 000000000000..f9db2ce4c5c6 --- /dev/null +++ b/drivers/staging/irda/drivers/vlsi_ir.h @@ -0,0 +1,757 @@ + +/********************************************************************* + * + * vlsi_ir.h: VLSI82C147 PCI IrDA controller driver for Linux + * + * Version: 0.5 + * + * Copyright (c) 2001-2003 Martin Diehl + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + ********************************************************************/ + +#ifndef IRDA_VLSI_FIR_H +#define IRDA_VLSI_FIR_H + +/* ================================================================ + * compatibility stuff + */ + +/* definitions not present in pci_ids.h */ + +#ifndef PCI_CLASS_WIRELESS_IRDA +#define PCI_CLASS_WIRELESS_IRDA 0x0d00 +#endif + +#ifndef PCI_CLASS_SUBCLASS_MASK +#define PCI_CLASS_SUBCLASS_MASK 0xffff +#endif + +/* ================================================================ */ + +/* non-standard PCI registers */ + +enum vlsi_pci_regs { + VLSI_PCI_CLKCTL = 0x40, /* chip clock input control */ + VLSI_PCI_MSTRPAGE = 0x41, /* addr [31:24] for all busmaster cycles */ + VLSI_PCI_IRMISC = 0x42 /* mainly legacy UART related */ +}; + +/* ------------------------------------------ */ + +/* VLSI_PCI_CLKCTL: Clock Control Register (u8, rw) */ + +/* Three possible clock sources: either on-chip 48MHz PLL or + * external clock applied to EXTCLK pin. External clock may + * be either 48MHz or 40MHz, which is indicated by XCKSEL. + * CLKSTP controls whether the selected clock source gets + * connected to the IrDA block. + * + * On my HP OB-800 the BIOS sets external 40MHz clock as source + * when IrDA enabled and I've never detected any PLL lock success. + * Apparently the 14.3...MHz OSC input required for the PLL to work + * is not connected and the 40MHz EXTCLK is provided externally. + * At least this is what makes the driver working for me. + */ + +enum vlsi_pci_clkctl { + + /* PLL control */ + + CLKCTL_PD_INV = 0x04, /* PD#: inverted power down signal, + * i.e. PLL is powered, if PD_INV set */ + CLKCTL_LOCK = 0x40, /* (ro) set, if PLL is locked */ + + /* clock source selection */ + + CLKCTL_EXTCLK = 0x20, /* set to select external clock input, not PLL */ + CLKCTL_XCKSEL = 0x10, /* set to indicate EXTCLK is 40MHz, not 48MHz */ + + /* IrDA block control */ + + CLKCTL_CLKSTP = 0x80, /* set to disconnect from selected clock source */ + CLKCTL_WAKE = 0x08 /* set to enable wakeup feature: whenever IR activity + * is detected, PD_INV gets set(?) and CLKSTP cleared */ +}; + +/* ------------------------------------------ */ + +/* VLSI_PCI_MSTRPAGE: Master Page Register (u8, rw) and busmastering stuff */ + +#define DMA_MASK_USED_BY_HW 0xffffffff +#define DMA_MASK_MSTRPAGE 0x00ffffff +#define MSTRPAGE_VALUE (DMA_MASK_MSTRPAGE >> 24) + + /* PCI busmastering is somewhat special for this guy - in short: + * + * We select to operate using fixed MSTRPAGE=0, use ISA DMA + * address restrictions to make the PCI BM api aware of this, + * but ensure the hardware is dealing with real 32bit access. + * + * In detail: + * The chip executes normal 32bit busmaster cycles, i.e. + * drives all 32 address lines. These addresses however are + * composed of [0:23] taken from various busaddr-pointers + * and [24:31] taken from the MSTRPAGE register in the VLSI82C147 + * config space. Therefore _all_ busmastering must be + * targeted to/from one single 16MB (busaddr-) superpage! + * The point is to make sure all the allocations for memory + * locations with busmaster access (ring descriptors, buffers) + * are indeed bus-mappable to the same 16MB range (for x86 this + * means they must reside in the same 16MB physical memory address + * range). The only constraint we have which supports "several objects + * mappable to common 16MB range" paradigma, is the old ISA DMA + * restriction to the first 16MB of physical address range. + * Hence the approach here is to enable PCI busmaster support using + * the correct 32bit dma-mask used by the chip. Afterwards the device's + * dma-mask gets restricted to 24bit, which must be honoured somehow by + * all allocations for memory areas to be exposed to the chip ... + * + * Note: + * Don't be surprised to get "Setting latency timer..." messages every + * time when PCI busmastering is enabled for the chip. + * The chip has its PCI latency timer RO fixed at 0 - which is not a + * problem here, because it is never requesting _burst_ transactions. + */ + +/* ------------------------------------------ */ + +/* VLSI_PCIIRMISC: IR Miscellaneous Register (u8, rw) */ + +/* legacy UART emulation - not used by this driver - would require: + * (see below for some register-value definitions) + * + * - IRMISC_UARTEN must be set to enable UART address decoding + * - IRMISC_UARTSEL configured + * - IRCFG_MASTER must be cleared + * - IRCFG_SIR must be set + * - IRENABLE_PHYANDCLOCK must be asserted 0->1 (and hence IRENABLE_SIR_ON) + */ + +enum vlsi_pci_irmisc { + + /* IR transceiver control */ + + IRMISC_IRRAIL = 0x40, /* (ro?) IR rail power indication (and control?) + * 0=3.3V / 1=5V. Probably set during power-on? + * unclear - not touched by driver */ + IRMISC_IRPD = 0x08, /* transceiver power down, if set */ + + /* legacy UART control */ + + IRMISC_UARTTST = 0x80, /* UART test mode - "always write 0" */ + IRMISC_UARTEN = 0x04, /* enable UART address decoding */ + + /* bits [1:0] IRMISC_UARTSEL to select legacy UART address */ + + IRMISC_UARTSEL_3f8 = 0x00, + IRMISC_UARTSEL_2f8 = 0x01, + IRMISC_UARTSEL_3e8 = 0x02, + IRMISC_UARTSEL_2e8 = 0x03 +}; + +/* ================================================================ */ + +/* registers mapped to 32 byte PCI IO space */ + +/* note: better access all registers at the indicated u8/u16 size + * although some of them contain only 1 byte of information. + * some of them (particaluarly PROMPT and IRCFG) ignore + * access when using the wrong addressing mode! + */ + +enum vlsi_pio_regs { + VLSI_PIO_IRINTR = 0x00, /* interrupt enable/request (u8, rw) */ + VLSI_PIO_RINGPTR = 0x02, /* rx/tx ring pointer (u16, ro) */ + VLSI_PIO_RINGBASE = 0x04, /* [23:10] of ring address (u16, rw) */ + VLSI_PIO_RINGSIZE = 0x06, /* rx/tx ring size (u16, rw) */ + VLSI_PIO_PROMPT = 0x08, /* triggers ring processing (u16, wo) */ + /* 0x0a-0x0f: reserved / duplicated UART regs */ + VLSI_PIO_IRCFG = 0x10, /* configuration select (u16, rw) */ + VLSI_PIO_SIRFLAG = 0x12, /* BOF/EOF for filtered SIR (u16, ro) */ + VLSI_PIO_IRENABLE = 0x14, /* enable and status register (u16, rw/ro) */ + VLSI_PIO_PHYCTL = 0x16, /* physical layer current status (u16, ro) */ + VLSI_PIO_NPHYCTL = 0x18, /* next physical layer select (u16, rw) */ + VLSI_PIO_MAXPKT = 0x1a, /* [11:0] max len for packet receive (u16, rw) */ + VLSI_PIO_RCVBCNT = 0x1c /* current receive-FIFO byte count (u16, ro) */ + /* 0x1e-0x1f: reserved / duplicated UART regs */ +}; + +/* ------------------------------------------ */ + +/* VLSI_PIO_IRINTR: Interrupt Register (u8, rw) */ + +/* enable-bits: + * 1 = enable / 0 = disable + * interrupt condition bits: + * set according to corresponding interrupt source + * (regardless of the state of the enable bits) + * enable bit status indicates whether interrupt gets raised + * write-to-clear + * note: RPKTINT and TPKTINT behave different in legacy UART mode (which we don't use :-) + */ + +enum vlsi_pio_irintr { + IRINTR_ACTEN = 0x80, /* activity interrupt enable */ + IRINTR_ACTIVITY = 0x40, /* activity monitor (traffic detected) */ + IRINTR_RPKTEN = 0x20, /* receive packet interrupt enable*/ + IRINTR_RPKTINT = 0x10, /* rx-packet transferred from fifo to memory finished */ + IRINTR_TPKTEN = 0x08, /* transmit packet interrupt enable */ + IRINTR_TPKTINT = 0x04, /* last bit of tx-packet+crc shifted to ir-pulser */ + IRINTR_OE_EN = 0x02, /* UART rx fifo overrun error interrupt enable */ + IRINTR_OE_INT = 0x01 /* UART rx fifo overrun error (read LSR to clear) */ +}; + +/* we use this mask to check whether the (shared PCI) interrupt is ours */ + +#define IRINTR_INT_MASK (IRINTR_ACTIVITY|IRINTR_RPKTINT|IRINTR_TPKTINT) + +/* ------------------------------------------ */ + +/* VLSI_PIO_RINGPTR: Ring Pointer Read-Back Register (u16, ro) */ + +/* _both_ ring pointers are indices relative to the _entire_ rx,tx-ring! + * i.e. the referenced descriptor is located + * at RINGBASE + PTR * sizeof(descr) for rx and tx + * therefore, the tx-pointer has offset MAX_RING_DESCR + */ + +#define MAX_RING_DESCR 64 /* tx, rx rings may contain up to 64 descr each */ + +#define RINGPTR_RX_MASK (MAX_RING_DESCR-1) +#define RINGPTR_TX_MASK ((MAX_RING_DESCR-1)<<8) + +#define RINGPTR_GET_RX(p) ((p)&RINGPTR_RX_MASK) +#define RINGPTR_GET_TX(p) (((p)&RINGPTR_TX_MASK)>>8) + +/* ------------------------------------------ */ + +/* VLSI_PIO_RINGBASE: Ring Pointer Base Address Register (u16, ro) */ + +/* Contains [23:10] part of the ring base (bus-) address + * which must be 1k-alinged. [31:24] is taken from + * VLSI_PCI_MSTRPAGE above. + * The controller initiates non-burst PCI BM cycles to + * fetch and update the descriptors in the ring. + * Once fetched, the descriptor remains cached onchip + * until it gets closed and updated due to the ring + * processing state machine. + * The entire ring area is split in rx and tx areas with each + * area consisting of 64 descriptors of 8 bytes each. + * The rx(tx) ring is located at ringbase+0 (ringbase+64*8). + */ + +#define BUS_TO_RINGBASE(p) (((p)>>10)&0x3fff) + +/* ------------------------------------------ */ + +/* VLSI_PIO_RINGSIZE: Ring Size Register (u16, rw) */ + +/* bit mask to indicate the ring size to be used for rx and tx. + * possible values encoded bits + * 4 0000 + * 8 0001 + * 16 0011 + * 32 0111 + * 64 1111 + * located at [15:12] for tx and [11:8] for rx ([7:0] unused) + * + * note: probably a good idea to have IRCFG_MSTR cleared when writing + * this so the state machines are stopped and the RINGPTR is reset! + */ + +#define SIZE_TO_BITS(num) ((((num)-1)>>2)&0x0f) +#define TX_RX_TO_RINGSIZE(tx,rx) ((SIZE_TO_BITS(tx)<<12)|(SIZE_TO_BITS(rx)<<8)) +#define RINGSIZE_TO_RXSIZE(rs) ((((rs)&0x0f00)>>6)+4) +#define RINGSIZE_TO_TXSIZE(rs) ((((rs)&0xf000)>>10)+4) + + +/* ------------------------------------------ */ + +/* VLSI_PIO_PROMPT: Ring Prompting Register (u16, write-to-start) */ + +/* writing any value kicks the ring processing state machines + * for both tx, rx rings as follows: + * - active rings (currently owning an active descriptor) + * ignore the prompt and continue + * - idle rings fetch the next descr from the ring and start + * their processing + */ + +/* ------------------------------------------ */ + +/* VLSI_PIO_IRCFG: IR Config Register (u16, rw) */ + +/* notes: + * - not more than one SIR/MIR/FIR bit must be set at any time + * - SIR, MIR, FIR and CRC16 select the configuration which will + * be applied on next 0->1 transition of IRENABLE_PHYANDCLOCK (see below). + * - besides allowing the PCI interface to execute busmaster cycles + * and therefore the ring SM to operate, the MSTR bit has side-effects: + * when MSTR is cleared, the RINGPTR's get reset and the legacy UART mode + * (in contrast to busmaster access mode) gets enabled. + * - clearing ENRX or setting ENTX while data is received may stall the + * receive fifo until ENRX reenabled _and_ another packet arrives + * - SIRFILT means the chip performs the required unwrapping of hardware + * headers (XBOF's, BOF/EOF) and un-escaping in the _receive_ direction. + * Only the resulting IrLAP payload is copied to the receive buffers - + * but with the 16bit FCS still encluded. Question remains, whether it + * was already checked or we should do it before passing the packet to IrLAP? + */ + +enum vlsi_pio_ircfg { + IRCFG_LOOP = 0x4000, /* enable loopback test mode */ + IRCFG_ENTX = 0x1000, /* transmit enable */ + IRCFG_ENRX = 0x0800, /* receive enable */ + IRCFG_MSTR = 0x0400, /* master enable */ + IRCFG_RXANY = 0x0200, /* receive any packet */ + IRCFG_CRC16 = 0x0080, /* 16bit (not 32bit) CRC select for MIR/FIR */ + IRCFG_FIR = 0x0040, /* FIR 4PPM encoding mode enable */ + IRCFG_MIR = 0x0020, /* MIR HDLC encoding mode enable */ + IRCFG_SIR = 0x0010, /* SIR encoding mode enable */ + IRCFG_SIRFILT = 0x0008, /* enable SIR decode filter (receiver unwrapping) */ + IRCFG_SIRTEST = 0x0004, /* allow SIR decode filter when not in SIR mode */ + IRCFG_TXPOL = 0x0002, /* invert tx polarity when set */ + IRCFG_RXPOL = 0x0001 /* invert rx polarity when set */ +}; + +/* ------------------------------------------ */ + +/* VLSI_PIO_SIRFLAG: SIR Flag Register (u16, ro) */ + +/* register contains hardcoded BOF=0xc0 at [7:0] and EOF=0xc1 at [15:8] + * which is used for unwrapping received frames in SIR decode-filter mode + */ + +/* ------------------------------------------ */ + +/* VLSI_PIO_IRENABLE: IR Enable Register (u16, rw/ro) */ + +/* notes: + * - IREN acts as gate for latching the configured IR mode information + * from IRCFG and IRPHYCTL when IREN=reset and applying them when + * IREN gets set afterwards. + * - ENTXST reflects IRCFG_ENTX + * - ENRXST = IRCFG_ENRX && (!IRCFG_ENTX || IRCFG_LOOP) + */ + +enum vlsi_pio_irenable { + IRENABLE_PHYANDCLOCK = 0x8000, /* enable IR phy and gate the mode config (rw) */ + IRENABLE_CFGER = 0x4000, /* mode configuration error (ro) */ + IRENABLE_FIR_ON = 0x2000, /* FIR on status (ro) */ + IRENABLE_MIR_ON = 0x1000, /* MIR on status (ro) */ + IRENABLE_SIR_ON = 0x0800, /* SIR on status (ro) */ + IRENABLE_ENTXST = 0x0400, /* transmit enable status (ro) */ + IRENABLE_ENRXST = 0x0200, /* Receive enable status (ro) */ + IRENABLE_CRC16_ON = 0x0100 /* 16bit (not 32bit) CRC enabled status (ro) */ +}; + +#define IRENABLE_MASK 0xff00 /* Read mask */ + +/* ------------------------------------------ */ + +/* VLSI_PIO_PHYCTL: IR Physical Layer Current Control Register (u16, ro) */ + +/* read-back of the currently applied physical layer status. + * applied from VLSI_PIO_NPHYCTL at rising edge of IRENABLE_PHYANDCLOCK + * contents identical to VLSI_PIO_NPHYCTL (see below) + */ + +/* ------------------------------------------ */ + +/* VLSI_PIO_NPHYCTL: IR Physical Layer Next Control Register (u16, rw) */ + +/* latched during IRENABLE_PHYANDCLOCK=0 and applied at 0-1 transition + * + * consists of BAUD[15:10], PLSWID[9:5] and PREAMB[4:0] bits defined as follows: + * + * SIR-mode: BAUD = (115.2kHz / baudrate) - 1 + * PLSWID = (pulsetime * freq / (BAUD+1)) - 1 + * where pulsetime is the requested IrPHY pulse width + * and freq is 8(16)MHz for 40(48)MHz primary input clock + * PREAMB: don't care for SIR + * + * The nominal SIR pulse width is 3/16 bit time so we have PLSWID=12 + * fixed for all SIR speeds at 40MHz input clock (PLSWID=24 at 48MHz). + * IrPHY also allows shorter pulses down to the nominal pulse duration + * at 115.2kbaud (minus some tolerance) which is 1.41 usec. + * Using the expression PLSWID = 12/(BAUD+1)-1 (multiplied by two for 48MHz) + * we get the minimum acceptable PLSWID values according to the VLSI + * specification, which provides 1.5 usec pulse width for all speeds (except + * for 2.4kbaud getting 6usec). This is fine with IrPHY v1.3 specs and + * reduces the transceiver power which drains the battery. At 9.6kbaud for + * example this amounts to more than 90% battery power saving! + * + * MIR-mode: BAUD = 0 + * PLSWID = 9(10) for 40(48) MHz input clock + * to get nominal MIR pulse width + * PREAMB = 1 + * + * FIR-mode: BAUD = 0 + * PLSWID: don't care + * PREAMB = 15 + */ + +#define PHYCTL_BAUD_SHIFT 10 +#define PHYCTL_BAUD_MASK 0xfc00 +#define PHYCTL_PLSWID_SHIFT 5 +#define PHYCTL_PLSWID_MASK 0x03e0 +#define PHYCTL_PREAMB_SHIFT 0 +#define PHYCTL_PREAMB_MASK 0x001f + +#define PHYCTL_TO_BAUD(bwp) (((bwp)&PHYCTL_BAUD_MASK)>>PHYCTL_BAUD_SHIFT) +#define PHYCTL_TO_PLSWID(bwp) (((bwp)&PHYCTL_PLSWID_MASK)>>PHYCTL_PLSWID_SHIFT) +#define PHYCTL_TO_PREAMB(bwp) (((bwp)&PHYCTL_PREAMB_MASK)>>PHYCTL_PREAMB_SHIFT) + +#define BWP_TO_PHYCTL(b,w,p) ((((b)<<PHYCTL_BAUD_SHIFT)&PHYCTL_BAUD_MASK) \ + | (((w)<<PHYCTL_PLSWID_SHIFT)&PHYCTL_PLSWID_MASK) \ + | (((p)<<PHYCTL_PREAMB_SHIFT)&PHYCTL_PREAMB_MASK)) + +#define BAUD_BITS(br) ((115200/(br))-1) + +static inline unsigned +calc_width_bits(unsigned baudrate, unsigned widthselect, unsigned clockselect) +{ + unsigned tmp; + + if (widthselect) /* nominal 3/16 puls width */ + return (clockselect) ? 12 : 24; + + tmp = ((clockselect) ? 12 : 24) / (BAUD_BITS(baudrate)+1); + + /* intermediate result of integer division needed here */ + + return (tmp>0) ? (tmp-1) : 0; +} + +#define PHYCTL_SIR(br,ws,cs) BWP_TO_PHYCTL(BAUD_BITS(br),calc_width_bits((br),(ws),(cs)),0) +#define PHYCTL_MIR(cs) BWP_TO_PHYCTL(0,((cs)?9:10),1) +#define PHYCTL_FIR BWP_TO_PHYCTL(0,0,15) + +/* quite ugly, I know. But implementing these calculations here avoids + * having magic numbers in the code and allows some playing with pulsewidths + * without risk to violate the standards. + * FWIW, here is the table for reference: + * + * baudrate BAUD min-PLSWID nom-PLSWID PREAMB + * 2400 47 0(0) 12(24) 0 + * 9600 11 0(0) 12(24) 0 + * 19200 5 1(2) 12(24) 0 + * 38400 2 3(6) 12(24) 0 + * 57600 1 5(10) 12(24) 0 + * 115200 0 11(22) 12(24) 0 + * MIR 0 - 9(10) 1 + * FIR 0 - 0 15 + * + * note: x(y) means x-value for 40MHz / y-value for 48MHz primary input clock + */ + +/* ------------------------------------------ */ + + +/* VLSI_PIO_MAXPKT: Maximum Packet Length register (u16, rw) */ + +/* maximum acceptable length for received packets */ + +/* hw imposed limitation - register uses only [11:0] */ +#define MAX_PACKET_LENGTH 0x0fff + +/* IrLAP I-field (apparently not defined elsewhere) */ +#define IRDA_MTU 2048 + +/* complete packet consists of A(1)+C(1)+I(<=IRDA_MTU) */ +#define IRLAP_SKB_ALLOCSIZE (1+1+IRDA_MTU) + +/* the buffers we use to exchange frames with the hardware need to be + * larger than IRLAP_SKB_ALLOCSIZE because we may have up to 4 bytes FCS + * appended and, in SIR mode, a lot of frame wrapping bytes. The worst + * case appears to be a SIR packet with I-size==IRDA_MTU and all bytes + * requiring to be escaped to provide transparency. Furthermore, the peer + * might ask for quite a number of additional XBOFs: + * up to 115+48 XBOFS 163 + * regular BOF 1 + * A-field 1 + * C-field 1 + * I-field, IRDA_MTU, all escaped 4096 + * FCS (16 bit at SIR, escaped) 4 + * EOF 1 + * AFAICS nothing in IrLAP guarantees A/C field not to need escaping + * (f.e. 0xc0/0xc1 - i.e. BOF/EOF - are legal values there) so in the + * worst case we have 4269 bytes total frame size. + * However, the VLSI uses 12 bits only for all buffer length values, + * which limits the maximum useable buffer size <= 4095. + * Note this is not a limitation in the receive case because we use + * the SIR filtering mode where the hw unwraps the frame and only the + * bare packet+fcs is stored into the buffer - in contrast to the SIR + * tx case where we have to pass frame-wrapped packets to the hw. + * If this would ever become an issue in real life, the only workaround + * I see would be using the legacy UART emulation in SIR mode. + */ + +#define XFER_BUF_SIZE MAX_PACKET_LENGTH + +/* ------------------------------------------ */ + +/* VLSI_PIO_RCVBCNT: Receive Byte Count Register (u16, ro) */ + +/* receive packet counter gets incremented on every non-filtered + * byte which was put in the receive fifo and reset for each + * new packet. Used to decide whether we are just in the middle + * of receiving + */ + +/* better apply the [11:0] mask when reading, as some docs say the + * reserved [15:12] would return 1 when reading - which is wrong AFAICS + */ +#define RCVBCNT_MASK 0x0fff + +/******************************************************************/ + +/* descriptors for rx/tx ring + * + * accessed by hardware - don't change! + * + * the descriptor is owned by hardware, when the ACTIVE status bit + * is set and nothing (besides reading status to test the bit) + * shall be done. The bit gets cleared by hw, when the descriptor + * gets closed. Premature reaping of descriptors owned be the chip + * can be achieved by disabling IRCFG_MSTR + * + * Attention: Writing addr overwrites status! + * + * ### FIXME: depends on endianess (but there ain't no non-i586 ob800 ;-) + */ + +struct ring_descr_hw { + volatile __le16 rd_count; /* tx/rx count [11:0] */ + __le16 reserved; + union { + __le32 addr; /* [23:0] of the buffer's busaddress */ + struct { + u8 addr_res[3]; + volatile u8 status; /* descriptor status */ + } __packed rd_s; + } __packed rd_u; +} __packed; + +#define rd_addr rd_u.addr +#define rd_status rd_u.rd_s.status + +/* ring descriptor status bits */ + +#define RD_ACTIVE 0x80 /* descriptor owned by hw (both TX,RX) */ + +/* TX ring descriptor status */ + +#define RD_TX_DISCRC 0x40 /* do not send CRC (for SIR) */ +#define RD_TX_BADCRC 0x20 /* force a bad CRC */ +#define RD_TX_PULSE 0x10 /* send indication pulse after this frame (MIR/FIR) */ +#define RD_TX_FRCEUND 0x08 /* force underrun */ +#define RD_TX_CLRENTX 0x04 /* clear ENTX after this frame */ +#define RD_TX_UNDRN 0x01 /* TX fifo underrun (probably PCI problem) */ + +/* RX ring descriptor status */ + +#define RD_RX_PHYERR 0x40 /* physical encoding error */ +#define RD_RX_CRCERR 0x20 /* CRC error (MIR/FIR) */ +#define RD_RX_LENGTH 0x10 /* frame exceeds buffer length */ +#define RD_RX_OVER 0x08 /* RX fifo overrun (probably PCI problem) */ +#define RD_RX_SIRBAD 0x04 /* EOF missing: BOF follows BOF (SIR, filtered) */ + +#define RD_RX_ERROR 0x7c /* any error in received frame */ + +/* the memory required to hold the 2 descriptor rings */ +#define HW_RING_AREA_SIZE (2 * MAX_RING_DESCR * sizeof(struct ring_descr_hw)) + +/******************************************************************/ + +/* sw-ring descriptors consists of a bus-mapped transfer buffer with + * associated skb and a pointer to the hw entry descriptor + */ + +struct ring_descr { + struct ring_descr_hw *hw; + struct sk_buff *skb; + void *buf; +}; + +/* wrappers for operations on hw-exposed ring descriptors + * access to the hw-part of the descriptors must use these. + */ + +static inline int rd_is_active(struct ring_descr *rd) +{ + return (rd->hw->rd_status & RD_ACTIVE) != 0; +} + +static inline void rd_activate(struct ring_descr *rd) +{ + rd->hw->rd_status |= RD_ACTIVE; +} + +static inline void rd_set_status(struct ring_descr *rd, u8 s) +{ + rd->hw->rd_status = s; /* may pass ownership to the hardware */ +} + +static inline void rd_set_addr_status(struct ring_descr *rd, dma_addr_t a, u8 s) +{ + /* order is important for two reasons: + * - overlayed: writing addr overwrites status + * - we want to write status last so we have valid address in + * case status has RD_ACTIVE set + */ + + if ((a & ~DMA_MASK_MSTRPAGE)>>24 != MSTRPAGE_VALUE) { + net_err_ratelimited("%s: pci busaddr inconsistency!\n", + __func__); + dump_stack(); + return; + } + + a &= DMA_MASK_MSTRPAGE; /* clear highbyte to make sure we won't write + * to status - just in case MSTRPAGE_VALUE!=0 + */ + rd->hw->rd_addr = cpu_to_le32(a); + wmb(); + rd_set_status(rd, s); /* may pass ownership to the hardware */ +} + +static inline void rd_set_count(struct ring_descr *rd, u16 c) +{ + rd->hw->rd_count = cpu_to_le16(c); +} + +static inline u8 rd_get_status(struct ring_descr *rd) +{ + return rd->hw->rd_status; +} + +static inline dma_addr_t rd_get_addr(struct ring_descr *rd) +{ + dma_addr_t a; + + a = le32_to_cpu(rd->hw->rd_addr); + return (a & DMA_MASK_MSTRPAGE) | (MSTRPAGE_VALUE << 24); +} + +static inline u16 rd_get_count(struct ring_descr *rd) +{ + return le16_to_cpu(rd->hw->rd_count); +} + +/******************************************************************/ + +/* sw descriptor rings for rx, tx: + * + * operations follow producer-consumer paradigm, with the hw + * in the middle doing the processing. + * ring size must be power of two. + * + * producer advances r->tail after inserting for processing + * consumer advances r->head after removing processed rd + * ring is empty if head==tail / full if (tail+1)==head + */ + +struct vlsi_ring { + struct pci_dev *pdev; + int dir; + unsigned len; + unsigned size; + unsigned mask; + atomic_t head, tail; + struct ring_descr *rd; +}; + +/* ring processing helpers */ + +static inline struct ring_descr *ring_last(struct vlsi_ring *r) +{ + int t; + + t = atomic_read(&r->tail) & r->mask; + return (((t+1) & r->mask) == (atomic_read(&r->head) & r->mask)) ? NULL : &r->rd[t]; +} + +static inline struct ring_descr *ring_put(struct vlsi_ring *r) +{ + atomic_inc(&r->tail); + return ring_last(r); +} + +static inline struct ring_descr *ring_first(struct vlsi_ring *r) +{ + int h; + + h = atomic_read(&r->head) & r->mask; + return (h == (atomic_read(&r->tail) & r->mask)) ? NULL : &r->rd[h]; +} + +static inline struct ring_descr *ring_get(struct vlsi_ring *r) +{ + atomic_inc(&r->head); + return ring_first(r); +} + +/******************************************************************/ + +/* our private compound VLSI-PCI-IRDA device information */ + +typedef struct vlsi_irda_dev { + struct pci_dev *pdev; + + struct irlap_cb *irlap; + + struct qos_info qos; + + unsigned mode; + int baud, new_baud; + + dma_addr_t busaddr; + void *virtaddr; + struct vlsi_ring *tx_ring, *rx_ring; + + ktime_t last_rx; + + spinlock_t lock; + struct mutex mtx; + + u8 resume_ok; + struct proc_dir_entry *proc_entry; + +} vlsi_irda_dev_t; + +/********************************************************/ + +/* the remapped error flags we use for returning from frame + * post-processing in vlsi_process_tx/rx() after it was completed + * by the hardware. These functions either return the >=0 number + * of transferred bytes in case of success or the negative (-) + * of the or'ed error flags. + */ + +#define VLSI_TX_DROP 0x0001 +#define VLSI_TX_FIFO 0x0002 + +#define VLSI_RX_DROP 0x0100 +#define VLSI_RX_OVER 0x0200 +#define VLSI_RX_LENGTH 0x0400 +#define VLSI_RX_FRAME 0x0800 +#define VLSI_RX_CRC 0x1000 + +/********************************************************/ + +#endif /* IRDA_VLSI_FIR_H */ + diff --git a/drivers/staging/irda/drivers/w83977af.h b/drivers/staging/irda/drivers/w83977af.h new file mode 100644 index 000000000000..04476c2e9121 --- /dev/null +++ b/drivers/staging/irda/drivers/w83977af.h @@ -0,0 +1,53 @@ +#ifndef W83977AF_H +#define W83977AF_H + +#define W977_EFIO_BASE 0x370 +#define W977_EFIO2_BASE 0x3f0 +#define W977_DEVICE_IR 0x06 + + +/* + * Enter extended function mode + */ +static inline void w977_efm_enter(unsigned int efio) +{ + outb(0x87, efio); + outb(0x87, efio); +} + +/* + * Select a device to configure + */ + +static inline void w977_select_device(__u8 devnum, unsigned int efio) +{ + outb(0x07, efio); + outb(devnum, efio+1); +} + +/* + * Write a byte to a register + */ +static inline void w977_write_reg(__u8 reg, __u8 value, unsigned int efio) +{ + outb(reg, efio); + outb(value, efio+1); +} + +/* + * read a byte from a register + */ +static inline __u8 w977_read_reg(__u8 reg, unsigned int efio) +{ + outb(reg, efio); + return inb(efio+1); +} + +/* + * Exit extended function mode + */ +static inline void w977_efm_exit(unsigned int efio) +{ + outb(0xAA, efio); +} +#endif diff --git a/drivers/staging/irda/drivers/w83977af_ir.c b/drivers/staging/irda/drivers/w83977af_ir.c new file mode 100644 index 000000000000..282b6c9ae05b --- /dev/null +++ b/drivers/staging/irda/drivers/w83977af_ir.c @@ -0,0 +1,1285 @@ +/********************************************************************* + * + * Filename: w83977af_ir.c + * Version: 1.0 + * Description: FIR driver for the Winbond W83977AF Super I/O chip + * Status: Experimental. + * Author: Paul VanderSpek + * Created at: Wed Nov 4 11:46:16 1998 + * Modified at: Fri Jan 28 12:10:59 2000 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no> + * Copyright (c) 1998-1999 Rebel.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Paul VanderSpek nor Rebel.com admit liability nor provide + * warranty for any of this software. This material is provided "AS-IS" + * and at no charge. + * + * If you find bugs in this file, its very likely that the same bug + * will also be in pc87108.c since the implementations are quite + * similar. + * + * Notice that all functions that needs to access the chip in _any_ + * way, must save BSR register on entry, and restore it on exit. + * It is _very_ important to follow this policy! + * + * __u8 bank; + * + * bank = inb( iobase+BSR); + * + * do_your_stuff_here(); + * + * outb( bank, iobase+BSR); + * + ********************************************************************/ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/skbuff.h> +#include <linux/netdevice.h> +#include <linux/ioport.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/rtnetlink.h> +#include <linux/dma-mapping.h> +#include <linux/gfp.h> + +#include <asm/io.h> +#include <asm/dma.h> +#include <asm/byteorder.h> + +#include <net/irda/irda.h> +#include <net/irda/wrapper.h> +#include <net/irda/irda_device.h> +#include "w83977af.h" +#include "w83977af_ir.h" + +#define CONFIG_USE_W977_PNP /* Currently needed */ +#define PIO_MAX_SPEED 115200 + +static char *driver_name = "w83977af_ir"; +static int qos_mtt_bits = 0x07; /* 1 ms or more */ + +#define CHIP_IO_EXTENT 8 + +static unsigned int io[] = { 0x180, ~0, ~0, ~0 }; +#ifdef CONFIG_ARCH_NETWINDER /* Adjust to NetWinder differences */ +static unsigned int irq[] = { 6, 0, 0, 0 }; +#else +static unsigned int irq[] = { 11, 0, 0, 0 }; +#endif +static unsigned int dma[] = { 1, 0, 0, 0 }; +static unsigned int efbase[] = { W977_EFIO_BASE, W977_EFIO2_BASE }; +static unsigned int efio = W977_EFIO_BASE; + +static struct w83977af_ir *dev_self[] = { NULL, NULL, NULL, NULL}; + +/* Some prototypes */ +static int w83977af_open(int i, unsigned int iobase, unsigned int irq, + unsigned int dma); +static int w83977af_close(struct w83977af_ir *self); +static int w83977af_probe(int iobase, int irq, int dma); +static int w83977af_dma_receive(struct w83977af_ir *self); +static int w83977af_dma_receive_complete(struct w83977af_ir *self); +static netdev_tx_t w83977af_hard_xmit(struct sk_buff *skb, + struct net_device *dev); +static int w83977af_pio_write(int iobase, __u8 *buf, int len, int fifo_size); +static void w83977af_dma_write(struct w83977af_ir *self, int iobase); +static void w83977af_change_speed(struct w83977af_ir *self, __u32 speed); +static int w83977af_is_receiving(struct w83977af_ir *self); + +static int w83977af_net_open(struct net_device *dev); +static int w83977af_net_close(struct net_device *dev); +static int w83977af_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); + +/* + * Function w83977af_init () + * + * Initialize chip. Just try to find out how many chips we are dealing with + * and where they are + */ +static int __init w83977af_init(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(dev_self) && io[i] < 2000; i++) { + if (w83977af_open(i, io[i], irq[i], dma[i]) == 0) + return 0; + } + return -ENODEV; +} + +/* + * Function w83977af_cleanup () + * + * Close all configured chips + * + */ +static void __exit w83977af_cleanup(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(dev_self); i++) { + if (dev_self[i]) + w83977af_close(dev_self[i]); + } +} + +static const struct net_device_ops w83977_netdev_ops = { + .ndo_open = w83977af_net_open, + .ndo_stop = w83977af_net_close, + .ndo_start_xmit = w83977af_hard_xmit, + .ndo_do_ioctl = w83977af_net_ioctl, +}; + +/* + * Function w83977af_open (iobase, irq) + * + * Open driver instance + * + */ +static int w83977af_open(int i, unsigned int iobase, unsigned int irq, + unsigned int dma) +{ + struct net_device *dev; + struct w83977af_ir *self; + int err; + + /* Lock the port that we need */ + if (!request_region(iobase, CHIP_IO_EXTENT, driver_name)) { + pr_debug("%s: can't get iobase of 0x%03x\n", + __func__, iobase); + return -ENODEV; + } + + if (w83977af_probe(iobase, irq, dma) == -1) { + err = -1; + goto err_out; + } + /* + * Allocate new instance of the driver + */ + dev = alloc_irdadev(sizeof(struct w83977af_ir)); + if (!dev) { + pr_err("IrDA: Can't allocate memory for IrDA control block!\n"); + err = -ENOMEM; + goto err_out; + } + + self = netdev_priv(dev); + spin_lock_init(&self->lock); + + /* Initialize IO */ + self->io.fir_base = iobase; + self->io.irq = irq; + self->io.fir_ext = CHIP_IO_EXTENT; + self->io.dma = dma; + self->io.fifo_size = 32; + + /* Initialize QoS for this device */ + irda_init_max_qos_capabilies(&self->qos); + + /* The only value we must override it the baudrate */ + + /* FIXME: The HP HDLS-1100 does not support 1152000! */ + self->qos.baud_rate.bits = IR_9600 | IR_19200 | IR_38400 | IR_57600 | + IR_115200 | IR_576000 | IR_1152000 | (IR_4000000 << 8); + + /* The HP HDLS-1100 needs 1 ms according to the specs */ + self->qos.min_turn_time.bits = qos_mtt_bits; + irda_qos_bits_to_value(&self->qos); + + /* Max DMA buffer size needed = (data_size + 6) * (window_size) + 6; */ + self->rx_buff.truesize = 14384; + self->tx_buff.truesize = 4000; + + /* Allocate memory if needed */ + self->rx_buff.head = + dma_zalloc_coherent(NULL, self->rx_buff.truesize, + &self->rx_buff_dma, GFP_KERNEL); + if (!self->rx_buff.head) { + err = -ENOMEM; + goto err_out1; + } + + self->tx_buff.head = + dma_zalloc_coherent(NULL, self->tx_buff.truesize, + &self->tx_buff_dma, GFP_KERNEL); + if (!self->tx_buff.head) { + err = -ENOMEM; + goto err_out2; + } + + self->rx_buff.in_frame = FALSE; + self->rx_buff.state = OUTSIDE_FRAME; + self->tx_buff.data = self->tx_buff.head; + self->rx_buff.data = self->rx_buff.head; + self->netdev = dev; + + dev->netdev_ops = &w83977_netdev_ops; + + err = register_netdev(dev); + if (err) { + net_err_ratelimited("%s:, register_netdevice() failed!\n", + __func__); + goto err_out3; + } + net_info_ratelimited("IrDA: Registered device %s\n", dev->name); + + /* Need to store self somewhere */ + dev_self[i] = self; + + return 0; +err_out3: + dma_free_coherent(NULL, self->tx_buff.truesize, + self->tx_buff.head, self->tx_buff_dma); +err_out2: + dma_free_coherent(NULL, self->rx_buff.truesize, + self->rx_buff.head, self->rx_buff_dma); +err_out1: + free_netdev(dev); +err_out: + release_region(iobase, CHIP_IO_EXTENT); + return err; +} + +/* + * Function w83977af_close (self) + * + * Close driver instance + * + */ +static int w83977af_close(struct w83977af_ir *self) +{ + int iobase; + + iobase = self->io.fir_base; + +#ifdef CONFIG_USE_W977_PNP + /* enter PnP configuration mode */ + w977_efm_enter(efio); + + w977_select_device(W977_DEVICE_IR, efio); + + /* Deactivate device */ + w977_write_reg(0x30, 0x00, efio); + + w977_efm_exit(efio); +#endif /* CONFIG_USE_W977_PNP */ + + /* Remove netdevice */ + unregister_netdev(self->netdev); + + /* Release the PORT that this driver is using */ + pr_debug("%s: Releasing Region %03x\n", __func__, self->io.fir_base); + release_region(self->io.fir_base, self->io.fir_ext); + + if (self->tx_buff.head) + dma_free_coherent(NULL, self->tx_buff.truesize, + self->tx_buff.head, self->tx_buff_dma); + + if (self->rx_buff.head) + dma_free_coherent(NULL, self->rx_buff.truesize, + self->rx_buff.head, self->rx_buff_dma); + + free_netdev(self->netdev); + + return 0; +} + +static int w83977af_probe(int iobase, int irq, int dma) +{ + int version; + int i; + + for (i = 0; i < 2; i++) { +#ifdef CONFIG_USE_W977_PNP + /* Enter PnP configuration mode */ + w977_efm_enter(efbase[i]); + + w977_select_device(W977_DEVICE_IR, efbase[i]); + + /* Configure PnP port, IRQ, and DMA channel */ + w977_write_reg(0x60, (iobase >> 8) & 0xff, efbase[i]); + w977_write_reg(0x61, (iobase) & 0xff, efbase[i]); + + w977_write_reg(0x70, irq, efbase[i]); +#ifdef CONFIG_ARCH_NETWINDER + /* Netwinder uses 1 higher than Linux */ + w977_write_reg(0x74, dma + 1, efbase[i]); +#else + w977_write_reg(0x74, dma, efbase[i]); +#endif /* CONFIG_ARCH_NETWINDER */ + w977_write_reg(0x75, 0x04, efbase[i]);/* Disable Tx DMA */ + + /* Set append hardware CRC, enable IR bank selection */ + w977_write_reg(0xf0, APEDCRC | ENBNKSEL, efbase[i]); + + /* Activate device */ + w977_write_reg(0x30, 0x01, efbase[i]); + + w977_efm_exit(efbase[i]); +#endif /* CONFIG_USE_W977_PNP */ + /* Disable Advanced mode */ + switch_bank(iobase, SET2); + outb(iobase + 2, 0x00); + + /* Turn on UART (global) interrupts */ + switch_bank(iobase, SET0); + outb(HCR_EN_IRQ, iobase + HCR); + + /* Switch to advanced mode */ + switch_bank(iobase, SET2); + outb(inb(iobase + ADCR1) | ADCR1_ADV_SL, iobase + ADCR1); + + /* Set default IR-mode */ + switch_bank(iobase, SET0); + outb(HCR_SIR, iobase + HCR); + + /* Read the Advanced IR ID */ + switch_bank(iobase, SET3); + version = inb(iobase + AUID); + + /* Should be 0x1? */ + if (0x10 == (version & 0xf0)) { + efio = efbase[i]; + + /* Set FIFO size to 32 */ + switch_bank(iobase, SET2); + outb(ADCR2_RXFS32 | ADCR2_TXFS32, iobase + ADCR2); + + /* Set FIFO threshold to TX17, RX16 */ + switch_bank(iobase, SET0); + outb(UFR_RXTL | UFR_TXTL | UFR_TXF_RST | UFR_RXF_RST | + UFR_EN_FIFO, iobase + UFR); + + /* Receiver frame length */ + switch_bank(iobase, SET4); + outb(2048 & 0xff, iobase + 6); + outb((2048 >> 8) & 0x1f, iobase + 7); + + /* + * Init HP HSDL-1100 transceiver. + * + * Set IRX_MSL since we have 2 * receive paths IRRX, + * and IRRXH. Clear IRSL0D since we want IRSL0 * to + * be a input pin used for IRRXH + * + * IRRX pin 37 connected to receiver + * IRTX pin 38 connected to transmitter + * FIRRX pin 39 connected to receiver (IRSL0) + * CIRRX pin 40 connected to pin 37 + */ + switch_bank(iobase, SET7); + outb(0x40, iobase + 7); + + net_info_ratelimited("W83977AF (IR) driver loaded. Version: 0x%02x\n", + version); + + return 0; + } else { + /* Try next extented function register address */ + pr_debug("%s: Wrong chip version\n", __func__); + } + } + return -1; +} + +static void w83977af_change_speed(struct w83977af_ir *self, __u32 speed) +{ + int ir_mode = HCR_SIR; + int iobase; + __u8 set; + + iobase = self->io.fir_base; + + /* Update accounting for new speed */ + self->io.speed = speed; + + /* Save current bank */ + set = inb(iobase + SSR); + + /* Disable interrupts */ + switch_bank(iobase, SET0); + outb(0, iobase + ICR); + + /* Select Set 2 */ + switch_bank(iobase, SET2); + outb(0x00, iobase + ABHL); + + switch (speed) { + case 9600: outb(0x0c, iobase + ABLL); break; + case 19200: outb(0x06, iobase + ABLL); break; + case 38400: outb(0x03, iobase + ABLL); break; + case 57600: outb(0x02, iobase + ABLL); break; + case 115200: outb(0x01, iobase + ABLL); break; + case 576000: + ir_mode = HCR_MIR_576; + pr_debug("%s: handling baud of 576000\n", __func__); + break; + case 1152000: + ir_mode = HCR_MIR_1152; + pr_debug("%s: handling baud of 1152000\n", __func__); + break; + case 4000000: + ir_mode = HCR_FIR; + pr_debug("%s: handling baud of 4000000\n", __func__); + break; + default: + ir_mode = HCR_FIR; + pr_debug("%s: unknown baud rate of %d\n", __func__, speed); + break; + } + + /* Set speed mode */ + switch_bank(iobase, SET0); + outb(ir_mode, iobase + HCR); + + /* set FIFO size to 32 */ + switch_bank(iobase, SET2); + outb(ADCR2_RXFS32 | ADCR2_TXFS32, iobase + ADCR2); + + /* set FIFO threshold to TX17, RX16 */ + switch_bank(iobase, SET0); + outb(0x00, iobase + UFR); /* Reset */ + outb(UFR_EN_FIFO, iobase + UFR); /* First we must enable FIFO */ + outb(0xa7, iobase + UFR); + + netif_wake_queue(self->netdev); + + /* Enable some interrupts so we can receive frames */ + switch_bank(iobase, SET0); + if (speed > PIO_MAX_SPEED) { + outb(ICR_EFSFI, iobase + ICR); + w83977af_dma_receive(self); + } else { + outb(ICR_ERBRI, iobase + ICR); + } + + /* Restore SSR */ + outb(set, iobase + SSR); +} + +/* + * Function w83977af_hard_xmit (skb, dev) + * + * Sets up a DMA transfer to send the current frame. + * + */ +static netdev_tx_t w83977af_hard_xmit(struct sk_buff *skb, + struct net_device *dev) +{ + struct w83977af_ir *self; + __s32 speed; + int iobase; + __u8 set; + int mtt; + + self = netdev_priv(dev); + + iobase = self->io.fir_base; + + pr_debug("%s: %ld, skb->len=%d\n", __func__, jiffies, (int)skb->len); + + /* Lock transmit buffer */ + netif_stop_queue(dev); + + /* Check if we need to change the speed */ + speed = irda_get_next_speed(skb); + if ((speed != self->io.speed) && (speed != -1)) { + /* Check for empty frame */ + if (!skb->len) { + w83977af_change_speed(self, speed); + dev_kfree_skb(skb); + return NETDEV_TX_OK; + } + self->new_speed = speed; + } + + /* Save current set */ + set = inb(iobase + SSR); + + /* Decide if we should use PIO or DMA transfer */ + if (self->io.speed > PIO_MAX_SPEED) { + self->tx_buff.data = self->tx_buff.head; + skb_copy_from_linear_data(skb, self->tx_buff.data, skb->len); + self->tx_buff.len = skb->len; + + mtt = irda_get_mtt(skb); + pr_debug("%s: %ld, mtt=%d\n", __func__, jiffies, mtt); + if (mtt > 1000) + mdelay(mtt / 1000); + else if (mtt) + udelay(mtt); + + /* Enable DMA interrupt */ + switch_bank(iobase, SET0); + outb(ICR_EDMAI, iobase + ICR); + w83977af_dma_write(self, iobase); + } else { + self->tx_buff.data = self->tx_buff.head; + self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data, + self->tx_buff.truesize); + + /* Add interrupt on tx low level (will fire immediately) */ + switch_bank(iobase, SET0); + outb(ICR_ETXTHI, iobase + ICR); + } + dev_kfree_skb(skb); + + /* Restore set register */ + outb(set, iobase + SSR); + + return NETDEV_TX_OK; +} + +/* + * Function w83977af_dma_write (self, iobase) + * + * Send frame using DMA + * + */ +static void w83977af_dma_write(struct w83977af_ir *self, int iobase) +{ + __u8 set; + + pr_debug("%s: len=%d\n", __func__, self->tx_buff.len); + + /* Save current set */ + set = inb(iobase + SSR); + + /* Disable DMA */ + switch_bank(iobase, SET0); + outb(inb(iobase + HCR) & ~HCR_EN_DMA, iobase + HCR); + + /* Choose transmit DMA channel */ + switch_bank(iobase, SET2); + outb(ADCR1_D_CHSW | /*ADCR1_DMA_F|*/ADCR1_ADV_SL, iobase + ADCR1); + irda_setup_dma(self->io.dma, self->tx_buff_dma, self->tx_buff.len, + DMA_MODE_WRITE); + self->io.direction = IO_XMIT; + + /* Enable DMA */ + switch_bank(iobase, SET0); + outb(inb(iobase + HCR) | HCR_EN_DMA | HCR_TX_WT, iobase + HCR); + + /* Restore set register */ + outb(set, iobase + SSR); +} + +/* + * Function w83977af_pio_write (iobase, buf, len, fifo_size) + * + * + * + */ +static int w83977af_pio_write(int iobase, __u8 *buf, int len, int fifo_size) +{ + int actual = 0; + __u8 set; + + /* Save current bank */ + set = inb(iobase + SSR); + + switch_bank(iobase, SET0); + if (!(inb_p(iobase + USR) & USR_TSRE)) { + pr_debug("%s: warning, FIFO not empty yet!\n", __func__); + + fifo_size -= 17; + pr_debug("%s: %d bytes left in tx fifo\n", __func__, fifo_size); + } + + /* Fill FIFO with current frame */ + while ((fifo_size-- > 0) && (actual < len)) { + /* Transmit next byte */ + outb(buf[actual++], iobase + TBR); + } + + pr_debug("%s: fifo_size %d ; %d sent of %d\n", + __func__, fifo_size, actual, len); + + /* Restore bank */ + outb(set, iobase + SSR); + + return actual; +} + +/* + * Function w83977af_dma_xmit_complete (self) + * + * The transfer of a frame in finished. So do the necessary things + * + * + */ +static void w83977af_dma_xmit_complete(struct w83977af_ir *self) +{ + int iobase; + __u8 set; + + pr_debug("%s: %ld\n", __func__, jiffies); + + IRDA_ASSERT(self, return;); + + iobase = self->io.fir_base; + + /* Save current set */ + set = inb(iobase + SSR); + + /* Disable DMA */ + switch_bank(iobase, SET0); + outb(inb(iobase + HCR) & ~HCR_EN_DMA, iobase + HCR); + + /* Check for underrun! */ + if (inb(iobase + AUDR) & AUDR_UNDR) { + pr_debug("%s: Transmit underrun!\n", __func__); + + self->netdev->stats.tx_errors++; + self->netdev->stats.tx_fifo_errors++; + + /* Clear bit, by writing 1 to it */ + outb(AUDR_UNDR, iobase + AUDR); + } else { + self->netdev->stats.tx_packets++; + } + + if (self->new_speed) { + w83977af_change_speed(self, self->new_speed); + self->new_speed = 0; + } + + /* Unlock tx_buff and request another frame */ + /* Tell the network layer, that we want more frames */ + netif_wake_queue(self->netdev); + + /* Restore set */ + outb(set, iobase + SSR); +} + +/* + * Function w83977af_dma_receive (self) + * + * Get ready for receiving a frame. The device will initiate a DMA + * if it starts to receive a frame. + * + */ +static int w83977af_dma_receive(struct w83977af_ir *self) +{ + int iobase; + __u8 set; +#ifdef CONFIG_ARCH_NETWINDER + unsigned long flags; + __u8 hcr; +#endif + IRDA_ASSERT(self, return -1;); + + pr_debug("%s\n", __func__); + + iobase = self->io.fir_base; + + /* Save current set */ + set = inb(iobase + SSR); + + /* Disable DMA */ + switch_bank(iobase, SET0); + outb(inb(iobase + HCR) & ~HCR_EN_DMA, iobase + HCR); + + /* Choose DMA Rx, DMA Fairness, and Advanced mode */ + switch_bank(iobase, SET2); + outb((inb(iobase + ADCR1) & ~ADCR1_D_CHSW)/*|ADCR1_DMA_F*/ | ADCR1_ADV_SL, + iobase + ADCR1); + + self->io.direction = IO_RECV; + self->rx_buff.data = self->rx_buff.head; + +#ifdef CONFIG_ARCH_NETWINDER + spin_lock_irqsave(&self->lock, flags); + + disable_dma(self->io.dma); + clear_dma_ff(self->io.dma); + set_dma_mode(self->io.dma, DMA_MODE_READ); + set_dma_addr(self->io.dma, self->rx_buff_dma); + set_dma_count(self->io.dma, self->rx_buff.truesize); +#else + irda_setup_dma(self->io.dma, self->rx_buff_dma, self->rx_buff.truesize, + DMA_MODE_READ); +#endif + /* + * Reset Rx FIFO. This will also flush the ST_FIFO, it's very + * important that we don't reset the Tx FIFO since it might not + * be finished transmitting yet + */ + switch_bank(iobase, SET0); + outb(UFR_RXTL | UFR_TXTL | UFR_RXF_RST | UFR_EN_FIFO, iobase + UFR); + self->st_fifo.len = self->st_fifo.tail = self->st_fifo.head = 0; + + /* Enable DMA */ + switch_bank(iobase, SET0); +#ifdef CONFIG_ARCH_NETWINDER + hcr = inb(iobase + HCR); + outb(hcr | HCR_EN_DMA, iobase + HCR); + enable_dma(self->io.dma); + spin_unlock_irqrestore(&self->lock, flags); +#else + outb(inb(iobase + HCR) | HCR_EN_DMA, iobase + HCR); +#endif + /* Restore set */ + outb(set, iobase + SSR); + + return 0; +} + +/* + * Function w83977af_receive_complete (self) + * + * Finished with receiving a frame + * + */ +static int w83977af_dma_receive_complete(struct w83977af_ir *self) +{ + struct sk_buff *skb; + struct st_fifo *st_fifo; + int len; + int iobase; + __u8 set; + __u8 status; + + pr_debug("%s\n", __func__); + + st_fifo = &self->st_fifo; + + iobase = self->io.fir_base; + + /* Save current set */ + set = inb(iobase + SSR); + + iobase = self->io.fir_base; + + /* Read status FIFO */ + switch_bank(iobase, SET5); + while ((status = inb(iobase + FS_FO)) & FS_FO_FSFDR) { + st_fifo->entries[st_fifo->tail].status = status; + + st_fifo->entries[st_fifo->tail].len = inb(iobase + RFLFL); + st_fifo->entries[st_fifo->tail].len |= inb(iobase + RFLFH) << 8; + + st_fifo->tail++; + st_fifo->len++; + } + + while (st_fifo->len) { + /* Get first entry */ + status = st_fifo->entries[st_fifo->head].status; + len = st_fifo->entries[st_fifo->head].len; + st_fifo->head++; + st_fifo->len--; + + /* Check for errors */ + if (status & FS_FO_ERR_MSK) { + if (status & FS_FO_LST_FR) { + /* Add number of lost frames to stats */ + self->netdev->stats.rx_errors += len; + } else { + /* Skip frame */ + self->netdev->stats.rx_errors++; + + self->rx_buff.data += len; + + if (status & FS_FO_MX_LEX) + self->netdev->stats.rx_length_errors++; + + if (status & FS_FO_PHY_ERR) + self->netdev->stats.rx_frame_errors++; + + if (status & FS_FO_CRC_ERR) + self->netdev->stats.rx_crc_errors++; + } + /* The errors below can be reported in both cases */ + if (status & FS_FO_RX_OV) + self->netdev->stats.rx_fifo_errors++; + + if (status & FS_FO_FSF_OV) + self->netdev->stats.rx_fifo_errors++; + + } else { + /* Check if we have transferred all data to memory */ + switch_bank(iobase, SET0); + if (inb(iobase + USR) & USR_RDR) + udelay(80); /* Should be enough!? */ + + skb = dev_alloc_skb(len + 1); + if (!skb) { + pr_info("%s: memory squeeze, dropping frame\n", + __func__); + /* Restore set register */ + outb(set, iobase + SSR); + + return FALSE; + } + + /* Align to 20 bytes */ + skb_reserve(skb, 1); + + /* Copy frame without CRC */ + if (self->io.speed < 4000000) { + skb_put(skb, len - 2); + skb_copy_to_linear_data(skb, + self->rx_buff.data, + len - 2); + } else { + skb_put(skb, len - 4); + skb_copy_to_linear_data(skb, + self->rx_buff.data, + len - 4); + } + + /* Move to next frame */ + self->rx_buff.data += len; + self->netdev->stats.rx_packets++; + + skb->dev = self->netdev; + skb_reset_mac_header(skb); + skb->protocol = htons(ETH_P_IRDA); + netif_rx(skb); + } + } + /* Restore set register */ + outb(set, iobase + SSR); + + return TRUE; +} + +/* + * Function pc87108_pio_receive (self) + * + * Receive all data in receiver FIFO + * + */ +static void w83977af_pio_receive(struct w83977af_ir *self) +{ + __u8 byte = 0x00; + int iobase; + + IRDA_ASSERT(self, return;); + + iobase = self->io.fir_base; + + /* Receive all characters in Rx FIFO */ + do { + byte = inb(iobase + RBR); + async_unwrap_char(self->netdev, &self->netdev->stats, &self->rx_buff, + byte); + } while (inb(iobase + USR) & USR_RDR); /* Data available */ +} + +/* + * Function w83977af_sir_interrupt (self, eir) + * + * Handle SIR interrupt + * + */ +static __u8 w83977af_sir_interrupt(struct w83977af_ir *self, int isr) +{ + int actual; + __u8 new_icr = 0; + __u8 set; + int iobase; + + pr_debug("%s: isr=%#x\n", __func__, isr); + + iobase = self->io.fir_base; + /* Transmit FIFO low on data */ + if (isr & ISR_TXTH_I) { + /* Write data left in transmit buffer */ + actual = w83977af_pio_write(self->io.fir_base, + self->tx_buff.data, + self->tx_buff.len, + self->io.fifo_size); + + self->tx_buff.data += actual; + self->tx_buff.len -= actual; + + self->io.direction = IO_XMIT; + + /* Check if finished */ + if (self->tx_buff.len > 0) { + new_icr |= ICR_ETXTHI; + } else { + set = inb(iobase + SSR); + switch_bank(iobase, SET0); + outb(AUDR_SFEND, iobase + AUDR); + outb(set, iobase + SSR); + + self->netdev->stats.tx_packets++; + + /* Feed me more packets */ + netif_wake_queue(self->netdev); + new_icr |= ICR_ETBREI; + } + } + /* Check if transmission has completed */ + if (isr & ISR_TXEMP_I) { + /* Check if we need to change the speed? */ + if (self->new_speed) { + pr_debug("%s: Changing speed!\n", __func__); + w83977af_change_speed(self, self->new_speed); + self->new_speed = 0; + } + + /* Turn around and get ready to receive some data */ + self->io.direction = IO_RECV; + new_icr |= ICR_ERBRI; + } + + /* Rx FIFO threshold or timeout */ + if (isr & ISR_RXTH_I) { + w83977af_pio_receive(self); + + /* Keep receiving */ + new_icr |= ICR_ERBRI; + } + return new_icr; +} + +/* + * Function pc87108_fir_interrupt (self, eir) + * + * Handle MIR/FIR interrupt + * + */ +static __u8 w83977af_fir_interrupt(struct w83977af_ir *self, int isr) +{ + __u8 new_icr = 0; + __u8 set; + int iobase; + + iobase = self->io.fir_base; + set = inb(iobase + SSR); + + /* End of frame detected in FIFO */ + if (isr & (ISR_FEND_I | ISR_FSF_I)) { + if (w83977af_dma_receive_complete(self)) { + /* Wait for next status FIFO interrupt */ + new_icr |= ICR_EFSFI; + } else { + /* DMA not finished yet */ + + /* Set timer value, resolution 1 ms */ + switch_bank(iobase, SET4); + outb(0x01, iobase + TMRL); /* 1 ms */ + outb(0x00, iobase + TMRH); + + /* Start timer */ + outb(IR_MSL_EN_TMR, iobase + IR_MSL); + + new_icr |= ICR_ETMRI; + } + } + /* Timer finished */ + if (isr & ISR_TMR_I) { + /* Disable timer */ + switch_bank(iobase, SET4); + outb(0, iobase + IR_MSL); + + /* Clear timer event */ + /* switch_bank(iobase, SET0); */ +/* outb(ASCR_CTE, iobase+ASCR); */ + + /* Check if this is a TX timer interrupt */ + if (self->io.direction == IO_XMIT) { + w83977af_dma_write(self, iobase); + + new_icr |= ICR_EDMAI; + } else { + /* Check if DMA has now finished */ + w83977af_dma_receive_complete(self); + + new_icr |= ICR_EFSFI; + } + } + /* Finished with DMA */ + if (isr & ISR_DMA_I) { + w83977af_dma_xmit_complete(self); + + /* Check if there are more frames to be transmitted */ + /* if (irda_device_txqueue_empty(self)) { */ + + /* Prepare for receive + * + * ** Netwinder Tx DMA likes that we do this anyway ** + */ + w83977af_dma_receive(self); + new_icr = ICR_EFSFI; + /* } */ + } + + /* Restore set */ + outb(set, iobase + SSR); + + return new_icr; +} + +/* + * Function w83977af_interrupt (irq, dev_id, regs) + * + * An interrupt from the chip has arrived. Time to do some work + * + */ +static irqreturn_t w83977af_interrupt(int irq, void *dev_id) +{ + struct net_device *dev = dev_id; + struct w83977af_ir *self; + __u8 set, icr, isr; + int iobase; + + self = netdev_priv(dev); + + iobase = self->io.fir_base; + + /* Save current bank */ + set = inb(iobase + SSR); + switch_bank(iobase, SET0); + + icr = inb(iobase + ICR); + isr = inb(iobase + ISR) & icr; /* Mask out the interesting ones */ + + outb(0, iobase + ICR); /* Disable interrupts */ + + if (isr) { + /* Dispatch interrupt handler for the current speed */ + if (self->io.speed > PIO_MAX_SPEED) + icr = w83977af_fir_interrupt(self, isr); + else + icr = w83977af_sir_interrupt(self, isr); + } + + outb(icr, iobase + ICR); /* Restore (new) interrupts */ + outb(set, iobase + SSR); /* Restore bank register */ + return IRQ_RETVAL(isr); +} + +/* + * Function w83977af_is_receiving (self) + * + * Return TRUE is we are currently receiving a frame + * + */ +static int w83977af_is_receiving(struct w83977af_ir *self) +{ + int status = FALSE; + int iobase; + __u8 set; + + IRDA_ASSERT(self, return FALSE;); + + if (self->io.speed > 115200) { + iobase = self->io.fir_base; + + /* Check if rx FIFO is not empty */ + set = inb(iobase + SSR); + switch_bank(iobase, SET2); + if ((inb(iobase + RXFDTH) & 0x3f) != 0) { + /* We are receiving something */ + status = TRUE; + } + outb(set, iobase + SSR); + } else { + status = (self->rx_buff.state != OUTSIDE_FRAME); + } + + return status; +} + +/* + * Function w83977af_net_open (dev) + * + * Start the device + * + */ +static int w83977af_net_open(struct net_device *dev) +{ + struct w83977af_ir *self; + int iobase; + char hwname[32]; + __u8 set; + + IRDA_ASSERT(dev, return -1;); + self = netdev_priv(dev); + + IRDA_ASSERT(self, return 0;); + + iobase = self->io.fir_base; + + if (request_irq(self->io.irq, w83977af_interrupt, 0, dev->name, + (void *)dev)) { + return -EAGAIN; + } + /* + * Always allocate the DMA channel after the IRQ, + * and clean up on failure. + */ + if (request_dma(self->io.dma, dev->name)) { + free_irq(self->io.irq, dev); + return -EAGAIN; + } + + /* Save current set */ + set = inb(iobase + SSR); + + /* Enable some interrupts so we can receive frames again */ + switch_bank(iobase, SET0); + if (self->io.speed > 115200) { + outb(ICR_EFSFI, iobase + ICR); + w83977af_dma_receive(self); + } else { + outb(ICR_ERBRI, iobase + ICR); + } + + /* Restore bank register */ + outb(set, iobase + SSR); + + /* Ready to play! */ + netif_start_queue(dev); + + /* Give self a hardware name */ + sprintf(hwname, "w83977af @ 0x%03x", self->io.fir_base); + + /* + * Open new IrLAP layer instance, now that everything should be + * initialized properly + */ + self->irlap = irlap_open(dev, &self->qos, hwname); + + return 0; +} + +/* + * Function w83977af_net_close (dev) + * + * Stop the device + * + */ +static int w83977af_net_close(struct net_device *dev) +{ + struct w83977af_ir *self; + int iobase; + __u8 set; + + IRDA_ASSERT(dev, return -1;); + + self = netdev_priv(dev); + + IRDA_ASSERT(self, return 0;); + + iobase = self->io.fir_base; + + /* Stop device */ + netif_stop_queue(dev); + + /* Stop and remove instance of IrLAP */ + if (self->irlap) + irlap_close(self->irlap); + self->irlap = NULL; + + disable_dma(self->io.dma); + + /* Save current set */ + set = inb(iobase + SSR); + + /* Disable interrupts */ + switch_bank(iobase, SET0); + outb(0, iobase + ICR); + + free_irq(self->io.irq, dev); + free_dma(self->io.dma); + + /* Restore bank register */ + outb(set, iobase + SSR); + + return 0; +} + +/* + * Function w83977af_net_ioctl (dev, rq, cmd) + * + * Process IOCTL commands for this device + * + */ +static int w83977af_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct if_irda_req *irq = (struct if_irda_req *)rq; + struct w83977af_ir *self; + unsigned long flags; + int ret = 0; + + IRDA_ASSERT(dev, return -1;); + + self = netdev_priv(dev); + + IRDA_ASSERT(self, return -1;); + + pr_debug("%s: %s, (cmd=0x%X)\n", __func__, dev->name, cmd); + + spin_lock_irqsave(&self->lock, flags); + + switch (cmd) { + case SIOCSBANDWIDTH: /* Set bandwidth */ + if (!capable(CAP_NET_ADMIN)) { + ret = -EPERM; + goto out; + } + w83977af_change_speed(self, irq->ifr_baudrate); + break; + case SIOCSMEDIABUSY: /* Set media busy */ + if (!capable(CAP_NET_ADMIN)) { + ret = -EPERM; + goto out; + } + irda_device_set_media_busy(self->netdev, TRUE); + break; + case SIOCGRECEIVING: /* Check if we are receiving right now */ + irq->ifr_receiving = w83977af_is_receiving(self); + break; + default: + ret = -EOPNOTSUPP; + } +out: + spin_unlock_irqrestore(&self->lock, flags); + return ret; +} + +MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>"); +MODULE_DESCRIPTION("Winbond W83977AF IrDA Device Driver"); +MODULE_LICENSE("GPL"); + +module_param(qos_mtt_bits, int, 0); +MODULE_PARM_DESC(qos_mtt_bits, "Mimimum Turn Time"); +module_param_hw_array(io, int, ioport, NULL, 0); +MODULE_PARM_DESC(io, "Base I/O addresses"); +module_param_hw_array(irq, int, irq, NULL, 0); +MODULE_PARM_DESC(irq, "IRQ lines"); + +/* + * Function init_module (void) + * + * + * + */ +module_init(w83977af_init); + +/* + * Function cleanup_module (void) + * + * + * + */ +module_exit(w83977af_cleanup); diff --git a/drivers/staging/irda/drivers/w83977af_ir.h b/drivers/staging/irda/drivers/w83977af_ir.h new file mode 100644 index 000000000000..fefe9b11e200 --- /dev/null +++ b/drivers/staging/irda/drivers/w83977af_ir.h @@ -0,0 +1,198 @@ +/********************************************************************* + * + * Filename: w83977af_ir.h + * Version: + * Description: + * Status: Experimental. + * Author: Paul VanderSpek + * Created at: Thu Nov 19 13:55:34 1998 + * Modified at: Tue Jan 11 13:08:19 2000 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1998-2000 Dag Brattli, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#ifndef W83977AF_IR_H +#define W83977AF_IR_H + +#include <asm/io.h> +#include <linux/types.h> + +/* Flags for configuration register CRF0 */ +#define ENBNKSEL 0x01 +#define APEDCRC 0x02 +#define TXW4C 0x04 +#define RXW4C 0x08 + +/* Bank 0 */ +#define RBR 0x00 /* Receiver buffer register */ +#define TBR 0x00 /* Transmitter buffer register */ + +#define ICR 0x01 /* Interrupt configuration register */ +#define ICR_ERBRI 0x01 /* Receiver buffer register interrupt */ +#define ICR_ETBREI 0x02 /* Transeiver empty interrupt */ +#define ICR_EUSRI 0x04//* IR status interrupt */ +#define ICR_EHSRI 0x04 +#define ICR_ETXURI 0x04 /* Tx underrun */ +#define ICR_EDMAI 0x10 /* DMA interrupt */ +#define ICR_ETXTHI 0x20 /* Transmitter threshold interrupt */ +#define ICR_EFSFI 0x40 /* Frame status FIFO interrupt */ +#define ICR_ETMRI 0x80 /* Timer interrupt */ + +#define UFR 0x02 /* FIFO control register */ +#define UFR_EN_FIFO 0x01 /* Enable FIFO's */ +#define UFR_RXF_RST 0x02 /* Reset Rx FIFO */ +#define UFR_TXF_RST 0x04 /* Reset Tx FIFO */ +#define UFR_RXTL 0x80 /* Rx FIFO threshold (set to 16) */ +#define UFR_TXTL 0x20 /* Tx FIFO threshold (set to 17) */ + +#define ISR 0x02 /* Interrupt status register */ +#define ISR_RXTH_I 0x01 /* Receive threshold interrupt */ +#define ISR_TXEMP_I 0x02 /* Transmitter empty interrupt */ +#define ISR_FEND_I 0x04 +#define ISR_DMA_I 0x10 +#define ISR_TXTH_I 0x20 /* Transmitter threshold interrupt */ +#define ISR_FSF_I 0x40 +#define ISR_TMR_I 0x80 /* Timer interrupt */ + +#define UCR 0x03 /* Uart control register */ +#define UCR_DLS8 0x03 /* 8N1 */ + +#define SSR 0x03 /* Sets select register */ +#define SET0 UCR_DLS8 /* Make sure we keep 8N1 */ +#define SET1 (0x80|UCR_DLS8) /* Make sure we keep 8N1 */ +#define SET2 0xE0 +#define SET3 0xE4 +#define SET4 0xE8 +#define SET5 0xEC +#define SET6 0xF0 +#define SET7 0xF4 + +#define HCR 0x04 +#define HCR_MODE_MASK ~(0xD0) +#define HCR_SIR 0x60 +#define HCR_MIR_576 0x20 +#define HCR_MIR_1152 0x80 +#define HCR_FIR 0xA0 +#define HCR_EN_DMA 0x04 +#define HCR_EN_IRQ 0x08 +#define HCR_TX_WT 0x08 + +#define USR 0x05 /* IR status register */ +#define USR_RDR 0x01 /* Receive data ready */ +#define USR_TSRE 0x40 /* Transmitter empty? */ + +#define AUDR 0x07 +#define AUDR_SFEND 0x08 /* Set a frame end */ +#define AUDR_RXBSY 0x20 /* Rx busy */ +#define AUDR_UNDR 0x40 /* Transeiver underrun */ + +/* Set 2 */ +#define ABLL 0x00 /* Advanced baud rate divisor latch (low byte) */ +#define ABHL 0x01 /* Advanced baud rate divisor latch (high byte) */ + +#define ADCR1 0x02 +#define ADCR1_ADV_SL 0x01 +#define ADCR1_D_CHSW 0x08 /* the specs are wrong. its bit 3, not 4 */ +#define ADCR1_DMA_F 0x02 + +#define ADCR2 0x04 +#define ADCR2_TXFS32 0x01 +#define ADCR2_RXFS32 0x04 + +#define RXFDTH 0x07 + +/* Set 3 */ +#define AUID 0x00 + +/* Set 4 */ +#define TMRL 0x00 /* Timer value register (low byte) */ +#define TMRH 0x01 /* Timer value register (high byte) */ + +#define IR_MSL 0x02 /* Infrared mode select */ +#define IR_MSL_EN_TMR 0x01 /* Enable timer */ + +#define TFRLL 0x04 /* Transmitter frame length (low byte) */ +#define TFRLH 0x05 /* Transmitter frame length (high byte) */ +#define RFRLL 0x06 /* Receiver frame length (low byte) */ +#define RFRLH 0x07 /* Receiver frame length (high byte) */ + +/* Set 5 */ + +#define FS_FO 0x05 /* Frame status FIFO */ +#define FS_FO_FSFDR 0x80 /* Frame status FIFO data ready */ +#define FS_FO_LST_FR 0x40 /* Frame lost */ +#define FS_FO_MX_LEX 0x10 /* Max frame len exceeded */ +#define FS_FO_PHY_ERR 0x08 /* Physical layer error */ +#define FS_FO_CRC_ERR 0x04 +#define FS_FO_RX_OV 0x02 /* Receive overrun */ +#define FS_FO_FSF_OV 0x01 /* Frame status FIFO overrun */ +#define FS_FO_ERR_MSK 0x5f /* Error mask */ + +#define RFLFL 0x06 +#define RFLFH 0x07 + +/* Set 6 */ +#define IR_CFG2 0x00 +#define IR_CFG2_DIS_CRC 0x02 + +/* Set 7 */ +#define IRM_CR 0x07 /* Infrared module control register */ +#define IRM_CR_IRX_MSL 0x40 +#define IRM_CR_AF_MNT 0x80 /* Automatic format */ + +/* For storing entries in the status FIFO */ +struct st_fifo_entry { + int status; + int len; +}; + +struct st_fifo { + struct st_fifo_entry entries[10]; + int head; + int tail; + int len; +}; + +/* Private data for each instance */ +struct w83977af_ir { + struct st_fifo st_fifo; + + int tx_buff_offsets[10]; /* Offsets between frames in tx_buff */ + int tx_len; /* Number of frames in tx_buff */ + + struct net_device *netdev; /* Yes! we are some kind of netdevice */ + + struct irlap_cb *irlap; /* The link layer we are binded to */ + struct qos_info qos; /* QoS capabilities for this device */ + + chipio_t io; /* IrDA controller information */ + iobuff_t tx_buff; /* Transmit buffer */ + iobuff_t rx_buff; /* Receive buffer */ + dma_addr_t tx_buff_dma; + dma_addr_t rx_buff_dma; + + /* Note : currently locking is *very* incomplete, but this + * will get you started. Check in nsc-ircc.c for a proper + * locking strategy. - Jean II */ + spinlock_t lock; /* For serializing operations */ + + __u32 new_speed; +}; + +static inline void switch_bank( int iobase, int set) +{ + outb(set, iobase+SSR); +} + +#endif diff --git a/drivers/staging/irda/include/net/irda/af_irda.h b/drivers/staging/irda/include/net/irda/af_irda.h new file mode 100644 index 000000000000..0df574931522 --- /dev/null +++ b/drivers/staging/irda/include/net/irda/af_irda.h @@ -0,0 +1,87 @@ +/********************************************************************* + * + * Filename: af_irda.h + * Version: 1.0 + * Description: IrDA sockets declarations + * Status: Stable + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Tue Dec 9 21:13:12 1997 + * Modified at: Fri Jan 28 13:16:32 2000 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1998-2000 Dag Brattli, All Rights Reserved. + * Copyright (c) 2000-2002 Jean Tourrilhes <jt@hpl.hp.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#ifndef AF_IRDA_H +#define AF_IRDA_H + +#include <linux/irda.h> +#include <net/irda/irda.h> +#include <net/irda/iriap.h> /* struct iriap_cb */ +#include <net/irda/irias_object.h> /* struct ias_value */ +#include <net/irda/irlmp.h> /* struct lsap_cb */ +#include <net/irda/irttp.h> /* struct tsap_cb */ +#include <net/irda/discovery.h> /* struct discovery_t */ +#include <net/sock.h> + +/* IrDA Socket */ +struct irda_sock { + /* struct sock has to be the first member of irda_sock */ + struct sock sk; + __u32 saddr; /* my local address */ + __u32 daddr; /* peer address */ + + struct lsap_cb *lsap; /* LSAP used by Ultra */ + __u8 pid; /* Protocol IP (PID) used by Ultra */ + + struct tsap_cb *tsap; /* TSAP used by this connection */ + __u8 dtsap_sel; /* remote TSAP address */ + __u8 stsap_sel; /* local TSAP address */ + + __u32 max_sdu_size_rx; + __u32 max_sdu_size_tx; + __u32 max_data_size; + __u8 max_header_size; + struct qos_info qos_tx; + + __u16_host_order mask; /* Hint bits mask */ + __u16_host_order hints; /* Hint bits */ + + void *ckey; /* IrLMP client handle */ + void *skey; /* IrLMP service handle */ + + struct ias_object *ias_obj; /* Our service name + lsap in IAS */ + struct iriap_cb *iriap; /* Used to query remote IAS */ + struct ias_value *ias_result; /* Result of remote IAS query */ + + hashbin_t *cachelog; /* Result of discovery query */ + __u32 cachedaddr; /* Result of selective discovery query */ + + int nslots; /* Number of slots to use for discovery */ + + int errno; /* status of the IAS query */ + + wait_queue_head_t query_wait; /* Wait for the answer to a query */ + struct timer_list watchdog; /* Timeout for discovery */ + + LOCAL_FLOW tx_flow; + LOCAL_FLOW rx_flow; +}; + +static inline struct irda_sock *irda_sk(struct sock *sk) +{ + return (struct irda_sock *)sk; +} + +#endif /* AF_IRDA_H */ diff --git a/drivers/staging/irda/include/net/irda/crc.h b/drivers/staging/irda/include/net/irda/crc.h new file mode 100644 index 000000000000..f202296df9bb --- /dev/null +++ b/drivers/staging/irda/include/net/irda/crc.h @@ -0,0 +1,29 @@ +/********************************************************************* + * + * Filename: crc.h + * Version: + * Description: CRC routines + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Mon Aug 4 20:40:53 1997 + * Modified at: Sun May 2 20:25:23 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + ********************************************************************/ + +#ifndef IRDA_CRC_H +#define IRDA_CRC_H + +#include <linux/types.h> +#include <linux/crc-ccitt.h> + +#define INIT_FCS 0xffff /* Initial FCS value */ +#define GOOD_FCS 0xf0b8 /* Good final FCS value */ + +/* Recompute the FCS with one more character appended. */ +#define irda_fcs(fcs, c) crc_ccitt_byte(fcs, c) + +/* Recompute the FCS with len bytes appended. */ +#define irda_calc_crc16(fcs, buf, len) crc_ccitt(fcs, buf, len) + +#endif diff --git a/drivers/staging/irda/include/net/irda/discovery.h b/drivers/staging/irda/include/net/irda/discovery.h new file mode 100644 index 000000000000..63ae32530567 --- /dev/null +++ b/drivers/staging/irda/include/net/irda/discovery.h @@ -0,0 +1,95 @@ +/********************************************************************* + * + * Filename: discovery.h + * Version: + * Description: + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Tue Apr 6 16:53:53 1999 + * Modified at: Tue Oct 5 10:05:10 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1999 Dag Brattli, All Rights Reserved. + * Copyright (c) 2000-2002 Jean Tourrilhes <jt@hpl.hp.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + ********************************************************************/ + +#ifndef DISCOVERY_H +#define DISCOVERY_H + +#include <asm/param.h> + +#include <net/irda/irda.h> +#include <net/irda/irqueue.h> /* irda_queue_t */ +#include <net/irda/irlap_event.h> /* LAP_REASON */ + +#define DISCOVERY_EXPIRE_TIMEOUT (2*sysctl_discovery_timeout*HZ) +#define DISCOVERY_DEFAULT_SLOTS 0 + +/* + * This type is used by the protocols that transmit 16 bits words in + * little endian format. A little endian machine stores MSB of word in + * byte[1] and LSB in byte[0]. A big endian machine stores MSB in byte[0] + * and LSB in byte[1]. + * + * This structure is used in the code for things that are endian neutral + * but that fit in a word so that we can manipulate them efficiently. + * By endian neutral, I mean things that are really an array of bytes, + * and always used as such, for example the hint bits. Jean II + */ +typedef union { + __u16 word; + __u8 byte[2]; +} __u16_host_order; + +/* Types of discovery */ +typedef enum { + DISCOVERY_LOG, /* What's in our discovery log */ + DISCOVERY_ACTIVE, /* Doing our own discovery on the medium */ + DISCOVERY_PASSIVE, /* Peer doing discovery on the medium */ + EXPIRY_TIMEOUT, /* Entry expired due to timeout */ +} DISCOVERY_MODE; + +#define NICKNAME_MAX_LEN 21 + +/* Basic discovery information about a peer */ +typedef struct irda_device_info discinfo_t; /* linux/irda.h */ + +/* + * The DISCOVERY structure is used for both discovery requests and responses + */ +typedef struct discovery_t { + irda_queue_t q; /* Must be first! */ + + discinfo_t data; /* Basic discovery information */ + int name_len; /* Length of nickname */ + + LAP_REASON condition; /* More info about the discovery */ + int gen_addr_bit; /* Need to generate a new device + * address? */ + int nslots; /* Number of slots to use when + * discovering */ + unsigned long timestamp; /* Last time discovered */ + unsigned long firststamp; /* First time discovered */ +} discovery_t; + +void irlmp_add_discovery(hashbin_t *cachelog, discovery_t *discovery); +void irlmp_add_discovery_log(hashbin_t *cachelog, hashbin_t *log); +void irlmp_expire_discoveries(hashbin_t *log, __u32 saddr, int force); +struct irda_device_info *irlmp_copy_discoveries(hashbin_t *log, int *pn, + __u16 mask, int old_entries); + +#endif diff --git a/drivers/staging/irda/include/net/irda/ircomm_core.h b/drivers/staging/irda/include/net/irda/ircomm_core.h new file mode 100644 index 000000000000..2a580ce9edad --- /dev/null +++ b/drivers/staging/irda/include/net/irda/ircomm_core.h @@ -0,0 +1,106 @@ +/********************************************************************* + * + * Filename: ircomm_core.h + * Version: + * Description: + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Wed Jun 9 08:58:43 1999 + * Modified at: Mon Dec 13 11:52:29 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1999 Dag Brattli, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + ********************************************************************/ + +#ifndef IRCOMM_CORE_H +#define IRCOMM_CORE_H + +#include <net/irda/irda.h> +#include <net/irda/irqueue.h> +#include <net/irda/ircomm_event.h> + +#define IRCOMM_MAGIC 0x98347298 +#define IRCOMM_HEADER_SIZE 1 + +struct ircomm_cb; /* Forward decl. */ + +/* + * A small call-table, so we don't have to check the service-type whenever + * we want to do something + */ +typedef struct { + int (*data_request)(struct ircomm_cb *, struct sk_buff *, int clen); + int (*connect_request)(struct ircomm_cb *, struct sk_buff *, + struct ircomm_info *); + int (*connect_response)(struct ircomm_cb *, struct sk_buff *); + int (*disconnect_request)(struct ircomm_cb *, struct sk_buff *, + struct ircomm_info *); +} call_t; + +struct ircomm_cb { + irda_queue_t queue; + magic_t magic; + + notify_t notify; + call_t issue; + + int state; + int line; /* Which TTY line we are using */ + + struct tsap_cb *tsap; + struct lsap_cb *lsap; + + __u8 dlsap_sel; /* Destination LSAP/TSAP selector */ + __u8 slsap_sel; /* Source LSAP/TSAP selector */ + + __u32 saddr; /* Source device address (link we are using) */ + __u32 daddr; /* Destination device address */ + + int max_header_size; /* Header space we must reserve for each frame */ + int max_data_size; /* The amount of data we can fill in each frame */ + + LOCAL_FLOW flow_status; /* Used by ircomm_lmp */ + int pkt_count; /* Number of frames we have sent to IrLAP */ + + __u8 service_type; +}; + +extern hashbin_t *ircomm; + +struct ircomm_cb *ircomm_open(notify_t *notify, __u8 service_type, int line); +int ircomm_close(struct ircomm_cb *self); + +int ircomm_data_request(struct ircomm_cb *self, struct sk_buff *skb); +void ircomm_data_indication(struct ircomm_cb *self, struct sk_buff *skb); +void ircomm_process_data(struct ircomm_cb *self, struct sk_buff *skb); +int ircomm_control_request(struct ircomm_cb *self, struct sk_buff *skb); +int ircomm_connect_request(struct ircomm_cb *self, __u8 dlsap_sel, + __u32 saddr, __u32 daddr, struct sk_buff *skb, + __u8 service_type); +void ircomm_connect_indication(struct ircomm_cb *self, struct sk_buff *skb, + struct ircomm_info *info); +void ircomm_connect_confirm(struct ircomm_cb *self, struct sk_buff *skb, + struct ircomm_info *info); +int ircomm_connect_response(struct ircomm_cb *self, struct sk_buff *userdata); +int ircomm_disconnect_request(struct ircomm_cb *self, struct sk_buff *userdata); +void ircomm_disconnect_indication(struct ircomm_cb *self, struct sk_buff *skb, + struct ircomm_info *info); +void ircomm_flow_request(struct ircomm_cb *self, LOCAL_FLOW flow); + +#define ircomm_is_connected(self) (self->state == IRCOMM_CONN) + +#endif diff --git a/drivers/staging/irda/include/net/irda/ircomm_event.h b/drivers/staging/irda/include/net/irda/ircomm_event.h new file mode 100644 index 000000000000..5bbc32998d57 --- /dev/null +++ b/drivers/staging/irda/include/net/irda/ircomm_event.h @@ -0,0 +1,83 @@ +/********************************************************************* + * + * Filename: ircomm_event.h + * Version: + * Description: + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Sun Jun 6 23:51:13 1999 + * Modified at: Thu Jun 10 08:36:25 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1999 Dag Brattli, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + ********************************************************************/ + +#ifndef IRCOMM_EVENT_H +#define IRCOMM_EVENT_H + +#include <net/irda/irmod.h> + +typedef enum { + IRCOMM_IDLE, + IRCOMM_WAITI, + IRCOMM_WAITR, + IRCOMM_CONN, +} IRCOMM_STATE; + +/* IrCOMM Events */ +typedef enum { + IRCOMM_CONNECT_REQUEST, + IRCOMM_CONNECT_RESPONSE, + IRCOMM_TTP_CONNECT_INDICATION, + IRCOMM_LMP_CONNECT_INDICATION, + IRCOMM_TTP_CONNECT_CONFIRM, + IRCOMM_LMP_CONNECT_CONFIRM, + + IRCOMM_LMP_DISCONNECT_INDICATION, + IRCOMM_TTP_DISCONNECT_INDICATION, + IRCOMM_DISCONNECT_REQUEST, + + IRCOMM_TTP_DATA_INDICATION, + IRCOMM_LMP_DATA_INDICATION, + IRCOMM_DATA_REQUEST, + IRCOMM_CONTROL_REQUEST, + IRCOMM_CONTROL_INDICATION, +} IRCOMM_EVENT; + +/* + * Used for passing information through the state-machine + */ +struct ircomm_info { + __u32 saddr; /* Source device address */ + __u32 daddr; /* Destination device address */ + __u8 dlsap_sel; + LM_REASON reason; /* Reason for disconnect */ + __u32 max_data_size; + __u32 max_header_size; + + struct qos_info *qos; +}; + +extern const char *const ircomm_state[]; + +struct ircomm_cb; /* Forward decl. */ + +int ircomm_do_event(struct ircomm_cb *self, IRCOMM_EVENT event, + struct sk_buff *skb, struct ircomm_info *info); +void ircomm_next_state(struct ircomm_cb *self, IRCOMM_STATE state); + +#endif diff --git a/drivers/staging/irda/include/net/irda/ircomm_lmp.h b/drivers/staging/irda/include/net/irda/ircomm_lmp.h new file mode 100644 index 000000000000..5042a5021a04 --- /dev/null +++ b/drivers/staging/irda/include/net/irda/ircomm_lmp.h @@ -0,0 +1,36 @@ +/********************************************************************* + * + * Filename: ircomm_lmp.h + * Version: + * Description: + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Wed Jun 9 10:06:07 1999 + * Modified at: Fri Aug 13 07:32:32 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1999 Dag Brattli, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + ********************************************************************/ + +#ifndef IRCOMM_LMP_H +#define IRCOMM_LMP_H + +#include <net/irda/ircomm_core.h> + +int ircomm_open_lsap(struct ircomm_cb *self); + +#endif diff --git a/drivers/staging/irda/include/net/irda/ircomm_param.h b/drivers/staging/irda/include/net/irda/ircomm_param.h new file mode 100644 index 000000000000..1f67432321c4 --- /dev/null +++ b/drivers/staging/irda/include/net/irda/ircomm_param.h @@ -0,0 +1,147 @@ +/********************************************************************* + * + * Filename: ircomm_param.h + * Version: 1.0 + * Description: Parameter handling for the IrCOMM protocol + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Mon Jun 7 08:47:28 1999 + * Modified at: Wed Aug 25 13:46:33 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1999 Dag Brattli, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + ********************************************************************/ + +#ifndef IRCOMM_PARAMS_H +#define IRCOMM_PARAMS_H + +#include <net/irda/parameters.h> + +/* Parameters common to all service types */ +#define IRCOMM_SERVICE_TYPE 0x00 +#define IRCOMM_PORT_TYPE 0x01 /* Only used in LM-IAS */ +#define IRCOMM_PORT_NAME 0x02 /* Only used in LM-IAS */ + +/* Parameters for both 3 wire and 9 wire */ +#define IRCOMM_DATA_RATE 0x10 +#define IRCOMM_DATA_FORMAT 0x11 +#define IRCOMM_FLOW_CONTROL 0x12 +#define IRCOMM_XON_XOFF 0x13 +#define IRCOMM_ENQ_ACK 0x14 +#define IRCOMM_LINE_STATUS 0x15 +#define IRCOMM_BREAK 0x16 + +/* Parameters for 9 wire */ +#define IRCOMM_DTE 0x20 +#define IRCOMM_DCE 0x21 +#define IRCOMM_POLL 0x22 + +/* Service type (details) */ +#define IRCOMM_3_WIRE_RAW 0x01 +#define IRCOMM_3_WIRE 0x02 +#define IRCOMM_9_WIRE 0x04 +#define IRCOMM_CENTRONICS 0x08 + +/* Port type (details) */ +#define IRCOMM_SERIAL 0x00 +#define IRCOMM_PARALLEL 0x01 + +/* Data format (details) */ +#define IRCOMM_WSIZE_5 0x00 +#define IRCOMM_WSIZE_6 0x01 +#define IRCOMM_WSIZE_7 0x02 +#define IRCOMM_WSIZE_8 0x03 + +#define IRCOMM_1_STOP_BIT 0x00 +#define IRCOMM_2_STOP_BIT 0x04 /* 1.5 if char len 5 */ + +#define IRCOMM_PARITY_DISABLE 0x00 +#define IRCOMM_PARITY_ENABLE 0x08 + +#define IRCOMM_PARITY_ODD 0x00 +#define IRCOMM_PARITY_EVEN 0x10 +#define IRCOMM_PARITY_MARK 0x20 +#define IRCOMM_PARITY_SPACE 0x30 + +/* Flow control */ +#define IRCOMM_XON_XOFF_IN 0x01 +#define IRCOMM_XON_XOFF_OUT 0x02 +#define IRCOMM_RTS_CTS_IN 0x04 +#define IRCOMM_RTS_CTS_OUT 0x08 +#define IRCOMM_DSR_DTR_IN 0x10 +#define IRCOMM_DSR_DTR_OUT 0x20 +#define IRCOMM_ENQ_ACK_IN 0x40 +#define IRCOMM_ENQ_ACK_OUT 0x80 + +/* Line status */ +#define IRCOMM_OVERRUN_ERROR 0x02 +#define IRCOMM_PARITY_ERROR 0x04 +#define IRCOMM_FRAMING_ERROR 0x08 + +/* DTE (Data terminal equipment) line settings */ +#define IRCOMM_DELTA_DTR 0x01 +#define IRCOMM_DELTA_RTS 0x02 +#define IRCOMM_DTR 0x04 +#define IRCOMM_RTS 0x08 + +/* DCE (Data communications equipment) line settings */ +#define IRCOMM_DELTA_CTS 0x01 /* Clear to send has changed */ +#define IRCOMM_DELTA_DSR 0x02 /* Data set ready has changed */ +#define IRCOMM_DELTA_RI 0x04 /* Ring indicator has changed */ +#define IRCOMM_DELTA_CD 0x08 /* Carrier detect has changed */ +#define IRCOMM_CTS 0x10 /* Clear to send is high */ +#define IRCOMM_DSR 0x20 /* Data set ready is high */ +#define IRCOMM_RI 0x40 /* Ring indicator is high */ +#define IRCOMM_CD 0x80 /* Carrier detect is high */ +#define IRCOMM_DCE_DELTA_ANY 0x0f + +/* + * Parameter state + */ +struct ircomm_params { + /* General control params */ + __u8 service_type; + __u8 port_type; + char port_name[32]; + + /* Control params for 3- and 9-wire service type */ + __u32 data_rate; /* Data rate in bps */ + __u8 data_format; + __u8 flow_control; + char xonxoff[2]; + char enqack[2]; + __u8 line_status; + __u8 _break; + + __u8 null_modem; + + /* Control params for 9-wire service type */ + __u8 dte; + __u8 dce; + __u8 poll; + + /* Control params for Centronics service type */ +}; + +struct ircomm_tty_cb; /* Forward decl. */ + +int ircomm_param_request(struct ircomm_tty_cb *self, __u8 pi, int flush); + +extern pi_param_info_t ircomm_param_info; + +#endif /* IRCOMM_PARAMS_H */ + diff --git a/drivers/staging/irda/include/net/irda/ircomm_ttp.h b/drivers/staging/irda/include/net/irda/ircomm_ttp.h new file mode 100644 index 000000000000..c5627288bca3 --- /dev/null +++ b/drivers/staging/irda/include/net/irda/ircomm_ttp.h @@ -0,0 +1,37 @@ +/********************************************************************* + * + * Filename: ircomm_ttp.h + * Version: + * Description: + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Wed Jun 9 10:06:07 1999 + * Modified at: Fri Aug 13 07:32:22 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1999 Dag Brattli, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + ********************************************************************/ + +#ifndef IRCOMM_TTP_H +#define IRCOMM_TTP_H + +#include <net/irda/ircomm_core.h> + +int ircomm_open_tsap(struct ircomm_cb *self); + +#endif + diff --git a/drivers/staging/irda/include/net/irda/ircomm_tty.h b/drivers/staging/irda/include/net/irda/ircomm_tty.h new file mode 100644 index 000000000000..8d4f588974bc --- /dev/null +++ b/drivers/staging/irda/include/net/irda/ircomm_tty.h @@ -0,0 +1,121 @@ +/********************************************************************* + * + * Filename: ircomm_tty.h + * Version: + * Description: + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Sun Jun 6 23:24:22 1999 + * Modified at: Fri Jan 28 13:16:57 2000 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1999-2000 Dag Brattli, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + ********************************************************************/ + +#ifndef IRCOMM_TTY_H +#define IRCOMM_TTY_H + +#include <linux/serial.h> +#include <linux/termios.h> +#include <linux/timer.h> +#include <linux/tty.h> /* struct tty_struct */ + +#include <net/irda/irias_object.h> +#include <net/irda/ircomm_core.h> +#include <net/irda/ircomm_param.h> + +#define IRCOMM_TTY_PORTS 32 +#define IRCOMM_TTY_MAGIC 0x3432 +#define IRCOMM_TTY_MAJOR 161 +#define IRCOMM_TTY_MINOR 0 + +/* This is used as an initial value to max_header_size before the proper + * value is filled in (5 for ttp, 4 for lmp). This allow us to detect + * the state of the underlying connection. - Jean II */ +#define IRCOMM_TTY_HDR_UNINITIALISED 16 +/* Same for payload size. See qos.c for the smallest max data size */ +#define IRCOMM_TTY_DATA_UNINITIALISED (64 - IRCOMM_TTY_HDR_UNINITIALISED) + +/* + * IrCOMM TTY driver state + */ +struct ircomm_tty_cb { + irda_queue_t queue; /* Must be first */ + struct tty_port port; + magic_t magic; + + int state; /* Connect state */ + + struct ircomm_cb *ircomm; /* IrCOMM layer instance */ + + struct sk_buff *tx_skb; /* Transmit buffer */ + struct sk_buff *ctrl_skb; /* Control data buffer */ + + /* Parameters */ + struct ircomm_params settings; + + __u8 service_type; /* The service that we support */ + int client; /* True if we are a client */ + LOCAL_FLOW flow; /* IrTTP flow status */ + + int line; + + __u8 dlsap_sel; + __u8 slsap_sel; + + __u32 saddr; + __u32 daddr; + + __u32 max_data_size; /* Max data we can transmit in one packet */ + __u32 max_header_size; /* The amount of header space we must reserve */ + __u32 tx_data_size; /* Max data size of current tx_skb */ + + struct iriap_cb *iriap; /* Instance used for querying remote IAS */ + struct ias_object* obj; + void *skey; + void *ckey; + + struct timer_list watchdog_timer; + struct work_struct tqueue; + + /* Protect concurent access to : + * o self->ctrl_skb + * o self->tx_skb + * Maybe other things may gain to be protected as well... + * Jean II */ + spinlock_t spinlock; +}; + +void ircomm_tty_start(struct tty_struct *tty); +void ircomm_tty_check_modem_status(struct ircomm_tty_cb *self); + +int ircomm_tty_tiocmget(struct tty_struct *tty); +int ircomm_tty_tiocmset(struct tty_struct *tty, unsigned int set, + unsigned int clear); +int ircomm_tty_ioctl(struct tty_struct *tty, unsigned int cmd, + unsigned long arg); +void ircomm_tty_set_termios(struct tty_struct *tty, + struct ktermios *old_termios); + +#endif + + + + + + + diff --git a/drivers/staging/irda/include/net/irda/ircomm_tty_attach.h b/drivers/staging/irda/include/net/irda/ircomm_tty_attach.h new file mode 100644 index 000000000000..20dcbdf258cf --- /dev/null +++ b/drivers/staging/irda/include/net/irda/ircomm_tty_attach.h @@ -0,0 +1,92 @@ +/********************************************************************* + * + * Filename: ircomm_tty_attach.h + * Version: + * Description: + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Wed Jun 9 15:55:18 1999 + * Modified at: Fri Dec 10 21:04:55 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1999 Dag Brattli, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + ********************************************************************/ + +#ifndef IRCOMM_TTY_ATTACH_H +#define IRCOMM_TTY_ATTACH_H + +#include <net/irda/ircomm_tty.h> + +typedef enum { + IRCOMM_TTY_IDLE, + IRCOMM_TTY_SEARCH, + IRCOMM_TTY_QUERY_PARAMETERS, + IRCOMM_TTY_QUERY_LSAP_SEL, + IRCOMM_TTY_SETUP, + IRCOMM_TTY_READY, +} IRCOMM_TTY_STATE; + +/* IrCOMM TTY Events */ +typedef enum { + IRCOMM_TTY_ATTACH_CABLE, + IRCOMM_TTY_DETACH_CABLE, + IRCOMM_TTY_DATA_REQUEST, + IRCOMM_TTY_DATA_INDICATION, + IRCOMM_TTY_DISCOVERY_REQUEST, + IRCOMM_TTY_DISCOVERY_INDICATION, + IRCOMM_TTY_CONNECT_CONFIRM, + IRCOMM_TTY_CONNECT_INDICATION, + IRCOMM_TTY_DISCONNECT_REQUEST, + IRCOMM_TTY_DISCONNECT_INDICATION, + IRCOMM_TTY_WD_TIMER_EXPIRED, + IRCOMM_TTY_GOT_PARAMETERS, + IRCOMM_TTY_GOT_LSAPSEL, +} IRCOMM_TTY_EVENT; + +/* Used for passing information through the state-machine */ +struct ircomm_tty_info { + __u32 saddr; /* Source device address */ + __u32 daddr; /* Destination device address */ + __u8 dlsap_sel; +}; + +extern const char *const ircomm_state[]; +extern const char *const ircomm_tty_state[]; + +int ircomm_tty_do_event(struct ircomm_tty_cb *self, IRCOMM_TTY_EVENT event, + struct sk_buff *skb, struct ircomm_tty_info *info); + + +int ircomm_tty_attach_cable(struct ircomm_tty_cb *self); +void ircomm_tty_detach_cable(struct ircomm_tty_cb *self); +void ircomm_tty_connect_confirm(void *instance, void *sap, + struct qos_info *qos, + __u32 max_sdu_size, + __u8 max_header_size, + struct sk_buff *skb); +void ircomm_tty_disconnect_indication(void *instance, void *sap, + LM_REASON reason, + struct sk_buff *skb); +void ircomm_tty_connect_indication(void *instance, void *sap, + struct qos_info *qos, + __u32 max_sdu_size, + __u8 max_header_size, + struct sk_buff *skb); +int ircomm_tty_send_initial_parameters(struct ircomm_tty_cb *self); +void ircomm_tty_link_established(struct ircomm_tty_cb *self); + +#endif /* IRCOMM_TTY_ATTACH_H */ diff --git a/drivers/staging/irda/include/net/irda/irda.h b/drivers/staging/irda/include/net/irda/irda.h new file mode 100644 index 000000000000..92c8fb575213 --- /dev/null +++ b/drivers/staging/irda/include/net/irda/irda.h @@ -0,0 +1,115 @@ +/********************************************************************* + * + * Filename: irda.h + * Version: 1.0 + * Description: IrDA common include file for kernel internal use + * Status: Stable + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Tue Dec 9 21:13:12 1997 + * Modified at: Fri Jan 28 13:16:32 2000 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1998-2000 Dag Brattli, All Rights Reserved. + * Copyright (c) 2000-2002 Jean Tourrilhes <jt@hpl.hp.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#ifndef NET_IRDA_H +#define NET_IRDA_H + +#include <linux/skbuff.h> /* struct sk_buff */ +#include <linux/kernel.h> +#include <linux/if.h> /* sa_family_t in <linux/irda.h> */ +#include <linux/irda.h> + +typedef __u32 magic_t; + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +/* Hack to do small backoff when setting media busy in IrLAP */ +#ifndef SMALL +#define SMALL 5 +#endif + +#ifndef IRDA_MIN /* Lets not mix this MIN with other header files */ +#define IRDA_MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif + +#ifndef IRDA_ALIGN +# define IRDA_ALIGN __attribute__((aligned)) +#endif + +#ifdef CONFIG_IRDA_DEBUG +#define IRDA_ASSERT(expr, func) \ +do { if(!(expr)) { \ + printk( "Assertion failed! %s:%s:%d %s\n", \ + __FILE__,__func__,__LINE__,(#expr) ); \ + func } } while (0) +#define IRDA_ASSERT_LABEL(label) label +#else +#define IRDA_ASSERT(expr, func) do { (void)(expr); } while (0) +#define IRDA_ASSERT_LABEL(label) +#endif /* CONFIG_IRDA_DEBUG */ + +/* + * Magic numbers used by Linux-IrDA. Random numbers which must be unique to + * give the best protection + */ + +#define IRTTY_MAGIC 0x2357 +#define LAP_MAGIC 0x1357 +#define LMP_MAGIC 0x4321 +#define LMP_LSAP_MAGIC 0x69333 +#define LMP_LAP_MAGIC 0x3432 +#define IRDA_DEVICE_MAGIC 0x63454 +#define IAS_MAGIC 0x007 +#define TTP_MAGIC 0x241169 +#define TTP_TSAP_MAGIC 0x4345 +#define IROBEX_MAGIC 0x341324 +#define HB_MAGIC 0x64534 +#define IRLAN_MAGIC 0x754 +#define IAS_OBJECT_MAGIC 0x34234 +#define IAS_ATTRIB_MAGIC 0x45232 +#define IRDA_TASK_MAGIC 0x38423 + +#define IAS_DEVICE_ID 0x0000 /* Defined by IrDA, IrLMP section 4.1 (page 68) */ +#define IAS_PNP_ID 0xd342 +#define IAS_OBEX_ID 0x34323 +#define IAS_IRLAN_ID 0x34234 +#define IAS_IRCOMM_ID 0x2343 +#define IAS_IRLPT_ID 0x9876 + +struct net_device; +struct packet_type; + +void irda_proc_register(void); +void irda_proc_unregister(void); + +int irda_sysctl_register(void); +void irda_sysctl_unregister(void); + +int irsock_init(void); +void irsock_cleanup(void); + +int irda_nl_register(void); +void irda_nl_unregister(void); + +int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev, + struct packet_type *ptype, struct net_device *orig_dev); + +#endif /* NET_IRDA_H */ diff --git a/drivers/staging/irda/include/net/irda/irda_device.h b/drivers/staging/irda/include/net/irda/irda_device.h new file mode 100644 index 000000000000..664bf8178412 --- /dev/null +++ b/drivers/staging/irda/include/net/irda/irda_device.h @@ -0,0 +1,285 @@ +/********************************************************************* + * + * Filename: irda_device.h + * Version: 0.9 + * Description: Contains various declarations used by the drivers + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Tue Apr 14 12:41:42 1998 + * Modified at: Mon Mar 20 09:08:57 2000 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1999-2000 Dag Brattli, All Rights Reserved. + * Copyright (c) 1998 Thomas Davis, <ratbert@radiks.net>, + * Copyright (c) 2000-2002 Jean Tourrilhes <jt@hpl.hp.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + ********************************************************************/ + +/* + * This header contains all the IrDA definitions a driver really + * needs, and therefore the driver should not need to include + * any other IrDA headers - Jean II + */ + +#ifndef IRDA_DEVICE_H +#define IRDA_DEVICE_H + +#include <linux/tty.h> +#include <linux/netdevice.h> +#include <linux/spinlock.h> +#include <linux/skbuff.h> /* struct sk_buff */ +#include <linux/irda.h> +#include <linux/types.h> + +#include <net/pkt_sched.h> +#include <net/irda/irda.h> +#include <net/irda/qos.h> /* struct qos_info */ +#include <net/irda/irqueue.h> /* irda_queue_t */ + +/* A few forward declarations (to make compiler happy) */ +struct irlap_cb; + +/* Some non-standard interface flags (should not conflict with any in if.h) */ +#define IFF_SIR 0x0001 /* Supports SIR speeds */ +#define IFF_MIR 0x0002 /* Supports MIR speeds */ +#define IFF_FIR 0x0004 /* Supports FIR speeds */ +#define IFF_VFIR 0x0008 /* Supports VFIR speeds */ +#define IFF_PIO 0x0010 /* Supports PIO transfer of data */ +#define IFF_DMA 0x0020 /* Supports DMA transfer of data */ +#define IFF_SHM 0x0040 /* Supports shared memory data transfers */ +#define IFF_DONGLE 0x0080 /* Interface has a dongle attached */ +#define IFF_AIR 0x0100 /* Supports Advanced IR (AIR) standards */ + +#define IO_XMIT 0x01 +#define IO_RECV 0x02 + +typedef enum { + IRDA_IRLAP, /* IrDA mode, and deliver to IrLAP */ + IRDA_RAW, /* IrDA mode */ + SHARP_ASK, + TV_REMOTE, /* Also known as Consumer Electronics IR */ +} INFRARED_MODE; + +typedef enum { + IRDA_TASK_INIT, /* All tasks are initialized with this state */ + IRDA_TASK_DONE, /* Signals that the task is finished */ + IRDA_TASK_WAIT, + IRDA_TASK_WAIT1, + IRDA_TASK_WAIT2, + IRDA_TASK_WAIT3, + IRDA_TASK_CHILD_INIT, /* Initializing child task */ + IRDA_TASK_CHILD_WAIT, /* Waiting for child task to finish */ + IRDA_TASK_CHILD_DONE /* Child task is finished */ +} IRDA_TASK_STATE; + +struct irda_task; +typedef int (*IRDA_TASK_CALLBACK) (struct irda_task *task); + +struct irda_task { + irda_queue_t q; + magic_t magic; + + IRDA_TASK_STATE state; + IRDA_TASK_CALLBACK function; + IRDA_TASK_CALLBACK finished; + + struct irda_task *parent; + struct timer_list timer; + + void *instance; /* Instance being called */ + void *param; /* Parameter to be used by instance */ +}; + +/* Dongle info */ +struct dongle_reg; +typedef struct { + struct dongle_reg *issue; /* Registration info */ + struct net_device *dev; /* Device we are attached to */ + struct irda_task *speed_task; /* Task handling speed change */ + struct irda_task *reset_task; /* Task handling reset */ + __u32 speed; /* Current speed */ + + /* Callbacks to the IrDA device driver */ + int (*set_mode)(struct net_device *, int mode); + int (*read)(struct net_device *dev, __u8 *buf, int len); + int (*write)(struct net_device *dev, __u8 *buf, int len); + int (*set_dtr_rts)(struct net_device *dev, int dtr, int rts); +} dongle_t; + +/* Dongle registration info */ +struct dongle_reg { + irda_queue_t q; /* Must be first */ + IRDA_DONGLE type; + + void (*open)(dongle_t *dongle, struct qos_info *qos); + void (*close)(dongle_t *dongle); + int (*reset)(struct irda_task *task); + int (*change_speed)(struct irda_task *task); + struct module *owner; +}; + +/* + * Per-packet information we need to hide inside sk_buff + * (must not exceed 48 bytes, check with struct sk_buff) + * The default_qdisc_pad field is a temporary hack. + */ +struct irda_skb_cb { + unsigned int default_qdisc_pad; + magic_t magic; /* Be sure that we can trust the information */ + __u32 next_speed; /* The Speed to be set *after* this frame */ + __u16 mtt; /* Minimum turn around time */ + __u16 xbofs; /* Number of xbofs required, used by SIR mode */ + __u16 next_xbofs; /* Number of xbofs required *after* this frame */ + void *context; /* May be used by drivers */ + void (*destructor)(struct sk_buff *skb); /* Used for flow control */ + __u16 xbofs_delay; /* Number of xbofs used for generating the mtt */ + __u8 line; /* Used by IrCOMM in IrLPT mode */ +}; + +/* Chip specific info */ +typedef struct { + int cfg_base; /* Config register IO base */ + int sir_base; /* SIR IO base */ + int fir_base; /* FIR IO base */ + int mem_base; /* Shared memory base */ + int sir_ext; /* Length of SIR iobase */ + int fir_ext; /* Length of FIR iobase */ + int irq, irq2; /* Interrupts used */ + int dma, dma2; /* DMA channel(s) used */ + int fifo_size; /* FIFO size */ + int irqflags; /* interrupt flags (ie, IRQF_SHARED) */ + int direction; /* Link direction, used by some FIR drivers */ + int enabled; /* Powered on? */ + int suspended; /* Suspended by APM */ + __u32 speed; /* Currently used speed */ + __u32 new_speed; /* Speed we must change to when Tx is finished */ + int dongle_id; /* Dongle or transceiver currently used */ +} chipio_t; + +/* IO buffer specific info (inspired by struct sk_buff) */ +typedef struct { + int state; /* Receiving state (transmit state not used) */ + int in_frame; /* True if receiving frame */ + + __u8 *head; /* start of buffer */ + __u8 *data; /* start of data in buffer */ + + int len; /* current length of data */ + int truesize; /* total allocated size of buffer */ + __u16 fcs; + + struct sk_buff *skb; /* ZeroCopy Rx in async_unwrap_char() */ +} iobuff_t; + +/* Maximum SIR frame (skb) that we expect to receive *unwrapped*. + * Max LAP MTU (I field) is 2048 bytes max (IrLAP 1.1, chapt 6.6.5, p40). + * Max LAP header is 2 bytes (for now). + * Max CRC is 2 bytes at SIR, 4 bytes at FIR. + * Need 1 byte for skb_reserve() to align IP header for IrLAN. + * Add a few extra bytes just to be safe (buffer is power of two anyway) + * Jean II */ +#define IRDA_SKB_MAX_MTU 2064 +/* Maximum SIR frame that we expect to send, wrapped (i.e. with XBOFS + * and escaped characters on top of above). */ +#define IRDA_SIR_MAX_FRAME 4269 + +/* The SIR unwrapper async_unwrap_char() will use a Rx-copy-break mechanism + * when using the optional ZeroCopy Rx, where only small frames are memcpy + * to a smaller skb to save memory. This is the threshold under which copy + * will happen (and over which it won't happen). + * Some FIR drivers may use this #define as well... + * This is the same value as various Ethernet drivers. - Jean II */ +#define IRDA_RX_COPY_THRESHOLD 256 + +/* Function prototypes */ +int irda_device_init(void); +void irda_device_cleanup(void); + +/* IrLAP entry points used by the drivers. + * We declare them here to avoid the driver pulling a whole bunch stack + * headers they don't really need - Jean II */ +struct irlap_cb *irlap_open(struct net_device *dev, struct qos_info *qos, + const char *hw_name); +void irlap_close(struct irlap_cb *self); + +/* Interface to be uses by IrLAP */ +void irda_device_set_media_busy(struct net_device *dev, int status); +int irda_device_is_media_busy(struct net_device *dev); +int irda_device_is_receiving(struct net_device *dev); + +/* Interface for internal use */ +static inline int irda_device_txqueue_empty(const struct net_device *dev) +{ + return qdisc_all_tx_empty(dev); +} +int irda_device_set_raw_mode(struct net_device* self, int status); +struct net_device *alloc_irdadev(int sizeof_priv); + +void irda_setup_dma(int channel, dma_addr_t buffer, int count, int mode); + +/* + * Function irda_get_mtt (skb) + * + * Utility function for getting the minimum turnaround time out of + * the skb, where it has been hidden in the cb field. + */ +static inline __u16 irda_get_mtt(const struct sk_buff *skb) +{ + const struct irda_skb_cb *cb = (const struct irda_skb_cb *) skb->cb; + return (cb->magic == LAP_MAGIC) ? cb->mtt : 10000; +} + +/* + * Function irda_get_next_speed (skb) + * + * Extract the speed that should be set *after* this frame from the skb + * + * Note : return -1 for user space frames + */ +static inline __u32 irda_get_next_speed(const struct sk_buff *skb) +{ + const struct irda_skb_cb *cb = (const struct irda_skb_cb *) skb->cb; + return (cb->magic == LAP_MAGIC) ? cb->next_speed : -1; +} + +/* + * Function irda_get_next_xbofs (skb) + * + * Extract the xbofs that should be set for this frame from the skb + * + * Note : default to 10 for user space frames + */ +static inline __u16 irda_get_xbofs(const struct sk_buff *skb) +{ + const struct irda_skb_cb *cb = (const struct irda_skb_cb *) skb->cb; + return (cb->magic == LAP_MAGIC) ? cb->xbofs : 10; +} + +/* + * Function irda_get_next_xbofs (skb) + * + * Extract the xbofs that should be set *after* this frame from the skb + * + * Note : return -1 for user space frames + */ +static inline __u16 irda_get_next_xbofs(const struct sk_buff *skb) +{ + const struct irda_skb_cb *cb = (const struct irda_skb_cb *) skb->cb; + return (cb->magic == LAP_MAGIC) ? cb->next_xbofs : -1; +} +#endif /* IRDA_DEVICE_H */ + + diff --git a/drivers/staging/irda/include/net/irda/iriap.h b/drivers/staging/irda/include/net/irda/iriap.h new file mode 100644 index 000000000000..fcc896491a95 --- /dev/null +++ b/drivers/staging/irda/include/net/irda/iriap.h @@ -0,0 +1,108 @@ +/********************************************************************* + * + * Filename: iriap.h + * Version: 0.5 + * Description: Information Access Protocol (IAP) + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Thu Aug 21 00:02:07 1997 + * Modified at: Sat Dec 25 16:42:09 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1997-1999 Dag Brattli <dagb@cs.uit.no>, + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#ifndef IRIAP_H +#define IRIAP_H + +#include <linux/types.h> +#include <linux/skbuff.h> + +#include <net/irda/iriap_event.h> +#include <net/irda/irias_object.h> +#include <net/irda/irqueue.h> /* irda_queue_t */ +#include <net/irda/timer.h> /* struct timer_list */ + +#define IAP_LST 0x80 +#define IAP_ACK 0x40 + +#define IAS_SERVER 0 +#define IAS_CLIENT 1 + +/* IrIAP Op-codes */ +#define GET_INFO_BASE 0x01 +#define GET_OBJECTS 0x02 +#define GET_VALUE 0x03 +#define GET_VALUE_BY_CLASS 0x04 +#define GET_OBJECT_INFO 0x05 +#define GET_ATTRIB_NAMES 0x06 + +#define IAS_SUCCESS 0 +#define IAS_CLASS_UNKNOWN 1 +#define IAS_ATTRIB_UNKNOWN 2 +#define IAS_DISCONNECT 10 + +typedef void (*CONFIRM_CALLBACK)(int result, __u16 obj_id, + struct ias_value *value, void *priv); + +struct iriap_cb { + irda_queue_t q; /* Must be first */ + magic_t magic; /* Magic cookie */ + + int mode; /* Client or server */ + + __u32 saddr; + __u32 daddr; + __u8 operation; + + struct sk_buff *request_skb; + struct lsap_cb *lsap; + __u8 slsap_sel; + + /* Client states */ + IRIAP_STATE client_state; + IRIAP_STATE call_state; + + /* Server states */ + IRIAP_STATE server_state; + IRIAP_STATE r_connect_state; + + CONFIRM_CALLBACK confirm; + void *priv; /* Used to identify client */ + + __u8 max_header_size; + __u32 max_data_size; + + struct timer_list watchdog_timer; +}; + +int iriap_init(void); +void iriap_cleanup(void); + +struct iriap_cb *iriap_open(__u8 slsap_sel, int mode, void *priv, + CONFIRM_CALLBACK callback); +void iriap_close(struct iriap_cb *self); + +int iriap_getvaluebyclass_request(struct iriap_cb *self, + __u32 saddr, __u32 daddr, + char *name, char *attr); +void iriap_connect_request(struct iriap_cb *self); +void iriap_send_ack( struct iriap_cb *self); +void iriap_call_indication(struct iriap_cb *self, struct sk_buff *skb); + +void iriap_register_server(void); + +#endif + + diff --git a/drivers/staging/irda/include/net/irda/iriap_event.h b/drivers/staging/irda/include/net/irda/iriap_event.h new file mode 100644 index 000000000000..89747f06d9eb --- /dev/null +++ b/drivers/staging/irda/include/net/irda/iriap_event.h @@ -0,0 +1,85 @@ +/********************************************************************* + * + * Filename: iriap_event.h + * Version: + * Description: + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Mon Aug 4 20:40:53 1997 + * Modified at: Sun Oct 31 22:02:54 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#ifndef IRIAP_FSM_H +#define IRIAP_FSM_H + +/* Forward because of circular include dependecies */ +struct iriap_cb; + +/* IrIAP states */ +typedef enum { + /* Client */ + S_DISCONNECT, + S_CONNECTING, + S_CALL, + + /* S-Call */ + S_MAKE_CALL, + S_CALLING, + S_OUTSTANDING, + S_REPLYING, + S_WAIT_FOR_CALL, + S_WAIT_ACTIVE, + + /* Server */ + R_DISCONNECT, + R_CALL, + + /* R-Connect */ + R_WAITING, + R_WAIT_ACTIVE, + R_RECEIVING, + R_EXECUTE, + R_RETURNING, +} IRIAP_STATE; + +typedef enum { + IAP_CALL_REQUEST, + IAP_CALL_REQUEST_GVBC, + IAP_CALL_RESPONSE, + IAP_RECV_F_LST, + IAP_LM_DISCONNECT_INDICATION, + IAP_LM_CONNECT_INDICATION, + IAP_LM_CONNECT_CONFIRM, +} IRIAP_EVENT; + +void iriap_next_client_state (struct iriap_cb *self, IRIAP_STATE state); +void iriap_next_call_state (struct iriap_cb *self, IRIAP_STATE state); +void iriap_next_server_state (struct iriap_cb *self, IRIAP_STATE state); +void iriap_next_r_connect_state(struct iriap_cb *self, IRIAP_STATE state); + + +void iriap_do_client_event(struct iriap_cb *self, IRIAP_EVENT event, + struct sk_buff *skb); +void iriap_do_call_event (struct iriap_cb *self, IRIAP_EVENT event, + struct sk_buff *skb); + +void iriap_do_server_event (struct iriap_cb *self, IRIAP_EVENT event, + struct sk_buff *skb); +void iriap_do_r_connect_event(struct iriap_cb *self, IRIAP_EVENT event, + struct sk_buff *skb); + +#endif /* IRIAP_FSM_H */ + diff --git a/drivers/staging/irda/include/net/irda/irias_object.h b/drivers/staging/irda/include/net/irda/irias_object.h new file mode 100644 index 000000000000..83f78081799c --- /dev/null +++ b/drivers/staging/irda/include/net/irda/irias_object.h @@ -0,0 +1,108 @@ +/********************************************************************* + * + * Filename: irias_object.h + * Version: + * Description: + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Thu Oct 1 22:49:50 1998 + * Modified at: Wed Dec 15 11:20:57 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#ifndef LM_IAS_OBJECT_H +#define LM_IAS_OBJECT_H + +#include <net/irda/irda.h> +#include <net/irda/irqueue.h> + +/* LM-IAS Attribute types */ +#define IAS_MISSING 0 +#define IAS_INTEGER 1 +#define IAS_OCT_SEQ 2 +#define IAS_STRING 3 + +/* Object ownership of attributes (user or kernel) */ +#define IAS_KERNEL_ATTR 0 +#define IAS_USER_ATTR 1 + +/* + * LM-IAS Object + */ +struct ias_object { + irda_queue_t q; /* Must be first! */ + magic_t magic; + + char *name; + int id; + hashbin_t *attribs; +}; + +/* + * Values used by LM-IAS attributes + */ +struct ias_value { + __u8 type; /* Value description */ + __u8 owner; /* Managed from user/kernel space */ + int charset; /* Only used by string type */ + int len; + + /* Value */ + union { + int integer; + char *string; + __u8 *oct_seq; + } t; +}; + +/* + * Attributes used by LM-IAS objects + */ +struct ias_attrib { + irda_queue_t q; /* Must be first! */ + int magic; + + char *name; /* Attribute name */ + struct ias_value *value; /* Attribute value */ +}; + +struct ias_object *irias_new_object(char *name, int id); +void irias_insert_object(struct ias_object *obj); +int irias_delete_object(struct ias_object *obj); +int irias_delete_attrib(struct ias_object *obj, struct ias_attrib *attrib, + int cleanobject); +void __irias_delete_object(struct ias_object *obj); + +void irias_add_integer_attrib(struct ias_object *obj, char *name, int value, + int user); +void irias_add_string_attrib(struct ias_object *obj, char *name, char *value, + int user); +void irias_add_octseq_attrib(struct ias_object *obj, char *name, __u8 *octets, + int len, int user); +int irias_object_change_attribute(char *obj_name, char *attrib_name, + struct ias_value *new_value); +struct ias_object *irias_find_object(char *name); +struct ias_attrib *irias_find_attrib(struct ias_object *obj, char *name); + +struct ias_value *irias_new_string_value(char *string); +struct ias_value *irias_new_integer_value(int integer); +struct ias_value *irias_new_octseq_value(__u8 *octseq , int len); +struct ias_value *irias_new_missing_value(void); +void irias_delete_value(struct ias_value *value); + +extern struct ias_value irias_missing; +extern hashbin_t *irias_objects; + +#endif diff --git a/drivers/staging/irda/include/net/irda/irlan_client.h b/drivers/staging/irda/include/net/irda/irlan_client.h new file mode 100644 index 000000000000..fa8455eda280 --- /dev/null +++ b/drivers/staging/irda/include/net/irda/irlan_client.h @@ -0,0 +1,42 @@ +/********************************************************************* + * + * Filename: irlan_client.h + * Version: 0.3 + * Description: IrDA LAN access layer + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Sun Aug 31 20:14:37 1997 + * Modified at: Thu Apr 22 14:13:34 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#ifndef IRLAN_CLIENT_H +#define IRLAN_CLIENT_H + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/skbuff.h> +#include <linux/netdevice.h> + +#include <net/irda/irias_object.h> +#include <net/irda/irlan_event.h> + +void irlan_client_discovery_indication(discinfo_t *, DISCOVERY_MODE, void *); +void irlan_client_wakeup(struct irlan_cb *self, __u32 saddr, __u32 daddr); + +void irlan_client_parse_response(struct irlan_cb *self, struct sk_buff *skb); +void irlan_client_get_value_confirm(int result, __u16 obj_id, + struct ias_value *value, void *priv); +#endif diff --git a/drivers/staging/irda/include/net/irda/irlan_common.h b/drivers/staging/irda/include/net/irda/irlan_common.h new file mode 100644 index 000000000000..550c2d6ec7ff --- /dev/null +++ b/drivers/staging/irda/include/net/irda/irlan_common.h @@ -0,0 +1,230 @@ +/********************************************************************* + * + * Filename: irlan_common.h + * Version: 0.8 + * Description: IrDA LAN access layer + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Sun Aug 31 20:14:37 1997 + * Modified at: Sun Oct 31 19:41:24 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#ifndef IRLAN_H +#define IRLAN_H + +#include <asm/param.h> /* for HZ */ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/skbuff.h> +#include <linux/netdevice.h> +#include <linux/if_ether.h> + +#include <net/irda/irttp.h> + +#define IRLAN_MTU 1518 +#define IRLAN_TIMEOUT 10*HZ /* 10 seconds */ + +/* Command packet types */ +#define CMD_GET_PROVIDER_INFO 0 +#define CMD_GET_MEDIA_CHAR 1 +#define CMD_OPEN_DATA_CHANNEL 2 +#define CMD_CLOSE_DATA_CHAN 3 +#define CMD_RECONNECT_DATA_CHAN 4 +#define CMD_FILTER_OPERATION 5 + +/* Some responses */ +#define RSP_SUCCESS 0 +#define RSP_INSUFFICIENT_RESOURCES 1 +#define RSP_INVALID_COMMAND_FORMAT 2 +#define RSP_COMMAND_NOT_SUPPORTED 3 +#define RSP_PARAM_NOT_SUPPORTED 4 +#define RSP_VALUE_NOT_SUPPORTED 5 +#define RSP_NOT_OPEN 6 +#define RSP_AUTHENTICATION_REQUIRED 7 +#define RSP_INVALID_PASSWORD 8 +#define RSP_PROTOCOL_ERROR 9 +#define RSP_ASYNCHRONOUS_ERROR 255 + +/* Media types */ +#define MEDIA_802_3 1 +#define MEDIA_802_5 2 + +/* Filter parameters */ +#define DATA_CHAN 1 +#define FILTER_TYPE 2 +#define FILTER_MODE 3 + +/* Filter types */ +#define IRLAN_DIRECTED 0x01 +#define IRLAN_FUNCTIONAL 0x02 +#define IRLAN_GROUP 0x04 +#define IRLAN_MAC_FRAME 0x08 +#define IRLAN_MULTICAST 0x10 +#define IRLAN_BROADCAST 0x20 +#define IRLAN_IPX_SOCKET 0x40 + +/* Filter modes */ +#define ALL 1 +#define FILTER 2 +#define NONE 3 + +/* Filter operations */ +#define GET 1 +#define CLEAR 2 +#define ADD 3 +#define REMOVE 4 +#define DYNAMIC 5 + +/* Access types */ +#define ACCESS_DIRECT 1 +#define ACCESS_PEER 2 +#define ACCESS_HOSTED 3 + +#define IRLAN_BYTE 0 +#define IRLAN_SHORT 1 +#define IRLAN_ARRAY 2 + +/* IrLAN sits on top if IrTTP */ +#define IRLAN_MAX_HEADER (TTP_HEADER+LMP_HEADER) +/* 1 byte for the command code and 1 byte for the parameter count */ +#define IRLAN_CMD_HEADER 2 + +#define IRLAN_STRING_PARAMETER_LEN(name, value) (1 + strlen((name)) + 2 \ + + strlen ((value))) +#define IRLAN_BYTE_PARAMETER_LEN(name) (1 + strlen((name)) + 2 + 1) +#define IRLAN_SHORT_PARAMETER_LEN(name) (1 + strlen((name)) + 2 + 2) + +/* + * IrLAN client + */ +struct irlan_client_cb { + int state; + + int open_retries; + + struct tsap_cb *tsap_ctrl; + __u32 max_sdu_size; + __u8 max_header_size; + + int access_type; /* Access type of provider */ + __u8 reconnect_key[255]; + __u8 key_len; + + __u16 recv_arb_val; + __u16 max_frame; + int filter_type; + + int unicast_open; + int broadcast_open; + + int tx_busy; + struct sk_buff_head txq; /* Transmit control queue */ + + struct iriap_cb *iriap; + + struct timer_list kick_timer; +}; + +/* + * IrLAN provider + */ +struct irlan_provider_cb { + int state; + + struct tsap_cb *tsap_ctrl; + __u32 max_sdu_size; + __u8 max_header_size; + + /* + * Store some values here which are used by the provider to parse + * the filter operations + */ + int data_chan; + int filter_type; + int filter_mode; + int filter_operation; + int filter_entry; + int access_type; /* Access type */ + __u16 send_arb_val; + + __u8 mac_address[ETH_ALEN]; /* Generated MAC address for peer device */ +}; + +/* + * IrLAN control block + */ +struct irlan_cb { + int magic; + struct list_head dev_list; + struct net_device *dev; /* Ethernet device structure*/ + + __u32 saddr; /* Source device address */ + __u32 daddr; /* Destination device address */ + int disconnect_reason; /* Why we got disconnected */ + + int media; /* Media type */ + __u8 version[2]; /* IrLAN version */ + + struct tsap_cb *tsap_data; /* Data TSAP */ + + int use_udata; /* Use Unit Data transfers */ + + __u8 stsap_sel_data; /* Source data TSAP selector */ + __u8 dtsap_sel_data; /* Destination data TSAP selector */ + __u8 dtsap_sel_ctrl; /* Destination ctrl TSAP selector */ + + struct irlan_client_cb client; /* Client specific fields */ + struct irlan_provider_cb provider; /* Provider specific fields */ + + __u32 max_sdu_size; + __u8 max_header_size; + + wait_queue_head_t open_wait; + struct timer_list watchdog_timer; +}; + +void irlan_close(struct irlan_cb *self); +void irlan_close_tsaps(struct irlan_cb *self); + +int irlan_register_netdev(struct irlan_cb *self); +void irlan_ias_register(struct irlan_cb *self, __u8 tsap_sel); +void irlan_start_watchdog_timer(struct irlan_cb *self, int timeout); + +void irlan_open_data_tsap(struct irlan_cb *self); + +int irlan_run_ctrl_tx_queue(struct irlan_cb *self); + +struct irlan_cb *irlan_get_any(void); +void irlan_get_provider_info(struct irlan_cb *self); +void irlan_get_media_char(struct irlan_cb *self); +void irlan_open_data_channel(struct irlan_cb *self); +void irlan_close_data_channel(struct irlan_cb *self); +void irlan_set_multicast_filter(struct irlan_cb *self, int status); +void irlan_set_broadcast_filter(struct irlan_cb *self, int status); + +int irlan_insert_byte_param(struct sk_buff *skb, char *param, __u8 value); +int irlan_insert_short_param(struct sk_buff *skb, char *param, __u16 value); +int irlan_insert_string_param(struct sk_buff *skb, char *param, char *value); +int irlan_insert_array_param(struct sk_buff *skb, char *name, __u8 *value, + __u16 value_len); + +int irlan_extract_param(__u8 *buf, char *name, char *value, __u16 *len); + +#endif + + diff --git a/drivers/staging/irda/include/net/irda/irlan_eth.h b/drivers/staging/irda/include/net/irda/irlan_eth.h new file mode 100644 index 000000000000..de5c81691f33 --- /dev/null +++ b/drivers/staging/irda/include/net/irda/irlan_eth.h @@ -0,0 +1,32 @@ +/********************************************************************* + * + * Filename: irlan_eth.h + * Version: + * Description: + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Thu Oct 15 08:36:58 1998 + * Modified at: Fri May 14 23:29:00 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#ifndef IRLAN_ETH_H +#define IRLAN_ETH_H + +struct net_device *alloc_irlandev(const char *name); +int irlan_eth_receive(void *instance, void *sap, struct sk_buff *skb); + +void irlan_eth_flow_indication( void *instance, void *sap, LOCAL_FLOW flow); +#endif diff --git a/drivers/staging/irda/include/net/irda/irlan_event.h b/drivers/staging/irda/include/net/irda/irlan_event.h new file mode 100644 index 000000000000..018b5a77e610 --- /dev/null +++ b/drivers/staging/irda/include/net/irda/irlan_event.h @@ -0,0 +1,81 @@ +/********************************************************************* + * + * Filename: irlan_event.h + * Version: + * Description: LAN access + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Sun Aug 31 20:14:37 1997 + * Modified at: Tue Feb 2 09:45:17 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1997 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#ifndef IRLAN_EVENT_H +#define IRLAN_EVENT_H + +#include <linux/kernel.h> +#include <linux/skbuff.h> + +#include <net/irda/irlan_common.h> + +typedef enum { + IRLAN_IDLE, + IRLAN_QUERY, + IRLAN_CONN, + IRLAN_INFO, + IRLAN_MEDIA, + IRLAN_OPEN, + IRLAN_WAIT, + IRLAN_ARB, + IRLAN_DATA, + IRLAN_CLOSE, + IRLAN_SYNC +} IRLAN_STATE; + +typedef enum { + IRLAN_DISCOVERY_INDICATION, + IRLAN_IAS_PROVIDER_AVAIL, + IRLAN_IAS_PROVIDER_NOT_AVAIL, + IRLAN_LAP_DISCONNECT, + IRLAN_LMP_DISCONNECT, + IRLAN_CONNECT_COMPLETE, + IRLAN_DATA_INDICATION, + IRLAN_DATA_CONNECT_INDICATION, + IRLAN_RETRY_CONNECT, + + IRLAN_CONNECT_INDICATION, + IRLAN_GET_INFO_CMD, + IRLAN_GET_MEDIA_CMD, + IRLAN_OPEN_DATA_CMD, + IRLAN_FILTER_CONFIG_CMD, + + IRLAN_CHECK_CON_ARB, + IRLAN_PROVIDER_SIGNAL, + + IRLAN_WATCHDOG_TIMEOUT, +} IRLAN_EVENT; + +extern const char * const irlan_state[]; + +void irlan_do_client_event(struct irlan_cb *self, IRLAN_EVENT event, + struct sk_buff *skb); + +void irlan_do_provider_event(struct irlan_cb *self, IRLAN_EVENT event, + struct sk_buff *skb); + +void irlan_next_client_state(struct irlan_cb *self, IRLAN_STATE state); +void irlan_next_provider_state(struct irlan_cb *self, IRLAN_STATE state); + +#endif diff --git a/drivers/staging/irda/include/net/irda/irlan_filter.h b/drivers/staging/irda/include/net/irda/irlan_filter.h new file mode 100644 index 000000000000..a5a2539485bd --- /dev/null +++ b/drivers/staging/irda/include/net/irda/irlan_filter.h @@ -0,0 +1,35 @@ +/********************************************************************* + * + * Filename: irlan_filter.h + * Version: + * Description: + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Fri Jan 29 15:24:08 1999 + * Modified at: Sun Feb 7 23:35:31 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1998 Dag Brattli, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#ifndef IRLAN_FILTER_H +#define IRLAN_FILTER_H + +void irlan_check_command_param(struct irlan_cb *self, char *param, + char *value); +void irlan_filter_request(struct irlan_cb *self, struct sk_buff *skb); +#ifdef CONFIG_PROC_FS +void irlan_print_filter(struct seq_file *seq, int filter_type); +#endif + +#endif /* IRLAN_FILTER_H */ diff --git a/drivers/staging/irda/include/net/irda/irlan_provider.h b/drivers/staging/irda/include/net/irda/irlan_provider.h new file mode 100644 index 000000000000..92f3b0e1029b --- /dev/null +++ b/drivers/staging/irda/include/net/irda/irlan_provider.h @@ -0,0 +1,52 @@ +/********************************************************************* + * + * Filename: irlan_provider.h + * Version: 0.1 + * Description: IrDA LAN access layer + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Sun Aug 31 20:14:37 1997 + * Modified at: Sun May 9 12:26:11 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#ifndef IRLAN_SERVER_H +#define IRLAN_SERVER_H + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/skbuff.h> +#include <linux/netdevice.h> + +#include <net/irda/irlan_common.h> + +void irlan_provider_ctrl_disconnect_indication(void *instance, void *sap, + LM_REASON reason, + struct sk_buff *skb); + + +void irlan_provider_connect_response(struct irlan_cb *, struct tsap_cb *); + +int irlan_parse_open_data_cmd(struct irlan_cb *self, struct sk_buff *skb); +int irlan_provider_parse_command(struct irlan_cb *self, int cmd, + struct sk_buff *skb); + +void irlan_provider_send_reply(struct irlan_cb *self, int command, + int ret_code); +int irlan_provider_open_ctrl_tsap(struct irlan_cb *self); + +#endif + + diff --git a/drivers/staging/irda/include/net/irda/irlap.h b/drivers/staging/irda/include/net/irda/irlap.h new file mode 100644 index 000000000000..6f23e820618c --- /dev/null +++ b/drivers/staging/irda/include/net/irda/irlap.h @@ -0,0 +1,311 @@ +/********************************************************************* + * + * Filename: irlap.h + * Version: 0.8 + * Description: An IrDA LAP driver for Linux + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Mon Aug 4 20:40:53 1997 + * Modified at: Fri Dec 10 13:21:17 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, + * All Rights Reserved. + * Copyright (c) 2000-2002 Jean Tourrilhes <jt@hpl.hp.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#ifndef IRLAP_H +#define IRLAP_H + +#include <linux/types.h> +#include <linux/skbuff.h> +#include <linux/netdevice.h> +#include <linux/timer.h> + +#include <net/irda/irqueue.h> /* irda_queue_t */ +#include <net/irda/qos.h> /* struct qos_info */ +#include <net/irda/discovery.h> /* discovery_t */ +#include <net/irda/irlap_event.h> /* IRLAP_STATE, ... */ +#include <net/irda/irmod.h> /* struct notify_t */ + +#define CONFIG_IRDA_DYNAMIC_WINDOW 1 + +#define LAP_RELIABLE 1 +#define LAP_UNRELIABLE 0 + +#define LAP_ADDR_HEADER 1 /* IrLAP Address Header */ +#define LAP_CTRL_HEADER 1 /* IrLAP Control Header */ + +/* May be different when we get VFIR */ +#define LAP_MAX_HEADER (LAP_ADDR_HEADER + LAP_CTRL_HEADER) + +/* Each IrDA device gets a random 32 bits IRLAP device address */ +#define LAP_ALEN 4 + +#define BROADCAST 0xffffffff /* Broadcast device address */ +#define CBROADCAST 0xfe /* Connection broadcast address */ +#define XID_FORMAT 0x01 /* Discovery XID format */ + +/* Nobody seems to use this constant. */ +#define LAP_WINDOW_SIZE 8 +/* We keep the LAP queue very small to minimise the amount of buffering. + * this improve latency and reduce resource consumption. + * This work only because we have synchronous refilling of IrLAP through + * the flow control mechanism (via scheduler and IrTTP). + * 2 buffers is the minimum we can work with, one that we send while polling + * IrTTP, and another to know that we should not send the pf bit. + * Jean II */ +#define LAP_HIGH_THRESHOLD 2 +/* Some rare non TTP clients don't implement flow control, and + * so don't comply with the above limit (and neither with this one). + * For IAP and management, it doesn't matter, because they never transmit much. + *.For IrLPT, this should be fixed. + * - Jean II */ +#define LAP_MAX_QUEUE 10 +/* Please note that all IrDA management frames (LMP/TTP conn req/disc and + * IAS queries) fall in the second category and are sent to LAP even if TTP + * is stopped. This means that those frames will wait only a maximum of + * two (2) data frames before beeing sent on the "wire", which speed up + * new socket setup when the link is saturated. + * Same story for two sockets competing for the medium : if one saturates + * the LAP, when the other want to transmit it only has to wait for + * maximum three (3) packets (2 + one scheduling), which improve performance + * of delay sensitive applications. + * Jean II */ + +#define NR_EXPECTED 1 +#define NR_UNEXPECTED 0 +#define NR_INVALID -1 + +#define NS_EXPECTED 1 +#define NS_UNEXPECTED 0 +#define NS_INVALID -1 + +/* + * Meta information passed within the IrLAP state machine + */ +struct irlap_info { + __u8 caddr; /* Connection address */ + __u8 control; /* Frame type */ + __u8 cmd; + + __u32 saddr; + __u32 daddr; + + int pf; /* Poll/final bit set */ + + __u8 nr; /* Sequence number of next frame expected */ + __u8 ns; /* Sequence number of frame sent */ + + int S; /* Number of slots */ + int slot; /* Random chosen slot */ + int s; /* Current slot */ + + discovery_t *discovery; /* Discovery information */ +}; + +/* Main structure of IrLAP */ +struct irlap_cb { + irda_queue_t q; /* Must be first */ + magic_t magic; + + /* Device we are attached to */ + struct net_device *netdev; + char hw_name[2*IFNAMSIZ + 1]; + + /* Connection state */ + volatile IRLAP_STATE state; /* Current state */ + + /* Timers used by IrLAP */ + struct timer_list query_timer; + struct timer_list slot_timer; + struct timer_list discovery_timer; + struct timer_list final_timer; + struct timer_list poll_timer; + struct timer_list wd_timer; + struct timer_list backoff_timer; + + /* Media busy stuff */ + struct timer_list media_busy_timer; + int media_busy; + + /* Timeouts which will be different with different turn time */ + int slot_timeout; + int poll_timeout; + int final_timeout; + int wd_timeout; + + struct sk_buff_head txq; /* Frames to be transmitted */ + struct sk_buff_head txq_ultra; + + __u8 caddr; /* Connection address */ + __u32 saddr; /* Source device address */ + __u32 daddr; /* Destination device address */ + + int retry_count; /* Times tried to establish connection */ + int add_wait; /* True if we are waiting for frame */ + + __u8 connect_pending; + __u8 disconnect_pending; + + /* To send a faster RR if tx queue empty */ +#ifdef CONFIG_IRDA_FAST_RR + int fast_RR_timeout; + int fast_RR; +#endif /* CONFIG_IRDA_FAST_RR */ + + int N1; /* N1 * F-timer = Negitiated link disconnect warning threshold */ + int N2; /* N2 * F-timer = Negitiated link disconnect time */ + int N3; /* Connection retry count */ + + int local_busy; + int remote_busy; + int xmitflag; + + __u8 vs; /* Next frame to be sent */ + __u8 vr; /* Next frame to be received */ + __u8 va; /* Last frame acked */ + int window; /* Nr of I-frames allowed to send */ + int window_size; /* Current negotiated window size */ + +#ifdef CONFIG_IRDA_DYNAMIC_WINDOW + __u32 line_capacity; /* Number of bytes allowed to send */ + __u32 bytes_left; /* Number of bytes still allowed to transmit */ +#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */ + + struct sk_buff_head wx_list; + + __u8 ack_required; + + /* XID parameters */ + __u8 S; /* Number of slots */ + __u8 slot; /* Random chosen slot */ + __u8 s; /* Current slot */ + int frame_sent; /* Have we sent reply? */ + + hashbin_t *discovery_log; + discovery_t *discovery_cmd; + + __u32 speed; /* Link speed */ + + struct qos_info qos_tx; /* QoS requested by peer */ + struct qos_info qos_rx; /* QoS requested by self */ + struct qos_info *qos_dev; /* QoS supported by device */ + + notify_t notify; /* Callbacks to IrLMP */ + + int mtt_required; /* Minimum turnaround time required */ + int xbofs_delay; /* Nr of XBOF's used to MTT */ + int bofs_count; /* Negotiated extra BOFs */ + int next_bofs; /* Negotiated extra BOFs after next frame */ + + int mode; /* IrLAP mode (primary, secondary or monitor) */ +}; + +/* + * Function prototypes + */ +int irlap_init(void); +void irlap_cleanup(void); + +struct irlap_cb *irlap_open(struct net_device *dev, struct qos_info *qos, + const char *hw_name); +void irlap_close(struct irlap_cb *self); + +void irlap_connect_request(struct irlap_cb *self, __u32 daddr, + struct qos_info *qos, int sniff); +void irlap_connect_response(struct irlap_cb *self, struct sk_buff *skb); +void irlap_connect_indication(struct irlap_cb *self, struct sk_buff *skb); +void irlap_connect_confirm(struct irlap_cb *, struct sk_buff *skb); + +void irlap_data_indication(struct irlap_cb *, struct sk_buff *, int unreliable); +void irlap_data_request(struct irlap_cb *, struct sk_buff *, int unreliable); + +#ifdef CONFIG_IRDA_ULTRA +void irlap_unitdata_request(struct irlap_cb *, struct sk_buff *); +void irlap_unitdata_indication(struct irlap_cb *, struct sk_buff *); +#endif /* CONFIG_IRDA_ULTRA */ + +void irlap_disconnect_request(struct irlap_cb *); +void irlap_disconnect_indication(struct irlap_cb *, LAP_REASON reason); + +void irlap_status_indication(struct irlap_cb *, int quality_of_link); + +void irlap_test_request(__u8 *info, int len); + +void irlap_discovery_request(struct irlap_cb *, discovery_t *discovery); +void irlap_discovery_confirm(struct irlap_cb *, hashbin_t *discovery_log); +void irlap_discovery_indication(struct irlap_cb *, discovery_t *discovery); + +void irlap_reset_indication(struct irlap_cb *self); +void irlap_reset_confirm(void); + +void irlap_update_nr_received(struct irlap_cb *, int nr); +int irlap_validate_nr_received(struct irlap_cb *, int nr); +int irlap_validate_ns_received(struct irlap_cb *, int ns); + +int irlap_generate_rand_time_slot(int S, int s); +void irlap_initiate_connection_state(struct irlap_cb *); +void irlap_flush_all_queues(struct irlap_cb *); +void irlap_wait_min_turn_around(struct irlap_cb *, struct qos_info *); + +void irlap_apply_default_connection_parameters(struct irlap_cb *self); +void irlap_apply_connection_parameters(struct irlap_cb *self, int now); + +#define IRLAP_GET_HEADER_SIZE(self) (LAP_MAX_HEADER) +#define IRLAP_GET_TX_QUEUE_LEN(self) skb_queue_len(&self->txq) + +/* Return TRUE if the node is in primary mode (i.e. master) + * - Jean II */ +static inline int irlap_is_primary(struct irlap_cb *self) +{ + int ret; + switch(self->state) { + case LAP_XMIT_P: + case LAP_NRM_P: + ret = 1; + break; + case LAP_XMIT_S: + case LAP_NRM_S: + ret = 0; + break; + default: + ret = -1; + } + return ret; +} + +/* Clear a pending IrLAP disconnect. - Jean II */ +static inline void irlap_clear_disconnect(struct irlap_cb *self) +{ + self->disconnect_pending = FALSE; +} + +/* + * Function irlap_next_state (self, state) + * + * Switches state and provides debug information + * + */ +static inline void irlap_next_state(struct irlap_cb *self, IRLAP_STATE state) +{ + /* + if (!self || self->magic != LAP_MAGIC) + return; + + pr_debug("next LAP state = %s\n", irlap_state[state]); + */ + self->state = state; +} + +#endif diff --git a/drivers/staging/irda/include/net/irda/irlap_event.h b/drivers/staging/irda/include/net/irda/irlap_event.h new file mode 100644 index 000000000000..e4325fee1267 --- /dev/null +++ b/drivers/staging/irda/include/net/irda/irlap_event.h @@ -0,0 +1,129 @@ +/********************************************************************* + * + * + * Filename: irlap_event.h + * Version: 0.1 + * Description: + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Sat Aug 16 00:59:29 1997 + * Modified at: Tue Dec 21 11:20:30 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, + * All Rights Reserved. + * Copyright (c) 2000-2002 Jean Tourrilhes <jt@hpl.hp.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + ********************************************************************/ + +#ifndef IRLAP_EVENT_H +#define IRLAP_EVENT_H + +#include <net/irda/irda.h> + +/* A few forward declarations (to make compiler happy) */ +struct irlap_cb; +struct irlap_info; + +/* IrLAP States */ +typedef enum { + LAP_NDM, /* Normal disconnected mode */ + LAP_QUERY, + LAP_REPLY, + LAP_CONN, /* Connect indication */ + LAP_SETUP, /* Setting up connection */ + LAP_OFFLINE, /* A really boring state */ + LAP_XMIT_P, + LAP_PCLOSE, + LAP_NRM_P, /* Normal response mode as primary */ + LAP_RESET_WAIT, + LAP_RESET, + LAP_NRM_S, /* Normal response mode as secondary */ + LAP_XMIT_S, + LAP_SCLOSE, + LAP_RESET_CHECK, +} IRLAP_STATE; + +/* IrLAP Events */ +typedef enum { + /* Services events */ + DISCOVERY_REQUEST, + CONNECT_REQUEST, + CONNECT_RESPONSE, + DISCONNECT_REQUEST, + DATA_REQUEST, + RESET_REQUEST, + RESET_RESPONSE, + + /* Send events */ + SEND_I_CMD, + SEND_UI_FRAME, + + /* Receive events */ + RECV_DISCOVERY_XID_CMD, + RECV_DISCOVERY_XID_RSP, + RECV_SNRM_CMD, + RECV_TEST_CMD, + RECV_TEST_RSP, + RECV_UA_RSP, + RECV_DM_RSP, + RECV_RD_RSP, + RECV_I_CMD, + RECV_I_RSP, + RECV_UI_FRAME, + RECV_FRMR_RSP, + RECV_RR_CMD, + RECV_RR_RSP, + RECV_RNR_CMD, + RECV_RNR_RSP, + RECV_REJ_CMD, + RECV_REJ_RSP, + RECV_SREJ_CMD, + RECV_SREJ_RSP, + RECV_DISC_CMD, + + /* Timer events */ + SLOT_TIMER_EXPIRED, + QUERY_TIMER_EXPIRED, + FINAL_TIMER_EXPIRED, + POLL_TIMER_EXPIRED, + DISCOVERY_TIMER_EXPIRED, + WD_TIMER_EXPIRED, + BACKOFF_TIMER_EXPIRED, + MEDIA_BUSY_TIMER_EXPIRED, +} IRLAP_EVENT; + +/* + * Disconnect reason code + */ +typedef enum { /* FIXME check the two first reason codes */ + LAP_DISC_INDICATION=1, /* Received a disconnect request from peer */ + LAP_NO_RESPONSE, /* To many retransmits without response */ + LAP_RESET_INDICATION, /* To many retransmits, or invalid nr/ns */ + LAP_FOUND_NONE, /* No devices were discovered */ + LAP_MEDIA_BUSY, + LAP_PRIMARY_CONFLICT, +} LAP_REASON; + +extern const char *const irlap_state[]; + +void irlap_do_event(struct irlap_cb *self, IRLAP_EVENT event, + struct sk_buff *skb, struct irlap_info *info); +void irlap_print_event(IRLAP_EVENT event); + +int irlap_qos_negotiate(struct irlap_cb *self, struct sk_buff *skb); + +#endif diff --git a/drivers/staging/irda/include/net/irda/irlap_frame.h b/drivers/staging/irda/include/net/irda/irlap_frame.h new file mode 100644 index 000000000000..cbc12a926e5f --- /dev/null +++ b/drivers/staging/irda/include/net/irda/irlap_frame.h @@ -0,0 +1,167 @@ +/********************************************************************* + * + * Filename: irlap_frame.h + * Version: 0.9 + * Description: IrLAP frame declarations + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Tue Aug 19 10:27:26 1997 + * Modified at: Sat Dec 25 21:07:26 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1997-1999 Dag Brattli <dagb@cs.uit.no>, + * All Rights Reserved. + * Copyright (c) 2000-2002 Jean Tourrilhes <jt@hpl.hp.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + ********************************************************************/ + +#ifndef IRLAP_FRAME_H +#define IRLAP_FRAME_H + +#include <linux/skbuff.h> + +#include <net/irda/irda.h> + +/* A few forward declarations (to make compiler happy) */ +struct irlap_cb; +struct discovery_t; + +/* Frame types and templates */ +#define INVALID 0xff + +/* Unnumbered (U) commands */ +#define SNRM_CMD 0x83 /* Set Normal Response Mode */ +#define DISC_CMD 0x43 /* Disconnect */ +#define XID_CMD 0x2f /* Exchange Station Identification */ +#define TEST_CMD 0xe3 /* Test */ + +/* Unnumbered responses */ +#define RNRM_RSP 0x83 /* Request Normal Response Mode */ +#define UA_RSP 0x63 /* Unnumbered Acknowledgement */ +#define FRMR_RSP 0x87 /* Frame Reject */ +#define DM_RSP 0x0f /* Disconnect Mode */ +#define RD_RSP 0x43 /* Request Disconnection */ +#define XID_RSP 0xaf /* Exchange Station Identification */ +#define TEST_RSP 0xe3 /* Test frame */ + +/* Supervisory (S) */ +#define RR 0x01 /* Receive Ready */ +#define REJ 0x09 /* Reject */ +#define RNR 0x05 /* Receive Not Ready */ +#define SREJ 0x0d /* Selective Reject */ + +/* Information (I) */ +#define I_FRAME 0x00 /* Information Format */ +#define UI_FRAME 0x03 /* Unnumbered Information */ + +#define CMD_FRAME 0x01 +#define RSP_FRAME 0x00 + +#define PF_BIT 0x10 /* Poll/final bit */ + +/* Some IrLAP field lengths */ +/* + * Only baud rate triplet is 4 bytes (PV can be 2 bytes). + * All others params (7) are 3 bytes, so that's 7*3 + 1*4 bytes. + */ +#define IRLAP_NEGOCIATION_PARAMS_LEN 25 +#define IRLAP_DISCOVERY_INFO_LEN 32 + +struct disc_frame { + __u8 caddr; /* Connection address */ + __u8 control; +} __packed; + +struct xid_frame { + __u8 caddr; /* Connection address */ + __u8 control; + __u8 ident; /* Should always be XID_FORMAT */ + __le32 saddr; /* Source device address */ + __le32 daddr; /* Destination device address */ + __u8 flags; /* Discovery flags */ + __u8 slotnr; + __u8 version; +} __packed; + +struct test_frame { + __u8 caddr; /* Connection address */ + __u8 control; + __le32 saddr; /* Source device address */ + __le32 daddr; /* Destination device address */ +} __packed; + +struct ua_frame { + __u8 caddr; + __u8 control; + __le32 saddr; /* Source device address */ + __le32 daddr; /* Dest device address */ +} __packed; + +struct dm_frame { + __u8 caddr; /* Connection address */ + __u8 control; +} __packed; + +struct rd_frame { + __u8 caddr; /* Connection address */ + __u8 control; +} __packed; + +struct rr_frame { + __u8 caddr; /* Connection address */ + __u8 control; +} __packed; + +struct i_frame { + __u8 caddr; + __u8 control; +} __packed; + +struct snrm_frame { + __u8 caddr; + __u8 control; + __le32 saddr; + __le32 daddr; + __u8 ncaddr; +} __packed; + +void irlap_queue_xmit(struct irlap_cb *self, struct sk_buff *skb); +void irlap_send_discovery_xid_frame(struct irlap_cb *, int S, __u8 s, + __u8 command, + struct discovery_t *discovery); +void irlap_send_snrm_frame(struct irlap_cb *, struct qos_info *); +void irlap_send_test_frame(struct irlap_cb *self, __u8 caddr, __u32 daddr, + struct sk_buff *cmd); +void irlap_send_ua_response_frame(struct irlap_cb *, struct qos_info *); +void irlap_send_dm_frame(struct irlap_cb *self); +void irlap_send_rd_frame(struct irlap_cb *self); +void irlap_send_disc_frame(struct irlap_cb *self); +void irlap_send_rr_frame(struct irlap_cb *self, int command); + +void irlap_send_data_primary(struct irlap_cb *, struct sk_buff *); +void irlap_send_data_primary_poll(struct irlap_cb *, struct sk_buff *); +void irlap_send_data_secondary(struct irlap_cb *, struct sk_buff *); +void irlap_send_data_secondary_final(struct irlap_cb *, struct sk_buff *); +void irlap_resend_rejected_frames(struct irlap_cb *, int command); +void irlap_resend_rejected_frame(struct irlap_cb *self, int command); + +void irlap_send_ui_frame(struct irlap_cb *self, struct sk_buff *skb, + __u8 caddr, int command); + +int irlap_insert_qos_negotiation_params(struct irlap_cb *self, + struct sk_buff *skb); + +#endif diff --git a/drivers/staging/irda/include/net/irda/irlmp.h b/drivers/staging/irda/include/net/irda/irlmp.h new file mode 100644 index 000000000000..f132924cc9da --- /dev/null +++ b/drivers/staging/irda/include/net/irda/irlmp.h @@ -0,0 +1,295 @@ +/********************************************************************* + * + * Filename: irlmp.h + * Version: 0.9 + * Description: IrDA Link Management Protocol (LMP) layer + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Sun Aug 17 20:54:32 1997 + * Modified at: Fri Dec 10 13:23:01 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, + * All Rights Reserved. + * Copyright (c) 2000-2002 Jean Tourrilhes <jt@hpl.hp.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#ifndef IRLMP_H +#define IRLMP_H + +#include <asm/param.h> /* for HZ */ + +#include <linux/types.h> + +#include <net/irda/irda.h> +#include <net/irda/qos.h> +#include <net/irda/irlap.h> /* LAP_MAX_HEADER, ... */ +#include <net/irda/irlmp_event.h> +#include <net/irda/irqueue.h> +#include <net/irda/discovery.h> + +/* LSAP-SEL's */ +#define LSAP_MASK 0x7f +#define LSAP_IAS 0x00 +#define LSAP_ANY 0xff +#define LSAP_MAX 0x6f /* 0x70-0x7f are reserved */ +#define LSAP_CONNLESS 0x70 /* Connectionless LSAP, mostly used for Ultra */ + +#define DEV_ADDR_ANY 0xffffffff + +#define LMP_HEADER 2 /* Dest LSAP + Source LSAP */ +#define LMP_CONTROL_HEADER 4 /* LMP_HEADER + opcode + parameter */ +#define LMP_PID_HEADER 1 /* Used by Ultra */ +#define LMP_MAX_HEADER (LMP_CONTROL_HEADER+LAP_MAX_HEADER) + +#define LM_MAX_CONNECTIONS 10 + +#define LM_IDLE_TIMEOUT 2*HZ /* 2 seconds for now */ + +typedef enum { + S_PNP = 0, + S_PDA, + S_COMPUTER, + S_PRINTER, + S_MODEM, + S_FAX, + S_LAN, + S_TELEPHONY, + S_COMM, + S_OBEX, + S_ANY, + S_END, +} SERVICE; + +/* For selective discovery */ +typedef void (*DISCOVERY_CALLBACK1) (discinfo_t *, DISCOVERY_MODE, void *); +/* For expiry (the same) */ +typedef void (*DISCOVERY_CALLBACK2) (discinfo_t *, DISCOVERY_MODE, void *); + +typedef struct { + irda_queue_t queue; /* Must be first */ + + __u16_host_order hints; /* Hint bits */ +} irlmp_service_t; + +typedef struct { + irda_queue_t queue; /* Must be first */ + + __u16_host_order hint_mask; + + DISCOVERY_CALLBACK1 disco_callback; /* Selective discovery */ + DISCOVERY_CALLBACK2 expir_callback; /* Selective expiration */ + void *priv; /* Used to identify client */ +} irlmp_client_t; + +/* + * Information about each logical LSAP connection + */ +struct lsap_cb { + irda_queue_t queue; /* Must be first */ + magic_t magic; + + unsigned long connected; /* set_bit used on this */ + int persistent; + + __u8 slsap_sel; /* Source (this) LSAP address */ + __u8 dlsap_sel; /* Destination LSAP address (if connected) */ +#ifdef CONFIG_IRDA_ULTRA + __u8 pid; /* Used by connectionless LSAP */ +#endif /* CONFIG_IRDA_ULTRA */ + struct sk_buff *conn_skb; /* Store skb here while connecting */ + + struct timer_list watchdog_timer; + + LSAP_STATE lsap_state; /* Connection state */ + notify_t notify; /* Indication/Confirm entry points */ + struct qos_info qos; /* QoS for this connection */ + + struct lap_cb *lap; /* Pointer to LAP connection structure */ +}; + +/* + * Used for caching the last slsap->dlsap->handle mapping + * + * We don't need to keep/match the remote address in the cache because + * we are associated with a specific LAP (which implies it). + * Jean II + */ +typedef struct { + int valid; + + __u8 slsap_sel; + __u8 dlsap_sel; + struct lsap_cb *lsap; +} CACHE_ENTRY; + +/* + * Information about each registered IrLAP layer + */ +struct lap_cb { + irda_queue_t queue; /* Must be first */ + magic_t magic; + + int reason; /* LAP disconnect reason */ + + IRLMP_STATE lap_state; + + struct irlap_cb *irlap; /* Instance of IrLAP layer */ + hashbin_t *lsaps; /* LSAP associated with this link */ + struct lsap_cb *flow_next; /* Next lsap to be polled for Tx */ + + __u8 caddr; /* Connection address */ + __u32 saddr; /* Source device address */ + __u32 daddr; /* Destination device address */ + + struct qos_info *qos; /* LAP QoS for this session */ + struct timer_list idle_timer; + +#ifdef CONFIG_IRDA_CACHE_LAST_LSAP + /* The lsap cache was moved from struct irlmp_cb to here because + * it must be associated with the specific LAP. Also, this + * improves performance. - Jean II */ + CACHE_ENTRY cache; /* Caching last slsap->dlsap->handle mapping */ +#endif +}; + +/* + * Main structure for IrLMP + */ +struct irlmp_cb { + magic_t magic; + + __u8 conflict_flag; + + discovery_t discovery_cmd; /* Discovery command to use by IrLAP */ + discovery_t discovery_rsp; /* Discovery response to use by IrLAP */ + + /* Last lsap picked automatically by irlmp_find_free_slsap() */ + int last_lsap_sel; + + struct timer_list discovery_timer; + + hashbin_t *links; /* IrLAP connection table */ + hashbin_t *unconnected_lsaps; + hashbin_t *clients; + hashbin_t *services; + + hashbin_t *cachelog; /* Current discovery log */ + + int running; + + __u16_host_order hints; /* Hint bits */ +}; + +/* Prototype declarations */ +int irlmp_init(void); +void irlmp_cleanup(void); +struct lsap_cb *irlmp_open_lsap(__u8 slsap, notify_t *notify, __u8 pid); +void irlmp_close_lsap( struct lsap_cb *self); + +__u16 irlmp_service_to_hint(int service); +void *irlmp_register_service(__u16 hints); +int irlmp_unregister_service(void *handle); +void *irlmp_register_client(__u16 hint_mask, DISCOVERY_CALLBACK1 disco_clb, + DISCOVERY_CALLBACK2 expir_clb, void *priv); +int irlmp_unregister_client(void *handle); +int irlmp_update_client(void *handle, __u16 hint_mask, + DISCOVERY_CALLBACK1 disco_clb, + DISCOVERY_CALLBACK2 expir_clb, void *priv); + +void irlmp_register_link(struct irlap_cb *, __u32 saddr, notify_t *); +void irlmp_unregister_link(__u32 saddr); + +int irlmp_connect_request(struct lsap_cb *, __u8 dlsap_sel, + __u32 saddr, __u32 daddr, + struct qos_info *, struct sk_buff *); +void irlmp_connect_indication(struct lsap_cb *self, struct sk_buff *skb); +int irlmp_connect_response(struct lsap_cb *, struct sk_buff *); +void irlmp_connect_confirm(struct lsap_cb *, struct sk_buff *); +struct lsap_cb *irlmp_dup(struct lsap_cb *self, void *instance); + +void irlmp_disconnect_indication(struct lsap_cb *self, LM_REASON reason, + struct sk_buff *userdata); +int irlmp_disconnect_request(struct lsap_cb *, struct sk_buff *userdata); + +void irlmp_discovery_confirm(hashbin_t *discovery_log, DISCOVERY_MODE mode); +void irlmp_discovery_request(int nslots); +discinfo_t *irlmp_get_discoveries(int *pn, __u16 mask, int nslots); +void irlmp_do_expiry(void); +void irlmp_do_discovery(int nslots); +discovery_t *irlmp_get_discovery_response(void); +void irlmp_discovery_expiry(discinfo_t *expiry, int number); + +int irlmp_data_request(struct lsap_cb *, struct sk_buff *); +void irlmp_data_indication(struct lsap_cb *, struct sk_buff *); + +int irlmp_udata_request(struct lsap_cb *, struct sk_buff *); +void irlmp_udata_indication(struct lsap_cb *, struct sk_buff *); + +#ifdef CONFIG_IRDA_ULTRA +int irlmp_connless_data_request(struct lsap_cb *, struct sk_buff *, __u8); +void irlmp_connless_data_indication(struct lsap_cb *, struct sk_buff *); +#endif /* CONFIG_IRDA_ULTRA */ + +void irlmp_status_indication(struct lap_cb *, LINK_STATUS link, LOCK_STATUS lock); +void irlmp_flow_indication(struct lap_cb *self, LOCAL_FLOW flow); + +LM_REASON irlmp_convert_lap_reason(LAP_REASON); + +static inline __u32 irlmp_get_saddr(const struct lsap_cb *self) +{ + return (self && self->lap) ? self->lap->saddr : 0; +} + +static inline __u32 irlmp_get_daddr(const struct lsap_cb *self) +{ + return (self && self->lap) ? self->lap->daddr : 0; +} + +const char *irlmp_reason_str(LM_REASON reason); + +extern int sysctl_discovery_timeout; +extern int sysctl_discovery_slots; +extern int sysctl_discovery; +extern int sysctl_lap_keepalive_time; /* in ms, default is LM_IDLE_TIMEOUT */ +extern struct irlmp_cb *irlmp; + +/* Check if LAP queue is full. + * Used by IrTTP for low control, see comments in irlap.h - Jean II */ +static inline int irlmp_lap_tx_queue_full(struct lsap_cb *self) +{ + if (self == NULL) + return 0; + if (self->lap == NULL) + return 0; + if (self->lap->irlap == NULL) + return 0; + + return IRLAP_GET_TX_QUEUE_LEN(self->lap->irlap) >= LAP_HIGH_THRESHOLD; +} + +/* After doing a irlmp_dup(), this get one of the two socket back into + * a state where it's waiting incoming connections. + * Note : this can be used *only* if the socket is not yet connected + * (i.e. NO irlmp_connect_response() done on this socket). + * - Jean II */ +static inline void irlmp_listen(struct lsap_cb *self) +{ + self->dlsap_sel = LSAP_ANY; + self->lap = NULL; + self->lsap_state = LSAP_DISCONNECTED; + /* Started when we received the LM_CONNECT_INDICATION */ + del_timer(&self->watchdog_timer); +} + +#endif diff --git a/drivers/staging/irda/include/net/irda/irlmp_event.h b/drivers/staging/irda/include/net/irda/irlmp_event.h new file mode 100644 index 000000000000..9e4ec17a7449 --- /dev/null +++ b/drivers/staging/irda/include/net/irda/irlmp_event.h @@ -0,0 +1,98 @@ +/********************************************************************* + * + * Filename: irlmp_event.h + * Version: 0.1 + * Description: IrDA-LMP event handling + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Mon Aug 4 20:40:53 1997 + * Modified at: Thu Jul 8 12:18:54 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1997, 1999 Dag Brattli <dagb@cs.uit.no>, + * All Rights Reserved. + * Copyright (c) 2000-2002 Jean Tourrilhes <jt@hpl.hp.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#ifndef IRLMP_EVENT_H +#define IRLMP_EVENT_H + +/* A few forward declarations (to make compiler happy) */ +struct irlmp_cb; +struct lsap_cb; +struct lap_cb; +struct discovery_t; + +/* LAP states */ +typedef enum { + /* IrLAP connection control states */ + LAP_STANDBY, /* No LAP connection */ + LAP_U_CONNECT, /* Starting LAP connection */ + LAP_ACTIVE, /* LAP connection is active */ +} IRLMP_STATE; + +/* LSAP connection control states */ +typedef enum { + LSAP_DISCONNECTED, /* No LSAP connection */ + LSAP_CONNECT, /* Connect indication from peer */ + LSAP_CONNECT_PEND, /* Connect request from service user */ + LSAP_DATA_TRANSFER_READY, /* LSAP connection established */ + LSAP_SETUP, /* Trying to set up LSAP connection */ + LSAP_SETUP_PEND, /* Request to start LAP connection */ +} LSAP_STATE; + +typedef enum { + /* LSAP events */ + LM_CONNECT_REQUEST, + LM_CONNECT_CONFIRM, + LM_CONNECT_RESPONSE, + LM_CONNECT_INDICATION, + + LM_DISCONNECT_INDICATION, + LM_DISCONNECT_REQUEST, + + LM_DATA_REQUEST, + LM_UDATA_REQUEST, + LM_DATA_INDICATION, + LM_UDATA_INDICATION, + + LM_WATCHDOG_TIMEOUT, + + /* IrLAP events */ + LM_LAP_CONNECT_REQUEST, + LM_LAP_CONNECT_INDICATION, + LM_LAP_CONNECT_CONFIRM, + LM_LAP_DISCONNECT_INDICATION, + LM_LAP_DISCONNECT_REQUEST, + LM_LAP_DISCOVERY_REQUEST, + LM_LAP_DISCOVERY_CONFIRM, + LM_LAP_IDLE_TIMEOUT, +} IRLMP_EVENT; + +extern const char *const irlmp_state[]; +extern const char *const irlsap_state[]; + +void irlmp_watchdog_timer_expired(void *data); +void irlmp_discovery_timer_expired(void *data); +void irlmp_idle_timer_expired(void *data); + +void irlmp_do_lap_event(struct lap_cb *self, IRLMP_EVENT event, + struct sk_buff *skb); +int irlmp_do_lsap_event(struct lsap_cb *self, IRLMP_EVENT event, + struct sk_buff *skb); + +#endif /* IRLMP_EVENT_H */ + + + + diff --git a/drivers/staging/irda/include/net/irda/irlmp_frame.h b/drivers/staging/irda/include/net/irda/irlmp_frame.h new file mode 100644 index 000000000000..1906eb71422e --- /dev/null +++ b/drivers/staging/irda/include/net/irda/irlmp_frame.h @@ -0,0 +1,62 @@ +/********************************************************************* + * + * Filename: irlmp_frame.h + * Version: 0.9 + * Description: + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Tue Aug 19 02:09:59 1997 + * Modified at: Fri Dec 10 13:21:53 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1997, 1999 Dag Brattli <dagb@cs.uit.no>, + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#ifndef IRMLP_FRAME_H +#define IRMLP_FRAME_H + +#include <linux/skbuff.h> + +#include <net/irda/discovery.h> + +/* IrLMP frame opcodes */ +#define CONNECT_CMD 0x01 +#define CONNECT_CNF 0x81 +#define DISCONNECT 0x02 +#define ACCESSMODE_CMD 0x03 +#define ACCESSMODE_CNF 0x83 + +#define CONTROL_BIT 0x80 + +void irlmp_send_data_pdu(struct lap_cb *self, __u8 dlsap, __u8 slsap, + int expedited, struct sk_buff *skb); +void irlmp_send_lcf_pdu(struct lap_cb *self, __u8 dlsap, __u8 slsap, + __u8 opcode, struct sk_buff *skb); +void irlmp_link_data_indication(struct lap_cb *, struct sk_buff *, + int unreliable); +#ifdef CONFIG_IRDA_ULTRA +void irlmp_link_unitdata_indication(struct lap_cb *, struct sk_buff *); +#endif /* CONFIG_IRDA_ULTRA */ + +void irlmp_link_connect_indication(struct lap_cb *, __u32 saddr, __u32 daddr, + struct qos_info *qos, struct sk_buff *skb); +void irlmp_link_connect_request(__u32 daddr); +void irlmp_link_connect_confirm(struct lap_cb *self, struct qos_info *qos, + struct sk_buff *skb); +void irlmp_link_disconnect_indication(struct lap_cb *, struct irlap_cb *, + LAP_REASON reason, struct sk_buff *); +void irlmp_link_discovery_confirm(struct lap_cb *self, hashbin_t *log); +void irlmp_link_discovery_indication(struct lap_cb *, discovery_t *discovery); + +#endif diff --git a/drivers/staging/irda/include/net/irda/irmod.h b/drivers/staging/irda/include/net/irda/irmod.h new file mode 100644 index 000000000000..86f0dbb8ee5d --- /dev/null +++ b/drivers/staging/irda/include/net/irda/irmod.h @@ -0,0 +1,109 @@ +/********************************************************************* + * + * Filename: irmod.h + * Version: 0.3 + * Description: IrDA module and utilities functions + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Mon Dec 15 13:58:52 1997 + * Modified at: Fri Jan 28 13:15:24 2000 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1998-2000 Dag Brattli, All Rights Reserved. + * Copyright (c) 2000-2002 Jean Tourrilhes <jt@hpl.hp.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charg. + * + ********************************************************************/ + +#ifndef IRMOD_H +#define IRMOD_H + +/* Misc status information */ +typedef enum { + STATUS_OK, + STATUS_ABORTED, + STATUS_NO_ACTIVITY, + STATUS_NOISY, + STATUS_REMOTE, +} LINK_STATUS; + +typedef enum { + LOCK_NO_CHANGE, + LOCK_LOCKED, + LOCK_UNLOCKED, +} LOCK_STATUS; + +typedef enum { FLOW_STOP, FLOW_START } LOCAL_FLOW; + +/* + * IrLMP disconnect reasons. The order is very important, since they + * correspond to disconnect reasons sent in IrLMP disconnect frames, so + * please do not touch :-) + */ +typedef enum { + LM_USER_REQUEST = 1, /* User request */ + LM_LAP_DISCONNECT, /* Unexpected IrLAP disconnect */ + LM_CONNECT_FAILURE, /* Failed to establish IrLAP connection */ + LM_LAP_RESET, /* IrLAP reset */ + LM_INIT_DISCONNECT, /* Link Management initiated disconnect */ + LM_LSAP_NOTCONN, /* Data delivered on unconnected LSAP */ + LM_NON_RESP_CLIENT, /* Non responsive LM-MUX client */ + LM_NO_AVAIL_CLIENT, /* No available LM-MUX client */ + LM_CONN_HALF_OPEN, /* Connection is half open */ + LM_BAD_SOURCE_ADDR, /* Illegal source address (i.e 0x00) */ +} LM_REASON; +#define LM_UNKNOWN 0xff /* Unspecified disconnect reason */ + +/* A few forward declarations (to make compiler happy) */ +struct qos_info; /* in <net/irda/qos.h> */ + +/* + * Notify structure used between transport and link management layers + */ +typedef struct { + int (*data_indication)(void *priv, void *sap, struct sk_buff *skb); + int (*udata_indication)(void *priv, void *sap, struct sk_buff *skb); + void (*connect_confirm)(void *instance, void *sap, + struct qos_info *qos, __u32 max_sdu_size, + __u8 max_header_size, struct sk_buff *skb); + void (*connect_indication)(void *instance, void *sap, + struct qos_info *qos, __u32 max_sdu_size, + __u8 max_header_size, struct sk_buff *skb); + void (*disconnect_indication)(void *instance, void *sap, + LM_REASON reason, struct sk_buff *); + void (*flow_indication)(void *instance, void *sap, LOCAL_FLOW flow); + void (*status_indication)(void *instance, + LINK_STATUS link, LOCK_STATUS lock); + void *instance; /* Layer instance pointer */ + char name[16]; /* Name of layer */ +} notify_t; + +#define NOTIFY_MAX_NAME 16 + +/* Zero the notify structure */ +void irda_notify_init(notify_t *notify); + +/* Locking wrapper - Note the inverted logic on irda_lock(). + * Those function basically return false if the lock is already in the + * position you want to set it. - Jean II */ +#define irda_lock(lock) (! test_and_set_bit(0, (void *) (lock))) +#define irda_unlock(lock) (test_and_clear_bit(0, (void *) (lock))) + +#endif /* IRMOD_H */ + + + + + + + + + diff --git a/drivers/staging/irda/include/net/irda/irqueue.h b/drivers/staging/irda/include/net/irda/irqueue.h new file mode 100644 index 000000000000..37f512bd6733 --- /dev/null +++ b/drivers/staging/irda/include/net/irda/irqueue.h @@ -0,0 +1,96 @@ +/********************************************************************* + * + * Filename: irqueue.h + * Version: 0.3 + * Description: General queue implementation + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Tue Jun 9 13:26:50 1998 + * Modified at: Thu Oct 7 13:25:16 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (C) 1998-1999, Aage Kvalnes <aage@cs.uit.no> + * Copyright (c) 1998, Dag Brattli + * All Rights Reserved. + * + * This code is taken from the Vortex Operating System written by Aage + * Kvalnes and has been ported to Linux and Linux/IR by Dag Brattli + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#include <linux/types.h> +#include <linux/spinlock.h> + +#ifndef IRDA_QUEUE_H +#define IRDA_QUEUE_H + +#define NAME_SIZE 32 + +/* + * Hash types (some flags can be xored) + * See comments in irqueue.c for which one to use... + */ +#define HB_NOLOCK 0 /* No concurent access prevention */ +#define HB_LOCK 1 /* Prevent concurent write with global lock */ + +/* + * Hash defines + */ +#define HASHBIN_SIZE 8 +#define HASHBIN_MASK 0x7 + +#ifndef IRDA_ALIGN +#define IRDA_ALIGN __attribute__((aligned)) +#endif + +#define Q_NULL { NULL, NULL, "", 0 } + +typedef void (*FREE_FUNC)(void *arg); + +struct irda_queue { + struct irda_queue *q_next; + struct irda_queue *q_prev; + + char q_name[NAME_SIZE]; + long q_hash; /* Must be able to cast a (void *) */ +}; +typedef struct irda_queue irda_queue_t; + +typedef struct hashbin_t { + __u32 magic; + int hb_type; + int hb_size; + spinlock_t hb_spinlock; /* HB_LOCK - Can be used by the user */ + + irda_queue_t* hb_queue[HASHBIN_SIZE] IRDA_ALIGN; + + irda_queue_t* hb_current; +} hashbin_t; + +hashbin_t *hashbin_new(int type); +int hashbin_delete(hashbin_t* hashbin, FREE_FUNC func); +int hashbin_clear(hashbin_t* hashbin, FREE_FUNC free_func); +void hashbin_insert(hashbin_t* hashbin, irda_queue_t* entry, long hashv, + const char* name); +void* hashbin_remove(hashbin_t* hashbin, long hashv, const char* name); +void* hashbin_remove_first(hashbin_t *hashbin); +void* hashbin_remove_this( hashbin_t* hashbin, irda_queue_t* entry); +void* hashbin_find(hashbin_t* hashbin, long hashv, const char* name); +void* hashbin_lock_find(hashbin_t* hashbin, long hashv, const char* name); +void* hashbin_find_next(hashbin_t* hashbin, long hashv, const char* name, + void ** pnext); +irda_queue_t *hashbin_get_first(hashbin_t *hashbin); +irda_queue_t *hashbin_get_next(hashbin_t *hashbin); + +#define HASHBIN_GET_SIZE(hashbin) hashbin->hb_size + +#endif diff --git a/drivers/staging/irda/include/net/irda/irttp.h b/drivers/staging/irda/include/net/irda/irttp.h new file mode 100644 index 000000000000..98682d4bae8f --- /dev/null +++ b/drivers/staging/irda/include/net/irda/irttp.h @@ -0,0 +1,210 @@ +/********************************************************************* + * + * Filename: irttp.h + * Version: 1.0 + * Description: Tiny Transport Protocol (TTP) definitions + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Sun Aug 31 20:14:31 1997 + * Modified at: Sun Dec 12 13:09:07 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, + * All Rights Reserved. + * Copyright (c) 2000-2002 Jean Tourrilhes <jt@hpl.hp.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#ifndef IRTTP_H +#define IRTTP_H + +#include <linux/types.h> +#include <linux/skbuff.h> +#include <linux/spinlock.h> + +#include <net/irda/irda.h> +#include <net/irda/irlmp.h> /* struct lsap_cb */ +#include <net/irda/qos.h> /* struct qos_info */ +#include <net/irda/irqueue.h> + +#define TTP_MAX_CONNECTIONS LM_MAX_CONNECTIONS +#define TTP_HEADER 1 +#define TTP_MAX_HEADER (TTP_HEADER + LMP_MAX_HEADER) +#define TTP_SAR_HEADER 5 +#define TTP_PARAMETERS 0x80 +#define TTP_MORE 0x80 + +/* Transmission queue sizes */ +/* Worst case scenario, two window of data - Jean II */ +#define TTP_TX_MAX_QUEUE 14 +/* We need to keep at least 5 frames to make sure that we can refill + * appropriately the LAP layer. LAP keeps only two buffers, and we need + * to have 7 to make a full window - Jean II */ +#define TTP_TX_LOW_THRESHOLD 5 +/* Most clients are synchronous with respect to flow control, so we can + * keep a low number of Tx buffers in TTP - Jean II */ +#define TTP_TX_HIGH_THRESHOLD 7 + +/* Receive queue sizes */ +/* Minimum of credit that the peer should hold. + * If the peer has less credits than 9 frames, we will explicitly send + * him some credits (through irttp_give_credit() and a specific frame). + * Note that when we give credits it's likely that it won't be sent in + * this LAP window, but in the next one. So, we make sure that the peer + * has something to send while waiting for credits (one LAP window == 7 + * + 1 frames while he process the credits). - Jean II */ +#define TTP_RX_MIN_CREDIT 8 +/* This is the default maximum number of credits held by the peer, so the + * default maximum number of frames he can send us before needing flow + * control answer from us (this may be negociated differently at TSAP setup). + * We want to minimise the number of times we have to explicitly send some + * credit to the peer, hoping we can piggyback it on the return data. In + * particular, it doesn't make sense for us to send credit more than once + * per LAP window. + * Moreover, giving credits has some latency, so we need strictly more than + * a LAP window, otherwise we may already have credits in our Tx queue. + * But on the other hand, we don't want to keep too many Rx buffer here + * before starting to flow control the other end, so make it exactly one + * LAP window + 1 + MIN_CREDITS. - Jean II */ +#define TTP_RX_DEFAULT_CREDIT 16 +/* Maximum number of credits we can allow the peer to have, and therefore + * maximum Rx queue size. + * Note that we try to deliver packets to the higher layer every time we + * receive something, so in normal mode the Rx queue will never contains + * more than one or two packets. - Jean II */ +#define TTP_RX_MAX_CREDIT 21 + +/* What clients should use when calling ttp_open_tsap() */ +#define DEFAULT_INITIAL_CREDIT TTP_RX_DEFAULT_CREDIT + +/* Some priorities for disconnect requests */ +#define P_NORMAL 0 +#define P_HIGH 1 + +#define TTP_SAR_DISABLE 0 +#define TTP_SAR_UNBOUND 0xffffffff + +/* Parameters */ +#define TTP_MAX_SDU_SIZE 0x01 + +/* + * This structure contains all data associated with one instance of a TTP + * connection. + */ +struct tsap_cb { + irda_queue_t q; /* Must be first */ + magic_t magic; /* Just in case */ + + __u8 stsap_sel; /* Source TSAP */ + __u8 dtsap_sel; /* Destination TSAP */ + + struct lsap_cb *lsap; /* Corresponding LSAP to this TSAP */ + + __u8 connected; /* TSAP connected */ + + __u8 initial_credit; /* Initial credit to give peer */ + + int avail_credit; /* Available credit to return to peer */ + int remote_credit; /* Credit held by peer TTP entity */ + int send_credit; /* Credit held by local TTP entity */ + + struct sk_buff_head tx_queue; /* Frames to be transmitted */ + struct sk_buff_head rx_queue; /* Received frames */ + struct sk_buff_head rx_fragments; + int tx_queue_lock; + int rx_queue_lock; + spinlock_t lock; + + notify_t notify; /* Callbacks to client layer */ + + struct net_device_stats stats; + struct timer_list todo_timer; + + __u32 max_seg_size; /* Max data that fit into an IrLAP frame */ + __u8 max_header_size; + + int rx_sdu_busy; /* RxSdu.busy */ + __u32 rx_sdu_size; /* Current size of a partially received frame */ + __u32 rx_max_sdu_size; /* Max receive user data size */ + + int tx_sdu_busy; /* TxSdu.busy */ + __u32 tx_max_sdu_size; /* Max transmit user data size */ + + int close_pend; /* Close, but disconnect_pend */ + unsigned long disconnect_pend; /* Disconnect, but still data to send */ + struct sk_buff *disconnect_skb; +}; + +struct irttp_cb { + magic_t magic; + hashbin_t *tsaps; +}; + +int irttp_init(void); +void irttp_cleanup(void); + +struct tsap_cb *irttp_open_tsap(__u8 stsap_sel, int credit, notify_t *notify); +int irttp_close_tsap(struct tsap_cb *self); + +int irttp_data_request(struct tsap_cb *self, struct sk_buff *skb); +int irttp_udata_request(struct tsap_cb *self, struct sk_buff *skb); + +int irttp_connect_request(struct tsap_cb *self, __u8 dtsap_sel, + __u32 saddr, __u32 daddr, + struct qos_info *qos, __u32 max_sdu_size, + struct sk_buff *userdata); +int irttp_connect_response(struct tsap_cb *self, __u32 max_sdu_size, + struct sk_buff *userdata); +int irttp_disconnect_request(struct tsap_cb *self, struct sk_buff *skb, + int priority); +void irttp_flow_request(struct tsap_cb *self, LOCAL_FLOW flow); +struct tsap_cb *irttp_dup(struct tsap_cb *self, void *instance); + +static inline __u32 irttp_get_saddr(struct tsap_cb *self) +{ + return irlmp_get_saddr(self->lsap); +} + +static inline __u32 irttp_get_daddr(struct tsap_cb *self) +{ + return irlmp_get_daddr(self->lsap); +} + +static inline __u32 irttp_get_max_seg_size(struct tsap_cb *self) +{ + return self->max_seg_size; +} + +/* After doing a irttp_dup(), this get one of the two socket back into + * a state where it's waiting incoming connections. + * Note : this can be used *only* if the socket is not yet connected + * (i.e. NO irttp_connect_response() done on this socket). + * - Jean II */ +static inline void irttp_listen(struct tsap_cb *self) +{ + irlmp_listen(self->lsap); + self->dtsap_sel = LSAP_ANY; +} + +/* Return TRUE if the node is in primary mode (i.e. master) + * - Jean II */ +static inline int irttp_is_primary(struct tsap_cb *self) +{ + if ((self == NULL) || + (self->lsap == NULL) || + (self->lsap->lap == NULL) || + (self->lsap->lap->irlap == NULL)) + return -2; + return irlap_is_primary(self->lsap->lap->irlap); +} + +#endif /* IRTTP_H */ diff --git a/drivers/staging/irda/include/net/irda/parameters.h b/drivers/staging/irda/include/net/irda/parameters.h new file mode 100644 index 000000000000..2d9cd0007cba --- /dev/null +++ b/drivers/staging/irda/include/net/irda/parameters.h @@ -0,0 +1,100 @@ +/********************************************************************* + * + * Filename: parameters.h + * Version: 1.0 + * Description: A more general way to handle (pi,pl,pv) parameters + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Mon Jun 7 08:47:28 1999 + * Modified at: Sun Jan 30 14:05:14 2000 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1999-2000 Dag Brattli, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + * Michel Dänzer <daenzer@debian.org>, 10/2001 + * - simplify irda_pv_t to avoid endianness issues + * + ********************************************************************/ + +#ifndef IRDA_PARAMS_H +#define IRDA_PARAMS_H + +/* + * The currently supported types. Beware not to change the sequence since + * it a good reason why the sized integers has a value equal to their size + */ +typedef enum { + PV_INTEGER, /* Integer of any (pl) length */ + PV_INT_8_BITS, /* Integer of 8 bits in length */ + PV_INT_16_BITS, /* Integer of 16 bits in length */ + PV_STRING, /* \0 terminated string */ + PV_INT_32_BITS, /* Integer of 32 bits in length */ + PV_OCT_SEQ, /* Octet sequence */ + PV_NO_VALUE /* Does not contain any value (pl=0) */ +} PV_TYPE; + +/* Bit 7 of type field */ +#define PV_BIG_ENDIAN 0x80 +#define PV_LITTLE_ENDIAN 0x00 +#define PV_MASK 0x7f /* To mask away endian bit */ + +#define PV_PUT 0 +#define PV_GET 1 + +typedef union { + char *c; + __u32 i; + __u32 *ip; +} irda_pv_t; + +typedef struct { + __u8 pi; + __u8 pl; + irda_pv_t pv; +} irda_param_t; + +typedef int (*PI_HANDLER)(void *self, irda_param_t *param, int get); +typedef int (*PV_HANDLER)(void *self, __u8 *buf, int len, __u8 pi, + PV_TYPE type, PI_HANDLER func); + +typedef struct { + const PI_HANDLER func; /* Handler for this parameter identifier */ + PV_TYPE type; /* Data type for this parameter */ +} pi_minor_info_t; + +typedef struct { + const pi_minor_info_t *pi_minor_call_table; + int len; +} pi_major_info_t; + +typedef struct { + const pi_major_info_t *tables; + int len; + __u8 pi_mask; + int pi_major_offset; +} pi_param_info_t; + +int irda_param_pack(__u8 *buf, char *fmt, ...); + +int irda_param_insert(void *self, __u8 pi, __u8 *buf, int len, + pi_param_info_t *info); +int irda_param_extract_all(void *self, __u8 *buf, int len, + pi_param_info_t *info); + +#define irda_param_insert_byte(buf,pi,pv) irda_param_pack(buf,"bbb",pi,1,pv) + +#endif /* IRDA_PARAMS_H */ + diff --git a/drivers/staging/irda/include/net/irda/qos.h b/drivers/staging/irda/include/net/irda/qos.h new file mode 100644 index 000000000000..05a5a249956f --- /dev/null +++ b/drivers/staging/irda/include/net/irda/qos.h @@ -0,0 +1,101 @@ +/********************************************************************* + * + * Filename: qos.h + * Version: 1.0 + * Description: Quality of Service definitions + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Fri Sep 19 23:21:09 1997 + * Modified at: Thu Dec 2 13:51:54 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1999 Dag Brattli, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + ********************************************************************/ + +#ifndef IRDA_QOS_H +#define IRDA_QOS_H + +#include <linux/skbuff.h> + +#include <net/irda/parameters.h> + +#define PI_BAUD_RATE 0x01 +#define PI_MAX_TURN_TIME 0x82 +#define PI_DATA_SIZE 0x83 +#define PI_WINDOW_SIZE 0x84 +#define PI_ADD_BOFS 0x85 +#define PI_MIN_TURN_TIME 0x86 +#define PI_LINK_DISC 0x08 + +#define IR_115200_MAX 0x3f + +/* Baud rates (first byte) */ +#define IR_2400 0x01 +#define IR_9600 0x02 +#define IR_19200 0x04 +#define IR_38400 0x08 +#define IR_57600 0x10 +#define IR_115200 0x20 +#define IR_576000 0x40 +#define IR_1152000 0x80 + +/* Baud rates (second byte) */ +#define IR_4000000 0x01 +#define IR_16000000 0x02 + +/* Quality of Service information */ +typedef struct { + __u32 value; + __u16 bits; /* LSB is first byte, MSB is second byte */ +} qos_value_t; + +struct qos_info { + magic_t magic; + + qos_value_t baud_rate; /* IR_11520O | ... */ + qos_value_t max_turn_time; + qos_value_t data_size; + qos_value_t window_size; + qos_value_t additional_bofs; + qos_value_t min_turn_time; + qos_value_t link_disc_time; + + qos_value_t power; +}; + +extern int sysctl_max_baud_rate; +extern int sysctl_max_inactive_time; + +void irda_init_max_qos_capabilies(struct qos_info *qos); +void irda_qos_compute_intersection(struct qos_info *, struct qos_info *); + +__u32 irlap_max_line_capacity(__u32 speed, __u32 max_turn_time); + +void irda_qos_bits_to_value(struct qos_info *qos); + +/* So simple, how could we not inline those two ? + * Note : one byte is 10 bits if you include start and stop bits + * Jean II */ +#define irlap_min_turn_time_in_bytes(speed, min_turn_time) ( \ + speed * min_turn_time / 10000000 \ +) +#define irlap_xbofs_in_usec(speed, xbofs) ( \ + xbofs * 10000000 / speed \ +) + +#endif + diff --git a/drivers/staging/irda/include/net/irda/timer.h b/drivers/staging/irda/include/net/irda/timer.h new file mode 100644 index 000000000000..d784f242cf7b --- /dev/null +++ b/drivers/staging/irda/include/net/irda/timer.h @@ -0,0 +1,105 @@ +/********************************************************************* + * + * Filename: timer.h + * Version: + * Description: + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Sat Aug 16 00:59:29 1997 + * Modified at: Thu Oct 7 12:25:24 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1997, 1998-1999 Dag Brattli <dagb@cs.uit.no>, + * All Rights Reserved. + * Copyright (c) 2000-2002 Jean Tourrilhes <jt@hpl.hp.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#ifndef TIMER_H +#define TIMER_H + +#include <linux/timer.h> +#include <linux/jiffies.h> + +#include <asm/param.h> /* for HZ */ + +#include <net/irda/irda.h> + +/* A few forward declarations (to make compiler happy) */ +struct irlmp_cb; +struct irlap_cb; +struct lsap_cb; +struct lap_cb; + +/* + * Timeout definitions, some defined in IrLAP 6.13.5 - p. 92 + */ +#define POLL_TIMEOUT (450*HZ/1000) /* Must never exceed 500 ms */ +#define FINAL_TIMEOUT (500*HZ/1000) /* Must never exceed 500 ms */ + +/* + * Normally twice of p-timer. Note 3, IrLAP 6.3.11.2 - p. 60 suggests + * at least twice duration of the P-timer. + */ +#define WD_TIMEOUT (POLL_TIMEOUT*2) + +#define MEDIABUSY_TIMEOUT (500*HZ/1000) /* 500 msec */ +#define SMALLBUSY_TIMEOUT (100*HZ/1000) /* 100 msec - IrLAP 6.13.4 */ + +/* + * Slot timer must never exceed 85 ms, and must always be at least 25 ms, + * suggested to 75-85 msec by IrDA lite. This doesn't work with a lot of + * devices, and other stackes uses a lot more, so it's best we do it as well + * (Note : this is the default value and sysctl overrides it - Jean II) + */ +#define SLOT_TIMEOUT (90*HZ/1000) + +/* + * The latest discovery frame (XID) is longer due to the extra discovery + * information (hints, device name...). This is its extra length. + * We use that when setting the query timeout. Jean II + */ +#define XIDEXTRA_TIMEOUT (34*HZ/1000) /* 34 msec */ + +#define WATCHDOG_TIMEOUT (20*HZ) /* 20 sec */ + +typedef void (*TIMER_CALLBACK)(void *); + +static inline void irda_start_timer(struct timer_list *ptimer, int timeout, + void* data, TIMER_CALLBACK callback) +{ + ptimer->function = (void (*)(unsigned long)) callback; + ptimer->data = (unsigned long) data; + + /* Set new value for timer (update or add timer). + * We use mod_timer() because it's more efficient and also + * safer with respect to race conditions - Jean II */ + mod_timer(ptimer, jiffies + timeout); +} + + +void irlap_start_slot_timer(struct irlap_cb *self, int timeout); +void irlap_start_query_timer(struct irlap_cb *self, int S, int s); +void irlap_start_final_timer(struct irlap_cb *self, int timeout); +void irlap_start_wd_timer(struct irlap_cb *self, int timeout); +void irlap_start_backoff_timer(struct irlap_cb *self, int timeout); + +void irlap_start_mbusy_timer(struct irlap_cb *self, int timeout); +void irlap_stop_mbusy_timer(struct irlap_cb *); + +void irlmp_start_watchdog_timer(struct lsap_cb *, int timeout); +void irlmp_start_discovery_timer(struct irlmp_cb *, int timeout); +void irlmp_start_idle_timer(struct lap_cb *, int timeout); +void irlmp_stop_idle_timer(struct lap_cb *self); + +#endif + diff --git a/drivers/staging/irda/include/net/irda/wrapper.h b/drivers/staging/irda/include/net/irda/wrapper.h new file mode 100644 index 000000000000..eef53ebe3d76 --- /dev/null +++ b/drivers/staging/irda/include/net/irda/wrapper.h @@ -0,0 +1,58 @@ +/********************************************************************* + * + * Filename: wrapper.h + * Version: 1.2 + * Description: IrDA SIR async wrapper layer + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Mon Aug 4 20:40:53 1997 + * Modified at: Tue Jan 11 12:37:29 2000 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>, + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#ifndef WRAPPER_H +#define WRAPPER_H + +#include <linux/types.h> +#include <linux/skbuff.h> +#include <linux/netdevice.h> + +#include <net/irda/irda_device.h> /* iobuff_t */ + +#define BOF 0xc0 /* Beginning of frame */ +#define XBOF 0xff +#define EOF 0xc1 /* End of frame */ +#define CE 0x7d /* Control escape */ + +#define STA BOF /* Start flag */ +#define STO EOF /* End flag */ + +#define IRDA_TRANS 0x20 /* Asynchronous transparency modifier */ + +/* States for receiving a frame in async mode */ +enum { + OUTSIDE_FRAME, + BEGIN_FRAME, + LINK_ESCAPE, + INSIDE_FRAME +}; + +/* Proto definitions */ +int async_wrap_skb(struct sk_buff *skb, __u8 *tx_buff, int buffsize); +void async_unwrap_char(struct net_device *dev, struct net_device_stats *stats, + iobuff_t *buf, __u8 byte); + +#endif diff --git a/drivers/staging/irda/net/Kconfig b/drivers/staging/irda/net/Kconfig new file mode 100644 index 000000000000..6abeae6c666a --- /dev/null +++ b/drivers/staging/irda/net/Kconfig @@ -0,0 +1,96 @@ +# +# IrDA protocol configuration +# + +menuconfig IRDA + depends on NET && !S390 + tristate "IrDA (infrared) subsystem support" + select CRC_CCITT + ---help--- + Say Y here if you want to build support for the IrDA (TM) protocols. + The Infrared Data Associations (tm) specifies standards for wireless + infrared communication and is supported by most laptops and PDA's. + + To use Linux support for the IrDA (tm) protocols, you will also need + some user-space utilities like irattach. For more information, see + the file <file:Documentation/networking/irda.txt>. You also want to + read the IR-HOWTO, available at + <http://www.tldp.org/docs.html#howto>. + + If you want to exchange bits of data (vCal, vCard) with a PDA, you + will need to install some OBEX application, such as OpenObex : + <http://sourceforge.net/projects/openobex/> + + To compile this support as a module, choose M here: the module will + be called irda. + +comment "IrDA protocols" + depends on IRDA + +source "drivers/staging/irda/net/irlan/Kconfig" + +source "drivers/staging/irda/net/irnet/Kconfig" + +source "drivers/staging/irda/net/ircomm/Kconfig" + +config IRDA_ULTRA + bool "Ultra (connectionless) protocol" + depends on IRDA + help + Say Y here to support the connectionless Ultra IRDA protocol. + Ultra allows to exchange data over IrDA with really simple devices + (watch, beacon) without the overhead of the IrDA protocol (no handshaking, + no management frames, simple fixed header). + Ultra is available as a special socket : socket(AF_IRDA, SOCK_DGRAM, 1); + +comment "IrDA options" + depends on IRDA + +config IRDA_CACHE_LAST_LSAP + bool "Cache last LSAP" + depends on IRDA + help + Say Y here if you want IrLMP to cache the last LSAP used. This + makes sense since most frames will be sent/received on the same + connection. Enabling this option will save a hash-lookup per frame. + + If unsure, say Y. + +config IRDA_FAST_RR + bool "Fast RRs (low latency)" + depends on IRDA + ---help--- + Say Y here is you want IrLAP to send fast RR (Receive Ready) frames + when acting as a primary station. + Disabling this option will make latency over IrDA very bad. Enabling + this option will make the IrDA stack send more packet than strictly + necessary, thus reduce your battery life (but not that much). + + Fast RR will make IrLAP send out a RR frame immediately when + receiving a frame if its own transmit queue is currently empty. This + will give a lot of speed improvement when receiving much data since + the secondary station will not have to wait the max. turn around + time (usually 500ms) before it is allowed to transmit the next time. + If the transmit queue of the secondary is also empty, the primary will + start backing-off before sending another RR frame, waiting longer + each time until the back-off reaches the max. turn around time. + This back-off increase in controlled via + /proc/sys/net/irda/fast_poll_increase + + If unsure, say Y. + +config IRDA_DEBUG + bool "Debug information" + depends on IRDA + help + Say Y here if you want the IrDA subsystem to write debug information + to your syslog. You can change the debug level in + /proc/sys/net/irda/debug . + When this option is enabled, the IrDA also perform many extra internal + verifications which will usually prevent the kernel to crash in case of + bugs. + + If unsure, say Y (since it makes it easier to find the bugs). + +source "drivers/staging/irda/drivers/Kconfig" + diff --git a/drivers/staging/irda/net/Makefile b/drivers/staging/irda/net/Makefile new file mode 100644 index 000000000000..bd1a635b88cf --- /dev/null +++ b/drivers/staging/irda/net/Makefile @@ -0,0 +1,17 @@ +# +# Makefile for the Linux IrDA protocol layer. +# + +subdir-ccflags-y += -I$(srctree)/drivers/staging/irda/include + +obj-$(CONFIG_IRDA) += irda.o +obj-$(CONFIG_IRLAN) += irlan/ +obj-$(CONFIG_IRNET) += irnet/ +obj-$(CONFIG_IRCOMM) += ircomm/ + +irda-y := iriap.o iriap_event.o irlmp.o irlmp_event.o irlmp_frame.o \ + irlap.o irlap_event.o irlap_frame.o timer.o qos.o irqueue.o \ + irttp.o irda_device.o irias_object.o wrapper.o af_irda.o \ + discovery.o parameters.o irnetlink.o irmod.o +irda-$(CONFIG_PROC_FS) += irproc.o +irda-$(CONFIG_SYSCTL) += irsysctl.o diff --git a/drivers/staging/irda/net/af_irda.c b/drivers/staging/irda/net/af_irda.c new file mode 100644 index 000000000000..23fa7c8b09a5 --- /dev/null +++ b/drivers/staging/irda/net/af_irda.c @@ -0,0 +1,2695 @@ +/********************************************************************* + * + * Filename: af_irda.c + * Version: 0.9 + * Description: IrDA sockets implementation + * Status: Stable + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Sun May 31 10:12:43 1998 + * Modified at: Sat Dec 25 21:10:23 1999 + * Modified by: Dag Brattli <dag@brattli.net> + * Sources: af_netroom.c, af_ax25.c, af_rose.c, af_x25.c etc. + * + * Copyright (c) 1999 Dag Brattli <dagb@cs.uit.no> + * Copyright (c) 1999-2003 Jean Tourrilhes <jt@hpl.hp.com> + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + * Linux-IrDA now supports four different types of IrDA sockets: + * + * o SOCK_STREAM: TinyTP connections with SAR disabled. The + * max SDU size is 0 for conn. of this type + * o SOCK_SEQPACKET: TinyTP connections with SAR enabled. TTP may + * fragment the messages, but will preserve + * the message boundaries + * o SOCK_DGRAM: IRDAPROTO_UNITDATA: TinyTP connections with Unitdata + * (unreliable) transfers + * IRDAPROTO_ULTRA: Connectionless and unreliable data + * + ********************************************************************/ + +#include <linux/capability.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/socket.h> +#include <linux/sockios.h> +#include <linux/slab.h> +#include <linux/sched/signal.h> +#include <linux/init.h> +#include <linux/net.h> +#include <linux/irda.h> +#include <linux/poll.h> + +#include <asm/ioctls.h> /* TIOCOUTQ, TIOCINQ */ +#include <linux/uaccess.h> + +#include <net/sock.h> +#include <net/tcp_states.h> + +#include <net/irda/af_irda.h> + +static int irda_create(struct net *net, struct socket *sock, int protocol, int kern); + +static const struct proto_ops irda_stream_ops; +static const struct proto_ops irda_seqpacket_ops; +static const struct proto_ops irda_dgram_ops; + +#ifdef CONFIG_IRDA_ULTRA +static const struct proto_ops irda_ultra_ops; +#define ULTRA_MAX_DATA 382 +#endif /* CONFIG_IRDA_ULTRA */ + +#define IRDA_MAX_HEADER (TTP_MAX_HEADER) + +/* + * Function irda_data_indication (instance, sap, skb) + * + * Received some data from TinyTP. Just queue it on the receive queue + * + */ +static int irda_data_indication(void *instance, void *sap, struct sk_buff *skb) +{ + struct irda_sock *self; + struct sock *sk; + int err; + + self = instance; + sk = instance; + + err = sock_queue_rcv_skb(sk, skb); + if (err) { + pr_debug("%s(), error: no more mem!\n", __func__); + self->rx_flow = FLOW_STOP; + + /* When we return error, TTP will need to requeue the skb */ + return err; + } + + return 0; +} + +/* + * Function irda_disconnect_indication (instance, sap, reason, skb) + * + * Connection has been closed. Check reason to find out why + * + */ +static void irda_disconnect_indication(void *instance, void *sap, + LM_REASON reason, struct sk_buff *skb) +{ + struct irda_sock *self; + struct sock *sk; + + self = instance; + + pr_debug("%s(%p)\n", __func__, self); + + /* Don't care about it, but let's not leak it */ + if(skb) + dev_kfree_skb(skb); + + sk = instance; + if (sk == NULL) { + pr_debug("%s(%p) : BUG : sk is NULL\n", + __func__, self); + return; + } + + /* Prevent race conditions with irda_release() and irda_shutdown() */ + bh_lock_sock(sk); + if (!sock_flag(sk, SOCK_DEAD) && sk->sk_state != TCP_CLOSE) { + sk->sk_state = TCP_CLOSE; + sk->sk_shutdown |= SEND_SHUTDOWN; + + sk->sk_state_change(sk); + + /* Close our TSAP. + * If we leave it open, IrLMP put it back into the list of + * unconnected LSAPs. The problem is that any incoming request + * can then be matched to this socket (and it will be, because + * it is at the head of the list). This would prevent any + * listening socket waiting on the same TSAP to get those + * requests. Some apps forget to close sockets, or hang to it + * a bit too long, so we may stay in this dead state long + * enough to be noticed... + * Note : all socket function do check sk->sk_state, so we are + * safe... + * Jean II + */ + if (self->tsap) { + irttp_close_tsap(self->tsap); + self->tsap = NULL; + } + } + bh_unlock_sock(sk); + + /* Note : once we are there, there is not much you want to do + * with the socket anymore, apart from closing it. + * For example, bind() and connect() won't reset sk->sk_err, + * sk->sk_shutdown and sk->sk_flags to valid values... + * Jean II + */ +} + +/* + * Function irda_connect_confirm (instance, sap, qos, max_sdu_size, skb) + * + * Connections has been confirmed by the remote device + * + */ +static void irda_connect_confirm(void *instance, void *sap, + struct qos_info *qos, + __u32 max_sdu_size, __u8 max_header_size, + struct sk_buff *skb) +{ + struct irda_sock *self; + struct sock *sk; + + self = instance; + + pr_debug("%s(%p)\n", __func__, self); + + sk = instance; + if (sk == NULL) { + dev_kfree_skb(skb); + return; + } + + dev_kfree_skb(skb); + // Should be ??? skb_queue_tail(&sk->sk_receive_queue, skb); + + /* How much header space do we need to reserve */ + self->max_header_size = max_header_size; + + /* IrTTP max SDU size in transmit direction */ + self->max_sdu_size_tx = max_sdu_size; + + /* Find out what the largest chunk of data that we can transmit is */ + switch (sk->sk_type) { + case SOCK_STREAM: + if (max_sdu_size != 0) { + net_err_ratelimited("%s: max_sdu_size must be 0\n", + __func__); + return; + } + self->max_data_size = irttp_get_max_seg_size(self->tsap); + break; + case SOCK_SEQPACKET: + if (max_sdu_size == 0) { + net_err_ratelimited("%s: max_sdu_size cannot be 0\n", + __func__); + return; + } + self->max_data_size = max_sdu_size; + break; + default: + self->max_data_size = irttp_get_max_seg_size(self->tsap); + } + + pr_debug("%s(), max_data_size=%d\n", __func__, + self->max_data_size); + + memcpy(&self->qos_tx, qos, sizeof(struct qos_info)); + + /* We are now connected! */ + sk->sk_state = TCP_ESTABLISHED; + sk->sk_state_change(sk); +} + +/* + * Function irda_connect_indication(instance, sap, qos, max_sdu_size, userdata) + * + * Incoming connection + * + */ +static void irda_connect_indication(void *instance, void *sap, + struct qos_info *qos, __u32 max_sdu_size, + __u8 max_header_size, struct sk_buff *skb) +{ + struct irda_sock *self; + struct sock *sk; + + self = instance; + + pr_debug("%s(%p)\n", __func__, self); + + sk = instance; + if (sk == NULL) { + dev_kfree_skb(skb); + return; + } + + /* How much header space do we need to reserve */ + self->max_header_size = max_header_size; + + /* IrTTP max SDU size in transmit direction */ + self->max_sdu_size_tx = max_sdu_size; + + /* Find out what the largest chunk of data that we can transmit is */ + switch (sk->sk_type) { + case SOCK_STREAM: + if (max_sdu_size != 0) { + net_err_ratelimited("%s: max_sdu_size must be 0\n", + __func__); + kfree_skb(skb); + return; + } + self->max_data_size = irttp_get_max_seg_size(self->tsap); + break; + case SOCK_SEQPACKET: + if (max_sdu_size == 0) { + net_err_ratelimited("%s: max_sdu_size cannot be 0\n", + __func__); + kfree_skb(skb); + return; + } + self->max_data_size = max_sdu_size; + break; + default: + self->max_data_size = irttp_get_max_seg_size(self->tsap); + } + + pr_debug("%s(), max_data_size=%d\n", __func__, + self->max_data_size); + + memcpy(&self->qos_tx, qos, sizeof(struct qos_info)); + + skb_queue_tail(&sk->sk_receive_queue, skb); + sk->sk_state_change(sk); +} + +/* + * Function irda_connect_response (handle) + * + * Accept incoming connection + * + */ +static void irda_connect_response(struct irda_sock *self) +{ + struct sk_buff *skb; + + skb = alloc_skb(TTP_MAX_HEADER + TTP_SAR_HEADER, GFP_KERNEL); + if (skb == NULL) { + pr_debug("%s() Unable to allocate sk_buff!\n", + __func__); + return; + } + + /* Reserve space for MUX_CONTROL and LAP header */ + skb_reserve(skb, IRDA_MAX_HEADER); + + irttp_connect_response(self->tsap, self->max_sdu_size_rx, skb); +} + +/* + * Function irda_flow_indication (instance, sap, flow) + * + * Used by TinyTP to tell us if it can accept more data or not + * + */ +static void irda_flow_indication(void *instance, void *sap, LOCAL_FLOW flow) +{ + struct irda_sock *self; + struct sock *sk; + + self = instance; + sk = instance; + BUG_ON(sk == NULL); + + switch (flow) { + case FLOW_STOP: + pr_debug("%s(), IrTTP wants us to slow down\n", + __func__); + self->tx_flow = flow; + break; + case FLOW_START: + self->tx_flow = flow; + pr_debug("%s(), IrTTP wants us to start again\n", + __func__); + wake_up_interruptible(sk_sleep(sk)); + break; + default: + pr_debug("%s(), Unknown flow command!\n", __func__); + /* Unknown flow command, better stop */ + self->tx_flow = flow; + break; + } +} + +/* + * Function irda_getvalue_confirm (obj_id, value, priv) + * + * Got answer from remote LM-IAS, just pass object to requester... + * + * Note : duplicate from above, but we need our own version that + * doesn't touch the dtsap_sel and save the full value structure... + */ +static void irda_getvalue_confirm(int result, __u16 obj_id, + struct ias_value *value, void *priv) +{ + struct irda_sock *self; + + self = priv; + if (!self) { + net_warn_ratelimited("%s: lost myself!\n", __func__); + return; + } + + pr_debug("%s(%p)\n", __func__, self); + + /* We probably don't need to make any more queries */ + iriap_close(self->iriap); + self->iriap = NULL; + + /* Check if request succeeded */ + if (result != IAS_SUCCESS) { + pr_debug("%s(), IAS query failed! (%d)\n", __func__, + result); + + self->errno = result; /* We really need it later */ + + /* Wake up any processes waiting for result */ + wake_up_interruptible(&self->query_wait); + + return; + } + + /* Pass the object to the caller (so the caller must delete it) */ + self->ias_result = value; + self->errno = 0; + + /* Wake up any processes waiting for result */ + wake_up_interruptible(&self->query_wait); +} + +/* + * Function irda_selective_discovery_indication (discovery) + * + * Got a selective discovery indication from IrLMP. + * + * IrLMP is telling us that this node is new and matching our hint bit + * filter. Wake up any process waiting for answer... + */ +static void irda_selective_discovery_indication(discinfo_t *discovery, + DISCOVERY_MODE mode, + void *priv) +{ + struct irda_sock *self; + + self = priv; + if (!self) { + net_warn_ratelimited("%s: lost myself!\n", __func__); + return; + } + + /* Pass parameter to the caller */ + self->cachedaddr = discovery->daddr; + + /* Wake up process if its waiting for device to be discovered */ + wake_up_interruptible(&self->query_wait); +} + +/* + * Function irda_discovery_timeout (priv) + * + * Timeout in the selective discovery process + * + * We were waiting for a node to be discovered, but nothing has come up + * so far. Wake up the user and tell him that we failed... + */ +static void irda_discovery_timeout(u_long priv) +{ + struct irda_sock *self; + + self = (struct irda_sock *) priv; + BUG_ON(self == NULL); + + /* Nothing for the caller */ + self->cachelog = NULL; + self->cachedaddr = 0; + self->errno = -ETIME; + + /* Wake up process if its still waiting... */ + wake_up_interruptible(&self->query_wait); +} + +/* + * Function irda_open_tsap (self) + * + * Open local Transport Service Access Point (TSAP) + * + */ +static int irda_open_tsap(struct irda_sock *self, __u8 tsap_sel, char *name) +{ + notify_t notify; + + if (self->tsap) { + pr_debug("%s: busy!\n", __func__); + return -EBUSY; + } + + /* Initialize callbacks to be used by the IrDA stack */ + irda_notify_init(¬ify); + notify.connect_confirm = irda_connect_confirm; + notify.connect_indication = irda_connect_indication; + notify.disconnect_indication = irda_disconnect_indication; + notify.data_indication = irda_data_indication; + notify.udata_indication = irda_data_indication; + notify.flow_indication = irda_flow_indication; + notify.instance = self; + strncpy(notify.name, name, NOTIFY_MAX_NAME); + + self->tsap = irttp_open_tsap(tsap_sel, DEFAULT_INITIAL_CREDIT, + ¬ify); + if (self->tsap == NULL) { + pr_debug("%s(), Unable to allocate TSAP!\n", + __func__); + return -ENOMEM; + } + /* Remember which TSAP selector we actually got */ + self->stsap_sel = self->tsap->stsap_sel; + + return 0; +} + +/* + * Function irda_open_lsap (self) + * + * Open local Link Service Access Point (LSAP). Used for opening Ultra + * sockets + */ +#ifdef CONFIG_IRDA_ULTRA +static int irda_open_lsap(struct irda_sock *self, int pid) +{ + notify_t notify; + + if (self->lsap) { + net_warn_ratelimited("%s(), busy!\n", __func__); + return -EBUSY; + } + + /* Initialize callbacks to be used by the IrDA stack */ + irda_notify_init(¬ify); + notify.udata_indication = irda_data_indication; + notify.instance = self; + strncpy(notify.name, "Ultra", NOTIFY_MAX_NAME); + + self->lsap = irlmp_open_lsap(LSAP_CONNLESS, ¬ify, pid); + if (self->lsap == NULL) { + pr_debug("%s(), Unable to allocate LSAP!\n", __func__); + return -ENOMEM; + } + + return 0; +} +#endif /* CONFIG_IRDA_ULTRA */ + +/* + * Function irda_find_lsap_sel (self, name) + * + * Try to lookup LSAP selector in remote LM-IAS + * + * Basically, we start a IAP query, and then go to sleep. When the query + * return, irda_getvalue_confirm will wake us up, and we can examine the + * result of the query... + * Note that in some case, the query fail even before we go to sleep, + * creating some races... + */ +static int irda_find_lsap_sel(struct irda_sock *self, char *name) +{ + pr_debug("%s(%p, %s)\n", __func__, self, name); + + if (self->iriap) { + net_warn_ratelimited("%s(): busy with a previous query\n", + __func__); + return -EBUSY; + } + + self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self, + irda_getvalue_confirm); + if(self->iriap == NULL) + return -ENOMEM; + + /* Treat unexpected wakeup as disconnect */ + self->errno = -EHOSTUNREACH; + + /* Query remote LM-IAS */ + iriap_getvaluebyclass_request(self->iriap, self->saddr, self->daddr, + name, "IrDA:TinyTP:LsapSel"); + + /* Wait for answer, if not yet finished (or failed) */ + if (wait_event_interruptible(self->query_wait, (self->iriap==NULL))) + /* Treat signals as disconnect */ + return -EHOSTUNREACH; + + /* Check what happened */ + if (self->errno) + { + /* Requested object/attribute doesn't exist */ + if((self->errno == IAS_CLASS_UNKNOWN) || + (self->errno == IAS_ATTRIB_UNKNOWN)) + return -EADDRNOTAVAIL; + else + return -EHOSTUNREACH; + } + + /* Get the remote TSAP selector */ + switch (self->ias_result->type) { + case IAS_INTEGER: + pr_debug("%s() int=%d\n", + __func__, self->ias_result->t.integer); + + if (self->ias_result->t.integer != -1) + self->dtsap_sel = self->ias_result->t.integer; + else + self->dtsap_sel = 0; + break; + default: + self->dtsap_sel = 0; + pr_debug("%s(), bad type!\n", __func__); + break; + } + if (self->ias_result) + irias_delete_value(self->ias_result); + + if (self->dtsap_sel) + return 0; + + return -EADDRNOTAVAIL; +} + +/* + * Function irda_discover_daddr_and_lsap_sel (self, name) + * + * This try to find a device with the requested service. + * + * It basically look into the discovery log. For each address in the list, + * it queries the LM-IAS of the device to find if this device offer + * the requested service. + * If there is more than one node supporting the service, we complain + * to the user (it should move devices around). + * The, we set both the destination address and the lsap selector to point + * on the service on the unique device we have found. + * + * Note : this function fails if there is more than one device in range, + * because IrLMP doesn't disconnect the LAP when the last LSAP is closed. + * Moreover, we would need to wait the LAP disconnection... + */ +static int irda_discover_daddr_and_lsap_sel(struct irda_sock *self, char *name) +{ + discinfo_t *discoveries; /* Copy of the discovery log */ + int number; /* Number of nodes in the log */ + int i; + int err = -ENETUNREACH; + __u32 daddr = DEV_ADDR_ANY; /* Address we found the service on */ + __u8 dtsap_sel = 0x0; /* TSAP associated with it */ + + pr_debug("%s(), name=%s\n", __func__, name); + + /* Ask lmp for the current discovery log + * Note : we have to use irlmp_get_discoveries(), as opposed + * to play with the cachelog directly, because while we are + * making our ias query, le log might change... */ + discoveries = irlmp_get_discoveries(&number, self->mask.word, + self->nslots); + /* Check if the we got some results */ + if (discoveries == NULL) + return -ENETUNREACH; /* No nodes discovered */ + + /* + * Now, check all discovered devices (if any), and connect + * client only about the services that the client is + * interested in... + */ + for(i = 0; i < number; i++) { + /* Try the address in the log */ + self->daddr = discoveries[i].daddr; + self->saddr = 0x0; + pr_debug("%s(), trying daddr = %08x\n", + __func__, self->daddr); + + /* Query remote LM-IAS for this service */ + err = irda_find_lsap_sel(self, name); + switch (err) { + case 0: + /* We found the requested service */ + if(daddr != DEV_ADDR_ANY) { + pr_debug("%s(), discovered service ''%s'' in two different devices !!!\n", + __func__, name); + self->daddr = DEV_ADDR_ANY; + kfree(discoveries); + return -ENOTUNIQ; + } + /* First time we found that one, save it ! */ + daddr = self->daddr; + dtsap_sel = self->dtsap_sel; + break; + case -EADDRNOTAVAIL: + /* Requested service simply doesn't exist on this node */ + break; + default: + /* Something bad did happen :-( */ + pr_debug("%s(), unexpected IAS query failure\n", + __func__); + self->daddr = DEV_ADDR_ANY; + kfree(discoveries); + return -EHOSTUNREACH; + } + } + /* Cleanup our copy of the discovery log */ + kfree(discoveries); + + /* Check out what we found */ + if(daddr == DEV_ADDR_ANY) { + pr_debug("%s(), cannot discover service ''%s'' in any device !!!\n", + __func__, name); + self->daddr = DEV_ADDR_ANY; + return -EADDRNOTAVAIL; + } + + /* Revert back to discovered device & service */ + self->daddr = daddr; + self->saddr = 0x0; + self->dtsap_sel = dtsap_sel; + + pr_debug("%s(), discovered requested service ''%s'' at address %08x\n", + __func__, name, self->daddr); + + return 0; +} + +/* + * Function irda_getname (sock, uaddr, uaddr_len, peer) + * + * Return the our own, or peers socket address (sockaddr_irda) + * + */ +static int irda_getname(struct socket *sock, struct sockaddr *uaddr, + int *uaddr_len, int peer) +{ + struct sockaddr_irda saddr; + struct sock *sk = sock->sk; + struct irda_sock *self = irda_sk(sk); + + memset(&saddr, 0, sizeof(saddr)); + if (peer) { + if (sk->sk_state != TCP_ESTABLISHED) + return -ENOTCONN; + + saddr.sir_family = AF_IRDA; + saddr.sir_lsap_sel = self->dtsap_sel; + saddr.sir_addr = self->daddr; + } else { + saddr.sir_family = AF_IRDA; + saddr.sir_lsap_sel = self->stsap_sel; + saddr.sir_addr = self->saddr; + } + + pr_debug("%s(), tsap_sel = %#x\n", __func__, saddr.sir_lsap_sel); + pr_debug("%s(), addr = %08x\n", __func__, saddr.sir_addr); + + /* uaddr_len come to us uninitialised */ + *uaddr_len = sizeof (struct sockaddr_irda); + memcpy(uaddr, &saddr, *uaddr_len); + + return 0; +} + +/* + * Function irda_listen (sock, backlog) + * + * Just move to the listen state + * + */ +static int irda_listen(struct socket *sock, int backlog) +{ + struct sock *sk = sock->sk; + int err = -EOPNOTSUPP; + + lock_sock(sk); + + if ((sk->sk_type != SOCK_STREAM) && (sk->sk_type != SOCK_SEQPACKET) && + (sk->sk_type != SOCK_DGRAM)) + goto out; + + if (sk->sk_state != TCP_LISTEN) { + sk->sk_max_ack_backlog = backlog; + sk->sk_state = TCP_LISTEN; + + err = 0; + } +out: + release_sock(sk); + + return err; +} + +/* + * Function irda_bind (sock, uaddr, addr_len) + * + * Used by servers to register their well known TSAP + * + */ +static int irda_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) +{ + struct sock *sk = sock->sk; + struct sockaddr_irda *addr = (struct sockaddr_irda *) uaddr; + struct irda_sock *self = irda_sk(sk); + int err; + + pr_debug("%s(%p)\n", __func__, self); + + if (addr_len != sizeof(struct sockaddr_irda)) + return -EINVAL; + + lock_sock(sk); +#ifdef CONFIG_IRDA_ULTRA + /* Special care for Ultra sockets */ + if ((sk->sk_type == SOCK_DGRAM) && + (sk->sk_protocol == IRDAPROTO_ULTRA)) { + self->pid = addr->sir_lsap_sel; + err = -EOPNOTSUPP; + if (self->pid & 0x80) { + pr_debug("%s(), extension in PID not supp!\n", + __func__); + goto out; + } + err = irda_open_lsap(self, self->pid); + if (err < 0) + goto out; + + /* Pretend we are connected */ + sock->state = SS_CONNECTED; + sk->sk_state = TCP_ESTABLISHED; + err = 0; + + goto out; + } +#endif /* CONFIG_IRDA_ULTRA */ + + self->ias_obj = irias_new_object(addr->sir_name, jiffies); + err = -ENOMEM; + if (self->ias_obj == NULL) + goto out; + + err = irda_open_tsap(self, addr->sir_lsap_sel, addr->sir_name); + if (err < 0) { + irias_delete_object(self->ias_obj); + self->ias_obj = NULL; + goto out; + } + + /* Register with LM-IAS */ + irias_add_integer_attrib(self->ias_obj, "IrDA:TinyTP:LsapSel", + self->stsap_sel, IAS_KERNEL_ATTR); + irias_insert_object(self->ias_obj); + + err = 0; +out: + release_sock(sk); + return err; +} + +/* + * Function irda_accept (sock, newsock, flags) + * + * Wait for incoming connection + * + */ +static int irda_accept(struct socket *sock, struct socket *newsock, int flags, + bool kern) +{ + struct sock *sk = sock->sk; + struct irda_sock *new, *self = irda_sk(sk); + struct sock *newsk; + struct sk_buff *skb = NULL; + int err; + + err = irda_create(sock_net(sk), newsock, sk->sk_protocol, kern); + if (err) + return err; + + err = -EINVAL; + + lock_sock(sk); + if (sock->state != SS_UNCONNECTED) + goto out; + + err = -EOPNOTSUPP; + if ((sk->sk_type != SOCK_STREAM) && (sk->sk_type != SOCK_SEQPACKET) && + (sk->sk_type != SOCK_DGRAM)) + goto out; + + err = -EINVAL; + if (sk->sk_state != TCP_LISTEN) + goto out; + + /* + * The read queue this time is holding sockets ready to use + * hooked into the SABM we saved + */ + + /* + * We can perform the accept only if there is incoming data + * on the listening socket. + * So, we will block the caller until we receive any data. + * If the caller was waiting on select() or poll() before + * calling us, the data is waiting for us ;-) + * Jean II + */ + while (1) { + skb = skb_dequeue(&sk->sk_receive_queue); + if (skb) + break; + + /* Non blocking operation */ + err = -EWOULDBLOCK; + if (flags & O_NONBLOCK) + goto out; + + err = wait_event_interruptible(*(sk_sleep(sk)), + skb_peek(&sk->sk_receive_queue)); + if (err) + goto out; + } + + newsk = newsock->sk; + err = -EIO; + if (newsk == NULL) + goto out; + + newsk->sk_state = TCP_ESTABLISHED; + + new = irda_sk(newsk); + + /* Now attach up the new socket */ + new->tsap = irttp_dup(self->tsap, new); + err = -EPERM; /* value does not seem to make sense. -arnd */ + if (!new->tsap) { + pr_debug("%s(), dup failed!\n", __func__); + goto out; + } + + new->stsap_sel = new->tsap->stsap_sel; + new->dtsap_sel = new->tsap->dtsap_sel; + new->saddr = irttp_get_saddr(new->tsap); + new->daddr = irttp_get_daddr(new->tsap); + + new->max_sdu_size_tx = self->max_sdu_size_tx; + new->max_sdu_size_rx = self->max_sdu_size_rx; + new->max_data_size = self->max_data_size; + new->max_header_size = self->max_header_size; + + memcpy(&new->qos_tx, &self->qos_tx, sizeof(struct qos_info)); + + /* Clean up the original one to keep it in listen state */ + irttp_listen(self->tsap); + + sk->sk_ack_backlog--; + + newsock->state = SS_CONNECTED; + + irda_connect_response(new); + err = 0; +out: + kfree_skb(skb); + release_sock(sk); + return err; +} + +/* + * Function irda_connect (sock, uaddr, addr_len, flags) + * + * Connect to a IrDA device + * + * The main difference with a "standard" connect is that with IrDA we need + * to resolve the service name into a TSAP selector (in TCP, port number + * doesn't have to be resolved). + * Because of this service name resolution, we can offer "auto-connect", + * where we connect to a service without specifying a destination address. + * + * Note : by consulting "errno", the user space caller may learn the cause + * of the failure. Most of them are visible in the function, others may come + * from subroutines called and are listed here : + * o EBUSY : already processing a connect + * o EHOSTUNREACH : bad addr->sir_addr argument + * o EADDRNOTAVAIL : bad addr->sir_name argument + * o ENOTUNIQ : more than one node has addr->sir_name (auto-connect) + * o ENETUNREACH : no node found on the network (auto-connect) + */ +static int irda_connect(struct socket *sock, struct sockaddr *uaddr, + int addr_len, int flags) +{ + struct sock *sk = sock->sk; + struct sockaddr_irda *addr = (struct sockaddr_irda *) uaddr; + struct irda_sock *self = irda_sk(sk); + int err; + + pr_debug("%s(%p)\n", __func__, self); + + lock_sock(sk); + /* Don't allow connect for Ultra sockets */ + err = -ESOCKTNOSUPPORT; + if ((sk->sk_type == SOCK_DGRAM) && (sk->sk_protocol == IRDAPROTO_ULTRA)) + goto out; + + if (sk->sk_state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) { + sock->state = SS_CONNECTED; + err = 0; + goto out; /* Connect completed during a ERESTARTSYS event */ + } + + if (sk->sk_state == TCP_CLOSE && sock->state == SS_CONNECTING) { + sock->state = SS_UNCONNECTED; + err = -ECONNREFUSED; + goto out; + } + + err = -EISCONN; /* No reconnect on a seqpacket socket */ + if (sk->sk_state == TCP_ESTABLISHED) + goto out; + + sk->sk_state = TCP_CLOSE; + sock->state = SS_UNCONNECTED; + + err = -EINVAL; + if (addr_len != sizeof(struct sockaddr_irda)) + goto out; + + /* Check if user supplied any destination device address */ + if ((!addr->sir_addr) || (addr->sir_addr == DEV_ADDR_ANY)) { + /* Try to find one suitable */ + err = irda_discover_daddr_and_lsap_sel(self, addr->sir_name); + if (err) { + pr_debug("%s(), auto-connect failed!\n", __func__); + goto out; + } + } else { + /* Use the one provided by the user */ + self->daddr = addr->sir_addr; + pr_debug("%s(), daddr = %08x\n", __func__, self->daddr); + + /* If we don't have a valid service name, we assume the + * user want to connect on a specific LSAP. Prevent + * the use of invalid LSAPs (IrLMP 1.1 p10). Jean II */ + if((addr->sir_name[0] != '\0') || + (addr->sir_lsap_sel >= 0x70)) { + /* Query remote LM-IAS using service name */ + err = irda_find_lsap_sel(self, addr->sir_name); + if (err) { + pr_debug("%s(), connect failed!\n", __func__); + goto out; + } + } else { + /* Directly connect to the remote LSAP + * specified by the sir_lsap field. + * Please use with caution, in IrDA LSAPs are + * dynamic and there is no "well-known" LSAP. */ + self->dtsap_sel = addr->sir_lsap_sel; + } + } + + /* Check if we have opened a local TSAP */ + if (!self->tsap) { + err = irda_open_tsap(self, LSAP_ANY, addr->sir_name); + if (err) + goto out; + } + + /* Move to connecting socket, start sending Connect Requests */ + sock->state = SS_CONNECTING; + sk->sk_state = TCP_SYN_SENT; + + /* Connect to remote device */ + err = irttp_connect_request(self->tsap, self->dtsap_sel, + self->saddr, self->daddr, NULL, + self->max_sdu_size_rx, NULL); + if (err) { + pr_debug("%s(), connect failed!\n", __func__); + goto out; + } + + /* Now the loop */ + err = -EINPROGRESS; + if (sk->sk_state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) + goto out; + + err = -ERESTARTSYS; + if (wait_event_interruptible(*(sk_sleep(sk)), + (sk->sk_state != TCP_SYN_SENT))) + goto out; + + if (sk->sk_state != TCP_ESTABLISHED) { + sock->state = SS_UNCONNECTED; + err = sock_error(sk); + if (!err) + err = -ECONNRESET; + goto out; + } + + sock->state = SS_CONNECTED; + + /* At this point, IrLMP has assigned our source address */ + self->saddr = irttp_get_saddr(self->tsap); + err = 0; +out: + release_sock(sk); + return err; +} + +static struct proto irda_proto = { + .name = "IRDA", + .owner = THIS_MODULE, + .obj_size = sizeof(struct irda_sock), +}; + +/* + * Function irda_create (sock, protocol) + * + * Create IrDA socket + * + */ +static int irda_create(struct net *net, struct socket *sock, int protocol, + int kern) +{ + struct sock *sk; + struct irda_sock *self; + + if (protocol < 0 || protocol > SK_PROTOCOL_MAX) + return -EINVAL; + + if (net != &init_net) + return -EAFNOSUPPORT; + + /* Check for valid socket type */ + switch (sock->type) { + case SOCK_STREAM: /* For TTP connections with SAR disabled */ + case SOCK_SEQPACKET: /* For TTP connections with SAR enabled */ + case SOCK_DGRAM: /* For TTP Unitdata or LMP Ultra transfers */ + break; + default: + return -ESOCKTNOSUPPORT; + } + + /* Allocate networking socket */ + sk = sk_alloc(net, PF_IRDA, GFP_KERNEL, &irda_proto, kern); + if (sk == NULL) + return -ENOMEM; + + self = irda_sk(sk); + pr_debug("%s() : self is %p\n", __func__, self); + + init_waitqueue_head(&self->query_wait); + + switch (sock->type) { + case SOCK_STREAM: + sock->ops = &irda_stream_ops; + self->max_sdu_size_rx = TTP_SAR_DISABLE; + break; + case SOCK_SEQPACKET: + sock->ops = &irda_seqpacket_ops; + self->max_sdu_size_rx = TTP_SAR_UNBOUND; + break; + case SOCK_DGRAM: + switch (protocol) { +#ifdef CONFIG_IRDA_ULTRA + case IRDAPROTO_ULTRA: + sock->ops = &irda_ultra_ops; + /* Initialise now, because we may send on unbound + * sockets. Jean II */ + self->max_data_size = ULTRA_MAX_DATA - LMP_PID_HEADER; + self->max_header_size = IRDA_MAX_HEADER + LMP_PID_HEADER; + break; +#endif /* CONFIG_IRDA_ULTRA */ + case IRDAPROTO_UNITDATA: + sock->ops = &irda_dgram_ops; + /* We let Unitdata conn. be like seqpack conn. */ + self->max_sdu_size_rx = TTP_SAR_UNBOUND; + break; + default: + sk_free(sk); + return -ESOCKTNOSUPPORT; + } + break; + default: + sk_free(sk); + return -ESOCKTNOSUPPORT; + } + + /* Initialise networking socket struct */ + sock_init_data(sock, sk); /* Note : set sk->sk_refcnt to 1 */ + sk->sk_family = PF_IRDA; + sk->sk_protocol = protocol; + + /* Register as a client with IrLMP */ + self->ckey = irlmp_register_client(0, NULL, NULL, NULL); + self->mask.word = 0xffff; + self->rx_flow = self->tx_flow = FLOW_START; + self->nslots = DISCOVERY_DEFAULT_SLOTS; + self->daddr = DEV_ADDR_ANY; /* Until we get connected */ + self->saddr = 0x0; /* so IrLMP assign us any link */ + return 0; +} + +/* + * Function irda_destroy_socket (self) + * + * Destroy socket + * + */ +static void irda_destroy_socket(struct irda_sock *self) +{ + pr_debug("%s(%p)\n", __func__, self); + + /* Unregister with IrLMP */ + irlmp_unregister_client(self->ckey); + irlmp_unregister_service(self->skey); + + /* Unregister with LM-IAS */ + if (self->ias_obj) { + irias_delete_object(self->ias_obj); + self->ias_obj = NULL; + } + + if (self->iriap) { + iriap_close(self->iriap); + self->iriap = NULL; + } + + if (self->tsap) { + irttp_disconnect_request(self->tsap, NULL, P_NORMAL); + irttp_close_tsap(self->tsap); + self->tsap = NULL; + } +#ifdef CONFIG_IRDA_ULTRA + if (self->lsap) { + irlmp_close_lsap(self->lsap); + self->lsap = NULL; + } +#endif /* CONFIG_IRDA_ULTRA */ +} + +/* + * Function irda_release (sock) + */ +static int irda_release(struct socket *sock) +{ + struct sock *sk = sock->sk; + + if (sk == NULL) + return 0; + + lock_sock(sk); + sk->sk_state = TCP_CLOSE; + sk->sk_shutdown |= SEND_SHUTDOWN; + sk->sk_state_change(sk); + + /* Destroy IrDA socket */ + irda_destroy_socket(irda_sk(sk)); + + sock_orphan(sk); + sock->sk = NULL; + release_sock(sk); + + /* Purge queues (see sock_init_data()) */ + skb_queue_purge(&sk->sk_receive_queue); + + /* Destroy networking socket if we are the last reference on it, + * i.e. if(sk->sk_refcnt == 0) -> sk_free(sk) */ + sock_put(sk); + + /* Notes on socket locking and deallocation... - Jean II + * In theory we should put pairs of sock_hold() / sock_put() to + * prevent the socket to be destroyed whenever there is an + * outstanding request or outstanding incoming packet or event. + * + * 1) This may include IAS request, both in connect and getsockopt. + * Unfortunately, the situation is a bit more messy than it looks, + * because we close iriap and kfree(self) above. + * + * 2) This may include selective discovery in getsockopt. + * Same stuff as above, irlmp registration and self are gone. + * + * Probably 1 and 2 may not matter, because it's all triggered + * by a process and the socket layer already prevent the + * socket to go away while a process is holding it, through + * sockfd_put() and fput()... + * + * 3) This may include deferred TSAP closure. In particular, + * we may receive a late irda_disconnect_indication() + * Fortunately, (tsap_cb *)->close_pend should protect us + * from that. + * + * I did some testing on SMP, and it looks solid. And the socket + * memory leak is now gone... - Jean II + */ + + return 0; +} + +/* + * Function irda_sendmsg (sock, msg, len) + * + * Send message down to TinyTP. This function is used for both STREAM and + * SEQPACK services. This is possible since it forces the client to + * fragment the message if necessary + */ +static int irda_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) +{ + struct sock *sk = sock->sk; + struct irda_sock *self; + struct sk_buff *skb; + int err = -EPIPE; + + pr_debug("%s(), len=%zd\n", __func__, len); + + /* Note : socket.c set MSG_EOR on SEQPACKET sockets */ + if (msg->msg_flags & ~(MSG_DONTWAIT | MSG_EOR | MSG_CMSG_COMPAT | + MSG_NOSIGNAL)) { + return -EINVAL; + } + + lock_sock(sk); + + if (sk->sk_shutdown & SEND_SHUTDOWN) + goto out_err; + + if (sk->sk_state != TCP_ESTABLISHED) { + err = -ENOTCONN; + goto out; + } + + self = irda_sk(sk); + + /* Check if IrTTP is wants us to slow down */ + + if (wait_event_interruptible(*(sk_sleep(sk)), + (self->tx_flow != FLOW_STOP || sk->sk_state != TCP_ESTABLISHED))) { + err = -ERESTARTSYS; + goto out; + } + + /* Check if we are still connected */ + if (sk->sk_state != TCP_ESTABLISHED) { + err = -ENOTCONN; + goto out; + } + + /* Check that we don't send out too big frames */ + if (len > self->max_data_size) { + pr_debug("%s(), Chopping frame from %zd to %d bytes!\n", + __func__, len, self->max_data_size); + len = self->max_data_size; + } + + skb = sock_alloc_send_skb(sk, len + self->max_header_size + 16, + msg->msg_flags & MSG_DONTWAIT, &err); + if (!skb) + goto out_err; + + skb_reserve(skb, self->max_header_size + 16); + skb_reset_transport_header(skb); + skb_put(skb, len); + err = memcpy_from_msg(skb_transport_header(skb), msg, len); + if (err) { + kfree_skb(skb); + goto out_err; + } + + /* + * Just send the message to TinyTP, and let it deal with possible + * errors. No need to duplicate all that here + */ + err = irttp_data_request(self->tsap, skb); + if (err) { + pr_debug("%s(), err=%d\n", __func__, err); + goto out_err; + } + + release_sock(sk); + /* Tell client how much data we actually sent */ + return len; + +out_err: + err = sk_stream_error(sk, msg->msg_flags, err); +out: + release_sock(sk); + return err; + +} + +/* + * Function irda_recvmsg_dgram (sock, msg, size, flags) + * + * Try to receive message and copy it to user. The frame is discarded + * after being read, regardless of how much the user actually read + */ +static int irda_recvmsg_dgram(struct socket *sock, struct msghdr *msg, + size_t size, int flags) +{ + struct sock *sk = sock->sk; + struct irda_sock *self = irda_sk(sk); + struct sk_buff *skb; + size_t copied; + int err; + + skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, + flags & MSG_DONTWAIT, &err); + if (!skb) + return err; + + skb_reset_transport_header(skb); + copied = skb->len; + + if (copied > size) { + pr_debug("%s(), Received truncated frame (%zd < %zd)!\n", + __func__, copied, size); + copied = size; + msg->msg_flags |= MSG_TRUNC; + } + skb_copy_datagram_msg(skb, 0, msg, copied); + + skb_free_datagram(sk, skb); + + /* + * Check if we have previously stopped IrTTP and we know + * have more free space in our rx_queue. If so tell IrTTP + * to start delivering frames again before our rx_queue gets + * empty + */ + if (self->rx_flow == FLOW_STOP) { + if ((atomic_read(&sk->sk_rmem_alloc) << 2) <= sk->sk_rcvbuf) { + pr_debug("%s(), Starting IrTTP\n", __func__); + self->rx_flow = FLOW_START; + irttp_flow_request(self->tsap, FLOW_START); + } + } + + return copied; +} + +/* + * Function irda_recvmsg_stream (sock, msg, size, flags) + */ +static int irda_recvmsg_stream(struct socket *sock, struct msghdr *msg, + size_t size, int flags) +{ + struct sock *sk = sock->sk; + struct irda_sock *self = irda_sk(sk); + int noblock = flags & MSG_DONTWAIT; + size_t copied = 0; + int target, err; + long timeo; + + if ((err = sock_error(sk)) < 0) + return err; + + if (sock->flags & __SO_ACCEPTCON) + return -EINVAL; + + err =-EOPNOTSUPP; + if (flags & MSG_OOB) + return -EOPNOTSUPP; + + err = 0; + target = sock_rcvlowat(sk, flags & MSG_WAITALL, size); + timeo = sock_rcvtimeo(sk, noblock); + + do { + int chunk; + struct sk_buff *skb = skb_dequeue(&sk->sk_receive_queue); + + if (skb == NULL) { + DEFINE_WAIT(wait); + err = 0; + + if (copied >= target) + break; + + prepare_to_wait_exclusive(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); + + /* + * POSIX 1003.1g mandates this order. + */ + err = sock_error(sk); + if (err) + ; + else if (sk->sk_shutdown & RCV_SHUTDOWN) + ; + else if (noblock) + err = -EAGAIN; + else if (signal_pending(current)) + err = sock_intr_errno(timeo); + else if (sk->sk_state != TCP_ESTABLISHED) + err = -ENOTCONN; + else if (skb_peek(&sk->sk_receive_queue) == NULL) + /* Wait process until data arrives */ + schedule(); + + finish_wait(sk_sleep(sk), &wait); + + if (err) + return err; + if (sk->sk_shutdown & RCV_SHUTDOWN) + break; + + continue; + } + + chunk = min_t(unsigned int, skb->len, size); + if (memcpy_to_msg(msg, skb->data, chunk)) { + skb_queue_head(&sk->sk_receive_queue, skb); + if (copied == 0) + copied = -EFAULT; + break; + } + copied += chunk; + size -= chunk; + + /* Mark read part of skb as used */ + if (!(flags & MSG_PEEK)) { + skb_pull(skb, chunk); + + /* put the skb back if we didn't use it up.. */ + if (skb->len) { + pr_debug("%s(), back on q!\n", + __func__); + skb_queue_head(&sk->sk_receive_queue, skb); + break; + } + + kfree_skb(skb); + } else { + pr_debug("%s() questionable!?\n", __func__); + + /* put message back and return */ + skb_queue_head(&sk->sk_receive_queue, skb); + break; + } + } while (size); + + /* + * Check if we have previously stopped IrTTP and we know + * have more free space in our rx_queue. If so tell IrTTP + * to start delivering frames again before our rx_queue gets + * empty + */ + if (self->rx_flow == FLOW_STOP) { + if ((atomic_read(&sk->sk_rmem_alloc) << 2) <= sk->sk_rcvbuf) { + pr_debug("%s(), Starting IrTTP\n", __func__); + self->rx_flow = FLOW_START; + irttp_flow_request(self->tsap, FLOW_START); + } + } + + return copied; +} + +/* + * Function irda_sendmsg_dgram (sock, msg, len) + * + * Send message down to TinyTP for the unreliable sequenced + * packet service... + * + */ +static int irda_sendmsg_dgram(struct socket *sock, struct msghdr *msg, + size_t len) +{ + struct sock *sk = sock->sk; + struct irda_sock *self; + struct sk_buff *skb; + int err; + + pr_debug("%s(), len=%zd\n", __func__, len); + + if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_CMSG_COMPAT)) + return -EINVAL; + + lock_sock(sk); + + if (sk->sk_shutdown & SEND_SHUTDOWN) { + send_sig(SIGPIPE, current, 0); + err = -EPIPE; + goto out; + } + + err = -ENOTCONN; + if (sk->sk_state != TCP_ESTABLISHED) + goto out; + + self = irda_sk(sk); + + /* + * Check that we don't send out too big frames. This is an unreliable + * service, so we have no fragmentation and no coalescence + */ + if (len > self->max_data_size) { + pr_debug("%s(), Warning too much data! Chopping frame from %zd to %d bytes!\n", + __func__, len, self->max_data_size); + len = self->max_data_size; + } + + skb = sock_alloc_send_skb(sk, len + self->max_header_size, + msg->msg_flags & MSG_DONTWAIT, &err); + err = -ENOBUFS; + if (!skb) + goto out; + + skb_reserve(skb, self->max_header_size); + skb_reset_transport_header(skb); + + pr_debug("%s(), appending user data\n", __func__); + skb_put(skb, len); + err = memcpy_from_msg(skb_transport_header(skb), msg, len); + if (err) { + kfree_skb(skb); + goto out; + } + + /* + * Just send the message to TinyTP, and let it deal with possible + * errors. No need to duplicate all that here + */ + err = irttp_udata_request(self->tsap, skb); + if (err) { + pr_debug("%s(), err=%d\n", __func__, err); + goto out; + } + + release_sock(sk); + return len; + +out: + release_sock(sk); + return err; +} + +/* + * Function irda_sendmsg_ultra (sock, msg, len) + * + * Send message down to IrLMP for the unreliable Ultra + * packet service... + */ +#ifdef CONFIG_IRDA_ULTRA +static int irda_sendmsg_ultra(struct socket *sock, struct msghdr *msg, + size_t len) +{ + struct sock *sk = sock->sk; + struct irda_sock *self; + __u8 pid = 0; + int bound = 0; + struct sk_buff *skb; + int err; + + pr_debug("%s(), len=%zd\n", __func__, len); + + err = -EINVAL; + if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_CMSG_COMPAT)) + return -EINVAL; + + lock_sock(sk); + + err = -EPIPE; + if (sk->sk_shutdown & SEND_SHUTDOWN) { + send_sig(SIGPIPE, current, 0); + goto out; + } + + self = irda_sk(sk); + + /* Check if an address was specified with sendto. Jean II */ + if (msg->msg_name) { + DECLARE_SOCKADDR(struct sockaddr_irda *, addr, msg->msg_name); + err = -EINVAL; + /* Check address, extract pid. Jean II */ + if (msg->msg_namelen < sizeof(*addr)) + goto out; + if (addr->sir_family != AF_IRDA) + goto out; + + pid = addr->sir_lsap_sel; + if (pid & 0x80) { + pr_debug("%s(), extension in PID not supp!\n", + __func__); + err = -EOPNOTSUPP; + goto out; + } + } else { + /* Check that the socket is properly bound to an Ultra + * port. Jean II */ + if ((self->lsap == NULL) || + (sk->sk_state != TCP_ESTABLISHED)) { + pr_debug("%s(), socket not bound to Ultra PID.\n", + __func__); + err = -ENOTCONN; + goto out; + } + /* Use PID from socket */ + bound = 1; + } + + /* + * Check that we don't send out too big frames. This is an unreliable + * service, so we have no fragmentation and no coalescence + */ + if (len > self->max_data_size) { + pr_debug("%s(), Warning too much data! Chopping frame from %zd to %d bytes!\n", + __func__, len, self->max_data_size); + len = self->max_data_size; + } + + skb = sock_alloc_send_skb(sk, len + self->max_header_size, + msg->msg_flags & MSG_DONTWAIT, &err); + err = -ENOBUFS; + if (!skb) + goto out; + + skb_reserve(skb, self->max_header_size); + skb_reset_transport_header(skb); + + pr_debug("%s(), appending user data\n", __func__); + skb_put(skb, len); + err = memcpy_from_msg(skb_transport_header(skb), msg, len); + if (err) { + kfree_skb(skb); + goto out; + } + + err = irlmp_connless_data_request((bound ? self->lsap : NULL), + skb, pid); + if (err) + pr_debug("%s(), err=%d\n", __func__, err); +out: + release_sock(sk); + return err ? : len; +} +#endif /* CONFIG_IRDA_ULTRA */ + +/* + * Function irda_shutdown (sk, how) + */ +static int irda_shutdown(struct socket *sock, int how) +{ + struct sock *sk = sock->sk; + struct irda_sock *self = irda_sk(sk); + + pr_debug("%s(%p)\n", __func__, self); + + lock_sock(sk); + + sk->sk_state = TCP_CLOSE; + sk->sk_shutdown |= SEND_SHUTDOWN; + sk->sk_state_change(sk); + + if (self->iriap) { + iriap_close(self->iriap); + self->iriap = NULL; + } + + if (self->tsap) { + irttp_disconnect_request(self->tsap, NULL, P_NORMAL); + irttp_close_tsap(self->tsap); + self->tsap = NULL; + } + + /* A few cleanup so the socket look as good as new... */ + self->rx_flow = self->tx_flow = FLOW_START; /* needed ??? */ + self->daddr = DEV_ADDR_ANY; /* Until we get re-connected */ + self->saddr = 0x0; /* so IrLMP assign us any link */ + + release_sock(sk); + + return 0; +} + +/* + * Function irda_poll (file, sock, wait) + */ +static unsigned int irda_poll(struct file * file, struct socket *sock, + poll_table *wait) +{ + struct sock *sk = sock->sk; + struct irda_sock *self = irda_sk(sk); + unsigned int mask; + + poll_wait(file, sk_sleep(sk), wait); + mask = 0; + + /* Exceptional events? */ + if (sk->sk_err) + mask |= POLLERR; + if (sk->sk_shutdown & RCV_SHUTDOWN) { + pr_debug("%s(), POLLHUP\n", __func__); + mask |= POLLHUP; + } + + /* Readable? */ + if (!skb_queue_empty(&sk->sk_receive_queue)) { + pr_debug("Socket is readable\n"); + mask |= POLLIN | POLLRDNORM; + } + + /* Connection-based need to check for termination and startup */ + switch (sk->sk_type) { + case SOCK_STREAM: + if (sk->sk_state == TCP_CLOSE) { + pr_debug("%s(), POLLHUP\n", __func__); + mask |= POLLHUP; + } + + if (sk->sk_state == TCP_ESTABLISHED) { + if ((self->tx_flow == FLOW_START) && + sock_writeable(sk)) + { + mask |= POLLOUT | POLLWRNORM | POLLWRBAND; + } + } + break; + case SOCK_SEQPACKET: + if ((self->tx_flow == FLOW_START) && + sock_writeable(sk)) + { + mask |= POLLOUT | POLLWRNORM | POLLWRBAND; + } + break; + case SOCK_DGRAM: + if (sock_writeable(sk)) + mask |= POLLOUT | POLLWRNORM | POLLWRBAND; + break; + default: + break; + } + + return mask; +} + +/* + * Function irda_ioctl (sock, cmd, arg) + */ +static int irda_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) +{ + struct sock *sk = sock->sk; + int err; + + pr_debug("%s(), cmd=%#x\n", __func__, cmd); + + err = -EINVAL; + switch (cmd) { + case TIOCOUTQ: { + long amount; + + amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk); + if (amount < 0) + amount = 0; + err = put_user(amount, (unsigned int __user *)arg); + break; + } + + case TIOCINQ: { + struct sk_buff *skb; + long amount = 0L; + /* These two are safe on a single CPU system as only user tasks fiddle here */ + if ((skb = skb_peek(&sk->sk_receive_queue)) != NULL) + amount = skb->len; + err = put_user(amount, (unsigned int __user *)arg); + break; + } + + case SIOCGSTAMP: + if (sk != NULL) + err = sock_get_timestamp(sk, (struct timeval __user *)arg); + break; + + case SIOCGIFADDR: + case SIOCSIFADDR: + case SIOCGIFDSTADDR: + case SIOCSIFDSTADDR: + case SIOCGIFBRDADDR: + case SIOCSIFBRDADDR: + case SIOCGIFNETMASK: + case SIOCSIFNETMASK: + case SIOCGIFMETRIC: + case SIOCSIFMETRIC: + break; + default: + pr_debug("%s(), doing device ioctl!\n", __func__); + err = -ENOIOCTLCMD; + } + + return err; +} + +#ifdef CONFIG_COMPAT +/* + * Function irda_ioctl (sock, cmd, arg) + */ +static int irda_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) +{ + /* + * All IRDA's ioctl are standard ones. + */ + return -ENOIOCTLCMD; +} +#endif + +/* + * Function irda_setsockopt (sock, level, optname, optval, optlen) + * + * Set some options for the socket + * + */ +static int irda_setsockopt(struct socket *sock, int level, int optname, + char __user *optval, unsigned int optlen) +{ + struct sock *sk = sock->sk; + struct irda_sock *self = irda_sk(sk); + struct irda_ias_set *ias_opt; + struct ias_object *ias_obj; + struct ias_attrib * ias_attr; /* Attribute in IAS object */ + int opt, free_ias = 0, err = 0; + + pr_debug("%s(%p)\n", __func__, self); + + if (level != SOL_IRLMP) + return -ENOPROTOOPT; + + lock_sock(sk); + + switch (optname) { + case IRLMP_IAS_SET: + /* The user want to add an attribute to an existing IAS object + * (in the IAS database) or to create a new object with this + * attribute. + * We first query IAS to know if the object exist, and then + * create the right attribute... + */ + + if (optlen != sizeof(struct irda_ias_set)) { + err = -EINVAL; + goto out; + } + + /* Copy query to the driver. */ + ias_opt = memdup_user(optval, optlen); + if (IS_ERR(ias_opt)) { + err = PTR_ERR(ias_opt); + goto out; + } + + /* Find the object we target. + * If the user gives us an empty string, we use the object + * associated with this socket. This will workaround + * duplicated class name - Jean II */ + if(ias_opt->irda_class_name[0] == '\0') { + if(self->ias_obj == NULL) { + kfree(ias_opt); + err = -EINVAL; + goto out; + } + ias_obj = self->ias_obj; + } else + ias_obj = irias_find_object(ias_opt->irda_class_name); + + /* Only ROOT can mess with the global IAS database. + * Users can only add attributes to the object associated + * with the socket they own - Jean II */ + if((!capable(CAP_NET_ADMIN)) && + ((ias_obj == NULL) || (ias_obj != self->ias_obj))) { + kfree(ias_opt); + err = -EPERM; + goto out; + } + + /* If the object doesn't exist, create it */ + if(ias_obj == (struct ias_object *) NULL) { + /* Create a new object */ + ias_obj = irias_new_object(ias_opt->irda_class_name, + jiffies); + if (ias_obj == NULL) { + kfree(ias_opt); + err = -ENOMEM; + goto out; + } + free_ias = 1; + } + + /* Do we have the attribute already ? */ + if(irias_find_attrib(ias_obj, ias_opt->irda_attrib_name)) { + kfree(ias_opt); + if (free_ias) { + kfree(ias_obj->name); + kfree(ias_obj); + } + err = -EINVAL; + goto out; + } + + /* Look at the type */ + switch(ias_opt->irda_attrib_type) { + case IAS_INTEGER: + /* Add an integer attribute */ + irias_add_integer_attrib( + ias_obj, + ias_opt->irda_attrib_name, + ias_opt->attribute.irda_attrib_int, + IAS_USER_ATTR); + break; + case IAS_OCT_SEQ: + /* Check length */ + if(ias_opt->attribute.irda_attrib_octet_seq.len > + IAS_MAX_OCTET_STRING) { + kfree(ias_opt); + if (free_ias) { + kfree(ias_obj->name); + kfree(ias_obj); + } + + err = -EINVAL; + goto out; + } + /* Add an octet sequence attribute */ + irias_add_octseq_attrib( + ias_obj, + ias_opt->irda_attrib_name, + ias_opt->attribute.irda_attrib_octet_seq.octet_seq, + ias_opt->attribute.irda_attrib_octet_seq.len, + IAS_USER_ATTR); + break; + case IAS_STRING: + /* Should check charset & co */ + /* Check length */ + /* The length is encoded in a __u8, and + * IAS_MAX_STRING == 256, so there is no way + * userspace can pass us a string too large. + * Jean II */ + /* NULL terminate the string (avoid troubles) */ + ias_opt->attribute.irda_attrib_string.string[ias_opt->attribute.irda_attrib_string.len] = '\0'; + /* Add a string attribute */ + irias_add_string_attrib( + ias_obj, + ias_opt->irda_attrib_name, + ias_opt->attribute.irda_attrib_string.string, + IAS_USER_ATTR); + break; + default : + kfree(ias_opt); + if (free_ias) { + kfree(ias_obj->name); + kfree(ias_obj); + } + err = -EINVAL; + goto out; + } + irias_insert_object(ias_obj); + kfree(ias_opt); + break; + case IRLMP_IAS_DEL: + /* The user want to delete an object from our local IAS + * database. We just need to query the IAS, check is the + * object is not owned by the kernel and delete it. + */ + + if (optlen != sizeof(struct irda_ias_set)) { + err = -EINVAL; + goto out; + } + + /* Copy query to the driver. */ + ias_opt = memdup_user(optval, optlen); + if (IS_ERR(ias_opt)) { + err = PTR_ERR(ias_opt); + goto out; + } + + /* Find the object we target. + * If the user gives us an empty string, we use the object + * associated with this socket. This will workaround + * duplicated class name - Jean II */ + if(ias_opt->irda_class_name[0] == '\0') + ias_obj = self->ias_obj; + else + ias_obj = irias_find_object(ias_opt->irda_class_name); + if(ias_obj == (struct ias_object *) NULL) { + kfree(ias_opt); + err = -EINVAL; + goto out; + } + + /* Only ROOT can mess with the global IAS database. + * Users can only del attributes from the object associated + * with the socket they own - Jean II */ + if((!capable(CAP_NET_ADMIN)) && + ((ias_obj == NULL) || (ias_obj != self->ias_obj))) { + kfree(ias_opt); + err = -EPERM; + goto out; + } + + /* Find the attribute (in the object) we target */ + ias_attr = irias_find_attrib(ias_obj, + ias_opt->irda_attrib_name); + if(ias_attr == (struct ias_attrib *) NULL) { + kfree(ias_opt); + err = -EINVAL; + goto out; + } + + /* Check is the user space own the object */ + if(ias_attr->value->owner != IAS_USER_ATTR) { + pr_debug("%s(), attempting to delete a kernel attribute\n", + __func__); + kfree(ias_opt); + err = -EPERM; + goto out; + } + + /* Remove the attribute (and maybe the object) */ + irias_delete_attrib(ias_obj, ias_attr, 1); + kfree(ias_opt); + break; + case IRLMP_MAX_SDU_SIZE: + if (optlen < sizeof(int)) { + err = -EINVAL; + goto out; + } + + if (get_user(opt, (int __user *)optval)) { + err = -EFAULT; + goto out; + } + + /* Only possible for a seqpacket service (TTP with SAR) */ + if (sk->sk_type != SOCK_SEQPACKET) { + pr_debug("%s(), setting max_sdu_size = %d\n", + __func__, opt); + self->max_sdu_size_rx = opt; + } else { + net_warn_ratelimited("%s: not allowed to set MAXSDUSIZE for this socket type!\n", + __func__); + err = -ENOPROTOOPT; + goto out; + } + break; + case IRLMP_HINTS_SET: + if (optlen < sizeof(int)) { + err = -EINVAL; + goto out; + } + + /* The input is really a (__u8 hints[2]), easier as an int */ + if (get_user(opt, (int __user *)optval)) { + err = -EFAULT; + goto out; + } + + /* Unregister any old registration */ + irlmp_unregister_service(self->skey); + + self->skey = irlmp_register_service((__u16) opt); + break; + case IRLMP_HINT_MASK_SET: + /* As opposed to the previous case which set the hint bits + * that we advertise, this one set the filter we use when + * making a discovery (nodes which don't match any hint + * bit in the mask are not reported). + */ + if (optlen < sizeof(int)) { + err = -EINVAL; + goto out; + } + + /* The input is really a (__u8 hints[2]), easier as an int */ + if (get_user(opt, (int __user *)optval)) { + err = -EFAULT; + goto out; + } + + /* Set the new hint mask */ + self->mask.word = (__u16) opt; + /* Mask out extension bits */ + self->mask.word &= 0x7f7f; + /* Check if no bits */ + if(!self->mask.word) + self->mask.word = 0xFFFF; + + break; + default: + err = -ENOPROTOOPT; + break; + } + +out: + release_sock(sk); + + return err; +} + +/* + * Function irda_extract_ias_value(ias_opt, ias_value) + * + * Translate internal IAS value structure to the user space representation + * + * The external representation of IAS values, as we exchange them with + * user space program is quite different from the internal representation, + * as stored in the IAS database (because we need a flat structure for + * crossing kernel boundary). + * This function transform the former in the latter. We also check + * that the value type is valid. + */ +static int irda_extract_ias_value(struct irda_ias_set *ias_opt, + struct ias_value *ias_value) +{ + /* Look at the type */ + switch (ias_value->type) { + case IAS_INTEGER: + /* Copy the integer */ + ias_opt->attribute.irda_attrib_int = ias_value->t.integer; + break; + case IAS_OCT_SEQ: + /* Set length */ + ias_opt->attribute.irda_attrib_octet_seq.len = ias_value->len; + /* Copy over */ + memcpy(ias_opt->attribute.irda_attrib_octet_seq.octet_seq, + ias_value->t.oct_seq, ias_value->len); + break; + case IAS_STRING: + /* Set length */ + ias_opt->attribute.irda_attrib_string.len = ias_value->len; + ias_opt->attribute.irda_attrib_string.charset = ias_value->charset; + /* Copy over */ + memcpy(ias_opt->attribute.irda_attrib_string.string, + ias_value->t.string, ias_value->len); + /* NULL terminate the string (avoid troubles) */ + ias_opt->attribute.irda_attrib_string.string[ias_value->len] = '\0'; + break; + case IAS_MISSING: + default : + return -EINVAL; + } + + /* Copy type over */ + ias_opt->irda_attrib_type = ias_value->type; + + return 0; +} + +/* + * Function irda_getsockopt (sock, level, optname, optval, optlen) + */ +static int irda_getsockopt(struct socket *sock, int level, int optname, + char __user *optval, int __user *optlen) +{ + struct sock *sk = sock->sk; + struct irda_sock *self = irda_sk(sk); + struct irda_device_list list = { 0 }; + struct irda_device_info *discoveries; + struct irda_ias_set * ias_opt; /* IAS get/query params */ + struct ias_object * ias_obj; /* Object in IAS */ + struct ias_attrib * ias_attr; /* Attribute in IAS object */ + int daddr = DEV_ADDR_ANY; /* Dest address for IAS queries */ + int val = 0; + int len = 0; + int err = 0; + int offset, total; + + pr_debug("%s(%p)\n", __func__, self); + + if (level != SOL_IRLMP) + return -ENOPROTOOPT; + + if (get_user(len, optlen)) + return -EFAULT; + + if(len < 0) + return -EINVAL; + + lock_sock(sk); + + switch (optname) { + case IRLMP_ENUMDEVICES: + + /* Offset to first device entry */ + offset = sizeof(struct irda_device_list) - + sizeof(struct irda_device_info); + + if (len < offset) { + err = -EINVAL; + goto out; + } + + /* Ask lmp for the current discovery log */ + discoveries = irlmp_get_discoveries(&list.len, self->mask.word, + self->nslots); + /* Check if the we got some results */ + if (discoveries == NULL) { + err = -EAGAIN; + goto out; /* Didn't find any devices */ + } + + /* Write total list length back to client */ + if (copy_to_user(optval, &list, offset)) + err = -EFAULT; + + /* Copy the list itself - watch for overflow */ + if (list.len > 2048) { + err = -EINVAL; + goto bed; + } + total = offset + (list.len * sizeof(struct irda_device_info)); + if (total > len) + total = len; + if (copy_to_user(optval+offset, discoveries, total - offset)) + err = -EFAULT; + + /* Write total number of bytes used back to client */ + if (put_user(total, optlen)) + err = -EFAULT; +bed: + /* Free up our buffer */ + kfree(discoveries); + break; + case IRLMP_MAX_SDU_SIZE: + val = self->max_data_size; + len = sizeof(int); + if (put_user(len, optlen)) { + err = -EFAULT; + goto out; + } + + if (copy_to_user(optval, &val, len)) { + err = -EFAULT; + goto out; + } + + break; + case IRLMP_IAS_GET: + /* The user want an object from our local IAS database. + * We just need to query the IAS and return the value + * that we found */ + + /* Check that the user has allocated the right space for us */ + if (len != sizeof(struct irda_ias_set)) { + err = -EINVAL; + goto out; + } + + /* Copy query to the driver. */ + ias_opt = memdup_user(optval, len); + if (IS_ERR(ias_opt)) { + err = PTR_ERR(ias_opt); + goto out; + } + + /* Find the object we target. + * If the user gives us an empty string, we use the object + * associated with this socket. This will workaround + * duplicated class name - Jean II */ + if(ias_opt->irda_class_name[0] == '\0') + ias_obj = self->ias_obj; + else + ias_obj = irias_find_object(ias_opt->irda_class_name); + if(ias_obj == (struct ias_object *) NULL) { + kfree(ias_opt); + err = -EINVAL; + goto out; + } + + /* Find the attribute (in the object) we target */ + ias_attr = irias_find_attrib(ias_obj, + ias_opt->irda_attrib_name); + if(ias_attr == (struct ias_attrib *) NULL) { + kfree(ias_opt); + err = -EINVAL; + goto out; + } + + /* Translate from internal to user structure */ + err = irda_extract_ias_value(ias_opt, ias_attr->value); + if(err) { + kfree(ias_opt); + goto out; + } + + /* Copy reply to the user */ + if (copy_to_user(optval, ias_opt, + sizeof(struct irda_ias_set))) { + kfree(ias_opt); + err = -EFAULT; + goto out; + } + /* Note : don't need to put optlen, we checked it */ + kfree(ias_opt); + break; + case IRLMP_IAS_QUERY: + /* The user want an object from a remote IAS database. + * We need to use IAP to query the remote database and + * then wait for the answer to come back. */ + + /* Check that the user has allocated the right space for us */ + if (len != sizeof(struct irda_ias_set)) { + err = -EINVAL; + goto out; + } + + /* Copy query to the driver. */ + ias_opt = memdup_user(optval, len); + if (IS_ERR(ias_opt)) { + err = PTR_ERR(ias_opt); + goto out; + } + + /* At this point, there are two cases... + * 1) the socket is connected - that's the easy case, we + * just query the device we are connected to... + * 2) the socket is not connected - the user doesn't want + * to connect and/or may not have a valid service name + * (so can't create a fake connection). In this case, + * we assume that the user pass us a valid destination + * address in the requesting structure... + */ + if(self->daddr != DEV_ADDR_ANY) { + /* We are connected - reuse known daddr */ + daddr = self->daddr; + } else { + /* We are not connected, we must specify a valid + * destination address */ + daddr = ias_opt->daddr; + if((!daddr) || (daddr == DEV_ADDR_ANY)) { + kfree(ias_opt); + err = -EINVAL; + goto out; + } + } + + /* Check that we can proceed with IAP */ + if (self->iriap) { + net_warn_ratelimited("%s: busy with a previous query\n", + __func__); + kfree(ias_opt); + err = -EBUSY; + goto out; + } + + self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self, + irda_getvalue_confirm); + + if (self->iriap == NULL) { + kfree(ias_opt); + err = -ENOMEM; + goto out; + } + + /* Treat unexpected wakeup as disconnect */ + self->errno = -EHOSTUNREACH; + + /* Query remote LM-IAS */ + iriap_getvaluebyclass_request(self->iriap, + self->saddr, daddr, + ias_opt->irda_class_name, + ias_opt->irda_attrib_name); + + /* Wait for answer, if not yet finished (or failed) */ + if (wait_event_interruptible(self->query_wait, + (self->iriap == NULL))) { + /* pending request uses copy of ias_opt-content + * we can free it regardless! */ + kfree(ias_opt); + /* Treat signals as disconnect */ + err = -EHOSTUNREACH; + goto out; + } + + /* Check what happened */ + if (self->errno) + { + kfree(ias_opt); + /* Requested object/attribute doesn't exist */ + if((self->errno == IAS_CLASS_UNKNOWN) || + (self->errno == IAS_ATTRIB_UNKNOWN)) + err = -EADDRNOTAVAIL; + else + err = -EHOSTUNREACH; + + goto out; + } + + /* Translate from internal to user structure */ + err = irda_extract_ias_value(ias_opt, self->ias_result); + if (self->ias_result) + irias_delete_value(self->ias_result); + if (err) { + kfree(ias_opt); + goto out; + } + + /* Copy reply to the user */ + if (copy_to_user(optval, ias_opt, + sizeof(struct irda_ias_set))) { + kfree(ias_opt); + err = -EFAULT; + goto out; + } + /* Note : don't need to put optlen, we checked it */ + kfree(ias_opt); + break; + case IRLMP_WAITDEVICE: + /* This function is just another way of seeing life ;-) + * IRLMP_ENUMDEVICES assumes that you have a static network, + * and that you just want to pick one of the devices present. + * On the other hand, in here we assume that no device is + * present and that at some point in the future a device will + * come into range. When this device arrive, we just wake + * up the caller, so that he has time to connect to it before + * the device goes away... + * Note : once the node has been discovered for more than a + * few second, it won't trigger this function, unless it + * goes away and come back changes its hint bits (so we + * might call it IRLMP_WAITNEWDEVICE). + */ + + /* Check that the user is passing us an int */ + if (len != sizeof(int)) { + err = -EINVAL; + goto out; + } + /* Get timeout in ms (max time we block the caller) */ + if (get_user(val, (int __user *)optval)) { + err = -EFAULT; + goto out; + } + + /* Tell IrLMP we want to be notified */ + irlmp_update_client(self->ckey, self->mask.word, + irda_selective_discovery_indication, + NULL, (void *) self); + + /* Do some discovery (and also return cached results) */ + irlmp_discovery_request(self->nslots); + + /* Wait until a node is discovered */ + if (!self->cachedaddr) { + pr_debug("%s(), nothing discovered yet, going to sleep...\n", + __func__); + + /* Set watchdog timer to expire in <val> ms. */ + self->errno = 0; + setup_timer(&self->watchdog, irda_discovery_timeout, + (unsigned long)self); + mod_timer(&self->watchdog, + jiffies + msecs_to_jiffies(val)); + + /* Wait for IR-LMP to call us back */ + err = __wait_event_interruptible(self->query_wait, + (self->cachedaddr != 0 || self->errno == -ETIME)); + + /* If watchdog is still activated, kill it! */ + del_timer(&(self->watchdog)); + + pr_debug("%s(), ...waking up !\n", __func__); + + if (err != 0) + goto out; + } + else + pr_debug("%s(), found immediately !\n", + __func__); + + /* Tell IrLMP that we have been notified */ + irlmp_update_client(self->ckey, self->mask.word, + NULL, NULL, NULL); + + /* Check if the we got some results */ + if (!self->cachedaddr) { + err = -EAGAIN; /* Didn't find any devices */ + goto out; + } + daddr = self->cachedaddr; + /* Cleanup */ + self->cachedaddr = 0; + + /* We return the daddr of the device that trigger the + * wakeup. As irlmp pass us only the new devices, we + * are sure that it's not an old device. + * If the user want more details, he should query + * the whole discovery log and pick one device... + */ + if (put_user(daddr, (int __user *)optval)) { + err = -EFAULT; + goto out; + } + + break; + default: + err = -ENOPROTOOPT; + } + +out: + + release_sock(sk); + + return err; +} + +static const struct net_proto_family irda_family_ops = { + .family = PF_IRDA, + .create = irda_create, + .owner = THIS_MODULE, +}; + +static const struct proto_ops irda_stream_ops = { + .family = PF_IRDA, + .owner = THIS_MODULE, + .release = irda_release, + .bind = irda_bind, + .connect = irda_connect, + .socketpair = sock_no_socketpair, + .accept = irda_accept, + .getname = irda_getname, + .poll = irda_poll, + .ioctl = irda_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = irda_compat_ioctl, +#endif + .listen = irda_listen, + .shutdown = irda_shutdown, + .setsockopt = irda_setsockopt, + .getsockopt = irda_getsockopt, + .sendmsg = irda_sendmsg, + .recvmsg = irda_recvmsg_stream, + .mmap = sock_no_mmap, + .sendpage = sock_no_sendpage, +}; + +static const struct proto_ops irda_seqpacket_ops = { + .family = PF_IRDA, + .owner = THIS_MODULE, + .release = irda_release, + .bind = irda_bind, + .connect = irda_connect, + .socketpair = sock_no_socketpair, + .accept = irda_accept, + .getname = irda_getname, + .poll = datagram_poll, + .ioctl = irda_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = irda_compat_ioctl, +#endif + .listen = irda_listen, + .shutdown = irda_shutdown, + .setsockopt = irda_setsockopt, + .getsockopt = irda_getsockopt, + .sendmsg = irda_sendmsg, + .recvmsg = irda_recvmsg_dgram, + .mmap = sock_no_mmap, + .sendpage = sock_no_sendpage, +}; + +static const struct proto_ops irda_dgram_ops = { + .family = PF_IRDA, + .owner = THIS_MODULE, + .release = irda_release, + .bind = irda_bind, + .connect = irda_connect, + .socketpair = sock_no_socketpair, + .accept = irda_accept, + .getname = irda_getname, + .poll = datagram_poll, + .ioctl = irda_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = irda_compat_ioctl, +#endif + .listen = irda_listen, + .shutdown = irda_shutdown, + .setsockopt = irda_setsockopt, + .getsockopt = irda_getsockopt, + .sendmsg = irda_sendmsg_dgram, + .recvmsg = irda_recvmsg_dgram, + .mmap = sock_no_mmap, + .sendpage = sock_no_sendpage, +}; + +#ifdef CONFIG_IRDA_ULTRA +static const struct proto_ops irda_ultra_ops = { + .family = PF_IRDA, + .owner = THIS_MODULE, + .release = irda_release, + .bind = irda_bind, + .connect = sock_no_connect, + .socketpair = sock_no_socketpair, + .accept = sock_no_accept, + .getname = irda_getname, + .poll = datagram_poll, + .ioctl = irda_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = irda_compat_ioctl, +#endif + .listen = sock_no_listen, + .shutdown = irda_shutdown, + .setsockopt = irda_setsockopt, + .getsockopt = irda_getsockopt, + .sendmsg = irda_sendmsg_ultra, + .recvmsg = irda_recvmsg_dgram, + .mmap = sock_no_mmap, + .sendpage = sock_no_sendpage, +}; +#endif /* CONFIG_IRDA_ULTRA */ + +/* + * Function irsock_init (pro) + * + * Initialize IrDA protocol + * + */ +int __init irsock_init(void) +{ + int rc = proto_register(&irda_proto, 0); + + if (rc == 0) + rc = sock_register(&irda_family_ops); + + return rc; +} + +/* + * Function irsock_cleanup (void) + * + * Remove IrDA protocol + * + */ +void irsock_cleanup(void) +{ + sock_unregister(PF_IRDA); + proto_unregister(&irda_proto); +} diff --git a/drivers/staging/irda/net/discovery.c b/drivers/staging/irda/net/discovery.c new file mode 100644 index 000000000000..364d70aed068 --- /dev/null +++ b/drivers/staging/irda/net/discovery.c @@ -0,0 +1,417 @@ +/********************************************************************* + * + * Filename: discovery.c + * Version: 0.1 + * Description: Routines for handling discoveries at the IrLMP layer + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Tue Apr 6 15:33:50 1999 + * Modified at: Sat Oct 9 17:11:31 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * Modified at: Fri May 28 3:11 CST 1999 + * Modified by: Horst von Brand <vonbrand@sleipnir.valparaiso.cl> + * + * Copyright (c) 1999 Dag Brattli, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + ********************************************************************/ + +#include <linux/string.h> +#include <linux/socket.h> +#include <linux/fs.h> +#include <linux/seq_file.h> +#include <linux/slab.h> +#include <linux/export.h> + +#include <net/irda/irda.h> +#include <net/irda/irlmp.h> + +#include <net/irda/discovery.h> + +#include <asm/unaligned.h> + +/* + * Function irlmp_add_discovery (cachelog, discovery) + * + * Add a new discovery to the cachelog, and remove any old discoveries + * from the same device + * + * Note : we try to preserve the time this device was *first* discovered + * (as opposed to the time of last discovery used for cleanup). This is + * used by clients waiting for discovery events to tell if the device + * discovered is "new" or just the same old one. They can't rely there + * on a binary flag (new/old), because not all discovery events are + * propagated to them, and they might not always listen, so they would + * miss some new devices popping up... + * Jean II + */ +void irlmp_add_discovery(hashbin_t *cachelog, discovery_t *new) +{ + discovery_t *discovery, *node; + unsigned long flags; + + /* Set time of first discovery if node is new (see below) */ + new->firststamp = new->timestamp; + + spin_lock_irqsave(&cachelog->hb_spinlock, flags); + + /* + * Remove all discoveries of devices that has previously been + * discovered on the same link with the same name (info), or the + * same daddr. We do this since some devices (mostly PDAs) change + * their device address between every discovery. + */ + discovery = (discovery_t *) hashbin_get_first(cachelog); + while (discovery != NULL ) { + node = discovery; + + /* Be sure to stay one item ahead */ + discovery = (discovery_t *) hashbin_get_next(cachelog); + + if ((node->data.saddr == new->data.saddr) && + ((node->data.daddr == new->data.daddr) || + (strcmp(node->data.info, new->data.info) == 0))) + { + /* This discovery is a previous discovery + * from the same device, so just remove it + */ + hashbin_remove_this(cachelog, (irda_queue_t *) node); + /* Check if hints bits are unchanged */ + if (get_unaligned((__u16 *)node->data.hints) == get_unaligned((__u16 *)new->data.hints)) + /* Set time of first discovery for this node */ + new->firststamp = node->firststamp; + kfree(node); + } + } + + /* Insert the new and updated version */ + hashbin_insert(cachelog, (irda_queue_t *) new, new->data.daddr, NULL); + + spin_unlock_irqrestore(&cachelog->hb_spinlock, flags); +} + +/* + * Function irlmp_add_discovery_log (cachelog, log) + * + * Merge a disovery log into the cachelog. + * + */ +void irlmp_add_discovery_log(hashbin_t *cachelog, hashbin_t *log) +{ + discovery_t *discovery; + + /* + * If log is missing this means that IrLAP was unable to perform the + * discovery, so restart discovery again with just the half timeout + * of the normal one. + */ + /* Well... It means that there was nobody out there - Jean II */ + if (log == NULL) { + /* irlmp_start_discovery_timer(irlmp, 150); */ + return; + } + + /* + * Locking : we are the only owner of this discovery log, so + * no need to lock it. + * We just need to lock the global log in irlmp_add_discovery(). + */ + discovery = (discovery_t *) hashbin_remove_first(log); + while (discovery != NULL) { + irlmp_add_discovery(cachelog, discovery); + + discovery = (discovery_t *) hashbin_remove_first(log); + } + + /* Delete the now empty log */ + hashbin_delete(log, (FREE_FUNC) kfree); +} + +/* + * Function irlmp_expire_discoveries (log, saddr, force) + * + * Go through all discoveries and expire all that has stayed too long + * + * Note : this assume that IrLAP won't change its saddr, which + * currently is a valid assumption... + */ +void irlmp_expire_discoveries(hashbin_t *log, __u32 saddr, int force) +{ + discovery_t * discovery; + discovery_t * curr; + unsigned long flags; + discinfo_t * buffer = NULL; + int n; /* Size of the full log */ + int i = 0; /* How many we expired */ + + IRDA_ASSERT(log != NULL, return;); + spin_lock_irqsave(&log->hb_spinlock, flags); + + discovery = (discovery_t *) hashbin_get_first(log); + while (discovery != NULL) { + /* Be sure to be one item ahead */ + curr = discovery; + discovery = (discovery_t *) hashbin_get_next(log); + + /* Test if it's time to expire this discovery */ + if ((curr->data.saddr == saddr) && + (force || + ((jiffies - curr->timestamp) > DISCOVERY_EXPIRE_TIMEOUT))) + { + /* Create buffer as needed. + * As this function get called a lot and most time + * we don't have anything to put in the log (we are + * quite picky), we can save a lot of overhead + * by not calling kmalloc. Jean II */ + if(buffer == NULL) { + /* Create the client specific buffer */ + n = HASHBIN_GET_SIZE(log); + buffer = kmalloc(n * sizeof(struct irda_device_info), GFP_ATOMIC); + if (buffer == NULL) { + spin_unlock_irqrestore(&log->hb_spinlock, flags); + return; + } + + } + + /* Copy discovery information */ + memcpy(&(buffer[i]), &(curr->data), + sizeof(discinfo_t)); + i++; + + /* Remove it from the log */ + curr = hashbin_remove_this(log, (irda_queue_t *) curr); + kfree(curr); + } + } + + /* Drop the spinlock before calling the higher layers, as + * we can't guarantee they won't call us back and create a + * deadlock. We will work on our own private data, so we + * don't care to be interrupted. - Jean II */ + spin_unlock_irqrestore(&log->hb_spinlock, flags); + + if(buffer == NULL) + return; + + /* Tell IrLMP and registered clients about it */ + irlmp_discovery_expiry(buffer, i); + + /* Free up our buffer */ + kfree(buffer); +} + +#if 0 +/* + * Function irlmp_dump_discoveries (log) + * + * Print out all discoveries in log + * + */ +void irlmp_dump_discoveries(hashbin_t *log) +{ + discovery_t *discovery; + + IRDA_ASSERT(log != NULL, return;); + + discovery = (discovery_t *) hashbin_get_first(log); + while (discovery != NULL) { + pr_debug("Discovery:\n"); + pr_debug(" daddr=%08x\n", discovery->data.daddr); + pr_debug(" saddr=%08x\n", discovery->data.saddr); + pr_debug(" nickname=%s\n", discovery->data.info); + + discovery = (discovery_t *) hashbin_get_next(log); + } +} +#endif + +/* + * Function irlmp_copy_discoveries (log, pn, mask) + * + * Copy all discoveries in a buffer + * + * This function implement a safe way for lmp clients to access the + * discovery log. The basic problem is that we don't want the log + * to change (add/remove) while the client is reading it. If the + * lmp client manipulate directly the hashbin, he is sure to get + * into troubles... + * The idea is that we copy all the current discovery log in a buffer + * which is specific to the client and pass this copy to him. As we + * do this operation with the spinlock grabbed, we are safe... + * Note : we don't want those clients to grab the spinlock, because + * we have no control on how long they will hold it... + * Note : we choose to copy the log in "struct irda_device_info" to + * save space... + * Note : the client must kfree himself() the log... + * Jean II + */ +struct irda_device_info *irlmp_copy_discoveries(hashbin_t *log, int *pn, + __u16 mask, int old_entries) +{ + discovery_t * discovery; + unsigned long flags; + discinfo_t * buffer = NULL; + int j_timeout = (sysctl_discovery_timeout * HZ); + int n; /* Size of the full log */ + int i = 0; /* How many we picked */ + + IRDA_ASSERT(pn != NULL, return NULL;); + IRDA_ASSERT(log != NULL, return NULL;); + + /* Save spin lock */ + spin_lock_irqsave(&log->hb_spinlock, flags); + + discovery = (discovery_t *) hashbin_get_first(log); + while (discovery != NULL) { + /* Mask out the ones we don't want : + * We want to match the discovery mask, and to get only + * the most recent one (unless we want old ones) */ + if ((get_unaligned((__u16 *)discovery->data.hints) & mask) && + ((old_entries) || + ((jiffies - discovery->firststamp) < j_timeout))) { + /* Create buffer as needed. + * As this function get called a lot and most time + * we don't have anything to put in the log (we are + * quite picky), we can save a lot of overhead + * by not calling kmalloc. Jean II */ + if(buffer == NULL) { + /* Create the client specific buffer */ + n = HASHBIN_GET_SIZE(log); + buffer = kmalloc(n * sizeof(struct irda_device_info), GFP_ATOMIC); + if (buffer == NULL) { + spin_unlock_irqrestore(&log->hb_spinlock, flags); + return NULL; + } + + } + + /* Copy discovery information */ + memcpy(&(buffer[i]), &(discovery->data), + sizeof(discinfo_t)); + i++; + } + discovery = (discovery_t *) hashbin_get_next(log); + } + + spin_unlock_irqrestore(&log->hb_spinlock, flags); + + /* Get the actual number of device in the buffer and return */ + *pn = i; + return buffer; +} + +#ifdef CONFIG_PROC_FS +static inline discovery_t *discovery_seq_idx(loff_t pos) + +{ + discovery_t *discovery; + + for (discovery = (discovery_t *) hashbin_get_first(irlmp->cachelog); + discovery != NULL; + discovery = (discovery_t *) hashbin_get_next(irlmp->cachelog)) { + if (pos-- == 0) + break; + } + + return discovery; +} + +static void *discovery_seq_start(struct seq_file *seq, loff_t *pos) +{ + spin_lock_irq(&irlmp->cachelog->hb_spinlock); + return *pos ? discovery_seq_idx(*pos - 1) : SEQ_START_TOKEN; +} + +static void *discovery_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + ++*pos; + return (v == SEQ_START_TOKEN) + ? (void *) hashbin_get_first(irlmp->cachelog) + : (void *) hashbin_get_next(irlmp->cachelog); +} + +static void discovery_seq_stop(struct seq_file *seq, void *v) +{ + spin_unlock_irq(&irlmp->cachelog->hb_spinlock); +} + +static int discovery_seq_show(struct seq_file *seq, void *v) +{ + if (v == SEQ_START_TOKEN) + seq_puts(seq, "IrLMP: Discovery log:\n\n"); + else { + const discovery_t *discovery = v; + + seq_printf(seq, "nickname: %s, hint: 0x%02x%02x", + discovery->data.info, + discovery->data.hints[0], + discovery->data.hints[1]); +#if 0 + if ( discovery->data.hints[0] & HINT_PNP) + seq_puts(seq, "PnP Compatible "); + if ( discovery->data.hints[0] & HINT_PDA) + seq_puts(seq, "PDA/Palmtop "); + if ( discovery->data.hints[0] & HINT_COMPUTER) + seq_puts(seq, "Computer "); + if ( discovery->data.hints[0] & HINT_PRINTER) + seq_puts(seq, "Printer "); + if ( discovery->data.hints[0] & HINT_MODEM) + seq_puts(seq, "Modem "); + if ( discovery->data.hints[0] & HINT_FAX) + seq_puts(seq, "Fax "); + if ( discovery->data.hints[0] & HINT_LAN) + seq_puts(seq, "LAN Access "); + + if ( discovery->data.hints[1] & HINT_TELEPHONY) + seq_puts(seq, "Telephony "); + if ( discovery->data.hints[1] & HINT_FILE_SERVER) + seq_puts(seq, "File Server "); + if ( discovery->data.hints[1] & HINT_COMM) + seq_puts(seq, "IrCOMM "); + if ( discovery->data.hints[1] & HINT_OBEX) + seq_puts(seq, "IrOBEX "); +#endif + seq_printf(seq,", saddr: 0x%08x, daddr: 0x%08x\n\n", + discovery->data.saddr, + discovery->data.daddr); + + seq_putc(seq, '\n'); + } + return 0; +} + +static const struct seq_operations discovery_seq_ops = { + .start = discovery_seq_start, + .next = discovery_seq_next, + .stop = discovery_seq_stop, + .show = discovery_seq_show, +}; + +static int discovery_seq_open(struct inode *inode, struct file *file) +{ + IRDA_ASSERT(irlmp != NULL, return -EINVAL;); + + return seq_open(file, &discovery_seq_ops); +} + +const struct file_operations discovery_seq_fops = { + .owner = THIS_MODULE, + .open = discovery_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; +#endif diff --git a/drivers/staging/irda/net/ircomm/Kconfig b/drivers/staging/irda/net/ircomm/Kconfig new file mode 100644 index 000000000000..19492c1707b7 --- /dev/null +++ b/drivers/staging/irda/net/ircomm/Kconfig @@ -0,0 +1,12 @@ +config IRCOMM + tristate "IrCOMM protocol" + depends on IRDA && TTY + help + Say Y here if you want to build support for the IrCOMM protocol. + To compile it as modules, choose M here: the modules will be + called ircomm and ircomm_tty. + IrCOMM implements serial port emulation, and makes it possible to + use all existing applications that understands TTY's with an + infrared link. Thus you should be able to use application like PPP, + minicom and others. + diff --git a/drivers/staging/irda/net/ircomm/Makefile b/drivers/staging/irda/net/ircomm/Makefile new file mode 100644 index 000000000000..ab23b5ba7e33 --- /dev/null +++ b/drivers/staging/irda/net/ircomm/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for the Linux IrDA IrCOMM protocol layer. +# + +obj-$(CONFIG_IRCOMM) += ircomm.o ircomm-tty.o + +ircomm-y := ircomm_core.o ircomm_event.o ircomm_lmp.o ircomm_ttp.o +ircomm-tty-y := ircomm_tty.o ircomm_tty_attach.o ircomm_tty_ioctl.o ircomm_param.o diff --git a/drivers/staging/irda/net/ircomm/ircomm_core.c b/drivers/staging/irda/net/ircomm/ircomm_core.c new file mode 100644 index 000000000000..3af219545f6d --- /dev/null +++ b/drivers/staging/irda/net/ircomm/ircomm_core.c @@ -0,0 +1,563 @@ +/********************************************************************* + * + * Filename: ircomm_core.c + * Version: 1.0 + * Description: IrCOMM service interface + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Sun Jun 6 20:37:34 1999 + * Modified at: Tue Dec 21 13:26:41 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1999 Dag Brattli, All Rights Reserved. + * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + ********************************************************************/ + +#include <linux/module.h> +#include <linux/proc_fs.h> +#include <linux/seq_file.h> +#include <linux/init.h> +#include <linux/slab.h> + +#include <net/irda/irda.h> +#include <net/irda/irmod.h> +#include <net/irda/irlmp.h> +#include <net/irda/iriap.h> +#include <net/irda/irttp.h> +#include <net/irda/irias_object.h> + +#include <net/irda/ircomm_event.h> +#include <net/irda/ircomm_lmp.h> +#include <net/irda/ircomm_ttp.h> +#include <net/irda/ircomm_param.h> +#include <net/irda/ircomm_core.h> + +static int __ircomm_close(struct ircomm_cb *self); +static void ircomm_control_indication(struct ircomm_cb *self, + struct sk_buff *skb, int clen); + +#ifdef CONFIG_PROC_FS +extern struct proc_dir_entry *proc_irda; +static int ircomm_seq_open(struct inode *, struct file *); + +static const struct file_operations ircomm_proc_fops = { + .owner = THIS_MODULE, + .open = ircomm_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; +#endif /* CONFIG_PROC_FS */ + +hashbin_t *ircomm = NULL; + +static int __init ircomm_init(void) +{ + ircomm = hashbin_new(HB_LOCK); + if (ircomm == NULL) { + net_err_ratelimited("%s(), can't allocate hashbin!\n", + __func__); + return -ENOMEM; + } + +#ifdef CONFIG_PROC_FS + { struct proc_dir_entry *ent; + ent = proc_create("ircomm", 0, proc_irda, &ircomm_proc_fops); + if (!ent) { + printk(KERN_ERR "ircomm_init: can't create /proc entry!\n"); + return -ENODEV; + } + } +#endif /* CONFIG_PROC_FS */ + + net_info_ratelimited("IrCOMM protocol (Dag Brattli)\n"); + + return 0; +} + +static void __exit ircomm_cleanup(void) +{ + hashbin_delete(ircomm, (FREE_FUNC) __ircomm_close); + +#ifdef CONFIG_PROC_FS + remove_proc_entry("ircomm", proc_irda); +#endif /* CONFIG_PROC_FS */ +} + +/* + * Function ircomm_open (client_notify) + * + * Start a new IrCOMM instance + * + */ +struct ircomm_cb *ircomm_open(notify_t *notify, __u8 service_type, int line) +{ + struct ircomm_cb *self = NULL; + int ret; + + pr_debug("%s(), service_type=0x%02x\n", __func__ , + service_type); + + IRDA_ASSERT(ircomm != NULL, return NULL;); + + self = kzalloc(sizeof(struct ircomm_cb), GFP_KERNEL); + if (self == NULL) + return NULL; + + self->notify = *notify; + self->magic = IRCOMM_MAGIC; + + /* Check if we should use IrLMP or IrTTP */ + if (service_type & IRCOMM_3_WIRE_RAW) { + self->flow_status = FLOW_START; + ret = ircomm_open_lsap(self); + } else + ret = ircomm_open_tsap(self); + + if (ret < 0) { + kfree(self); + return NULL; + } + + self->service_type = service_type; + self->line = line; + + hashbin_insert(ircomm, (irda_queue_t *) self, line, NULL); + + ircomm_next_state(self, IRCOMM_IDLE); + + return self; +} + +EXPORT_SYMBOL(ircomm_open); + +/* + * Function ircomm_close_instance (self) + * + * Remove IrCOMM instance + * + */ +static int __ircomm_close(struct ircomm_cb *self) +{ + /* Disconnect link if any */ + ircomm_do_event(self, IRCOMM_DISCONNECT_REQUEST, NULL, NULL); + + /* Remove TSAP */ + if (self->tsap) { + irttp_close_tsap(self->tsap); + self->tsap = NULL; + } + + /* Remove LSAP */ + if (self->lsap) { + irlmp_close_lsap(self->lsap); + self->lsap = NULL; + } + self->magic = 0; + + kfree(self); + + return 0; +} + +/* + * Function ircomm_close (self) + * + * Closes and removes the specified IrCOMM instance + * + */ +int ircomm_close(struct ircomm_cb *self) +{ + struct ircomm_cb *entry; + + IRDA_ASSERT(self != NULL, return -EIO;); + IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -EIO;); + + entry = hashbin_remove(ircomm, self->line, NULL); + + IRDA_ASSERT(entry == self, return -1;); + + return __ircomm_close(self); +} + +EXPORT_SYMBOL(ircomm_close); + +/* + * Function ircomm_connect_request (self, service_type) + * + * Impl. of this function is differ from one of the reference. This + * function does discovery as well as sending connect request + * + */ +int ircomm_connect_request(struct ircomm_cb *self, __u8 dlsap_sel, + __u32 saddr, __u32 daddr, struct sk_buff *skb, + __u8 service_type) +{ + struct ircomm_info info; + int ret; + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;); + + self->service_type= service_type; + + info.dlsap_sel = dlsap_sel; + info.saddr = saddr; + info.daddr = daddr; + + ret = ircomm_do_event(self, IRCOMM_CONNECT_REQUEST, skb, &info); + + return ret; +} + +EXPORT_SYMBOL(ircomm_connect_request); + +/* + * Function ircomm_connect_indication (self, qos, skb) + * + * Notify user layer about the incoming connection + * + */ +void ircomm_connect_indication(struct ircomm_cb *self, struct sk_buff *skb, + struct ircomm_info *info) +{ + /* + * If there are any data hiding in the control channel, we must + * deliver it first. The side effect is that the control channel + * will be removed from the skb + */ + if (self->notify.connect_indication) + self->notify.connect_indication(self->notify.instance, self, + info->qos, info->max_data_size, + info->max_header_size, skb); + else { + pr_debug("%s(), missing handler\n", __func__); + } +} + +/* + * Function ircomm_connect_response (self, userdata, max_sdu_size) + * + * User accepts connection + * + */ +int ircomm_connect_response(struct ircomm_cb *self, struct sk_buff *userdata) +{ + int ret; + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;); + + ret = ircomm_do_event(self, IRCOMM_CONNECT_RESPONSE, userdata, NULL); + + return ret; +} + +EXPORT_SYMBOL(ircomm_connect_response); + +/* + * Function connect_confirm (self, skb) + * + * Notify user layer that the link is now connected + * + */ +void ircomm_connect_confirm(struct ircomm_cb *self, struct sk_buff *skb, + struct ircomm_info *info) +{ + if (self->notify.connect_confirm ) + self->notify.connect_confirm(self->notify.instance, + self, info->qos, + info->max_data_size, + info->max_header_size, skb); + else { + pr_debug("%s(), missing handler\n", __func__); + } +} + +/* + * Function ircomm_data_request (self, userdata) + * + * Send IrCOMM data to peer device + * + */ +int ircomm_data_request(struct ircomm_cb *self, struct sk_buff *skb) +{ + int ret; + + IRDA_ASSERT(self != NULL, return -EFAULT;); + IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -EFAULT;); + IRDA_ASSERT(skb != NULL, return -EFAULT;); + + ret = ircomm_do_event(self, IRCOMM_DATA_REQUEST, skb, NULL); + + return ret; +} + +EXPORT_SYMBOL(ircomm_data_request); + +/* + * Function ircomm_data_indication (self, skb) + * + * Data arrived, so deliver it to user + * + */ +void ircomm_data_indication(struct ircomm_cb *self, struct sk_buff *skb) +{ + IRDA_ASSERT(skb->len > 0, return;); + + if (self->notify.data_indication) + self->notify.data_indication(self->notify.instance, self, skb); + else { + pr_debug("%s(), missing handler\n", __func__); + } +} + +/* + * Function ircomm_process_data (self, skb) + * + * Data arrived which may contain control channel data + * + */ +void ircomm_process_data(struct ircomm_cb *self, struct sk_buff *skb) +{ + int clen; + + IRDA_ASSERT(skb->len > 0, return;); + + clen = skb->data[0]; + + /* + * Input validation check: a stir4200/mcp2150 combinations sometimes + * results in frames with clen > remaining packet size. These are + * illegal; if we throw away just this frame then it seems to carry on + * fine + */ + if (unlikely(skb->len < (clen + 1))) { + pr_debug("%s() throwing away illegal frame\n", + __func__); + return; + } + + /* + * If there are any data hiding in the control channel, we must + * deliver it first. The side effect is that the control channel + * will be removed from the skb + */ + if (clen > 0) + ircomm_control_indication(self, skb, clen); + + /* Remove control channel from data channel */ + skb_pull(skb, clen+1); + + if (skb->len) + ircomm_data_indication(self, skb); + else { + pr_debug("%s(), data was control info only!\n", + __func__); + } +} + +/* + * Function ircomm_control_request (self, params) + * + * Send control data to peer device + * + */ +int ircomm_control_request(struct ircomm_cb *self, struct sk_buff *skb) +{ + int ret; + + IRDA_ASSERT(self != NULL, return -EFAULT;); + IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -EFAULT;); + IRDA_ASSERT(skb != NULL, return -EFAULT;); + + ret = ircomm_do_event(self, IRCOMM_CONTROL_REQUEST, skb, NULL); + + return ret; +} + +EXPORT_SYMBOL(ircomm_control_request); + +/* + * Function ircomm_control_indication (self, skb) + * + * Data has arrived on the control channel + * + */ +static void ircomm_control_indication(struct ircomm_cb *self, + struct sk_buff *skb, int clen) +{ + /* Use udata for delivering data on the control channel */ + if (self->notify.udata_indication) { + struct sk_buff *ctrl_skb; + + /* We don't own the skb, so clone it */ + ctrl_skb = skb_clone(skb, GFP_ATOMIC); + if (!ctrl_skb) + return; + + /* Remove data channel from control channel */ + skb_trim(ctrl_skb, clen+1); + + self->notify.udata_indication(self->notify.instance, self, + ctrl_skb); + + /* Drop reference count - + * see ircomm_tty_control_indication(). */ + dev_kfree_skb(ctrl_skb); + } else { + pr_debug("%s(), missing handler\n", __func__); + } +} + +/* + * Function ircomm_disconnect_request (self, userdata, priority) + * + * User layer wants to disconnect the IrCOMM connection + * + */ +int ircomm_disconnect_request(struct ircomm_cb *self, struct sk_buff *userdata) +{ + struct ircomm_info info; + int ret; + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;); + + ret = ircomm_do_event(self, IRCOMM_DISCONNECT_REQUEST, userdata, + &info); + return ret; +} + +EXPORT_SYMBOL(ircomm_disconnect_request); + +/* + * Function disconnect_indication (self, skb) + * + * Tell user that the link has been disconnected + * + */ +void ircomm_disconnect_indication(struct ircomm_cb *self, struct sk_buff *skb, + struct ircomm_info *info) +{ + IRDA_ASSERT(info != NULL, return;); + + if (self->notify.disconnect_indication) { + self->notify.disconnect_indication(self->notify.instance, self, + info->reason, skb); + } else { + pr_debug("%s(), missing handler\n", __func__); + } +} + +/* + * Function ircomm_flow_request (self, flow) + * + * + * + */ +void ircomm_flow_request(struct ircomm_cb *self, LOCAL_FLOW flow) +{ + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;); + + if (self->service_type == IRCOMM_3_WIRE_RAW) + return; + + irttp_flow_request(self->tsap, flow); +} + +EXPORT_SYMBOL(ircomm_flow_request); + +#ifdef CONFIG_PROC_FS +static void *ircomm_seq_start(struct seq_file *seq, loff_t *pos) +{ + struct ircomm_cb *self; + loff_t off = 0; + + spin_lock_irq(&ircomm->hb_spinlock); + + for (self = (struct ircomm_cb *) hashbin_get_first(ircomm); + self != NULL; + self = (struct ircomm_cb *) hashbin_get_next(ircomm)) { + if (off++ == *pos) + break; + + } + return self; +} + +static void *ircomm_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + ++*pos; + + return (void *) hashbin_get_next(ircomm); +} + +static void ircomm_seq_stop(struct seq_file *seq, void *v) +{ + spin_unlock_irq(&ircomm->hb_spinlock); +} + +static int ircomm_seq_show(struct seq_file *seq, void *v) +{ + const struct ircomm_cb *self = v; + + IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -EINVAL; ); + + if(self->line < 0x10) + seq_printf(seq, "ircomm%d", self->line); + else + seq_printf(seq, "irlpt%d", self->line - 0x10); + + seq_printf(seq, + " state: %s, slsap_sel: %#02x, dlsap_sel: %#02x, mode:", + ircomm_state[ self->state], + self->slsap_sel, self->dlsap_sel); + + if(self->service_type & IRCOMM_3_WIRE_RAW) + seq_printf(seq, " 3-wire-raw"); + if(self->service_type & IRCOMM_3_WIRE) + seq_printf(seq, " 3-wire"); + if(self->service_type & IRCOMM_9_WIRE) + seq_printf(seq, " 9-wire"); + if(self->service_type & IRCOMM_CENTRONICS) + seq_printf(seq, " Centronics"); + seq_putc(seq, '\n'); + + return 0; +} + +static const struct seq_operations ircomm_seq_ops = { + .start = ircomm_seq_start, + .next = ircomm_seq_next, + .stop = ircomm_seq_stop, + .show = ircomm_seq_show, +}; + +static int ircomm_seq_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &ircomm_seq_ops); +} +#endif /* CONFIG_PROC_FS */ + +MODULE_AUTHOR("Dag Brattli <dag@brattli.net>"); +MODULE_DESCRIPTION("IrCOMM protocol"); +MODULE_LICENSE("GPL"); + +module_init(ircomm_init); +module_exit(ircomm_cleanup); diff --git a/drivers/staging/irda/net/ircomm/ircomm_event.c b/drivers/staging/irda/net/ircomm/ircomm_event.c new file mode 100644 index 000000000000..b0730ac9f388 --- /dev/null +++ b/drivers/staging/irda/net/ircomm/ircomm_event.c @@ -0,0 +1,246 @@ +/********************************************************************* + * + * Filename: ircomm_event.c + * Version: 1.0 + * Description: IrCOMM layer state machine + * Status: Stable + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Sun Jun 6 20:33:11 1999 + * Modified at: Sun Dec 12 13:44:32 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1999 Dag Brattli, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + ********************************************************************/ + +#include <linux/proc_fs.h> +#include <linux/init.h> + +#include <net/irda/irda.h> +#include <net/irda/irlmp.h> +#include <net/irda/iriap.h> +#include <net/irda/irttp.h> +#include <net/irda/irias_object.h> + +#include <net/irda/ircomm_core.h> +#include <net/irda/ircomm_event.h> + +static int ircomm_state_idle(struct ircomm_cb *self, IRCOMM_EVENT event, + struct sk_buff *skb, struct ircomm_info *info); +static int ircomm_state_waiti(struct ircomm_cb *self, IRCOMM_EVENT event, + struct sk_buff *skb, struct ircomm_info *info); +static int ircomm_state_waitr(struct ircomm_cb *self, IRCOMM_EVENT event, + struct sk_buff *skb, struct ircomm_info *info); +static int ircomm_state_conn(struct ircomm_cb *self, IRCOMM_EVENT event, + struct sk_buff *skb, struct ircomm_info *info); + +const char *const ircomm_state[] = { + "IRCOMM_IDLE", + "IRCOMM_WAITI", + "IRCOMM_WAITR", + "IRCOMM_CONN", +}; + +static const char *const ircomm_event[] __maybe_unused = { + "IRCOMM_CONNECT_REQUEST", + "IRCOMM_CONNECT_RESPONSE", + "IRCOMM_TTP_CONNECT_INDICATION", + "IRCOMM_LMP_CONNECT_INDICATION", + "IRCOMM_TTP_CONNECT_CONFIRM", + "IRCOMM_LMP_CONNECT_CONFIRM", + + "IRCOMM_LMP_DISCONNECT_INDICATION", + "IRCOMM_TTP_DISCONNECT_INDICATION", + "IRCOMM_DISCONNECT_REQUEST", + + "IRCOMM_TTP_DATA_INDICATION", + "IRCOMM_LMP_DATA_INDICATION", + "IRCOMM_DATA_REQUEST", + "IRCOMM_CONTROL_REQUEST", + "IRCOMM_CONTROL_INDICATION", +}; + +static int (*state[])(struct ircomm_cb *self, IRCOMM_EVENT event, + struct sk_buff *skb, struct ircomm_info *info) = +{ + ircomm_state_idle, + ircomm_state_waiti, + ircomm_state_waitr, + ircomm_state_conn, +}; + +/* + * Function ircomm_state_idle (self, event, skb) + * + * IrCOMM is currently idle + * + */ +static int ircomm_state_idle(struct ircomm_cb *self, IRCOMM_EVENT event, + struct sk_buff *skb, struct ircomm_info *info) +{ + int ret = 0; + + switch (event) { + case IRCOMM_CONNECT_REQUEST: + ircomm_next_state(self, IRCOMM_WAITI); + ret = self->issue.connect_request(self, skb, info); + break; + case IRCOMM_TTP_CONNECT_INDICATION: + case IRCOMM_LMP_CONNECT_INDICATION: + ircomm_next_state(self, IRCOMM_WAITR); + ircomm_connect_indication(self, skb, info); + break; + default: + pr_debug("%s(), unknown event: %s\n", __func__ , + ircomm_event[event]); + ret = -EINVAL; + } + return ret; +} + +/* + * Function ircomm_state_waiti (self, event, skb) + * + * The IrCOMM user has requested an IrCOMM connection to the remote + * device and is awaiting confirmation + */ +static int ircomm_state_waiti(struct ircomm_cb *self, IRCOMM_EVENT event, + struct sk_buff *skb, struct ircomm_info *info) +{ + int ret = 0; + + switch (event) { + case IRCOMM_TTP_CONNECT_CONFIRM: + case IRCOMM_LMP_CONNECT_CONFIRM: + ircomm_next_state(self, IRCOMM_CONN); + ircomm_connect_confirm(self, skb, info); + break; + case IRCOMM_TTP_DISCONNECT_INDICATION: + case IRCOMM_LMP_DISCONNECT_INDICATION: + ircomm_next_state(self, IRCOMM_IDLE); + ircomm_disconnect_indication(self, skb, info); + break; + default: + pr_debug("%s(), unknown event: %s\n", __func__ , + ircomm_event[event]); + ret = -EINVAL; + } + return ret; +} + +/* + * Function ircomm_state_waitr (self, event, skb) + * + * IrCOMM has received an incoming connection request and is awaiting + * response from the user + */ +static int ircomm_state_waitr(struct ircomm_cb *self, IRCOMM_EVENT event, + struct sk_buff *skb, struct ircomm_info *info) +{ + int ret = 0; + + switch (event) { + case IRCOMM_CONNECT_RESPONSE: + ircomm_next_state(self, IRCOMM_CONN); + ret = self->issue.connect_response(self, skb); + break; + case IRCOMM_DISCONNECT_REQUEST: + ircomm_next_state(self, IRCOMM_IDLE); + ret = self->issue.disconnect_request(self, skb, info); + break; + case IRCOMM_TTP_DISCONNECT_INDICATION: + case IRCOMM_LMP_DISCONNECT_INDICATION: + ircomm_next_state(self, IRCOMM_IDLE); + ircomm_disconnect_indication(self, skb, info); + break; + default: + pr_debug("%s(), unknown event = %s\n", __func__ , + ircomm_event[event]); + ret = -EINVAL; + } + return ret; +} + +/* + * Function ircomm_state_conn (self, event, skb) + * + * IrCOMM is connected to the peer IrCOMM device + * + */ +static int ircomm_state_conn(struct ircomm_cb *self, IRCOMM_EVENT event, + struct sk_buff *skb, struct ircomm_info *info) +{ + int ret = 0; + + switch (event) { + case IRCOMM_DATA_REQUEST: + ret = self->issue.data_request(self, skb, 0); + break; + case IRCOMM_TTP_DATA_INDICATION: + ircomm_process_data(self, skb); + break; + case IRCOMM_LMP_DATA_INDICATION: + ircomm_data_indication(self, skb); + break; + case IRCOMM_CONTROL_REQUEST: + /* Just send a separate frame for now */ + ret = self->issue.data_request(self, skb, skb->len); + break; + case IRCOMM_TTP_DISCONNECT_INDICATION: + case IRCOMM_LMP_DISCONNECT_INDICATION: + ircomm_next_state(self, IRCOMM_IDLE); + ircomm_disconnect_indication(self, skb, info); + break; + case IRCOMM_DISCONNECT_REQUEST: + ircomm_next_state(self, IRCOMM_IDLE); + ret = self->issue.disconnect_request(self, skb, info); + break; + default: + pr_debug("%s(), unknown event = %s\n", __func__ , + ircomm_event[event]); + ret = -EINVAL; + } + return ret; +} + +/* + * Function ircomm_do_event (self, event, skb) + * + * Process event + * + */ +int ircomm_do_event(struct ircomm_cb *self, IRCOMM_EVENT event, + struct sk_buff *skb, struct ircomm_info *info) +{ + pr_debug("%s: state=%s, event=%s\n", __func__ , + ircomm_state[self->state], ircomm_event[event]); + + return (*state[self->state])(self, event, skb, info); +} + +/* + * Function ircomm_next_state (self, state) + * + * Switch state + * + */ +void ircomm_next_state(struct ircomm_cb *self, IRCOMM_STATE state) +{ + self->state = state; + + pr_debug("%s: next state=%s, service type=%d\n", __func__ , + ircomm_state[self->state], self->service_type); +} diff --git a/drivers/staging/irda/net/ircomm/ircomm_lmp.c b/drivers/staging/irda/net/ircomm/ircomm_lmp.c new file mode 100644 index 000000000000..e4cc847bb933 --- /dev/null +++ b/drivers/staging/irda/net/ircomm/ircomm_lmp.c @@ -0,0 +1,350 @@ +/********************************************************************* + * + * Filename: ircomm_lmp.c + * Version: 1.0 + * Description: Interface between IrCOMM and IrLMP + * Status: Stable + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Sun Jun 6 20:48:27 1999 + * Modified at: Sun Dec 12 13:44:17 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * Sources: Previous IrLPT work by Thomas Davis + * + * Copyright (c) 1999 Dag Brattli, All Rights Reserved. + * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + ********************************************************************/ + +#include <linux/init.h> +#include <linux/gfp.h> + +#include <net/irda/irda.h> +#include <net/irda/irlmp.h> +#include <net/irda/iriap.h> +#include <net/irda/irda_device.h> /* struct irda_skb_cb */ + +#include <net/irda/ircomm_event.h> +#include <net/irda/ircomm_lmp.h> + + +/* + * Function ircomm_lmp_connect_request (self, userdata) + * + * + * + */ +static int ircomm_lmp_connect_request(struct ircomm_cb *self, + struct sk_buff *userdata, + struct ircomm_info *info) +{ + int ret = 0; + + /* Don't forget to refcount it - should be NULL anyway */ + if(userdata) + skb_get(userdata); + + ret = irlmp_connect_request(self->lsap, info->dlsap_sel, + info->saddr, info->daddr, NULL, userdata); + return ret; +} + +/* + * Function ircomm_lmp_connect_response (self, skb) + * + * + * + */ +static int ircomm_lmp_connect_response(struct ircomm_cb *self, + struct sk_buff *userdata) +{ + struct sk_buff *tx_skb; + + /* Any userdata supplied? */ + if (userdata == NULL) { + tx_skb = alloc_skb(LMP_MAX_HEADER, GFP_ATOMIC); + if (!tx_skb) + return -ENOMEM; + + /* Reserve space for MUX and LAP header */ + skb_reserve(tx_skb, LMP_MAX_HEADER); + } else { + /* + * Check that the client has reserved enough space for + * headers + */ + IRDA_ASSERT(skb_headroom(userdata) >= LMP_MAX_HEADER, + return -1;); + + /* Don't forget to refcount it - should be NULL anyway */ + skb_get(userdata); + tx_skb = userdata; + } + + return irlmp_connect_response(self->lsap, tx_skb); +} + +static int ircomm_lmp_disconnect_request(struct ircomm_cb *self, + struct sk_buff *userdata, + struct ircomm_info *info) +{ + struct sk_buff *tx_skb; + int ret; + + if (!userdata) { + tx_skb = alloc_skb(LMP_MAX_HEADER, GFP_ATOMIC); + if (!tx_skb) + return -ENOMEM; + + /* Reserve space for MUX and LAP header */ + skb_reserve(tx_skb, LMP_MAX_HEADER); + userdata = tx_skb; + } else { + /* Don't forget to refcount it - should be NULL anyway */ + skb_get(userdata); + } + + ret = irlmp_disconnect_request(self->lsap, userdata); + + return ret; +} + +/* + * Function ircomm_lmp_flow_control (skb) + * + * This function is called when a data frame we have sent to IrLAP has + * been deallocated. We do this to make sure we don't flood IrLAP with + * frames, since we are not using the IrTTP flow control mechanism + */ +static void ircomm_lmp_flow_control(struct sk_buff *skb) +{ + struct irda_skb_cb *cb; + struct ircomm_cb *self; + int line; + + IRDA_ASSERT(skb != NULL, return;); + + cb = (struct irda_skb_cb *) skb->cb; + + line = cb->line; + + self = (struct ircomm_cb *) hashbin_lock_find(ircomm, line, NULL); + if (!self) { + pr_debug("%s(), didn't find myself\n", __func__); + return; + } + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;); + + self->pkt_count--; + + if ((self->pkt_count < 2) && (self->flow_status == FLOW_STOP)) { + pr_debug("%s(), asking TTY to start again!\n", __func__); + self->flow_status = FLOW_START; + if (self->notify.flow_indication) + self->notify.flow_indication(self->notify.instance, + self, FLOW_START); + } +} + +/* + * Function ircomm_lmp_data_request (self, userdata) + * + * Send data frame to peer device + * + */ +static int ircomm_lmp_data_request(struct ircomm_cb *self, + struct sk_buff *skb, + int not_used) +{ + struct irda_skb_cb *cb; + int ret; + + IRDA_ASSERT(skb != NULL, return -1;); + + cb = (struct irda_skb_cb *) skb->cb; + + cb->line = self->line; + + pr_debug("%s(), sending frame\n", __func__); + + /* Don't forget to refcount it - see ircomm_tty_do_softint() */ + skb_get(skb); + + skb_orphan(skb); + skb->destructor = ircomm_lmp_flow_control; + + if ((self->pkt_count++ > 7) && (self->flow_status == FLOW_START)) { + pr_debug("%s(), asking TTY to slow down!\n", __func__); + self->flow_status = FLOW_STOP; + if (self->notify.flow_indication) + self->notify.flow_indication(self->notify.instance, + self, FLOW_STOP); + } + ret = irlmp_data_request(self->lsap, skb); + if (ret) { + net_err_ratelimited("%s(), failed\n", __func__); + /* irlmp_data_request already free the packet */ + } + + return ret; +} + +/* + * Function ircomm_lmp_data_indication (instance, sap, skb) + * + * Incoming data which we must deliver to the state machine, to check + * we are still connected. + */ +static int ircomm_lmp_data_indication(void *instance, void *sap, + struct sk_buff *skb) +{ + struct ircomm_cb *self = (struct ircomm_cb *) instance; + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;); + IRDA_ASSERT(skb != NULL, return -1;); + + ircomm_do_event(self, IRCOMM_LMP_DATA_INDICATION, skb, NULL); + + /* Drop reference count - see ircomm_tty_data_indication(). */ + dev_kfree_skb(skb); + + return 0; +} + +/* + * Function ircomm_lmp_connect_confirm (instance, sap, qos, max_sdu_size, + * max_header_size, skb) + * + * Connection has been confirmed by peer device + * + */ +static void ircomm_lmp_connect_confirm(void *instance, void *sap, + struct qos_info *qos, + __u32 max_seg_size, + __u8 max_header_size, + struct sk_buff *skb) +{ + struct ircomm_cb *self = (struct ircomm_cb *) instance; + struct ircomm_info info; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;); + IRDA_ASSERT(skb != NULL, return;); + IRDA_ASSERT(qos != NULL, return;); + + info.max_data_size = max_seg_size; + info.max_header_size = max_header_size; + info.qos = qos; + + ircomm_do_event(self, IRCOMM_LMP_CONNECT_CONFIRM, skb, &info); + + /* Drop reference count - see ircomm_tty_connect_confirm(). */ + dev_kfree_skb(skb); +} + +/* + * Function ircomm_lmp_connect_indication (instance, sap, qos, max_sdu_size, + * max_header_size, skb) + * + * Peer device wants to make a connection with us + * + */ +static void ircomm_lmp_connect_indication(void *instance, void *sap, + struct qos_info *qos, + __u32 max_seg_size, + __u8 max_header_size, + struct sk_buff *skb) +{ + struct ircomm_cb *self = (struct ircomm_cb *)instance; + struct ircomm_info info; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;); + IRDA_ASSERT(skb != NULL, return;); + IRDA_ASSERT(qos != NULL, return;); + + info.max_data_size = max_seg_size; + info.max_header_size = max_header_size; + info.qos = qos; + + ircomm_do_event(self, IRCOMM_LMP_CONNECT_INDICATION, skb, &info); + + /* Drop reference count - see ircomm_tty_connect_indication(). */ + dev_kfree_skb(skb); +} + +/* + * Function ircomm_lmp_disconnect_indication (instance, sap, reason, skb) + * + * Peer device has closed the connection, or the link went down for some + * other reason + */ +static void ircomm_lmp_disconnect_indication(void *instance, void *sap, + LM_REASON reason, + struct sk_buff *skb) +{ + struct ircomm_cb *self = (struct ircomm_cb *) instance; + struct ircomm_info info; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;); + + info.reason = reason; + + ircomm_do_event(self, IRCOMM_LMP_DISCONNECT_INDICATION, skb, &info); + + /* Drop reference count - see ircomm_tty_disconnect_indication(). */ + if(skb) + dev_kfree_skb(skb); +} +/* + * Function ircomm_open_lsap (self) + * + * Open LSAP. This function will only be used when using "raw" services + * + */ +int ircomm_open_lsap(struct ircomm_cb *self) +{ + notify_t notify; + + /* Register callbacks */ + irda_notify_init(¬ify); + notify.data_indication = ircomm_lmp_data_indication; + notify.connect_confirm = ircomm_lmp_connect_confirm; + notify.connect_indication = ircomm_lmp_connect_indication; + notify.disconnect_indication = ircomm_lmp_disconnect_indication; + notify.instance = self; + strlcpy(notify.name, "IrCOMM", sizeof(notify.name)); + + self->lsap = irlmp_open_lsap(LSAP_ANY, ¬ify, 0); + if (!self->lsap) { + pr_debug("%sfailed to allocate tsap\n", __func__); + return -1; + } + self->slsap_sel = self->lsap->slsap_sel; + + /* + * Initialize the call-table for issuing commands + */ + self->issue.data_request = ircomm_lmp_data_request; + self->issue.connect_request = ircomm_lmp_connect_request; + self->issue.connect_response = ircomm_lmp_connect_response; + self->issue.disconnect_request = ircomm_lmp_disconnect_request; + + return 0; +} diff --git a/drivers/staging/irda/net/ircomm/ircomm_param.c b/drivers/staging/irda/net/ircomm/ircomm_param.c new file mode 100644 index 000000000000..5728e76ca6d5 --- /dev/null +++ b/drivers/staging/irda/net/ircomm/ircomm_param.c @@ -0,0 +1,501 @@ +/********************************************************************* + * + * Filename: ircomm_param.c + * Version: 1.0 + * Description: Parameter handling for the IrCOMM protocol + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Mon Jun 7 10:25:11 1999 + * Modified at: Sun Jan 30 14:32:03 2000 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1999-2000 Dag Brattli, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + ********************************************************************/ + +#include <linux/gfp.h> +#include <linux/workqueue.h> +#include <linux/interrupt.h> + +#include <net/irda/irda.h> +#include <net/irda/parameters.h> + +#include <net/irda/ircomm_core.h> +#include <net/irda/ircomm_tty_attach.h> +#include <net/irda/ircomm_tty.h> + +#include <net/irda/ircomm_param.h> + +static int ircomm_param_service_type(void *instance, irda_param_t *param, + int get); +static int ircomm_param_port_type(void *instance, irda_param_t *param, + int get); +static int ircomm_param_port_name(void *instance, irda_param_t *param, + int get); +static int ircomm_param_service_type(void *instance, irda_param_t *param, + int get); +static int ircomm_param_data_rate(void *instance, irda_param_t *param, + int get); +static int ircomm_param_data_format(void *instance, irda_param_t *param, + int get); +static int ircomm_param_flow_control(void *instance, irda_param_t *param, + int get); +static int ircomm_param_xon_xoff(void *instance, irda_param_t *param, int get); +static int ircomm_param_enq_ack(void *instance, irda_param_t *param, int get); +static int ircomm_param_line_status(void *instance, irda_param_t *param, + int get); +static int ircomm_param_dte(void *instance, irda_param_t *param, int get); +static int ircomm_param_dce(void *instance, irda_param_t *param, int get); +static int ircomm_param_poll(void *instance, irda_param_t *param, int get); + +static const pi_minor_info_t pi_minor_call_table_common[] = { + { ircomm_param_service_type, PV_INT_8_BITS }, + { ircomm_param_port_type, PV_INT_8_BITS }, + { ircomm_param_port_name, PV_STRING } +}; +static const pi_minor_info_t pi_minor_call_table_non_raw[] = { + { ircomm_param_data_rate, PV_INT_32_BITS | PV_BIG_ENDIAN }, + { ircomm_param_data_format, PV_INT_8_BITS }, + { ircomm_param_flow_control, PV_INT_8_BITS }, + { ircomm_param_xon_xoff, PV_INT_16_BITS }, + { ircomm_param_enq_ack, PV_INT_16_BITS }, + { ircomm_param_line_status, PV_INT_8_BITS } +}; +static const pi_minor_info_t pi_minor_call_table_9_wire[] = { + { ircomm_param_dte, PV_INT_8_BITS }, + { ircomm_param_dce, PV_INT_8_BITS }, + { ircomm_param_poll, PV_NO_VALUE }, +}; + +static const pi_major_info_t pi_major_call_table[] = { + { pi_minor_call_table_common, 3 }, + { pi_minor_call_table_non_raw, 6 }, + { pi_minor_call_table_9_wire, 3 } +/* { pi_minor_call_table_centronics } */ +}; + +pi_param_info_t ircomm_param_info = { pi_major_call_table, 3, 0x0f, 4 }; + +/* + * Function ircomm_param_request (self, pi, flush) + * + * Queue a parameter for the control channel + * + */ +int ircomm_param_request(struct ircomm_tty_cb *self, __u8 pi, int flush) +{ + unsigned long flags; + struct sk_buff *skb; + int count; + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); + + /* Make sure we don't send parameters for raw mode */ + if (self->service_type == IRCOMM_3_WIRE_RAW) + return 0; + + spin_lock_irqsave(&self->spinlock, flags); + + skb = self->ctrl_skb; + if (!skb) { + skb = alloc_skb(256, GFP_ATOMIC); + if (!skb) { + spin_unlock_irqrestore(&self->spinlock, flags); + return -ENOMEM; + } + + skb_reserve(skb, self->max_header_size); + self->ctrl_skb = skb; + } + /* + * Inserting is a little bit tricky since we don't know how much + * room we will need. But this should hopefully work OK + */ + count = irda_param_insert(self, pi, skb_tail_pointer(skb), + skb_tailroom(skb), &ircomm_param_info); + if (count < 0) { + net_warn_ratelimited("%s(), no room for parameter!\n", + __func__); + spin_unlock_irqrestore(&self->spinlock, flags); + return -1; + } + skb_put(skb, count); + pr_debug("%s(), skb->len=%d\n", __func__, skb->len); + + spin_unlock_irqrestore(&self->spinlock, flags); + + if (flush) { + /* ircomm_tty_do_softint will take care of the rest */ + schedule_work(&self->tqueue); + } + + return count; +} + +/* + * Function ircomm_param_service_type (self, buf, len) + * + * Handle service type, this function will both be called after the LM-IAS + * query and then the remote device sends its initial parameters + * + */ +static int ircomm_param_service_type(void *instance, irda_param_t *param, + int get) +{ + struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; + __u8 service_type = (__u8) param->pv.i; + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); + + if (get) { + param->pv.i = self->settings.service_type; + return 0; + } + + /* Find all common service types */ + service_type &= self->service_type; + if (!service_type) { + pr_debug("%s(), No common service type to use!\n", __func__); + return -1; + } + pr_debug("%s(), services in common=%02x\n", __func__ , + service_type); + + /* + * Now choose a preferred service type of those available + */ + if (service_type & IRCOMM_CENTRONICS) + self->settings.service_type = IRCOMM_CENTRONICS; + else if (service_type & IRCOMM_9_WIRE) + self->settings.service_type = IRCOMM_9_WIRE; + else if (service_type & IRCOMM_3_WIRE) + self->settings.service_type = IRCOMM_3_WIRE; + else if (service_type & IRCOMM_3_WIRE_RAW) + self->settings.service_type = IRCOMM_3_WIRE_RAW; + + pr_debug("%s(), resulting service type=0x%02x\n", __func__ , + self->settings.service_type); + + /* + * Now the line is ready for some communication. Check if we are a + * server, and send over some initial parameters. + * Client do it in ircomm_tty_state_setup(). + * Note : we may get called from ircomm_tty_getvalue_confirm(), + * therefore before we even have open any socket. And self->client + * is initialised to TRUE only later. So, we check if the link is + * really initialised. - Jean II + */ + if ((self->max_header_size != IRCOMM_TTY_HDR_UNINITIALISED) && + (!self->client) && + (self->settings.service_type != IRCOMM_3_WIRE_RAW)) + { + /* Init connection */ + ircomm_tty_send_initial_parameters(self); + ircomm_tty_link_established(self); + } + + return 0; +} + +/* + * Function ircomm_param_port_type (self, param) + * + * The port type parameter tells if the devices are serial or parallel. + * Since we only advertise serial service, this parameter should only + * be equal to IRCOMM_SERIAL. + */ +static int ircomm_param_port_type(void *instance, irda_param_t *param, int get) +{ + struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); + + if (get) + param->pv.i = IRCOMM_SERIAL; + else { + self->settings.port_type = (__u8) param->pv.i; + + pr_debug("%s(), port type=%d\n", __func__ , + self->settings.port_type); + } + return 0; +} + +/* + * Function ircomm_param_port_name (self, param) + * + * Exchange port name + * + */ +static int ircomm_param_port_name(void *instance, irda_param_t *param, int get) +{ + struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); + + if (get) { + pr_debug("%s(), not imp!\n", __func__); + } else { + pr_debug("%s(), port-name=%s\n", __func__ , param->pv.c); + strncpy(self->settings.port_name, param->pv.c, 32); + } + + return 0; +} + +/* + * Function ircomm_param_data_rate (self, param) + * + * Exchange data rate to be used in this settings + * + */ +static int ircomm_param_data_rate(void *instance, irda_param_t *param, int get) +{ + struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); + + if (get) + param->pv.i = self->settings.data_rate; + else + self->settings.data_rate = param->pv.i; + + pr_debug("%s(), data rate = %d\n", __func__ , param->pv.i); + + return 0; +} + +/* + * Function ircomm_param_data_format (self, param) + * + * Exchange data format to be used in this settings + * + */ +static int ircomm_param_data_format(void *instance, irda_param_t *param, + int get) +{ + struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); + + if (get) + param->pv.i = self->settings.data_format; + else + self->settings.data_format = (__u8) param->pv.i; + + return 0; +} + +/* + * Function ircomm_param_flow_control (self, param) + * + * Exchange flow control settings to be used in this settings + * + */ +static int ircomm_param_flow_control(void *instance, irda_param_t *param, + int get) +{ + struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); + + if (get) + param->pv.i = self->settings.flow_control; + else + self->settings.flow_control = (__u8) param->pv.i; + + pr_debug("%s(), flow control = 0x%02x\n", __func__ , (__u8)param->pv.i); + + return 0; +} + +/* + * Function ircomm_param_xon_xoff (self, param) + * + * Exchange XON/XOFF characters + * + */ +static int ircomm_param_xon_xoff(void *instance, irda_param_t *param, int get) +{ + struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); + + if (get) { + param->pv.i = self->settings.xonxoff[0]; + param->pv.i |= self->settings.xonxoff[1] << 8; + } else { + self->settings.xonxoff[0] = (__u16) param->pv.i & 0xff; + self->settings.xonxoff[1] = (__u16) param->pv.i >> 8; + } + + pr_debug("%s(), XON/XOFF = 0x%02x,0x%02x\n", __func__ , + param->pv.i & 0xff, param->pv.i >> 8); + + return 0; +} + +/* + * Function ircomm_param_enq_ack (self, param) + * + * Exchange ENQ/ACK characters + * + */ +static int ircomm_param_enq_ack(void *instance, irda_param_t *param, int get) +{ + struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); + + if (get) { + param->pv.i = self->settings.enqack[0]; + param->pv.i |= self->settings.enqack[1] << 8; + } else { + self->settings.enqack[0] = (__u16) param->pv.i & 0xff; + self->settings.enqack[1] = (__u16) param->pv.i >> 8; + } + + pr_debug("%s(), ENQ/ACK = 0x%02x,0x%02x\n", __func__ , + param->pv.i & 0xff, param->pv.i >> 8); + + return 0; +} + +/* + * Function ircomm_param_line_status (self, param) + * + * + * + */ +static int ircomm_param_line_status(void *instance, irda_param_t *param, + int get) +{ + pr_debug("%s(), not impl.\n", __func__); + + return 0; +} + +/* + * Function ircomm_param_dte (instance, param) + * + * If we get here, there must be some sort of null-modem connection, and + * we are probably working in server mode as well. + */ +static int ircomm_param_dte(void *instance, irda_param_t *param, int get) +{ + struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; + __u8 dte; + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); + + if (get) + param->pv.i = self->settings.dte; + else { + dte = (__u8) param->pv.i; + + self->settings.dce = 0; + + if (dte & IRCOMM_DELTA_DTR) + self->settings.dce |= (IRCOMM_DELTA_DSR| + IRCOMM_DELTA_RI | + IRCOMM_DELTA_CD); + if (dte & IRCOMM_DTR) + self->settings.dce |= (IRCOMM_DSR| + IRCOMM_RI | + IRCOMM_CD); + + if (dte & IRCOMM_DELTA_RTS) + self->settings.dce |= IRCOMM_DELTA_CTS; + if (dte & IRCOMM_RTS) + self->settings.dce |= IRCOMM_CTS; + + /* Take appropriate actions */ + ircomm_tty_check_modem_status(self); + + /* Null modem cable emulator */ + self->settings.null_modem = TRUE; + } + + return 0; +} + +/* + * Function ircomm_param_dce (instance, param) + * + * + * + */ +static int ircomm_param_dce(void *instance, irda_param_t *param, int get) +{ + struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; + __u8 dce; + + pr_debug("%s(), dce = 0x%02x\n", __func__ , (__u8)param->pv.i); + + dce = (__u8) param->pv.i; + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); + + self->settings.dce = dce; + + /* Check if any of the settings have changed */ + if (dce & 0x0f) { + if (dce & IRCOMM_DELTA_CTS) { + pr_debug("%s(), CTS\n", __func__); + } + } + + ircomm_tty_check_modem_status(self); + + return 0; +} + +/* + * Function ircomm_param_poll (instance, param) + * + * Called when the peer device is polling for the line settings + * + */ +static int ircomm_param_poll(void *instance, irda_param_t *param, int get) +{ + struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); + + /* Poll parameters are always of length 0 (just a signal) */ + if (!get) { + /* Respond with DTE line settings */ + ircomm_param_request(self, IRCOMM_DTE, TRUE); + } + return 0; +} + + + + + diff --git a/drivers/staging/irda/net/ircomm/ircomm_ttp.c b/drivers/staging/irda/net/ircomm/ircomm_ttp.c new file mode 100644 index 000000000000..4b81e0934770 --- /dev/null +++ b/drivers/staging/irda/net/ircomm/ircomm_ttp.c @@ -0,0 +1,350 @@ +/********************************************************************* + * + * Filename: ircomm_ttp.c + * Version: 1.0 + * Description: Interface between IrCOMM and IrTTP + * Status: Stable + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Sun Jun 6 20:48:27 1999 + * Modified at: Mon Dec 13 11:35:13 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1999 Dag Brattli, All Rights Reserved. + * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + ********************************************************************/ + +#include <linux/init.h> + +#include <net/irda/irda.h> +#include <net/irda/irlmp.h> +#include <net/irda/iriap.h> +#include <net/irda/irttp.h> + +#include <net/irda/ircomm_event.h> +#include <net/irda/ircomm_ttp.h> + +static int ircomm_ttp_data_indication(void *instance, void *sap, + struct sk_buff *skb); +static void ircomm_ttp_connect_confirm(void *instance, void *sap, + struct qos_info *qos, + __u32 max_sdu_size, + __u8 max_header_size, + struct sk_buff *skb); +static void ircomm_ttp_connect_indication(void *instance, void *sap, + struct qos_info *qos, + __u32 max_sdu_size, + __u8 max_header_size, + struct sk_buff *skb); +static void ircomm_ttp_flow_indication(void *instance, void *sap, + LOCAL_FLOW cmd); +static void ircomm_ttp_disconnect_indication(void *instance, void *sap, + LM_REASON reason, + struct sk_buff *skb); +static int ircomm_ttp_data_request(struct ircomm_cb *self, + struct sk_buff *skb, + int clen); +static int ircomm_ttp_connect_request(struct ircomm_cb *self, + struct sk_buff *userdata, + struct ircomm_info *info); +static int ircomm_ttp_connect_response(struct ircomm_cb *self, + struct sk_buff *userdata); +static int ircomm_ttp_disconnect_request(struct ircomm_cb *self, + struct sk_buff *userdata, + struct ircomm_info *info); + +/* + * Function ircomm_open_tsap (self) + * + * + * + */ +int ircomm_open_tsap(struct ircomm_cb *self) +{ + notify_t notify; + + /* Register callbacks */ + irda_notify_init(¬ify); + notify.data_indication = ircomm_ttp_data_indication; + notify.connect_confirm = ircomm_ttp_connect_confirm; + notify.connect_indication = ircomm_ttp_connect_indication; + notify.flow_indication = ircomm_ttp_flow_indication; + notify.disconnect_indication = ircomm_ttp_disconnect_indication; + notify.instance = self; + strlcpy(notify.name, "IrCOMM", sizeof(notify.name)); + + self->tsap = irttp_open_tsap(LSAP_ANY, DEFAULT_INITIAL_CREDIT, + ¬ify); + if (!self->tsap) { + pr_debug("%sfailed to allocate tsap\n", __func__); + return -1; + } + self->slsap_sel = self->tsap->stsap_sel; + + /* + * Initialize the call-table for issuing commands + */ + self->issue.data_request = ircomm_ttp_data_request; + self->issue.connect_request = ircomm_ttp_connect_request; + self->issue.connect_response = ircomm_ttp_connect_response; + self->issue.disconnect_request = ircomm_ttp_disconnect_request; + + return 0; +} + +/* + * Function ircomm_ttp_connect_request (self, userdata) + * + * + * + */ +static int ircomm_ttp_connect_request(struct ircomm_cb *self, + struct sk_buff *userdata, + struct ircomm_info *info) +{ + int ret = 0; + + /* Don't forget to refcount it - should be NULL anyway */ + if(userdata) + skb_get(userdata); + + ret = irttp_connect_request(self->tsap, info->dlsap_sel, + info->saddr, info->daddr, NULL, + TTP_SAR_DISABLE, userdata); + + return ret; +} + +/* + * Function ircomm_ttp_connect_response (self, skb) + * + * + * + */ +static int ircomm_ttp_connect_response(struct ircomm_cb *self, + struct sk_buff *userdata) +{ + int ret; + + /* Don't forget to refcount it - should be NULL anyway */ + if(userdata) + skb_get(userdata); + + ret = irttp_connect_response(self->tsap, TTP_SAR_DISABLE, userdata); + + return ret; +} + +/* + * Function ircomm_ttp_data_request (self, userdata) + * + * Send IrCOMM data to IrTTP layer. Currently we do not try to combine + * control data with pure data, so they will be sent as separate frames. + * Should not be a big problem though, since control frames are rare. But + * some of them are sent after connection establishment, so this can + * increase the latency a bit. + */ +static int ircomm_ttp_data_request(struct ircomm_cb *self, + struct sk_buff *skb, + int clen) +{ + int ret; + + IRDA_ASSERT(skb != NULL, return -1;); + + pr_debug("%s(), clen=%d\n", __func__ , clen); + + /* + * Insert clen field, currently we either send data only, or control + * only frames, to make things easier and avoid queueing + */ + IRDA_ASSERT(skb_headroom(skb) >= IRCOMM_HEADER_SIZE, return -1;); + + /* Don't forget to refcount it - see ircomm_tty_do_softint() */ + skb_get(skb); + + skb_push(skb, IRCOMM_HEADER_SIZE); + + skb->data[0] = clen; + + ret = irttp_data_request(self->tsap, skb); + if (ret) { + net_err_ratelimited("%s(), failed\n", __func__); + /* irttp_data_request already free the packet */ + } + + return ret; +} + +/* + * Function ircomm_ttp_data_indication (instance, sap, skb) + * + * Incoming data + * + */ +static int ircomm_ttp_data_indication(void *instance, void *sap, + struct sk_buff *skb) +{ + struct ircomm_cb *self = (struct ircomm_cb *) instance; + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;); + IRDA_ASSERT(skb != NULL, return -1;); + + ircomm_do_event(self, IRCOMM_TTP_DATA_INDICATION, skb, NULL); + + /* Drop reference count - see ircomm_tty_data_indication(). */ + dev_kfree_skb(skb); + + return 0; +} + +static void ircomm_ttp_connect_confirm(void *instance, void *sap, + struct qos_info *qos, + __u32 max_sdu_size, + __u8 max_header_size, + struct sk_buff *skb) +{ + struct ircomm_cb *self = (struct ircomm_cb *) instance; + struct ircomm_info info; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;); + IRDA_ASSERT(skb != NULL, return;); + IRDA_ASSERT(qos != NULL, goto out;); + + if (max_sdu_size != TTP_SAR_DISABLE) { + net_err_ratelimited("%s(), SAR not allowed for IrCOMM!\n", + __func__); + goto out; + } + + info.max_data_size = irttp_get_max_seg_size(self->tsap) + - IRCOMM_HEADER_SIZE; + info.max_header_size = max_header_size + IRCOMM_HEADER_SIZE; + info.qos = qos; + + ircomm_do_event(self, IRCOMM_TTP_CONNECT_CONFIRM, skb, &info); + +out: + /* Drop reference count - see ircomm_tty_connect_confirm(). */ + dev_kfree_skb(skb); +} + +/* + * Function ircomm_ttp_connect_indication (instance, sap, qos, max_sdu_size, + * max_header_size, skb) + * + * + * + */ +static void ircomm_ttp_connect_indication(void *instance, void *sap, + struct qos_info *qos, + __u32 max_sdu_size, + __u8 max_header_size, + struct sk_buff *skb) +{ + struct ircomm_cb *self = (struct ircomm_cb *)instance; + struct ircomm_info info; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;); + IRDA_ASSERT(skb != NULL, return;); + IRDA_ASSERT(qos != NULL, goto out;); + + if (max_sdu_size != TTP_SAR_DISABLE) { + net_err_ratelimited("%s(), SAR not allowed for IrCOMM!\n", + __func__); + goto out; + } + + info.max_data_size = irttp_get_max_seg_size(self->tsap) + - IRCOMM_HEADER_SIZE; + info.max_header_size = max_header_size + IRCOMM_HEADER_SIZE; + info.qos = qos; + + ircomm_do_event(self, IRCOMM_TTP_CONNECT_INDICATION, skb, &info); + +out: + /* Drop reference count - see ircomm_tty_connect_indication(). */ + dev_kfree_skb(skb); +} + +/* + * Function ircomm_ttp_disconnect_request (self, userdata, info) + * + * + * + */ +static int ircomm_ttp_disconnect_request(struct ircomm_cb *self, + struct sk_buff *userdata, + struct ircomm_info *info) +{ + int ret; + + /* Don't forget to refcount it - should be NULL anyway */ + if(userdata) + skb_get(userdata); + + ret = irttp_disconnect_request(self->tsap, userdata, P_NORMAL); + + return ret; +} + +/* + * Function ircomm_ttp_disconnect_indication (instance, sap, reason, skb) + * + * + * + */ +static void ircomm_ttp_disconnect_indication(void *instance, void *sap, + LM_REASON reason, + struct sk_buff *skb) +{ + struct ircomm_cb *self = (struct ircomm_cb *) instance; + struct ircomm_info info; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;); + + info.reason = reason; + + ircomm_do_event(self, IRCOMM_TTP_DISCONNECT_INDICATION, skb, &info); + + /* Drop reference count - see ircomm_tty_disconnect_indication(). */ + if(skb) + dev_kfree_skb(skb); +} + +/* + * Function ircomm_ttp_flow_indication (instance, sap, cmd) + * + * Layer below is telling us to start or stop the flow of data + * + */ +static void ircomm_ttp_flow_indication(void *instance, void *sap, + LOCAL_FLOW cmd) +{ + struct ircomm_cb *self = (struct ircomm_cb *) instance; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;); + + if (self->notify.flow_indication) + self->notify.flow_indication(self->notify.instance, self, cmd); +} + + diff --git a/drivers/staging/irda/net/ircomm/ircomm_tty.c b/drivers/staging/irda/net/ircomm/ircomm_tty.c new file mode 100644 index 000000000000..ec157c3419b5 --- /dev/null +++ b/drivers/staging/irda/net/ircomm/ircomm_tty.c @@ -0,0 +1,1329 @@ +/********************************************************************* + * + * Filename: ircomm_tty.c + * Version: 1.0 + * Description: IrCOMM serial TTY driver + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Sun Jun 6 21:00:56 1999 + * Modified at: Wed Feb 23 00:09:02 2000 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * Sources: serial.c and previous IrCOMM work by Takahide Higuchi + * + * Copyright (c) 1999-2000 Dag Brattli, All Rights Reserved. + * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + ********************************************************************/ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/fs.h> +#include <linux/slab.h> +#include <linux/sched/signal.h> +#include <linux/seq_file.h> +#include <linux/termios.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> +#include <linux/interrupt.h> +#include <linux/device.h> /* for MODULE_ALIAS_CHARDEV_MAJOR */ + +#include <linux/uaccess.h> + +#include <net/irda/irda.h> +#include <net/irda/irmod.h> + +#include <net/irda/ircomm_core.h> +#include <net/irda/ircomm_param.h> +#include <net/irda/ircomm_tty_attach.h> +#include <net/irda/ircomm_tty.h> + +static int ircomm_tty_install(struct tty_driver *driver, + struct tty_struct *tty); +static int ircomm_tty_open(struct tty_struct *tty, struct file *filp); +static void ircomm_tty_close(struct tty_struct * tty, struct file *filp); +static int ircomm_tty_write(struct tty_struct * tty, + const unsigned char *buf, int count); +static int ircomm_tty_write_room(struct tty_struct *tty); +static void ircomm_tty_throttle(struct tty_struct *tty); +static void ircomm_tty_unthrottle(struct tty_struct *tty); +static int ircomm_tty_chars_in_buffer(struct tty_struct *tty); +static void ircomm_tty_flush_buffer(struct tty_struct *tty); +static void ircomm_tty_send_xchar(struct tty_struct *tty, char ch); +static void ircomm_tty_wait_until_sent(struct tty_struct *tty, int timeout); +static void ircomm_tty_hangup(struct tty_struct *tty); +static void ircomm_tty_do_softint(struct work_struct *work); +static void ircomm_tty_shutdown(struct ircomm_tty_cb *self); +static void ircomm_tty_stop(struct tty_struct *tty); + +static int ircomm_tty_data_indication(void *instance, void *sap, + struct sk_buff *skb); +static int ircomm_tty_control_indication(void *instance, void *sap, + struct sk_buff *skb); +static void ircomm_tty_flow_indication(void *instance, void *sap, + LOCAL_FLOW cmd); +#ifdef CONFIG_PROC_FS +static const struct file_operations ircomm_tty_proc_fops; +#endif /* CONFIG_PROC_FS */ +static struct tty_driver *driver; + +static hashbin_t *ircomm_tty = NULL; + +static const struct tty_operations ops = { + .install = ircomm_tty_install, + .open = ircomm_tty_open, + .close = ircomm_tty_close, + .write = ircomm_tty_write, + .write_room = ircomm_tty_write_room, + .chars_in_buffer = ircomm_tty_chars_in_buffer, + .flush_buffer = ircomm_tty_flush_buffer, + .ioctl = ircomm_tty_ioctl, /* ircomm_tty_ioctl.c */ + .tiocmget = ircomm_tty_tiocmget, /* ircomm_tty_ioctl.c */ + .tiocmset = ircomm_tty_tiocmset, /* ircomm_tty_ioctl.c */ + .throttle = ircomm_tty_throttle, + .unthrottle = ircomm_tty_unthrottle, + .send_xchar = ircomm_tty_send_xchar, + .set_termios = ircomm_tty_set_termios, + .stop = ircomm_tty_stop, + .start = ircomm_tty_start, + .hangup = ircomm_tty_hangup, + .wait_until_sent = ircomm_tty_wait_until_sent, +#ifdef CONFIG_PROC_FS + .proc_fops = &ircomm_tty_proc_fops, +#endif /* CONFIG_PROC_FS */ +}; + +static void ircomm_port_raise_dtr_rts(struct tty_port *port, int raise) +{ + struct ircomm_tty_cb *self = container_of(port, struct ircomm_tty_cb, + port); + /* + * Here, we use to lock those two guys, but as ircomm_param_request() + * does it itself, I don't see the point (and I see the deadlock). + * Jean II + */ + if (raise) + self->settings.dte |= IRCOMM_RTS | IRCOMM_DTR; + else + self->settings.dte &= ~(IRCOMM_RTS | IRCOMM_DTR); + + ircomm_param_request(self, IRCOMM_DTE, TRUE); +} + +static int ircomm_port_carrier_raised(struct tty_port *port) +{ + struct ircomm_tty_cb *self = container_of(port, struct ircomm_tty_cb, + port); + return self->settings.dce & IRCOMM_CD; +} + +static const struct tty_port_operations ircomm_port_ops = { + .dtr_rts = ircomm_port_raise_dtr_rts, + .carrier_raised = ircomm_port_carrier_raised, +}; + +/* + * Function ircomm_tty_init() + * + * Init IrCOMM TTY layer/driver + * + */ +static int __init ircomm_tty_init(void) +{ + driver = alloc_tty_driver(IRCOMM_TTY_PORTS); + if (!driver) + return -ENOMEM; + ircomm_tty = hashbin_new(HB_LOCK); + if (ircomm_tty == NULL) { + net_err_ratelimited("%s(), can't allocate hashbin!\n", + __func__); + put_tty_driver(driver); + return -ENOMEM; + } + + driver->driver_name = "ircomm"; + driver->name = "ircomm"; + driver->major = IRCOMM_TTY_MAJOR; + driver->minor_start = IRCOMM_TTY_MINOR; + driver->type = TTY_DRIVER_TYPE_SERIAL; + driver->subtype = SERIAL_TYPE_NORMAL; + driver->init_termios = tty_std_termios; + driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; + driver->flags = TTY_DRIVER_REAL_RAW; + tty_set_operations(driver, &ops); + if (tty_register_driver(driver)) { + net_err_ratelimited("%s(): Couldn't register serial driver\n", + __func__); + put_tty_driver(driver); + return -1; + } + return 0; +} + +static void __exit __ircomm_tty_cleanup(struct ircomm_tty_cb *self) +{ + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); + + ircomm_tty_shutdown(self); + + self->magic = 0; + tty_port_destroy(&self->port); + kfree(self); +} + +/* + * Function ircomm_tty_cleanup () + * + * Remove IrCOMM TTY layer/driver + * + */ +static void __exit ircomm_tty_cleanup(void) +{ + int ret; + + ret = tty_unregister_driver(driver); + if (ret) { + net_err_ratelimited("%s(), failed to unregister driver\n", + __func__); + return; + } + + hashbin_delete(ircomm_tty, (FREE_FUNC) __ircomm_tty_cleanup); + put_tty_driver(driver); +} + +/* + * Function ircomm_startup (self) + * + * + * + */ +static int ircomm_tty_startup(struct ircomm_tty_cb *self) +{ + notify_t notify; + int ret = -ENODEV; + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); + + /* Check if already open */ + if (tty_port_initialized(&self->port)) { + pr_debug("%s(), already open so break out!\n", __func__); + return 0; + } + tty_port_set_initialized(&self->port, 1); + + /* Register with IrCOMM */ + irda_notify_init(¬ify); + /* These callbacks we must handle ourselves */ + notify.data_indication = ircomm_tty_data_indication; + notify.udata_indication = ircomm_tty_control_indication; + notify.flow_indication = ircomm_tty_flow_indication; + + /* Use the ircomm_tty interface for these ones */ + notify.disconnect_indication = ircomm_tty_disconnect_indication; + notify.connect_confirm = ircomm_tty_connect_confirm; + notify.connect_indication = ircomm_tty_connect_indication; + strlcpy(notify.name, "ircomm_tty", sizeof(notify.name)); + notify.instance = self; + + if (!self->ircomm) { + self->ircomm = ircomm_open(¬ify, self->service_type, + self->line); + } + if (!self->ircomm) + goto err; + + self->slsap_sel = self->ircomm->slsap_sel; + + /* Connect IrCOMM link with remote device */ + ret = ircomm_tty_attach_cable(self); + if (ret < 0) { + net_err_ratelimited("%s(), error attaching cable!\n", __func__); + goto err; + } + + return 0; +err: + tty_port_set_initialized(&self->port, 0); + return ret; +} + +/* + * Function ircomm_block_til_ready (self, filp) + * + * + * + */ +static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self, + struct tty_struct *tty, struct file *filp) +{ + struct tty_port *port = &self->port; + DECLARE_WAITQUEUE(wait, current); + int retval; + int do_clocal = 0; + unsigned long flags; + + /* + * If non-blocking mode is set, or the port is not enabled, + * then make the check up front and then exit. + */ + if (tty_io_error(tty)) { + tty_port_set_active(port, 1); + return 0; + } + + if (filp->f_flags & O_NONBLOCK) { + /* nonblock mode is set */ + if (C_BAUD(tty)) + tty_port_raise_dtr_rts(port); + tty_port_set_active(port, 1); + pr_debug("%s(), O_NONBLOCK requested!\n", __func__); + return 0; + } + + if (C_CLOCAL(tty)) { + pr_debug("%s(), doing CLOCAL!\n", __func__); + do_clocal = 1; + } + + /* Wait for carrier detect and the line to become + * free (i.e., not in use by the callout). While we are in + * this loop, port->count is dropped by one, so that + * mgsl_close() knows when to free things. We restore it upon + * exit, either normal or abnormal. + */ + + retval = 0; + add_wait_queue(&port->open_wait, &wait); + + pr_debug("%s(%d):block_til_ready before block on %s open_count=%d\n", + __FILE__, __LINE__, tty->driver->name, port->count); + + spin_lock_irqsave(&port->lock, flags); + port->count--; + port->blocked_open++; + spin_unlock_irqrestore(&port->lock, flags); + + while (1) { + if (C_BAUD(tty) && tty_port_initialized(port)) + tty_port_raise_dtr_rts(port); + + set_current_state(TASK_INTERRUPTIBLE); + + if (tty_hung_up_p(filp) || !tty_port_initialized(port)) { + retval = (port->flags & ASYNC_HUP_NOTIFY) ? + -EAGAIN : -ERESTARTSYS; + break; + } + + /* + * Check if link is ready now. Even if CLOCAL is + * specified, we cannot return before the IrCOMM link is + * ready + */ + if ((do_clocal || tty_port_carrier_raised(port)) && + self->state == IRCOMM_TTY_READY) + { + break; + } + + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } + + pr_debug("%s(%d):block_til_ready blocking on %s open_count=%d\n", + __FILE__, __LINE__, tty->driver->name, port->count); + + schedule(); + } + + __set_current_state(TASK_RUNNING); + remove_wait_queue(&port->open_wait, &wait); + + spin_lock_irqsave(&port->lock, flags); + if (!tty_hung_up_p(filp)) + port->count++; + port->blocked_open--; + spin_unlock_irqrestore(&port->lock, flags); + + pr_debug("%s(%d):block_til_ready after blocking on %s open_count=%d\n", + __FILE__, __LINE__, tty->driver->name, port->count); + + if (!retval) + tty_port_set_active(port, 1); + + return retval; +} + + +static int ircomm_tty_install(struct tty_driver *driver, struct tty_struct *tty) +{ + struct ircomm_tty_cb *self; + unsigned int line = tty->index; + + /* Check if instance already exists */ + self = hashbin_lock_find(ircomm_tty, line, NULL); + if (!self) { + /* No, so make new instance */ + self = kzalloc(sizeof(struct ircomm_tty_cb), GFP_KERNEL); + if (self == NULL) + return -ENOMEM; + + tty_port_init(&self->port); + self->port.ops = &ircomm_port_ops; + self->magic = IRCOMM_TTY_MAGIC; + self->flow = FLOW_STOP; + + self->line = line; + INIT_WORK(&self->tqueue, ircomm_tty_do_softint); + self->max_header_size = IRCOMM_TTY_HDR_UNINITIALISED; + self->max_data_size = IRCOMM_TTY_DATA_UNINITIALISED; + + /* Init some important stuff */ + init_timer(&self->watchdog_timer); + spin_lock_init(&self->spinlock); + + /* + * Force TTY into raw mode by default which is usually what + * we want for IrCOMM and IrLPT. This way applications will + * not have to twiddle with printcap etc. + * + * Note this is completely usafe and doesn't work properly + */ + tty->termios.c_iflag = 0; + tty->termios.c_oflag = 0; + + /* Insert into hash */ + hashbin_insert(ircomm_tty, (irda_queue_t *) self, line, NULL); + } + + tty->driver_data = self; + + return tty_port_install(&self->port, driver, tty); +} + +/* + * Function ircomm_tty_open (tty, filp) + * + * This routine is called when a particular tty device is opened. This + * routine is mandatory; if this routine is not filled in, the attempted + * open will fail with ENODEV. + */ +static int ircomm_tty_open(struct tty_struct *tty, struct file *filp) +{ + struct ircomm_tty_cb *self = tty->driver_data; + unsigned long flags; + int ret; + + /* ++ is not atomic, so this should be protected - Jean II */ + spin_lock_irqsave(&self->port.lock, flags); + self->port.count++; + spin_unlock_irqrestore(&self->port.lock, flags); + tty_port_tty_set(&self->port, tty); + + pr_debug("%s(), %s%d, count = %d\n", __func__ , tty->driver->name, + self->line, self->port.count); + + /* Not really used by us, but lets do it anyway */ + self->port.low_latency = (self->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0; + + /* Check if this is a "normal" ircomm device, or an irlpt device */ + if (self->line < 0x10) { + self->service_type = IRCOMM_3_WIRE | IRCOMM_9_WIRE; + self->settings.service_type = IRCOMM_9_WIRE; /* 9 wire as default */ + /* Jan Kiszka -> add DSR/RI -> Conform to IrCOMM spec */ + self->settings.dce = IRCOMM_CTS | IRCOMM_CD | IRCOMM_DSR | IRCOMM_RI; /* Default line settings */ + pr_debug("%s(), IrCOMM device\n", __func__); + } else { + pr_debug("%s(), IrLPT device\n", __func__); + self->service_type = IRCOMM_3_WIRE_RAW; + self->settings.service_type = IRCOMM_3_WIRE_RAW; /* Default */ + } + + ret = ircomm_tty_startup(self); + if (ret) + return ret; + + ret = ircomm_tty_block_til_ready(self, tty, filp); + if (ret) { + pr_debug("%s(), returning after block_til_ready with %d\n", + __func__, ret); + + return ret; + } + return 0; +} + +/* + * Function ircomm_tty_close (tty, filp) + * + * This routine is called when a particular tty device is closed. + * + */ +static void ircomm_tty_close(struct tty_struct *tty, struct file *filp) +{ + struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; + struct tty_port *port = &self->port; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); + + if (tty_port_close_start(port, tty, filp) == 0) + return; + + ircomm_tty_shutdown(self); + + tty_driver_flush_buffer(tty); + + tty_port_close_end(port, tty); + tty_port_tty_set(port, NULL); +} + +/* + * Function ircomm_tty_flush_buffer (tty) + * + * + * + */ +static void ircomm_tty_flush_buffer(struct tty_struct *tty) +{ + struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); + + /* + * Let do_softint() do this to avoid race condition with + * do_softint() ;-) + */ + schedule_work(&self->tqueue); +} + +/* + * Function ircomm_tty_do_softint (work) + * + * We use this routine to give the write wakeup to the user at at a + * safe time (as fast as possible after write have completed). This + * can be compared to the Tx interrupt. + */ +static void ircomm_tty_do_softint(struct work_struct *work) +{ + struct ircomm_tty_cb *self = + container_of(work, struct ircomm_tty_cb, tqueue); + struct tty_struct *tty; + unsigned long flags; + struct sk_buff *skb, *ctrl_skb; + + if (!self || self->magic != IRCOMM_TTY_MAGIC) + return; + + tty = tty_port_tty_get(&self->port); + if (!tty) + return; + + /* Unlink control buffer */ + spin_lock_irqsave(&self->spinlock, flags); + + ctrl_skb = self->ctrl_skb; + self->ctrl_skb = NULL; + + spin_unlock_irqrestore(&self->spinlock, flags); + + /* Flush control buffer if any */ + if(ctrl_skb) { + if(self->flow == FLOW_START) + ircomm_control_request(self->ircomm, ctrl_skb); + /* Drop reference count - see ircomm_ttp_data_request(). */ + dev_kfree_skb(ctrl_skb); + } + + if (tty->hw_stopped) + goto put; + + /* Unlink transmit buffer */ + spin_lock_irqsave(&self->spinlock, flags); + + skb = self->tx_skb; + self->tx_skb = NULL; + + spin_unlock_irqrestore(&self->spinlock, flags); + + /* Flush transmit buffer if any */ + if (skb) { + ircomm_tty_do_event(self, IRCOMM_TTY_DATA_REQUEST, skb, NULL); + /* Drop reference count - see ircomm_ttp_data_request(). */ + dev_kfree_skb(skb); + } + + /* Check if user (still) wants to be waken up */ + tty_wakeup(tty); +put: + tty_kref_put(tty); +} + +/* + * Function ircomm_tty_write (tty, buf, count) + * + * This routine is called by the kernel to write a series of characters + * to the tty device. The characters may come from user space or kernel + * space. This routine will return the number of characters actually + * accepted for writing. This routine is mandatory. + */ +static int ircomm_tty_write(struct tty_struct *tty, + const unsigned char *buf, int count) +{ + struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; + unsigned long flags; + struct sk_buff *skb; + int tailroom = 0; + int len = 0; + int size; + + pr_debug("%s(), count=%d, hw_stopped=%d\n", __func__ , count, + tty->hw_stopped); + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); + + /* We may receive packets from the TTY even before we have finished + * our setup. Not cool. + * The problem is that we don't know the final header and data size + * to create the proper skb, so any skb we would create would have + * bogus header and data size, so need care. + * We use a bogus header size to safely detect this condition. + * Another problem is that hw_stopped was set to 0 way before it + * should be, so we would drop this skb. It should now be fixed. + * One option is to not accept data until we are properly setup. + * But, I suspect that when it happens, the ppp line discipline + * just "drops" the data, which might screw up connect scripts. + * The second option is to create a "safe skb", with large header + * and small size (see ircomm_tty_open() for values). + * We just need to make sure that when the real values get filled, + * we don't mess up the original "safe skb" (see tx_data_size). + * Jean II */ + if (self->max_header_size == IRCOMM_TTY_HDR_UNINITIALISED) { + pr_debug("%s() : not initialised\n", __func__); +#ifdef IRCOMM_NO_TX_BEFORE_INIT + /* We didn't consume anything, TTY will retry */ + return 0; +#endif + } + + if (count < 1) + return 0; + + /* Protect our manipulation of self->tx_skb and related */ + spin_lock_irqsave(&self->spinlock, flags); + + /* Fetch current transmit buffer */ + skb = self->tx_skb; + + /* + * Send out all the data we get, possibly as multiple fragmented + * frames, but this will only happen if the data is larger than the + * max data size. The normal case however is just the opposite, and + * this function may be called multiple times, and will then actually + * defragment the data and send it out as one packet as soon as + * possible, but at a safer point in time + */ + while (count) { + size = count; + + /* Adjust data size to the max data size */ + if (size > self->max_data_size) + size = self->max_data_size; + + /* + * Do we already have a buffer ready for transmit, or do + * we need to allocate a new frame + */ + if (skb) { + /* + * Any room for more data at the end of the current + * transmit buffer? Cannot use skb_tailroom, since + * dev_alloc_skb gives us a larger skb than we + * requested + * Note : use tx_data_size, because max_data_size + * may have changed and we don't want to overwrite + * the skb. - Jean II + */ + if ((tailroom = (self->tx_data_size - skb->len)) > 0) { + /* Adjust data to tailroom */ + if (size > tailroom) + size = tailroom; + } else { + /* + * Current transmit frame is full, so break + * out, so we can send it as soon as possible + */ + break; + } + } else { + /* Prepare a full sized frame */ + skb = alloc_skb(self->max_data_size+ + self->max_header_size, + GFP_ATOMIC); + if (!skb) { + spin_unlock_irqrestore(&self->spinlock, flags); + return -ENOBUFS; + } + skb_reserve(skb, self->max_header_size); + self->tx_skb = skb; + /* Remember skb size because max_data_size may + * change later on - Jean II */ + self->tx_data_size = self->max_data_size; + } + + /* Copy data */ + skb_put_data(skb, buf + len, size); + + count -= size; + len += size; + } + + spin_unlock_irqrestore(&self->spinlock, flags); + + /* + * Schedule a new thread which will transmit the frame as soon + * as possible, but at a safe point in time. We do this so the + * "user" can give us data multiple times, as PPP does (because of + * its 256 byte tx buffer). We will then defragment and send out + * all this data as one single packet. + */ + schedule_work(&self->tqueue); + + return len; +} + +/* + * Function ircomm_tty_write_room (tty) + * + * This routine returns the numbers of characters the tty driver will + * accept for queuing to be written. This number is subject to change as + * output buffers get emptied, or if the output flow control is acted. + */ +static int ircomm_tty_write_room(struct tty_struct *tty) +{ + struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; + unsigned long flags; + int ret; + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); + +#ifdef IRCOMM_NO_TX_BEFORE_INIT + /* max_header_size tells us if the channel is initialised or not. */ + if (self->max_header_size == IRCOMM_TTY_HDR_UNINITIALISED) + /* Don't bother us yet */ + return 0; +#endif + + /* Check if we are allowed to transmit any data. + * hw_stopped is the regular flow control. + * Jean II */ + if (tty->hw_stopped) + ret = 0; + else { + spin_lock_irqsave(&self->spinlock, flags); + if (self->tx_skb) + ret = self->tx_data_size - self->tx_skb->len; + else + ret = self->max_data_size; + spin_unlock_irqrestore(&self->spinlock, flags); + } + pr_debug("%s(), ret=%d\n", __func__ , ret); + + return ret; +} + +/* + * Function ircomm_tty_wait_until_sent (tty, timeout) + * + * This routine waits until the device has written out all of the + * characters in its transmitter FIFO. + */ +static void ircomm_tty_wait_until_sent(struct tty_struct *tty, int timeout) +{ + struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; + unsigned long orig_jiffies, poll_time; + unsigned long flags; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); + + orig_jiffies = jiffies; + + /* Set poll time to 200 ms */ + poll_time = msecs_to_jiffies(200); + if (timeout) + poll_time = min_t(unsigned long, timeout, poll_time); + + spin_lock_irqsave(&self->spinlock, flags); + while (self->tx_skb && self->tx_skb->len) { + spin_unlock_irqrestore(&self->spinlock, flags); + schedule_timeout_interruptible(poll_time); + spin_lock_irqsave(&self->spinlock, flags); + if (signal_pending(current)) + break; + if (timeout && time_after(jiffies, orig_jiffies + timeout)) + break; + } + spin_unlock_irqrestore(&self->spinlock, flags); + __set_current_state(TASK_RUNNING); +} + +/* + * Function ircomm_tty_throttle (tty) + * + * This routine notifies the tty driver that input buffers for the line + * discipline are close to full, and it should somehow signal that no + * more characters should be sent to the tty. + */ +static void ircomm_tty_throttle(struct tty_struct *tty) +{ + struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); + + /* Software flow control? */ + if (I_IXOFF(tty)) + ircomm_tty_send_xchar(tty, STOP_CHAR(tty)); + + /* Hardware flow control? */ + if (C_CRTSCTS(tty)) { + self->settings.dte &= ~IRCOMM_RTS; + self->settings.dte |= IRCOMM_DELTA_RTS; + + ircomm_param_request(self, IRCOMM_DTE, TRUE); + } + + ircomm_flow_request(self->ircomm, FLOW_STOP); +} + +/* + * Function ircomm_tty_unthrottle (tty) + * + * This routine notifies the tty drivers that it should signals that + * characters can now be sent to the tty without fear of overrunning the + * input buffers of the line disciplines. + */ +static void ircomm_tty_unthrottle(struct tty_struct *tty) +{ + struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); + + /* Using software flow control? */ + if (I_IXOFF(tty)) + ircomm_tty_send_xchar(tty, START_CHAR(tty)); + + /* Using hardware flow control? */ + if (C_CRTSCTS(tty)) { + self->settings.dte |= (IRCOMM_RTS|IRCOMM_DELTA_RTS); + + ircomm_param_request(self, IRCOMM_DTE, TRUE); + pr_debug("%s(), FLOW_START\n", __func__); + } + ircomm_flow_request(self->ircomm, FLOW_START); +} + +/* + * Function ircomm_tty_chars_in_buffer (tty) + * + * Indicates if there are any data in the buffer + * + */ +static int ircomm_tty_chars_in_buffer(struct tty_struct *tty) +{ + struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; + unsigned long flags; + int len = 0; + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); + + spin_lock_irqsave(&self->spinlock, flags); + + if (self->tx_skb) + len = self->tx_skb->len; + + spin_unlock_irqrestore(&self->spinlock, flags); + + return len; +} + +static void ircomm_tty_shutdown(struct ircomm_tty_cb *self) +{ + unsigned long flags; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); + + if (!tty_port_initialized(&self->port)) + return; + tty_port_set_initialized(&self->port, 0); + + ircomm_tty_detach_cable(self); + + spin_lock_irqsave(&self->spinlock, flags); + + del_timer(&self->watchdog_timer); + + /* Free parameter buffer */ + if (self->ctrl_skb) { + dev_kfree_skb(self->ctrl_skb); + self->ctrl_skb = NULL; + } + + /* Free transmit buffer */ + if (self->tx_skb) { + dev_kfree_skb(self->tx_skb); + self->tx_skb = NULL; + } + + if (self->ircomm) { + ircomm_close(self->ircomm); + self->ircomm = NULL; + } + + spin_unlock_irqrestore(&self->spinlock, flags); +} + +/* + * Function ircomm_tty_hangup (tty) + * + * This routine notifies the tty driver that it should hangup the tty + * device. + * + */ +static void ircomm_tty_hangup(struct tty_struct *tty) +{ + struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; + struct tty_port *port = &self->port; + unsigned long flags; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); + + /* ircomm_tty_flush_buffer(tty); */ + ircomm_tty_shutdown(self); + + spin_lock_irqsave(&port->lock, flags); + if (port->tty) { + set_bit(TTY_IO_ERROR, &port->tty->flags); + tty_kref_put(port->tty); + } + port->tty = NULL; + port->count = 0; + spin_unlock_irqrestore(&port->lock, flags); + tty_port_set_active(port, 0); + + wake_up_interruptible(&port->open_wait); +} + +/* + * Function ircomm_tty_send_xchar (tty, ch) + * + * This routine is used to send a high-priority XON/XOFF character to + * the device. + */ +static void ircomm_tty_send_xchar(struct tty_struct *tty, char ch) +{ + pr_debug("%s(), not impl\n", __func__); +} + +/* + * Function ircomm_tty_start (tty) + * + * This routine notifies the tty driver that it resume sending + * characters to the tty device. + */ +void ircomm_tty_start(struct tty_struct *tty) +{ + struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; + + ircomm_flow_request(self->ircomm, FLOW_START); +} + +/* + * Function ircomm_tty_stop (tty) + * + * This routine notifies the tty driver that it should stop outputting + * characters to the tty device. + */ +static void ircomm_tty_stop(struct tty_struct *tty) +{ + struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); + + ircomm_flow_request(self->ircomm, FLOW_STOP); +} + +/* + * Function ircomm_check_modem_status (self) + * + * Check for any changes in the DCE's line settings. This function should + * be called whenever the dce parameter settings changes, to update the + * flow control settings and other things + */ +void ircomm_tty_check_modem_status(struct ircomm_tty_cb *self) +{ + struct tty_struct *tty; + int status; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); + + tty = tty_port_tty_get(&self->port); + + status = self->settings.dce; + + if (status & IRCOMM_DCE_DELTA_ANY) { + /*wake_up_interruptible(&self->delta_msr_wait);*/ + } + if (tty_port_check_carrier(&self->port) && (status & IRCOMM_DELTA_CD)) { + pr_debug("%s(), ircomm%d CD now %s...\n", __func__ , self->line, + (status & IRCOMM_CD) ? "on" : "off"); + + if (status & IRCOMM_CD) { + wake_up_interruptible(&self->port.open_wait); + } else { + pr_debug("%s(), Doing serial hangup..\n", __func__); + if (tty) + tty_hangup(tty); + + /* Hangup will remote the tty, so better break out */ + goto put; + } + } + if (tty && tty_port_cts_enabled(&self->port)) { + if (tty->hw_stopped) { + if (status & IRCOMM_CTS) { + pr_debug("%s(), CTS tx start...\n", __func__); + tty->hw_stopped = 0; + + /* Wake up processes blocked on open */ + wake_up_interruptible(&self->port.open_wait); + + schedule_work(&self->tqueue); + goto put; + } + } else { + if (!(status & IRCOMM_CTS)) { + pr_debug("%s(), CTS tx stop...\n", __func__); + tty->hw_stopped = 1; + } + } + } +put: + tty_kref_put(tty); +} + +/* + * Function ircomm_tty_data_indication (instance, sap, skb) + * + * Handle incoming data, and deliver it to the line discipline + * + */ +static int ircomm_tty_data_indication(void *instance, void *sap, + struct sk_buff *skb) +{ + struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; + struct tty_struct *tty; + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); + IRDA_ASSERT(skb != NULL, return -1;); + + tty = tty_port_tty_get(&self->port); + if (!tty) { + pr_debug("%s(), no tty!\n", __func__); + return 0; + } + + /* + * If we receive data when hardware is stopped then something is wrong. + * We try to poll the peers line settings to check if we are up todate. + * Devices like WinCE can do this, and since they don't send any + * params, we can just as well declare the hardware for running. + */ + if (tty->hw_stopped && (self->flow == FLOW_START)) { + pr_debug("%s(), polling for line settings!\n", __func__); + ircomm_param_request(self, IRCOMM_POLL, TRUE); + + /* We can just as well declare the hardware for running */ + ircomm_tty_send_initial_parameters(self); + ircomm_tty_link_established(self); + } + tty_kref_put(tty); + + /* + * Use flip buffer functions since the code may be called from interrupt + * context + */ + tty_insert_flip_string(&self->port, skb->data, skb->len); + tty_flip_buffer_push(&self->port); + + /* No need to kfree_skb - see ircomm_ttp_data_indication() */ + + return 0; +} + +/* + * Function ircomm_tty_control_indication (instance, sap, skb) + * + * Parse all incoming parameters (easy!) + * + */ +static int ircomm_tty_control_indication(void *instance, void *sap, + struct sk_buff *skb) +{ + struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; + int clen; + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); + IRDA_ASSERT(skb != NULL, return -1;); + + clen = skb->data[0]; + + irda_param_extract_all(self, skb->data+1, IRDA_MIN(skb->len-1, clen), + &ircomm_param_info); + + /* No need to kfree_skb - see ircomm_control_indication() */ + + return 0; +} + +/* + * Function ircomm_tty_flow_indication (instance, sap, cmd) + * + * This function is called by IrTTP when it wants us to slow down the + * transmission of data. We just mark the hardware as stopped, and wait + * for IrTTP to notify us that things are OK again. + */ +static void ircomm_tty_flow_indication(void *instance, void *sap, + LOCAL_FLOW cmd) +{ + struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; + struct tty_struct *tty; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); + + tty = tty_port_tty_get(&self->port); + + switch (cmd) { + case FLOW_START: + pr_debug("%s(), hw start!\n", __func__); + if (tty) + tty->hw_stopped = 0; + + /* ircomm_tty_do_softint will take care of the rest */ + schedule_work(&self->tqueue); + break; + default: /* If we get here, something is very wrong, better stop */ + case FLOW_STOP: + pr_debug("%s(), hw stopped!\n", __func__); + if (tty) + tty->hw_stopped = 1; + break; + } + + tty_kref_put(tty); + self->flow = cmd; +} + +#ifdef CONFIG_PROC_FS +static void ircomm_tty_line_info(struct ircomm_tty_cb *self, struct seq_file *m) +{ + struct tty_struct *tty; + char sep; + + seq_printf(m, "State: %s\n", ircomm_tty_state[self->state]); + + seq_puts(m, "Service type: "); + if (self->service_type & IRCOMM_9_WIRE) + seq_puts(m, "9_WIRE"); + else if (self->service_type & IRCOMM_3_WIRE) + seq_puts(m, "3_WIRE"); + else if (self->service_type & IRCOMM_3_WIRE_RAW) + seq_puts(m, "3_WIRE_RAW"); + else + seq_puts(m, "No common service type!\n"); + seq_putc(m, '\n'); + + seq_printf(m, "Port name: %s\n", self->settings.port_name); + + seq_printf(m, "DTE status:"); + sep = ' '; + if (self->settings.dte & IRCOMM_RTS) { + seq_printf(m, "%cRTS", sep); + sep = '|'; + } + if (self->settings.dte & IRCOMM_DTR) { + seq_printf(m, "%cDTR", sep); + sep = '|'; + } + seq_putc(m, '\n'); + + seq_puts(m, "DCE status:"); + sep = ' '; + if (self->settings.dce & IRCOMM_CTS) { + seq_printf(m, "%cCTS", sep); + sep = '|'; + } + if (self->settings.dce & IRCOMM_DSR) { + seq_printf(m, "%cDSR", sep); + sep = '|'; + } + if (self->settings.dce & IRCOMM_CD) { + seq_printf(m, "%cCD", sep); + sep = '|'; + } + if (self->settings.dce & IRCOMM_RI) { + seq_printf(m, "%cRI", sep); + sep = '|'; + } + seq_putc(m, '\n'); + + seq_puts(m, "Configuration: "); + if (!self->settings.null_modem) + seq_puts(m, "DTE <-> DCE\n"); + else + seq_puts(m, "DTE <-> DTE (null modem emulation)\n"); + + seq_printf(m, "Data rate: %d\n", self->settings.data_rate); + + seq_puts(m, "Flow control:"); + sep = ' '; + if (self->settings.flow_control & IRCOMM_XON_XOFF_IN) { + seq_printf(m, "%cXON_XOFF_IN", sep); + sep = '|'; + } + if (self->settings.flow_control & IRCOMM_XON_XOFF_OUT) { + seq_printf(m, "%cXON_XOFF_OUT", sep); + sep = '|'; + } + if (self->settings.flow_control & IRCOMM_RTS_CTS_IN) { + seq_printf(m, "%cRTS_CTS_IN", sep); + sep = '|'; + } + if (self->settings.flow_control & IRCOMM_RTS_CTS_OUT) { + seq_printf(m, "%cRTS_CTS_OUT", sep); + sep = '|'; + } + if (self->settings.flow_control & IRCOMM_DSR_DTR_IN) { + seq_printf(m, "%cDSR_DTR_IN", sep); + sep = '|'; + } + if (self->settings.flow_control & IRCOMM_DSR_DTR_OUT) { + seq_printf(m, "%cDSR_DTR_OUT", sep); + sep = '|'; + } + if (self->settings.flow_control & IRCOMM_ENQ_ACK_IN) { + seq_printf(m, "%cENQ_ACK_IN", sep); + sep = '|'; + } + if (self->settings.flow_control & IRCOMM_ENQ_ACK_OUT) { + seq_printf(m, "%cENQ_ACK_OUT", sep); + sep = '|'; + } + seq_putc(m, '\n'); + + seq_puts(m, "Flags:"); + sep = ' '; + if (tty_port_cts_enabled(&self->port)) { + seq_printf(m, "%cASYNC_CTS_FLOW", sep); + sep = '|'; + } + if (tty_port_check_carrier(&self->port)) { + seq_printf(m, "%cASYNC_CHECK_CD", sep); + sep = '|'; + } + if (tty_port_initialized(&self->port)) { + seq_printf(m, "%cASYNC_INITIALIZED", sep); + sep = '|'; + } + if (self->port.flags & ASYNC_LOW_LATENCY) { + seq_printf(m, "%cASYNC_LOW_LATENCY", sep); + sep = '|'; + } + if (tty_port_active(&self->port)) { + seq_printf(m, "%cASYNC_NORMAL_ACTIVE", sep); + sep = '|'; + } + seq_putc(m, '\n'); + + seq_printf(m, "Role: %s\n", self->client ? "client" : "server"); + seq_printf(m, "Open count: %d\n", self->port.count); + seq_printf(m, "Max data size: %d\n", self->max_data_size); + seq_printf(m, "Max header size: %d\n", self->max_header_size); + + tty = tty_port_tty_get(&self->port); + if (tty) { + seq_printf(m, "Hardware: %s\n", + tty->hw_stopped ? "Stopped" : "Running"); + tty_kref_put(tty); + } +} + +static int ircomm_tty_proc_show(struct seq_file *m, void *v) +{ + struct ircomm_tty_cb *self; + unsigned long flags; + + spin_lock_irqsave(&ircomm_tty->hb_spinlock, flags); + + self = (struct ircomm_tty_cb *) hashbin_get_first(ircomm_tty); + while (self != NULL) { + if (self->magic != IRCOMM_TTY_MAGIC) + break; + + ircomm_tty_line_info(self, m); + self = (struct ircomm_tty_cb *) hashbin_get_next(ircomm_tty); + } + spin_unlock_irqrestore(&ircomm_tty->hb_spinlock, flags); + return 0; +} + +static int ircomm_tty_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, ircomm_tty_proc_show, NULL); +} + +static const struct file_operations ircomm_tty_proc_fops = { + .owner = THIS_MODULE, + .open = ircomm_tty_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; +#endif /* CONFIG_PROC_FS */ + +MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>"); +MODULE_DESCRIPTION("IrCOMM serial TTY driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_CHARDEV_MAJOR(IRCOMM_TTY_MAJOR); + +module_init(ircomm_tty_init); +module_exit(ircomm_tty_cleanup); diff --git a/drivers/staging/irda/net/ircomm/ircomm_tty_attach.c b/drivers/staging/irda/net/ircomm/ircomm_tty_attach.c new file mode 100644 index 000000000000..0a411019c098 --- /dev/null +++ b/drivers/staging/irda/net/ircomm/ircomm_tty_attach.c @@ -0,0 +1,987 @@ +/********************************************************************* + * + * Filename: ircomm_tty_attach.c + * Version: + * Description: Code for attaching the serial driver to IrCOMM + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Sat Jun 5 17:42:00 1999 + * Modified at: Tue Jan 4 14:20:49 2000 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1999-2000 Dag Brattli, All Rights Reserved. + * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + ********************************************************************/ + +#include <linux/init.h> +#include <linux/sched.h> + +#include <net/irda/irda.h> +#include <net/irda/irlmp.h> +#include <net/irda/iriap.h> +#include <net/irda/irttp.h> +#include <net/irda/irias_object.h> +#include <net/irda/parameters.h> + +#include <net/irda/ircomm_core.h> +#include <net/irda/ircomm_param.h> +#include <net/irda/ircomm_event.h> + +#include <net/irda/ircomm_tty.h> +#include <net/irda/ircomm_tty_attach.h> + +static void ircomm_tty_ias_register(struct ircomm_tty_cb *self); +static void ircomm_tty_discovery_indication(discinfo_t *discovery, + DISCOVERY_MODE mode, + void *priv); +static void ircomm_tty_getvalue_confirm(int result, __u16 obj_id, + struct ias_value *value, void *priv); +static void ircomm_tty_start_watchdog_timer(struct ircomm_tty_cb *self, + int timeout); +static void ircomm_tty_watchdog_timer_expired(void *data); + +static int ircomm_tty_state_idle(struct ircomm_tty_cb *self, + IRCOMM_TTY_EVENT event, + struct sk_buff *skb, + struct ircomm_tty_info *info); +static int ircomm_tty_state_search(struct ircomm_tty_cb *self, + IRCOMM_TTY_EVENT event, + struct sk_buff *skb, + struct ircomm_tty_info *info); +static int ircomm_tty_state_query_parameters(struct ircomm_tty_cb *self, + IRCOMM_TTY_EVENT event, + struct sk_buff *skb, + struct ircomm_tty_info *info); +static int ircomm_tty_state_query_lsap_sel(struct ircomm_tty_cb *self, + IRCOMM_TTY_EVENT event, + struct sk_buff *skb, + struct ircomm_tty_info *info); +static int ircomm_tty_state_setup(struct ircomm_tty_cb *self, + IRCOMM_TTY_EVENT event, + struct sk_buff *skb, + struct ircomm_tty_info *info); +static int ircomm_tty_state_ready(struct ircomm_tty_cb *self, + IRCOMM_TTY_EVENT event, + struct sk_buff *skb, + struct ircomm_tty_info *info); + +const char *const ircomm_tty_state[] = { + "IRCOMM_TTY_IDLE", + "IRCOMM_TTY_SEARCH", + "IRCOMM_TTY_QUERY_PARAMETERS", + "IRCOMM_TTY_QUERY_LSAP_SEL", + "IRCOMM_TTY_SETUP", + "IRCOMM_TTY_READY", + "*** ERROR *** ", +}; + +static const char *const ircomm_tty_event[] __maybe_unused = { + "IRCOMM_TTY_ATTACH_CABLE", + "IRCOMM_TTY_DETACH_CABLE", + "IRCOMM_TTY_DATA_REQUEST", + "IRCOMM_TTY_DATA_INDICATION", + "IRCOMM_TTY_DISCOVERY_REQUEST", + "IRCOMM_TTY_DISCOVERY_INDICATION", + "IRCOMM_TTY_CONNECT_CONFIRM", + "IRCOMM_TTY_CONNECT_INDICATION", + "IRCOMM_TTY_DISCONNECT_REQUEST", + "IRCOMM_TTY_DISCONNECT_INDICATION", + "IRCOMM_TTY_WD_TIMER_EXPIRED", + "IRCOMM_TTY_GOT_PARAMETERS", + "IRCOMM_TTY_GOT_LSAPSEL", + "*** ERROR ****", +}; + +static int (*state[])(struct ircomm_tty_cb *self, IRCOMM_TTY_EVENT event, + struct sk_buff *skb, struct ircomm_tty_info *info) = +{ + ircomm_tty_state_idle, + ircomm_tty_state_search, + ircomm_tty_state_query_parameters, + ircomm_tty_state_query_lsap_sel, + ircomm_tty_state_setup, + ircomm_tty_state_ready, +}; + +/* + * Function ircomm_tty_attach_cable (driver) + * + * Try to attach cable (IrCOMM link). This function will only return + * when the link has been connected, or if an error condition occurs. + * If success, the return value is the resulting service type. + */ +int ircomm_tty_attach_cable(struct ircomm_tty_cb *self) +{ + struct tty_struct *tty; + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); + + /* Check if somebody has already connected to us */ + if (ircomm_is_connected(self->ircomm)) { + pr_debug("%s(), already connected!\n", __func__); + return 0; + } + + /* Make sure nobody tries to write before the link is up */ + tty = tty_port_tty_get(&self->port); + if (tty) { + tty->hw_stopped = 1; + tty_kref_put(tty); + } + + ircomm_tty_ias_register(self); + + ircomm_tty_do_event(self, IRCOMM_TTY_ATTACH_CABLE, NULL, NULL); + + return 0; +} + +/* + * Function ircomm_detach_cable (driver) + * + * Detach cable, or cable has been detached by peer + * + */ +void ircomm_tty_detach_cable(struct ircomm_tty_cb *self) +{ + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); + + del_timer(&self->watchdog_timer); + + /* Remove discovery handler */ + if (self->ckey) { + irlmp_unregister_client(self->ckey); + self->ckey = NULL; + } + /* Remove IrCOMM hint bits */ + if (self->skey) { + irlmp_unregister_service(self->skey); + self->skey = NULL; + } + + if (self->iriap) { + iriap_close(self->iriap); + self->iriap = NULL; + } + + /* Remove LM-IAS object */ + if (self->obj) { + irias_delete_object(self->obj); + self->obj = NULL; + } + + ircomm_tty_do_event(self, IRCOMM_TTY_DETACH_CABLE, NULL, NULL); + + /* Reset some values */ + self->daddr = self->saddr = 0; + self->dlsap_sel = self->slsap_sel = 0; + + memset(&self->settings, 0, sizeof(struct ircomm_params)); +} + +/* + * Function ircomm_tty_ias_register (self) + * + * Register with LM-IAS depending on which service type we are + * + */ +static void ircomm_tty_ias_register(struct ircomm_tty_cb *self) +{ + __u8 oct_seq[6]; + __u16 hints; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); + + /* Compute hint bits based on service */ + hints = irlmp_service_to_hint(S_COMM); + if (self->service_type & IRCOMM_3_WIRE_RAW) + hints |= irlmp_service_to_hint(S_PRINTER); + + /* Advertise IrCOMM hint bit in discovery */ + if (!self->skey) + self->skey = irlmp_register_service(hints); + /* Set up a discovery handler */ + if (!self->ckey) + self->ckey = irlmp_register_client(hints, + ircomm_tty_discovery_indication, + NULL, (void *) self); + + /* If already done, no need to do it again */ + if (self->obj) + return; + + if (self->service_type & IRCOMM_3_WIRE_RAW) { + /* Register IrLPT with LM-IAS */ + self->obj = irias_new_object("IrLPT", IAS_IRLPT_ID); + irias_add_integer_attrib(self->obj, "IrDA:IrLMP:LsapSel", + self->slsap_sel, IAS_KERNEL_ATTR); + } else { + /* Register IrCOMM with LM-IAS */ + self->obj = irias_new_object("IrDA:IrCOMM", IAS_IRCOMM_ID); + irias_add_integer_attrib(self->obj, "IrDA:TinyTP:LsapSel", + self->slsap_sel, IAS_KERNEL_ATTR); + + /* Code the parameters into the buffer */ + irda_param_pack(oct_seq, "bbbbbb", + IRCOMM_SERVICE_TYPE, 1, self->service_type, + IRCOMM_PORT_TYPE, 1, IRCOMM_SERIAL); + + /* Register parameters with LM-IAS */ + irias_add_octseq_attrib(self->obj, "Parameters", oct_seq, 6, + IAS_KERNEL_ATTR); + } + irias_insert_object(self->obj); +} + +/* + * Function ircomm_tty_ias_unregister (self) + * + * Remove our IAS object and client hook while connected. + * + */ +static void ircomm_tty_ias_unregister(struct ircomm_tty_cb *self) +{ + /* Remove LM-IAS object now so it is not reused. + * IrCOMM deals very poorly with multiple incoming connections. + * It should looks a lot more like IrNET, and "dup" a server TSAP + * to the application TSAP (based on various rules). + * This is a cheap workaround allowing multiple clients to + * connect to us. It will not always work. + * Each IrCOMM socket has an IAS entry. Incoming connection will + * pick the first one found. So, when we are fully connected, + * we remove our IAS entries so that the next IAS entry is used. + * We do that for *both* client and server, because a server + * can also create client instances. + * Jean II */ + if (self->obj) { + irias_delete_object(self->obj); + self->obj = NULL; + } + +#if 0 + /* Remove discovery handler. + * While we are connected, we no longer need to receive + * discovery events. This would be the case if there is + * multiple IrLAP interfaces. Jean II */ + if (self->ckey) { + irlmp_unregister_client(self->ckey); + self->ckey = NULL; + } +#endif +} + +/* + * Function ircomm_send_initial_parameters (self) + * + * Send initial parameters to the remote IrCOMM device. These parameters + * must be sent before any data. + */ +int ircomm_tty_send_initial_parameters(struct ircomm_tty_cb *self) +{ + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); + + if (self->service_type & IRCOMM_3_WIRE_RAW) + return 0; + + /* + * Set default values, but only if the application for some reason + * haven't set them already + */ + pr_debug("%s(), data-rate = %d\n", __func__ , + self->settings.data_rate); + if (!self->settings.data_rate) + self->settings.data_rate = 9600; + pr_debug("%s(), data-format = %d\n", __func__ , + self->settings.data_format); + if (!self->settings.data_format) + self->settings.data_format = IRCOMM_WSIZE_8; /* 8N1 */ + + pr_debug("%s(), flow-control = %d\n", __func__ , + self->settings.flow_control); + /*self->settings.flow_control = IRCOMM_RTS_CTS_IN|IRCOMM_RTS_CTS_OUT;*/ + + /* Do not set delta values for the initial parameters */ + self->settings.dte = IRCOMM_DTR | IRCOMM_RTS; + + /* Only send service type parameter when we are the client */ + if (self->client) + ircomm_param_request(self, IRCOMM_SERVICE_TYPE, FALSE); + ircomm_param_request(self, IRCOMM_DATA_RATE, FALSE); + ircomm_param_request(self, IRCOMM_DATA_FORMAT, FALSE); + + /* For a 3 wire service, we just flush the last parameter and return */ + if (self->settings.service_type == IRCOMM_3_WIRE) { + ircomm_param_request(self, IRCOMM_FLOW_CONTROL, TRUE); + return 0; + } + + /* Only 9-wire service types continue here */ + ircomm_param_request(self, IRCOMM_FLOW_CONTROL, FALSE); +#if 0 + ircomm_param_request(self, IRCOMM_XON_XOFF, FALSE); + ircomm_param_request(self, IRCOMM_ENQ_ACK, FALSE); +#endif + /* Notify peer that we are ready to receive data */ + ircomm_param_request(self, IRCOMM_DTE, TRUE); + + return 0; +} + +/* + * Function ircomm_tty_discovery_indication (discovery) + * + * Remote device is discovered, try query the remote IAS to see which + * device it is, and which services it has. + * + */ +static void ircomm_tty_discovery_indication(discinfo_t *discovery, + DISCOVERY_MODE mode, + void *priv) +{ + struct ircomm_tty_cb *self; + struct ircomm_tty_info info; + + /* Important note : + * We need to drop all passive discoveries. + * The LSAP management of IrComm is deficient and doesn't deal + * with the case of two instance connecting to each other + * simultaneously (it will deadlock in LMP). + * The proper fix would be to use the same technique as in IrNET, + * to have one server socket and separate instances for the + * connecting/connected socket. + * The workaround is to drop passive discovery, which drastically + * reduce the probability of this happening. + * Jean II */ + if(mode == DISCOVERY_PASSIVE) + return; + + info.daddr = discovery->daddr; + info.saddr = discovery->saddr; + + self = priv; + ircomm_tty_do_event(self, IRCOMM_TTY_DISCOVERY_INDICATION, + NULL, &info); +} + +/* + * Function ircomm_tty_disconnect_indication (instance, sap, reason, skb) + * + * Link disconnected + * + */ +void ircomm_tty_disconnect_indication(void *instance, void *sap, + LM_REASON reason, + struct sk_buff *skb) +{ + struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; + struct tty_struct *tty; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); + + tty = tty_port_tty_get(&self->port); + if (!tty) + return; + + /* This will stop control data transfers */ + self->flow = FLOW_STOP; + + /* Stop data transfers */ + tty->hw_stopped = 1; + + ircomm_tty_do_event(self, IRCOMM_TTY_DISCONNECT_INDICATION, NULL, + NULL); + tty_kref_put(tty); +} + +/* + * Function ircomm_tty_getvalue_confirm (result, obj_id, value, priv) + * + * Got result from the IAS query we make + * + */ +static void ircomm_tty_getvalue_confirm(int result, __u16 obj_id, + struct ias_value *value, + void *priv) +{ + struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) priv; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); + + /* We probably don't need to make any more queries */ + iriap_close(self->iriap); + self->iriap = NULL; + + /* Check if request succeeded */ + if (result != IAS_SUCCESS) { + pr_debug("%s(), got NULL value!\n", __func__); + return; + } + + switch (value->type) { + case IAS_OCT_SEQ: + pr_debug("%s(), got octet sequence\n", __func__); + + irda_param_extract_all(self, value->t.oct_seq, value->len, + &ircomm_param_info); + + ircomm_tty_do_event(self, IRCOMM_TTY_GOT_PARAMETERS, NULL, + NULL); + break; + case IAS_INTEGER: + /* Got LSAP selector */ + pr_debug("%s(), got lsapsel = %d\n", __func__ , + value->t.integer); + + if (value->t.integer == -1) { + pr_debug("%s(), invalid value!\n", __func__); + } else + self->dlsap_sel = value->t.integer; + + ircomm_tty_do_event(self, IRCOMM_TTY_GOT_LSAPSEL, NULL, NULL); + break; + case IAS_MISSING: + pr_debug("%s(), got IAS_MISSING\n", __func__); + break; + default: + pr_debug("%s(), got unknown type!\n", __func__); + break; + } + irias_delete_value(value); +} + +/* + * Function ircomm_tty_connect_confirm (instance, sap, qos, max_sdu_size, skb) + * + * Connection confirmed + * + */ +void ircomm_tty_connect_confirm(void *instance, void *sap, + struct qos_info *qos, + __u32 max_data_size, + __u8 max_header_size, + struct sk_buff *skb) +{ + struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); + + self->client = TRUE; + self->max_data_size = max_data_size; + self->max_header_size = max_header_size; + self->flow = FLOW_START; + + ircomm_tty_do_event(self, IRCOMM_TTY_CONNECT_CONFIRM, NULL, NULL); + + /* No need to kfree_skb - see ircomm_ttp_connect_confirm() */ +} + +/* + * Function ircomm_tty_connect_indication (instance, sap, qos, max_sdu_size, + * skb) + * + * we are discovered and being requested to connect by remote device ! + * + */ +void ircomm_tty_connect_indication(void *instance, void *sap, + struct qos_info *qos, + __u32 max_data_size, + __u8 max_header_size, + struct sk_buff *skb) +{ + struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; + int clen; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); + + self->client = FALSE; + self->max_data_size = max_data_size; + self->max_header_size = max_header_size; + self->flow = FLOW_START; + + clen = skb->data[0]; + if (clen) + irda_param_extract_all(self, skb->data+1, + IRDA_MIN(skb->len, clen), + &ircomm_param_info); + + ircomm_tty_do_event(self, IRCOMM_TTY_CONNECT_INDICATION, NULL, NULL); + + /* No need to kfree_skb - see ircomm_ttp_connect_indication() */ +} + +/* + * Function ircomm_tty_link_established (self) + * + * Called when the IrCOMM link is established + * + */ +void ircomm_tty_link_established(struct ircomm_tty_cb *self) +{ + struct tty_struct *tty; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); + + tty = tty_port_tty_get(&self->port); + if (!tty) + return; + + del_timer(&self->watchdog_timer); + + /* + * IrCOMM link is now up, and if we are not using hardware + * flow-control, then declare the hardware as running. Otherwise we + * will have to wait for the peer device (DCE) to raise the CTS + * line. + */ + if (tty_port_cts_enabled(&self->port) && + ((self->settings.dce & IRCOMM_CTS) == 0)) { + pr_debug("%s(), waiting for CTS ...\n", __func__); + goto put; + } else { + pr_debug("%s(), starting hardware!\n", __func__); + + tty->hw_stopped = 0; + + /* Wake up processes blocked on open */ + wake_up_interruptible(&self->port.open_wait); + } + + schedule_work(&self->tqueue); +put: + tty_kref_put(tty); +} + +/* + * Function ircomm_tty_start_watchdog_timer (self, timeout) + * + * Start the watchdog timer. This timer is used to make sure that any + * connection attempt is successful, and if not, we will retry after + * the timeout + */ +static void ircomm_tty_start_watchdog_timer(struct ircomm_tty_cb *self, + int timeout) +{ + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); + + irda_start_timer(&self->watchdog_timer, timeout, (void *) self, + ircomm_tty_watchdog_timer_expired); +} + +/* + * Function ircomm_tty_watchdog_timer_expired (data) + * + * Called when the connect procedure have taken to much time. + * + */ +static void ircomm_tty_watchdog_timer_expired(void *data) +{ + struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) data; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); + + ircomm_tty_do_event(self, IRCOMM_TTY_WD_TIMER_EXPIRED, NULL, NULL); +} + + +/* + * Function ircomm_tty_do_event (self, event, skb) + * + * Process event + * + */ +int ircomm_tty_do_event(struct ircomm_tty_cb *self, IRCOMM_TTY_EVENT event, + struct sk_buff *skb, struct ircomm_tty_info *info) +{ + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); + + pr_debug("%s: state=%s, event=%s\n", __func__ , + ircomm_tty_state[self->state], ircomm_tty_event[event]); + + return (*state[self->state])(self, event, skb, info); +} + +/* + * Function ircomm_tty_next_state (self, state) + * + * Switch state + * + */ +static inline void ircomm_tty_next_state(struct ircomm_tty_cb *self, IRCOMM_TTY_STATE state) +{ + /* + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); + + pr_debug("%s: next state=%s, service type=%d\n", __func__ , + ircomm_tty_state[self->state], self->service_type); + */ + self->state = state; +} + +/* + * Function ircomm_tty_state_idle (self, event, skb, info) + * + * Just hanging around + * + */ +static int ircomm_tty_state_idle(struct ircomm_tty_cb *self, + IRCOMM_TTY_EVENT event, + struct sk_buff *skb, + struct ircomm_tty_info *info) +{ + int ret = 0; + + pr_debug("%s: state=%s, event=%s\n", __func__ , + ircomm_tty_state[self->state], ircomm_tty_event[event]); + switch (event) { + case IRCOMM_TTY_ATTACH_CABLE: + /* Try to discover any remote devices */ + ircomm_tty_start_watchdog_timer(self, 3*HZ); + ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH); + + irlmp_discovery_request(DISCOVERY_DEFAULT_SLOTS); + break; + case IRCOMM_TTY_DISCOVERY_INDICATION: + self->daddr = info->daddr; + self->saddr = info->saddr; + + if (self->iriap) { + net_warn_ratelimited("%s(), busy with a previous query\n", + __func__); + return -EBUSY; + } + + self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self, + ircomm_tty_getvalue_confirm); + + iriap_getvaluebyclass_request(self->iriap, + self->saddr, self->daddr, + "IrDA:IrCOMM", "Parameters"); + + ircomm_tty_start_watchdog_timer(self, 3*HZ); + ircomm_tty_next_state(self, IRCOMM_TTY_QUERY_PARAMETERS); + break; + case IRCOMM_TTY_CONNECT_INDICATION: + del_timer(&self->watchdog_timer); + + /* Accept connection */ + ircomm_connect_response(self->ircomm, NULL); + ircomm_tty_next_state(self, IRCOMM_TTY_READY); + break; + case IRCOMM_TTY_WD_TIMER_EXPIRED: + /* Just stay idle */ + break; + case IRCOMM_TTY_DETACH_CABLE: + ircomm_tty_next_state(self, IRCOMM_TTY_IDLE); + break; + default: + pr_debug("%s(), unknown event: %s\n", __func__ , + ircomm_tty_event[event]); + ret = -EINVAL; + } + return ret; +} + +/* + * Function ircomm_tty_state_search (self, event, skb, info) + * + * Trying to discover an IrCOMM device + * + */ +static int ircomm_tty_state_search(struct ircomm_tty_cb *self, + IRCOMM_TTY_EVENT event, + struct sk_buff *skb, + struct ircomm_tty_info *info) +{ + int ret = 0; + + pr_debug("%s: state=%s, event=%s\n", __func__ , + ircomm_tty_state[self->state], ircomm_tty_event[event]); + + switch (event) { + case IRCOMM_TTY_DISCOVERY_INDICATION: + self->daddr = info->daddr; + self->saddr = info->saddr; + + if (self->iriap) { + net_warn_ratelimited("%s(), busy with a previous query\n", + __func__); + return -EBUSY; + } + + self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self, + ircomm_tty_getvalue_confirm); + + if (self->service_type == IRCOMM_3_WIRE_RAW) { + iriap_getvaluebyclass_request(self->iriap, self->saddr, + self->daddr, "IrLPT", + "IrDA:IrLMP:LsapSel"); + ircomm_tty_next_state(self, IRCOMM_TTY_QUERY_LSAP_SEL); + } else { + iriap_getvaluebyclass_request(self->iriap, self->saddr, + self->daddr, + "IrDA:IrCOMM", + "Parameters"); + + ircomm_tty_next_state(self, IRCOMM_TTY_QUERY_PARAMETERS); + } + ircomm_tty_start_watchdog_timer(self, 3*HZ); + break; + case IRCOMM_TTY_CONNECT_INDICATION: + del_timer(&self->watchdog_timer); + ircomm_tty_ias_unregister(self); + + /* Accept connection */ + ircomm_connect_response(self->ircomm, NULL); + ircomm_tty_next_state(self, IRCOMM_TTY_READY); + break; + case IRCOMM_TTY_WD_TIMER_EXPIRED: +#if 1 + /* Give up */ +#else + /* Try to discover any remote devices */ + ircomm_tty_start_watchdog_timer(self, 3*HZ); + irlmp_discovery_request(DISCOVERY_DEFAULT_SLOTS); +#endif + break; + case IRCOMM_TTY_DETACH_CABLE: + ircomm_tty_next_state(self, IRCOMM_TTY_IDLE); + break; + default: + pr_debug("%s(), unknown event: %s\n", __func__ , + ircomm_tty_event[event]); + ret = -EINVAL; + } + return ret; +} + +/* + * Function ircomm_tty_state_query (self, event, skb, info) + * + * Querying the remote LM-IAS for IrCOMM parameters + * + */ +static int ircomm_tty_state_query_parameters(struct ircomm_tty_cb *self, + IRCOMM_TTY_EVENT event, + struct sk_buff *skb, + struct ircomm_tty_info *info) +{ + int ret = 0; + + pr_debug("%s: state=%s, event=%s\n", __func__ , + ircomm_tty_state[self->state], ircomm_tty_event[event]); + + switch (event) { + case IRCOMM_TTY_GOT_PARAMETERS: + if (self->iriap) { + net_warn_ratelimited("%s(), busy with a previous query\n", + __func__); + return -EBUSY; + } + + self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self, + ircomm_tty_getvalue_confirm); + + iriap_getvaluebyclass_request(self->iriap, self->saddr, + self->daddr, "IrDA:IrCOMM", + "IrDA:TinyTP:LsapSel"); + + ircomm_tty_start_watchdog_timer(self, 3*HZ); + ircomm_tty_next_state(self, IRCOMM_TTY_QUERY_LSAP_SEL); + break; + case IRCOMM_TTY_WD_TIMER_EXPIRED: + /* Go back to search mode */ + ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH); + ircomm_tty_start_watchdog_timer(self, 3*HZ); + break; + case IRCOMM_TTY_CONNECT_INDICATION: + del_timer(&self->watchdog_timer); + ircomm_tty_ias_unregister(self); + + /* Accept connection */ + ircomm_connect_response(self->ircomm, NULL); + ircomm_tty_next_state(self, IRCOMM_TTY_READY); + break; + case IRCOMM_TTY_DETACH_CABLE: + ircomm_tty_next_state(self, IRCOMM_TTY_IDLE); + break; + default: + pr_debug("%s(), unknown event: %s\n", __func__ , + ircomm_tty_event[event]); + ret = -EINVAL; + } + return ret; +} + +/* + * Function ircomm_tty_state_query_lsap_sel (self, event, skb, info) + * + * Query remote LM-IAS for the LSAP selector which we can connect to + * + */ +static int ircomm_tty_state_query_lsap_sel(struct ircomm_tty_cb *self, + IRCOMM_TTY_EVENT event, + struct sk_buff *skb, + struct ircomm_tty_info *info) +{ + int ret = 0; + + pr_debug("%s: state=%s, event=%s\n", __func__ , + ircomm_tty_state[self->state], ircomm_tty_event[event]); + + switch (event) { + case IRCOMM_TTY_GOT_LSAPSEL: + /* Connect to remote device */ + ret = ircomm_connect_request(self->ircomm, self->dlsap_sel, + self->saddr, self->daddr, + NULL, self->service_type); + ircomm_tty_start_watchdog_timer(self, 3*HZ); + ircomm_tty_next_state(self, IRCOMM_TTY_SETUP); + break; + case IRCOMM_TTY_WD_TIMER_EXPIRED: + /* Go back to search mode */ + ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH); + ircomm_tty_start_watchdog_timer(self, 3*HZ); + break; + case IRCOMM_TTY_CONNECT_INDICATION: + del_timer(&self->watchdog_timer); + ircomm_tty_ias_unregister(self); + + /* Accept connection */ + ircomm_connect_response(self->ircomm, NULL); + ircomm_tty_next_state(self, IRCOMM_TTY_READY); + break; + case IRCOMM_TTY_DETACH_CABLE: + ircomm_tty_next_state(self, IRCOMM_TTY_IDLE); + break; + default: + pr_debug("%s(), unknown event: %s\n", __func__ , + ircomm_tty_event[event]); + ret = -EINVAL; + } + return ret; +} + +/* + * Function ircomm_tty_state_setup (self, event, skb, info) + * + * Trying to connect + * + */ +static int ircomm_tty_state_setup(struct ircomm_tty_cb *self, + IRCOMM_TTY_EVENT event, + struct sk_buff *skb, + struct ircomm_tty_info *info) +{ + int ret = 0; + + pr_debug("%s: state=%s, event=%s\n", __func__ , + ircomm_tty_state[self->state], ircomm_tty_event[event]); + + switch (event) { + case IRCOMM_TTY_CONNECT_CONFIRM: + del_timer(&self->watchdog_timer); + ircomm_tty_ias_unregister(self); + + /* + * Send initial parameters. This will also send out queued + * parameters waiting for the connection to come up + */ + ircomm_tty_send_initial_parameters(self); + ircomm_tty_link_established(self); + ircomm_tty_next_state(self, IRCOMM_TTY_READY); + break; + case IRCOMM_TTY_CONNECT_INDICATION: + del_timer(&self->watchdog_timer); + ircomm_tty_ias_unregister(self); + + /* Accept connection */ + ircomm_connect_response(self->ircomm, NULL); + ircomm_tty_next_state(self, IRCOMM_TTY_READY); + break; + case IRCOMM_TTY_WD_TIMER_EXPIRED: + /* Go back to search mode */ + ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH); + ircomm_tty_start_watchdog_timer(self, 3*HZ); + break; + case IRCOMM_TTY_DETACH_CABLE: + /* ircomm_disconnect_request(self->ircomm, NULL); */ + ircomm_tty_next_state(self, IRCOMM_TTY_IDLE); + break; + default: + pr_debug("%s(), unknown event: %s\n", __func__ , + ircomm_tty_event[event]); + ret = -EINVAL; + } + return ret; +} + +/* + * Function ircomm_tty_state_ready (self, event, skb, info) + * + * IrCOMM is now connected + * + */ +static int ircomm_tty_state_ready(struct ircomm_tty_cb *self, + IRCOMM_TTY_EVENT event, + struct sk_buff *skb, + struct ircomm_tty_info *info) +{ + int ret = 0; + + switch (event) { + case IRCOMM_TTY_DATA_REQUEST: + ret = ircomm_data_request(self->ircomm, skb); + break; + case IRCOMM_TTY_DETACH_CABLE: + ircomm_disconnect_request(self->ircomm, NULL); + ircomm_tty_next_state(self, IRCOMM_TTY_IDLE); + break; + case IRCOMM_TTY_DISCONNECT_INDICATION: + ircomm_tty_ias_register(self); + ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH); + ircomm_tty_start_watchdog_timer(self, 3*HZ); + + if (tty_port_check_carrier(&self->port)) { + /* Drop carrier */ + self->settings.dce = IRCOMM_DELTA_CD; + ircomm_tty_check_modem_status(self); + } else { + pr_debug("%s(), hanging up!\n", __func__); + tty_port_tty_hangup(&self->port, false); + } + break; + default: + pr_debug("%s(), unknown event: %s\n", __func__ , + ircomm_tty_event[event]); + ret = -EINVAL; + } + return ret; +} + diff --git a/drivers/staging/irda/net/ircomm/ircomm_tty_ioctl.c b/drivers/staging/irda/net/ircomm/ircomm_tty_ioctl.c new file mode 100644 index 000000000000..171c3dee760e --- /dev/null +++ b/drivers/staging/irda/net/ircomm/ircomm_tty_ioctl.c @@ -0,0 +1,291 @@ +/********************************************************************* + * + * Filename: ircomm_tty_ioctl.c + * Version: + * Description: + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Thu Jun 10 14:39:09 1999 + * Modified at: Wed Jan 5 14:45:43 2000 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1999-2000 Dag Brattli, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + ********************************************************************/ + +#include <linux/init.h> +#include <linux/fs.h> +#include <linux/termios.h> +#include <linux/tty.h> +#include <linux/serial.h> + +#include <linux/uaccess.h> + +#include <net/irda/irda.h> +#include <net/irda/irmod.h> + +#include <net/irda/ircomm_core.h> +#include <net/irda/ircomm_param.h> +#include <net/irda/ircomm_tty_attach.h> +#include <net/irda/ircomm_tty.h> + +#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) + +/* + * Function ircomm_tty_change_speed (driver) + * + * Change speed of the driver. If the remote device is a DCE, then this + * should make it change the speed of its serial port + */ +static void ircomm_tty_change_speed(struct ircomm_tty_cb *self, + struct tty_struct *tty) +{ + unsigned int cflag, cval; + int baud; + + if (!self->ircomm) + return; + + cflag = tty->termios.c_cflag; + + /* byte size and parity */ + switch (cflag & CSIZE) { + case CS5: cval = IRCOMM_WSIZE_5; break; + case CS6: cval = IRCOMM_WSIZE_6; break; + case CS7: cval = IRCOMM_WSIZE_7; break; + case CS8: cval = IRCOMM_WSIZE_8; break; + default: cval = IRCOMM_WSIZE_5; break; + } + if (cflag & CSTOPB) + cval |= IRCOMM_2_STOP_BIT; + + if (cflag & PARENB) + cval |= IRCOMM_PARITY_ENABLE; + if (!(cflag & PARODD)) + cval |= IRCOMM_PARITY_EVEN; + + /* Determine divisor based on baud rate */ + baud = tty_get_baud_rate(tty); + if (!baud) + baud = 9600; /* B0 transition handled in rs_set_termios */ + + self->settings.data_rate = baud; + ircomm_param_request(self, IRCOMM_DATA_RATE, FALSE); + + /* CTS flow control flag and modem status interrupts */ + tty_port_set_cts_flow(&self->port, cflag & CRTSCTS); + if (cflag & CRTSCTS) { + self->settings.flow_control |= IRCOMM_RTS_CTS_IN; + /* This got me. Bummer. Jean II */ + if (self->service_type == IRCOMM_3_WIRE_RAW) + net_warn_ratelimited("%s(), enabling RTS/CTS on link that doesn't support it (3-wire-raw)\n", + __func__); + } else { + self->settings.flow_control &= ~IRCOMM_RTS_CTS_IN; + } + tty_port_set_check_carrier(&self->port, ~cflag & CLOCAL); + + self->settings.data_format = cval; + + ircomm_param_request(self, IRCOMM_DATA_FORMAT, FALSE); + ircomm_param_request(self, IRCOMM_FLOW_CONTROL, TRUE); +} + +/* + * Function ircomm_tty_set_termios (tty, old_termios) + * + * This routine allows the tty driver to be notified when device's + * termios settings have changed. Note that a well-designed tty driver + * should be prepared to accept the case where old == NULL, and try to + * do something rational. + */ +void ircomm_tty_set_termios(struct tty_struct *tty, + struct ktermios *old_termios) +{ + struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; + unsigned int cflag = tty->termios.c_cflag; + + if ((cflag == old_termios->c_cflag) && + (RELEVANT_IFLAG(tty->termios.c_iflag) == + RELEVANT_IFLAG(old_termios->c_iflag))) + { + return; + } + + ircomm_tty_change_speed(self, tty); + + /* Handle transition to B0 status */ + if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD)) { + self->settings.dte &= ~(IRCOMM_DTR|IRCOMM_RTS); + ircomm_param_request(self, IRCOMM_DTE, TRUE); + } + + /* Handle transition away from B0 status */ + if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) { + self->settings.dte |= IRCOMM_DTR; + if (!C_CRTSCTS(tty) || !tty_throttled(tty)) + self->settings.dte |= IRCOMM_RTS; + ircomm_param_request(self, IRCOMM_DTE, TRUE); + } + + /* Handle turning off CRTSCTS */ + if ((old_termios->c_cflag & CRTSCTS) && !C_CRTSCTS(tty)) + { + tty->hw_stopped = 0; + ircomm_tty_start(tty); + } +} + +/* + * Function ircomm_tty_tiocmget (tty) + * + * + * + */ +int ircomm_tty_tiocmget(struct tty_struct *tty) +{ + struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; + unsigned int result; + + if (tty_io_error(tty)) + return -EIO; + + result = ((self->settings.dte & IRCOMM_RTS) ? TIOCM_RTS : 0) + | ((self->settings.dte & IRCOMM_DTR) ? TIOCM_DTR : 0) + | ((self->settings.dce & IRCOMM_CD) ? TIOCM_CAR : 0) + | ((self->settings.dce & IRCOMM_RI) ? TIOCM_RNG : 0) + | ((self->settings.dce & IRCOMM_DSR) ? TIOCM_DSR : 0) + | ((self->settings.dce & IRCOMM_CTS) ? TIOCM_CTS : 0); + return result; +} + +/* + * Function ircomm_tty_tiocmset (tty, set, clear) + * + * + * + */ +int ircomm_tty_tiocmset(struct tty_struct *tty, + unsigned int set, unsigned int clear) +{ + struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; + + if (tty_io_error(tty)) + return -EIO; + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); + + if (set & TIOCM_RTS) + self->settings.dte |= IRCOMM_RTS; + if (set & TIOCM_DTR) + self->settings.dte |= IRCOMM_DTR; + + if (clear & TIOCM_RTS) + self->settings.dte &= ~IRCOMM_RTS; + if (clear & TIOCM_DTR) + self->settings.dte &= ~IRCOMM_DTR; + + if ((set|clear) & TIOCM_RTS) + self->settings.dte |= IRCOMM_DELTA_RTS; + if ((set|clear) & TIOCM_DTR) + self->settings.dte |= IRCOMM_DELTA_DTR; + + ircomm_param_request(self, IRCOMM_DTE, TRUE); + + return 0; +} + +/* + * Function get_serial_info (driver, retinfo) + * + * + * + */ +static int ircomm_tty_get_serial_info(struct ircomm_tty_cb *self, + struct serial_struct __user *retinfo) +{ + struct serial_struct info; + + memset(&info, 0, sizeof(info)); + info.line = self->line; + info.flags = self->port.flags; + info.baud_base = self->settings.data_rate; + info.close_delay = self->port.close_delay; + info.closing_wait = self->port.closing_wait; + + /* For compatibility */ + info.type = PORT_16550A; + + if (copy_to_user(retinfo, &info, sizeof(*retinfo))) + return -EFAULT; + + return 0; +} + +/* + * Function set_serial_info (driver, new_info) + * + * + * + */ +static int ircomm_tty_set_serial_info(struct ircomm_tty_cb *self, + struct serial_struct __user *new_info) +{ + return 0; +} + +/* + * Function ircomm_tty_ioctl (tty, cmd, arg) + * + * + * + */ +int ircomm_tty_ioctl(struct tty_struct *tty, + unsigned int cmd, unsigned long arg) +{ + struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; + int ret = 0; + + if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && + (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) && + (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) { + if (tty_io_error(tty)) + return -EIO; + } + + switch (cmd) { + case TIOCGSERIAL: + ret = ircomm_tty_get_serial_info(self, (struct serial_struct __user *) arg); + break; + case TIOCSSERIAL: + ret = ircomm_tty_set_serial_info(self, (struct serial_struct __user *) arg); + break; + case TIOCMIWAIT: + pr_debug("(), TIOCMIWAIT, not impl!\n"); + break; + + case TIOCGICOUNT: + pr_debug("%s(), TIOCGICOUNT not impl!\n", __func__); + return 0; + default: + ret = -ENOIOCTLCMD; /* ioctls which we must ignore */ + } + return ret; +} + + + diff --git a/drivers/staging/irda/net/irda_device.c b/drivers/staging/irda/net/irda_device.c new file mode 100644 index 000000000000..890b90d055d5 --- /dev/null +++ b/drivers/staging/irda/net/irda_device.c @@ -0,0 +1,316 @@ +/********************************************************************* + * + * Filename: irda_device.c + * Version: 0.9 + * Description: Utility functions used by the device drivers + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Sat Oct 9 09:22:27 1999 + * Modified at: Sun Jan 23 17:41:24 2000 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1999-2000 Dag Brattli, All Rights Reserved. + * Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + ********************************************************************/ + +#include <linux/string.h> +#include <linux/proc_fs.h> +#include <linux/skbuff.h> +#include <linux/capability.h> +#include <linux/if.h> +#include <linux/if_ether.h> +#include <linux/if_arp.h> +#include <linux/netdevice.h> +#include <linux/init.h> +#include <linux/tty.h> +#include <linux/kmod.h> +#include <linux/spinlock.h> +#include <linux/slab.h> +#include <linux/export.h> + +#include <asm/ioctls.h> +#include <linux/uaccess.h> +#include <asm/dma.h> +#include <asm/io.h> + +#include <net/irda/irda_device.h> +#include <net/irda/irlap.h> +#include <net/irda/timer.h> +#include <net/irda/wrapper.h> + +static void __irda_task_delete(struct irda_task *task); + +static hashbin_t *dongles = NULL; +static hashbin_t *tasks = NULL; + +static void irda_task_timer_expired(void *data); + +int __init irda_device_init( void) +{ + dongles = hashbin_new(HB_NOLOCK); + if (dongles == NULL) { + net_warn_ratelimited("IrDA: Can't allocate dongles hashbin!\n"); + return -ENOMEM; + } + spin_lock_init(&dongles->hb_spinlock); + + tasks = hashbin_new(HB_LOCK); + if (tasks == NULL) { + net_warn_ratelimited("IrDA: Can't allocate tasks hashbin!\n"); + hashbin_delete(dongles, NULL); + return -ENOMEM; + } + + /* We no longer initialise the driver ourselves here, we let + * the system do it for us... - Jean II */ + + return 0; +} + +static void leftover_dongle(void *arg) +{ + struct dongle_reg *reg = arg; + net_warn_ratelimited("IrDA: Dongle type %x not unregistered\n", + reg->type); +} + +void irda_device_cleanup(void) +{ + hashbin_delete(tasks, (FREE_FUNC) __irda_task_delete); + + hashbin_delete(dongles, leftover_dongle); +} + +/* + * Function irda_device_set_media_busy (self, status) + * + * Called when we have detected that another station is transmitting + * in contention mode. + */ +void irda_device_set_media_busy(struct net_device *dev, int status) +{ + struct irlap_cb *self; + + pr_debug("%s(%s)\n", __func__, status ? "TRUE" : "FALSE"); + + self = (struct irlap_cb *) dev->atalk_ptr; + + /* Some drivers may enable the receive interrupt before calling + * irlap_open(), or they may disable the receive interrupt + * after calling irlap_close(). + * The IrDA stack is protected from this in irlap_driver_rcv(). + * However, the driver calls directly the wrapper, that calls + * us directly. Make sure we protect ourselves. + * Jean II */ + if (!self || self->magic != LAP_MAGIC) + return; + + if (status) { + self->media_busy = TRUE; + if (status == SMALL) + irlap_start_mbusy_timer(self, SMALLBUSY_TIMEOUT); + else + irlap_start_mbusy_timer(self, MEDIABUSY_TIMEOUT); + pr_debug("Media busy!\n"); + } else { + self->media_busy = FALSE; + irlap_stop_mbusy_timer(self); + } +} +EXPORT_SYMBOL(irda_device_set_media_busy); + + +/* + * Function irda_device_is_receiving (dev) + * + * Check if the device driver is currently receiving data + * + */ +int irda_device_is_receiving(struct net_device *dev) +{ + struct if_irda_req req; + int ret; + + if (!dev->netdev_ops->ndo_do_ioctl) { + net_err_ratelimited("%s: do_ioctl not impl. by device driver\n", + __func__); + return -1; + } + + ret = (dev->netdev_ops->ndo_do_ioctl)(dev, (struct ifreq *) &req, + SIOCGRECEIVING); + if (ret < 0) + return ret; + + return req.ifr_receiving; +} + +static void __irda_task_delete(struct irda_task *task) +{ + del_timer(&task->timer); + + kfree(task); +} + +static void irda_task_delete(struct irda_task *task) +{ + /* Unregister task */ + hashbin_remove(tasks, (long) task, NULL); + + __irda_task_delete(task); +} + +/* + * Function irda_task_kick (task) + * + * Tries to execute a task possible multiple times until the task is either + * finished, or askes for a timeout. When a task is finished, we do post + * processing, and notify the parent task, that is waiting for this task + * to complete. + */ +static int irda_task_kick(struct irda_task *task) +{ + int finished = TRUE; + int count = 0; + int timeout; + + IRDA_ASSERT(task != NULL, return -1;); + IRDA_ASSERT(task->magic == IRDA_TASK_MAGIC, return -1;); + + /* Execute task until it's finished, or askes for a timeout */ + do { + timeout = task->function(task); + if (count++ > 100) { + net_err_ratelimited("%s: error in task handler!\n", + __func__); + irda_task_delete(task); + return TRUE; + } + } while ((timeout == 0) && (task->state != IRDA_TASK_DONE)); + + if (timeout < 0) { + net_err_ratelimited("%s: Error executing task!\n", __func__); + irda_task_delete(task); + return TRUE; + } + + /* Check if we are finished */ + if (task->state == IRDA_TASK_DONE) { + del_timer(&task->timer); + + /* Do post processing */ + if (task->finished) + task->finished(task); + + /* Notify parent */ + if (task->parent) { + /* Check if parent is waiting for us to complete */ + if (task->parent->state == IRDA_TASK_CHILD_WAIT) { + task->parent->state = IRDA_TASK_CHILD_DONE; + + /* Stop timer now that we are here */ + del_timer(&task->parent->timer); + + /* Kick parent task */ + irda_task_kick(task->parent); + } + } + irda_task_delete(task); + } else if (timeout > 0) { + irda_start_timer(&task->timer, timeout, (void *) task, + irda_task_timer_expired); + finished = FALSE; + } else { + pr_debug("%s(), not finished, and no timeout!\n", + __func__); + finished = FALSE; + } + + return finished; +} + +/* + * Function irda_task_timer_expired (data) + * + * Task time has expired. We now try to execute task (again), and restart + * the timer if the task has not finished yet + */ +static void irda_task_timer_expired(void *data) +{ + struct irda_task *task; + + task = data; + + irda_task_kick(task); +} + +/* + * Function irda_device_setup (dev) + * + * This function should be used by low level device drivers in a similar way + * as ether_setup() is used by normal network device drivers + */ +static void irda_device_setup(struct net_device *dev) +{ + dev->hard_header_len = 0; + dev->addr_len = LAP_ALEN; + + dev->type = ARPHRD_IRDA; + dev->tx_queue_len = 8; /* Window size + 1 s-frame */ + + memset(dev->broadcast, 0xff, LAP_ALEN); + + dev->mtu = 2048; + dev->flags = IFF_NOARP; +} + +/* + * Funciton alloc_irdadev + * Allocates and sets up an IRDA device in a manner similar to + * alloc_etherdev. + */ +struct net_device *alloc_irdadev(int sizeof_priv) +{ + return alloc_netdev(sizeof_priv, "irda%d", NET_NAME_UNKNOWN, + irda_device_setup); +} +EXPORT_SYMBOL(alloc_irdadev); + +#ifdef CONFIG_ISA_DMA_API +/* + * Function setup_dma (idev, buffer, count, mode) + * + * Setup the DMA channel. Commonly used by LPC FIR drivers + * + */ +void irda_setup_dma(int channel, dma_addr_t buffer, int count, int mode) +{ + unsigned long flags; + + flags = claim_dma_lock(); + + disable_dma(channel); + clear_dma_ff(channel); + set_dma_mode(channel, mode); + set_dma_addr(channel, buffer); + set_dma_count(channel, count); + enable_dma(channel); + + release_dma_lock(flags); +} +EXPORT_SYMBOL(irda_setup_dma); +#endif diff --git a/drivers/staging/irda/net/iriap.c b/drivers/staging/irda/net/iriap.c new file mode 100644 index 000000000000..1138eaf5c682 --- /dev/null +++ b/drivers/staging/irda/net/iriap.c @@ -0,0 +1,1085 @@ +/********************************************************************* + * + * Filename: iriap.c + * Version: 0.8 + * Description: Information Access Protocol (IAP) + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Thu Aug 21 00:02:07 1997 + * Modified at: Sat Dec 25 16:42:42 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, + * All Rights Reserved. + * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/skbuff.h> +#include <linux/fs.h> +#include <linux/string.h> +#include <linux/init.h> +#include <linux/seq_file.h> +#include <linux/slab.h> + +#include <asm/byteorder.h> +#include <asm/unaligned.h> + +#include <net/irda/irda.h> +#include <net/irda/irttp.h> +#include <net/irda/irlmp.h> +#include <net/irda/irias_object.h> +#include <net/irda/iriap_event.h> +#include <net/irda/iriap.h> + +/* FIXME: This one should go in irlmp.c */ +static const char *const ias_charset_types[] __maybe_unused = { + "CS_ASCII", + "CS_ISO_8859_1", + "CS_ISO_8859_2", + "CS_ISO_8859_3", + "CS_ISO_8859_4", + "CS_ISO_8859_5", + "CS_ISO_8859_6", + "CS_ISO_8859_7", + "CS_ISO_8859_8", + "CS_ISO_8859_9", + "CS_UNICODE" +}; + +static hashbin_t *iriap = NULL; +static void *service_handle; + +static void __iriap_close(struct iriap_cb *self); +static int iriap_register_lsap(struct iriap_cb *self, __u8 slsap_sel, int mode); +static void iriap_disconnect_indication(void *instance, void *sap, + LM_REASON reason, struct sk_buff *skb); +static void iriap_connect_indication(void *instance, void *sap, + struct qos_info *qos, __u32 max_sdu_size, + __u8 max_header_size, + struct sk_buff *skb); +static void iriap_connect_confirm(void *instance, void *sap, + struct qos_info *qos, + __u32 max_sdu_size, __u8 max_header_size, + struct sk_buff *skb); +static int iriap_data_indication(void *instance, void *sap, + struct sk_buff *skb); + +static void iriap_watchdog_timer_expired(void *data); + +static inline void iriap_start_watchdog_timer(struct iriap_cb *self, + int timeout) +{ + irda_start_timer(&self->watchdog_timer, timeout, self, + iriap_watchdog_timer_expired); +} + +static struct lock_class_key irias_objects_key; + +/* + * Function iriap_init (void) + * + * Initializes the IrIAP layer, called by the module initialization code + * in irmod.c + */ +int __init iriap_init(void) +{ + struct ias_object *obj; + struct iriap_cb *server; + __u8 oct_seq[6]; + __u16 hints; + + /* Allocate master array */ + iriap = hashbin_new(HB_LOCK); + if (!iriap) + return -ENOMEM; + + /* Object repository - defined in irias_object.c */ + irias_objects = hashbin_new(HB_LOCK); + if (!irias_objects) { + net_warn_ratelimited("%s: Can't allocate irias_objects hashbin!\n", + __func__); + hashbin_delete(iriap, NULL); + return -ENOMEM; + } + + lockdep_set_class_and_name(&irias_objects->hb_spinlock, &irias_objects_key, + "irias_objects"); + + /* + * Register some default services for IrLMP + */ + hints = irlmp_service_to_hint(S_COMPUTER); + service_handle = irlmp_register_service(hints); + + /* Register the Device object with LM-IAS */ + obj = irias_new_object("Device", IAS_DEVICE_ID); + irias_add_string_attrib(obj, "DeviceName", "Linux", IAS_KERNEL_ATTR); + + oct_seq[0] = 0x01; /* Version 1 */ + oct_seq[1] = 0x00; /* IAS support bits */ + oct_seq[2] = 0x00; /* LM-MUX support bits */ +#ifdef CONFIG_IRDA_ULTRA + oct_seq[2] |= 0x04; /* Connectionless Data support */ +#endif + irias_add_octseq_attrib(obj, "IrLMPSupport", oct_seq, 3, + IAS_KERNEL_ATTR); + irias_insert_object(obj); + + /* + * Register server support with IrLMP so we can accept incoming + * connections + */ + server = iriap_open(LSAP_IAS, IAS_SERVER, NULL, NULL); + if (!server) { + pr_debug("%s(), unable to open server\n", __func__); + return -1; + } + iriap_register_lsap(server, LSAP_IAS, IAS_SERVER); + + return 0; +} + +/* + * Function iriap_cleanup (void) + * + * Initializes the IrIAP layer, called by the module cleanup code in + * irmod.c + */ +void iriap_cleanup(void) +{ + irlmp_unregister_service(service_handle); + + hashbin_delete(iriap, (FREE_FUNC) __iriap_close); + hashbin_delete(irias_objects, (FREE_FUNC) __irias_delete_object); +} + +/* + * Function iriap_open (void) + * + * Opens an instance of the IrIAP layer, and registers with IrLMP + */ +struct iriap_cb *iriap_open(__u8 slsap_sel, int mode, void *priv, + CONFIRM_CALLBACK callback) +{ + struct iriap_cb *self; + + self = kzalloc(sizeof(*self), GFP_ATOMIC); + if (!self) + return NULL; + + /* + * Initialize instance + */ + + self->magic = IAS_MAGIC; + self->mode = mode; + if (mode == IAS_CLIENT) { + if (iriap_register_lsap(self, slsap_sel, mode)) { + kfree(self); + return NULL; + } + } + + self->confirm = callback; + self->priv = priv; + + /* iriap_getvaluebyclass_request() will construct packets before + * we connect, so this must have a sane value... Jean II */ + self->max_header_size = LMP_MAX_HEADER; + + init_timer(&self->watchdog_timer); + + hashbin_insert(iriap, (irda_queue_t *) self, (long) self, NULL); + + /* Initialize state machines */ + iriap_next_client_state(self, S_DISCONNECT); + iriap_next_call_state(self, S_MAKE_CALL); + iriap_next_server_state(self, R_DISCONNECT); + iriap_next_r_connect_state(self, R_WAITING); + + return self; +} +EXPORT_SYMBOL(iriap_open); + +/* + * Function __iriap_close (self) + * + * Removes (deallocates) the IrIAP instance + * + */ +static void __iriap_close(struct iriap_cb *self) +{ + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IAS_MAGIC, return;); + + del_timer(&self->watchdog_timer); + + if (self->request_skb) + dev_kfree_skb(self->request_skb); + + self->magic = 0; + + kfree(self); +} + +/* + * Function iriap_close (void) + * + * Closes IrIAP and deregisters with IrLMP + */ +void iriap_close(struct iriap_cb *self) +{ + struct iriap_cb *entry; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IAS_MAGIC, return;); + + if (self->lsap) { + irlmp_close_lsap(self->lsap); + self->lsap = NULL; + } + + entry = (struct iriap_cb *) hashbin_remove(iriap, (long) self, NULL); + IRDA_ASSERT(entry == self, return;); + + __iriap_close(self); +} +EXPORT_SYMBOL(iriap_close); + +static int iriap_register_lsap(struct iriap_cb *self, __u8 slsap_sel, int mode) +{ + notify_t notify; + + irda_notify_init(¬ify); + notify.connect_confirm = iriap_connect_confirm; + notify.connect_indication = iriap_connect_indication; + notify.disconnect_indication = iriap_disconnect_indication; + notify.data_indication = iriap_data_indication; + notify.instance = self; + if (mode == IAS_CLIENT) + strcpy(notify.name, "IrIAS cli"); + else + strcpy(notify.name, "IrIAS srv"); + + self->lsap = irlmp_open_lsap(slsap_sel, ¬ify, 0); + if (self->lsap == NULL) { + net_err_ratelimited("%s: Unable to allocated LSAP!\n", + __func__); + return -1; + } + self->slsap_sel = self->lsap->slsap_sel; + + return 0; +} + +/* + * Function iriap_disconnect_indication (handle, reason) + * + * Got disconnect, so clean up everything associated with this connection + * + */ +static void iriap_disconnect_indication(void *instance, void *sap, + LM_REASON reason, + struct sk_buff *skb) +{ + struct iriap_cb *self; + + pr_debug("%s(), reason=%s [%d]\n", __func__, + irlmp_reason_str(reason), reason); + + self = instance; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IAS_MAGIC, return;); + + IRDA_ASSERT(iriap != NULL, return;); + + del_timer(&self->watchdog_timer); + + /* Not needed */ + if (skb) + dev_kfree_skb(skb); + + if (self->mode == IAS_CLIENT) { + pr_debug("%s(), disconnect as client\n", __func__); + + + iriap_do_client_event(self, IAP_LM_DISCONNECT_INDICATION, + NULL); + /* + * Inform service user that the request failed by sending + * it a NULL value. Warning, the client might close us, so + * remember no to use self anymore after calling confirm + */ + if (self->confirm) + self->confirm(IAS_DISCONNECT, 0, NULL, self->priv); + } else { + pr_debug("%s(), disconnect as server\n", __func__); + iriap_do_server_event(self, IAP_LM_DISCONNECT_INDICATION, + NULL); + iriap_close(self); + } +} + +/* + * Function iriap_disconnect_request (handle) + */ +static void iriap_disconnect_request(struct iriap_cb *self) +{ + struct sk_buff *tx_skb; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IAS_MAGIC, return;); + + tx_skb = alloc_skb(LMP_MAX_HEADER, GFP_ATOMIC); + if (tx_skb == NULL) { + pr_debug("%s(), Could not allocate an sk_buff of length %d\n", + __func__, LMP_MAX_HEADER); + return; + } + + /* + * Reserve space for MUX control and LAP header + */ + skb_reserve(tx_skb, LMP_MAX_HEADER); + + irlmp_disconnect_request(self->lsap, tx_skb); +} + +/* + * Function iriap_getvaluebyclass (addr, name, attr) + * + * Retrieve all values from attribute in all objects with given class + * name + */ +int iriap_getvaluebyclass_request(struct iriap_cb *self, + __u32 saddr, __u32 daddr, + char *name, char *attr) +{ + struct sk_buff *tx_skb; + int name_len, attr_len, skb_len; + __u8 *frame; + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == IAS_MAGIC, return -1;); + + /* Client must supply the destination device address */ + if (!daddr) + return -1; + + self->daddr = daddr; + self->saddr = saddr; + + /* + * Save operation, so we know what the later indication is about + */ + self->operation = GET_VALUE_BY_CLASS; + + /* Give ourselves 10 secs to finish this operation */ + iriap_start_watchdog_timer(self, 10*HZ); + + name_len = strlen(name); /* Up to IAS_MAX_CLASSNAME = 60 */ + attr_len = strlen(attr); /* Up to IAS_MAX_ATTRIBNAME = 60 */ + + skb_len = self->max_header_size+2+name_len+1+attr_len+4; + tx_skb = alloc_skb(skb_len, GFP_ATOMIC); + if (!tx_skb) + return -ENOMEM; + + /* Reserve space for MUX and LAP header */ + skb_reserve(tx_skb, self->max_header_size); + skb_put(tx_skb, 3+name_len+attr_len); + frame = tx_skb->data; + + /* Build frame */ + frame[0] = IAP_LST | GET_VALUE_BY_CLASS; + frame[1] = name_len; /* Insert length of name */ + memcpy(frame+2, name, name_len); /* Insert name */ + frame[2+name_len] = attr_len; /* Insert length of attr */ + memcpy(frame+3+name_len, attr, attr_len); /* Insert attr */ + + iriap_do_client_event(self, IAP_CALL_REQUEST_GVBC, tx_skb); + + /* Drop reference count - see state_s_disconnect(). */ + dev_kfree_skb(tx_skb); + + return 0; +} +EXPORT_SYMBOL(iriap_getvaluebyclass_request); + +/* + * Function iriap_getvaluebyclass_confirm (self, skb) + * + * Got result from GetValueByClass command. Parse it and return result + * to service user. + * + */ +static void iriap_getvaluebyclass_confirm(struct iriap_cb *self, + struct sk_buff *skb) +{ + struct ias_value *value; + int charset; + __u32 value_len; + __u32 tmp_cpu32; + __u16 obj_id; + __u16 len; + __u8 type; + __u8 *fp; + int n; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IAS_MAGIC, return;); + IRDA_ASSERT(skb != NULL, return;); + + /* Initialize variables */ + fp = skb->data; + n = 2; + + /* Get length, MSB first */ + len = get_unaligned_be16(fp + n); + n += 2; + + pr_debug("%s(), len=%d\n", __func__, len); + + /* Get object ID, MSB first */ + obj_id = get_unaligned_be16(fp + n); + n += 2; + + type = fp[n++]; + pr_debug("%s(), Value type = %d\n", __func__, type); + + switch (type) { + case IAS_INTEGER: + memcpy(&tmp_cpu32, fp+n, 4); n += 4; + be32_to_cpus(&tmp_cpu32); + value = irias_new_integer_value(tmp_cpu32); + + /* Legal values restricted to 0x01-0x6f, page 15 irttp */ + pr_debug("%s(), lsap=%d\n", __func__, value->t.integer); + break; + case IAS_STRING: + charset = fp[n++]; + + switch (charset) { + case CS_ASCII: + break; +/* case CS_ISO_8859_1: */ +/* case CS_ISO_8859_2: */ +/* case CS_ISO_8859_3: */ +/* case CS_ISO_8859_4: */ +/* case CS_ISO_8859_5: */ +/* case CS_ISO_8859_6: */ +/* case CS_ISO_8859_7: */ +/* case CS_ISO_8859_8: */ +/* case CS_ISO_8859_9: */ +/* case CS_UNICODE: */ + default: + pr_debug("%s(), charset [%d] %s, not supported\n", + __func__, charset, + charset < ARRAY_SIZE(ias_charset_types) ? + ias_charset_types[charset] : + "(unknown)"); + + /* Aborting, close connection! */ + iriap_disconnect_request(self); + return; + /* break; */ + } + value_len = fp[n++]; + pr_debug("%s(), strlen=%d\n", __func__, value_len); + + /* Make sure the string is null-terminated */ + if (n + value_len < skb->len) + fp[n + value_len] = 0x00; + pr_debug("Got string %s\n", fp+n); + + /* Will truncate to IAS_MAX_STRING bytes */ + value = irias_new_string_value(fp+n); + break; + case IAS_OCT_SEQ: + value_len = get_unaligned_be16(fp + n); + n += 2; + + /* Will truncate to IAS_MAX_OCTET_STRING bytes */ + value = irias_new_octseq_value(fp+n, value_len); + break; + default: + value = irias_new_missing_value(); + break; + } + + /* Finished, close connection! */ + iriap_disconnect_request(self); + + /* Warning, the client might close us, so remember no to use self + * anymore after calling confirm + */ + if (self->confirm) + self->confirm(IAS_SUCCESS, obj_id, value, self->priv); + else { + pr_debug("%s(), missing handler!\n", __func__); + irias_delete_value(value); + } +} + +/* + * Function iriap_getvaluebyclass_response () + * + * Send answer back to remote LM-IAS + * + */ +static void iriap_getvaluebyclass_response(struct iriap_cb *self, + __u16 obj_id, + __u8 ret_code, + struct ias_value *value) +{ + struct sk_buff *tx_skb; + int n; + __be32 tmp_be32; + __be16 tmp_be16; + __u8 *fp; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IAS_MAGIC, return;); + IRDA_ASSERT(value != NULL, return;); + IRDA_ASSERT(value->len <= 1024, return;); + + /* Initialize variables */ + n = 0; + + /* + * We must adjust the size of the response after the length of the + * value. We add 32 bytes because of the 6 bytes for the frame and + * max 5 bytes for the value coding. + */ + tx_skb = alloc_skb(value->len + self->max_header_size + 32, + GFP_ATOMIC); + if (!tx_skb) + return; + + /* Reserve space for MUX and LAP header */ + skb_reserve(tx_skb, self->max_header_size); + skb_put(tx_skb, 6); + + fp = tx_skb->data; + + /* Build frame */ + fp[n++] = GET_VALUE_BY_CLASS | IAP_LST; + fp[n++] = ret_code; + + /* Insert list length (MSB first) */ + tmp_be16 = htons(0x0001); + memcpy(fp+n, &tmp_be16, 2); n += 2; + + /* Insert object identifier ( MSB first) */ + tmp_be16 = cpu_to_be16(obj_id); + memcpy(fp+n, &tmp_be16, 2); n += 2; + + switch (value->type) { + case IAS_STRING: + skb_put(tx_skb, 3 + value->len); + fp[n++] = value->type; + fp[n++] = 0; /* ASCII */ + fp[n++] = (__u8) value->len; + memcpy(fp+n, value->t.string, value->len); n+=value->len; + break; + case IAS_INTEGER: + skb_put(tx_skb, 5); + fp[n++] = value->type; + + tmp_be32 = cpu_to_be32(value->t.integer); + memcpy(fp+n, &tmp_be32, 4); n += 4; + break; + case IAS_OCT_SEQ: + skb_put(tx_skb, 3 + value->len); + fp[n++] = value->type; + + tmp_be16 = cpu_to_be16(value->len); + memcpy(fp+n, &tmp_be16, 2); n += 2; + memcpy(fp+n, value->t.oct_seq, value->len); n+=value->len; + break; + case IAS_MISSING: + pr_debug("%s: sending IAS_MISSING\n", __func__); + skb_put(tx_skb, 1); + fp[n++] = value->type; + break; + default: + pr_debug("%s(), type not implemented!\n", __func__); + break; + } + iriap_do_r_connect_event(self, IAP_CALL_RESPONSE, tx_skb); + + /* Drop reference count - see state_r_execute(). */ + dev_kfree_skb(tx_skb); +} + +/* + * Function iriap_getvaluebyclass_indication (self, skb) + * + * getvaluebyclass is requested from peer LM-IAS + * + */ +static void iriap_getvaluebyclass_indication(struct iriap_cb *self, + struct sk_buff *skb) +{ + struct ias_object *obj; + struct ias_attrib *attrib; + int name_len; + int attr_len; + char name[IAS_MAX_CLASSNAME + 1]; /* 60 bytes */ + char attr[IAS_MAX_ATTRIBNAME + 1]; /* 60 bytes */ + __u8 *fp; + int n; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IAS_MAGIC, return;); + IRDA_ASSERT(skb != NULL, return;); + + fp = skb->data; + n = 1; + + name_len = fp[n++]; + + IRDA_ASSERT(name_len < IAS_MAX_CLASSNAME + 1, return;); + + memcpy(name, fp+n, name_len); n+=name_len; + name[name_len] = '\0'; + + attr_len = fp[n++]; + + IRDA_ASSERT(attr_len < IAS_MAX_ATTRIBNAME + 1, return;); + + memcpy(attr, fp+n, attr_len); n+=attr_len; + attr[attr_len] = '\0'; + + pr_debug("LM-IAS: Looking up %s: %s\n", name, attr); + obj = irias_find_object(name); + + if (obj == NULL) { + pr_debug("LM-IAS: Object %s not found\n", name); + iriap_getvaluebyclass_response(self, 0x1235, IAS_CLASS_UNKNOWN, + &irias_missing); + return; + } + pr_debug("LM-IAS: found %s, id=%d\n", obj->name, obj->id); + + attrib = irias_find_attrib(obj, attr); + if (attrib == NULL) { + pr_debug("LM-IAS: Attribute %s not found\n", attr); + iriap_getvaluebyclass_response(self, obj->id, + IAS_ATTRIB_UNKNOWN, + &irias_missing); + return; + } + + /* We have a match; send the value. */ + iriap_getvaluebyclass_response(self, obj->id, IAS_SUCCESS, + attrib->value); +} + +/* + * Function iriap_send_ack (void) + * + * Currently not used + * + */ +void iriap_send_ack(struct iriap_cb *self) +{ + struct sk_buff *tx_skb; + __u8 *frame; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IAS_MAGIC, return;); + + tx_skb = alloc_skb(LMP_MAX_HEADER + 1, GFP_ATOMIC); + if (!tx_skb) + return; + + /* Reserve space for MUX and LAP header */ + skb_reserve(tx_skb, self->max_header_size); + skb_put(tx_skb, 1); + frame = tx_skb->data; + + /* Build frame */ + frame[0] = IAP_LST | IAP_ACK | self->operation; + + irlmp_data_request(self->lsap, tx_skb); +} + +void iriap_connect_request(struct iriap_cb *self) +{ + int ret; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IAS_MAGIC, return;); + + ret = irlmp_connect_request(self->lsap, LSAP_IAS, + self->saddr, self->daddr, + NULL, NULL); + if (ret < 0) { + pr_debug("%s(), connect failed!\n", __func__); + self->confirm(IAS_DISCONNECT, 0, NULL, self->priv); + } +} + +/* + * Function iriap_connect_confirm (handle, skb) + * + * LSAP connection confirmed! + * + */ +static void iriap_connect_confirm(void *instance, void *sap, + struct qos_info *qos, __u32 max_seg_size, + __u8 max_header_size, + struct sk_buff *skb) +{ + struct iriap_cb *self; + + self = instance; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IAS_MAGIC, return;); + IRDA_ASSERT(skb != NULL, return;); + + self->max_data_size = max_seg_size; + self->max_header_size = max_header_size; + + del_timer(&self->watchdog_timer); + + iriap_do_client_event(self, IAP_LM_CONNECT_CONFIRM, skb); + + /* Drop reference count - see state_s_make_call(). */ + dev_kfree_skb(skb); +} + +/* + * Function iriap_connect_indication ( handle, skb) + * + * Remote LM-IAS is requesting connection + * + */ +static void iriap_connect_indication(void *instance, void *sap, + struct qos_info *qos, __u32 max_seg_size, + __u8 max_header_size, + struct sk_buff *skb) +{ + struct iriap_cb *self, *new; + + self = instance; + + IRDA_ASSERT(skb != NULL, return;); + IRDA_ASSERT(self != NULL, goto out;); + IRDA_ASSERT(self->magic == IAS_MAGIC, goto out;); + + /* Start new server */ + new = iriap_open(LSAP_IAS, IAS_SERVER, NULL, NULL); + if (!new) { + pr_debug("%s(), open failed\n", __func__); + goto out; + } + + /* Now attach up the new "socket" */ + new->lsap = irlmp_dup(self->lsap, new); + if (!new->lsap) { + pr_debug("%s(), dup failed!\n", __func__); + goto out; + } + + new->max_data_size = max_seg_size; + new->max_header_size = max_header_size; + + /* Clean up the original one to keep it in listen state */ + irlmp_listen(self->lsap); + + iriap_do_server_event(new, IAP_LM_CONNECT_INDICATION, skb); + +out: + /* Drop reference count - see state_r_disconnect(). */ + dev_kfree_skb(skb); +} + +/* + * Function iriap_data_indication (handle, skb) + * + * Receives data from connection identified by handle from IrLMP + * + */ +static int iriap_data_indication(void *instance, void *sap, + struct sk_buff *skb) +{ + struct iriap_cb *self; + __u8 *frame; + __u8 opcode; + + self = instance; + + IRDA_ASSERT(skb != NULL, return 0;); + IRDA_ASSERT(self != NULL, goto out;); + IRDA_ASSERT(self->magic == IAS_MAGIC, goto out;); + + frame = skb->data; + + if (self->mode == IAS_SERVER) { + /* Call server */ + pr_debug("%s(), Calling server!\n", __func__); + iriap_do_r_connect_event(self, IAP_RECV_F_LST, skb); + goto out; + } + opcode = frame[0]; + if (~opcode & IAP_LST) { + net_warn_ratelimited("%s:, IrIAS multiframe commands or results is not implemented yet!\n", + __func__); + goto out; + } + + /* Check for ack frames since they don't contain any data */ + if (opcode & IAP_ACK) { + pr_debug("%s() Got ack frame!\n", __func__); + goto out; + } + + opcode &= ~IAP_LST; /* Mask away LST bit */ + + switch (opcode) { + case GET_INFO_BASE: + pr_debug("IrLMP GetInfoBaseDetails not implemented!\n"); + break; + case GET_VALUE_BY_CLASS: + iriap_do_call_event(self, IAP_RECV_F_LST, NULL); + + switch (frame[1]) { + case IAS_SUCCESS: + iriap_getvaluebyclass_confirm(self, skb); + break; + case IAS_CLASS_UNKNOWN: + pr_debug("%s(), No such class!\n", __func__); + /* Finished, close connection! */ + iriap_disconnect_request(self); + + /* + * Warning, the client might close us, so remember + * no to use self anymore after calling confirm + */ + if (self->confirm) + self->confirm(IAS_CLASS_UNKNOWN, 0, NULL, + self->priv); + break; + case IAS_ATTRIB_UNKNOWN: + pr_debug("%s(), No such attribute!\n", __func__); + /* Finished, close connection! */ + iriap_disconnect_request(self); + + /* + * Warning, the client might close us, so remember + * no to use self anymore after calling confirm + */ + if (self->confirm) + self->confirm(IAS_ATTRIB_UNKNOWN, 0, NULL, + self->priv); + break; + } + break; + default: + pr_debug("%s(), Unknown op-code: %02x\n", __func__, + opcode); + break; + } + +out: + /* Cleanup - sub-calls will have done skb_get() as needed. */ + dev_kfree_skb(skb); + return 0; +} + +/* + * Function iriap_call_indication (self, skb) + * + * Received call to server from peer LM-IAS + * + */ +void iriap_call_indication(struct iriap_cb *self, struct sk_buff *skb) +{ + __u8 *fp; + __u8 opcode; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IAS_MAGIC, return;); + IRDA_ASSERT(skb != NULL, return;); + + fp = skb->data; + + opcode = fp[0]; + if (~opcode & 0x80) { + net_warn_ratelimited("%s: IrIAS multiframe commands or results is not implemented yet!\n", + __func__); + return; + } + opcode &= 0x7f; /* Mask away LST bit */ + + switch (opcode) { + case GET_INFO_BASE: + net_warn_ratelimited("%s: GetInfoBaseDetails not implemented yet!\n", + __func__); + break; + case GET_VALUE_BY_CLASS: + iriap_getvaluebyclass_indication(self, skb); + break; + } + /* skb will be cleaned up in iriap_data_indication */ +} + +/* + * Function iriap_watchdog_timer_expired (data) + * + * Query has taken too long time, so abort + * + */ +static void iriap_watchdog_timer_expired(void *data) +{ + struct iriap_cb *self = (struct iriap_cb *) data; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IAS_MAGIC, return;); + + /* iriap_close(self); */ +} + +#ifdef CONFIG_PROC_FS + +static const char *const ias_value_types[] = { + "IAS_MISSING", + "IAS_INTEGER", + "IAS_OCT_SEQ", + "IAS_STRING" +}; + +static inline struct ias_object *irias_seq_idx(loff_t pos) +{ + struct ias_object *obj; + + for (obj = (struct ias_object *) hashbin_get_first(irias_objects); + obj; obj = (struct ias_object *) hashbin_get_next(irias_objects)) { + if (pos-- == 0) + break; + } + + return obj; +} + +static void *irias_seq_start(struct seq_file *seq, loff_t *pos) +{ + spin_lock_irq(&irias_objects->hb_spinlock); + + return *pos ? irias_seq_idx(*pos - 1) : SEQ_START_TOKEN; +} + +static void *irias_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + ++*pos; + + return (v == SEQ_START_TOKEN) + ? (void *) hashbin_get_first(irias_objects) + : (void *) hashbin_get_next(irias_objects); +} + +static void irias_seq_stop(struct seq_file *seq, void *v) +{ + spin_unlock_irq(&irias_objects->hb_spinlock); +} + +static int irias_seq_show(struct seq_file *seq, void *v) +{ + if (v == SEQ_START_TOKEN) + seq_puts(seq, "LM-IAS Objects:\n"); + else { + struct ias_object *obj = v; + struct ias_attrib *attrib; + + IRDA_ASSERT(obj->magic == IAS_OBJECT_MAGIC, return -EINVAL;); + + seq_printf(seq, "name: %s, id=%d\n", + obj->name, obj->id); + + /* Careful for priority inversions here ! + * All other uses of attrib spinlock are independent of + * the object spinlock, so we are safe. Jean II */ + spin_lock(&obj->attribs->hb_spinlock); + + /* List all attributes for this object */ + for (attrib = (struct ias_attrib *) hashbin_get_first(obj->attribs); + attrib != NULL; + attrib = (struct ias_attrib *) hashbin_get_next(obj->attribs)) { + + IRDA_ASSERT(attrib->magic == IAS_ATTRIB_MAGIC, + goto outloop; ); + + seq_printf(seq, " - Attribute name: \"%s\", ", + attrib->name); + seq_printf(seq, "value[%s]: ", + ias_value_types[attrib->value->type]); + + switch (attrib->value->type) { + case IAS_INTEGER: + seq_printf(seq, "%d\n", + attrib->value->t.integer); + break; + case IAS_STRING: + seq_printf(seq, "\"%s\"\n", + attrib->value->t.string); + break; + case IAS_OCT_SEQ: + seq_printf(seq, "octet sequence (%d bytes)\n", + attrib->value->len); + break; + case IAS_MISSING: + seq_puts(seq, "missing\n"); + break; + default: + seq_printf(seq, "type %d?\n", + attrib->value->type); + } + seq_putc(seq, '\n'); + + } + IRDA_ASSERT_LABEL(outloop:) + spin_unlock(&obj->attribs->hb_spinlock); + } + + return 0; +} + +static const struct seq_operations irias_seq_ops = { + .start = irias_seq_start, + .next = irias_seq_next, + .stop = irias_seq_stop, + .show = irias_seq_show, +}; + +static int irias_seq_open(struct inode *inode, struct file *file) +{ + IRDA_ASSERT( irias_objects != NULL, return -EINVAL;); + + return seq_open(file, &irias_seq_ops); +} + +const struct file_operations irias_seq_fops = { + .owner = THIS_MODULE, + .open = irias_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +#endif /* PROC_FS */ diff --git a/drivers/staging/irda/net/iriap_event.c b/drivers/staging/irda/net/iriap_event.c new file mode 100644 index 000000000000..e6098b2e048a --- /dev/null +++ b/drivers/staging/irda/net/iriap_event.c @@ -0,0 +1,496 @@ +/********************************************************************* + * + * Filename: iriap_event.c + * Version: 0.1 + * Description: IAP Finite State Machine + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Thu Aug 21 00:02:07 1997 + * Modified at: Wed Mar 1 11:28:34 2000 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1997, 1999-2000 Dag Brattli <dagb@cs.uit.no>, + * All Rights Reserved. + * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#include <linux/slab.h> + +#include <net/irda/irda.h> +#include <net/irda/irlmp.h> +#include <net/irda/iriap.h> +#include <net/irda/iriap_event.h> + +static void state_s_disconnect (struct iriap_cb *self, IRIAP_EVENT event, + struct sk_buff *skb); +static void state_s_connecting (struct iriap_cb *self, IRIAP_EVENT event, + struct sk_buff *skb); +static void state_s_call (struct iriap_cb *self, IRIAP_EVENT event, + struct sk_buff *skb); + +static void state_s_make_call (struct iriap_cb *self, IRIAP_EVENT event, + struct sk_buff *skb); +static void state_s_calling (struct iriap_cb *self, IRIAP_EVENT event, + struct sk_buff *skb); +static void state_s_outstanding (struct iriap_cb *self, IRIAP_EVENT event, + struct sk_buff *skb); +static void state_s_replying (struct iriap_cb *self, IRIAP_EVENT event, + struct sk_buff *skb); +static void state_s_wait_for_call(struct iriap_cb *self, IRIAP_EVENT event, + struct sk_buff *skb); +static void state_s_wait_active (struct iriap_cb *self, IRIAP_EVENT event, + struct sk_buff *skb); + +static void state_r_disconnect (struct iriap_cb *self, IRIAP_EVENT event, + struct sk_buff *skb); +static void state_r_call (struct iriap_cb *self, IRIAP_EVENT event, + struct sk_buff *skb); +static void state_r_waiting (struct iriap_cb *self, IRIAP_EVENT event, + struct sk_buff *skb); +static void state_r_wait_active (struct iriap_cb *self, IRIAP_EVENT event, + struct sk_buff *skb); +static void state_r_receiving (struct iriap_cb *self, IRIAP_EVENT event, + struct sk_buff *skb); +static void state_r_execute (struct iriap_cb *self, IRIAP_EVENT event, + struct sk_buff *skb); +static void state_r_returning (struct iriap_cb *self, IRIAP_EVENT event, + struct sk_buff *skb); + +static void (*iriap_state[])(struct iriap_cb *self, IRIAP_EVENT event, + struct sk_buff *skb) = { + /* Client FSM */ + state_s_disconnect, + state_s_connecting, + state_s_call, + + /* S-Call FSM */ + state_s_make_call, + state_s_calling, + state_s_outstanding, + state_s_replying, + state_s_wait_for_call, + state_s_wait_active, + + /* Server FSM */ + state_r_disconnect, + state_r_call, + + /* R-Connect FSM */ + state_r_waiting, + state_r_wait_active, + state_r_receiving, + state_r_execute, + state_r_returning, +}; + +void iriap_next_client_state(struct iriap_cb *self, IRIAP_STATE state) +{ + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IAS_MAGIC, return;); + + self->client_state = state; +} + +void iriap_next_call_state(struct iriap_cb *self, IRIAP_STATE state) +{ + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IAS_MAGIC, return;); + + self->call_state = state; +} + +void iriap_next_server_state(struct iriap_cb *self, IRIAP_STATE state) +{ + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IAS_MAGIC, return;); + + self->server_state = state; +} + +void iriap_next_r_connect_state(struct iriap_cb *self, IRIAP_STATE state) +{ + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IAS_MAGIC, return;); + + self->r_connect_state = state; +} + +void iriap_do_client_event(struct iriap_cb *self, IRIAP_EVENT event, + struct sk_buff *skb) +{ + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IAS_MAGIC, return;); + + (*iriap_state[ self->client_state]) (self, event, skb); +} + +void iriap_do_call_event(struct iriap_cb *self, IRIAP_EVENT event, + struct sk_buff *skb) +{ + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IAS_MAGIC, return;); + + (*iriap_state[ self->call_state]) (self, event, skb); +} + +void iriap_do_server_event(struct iriap_cb *self, IRIAP_EVENT event, + struct sk_buff *skb) +{ + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IAS_MAGIC, return;); + + (*iriap_state[ self->server_state]) (self, event, skb); +} + +void iriap_do_r_connect_event(struct iriap_cb *self, IRIAP_EVENT event, + struct sk_buff *skb) +{ + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IAS_MAGIC, return;); + + (*iriap_state[ self->r_connect_state]) (self, event, skb); +} + + +/* + * Function state_s_disconnect (event, skb) + * + * S-Disconnect, The device has no LSAP connection to a particular + * remote device. + */ +static void state_s_disconnect(struct iriap_cb *self, IRIAP_EVENT event, + struct sk_buff *skb) +{ + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IAS_MAGIC, return;); + + switch (event) { + case IAP_CALL_REQUEST_GVBC: + iriap_next_client_state(self, S_CONNECTING); + IRDA_ASSERT(self->request_skb == NULL, return;); + /* Don't forget to refcount it - + * see iriap_getvaluebyclass_request(). */ + skb_get(skb); + self->request_skb = skb; + iriap_connect_request(self); + break; + case IAP_LM_DISCONNECT_INDICATION: + break; + default: + pr_debug("%s(), Unknown event %d\n", __func__, event); + break; + } +} + +/* + * Function state_s_connecting (self, event, skb) + * + * S-Connecting + * + */ +static void state_s_connecting(struct iriap_cb *self, IRIAP_EVENT event, + struct sk_buff *skb) +{ + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IAS_MAGIC, return;); + + switch (event) { + case IAP_LM_CONNECT_CONFIRM: + /* + * Jump to S-Call FSM + */ + iriap_do_call_event(self, IAP_CALL_REQUEST, skb); + /* iriap_call_request(self, 0,0,0); */ + iriap_next_client_state(self, S_CALL); + break; + case IAP_LM_DISCONNECT_INDICATION: + /* Abort calls */ + iriap_next_call_state(self, S_MAKE_CALL); + iriap_next_client_state(self, S_DISCONNECT); + break; + default: + pr_debug("%s(), Unknown event %d\n", __func__, event); + break; + } +} + +/* + * Function state_s_call (self, event, skb) + * + * S-Call, The device can process calls to a specific remote + * device. Whenever the LSAP connection is disconnected, this state + * catches that event and clears up + */ +static void state_s_call(struct iriap_cb *self, IRIAP_EVENT event, + struct sk_buff *skb) +{ + IRDA_ASSERT(self != NULL, return;); + + switch (event) { + case IAP_LM_DISCONNECT_INDICATION: + /* Abort calls */ + iriap_next_call_state(self, S_MAKE_CALL); + iriap_next_client_state(self, S_DISCONNECT); + break; + default: + pr_debug("state_s_call: Unknown event %d\n", event); + break; + } +} + +/* + * Function state_s_make_call (event, skb) + * + * S-Make-Call + * + */ +static void state_s_make_call(struct iriap_cb *self, IRIAP_EVENT event, + struct sk_buff *skb) +{ + struct sk_buff *tx_skb; + + IRDA_ASSERT(self != NULL, return;); + + switch (event) { + case IAP_CALL_REQUEST: + /* Already refcounted - see state_s_disconnect() */ + tx_skb = self->request_skb; + self->request_skb = NULL; + + irlmp_data_request(self->lsap, tx_skb); + iriap_next_call_state(self, S_OUTSTANDING); + break; + default: + pr_debug("%s(), Unknown event %d\n", __func__, event); + break; + } +} + +/* + * Function state_s_calling (event, skb) + * + * S-Calling + * + */ +static void state_s_calling(struct iriap_cb *self, IRIAP_EVENT event, + struct sk_buff *skb) +{ + pr_debug("%s(), Not implemented\n", __func__); +} + +/* + * Function state_s_outstanding (event, skb) + * + * S-Outstanding, The device is waiting for a response to a command + * + */ +static void state_s_outstanding(struct iriap_cb *self, IRIAP_EVENT event, + struct sk_buff *skb) +{ + IRDA_ASSERT(self != NULL, return;); + + switch (event) { + case IAP_RECV_F_LST: + /*iriap_send_ack(self);*/ + /*LM_Idle_request(idle); */ + + iriap_next_call_state(self, S_WAIT_FOR_CALL); + break; + default: + pr_debug("%s(), Unknown event %d\n", __func__, event); + break; + } +} + +/* + * Function state_s_replying (event, skb) + * + * S-Replying, The device is collecting a multiple part response + */ +static void state_s_replying(struct iriap_cb *self, IRIAP_EVENT event, + struct sk_buff *skb) +{ + pr_debug("%s(), Not implemented\n", __func__); +} + +/* + * Function state_s_wait_for_call (event, skb) + * + * S-Wait-for-Call + * + */ +static void state_s_wait_for_call(struct iriap_cb *self, IRIAP_EVENT event, + struct sk_buff *skb) +{ + pr_debug("%s(), Not implemented\n", __func__); +} + + +/* + * Function state_s_wait_active (event, skb) + * + * S-Wait-Active + * + */ +static void state_s_wait_active(struct iriap_cb *self, IRIAP_EVENT event, + struct sk_buff *skb) +{ + pr_debug("%s(), Not implemented\n", __func__); +} + +/************************************************************************** + * + * Server FSM + * + **************************************************************************/ + +/* + * Function state_r_disconnect (self, event, skb) + * + * LM-IAS server is disconnected (not processing any requests!) + * + */ +static void state_r_disconnect(struct iriap_cb *self, IRIAP_EVENT event, + struct sk_buff *skb) +{ + struct sk_buff *tx_skb; + + switch (event) { + case IAP_LM_CONNECT_INDICATION: + tx_skb = alloc_skb(LMP_MAX_HEADER, GFP_ATOMIC); + if (tx_skb == NULL) + return; + + /* Reserve space for MUX_CONTROL and LAP header */ + skb_reserve(tx_skb, LMP_MAX_HEADER); + + irlmp_connect_response(self->lsap, tx_skb); + /*LM_Idle_request(idle); */ + + iriap_next_server_state(self, R_CALL); + + /* + * Jump to R-Connect FSM, we skip R-Waiting since we do not + * care about LM_Idle_request()! + */ + iriap_next_r_connect_state(self, R_RECEIVING); + break; + default: + pr_debug("%s(), unknown event %d\n", __func__, event); + break; + } +} + +/* + * Function state_r_call (self, event, skb) + */ +static void state_r_call(struct iriap_cb *self, IRIAP_EVENT event, + struct sk_buff *skb) +{ + switch (event) { + case IAP_LM_DISCONNECT_INDICATION: + /* Abort call */ + iriap_next_server_state(self, R_DISCONNECT); + iriap_next_r_connect_state(self, R_WAITING); + break; + default: + pr_debug("%s(), unknown event!\n", __func__); + break; + } +} + +/* + * R-Connect FSM + */ + +/* + * Function state_r_waiting (self, event, skb) + */ +static void state_r_waiting(struct iriap_cb *self, IRIAP_EVENT event, + struct sk_buff *skb) +{ + pr_debug("%s(), Not implemented\n", __func__); +} + +static void state_r_wait_active(struct iriap_cb *self, IRIAP_EVENT event, + struct sk_buff *skb) +{ + pr_debug("%s(), Not implemented\n", __func__); +} + +/* + * Function state_r_receiving (self, event, skb) + * + * We are receiving a command + * + */ +static void state_r_receiving(struct iriap_cb *self, IRIAP_EVENT event, + struct sk_buff *skb) +{ + switch (event) { + case IAP_RECV_F_LST: + iriap_next_r_connect_state(self, R_EXECUTE); + + iriap_call_indication(self, skb); + break; + default: + pr_debug("%s(), unknown event!\n", __func__); + break; + } +} + +/* + * Function state_r_execute (self, event, skb) + * + * The server is processing the request + * + */ +static void state_r_execute(struct iriap_cb *self, IRIAP_EVENT event, + struct sk_buff *skb) +{ + IRDA_ASSERT(skb != NULL, return;); + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IAS_MAGIC, return;); + + switch (event) { + case IAP_CALL_RESPONSE: + /* + * Since we don't implement the Waiting state, we return + * to state Receiving instead, DB. + */ + iriap_next_r_connect_state(self, R_RECEIVING); + + /* Don't forget to refcount it - see + * iriap_getvaluebyclass_response(). */ + skb_get(skb); + + irlmp_data_request(self->lsap, skb); + break; + default: + pr_debug("%s(), unknown event!\n", __func__); + break; + } +} + +static void state_r_returning(struct iriap_cb *self, IRIAP_EVENT event, + struct sk_buff *skb) +{ + pr_debug("%s(), event=%d\n", __func__, event); + + switch (event) { + case IAP_RECV_F_LST: + break; + default: + break; + } +} diff --git a/drivers/staging/irda/net/irias_object.c b/drivers/staging/irda/net/irias_object.c new file mode 100644 index 000000000000..53b86d0e1630 --- /dev/null +++ b/drivers/staging/irda/net/irias_object.c @@ -0,0 +1,555 @@ +/********************************************************************* + * + * Filename: irias_object.c + * Version: 0.3 + * Description: IAS object database and functions + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Thu Oct 1 22:50:04 1998 + * Modified at: Wed Dec 15 11:23:16 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/socket.h> +#include <linux/module.h> + +#include <net/irda/irda.h> +#include <net/irda/irias_object.h> + +hashbin_t *irias_objects; + +/* + * Used when a missing value needs to be returned + */ +struct ias_value irias_missing = { IAS_MISSING, 0, 0, 0, {0}}; + + +/* + * Function ias_new_object (name, id) + * + * Create a new IAS object + * + */ +struct ias_object *irias_new_object( char *name, int id) +{ + struct ias_object *obj; + + obj = kzalloc(sizeof(struct ias_object), GFP_ATOMIC); + if (obj == NULL) { + net_warn_ratelimited("%s(), Unable to allocate object!\n", + __func__); + return NULL; + } + + obj->magic = IAS_OBJECT_MAGIC; + obj->name = kstrndup(name, IAS_MAX_CLASSNAME, GFP_ATOMIC); + if (!obj->name) { + net_warn_ratelimited("%s(), Unable to allocate name!\n", + __func__); + kfree(obj); + return NULL; + } + obj->id = id; + + /* Locking notes : the attrib spinlock has lower precendence + * than the objects spinlock. Never grap the objects spinlock + * while holding any attrib spinlock (risk of deadlock). Jean II */ + obj->attribs = hashbin_new(HB_LOCK); + + if (obj->attribs == NULL) { + net_warn_ratelimited("%s(), Unable to allocate attribs!\n", + __func__); + kfree(obj->name); + kfree(obj); + return NULL; + } + + return obj; +} +EXPORT_SYMBOL(irias_new_object); + +/* + * Function irias_delete_attrib (attrib) + * + * Delete given attribute and deallocate all its memory + * + */ +static void __irias_delete_attrib(struct ias_attrib *attrib) +{ + IRDA_ASSERT(attrib != NULL, return;); + IRDA_ASSERT(attrib->magic == IAS_ATTRIB_MAGIC, return;); + + kfree(attrib->name); + + irias_delete_value(attrib->value); + attrib->magic = ~IAS_ATTRIB_MAGIC; + + kfree(attrib); +} + +void __irias_delete_object(struct ias_object *obj) +{ + IRDA_ASSERT(obj != NULL, return;); + IRDA_ASSERT(obj->magic == IAS_OBJECT_MAGIC, return;); + + kfree(obj->name); + + hashbin_delete(obj->attribs, (FREE_FUNC) __irias_delete_attrib); + + obj->magic = ~IAS_OBJECT_MAGIC; + + kfree(obj); +} + +/* + * Function irias_delete_object (obj) + * + * Remove object from hashbin and deallocate all attributes associated with + * with this object and the object itself + * + */ +int irias_delete_object(struct ias_object *obj) +{ + struct ias_object *node; + + IRDA_ASSERT(obj != NULL, return -1;); + IRDA_ASSERT(obj->magic == IAS_OBJECT_MAGIC, return -1;); + + /* Remove from list */ + node = hashbin_remove_this(irias_objects, (irda_queue_t *) obj); + if (!node) + pr_debug("%s(), object already removed!\n", + __func__); + + /* Destroy */ + __irias_delete_object(obj); + + return 0; +} +EXPORT_SYMBOL(irias_delete_object); + +/* + * Function irias_delete_attrib (obj) + * + * Remove attribute from hashbin and, if it was the last attribute of + * the object, remove the object as well. + * + */ +int irias_delete_attrib(struct ias_object *obj, struct ias_attrib *attrib, + int cleanobject) +{ + struct ias_attrib *node; + + IRDA_ASSERT(obj != NULL, return -1;); + IRDA_ASSERT(obj->magic == IAS_OBJECT_MAGIC, return -1;); + IRDA_ASSERT(attrib != NULL, return -1;); + + /* Remove attribute from object */ + node = hashbin_remove_this(obj->attribs, (irda_queue_t *) attrib); + if (!node) + return 0; /* Already removed or non-existent */ + + /* Deallocate attribute */ + __irias_delete_attrib(node); + + /* Check if object has still some attributes, destroy it if none. + * At first glance, this look dangerous, as the kernel reference + * various IAS objects. However, we only use this function on + * user attributes, not kernel attributes, so there is no risk + * of deleting a kernel object this way. Jean II */ + node = (struct ias_attrib *) hashbin_get_first(obj->attribs); + if (cleanobject && !node) + irias_delete_object(obj); + + return 0; +} + +/* + * Function irias_insert_object (obj) + * + * Insert an object into the LM-IAS database + * + */ +void irias_insert_object(struct ias_object *obj) +{ + IRDA_ASSERT(obj != NULL, return;); + IRDA_ASSERT(obj->magic == IAS_OBJECT_MAGIC, return;); + + hashbin_insert(irias_objects, (irda_queue_t *) obj, 0, obj->name); +} +EXPORT_SYMBOL(irias_insert_object); + +/* + * Function irias_find_object (name) + * + * Find object with given name + * + */ +struct ias_object *irias_find_object(char *name) +{ + IRDA_ASSERT(name != NULL, return NULL;); + + /* Unsafe (locking), object might change */ + return hashbin_lock_find(irias_objects, 0, name); +} +EXPORT_SYMBOL(irias_find_object); + +/* + * Function irias_find_attrib (obj, name) + * + * Find named attribute in object + * + */ +struct ias_attrib *irias_find_attrib(struct ias_object *obj, char *name) +{ + struct ias_attrib *attrib; + + IRDA_ASSERT(obj != NULL, return NULL;); + IRDA_ASSERT(obj->magic == IAS_OBJECT_MAGIC, return NULL;); + IRDA_ASSERT(name != NULL, return NULL;); + + attrib = hashbin_lock_find(obj->attribs, 0, name); + if (attrib == NULL) + return NULL; + + /* Unsafe (locking), attrib might change */ + return attrib; +} + +/* + * Function irias_add_attribute (obj, attrib) + * + * Add attribute to object + * + */ +static void irias_add_attrib(struct ias_object *obj, struct ias_attrib *attrib, + int owner) +{ + IRDA_ASSERT(obj != NULL, return;); + IRDA_ASSERT(obj->magic == IAS_OBJECT_MAGIC, return;); + + IRDA_ASSERT(attrib != NULL, return;); + IRDA_ASSERT(attrib->magic == IAS_ATTRIB_MAGIC, return;); + + /* Set if attrib is owned by kernel or user space */ + attrib->value->owner = owner; + + hashbin_insert(obj->attribs, (irda_queue_t *) attrib, 0, attrib->name); +} + +/* + * Function irias_object_change_attribute (obj_name, attrib_name, new_value) + * + * Change the value of an objects attribute. + * + */ +int irias_object_change_attribute(char *obj_name, char *attrib_name, + struct ias_value *new_value) +{ + struct ias_object *obj; + struct ias_attrib *attrib; + unsigned long flags; + + /* Find object */ + obj = hashbin_lock_find(irias_objects, 0, obj_name); + if (obj == NULL) { + net_warn_ratelimited("%s: Unable to find object: %s\n", + __func__, obj_name); + return -1; + } + + /* Slightly unsafe (obj might get removed under us) */ + spin_lock_irqsave(&obj->attribs->hb_spinlock, flags); + + /* Find attribute */ + attrib = hashbin_find(obj->attribs, 0, attrib_name); + if (attrib == NULL) { + net_warn_ratelimited("%s: Unable to find attribute: %s\n", + __func__, attrib_name); + spin_unlock_irqrestore(&obj->attribs->hb_spinlock, flags); + return -1; + } + + if ( attrib->value->type != new_value->type) { + pr_debug("%s(), changing value type not allowed!\n", + __func__); + spin_unlock_irqrestore(&obj->attribs->hb_spinlock, flags); + return -1; + } + + /* Delete old value */ + irias_delete_value(attrib->value); + + /* Insert new value */ + attrib->value = new_value; + + /* Success */ + spin_unlock_irqrestore(&obj->attribs->hb_spinlock, flags); + return 0; +} +EXPORT_SYMBOL(irias_object_change_attribute); + +/* + * Function irias_object_add_integer_attrib (obj, name, value) + * + * Add an integer attribute to an LM-IAS object + * + */ +void irias_add_integer_attrib(struct ias_object *obj, char *name, int value, + int owner) +{ + struct ias_attrib *attrib; + + IRDA_ASSERT(obj != NULL, return;); + IRDA_ASSERT(obj->magic == IAS_OBJECT_MAGIC, return;); + IRDA_ASSERT(name != NULL, return;); + + attrib = kzalloc(sizeof(struct ias_attrib), GFP_ATOMIC); + if (attrib == NULL) { + net_warn_ratelimited("%s: Unable to allocate attribute!\n", + __func__); + return; + } + + attrib->magic = IAS_ATTRIB_MAGIC; + attrib->name = kstrndup(name, IAS_MAX_ATTRIBNAME, GFP_ATOMIC); + + /* Insert value */ + attrib->value = irias_new_integer_value(value); + if (!attrib->name || !attrib->value) { + net_warn_ratelimited("%s: Unable to allocate attribute!\n", + __func__); + if (attrib->value) + irias_delete_value(attrib->value); + kfree(attrib->name); + kfree(attrib); + return; + } + + irias_add_attrib(obj, attrib, owner); +} +EXPORT_SYMBOL(irias_add_integer_attrib); + + /* + * Function irias_add_octseq_attrib (obj, name, octet_seq, len) + * + * Add a octet sequence attribute to an LM-IAS object + * + */ + +void irias_add_octseq_attrib(struct ias_object *obj, char *name, __u8 *octets, + int len, int owner) +{ + struct ias_attrib *attrib; + + IRDA_ASSERT(obj != NULL, return;); + IRDA_ASSERT(obj->magic == IAS_OBJECT_MAGIC, return;); + + IRDA_ASSERT(name != NULL, return;); + IRDA_ASSERT(octets != NULL, return;); + + attrib = kzalloc(sizeof(struct ias_attrib), GFP_ATOMIC); + if (attrib == NULL) { + net_warn_ratelimited("%s: Unable to allocate attribute!\n", + __func__); + return; + } + + attrib->magic = IAS_ATTRIB_MAGIC; + attrib->name = kstrndup(name, IAS_MAX_ATTRIBNAME, GFP_ATOMIC); + + attrib->value = irias_new_octseq_value( octets, len); + if (!attrib->name || !attrib->value) { + net_warn_ratelimited("%s: Unable to allocate attribute!\n", + __func__); + if (attrib->value) + irias_delete_value(attrib->value); + kfree(attrib->name); + kfree(attrib); + return; + } + + irias_add_attrib(obj, attrib, owner); +} +EXPORT_SYMBOL(irias_add_octseq_attrib); + +/* + * Function irias_object_add_string_attrib (obj, string) + * + * Add a string attribute to an LM-IAS object + * + */ +void irias_add_string_attrib(struct ias_object *obj, char *name, char *value, + int owner) +{ + struct ias_attrib *attrib; + + IRDA_ASSERT(obj != NULL, return;); + IRDA_ASSERT(obj->magic == IAS_OBJECT_MAGIC, return;); + + IRDA_ASSERT(name != NULL, return;); + IRDA_ASSERT(value != NULL, return;); + + attrib = kzalloc(sizeof( struct ias_attrib), GFP_ATOMIC); + if (attrib == NULL) { + net_warn_ratelimited("%s: Unable to allocate attribute!\n", + __func__); + return; + } + + attrib->magic = IAS_ATTRIB_MAGIC; + attrib->name = kstrndup(name, IAS_MAX_ATTRIBNAME, GFP_ATOMIC); + + attrib->value = irias_new_string_value(value); + if (!attrib->name || !attrib->value) { + net_warn_ratelimited("%s: Unable to allocate attribute!\n", + __func__); + if (attrib->value) + irias_delete_value(attrib->value); + kfree(attrib->name); + kfree(attrib); + return; + } + + irias_add_attrib(obj, attrib, owner); +} +EXPORT_SYMBOL(irias_add_string_attrib); + +/* + * Function irias_new_integer_value (integer) + * + * Create new IAS integer value + * + */ +struct ias_value *irias_new_integer_value(int integer) +{ + struct ias_value *value; + + value = kzalloc(sizeof(struct ias_value), GFP_ATOMIC); + if (value == NULL) + return NULL; + + value->type = IAS_INTEGER; + value->len = 4; + value->t.integer = integer; + + return value; +} +EXPORT_SYMBOL(irias_new_integer_value); + +/* + * Function irias_new_string_value (string) + * + * Create new IAS string value + * + * Per IrLMP 1.1, 4.3.3.2, strings are up to 256 chars - Jean II + */ +struct ias_value *irias_new_string_value(char *string) +{ + struct ias_value *value; + + value = kzalloc(sizeof(struct ias_value), GFP_ATOMIC); + if (value == NULL) + return NULL; + + value->type = IAS_STRING; + value->charset = CS_ASCII; + value->t.string = kstrndup(string, IAS_MAX_STRING, GFP_ATOMIC); + if (!value->t.string) { + net_warn_ratelimited("%s: Unable to kmalloc!\n", __func__); + kfree(value); + return NULL; + } + + value->len = strlen(value->t.string); + + return value; +} + +/* + * Function irias_new_octseq_value (octets, len) + * + * Create new IAS octet-sequence value + * + * Per IrLMP 1.1, 4.3.3.2, octet-sequence are up to 1024 bytes - Jean II + */ +struct ias_value *irias_new_octseq_value(__u8 *octseq , int len) +{ + struct ias_value *value; + + value = kzalloc(sizeof(struct ias_value), GFP_ATOMIC); + if (value == NULL) + return NULL; + + value->type = IAS_OCT_SEQ; + /* Check length */ + if(len > IAS_MAX_OCTET_STRING) + len = IAS_MAX_OCTET_STRING; + value->len = len; + + value->t.oct_seq = kmemdup(octseq, len, GFP_ATOMIC); + if (value->t.oct_seq == NULL){ + net_warn_ratelimited("%s: Unable to kmalloc!\n", __func__); + kfree(value); + return NULL; + } + return value; +} + +struct ias_value *irias_new_missing_value(void) +{ + struct ias_value *value; + + value = kzalloc(sizeof(struct ias_value), GFP_ATOMIC); + if (value == NULL) + return NULL; + + value->type = IAS_MISSING; + + return value; +} + +/* + * Function irias_delete_value (value) + * + * Delete IAS value + * + */ +void irias_delete_value(struct ias_value *value) +{ + IRDA_ASSERT(value != NULL, return;); + + switch (value->type) { + case IAS_INTEGER: /* Fallthrough */ + case IAS_MISSING: + /* No need to deallocate */ + break; + case IAS_STRING: + /* Deallocate string */ + kfree(value->t.string); + break; + case IAS_OCT_SEQ: + /* Deallocate byte stream */ + kfree(value->t.oct_seq); + break; + default: + pr_debug("%s(), Unknown value type!\n", __func__); + break; + } + kfree(value); +} +EXPORT_SYMBOL(irias_delete_value); diff --git a/drivers/staging/irda/net/irlan/Kconfig b/drivers/staging/irda/net/irlan/Kconfig new file mode 100644 index 000000000000..951abc2e3a7f --- /dev/null +++ b/drivers/staging/irda/net/irlan/Kconfig @@ -0,0 +1,14 @@ +config IRLAN + tristate "IrLAN protocol" + depends on IRDA + help + Say Y here if you want to build support for the IrLAN protocol. + To compile it as a module, choose M here: the module will be called + irlan. IrLAN emulates an Ethernet and makes it possible to put up + a wireless LAN using infrared beams. + + The IrLAN protocol can be used to talk with infrared access points + like the HP NetbeamIR, or the ESI JetEye NET. You can also connect + to another Linux machine running the IrLAN protocol for ad-hoc + networking! + diff --git a/drivers/staging/irda/net/irlan/Makefile b/drivers/staging/irda/net/irlan/Makefile new file mode 100644 index 000000000000..94eefbc8e6b9 --- /dev/null +++ b/drivers/staging/irda/net/irlan/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for the Linux IrDA IrLAN protocol layer. +# + +obj-$(CONFIG_IRLAN) += irlan.o + +irlan-y := irlan_common.o irlan_eth.o irlan_event.o irlan_client.o irlan_provider.o irlan_filter.o irlan_provider_event.o irlan_client_event.o diff --git a/drivers/staging/irda/net/irlan/irlan_client.c b/drivers/staging/irda/net/irlan/irlan_client.c new file mode 100644 index 000000000000..c5837a40c78e --- /dev/null +++ b/drivers/staging/irda/net/irlan/irlan_client.c @@ -0,0 +1,559 @@ +/********************************************************************* + * + * Filename: irlan_client.c + * Version: 0.9 + * Description: IrDA LAN Access Protocol (IrLAN) Client + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Sun Aug 31 20:14:37 1997 + * Modified at: Tue Dec 14 15:47:02 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * Sources: skeleton.c by Donald Becker <becker@CESDIS.gsfc.nasa.gov> + * slip.c by Laurence Culhane, <loz@holmes.demon.co.uk> + * Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org> + * + * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/slab.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/if_arp.h> +#include <linux/bitops.h> +#include <net/arp.h> + +#include <asm/byteorder.h> + +#include <net/irda/irda.h> +#include <net/irda/irttp.h> +#include <net/irda/irlmp.h> +#include <net/irda/irias_object.h> +#include <net/irda/iriap.h> +#include <net/irda/timer.h> + +#include <net/irda/irlan_common.h> +#include <net/irda/irlan_event.h> +#include <net/irda/irlan_eth.h> +#include <net/irda/irlan_provider.h> +#include <net/irda/irlan_client.h> + +#undef CONFIG_IRLAN_GRATUITOUS_ARP + +static void irlan_client_ctrl_disconnect_indication(void *instance, void *sap, + LM_REASON reason, + struct sk_buff *); +static int irlan_client_ctrl_data_indication(void *instance, void *sap, + struct sk_buff *skb); +static void irlan_client_ctrl_connect_confirm(void *instance, void *sap, + struct qos_info *qos, + __u32 max_sdu_size, + __u8 max_header_size, + struct sk_buff *); +static void irlan_check_response_param(struct irlan_cb *self, char *param, + char *value, int val_len); +static void irlan_client_open_ctrl_tsap(struct irlan_cb *self); + +static void irlan_client_kick_timer_expired(void *data) +{ + struct irlan_cb *self = (struct irlan_cb *) data; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); + + /* + * If we are in peer mode, the client may not have got the discovery + * indication it needs to make progress. If the client is still in + * IDLE state, we must kick it to, but only if the provider is not IDLE + */ + if ((self->provider.access_type == ACCESS_PEER) && + (self->client.state == IRLAN_IDLE) && + (self->provider.state != IRLAN_IDLE)) { + irlan_client_wakeup(self, self->saddr, self->daddr); + } +} + +static void irlan_client_start_kick_timer(struct irlan_cb *self, int timeout) +{ + irda_start_timer(&self->client.kick_timer, timeout, (void *) self, + irlan_client_kick_timer_expired); +} + +/* + * Function irlan_client_wakeup (self, saddr, daddr) + * + * Wake up client + * + */ +void irlan_client_wakeup(struct irlan_cb *self, __u32 saddr, __u32 daddr) +{ + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); + + /* + * Check if we are already awake, or if we are a provider in direct + * mode (in that case we must leave the client idle + */ + if ((self->client.state != IRLAN_IDLE) || + (self->provider.access_type == ACCESS_DIRECT)) + { + pr_debug("%s(), already awake!\n", __func__); + return; + } + + /* Addresses may have changed! */ + self->saddr = saddr; + self->daddr = daddr; + + if (self->disconnect_reason == LM_USER_REQUEST) { + pr_debug("%s(), still stopped by user\n", __func__); + return; + } + + /* Open TSAPs */ + irlan_client_open_ctrl_tsap(self); + irlan_open_data_tsap(self); + + irlan_do_client_event(self, IRLAN_DISCOVERY_INDICATION, NULL); + + /* Start kick timer */ + irlan_client_start_kick_timer(self, 2*HZ); +} + +/* + * Function irlan_discovery_indication (daddr) + * + * Remote device with IrLAN server support discovered + * + */ +void irlan_client_discovery_indication(discinfo_t *discovery, + DISCOVERY_MODE mode, + void *priv) +{ + struct irlan_cb *self; + __u32 saddr, daddr; + + IRDA_ASSERT(discovery != NULL, return;); + + /* + * I didn't check it, but I bet that IrLAN suffer from the same + * deficiency as IrComm and doesn't handle two instances + * simultaneously connecting to each other. + * Same workaround, drop passive discoveries. + * Jean II */ + if(mode == DISCOVERY_PASSIVE) + return; + + saddr = discovery->saddr; + daddr = discovery->daddr; + + /* Find instance */ + rcu_read_lock(); + self = irlan_get_any(); + if (self) { + IRDA_ASSERT(self->magic == IRLAN_MAGIC, goto out;); + + pr_debug("%s(), Found instance (%08x)!\n", __func__ , + daddr); + + irlan_client_wakeup(self, saddr, daddr); + } +IRDA_ASSERT_LABEL(out:) + rcu_read_unlock(); +} + +/* + * Function irlan_client_data_indication (handle, skb) + * + * This function gets the data that is received on the control channel + * + */ +static int irlan_client_ctrl_data_indication(void *instance, void *sap, + struct sk_buff *skb) +{ + struct irlan_cb *self; + + self = instance; + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;); + IRDA_ASSERT(skb != NULL, return -1;); + + irlan_do_client_event(self, IRLAN_DATA_INDICATION, skb); + + /* Ready for a new command */ + pr_debug("%s(), clearing tx_busy\n", __func__); + self->client.tx_busy = FALSE; + + /* Check if we have some queued commands waiting to be sent */ + irlan_run_ctrl_tx_queue(self); + + return 0; +} + +static void irlan_client_ctrl_disconnect_indication(void *instance, void *sap, + LM_REASON reason, + struct sk_buff *userdata) +{ + struct irlan_cb *self; + struct tsap_cb *tsap; + struct sk_buff *skb; + + pr_debug("%s(), reason=%d\n", __func__ , reason); + + self = instance; + tsap = sap; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); + IRDA_ASSERT(tsap != NULL, return;); + IRDA_ASSERT(tsap->magic == TTP_TSAP_MAGIC, return;); + + IRDA_ASSERT(tsap == self->client.tsap_ctrl, return;); + + /* Remove frames queued on the control channel */ + while ((skb = skb_dequeue(&self->client.txq)) != NULL) { + dev_kfree_skb(skb); + } + self->client.tx_busy = FALSE; + + irlan_do_client_event(self, IRLAN_LMP_DISCONNECT, NULL); +} + +/* + * Function irlan_client_open_tsaps (self) + * + * Initialize callbacks and open IrTTP TSAPs + * + */ +static void irlan_client_open_ctrl_tsap(struct irlan_cb *self) +{ + struct tsap_cb *tsap; + notify_t notify; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); + + /* Check if already open */ + if (self->client.tsap_ctrl) + return; + + irda_notify_init(¬ify); + + /* Set up callbacks */ + notify.data_indication = irlan_client_ctrl_data_indication; + notify.connect_confirm = irlan_client_ctrl_connect_confirm; + notify.disconnect_indication = irlan_client_ctrl_disconnect_indication; + notify.instance = self; + strlcpy(notify.name, "IrLAN ctrl (c)", sizeof(notify.name)); + + tsap = irttp_open_tsap(LSAP_ANY, DEFAULT_INITIAL_CREDIT, ¬ify); + if (!tsap) { + pr_debug("%s(), Got no tsap!\n", __func__); + return; + } + self->client.tsap_ctrl = tsap; +} + +/* + * Function irlan_client_connect_confirm (handle, skb) + * + * Connection to peer IrLAN laye confirmed + * + */ +static void irlan_client_ctrl_connect_confirm(void *instance, void *sap, + struct qos_info *qos, + __u32 max_sdu_size, + __u8 max_header_size, + struct sk_buff *skb) +{ + struct irlan_cb *self; + + self = instance; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); + + self->client.max_sdu_size = max_sdu_size; + self->client.max_header_size = max_header_size; + + /* TODO: we could set the MTU depending on the max_sdu_size */ + + irlan_do_client_event(self, IRLAN_CONNECT_COMPLETE, NULL); +} + +/* + * Function print_ret_code (code) + * + * Print return code of request to peer IrLAN layer. + * + */ +static void print_ret_code(__u8 code) +{ + switch(code) { + case 0: + printk(KERN_INFO "Success\n"); + break; + case 1: + net_warn_ratelimited("IrLAN: Insufficient resources\n"); + break; + case 2: + net_warn_ratelimited("IrLAN: Invalid command format\n"); + break; + case 3: + net_warn_ratelimited("IrLAN: Command not supported\n"); + break; + case 4: + net_warn_ratelimited("IrLAN: Parameter not supported\n"); + break; + case 5: + net_warn_ratelimited("IrLAN: Value not supported\n"); + break; + case 6: + net_warn_ratelimited("IrLAN: Not open\n"); + break; + case 7: + net_warn_ratelimited("IrLAN: Authentication required\n"); + break; + case 8: + net_warn_ratelimited("IrLAN: Invalid password\n"); + break; + case 9: + net_warn_ratelimited("IrLAN: Protocol error\n"); + break; + case 255: + net_warn_ratelimited("IrLAN: Asynchronous status\n"); + break; + } +} + +/* + * Function irlan_client_parse_response (self, skb) + * + * Extract all parameters from received buffer, then feed them to + * check_params for parsing + */ +void irlan_client_parse_response(struct irlan_cb *self, struct sk_buff *skb) +{ + __u8 *frame; + __u8 *ptr; + int count; + int ret; + __u16 val_len; + int i; + char *name; + char *value; + + IRDA_ASSERT(skb != NULL, return;); + + pr_debug("%s() skb->len=%d\n", __func__ , (int)skb->len); + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); + + if (!skb) { + net_err_ratelimited("%s(), Got NULL skb!\n", __func__); + return; + } + frame = skb->data; + + /* + * Check return code and print it if not success + */ + if (frame[0]) { + print_ret_code(frame[0]); + return; + } + + name = kmalloc(255, GFP_ATOMIC); + if (!name) + return; + value = kmalloc(1016, GFP_ATOMIC); + if (!value) { + kfree(name); + return; + } + + /* How many parameters? */ + count = frame[1]; + + pr_debug("%s(), got %d parameters\n", __func__ , count); + + ptr = frame+2; + + /* For all parameters */ + for (i=0; i<count;i++) { + ret = irlan_extract_param(ptr, name, value, &val_len); + if (ret < 0) { + pr_debug("%s(), IrLAN, Error!\n", __func__); + break; + } + ptr += ret; + irlan_check_response_param(self, name, value, val_len); + } + /* Cleanup */ + kfree(name); + kfree(value); +} + +/* + * Function irlan_check_response_param (self, param, value, val_len) + * + * Check which parameter is received and update local variables + * + */ +static void irlan_check_response_param(struct irlan_cb *self, char *param, + char *value, int val_len) +{ + __u16 tmp_cpu; /* Temporary value in host order */ + __u8 *bytes; + int i; + + pr_debug("%s(), parm=%s\n", __func__ , param); + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); + + /* Media type */ + if (strcmp(param, "MEDIA") == 0) { + if (strcmp(value, "802.3") == 0) + self->media = MEDIA_802_3; + else + self->media = MEDIA_802_5; + return; + } + if (strcmp(param, "FILTER_TYPE") == 0) { + if (strcmp(value, "DIRECTED") == 0) + self->client.filter_type |= IRLAN_DIRECTED; + else if (strcmp(value, "FUNCTIONAL") == 0) + self->client.filter_type |= IRLAN_FUNCTIONAL; + else if (strcmp(value, "GROUP") == 0) + self->client.filter_type |= IRLAN_GROUP; + else if (strcmp(value, "MAC_FRAME") == 0) + self->client.filter_type |= IRLAN_MAC_FRAME; + else if (strcmp(value, "MULTICAST") == 0) + self->client.filter_type |= IRLAN_MULTICAST; + else if (strcmp(value, "BROADCAST") == 0) + self->client.filter_type |= IRLAN_BROADCAST; + else if (strcmp(value, "IPX_SOCKET") == 0) + self->client.filter_type |= IRLAN_IPX_SOCKET; + + } + if (strcmp(param, "ACCESS_TYPE") == 0) { + if (strcmp(value, "DIRECT") == 0) + self->client.access_type = ACCESS_DIRECT; + else if (strcmp(value, "PEER") == 0) + self->client.access_type = ACCESS_PEER; + else if (strcmp(value, "HOSTED") == 0) + self->client.access_type = ACCESS_HOSTED; + else { + pr_debug("%s(), unknown access type!\n", __func__); + } + } + /* IRLAN version */ + if (strcmp(param, "IRLAN_VER") == 0) { + pr_debug("IrLAN version %d.%d\n", (__u8)value[0], + (__u8)value[1]); + + self->version[0] = value[0]; + self->version[1] = value[1]; + return; + } + /* Which remote TSAP to use for data channel */ + if (strcmp(param, "DATA_CHAN") == 0) { + self->dtsap_sel_data = value[0]; + pr_debug("Data TSAP = %02x\n", self->dtsap_sel_data); + return; + } + if (strcmp(param, "CON_ARB") == 0) { + memcpy(&tmp_cpu, value, 2); /* Align value */ + le16_to_cpus(&tmp_cpu); /* Convert to host order */ + self->client.recv_arb_val = tmp_cpu; + pr_debug("%s(), receive arb val=%d\n", __func__ , + self->client.recv_arb_val); + } + if (strcmp(param, "MAX_FRAME") == 0) { + memcpy(&tmp_cpu, value, 2); /* Align value */ + le16_to_cpus(&tmp_cpu); /* Convert to host order */ + self->client.max_frame = tmp_cpu; + pr_debug("%s(), max frame=%d\n", __func__ , + self->client.max_frame); + } + + /* RECONNECT_KEY, in case the link goes down! */ + if (strcmp(param, "RECONNECT_KEY") == 0) { + pr_debug("Got reconnect key: "); + /* for (i = 0; i < val_len; i++) */ +/* printk("%02x", value[i]); */ + memcpy(self->client.reconnect_key, value, val_len); + self->client.key_len = val_len; + pr_debug("\n"); + } + /* FILTER_ENTRY, have we got an ethernet address? */ + if (strcmp(param, "FILTER_ENTRY") == 0) { + bytes = value; + pr_debug("Ethernet address = %pM\n", bytes); + for (i = 0; i < 6; i++) + self->dev->dev_addr[i] = bytes[i]; + } +} + +/* + * Function irlan_client_get_value_confirm (obj_id, value) + * + * Got results from remote LM-IAS + * + */ +void irlan_client_get_value_confirm(int result, __u16 obj_id, + struct ias_value *value, void *priv) +{ + struct irlan_cb *self; + + IRDA_ASSERT(priv != NULL, return;); + + self = priv; + IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); + + /* We probably don't need to make any more queries */ + iriap_close(self->client.iriap); + self->client.iriap = NULL; + + /* Check if request succeeded */ + if (result != IAS_SUCCESS) { + pr_debug("%s(), got NULL value!\n", __func__); + irlan_do_client_event(self, IRLAN_IAS_PROVIDER_NOT_AVAIL, + NULL); + return; + } + + switch (value->type) { + case IAS_INTEGER: + self->dtsap_sel_ctrl = value->t.integer; + + if (value->t.integer != -1) { + irlan_do_client_event(self, IRLAN_IAS_PROVIDER_AVAIL, + NULL); + return; + } + irias_delete_value(value); + break; + default: + pr_debug("%s(), unknown type!\n", __func__); + break; + } + irlan_do_client_event(self, IRLAN_IAS_PROVIDER_NOT_AVAIL, NULL); +} diff --git a/drivers/staging/irda/net/irlan/irlan_client_event.c b/drivers/staging/irda/net/irlan/irlan_client_event.c new file mode 100644 index 000000000000..cc93fabbbb19 --- /dev/null +++ b/drivers/staging/irda/net/irlan/irlan_client_event.c @@ -0,0 +1,511 @@ +/********************************************************************* + * + * Filename: irlan_client_event.c + * Version: 0.9 + * Description: IrLAN client state machine + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Sun Aug 31 20:14:37 1997 + * Modified at: Sun Dec 26 21:52:24 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#include <linux/skbuff.h> + +#include <net/irda/irda.h> +#include <net/irda/timer.h> +#include <net/irda/irmod.h> +#include <net/irda/iriap.h> +#include <net/irda/irlmp.h> +#include <net/irda/irttp.h> + +#include <net/irda/irlan_common.h> +#include <net/irda/irlan_client.h> +#include <net/irda/irlan_event.h> + +static int irlan_client_state_idle (struct irlan_cb *self, IRLAN_EVENT event, + struct sk_buff *skb); +static int irlan_client_state_query(struct irlan_cb *self, IRLAN_EVENT event, + struct sk_buff *skb); +static int irlan_client_state_conn (struct irlan_cb *self, IRLAN_EVENT event, + struct sk_buff *skb); +static int irlan_client_state_info (struct irlan_cb *self, IRLAN_EVENT event, + struct sk_buff *skb); +static int irlan_client_state_media(struct irlan_cb *self, IRLAN_EVENT event, + struct sk_buff *skb); +static int irlan_client_state_open (struct irlan_cb *self, IRLAN_EVENT event, + struct sk_buff *skb); +static int irlan_client_state_wait (struct irlan_cb *self, IRLAN_EVENT event, + struct sk_buff *skb); +static int irlan_client_state_arb (struct irlan_cb *self, IRLAN_EVENT event, + struct sk_buff *skb); +static int irlan_client_state_data (struct irlan_cb *self, IRLAN_EVENT event, + struct sk_buff *skb); +static int irlan_client_state_close(struct irlan_cb *self, IRLAN_EVENT event, + struct sk_buff *skb); +static int irlan_client_state_sync (struct irlan_cb *self, IRLAN_EVENT event, + struct sk_buff *skb); + +static int (*state[])(struct irlan_cb *, IRLAN_EVENT event, struct sk_buff *) = +{ + irlan_client_state_idle, + irlan_client_state_query, + irlan_client_state_conn, + irlan_client_state_info, + irlan_client_state_media, + irlan_client_state_open, + irlan_client_state_wait, + irlan_client_state_arb, + irlan_client_state_data, + irlan_client_state_close, + irlan_client_state_sync +}; + +void irlan_do_client_event(struct irlan_cb *self, IRLAN_EVENT event, + struct sk_buff *skb) +{ + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); + + (*state[ self->client.state]) (self, event, skb); +} + +/* + * Function irlan_client_state_idle (event, skb, info) + * + * IDLE, We are waiting for an indication that there is a provider + * available. + */ +static int irlan_client_state_idle(struct irlan_cb *self, IRLAN_EVENT event, + struct sk_buff *skb) +{ + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;); + + switch (event) { + case IRLAN_DISCOVERY_INDICATION: + if (self->client.iriap) { + net_warn_ratelimited("%s(), busy with a previous query\n", + __func__); + return -EBUSY; + } + + self->client.iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self, + irlan_client_get_value_confirm); + /* Get some values from peer IAS */ + irlan_next_client_state(self, IRLAN_QUERY); + iriap_getvaluebyclass_request(self->client.iriap, + self->saddr, self->daddr, + "IrLAN", "IrDA:TinyTP:LsapSel"); + break; + case IRLAN_WATCHDOG_TIMEOUT: + pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__); + break; + default: + pr_debug("%s(), Unknown event %d\n", __func__ , event); + break; + } + if (skb) + dev_kfree_skb(skb); + + return 0; +} + +/* + * Function irlan_client_state_query (event, skb, info) + * + * QUERY, We have queryed the remote IAS and is ready to connect + * to provider, just waiting for the confirm. + * + */ +static int irlan_client_state_query(struct irlan_cb *self, IRLAN_EVENT event, + struct sk_buff *skb) +{ + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;); + + switch(event) { + case IRLAN_IAS_PROVIDER_AVAIL: + IRDA_ASSERT(self->dtsap_sel_ctrl != 0, return -1;); + + self->client.open_retries = 0; + + irttp_connect_request(self->client.tsap_ctrl, + self->dtsap_sel_ctrl, + self->saddr, self->daddr, NULL, + IRLAN_MTU, NULL); + irlan_next_client_state(self, IRLAN_CONN); + break; + case IRLAN_IAS_PROVIDER_NOT_AVAIL: + pr_debug("%s(), IAS_PROVIDER_NOT_AVAIL\n", __func__); + irlan_next_client_state(self, IRLAN_IDLE); + + /* Give the client a kick! */ + if ((self->provider.access_type == ACCESS_PEER) && + (self->provider.state != IRLAN_IDLE)) + irlan_client_wakeup(self, self->saddr, self->daddr); + break; + case IRLAN_LMP_DISCONNECT: + case IRLAN_LAP_DISCONNECT: + irlan_next_client_state(self, IRLAN_IDLE); + break; + case IRLAN_WATCHDOG_TIMEOUT: + pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__); + break; + default: + pr_debug("%s(), Unknown event %d\n", __func__ , event); + break; + } + if (skb) + dev_kfree_skb(skb); + + return 0; +} + +/* + * Function irlan_client_state_conn (event, skb, info) + * + * CONN, We have connected to a provider but has not issued any + * commands yet. + * + */ +static int irlan_client_state_conn(struct irlan_cb *self, IRLAN_EVENT event, + struct sk_buff *skb) +{ + IRDA_ASSERT(self != NULL, return -1;); + + switch (event) { + case IRLAN_CONNECT_COMPLETE: + /* Send getinfo cmd */ + irlan_get_provider_info(self); + irlan_next_client_state(self, IRLAN_INFO); + break; + case IRLAN_LMP_DISCONNECT: + case IRLAN_LAP_DISCONNECT: + irlan_next_client_state(self, IRLAN_IDLE); + break; + case IRLAN_WATCHDOG_TIMEOUT: + pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__); + break; + default: + pr_debug("%s(), Unknown event %d\n", __func__ , event); + break; + } + if (skb) + dev_kfree_skb(skb); + + return 0; +} + +/* + * Function irlan_client_state_info (self, event, skb, info) + * + * INFO, We have issued a GetInfo command and is awaiting a reply. + */ +static int irlan_client_state_info(struct irlan_cb *self, IRLAN_EVENT event, + struct sk_buff *skb) +{ + IRDA_ASSERT(self != NULL, return -1;); + + switch (event) { + case IRLAN_DATA_INDICATION: + IRDA_ASSERT(skb != NULL, return -1;); + + irlan_client_parse_response(self, skb); + + irlan_next_client_state(self, IRLAN_MEDIA); + + irlan_get_media_char(self); + break; + + case IRLAN_LMP_DISCONNECT: + case IRLAN_LAP_DISCONNECT: + irlan_next_client_state(self, IRLAN_IDLE); + break; + case IRLAN_WATCHDOG_TIMEOUT: + pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__); + break; + default: + pr_debug("%s(), Unknown event %d\n", __func__ , event); + break; + } + if (skb) + dev_kfree_skb(skb); + + return 0; +} + +/* + * Function irlan_client_state_media (self, event, skb, info) + * + * MEDIA, The irlan_client has issued a GetMedia command and is awaiting a + * reply. + * + */ +static int irlan_client_state_media(struct irlan_cb *self, IRLAN_EVENT event, + struct sk_buff *skb) +{ + IRDA_ASSERT(self != NULL, return -1;); + + switch(event) { + case IRLAN_DATA_INDICATION: + irlan_client_parse_response(self, skb); + irlan_open_data_channel(self); + irlan_next_client_state(self, IRLAN_OPEN); + break; + case IRLAN_LMP_DISCONNECT: + case IRLAN_LAP_DISCONNECT: + irlan_next_client_state(self, IRLAN_IDLE); + break; + case IRLAN_WATCHDOG_TIMEOUT: + pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__); + break; + default: + pr_debug("%s(), Unknown event %d\n", __func__ , event); + break; + } + if (skb) + dev_kfree_skb(skb); + + return 0; +} + +/* + * Function irlan_client_state_open (self, event, skb, info) + * + * OPEN, The irlan_client has issued a OpenData command and is awaiting a + * reply + * + */ +static int irlan_client_state_open(struct irlan_cb *self, IRLAN_EVENT event, + struct sk_buff *skb) +{ + struct qos_info qos; + + IRDA_ASSERT(self != NULL, return -1;); + + switch(event) { + case IRLAN_DATA_INDICATION: + irlan_client_parse_response(self, skb); + + /* + * Check if we have got the remote TSAP for data + * communications + */ + IRDA_ASSERT(self->dtsap_sel_data != 0, return -1;); + + /* Check which access type we are dealing with */ + switch (self->client.access_type) { + case ACCESS_PEER: + if (self->provider.state == IRLAN_OPEN) { + + irlan_next_client_state(self, IRLAN_ARB); + irlan_do_client_event(self, IRLAN_CHECK_CON_ARB, + NULL); + } else { + + irlan_next_client_state(self, IRLAN_WAIT); + } + break; + case ACCESS_DIRECT: + case ACCESS_HOSTED: + qos.link_disc_time.bits = 0x01; /* 3 secs */ + + irttp_connect_request(self->tsap_data, + self->dtsap_sel_data, + self->saddr, self->daddr, &qos, + IRLAN_MTU, NULL); + + irlan_next_client_state(self, IRLAN_DATA); + break; + default: + pr_debug("%s(), unknown access type!\n", __func__); + break; + } + break; + case IRLAN_LMP_DISCONNECT: + case IRLAN_LAP_DISCONNECT: + irlan_next_client_state(self, IRLAN_IDLE); + break; + case IRLAN_WATCHDOG_TIMEOUT: + pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__); + break; + default: + pr_debug("%s(), Unknown event %d\n", __func__ , event); + break; + } + + if (skb) + dev_kfree_skb(skb); + + return 0; +} + +/* + * Function irlan_client_state_wait (self, event, skb, info) + * + * WAIT, The irlan_client is waiting for the local provider to enter the + * provider OPEN state. + * + */ +static int irlan_client_state_wait(struct irlan_cb *self, IRLAN_EVENT event, + struct sk_buff *skb) +{ + IRDA_ASSERT(self != NULL, return -1;); + + switch(event) { + case IRLAN_PROVIDER_SIGNAL: + irlan_next_client_state(self, IRLAN_ARB); + irlan_do_client_event(self, IRLAN_CHECK_CON_ARB, NULL); + break; + case IRLAN_LMP_DISCONNECT: + case IRLAN_LAP_DISCONNECT: + irlan_next_client_state(self, IRLAN_IDLE); + break; + case IRLAN_WATCHDOG_TIMEOUT: + pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__); + break; + default: + pr_debug("%s(), Unknown event %d\n", __func__ , event); + break; + } + if (skb) + dev_kfree_skb(skb); + + return 0; +} + +static int irlan_client_state_arb(struct irlan_cb *self, IRLAN_EVENT event, + struct sk_buff *skb) +{ + struct qos_info qos; + + IRDA_ASSERT(self != NULL, return -1;); + + switch(event) { + case IRLAN_CHECK_CON_ARB: + if (self->client.recv_arb_val == self->provider.send_arb_val) { + irlan_next_client_state(self, IRLAN_CLOSE); + irlan_close_data_channel(self); + } else if (self->client.recv_arb_val < + self->provider.send_arb_val) + { + qos.link_disc_time.bits = 0x01; /* 3 secs */ + + irlan_next_client_state(self, IRLAN_DATA); + irttp_connect_request(self->tsap_data, + self->dtsap_sel_data, + self->saddr, self->daddr, &qos, + IRLAN_MTU, NULL); + } else if (self->client.recv_arb_val > + self->provider.send_arb_val) + { + pr_debug("%s(), lost the battle :-(\n", __func__); + } + break; + case IRLAN_DATA_CONNECT_INDICATION: + irlan_next_client_state(self, IRLAN_DATA); + break; + case IRLAN_LMP_DISCONNECT: + case IRLAN_LAP_DISCONNECT: + irlan_next_client_state(self, IRLAN_IDLE); + break; + case IRLAN_WATCHDOG_TIMEOUT: + pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__); + break; + default: + pr_debug("%s(), Unknown event %d\n", __func__ , event); + break; + } + if (skb) + dev_kfree_skb(skb); + + return 0; +} + +/* + * Function irlan_client_state_data (self, event, skb, info) + * + * DATA, The data channel is connected, allowing data transfers between + * the local and remote machines. + * + */ +static int irlan_client_state_data(struct irlan_cb *self, IRLAN_EVENT event, + struct sk_buff *skb) +{ + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;); + + switch(event) { + case IRLAN_DATA_INDICATION: + irlan_client_parse_response(self, skb); + break; + case IRLAN_LMP_DISCONNECT: /* FALLTHROUGH */ + case IRLAN_LAP_DISCONNECT: + irlan_next_client_state(self, IRLAN_IDLE); + break; + default: + pr_debug("%s(), Unknown event %d\n", __func__ , event); + break; + } + if (skb) + dev_kfree_skb(skb); + + return 0; +} + +/* + * Function irlan_client_state_close (self, event, skb, info) + * + * + * + */ +static int irlan_client_state_close(struct irlan_cb *self, IRLAN_EVENT event, + struct sk_buff *skb) +{ + if (skb) + dev_kfree_skb(skb); + + return 0; +} + +/* + * Function irlan_client_state_sync (self, event, skb, info) + * + * + * + */ +static int irlan_client_state_sync(struct irlan_cb *self, IRLAN_EVENT event, + struct sk_buff *skb) +{ + if (skb) + dev_kfree_skb(skb); + + return 0; +} + + + + + + + + + + + + + diff --git a/drivers/staging/irda/net/irlan/irlan_common.c b/drivers/staging/irda/net/irlan/irlan_common.c new file mode 100644 index 000000000000..481bbc2a4349 --- /dev/null +++ b/drivers/staging/irda/net/irlan/irlan_common.c @@ -0,0 +1,1176 @@ +/********************************************************************* + * + * Filename: irlan_common.c + * Version: 0.9 + * Description: IrDA LAN Access Protocol Implementation + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Sun Aug 31 20:14:37 1997 + * Modified at: Sun Dec 26 21:53:10 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1997, 1999 Dag Brattli <dagb@cs.uit.no>, + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#include <linux/module.h> + +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/gfp.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/proc_fs.h> +#include <linux/sched.h> +#include <linux/seq_file.h> +#include <linux/random.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/rtnetlink.h> +#include <linux/moduleparam.h> +#include <linux/bitops.h> + +#include <asm/byteorder.h> + +#include <net/irda/irda.h> +#include <net/irda/irttp.h> +#include <net/irda/irlmp.h> +#include <net/irda/iriap.h> +#include <net/irda/timer.h> + +#include <net/irda/irlan_common.h> +#include <net/irda/irlan_client.h> +#include <net/irda/irlan_provider.h> +#include <net/irda/irlan_eth.h> +#include <net/irda/irlan_filter.h> + + +/* extern char sysctl_devname[]; */ + +/* + * Master structure + */ +static LIST_HEAD(irlans); + +static void *ckey; +static void *skey; + +/* Module parameters */ +static bool eth; /* Use "eth" or "irlan" name for devices */ +static int access = ACCESS_PEER; /* PEER, DIRECT or HOSTED */ + +#ifdef CONFIG_PROC_FS +static const char *const irlan_access[] = { + "UNKNOWN", + "DIRECT", + "PEER", + "HOSTED" +}; + +static const char *const irlan_media[] = { + "UNKNOWN", + "802.3", + "802.5" +}; + +extern struct proc_dir_entry *proc_irda; + +static int irlan_seq_open(struct inode *inode, struct file *file); + +static const struct file_operations irlan_fops = { + .owner = THIS_MODULE, + .open = irlan_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +extern struct proc_dir_entry *proc_irda; +#endif /* CONFIG_PROC_FS */ + +static struct irlan_cb __init *irlan_open(__u32 saddr, __u32 daddr); +static void __irlan_close(struct irlan_cb *self); +static int __irlan_insert_param(struct sk_buff *skb, char *param, int type, + __u8 value_byte, __u16 value_short, + __u8 *value_array, __u16 value_len); +static void irlan_open_unicast_addr(struct irlan_cb *self); +static void irlan_get_unicast_addr(struct irlan_cb *self); +void irlan_close_tsaps(struct irlan_cb *self); + +/* + * Function irlan_init (void) + * + * Initialize IrLAN layer + * + */ +static int __init irlan_init(void) +{ + struct irlan_cb *new; + __u16 hints; + +#ifdef CONFIG_PROC_FS + { struct proc_dir_entry *proc; + proc = proc_create("irlan", 0, proc_irda, &irlan_fops); + if (!proc) { + printk(KERN_ERR "irlan_init: can't create /proc entry!\n"); + return -ENODEV; + } + } +#endif /* CONFIG_PROC_FS */ + + hints = irlmp_service_to_hint(S_LAN); + + /* Register with IrLMP as a client */ + ckey = irlmp_register_client(hints, &irlan_client_discovery_indication, + NULL, NULL); + if (!ckey) + goto err_ckey; + + /* Register with IrLMP as a service */ + skey = irlmp_register_service(hints); + if (!skey) + goto err_skey; + + /* Start the master IrLAN instance (the only one for now) */ + new = irlan_open(DEV_ADDR_ANY, DEV_ADDR_ANY); + if (!new) + goto err_open; + + /* The master will only open its (listen) control TSAP */ + irlan_provider_open_ctrl_tsap(new); + + /* Do some fast discovery! */ + irlmp_discovery_request(DISCOVERY_DEFAULT_SLOTS); + + return 0; + +err_open: + irlmp_unregister_service(skey); +err_skey: + irlmp_unregister_client(ckey); +err_ckey: +#ifdef CONFIG_PROC_FS + remove_proc_entry("irlan", proc_irda); +#endif /* CONFIG_PROC_FS */ + + return -ENOMEM; +} + +static void __exit irlan_cleanup(void) +{ + struct irlan_cb *self, *next; + + irlmp_unregister_client(ckey); + irlmp_unregister_service(skey); + +#ifdef CONFIG_PROC_FS + remove_proc_entry("irlan", proc_irda); +#endif /* CONFIG_PROC_FS */ + + /* Cleanup any leftover network devices */ + rtnl_lock(); + list_for_each_entry_safe(self, next, &irlans, dev_list) { + __irlan_close(self); + } + rtnl_unlock(); +} + +/* + * Function irlan_open (void) + * + * Open new instance of a client/provider, we should only register the + * network device if this instance is ment for a particular client/provider + */ +static struct irlan_cb __init *irlan_open(__u32 saddr, __u32 daddr) +{ + struct net_device *dev; + struct irlan_cb *self; + + /* Create network device with irlan */ + dev = alloc_irlandev(eth ? "eth%d" : "irlan%d"); + if (!dev) + return NULL; + + self = netdev_priv(dev); + self->dev = dev; + + /* + * Initialize local device structure + */ + self->magic = IRLAN_MAGIC; + self->saddr = saddr; + self->daddr = daddr; + + /* Provider access can only be PEER, DIRECT, or HOSTED */ + self->provider.access_type = access; + if (access == ACCESS_DIRECT) { + /* + * Since we are emulating an IrLAN sever we will have to + * give ourself an ethernet address! + */ + dev->dev_addr[0] = 0x40; + dev->dev_addr[1] = 0x00; + dev->dev_addr[2] = 0x00; + dev->dev_addr[3] = 0x00; + get_random_bytes(dev->dev_addr+4, 1); + get_random_bytes(dev->dev_addr+5, 1); + } + + self->media = MEDIA_802_3; + self->disconnect_reason = LM_USER_REQUEST; + init_timer(&self->watchdog_timer); + init_timer(&self->client.kick_timer); + init_waitqueue_head(&self->open_wait); + + skb_queue_head_init(&self->client.txq); + + irlan_next_client_state(self, IRLAN_IDLE); + irlan_next_provider_state(self, IRLAN_IDLE); + + if (register_netdev(dev)) { + pr_debug("%s(), register_netdev() failed!\n", + __func__); + self = NULL; + free_netdev(dev); + } else { + rtnl_lock(); + list_add_rcu(&self->dev_list, &irlans); + rtnl_unlock(); + } + + return self; +} +/* + * Function __irlan_close (self) + * + * This function closes and deallocates the IrLAN client instances. Be + * aware that other functions which calls client_close() must + * remove self from irlans list first. + */ +static void __irlan_close(struct irlan_cb *self) +{ + ASSERT_RTNL(); + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); + + del_timer_sync(&self->watchdog_timer); + del_timer_sync(&self->client.kick_timer); + + /* Close all open connections and remove TSAPs */ + irlan_close_tsaps(self); + + if (self->client.iriap) + iriap_close(self->client.iriap); + + /* Remove frames queued on the control channel */ + skb_queue_purge(&self->client.txq); + + /* Unregister and free self via destructor */ + unregister_netdevice(self->dev); +} + +/* Find any instance of irlan, used for client discovery wakeup */ +struct irlan_cb *irlan_get_any(void) +{ + struct irlan_cb *self; + + list_for_each_entry_rcu(self, &irlans, dev_list) { + return self; + } + return NULL; +} + +/* + * Function irlan_connect_indication (instance, sap, qos, max_sdu_size, skb) + * + * Here we receive the connect indication for the data channel + * + */ +static void irlan_connect_indication(void *instance, void *sap, + struct qos_info *qos, + __u32 max_sdu_size, + __u8 max_header_size, + struct sk_buff *skb) +{ + struct irlan_cb *self; + struct tsap_cb *tsap; + + self = instance; + tsap = sap; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); + IRDA_ASSERT(tsap == self->tsap_data,return;); + + self->max_sdu_size = max_sdu_size; + self->max_header_size = max_header_size; + + pr_debug("%s: We are now connected!\n", __func__); + + del_timer(&self->watchdog_timer); + + /* If you want to pass the skb to *both* state machines, you will + * need to skb_clone() it, so that you don't free it twice. + * As the state machines don't need it, git rid of it here... + * Jean II */ + if (skb) + dev_kfree_skb(skb); + + irlan_do_provider_event(self, IRLAN_DATA_CONNECT_INDICATION, NULL); + irlan_do_client_event(self, IRLAN_DATA_CONNECT_INDICATION, NULL); + + if (self->provider.access_type == ACCESS_PEER) { + /* + * Data channel is open, so we are now allowed to + * configure the remote filter + */ + irlan_get_unicast_addr(self); + irlan_open_unicast_addr(self); + } + /* Ready to transfer Ethernet frames (at last) */ + netif_start_queue(self->dev); /* Clear reason */ +} + +static void irlan_connect_confirm(void *instance, void *sap, + struct qos_info *qos, + __u32 max_sdu_size, + __u8 max_header_size, + struct sk_buff *skb) +{ + struct irlan_cb *self; + + self = instance; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); + + self->max_sdu_size = max_sdu_size; + self->max_header_size = max_header_size; + + /* TODO: we could set the MTU depending on the max_sdu_size */ + + pr_debug("%s: We are now connected!\n", __func__); + del_timer(&self->watchdog_timer); + + /* + * Data channel is open, so we are now allowed to configure the remote + * filter + */ + irlan_get_unicast_addr(self); + irlan_open_unicast_addr(self); + + /* Open broadcast and multicast filter by default */ + irlan_set_broadcast_filter(self, TRUE); + irlan_set_multicast_filter(self, TRUE); + + /* Ready to transfer Ethernet frames */ + netif_start_queue(self->dev); + self->disconnect_reason = 0; /* Clear reason */ + wake_up_interruptible(&self->open_wait); +} + +/* + * Function irlan_client_disconnect_indication (handle) + * + * Callback function for the IrTTP layer. Indicates a disconnection of + * the specified connection (handle) + */ +static void irlan_disconnect_indication(void *instance, + void *sap, LM_REASON reason, + struct sk_buff *userdata) +{ + struct irlan_cb *self; + struct tsap_cb *tsap; + + pr_debug("%s(), reason=%d\n", __func__ , reason); + + self = instance; + tsap = sap; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); + IRDA_ASSERT(tsap != NULL, return;); + IRDA_ASSERT(tsap->magic == TTP_TSAP_MAGIC, return;); + + IRDA_ASSERT(tsap == self->tsap_data, return;); + + pr_debug("IrLAN, data channel disconnected by peer!\n"); + + /* Save reason so we know if we should try to reconnect or not */ + self->disconnect_reason = reason; + + switch (reason) { + case LM_USER_REQUEST: /* User request */ + pr_debug("%s(), User requested\n", __func__); + break; + case LM_LAP_DISCONNECT: /* Unexpected IrLAP disconnect */ + pr_debug("%s(), Unexpected IrLAP disconnect\n", __func__); + break; + case LM_CONNECT_FAILURE: /* Failed to establish IrLAP connection */ + pr_debug("%s(), IrLAP connect failed\n", __func__); + break; + case LM_LAP_RESET: /* IrLAP reset */ + pr_debug("%s(), IrLAP reset\n", __func__); + break; + case LM_INIT_DISCONNECT: + pr_debug("%s(), IrLMP connect failed\n", __func__); + break; + default: + net_err_ratelimited("%s(), Unknown disconnect reason\n", + __func__); + break; + } + + /* If you want to pass the skb to *both* state machines, you will + * need to skb_clone() it, so that you don't free it twice. + * As the state machines don't need it, git rid of it here... + * Jean II */ + if (userdata) + dev_kfree_skb(userdata); + + irlan_do_client_event(self, IRLAN_LMP_DISCONNECT, NULL); + irlan_do_provider_event(self, IRLAN_LMP_DISCONNECT, NULL); + + wake_up_interruptible(&self->open_wait); +} + +void irlan_open_data_tsap(struct irlan_cb *self) +{ + struct tsap_cb *tsap; + notify_t notify; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); + + /* Check if already open */ + if (self->tsap_data) + return; + + irda_notify_init(¬ify); + + notify.data_indication = irlan_eth_receive; + notify.udata_indication = irlan_eth_receive; + notify.connect_indication = irlan_connect_indication; + notify.connect_confirm = irlan_connect_confirm; + notify.flow_indication = irlan_eth_flow_indication; + notify.disconnect_indication = irlan_disconnect_indication; + notify.instance = self; + strlcpy(notify.name, "IrLAN data", sizeof(notify.name)); + + tsap = irttp_open_tsap(LSAP_ANY, DEFAULT_INITIAL_CREDIT, ¬ify); + if (!tsap) { + pr_debug("%s(), Got no tsap!\n", __func__); + return; + } + self->tsap_data = tsap; + + /* + * This is the data TSAP selector which we will pass to the client + * when the client ask for it. + */ + self->stsap_sel_data = self->tsap_data->stsap_sel; +} + +void irlan_close_tsaps(struct irlan_cb *self) +{ + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); + + /* Disconnect and close all open TSAP connections */ + if (self->tsap_data) { + irttp_disconnect_request(self->tsap_data, NULL, P_NORMAL); + irttp_close_tsap(self->tsap_data); + self->tsap_data = NULL; + } + if (self->client.tsap_ctrl) { + irttp_disconnect_request(self->client.tsap_ctrl, NULL, + P_NORMAL); + irttp_close_tsap(self->client.tsap_ctrl); + self->client.tsap_ctrl = NULL; + } + if (self->provider.tsap_ctrl) { + irttp_disconnect_request(self->provider.tsap_ctrl, NULL, + P_NORMAL); + irttp_close_tsap(self->provider.tsap_ctrl); + self->provider.tsap_ctrl = NULL; + } + self->disconnect_reason = LM_USER_REQUEST; +} + +/* + * Function irlan_ias_register (self, tsap_sel) + * + * Register with LM-IAS + * + */ +void irlan_ias_register(struct irlan_cb *self, __u8 tsap_sel) +{ + struct ias_object *obj; + struct ias_value *new_value; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); + + /* + * Check if object has already been registered by a previous provider. + * If that is the case, we just change the value of the attribute + */ + if (!irias_find_object("IrLAN")) { + obj = irias_new_object("IrLAN", IAS_IRLAN_ID); + irias_add_integer_attrib(obj, "IrDA:TinyTP:LsapSel", tsap_sel, + IAS_KERNEL_ATTR); + irias_insert_object(obj); + } else { + new_value = irias_new_integer_value(tsap_sel); + irias_object_change_attribute("IrLAN", "IrDA:TinyTP:LsapSel", + new_value); + } + + /* Register PnP object only if not registered before */ + if (!irias_find_object("PnP")) { + obj = irias_new_object("PnP", IAS_PNP_ID); +#if 0 + irias_add_string_attrib(obj, "Name", sysctl_devname, + IAS_KERNEL_ATTR); +#else + irias_add_string_attrib(obj, "Name", "Linux", IAS_KERNEL_ATTR); +#endif + irias_add_string_attrib(obj, "DeviceID", "HWP19F0", + IAS_KERNEL_ATTR); + irias_add_integer_attrib(obj, "CompCnt", 1, IAS_KERNEL_ATTR); + if (self->provider.access_type == ACCESS_PEER) + irias_add_string_attrib(obj, "Comp#01", "PNP8389", + IAS_KERNEL_ATTR); + else + irias_add_string_attrib(obj, "Comp#01", "PNP8294", + IAS_KERNEL_ATTR); + + irias_add_string_attrib(obj, "Manufacturer", + "Linux-IrDA Project", IAS_KERNEL_ATTR); + irias_insert_object(obj); + } +} + +/* + * Function irlan_run_ctrl_tx_queue (self) + * + * Try to send the next command in the control transmit queue + * + */ +int irlan_run_ctrl_tx_queue(struct irlan_cb *self) +{ + struct sk_buff *skb; + + if (irda_lock(&self->client.tx_busy) == FALSE) + return -EBUSY; + + skb = skb_dequeue(&self->client.txq); + if (!skb) { + self->client.tx_busy = FALSE; + return 0; + } + + /* Check that it's really possible to send commands */ + if ((self->client.tsap_ctrl == NULL) || + (self->client.state == IRLAN_IDLE)) + { + self->client.tx_busy = FALSE; + dev_kfree_skb(skb); + return -1; + } + pr_debug("%s(), sending ...\n", __func__); + + return irttp_data_request(self->client.tsap_ctrl, skb); +} + +/* + * Function irlan_ctrl_data_request (self, skb) + * + * This function makes sure that commands on the control channel is being + * sent in a command/response fashion + */ +static void irlan_ctrl_data_request(struct irlan_cb *self, struct sk_buff *skb) +{ + /* Queue command */ + skb_queue_tail(&self->client.txq, skb); + + /* Try to send command */ + irlan_run_ctrl_tx_queue(self); +} + +/* + * Function irlan_get_provider_info (self) + * + * Send Get Provider Information command to peer IrLAN layer + * + */ +void irlan_get_provider_info(struct irlan_cb *self) +{ + struct sk_buff *skb; + __u8 *frame; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); + + skb = alloc_skb(IRLAN_MAX_HEADER + IRLAN_CMD_HEADER, + GFP_ATOMIC); + if (!skb) + return; + + /* Reserve space for TTP, LMP, and LAP header */ + skb_reserve(skb, self->client.max_header_size); + skb_put(skb, 2); + + frame = skb->data; + + frame[0] = CMD_GET_PROVIDER_INFO; + frame[1] = 0x00; /* Zero parameters */ + + irlan_ctrl_data_request(self, skb); +} + +/* + * Function irlan_open_data_channel (self) + * + * Send an Open Data Command to provider + * + */ +void irlan_open_data_channel(struct irlan_cb *self) +{ + struct sk_buff *skb; + __u8 *frame; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); + + skb = alloc_skb(IRLAN_MAX_HEADER + IRLAN_CMD_HEADER + + IRLAN_STRING_PARAMETER_LEN("MEDIA", "802.3") + + IRLAN_STRING_PARAMETER_LEN("ACCESS_TYPE", "DIRECT"), + GFP_ATOMIC); + if (!skb) + return; + + skb_reserve(skb, self->client.max_header_size); + skb_put(skb, 2); + + frame = skb->data; + + /* Build frame */ + frame[0] = CMD_OPEN_DATA_CHANNEL; + frame[1] = 0x02; /* Two parameters */ + + irlan_insert_string_param(skb, "MEDIA", "802.3"); + irlan_insert_string_param(skb, "ACCESS_TYPE", "DIRECT"); + /* irlan_insert_string_param(skb, "MODE", "UNRELIABLE"); */ + +/* self->use_udata = TRUE; */ + + irlan_ctrl_data_request(self, skb); +} + +void irlan_close_data_channel(struct irlan_cb *self) +{ + struct sk_buff *skb; + __u8 *frame; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); + + /* Check if the TSAP is still there */ + if (self->client.tsap_ctrl == NULL) + return; + + skb = alloc_skb(IRLAN_MAX_HEADER + IRLAN_CMD_HEADER + + IRLAN_BYTE_PARAMETER_LEN("DATA_CHAN"), + GFP_ATOMIC); + if (!skb) + return; + + skb_reserve(skb, self->client.max_header_size); + skb_put(skb, 2); + + frame = skb->data; + + /* Build frame */ + frame[0] = CMD_CLOSE_DATA_CHAN; + frame[1] = 0x01; /* One parameter */ + + irlan_insert_byte_param(skb, "DATA_CHAN", self->dtsap_sel_data); + + irlan_ctrl_data_request(self, skb); +} + +/* + * Function irlan_open_unicast_addr (self) + * + * Make IrLAN provider accept ethernet frames addressed to the unicast + * address. + * + */ +static void irlan_open_unicast_addr(struct irlan_cb *self) +{ + struct sk_buff *skb; + __u8 *frame; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); + + skb = alloc_skb(IRLAN_MAX_HEADER + IRLAN_CMD_HEADER + + IRLAN_BYTE_PARAMETER_LEN("DATA_CHAN") + + IRLAN_STRING_PARAMETER_LEN("FILTER_TYPE", "DIRECTED") + + IRLAN_STRING_PARAMETER_LEN("FILTER_MODE", "FILTER"), + GFP_ATOMIC); + if (!skb) + return; + + /* Reserve space for TTP, LMP, and LAP header */ + skb_reserve(skb, self->max_header_size); + skb_put(skb, 2); + + frame = skb->data; + + frame[0] = CMD_FILTER_OPERATION; + frame[1] = 0x03; /* Three parameters */ + irlan_insert_byte_param(skb, "DATA_CHAN" , self->dtsap_sel_data); + irlan_insert_string_param(skb, "FILTER_TYPE", "DIRECTED"); + irlan_insert_string_param(skb, "FILTER_MODE", "FILTER"); + + irlan_ctrl_data_request(self, skb); +} + +/* + * Function irlan_set_broadcast_filter (self, status) + * + * Make IrLAN provider accept ethernet frames addressed to the broadcast + * address. Be careful with the use of this one, since there may be a lot + * of broadcast traffic out there. We can still function without this + * one but then _we_ have to initiate all communication with other + * hosts, since ARP request for this host will not be answered. + */ +void irlan_set_broadcast_filter(struct irlan_cb *self, int status) +{ + struct sk_buff *skb; + __u8 *frame; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); + + skb = alloc_skb(IRLAN_MAX_HEADER + IRLAN_CMD_HEADER + + IRLAN_BYTE_PARAMETER_LEN("DATA_CHAN") + + IRLAN_STRING_PARAMETER_LEN("FILTER_TYPE", "BROADCAST") + + /* We may waste one byte here...*/ + IRLAN_STRING_PARAMETER_LEN("FILTER_MODE", "FILTER"), + GFP_ATOMIC); + if (!skb) + return; + + /* Reserve space for TTP, LMP, and LAP header */ + skb_reserve(skb, self->client.max_header_size); + skb_put(skb, 2); + + frame = skb->data; + + frame[0] = CMD_FILTER_OPERATION; + frame[1] = 0x03; /* Three parameters */ + irlan_insert_byte_param(skb, "DATA_CHAN", self->dtsap_sel_data); + irlan_insert_string_param(skb, "FILTER_TYPE", "BROADCAST"); + if (status) + irlan_insert_string_param(skb, "FILTER_MODE", "FILTER"); + else + irlan_insert_string_param(skb, "FILTER_MODE", "NONE"); + + irlan_ctrl_data_request(self, skb); +} + +/* + * Function irlan_set_multicast_filter (self, status) + * + * Make IrLAN provider accept ethernet frames addressed to the multicast + * address. + * + */ +void irlan_set_multicast_filter(struct irlan_cb *self, int status) +{ + struct sk_buff *skb; + __u8 *frame; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); + + skb = alloc_skb(IRLAN_MAX_HEADER + IRLAN_CMD_HEADER + + IRLAN_BYTE_PARAMETER_LEN("DATA_CHAN") + + IRLAN_STRING_PARAMETER_LEN("FILTER_TYPE", "MULTICAST") + + /* We may waste one byte here...*/ + IRLAN_STRING_PARAMETER_LEN("FILTER_MODE", "NONE"), + GFP_ATOMIC); + if (!skb) + return; + + /* Reserve space for TTP, LMP, and LAP header */ + skb_reserve(skb, self->client.max_header_size); + skb_put(skb, 2); + + frame = skb->data; + + frame[0] = CMD_FILTER_OPERATION; + frame[1] = 0x03; /* Three parameters */ + irlan_insert_byte_param(skb, "DATA_CHAN", self->dtsap_sel_data); + irlan_insert_string_param(skb, "FILTER_TYPE", "MULTICAST"); + if (status) + irlan_insert_string_param(skb, "FILTER_MODE", "ALL"); + else + irlan_insert_string_param(skb, "FILTER_MODE", "NONE"); + + irlan_ctrl_data_request(self, skb); +} + +/* + * Function irlan_get_unicast_addr (self) + * + * Retrieves the unicast address from the IrLAN provider. This address + * will be inserted into the devices structure, so the ethernet layer + * can construct its packets. + * + */ +static void irlan_get_unicast_addr(struct irlan_cb *self) +{ + struct sk_buff *skb; + __u8 *frame; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); + + skb = alloc_skb(IRLAN_MAX_HEADER + IRLAN_CMD_HEADER + + IRLAN_BYTE_PARAMETER_LEN("DATA_CHAN") + + IRLAN_STRING_PARAMETER_LEN("FILTER_TYPE", "DIRECTED") + + IRLAN_STRING_PARAMETER_LEN("FILTER_OPERATION", + "DYNAMIC"), + GFP_ATOMIC); + if (!skb) + return; + + /* Reserve space for TTP, LMP, and LAP header */ + skb_reserve(skb, self->client.max_header_size); + skb_put(skb, 2); + + frame = skb->data; + + frame[0] = CMD_FILTER_OPERATION; + frame[1] = 0x03; /* Three parameters */ + irlan_insert_byte_param(skb, "DATA_CHAN", self->dtsap_sel_data); + irlan_insert_string_param(skb, "FILTER_TYPE", "DIRECTED"); + irlan_insert_string_param(skb, "FILTER_OPERATION", "DYNAMIC"); + + irlan_ctrl_data_request(self, skb); +} + +/* + * Function irlan_get_media_char (self) + * + * + * + */ +void irlan_get_media_char(struct irlan_cb *self) +{ + struct sk_buff *skb; + __u8 *frame; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); + + skb = alloc_skb(IRLAN_MAX_HEADER + IRLAN_CMD_HEADER + + IRLAN_STRING_PARAMETER_LEN("MEDIA", "802.3"), + GFP_ATOMIC); + + if (!skb) + return; + + /* Reserve space for TTP, LMP, and LAP header */ + skb_reserve(skb, self->client.max_header_size); + skb_put(skb, 2); + + frame = skb->data; + + /* Build frame */ + frame[0] = CMD_GET_MEDIA_CHAR; + frame[1] = 0x01; /* One parameter */ + + irlan_insert_string_param(skb, "MEDIA", "802.3"); + irlan_ctrl_data_request(self, skb); +} + +/* + * Function insert_byte_param (skb, param, value) + * + * Insert byte parameter into frame + * + */ +int irlan_insert_byte_param(struct sk_buff *skb, char *param, __u8 value) +{ + return __irlan_insert_param(skb, param, IRLAN_BYTE, value, 0, NULL, 0); +} + +int irlan_insert_short_param(struct sk_buff *skb, char *param, __u16 value) +{ + return __irlan_insert_param(skb, param, IRLAN_SHORT, 0, value, NULL, 0); +} + +/* + * Function insert_string (skb, param, value) + * + * Insert string parameter into frame + * + */ +int irlan_insert_string_param(struct sk_buff *skb, char *param, char *string) +{ + int string_len = strlen(string); + + return __irlan_insert_param(skb, param, IRLAN_ARRAY, 0, 0, string, + string_len); +} + +/* + * Function insert_array_param(skb, param, value, len_value) + * + * Insert array parameter into frame + * + */ +int irlan_insert_array_param(struct sk_buff *skb, char *name, __u8 *array, + __u16 array_len) +{ + return __irlan_insert_param(skb, name, IRLAN_ARRAY, 0, 0, array, + array_len); +} + +/* + * Function insert_param (skb, param, value, byte) + * + * Insert parameter at end of buffer, structure of a parameter is: + * + * ----------------------------------------------------------------------- + * | Name Length[1] | Param Name[1..255] | Val Length[2] | Value[0..1016]| + * ----------------------------------------------------------------------- + */ +static int __irlan_insert_param(struct sk_buff *skb, char *param, int type, + __u8 value_byte, __u16 value_short, + __u8 *value_array, __u16 value_len) +{ + __u8 *frame; + __u8 param_len; + __le16 tmp_le; /* Temporary value in little endian format */ + int n=0; + + if (skb == NULL) { + pr_debug("%s(), Got NULL skb\n", __func__); + return 0; + } + + param_len = strlen(param); + switch (type) { + case IRLAN_BYTE: + value_len = 1; + break; + case IRLAN_SHORT: + value_len = 2; + break; + case IRLAN_ARRAY: + IRDA_ASSERT(value_array != NULL, return 0;); + IRDA_ASSERT(value_len > 0, return 0;); + break; + default: + pr_debug("%s(), Unknown parameter type!\n", __func__); + return 0; + } + + /* Insert at end of sk-buffer */ + frame = skb_tail_pointer(skb); + + /* Make space for data */ + if (skb_tailroom(skb) < (param_len+value_len+3)) { + pr_debug("%s(), No more space at end of skb\n", __func__); + return 0; + } + skb_put(skb, param_len+value_len+3); + + /* Insert parameter length */ + frame[n++] = param_len; + + /* Insert parameter */ + memcpy(frame+n, param, param_len); n += param_len; + + /* Insert value length (2 byte little endian format, LSB first) */ + tmp_le = cpu_to_le16(value_len); + memcpy(frame+n, &tmp_le, 2); n += 2; /* To avoid alignment problems */ + + /* Insert value */ + switch (type) { + case IRLAN_BYTE: + frame[n++] = value_byte; + break; + case IRLAN_SHORT: + tmp_le = cpu_to_le16(value_short); + memcpy(frame+n, &tmp_le, 2); n += 2; + break; + case IRLAN_ARRAY: + memcpy(frame+n, value_array, value_len); n+=value_len; + break; + default: + break; + } + IRDA_ASSERT(n == (param_len+value_len+3), return 0;); + + return param_len+value_len+3; +} + +/* + * Function irlan_extract_param (buf, name, value, len) + * + * Extracts a single parameter name/value pair from buffer and updates + * the buffer pointer to point to the next name/value pair. + */ +int irlan_extract_param(__u8 *buf, char *name, char *value, __u16 *len) +{ + __u8 name_len; + __u16 val_len; + int n=0; + + /* get length of parameter name (1 byte) */ + name_len = buf[n++]; + + if (name_len > 254) { + pr_debug("%s(), name_len > 254\n", __func__); + return -RSP_INVALID_COMMAND_FORMAT; + } + + /* get parameter name */ + memcpy(name, buf+n, name_len); + name[name_len] = '\0'; + n+=name_len; + + /* + * Get length of parameter value (2 bytes in little endian + * format) + */ + memcpy(&val_len, buf+n, 2); /* To avoid alignment problems */ + le16_to_cpus(&val_len); n+=2; + + if (val_len >= 1016) { + pr_debug("%s(), parameter length to long\n", __func__); + return -RSP_INVALID_COMMAND_FORMAT; + } + *len = val_len; + + /* get parameter value */ + memcpy(value, buf+n, val_len); + value[val_len] = '\0'; + n+=val_len; + + pr_debug("Parameter: %s ", name); + pr_debug("Value: %s\n", value); + + return n; +} + +#ifdef CONFIG_PROC_FS + +/* + * Start of reading /proc entries. + * Return entry at pos, + * or start_token to indicate print header line + * or NULL if end of file + */ +static void *irlan_seq_start(struct seq_file *seq, loff_t *pos) +{ + rcu_read_lock(); + return seq_list_start_head(&irlans, *pos); +} + +/* Return entry after v, and increment pos */ +static void *irlan_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + return seq_list_next(v, &irlans, pos); +} + +/* End of reading /proc file */ +static void irlan_seq_stop(struct seq_file *seq, void *v) +{ + rcu_read_unlock(); +} + + +/* + * Show one entry in /proc file. + */ +static int irlan_seq_show(struct seq_file *seq, void *v) +{ + if (v == &irlans) + seq_puts(seq, "IrLAN instances:\n"); + else { + struct irlan_cb *self = list_entry(v, struct irlan_cb, dev_list); + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;); + + seq_printf(seq,"ifname: %s,\n", + self->dev->name); + seq_printf(seq,"client state: %s, ", + irlan_state[ self->client.state]); + seq_printf(seq,"provider state: %s,\n", + irlan_state[ self->provider.state]); + seq_printf(seq,"saddr: %#08x, ", + self->saddr); + seq_printf(seq,"daddr: %#08x\n", + self->daddr); + seq_printf(seq,"version: %d.%d,\n", + self->version[1], self->version[0]); + seq_printf(seq,"access type: %s\n", + irlan_access[self->client.access_type]); + seq_printf(seq,"media: %s\n", + irlan_media[self->media]); + + seq_printf(seq,"local filter:\n"); + seq_printf(seq,"remote filter: "); + irlan_print_filter(seq, self->client.filter_type); + seq_printf(seq,"tx busy: %s\n", + netif_queue_stopped(self->dev) ? "TRUE" : "FALSE"); + + seq_putc(seq,'\n'); + } + return 0; +} + +static const struct seq_operations irlan_seq_ops = { + .start = irlan_seq_start, + .next = irlan_seq_next, + .stop = irlan_seq_stop, + .show = irlan_seq_show, +}; + +static int irlan_seq_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &irlan_seq_ops); +} +#endif + +MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>"); +MODULE_DESCRIPTION("The Linux IrDA LAN protocol"); +MODULE_LICENSE("GPL"); + +module_param(eth, bool, 0); +MODULE_PARM_DESC(eth, "Name devices ethX (0) or irlanX (1)"); +module_param(access, int, 0); +MODULE_PARM_DESC(access, "Access type DIRECT=1, PEER=2, HOSTED=3"); + +module_init(irlan_init); +module_exit(irlan_cleanup); + diff --git a/drivers/staging/irda/net/irlan/irlan_eth.c b/drivers/staging/irda/net/irlan/irlan_eth.c new file mode 100644 index 000000000000..3be852808a9d --- /dev/null +++ b/drivers/staging/irda/net/irlan/irlan_eth.c @@ -0,0 +1,340 @@ +/********************************************************************* + * + * Filename: irlan_eth.c + * Version: + * Description: + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Thu Oct 15 08:37:58 1998 + * Modified at: Tue Mar 21 09:06:41 2000 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * Sources: skeleton.c by Donald Becker <becker@CESDIS.gsfc.nasa.gov> + * slip.c by Laurence Culhane, <loz@holmes.demon.co.uk> + * Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org> + * + * Copyright (c) 1998-2000 Dag Brattli, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/inetdevice.h> +#include <linux/if_arp.h> +#include <linux/module.h> +#include <linux/sched.h> +#include <net/arp.h> + +#include <net/irda/irda.h> +#include <net/irda/irmod.h> +#include <net/irda/irlan_common.h> +#include <net/irda/irlan_client.h> +#include <net/irda/irlan_event.h> +#include <net/irda/irlan_eth.h> + +static int irlan_eth_open(struct net_device *dev); +static int irlan_eth_close(struct net_device *dev); +static netdev_tx_t irlan_eth_xmit(struct sk_buff *skb, + struct net_device *dev); +static void irlan_eth_set_multicast_list(struct net_device *dev); + +static const struct net_device_ops irlan_eth_netdev_ops = { + .ndo_open = irlan_eth_open, + .ndo_stop = irlan_eth_close, + .ndo_start_xmit = irlan_eth_xmit, + .ndo_set_rx_mode = irlan_eth_set_multicast_list, + .ndo_validate_addr = eth_validate_addr, +}; + +/* + * Function irlan_eth_setup (dev) + * + * The network device initialization function. + * + */ +static void irlan_eth_setup(struct net_device *dev) +{ + ether_setup(dev); + + dev->netdev_ops = &irlan_eth_netdev_ops; + dev->needs_free_netdev = true; + dev->min_mtu = 0; + dev->max_mtu = ETH_MAX_MTU; + + /* + * Lets do all queueing in IrTTP instead of this device driver. + * Queueing here as well can introduce some strange latency + * problems, which we will avoid by setting the queue size to 0. + */ + /* + * The bugs in IrTTP and IrLAN that created this latency issue + * have now been fixed, and we can propagate flow control properly + * to the network layer. However, this requires a minimal queue of + * packets for the device. + * Without flow control, the Tx Queue is 14 (ttp) + 0 (dev) = 14 + * With flow control, the Tx Queue is 7 (ttp) + 4 (dev) = 11 + * See irlan_eth_flow_indication()... + * Note : this number was randomly selected and would need to + * be adjusted. + * Jean II */ + dev->tx_queue_len = 4; +} + +/* + * Function alloc_irlandev + * + * Allocate network device and control block + * + */ +struct net_device *alloc_irlandev(const char *name) +{ + return alloc_netdev(sizeof(struct irlan_cb), name, NET_NAME_UNKNOWN, + irlan_eth_setup); +} + +/* + * Function irlan_eth_open (dev) + * + * Network device has been opened by user + * + */ +static int irlan_eth_open(struct net_device *dev) +{ + struct irlan_cb *self = netdev_priv(dev); + + /* Ready to play! */ + netif_stop_queue(dev); /* Wait until data link is ready */ + + /* We are now open, so time to do some work */ + self->disconnect_reason = 0; + irlan_client_wakeup(self, self->saddr, self->daddr); + + /* Make sure we have a hardware address before we return, + so DHCP clients gets happy */ + return wait_event_interruptible(self->open_wait, + !self->tsap_data->connected); +} + +/* + * Function irlan_eth_close (dev) + * + * Stop the ether network device, his function will usually be called by + * ifconfig down. We should now disconnect the link, We start the + * close timer, so that the instance will be removed if we are unable + * to discover the remote device after the disconnect. + */ +static int irlan_eth_close(struct net_device *dev) +{ + struct irlan_cb *self = netdev_priv(dev); + + /* Stop device */ + netif_stop_queue(dev); + + irlan_close_data_channel(self); + irlan_close_tsaps(self); + + irlan_do_client_event(self, IRLAN_LMP_DISCONNECT, NULL); + irlan_do_provider_event(self, IRLAN_LMP_DISCONNECT, NULL); + + /* Remove frames queued on the control channel */ + skb_queue_purge(&self->client.txq); + + self->client.tx_busy = 0; + + return 0; +} + +/* + * Function irlan_eth_tx (skb) + * + * Transmits ethernet frames over IrDA link. + * + */ +static netdev_tx_t irlan_eth_xmit(struct sk_buff *skb, + struct net_device *dev) +{ + struct irlan_cb *self = netdev_priv(dev); + int ret; + unsigned int len; + + /* skb headroom large enough to contain all IrDA-headers? */ + if ((skb_headroom(skb) < self->max_header_size) || (skb_shared(skb))) { + struct sk_buff *new_skb = + skb_realloc_headroom(skb, self->max_header_size); + + /* We have to free the original skb anyway */ + dev_kfree_skb(skb); + + /* Did the realloc succeed? */ + if (new_skb == NULL) + return NETDEV_TX_OK; + + /* Use the new skb instead */ + skb = new_skb; + } + + netif_trans_update(dev); + + len = skb->len; + /* Now queue the packet in the transport layer */ + if (self->use_udata) + ret = irttp_udata_request(self->tsap_data, skb); + else + ret = irttp_data_request(self->tsap_data, skb); + + if (ret < 0) { + /* + * IrTTPs tx queue is full, so we just have to + * drop the frame! You might think that we should + * just return -1 and don't deallocate the frame, + * but that is dangerous since it's possible that + * we have replaced the original skb with a new + * one with larger headroom, and that would really + * confuse do_dev_queue_xmit() in dev.c! I have + * tried :-) DB + */ + /* irttp_data_request already free the packet */ + dev->stats.tx_dropped++; + } else { + dev->stats.tx_packets++; + dev->stats.tx_bytes += len; + } + + return NETDEV_TX_OK; +} + +/* + * Function irlan_eth_receive (handle, skb) + * + * This function gets the data that is received on the data channel + * + */ +int irlan_eth_receive(void *instance, void *sap, struct sk_buff *skb) +{ + struct irlan_cb *self = instance; + struct net_device *dev = self->dev; + + if (skb == NULL) { + dev->stats.rx_dropped++; + return 0; + } + if (skb->len < ETH_HLEN) { + pr_debug("%s() : IrLAN frame too short (%d)\n", + __func__, skb->len); + dev->stats.rx_dropped++; + dev_kfree_skb(skb); + return 0; + } + + /* + * Adopt this frame! Important to set all these fields since they + * might have been previously set by the low level IrDA network + * device driver + */ + skb->protocol = eth_type_trans(skb, dev); /* Remove eth header */ + + dev->stats.rx_packets++; + dev->stats.rx_bytes += skb->len; + + netif_rx(skb); /* Eat it! */ + + return 0; +} + +/* + * Function irlan_eth_flow (status) + * + * Do flow control between IP/Ethernet and IrLAN/IrTTP. This is done by + * controlling the queue stop/start. + * + * The IrDA link layer has the advantage to have flow control, and + * IrTTP now properly handles that. Flow controlling the higher layers + * prevent us to drop Tx packets in here (up to 15% for a TCP socket, + * more for UDP socket). + * Also, this allow us to reduce the overall transmit queue, which means + * less latency in case of mixed traffic. + * Jean II + */ +void irlan_eth_flow_indication(void *instance, void *sap, LOCAL_FLOW flow) +{ + struct irlan_cb *self; + struct net_device *dev; + + self = instance; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); + + dev = self->dev; + + IRDA_ASSERT(dev != NULL, return;); + + pr_debug("%s() : flow %s ; running %d\n", __func__, + flow == FLOW_STOP ? "FLOW_STOP" : "FLOW_START", + netif_running(dev)); + + switch (flow) { + case FLOW_STOP: + /* IrTTP is full, stop higher layers */ + netif_stop_queue(dev); + break; + case FLOW_START: + default: + /* Tell upper layers that its time to transmit frames again */ + /* Schedule network layer */ + netif_wake_queue(dev); + break; + } +} + +/* + * Function set_multicast_list (dev) + * + * Configure the filtering of the device + * + */ +#define HW_MAX_ADDRS 4 /* Must query to get it! */ +static void irlan_eth_set_multicast_list(struct net_device *dev) +{ + struct irlan_cb *self = netdev_priv(dev); + + /* Check if data channel has been connected yet */ + if (self->client.state != IRLAN_DATA) { + pr_debug("%s(), delaying!\n", __func__); + return; + } + + if (dev->flags & IFF_PROMISC) { + /* Enable promiscuous mode */ + net_warn_ratelimited("Promiscuous mode not implemented by IrLAN!\n"); + } else if ((dev->flags & IFF_ALLMULTI) || + netdev_mc_count(dev) > HW_MAX_ADDRS) { + /* Disable promiscuous mode, use normal mode. */ + pr_debug("%s(), Setting multicast filter\n", __func__); + /* hardware_set_filter(NULL); */ + + irlan_set_multicast_filter(self, TRUE); + } else if (!netdev_mc_empty(dev)) { + pr_debug("%s(), Setting multicast filter\n", __func__); + /* Walk the address list, and load the filter */ + /* hardware_set_filter(dev->mc_list); */ + + irlan_set_multicast_filter(self, TRUE); + } else { + pr_debug("%s(), Clearing multicast filter\n", __func__); + irlan_set_multicast_filter(self, FALSE); + } + + if (dev->flags & IFF_BROADCAST) + irlan_set_broadcast_filter(self, TRUE); + else + irlan_set_broadcast_filter(self, FALSE); +} diff --git a/drivers/staging/irda/net/irlan/irlan_event.c b/drivers/staging/irda/net/irlan/irlan_event.c new file mode 100644 index 000000000000..9a1cc11c16f6 --- /dev/null +++ b/drivers/staging/irda/net/irlan/irlan_event.c @@ -0,0 +1,60 @@ +/********************************************************************* + * + * Filename: irlan_event.c + * Version: + * Description: + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Tue Oct 20 09:10:16 1998 + * Modified at: Sat Oct 30 12:59:01 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#include <net/irda/irlan_event.h> + +const char * const irlan_state[] = { + "IRLAN_IDLE", + "IRLAN_QUERY", + "IRLAN_CONN", + "IRLAN_INFO", + "IRLAN_MEDIA", + "IRLAN_OPEN", + "IRLAN_WAIT", + "IRLAN_ARB", + "IRLAN_DATA", + "IRLAN_CLOSE", + "IRLAN_SYNC", +}; + +void irlan_next_client_state(struct irlan_cb *self, IRLAN_STATE state) +{ + pr_debug("%s(), %s\n", __func__ , irlan_state[state]); + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); + + self->client.state = state; +} + +void irlan_next_provider_state(struct irlan_cb *self, IRLAN_STATE state) +{ + pr_debug("%s(), %s\n", __func__ , irlan_state[state]); + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); + + self->provider.state = state; +} + diff --git a/drivers/staging/irda/net/irlan/irlan_filter.c b/drivers/staging/irda/net/irlan/irlan_filter.c new file mode 100644 index 000000000000..e755e90b2f26 --- /dev/null +++ b/drivers/staging/irda/net/irlan/irlan_filter.c @@ -0,0 +1,240 @@ +/********************************************************************* + * + * Filename: irlan_filter.c + * Version: + * Description: + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Fri Jan 29 11:16:38 1999 + * Modified at: Sat Oct 30 12:58:45 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#include <linux/skbuff.h> +#include <linux/random.h> +#include <linux/seq_file.h> + +#include <net/irda/irlan_common.h> +#include <net/irda/irlan_filter.h> + +/* + * Function irlan_filter_request (self, skb) + * + * Handle filter request from client peer device + * + */ +void irlan_filter_request(struct irlan_cb *self, struct sk_buff *skb) +{ + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); + + if ((self->provider.filter_type == IRLAN_DIRECTED) && + (self->provider.filter_operation == DYNAMIC)) + { + pr_debug("Giving peer a dynamic Ethernet address\n"); + self->provider.mac_address[0] = 0x40; + self->provider.mac_address[1] = 0x00; + self->provider.mac_address[2] = 0x00; + self->provider.mac_address[3] = 0x00; + + /* Use arbitration value to generate MAC address */ + if (self->provider.access_type == ACCESS_PEER) { + self->provider.mac_address[4] = + self->provider.send_arb_val & 0xff; + self->provider.mac_address[5] = + (self->provider.send_arb_val >> 8) & 0xff; + } else { + /* Just generate something for now */ + get_random_bytes(self->provider.mac_address+4, 1); + get_random_bytes(self->provider.mac_address+5, 1); + } + + skb->data[0] = 0x00; /* Success */ + skb->data[1] = 0x03; + irlan_insert_string_param(skb, "FILTER_MODE", "NONE"); + irlan_insert_short_param(skb, "MAX_ENTRY", 0x0001); + irlan_insert_array_param(skb, "FILTER_ENTRY", + self->provider.mac_address, 6); + return; + } + + if ((self->provider.filter_type == IRLAN_DIRECTED) && + (self->provider.filter_mode == FILTER)) + { + pr_debug("Directed filter on\n"); + skb->data[0] = 0x00; /* Success */ + skb->data[1] = 0x00; + return; + } + if ((self->provider.filter_type == IRLAN_DIRECTED) && + (self->provider.filter_mode == NONE)) + { + pr_debug("Directed filter off\n"); + skb->data[0] = 0x00; /* Success */ + skb->data[1] = 0x00; + return; + } + + if ((self->provider.filter_type == IRLAN_BROADCAST) && + (self->provider.filter_mode == FILTER)) + { + pr_debug("Broadcast filter on\n"); + skb->data[0] = 0x00; /* Success */ + skb->data[1] = 0x00; + return; + } + if ((self->provider.filter_type == IRLAN_BROADCAST) && + (self->provider.filter_mode == NONE)) + { + pr_debug("Broadcast filter off\n"); + skb->data[0] = 0x00; /* Success */ + skb->data[1] = 0x00; + return; + } + if ((self->provider.filter_type == IRLAN_MULTICAST) && + (self->provider.filter_mode == FILTER)) + { + pr_debug("Multicast filter on\n"); + skb->data[0] = 0x00; /* Success */ + skb->data[1] = 0x00; + return; + } + if ((self->provider.filter_type == IRLAN_MULTICAST) && + (self->provider.filter_mode == NONE)) + { + pr_debug("Multicast filter off\n"); + skb->data[0] = 0x00; /* Success */ + skb->data[1] = 0x00; + return; + } + if ((self->provider.filter_type == IRLAN_MULTICAST) && + (self->provider.filter_operation == GET)) + { + pr_debug("Multicast filter get\n"); + skb->data[0] = 0x00; /* Success? */ + skb->data[1] = 0x02; + irlan_insert_string_param(skb, "FILTER_MODE", "NONE"); + irlan_insert_short_param(skb, "MAX_ENTRY", 16); + return; + } + skb->data[0] = 0x00; /* Command not supported */ + skb->data[1] = 0x00; + + pr_debug("Not implemented!\n"); +} + +/* + * Function check_request_param (self, param, value) + * + * Check parameters in request from peer device + * + */ +void irlan_check_command_param(struct irlan_cb *self, char *param, char *value) +{ + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); + + pr_debug("%s, %s\n", param, value); + + /* + * This is experimental!! DB. + */ + if (strcmp(param, "MODE") == 0) { + self->use_udata = TRUE; + return; + } + + /* + * FILTER_TYPE + */ + if (strcmp(param, "FILTER_TYPE") == 0) { + if (strcmp(value, "DIRECTED") == 0) { + self->provider.filter_type = IRLAN_DIRECTED; + return; + } + if (strcmp(value, "MULTICAST") == 0) { + self->provider.filter_type = IRLAN_MULTICAST; + return; + } + if (strcmp(value, "BROADCAST") == 0) { + self->provider.filter_type = IRLAN_BROADCAST; + return; + } + } + /* + * FILTER_MODE + */ + if (strcmp(param, "FILTER_MODE") == 0) { + if (strcmp(value, "ALL") == 0) { + self->provider.filter_mode = ALL; + return; + } + if (strcmp(value, "FILTER") == 0) { + self->provider.filter_mode = FILTER; + return; + } + if (strcmp(value, "NONE") == 0) { + self->provider.filter_mode = FILTER; + return; + } + } + /* + * FILTER_OPERATION + */ + if (strcmp(param, "FILTER_OPERATION") == 0) { + if (strcmp(value, "DYNAMIC") == 0) { + self->provider.filter_operation = DYNAMIC; + return; + } + if (strcmp(value, "GET") == 0) { + self->provider.filter_operation = GET; + return; + } + } +} + +/* + * Function irlan_print_filter (filter_type, buf) + * + * Print status of filter. Used by /proc file system + * + */ +#ifdef CONFIG_PROC_FS +#define MASK2STR(m,s) { .mask = m, .str = s } + +void irlan_print_filter(struct seq_file *seq, int filter_type) +{ + static struct { + int mask; + const char *str; + } filter_mask2str[] = { + MASK2STR(IRLAN_DIRECTED, "DIRECTED"), + MASK2STR(IRLAN_FUNCTIONAL, "FUNCTIONAL"), + MASK2STR(IRLAN_GROUP, "GROUP"), + MASK2STR(IRLAN_MAC_FRAME, "MAC_FRAME"), + MASK2STR(IRLAN_MULTICAST, "MULTICAST"), + MASK2STR(IRLAN_BROADCAST, "BROADCAST"), + MASK2STR(IRLAN_IPX_SOCKET, "IPX_SOCKET"), + MASK2STR(0, NULL) + }, *p; + + for (p = filter_mask2str; p->str; p++) { + if (filter_type & p->mask) + seq_printf(seq, "%s ", p->str); + } + seq_putc(seq, '\n'); +} +#undef MASK2STR +#endif diff --git a/drivers/staging/irda/net/irlan/irlan_provider.c b/drivers/staging/irda/net/irlan/irlan_provider.c new file mode 100644 index 000000000000..15c292cf2644 --- /dev/null +++ b/drivers/staging/irda/net/irlan/irlan_provider.c @@ -0,0 +1,408 @@ +/********************************************************************* + * + * Filename: irlan_provider.c + * Version: 0.9 + * Description: IrDA LAN Access Protocol Implementation + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Sun Aug 31 20:14:37 1997 + * Modified at: Sat Oct 30 12:52:10 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * Sources: skeleton.c by Donald Becker <becker@CESDIS.gsfc.nasa.gov> + * slip.c by Laurence Culhane, <loz@holmes.demon.co.uk> + * Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org> + * + * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/errno.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/init.h> +#include <linux/random.h> +#include <linux/bitops.h> +#include <linux/slab.h> + +#include <asm/byteorder.h> + +#include <net/irda/irda.h> +#include <net/irda/irttp.h> +#include <net/irda/irlmp.h> +#include <net/irda/irias_object.h> +#include <net/irda/iriap.h> +#include <net/irda/timer.h> + +#include <net/irda/irlan_common.h> +#include <net/irda/irlan_eth.h> +#include <net/irda/irlan_event.h> +#include <net/irda/irlan_provider.h> +#include <net/irda/irlan_filter.h> +#include <net/irda/irlan_client.h> + +static void irlan_provider_connect_indication(void *instance, void *sap, + struct qos_info *qos, + __u32 max_sdu_size, + __u8 max_header_size, + struct sk_buff *skb); + +/* + * Function irlan_provider_control_data_indication (handle, skb) + * + * This function gets the data that is received on the control channel + * + */ +static int irlan_provider_data_indication(void *instance, void *sap, + struct sk_buff *skb) +{ + struct irlan_cb *self; + __u8 code; + + self = instance; + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;); + + IRDA_ASSERT(skb != NULL, return -1;); + + code = skb->data[0]; + switch(code) { + case CMD_GET_PROVIDER_INFO: + pr_debug("Got GET_PROVIDER_INFO command!\n"); + irlan_do_provider_event(self, IRLAN_GET_INFO_CMD, skb); + break; + + case CMD_GET_MEDIA_CHAR: + pr_debug("Got GET_MEDIA_CHAR command!\n"); + irlan_do_provider_event(self, IRLAN_GET_MEDIA_CMD, skb); + break; + case CMD_OPEN_DATA_CHANNEL: + pr_debug("Got OPEN_DATA_CHANNEL command!\n"); + irlan_do_provider_event(self, IRLAN_OPEN_DATA_CMD, skb); + break; + case CMD_FILTER_OPERATION: + pr_debug("Got FILTER_OPERATION command!\n"); + irlan_do_provider_event(self, IRLAN_FILTER_CONFIG_CMD, skb); + break; + case CMD_RECONNECT_DATA_CHAN: + pr_debug("%s(), Got RECONNECT_DATA_CHAN command\n", __func__); + pr_debug("%s(), NOT IMPLEMENTED\n", __func__); + break; + case CMD_CLOSE_DATA_CHAN: + pr_debug("Got CLOSE_DATA_CHAN command!\n"); + pr_debug("%s(), NOT IMPLEMENTED\n", __func__); + break; + default: + pr_debug("%s(), Unknown command!\n", __func__); + break; + } + return 0; +} + +/* + * Function irlan_provider_connect_indication (handle, skb, priv) + * + * Got connection from peer IrLAN client + * + */ +static void irlan_provider_connect_indication(void *instance, void *sap, + struct qos_info *qos, + __u32 max_sdu_size, + __u8 max_header_size, + struct sk_buff *skb) +{ + struct irlan_cb *self; + struct tsap_cb *tsap; + + self = instance; + tsap = sap; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); + + IRDA_ASSERT(tsap == self->provider.tsap_ctrl,return;); + IRDA_ASSERT(self->provider.state == IRLAN_IDLE, return;); + + self->provider.max_sdu_size = max_sdu_size; + self->provider.max_header_size = max_header_size; + + irlan_do_provider_event(self, IRLAN_CONNECT_INDICATION, NULL); + + /* + * If we are in peer mode, the client may not have got the discovery + * indication it needs to make progress. If the client is still in + * IDLE state, we must kick it. + */ + if ((self->provider.access_type == ACCESS_PEER) && + (self->client.state == IRLAN_IDLE)) + { + irlan_client_wakeup(self, self->saddr, self->daddr); + } +} + +/* + * Function irlan_provider_connect_response (handle) + * + * Accept incoming connection + * + */ +void irlan_provider_connect_response(struct irlan_cb *self, + struct tsap_cb *tsap) +{ + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); + + /* Just accept */ + irttp_connect_response(tsap, IRLAN_MTU, NULL); +} + +static void irlan_provider_disconnect_indication(void *instance, void *sap, + LM_REASON reason, + struct sk_buff *userdata) +{ + struct irlan_cb *self; + struct tsap_cb *tsap; + + pr_debug("%s(), reason=%d\n", __func__ , reason); + + self = instance; + tsap = sap; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); + IRDA_ASSERT(tsap != NULL, return;); + IRDA_ASSERT(tsap->magic == TTP_TSAP_MAGIC, return;); + + IRDA_ASSERT(tsap == self->provider.tsap_ctrl, return;); + + irlan_do_provider_event(self, IRLAN_LMP_DISCONNECT, NULL); +} + +/* + * Function irlan_parse_open_data_cmd (self, skb) + * + * + * + */ +int irlan_parse_open_data_cmd(struct irlan_cb *self, struct sk_buff *skb) +{ + int ret; + + ret = irlan_provider_parse_command(self, CMD_OPEN_DATA_CHANNEL, skb); + + /* Open data channel */ + irlan_open_data_tsap(self); + + return ret; +} + +/* + * Function parse_command (skb) + * + * Extract all parameters from received buffer, then feed them to + * check_params for parsing + * + */ +int irlan_provider_parse_command(struct irlan_cb *self, int cmd, + struct sk_buff *skb) +{ + __u8 *frame; + __u8 *ptr; + int count; + __u16 val_len; + int i; + char *name; + char *value; + int ret = RSP_SUCCESS; + + IRDA_ASSERT(skb != NULL, return -RSP_PROTOCOL_ERROR;); + + pr_debug("%s(), skb->len=%d\n", __func__ , (int)skb->len); + + IRDA_ASSERT(self != NULL, return -RSP_PROTOCOL_ERROR;); + IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -RSP_PROTOCOL_ERROR;); + + if (!skb) + return -RSP_PROTOCOL_ERROR; + + frame = skb->data; + + name = kmalloc(255, GFP_ATOMIC); + if (!name) + return -RSP_INSUFFICIENT_RESOURCES; + value = kmalloc(1016, GFP_ATOMIC); + if (!value) { + kfree(name); + return -RSP_INSUFFICIENT_RESOURCES; + } + + /* How many parameters? */ + count = frame[1]; + + pr_debug("Got %d parameters\n", count); + + ptr = frame+2; + + /* For all parameters */ + for (i=0; i<count;i++) { + ret = irlan_extract_param(ptr, name, value, &val_len); + if (ret < 0) { + pr_debug("%s(), IrLAN, Error!\n", __func__); + break; + } + ptr+=ret; + ret = RSP_SUCCESS; + irlan_check_command_param(self, name, value); + } + /* Cleanup */ + kfree(name); + kfree(value); + + return ret; +} + +/* + * Function irlan_provider_send_reply (self, info) + * + * Send reply to query to peer IrLAN layer + * + */ +void irlan_provider_send_reply(struct irlan_cb *self, int command, + int ret_code) +{ + struct sk_buff *skb; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); + + skb = alloc_skb(IRLAN_MAX_HEADER + IRLAN_CMD_HEADER + + /* Bigger param length comes from CMD_GET_MEDIA_CHAR */ + IRLAN_STRING_PARAMETER_LEN("FILTER_TYPE", "DIRECTED") + + IRLAN_STRING_PARAMETER_LEN("FILTER_TYPE", "BROADCAST") + + IRLAN_STRING_PARAMETER_LEN("FILTER_TYPE", "MULTICAST") + + IRLAN_STRING_PARAMETER_LEN("ACCESS_TYPE", "HOSTED"), + GFP_ATOMIC); + + if (!skb) + return; + + /* Reserve space for TTP, LMP, and LAP header */ + skb_reserve(skb, self->provider.max_header_size); + skb_put(skb, 2); + + switch (command) { + case CMD_GET_PROVIDER_INFO: + skb->data[0] = 0x00; /* Success */ + skb->data[1] = 0x02; /* 2 parameters */ + switch (self->media) { + case MEDIA_802_3: + irlan_insert_string_param(skb, "MEDIA", "802.3"); + break; + case MEDIA_802_5: + irlan_insert_string_param(skb, "MEDIA", "802.5"); + break; + default: + pr_debug("%s(), unknown media type!\n", __func__); + break; + } + irlan_insert_short_param(skb, "IRLAN_VER", 0x0101); + break; + + case CMD_GET_MEDIA_CHAR: + skb->data[0] = 0x00; /* Success */ + skb->data[1] = 0x05; /* 5 parameters */ + irlan_insert_string_param(skb, "FILTER_TYPE", "DIRECTED"); + irlan_insert_string_param(skb, "FILTER_TYPE", "BROADCAST"); + irlan_insert_string_param(skb, "FILTER_TYPE", "MULTICAST"); + + switch (self->provider.access_type) { + case ACCESS_DIRECT: + irlan_insert_string_param(skb, "ACCESS_TYPE", "DIRECT"); + break; + case ACCESS_PEER: + irlan_insert_string_param(skb, "ACCESS_TYPE", "PEER"); + break; + case ACCESS_HOSTED: + irlan_insert_string_param(skb, "ACCESS_TYPE", "HOSTED"); + break; + default: + pr_debug("%s(), Unknown access type\n", __func__); + break; + } + irlan_insert_short_param(skb, "MAX_FRAME", 0x05ee); + break; + case CMD_OPEN_DATA_CHANNEL: + skb->data[0] = 0x00; /* Success */ + if (self->provider.send_arb_val) { + skb->data[1] = 0x03; /* 3 parameters */ + irlan_insert_short_param(skb, "CON_ARB", + self->provider.send_arb_val); + } else + skb->data[1] = 0x02; /* 2 parameters */ + irlan_insert_byte_param(skb, "DATA_CHAN", self->stsap_sel_data); + irlan_insert_string_param(skb, "RECONNECT_KEY", "LINUX RULES!"); + break; + case CMD_FILTER_OPERATION: + irlan_filter_request(self, skb); + break; + default: + pr_debug("%s(), Unknown command!\n", __func__); + break; + } + + irttp_data_request(self->provider.tsap_ctrl, skb); +} + +/* + * Function irlan_provider_register(void) + * + * Register provider support so we can accept incoming connections. + * + */ +int irlan_provider_open_ctrl_tsap(struct irlan_cb *self) +{ + struct tsap_cb *tsap; + notify_t notify; + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;); + + /* Check if already open */ + if (self->provider.tsap_ctrl) + return -1; + + /* + * First register well known control TSAP + */ + irda_notify_init(¬ify); + notify.data_indication = irlan_provider_data_indication; + notify.connect_indication = irlan_provider_connect_indication; + notify.disconnect_indication = irlan_provider_disconnect_indication; + notify.instance = self; + strlcpy(notify.name, "IrLAN ctrl (p)", sizeof(notify.name)); + + tsap = irttp_open_tsap(LSAP_ANY, 1, ¬ify); + if (!tsap) { + pr_debug("%s(), Got no tsap!\n", __func__); + return -1; + } + self->provider.tsap_ctrl = tsap; + + /* Register with LM-IAS */ + irlan_ias_register(self, tsap->stsap_sel); + + return 0; +} + diff --git a/drivers/staging/irda/net/irlan/irlan_provider_event.c b/drivers/staging/irda/net/irlan/irlan_provider_event.c new file mode 100644 index 000000000000..9c4f7f51d6b5 --- /dev/null +++ b/drivers/staging/irda/net/irlan/irlan_provider_event.c @@ -0,0 +1,233 @@ +/********************************************************************* + * + * Filename: irlan_provider_event.c + * Version: 0.9 + * Description: IrLAN provider state machine) + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Sun Aug 31 20:14:37 1997 + * Modified at: Sat Oct 30 12:52:41 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#include <net/irda/irda.h> +#include <net/irda/iriap.h> +#include <net/irda/irlmp.h> +#include <net/irda/irttp.h> + +#include <net/irda/irlan_provider.h> +#include <net/irda/irlan_event.h> + +static int irlan_provider_state_idle(struct irlan_cb *self, IRLAN_EVENT event, + struct sk_buff *skb); +static int irlan_provider_state_info(struct irlan_cb *self, IRLAN_EVENT event, + struct sk_buff *skb); +static int irlan_provider_state_open(struct irlan_cb *self, IRLAN_EVENT event, + struct sk_buff *skb); +static int irlan_provider_state_data(struct irlan_cb *self, IRLAN_EVENT event, + struct sk_buff *skb); + +static int (*state[])(struct irlan_cb *self, IRLAN_EVENT event, + struct sk_buff *skb) = +{ + irlan_provider_state_idle, + NULL, /* Query */ + NULL, /* Info */ + irlan_provider_state_info, + NULL, /* Media */ + irlan_provider_state_open, + NULL, /* Wait */ + NULL, /* Arb */ + irlan_provider_state_data, + NULL, /* Close */ + NULL, /* Sync */ +}; + +void irlan_do_provider_event(struct irlan_cb *self, IRLAN_EVENT event, + struct sk_buff *skb) +{ + IRDA_ASSERT(*state[ self->provider.state] != NULL, return;); + + (*state[self->provider.state]) (self, event, skb); +} + +/* + * Function irlan_provider_state_idle (event, skb, info) + * + * IDLE, We are waiting for an indication that there is a provider + * available. + */ +static int irlan_provider_state_idle(struct irlan_cb *self, IRLAN_EVENT event, + struct sk_buff *skb) +{ + IRDA_ASSERT(self != NULL, return -1;); + + switch(event) { + case IRLAN_CONNECT_INDICATION: + irlan_provider_connect_response( self, self->provider.tsap_ctrl); + irlan_next_provider_state( self, IRLAN_INFO); + break; + default: + pr_debug("%s(), Unknown event %d\n", __func__ , event); + break; + } + if (skb) + dev_kfree_skb(skb); + + return 0; +} + +/* + * Function irlan_provider_state_info (self, event, skb, info) + * + * INFO, We have issued a GetInfo command and is awaiting a reply. + */ +static int irlan_provider_state_info(struct irlan_cb *self, IRLAN_EVENT event, + struct sk_buff *skb) +{ + int ret; + + IRDA_ASSERT(self != NULL, return -1;); + + switch(event) { + case IRLAN_GET_INFO_CMD: + /* Be sure to use 802.3 in case of peer mode */ + if (self->provider.access_type == ACCESS_PEER) { + self->media = MEDIA_802_3; + + /* Check if client has started yet */ + if (self->client.state == IRLAN_IDLE) { + /* This should get the client going */ + irlmp_discovery_request(8); + } + } + + irlan_provider_send_reply(self, CMD_GET_PROVIDER_INFO, + RSP_SUCCESS); + /* Keep state */ + break; + case IRLAN_GET_MEDIA_CMD: + irlan_provider_send_reply(self, CMD_GET_MEDIA_CHAR, + RSP_SUCCESS); + /* Keep state */ + break; + case IRLAN_OPEN_DATA_CMD: + ret = irlan_parse_open_data_cmd(self, skb); + if (self->provider.access_type == ACCESS_PEER) { + /* FIXME: make use of random functions! */ + self->provider.send_arb_val = (jiffies & 0xffff); + } + irlan_provider_send_reply(self, CMD_OPEN_DATA_CHANNEL, ret); + + if (ret == RSP_SUCCESS) { + irlan_next_provider_state(self, IRLAN_OPEN); + + /* Signal client that we are now open */ + irlan_do_client_event(self, IRLAN_PROVIDER_SIGNAL, NULL); + } + break; + case IRLAN_LMP_DISCONNECT: /* FALLTHROUGH */ + case IRLAN_LAP_DISCONNECT: + irlan_next_provider_state(self, IRLAN_IDLE); + break; + default: + pr_debug("%s(), Unknown event %d\n", __func__ , event); + break; + } + if (skb) + dev_kfree_skb(skb); + + return 0; +} + +/* + * Function irlan_provider_state_open (self, event, skb, info) + * + * OPEN, The client has issued a OpenData command and is awaiting a + * reply + * + */ +static int irlan_provider_state_open(struct irlan_cb *self, IRLAN_EVENT event, + struct sk_buff *skb) +{ + IRDA_ASSERT(self != NULL, return -1;); + + switch(event) { + case IRLAN_FILTER_CONFIG_CMD: + irlan_provider_parse_command(self, CMD_FILTER_OPERATION, skb); + irlan_provider_send_reply(self, CMD_FILTER_OPERATION, + RSP_SUCCESS); + /* Keep state */ + break; + case IRLAN_DATA_CONNECT_INDICATION: + irlan_next_provider_state(self, IRLAN_DATA); + irlan_provider_connect_response(self, self->tsap_data); + break; + case IRLAN_LMP_DISCONNECT: /* FALLTHROUGH */ + case IRLAN_LAP_DISCONNECT: + irlan_next_provider_state(self, IRLAN_IDLE); + break; + default: + pr_debug("%s(), Unknown event %d\n", __func__ , event); + break; + } + if (skb) + dev_kfree_skb(skb); + + return 0; +} + +/* + * Function irlan_provider_state_data (self, event, skb, info) + * + * DATA, The data channel is connected, allowing data transfers between + * the local and remote machines. + * + */ +static int irlan_provider_state_data(struct irlan_cb *self, IRLAN_EVENT event, + struct sk_buff *skb) +{ + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;); + + switch(event) { + case IRLAN_FILTER_CONFIG_CMD: + irlan_provider_parse_command(self, CMD_FILTER_OPERATION, skb); + irlan_provider_send_reply(self, CMD_FILTER_OPERATION, + RSP_SUCCESS); + break; + case IRLAN_LMP_DISCONNECT: /* FALLTHROUGH */ + case IRLAN_LAP_DISCONNECT: + irlan_next_provider_state(self, IRLAN_IDLE); + break; + default: + pr_debug("%s(), Unknown event %d\n", __func__ , event); + break; + } + if (skb) + dev_kfree_skb(skb); + + return 0; +} + + + + + + + + + + diff --git a/drivers/staging/irda/net/irlap.c b/drivers/staging/irda/net/irlap.c new file mode 100644 index 000000000000..1cde711bcab5 --- /dev/null +++ b/drivers/staging/irda/net/irlap.c @@ -0,0 +1,1207 @@ +/********************************************************************* + * + * Filename: irlap.c + * Version: 1.0 + * Description: IrLAP implementation for Linux + * Status: Stable + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Mon Aug 4 20:40:53 1997 + * Modified at: Tue Dec 14 09:26:44 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved. + * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + ********************************************************************/ + +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/skbuff.h> +#include <linux/delay.h> +#include <linux/proc_fs.h> +#include <linux/init.h> +#include <linux/random.h> +#include <linux/module.h> +#include <linux/seq_file.h> + +#include <net/irda/irda.h> +#include <net/irda/irda_device.h> +#include <net/irda/irqueue.h> +#include <net/irda/irlmp.h> +#include <net/irda/irlmp_frame.h> +#include <net/irda/irlap_frame.h> +#include <net/irda/irlap.h> +#include <net/irda/timer.h> +#include <net/irda/qos.h> + +static hashbin_t *irlap = NULL; +int sysctl_slot_timeout = SLOT_TIMEOUT * 1000 / HZ; + +/* This is the delay of missed pf period before generating an event + * to the application. The spec mandate 3 seconds, but in some cases + * it's way too long. - Jean II */ +int sysctl_warn_noreply_time = 3; + +extern void irlap_queue_xmit(struct irlap_cb *self, struct sk_buff *skb); +static void __irlap_close(struct irlap_cb *self); +static void irlap_init_qos_capabilities(struct irlap_cb *self, + struct qos_info *qos_user); + +static const char *const lap_reasons[] __maybe_unused = { + "ERROR, NOT USED", + "LAP_DISC_INDICATION", + "LAP_NO_RESPONSE", + "LAP_RESET_INDICATION", + "LAP_FOUND_NONE", + "LAP_MEDIA_BUSY", + "LAP_PRIMARY_CONFLICT", + "ERROR, NOT USED", +}; + +int __init irlap_init(void) +{ + /* Check if the compiler did its job properly. + * May happen on some ARM configuration, check with Russell King. */ + IRDA_ASSERT(sizeof(struct xid_frame) == 14, ;); + IRDA_ASSERT(sizeof(struct test_frame) == 10, ;); + IRDA_ASSERT(sizeof(struct ua_frame) == 10, ;); + IRDA_ASSERT(sizeof(struct snrm_frame) == 11, ;); + + /* Allocate master array */ + irlap = hashbin_new(HB_LOCK); + if (irlap == NULL) { + net_err_ratelimited("%s: can't allocate irlap hashbin!\n", + __func__); + return -ENOMEM; + } + + return 0; +} + +void irlap_cleanup(void) +{ + IRDA_ASSERT(irlap != NULL, return;); + + hashbin_delete(irlap, (FREE_FUNC) __irlap_close); +} + +/* + * Function irlap_open (driver) + * + * Initialize IrLAP layer + * + */ +struct irlap_cb *irlap_open(struct net_device *dev, struct qos_info *qos, + const char *hw_name) +{ + struct irlap_cb *self; + + /* Initialize the irlap structure. */ + self = kzalloc(sizeof(struct irlap_cb), GFP_KERNEL); + if (self == NULL) + return NULL; + + self->magic = LAP_MAGIC; + + /* Make a binding between the layers */ + self->netdev = dev; + self->qos_dev = qos; + /* Copy hardware name */ + if(hw_name != NULL) { + strlcpy(self->hw_name, hw_name, sizeof(self->hw_name)); + } else { + self->hw_name[0] = '\0'; + } + + /* FIXME: should we get our own field? */ + dev->atalk_ptr = self; + + self->state = LAP_OFFLINE; + + /* Initialize transmit queue */ + skb_queue_head_init(&self->txq); + skb_queue_head_init(&self->txq_ultra); + skb_queue_head_init(&self->wx_list); + + /* My unique IrLAP device address! */ + /* We don't want the broadcast address, neither the NULL address + * (most often used to signify "invalid"), and we don't want an + * address already in use (otherwise connect won't be able + * to select the proper link). - Jean II */ + do { + get_random_bytes(&self->saddr, sizeof(self->saddr)); + } while ((self->saddr == 0x0) || (self->saddr == BROADCAST) || + (hashbin_lock_find(irlap, self->saddr, NULL)) ); + /* Copy to the driver */ + memcpy(dev->dev_addr, &self->saddr, 4); + + init_timer(&self->slot_timer); + init_timer(&self->query_timer); + init_timer(&self->discovery_timer); + init_timer(&self->final_timer); + init_timer(&self->poll_timer); + init_timer(&self->wd_timer); + init_timer(&self->backoff_timer); + init_timer(&self->media_busy_timer); + + irlap_apply_default_connection_parameters(self); + + self->N3 = 3; /* # connections attempts to try before giving up */ + + self->state = LAP_NDM; + + hashbin_insert(irlap, (irda_queue_t *) self, self->saddr, NULL); + + irlmp_register_link(self, self->saddr, &self->notify); + + return self; +} +EXPORT_SYMBOL(irlap_open); + +/* + * Function __irlap_close (self) + * + * Remove IrLAP and all allocated memory. Stop any pending timers. + * + */ +static void __irlap_close(struct irlap_cb *self) +{ + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return;); + + /* Stop timers */ + del_timer(&self->slot_timer); + del_timer(&self->query_timer); + del_timer(&self->discovery_timer); + del_timer(&self->final_timer); + del_timer(&self->poll_timer); + del_timer(&self->wd_timer); + del_timer(&self->backoff_timer); + del_timer(&self->media_busy_timer); + + irlap_flush_all_queues(self); + + self->magic = 0; + + kfree(self); +} + +/* + * Function irlap_close (self) + * + * Remove IrLAP instance + * + */ +void irlap_close(struct irlap_cb *self) +{ + struct irlap_cb *lap; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return;); + + /* We used to send a LAP_DISC_INDICATION here, but this was + * racy. This has been move within irlmp_unregister_link() + * itself. Jean II */ + + /* Kill the LAP and all LSAPs on top of it */ + irlmp_unregister_link(self->saddr); + self->notify.instance = NULL; + + /* Be sure that we manage to remove ourself from the hash */ + lap = hashbin_remove(irlap, self->saddr, NULL); + if (!lap) { + pr_debug("%s(), Didn't find myself!\n", __func__); + return; + } + __irlap_close(lap); +} +EXPORT_SYMBOL(irlap_close); + +/* + * Function irlap_connect_indication (self, skb) + * + * Another device is attempting to make a connection + * + */ +void irlap_connect_indication(struct irlap_cb *self, struct sk_buff *skb) +{ + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return;); + + irlap_init_qos_capabilities(self, NULL); /* No user QoS! */ + + irlmp_link_connect_indication(self->notify.instance, self->saddr, + self->daddr, &self->qos_tx, skb); +} + +/* + * Function irlap_connect_response (self, skb) + * + * Service user has accepted incoming connection + * + */ +void irlap_connect_response(struct irlap_cb *self, struct sk_buff *userdata) +{ + irlap_do_event(self, CONNECT_RESPONSE, userdata, NULL); +} + +/* + * Function irlap_connect_request (self, daddr, qos_user, sniff) + * + * Request connection with another device, sniffing is not implemented + * yet. + * + */ +void irlap_connect_request(struct irlap_cb *self, __u32 daddr, + struct qos_info *qos_user, int sniff) +{ + pr_debug("%s(), daddr=0x%08x\n", __func__, daddr); + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return;); + + self->daddr = daddr; + + /* + * If the service user specifies QoS values for this connection, + * then use them + */ + irlap_init_qos_capabilities(self, qos_user); + + if ((self->state == LAP_NDM) && !self->media_busy) + irlap_do_event(self, CONNECT_REQUEST, NULL, NULL); + else + self->connect_pending = TRUE; +} + +/* + * Function irlap_connect_confirm (self, skb) + * + * Connection request has been accepted + * + */ +void irlap_connect_confirm(struct irlap_cb *self, struct sk_buff *skb) +{ + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return;); + + irlmp_link_connect_confirm(self->notify.instance, &self->qos_tx, skb); +} + +/* + * Function irlap_data_indication (self, skb) + * + * Received data frames from IR-port, so we just pass them up to + * IrLMP for further processing + * + */ +void irlap_data_indication(struct irlap_cb *self, struct sk_buff *skb, + int unreliable) +{ + /* Hide LAP header from IrLMP layer */ + skb_pull(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER); + + irlmp_link_data_indication(self->notify.instance, skb, unreliable); +} + + +/* + * Function irlap_data_request (self, skb) + * + * Queue data for transmission, must wait until XMIT state + * + */ +void irlap_data_request(struct irlap_cb *self, struct sk_buff *skb, + int unreliable) +{ + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return;); + + IRDA_ASSERT(skb_headroom(skb) >= (LAP_ADDR_HEADER+LAP_CTRL_HEADER), + return;); + skb_push(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER); + + /* + * Must set frame format now so that the rest of the code knows + * if its dealing with an I or an UI frame + */ + if (unreliable) + skb->data[1] = UI_FRAME; + else + skb->data[1] = I_FRAME; + + /* Don't forget to refcount it - see irlmp_connect_request(). */ + skb_get(skb); + + /* Add at the end of the queue (keep ordering) - Jean II */ + skb_queue_tail(&self->txq, skb); + + /* + * Send event if this frame only if we are in the right state + * FIXME: udata should be sent first! (skb_queue_head?) + */ + if ((self->state == LAP_XMIT_P) || (self->state == LAP_XMIT_S)) { + /* If we are not already processing the Tx queue, trigger + * transmission immediately - Jean II */ + if((skb_queue_len(&self->txq) <= 1) && (!self->local_busy)) + irlap_do_event(self, DATA_REQUEST, skb, NULL); + /* Otherwise, the packets will be sent normally at the + * next pf-poll - Jean II */ + } +} + +/* + * Function irlap_unitdata_request (self, skb) + * + * Send Ultra data. This is data that must be sent outside any connection + * + */ +#ifdef CONFIG_IRDA_ULTRA +void irlap_unitdata_request(struct irlap_cb *self, struct sk_buff *skb) +{ + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return;); + + IRDA_ASSERT(skb_headroom(skb) >= (LAP_ADDR_HEADER+LAP_CTRL_HEADER), + return;); + skb_push(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER); + + skb->data[0] = CBROADCAST; + skb->data[1] = UI_FRAME; + + /* Don't need to refcount, see irlmp_connless_data_request() */ + + skb_queue_tail(&self->txq_ultra, skb); + + irlap_do_event(self, SEND_UI_FRAME, NULL, NULL); +} +#endif /*CONFIG_IRDA_ULTRA */ + +/* + * Function irlap_udata_indication (self, skb) + * + * Receive Ultra data. This is data that is received outside any connection + * + */ +#ifdef CONFIG_IRDA_ULTRA +void irlap_unitdata_indication(struct irlap_cb *self, struct sk_buff *skb) +{ + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return;); + IRDA_ASSERT(skb != NULL, return;); + + /* Hide LAP header from IrLMP layer */ + skb_pull(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER); + + irlmp_link_unitdata_indication(self->notify.instance, skb); +} +#endif /* CONFIG_IRDA_ULTRA */ + +/* + * Function irlap_disconnect_request (void) + * + * Request to disconnect connection by service user + */ +void irlap_disconnect_request(struct irlap_cb *self) +{ + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return;); + + /* Don't disconnect until all data frames are successfully sent */ + if (!skb_queue_empty(&self->txq)) { + self->disconnect_pending = TRUE; + return; + } + + /* Check if we are in the right state for disconnecting */ + switch (self->state) { + case LAP_XMIT_P: /* FALLTHROUGH */ + case LAP_XMIT_S: /* FALLTHROUGH */ + case LAP_CONN: /* FALLTHROUGH */ + case LAP_RESET_WAIT: /* FALLTHROUGH */ + case LAP_RESET_CHECK: + irlap_do_event(self, DISCONNECT_REQUEST, NULL, NULL); + break; + default: + pr_debug("%s(), disconnect pending!\n", __func__); + self->disconnect_pending = TRUE; + break; + } +} + +/* + * Function irlap_disconnect_indication (void) + * + * Disconnect request from other device + * + */ +void irlap_disconnect_indication(struct irlap_cb *self, LAP_REASON reason) +{ + pr_debug("%s(), reason=%s\n", __func__, lap_reasons[reason]); + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return;); + + /* Flush queues */ + irlap_flush_all_queues(self); + + switch (reason) { + case LAP_RESET_INDICATION: + pr_debug("%s(), Sending reset request!\n", __func__); + irlap_do_event(self, RESET_REQUEST, NULL, NULL); + break; + case LAP_NO_RESPONSE: /* FALLTHROUGH */ + case LAP_DISC_INDICATION: /* FALLTHROUGH */ + case LAP_FOUND_NONE: /* FALLTHROUGH */ + case LAP_MEDIA_BUSY: + irlmp_link_disconnect_indication(self->notify.instance, self, + reason, NULL); + break; + default: + net_err_ratelimited("%s: Unknown reason %d\n", + __func__, reason); + } +} + +/* + * Function irlap_discovery_request (gen_addr_bit) + * + * Start one single discovery operation. + * + */ +void irlap_discovery_request(struct irlap_cb *self, discovery_t *discovery) +{ + struct irlap_info info; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return;); + IRDA_ASSERT(discovery != NULL, return;); + + pr_debug("%s(), nslots = %d\n", __func__, discovery->nslots); + + IRDA_ASSERT((discovery->nslots == 1) || (discovery->nslots == 6) || + (discovery->nslots == 8) || (discovery->nslots == 16), + return;); + + /* Discovery is only possible in NDM mode */ + if (self->state != LAP_NDM) { + pr_debug("%s(), discovery only possible in NDM mode\n", + __func__); + irlap_discovery_confirm(self, NULL); + /* Note : in theory, if we are not in NDM, we could postpone + * the discovery like we do for connection request. + * In practice, it's not worth it. If the media was busy, + * it's likely next time around it won't be busy. If we are + * in REPLY state, we will get passive discovery info & event. + * Jean II */ + return; + } + + /* Check if last discovery request finished in time, or if + * it was aborted due to the media busy flag. */ + if (self->discovery_log != NULL) { + hashbin_delete(self->discovery_log, (FREE_FUNC) kfree); + self->discovery_log = NULL; + } + + /* All operations will occur at predictable time, no need to lock */ + self->discovery_log = hashbin_new(HB_NOLOCK); + + if (self->discovery_log == NULL) { + net_warn_ratelimited("%s(), Unable to allocate discovery log!\n", + __func__); + return; + } + + info.S = discovery->nslots; /* Number of slots */ + info.s = 0; /* Current slot */ + + self->discovery_cmd = discovery; + info.discovery = discovery; + + /* sysctl_slot_timeout bounds are checked in irsysctl.c - Jean II */ + self->slot_timeout = msecs_to_jiffies(sysctl_slot_timeout); + + irlap_do_event(self, DISCOVERY_REQUEST, NULL, &info); +} + +/* + * Function irlap_discovery_confirm (log) + * + * A device has been discovered in front of this station, we + * report directly to LMP. + */ +void irlap_discovery_confirm(struct irlap_cb *self, hashbin_t *discovery_log) +{ + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return;); + + IRDA_ASSERT(self->notify.instance != NULL, return;); + + /* + * Check for successful discovery, since we are then allowed to clear + * the media busy condition (IrLAP 6.13.4 - p.94). This should allow + * us to make connection attempts much faster and easier (i.e. no + * collisions). + * Setting media busy to false will also generate an event allowing + * to process pending events in NDM state machine. + * Note : the spec doesn't define what's a successful discovery is. + * If we want Ultra to work, it's successful even if there is + * nobody discovered - Jean II + */ + if (discovery_log) + irda_device_set_media_busy(self->netdev, FALSE); + + /* Inform IrLMP */ + irlmp_link_discovery_confirm(self->notify.instance, discovery_log); +} + +/* + * Function irlap_discovery_indication (log) + * + * Somebody is trying to discover us! + * + */ +void irlap_discovery_indication(struct irlap_cb *self, discovery_t *discovery) +{ + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return;); + IRDA_ASSERT(discovery != NULL, return;); + + IRDA_ASSERT(self->notify.instance != NULL, return;); + + /* A device is very likely to connect immediately after it performs + * a successful discovery. This means that in our case, we are much + * more likely to receive a connection request over the medium. + * So, we backoff to avoid collisions. + * IrLAP spec 6.13.4 suggest 100ms... + * Note : this little trick actually make a *BIG* difference. If I set + * my Linux box with discovery enabled and one Ultra frame sent every + * second, my Palm has no trouble connecting to it every time ! + * Jean II */ + irda_device_set_media_busy(self->netdev, SMALL); + + irlmp_link_discovery_indication(self->notify.instance, discovery); +} + +/* + * Function irlap_status_indication (quality_of_link) + */ +void irlap_status_indication(struct irlap_cb *self, int quality_of_link) +{ + switch (quality_of_link) { + case STATUS_NO_ACTIVITY: + net_info_ratelimited("IrLAP, no activity on link!\n"); + break; + case STATUS_NOISY: + net_info_ratelimited("IrLAP, noisy link!\n"); + break; + default: + break; + } + irlmp_status_indication(self->notify.instance, + quality_of_link, LOCK_NO_CHANGE); +} + +/* + * Function irlap_reset_indication (void) + */ +void irlap_reset_indication(struct irlap_cb *self) +{ + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return;); + + if (self->state == LAP_RESET_WAIT) + irlap_do_event(self, RESET_REQUEST, NULL, NULL); + else + irlap_do_event(self, RESET_RESPONSE, NULL, NULL); +} + +/* + * Function irlap_reset_confirm (void) + */ +void irlap_reset_confirm(void) +{ +} + +/* + * Function irlap_generate_rand_time_slot (S, s) + * + * Generate a random time slot between s and S-1 where + * S = Number of slots (0 -> S-1) + * s = Current slot + */ +int irlap_generate_rand_time_slot(int S, int s) +{ + static int rand; + int slot; + + IRDA_ASSERT((S - s) > 0, return 0;); + + rand += jiffies; + rand ^= (rand << 12); + rand ^= (rand >> 20); + + slot = s + rand % (S-s); + + IRDA_ASSERT((slot >= s) || (slot < S), return 0;); + + return slot; +} + +/* + * Function irlap_update_nr_received (nr) + * + * Remove all acknowledged frames in current window queue. This code is + * not intuitive and you should not try to change it. If you think it + * contains bugs, please mail a patch to the author instead. + */ +void irlap_update_nr_received(struct irlap_cb *self, int nr) +{ + struct sk_buff *skb = NULL; + int count = 0; + + /* + * Remove all the ack-ed frames from the window queue. + */ + + /* + * Optimize for the common case. It is most likely that the receiver + * will acknowledge all the frames we have sent! So in that case we + * delete all frames stored in window. + */ + if (nr == self->vs) { + while ((skb = skb_dequeue(&self->wx_list)) != NULL) { + dev_kfree_skb(skb); + } + /* The last acked frame is the next to send minus one */ + self->va = nr - 1; + } else { + /* Remove all acknowledged frames in current window */ + while ((skb_peek(&self->wx_list) != NULL) && + (((self->va+1) % 8) != nr)) + { + skb = skb_dequeue(&self->wx_list); + dev_kfree_skb(skb); + + self->va = (self->va + 1) % 8; + count++; + } + } + + /* Advance window */ + self->window = self->window_size - skb_queue_len(&self->wx_list); +} + +/* + * Function irlap_validate_ns_received (ns) + * + * Validate the next to send (ns) field from received frame. + */ +int irlap_validate_ns_received(struct irlap_cb *self, int ns) +{ + /* ns as expected? */ + if (ns == self->vr) + return NS_EXPECTED; + /* + * Stations are allowed to treat invalid NS as unexpected NS + * IrLAP, Recv ... with-invalid-Ns. p. 84 + */ + return NS_UNEXPECTED; + + /* return NR_INVALID; */ +} +/* + * Function irlap_validate_nr_received (nr) + * + * Validate the next to receive (nr) field from received frame. + * + */ +int irlap_validate_nr_received(struct irlap_cb *self, int nr) +{ + /* nr as expected? */ + if (nr == self->vs) { + pr_debug("%s(), expected!\n", __func__); + return NR_EXPECTED; + } + + /* + * unexpected nr? (but within current window), first we check if the + * ns numbers of the frames in the current window wrap. + */ + if (self->va < self->vs) { + if ((nr >= self->va) && (nr <= self->vs)) + return NR_UNEXPECTED; + } else { + if ((nr >= self->va) || (nr <= self->vs)) + return NR_UNEXPECTED; + } + + /* Invalid nr! */ + return NR_INVALID; +} + +/* + * Function irlap_initiate_connection_state () + * + * Initialize the connection state parameters + * + */ +void irlap_initiate_connection_state(struct irlap_cb *self) +{ + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return;); + + /* Next to send and next to receive */ + self->vs = self->vr = 0; + + /* Last frame which got acked (0 - 1) % 8 */ + self->va = 7; + + self->window = 1; + + self->remote_busy = FALSE; + self->retry_count = 0; +} + +/* + * Function irlap_wait_min_turn_around (self, qos) + * + * Wait negotiated minimum turn around time, this function actually sets + * the number of BOS's that must be sent before the next transmitted + * frame in order to delay for the specified amount of time. This is + * done to avoid using timers, and the forbidden udelay! + */ +void irlap_wait_min_turn_around(struct irlap_cb *self, struct qos_info *qos) +{ + __u32 min_turn_time; + __u32 speed; + + /* Get QoS values. */ + speed = qos->baud_rate.value; + min_turn_time = qos->min_turn_time.value; + + /* No need to calculate XBOFs for speeds over 115200 bps */ + if (speed > 115200) { + self->mtt_required = min_turn_time; + return; + } + + /* + * Send additional BOF's for the next frame for the requested + * min turn time, so now we must calculate how many chars (XBOF's) we + * must send for the requested time period (min turn time) + */ + self->xbofs_delay = irlap_min_turn_time_in_bytes(speed, min_turn_time); +} + +/* + * Function irlap_flush_all_queues (void) + * + * Flush all queues + * + */ +void irlap_flush_all_queues(struct irlap_cb *self) +{ + struct sk_buff* skb; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return;); + + /* Free transmission queue */ + while ((skb = skb_dequeue(&self->txq)) != NULL) + dev_kfree_skb(skb); + + while ((skb = skb_dequeue(&self->txq_ultra)) != NULL) + dev_kfree_skb(skb); + + /* Free sliding window buffered packets */ + while ((skb = skb_dequeue(&self->wx_list)) != NULL) + dev_kfree_skb(skb); +} + +/* + * Function irlap_setspeed (self, speed) + * + * Change the speed of the IrDA port + * + */ +static void irlap_change_speed(struct irlap_cb *self, __u32 speed, int now) +{ + struct sk_buff *skb; + + pr_debug("%s(), setting speed to %d\n", __func__, speed); + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return;); + + self->speed = speed; + + /* Change speed now, or just piggyback speed on frames */ + if (now) { + /* Send down empty frame to trigger speed change */ + skb = alloc_skb(0, GFP_ATOMIC); + if (skb) + irlap_queue_xmit(self, skb); + } +} + +/* + * Function irlap_init_qos_capabilities (self, qos) + * + * Initialize QoS for this IrLAP session, What we do is to compute the + * intersection of the QoS capabilities for the user, driver and for + * IrLAP itself. Normally, IrLAP will not specify any values, but it can + * be used to restrict certain values. + */ +static void irlap_init_qos_capabilities(struct irlap_cb *self, + struct qos_info *qos_user) +{ + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return;); + IRDA_ASSERT(self->netdev != NULL, return;); + + /* Start out with the maximum QoS support possible */ + irda_init_max_qos_capabilies(&self->qos_rx); + + /* Apply drivers QoS capabilities */ + irda_qos_compute_intersection(&self->qos_rx, self->qos_dev); + + /* + * Check for user supplied QoS parameters. The service user is only + * allowed to supply these values. We check each parameter since the + * user may not have set all of them. + */ + if (qos_user) { + pr_debug("%s(), Found user specified QoS!\n", __func__); + + if (qos_user->baud_rate.bits) + self->qos_rx.baud_rate.bits &= qos_user->baud_rate.bits; + + if (qos_user->max_turn_time.bits) + self->qos_rx.max_turn_time.bits &= qos_user->max_turn_time.bits; + if (qos_user->data_size.bits) + self->qos_rx.data_size.bits &= qos_user->data_size.bits; + + if (qos_user->link_disc_time.bits) + self->qos_rx.link_disc_time.bits &= qos_user->link_disc_time.bits; + } + + /* Use 500ms in IrLAP for now */ + self->qos_rx.max_turn_time.bits &= 0x01; + + /* Set data size */ + /*self->qos_rx.data_size.bits &= 0x03;*/ + + irda_qos_bits_to_value(&self->qos_rx); +} + +/* + * Function irlap_apply_default_connection_parameters (void, now) + * + * Use the default connection and transmission parameters + */ +void irlap_apply_default_connection_parameters(struct irlap_cb *self) +{ + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return;); + + /* xbofs : Default value in NDM */ + self->next_bofs = 12; + self->bofs_count = 12; + + /* NDM Speed is 9600 */ + irlap_change_speed(self, 9600, TRUE); + + /* Set mbusy when going to NDM state */ + irda_device_set_media_busy(self->netdev, TRUE); + + /* + * Generate random connection address for this session, which must + * be 7 bits wide and different from 0x00 and 0xfe + */ + while ((self->caddr == 0x00) || (self->caddr == 0xfe)) { + get_random_bytes(&self->caddr, sizeof(self->caddr)); + self->caddr &= 0xfe; + } + + /* Use default values until connection has been negitiated */ + self->slot_timeout = sysctl_slot_timeout; + self->final_timeout = FINAL_TIMEOUT; + self->poll_timeout = POLL_TIMEOUT; + self->wd_timeout = WD_TIMEOUT; + + /* Set some default values */ + self->qos_tx.baud_rate.value = 9600; + self->qos_rx.baud_rate.value = 9600; + self->qos_tx.max_turn_time.value = 0; + self->qos_rx.max_turn_time.value = 0; + self->qos_tx.min_turn_time.value = 0; + self->qos_rx.min_turn_time.value = 0; + self->qos_tx.data_size.value = 64; + self->qos_rx.data_size.value = 64; + self->qos_tx.window_size.value = 1; + self->qos_rx.window_size.value = 1; + self->qos_tx.additional_bofs.value = 12; + self->qos_rx.additional_bofs.value = 12; + self->qos_tx.link_disc_time.value = 0; + self->qos_rx.link_disc_time.value = 0; + + irlap_flush_all_queues(self); + + self->disconnect_pending = FALSE; + self->connect_pending = FALSE; +} + +/* + * Function irlap_apply_connection_parameters (qos, now) + * + * Initialize IrLAP with the negotiated QoS values + * + * If 'now' is false, the speed and xbofs will be changed after the next + * frame is sent. + * If 'now' is true, the speed and xbofs is changed immediately + */ +void irlap_apply_connection_parameters(struct irlap_cb *self, int now) +{ + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return;); + + /* Set the negotiated xbofs value */ + self->next_bofs = self->qos_tx.additional_bofs.value; + if (now) + self->bofs_count = self->next_bofs; + + /* Set the negotiated link speed (may need the new xbofs value) */ + irlap_change_speed(self, self->qos_tx.baud_rate.value, now); + + self->window_size = self->qos_tx.window_size.value; + self->window = self->qos_tx.window_size.value; + +#ifdef CONFIG_IRDA_DYNAMIC_WINDOW + /* + * Calculate how many bytes it is possible to transmit before the + * link must be turned around + */ + self->line_capacity = + irlap_max_line_capacity(self->qos_tx.baud_rate.value, + self->qos_tx.max_turn_time.value); + self->bytes_left = self->line_capacity; +#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */ + + + /* + * Initialize timeout values, some of the rules are listed on + * page 92 in IrLAP. + */ + IRDA_ASSERT(self->qos_tx.max_turn_time.value != 0, return;); + IRDA_ASSERT(self->qos_rx.max_turn_time.value != 0, return;); + /* The poll timeout applies only to the primary station. + * It defines the maximum time the primary stay in XMIT mode + * before timeout and turning the link around (sending a RR). + * Or, this is how much we can keep the pf bit in primary mode. + * Therefore, it must be lower or equal than our *OWN* max turn around. + * Jean II */ + self->poll_timeout = msecs_to_jiffies( + self->qos_tx.max_turn_time.value); + /* The Final timeout applies only to the primary station. + * It defines the maximum time the primary wait (mostly in RECV mode) + * for an answer from the secondary station before polling it again. + * Therefore, it must be greater or equal than our *PARTNER* + * max turn around time - Jean II */ + self->final_timeout = msecs_to_jiffies( + self->qos_rx.max_turn_time.value); + /* The Watchdog Bit timeout applies only to the secondary station. + * It defines the maximum time the secondary wait (mostly in RECV mode) + * for poll from the primary station before getting annoyed. + * Therefore, it must be greater or equal than our *PARTNER* + * max turn around time - Jean II */ + self->wd_timeout = self->final_timeout * 2; + + /* + * N1 and N2 are maximum retry count for *both* the final timer + * and the wd timer (with a factor 2) as defined above. + * After N1 retry of a timer, we give a warning to the user. + * After N2 retry, we consider the link dead and disconnect it. + * Jean II + */ + + /* + * Set N1 to 0 if Link Disconnect/Threshold Time = 3 and set it to + * 3 seconds otherwise. See page 71 in IrLAP for more details. + * Actually, it's not always 3 seconds, as we allow to set + * it via sysctl... Max maxtt is 500ms, and N1 need to be multiple + * of 2, so 1 second is minimum we can allow. - Jean II + */ + if (self->qos_tx.link_disc_time.value == sysctl_warn_noreply_time) + /* + * If we set N1 to 0, it will trigger immediately, which is + * not what we want. What we really want is to disable it, + * Jean II + */ + self->N1 = -2; /* Disable - Need to be multiple of 2*/ + else + self->N1 = sysctl_warn_noreply_time * 1000 / + self->qos_rx.max_turn_time.value; + + pr_debug("Setting N1 = %d\n", self->N1); + + /* Set N2 to match our own disconnect time */ + self->N2 = self->qos_tx.link_disc_time.value * 1000 / + self->qos_rx.max_turn_time.value; + pr_debug("Setting N2 = %d\n", self->N2); +} + +#ifdef CONFIG_PROC_FS +struct irlap_iter_state { + int id; +}; + +static void *irlap_seq_start(struct seq_file *seq, loff_t *pos) +{ + struct irlap_iter_state *iter = seq->private; + struct irlap_cb *self; + + /* Protect our access to the tsap list */ + spin_lock_irq(&irlap->hb_spinlock); + iter->id = 0; + + for (self = (struct irlap_cb *) hashbin_get_first(irlap); + self; self = (struct irlap_cb *) hashbin_get_next(irlap)) { + if (iter->id == *pos) + break; + ++iter->id; + } + + return self; +} + +static void *irlap_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + struct irlap_iter_state *iter = seq->private; + + ++*pos; + ++iter->id; + return (void *) hashbin_get_next(irlap); +} + +static void irlap_seq_stop(struct seq_file *seq, void *v) +{ + spin_unlock_irq(&irlap->hb_spinlock); +} + +static int irlap_seq_show(struct seq_file *seq, void *v) +{ + const struct irlap_iter_state *iter = seq->private; + const struct irlap_cb *self = v; + + IRDA_ASSERT(self->magic == LAP_MAGIC, return -EINVAL;); + + seq_printf(seq, "irlap%d ", iter->id); + seq_printf(seq, "state: %s\n", + irlap_state[self->state]); + + seq_printf(seq, " device name: %s, ", + (self->netdev) ? self->netdev->name : "bug"); + seq_printf(seq, "hardware name: %s\n", self->hw_name); + + seq_printf(seq, " caddr: %#02x, ", self->caddr); + seq_printf(seq, "saddr: %#08x, ", self->saddr); + seq_printf(seq, "daddr: %#08x\n", self->daddr); + + seq_printf(seq, " win size: %d, ", + self->window_size); + seq_printf(seq, "win: %d, ", self->window); +#ifdef CONFIG_IRDA_DYNAMIC_WINDOW + seq_printf(seq, "line capacity: %d, ", + self->line_capacity); + seq_printf(seq, "bytes left: %d\n", self->bytes_left); +#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */ + seq_printf(seq, " tx queue len: %d ", + skb_queue_len(&self->txq)); + seq_printf(seq, "win queue len: %d ", + skb_queue_len(&self->wx_list)); + seq_printf(seq, "rbusy: %s", self->remote_busy ? + "TRUE" : "FALSE"); + seq_printf(seq, " mbusy: %s\n", self->media_busy ? + "TRUE" : "FALSE"); + + seq_printf(seq, " retrans: %d ", self->retry_count); + seq_printf(seq, "vs: %d ", self->vs); + seq_printf(seq, "vr: %d ", self->vr); + seq_printf(seq, "va: %d\n", self->va); + + seq_printf(seq, " qos\tbps\tmaxtt\tdsize\twinsize\taddbofs\tmintt\tldisc\tcomp\n"); + + seq_printf(seq, " tx\t%d\t", + self->qos_tx.baud_rate.value); + seq_printf(seq, "%d\t", + self->qos_tx.max_turn_time.value); + seq_printf(seq, "%d\t", + self->qos_tx.data_size.value); + seq_printf(seq, "%d\t", + self->qos_tx.window_size.value); + seq_printf(seq, "%d\t", + self->qos_tx.additional_bofs.value); + seq_printf(seq, "%d\t", + self->qos_tx.min_turn_time.value); + seq_printf(seq, "%d\t", + self->qos_tx.link_disc_time.value); + seq_printf(seq, "\n"); + + seq_printf(seq, " rx\t%d\t", + self->qos_rx.baud_rate.value); + seq_printf(seq, "%d\t", + self->qos_rx.max_turn_time.value); + seq_printf(seq, "%d\t", + self->qos_rx.data_size.value); + seq_printf(seq, "%d\t", + self->qos_rx.window_size.value); + seq_printf(seq, "%d\t", + self->qos_rx.additional_bofs.value); + seq_printf(seq, "%d\t", + self->qos_rx.min_turn_time.value); + seq_printf(seq, "%d\n", + self->qos_rx.link_disc_time.value); + + return 0; +} + +static const struct seq_operations irlap_seq_ops = { + .start = irlap_seq_start, + .next = irlap_seq_next, + .stop = irlap_seq_stop, + .show = irlap_seq_show, +}; + +static int irlap_seq_open(struct inode *inode, struct file *file) +{ + if (irlap == NULL) + return -EINVAL; + + return seq_open_private(file, &irlap_seq_ops, + sizeof(struct irlap_iter_state)); +} + +const struct file_operations irlap_seq_fops = { + .owner = THIS_MODULE, + .open = irlap_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release_private, +}; + +#endif /* CONFIG_PROC_FS */ diff --git a/drivers/staging/irda/net/irlap_event.c b/drivers/staging/irda/net/irlap_event.c new file mode 100644 index 000000000000..0e1b4d79f745 --- /dev/null +++ b/drivers/staging/irda/net/irlap_event.c @@ -0,0 +1,2316 @@ +/********************************************************************* + * + * Filename: irlap_event.c + * Version: 0.9 + * Description: IrLAP state machine implementation + * Status: Experimental. + * Author: Dag Brattli <dag@brattli.net> + * Created at: Sat Aug 16 00:59:29 1997 + * Modified at: Sat Dec 25 21:07:57 1999 + * Modified by: Dag Brattli <dag@brattli.net> + * + * Copyright (c) 1998-2000 Dag Brattli <dag@brattli.net>, + * Copyright (c) 1998 Thomas Davis <ratbert@radiks.net> + * All Rights Reserved. + * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#include <linux/string.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/skbuff.h> +#include <linux/slab.h> + +#include <net/irda/irda.h> +#include <net/irda/irlap_event.h> + +#include <net/irda/timer.h> +#include <net/irda/irlap.h> +#include <net/irda/irlap_frame.h> +#include <net/irda/qos.h> +#include <net/irda/parameters.h> +#include <net/irda/irlmp.h> /* irlmp_flow_indication(), ... */ + +#include <net/irda/irda_device.h> + +#ifdef CONFIG_IRDA_FAST_RR +int sysctl_fast_poll_increase = 50; +#endif + +static int irlap_state_ndm (struct irlap_cb *self, IRLAP_EVENT event, + struct sk_buff *skb, struct irlap_info *info); +static int irlap_state_query (struct irlap_cb *self, IRLAP_EVENT event, + struct sk_buff *skb, struct irlap_info *info); +static int irlap_state_reply (struct irlap_cb *self, IRLAP_EVENT event, + struct sk_buff *skb, struct irlap_info *info); +static int irlap_state_conn (struct irlap_cb *self, IRLAP_EVENT event, + struct sk_buff *skb, struct irlap_info *info); +static int irlap_state_setup (struct irlap_cb *self, IRLAP_EVENT event, + struct sk_buff *skb, struct irlap_info *info); +static int irlap_state_offline(struct irlap_cb *self, IRLAP_EVENT event, + struct sk_buff *skb, struct irlap_info *info); +static int irlap_state_xmit_p (struct irlap_cb *self, IRLAP_EVENT event, + struct sk_buff *skb, struct irlap_info *info); +static int irlap_state_pclose (struct irlap_cb *self, IRLAP_EVENT event, + struct sk_buff *skb, struct irlap_info *info); +static int irlap_state_nrm_p (struct irlap_cb *self, IRLAP_EVENT event, + struct sk_buff *skb, struct irlap_info *info); +static int irlap_state_reset_wait(struct irlap_cb *self, IRLAP_EVENT event, + struct sk_buff *skb, struct irlap_info *info); +static int irlap_state_reset (struct irlap_cb *self, IRLAP_EVENT event, + struct sk_buff *skb, struct irlap_info *info); +static int irlap_state_nrm_s (struct irlap_cb *self, IRLAP_EVENT event, + struct sk_buff *skb, struct irlap_info *info); +static int irlap_state_xmit_s (struct irlap_cb *self, IRLAP_EVENT event, + struct sk_buff *skb, struct irlap_info *info); +static int irlap_state_sclose (struct irlap_cb *self, IRLAP_EVENT event, + struct sk_buff *skb, struct irlap_info *info); +static int irlap_state_reset_check(struct irlap_cb *, IRLAP_EVENT event, + struct sk_buff *, struct irlap_info *); + +static const char *const irlap_event[] __maybe_unused = { + "DISCOVERY_REQUEST", + "CONNECT_REQUEST", + "CONNECT_RESPONSE", + "DISCONNECT_REQUEST", + "DATA_REQUEST", + "RESET_REQUEST", + "RESET_RESPONSE", + "SEND_I_CMD", + "SEND_UI_FRAME", + "RECV_DISCOVERY_XID_CMD", + "RECV_DISCOVERY_XID_RSP", + "RECV_SNRM_CMD", + "RECV_TEST_CMD", + "RECV_TEST_RSP", + "RECV_UA_RSP", + "RECV_DM_RSP", + "RECV_RD_RSP", + "RECV_I_CMD", + "RECV_I_RSP", + "RECV_UI_FRAME", + "RECV_FRMR_RSP", + "RECV_RR_CMD", + "RECV_RR_RSP", + "RECV_RNR_CMD", + "RECV_RNR_RSP", + "RECV_REJ_CMD", + "RECV_REJ_RSP", + "RECV_SREJ_CMD", + "RECV_SREJ_RSP", + "RECV_DISC_CMD", + "SLOT_TIMER_EXPIRED", + "QUERY_TIMER_EXPIRED", + "FINAL_TIMER_EXPIRED", + "POLL_TIMER_EXPIRED", + "DISCOVERY_TIMER_EXPIRED", + "WD_TIMER_EXPIRED", + "BACKOFF_TIMER_EXPIRED", + "MEDIA_BUSY_TIMER_EXPIRED", +}; + +const char *const irlap_state[] = { + "LAP_NDM", + "LAP_QUERY", + "LAP_REPLY", + "LAP_CONN", + "LAP_SETUP", + "LAP_OFFLINE", + "LAP_XMIT_P", + "LAP_PCLOSE", + "LAP_NRM_P", + "LAP_RESET_WAIT", + "LAP_RESET", + "LAP_NRM_S", + "LAP_XMIT_S", + "LAP_SCLOSE", + "LAP_RESET_CHECK", +}; + +static int (*state[])(struct irlap_cb *self, IRLAP_EVENT event, + struct sk_buff *skb, struct irlap_info *info) = +{ + irlap_state_ndm, + irlap_state_query, + irlap_state_reply, + irlap_state_conn, + irlap_state_setup, + irlap_state_offline, + irlap_state_xmit_p, + irlap_state_pclose, + irlap_state_nrm_p, + irlap_state_reset_wait, + irlap_state_reset, + irlap_state_nrm_s, + irlap_state_xmit_s, + irlap_state_sclose, + irlap_state_reset_check, +}; + +/* + * Function irda_poll_timer_expired (data) + * + * Poll timer has expired. Normally we must now send a RR frame to the + * remote device + */ +static void irlap_poll_timer_expired(void *data) +{ + struct irlap_cb *self = (struct irlap_cb *) data; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return;); + + irlap_do_event(self, POLL_TIMER_EXPIRED, NULL, NULL); +} + +/* + * Calculate and set time before we will have to send back the pf bit + * to the peer. Use in primary. + * Make sure that state is XMIT_P/XMIT_S when calling this function + * (and that nobody messed up with the state). - Jean II + */ +static void irlap_start_poll_timer(struct irlap_cb *self, int timeout) +{ + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return;); + +#ifdef CONFIG_IRDA_FAST_RR + /* + * Send out the RR frames faster if our own transmit queue is empty, or + * if the peer is busy. The effect is a much faster conversation + */ + if (skb_queue_empty(&self->txq) || self->remote_busy) { + if (self->fast_RR == TRUE) { + /* + * Assert that the fast poll timer has not reached the + * normal poll timer yet + */ + if (self->fast_RR_timeout < timeout) { + /* + * FIXME: this should be a more configurable + * function + */ + self->fast_RR_timeout += + (sysctl_fast_poll_increase * HZ/1000); + + /* Use this fast(er) timeout instead */ + timeout = self->fast_RR_timeout; + } + } else { + self->fast_RR = TRUE; + + /* Start with just 0 ms */ + self->fast_RR_timeout = 0; + timeout = 0; + } + } else + self->fast_RR = FALSE; + + pr_debug("%s(), timeout=%d (%ld)\n", __func__, timeout, jiffies); +#endif /* CONFIG_IRDA_FAST_RR */ + + if (timeout == 0) + irlap_do_event(self, POLL_TIMER_EXPIRED, NULL, NULL); + else + irda_start_timer(&self->poll_timer, timeout, self, + irlap_poll_timer_expired); +} + +/* + * Function irlap_do_event (event, skb, info) + * + * Rushes through the state machine without any delay. If state == XMIT + * then send queued data frames. + */ +void irlap_do_event(struct irlap_cb *self, IRLAP_EVENT event, + struct sk_buff *skb, struct irlap_info *info) +{ + int ret; + + if (!self || self->magic != LAP_MAGIC) + return; + + pr_debug("%s(), event = %s, state = %s\n", __func__, + irlap_event[event], irlap_state[self->state]); + + ret = (*state[self->state])(self, event, skb, info); + + /* + * Check if there are any pending events that needs to be executed + */ + switch (self->state) { + case LAP_XMIT_P: /* FALLTHROUGH */ + case LAP_XMIT_S: + /* + * We just received the pf bit and are at the beginning + * of a new LAP transmit window. + * Check if there are any queued data frames, and do not + * try to disconnect link if we send any data frames, since + * that will change the state away form XMIT + */ + pr_debug("%s() : queue len = %d\n", __func__, + skb_queue_len(&self->txq)); + + if (!skb_queue_empty(&self->txq)) { + /* Prevent race conditions with irlap_data_request() */ + self->local_busy = TRUE; + + /* Theory of operation. + * We send frames up to when we fill the window or + * reach line capacity. Those frames will queue up + * in the device queue, and the driver will slowly + * send them. + * After each frame that we send, we poll the higher + * layer for more data. It's the right time to do + * that because the link layer need to perform the mtt + * and then send the first frame, so we can afford + * to send a bit of time in kernel space. + * The explicit flow indication allow to minimise + * buffers (== lower latency), to avoid higher layer + * polling via timers (== less context switches) and + * to implement a crude scheduler - Jean II */ + + /* Try to send away all queued data frames */ + while ((skb = skb_dequeue(&self->txq)) != NULL) { + /* Send one frame */ + ret = (*state[self->state])(self, SEND_I_CMD, + skb, NULL); + /* Drop reference count. + * It will be increase as needed in + * irlap_send_data_xxx() */ + kfree_skb(skb); + + /* Poll the higher layers for one more frame */ + irlmp_flow_indication(self->notify.instance, + FLOW_START); + + if (ret == -EPROTO) + break; /* Try again later! */ + } + /* Finished transmitting */ + self->local_busy = FALSE; + } else if (self->disconnect_pending) { + self->disconnect_pending = FALSE; + + ret = (*state[self->state])(self, DISCONNECT_REQUEST, + NULL, NULL); + } + break; +/* case LAP_NDM: */ +/* case LAP_CONN: */ +/* case LAP_RESET_WAIT: */ +/* case LAP_RESET_CHECK: */ + default: + break; + } +} + +/* + * Function irlap_state_ndm (event, skb, frame) + * + * NDM (Normal Disconnected Mode) state + * + */ +static int irlap_state_ndm(struct irlap_cb *self, IRLAP_EVENT event, + struct sk_buff *skb, struct irlap_info *info) +{ + discovery_t *discovery_rsp; + int ret = 0; + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); + + switch (event) { + case CONNECT_REQUEST: + IRDA_ASSERT(self->netdev != NULL, return -1;); + + if (self->media_busy) { + /* Note : this will never happen, because we test + * media busy in irlap_connect_request() and + * postpone the event... - Jean II */ + pr_debug("%s(), CONNECT_REQUEST: media busy!\n", + __func__); + + /* Always switch state before calling upper layers */ + irlap_next_state(self, LAP_NDM); + + irlap_disconnect_indication(self, LAP_MEDIA_BUSY); + } else { + irlap_send_snrm_frame(self, &self->qos_rx); + + /* Start Final-bit timer */ + irlap_start_final_timer(self, self->final_timeout); + + self->retry_count = 0; + irlap_next_state(self, LAP_SETUP); + } + break; + case RECV_SNRM_CMD: + /* Check if the frame contains and I field */ + if (info) { + self->daddr = info->daddr; + self->caddr = info->caddr; + + irlap_next_state(self, LAP_CONN); + + irlap_connect_indication(self, skb); + } else { + pr_debug("%s(), SNRM frame does not contain an I field!\n", + __func__); + } + break; + case DISCOVERY_REQUEST: + IRDA_ASSERT(info != NULL, return -1;); + + if (self->media_busy) { + pr_debug("%s(), DISCOVERY_REQUEST: media busy!\n", + __func__); + /* irlap->log.condition = MEDIA_BUSY; */ + + /* This will make IrLMP try again */ + irlap_discovery_confirm(self, NULL); + /* Note : the discovery log is not cleaned up here, + * it will be done in irlap_discovery_request() + * Jean II */ + return 0; + } + + self->S = info->S; + self->s = info->s; + irlap_send_discovery_xid_frame(self, info->S, info->s, TRUE, + info->discovery); + self->frame_sent = FALSE; + self->s++; + + irlap_start_slot_timer(self, self->slot_timeout); + irlap_next_state(self, LAP_QUERY); + break; + case RECV_DISCOVERY_XID_CMD: + IRDA_ASSERT(info != NULL, return -1;); + + /* Assert that this is not the final slot */ + if (info->s <= info->S) { + self->slot = irlap_generate_rand_time_slot(info->S, + info->s); + if (self->slot == info->s) { + discovery_rsp = irlmp_get_discovery_response(); + discovery_rsp->data.daddr = info->daddr; + + irlap_send_discovery_xid_frame(self, info->S, + self->slot, + FALSE, + discovery_rsp); + self->frame_sent = TRUE; + } else + self->frame_sent = FALSE; + + /* + * Go to reply state until end of discovery to + * inhibit our own transmissions. Set the timer + * to not stay forever there... Jean II + */ + irlap_start_query_timer(self, info->S, info->s); + irlap_next_state(self, LAP_REPLY); + } else { + /* This is the final slot. How is it possible ? + * This would happen is both discoveries are just slightly + * offset (if they are in sync, all packets are lost). + * Most often, all the discovery requests will be received + * in QUERY state (see my comment there), except for the + * last frame that will come here. + * The big trouble when it happen is that active discovery + * doesn't happen, because nobody answer the discoveries + * frame of the other guy, so the log shows up empty. + * What should we do ? + * Not much. It's too late to answer those discovery frames, + * so we just pass the info to IrLMP who will put it in the + * log (and post an event). + * Another cause would be devices that do discovery much + * slower than us, however the latest fixes should minimise + * those cases... + * Jean II + */ + pr_debug("%s(), Receiving final discovery request, missed the discovery slots :-(\n", + __func__); + + /* Last discovery request -> in the log */ + irlap_discovery_indication(self, info->discovery); + } + break; + case MEDIA_BUSY_TIMER_EXPIRED: + /* A bunch of events may be postponed because the media is + * busy (usually immediately after we close a connection), + * or while we are doing discovery (state query/reply). + * In all those cases, the media busy flag will be cleared + * when it's OK for us to process those postponed events. + * This event is not mentioned in the state machines in the + * IrLAP spec. It's because they didn't consider Ultra and + * postponing connection request is optional. + * Jean II */ +#ifdef CONFIG_IRDA_ULTRA + /* Send any pending Ultra frames if any */ + if (!skb_queue_empty(&self->txq_ultra)) { + /* We don't send the frame, just post an event. + * Also, previously this code was in timer.c... + * Jean II */ + ret = (*state[self->state])(self, SEND_UI_FRAME, + NULL, NULL); + } +#endif /* CONFIG_IRDA_ULTRA */ + /* Check if we should try to connect. + * This code was previously in irlap_do_event() */ + if (self->connect_pending) { + self->connect_pending = FALSE; + + /* This one *should* not pend in this state, except + * if a socket try to connect and immediately + * disconnect. - clear - Jean II */ + if (self->disconnect_pending) + irlap_disconnect_indication(self, LAP_DISC_INDICATION); + else + ret = (*state[self->state])(self, + CONNECT_REQUEST, + NULL, NULL); + self->disconnect_pending = FALSE; + } + /* Note : one way to test if this code works well (including + * media busy and small busy) is to create a user space + * application generating an Ultra packet every 3.05 sec (or + * 2.95 sec) and to see how it interact with discovery. + * It's fairly easy to check that no packet is lost, that the + * packets are postponed during discovery and that after + * discovery indication you have a 100ms "gap". + * As connection request and Ultra are now processed the same + * way, this avoid the tedious job of trying IrLAP connection + * in all those cases... + * Jean II */ + break; +#ifdef CONFIG_IRDA_ULTRA + case SEND_UI_FRAME: + { + int i; + /* Only allowed to repeat an operation twice */ + for (i=0; ((i<2) && (self->media_busy == FALSE)); i++) { + skb = skb_dequeue(&self->txq_ultra); + if (skb) + irlap_send_ui_frame(self, skb, CBROADCAST, + CMD_FRAME); + else + break; + /* irlap_send_ui_frame() won't increase skb reference + * count, so no dev_kfree_skb() - Jean II */ + } + if (i == 2) { + /* Force us to listen 500 ms again */ + irda_device_set_media_busy(self->netdev, TRUE); + } + break; + } + case RECV_UI_FRAME: + /* Only accept broadcast frames in NDM mode */ + if (info->caddr != CBROADCAST) { + pr_debug("%s(), not a broadcast frame!\n", + __func__); + } else + irlap_unitdata_indication(self, skb); + break; +#endif /* CONFIG_IRDA_ULTRA */ + case RECV_TEST_CMD: + /* Remove test frame header */ + skb_pull(skb, sizeof(struct test_frame)); + + /* + * Send response. This skb will not be sent out again, and + * will only be used to send out the same info as the cmd + */ + irlap_send_test_frame(self, CBROADCAST, info->daddr, skb); + break; + case RECV_TEST_RSP: + pr_debug("%s() not implemented!\n", __func__); + break; + default: + pr_debug("%s(), Unknown event %s\n", __func__, + irlap_event[event]); + + ret = -1; + break; + } + return ret; +} + +/* + * Function irlap_state_query (event, skb, info) + * + * QUERY state + * + */ +static int irlap_state_query(struct irlap_cb *self, IRLAP_EVENT event, + struct sk_buff *skb, struct irlap_info *info) +{ + int ret = 0; + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); + + switch (event) { + case RECV_DISCOVERY_XID_RSP: + IRDA_ASSERT(info != NULL, return -1;); + IRDA_ASSERT(info->discovery != NULL, return -1;); + + pr_debug("%s(), daddr=%08x\n", __func__, + info->discovery->data.daddr); + + if (!self->discovery_log) { + net_warn_ratelimited("%s: discovery log is gone! maybe the discovery timeout has been set too short?\n", + __func__); + break; + } + hashbin_insert(self->discovery_log, + (irda_queue_t *) info->discovery, + info->discovery->data.daddr, NULL); + + /* Keep state */ + /* irlap_next_state(self, LAP_QUERY); */ + + break; + case RECV_DISCOVERY_XID_CMD: + /* Yes, it is possible to receive those frames in this mode. + * Note that most often the last discovery request won't + * occur here but in NDM state (see my comment there). + * What should we do ? + * Not much. We are currently performing our own discovery, + * therefore we can't answer those frames. We don't want + * to change state either. We just pass the info to + * IrLMP who will put it in the log (and post an event). + * Jean II + */ + + IRDA_ASSERT(info != NULL, return -1;); + + pr_debug("%s(), Receiving discovery request (s = %d) while performing discovery :-(\n", + __func__, info->s); + + /* Last discovery request ? */ + if (info->s == 0xff) + irlap_discovery_indication(self, info->discovery); + break; + case SLOT_TIMER_EXPIRED: + /* + * Wait a little longer if we detect an incoming frame. This + * is not mentioned in the spec, but is a good thing to do, + * since we want to work even with devices that violate the + * timing requirements. + */ + if (irda_device_is_receiving(self->netdev) && !self->add_wait) { + pr_debug("%s(), device is slow to answer, waiting some more!\n", + __func__); + irlap_start_slot_timer(self, msecs_to_jiffies(10)); + self->add_wait = TRUE; + return ret; + } + self->add_wait = FALSE; + + if (self->s < self->S) { + irlap_send_discovery_xid_frame(self, self->S, + self->s, TRUE, + self->discovery_cmd); + self->s++; + irlap_start_slot_timer(self, self->slot_timeout); + + /* Keep state */ + irlap_next_state(self, LAP_QUERY); + } else { + /* This is the final slot! */ + irlap_send_discovery_xid_frame(self, self->S, 0xff, + TRUE, + self->discovery_cmd); + + /* Always switch state before calling upper layers */ + irlap_next_state(self, LAP_NDM); + + /* + * We are now finished with the discovery procedure, + * so now we must return the results + */ + irlap_discovery_confirm(self, self->discovery_log); + + /* IrLMP should now have taken care of the log */ + self->discovery_log = NULL; + } + break; + default: + pr_debug("%s(), Unknown event %s\n", __func__, + irlap_event[event]); + + ret = -1; + break; + } + return ret; +} + +/* + * Function irlap_state_reply (self, event, skb, info) + * + * REPLY, we have received a XID discovery frame from a device and we + * are waiting for the right time slot to send a response XID frame + * + */ +static int irlap_state_reply(struct irlap_cb *self, IRLAP_EVENT event, + struct sk_buff *skb, struct irlap_info *info) +{ + discovery_t *discovery_rsp; + int ret=0; + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); + + switch (event) { + case QUERY_TIMER_EXPIRED: + pr_debug("%s(), QUERY_TIMER_EXPIRED <%ld>\n", + __func__, jiffies); + irlap_next_state(self, LAP_NDM); + break; + case RECV_DISCOVERY_XID_CMD: + IRDA_ASSERT(info != NULL, return -1;); + /* Last frame? */ + if (info->s == 0xff) { + del_timer(&self->query_timer); + + /* info->log.condition = REMOTE; */ + + /* Always switch state before calling upper layers */ + irlap_next_state(self, LAP_NDM); + + irlap_discovery_indication(self, info->discovery); + } else { + /* If it's our slot, send our reply */ + if ((info->s >= self->slot) && (!self->frame_sent)) { + discovery_rsp = irlmp_get_discovery_response(); + discovery_rsp->data.daddr = info->daddr; + + irlap_send_discovery_xid_frame(self, info->S, + self->slot, + FALSE, + discovery_rsp); + + self->frame_sent = TRUE; + } + /* Readjust our timer to accommodate devices + * doing faster or slower discovery than us... + * Jean II */ + irlap_start_query_timer(self, info->S, info->s); + + /* Keep state */ + //irlap_next_state(self, LAP_REPLY); + } + break; + default: + pr_debug("%s(), Unknown event %d, %s\n", __func__, + event, irlap_event[event]); + + ret = -1; + break; + } + return ret; +} + +/* + * Function irlap_state_conn (event, skb, info) + * + * CONN, we have received a SNRM command and is waiting for the upper + * layer to accept or refuse connection + * + */ +static int irlap_state_conn(struct irlap_cb *self, IRLAP_EVENT event, + struct sk_buff *skb, struct irlap_info *info) +{ + int ret = 0; + + pr_debug("%s(), event=%s\n", __func__, irlap_event[event]); + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); + + switch (event) { + case CONNECT_RESPONSE: + skb_pull(skb, sizeof(struct snrm_frame)); + + IRDA_ASSERT(self->netdev != NULL, return -1;); + + irlap_qos_negotiate(self, skb); + + irlap_initiate_connection_state(self); + + /* + * Applying the parameters now will make sure we change speed + * *after* we have sent the next frame + */ + irlap_apply_connection_parameters(self, FALSE); + + /* + * Sending this frame will force a speed change after it has + * been sent (i.e. the frame will be sent at 9600). + */ + irlap_send_ua_response_frame(self, &self->qos_rx); + +#if 0 + /* + * We are allowed to send two frames, but this may increase + * the connect latency, so lets not do it for now. + */ + /* This is full of good intentions, but doesn't work in + * practice. + * After sending the first UA response, we switch the + * dongle to the negotiated speed, which is usually + * different than 9600 kb/s. + * From there, there is two solutions : + * 1) The other end has received the first UA response : + * it will set up the connection, move to state LAP_NRM_P, + * and will ignore and drop the second UA response. + * Actually, it's even worse : the other side will almost + * immediately send a RR that will likely collide with the + * UA response (depending on negotiated turnaround). + * 2) The other end has not received the first UA response, + * will stay at 9600 and will never see the second UA response. + * Jean II */ + irlap_send_ua_response_frame(self, &self->qos_rx); +#endif + + /* + * The WD-timer could be set to the duration of the P-timer + * for this case, but it is recommended to use twice the + * value (note 3 IrLAP p. 60). + */ + irlap_start_wd_timer(self, self->wd_timeout); + irlap_next_state(self, LAP_NRM_S); + + break; + case RECV_DISCOVERY_XID_CMD: + pr_debug("%s(), event RECV_DISCOVER_XID_CMD!\n", + __func__); + irlap_next_state(self, LAP_NDM); + + break; + case DISCONNECT_REQUEST: + pr_debug("%s(), Disconnect request!\n", __func__); + irlap_send_dm_frame(self); + irlap_next_state( self, LAP_NDM); + irlap_disconnect_indication(self, LAP_DISC_INDICATION); + break; + default: + pr_debug("%s(), Unknown event %d, %s\n", __func__, + event, irlap_event[event]); + + ret = -1; + break; + } + + return ret; +} + +/* + * Function irlap_state_setup (event, skb, frame) + * + * SETUP state, The local layer has transmitted a SNRM command frame to + * a remote peer layer and is awaiting a reply . + * + */ +static int irlap_state_setup(struct irlap_cb *self, IRLAP_EVENT event, + struct sk_buff *skb, struct irlap_info *info) +{ + int ret = 0; + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); + + switch (event) { + case FINAL_TIMER_EXPIRED: + if (self->retry_count < self->N3) { +/* + * Perform random backoff, Wait a random number of time units, minimum + * duration half the time taken to transmitt a SNRM frame, maximum duration + * 1.5 times the time taken to transmit a SNRM frame. So this time should + * between 15 msecs and 45 msecs. + */ + irlap_start_backoff_timer(self, msecs_to_jiffies(20 + + (jiffies % 30))); + } else { + /* Always switch state before calling upper layers */ + irlap_next_state(self, LAP_NDM); + + irlap_disconnect_indication(self, LAP_FOUND_NONE); + } + break; + case BACKOFF_TIMER_EXPIRED: + irlap_send_snrm_frame(self, &self->qos_rx); + irlap_start_final_timer(self, self->final_timeout); + self->retry_count++; + break; + case RECV_SNRM_CMD: + pr_debug("%s(), SNRM battle!\n", __func__); + + IRDA_ASSERT(skb != NULL, return 0;); + IRDA_ASSERT(info != NULL, return 0;); + + /* + * The device with the largest device address wins the battle + * (both have sent a SNRM command!) + */ + if (info &&(info->daddr > self->saddr)) { + del_timer(&self->final_timer); + irlap_initiate_connection_state(self); + + IRDA_ASSERT(self->netdev != NULL, return -1;); + + skb_pull(skb, sizeof(struct snrm_frame)); + + irlap_qos_negotiate(self, skb); + + /* Send UA frame and then change link settings */ + irlap_apply_connection_parameters(self, FALSE); + irlap_send_ua_response_frame(self, &self->qos_rx); + + irlap_next_state(self, LAP_NRM_S); + irlap_connect_confirm(self, skb); + + /* + * The WD-timer could be set to the duration of the + * P-timer for this case, but it is recommended + * to use twice the value (note 3 IrLAP p. 60). + */ + irlap_start_wd_timer(self, self->wd_timeout); + } else { + /* We just ignore the other device! */ + irlap_next_state(self, LAP_SETUP); + } + break; + case RECV_UA_RSP: + /* Stop F-timer */ + del_timer(&self->final_timer); + + /* Initiate connection state */ + irlap_initiate_connection_state(self); + + /* Negotiate connection parameters */ + IRDA_ASSERT(skb->len > 10, return -1;); + + skb_pull(skb, sizeof(struct ua_frame)); + + IRDA_ASSERT(self->netdev != NULL, return -1;); + + irlap_qos_negotiate(self, skb); + + /* Set the new link setting *now* (before the rr frame) */ + irlap_apply_connection_parameters(self, TRUE); + self->retry_count = 0; + + /* Wait for turnaround time to give a chance to the other + * device to be ready to receive us. + * Note : the time to switch speed is typically larger + * than the turnaround time, but as we don't have the other + * side speed switch time, that's our best guess... + * Jean II */ + irlap_wait_min_turn_around(self, &self->qos_tx); + + /* This frame will actually be sent at the new speed */ + irlap_send_rr_frame(self, CMD_FRAME); + + /* The timer is set to half the normal timer to quickly + * detect a failure to negotiate the new connection + * parameters. IrLAP 6.11.3.2, note 3. + * Note that currently we don't process this failure + * properly, as we should do a quick disconnect. + * Jean II */ + irlap_start_final_timer(self, self->final_timeout/2); + irlap_next_state(self, LAP_NRM_P); + + irlap_connect_confirm(self, skb); + break; + case RECV_DM_RSP: /* FALLTHROUGH */ + case RECV_DISC_CMD: + del_timer(&self->final_timer); + irlap_next_state(self, LAP_NDM); + + irlap_disconnect_indication(self, LAP_DISC_INDICATION); + break; + default: + pr_debug("%s(), Unknown event %d, %s\n", __func__, + event, irlap_event[event]); + + ret = -1; + break; + } + return ret; +} + +/* + * Function irlap_state_offline (self, event, skb, info) + * + * OFFLINE state, not used for now! + * + */ +static int irlap_state_offline(struct irlap_cb *self, IRLAP_EVENT event, + struct sk_buff *skb, struct irlap_info *info) +{ + pr_debug("%s(), Unknown event\n", __func__); + + return -1; +} + +/* + * Function irlap_state_xmit_p (self, event, skb, info) + * + * XMIT, Only the primary station has right to transmit, and we + * therefore do not expect to receive any transmissions from other + * stations. + * + */ +static int irlap_state_xmit_p(struct irlap_cb *self, IRLAP_EVENT event, + struct sk_buff *skb, struct irlap_info *info) +{ + int ret = 0; + + switch (event) { + case SEND_I_CMD: + /* + * Only send frame if send-window > 0. + */ + if ((self->window > 0) && (!self->remote_busy)) { + int nextfit; +#ifdef CONFIG_IRDA_DYNAMIC_WINDOW + struct sk_buff *skb_next; + + /* With DYNAMIC_WINDOW, we keep the window size + * maximum, and adapt on the packets we are sending. + * At 115k, we can send only 2 packets of 2048 bytes + * in a 500 ms turnaround. Without this option, we + * would always limit the window to 2. With this + * option, if we send smaller packets, we can send + * up to 7 of them (always depending on QoS). + * Jean II */ + + /* Look at the next skb. This is safe, as we are + * the only consumer of the Tx queue (if we are not, + * we have other problems) - Jean II */ + skb_next = skb_peek(&self->txq); + + /* Check if a subsequent skb exist and would fit in + * the current window (with respect to turnaround + * time). + * This allow us to properly mark the current packet + * with the pf bit, to avoid falling back on the + * second test below, and avoid waiting the + * end of the window and sending a extra RR. + * Note : (skb_next != NULL) <=> (skb_queue_len() > 0) + * Jean II */ + nextfit = ((skb_next != NULL) && + ((skb_next->len + skb->len) <= + self->bytes_left)); + + /* + * The current packet may not fit ! Because of test + * above, this should not happen any more !!! + * Test if we have transmitted more bytes over the + * link than its possible to do with the current + * speed and turn-around-time. + */ + if((!nextfit) && (skb->len > self->bytes_left)) { + pr_debug("%s(), Not allowed to transmit more bytes!\n", + __func__); + /* Requeue the skb */ + skb_queue_head(&self->txq, skb_get(skb)); + /* + * We should switch state to LAP_NRM_P, but + * that is not possible since we must be sure + * that we poll the other side. Since we have + * used up our time, the poll timer should + * trigger anyway now, so we just wait for it + * DB + */ + /* + * Sorry, but that's not totally true. If + * we send 2000B packets, we may wait another + * 1000B until our turnaround expire. That's + * why we need to be proactive in avoiding + * coming here. - Jean II + */ + return -EPROTO; + } + + /* Subtract space used by this skb */ + self->bytes_left -= skb->len; +#else /* CONFIG_IRDA_DYNAMIC_WINDOW */ + /* Window has been adjusted for the max packet + * size, so much simpler... - Jean II */ + nextfit = !skb_queue_empty(&self->txq); +#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */ + /* + * Send data with poll bit cleared only if window > 1 + * and there is more frames after this one to be sent + */ + if ((self->window > 1) && (nextfit)) { + /* More packet to send in current window */ + irlap_send_data_primary(self, skb); + irlap_next_state(self, LAP_XMIT_P); + } else { + /* Final packet of window */ + irlap_send_data_primary_poll(self, skb); + + /* + * Make sure state machine does not try to send + * any more frames + */ + ret = -EPROTO; + } +#ifdef CONFIG_IRDA_FAST_RR + /* Peer may want to reply immediately */ + self->fast_RR = FALSE; +#endif /* CONFIG_IRDA_FAST_RR */ + } else { + pr_debug("%s(), Unable to send! remote busy?\n", + __func__); + skb_queue_head(&self->txq, skb_get(skb)); + + /* + * The next ret is important, because it tells + * irlap_next_state _not_ to deliver more frames + */ + ret = -EPROTO; + } + break; + case POLL_TIMER_EXPIRED: + pr_debug("%s(), POLL_TIMER_EXPIRED <%ld>\n", + __func__, jiffies); + irlap_send_rr_frame(self, CMD_FRAME); + /* Return to NRM properly - Jean II */ + self->window = self->window_size; +#ifdef CONFIG_IRDA_DYNAMIC_WINDOW + /* Allowed to transmit a maximum number of bytes again. */ + self->bytes_left = self->line_capacity; +#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */ + irlap_start_final_timer(self, self->final_timeout); + irlap_next_state(self, LAP_NRM_P); + break; + case DISCONNECT_REQUEST: + del_timer(&self->poll_timer); + irlap_wait_min_turn_around(self, &self->qos_tx); + irlap_send_disc_frame(self); + irlap_flush_all_queues(self); + irlap_start_final_timer(self, self->final_timeout); + self->retry_count = 0; + irlap_next_state(self, LAP_PCLOSE); + break; + case DATA_REQUEST: + /* Nothing to do, irlap_do_event() will send the packet + * when we return... - Jean II */ + break; + default: + pr_debug("%s(), Unknown event %s\n", + __func__, irlap_event[event]); + + ret = -EINVAL; + break; + } + return ret; +} + +/* + * Function irlap_state_pclose (event, skb, info) + * + * PCLOSE state + */ +static int irlap_state_pclose(struct irlap_cb *self, IRLAP_EVENT event, + struct sk_buff *skb, struct irlap_info *info) +{ + int ret = 0; + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); + + switch (event) { + case RECV_UA_RSP: /* FALLTHROUGH */ + case RECV_DM_RSP: + del_timer(&self->final_timer); + + /* Set new link parameters */ + irlap_apply_default_connection_parameters(self); + + /* Always switch state before calling upper layers */ + irlap_next_state(self, LAP_NDM); + + irlap_disconnect_indication(self, LAP_DISC_INDICATION); + break; + case FINAL_TIMER_EXPIRED: + if (self->retry_count < self->N3) { + irlap_wait_min_turn_around(self, &self->qos_tx); + irlap_send_disc_frame(self); + irlap_start_final_timer(self, self->final_timeout); + self->retry_count++; + /* Keep state */ + } else { + irlap_apply_default_connection_parameters(self); + + /* Always switch state before calling upper layers */ + irlap_next_state(self, LAP_NDM); + + irlap_disconnect_indication(self, LAP_NO_RESPONSE); + } + break; + default: + pr_debug("%s(), Unknown event %d\n", __func__, event); + + ret = -1; + break; + } + return ret; +} + +/* + * Function irlap_state_nrm_p (self, event, skb, info) + * + * NRM_P (Normal Response Mode as Primary), The primary station has given + * permissions to a secondary station to transmit IrLAP resonse frames + * (by sending a frame with the P bit set). The primary station will not + * transmit any frames and is expecting to receive frames only from the + * secondary to which transmission permissions has been given. + */ +static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event, + struct sk_buff *skb, struct irlap_info *info) +{ + int ret = 0; + int ns_status; + int nr_status; + + switch (event) { + case RECV_I_RSP: /* Optimize for the common case */ + if (unlikely(skb->len <= LAP_ADDR_HEADER + LAP_CTRL_HEADER)) { + /* + * Input validation check: a stir4200/mcp2150 + * combination sometimes results in an empty i:rsp. + * This makes no sense; we can just ignore the frame + * and send an rr:cmd immediately. This happens before + * changing nr or ns so triggers a retransmit + */ + irlap_wait_min_turn_around(self, &self->qos_tx); + irlap_send_rr_frame(self, CMD_FRAME); + /* Keep state */ + break; + } + /* FIXME: must check for remote_busy below */ +#ifdef CONFIG_IRDA_FAST_RR + /* + * Reset the fast_RR so we can use the fast RR code with + * full speed the next time since peer may have more frames + * to transmitt + */ + self->fast_RR = FALSE; +#endif /* CONFIG_IRDA_FAST_RR */ + IRDA_ASSERT( info != NULL, return -1;); + + ns_status = irlap_validate_ns_received(self, info->ns); + nr_status = irlap_validate_nr_received(self, info->nr); + + /* + * Check for expected I(nformation) frame + */ + if ((ns_status == NS_EXPECTED) && (nr_status == NR_EXPECTED)) { + + /* Update Vr (next frame for us to receive) */ + self->vr = (self->vr + 1) % 8; + + /* Update Nr received, cleanup our retry queue */ + irlap_update_nr_received(self, info->nr); + + /* + * Got expected NR, so reset the + * retry_count. This is not done by IrLAP spec, + * which is strange! + */ + self->retry_count = 0; + self->ack_required = TRUE; + + /* poll bit cleared? */ + if (!info->pf) { + /* Keep state, do not move this line */ + irlap_next_state(self, LAP_NRM_P); + + irlap_data_indication(self, skb, FALSE); + } else { + /* No longer waiting for pf */ + del_timer(&self->final_timer); + + irlap_wait_min_turn_around(self, &self->qos_tx); + + /* Call higher layer *before* changing state + * to give them a chance to send data in the + * next LAP frame. + * Jean II */ + irlap_data_indication(self, skb, FALSE); + + /* XMIT states are the most dangerous state + * to be in, because user requests are + * processed directly and may change state. + * On the other hand, in NDM_P, those + * requests are queued and we will process + * them when we return to irlap_do_event(). + * Jean II + */ + irlap_next_state(self, LAP_XMIT_P); + + /* This is the last frame. + * Make sure it's always called in XMIT state. + * - Jean II */ + irlap_start_poll_timer(self, self->poll_timeout); + } + break; + + } + /* Unexpected next to send (Ns) */ + if ((ns_status == NS_UNEXPECTED) && (nr_status == NR_EXPECTED)) + { + if (!info->pf) { + irlap_update_nr_received(self, info->nr); + + /* + * Wait until the last frame before doing + * anything + */ + + /* Keep state */ + irlap_next_state(self, LAP_NRM_P); + } else { + pr_debug("%s(), missing or duplicate frame!\n", + __func__); + + /* Update Nr received */ + irlap_update_nr_received(self, info->nr); + + irlap_wait_min_turn_around(self, &self->qos_tx); + irlap_send_rr_frame(self, CMD_FRAME); + + self->ack_required = FALSE; + + irlap_start_final_timer(self, self->final_timeout); + irlap_next_state(self, LAP_NRM_P); + } + break; + } + /* + * Unexpected next to receive (Nr) + */ + if ((ns_status == NS_EXPECTED) && (nr_status == NR_UNEXPECTED)) + { + if (info->pf) { + self->vr = (self->vr + 1) % 8; + + /* Update Nr received */ + irlap_update_nr_received(self, info->nr); + + /* Resend rejected frames */ + irlap_resend_rejected_frames(self, CMD_FRAME); + + self->ack_required = FALSE; + + /* Make sure we account for the time + * to transmit our frames. See comemnts + * in irlap_send_data_primary_poll(). + * Jean II */ + irlap_start_final_timer(self, 2 * self->final_timeout); + + /* Keep state, do not move this line */ + irlap_next_state(self, LAP_NRM_P); + + irlap_data_indication(self, skb, FALSE); + } else { + /* + * Do not resend frames until the last + * frame has arrived from the other + * device. This is not documented in + * IrLAP!! + */ + self->vr = (self->vr + 1) % 8; + + /* Update Nr received */ + irlap_update_nr_received(self, info->nr); + + self->ack_required = FALSE; + + /* Keep state, do not move this line!*/ + irlap_next_state(self, LAP_NRM_P); + + irlap_data_indication(self, skb, FALSE); + } + break; + } + /* + * Unexpected next to send (Ns) and next to receive (Nr) + * Not documented by IrLAP! + */ + if ((ns_status == NS_UNEXPECTED) && + (nr_status == NR_UNEXPECTED)) + { + pr_debug("%s(), unexpected nr and ns!\n", + __func__); + if (info->pf) { + /* Resend rejected frames */ + irlap_resend_rejected_frames(self, CMD_FRAME); + + /* Give peer some time to retransmit! + * But account for our own Tx. */ + irlap_start_final_timer(self, 2 * self->final_timeout); + + /* Keep state, do not move this line */ + irlap_next_state(self, LAP_NRM_P); + } else { + /* Update Nr received */ + /* irlap_update_nr_received( info->nr); */ + + self->ack_required = FALSE; + } + break; + } + + /* + * Invalid NR or NS + */ + if ((nr_status == NR_INVALID) || (ns_status == NS_INVALID)) { + if (info->pf) { + del_timer(&self->final_timer); + + irlap_next_state(self, LAP_RESET_WAIT); + + irlap_disconnect_indication(self, LAP_RESET_INDICATION); + self->xmitflag = TRUE; + } else { + del_timer(&self->final_timer); + + irlap_disconnect_indication(self, LAP_RESET_INDICATION); + + self->xmitflag = FALSE; + } + break; + } + pr_debug("%s(), Not implemented!\n", __func__); + pr_debug("%s(), event=%s, ns_status=%d, nr_status=%d\n", + __func__, irlap_event[event], ns_status, nr_status); + break; + case RECV_UI_FRAME: + /* Poll bit cleared? */ + if (!info->pf) { + irlap_data_indication(self, skb, TRUE); + irlap_next_state(self, LAP_NRM_P); + } else { + del_timer(&self->final_timer); + irlap_data_indication(self, skb, TRUE); + irlap_next_state(self, LAP_XMIT_P); + pr_debug("%s: RECV_UI_FRAME: next state %s\n", + __func__, irlap_state[self->state]); + irlap_start_poll_timer(self, self->poll_timeout); + } + break; + case RECV_RR_RSP: + /* + * If you get a RR, the remote isn't busy anymore, + * no matter what the NR + */ + self->remote_busy = FALSE; + + /* Stop final timer */ + del_timer(&self->final_timer); + + /* + * Nr as expected? + */ + ret = irlap_validate_nr_received(self, info->nr); + if (ret == NR_EXPECTED) { + /* Update Nr received */ + irlap_update_nr_received(self, info->nr); + + /* + * Got expected NR, so reset the retry_count. This + * is not done by the IrLAP standard , which is + * strange! DB. + */ + self->retry_count = 0; + irlap_wait_min_turn_around(self, &self->qos_tx); + + irlap_next_state(self, LAP_XMIT_P); + + /* Start poll timer */ + irlap_start_poll_timer(self, self->poll_timeout); + } else if (ret == NR_UNEXPECTED) { + IRDA_ASSERT(info != NULL, return -1;); + /* + * Unexpected nr! + */ + + /* Update Nr received */ + irlap_update_nr_received(self, info->nr); + + pr_debug("RECV_RR_FRAME: Retrans:%d, nr=%d, va=%d, vs=%d, vr=%d\n", + self->retry_count, info->nr, self->va, + self->vs, self->vr); + + /* Resend rejected frames */ + irlap_resend_rejected_frames(self, CMD_FRAME); + irlap_start_final_timer(self, self->final_timeout * 2); + + irlap_next_state(self, LAP_NRM_P); + } else if (ret == NR_INVALID) { + pr_debug("%s(), Received RR with invalid nr !\n", + __func__); + + irlap_next_state(self, LAP_RESET_WAIT); + + irlap_disconnect_indication(self, LAP_RESET_INDICATION); + self->xmitflag = TRUE; + } + break; + case RECV_RNR_RSP: + IRDA_ASSERT(info != NULL, return -1;); + + /* Stop final timer */ + del_timer(&self->final_timer); + self->remote_busy = TRUE; + + /* Update Nr received */ + irlap_update_nr_received(self, info->nr); + irlap_next_state(self, LAP_XMIT_P); + + /* Start poll timer */ + irlap_start_poll_timer(self, self->poll_timeout); + break; + case RECV_FRMR_RSP: + del_timer(&self->final_timer); + self->xmitflag = TRUE; + irlap_next_state(self, LAP_RESET_WAIT); + irlap_reset_indication(self); + break; + case FINAL_TIMER_EXPIRED: + /* + * We are allowed to wait for additional 300 ms if + * final timer expires when we are in the middle + * of receiving a frame (page 45, IrLAP). Check that + * we only do this once for each frame. + */ + if (irda_device_is_receiving(self->netdev) && !self->add_wait) { + pr_debug("FINAL_TIMER_EXPIRED when receiving a frame! Waiting a little bit more!\n"); + irlap_start_final_timer(self, msecs_to_jiffies(300)); + + /* + * Don't allow this to happen one more time in a row, + * or else we can get a pretty tight loop here if + * if we only receive half a frame. DB. + */ + self->add_wait = TRUE; + break; + } + self->add_wait = FALSE; + + /* N2 is the disconnect timer. Until we reach it, we retry */ + if (self->retry_count < self->N2) { + if (skb_peek(&self->wx_list) == NULL) { + /* Retry sending the pf bit to the secondary */ + pr_debug("nrm_p: resending rr"); + irlap_wait_min_turn_around(self, &self->qos_tx); + irlap_send_rr_frame(self, CMD_FRAME); + } else { + pr_debug("nrm_p: resend frames"); + irlap_resend_rejected_frames(self, CMD_FRAME); + } + + irlap_start_final_timer(self, self->final_timeout); + self->retry_count++; + pr_debug("irlap_state_nrm_p: FINAL_TIMER_EXPIRED: retry_count=%d\n", + self->retry_count); + + /* Early warning event. I'm using a pretty liberal + * interpretation of the spec and generate an event + * every time the timer is multiple of N1 (and not + * only the first time). This allow application + * to know precisely if connectivity restart... + * Jean II */ + if((self->retry_count % self->N1) == 0) + irlap_status_indication(self, + STATUS_NO_ACTIVITY); + + /* Keep state */ + } else { + irlap_apply_default_connection_parameters(self); + + /* Always switch state before calling upper layers */ + irlap_next_state(self, LAP_NDM); + irlap_disconnect_indication(self, LAP_NO_RESPONSE); + } + break; + case RECV_REJ_RSP: + irlap_update_nr_received(self, info->nr); + if (self->remote_busy) { + irlap_wait_min_turn_around(self, &self->qos_tx); + irlap_send_rr_frame(self, CMD_FRAME); + } else + irlap_resend_rejected_frames(self, CMD_FRAME); + irlap_start_final_timer(self, 2 * self->final_timeout); + break; + case RECV_SREJ_RSP: + irlap_update_nr_received(self, info->nr); + if (self->remote_busy) { + irlap_wait_min_turn_around(self, &self->qos_tx); + irlap_send_rr_frame(self, CMD_FRAME); + } else + irlap_resend_rejected_frame(self, CMD_FRAME); + irlap_start_final_timer(self, 2 * self->final_timeout); + break; + case RECV_RD_RSP: + pr_debug("%s(), RECV_RD_RSP\n", __func__); + + irlap_flush_all_queues(self); + irlap_next_state(self, LAP_XMIT_P); + /* Call back the LAP state machine to do a proper disconnect */ + irlap_disconnect_request(self); + break; + default: + pr_debug("%s(), Unknown event %s\n", + __func__, irlap_event[event]); + + ret = -1; + break; + } + return ret; +} + +/* + * Function irlap_state_reset_wait (event, skb, info) + * + * We have informed the service user of a reset condition, and is + * awaiting reset of disconnect request. + * + */ +static int irlap_state_reset_wait(struct irlap_cb *self, IRLAP_EVENT event, + struct sk_buff *skb, struct irlap_info *info) +{ + int ret = 0; + + pr_debug("%s(), event = %s\n", __func__, irlap_event[event]); + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); + + switch (event) { + case RESET_REQUEST: + if (self->xmitflag) { + irlap_wait_min_turn_around(self, &self->qos_tx); + irlap_send_snrm_frame(self, NULL); + irlap_start_final_timer(self, self->final_timeout); + irlap_next_state(self, LAP_RESET); + } else { + irlap_start_final_timer(self, self->final_timeout); + irlap_next_state(self, LAP_RESET); + } + break; + case DISCONNECT_REQUEST: + irlap_wait_min_turn_around( self, &self->qos_tx); + irlap_send_disc_frame( self); + irlap_flush_all_queues( self); + irlap_start_final_timer( self, self->final_timeout); + self->retry_count = 0; + irlap_next_state( self, LAP_PCLOSE); + break; + default: + pr_debug("%s(), Unknown event %s\n", __func__, + irlap_event[event]); + + ret = -1; + break; + } + return ret; +} + +/* + * Function irlap_state_reset (self, event, skb, info) + * + * We have sent a SNRM reset command to the peer layer, and is awaiting + * reply. + * + */ +static int irlap_state_reset(struct irlap_cb *self, IRLAP_EVENT event, + struct sk_buff *skb, struct irlap_info *info) +{ + int ret = 0; + + pr_debug("%s(), event = %s\n", __func__, irlap_event[event]); + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); + + switch (event) { + case RECV_DISC_CMD: + del_timer(&self->final_timer); + + irlap_apply_default_connection_parameters(self); + + /* Always switch state before calling upper layers */ + irlap_next_state(self, LAP_NDM); + + irlap_disconnect_indication(self, LAP_NO_RESPONSE); + + break; + case RECV_UA_RSP: + del_timer(&self->final_timer); + + /* Initiate connection state */ + irlap_initiate_connection_state(self); + + irlap_reset_confirm(); + + self->remote_busy = FALSE; + + irlap_next_state(self, LAP_XMIT_P); + + irlap_start_poll_timer(self, self->poll_timeout); + + break; + case FINAL_TIMER_EXPIRED: + if (self->retry_count < 3) { + irlap_wait_min_turn_around(self, &self->qos_tx); + + IRDA_ASSERT(self->netdev != NULL, return -1;); + irlap_send_snrm_frame(self, self->qos_dev); + + self->retry_count++; /* Experimental!! */ + + irlap_start_final_timer(self, self->final_timeout); + irlap_next_state(self, LAP_RESET); + } else if (self->retry_count >= self->N3) { + irlap_apply_default_connection_parameters(self); + + /* Always switch state before calling upper layers */ + irlap_next_state(self, LAP_NDM); + + irlap_disconnect_indication(self, LAP_NO_RESPONSE); + } + break; + case RECV_SNRM_CMD: + /* + * SNRM frame is not allowed to contain an I-field in this + * state + */ + if (!info) { + pr_debug("%s(), RECV_SNRM_CMD\n", __func__); + irlap_initiate_connection_state(self); + irlap_wait_min_turn_around(self, &self->qos_tx); + irlap_send_ua_response_frame(self, &self->qos_rx); + irlap_reset_confirm(); + irlap_start_wd_timer(self, self->wd_timeout); + irlap_next_state(self, LAP_NDM); + } else { + pr_debug("%s(), SNRM frame contained an I field!\n", + __func__); + } + break; + default: + pr_debug("%s(), Unknown event %s\n", + __func__, irlap_event[event]); + + ret = -1; + break; + } + return ret; +} + +/* + * Function irlap_state_xmit_s (event, skb, info) + * + * XMIT_S, The secondary station has been given the right to transmit, + * and we therefore do not expect to receive any transmissions from other + * stations. + */ +static int irlap_state_xmit_s(struct irlap_cb *self, IRLAP_EVENT event, + struct sk_buff *skb, struct irlap_info *info) +{ + int ret = 0; + + pr_debug("%s(), event=%s\n", __func__, irlap_event[event]); + + IRDA_ASSERT(self != NULL, return -ENODEV;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return -EBADR;); + + switch (event) { + case SEND_I_CMD: + /* + * Send frame only if send window > 0 + */ + if ((self->window > 0) && (!self->remote_busy)) { + int nextfit; +#ifdef CONFIG_IRDA_DYNAMIC_WINDOW + struct sk_buff *skb_next; + + /* + * Same deal as in irlap_state_xmit_p(), so see + * the comments at that point. + * We are the secondary, so there are only subtle + * differences. - Jean II + */ + + /* Check if a subsequent skb exist and would fit in + * the current window (with respect to turnaround + * time). - Jean II */ + skb_next = skb_peek(&self->txq); + nextfit = ((skb_next != NULL) && + ((skb_next->len + skb->len) <= + self->bytes_left)); + + /* + * Test if we have transmitted more bytes over the + * link than its possible to do with the current + * speed and turn-around-time. + */ + if((!nextfit) && (skb->len > self->bytes_left)) { + pr_debug("%s(), Not allowed to transmit more bytes!\n", + __func__); + /* Requeue the skb */ + skb_queue_head(&self->txq, skb_get(skb)); + + /* + * Switch to NRM_S, this is only possible + * when we are in secondary mode, since we + * must be sure that we don't miss any RR + * frames + */ + self->window = self->window_size; + self->bytes_left = self->line_capacity; + irlap_start_wd_timer(self, self->wd_timeout); + + irlap_next_state(self, LAP_NRM_S); + /* Slight difference with primary : + * here we would wait for the other side to + * expire the turnaround. - Jean II */ + + return -EPROTO; /* Try again later */ + } + /* Subtract space used by this skb */ + self->bytes_left -= skb->len; +#else /* CONFIG_IRDA_DYNAMIC_WINDOW */ + /* Window has been adjusted for the max packet + * size, so much simpler... - Jean II */ + nextfit = !skb_queue_empty(&self->txq); +#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */ + /* + * Send data with final bit cleared only if window > 1 + * and there is more frames to be sent + */ + if ((self->window > 1) && (nextfit)) { + irlap_send_data_secondary(self, skb); + irlap_next_state(self, LAP_XMIT_S); + } else { + irlap_send_data_secondary_final(self, skb); + irlap_next_state(self, LAP_NRM_S); + + /* + * Make sure state machine does not try to send + * any more frames + */ + ret = -EPROTO; + } + } else { + pr_debug("%s(), Unable to send!\n", __func__); + skb_queue_head(&self->txq, skb_get(skb)); + ret = -EPROTO; + } + break; + case DISCONNECT_REQUEST: + irlap_send_rd_frame(self); + irlap_flush_all_queues(self); + irlap_start_wd_timer(self, self->wd_timeout); + irlap_next_state(self, LAP_SCLOSE); + break; + case DATA_REQUEST: + /* Nothing to do, irlap_do_event() will send the packet + * when we return... - Jean II */ + break; + default: + pr_debug("%s(), Unknown event %s\n", __func__, + irlap_event[event]); + + ret = -EINVAL; + break; + } + return ret; +} + +/* + * Function irlap_state_nrm_s (event, skb, info) + * + * NRM_S (Normal Response Mode as Secondary) state, in this state we are + * expecting to receive frames from the primary station + * + */ +static int irlap_state_nrm_s(struct irlap_cb *self, IRLAP_EVENT event, + struct sk_buff *skb, struct irlap_info *info) +{ + int ns_status; + int nr_status; + int ret = 0; + + pr_debug("%s(), event=%s\n", __func__, irlap_event[event]); + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); + + switch (event) { + case RECV_I_CMD: /* Optimize for the common case */ + /* FIXME: must check for remote_busy below */ + pr_debug("%s(), event=%s nr=%d, vs=%d, ns=%d, vr=%d, pf=%d\n", + __func__, irlap_event[event], info->nr, + self->vs, info->ns, self->vr, info->pf); + + self->retry_count = 0; + + ns_status = irlap_validate_ns_received(self, info->ns); + nr_status = irlap_validate_nr_received(self, info->nr); + /* + * Check for expected I(nformation) frame + */ + if ((ns_status == NS_EXPECTED) && (nr_status == NR_EXPECTED)) { + + /* Update Vr (next frame for us to receive) */ + self->vr = (self->vr + 1) % 8; + + /* Update Nr received */ + irlap_update_nr_received(self, info->nr); + + /* + * poll bit cleared? + */ + if (!info->pf) { + + self->ack_required = TRUE; + + /* + * Starting WD-timer here is optional, but + * not recommended. Note 6 IrLAP p. 83 + */ +#if 0 + irda_start_timer(WD_TIMER, self->wd_timeout); +#endif + /* Keep state, do not move this line */ + irlap_next_state(self, LAP_NRM_S); + + irlap_data_indication(self, skb, FALSE); + break; + } else { + /* + * We should wait before sending RR, and + * also before changing to XMIT_S + * state. (note 1, IrLAP p. 82) + */ + irlap_wait_min_turn_around(self, &self->qos_tx); + + /* + * Give higher layers a chance to + * immediately reply with some data before + * we decide if we should send a RR frame + * or not + */ + irlap_data_indication(self, skb, FALSE); + + /* Any pending data requests? */ + if (!skb_queue_empty(&self->txq) && + (self->window > 0)) + { + self->ack_required = TRUE; + + del_timer(&self->wd_timer); + + irlap_next_state(self, LAP_XMIT_S); + } else { + irlap_send_rr_frame(self, RSP_FRAME); + irlap_start_wd_timer(self, + self->wd_timeout); + + /* Keep the state */ + irlap_next_state(self, LAP_NRM_S); + } + break; + } + } + /* + * Check for Unexpected next to send (Ns) + */ + if ((ns_status == NS_UNEXPECTED) && (nr_status == NR_EXPECTED)) + { + /* Unexpected next to send, with final bit cleared */ + if (!info->pf) { + irlap_update_nr_received(self, info->nr); + + irlap_start_wd_timer(self, self->wd_timeout); + } else { + /* Update Nr received */ + irlap_update_nr_received(self, info->nr); + + irlap_wait_min_turn_around(self, &self->qos_tx); + irlap_send_rr_frame(self, RSP_FRAME); + + irlap_start_wd_timer(self, self->wd_timeout); + } + break; + } + + /* + * Unexpected Next to Receive(NR) ? + */ + if ((ns_status == NS_EXPECTED) && (nr_status == NR_UNEXPECTED)) + { + if (info->pf) { + pr_debug("RECV_I_RSP: frame(s) lost\n"); + + self->vr = (self->vr + 1) % 8; + + /* Update Nr received */ + irlap_update_nr_received(self, info->nr); + + /* Resend rejected frames */ + irlap_resend_rejected_frames(self, RSP_FRAME); + + /* Keep state, do not move this line */ + irlap_next_state(self, LAP_NRM_S); + + irlap_data_indication(self, skb, FALSE); + irlap_start_wd_timer(self, self->wd_timeout); + break; + } + /* + * This is not documented in IrLAP!! Unexpected NR + * with poll bit cleared + */ + if (!info->pf) { + self->vr = (self->vr + 1) % 8; + + /* Update Nr received */ + irlap_update_nr_received(self, info->nr); + + /* Keep state, do not move this line */ + irlap_next_state(self, LAP_NRM_S); + + irlap_data_indication(self, skb, FALSE); + irlap_start_wd_timer(self, self->wd_timeout); + } + break; + } + + if (ret == NR_INVALID) { + pr_debug("NRM_S, NR_INVALID not implemented!\n"); + } + if (ret == NS_INVALID) { + pr_debug("NRM_S, NS_INVALID not implemented!\n"); + } + break; + case RECV_UI_FRAME: + /* + * poll bit cleared? + */ + if (!info->pf) { + irlap_data_indication(self, skb, TRUE); + irlap_next_state(self, LAP_NRM_S); /* Keep state */ + } else { + /* + * Any pending data requests? + */ + if (!skb_queue_empty(&self->txq) && + (self->window > 0) && !self->remote_busy) + { + irlap_data_indication(self, skb, TRUE); + + del_timer(&self->wd_timer); + + irlap_next_state(self, LAP_XMIT_S); + } else { + irlap_data_indication(self, skb, TRUE); + + irlap_wait_min_turn_around(self, &self->qos_tx); + + irlap_send_rr_frame(self, RSP_FRAME); + self->ack_required = FALSE; + + irlap_start_wd_timer(self, self->wd_timeout); + + /* Keep the state */ + irlap_next_state(self, LAP_NRM_S); + } + } + break; + case RECV_RR_CMD: + self->retry_count = 0; + + /* + * Nr as expected? + */ + nr_status = irlap_validate_nr_received(self, info->nr); + if (nr_status == NR_EXPECTED) { + if (!skb_queue_empty(&self->txq) && + (self->window > 0)) { + self->remote_busy = FALSE; + + /* Update Nr received */ + irlap_update_nr_received(self, info->nr); + del_timer(&self->wd_timer); + + irlap_wait_min_turn_around(self, &self->qos_tx); + irlap_next_state(self, LAP_XMIT_S); + } else { + self->remote_busy = FALSE; + /* Update Nr received */ + irlap_update_nr_received(self, info->nr); + irlap_wait_min_turn_around(self, &self->qos_tx); + irlap_start_wd_timer(self, self->wd_timeout); + + /* Note : if the link is idle (this case), + * we never go in XMIT_S, so we never get a + * chance to process any DISCONNECT_REQUEST. + * Do it now ! - Jean II */ + if (self->disconnect_pending) { + /* Disconnect */ + irlap_send_rd_frame(self); + irlap_flush_all_queues(self); + + irlap_next_state(self, LAP_SCLOSE); + } else { + /* Just send back pf bit */ + irlap_send_rr_frame(self, RSP_FRAME); + + irlap_next_state(self, LAP_NRM_S); + } + } + } else if (nr_status == NR_UNEXPECTED) { + self->remote_busy = FALSE; + irlap_update_nr_received(self, info->nr); + irlap_resend_rejected_frames(self, RSP_FRAME); + + irlap_start_wd_timer(self, self->wd_timeout); + + /* Keep state */ + irlap_next_state(self, LAP_NRM_S); + } else { + pr_debug("%s(), invalid nr not implemented!\n", + __func__); + } + break; + case RECV_SNRM_CMD: + /* SNRM frame is not allowed to contain an I-field */ + if (!info) { + del_timer(&self->wd_timer); + pr_debug("%s(), received SNRM cmd\n", __func__); + irlap_next_state(self, LAP_RESET_CHECK); + + irlap_reset_indication(self); + } else { + pr_debug("%s(), SNRM frame contained an I-field!\n", + __func__); + + } + break; + case RECV_REJ_CMD: + irlap_update_nr_received(self, info->nr); + if (self->remote_busy) { + irlap_wait_min_turn_around(self, &self->qos_tx); + irlap_send_rr_frame(self, RSP_FRAME); + } else + irlap_resend_rejected_frames(self, RSP_FRAME); + irlap_start_wd_timer(self, self->wd_timeout); + break; + case RECV_SREJ_CMD: + irlap_update_nr_received(self, info->nr); + if (self->remote_busy) { + irlap_wait_min_turn_around(self, &self->qos_tx); + irlap_send_rr_frame(self, RSP_FRAME); + } else + irlap_resend_rejected_frame(self, RSP_FRAME); + irlap_start_wd_timer(self, self->wd_timeout); + break; + case WD_TIMER_EXPIRED: + /* + * Wait until retry_count * n matches negotiated threshold/ + * disconnect time (note 2 in IrLAP p. 82) + * + * Similar to irlap_state_nrm_p() -> FINAL_TIMER_EXPIRED + * Note : self->wd_timeout = (self->final_timeout * 2), + * which explain why we use (self->N2 / 2) here !!! + * Jean II + */ + pr_debug("%s(), retry_count = %d\n", __func__, + self->retry_count); + + if (self->retry_count < (self->N2 / 2)) { + /* No retry, just wait for primary */ + irlap_start_wd_timer(self, self->wd_timeout); + self->retry_count++; + + if((self->retry_count % (self->N1 / 2)) == 0) + irlap_status_indication(self, + STATUS_NO_ACTIVITY); + } else { + irlap_apply_default_connection_parameters(self); + + /* Always switch state before calling upper layers */ + irlap_next_state(self, LAP_NDM); + irlap_disconnect_indication(self, LAP_NO_RESPONSE); + } + break; + case RECV_DISC_CMD: + /* Always switch state before calling upper layers */ + irlap_next_state(self, LAP_NDM); + + /* Send disconnect response */ + irlap_wait_min_turn_around(self, &self->qos_tx); + irlap_send_ua_response_frame(self, NULL); + + del_timer(&self->wd_timer); + irlap_flush_all_queues(self); + /* Set default link parameters */ + irlap_apply_default_connection_parameters(self); + + irlap_disconnect_indication(self, LAP_DISC_INDICATION); + break; + case RECV_DISCOVERY_XID_CMD: + irlap_wait_min_turn_around(self, &self->qos_tx); + irlap_send_rr_frame(self, RSP_FRAME); + self->ack_required = TRUE; + irlap_start_wd_timer(self, self->wd_timeout); + irlap_next_state(self, LAP_NRM_S); + + break; + case RECV_TEST_CMD: + /* Remove test frame header (only LAP header in NRM) */ + skb_pull(skb, LAP_ADDR_HEADER + LAP_CTRL_HEADER); + + irlap_wait_min_turn_around(self, &self->qos_tx); + irlap_start_wd_timer(self, self->wd_timeout); + + /* Send response (info will be copied) */ + irlap_send_test_frame(self, self->caddr, info->daddr, skb); + break; + default: + pr_debug("%s(), Unknown event %d, (%s)\n", __func__, + event, irlap_event[event]); + + ret = -EINVAL; + break; + } + return ret; +} + +/* + * Function irlap_state_sclose (self, event, skb, info) + */ +static int irlap_state_sclose(struct irlap_cb *self, IRLAP_EVENT event, + struct sk_buff *skb, struct irlap_info *info) +{ + IRDA_ASSERT(self != NULL, return -ENODEV;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return -EBADR;); + + switch (event) { + case RECV_DISC_CMD: + /* Always switch state before calling upper layers */ + irlap_next_state(self, LAP_NDM); + + /* Send disconnect response */ + irlap_wait_min_turn_around(self, &self->qos_tx); + irlap_send_ua_response_frame(self, NULL); + + del_timer(&self->wd_timer); + /* Set default link parameters */ + irlap_apply_default_connection_parameters(self); + + irlap_disconnect_indication(self, LAP_DISC_INDICATION); + break; + case RECV_DM_RSP: + /* IrLAP-1.1 p.82: in SCLOSE, S and I type RSP frames + * shall take us down into default NDM state, like DM_RSP + */ + case RECV_RR_RSP: + case RECV_RNR_RSP: + case RECV_REJ_RSP: + case RECV_SREJ_RSP: + case RECV_I_RSP: + /* Always switch state before calling upper layers */ + irlap_next_state(self, LAP_NDM); + + del_timer(&self->wd_timer); + irlap_apply_default_connection_parameters(self); + + irlap_disconnect_indication(self, LAP_DISC_INDICATION); + break; + case WD_TIMER_EXPIRED: + /* Always switch state before calling upper layers */ + irlap_next_state(self, LAP_NDM); + + irlap_apply_default_connection_parameters(self); + + irlap_disconnect_indication(self, LAP_DISC_INDICATION); + break; + default: + /* IrLAP-1.1 p.82: in SCLOSE, basically any received frame + * with pf=1 shall restart the wd-timer and resend the rd:rsp + */ + if (info != NULL && info->pf) { + del_timer(&self->wd_timer); + irlap_wait_min_turn_around(self, &self->qos_tx); + irlap_send_rd_frame(self); + irlap_start_wd_timer(self, self->wd_timeout); + break; /* stay in SCLOSE */ + } + + pr_debug("%s(), Unknown event %d, (%s)\n", __func__, + event, irlap_event[event]); + + break; + } + + return -1; +} + +static int irlap_state_reset_check( struct irlap_cb *self, IRLAP_EVENT event, + struct sk_buff *skb, + struct irlap_info *info) +{ + int ret = 0; + + pr_debug("%s(), event=%s\n", __func__, irlap_event[event]); + + IRDA_ASSERT(self != NULL, return -ENODEV;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return -EBADR;); + + switch (event) { + case RESET_RESPONSE: + irlap_send_ua_response_frame(self, &self->qos_rx); + irlap_initiate_connection_state(self); + irlap_start_wd_timer(self, WD_TIMEOUT); + irlap_flush_all_queues(self); + + irlap_next_state(self, LAP_NRM_S); + break; + case DISCONNECT_REQUEST: + irlap_wait_min_turn_around(self, &self->qos_tx); + irlap_send_rd_frame(self); + irlap_start_wd_timer(self, WD_TIMEOUT); + irlap_next_state(self, LAP_SCLOSE); + break; + default: + pr_debug("%s(), Unknown event %d, (%s)\n", __func__, + event, irlap_event[event]); + + ret = -EINVAL; + break; + } + return ret; +} diff --git a/drivers/staging/irda/net/irlap_frame.c b/drivers/staging/irda/net/irlap_frame.c new file mode 100644 index 000000000000..debda3de4726 --- /dev/null +++ b/drivers/staging/irda/net/irlap_frame.c @@ -0,0 +1,1407 @@ +/********************************************************************* + * + * Filename: irlap_frame.c + * Version: 1.0 + * Description: Build and transmit IrLAP frames + * Status: Stable + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Tue Aug 19 10:27:26 1997 + * Modified at: Wed Jan 5 08:59:04 2000 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>, + * All Rights Reserved. + * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#include <linux/skbuff.h> +#include <linux/if.h> +#include <linux/if_ether.h> +#include <linux/netdevice.h> +#include <linux/irda.h> +#include <linux/slab.h> + +#include <net/pkt_sched.h> +#include <net/sock.h> + +#include <asm/byteorder.h> + +#include <net/irda/irda.h> +#include <net/irda/irda_device.h> +#include <net/irda/irlap.h> +#include <net/irda/wrapper.h> +#include <net/irda/timer.h> +#include <net/irda/irlap_frame.h> +#include <net/irda/qos.h> + +static void irlap_send_i_frame(struct irlap_cb *self, struct sk_buff *skb, + int command); + +/* + * Function irlap_insert_info (self, skb) + * + * Insert minimum turnaround time and speed information into the skb. We + * need to do this since it's per packet relevant information. Safe to + * have this function inlined since it's only called from one place + */ +static inline void irlap_insert_info(struct irlap_cb *self, + struct sk_buff *skb) +{ + struct irda_skb_cb *cb = (struct irda_skb_cb *) skb->cb; + + /* + * Insert MTT (min. turn time) and speed into skb, so that the + * device driver knows which settings to use + */ + cb->magic = LAP_MAGIC; + cb->mtt = self->mtt_required; + cb->next_speed = self->speed; + + /* Reset */ + self->mtt_required = 0; + + /* + * Delay equals negotiated BOFs count, plus the number of BOFs to + * force the negotiated minimum turnaround time + */ + cb->xbofs = self->bofs_count; + cb->next_xbofs = self->next_bofs; + cb->xbofs_delay = self->xbofs_delay; + + /* Reset XBOF's delay (used only for getting min turn time) */ + self->xbofs_delay = 0; + /* Put the correct xbofs value for the next packet */ + self->bofs_count = self->next_bofs; +} + +/* + * Function irlap_queue_xmit (self, skb) + * + * A little wrapper for dev_queue_xmit, so we can insert some common + * code into it. + */ +void irlap_queue_xmit(struct irlap_cb *self, struct sk_buff *skb) +{ + /* Some common init stuff */ + skb->dev = self->netdev; + skb_reset_mac_header(skb); + skb_reset_network_header(skb); + skb_reset_transport_header(skb); + skb->protocol = htons(ETH_P_IRDA); + skb->priority = TC_PRIO_BESTEFFORT; + + irlap_insert_info(self, skb); + + if (unlikely(self->mode & IRDA_MODE_MONITOR)) { + pr_debug("%s(): %s is in monitor mode\n", __func__, + self->netdev->name); + dev_kfree_skb(skb); + return; + } + + dev_queue_xmit(skb); +} + +/* + * Function irlap_send_snrm_cmd (void) + * + * Transmits a connect SNRM command frame + */ +void irlap_send_snrm_frame(struct irlap_cb *self, struct qos_info *qos) +{ + struct sk_buff *tx_skb; + struct snrm_frame *frame; + int ret; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return;); + + /* Allocate frame */ + tx_skb = alloc_skb(sizeof(struct snrm_frame) + + IRLAP_NEGOCIATION_PARAMS_LEN, + GFP_ATOMIC); + if (!tx_skb) + return; + + frame = skb_put(tx_skb, 2); + + /* Insert connection address field */ + if (qos) + frame->caddr = CMD_FRAME | CBROADCAST; + else + frame->caddr = CMD_FRAME | self->caddr; + + /* Insert control field */ + frame->control = SNRM_CMD | PF_BIT; + + /* + * If we are establishing a connection then insert QoS parameters + */ + if (qos) { + skb_put(tx_skb, 9); /* 25 left */ + frame->saddr = cpu_to_le32(self->saddr); + frame->daddr = cpu_to_le32(self->daddr); + + frame->ncaddr = self->caddr; + + ret = irlap_insert_qos_negotiation_params(self, tx_skb); + if (ret < 0) { + dev_kfree_skb(tx_skb); + return; + } + } + irlap_queue_xmit(self, tx_skb); +} + +/* + * Function irlap_recv_snrm_cmd (skb, info) + * + * Received SNRM (Set Normal Response Mode) command frame + * + */ +static void irlap_recv_snrm_cmd(struct irlap_cb *self, struct sk_buff *skb, + struct irlap_info *info) +{ + struct snrm_frame *frame; + + if (pskb_may_pull(skb,sizeof(struct snrm_frame))) { + frame = (struct snrm_frame *) skb->data; + + /* Copy the new connection address ignoring the C/R bit */ + info->caddr = frame->ncaddr & 0xFE; + + /* Check if the new connection address is valid */ + if ((info->caddr == 0x00) || (info->caddr == 0xfe)) { + pr_debug("%s(), invalid connection address!\n", + __func__); + return; + } + + /* Copy peer device address */ + info->daddr = le32_to_cpu(frame->saddr); + info->saddr = le32_to_cpu(frame->daddr); + + /* Only accept if addressed directly to us */ + if (info->saddr != self->saddr) { + pr_debug("%s(), not addressed to us!\n", + __func__); + return; + } + irlap_do_event(self, RECV_SNRM_CMD, skb, info); + } else { + /* Signal that this SNRM frame does not contain and I-field */ + irlap_do_event(self, RECV_SNRM_CMD, skb, NULL); + } +} + +/* + * Function irlap_send_ua_response_frame (qos) + * + * Send UA (Unnumbered Acknowledgement) frame + * + */ +void irlap_send_ua_response_frame(struct irlap_cb *self, struct qos_info *qos) +{ + struct sk_buff *tx_skb; + struct ua_frame *frame; + int ret; + + pr_debug("%s() <%ld>\n", __func__, jiffies); + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return;); + + /* Allocate frame */ + tx_skb = alloc_skb(sizeof(struct ua_frame) + + IRLAP_NEGOCIATION_PARAMS_LEN, + GFP_ATOMIC); + if (!tx_skb) + return; + + frame = skb_put(tx_skb, 10); + + /* Build UA response */ + frame->caddr = self->caddr; + frame->control = UA_RSP | PF_BIT; + + frame->saddr = cpu_to_le32(self->saddr); + frame->daddr = cpu_to_le32(self->daddr); + + /* Should we send QoS negotiation parameters? */ + if (qos) { + ret = irlap_insert_qos_negotiation_params(self, tx_skb); + if (ret < 0) { + dev_kfree_skb(tx_skb); + return; + } + } + + irlap_queue_xmit(self, tx_skb); +} + + +/* + * Function irlap_send_dm_frame (void) + * + * Send disconnected mode (DM) frame + * + */ +void irlap_send_dm_frame( struct irlap_cb *self) +{ + struct sk_buff *tx_skb = NULL; + struct dm_frame *frame; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return;); + + tx_skb = alloc_skb(sizeof(struct dm_frame), GFP_ATOMIC); + if (!tx_skb) + return; + + frame = skb_put(tx_skb, 2); + + if (self->state == LAP_NDM) + frame->caddr = CBROADCAST; + else + frame->caddr = self->caddr; + + frame->control = DM_RSP | PF_BIT; + + irlap_queue_xmit(self, tx_skb); +} + +/* + * Function irlap_send_disc_frame (void) + * + * Send disconnect (DISC) frame + * + */ +void irlap_send_disc_frame(struct irlap_cb *self) +{ + struct sk_buff *tx_skb = NULL; + struct disc_frame *frame; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return;); + + tx_skb = alloc_skb(sizeof(struct disc_frame), GFP_ATOMIC); + if (!tx_skb) + return; + + frame = skb_put(tx_skb, 2); + + frame->caddr = self->caddr | CMD_FRAME; + frame->control = DISC_CMD | PF_BIT; + + irlap_queue_xmit(self, tx_skb); +} + +/* + * Function irlap_send_discovery_xid_frame (S, s, command) + * + * Build and transmit a XID (eXchange station IDentifier) discovery + * frame. + */ +void irlap_send_discovery_xid_frame(struct irlap_cb *self, int S, __u8 s, + __u8 command, discovery_t *discovery) +{ + struct sk_buff *tx_skb = NULL; + struct xid_frame *frame; + __u32 bcast = BROADCAST; + __u8 *info; + + pr_debug("%s(), s=%d, S=%d, command=%d\n", __func__, + s, S, command); + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return;); + IRDA_ASSERT(discovery != NULL, return;); + + tx_skb = alloc_skb(sizeof(struct xid_frame) + IRLAP_DISCOVERY_INFO_LEN, + GFP_ATOMIC); + if (!tx_skb) + return; + + skb_put(tx_skb, 14); + frame = (struct xid_frame *) tx_skb->data; + + if (command) { + frame->caddr = CBROADCAST | CMD_FRAME; + frame->control = XID_CMD | PF_BIT; + } else { + frame->caddr = CBROADCAST; + frame->control = XID_RSP | PF_BIT; + } + frame->ident = XID_FORMAT; + + frame->saddr = cpu_to_le32(self->saddr); + + if (command) + frame->daddr = cpu_to_le32(bcast); + else + frame->daddr = cpu_to_le32(discovery->data.daddr); + + switch (S) { + case 1: + frame->flags = 0x00; + break; + case 6: + frame->flags = 0x01; + break; + case 8: + frame->flags = 0x02; + break; + case 16: + frame->flags = 0x03; + break; + default: + frame->flags = 0x02; + break; + } + + frame->slotnr = s; + frame->version = 0x00; + + /* + * Provide info for final slot only in commands, and for all + * responses. Send the second byte of the hint only if the + * EXTENSION bit is set in the first byte. + */ + if (!command || (frame->slotnr == 0xff)) { + int len; + + if (discovery->data.hints[0] & HINT_EXTENSION) { + info = skb_put(tx_skb, 2); + info[0] = discovery->data.hints[0]; + info[1] = discovery->data.hints[1]; + } else { + info = skb_put(tx_skb, 1); + info[0] = discovery->data.hints[0]; + } + info = skb_put(tx_skb, 1); + info[0] = discovery->data.charset; + + len = IRDA_MIN(discovery->name_len, skb_tailroom(tx_skb)); + skb_put_data(tx_skb, discovery->data.info, len); + } + irlap_queue_xmit(self, tx_skb); +} + +/* + * Function irlap_recv_discovery_xid_rsp (skb, info) + * + * Received a XID discovery response + * + */ +static void irlap_recv_discovery_xid_rsp(struct irlap_cb *self, + struct sk_buff *skb, + struct irlap_info *info) +{ + struct xid_frame *xid; + discovery_t *discovery = NULL; + __u8 *discovery_info; + char *text; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return;); + + if (!pskb_may_pull(skb, sizeof(struct xid_frame))) { + net_err_ratelimited("%s: frame too short!\n", __func__); + return; + } + + xid = (struct xid_frame *) skb->data; + + info->daddr = le32_to_cpu(xid->saddr); + info->saddr = le32_to_cpu(xid->daddr); + + /* Make sure frame is addressed to us */ + if ((info->saddr != self->saddr) && (info->saddr != BROADCAST)) { + pr_debug("%s(), frame is not addressed to us!\n", + __func__); + return; + } + + if ((discovery = kzalloc(sizeof(discovery_t), GFP_ATOMIC)) == NULL) { + net_warn_ratelimited("%s: kmalloc failed!\n", __func__); + return; + } + + discovery->data.daddr = info->daddr; + discovery->data.saddr = self->saddr; + discovery->timestamp = jiffies; + + pr_debug("%s(), daddr=%08x\n", __func__, + discovery->data.daddr); + + discovery_info = skb_pull(skb, sizeof(struct xid_frame)); + + /* Get info returned from peer */ + discovery->data.hints[0] = discovery_info[0]; + if (discovery_info[0] & HINT_EXTENSION) { + pr_debug("EXTENSION\n"); + discovery->data.hints[1] = discovery_info[1]; + discovery->data.charset = discovery_info[2]; + text = (char *) &discovery_info[3]; + } else { + discovery->data.hints[1] = 0; + discovery->data.charset = discovery_info[1]; + text = (char *) &discovery_info[2]; + } + /* + * Terminate info string, should be safe since this is where the + * FCS bytes resides. + */ + skb->data[skb->len] = '\0'; + strncpy(discovery->data.info, text, NICKNAME_MAX_LEN); + discovery->name_len = strlen(discovery->data.info); + + info->discovery = discovery; + + irlap_do_event(self, RECV_DISCOVERY_XID_RSP, skb, info); +} + +/* + * Function irlap_recv_discovery_xid_cmd (skb, info) + * + * Received a XID discovery command + * + */ +static void irlap_recv_discovery_xid_cmd(struct irlap_cb *self, + struct sk_buff *skb, + struct irlap_info *info) +{ + struct xid_frame *xid; + discovery_t *discovery = NULL; + __u8 *discovery_info; + char *text; + + if (!pskb_may_pull(skb, sizeof(struct xid_frame))) { + net_err_ratelimited("%s: frame too short!\n", __func__); + return; + } + + xid = (struct xid_frame *) skb->data; + + info->daddr = le32_to_cpu(xid->saddr); + info->saddr = le32_to_cpu(xid->daddr); + + /* Make sure frame is addressed to us */ + if ((info->saddr != self->saddr) && (info->saddr != BROADCAST)) { + pr_debug("%s(), frame is not addressed to us!\n", + __func__); + return; + } + + switch (xid->flags & 0x03) { + case 0x00: + info->S = 1; + break; + case 0x01: + info->S = 6; + break; + case 0x02: + info->S = 8; + break; + case 0x03: + info->S = 16; + break; + default: + /* Error!! */ + return; + } + info->s = xid->slotnr; + + discovery_info = skb_pull(skb, sizeof(struct xid_frame)); + + /* + * Check if last frame + */ + if (info->s == 0xff) { + /* Check if things are sane at this point... */ + if((discovery_info == NULL) || + !pskb_may_pull(skb, 3)) { + net_err_ratelimited("%s: discovery frame too short!\n", + __func__); + return; + } + + /* + * We now have some discovery info to deliver! + */ + discovery = kzalloc(sizeof(discovery_t), GFP_ATOMIC); + if (!discovery) + return; + + discovery->data.daddr = info->daddr; + discovery->data.saddr = self->saddr; + discovery->timestamp = jiffies; + + discovery->data.hints[0] = discovery_info[0]; + if (discovery_info[0] & HINT_EXTENSION) { + discovery->data.hints[1] = discovery_info[1]; + discovery->data.charset = discovery_info[2]; + text = (char *) &discovery_info[3]; + } else { + discovery->data.hints[1] = 0; + discovery->data.charset = discovery_info[1]; + text = (char *) &discovery_info[2]; + } + /* + * Terminate string, should be safe since this is where the + * FCS bytes resides. + */ + skb->data[skb->len] = '\0'; + strncpy(discovery->data.info, text, NICKNAME_MAX_LEN); + discovery->name_len = strlen(discovery->data.info); + + info->discovery = discovery; + } else + info->discovery = NULL; + + irlap_do_event(self, RECV_DISCOVERY_XID_CMD, skb, info); +} + +/* + * Function irlap_send_rr_frame (self, command) + * + * Build and transmit RR (Receive Ready) frame. Notice that it is currently + * only possible to send RR frames with the poll bit set. + */ +void irlap_send_rr_frame(struct irlap_cb *self, int command) +{ + struct sk_buff *tx_skb; + struct rr_frame *frame; + + tx_skb = alloc_skb(sizeof(struct rr_frame), GFP_ATOMIC); + if (!tx_skb) + return; + + frame = skb_put(tx_skb, 2); + + frame->caddr = self->caddr; + frame->caddr |= (command) ? CMD_FRAME : 0; + + frame->control = RR | PF_BIT | (self->vr << 5); + + irlap_queue_xmit(self, tx_skb); +} + +/* + * Function irlap_send_rd_frame (self) + * + * Request disconnect. Used by a secondary station to request the + * disconnection of the link. + */ +void irlap_send_rd_frame(struct irlap_cb *self) +{ + struct sk_buff *tx_skb; + struct rd_frame *frame; + + tx_skb = alloc_skb(sizeof(struct rd_frame), GFP_ATOMIC); + if (!tx_skb) + return; + + frame = skb_put(tx_skb, 2); + + frame->caddr = self->caddr; + frame->control = RD_RSP | PF_BIT; + + irlap_queue_xmit(self, tx_skb); +} + +/* + * Function irlap_recv_rr_frame (skb, info) + * + * Received RR (Receive Ready) frame from peer station, no harm in + * making it inline since its called only from one single place + * (irlap_driver_rcv). + */ +static inline void irlap_recv_rr_frame(struct irlap_cb *self, + struct sk_buff *skb, + struct irlap_info *info, int command) +{ + info->nr = skb->data[1] >> 5; + + /* Check if this is a command or a response frame */ + if (command) + irlap_do_event(self, RECV_RR_CMD, skb, info); + else + irlap_do_event(self, RECV_RR_RSP, skb, info); +} + +/* + * Function irlap_recv_rnr_frame (self, skb, info) + * + * Received RNR (Receive Not Ready) frame from peer station + * + */ +static void irlap_recv_rnr_frame(struct irlap_cb *self, struct sk_buff *skb, + struct irlap_info *info, int command) +{ + info->nr = skb->data[1] >> 5; + + pr_debug("%s(), nr=%d, %ld\n", __func__, info->nr, jiffies); + + if (command) + irlap_do_event(self, RECV_RNR_CMD, skb, info); + else + irlap_do_event(self, RECV_RNR_RSP, skb, info); +} + +static void irlap_recv_rej_frame(struct irlap_cb *self, struct sk_buff *skb, + struct irlap_info *info, int command) +{ + info->nr = skb->data[1] >> 5; + + /* Check if this is a command or a response frame */ + if (command) + irlap_do_event(self, RECV_REJ_CMD, skb, info); + else + irlap_do_event(self, RECV_REJ_RSP, skb, info); +} + +static void irlap_recv_srej_frame(struct irlap_cb *self, struct sk_buff *skb, + struct irlap_info *info, int command) +{ + info->nr = skb->data[1] >> 5; + + /* Check if this is a command or a response frame */ + if (command) + irlap_do_event(self, RECV_SREJ_CMD, skb, info); + else + irlap_do_event(self, RECV_SREJ_RSP, skb, info); +} + +static void irlap_recv_disc_frame(struct irlap_cb *self, struct sk_buff *skb, + struct irlap_info *info, int command) +{ + /* Check if this is a command or a response frame */ + if (command) + irlap_do_event(self, RECV_DISC_CMD, skb, info); + else + irlap_do_event(self, RECV_RD_RSP, skb, info); +} + +/* + * Function irlap_recv_ua_frame (skb, frame) + * + * Received UA (Unnumbered Acknowledgement) frame + * + */ +static inline void irlap_recv_ua_frame(struct irlap_cb *self, + struct sk_buff *skb, + struct irlap_info *info) +{ + irlap_do_event(self, RECV_UA_RSP, skb, info); +} + +/* + * Function irlap_send_data_primary(self, skb) + * + * Send I-frames as the primary station but without the poll bit set + * + */ +void irlap_send_data_primary(struct irlap_cb *self, struct sk_buff *skb) +{ + struct sk_buff *tx_skb; + + if (skb->data[1] == I_FRAME) { + + /* + * Insert frame sequence number (Vs) in control field before + * inserting into transmit window queue. + */ + skb->data[1] = I_FRAME | (self->vs << 1); + + /* + * Insert frame in store, in case of retransmissions + * Increase skb reference count, see irlap_do_event() + */ + skb_get(skb); + skb_queue_tail(&self->wx_list, skb); + + /* Copy buffer */ + tx_skb = skb_clone(skb, GFP_ATOMIC); + if (tx_skb == NULL) { + return; + } + + self->vs = (self->vs + 1) % 8; + self->ack_required = FALSE; + self->window -= 1; + + irlap_send_i_frame( self, tx_skb, CMD_FRAME); + } else { + pr_debug("%s(), sending unreliable frame\n", __func__); + irlap_send_ui_frame(self, skb_get(skb), self->caddr, CMD_FRAME); + self->window -= 1; + } +} +/* + * Function irlap_send_data_primary_poll (self, skb) + * + * Send I(nformation) frame as primary with poll bit set + */ +void irlap_send_data_primary_poll(struct irlap_cb *self, struct sk_buff *skb) +{ + struct sk_buff *tx_skb; + int transmission_time; + + /* Stop P timer */ + del_timer(&self->poll_timer); + + /* Is this reliable or unreliable data? */ + if (skb->data[1] == I_FRAME) { + + /* + * Insert frame sequence number (Vs) in control field before + * inserting into transmit window queue. + */ + skb->data[1] = I_FRAME | (self->vs << 1); + + /* + * Insert frame in store, in case of retransmissions + * Increase skb reference count, see irlap_do_event() + */ + skb_get(skb); + skb_queue_tail(&self->wx_list, skb); + + /* Copy buffer */ + tx_skb = skb_clone(skb, GFP_ATOMIC); + if (tx_skb == NULL) { + return; + } + + /* + * Set poll bit if necessary. We do this to the copied + * skb, since retransmitted need to set or clear the poll + * bit depending on when they are sent. + */ + tx_skb->data[1] |= PF_BIT; + + self->vs = (self->vs + 1) % 8; + self->ack_required = FALSE; + + irlap_next_state(self, LAP_NRM_P); + irlap_send_i_frame(self, tx_skb, CMD_FRAME); + } else { + pr_debug("%s(), sending unreliable frame\n", __func__); + + if (self->ack_required) { + irlap_send_ui_frame(self, skb_get(skb), self->caddr, CMD_FRAME); + irlap_next_state(self, LAP_NRM_P); + irlap_send_rr_frame(self, CMD_FRAME); + self->ack_required = FALSE; + } else { + skb->data[1] |= PF_BIT; + irlap_next_state(self, LAP_NRM_P); + irlap_send_ui_frame(self, skb_get(skb), self->caddr, CMD_FRAME); + } + } + + /* How much time we took for transmission of all frames. + * We don't know, so let assume we used the full window. Jean II */ + transmission_time = self->final_timeout; + + /* Reset parameter so that we can fill next window */ + self->window = self->window_size; + +#ifdef CONFIG_IRDA_DYNAMIC_WINDOW + /* Remove what we have not used. Just do a prorata of the + * bytes left in window to window capacity. + * See max_line_capacities[][] in qos.c for details. Jean II */ + transmission_time -= (self->final_timeout * self->bytes_left + / self->line_capacity); + pr_debug("%s() adjusting transmission_time : ft=%d, bl=%d, lc=%d -> tt=%d\n", + __func__, self->final_timeout, self->bytes_left, + self->line_capacity, transmission_time); + + /* We are allowed to transmit a maximum number of bytes again. */ + self->bytes_left = self->line_capacity; +#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */ + + /* + * The network layer has a intermediate buffer between IrLAP + * and the IrDA driver which can contain 8 frames. So, even + * though IrLAP is currently sending the *last* frame of the + * tx-window, the driver most likely has only just started + * sending the *first* frame of the same tx-window. + * I.e. we are always at the very beginning of or Tx window. + * Now, we are supposed to set the final timer from the end + * of our tx-window to let the other peer reply. So, we need + * to add extra time to compensate for the fact that we + * are really at the start of tx-window, otherwise the final timer + * might expire before he can answer... + * Jean II + */ + irlap_start_final_timer(self, self->final_timeout + transmission_time); + + /* + * The clever amongst you might ask why we do this adjustement + * only here, and not in all the other cases in irlap_event.c. + * In all those other case, we only send a very short management + * frame (few bytes), so the adjustement would be lost in the + * noise... + * The exception of course is irlap_resend_rejected_frame(). + * Jean II */ +} + +/* + * Function irlap_send_data_secondary_final (self, skb) + * + * Send I(nformation) frame as secondary with final bit set + * + */ +void irlap_send_data_secondary_final(struct irlap_cb *self, + struct sk_buff *skb) +{ + struct sk_buff *tx_skb = NULL; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return;); + IRDA_ASSERT(skb != NULL, return;); + + /* Is this reliable or unreliable data? */ + if (skb->data[1] == I_FRAME) { + + /* + * Insert frame sequence number (Vs) in control field before + * inserting into transmit window queue. + */ + skb->data[1] = I_FRAME | (self->vs << 1); + + /* + * Insert frame in store, in case of retransmissions + * Increase skb reference count, see irlap_do_event() + */ + skb_get(skb); + skb_queue_tail(&self->wx_list, skb); + + tx_skb = skb_clone(skb, GFP_ATOMIC); + if (tx_skb == NULL) { + return; + } + + tx_skb->data[1] |= PF_BIT; + + self->vs = (self->vs + 1) % 8; + self->ack_required = FALSE; + + irlap_send_i_frame(self, tx_skb, RSP_FRAME); + } else { + if (self->ack_required) { + irlap_send_ui_frame(self, skb_get(skb), self->caddr, RSP_FRAME); + irlap_send_rr_frame(self, RSP_FRAME); + self->ack_required = FALSE; + } else { + skb->data[1] |= PF_BIT; + irlap_send_ui_frame(self, skb_get(skb), self->caddr, RSP_FRAME); + } + } + + self->window = self->window_size; +#ifdef CONFIG_IRDA_DYNAMIC_WINDOW + /* We are allowed to transmit a maximum number of bytes again. */ + self->bytes_left = self->line_capacity; +#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */ + + irlap_start_wd_timer(self, self->wd_timeout); +} + +/* + * Function irlap_send_data_secondary (self, skb) + * + * Send I(nformation) frame as secondary without final bit set + * + */ +void irlap_send_data_secondary(struct irlap_cb *self, struct sk_buff *skb) +{ + struct sk_buff *tx_skb = NULL; + + /* Is this reliable or unreliable data? */ + if (skb->data[1] == I_FRAME) { + + /* + * Insert frame sequence number (Vs) in control field before + * inserting into transmit window queue. + */ + skb->data[1] = I_FRAME | (self->vs << 1); + + /* + * Insert frame in store, in case of retransmissions + * Increase skb reference count, see irlap_do_event() + */ + skb_get(skb); + skb_queue_tail(&self->wx_list, skb); + + tx_skb = skb_clone(skb, GFP_ATOMIC); + if (tx_skb == NULL) { + return; + } + + self->vs = (self->vs + 1) % 8; + self->ack_required = FALSE; + self->window -= 1; + + irlap_send_i_frame(self, tx_skb, RSP_FRAME); + } else { + irlap_send_ui_frame(self, skb_get(skb), self->caddr, RSP_FRAME); + self->window -= 1; + } +} + +/* + * Function irlap_resend_rejected_frames (nr) + * + * Resend frames which has not been acknowledged. Should be safe to + * traverse the list without locking it since this function will only be + * called from interrupt context (BH) + */ +void irlap_resend_rejected_frames(struct irlap_cb *self, int command) +{ + struct sk_buff *tx_skb; + struct sk_buff *skb; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return;); + + /* Resend unacknowledged frame(s) */ + skb_queue_walk(&self->wx_list, skb) { + irlap_wait_min_turn_around(self, &self->qos_tx); + + /* We copy the skb to be retransmitted since we will have to + * modify it. Cloning will confuse packet sniffers + */ + /* tx_skb = skb_clone( skb, GFP_ATOMIC); */ + tx_skb = skb_copy(skb, GFP_ATOMIC); + if (!tx_skb) { + pr_debug("%s(), unable to copy\n", __func__); + return; + } + + /* Clear old Nr field + poll bit */ + tx_skb->data[1] &= 0x0f; + + /* + * Set poll bit on the last frame retransmitted + */ + if (skb_queue_is_last(&self->wx_list, skb)) + tx_skb->data[1] |= PF_BIT; /* Set p/f bit */ + else + tx_skb->data[1] &= ~PF_BIT; /* Clear p/f bit */ + + irlap_send_i_frame(self, tx_skb, command); + } +#if 0 /* Not yet */ + /* + * We can now fill the window with additional data frames + */ + while (!skb_queue_empty(&self->txq)) { + + pr_debug("%s(), sending additional frames!\n", __func__); + if (self->window > 0) { + skb = skb_dequeue( &self->txq); + IRDA_ASSERT(skb != NULL, return;); + + /* + * If send window > 1 then send frame with pf + * bit cleared + */ + if ((self->window > 1) && + !skb_queue_empty(&self->txq)) { + irlap_send_data_primary(self, skb); + } else { + irlap_send_data_primary_poll(self, skb); + } + kfree_skb(skb); + } + } +#endif +} + +void irlap_resend_rejected_frame(struct irlap_cb *self, int command) +{ + struct sk_buff *tx_skb; + struct sk_buff *skb; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return;); + + /* Resend unacknowledged frame(s) */ + skb = skb_peek(&self->wx_list); + if (skb != NULL) { + irlap_wait_min_turn_around(self, &self->qos_tx); + + /* We copy the skb to be retransmitted since we will have to + * modify it. Cloning will confuse packet sniffers + */ + /* tx_skb = skb_clone( skb, GFP_ATOMIC); */ + tx_skb = skb_copy(skb, GFP_ATOMIC); + if (!tx_skb) { + pr_debug("%s(), unable to copy\n", __func__); + return; + } + + /* Clear old Nr field + poll bit */ + tx_skb->data[1] &= 0x0f; + + /* Set poll/final bit */ + tx_skb->data[1] |= PF_BIT; /* Set p/f bit */ + + irlap_send_i_frame(self, tx_skb, command); + } +} + +/* + * Function irlap_send_ui_frame (self, skb, command) + * + * Contruct and transmit an Unnumbered Information (UI) frame + * + */ +void irlap_send_ui_frame(struct irlap_cb *self, struct sk_buff *skb, + __u8 caddr, int command) +{ + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return;); + IRDA_ASSERT(skb != NULL, return;); + + /* Insert connection address */ + skb->data[0] = caddr | ((command) ? CMD_FRAME : 0); + + irlap_queue_xmit(self, skb); +} + +/* + * Function irlap_send_i_frame (skb) + * + * Contruct and transmit Information (I) frame + */ +static void irlap_send_i_frame(struct irlap_cb *self, struct sk_buff *skb, + int command) +{ + /* Insert connection address */ + skb->data[0] = self->caddr; + skb->data[0] |= (command) ? CMD_FRAME : 0; + + /* Insert next to receive (Vr) */ + skb->data[1] |= (self->vr << 5); /* insert nr */ + + irlap_queue_xmit(self, skb); +} + +/* + * Function irlap_recv_i_frame (skb, frame) + * + * Receive and parse an I (Information) frame, no harm in making it inline + * since it's called only from one single place (irlap_driver_rcv). + */ +static inline void irlap_recv_i_frame(struct irlap_cb *self, + struct sk_buff *skb, + struct irlap_info *info, int command) +{ + info->nr = skb->data[1] >> 5; /* Next to receive */ + info->pf = skb->data[1] & PF_BIT; /* Final bit */ + info->ns = (skb->data[1] >> 1) & 0x07; /* Next to send */ + + /* Check if this is a command or a response frame */ + if (command) + irlap_do_event(self, RECV_I_CMD, skb, info); + else + irlap_do_event(self, RECV_I_RSP, skb, info); +} + +/* + * Function irlap_recv_ui_frame (self, skb, info) + * + * Receive and parse an Unnumbered Information (UI) frame + * + */ +static void irlap_recv_ui_frame(struct irlap_cb *self, struct sk_buff *skb, + struct irlap_info *info) +{ + info->pf = skb->data[1] & PF_BIT; /* Final bit */ + + irlap_do_event(self, RECV_UI_FRAME, skb, info); +} + +/* + * Function irlap_recv_frmr_frame (skb, frame) + * + * Received Frame Reject response. + * + */ +static void irlap_recv_frmr_frame(struct irlap_cb *self, struct sk_buff *skb, + struct irlap_info *info) +{ + __u8 *frame; + int w, x, y, z; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return;); + IRDA_ASSERT(skb != NULL, return;); + IRDA_ASSERT(info != NULL, return;); + + if (!pskb_may_pull(skb, 4)) { + net_err_ratelimited("%s: frame too short!\n", __func__); + return; + } + + frame = skb->data; + + info->nr = frame[2] >> 5; /* Next to receive */ + info->pf = frame[2] & PF_BIT; /* Final bit */ + info->ns = (frame[2] >> 1) & 0x07; /* Next to send */ + + w = frame[3] & 0x01; + x = frame[3] & 0x02; + y = frame[3] & 0x04; + z = frame[3] & 0x08; + + if (w) { + pr_debug("Rejected control field is undefined or not implemented\n"); + } + if (x) { + pr_debug("Rejected control field was invalid because it contained a non permitted I field\n"); + } + if (y) { + pr_debug("Received I field exceeded the maximum negotiated for the existing connection or exceeded the maximum this station supports if no connection exists\n"); + } + if (z) { + pr_debug("Rejected control field control field contained an invalid Nr count\n"); + } + irlap_do_event(self, RECV_FRMR_RSP, skb, info); +} + +/* + * Function irlap_send_test_frame (self, daddr) + * + * Send a test frame response + * + */ +void irlap_send_test_frame(struct irlap_cb *self, __u8 caddr, __u32 daddr, + struct sk_buff *cmd) +{ + struct sk_buff *tx_skb; + struct test_frame *frame; + + tx_skb = alloc_skb(cmd->len + sizeof(struct test_frame), GFP_ATOMIC); + if (!tx_skb) + return; + + /* Broadcast frames must include saddr and daddr fields */ + if (caddr == CBROADCAST) { + frame = skb_put(tx_skb, sizeof(struct test_frame)); + + /* Insert the swapped addresses */ + frame->saddr = cpu_to_le32(self->saddr); + frame->daddr = cpu_to_le32(daddr); + } else + frame = skb_put(tx_skb, LAP_ADDR_HEADER + LAP_CTRL_HEADER); + + frame->caddr = caddr; + frame->control = TEST_RSP | PF_BIT; + + /* Copy info */ + skb_put_data(tx_skb, cmd->data, cmd->len); + + /* Return to sender */ + irlap_wait_min_turn_around(self, &self->qos_tx); + irlap_queue_xmit(self, tx_skb); +} + +/* + * Function irlap_recv_test_frame (self, skb) + * + * Receive a test frame + * + */ +static void irlap_recv_test_frame(struct irlap_cb *self, struct sk_buff *skb, + struct irlap_info *info, int command) +{ + struct test_frame *frame; + + if (!pskb_may_pull(skb, sizeof(*frame))) { + net_err_ratelimited("%s: frame too short!\n", __func__); + return; + } + frame = (struct test_frame *) skb->data; + + /* Broadcast frames must carry saddr and daddr fields */ + if (info->caddr == CBROADCAST) { + if (skb->len < sizeof(struct test_frame)) { + pr_debug("%s() test frame too short!\n", + __func__); + return; + } + + /* Read and swap addresses */ + info->daddr = le32_to_cpu(frame->saddr); + info->saddr = le32_to_cpu(frame->daddr); + + /* Make sure frame is addressed to us */ + if ((info->saddr != self->saddr) && + (info->saddr != BROADCAST)) { + return; + } + } + + if (command) + irlap_do_event(self, RECV_TEST_CMD, skb, info); + else + irlap_do_event(self, RECV_TEST_RSP, skb, info); +} + +/* + * Function irlap_driver_rcv (skb, netdev, ptype) + * + * Called when a frame is received. Dispatches the right receive function + * for processing of the frame. + * + * Note on skb management : + * After calling the higher layers of the IrDA stack, we always + * kfree() the skb, which drop the reference count (and potentially + * destroy it). + * If a higher layer of the stack want to keep the skb around (to put + * in a queue or pass it to the higher layer), it will need to use + * skb_get() to keep a reference on it. This is usually done at the + * LMP level in irlmp.c. + * Jean II + */ +int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev, + struct packet_type *ptype, struct net_device *orig_dev) +{ + struct irlap_info info; + struct irlap_cb *self; + int command; + __u8 control; + int ret = -1; + + if (!net_eq(dev_net(dev), &init_net)) + goto out; + + /* FIXME: should we get our own field? */ + self = (struct irlap_cb *) dev->atalk_ptr; + + /* If the net device is down, then IrLAP is gone! */ + if (!self || self->magic != LAP_MAGIC) + goto err; + + /* We are no longer an "old" protocol, so we need to handle + * share and non linear skbs. This should never happen, so + * we don't need to be clever about it. Jean II */ + if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) { + net_err_ratelimited("%s: can't clone shared skb!\n", __func__); + goto err; + } + + /* Check if frame is large enough for parsing */ + if (!pskb_may_pull(skb, 2)) { + net_err_ratelimited("%s: frame too short!\n", __func__); + goto err; + } + + command = skb->data[0] & CMD_FRAME; + info.caddr = skb->data[0] & CBROADCAST; + + info.pf = skb->data[1] & PF_BIT; + info.control = skb->data[1] & ~PF_BIT; /* Mask away poll/final bit */ + + control = info.control; + + /* First we check if this frame has a valid connection address */ + if ((info.caddr != self->caddr) && (info.caddr != CBROADCAST)) { + pr_debug("%s(), wrong connection address!\n", + __func__); + goto out; + } + /* + * Optimize for the common case and check if the frame is an + * I(nformation) frame. Only I-frames have bit 0 set to 0 + */ + if (~control & 0x01) { + irlap_recv_i_frame(self, skb, &info, command); + goto out; + } + /* + * We now check is the frame is an S(upervisory) frame. Only + * S-frames have bit 0 set to 1 and bit 1 set to 0 + */ + if (~control & 0x02) { + /* + * Received S(upervisory) frame, check which frame type it is + * only the first nibble is of interest + */ + switch (control & 0x0f) { + case RR: + irlap_recv_rr_frame(self, skb, &info, command); + break; + case RNR: + irlap_recv_rnr_frame(self, skb, &info, command); + break; + case REJ: + irlap_recv_rej_frame(self, skb, &info, command); + break; + case SREJ: + irlap_recv_srej_frame(self, skb, &info, command); + break; + default: + net_warn_ratelimited("%s: Unknown S-frame %02x received!\n", + __func__, info.control); + break; + } + goto out; + } + /* + * This must be a C(ontrol) frame + */ + switch (control) { + case XID_RSP: + irlap_recv_discovery_xid_rsp(self, skb, &info); + break; + case XID_CMD: + irlap_recv_discovery_xid_cmd(self, skb, &info); + break; + case SNRM_CMD: + irlap_recv_snrm_cmd(self, skb, &info); + break; + case DM_RSP: + irlap_do_event(self, RECV_DM_RSP, skb, &info); + break; + case DISC_CMD: /* And RD_RSP since they have the same value */ + irlap_recv_disc_frame(self, skb, &info, command); + break; + case TEST_CMD: + irlap_recv_test_frame(self, skb, &info, command); + break; + case UA_RSP: + irlap_recv_ua_frame(self, skb, &info); + break; + case FRMR_RSP: + irlap_recv_frmr_frame(self, skb, &info); + break; + case UI_FRAME: + irlap_recv_ui_frame(self, skb, &info); + break; + default: + net_warn_ratelimited("%s: Unknown frame %02x received!\n", + __func__, info.control); + break; + } +out: + ret = 0; +err: + /* Always drop our reference on the skb */ + dev_kfree_skb(skb); + return ret; +} diff --git a/drivers/staging/irda/net/irlmp.c b/drivers/staging/irda/net/irlmp.c new file mode 100644 index 000000000000..43964594aa12 --- /dev/null +++ b/drivers/staging/irda/net/irlmp.c @@ -0,0 +1,1996 @@ +/********************************************************************* + * + * Filename: irlmp.c + * Version: 1.0 + * Description: IrDA Link Management Protocol (LMP) layer + * Status: Stable. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Sun Aug 17 20:54:32 1997 + * Modified at: Wed Jan 5 11:26:03 2000 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>, + * All Rights Reserved. + * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/skbuff.h> +#include <linux/types.h> +#include <linux/proc_fs.h> +#include <linux/init.h> +#include <linux/kmod.h> +#include <linux/random.h> +#include <linux/seq_file.h> + +#include <net/irda/irda.h> +#include <net/irda/timer.h> +#include <net/irda/qos.h> +#include <net/irda/irlap.h> +#include <net/irda/iriap.h> +#include <net/irda/irlmp.h> +#include <net/irda/irlmp_frame.h> + +#include <asm/unaligned.h> + +static __u8 irlmp_find_free_slsap(void); +static int irlmp_slsap_inuse(__u8 slsap_sel); + +/* Master structure */ +struct irlmp_cb *irlmp = NULL; + +/* These can be altered by the sysctl interface */ +int sysctl_discovery = 0; +int sysctl_discovery_timeout = 3; /* 3 seconds by default */ +int sysctl_discovery_slots = 6; /* 6 slots by default */ +int sysctl_lap_keepalive_time = LM_IDLE_TIMEOUT * 1000 / HZ; +char sysctl_devname[65]; + +static const char *irlmp_reasons[] = { + "ERROR, NOT USED", + "LM_USER_REQUEST", + "LM_LAP_DISCONNECT", + "LM_CONNECT_FAILURE", + "LM_LAP_RESET", + "LM_INIT_DISCONNECT", + "ERROR, NOT USED", + "UNKNOWN", +}; + +const char *irlmp_reason_str(LM_REASON reason) +{ + reason = min_t(size_t, reason, ARRAY_SIZE(irlmp_reasons) - 1); + return irlmp_reasons[reason]; +} + +/* + * Function irlmp_init (void) + * + * Create (allocate) the main IrLMP structure + * + */ +int __init irlmp_init(void) +{ + /* Initialize the irlmp structure. */ + irlmp = kzalloc( sizeof(struct irlmp_cb), GFP_KERNEL); + if (irlmp == NULL) + return -ENOMEM; + + irlmp->magic = LMP_MAGIC; + + irlmp->clients = hashbin_new(HB_LOCK); + irlmp->services = hashbin_new(HB_LOCK); + irlmp->links = hashbin_new(HB_LOCK); + irlmp->unconnected_lsaps = hashbin_new(HB_LOCK); + irlmp->cachelog = hashbin_new(HB_NOLOCK); + + if ((irlmp->clients == NULL) || + (irlmp->services == NULL) || + (irlmp->links == NULL) || + (irlmp->unconnected_lsaps == NULL) || + (irlmp->cachelog == NULL)) { + return -ENOMEM; + } + + spin_lock_init(&irlmp->cachelog->hb_spinlock); + + irlmp->last_lsap_sel = 0x0f; /* Reserved 0x00-0x0f */ + strcpy(sysctl_devname, "Linux"); + + init_timer(&irlmp->discovery_timer); + + /* Do discovery every 3 seconds, conditionally */ + if (sysctl_discovery) + irlmp_start_discovery_timer(irlmp, + sysctl_discovery_timeout*HZ); + + return 0; +} + +/* + * Function irlmp_cleanup (void) + * + * Remove IrLMP layer + * + */ +void irlmp_cleanup(void) +{ + /* Check for main structure */ + IRDA_ASSERT(irlmp != NULL, return;); + IRDA_ASSERT(irlmp->magic == LMP_MAGIC, return;); + + del_timer(&irlmp->discovery_timer); + + hashbin_delete(irlmp->links, (FREE_FUNC) kfree); + hashbin_delete(irlmp->unconnected_lsaps, (FREE_FUNC) kfree); + hashbin_delete(irlmp->clients, (FREE_FUNC) kfree); + hashbin_delete(irlmp->services, (FREE_FUNC) kfree); + hashbin_delete(irlmp->cachelog, (FREE_FUNC) kfree); + + /* De-allocate main structure */ + kfree(irlmp); + irlmp = NULL; +} + +/* + * Function irlmp_open_lsap (slsap, notify) + * + * Register with IrLMP and create a local LSAP, + * returns handle to LSAP. + */ +struct lsap_cb *irlmp_open_lsap(__u8 slsap_sel, notify_t *notify, __u8 pid) +{ + struct lsap_cb *self; + + IRDA_ASSERT(notify != NULL, return NULL;); + IRDA_ASSERT(irlmp != NULL, return NULL;); + IRDA_ASSERT(irlmp->magic == LMP_MAGIC, return NULL;); + IRDA_ASSERT(notify->instance != NULL, return NULL;); + + /* Does the client care which Source LSAP selector it gets? */ + if (slsap_sel == LSAP_ANY) { + slsap_sel = irlmp_find_free_slsap(); + if (!slsap_sel) + return NULL; + } else if (irlmp_slsap_inuse(slsap_sel)) + return NULL; + + /* Allocate new instance of a LSAP connection */ + self = kzalloc(sizeof(struct lsap_cb), GFP_ATOMIC); + if (self == NULL) + return NULL; + + self->magic = LMP_LSAP_MAGIC; + self->slsap_sel = slsap_sel; + + /* Fix connectionless LSAP's */ + if (slsap_sel == LSAP_CONNLESS) { +#ifdef CONFIG_IRDA_ULTRA + self->dlsap_sel = LSAP_CONNLESS; + self->pid = pid; +#endif /* CONFIG_IRDA_ULTRA */ + } else + self->dlsap_sel = LSAP_ANY; + /* self->connected = FALSE; -> already NULL via memset() */ + + init_timer(&self->watchdog_timer); + + self->notify = *notify; + + self->lsap_state = LSAP_DISCONNECTED; + + /* Insert into queue of unconnected LSAPs */ + hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) self, + (long) self, NULL); + + return self; +} +EXPORT_SYMBOL(irlmp_open_lsap); + +/* + * Function __irlmp_close_lsap (self) + * + * Remove an instance of LSAP + */ +static void __irlmp_close_lsap(struct lsap_cb *self) +{ + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;); + + /* + * Set some of the variables to preset values + */ + self->magic = 0; + del_timer(&self->watchdog_timer); /* Important! */ + + if (self->conn_skb) + dev_kfree_skb(self->conn_skb); + + kfree(self); +} + +/* + * Function irlmp_close_lsap (self) + * + * Close and remove LSAP + * + */ +void irlmp_close_lsap(struct lsap_cb *self) +{ + struct lap_cb *lap; + struct lsap_cb *lsap = NULL; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;); + + /* + * Find out if we should remove this LSAP from a link or from the + * list of unconnected lsaps (not associated with a link) + */ + lap = self->lap; + if (lap) { + IRDA_ASSERT(lap->magic == LMP_LAP_MAGIC, return;); + /* We might close a LSAP before it has completed the + * connection setup. In those case, higher layers won't + * send a proper disconnect request. Harmless, except + * that we will forget to close LAP... - Jean II */ + if(self->lsap_state != LSAP_DISCONNECTED) { + self->lsap_state = LSAP_DISCONNECTED; + irlmp_do_lap_event(self->lap, + LM_LAP_DISCONNECT_REQUEST, NULL); + } + /* Now, remove from the link */ + lsap = hashbin_remove(lap->lsaps, (long) self, NULL); +#ifdef CONFIG_IRDA_CACHE_LAST_LSAP + lap->cache.valid = FALSE; +#endif + } + self->lap = NULL; + /* Check if we found the LSAP! If not then try the unconnected lsaps */ + if (!lsap) { + lsap = hashbin_remove(irlmp->unconnected_lsaps, (long) self, + NULL); + } + if (!lsap) { + pr_debug("%s(), Looks like somebody has removed me already!\n", + __func__); + return; + } + __irlmp_close_lsap(self); +} +EXPORT_SYMBOL(irlmp_close_lsap); + +/* + * Function irlmp_register_irlap (saddr, notify) + * + * Register IrLAP layer with IrLMP. There is possible to have multiple + * instances of the IrLAP layer, each connected to different IrDA ports + * + */ +void irlmp_register_link(struct irlap_cb *irlap, __u32 saddr, notify_t *notify) +{ + struct lap_cb *lap; + + IRDA_ASSERT(irlmp != NULL, return;); + IRDA_ASSERT(irlmp->magic == LMP_MAGIC, return;); + IRDA_ASSERT(notify != NULL, return;); + + /* + * Allocate new instance of a LSAP connection + */ + lap = kzalloc(sizeof(struct lap_cb), GFP_KERNEL); + if (lap == NULL) + return; + + lap->irlap = irlap; + lap->magic = LMP_LAP_MAGIC; + lap->saddr = saddr; + lap->daddr = DEV_ADDR_ANY; +#ifdef CONFIG_IRDA_CACHE_LAST_LSAP + lap->cache.valid = FALSE; +#endif + lap->lsaps = hashbin_new(HB_LOCK); + if (lap->lsaps == NULL) { + net_warn_ratelimited("%s(), unable to kmalloc lsaps\n", + __func__); + kfree(lap); + return; + } + + lap->lap_state = LAP_STANDBY; + + init_timer(&lap->idle_timer); + + /* + * Insert into queue of LMP links + */ + hashbin_insert(irlmp->links, (irda_queue_t *) lap, lap->saddr, NULL); + + /* + * We set only this variable so IrLAP can tell us on which link the + * different events happened on + */ + irda_notify_init(notify); + notify->instance = lap; +} + +/* + * Function irlmp_unregister_irlap (saddr) + * + * IrLAP layer has been removed! + * + */ +void irlmp_unregister_link(__u32 saddr) +{ + struct lap_cb *link; + + /* We must remove ourselves from the hashbin *first*. This ensure + * that no more LSAPs will be open on this link and no discovery + * will be triggered anymore. Jean II */ + link = hashbin_remove(irlmp->links, saddr, NULL); + if (link) { + IRDA_ASSERT(link->magic == LMP_LAP_MAGIC, return;); + + /* Kill all the LSAPs on this link. Jean II */ + link->reason = LAP_DISC_INDICATION; + link->daddr = DEV_ADDR_ANY; + irlmp_do_lap_event(link, LM_LAP_DISCONNECT_INDICATION, NULL); + + /* Remove all discoveries discovered at this link */ + irlmp_expire_discoveries(irlmp->cachelog, link->saddr, TRUE); + + /* Final cleanup */ + del_timer(&link->idle_timer); + link->magic = 0; + hashbin_delete(link->lsaps, (FREE_FUNC) __irlmp_close_lsap); + kfree(link); + } +} + +/* + * Function irlmp_connect_request (handle, dlsap, userdata) + * + * Connect with a peer LSAP + * + */ +int irlmp_connect_request(struct lsap_cb *self, __u8 dlsap_sel, + __u32 saddr, __u32 daddr, + struct qos_info *qos, struct sk_buff *userdata) +{ + struct sk_buff *tx_skb = userdata; + struct lap_cb *lap; + struct lsap_cb *lsap; + int ret; + + IRDA_ASSERT(self != NULL, return -EBADR;); + IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -EBADR;); + + pr_debug("%s(), slsap_sel=%02x, dlsap_sel=%02x, saddr=%08x, daddr=%08x\n", + __func__, self->slsap_sel, dlsap_sel, saddr, daddr); + + if (test_bit(0, &self->connected)) { + ret = -EISCONN; + goto err; + } + + /* Client must supply destination device address */ + if (!daddr) { + ret = -EINVAL; + goto err; + } + + /* Any userdata? */ + if (tx_skb == NULL) { + tx_skb = alloc_skb(LMP_MAX_HEADER, GFP_ATOMIC); + if (!tx_skb) + return -ENOMEM; + + skb_reserve(tx_skb, LMP_MAX_HEADER); + } + + /* Make room for MUX control header (3 bytes) */ + IRDA_ASSERT(skb_headroom(tx_skb) >= LMP_CONTROL_HEADER, return -1;); + skb_push(tx_skb, LMP_CONTROL_HEADER); + + self->dlsap_sel = dlsap_sel; + + /* + * Find the link to where we should try to connect since there may + * be more than one IrDA port on this machine. If the client has + * passed us the saddr (and already knows which link to use), then + * we use that to find the link, if not then we have to look in the + * discovery log and check if any of the links has discovered a + * device with the given daddr + */ + if ((!saddr) || (saddr == DEV_ADDR_ANY)) { + discovery_t *discovery; + unsigned long flags; + + spin_lock_irqsave(&irlmp->cachelog->hb_spinlock, flags); + if (daddr != DEV_ADDR_ANY) + discovery = hashbin_find(irlmp->cachelog, daddr, NULL); + else { + pr_debug("%s(), no daddr\n", __func__); + discovery = (discovery_t *) + hashbin_get_first(irlmp->cachelog); + } + + if (discovery) { + saddr = discovery->data.saddr; + daddr = discovery->data.daddr; + } + spin_unlock_irqrestore(&irlmp->cachelog->hb_spinlock, flags); + } + lap = hashbin_lock_find(irlmp->links, saddr, NULL); + if (lap == NULL) { + pr_debug("%s(), Unable to find a usable link!\n", __func__); + ret = -EHOSTUNREACH; + goto err; + } + + /* Check if LAP is disconnected or already connected */ + if (lap->daddr == DEV_ADDR_ANY) + lap->daddr = daddr; + else if (lap->daddr != daddr) { + /* Check if some LSAPs are active on this LAP */ + if (HASHBIN_GET_SIZE(lap->lsaps) == 0) { + /* No active connection, but LAP hasn't been + * disconnected yet (waiting for timeout in LAP). + * Maybe we could give LAP a bit of help in this case. + */ + pr_debug("%s(), sorry, but I'm waiting for LAP to timeout!\n", + __func__); + ret = -EAGAIN; + goto err; + } + + /* LAP is already connected to a different node, and LAP + * can only talk to one node at a time */ + pr_debug("%s(), sorry, but link is busy!\n", __func__); + ret = -EBUSY; + goto err; + } + + self->lap = lap; + + /* + * Remove LSAP from list of unconnected LSAPs and insert it into the + * list of connected LSAPs for the particular link + */ + lsap = hashbin_remove(irlmp->unconnected_lsaps, (long) self, NULL); + + IRDA_ASSERT(lsap != NULL, return -1;); + IRDA_ASSERT(lsap->magic == LMP_LSAP_MAGIC, return -1;); + IRDA_ASSERT(lsap->lap != NULL, return -1;); + IRDA_ASSERT(lsap->lap->magic == LMP_LAP_MAGIC, return -1;); + + hashbin_insert(self->lap->lsaps, (irda_queue_t *) self, (long) self, + NULL); + + set_bit(0, &self->connected); /* TRUE */ + + /* + * User supplied qos specifications? + */ + if (qos) + self->qos = *qos; + + irlmp_do_lsap_event(self, LM_CONNECT_REQUEST, tx_skb); + + /* Drop reference count - see irlap_data_request(). */ + dev_kfree_skb(tx_skb); + + return 0; + +err: + /* Cleanup */ + if(tx_skb) + dev_kfree_skb(tx_skb); + return ret; +} +EXPORT_SYMBOL(irlmp_connect_request); + +/* + * Function irlmp_connect_indication (self) + * + * Incoming connection + * + */ +void irlmp_connect_indication(struct lsap_cb *self, struct sk_buff *skb) +{ + int max_seg_size; + int lap_header_size; + int max_header_size; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;); + IRDA_ASSERT(skb != NULL, return;); + IRDA_ASSERT(self->lap != NULL, return;); + + pr_debug("%s(), slsap_sel=%02x, dlsap_sel=%02x\n", + __func__, self->slsap_sel, self->dlsap_sel); + + /* Note : self->lap is set in irlmp_link_data_indication(), + * (case CONNECT_CMD:) because we have no way to set it here. + * Similarly, self->dlsap_sel is usually set in irlmp_find_lsap(). + * Jean II */ + + self->qos = *self->lap->qos; + + max_seg_size = self->lap->qos->data_size.value-LMP_HEADER; + lap_header_size = IRLAP_GET_HEADER_SIZE(self->lap->irlap); + max_header_size = LMP_HEADER + lap_header_size; + + /* Hide LMP_CONTROL_HEADER header from layer above */ + skb_pull(skb, LMP_CONTROL_HEADER); + + if (self->notify.connect_indication) { + /* Don't forget to refcount it - see irlap_driver_rcv(). */ + skb_get(skb); + self->notify.connect_indication(self->notify.instance, self, + &self->qos, max_seg_size, + max_header_size, skb); + } +} + +/* + * Function irlmp_connect_response (handle, userdata) + * + * Service user is accepting connection + * + */ +int irlmp_connect_response(struct lsap_cb *self, struct sk_buff *userdata) +{ + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;); + IRDA_ASSERT(userdata != NULL, return -1;); + + /* We set the connected bit and move the lsap to the connected list + * in the state machine itself. Jean II */ + + pr_debug("%s(), slsap_sel=%02x, dlsap_sel=%02x\n", + __func__, self->slsap_sel, self->dlsap_sel); + + /* Make room for MUX control header (3 bytes) */ + IRDA_ASSERT(skb_headroom(userdata) >= LMP_CONTROL_HEADER, return -1;); + skb_push(userdata, LMP_CONTROL_HEADER); + + irlmp_do_lsap_event(self, LM_CONNECT_RESPONSE, userdata); + + /* Drop reference count - see irlap_data_request(). */ + dev_kfree_skb(userdata); + + return 0; +} +EXPORT_SYMBOL(irlmp_connect_response); + +/* + * Function irlmp_connect_confirm (handle, skb) + * + * LSAP connection confirmed peer device! + */ +void irlmp_connect_confirm(struct lsap_cb *self, struct sk_buff *skb) +{ + int max_header_size; + int lap_header_size; + int max_seg_size; + + IRDA_ASSERT(skb != NULL, return;); + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;); + IRDA_ASSERT(self->lap != NULL, return;); + + self->qos = *self->lap->qos; + + max_seg_size = self->lap->qos->data_size.value-LMP_HEADER; + lap_header_size = IRLAP_GET_HEADER_SIZE(self->lap->irlap); + max_header_size = LMP_HEADER + lap_header_size; + + pr_debug("%s(), max_header_size=%d\n", + __func__, max_header_size); + + /* Hide LMP_CONTROL_HEADER header from layer above */ + skb_pull(skb, LMP_CONTROL_HEADER); + + if (self->notify.connect_confirm) { + /* Don't forget to refcount it - see irlap_driver_rcv() */ + skb_get(skb); + self->notify.connect_confirm(self->notify.instance, self, + &self->qos, max_seg_size, + max_header_size, skb); + } +} + +/* + * Function irlmp_dup (orig, instance) + * + * Duplicate LSAP, can be used by servers to confirm a connection on a + * new LSAP so it can keep listening on the old one. + * + */ +struct lsap_cb *irlmp_dup(struct lsap_cb *orig, void *instance) +{ + struct lsap_cb *new; + unsigned long flags; + + spin_lock_irqsave(&irlmp->unconnected_lsaps->hb_spinlock, flags); + + /* Only allowed to duplicate unconnected LSAP's, and only LSAPs + * that have received a connect indication. Jean II */ + if ((!hashbin_find(irlmp->unconnected_lsaps, (long) orig, NULL)) || + (orig->lap == NULL)) { + pr_debug("%s(), invalid LSAP (wrong state)\n", + __func__); + spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock, + flags); + return NULL; + } + + /* Allocate a new instance */ + new = kmemdup(orig, sizeof(*new), GFP_ATOMIC); + if (!new) { + pr_debug("%s(), unable to kmalloc\n", __func__); + spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock, + flags); + return NULL; + } + /* new->lap = orig->lap; => done in the memcpy() */ + /* new->slsap_sel = orig->slsap_sel; => done in the memcpy() */ + new->conn_skb = NULL; + + spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock, flags); + + /* Not everything is the same */ + new->notify.instance = instance; + + init_timer(&new->watchdog_timer); + + hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) new, + (long) new, NULL); + +#ifdef CONFIG_IRDA_CACHE_LAST_LSAP + /* Make sure that we invalidate the LSAP cache */ + new->lap->cache.valid = FALSE; +#endif /* CONFIG_IRDA_CACHE_LAST_LSAP */ + + return new; +} + +/* + * Function irlmp_disconnect_request (handle, userdata) + * + * The service user is requesting disconnection, this will not remove the + * LSAP, but only mark it as disconnected + */ +int irlmp_disconnect_request(struct lsap_cb *self, struct sk_buff *userdata) +{ + struct lsap_cb *lsap; + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;); + IRDA_ASSERT(userdata != NULL, return -1;); + + /* Already disconnected ? + * There is a race condition between irlmp_disconnect_indication() + * and us that might mess up the hashbins below. This fixes it. + * Jean II */ + if (! test_and_clear_bit(0, &self->connected)) { + pr_debug("%s(), already disconnected!\n", __func__); + dev_kfree_skb(userdata); + return -1; + } + + skb_push(userdata, LMP_CONTROL_HEADER); + + /* + * Do the event before the other stuff since we must know + * which lap layer that the frame should be transmitted on + */ + irlmp_do_lsap_event(self, LM_DISCONNECT_REQUEST, userdata); + + /* Drop reference count - see irlap_data_request(). */ + dev_kfree_skb(userdata); + + /* + * Remove LSAP from list of connected LSAPs for the particular link + * and insert it into the list of unconnected LSAPs + */ + IRDA_ASSERT(self->lap != NULL, return -1;); + IRDA_ASSERT(self->lap->magic == LMP_LAP_MAGIC, return -1;); + IRDA_ASSERT(self->lap->lsaps != NULL, return -1;); + + lsap = hashbin_remove(self->lap->lsaps, (long) self, NULL); +#ifdef CONFIG_IRDA_CACHE_LAST_LSAP + self->lap->cache.valid = FALSE; +#endif + + IRDA_ASSERT(lsap != NULL, return -1;); + IRDA_ASSERT(lsap->magic == LMP_LSAP_MAGIC, return -1;); + IRDA_ASSERT(lsap == self, return -1;); + + hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) self, + (long) self, NULL); + + /* Reset some values */ + self->dlsap_sel = LSAP_ANY; + self->lap = NULL; + + return 0; +} +EXPORT_SYMBOL(irlmp_disconnect_request); + +/* + * Function irlmp_disconnect_indication (reason, userdata) + * + * LSAP is being closed! + */ +void irlmp_disconnect_indication(struct lsap_cb *self, LM_REASON reason, + struct sk_buff *skb) +{ + struct lsap_cb *lsap; + + pr_debug("%s(), reason=%s [%d]\n", __func__, + irlmp_reason_str(reason), reason); + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;); + + pr_debug("%s(), slsap_sel=%02x, dlsap_sel=%02x\n", + __func__, self->slsap_sel, self->dlsap_sel); + + /* Already disconnected ? + * There is a race condition between irlmp_disconnect_request() + * and us that might mess up the hashbins below. This fixes it. + * Jean II */ + if (! test_and_clear_bit(0, &self->connected)) { + pr_debug("%s(), already disconnected!\n", __func__); + return; + } + + /* + * Remove association between this LSAP and the link it used + */ + IRDA_ASSERT(self->lap != NULL, return;); + IRDA_ASSERT(self->lap->lsaps != NULL, return;); + + lsap = hashbin_remove(self->lap->lsaps, (long) self, NULL); +#ifdef CONFIG_IRDA_CACHE_LAST_LSAP + self->lap->cache.valid = FALSE; +#endif + + IRDA_ASSERT(lsap != NULL, return;); + IRDA_ASSERT(lsap == self, return;); + hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) lsap, + (long) lsap, NULL); + + self->dlsap_sel = LSAP_ANY; + self->lap = NULL; + + /* + * Inform service user + */ + if (self->notify.disconnect_indication) { + /* Don't forget to refcount it - see irlap_driver_rcv(). */ + if(skb) + skb_get(skb); + self->notify.disconnect_indication(self->notify.instance, + self, reason, skb); + } else { + pr_debug("%s(), no handler\n", __func__); + } +} + +/* + * Function irlmp_do_expiry (void) + * + * Do a cleanup of the discovery log (remove old entries) + * + * Note : separate from irlmp_do_discovery() so that we can handle + * passive discovery properly. + */ +void irlmp_do_expiry(void) +{ + struct lap_cb *lap; + + /* + * Expire discovery on all links which are *not* connected. + * On links which are connected, we can't do discovery + * anymore and can't refresh the log, so we freeze the + * discovery log to keep info about the device we are + * connected to. + * This info is mandatory if we want irlmp_connect_request() + * to work properly. - Jean II + */ + lap = (struct lap_cb *) hashbin_get_first(irlmp->links); + while (lap != NULL) { + IRDA_ASSERT(lap->magic == LMP_LAP_MAGIC, return;); + + if (lap->lap_state == LAP_STANDBY) { + /* Expire discoveries discovered on this link */ + irlmp_expire_discoveries(irlmp->cachelog, lap->saddr, + FALSE); + } + lap = (struct lap_cb *) hashbin_get_next(irlmp->links); + } +} + +/* + * Function irlmp_do_discovery (nslots) + * + * Do some discovery on all links + * + * Note : log expiry is done above. + */ +void irlmp_do_discovery(int nslots) +{ + struct lap_cb *lap; + __u16 *data_hintsp; + + /* Make sure the value is sane */ + if ((nslots != 1) && (nslots != 6) && (nslots != 8) && (nslots != 16)){ + net_warn_ratelimited("%s: invalid value for number of slots!\n", + __func__); + nslots = sysctl_discovery_slots = 8; + } + + /* Construct new discovery info to be used by IrLAP, */ + data_hintsp = (__u16 *) irlmp->discovery_cmd.data.hints; + put_unaligned(irlmp->hints.word, data_hintsp); + + /* + * Set character set for device name (we use ASCII), and + * copy device name. Remember to make room for a \0 at the + * end + */ + irlmp->discovery_cmd.data.charset = CS_ASCII; + strncpy(irlmp->discovery_cmd.data.info, sysctl_devname, + NICKNAME_MAX_LEN); + irlmp->discovery_cmd.name_len = strlen(irlmp->discovery_cmd.data.info); + irlmp->discovery_cmd.nslots = nslots; + + /* + * Try to send discovery packets on all links + */ + lap = (struct lap_cb *) hashbin_get_first(irlmp->links); + while (lap != NULL) { + IRDA_ASSERT(lap->magic == LMP_LAP_MAGIC, return;); + + if (lap->lap_state == LAP_STANDBY) { + /* Try to discover */ + irlmp_do_lap_event(lap, LM_LAP_DISCOVERY_REQUEST, + NULL); + } + lap = (struct lap_cb *) hashbin_get_next(irlmp->links); + } +} + +/* + * Function irlmp_discovery_request (nslots) + * + * Do a discovery of devices in front of the computer + * + * If the caller has registered a client discovery callback, this + * allow him to receive the full content of the discovery log through + * this callback (as normally he will receive only new discoveries). + */ +void irlmp_discovery_request(int nslots) +{ + /* Return current cached discovery log (in full) */ + irlmp_discovery_confirm(irlmp->cachelog, DISCOVERY_LOG); + + /* + * Start a single discovery operation if discovery is not already + * running + */ + if (!sysctl_discovery) { + /* Check if user wants to override the default */ + if (nslots == DISCOVERY_DEFAULT_SLOTS) + nslots = sysctl_discovery_slots; + + irlmp_do_discovery(nslots); + /* Note : we never do expiry here. Expiry will run on the + * discovery timer regardless of the state of sysctl_discovery + * Jean II */ + } +} +EXPORT_SYMBOL(irlmp_discovery_request); + +/* + * Function irlmp_get_discoveries (pn, mask, slots) + * + * Return the current discovery log + * + * If discovery is not enabled, you should call this function again + * after 1 or 2 seconds (i.e. after discovery has been done). + */ +struct irda_device_info *irlmp_get_discoveries(int *pn, __u16 mask, int nslots) +{ + /* If discovery is not enabled, it's likely that the discovery log + * will be empty. So, we trigger a single discovery, so that next + * time the user call us there might be some results in the log. + * Jean II + */ + if (!sysctl_discovery) { + /* Check if user wants to override the default */ + if (nslots == DISCOVERY_DEFAULT_SLOTS) + nslots = sysctl_discovery_slots; + + /* Start discovery - will complete sometime later */ + irlmp_do_discovery(nslots); + /* Note : we never do expiry here. Expiry will run on the + * discovery timer regardless of the state of sysctl_discovery + * Jean II */ + } + + /* Return current cached discovery log */ + return irlmp_copy_discoveries(irlmp->cachelog, pn, mask, TRUE); +} +EXPORT_SYMBOL(irlmp_get_discoveries); + +/* + * Function irlmp_notify_client (log) + * + * Notify all about discovered devices + * + * Clients registered with IrLMP are : + * o IrComm + * o IrLAN + * o Any socket (in any state - ouch, that may be a lot !) + * The client may have defined a callback to be notified in case of + * partial/selective discovery based on the hints that it passed to IrLMP. + */ +static inline void +irlmp_notify_client(irlmp_client_t *client, + hashbin_t *log, DISCOVERY_MODE mode) +{ + discinfo_t *discoveries; /* Copy of the discovery log */ + int number; /* Number of nodes in the log */ + int i; + + /* Check if client wants or not partial/selective log (optimisation) */ + if (!client->disco_callback) + return; + + /* + * Locking notes : + * the old code was manipulating the log directly, which was + * very racy. Now, we use copy_discoveries, that protects + * itself while dumping the log for us. + * The overhead of the copy is compensated by the fact that + * we only pass new discoveries in normal mode and don't + * pass the same old entry every 3s to the caller as we used + * to do (virtual function calling is expensive). + * Jean II + */ + + /* + * Now, check all discovered devices (if any), and notify client + * only about the services that the client is interested in + * We also notify only about the new devices unless the caller + * explicitly request a dump of the log. Jean II + */ + discoveries = irlmp_copy_discoveries(log, &number, + client->hint_mask.word, + (mode == DISCOVERY_LOG)); + /* Check if the we got some results */ + if (discoveries == NULL) + return; /* No nodes discovered */ + + /* Pass all entries to the listener */ + for(i = 0; i < number; i++) + client->disco_callback(&(discoveries[i]), mode, client->priv); + + /* Free up our buffer */ + kfree(discoveries); +} + +/* + * Function irlmp_discovery_confirm ( self, log) + * + * Some device(s) answered to our discovery request! Check to see which + * device it is, and give indication to the client(s) + * + */ +void irlmp_discovery_confirm(hashbin_t *log, DISCOVERY_MODE mode) +{ + irlmp_client_t *client; + irlmp_client_t *client_next; + + IRDA_ASSERT(log != NULL, return;); + + if (!(HASHBIN_GET_SIZE(log))) + return; + + /* For each client - notify callback may touch client list */ + client = (irlmp_client_t *) hashbin_get_first(irlmp->clients); + while (NULL != hashbin_find_next(irlmp->clients, (long) client, NULL, + (void *) &client_next) ) { + /* Check if we should notify client */ + irlmp_notify_client(client, log, mode); + + client = client_next; + } +} + +/* + * Function irlmp_discovery_expiry (expiry) + * + * This device is no longer been discovered, and therefore it is being + * purged from the discovery log. Inform all clients who have + * registered for this event... + * + * Note : called exclusively from discovery.c + * Note : this is no longer called under discovery spinlock, so the + * client can do whatever he wants in the callback. + */ +void irlmp_discovery_expiry(discinfo_t *expiries, int number) +{ + irlmp_client_t *client; + irlmp_client_t *client_next; + int i; + + IRDA_ASSERT(expiries != NULL, return;); + + /* For each client - notify callback may touch client list */ + client = (irlmp_client_t *) hashbin_get_first(irlmp->clients); + while (NULL != hashbin_find_next(irlmp->clients, (long) client, NULL, + (void *) &client_next) ) { + + /* Pass all entries to the listener */ + for(i = 0; i < number; i++) { + /* Check if we should notify client */ + if ((client->expir_callback) && + (client->hint_mask.word & + get_unaligned((__u16 *)expiries[i].hints) + & 0x7f7f) ) + client->expir_callback(&(expiries[i]), + EXPIRY_TIMEOUT, + client->priv); + } + + /* Next client */ + client = client_next; + } +} + +/* + * Function irlmp_get_discovery_response () + * + * Used by IrLAP to get the discovery info it needs when answering + * discovery requests by other devices. + */ +discovery_t *irlmp_get_discovery_response(void) +{ + IRDA_ASSERT(irlmp != NULL, return NULL;); + + put_unaligned(irlmp->hints.word, (__u16 *)irlmp->discovery_rsp.data.hints); + + /* + * Set character set for device name (we use ASCII), and + * copy device name. Remember to make room for a \0 at the + * end + */ + irlmp->discovery_rsp.data.charset = CS_ASCII; + + strncpy(irlmp->discovery_rsp.data.info, sysctl_devname, + NICKNAME_MAX_LEN); + irlmp->discovery_rsp.name_len = strlen(irlmp->discovery_rsp.data.info); + + return &irlmp->discovery_rsp; +} + +/* + * Function irlmp_data_request (self, skb) + * + * Send some data to peer device + * + * Note on skb management : + * After calling the lower layers of the IrDA stack, we always + * kfree() the skb, which drop the reference count (and potentially + * destroy it). + * IrLMP and IrLAP may queue the packet, and in those cases will need + * to use skb_get() to keep it around. + * Jean II + */ +int irlmp_data_request(struct lsap_cb *self, struct sk_buff *userdata) +{ + int ret; + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;); + + /* Make room for MUX header */ + IRDA_ASSERT(skb_headroom(userdata) >= LMP_HEADER, return -1;); + skb_push(userdata, LMP_HEADER); + + ret = irlmp_do_lsap_event(self, LM_DATA_REQUEST, userdata); + + /* Drop reference count - see irlap_data_request(). */ + dev_kfree_skb(userdata); + + return ret; +} +EXPORT_SYMBOL(irlmp_data_request); + +/* + * Function irlmp_data_indication (handle, skb) + * + * Got data from LAP layer so pass it up to upper layer + * + */ +void irlmp_data_indication(struct lsap_cb *self, struct sk_buff *skb) +{ + /* Hide LMP header from layer above */ + skb_pull(skb, LMP_HEADER); + + if (self->notify.data_indication) { + /* Don't forget to refcount it - see irlap_driver_rcv(). */ + skb_get(skb); + self->notify.data_indication(self->notify.instance, self, skb); + } +} + +/* + * Function irlmp_udata_request (self, skb) + */ +int irlmp_udata_request(struct lsap_cb *self, struct sk_buff *userdata) +{ + int ret; + + IRDA_ASSERT(userdata != NULL, return -1;); + + /* Make room for MUX header */ + IRDA_ASSERT(skb_headroom(userdata) >= LMP_HEADER, return -1;); + skb_push(userdata, LMP_HEADER); + + ret = irlmp_do_lsap_event(self, LM_UDATA_REQUEST, userdata); + + /* Drop reference count - see irlap_data_request(). */ + dev_kfree_skb(userdata); + + return ret; +} + +/* + * Function irlmp_udata_indication (self, skb) + * + * Send unreliable data (but still within the connection) + * + */ +void irlmp_udata_indication(struct lsap_cb *self, struct sk_buff *skb) +{ + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;); + IRDA_ASSERT(skb != NULL, return;); + + /* Hide LMP header from layer above */ + skb_pull(skb, LMP_HEADER); + + if (self->notify.udata_indication) { + /* Don't forget to refcount it - see irlap_driver_rcv(). */ + skb_get(skb); + self->notify.udata_indication(self->notify.instance, self, + skb); + } +} + +/* + * Function irlmp_connless_data_request (self, skb) + */ +#ifdef CONFIG_IRDA_ULTRA +int irlmp_connless_data_request(struct lsap_cb *self, struct sk_buff *userdata, + __u8 pid) +{ + struct sk_buff *clone_skb; + struct lap_cb *lap; + + IRDA_ASSERT(userdata != NULL, return -1;); + + /* Make room for MUX and PID header */ + IRDA_ASSERT(skb_headroom(userdata) >= LMP_HEADER+LMP_PID_HEADER, + return -1;); + + /* Insert protocol identifier */ + skb_push(userdata, LMP_PID_HEADER); + if(self != NULL) + userdata->data[0] = self->pid; + else + userdata->data[0] = pid; + + /* Connectionless sockets must use 0x70 */ + skb_push(userdata, LMP_HEADER); + userdata->data[0] = userdata->data[1] = LSAP_CONNLESS; + + /* Try to send Connectionless packets out on all links */ + lap = (struct lap_cb *) hashbin_get_first(irlmp->links); + while (lap != NULL) { + IRDA_ASSERT(lap->magic == LMP_LAP_MAGIC, return -1;); + + clone_skb = skb_clone(userdata, GFP_ATOMIC); + if (!clone_skb) { + dev_kfree_skb(userdata); + return -ENOMEM; + } + + irlap_unitdata_request(lap->irlap, clone_skb); + /* irlap_unitdata_request() don't increase refcount, + * so no dev_kfree_skb() - Jean II */ + + lap = (struct lap_cb *) hashbin_get_next(irlmp->links); + } + dev_kfree_skb(userdata); + + return 0; +} +#endif /* CONFIG_IRDA_ULTRA */ + +/* + * Function irlmp_connless_data_indication (self, skb) + * + * Receive unreliable data outside any connection. Mostly used by Ultra + * + */ +#ifdef CONFIG_IRDA_ULTRA +void irlmp_connless_data_indication(struct lsap_cb *self, struct sk_buff *skb) +{ + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;); + IRDA_ASSERT(skb != NULL, return;); + + /* Hide LMP and PID header from layer above */ + skb_pull(skb, LMP_HEADER+LMP_PID_HEADER); + + if (self->notify.udata_indication) { + /* Don't forget to refcount it - see irlap_driver_rcv(). */ + skb_get(skb); + self->notify.udata_indication(self->notify.instance, self, + skb); + } +} +#endif /* CONFIG_IRDA_ULTRA */ + +/* + * Propagate status indication from LAP to LSAPs (via LMP) + * This don't trigger any change of state in lap_cb, lmp_cb or lsap_cb, + * and the event is stateless, therefore we can bypass both state machines + * and send the event direct to the LSAP user. + * Jean II + */ +void irlmp_status_indication(struct lap_cb *self, + LINK_STATUS link, LOCK_STATUS lock) +{ + struct lsap_cb *next; + struct lsap_cb *curr; + + /* Send status_indication to all LSAPs using this link */ + curr = (struct lsap_cb *) hashbin_get_first( self->lsaps); + while (NULL != hashbin_find_next(self->lsaps, (long) curr, NULL, + (void *) &next) ) { + IRDA_ASSERT(curr->magic == LMP_LSAP_MAGIC, return;); + /* + * Inform service user if he has requested it + */ + if (curr->notify.status_indication != NULL) + curr->notify.status_indication(curr->notify.instance, + link, lock); + else + pr_debug("%s(), no handler\n", __func__); + + curr = next; + } +} + +/* + * Receive flow control indication from LAP. + * LAP want us to send it one more frame. We implement a simple round + * robin scheduler between the active sockets so that we get a bit of + * fairness. Note that the round robin is far from perfect, but it's + * better than nothing. + * We then poll the selected socket so that we can do synchronous + * refilling of IrLAP (which allow to minimise the number of buffers). + * Jean II + */ +void irlmp_flow_indication(struct lap_cb *self, LOCAL_FLOW flow) +{ + struct lsap_cb *next; + struct lsap_cb *curr; + int lsap_todo; + + IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;); + IRDA_ASSERT(flow == FLOW_START, return;); + + /* Get the number of lsap. That's the only safe way to know + * that we have looped around... - Jean II */ + lsap_todo = HASHBIN_GET_SIZE(self->lsaps); + pr_debug("%s() : %d lsaps to scan\n", __func__, lsap_todo); + + /* Poll lsap in order until the queue is full or until we + * tried them all. + * Most often, the current LSAP will have something to send, + * so we will go through this loop only once. - Jean II */ + while((lsap_todo--) && + (IRLAP_GET_TX_QUEUE_LEN(self->irlap) < LAP_HIGH_THRESHOLD)) { + /* Try to find the next lsap we should poll. */ + next = self->flow_next; + /* If we have no lsap, restart from first one */ + if(next == NULL) + next = (struct lsap_cb *) hashbin_get_first(self->lsaps); + /* Verify current one and find the next one */ + curr = hashbin_find_next(self->lsaps, (long) next, NULL, + (void *) &self->flow_next); + /* Uh-oh... Paranoia */ + if(curr == NULL) + break; + pr_debug("%s() : curr is %p, next was %p and is now %p, still %d to go - queue len = %d\n", + __func__, curr, next, self->flow_next, lsap_todo, + IRLAP_GET_TX_QUEUE_LEN(self->irlap)); + + /* Inform lsap user that it can send one more packet. */ + if (curr->notify.flow_indication != NULL) + curr->notify.flow_indication(curr->notify.instance, + curr, flow); + else + pr_debug("%s(), no handler\n", __func__); + } +} + +#if 0 +/* + * Function irlmp_hint_to_service (hint) + * + * Returns a list of all servics contained in the given hint bits. This + * function assumes that the hint bits have the size of two bytes only + */ +__u8 *irlmp_hint_to_service(__u8 *hint) +{ + __u8 *service; + int i = 0; + + /* + * Allocate array to store services in. 16 entries should be safe + * since we currently only support 2 hint bytes + */ + service = kmalloc(16, GFP_ATOMIC); + if (!service) + return NULL; + + if (!hint[0]) { + pr_debug("<None>\n"); + kfree(service); + return NULL; + } + if (hint[0] & HINT_PNP) + pr_debug("PnP Compatible "); + if (hint[0] & HINT_PDA) + pr_debug("PDA/Palmtop "); + if (hint[0] & HINT_COMPUTER) + pr_debug("Computer "); + if (hint[0] & HINT_PRINTER) { + pr_debug("Printer "); + service[i++] = S_PRINTER; + } + if (hint[0] & HINT_MODEM) + pr_debug("Modem "); + if (hint[0] & HINT_FAX) + pr_debug("Fax "); + if (hint[0] & HINT_LAN) { + pr_debug("LAN Access "); + service[i++] = S_LAN; + } + /* + * Test if extension byte exists. This byte will usually be + * there, but this is not really required by the standard. + * (IrLMP p. 29) + */ + if (hint[0] & HINT_EXTENSION) { + if (hint[1] & HINT_TELEPHONY) { + pr_debug("Telephony "); + service[i++] = S_TELEPHONY; + } + if (hint[1] & HINT_FILE_SERVER) + pr_debug("File Server "); + + if (hint[1] & HINT_COMM) { + pr_debug("IrCOMM "); + service[i++] = S_COMM; + } + if (hint[1] & HINT_OBEX) { + pr_debug("IrOBEX "); + service[i++] = S_OBEX; + } + } + pr_debug("\n"); + + /* So that client can be notified about any discovery */ + service[i++] = S_ANY; + + service[i] = S_END; + + return service; +} +#endif + +static const __u16 service_hint_mapping[S_END][2] = { + { HINT_PNP, 0 }, /* S_PNP */ + { HINT_PDA, 0 }, /* S_PDA */ + { HINT_COMPUTER, 0 }, /* S_COMPUTER */ + { HINT_PRINTER, 0 }, /* S_PRINTER */ + { HINT_MODEM, 0 }, /* S_MODEM */ + { HINT_FAX, 0 }, /* S_FAX */ + { HINT_LAN, 0 }, /* S_LAN */ + { HINT_EXTENSION, HINT_TELEPHONY }, /* S_TELEPHONY */ + { HINT_EXTENSION, HINT_COMM }, /* S_COMM */ + { HINT_EXTENSION, HINT_OBEX }, /* S_OBEX */ + { 0xFF, 0xFF }, /* S_ANY */ +}; + +/* + * Function irlmp_service_to_hint (service) + * + * Converts a service type, to a hint bit + * + * Returns: a 16 bit hint value, with the service bit set + */ +__u16 irlmp_service_to_hint(int service) +{ + __u16_host_order hint; + + hint.byte[0] = service_hint_mapping[service][0]; + hint.byte[1] = service_hint_mapping[service][1]; + + return hint.word; +} +EXPORT_SYMBOL(irlmp_service_to_hint); + +/* + * Function irlmp_register_service (service) + * + * Register local service with IrLMP + * + */ +void *irlmp_register_service(__u16 hints) +{ + irlmp_service_t *service; + + pr_debug("%s(), hints = %04x\n", __func__, hints); + + /* Make a new registration */ + service = kmalloc(sizeof(irlmp_service_t), GFP_ATOMIC); + if (!service) + return NULL; + + service->hints.word = hints; + hashbin_insert(irlmp->services, (irda_queue_t *) service, + (long) service, NULL); + + irlmp->hints.word |= hints; + + return (void *)service; +} +EXPORT_SYMBOL(irlmp_register_service); + +/* + * Function irlmp_unregister_service (handle) + * + * Unregister service with IrLMP. + * + * Returns: 0 on success, -1 on error + */ +int irlmp_unregister_service(void *handle) +{ + irlmp_service_t *service; + unsigned long flags; + + if (!handle) + return -1; + + /* Caller may call with invalid handle (it's legal) - Jean II */ + service = hashbin_lock_find(irlmp->services, (long) handle, NULL); + if (!service) { + pr_debug("%s(), Unknown service!\n", __func__); + return -1; + } + + hashbin_remove_this(irlmp->services, (irda_queue_t *) service); + kfree(service); + + /* Remove old hint bits */ + irlmp->hints.word = 0; + + /* Refresh current hint bits */ + spin_lock_irqsave(&irlmp->services->hb_spinlock, flags); + service = (irlmp_service_t *) hashbin_get_first(irlmp->services); + while (service) { + irlmp->hints.word |= service->hints.word; + + service = (irlmp_service_t *)hashbin_get_next(irlmp->services); + } + spin_unlock_irqrestore(&irlmp->services->hb_spinlock, flags); + return 0; +} +EXPORT_SYMBOL(irlmp_unregister_service); + +/* + * Function irlmp_register_client (hint_mask, callback1, callback2) + * + * Register a local client with IrLMP + * First callback is selective discovery (based on hints) + * Second callback is for selective discovery expiries + * + * Returns: handle > 0 on success, 0 on error + */ +void *irlmp_register_client(__u16 hint_mask, DISCOVERY_CALLBACK1 disco_clb, + DISCOVERY_CALLBACK2 expir_clb, void *priv) +{ + irlmp_client_t *client; + + IRDA_ASSERT(irlmp != NULL, return NULL;); + + /* Make a new registration */ + client = kmalloc(sizeof(irlmp_client_t), GFP_ATOMIC); + if (!client) + return NULL; + + /* Register the details */ + client->hint_mask.word = hint_mask; + client->disco_callback = disco_clb; + client->expir_callback = expir_clb; + client->priv = priv; + + hashbin_insert(irlmp->clients, (irda_queue_t *) client, + (long) client, NULL); + + return (void *) client; +} +EXPORT_SYMBOL(irlmp_register_client); + +/* + * Function irlmp_update_client (handle, hint_mask, callback1, callback2) + * + * Updates specified client (handle) with possibly new hint_mask and + * callback + * + * Returns: 0 on success, -1 on error + */ +int irlmp_update_client(void *handle, __u16 hint_mask, + DISCOVERY_CALLBACK1 disco_clb, + DISCOVERY_CALLBACK2 expir_clb, void *priv) +{ + irlmp_client_t *client; + + if (!handle) + return -1; + + client = hashbin_lock_find(irlmp->clients, (long) handle, NULL); + if (!client) { + pr_debug("%s(), Unknown client!\n", __func__); + return -1; + } + + client->hint_mask.word = hint_mask; + client->disco_callback = disco_clb; + client->expir_callback = expir_clb; + client->priv = priv; + + return 0; +} +EXPORT_SYMBOL(irlmp_update_client); + +/* + * Function irlmp_unregister_client (handle) + * + * Returns: 0 on success, -1 on error + * + */ +int irlmp_unregister_client(void *handle) +{ + struct irlmp_client *client; + + if (!handle) + return -1; + + /* Caller may call with invalid handle (it's legal) - Jean II */ + client = hashbin_lock_find(irlmp->clients, (long) handle, NULL); + if (!client) { + pr_debug("%s(), Unknown client!\n", __func__); + return -1; + } + + pr_debug("%s(), removing client!\n", __func__); + hashbin_remove_this(irlmp->clients, (irda_queue_t *) client); + kfree(client); + + return 0; +} +EXPORT_SYMBOL(irlmp_unregister_client); + +/* + * Function irlmp_slsap_inuse (slsap) + * + * Check if the given source LSAP selector is in use + * + * This function is clearly not very efficient. On the mitigating side, the + * stack make sure that in 99% of the cases, we are called only once + * for each socket allocation. We could probably keep a bitmap + * of the allocated LSAP, but I'm not sure the complexity is worth it. + * Jean II + */ +static int irlmp_slsap_inuse(__u8 slsap_sel) +{ + struct lsap_cb *self; + struct lap_cb *lap; + unsigned long flags; + + IRDA_ASSERT(irlmp != NULL, return TRUE;); + IRDA_ASSERT(irlmp->magic == LMP_MAGIC, return TRUE;); + IRDA_ASSERT(slsap_sel != LSAP_ANY, return TRUE;); + +#ifdef CONFIG_IRDA_ULTRA + /* Accept all bindings to the connectionless LSAP */ + if (slsap_sel == LSAP_CONNLESS) + return FALSE; +#endif /* CONFIG_IRDA_ULTRA */ + + /* Valid values are between 0 and 127 (0x0-0x6F) */ + if (slsap_sel > LSAP_MAX) + return TRUE; + + /* + * Check if slsap is already in use. To do this we have to loop over + * every IrLAP connection and check every LSAP associated with each + * the connection. + */ + spin_lock_irqsave_nested(&irlmp->links->hb_spinlock, flags, + SINGLE_DEPTH_NESTING); + lap = (struct lap_cb *) hashbin_get_first(irlmp->links); + while (lap != NULL) { + IRDA_ASSERT(lap->magic == LMP_LAP_MAGIC, goto errlap;); + + /* Careful for priority inversions here ! + * irlmp->links is never taken while another IrDA + * spinlock is held, so we are safe. Jean II */ + spin_lock(&lap->lsaps->hb_spinlock); + + /* For this IrLAP, check all the LSAPs */ + self = (struct lsap_cb *) hashbin_get_first(lap->lsaps); + while (self != NULL) { + IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, + goto errlsap;); + + if ((self->slsap_sel == slsap_sel)) { + pr_debug("Source LSAP selector=%02x in use\n", + self->slsap_sel); + goto errlsap; + } + self = (struct lsap_cb*) hashbin_get_next(lap->lsaps); + } + spin_unlock(&lap->lsaps->hb_spinlock); + + /* Next LAP */ + lap = (struct lap_cb *) hashbin_get_next(irlmp->links); + } + spin_unlock_irqrestore(&irlmp->links->hb_spinlock, flags); + + /* + * Server sockets are typically waiting for connections and + * therefore reside in the unconnected list. We don't want + * to give out their LSAPs for obvious reasons... + * Jean II + */ + spin_lock_irqsave(&irlmp->unconnected_lsaps->hb_spinlock, flags); + + self = (struct lsap_cb *) hashbin_get_first(irlmp->unconnected_lsaps); + while (self != NULL) { + IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, goto erruncon;); + if ((self->slsap_sel == slsap_sel)) { + pr_debug("Source LSAP selector=%02x in use (unconnected)\n", + self->slsap_sel); + goto erruncon; + } + self = (struct lsap_cb*) hashbin_get_next(irlmp->unconnected_lsaps); + } + spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock, flags); + + return FALSE; + + /* Error exit from within one of the two nested loops. + * Make sure we release the right spinlock in the righ order. + * Jean II */ +errlsap: + spin_unlock(&lap->lsaps->hb_spinlock); +IRDA_ASSERT_LABEL(errlap:) + spin_unlock_irqrestore(&irlmp->links->hb_spinlock, flags); + return TRUE; + + /* Error exit from within the unconnected loop. + * Just one spinlock to release... Jean II */ +erruncon: + spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock, flags); + return TRUE; +} + +/* + * Function irlmp_find_free_slsap () + * + * Find a free source LSAP to use. This function is called if the service + * user has requested a source LSAP equal to LM_ANY + */ +static __u8 irlmp_find_free_slsap(void) +{ + __u8 lsap_sel; + int wrapped = 0; + + IRDA_ASSERT(irlmp != NULL, return -1;); + IRDA_ASSERT(irlmp->magic == LMP_MAGIC, return -1;); + + /* Most users don't really care which LSAPs they are given, + * and therefore we automatically give them a free LSAP. + * This function try to find a suitable LSAP, i.e. which is + * not in use and is within the acceptable range. Jean II */ + + do { + /* Always increment to LSAP number before using it. + * In theory, we could reuse the last LSAP number, as long + * as it is no longer in use. Some IrDA stack do that. + * However, the previous socket may be half closed, i.e. + * we closed it, we think it's no longer in use, but the + * other side did not receive our close and think it's + * active and still send data on it. + * This is similar to what is done with PIDs and TCP ports. + * Also, this reduce the number of calls to irlmp_slsap_inuse() + * which is an expensive function to call. + * Jean II */ + irlmp->last_lsap_sel++; + + /* Check if we need to wraparound (0x70-0x7f are reserved) */ + if (irlmp->last_lsap_sel > LSAP_MAX) { + /* 0x00-0x10 are also reserved for well know ports */ + irlmp->last_lsap_sel = 0x10; + + /* Make sure we terminate the loop */ + if (wrapped++) { + net_err_ratelimited("%s: no more free LSAPs !\n", + __func__); + return 0; + } + } + + /* If the LSAP is in use, try the next one. + * Despite the autoincrement, we need to check if the lsap + * is really in use or not, first because LSAP may be + * directly allocated in irlmp_open_lsap(), and also because + * we may wraparound on old sockets. Jean II */ + } while (irlmp_slsap_inuse(irlmp->last_lsap_sel)); + + /* Got it ! */ + lsap_sel = irlmp->last_lsap_sel; + pr_debug("%s(), found free lsap_sel=%02x\n", + __func__, lsap_sel); + + return lsap_sel; +} + +/* + * Function irlmp_convert_lap_reason (lap_reason) + * + * Converts IrLAP disconnect reason codes to IrLMP disconnect reason + * codes + * + */ +LM_REASON irlmp_convert_lap_reason( LAP_REASON lap_reason) +{ + int reason = LM_LAP_DISCONNECT; + + switch (lap_reason) { + case LAP_DISC_INDICATION: /* Received a disconnect request from peer */ + pr_debug("%s(), LAP_DISC_INDICATION\n", __func__); + reason = LM_USER_REQUEST; + break; + case LAP_NO_RESPONSE: /* To many retransmits without response */ + pr_debug("%s(), LAP_NO_RESPONSE\n", __func__); + reason = LM_LAP_DISCONNECT; + break; + case LAP_RESET_INDICATION: + pr_debug("%s(), LAP_RESET_INDICATION\n", __func__); + reason = LM_LAP_RESET; + break; + case LAP_FOUND_NONE: + case LAP_MEDIA_BUSY: + case LAP_PRIMARY_CONFLICT: + pr_debug("%s(), LAP_FOUND_NONE, LAP_MEDIA_BUSY or LAP_PRIMARY_CONFLICT\n", + __func__); + reason = LM_CONNECT_FAILURE; + break; + default: + pr_debug("%s(), Unknown IrLAP disconnect reason %d!\n", + __func__, lap_reason); + reason = LM_LAP_DISCONNECT; + break; + } + + return reason; +} + +#ifdef CONFIG_PROC_FS + +struct irlmp_iter_state { + hashbin_t *hashbin; +}; + +#define LSAP_START_TOKEN ((void *)1) +#define LINK_START_TOKEN ((void *)2) + +static void *irlmp_seq_hb_idx(struct irlmp_iter_state *iter, loff_t *off) +{ + void *element; + + spin_lock_irq(&iter->hashbin->hb_spinlock); + for (element = hashbin_get_first(iter->hashbin); + element != NULL; + element = hashbin_get_next(iter->hashbin)) { + if (!off || (*off)-- == 0) { + /* NB: hashbin left locked */ + return element; + } + } + spin_unlock_irq(&iter->hashbin->hb_spinlock); + iter->hashbin = NULL; + return NULL; +} + + +static void *irlmp_seq_start(struct seq_file *seq, loff_t *pos) +{ + struct irlmp_iter_state *iter = seq->private; + void *v; + loff_t off = *pos; + + iter->hashbin = NULL; + if (off-- == 0) + return LSAP_START_TOKEN; + + iter->hashbin = irlmp->unconnected_lsaps; + v = irlmp_seq_hb_idx(iter, &off); + if (v) + return v; + + if (off-- == 0) + return LINK_START_TOKEN; + + iter->hashbin = irlmp->links; + return irlmp_seq_hb_idx(iter, &off); +} + +static void *irlmp_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + struct irlmp_iter_state *iter = seq->private; + + ++*pos; + + if (v == LSAP_START_TOKEN) { /* start of list of lsaps */ + iter->hashbin = irlmp->unconnected_lsaps; + v = irlmp_seq_hb_idx(iter, NULL); + return v ? v : LINK_START_TOKEN; + } + + if (v == LINK_START_TOKEN) { /* start of list of links */ + iter->hashbin = irlmp->links; + return irlmp_seq_hb_idx(iter, NULL); + } + + v = hashbin_get_next(iter->hashbin); + + if (v == NULL) { /* no more in this hash bin */ + spin_unlock_irq(&iter->hashbin->hb_spinlock); + + if (iter->hashbin == irlmp->unconnected_lsaps) + v = LINK_START_TOKEN; + + iter->hashbin = NULL; + } + return v; +} + +static void irlmp_seq_stop(struct seq_file *seq, void *v) +{ + struct irlmp_iter_state *iter = seq->private; + + if (iter->hashbin) + spin_unlock_irq(&iter->hashbin->hb_spinlock); +} + +static int irlmp_seq_show(struct seq_file *seq, void *v) +{ + const struct irlmp_iter_state *iter = seq->private; + struct lsap_cb *self = v; + + if (v == LSAP_START_TOKEN) + seq_puts(seq, "Unconnected LSAPs:\n"); + else if (v == LINK_START_TOKEN) + seq_puts(seq, "\nRegistered Link Layers:\n"); + else if (iter->hashbin == irlmp->unconnected_lsaps) { + self = v; + IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -EINVAL; ); + seq_printf(seq, "lsap state: %s, ", + irlsap_state[ self->lsap_state]); + seq_printf(seq, + "slsap_sel: %#02x, dlsap_sel: %#02x, ", + self->slsap_sel, self->dlsap_sel); + seq_printf(seq, "(%s)", self->notify.name); + seq_printf(seq, "\n"); + } else if (iter->hashbin == irlmp->links) { + struct lap_cb *lap = v; + + seq_printf(seq, "lap state: %s, ", + irlmp_state[lap->lap_state]); + + seq_printf(seq, "saddr: %#08x, daddr: %#08x, ", + lap->saddr, lap->daddr); + seq_printf(seq, "num lsaps: %d", + HASHBIN_GET_SIZE(lap->lsaps)); + seq_printf(seq, "\n"); + + /* Careful for priority inversions here ! + * All other uses of attrib spinlock are independent of + * the object spinlock, so we are safe. Jean II */ + spin_lock(&lap->lsaps->hb_spinlock); + + seq_printf(seq, "\n Connected LSAPs:\n"); + for (self = (struct lsap_cb *) hashbin_get_first(lap->lsaps); + self != NULL; + self = (struct lsap_cb *)hashbin_get_next(lap->lsaps)) { + IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, + goto outloop;); + seq_printf(seq, " lsap state: %s, ", + irlsap_state[ self->lsap_state]); + seq_printf(seq, + "slsap_sel: %#02x, dlsap_sel: %#02x, ", + self->slsap_sel, self->dlsap_sel); + seq_printf(seq, "(%s)", self->notify.name); + seq_putc(seq, '\n'); + + } + IRDA_ASSERT_LABEL(outloop:) + spin_unlock(&lap->lsaps->hb_spinlock); + seq_putc(seq, '\n'); + } else + return -EINVAL; + + return 0; +} + +static const struct seq_operations irlmp_seq_ops = { + .start = irlmp_seq_start, + .next = irlmp_seq_next, + .stop = irlmp_seq_stop, + .show = irlmp_seq_show, +}; + +static int irlmp_seq_open(struct inode *inode, struct file *file) +{ + IRDA_ASSERT(irlmp != NULL, return -EINVAL;); + + return seq_open_private(file, &irlmp_seq_ops, + sizeof(struct irlmp_iter_state)); +} + +const struct file_operations irlmp_seq_fops = { + .owner = THIS_MODULE, + .open = irlmp_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release_private, +}; + +#endif /* PROC_FS */ diff --git a/drivers/staging/irda/net/irlmp_event.c b/drivers/staging/irda/net/irlmp_event.c new file mode 100644 index 000000000000..e306cf2c1e04 --- /dev/null +++ b/drivers/staging/irda/net/irlmp_event.c @@ -0,0 +1,886 @@ +/********************************************************************* + * + * Filename: irlmp_event.c + * Version: 0.8 + * Description: An IrDA LMP event driver for Linux + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Mon Aug 4 20:40:53 1997 + * Modified at: Tue Dec 14 23:04:16 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, + * All Rights Reserved. + * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#include <linux/kernel.h> + +#include <net/irda/irda.h> +#include <net/irda/timer.h> +#include <net/irda/irlap.h> +#include <net/irda/irlmp.h> +#include <net/irda/irlmp_frame.h> +#include <net/irda/irlmp_event.h> + +const char *const irlmp_state[] = { + "LAP_STANDBY", + "LAP_U_CONNECT", + "LAP_ACTIVE", +}; + +const char *const irlsap_state[] = { + "LSAP_DISCONNECTED", + "LSAP_CONNECT", + "LSAP_CONNECT_PEND", + "LSAP_DATA_TRANSFER_READY", + "LSAP_SETUP", + "LSAP_SETUP_PEND", +}; + +static const char *const irlmp_event[] __maybe_unused = { + "LM_CONNECT_REQUEST", + "LM_CONNECT_CONFIRM", + "LM_CONNECT_RESPONSE", + "LM_CONNECT_INDICATION", + + "LM_DISCONNECT_INDICATION", + "LM_DISCONNECT_REQUEST", + + "LM_DATA_REQUEST", + "LM_UDATA_REQUEST", + "LM_DATA_INDICATION", + "LM_UDATA_INDICATION", + + "LM_WATCHDOG_TIMEOUT", + + /* IrLAP events */ + "LM_LAP_CONNECT_REQUEST", + "LM_LAP_CONNECT_INDICATION", + "LM_LAP_CONNECT_CONFIRM", + "LM_LAP_DISCONNECT_INDICATION", + "LM_LAP_DISCONNECT_REQUEST", + "LM_LAP_DISCOVERY_REQUEST", + "LM_LAP_DISCOVERY_CONFIRM", + "LM_LAP_IDLE_TIMEOUT", +}; + +/* LAP Connection control proto declarations */ +static void irlmp_state_standby (struct lap_cb *, IRLMP_EVENT, + struct sk_buff *); +static void irlmp_state_u_connect(struct lap_cb *, IRLMP_EVENT, + struct sk_buff *); +static void irlmp_state_active (struct lap_cb *, IRLMP_EVENT, + struct sk_buff *); + +/* LSAP Connection control proto declarations */ +static int irlmp_state_disconnected(struct lsap_cb *, IRLMP_EVENT, + struct sk_buff *); +static int irlmp_state_connect (struct lsap_cb *, IRLMP_EVENT, + struct sk_buff *); +static int irlmp_state_connect_pend(struct lsap_cb *, IRLMP_EVENT, + struct sk_buff *); +static int irlmp_state_dtr (struct lsap_cb *, IRLMP_EVENT, + struct sk_buff *); +static int irlmp_state_setup (struct lsap_cb *, IRLMP_EVENT, + struct sk_buff *); +static int irlmp_state_setup_pend (struct lsap_cb *, IRLMP_EVENT, + struct sk_buff *); + +static void (*lap_state[]) (struct lap_cb *, IRLMP_EVENT, struct sk_buff *) = +{ + irlmp_state_standby, + irlmp_state_u_connect, + irlmp_state_active, +}; + +static int (*lsap_state[])( struct lsap_cb *, IRLMP_EVENT, struct sk_buff *) = +{ + irlmp_state_disconnected, + irlmp_state_connect, + irlmp_state_connect_pend, + irlmp_state_dtr, + irlmp_state_setup, + irlmp_state_setup_pend +}; + +static inline void irlmp_next_lap_state(struct lap_cb *self, + IRLMP_STATE state) +{ + /* + pr_debug("%s(), LMP LAP = %s\n", __func__, irlmp_state[state]); + */ + self->lap_state = state; +} + +static inline void irlmp_next_lsap_state(struct lsap_cb *self, + LSAP_STATE state) +{ + /* + IRDA_ASSERT(self != NULL, return;); + pr_debug("%s(), LMP LSAP = %s\n", __func__, irlsap_state[state]); + */ + self->lsap_state = state; +} + +/* Do connection control events */ +int irlmp_do_lsap_event(struct lsap_cb *self, IRLMP_EVENT event, + struct sk_buff *skb) +{ + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;); + + pr_debug("%s(), EVENT = %s, STATE = %s\n", + __func__, irlmp_event[event], irlsap_state[self->lsap_state]); + + return (*lsap_state[self->lsap_state]) (self, event, skb); +} + +/* + * Function do_lap_event (event, skb, info) + * + * Do IrLAP control events + * + */ +void irlmp_do_lap_event(struct lap_cb *self, IRLMP_EVENT event, + struct sk_buff *skb) +{ + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;); + + pr_debug("%s(), EVENT = %s, STATE = %s\n", __func__, + irlmp_event[event], + irlmp_state[self->lap_state]); + + (*lap_state[self->lap_state]) (self, event, skb); +} + +void irlmp_discovery_timer_expired(void *data) +{ + /* We always cleanup the log (active & passive discovery) */ + irlmp_do_expiry(); + + irlmp_do_discovery(sysctl_discovery_slots); + + /* Restart timer */ + irlmp_start_discovery_timer(irlmp, sysctl_discovery_timeout * HZ); +} + +void irlmp_watchdog_timer_expired(void *data) +{ + struct lsap_cb *self = (struct lsap_cb *) data; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;); + + irlmp_do_lsap_event(self, LM_WATCHDOG_TIMEOUT, NULL); +} + +void irlmp_idle_timer_expired(void *data) +{ + struct lap_cb *self = (struct lap_cb *) data; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;); + + irlmp_do_lap_event(self, LM_LAP_IDLE_TIMEOUT, NULL); +} + +/* + * Send an event on all LSAPs attached to this LAP. + */ +static inline void +irlmp_do_all_lsap_event(hashbin_t * lsap_hashbin, + IRLMP_EVENT event) +{ + struct lsap_cb *lsap; + struct lsap_cb *lsap_next; + + /* Note : this function use the new hashbin_find_next() + * function, instead of the old hashbin_get_next(). + * This make sure that we are always pointing one lsap + * ahead, so that if the current lsap is removed as the + * result of sending the event, we don't care. + * Also, as we store the context ourselves, if an enumeration + * of the same lsap hashbin happens as the result of sending the + * event, we don't care. + * The only problem is if the next lsap is removed. In that case, + * hashbin_find_next() will return NULL and we will abort the + * enumeration. - Jean II */ + + /* Also : we don't accept any skb in input. We can *NOT* pass + * the same skb to multiple clients safely, we would need to + * skb_clone() it. - Jean II */ + + lsap = (struct lsap_cb *) hashbin_get_first(lsap_hashbin); + + while (NULL != hashbin_find_next(lsap_hashbin, + (long) lsap, + NULL, + (void *) &lsap_next) ) { + irlmp_do_lsap_event(lsap, event, NULL); + lsap = lsap_next; + } +} + +/********************************************************************* + * + * LAP connection control states + * + ********************************************************************/ + +/* + * Function irlmp_state_standby (event, skb, info) + * + * STANDBY, The IrLAP connection does not exist. + * + */ +static void irlmp_state_standby(struct lap_cb *self, IRLMP_EVENT event, + struct sk_buff *skb) +{ + IRDA_ASSERT(self->irlap != NULL, return;); + + switch (event) { + case LM_LAP_DISCOVERY_REQUEST: + /* irlmp_next_station_state( LMP_DISCOVER); */ + + irlap_discovery_request(self->irlap, &irlmp->discovery_cmd); + break; + case LM_LAP_CONNECT_INDICATION: + /* It's important to switch state first, to avoid IrLMP to + * think that the link is free since IrLMP may then start + * discovery before the connection is properly set up. DB. + */ + irlmp_next_lap_state(self, LAP_ACTIVE); + + /* Just accept connection TODO, this should be fixed */ + irlap_connect_response(self->irlap, skb); + break; + case LM_LAP_CONNECT_REQUEST: + pr_debug("%s() LS_CONNECT_REQUEST\n", __func__); + + irlmp_next_lap_state(self, LAP_U_CONNECT); + + /* FIXME: need to set users requested QoS */ + irlap_connect_request(self->irlap, self->daddr, NULL, 0); + break; + case LM_LAP_DISCONNECT_INDICATION: + pr_debug("%s(), Error LM_LAP_DISCONNECT_INDICATION\n", + __func__); + + irlmp_next_lap_state(self, LAP_STANDBY); + break; + default: + pr_debug("%s(), Unknown event %s\n", + __func__, irlmp_event[event]); + break; + } +} + +/* + * Function irlmp_state_u_connect (event, skb, info) + * + * U_CONNECT, The layer above has tried to open an LSAP connection but + * since the IrLAP connection does not exist, we must first start an + * IrLAP connection. We are now waiting response from IrLAP. + * */ +static void irlmp_state_u_connect(struct lap_cb *self, IRLMP_EVENT event, + struct sk_buff *skb) +{ + pr_debug("%s(), event=%s\n", __func__, irlmp_event[event]); + + switch (event) { + case LM_LAP_CONNECT_INDICATION: + /* It's important to switch state first, to avoid IrLMP to + * think that the link is free since IrLMP may then start + * discovery before the connection is properly set up. DB. + */ + irlmp_next_lap_state(self, LAP_ACTIVE); + + /* Just accept connection TODO, this should be fixed */ + irlap_connect_response(self->irlap, skb); + + /* Tell LSAPs that they can start sending data */ + irlmp_do_all_lsap_event(self->lsaps, LM_LAP_CONNECT_CONFIRM); + + /* Note : by the time we get there (LAP retries and co), + * the lsaps may already have gone. This avoid getting stuck + * forever in LAP_ACTIVE state - Jean II */ + if (HASHBIN_GET_SIZE(self->lsaps) == 0) { + pr_debug("%s() NO LSAPs !\n", __func__); + irlmp_start_idle_timer(self, LM_IDLE_TIMEOUT); + } + break; + case LM_LAP_CONNECT_REQUEST: + /* Already trying to connect */ + break; + case LM_LAP_CONNECT_CONFIRM: + /* For all lsap_ce E Associated do LS_Connect_confirm */ + irlmp_next_lap_state(self, LAP_ACTIVE); + + /* Tell LSAPs that they can start sending data */ + irlmp_do_all_lsap_event(self->lsaps, LM_LAP_CONNECT_CONFIRM); + + /* Note : by the time we get there (LAP retries and co), + * the lsaps may already have gone. This avoid getting stuck + * forever in LAP_ACTIVE state - Jean II */ + if (HASHBIN_GET_SIZE(self->lsaps) == 0) { + pr_debug("%s() NO LSAPs !\n", __func__); + irlmp_start_idle_timer(self, LM_IDLE_TIMEOUT); + } + break; + case LM_LAP_DISCONNECT_INDICATION: + pr_debug("%s(), LM_LAP_DISCONNECT_INDICATION\n", __func__); + irlmp_next_lap_state(self, LAP_STANDBY); + + /* Send disconnect event to all LSAPs using this link */ + irlmp_do_all_lsap_event(self->lsaps, + LM_LAP_DISCONNECT_INDICATION); + break; + case LM_LAP_DISCONNECT_REQUEST: + pr_debug("%s(), LM_LAP_DISCONNECT_REQUEST\n", __func__); + + /* One of the LSAP did timeout or was closed, if it was + * the last one, try to get out of here - Jean II */ + if (HASHBIN_GET_SIZE(self->lsaps) <= 1) { + irlap_disconnect_request(self->irlap); + } + break; + default: + pr_debug("%s(), Unknown event %s\n", + __func__, irlmp_event[event]); + break; + } +} + +/* + * Function irlmp_state_active (event, skb, info) + * + * ACTIVE, IrLAP connection is active + * + */ +static void irlmp_state_active(struct lap_cb *self, IRLMP_EVENT event, + struct sk_buff *skb) +{ + switch (event) { + case LM_LAP_CONNECT_REQUEST: + pr_debug("%s(), LS_CONNECT_REQUEST\n", __func__); + + /* + * IrLAP may have a pending disconnect. We tried to close + * IrLAP, but it was postponed because the link was + * busy or we were still sending packets. As we now + * need it, make sure it stays on. Jean II + */ + irlap_clear_disconnect(self->irlap); + + /* + * LAP connection already active, just bounce back! Since we + * don't know which LSAP that tried to do this, we have to + * notify all LSAPs using this LAP, but that should be safe to + * do anyway. + */ + irlmp_do_all_lsap_event(self->lsaps, LM_LAP_CONNECT_CONFIRM); + + /* Needed by connect indication */ + irlmp_do_all_lsap_event(irlmp->unconnected_lsaps, + LM_LAP_CONNECT_CONFIRM); + /* Keep state */ + break; + case LM_LAP_DISCONNECT_REQUEST: + /* + * Need to find out if we should close IrLAP or not. If there + * is only one LSAP connection left on this link, that LSAP + * must be the one that tries to close IrLAP. It will be + * removed later and moved to the list of unconnected LSAPs + */ + if (HASHBIN_GET_SIZE(self->lsaps) > 0) { + /* Timer value is checked in irsysctl - Jean II */ + irlmp_start_idle_timer(self, sysctl_lap_keepalive_time * HZ / 1000); + } else { + /* No more connections, so close IrLAP */ + + /* We don't want to change state just yet, because + * we want to reflect accurately the real state of + * the LAP, not the state we wish it was in, + * so that we don't lose LM_LAP_CONNECT_REQUEST. + * In some cases, IrLAP won't close the LAP + * immediately. For example, it might still be + * retrying packets or waiting for the pf bit. + * As the LAP always send a DISCONNECT_INDICATION + * in PCLOSE or SCLOSE, just change state on that. + * Jean II */ + irlap_disconnect_request(self->irlap); + } + break; + case LM_LAP_IDLE_TIMEOUT: + if (HASHBIN_GET_SIZE(self->lsaps) == 0) { + /* Same reasoning as above - keep state */ + irlap_disconnect_request(self->irlap); + } + break; + case LM_LAP_DISCONNECT_INDICATION: + irlmp_next_lap_state(self, LAP_STANDBY); + + /* In some case, at this point our side has already closed + * all lsaps, and we are waiting for the idle_timer to + * expire. If another device reconnect immediately, the + * idle timer will expire in the midle of the connection + * initialisation, screwing up things a lot... + * Therefore, we must stop the timer... */ + irlmp_stop_idle_timer(self); + + /* + * Inform all connected LSAP's using this link + */ + irlmp_do_all_lsap_event(self->lsaps, + LM_LAP_DISCONNECT_INDICATION); + + /* Force an expiry of the discovery log. + * Now that the LAP is free, the system may attempt to + * connect to another device. Unfortunately, our entries + * are stale. There is a small window (<3s) before the + * normal discovery will run and where irlmp_connect_request() + * can get the wrong info, so make sure things get + * cleaned *NOW* ;-) - Jean II */ + irlmp_do_expiry(); + break; + default: + pr_debug("%s(), Unknown event %s\n", + __func__, irlmp_event[event]); + break; + } +} + +/********************************************************************* + * + * LSAP connection control states + * + ********************************************************************/ + +/* + * Function irlmp_state_disconnected (event, skb, info) + * + * DISCONNECTED + * + */ +static int irlmp_state_disconnected(struct lsap_cb *self, IRLMP_EVENT event, + struct sk_buff *skb) +{ + int ret = 0; + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;); + + switch (event) { +#ifdef CONFIG_IRDA_ULTRA + case LM_UDATA_INDICATION: + /* This is most bizarre. Those packets are aka unreliable + * connected, aka IrLPT or SOCK_DGRAM/IRDAPROTO_UNITDATA. + * Why do we pass them as Ultra ??? Jean II */ + irlmp_connless_data_indication(self, skb); + break; +#endif /* CONFIG_IRDA_ULTRA */ + case LM_CONNECT_REQUEST: + pr_debug("%s(), LM_CONNECT_REQUEST\n", __func__); + + if (self->conn_skb) { + net_warn_ratelimited("%s: busy with another request!\n", + __func__); + return -EBUSY; + } + /* Don't forget to refcount it (see irlmp_connect_request()) */ + skb_get(skb); + self->conn_skb = skb; + + irlmp_next_lsap_state(self, LSAP_SETUP_PEND); + + /* Start watchdog timer (5 secs for now) */ + irlmp_start_watchdog_timer(self, 5*HZ); + + irlmp_do_lap_event(self->lap, LM_LAP_CONNECT_REQUEST, NULL); + break; + case LM_CONNECT_INDICATION: + if (self->conn_skb) { + net_warn_ratelimited("%s: busy with another request!\n", + __func__); + return -EBUSY; + } + /* Don't forget to refcount it (see irlap_driver_rcv()) */ + skb_get(skb); + self->conn_skb = skb; + + irlmp_next_lsap_state(self, LSAP_CONNECT_PEND); + + /* Start watchdog timer + * This is not mentionned in the spec, but there is a rare + * race condition that can get the socket stuck. + * If we receive this event while our LAP is closing down, + * the LM_LAP_CONNECT_REQUEST get lost and we get stuck in + * CONNECT_PEND state forever. + * The other cause of getting stuck down there is if the + * higher layer never reply to the CONNECT_INDICATION. + * Anyway, it make sense to make sure that we always have + * a backup plan. 1 second is plenty (should be immediate). + * Jean II */ + irlmp_start_watchdog_timer(self, 1*HZ); + + irlmp_do_lap_event(self->lap, LM_LAP_CONNECT_REQUEST, NULL); + break; + default: + pr_debug("%s(), Unknown event %s on LSAP %#02x\n", + __func__, irlmp_event[event], self->slsap_sel); + break; + } + return ret; +} + +/* + * Function irlmp_state_connect (self, event, skb) + * + * CONNECT + * + */ +static int irlmp_state_connect(struct lsap_cb *self, IRLMP_EVENT event, + struct sk_buff *skb) +{ + struct lsap_cb *lsap; + int ret = 0; + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;); + + switch (event) { + case LM_CONNECT_RESPONSE: + /* + * Bind this LSAP to the IrLAP link where the connect was + * received + */ + lsap = hashbin_remove(irlmp->unconnected_lsaps, (long) self, + NULL); + + IRDA_ASSERT(lsap == self, return -1;); + IRDA_ASSERT(self->lap != NULL, return -1;); + IRDA_ASSERT(self->lap->lsaps != NULL, return -1;); + + hashbin_insert(self->lap->lsaps, (irda_queue_t *) self, + (long) self, NULL); + + set_bit(0, &self->connected); /* TRUE */ + + irlmp_send_lcf_pdu(self->lap, self->dlsap_sel, + self->slsap_sel, CONNECT_CNF, skb); + + del_timer(&self->watchdog_timer); + + irlmp_next_lsap_state(self, LSAP_DATA_TRANSFER_READY); + break; + case LM_WATCHDOG_TIMEOUT: + /* May happen, who knows... + * Jean II */ + pr_debug("%s() WATCHDOG_TIMEOUT!\n", __func__); + + /* Disconnect, get out... - Jean II */ + self->lap = NULL; + self->dlsap_sel = LSAP_ANY; + irlmp_next_lsap_state(self, LSAP_DISCONNECTED); + break; + default: + /* LM_LAP_DISCONNECT_INDICATION : Should never happen, we + * are *not* yet bound to the IrLAP link. Jean II */ + pr_debug("%s(), Unknown event %s on LSAP %#02x\n", + __func__, irlmp_event[event], self->slsap_sel); + break; + } + return ret; +} + +/* + * Function irlmp_state_connect_pend (event, skb, info) + * + * CONNECT_PEND + * + */ +static int irlmp_state_connect_pend(struct lsap_cb *self, IRLMP_EVENT event, + struct sk_buff *skb) +{ + struct sk_buff *tx_skb; + int ret = 0; + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;); + + switch (event) { + case LM_CONNECT_REQUEST: + /* Keep state */ + break; + case LM_CONNECT_RESPONSE: + pr_debug("%s(), LM_CONNECT_RESPONSE, no indication issued yet\n", + __func__); + /* Keep state */ + break; + case LM_DISCONNECT_REQUEST: + pr_debug("%s(), LM_DISCONNECT_REQUEST, not yet bound to IrLAP connection\n", + __func__); + /* Keep state */ + break; + case LM_LAP_CONNECT_CONFIRM: + pr_debug("%s(), LS_CONNECT_CONFIRM\n", __func__); + irlmp_next_lsap_state(self, LSAP_CONNECT); + + tx_skb = self->conn_skb; + self->conn_skb = NULL; + + irlmp_connect_indication(self, tx_skb); + /* Drop reference count - see irlmp_connect_indication(). */ + dev_kfree_skb(tx_skb); + break; + case LM_WATCHDOG_TIMEOUT: + /* Will happen in some rare cases because of a race condition. + * Just make sure we don't stay there forever... + * Jean II */ + pr_debug("%s() WATCHDOG_TIMEOUT!\n", __func__); + + /* Go back to disconnected mode, keep the socket waiting */ + self->lap = NULL; + self->dlsap_sel = LSAP_ANY; + if(self->conn_skb) + dev_kfree_skb(self->conn_skb); + self->conn_skb = NULL; + irlmp_next_lsap_state(self, LSAP_DISCONNECTED); + break; + default: + /* LM_LAP_DISCONNECT_INDICATION : Should never happen, we + * are *not* yet bound to the IrLAP link. Jean II */ + pr_debug("%s(), Unknown event %s on LSAP %#02x\n", + __func__, irlmp_event[event], self->slsap_sel); + break; + } + return ret; +} + +/* + * Function irlmp_state_dtr (self, event, skb) + * + * DATA_TRANSFER_READY + * + */ +static int irlmp_state_dtr(struct lsap_cb *self, IRLMP_EVENT event, + struct sk_buff *skb) +{ + LM_REASON reason; + int ret = 0; + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;); + IRDA_ASSERT(self->lap != NULL, return -1;); + + switch (event) { + case LM_DATA_REQUEST: /* Optimize for the common case */ + irlmp_send_data_pdu(self->lap, self->dlsap_sel, + self->slsap_sel, FALSE, skb); + break; + case LM_DATA_INDICATION: /* Optimize for the common case */ + irlmp_data_indication(self, skb); + break; + case LM_UDATA_REQUEST: + IRDA_ASSERT(skb != NULL, return -1;); + irlmp_send_data_pdu(self->lap, self->dlsap_sel, + self->slsap_sel, TRUE, skb); + break; + case LM_UDATA_INDICATION: + irlmp_udata_indication(self, skb); + break; + case LM_CONNECT_REQUEST: + pr_debug("%s(), LM_CONNECT_REQUEST, error, LSAP already connected\n", + __func__); + /* Keep state */ + break; + case LM_CONNECT_RESPONSE: + pr_debug("%s(), LM_CONNECT_RESPONSE, error, LSAP already connected\n", + __func__); + /* Keep state */ + break; + case LM_DISCONNECT_REQUEST: + irlmp_send_lcf_pdu(self->lap, self->dlsap_sel, self->slsap_sel, + DISCONNECT, skb); + irlmp_next_lsap_state(self, LSAP_DISCONNECTED); + /* Called only from irlmp_disconnect_request(), will + * unbind from LAP over there. Jean II */ + + /* Try to close the LAP connection if its still there */ + if (self->lap) { + pr_debug("%s(), trying to close IrLAP\n", + __func__); + irlmp_do_lap_event(self->lap, + LM_LAP_DISCONNECT_REQUEST, + NULL); + } + break; + case LM_LAP_DISCONNECT_INDICATION: + irlmp_next_lsap_state(self, LSAP_DISCONNECTED); + + reason = irlmp_convert_lap_reason(self->lap->reason); + + irlmp_disconnect_indication(self, reason, NULL); + break; + case LM_DISCONNECT_INDICATION: + irlmp_next_lsap_state(self, LSAP_DISCONNECTED); + + IRDA_ASSERT(self->lap != NULL, return -1;); + IRDA_ASSERT(self->lap->magic == LMP_LAP_MAGIC, return -1;); + + IRDA_ASSERT(skb != NULL, return -1;); + IRDA_ASSERT(skb->len > 3, return -1;); + reason = skb->data[3]; + + /* Try to close the LAP connection */ + pr_debug("%s(), trying to close IrLAP\n", __func__); + irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL); + + irlmp_disconnect_indication(self, reason, skb); + break; + default: + pr_debug("%s(), Unknown event %s on LSAP %#02x\n", + __func__, irlmp_event[event], self->slsap_sel); + break; + } + return ret; +} + +/* + * Function irlmp_state_setup (event, skb, info) + * + * SETUP, Station Control has set up the underlying IrLAP connection. + * An LSAP connection request has been transmitted to the peer + * LSAP-Connection Control FSM and we are awaiting reply. + */ +static int irlmp_state_setup(struct lsap_cb *self, IRLMP_EVENT event, + struct sk_buff *skb) +{ + LM_REASON reason; + int ret = 0; + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;); + + switch (event) { + case LM_CONNECT_CONFIRM: + irlmp_next_lsap_state(self, LSAP_DATA_TRANSFER_READY); + + del_timer(&self->watchdog_timer); + + irlmp_connect_confirm(self, skb); + break; + case LM_DISCONNECT_INDICATION: + irlmp_next_lsap_state(self, LSAP_DISCONNECTED); + + IRDA_ASSERT(self->lap != NULL, return -1;); + IRDA_ASSERT(self->lap->magic == LMP_LAP_MAGIC, return -1;); + + IRDA_ASSERT(skb != NULL, return -1;); + IRDA_ASSERT(skb->len > 3, return -1;); + reason = skb->data[3]; + + /* Try to close the LAP connection */ + pr_debug("%s(), trying to close IrLAP\n", __func__); + irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL); + + irlmp_disconnect_indication(self, reason, skb); + break; + case LM_LAP_DISCONNECT_INDICATION: + irlmp_next_lsap_state(self, LSAP_DISCONNECTED); + + del_timer(&self->watchdog_timer); + + IRDA_ASSERT(self->lap != NULL, return -1;); + IRDA_ASSERT(self->lap->magic == LMP_LAP_MAGIC, return -1;); + + reason = irlmp_convert_lap_reason(self->lap->reason); + + irlmp_disconnect_indication(self, reason, skb); + break; + case LM_WATCHDOG_TIMEOUT: + pr_debug("%s() WATCHDOG_TIMEOUT!\n", __func__); + + IRDA_ASSERT(self->lap != NULL, return -1;); + irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL); + irlmp_next_lsap_state(self, LSAP_DISCONNECTED); + + irlmp_disconnect_indication(self, LM_CONNECT_FAILURE, NULL); + break; + default: + pr_debug("%s(), Unknown event %s on LSAP %#02x\n", + __func__, irlmp_event[event], self->slsap_sel); + break; + } + return ret; +} + +/* + * Function irlmp_state_setup_pend (event, skb, info) + * + * SETUP_PEND, An LM_CONNECT_REQUEST has been received from the service + * user to set up an LSAP connection. A request has been sent to the + * LAP FSM to set up the underlying IrLAP connection, and we + * are awaiting confirm. + */ +static int irlmp_state_setup_pend(struct lsap_cb *self, IRLMP_EVENT event, + struct sk_buff *skb) +{ + struct sk_buff *tx_skb; + LM_REASON reason; + int ret = 0; + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(irlmp != NULL, return -1;); + + switch (event) { + case LM_LAP_CONNECT_CONFIRM: + IRDA_ASSERT(self->conn_skb != NULL, return -1;); + + tx_skb = self->conn_skb; + self->conn_skb = NULL; + + irlmp_send_lcf_pdu(self->lap, self->dlsap_sel, + self->slsap_sel, CONNECT_CMD, tx_skb); + /* Drop reference count - see irlap_data_request(). */ + dev_kfree_skb(tx_skb); + + irlmp_next_lsap_state(self, LSAP_SETUP); + break; + case LM_WATCHDOG_TIMEOUT: + pr_debug("%s() : WATCHDOG_TIMEOUT !\n", __func__); + + IRDA_ASSERT(self->lap != NULL, return -1;); + irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL); + irlmp_next_lsap_state(self, LSAP_DISCONNECTED); + + irlmp_disconnect_indication(self, LM_CONNECT_FAILURE, NULL); + break; + case LM_LAP_DISCONNECT_INDICATION: /* LS_Disconnect.indication */ + del_timer( &self->watchdog_timer); + + irlmp_next_lsap_state(self, LSAP_DISCONNECTED); + + reason = irlmp_convert_lap_reason(self->lap->reason); + + irlmp_disconnect_indication(self, reason, NULL); + break; + default: + pr_debug("%s(), Unknown event %s on LSAP %#02x\n", + __func__, irlmp_event[event], self->slsap_sel); + break; + } + return ret; +} diff --git a/drivers/staging/irda/net/irlmp_frame.c b/drivers/staging/irda/net/irlmp_frame.c new file mode 100644 index 000000000000..38b0f994bc7b --- /dev/null +++ b/drivers/staging/irda/net/irlmp_frame.c @@ -0,0 +1,476 @@ +/********************************************************************* + * + * Filename: irlmp_frame.c + * Version: 0.9 + * Description: IrLMP frame implementation + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Tue Aug 19 02:09:59 1997 + * Modified at: Mon Dec 13 13:41:12 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no> + * All Rights Reserved. + * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#include <linux/skbuff.h> +#include <linux/kernel.h> + +#include <net/irda/irda.h> +#include <net/irda/irlap.h> +#include <net/irda/timer.h> +#include <net/irda/irlmp.h> +#include <net/irda/irlmp_frame.h> +#include <net/irda/discovery.h> + +static struct lsap_cb *irlmp_find_lsap(struct lap_cb *self, __u8 dlsap, + __u8 slsap, int status, hashbin_t *); + +inline void irlmp_send_data_pdu(struct lap_cb *self, __u8 dlsap, __u8 slsap, + int expedited, struct sk_buff *skb) +{ + skb->data[0] = dlsap; + skb->data[1] = slsap; + + if (expedited) { + pr_debug("%s(), sending expedited data\n", __func__); + irlap_data_request(self->irlap, skb, TRUE); + } else + irlap_data_request(self->irlap, skb, FALSE); +} + +/* + * Function irlmp_send_lcf_pdu (dlsap, slsap, opcode,skb) + * + * Send Link Control Frame to IrLAP + */ +void irlmp_send_lcf_pdu(struct lap_cb *self, __u8 dlsap, __u8 slsap, + __u8 opcode, struct sk_buff *skb) +{ + __u8 *frame; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;); + IRDA_ASSERT(skb != NULL, return;); + + frame = skb->data; + + frame[0] = dlsap | CONTROL_BIT; + frame[1] = slsap; + + frame[2] = opcode; + + if (opcode == DISCONNECT) + frame[3] = 0x01; /* Service user request */ + else + frame[3] = 0x00; /* rsvd */ + + irlap_data_request(self->irlap, skb, FALSE); +} + +/* + * Function irlmp_input (skb) + * + * Used by IrLAP to pass received data frames to IrLMP layer + * + */ +void irlmp_link_data_indication(struct lap_cb *self, struct sk_buff *skb, + int unreliable) +{ + struct lsap_cb *lsap; + __u8 slsap_sel; /* Source (this) LSAP address */ + __u8 dlsap_sel; /* Destination LSAP address */ + __u8 *fp; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;); + IRDA_ASSERT(skb->len > 2, return;); + + fp = skb->data; + + /* + * The next statements may be confusing, but we do this so that + * destination LSAP of received frame is source LSAP in our view + */ + slsap_sel = fp[0] & LSAP_MASK; + dlsap_sel = fp[1]; + + /* + * Check if this is an incoming connection, since we must deal with + * it in a different way than other established connections. + */ + if ((fp[0] & CONTROL_BIT) && (fp[2] == CONNECT_CMD)) { + pr_debug("%s(), incoming connection, source LSAP=%d, dest LSAP=%d\n", + __func__, slsap_sel, dlsap_sel); + + /* Try to find LSAP among the unconnected LSAPs */ + lsap = irlmp_find_lsap(self, dlsap_sel, slsap_sel, CONNECT_CMD, + irlmp->unconnected_lsaps); + + /* Maybe LSAP was already connected, so try one more time */ + if (!lsap) { + pr_debug("%s(), incoming connection for LSAP already connected\n", + __func__); + lsap = irlmp_find_lsap(self, dlsap_sel, slsap_sel, 0, + self->lsaps); + } + } else + lsap = irlmp_find_lsap(self, dlsap_sel, slsap_sel, 0, + self->lsaps); + + if (lsap == NULL) { + pr_debug("IrLMP, Sorry, no LSAP for received frame!\n"); + pr_debug("%s(), slsap_sel = %02x, dlsap_sel = %02x\n", + __func__, slsap_sel, dlsap_sel); + if (fp[0] & CONTROL_BIT) { + pr_debug("%s(), received control frame %02x\n", + __func__, fp[2]); + } else { + pr_debug("%s(), received data frame\n", __func__); + } + return; + } + + /* + * Check if we received a control frame? + */ + if (fp[0] & CONTROL_BIT) { + switch (fp[2]) { + case CONNECT_CMD: + lsap->lap = self; + irlmp_do_lsap_event(lsap, LM_CONNECT_INDICATION, skb); + break; + case CONNECT_CNF: + irlmp_do_lsap_event(lsap, LM_CONNECT_CONFIRM, skb); + break; + case DISCONNECT: + pr_debug("%s(), Disconnect indication!\n", + __func__); + irlmp_do_lsap_event(lsap, LM_DISCONNECT_INDICATION, + skb); + break; + case ACCESSMODE_CMD: + pr_debug("Access mode cmd not implemented!\n"); + break; + case ACCESSMODE_CNF: + pr_debug("Access mode cnf not implemented!\n"); + break; + default: + pr_debug("%s(), Unknown control frame %02x\n", + __func__, fp[2]); + break; + } + } else if (unreliable) { + /* Optimize and bypass the state machine if possible */ + if (lsap->lsap_state == LSAP_DATA_TRANSFER_READY) + irlmp_udata_indication(lsap, skb); + else + irlmp_do_lsap_event(lsap, LM_UDATA_INDICATION, skb); + } else { + /* Optimize and bypass the state machine if possible */ + if (lsap->lsap_state == LSAP_DATA_TRANSFER_READY) + irlmp_data_indication(lsap, skb); + else + irlmp_do_lsap_event(lsap, LM_DATA_INDICATION, skb); + } +} + +/* + * Function irlmp_link_unitdata_indication (self, skb) + * + * + * + */ +#ifdef CONFIG_IRDA_ULTRA +void irlmp_link_unitdata_indication(struct lap_cb *self, struct sk_buff *skb) +{ + struct lsap_cb *lsap; + __u8 slsap_sel; /* Source (this) LSAP address */ + __u8 dlsap_sel; /* Destination LSAP address */ + __u8 pid; /* Protocol identifier */ + __u8 *fp; + unsigned long flags; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;); + IRDA_ASSERT(skb->len > 2, return;); + + fp = skb->data; + + /* + * The next statements may be confusing, but we do this so that + * destination LSAP of received frame is source LSAP in our view + */ + slsap_sel = fp[0] & LSAP_MASK; + dlsap_sel = fp[1]; + pid = fp[2]; + + if (pid & 0x80) { + pr_debug("%s(), extension in PID not supp!\n", + __func__); + return; + } + + /* Check if frame is addressed to the connectionless LSAP */ + if ((slsap_sel != LSAP_CONNLESS) || (dlsap_sel != LSAP_CONNLESS)) { + pr_debug("%s(), dropping frame!\n", __func__); + return; + } + + /* Search the connectionless LSAP */ + spin_lock_irqsave(&irlmp->unconnected_lsaps->hb_spinlock, flags); + lsap = (struct lsap_cb *) hashbin_get_first(irlmp->unconnected_lsaps); + while (lsap != NULL) { + /* + * Check if source LSAP and dest LSAP selectors and PID match. + */ + if ((lsap->slsap_sel == slsap_sel) && + (lsap->dlsap_sel == dlsap_sel) && + (lsap->pid == pid)) + { + break; + } + lsap = (struct lsap_cb *) hashbin_get_next(irlmp->unconnected_lsaps); + } + spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock, flags); + + if (lsap) + irlmp_connless_data_indication(lsap, skb); + else { + pr_debug("%s(), found no matching LSAP!\n", __func__); + } +} +#endif /* CONFIG_IRDA_ULTRA */ + +/* + * Function irlmp_link_disconnect_indication (reason, userdata) + * + * IrLAP has disconnected + * + */ +void irlmp_link_disconnect_indication(struct lap_cb *lap, + struct irlap_cb *irlap, + LAP_REASON reason, + struct sk_buff *skb) +{ + IRDA_ASSERT(lap != NULL, return;); + IRDA_ASSERT(lap->magic == LMP_LAP_MAGIC, return;); + + lap->reason = reason; + lap->daddr = DEV_ADDR_ANY; + + /* FIXME: must do something with the skb if any */ + + /* + * Inform station state machine + */ + irlmp_do_lap_event(lap, LM_LAP_DISCONNECT_INDICATION, NULL); +} + +/* + * Function irlmp_link_connect_indication (qos) + * + * Incoming LAP connection! + * + */ +void irlmp_link_connect_indication(struct lap_cb *self, __u32 saddr, + __u32 daddr, struct qos_info *qos, + struct sk_buff *skb) +{ + /* Copy QoS settings for this session */ + self->qos = qos; + + /* Update destination device address */ + self->daddr = daddr; + IRDA_ASSERT(self->saddr == saddr, return;); + + irlmp_do_lap_event(self, LM_LAP_CONNECT_INDICATION, skb); +} + +/* + * Function irlmp_link_connect_confirm (qos) + * + * LAP connection confirmed! + * + */ +void irlmp_link_connect_confirm(struct lap_cb *self, struct qos_info *qos, + struct sk_buff *skb) +{ + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;); + IRDA_ASSERT(qos != NULL, return;); + + /* Don't need use the skb for now */ + + /* Copy QoS settings for this session */ + self->qos = qos; + + irlmp_do_lap_event(self, LM_LAP_CONNECT_CONFIRM, NULL); +} + +/* + * Function irlmp_link_discovery_indication (self, log) + * + * Device is discovering us + * + * It's not an answer to our own discoveries, just another device trying + * to perform discovery, but we don't want to miss the opportunity + * to exploit this information, because : + * o We may not actively perform discovery (just passive discovery) + * o This type of discovery is much more reliable. In some cases, it + * seem that less than 50% of our discoveries get an answer, while + * we always get ~100% of these. + * o Make faster discovery, statistically divide time of discovery + * events by 2 (important for the latency aspect and user feel) + * o Even is we do active discovery, the other node might not + * answer our discoveries (ex: Palm). The Palm will just perform + * one active discovery and connect directly to us. + * + * However, when both devices discover each other, they might attempt to + * connect to each other following the discovery event, and it would create + * collisions on the medium (SNRM battle). + * The "fix" for that is to disable all connection requests in IrLAP + * for 100ms after a discovery indication by setting the media_busy flag. + * Previously, we used to postpone the event which was quite ugly. Now + * that IrLAP takes care of this problem, just pass the event up... + * + * Jean II + */ +void irlmp_link_discovery_indication(struct lap_cb *self, + discovery_t *discovery) +{ + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;); + + /* Add to main log, cleanup */ + irlmp_add_discovery(irlmp->cachelog, discovery); + + /* Just handle it the same way as a discovery confirm, + * bypass the LM_LAP state machine (see below) */ + irlmp_discovery_confirm(irlmp->cachelog, DISCOVERY_PASSIVE); +} + +/* + * Function irlmp_link_discovery_confirm (self, log) + * + * Called by IrLAP with a list of discoveries after the discovery + * request has been carried out. A NULL log is received if IrLAP + * was unable to carry out the discovery request + * + */ +void irlmp_link_discovery_confirm(struct lap_cb *self, hashbin_t *log) +{ + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;); + + /* Add to main log, cleanup */ + irlmp_add_discovery_log(irlmp->cachelog, log); + + /* Propagate event to various LSAPs registered for it. + * We bypass the LM_LAP state machine because + * 1) We do it regardless of the LM_LAP state + * 2) It doesn't affect the LM_LAP state + * 3) Faster, slimer, simpler, ... + * Jean II */ + irlmp_discovery_confirm(irlmp->cachelog, DISCOVERY_ACTIVE); +} + +#ifdef CONFIG_IRDA_CACHE_LAST_LSAP +static inline void irlmp_update_cache(struct lap_cb *lap, + struct lsap_cb *lsap) +{ + /* Prevent concurrent read to get garbage */ + lap->cache.valid = FALSE; + /* Update cache entry */ + lap->cache.dlsap_sel = lsap->dlsap_sel; + lap->cache.slsap_sel = lsap->slsap_sel; + lap->cache.lsap = lsap; + lap->cache.valid = TRUE; +} +#endif + +/* + * Function irlmp_find_handle (self, dlsap_sel, slsap_sel, status, queue) + * + * Find handle associated with destination and source LSAP + * + * Any IrDA connection (LSAP/TSAP) is uniquely identified by + * 3 parameters, the local lsap, the remote lsap and the remote address. + * We may initiate multiple connections to the same remote service + * (they will have different local lsap), a remote device may initiate + * multiple connections to the same local service (they will have + * different remote lsap), or multiple devices may connect to the same + * service and may use the same remote lsap (and they will have + * different remote address). + * So, where is the remote address ? Each LAP connection is made with + * a single remote device, so imply a specific remote address. + * Jean II + */ +static struct lsap_cb *irlmp_find_lsap(struct lap_cb *self, __u8 dlsap_sel, + __u8 slsap_sel, int status, + hashbin_t *queue) +{ + struct lsap_cb *lsap; + unsigned long flags; + + /* + * Optimize for the common case. We assume that the last frame + * received is in the same connection as the last one, so check in + * cache first to avoid the linear search + */ +#ifdef CONFIG_IRDA_CACHE_LAST_LSAP + if ((self->cache.valid) && + (self->cache.slsap_sel == slsap_sel) && + (self->cache.dlsap_sel == dlsap_sel)) + { + return self->cache.lsap; + } +#endif + + spin_lock_irqsave(&queue->hb_spinlock, flags); + + lsap = (struct lsap_cb *) hashbin_get_first(queue); + while (lsap != NULL) { + /* + * If this is an incoming connection, then the destination + * LSAP selector may have been specified as LM_ANY so that + * any client can connect. In that case we only need to check + * if the source LSAP (in our view!) match! + */ + if ((status == CONNECT_CMD) && + (lsap->slsap_sel == slsap_sel) && + (lsap->dlsap_sel == LSAP_ANY)) { + /* This is where the dest lsap sel is set on incoming + * lsaps */ + lsap->dlsap_sel = dlsap_sel; + break; + } + /* + * Check if source LSAP and dest LSAP selectors match. + */ + if ((lsap->slsap_sel == slsap_sel) && + (lsap->dlsap_sel == dlsap_sel)) + break; + + lsap = (struct lsap_cb *) hashbin_get_next(queue); + } +#ifdef CONFIG_IRDA_CACHE_LAST_LSAP + if(lsap) + irlmp_update_cache(self, lsap); +#endif + spin_unlock_irqrestore(&queue->hb_spinlock, flags); + + /* Return what we've found or NULL */ + return lsap; +} diff --git a/drivers/staging/irda/net/irmod.c b/drivers/staging/irda/net/irmod.c new file mode 100644 index 000000000000..4319f4ff66b0 --- /dev/null +++ b/drivers/staging/irda/net/irmod.c @@ -0,0 +1,199 @@ +/********************************************************************* + * + * Filename: irmod.c + * Version: 0.9 + * Description: IrDA stack main entry points + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Mon Dec 15 13:55:39 1997 + * Modified at: Wed Jan 5 15:12:41 2000 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1997, 1999-2000 Dag Brattli, All Rights Reserved. + * Copyright (c) 2000-2004 Jean Tourrilhes <jt@hpl.hp.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +/* + * This file contains the main entry points of the IrDA stack. + * They are in this file and not af_irda.c because some developpers + * are using the IrDA stack without the socket API (compiling out + * af_irda.c). + * Jean II + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> + +#include <net/irda/irda.h> +#include <net/irda/irmod.h> /* notify_t */ +#include <net/irda/irlap.h> /* irlap_init */ +#include <net/irda/irlmp.h> /* irlmp_init */ +#include <net/irda/iriap.h> /* iriap_init */ +#include <net/irda/irttp.h> /* irttp_init */ +#include <net/irda/irda_device.h> /* irda_device_init */ + +/* Packet type handler. + * Tell the kernel how IrDA packets should be handled. + */ +static struct packet_type irda_packet_type __read_mostly = { + .type = cpu_to_be16(ETH_P_IRDA), + .func = irlap_driver_rcv, /* Packet type handler irlap_frame.c */ +}; + +/* + * Function irda_notify_init (notify) + * + * Used for initializing the notify structure + * + */ +void irda_notify_init(notify_t *notify) +{ + notify->data_indication = NULL; + notify->udata_indication = NULL; + notify->connect_confirm = NULL; + notify->connect_indication = NULL; + notify->disconnect_indication = NULL; + notify->flow_indication = NULL; + notify->status_indication = NULL; + notify->instance = NULL; + strlcpy(notify->name, "Unknown", sizeof(notify->name)); +} +EXPORT_SYMBOL(irda_notify_init); + +/* + * Function irda_init (void) + * + * Protocol stack initialisation entry point. + * Initialise the various components of the IrDA stack + */ +static int __init irda_init(void) +{ + int ret = 0; + + /* Lower layer of the stack */ + irlmp_init(); + irlap_init(); + + /* Driver/dongle support */ + irda_device_init(); + + /* Higher layers of the stack */ + iriap_init(); + irttp_init(); + ret = irsock_init(); + if (ret < 0) + goto out_err_1; + + /* Add IrDA packet type (Start receiving packets) */ + dev_add_pack(&irda_packet_type); + + /* External APIs */ +#ifdef CONFIG_PROC_FS + irda_proc_register(); +#endif +#ifdef CONFIG_SYSCTL + ret = irda_sysctl_register(); + if (ret < 0) + goto out_err_2; +#endif + + ret = irda_nl_register(); + if (ret < 0) + goto out_err_3; + + return 0; + + out_err_3: +#ifdef CONFIG_SYSCTL + irda_sysctl_unregister(); + out_err_2: +#endif +#ifdef CONFIG_PROC_FS + irda_proc_unregister(); +#endif + + /* Remove IrDA packet type (stop receiving packets) */ + dev_remove_pack(&irda_packet_type); + + /* Remove higher layers */ + irsock_cleanup(); + out_err_1: + irttp_cleanup(); + iriap_cleanup(); + + /* Remove lower layers */ + irda_device_cleanup(); + irlap_cleanup(); /* Must be done before irlmp_cleanup()! DB */ + + /* Remove middle layer */ + irlmp_cleanup(); + + + return ret; +} + +/* + * Function irda_cleanup (void) + * + * Protocol stack cleanup/removal entry point. + * Cleanup the various components of the IrDA stack + */ +static void __exit irda_cleanup(void) +{ + /* Remove External APIs */ + irda_nl_unregister(); + +#ifdef CONFIG_SYSCTL + irda_sysctl_unregister(); +#endif +#ifdef CONFIG_PROC_FS + irda_proc_unregister(); +#endif + + /* Remove IrDA packet type (stop receiving packets) */ + dev_remove_pack(&irda_packet_type); + + /* Remove higher layers */ + irsock_cleanup(); + irttp_cleanup(); + iriap_cleanup(); + + /* Remove lower layers */ + irda_device_cleanup(); + irlap_cleanup(); /* Must be done before irlmp_cleanup()! DB */ + + /* Remove middle layer */ + irlmp_cleanup(); +} + +/* + * The IrDA stack must be initialised *before* drivers get initialised, + * and *before* higher protocols (IrLAN/IrCOMM/IrNET) get initialised, + * otherwise bad things will happen (hashbins will be NULL for example). + * Those modules are at module_init()/device_initcall() level. + * + * On the other hand, it needs to be initialised *after* the basic + * networking, the /proc/net filesystem and sysctl module. Those are + * currently initialised in .../init/main.c (before initcalls). + * Also, IrDA drivers needs to be initialised *after* the random number + * generator (main stack and higher layer init don't need it anymore). + * + * Jean II + */ +device_initcall(irda_init); +module_exit(irda_cleanup); + +MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no> & Jean Tourrilhes <jt@hpl.hp.com>"); +MODULE_DESCRIPTION("The Linux IrDA Protocol Stack"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_NETPROTO(PF_IRDA); diff --git a/drivers/staging/irda/net/irnet/Kconfig b/drivers/staging/irda/net/irnet/Kconfig new file mode 100644 index 000000000000..28c557f0fdd2 --- /dev/null +++ b/drivers/staging/irda/net/irnet/Kconfig @@ -0,0 +1,13 @@ +config IRNET + tristate "IrNET protocol" + depends on IRDA && PPP + help + Say Y here if you want to build support for the IrNET protocol. + To compile it as a module, choose M here: the module will be + called irnet. IrNET is a PPP driver, so you will also need a + working PPP subsystem (driver, daemon and config)... + + IrNET is an alternate way to transfer TCP/IP traffic over IrDA. It + uses synchronous PPP over a set of point to point IrDA sockets. You + can use it between Linux machine or with W2k. + diff --git a/drivers/staging/irda/net/irnet/Makefile b/drivers/staging/irda/net/irnet/Makefile new file mode 100644 index 000000000000..61c365c8a2a0 --- /dev/null +++ b/drivers/staging/irda/net/irnet/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for the Linux IrDA IrNET protocol layer. +# + +obj-$(CONFIG_IRNET) += irnet.o + +irnet-y := irnet_ppp.o irnet_irda.o diff --git a/drivers/staging/irda/net/irnet/irnet.h b/drivers/staging/irda/net/irnet/irnet.h new file mode 100644 index 000000000000..9d451f8ed47a --- /dev/null +++ b/drivers/staging/irda/net/irnet/irnet.h @@ -0,0 +1,522 @@ +/* + * IrNET protocol module : Synchronous PPP over an IrDA socket. + * + * Jean II - HPL `00 - <jt@hpl.hp.com> + * + * This file contains definitions and declarations global to the IrNET module, + * all grouped in one place... + * This file is a *private* header, so other modules don't want to know + * what's in there... + * + * Note : as most part of the Linux kernel, this module is available + * under the GNU General Public License (GPL). + */ + +#ifndef IRNET_H +#define IRNET_H + +/************************** DOCUMENTATION ***************************/ +/* + * What is IrNET + * ------------- + * IrNET is a protocol allowing to carry TCP/IP traffic between two + * IrDA peers in an efficient fashion. It is a thin layer, passing PPP + * packets to IrTTP and vice versa. It uses PPP in synchronous mode, + * because IrTTP offer a reliable sequenced packet service (as opposed + * to a byte stream). In fact, you could see IrNET as carrying TCP/IP + * in a IrDA socket, using PPP to provide the glue. + * + * The main difference with traditional PPP over IrCOMM is that we + * avoid the framing and serial emulation which are a performance + * bottleneck. It also allows multipoint communications in a sensible + * fashion. + * + * The main difference with IrLAN is that we use PPP for the link + * management, which is more standard, interoperable and flexible than + * the IrLAN protocol. For example, PPP adds authentication, + * encryption, compression, header compression and automated routing + * setup. And, as IrNET let PPP do the hard work, the implementation + * is much simpler than IrLAN. + * + * The Linux implementation + * ------------------------ + * IrNET is written on top of the Linux-IrDA stack, and interface with + * the generic Linux PPP driver. Because IrNET depend on recent + * changes of the PPP driver interface, IrNET will work only with very + * recent kernel (2.3.99-pre6 and up). + * + * The present implementation offer the following features : + * o simple user interface using pppd + * o efficient implementation (interface directly to PPP and IrTTP) + * o addressing (you can specify the name of the IrNET recipient) + * o multipoint operation (limited by IrLAP specification) + * o information in /proc/net/irda/irnet + * o IrNET events on /dev/irnet (for user space daemon) + * o IrNET daemon (irnetd) to automatically handle incoming requests + * o Windows 2000 compatibility (tested, but need more work) + * Currently missing : + * o Lot's of testing (that's your job) + * o Connection retries (may be too hard to do) + * o Check pppd persist mode + * o User space daemon (to automatically handle incoming requests) + * + * The setup is not currently the most easy, but this should get much + * better when everything will get integrated... + * + * Acknowledgements + * ---------------- + * This module is based on : + * o The PPP driver (ppp_synctty/ppp_generic) by Paul Mackerras + * o The IrLAN protocol (irlan_common/XXX) by Dag Brattli + * o The IrSock interface (af_irda) by Dag Brattli + * o Some other bits from the kernel and my drivers... + * Infinite thanks to those brave souls for providing the infrastructure + * upon which IrNET is built. + * + * Thanks to all my colleagues in HP for helping me. In particular, + * thanks to Salil Pradhan and Bill Serra for W2k testing... + * Thanks to Luiz Magalhaes for irnetd and much testing... + * + * Thanks to Alan Cox for answering lot's of my stupid questions, and + * to Paul Mackerras answering my questions on how to best integrate + * IrNET and pppd. + * + * Jean II + * + * Note on some implementations choices... + * ------------------------------------ + * 1) Direct interface vs tty/socket + * I could have used a tty interface to hook to ppp and use the full + * socket API to connect to IrDA. The code would have been easier to + * maintain, and maybe the code would have been smaller... + * Instead, we hook directly to ppp_generic and to IrTTP, which make + * things more complicated... + * + * The first reason is flexibility : this allow us to create IrNET + * instances on demand (no /dev/ircommX crap) and to allow linkname + * specification on pppd command line... + * + * Second reason is speed optimisation. If you look closely at the + * transmit and receive paths, you will notice that they are "super lean" + * (that's why they look ugly), with no function calls and as little data + * copy and modification as I could... + * + * 2) irnetd in user space + * irnetd is implemented in user space, which is necessary to call pppd. + * This also give maximum benefits in term of flexibility and customability, + * and allow to offer the event channel, useful for other stuff like debug. + * + * On the other hand, this require a loose coordination between the + * present module and irnetd. One critical area is how incoming request + * are handled. + * When irnet receive an incoming request, it send an event to irnetd and + * drop the incoming IrNET socket. + * irnetd start a pppd instance, which create a new IrNET socket. This new + * socket is then connected in the originating node to the pppd instance. + * At this point, in the originating node, the first socket is closed. + * + * I admit, this is a bit messy and waste some resources. The alternative + * is caching incoming socket, and that's also quite messy and waste + * resources. + * We also make connection time slower. For example, on a 115 kb/s link it + * adds 60ms to the connection time (770 ms). However, this is slower than + * the time it takes to fire up pppd on my P133... + * + * + * History : + * ------- + * + * v1 - 15.5.00 - Jean II + * o Basic IrNET (hook to ppp_generic & IrTTP - incl. multipoint) + * o control channel on /dev/irnet (set name/address) + * o event channel on /dev/irnet (for user space daemon) + * + * v2 - 5.6.00 - Jean II + * o Enable DROP_NOT_READY to avoid PPP timeouts & other weirdness... + * o Add DISCONNECT_TO event and rename DISCONNECT_FROM. + * o Set official device number alloaction on /dev/irnet + * + * v3 - 30.8.00 - Jean II + * o Update to latest Linux-IrDA changes : + * - queue_t => irda_queue_t + * o Update to ppp-2.4.0 : + * - move irda_irnet_connect from PPPIOCATTACH to TIOCSETD + * o Add EXPIRE event (depend on new IrDA-Linux patch) + * o Switch from `hashbin_remove' to `hashbin_remove_this' to fix + * a multilink bug... (depend on new IrDA-Linux patch) + * o fix a self->daddr to self->raddr in irda_irnet_connect to fix + * another multilink bug (darn !) + * o Remove LINKNAME_IOCTL cruft + * + * v3b - 31.8.00 - Jean II + * o Dump discovery log at event channel startup + * + * v4 - 28.9.00 - Jean II + * o Fix interaction between poll/select and dump discovery log + * o Add IRNET_BLOCKED_LINK event (depend on new IrDA-Linux patch) + * o Add IRNET_NOANSWER_FROM event (mostly to help support) + * o Release flow control in disconnect_indication + * o Block packets while connecting (speed up connections) + * + * v5 - 11.01.01 - Jean II + * o Init self->max_header_size, just in case... + * o Set up ap->chan.hdrlen, to get zero copy on tx side working. + * o avoid tx->ttp->flow->ppp->tx->... loop, by checking flow state + * Thanks to Christian Gennerat for finding this bug ! + * --- + * o Declare the proper MTU/MRU that we can support + * (but PPP doesn't read the MTU value :-() + * o Declare hashbin HB_NOLOCK instead of HB_LOCAL to avoid + * disabling and enabling irq twice + * + * v6 - 31.05.01 - Jean II + * o Print source address in Found, Discovery, Expiry & Request events + * o Print requested source address in /proc/net/irnet + * o Change control channel input. Allow multiple commands in one line. + * o Add saddr command to change ap->rsaddr (and use that in IrDA) + * --- + * o Make the IrDA connection procedure totally asynchronous. + * Heavy rewrite of the IAS query code and the whole connection + * procedure. Now, irnet_connect() no longer need to be called from + * a process context... + * o Enable IrDA connect retries in ppp_irnet_send(). The good thing + * is that IrDA connect retries are directly driven by PPP LCP + * retries (we retry for each LCP packet), so that everything + * is transparently controlled from pppd lcp-max-configure. + * o Add ttp_connect flag to prevent rentry on the connect procedure + * o Test and fixups to eliminate side effects of retries + * + * v7 - 22.08.01 - Jean II + * o Cleanup : Change "saddr = 0x0" to "saddr = DEV_ADDR_ANY" + * o Fix bug in BLOCK_WHEN_CONNECT introduced in v6 : due to the + * asynchronous IAS query, self->tsap is NULL when PPP send the + * first packet. This was preventing "connect-delay 0" to work. + * Change the test in ppp_irnet_send() to self->ttp_connect. + * + * v8 - 1.11.01 - Jean II + * o Tighten the use of self->ttp_connect and self->ttp_open to + * prevent various race conditions. + * o Avoid leaking discovery log and skb + * o Replace "self" with "server" in irnet_connect_indication() to + * better detect cut'n'paste error ;-) + * + * v9 - 29.11.01 - Jean II + * o Fix event generation in disconnect indication that I broke in v8 + * It was always generation "No-Answer" because I was testing ttp_open + * just after clearing it. *blush*. + * o Use newly created irttp_listen() to fix potential crash when LAP + * destroyed before irnet module removed. + * + * v10 - 4.3.2 - Jean II + * o When receiving a disconnect indication, don't reenable the + * PPP Tx queue, this will trigger a reconnect. Instead, close + * the channel, which will kill pppd... + * + * v11 - 20.3.02 - Jean II + * o Oops ! v10 fix disabled IrNET retries and passive behaviour. + * Better fix in irnet_disconnect_indication() : + * - if connected, kill pppd via hangup. + * - if not connected, reenable ppp Tx, which trigger IrNET retry. + * + * v12 - 10.4.02 - Jean II + * o Fix race condition in irnet_connect_indication(). + * If the socket was already trying to connect, drop old connection + * and use new one only if acting as primary. See comments. + * + * v13 - 30.5.02 - Jean II + * o Update module init code + * + * v14 - 20.2.03 - Jean II + * o Add discovery hint bits in the control channel. + * o Remove obsolete MOD_INC/DEC_USE_COUNT in favor of .owner + * + * v15 - 7.4.03 - Jean II + * o Replace spin_lock_irqsave() with spin_lock_bh() so that we can + * use ppp_unit_number(). It's probably also better overall... + * o Disable call to ppp_unregister_channel(), because we can't do it. + */ + +/***************************** INCLUDES *****************************/ + +#include <linux/module.h> + +#include <linux/kernel.h> +#include <linux/skbuff.h> +#include <linux/tty.h> +#include <linux/proc_fs.h> +#include <linux/netdevice.h> +#include <linux/poll.h> +#include <linux/capability.h> +#include <linux/ctype.h> /* isspace() */ +#include <linux/string.h> /* skip_spaces() */ +#include <linux/uaccess.h> +#include <linux/init.h> + +#include <linux/ppp_defs.h> +#include <linux/ppp-ioctl.h> +#include <linux/ppp_channel.h> + +#include <net/irda/irda.h> +#include <net/irda/iriap.h> +#include <net/irda/irias_object.h> +#include <net/irda/irlmp.h> +#include <net/irda/irttp.h> +#include <net/irda/discovery.h> + +/***************************** OPTIONS *****************************/ +/* + * Define or undefine to compile or not some optional part of the + * IrNET driver... + * Note : the present defaults make sense, play with that at your + * own risk... + */ +/* IrDA side of the business... */ +#define DISCOVERY_NOMASK /* To enable W2k compatibility... */ +#define ADVERTISE_HINT /* Advertise IrLAN hint bit */ +#define ALLOW_SIMULT_CONNECT /* This seem to work, cross fingers... */ +#define DISCOVERY_EVENTS /* Query the discovery log to post events */ +#define INITIAL_DISCOVERY /* Dump current discovery log as events */ +#undef STREAM_COMPAT /* Not needed - potentially messy */ +#undef CONNECT_INDIC_KICK /* Might mess IrDA, not needed */ +#undef FAIL_SEND_DISCONNECT /* Might mess IrDA, not needed */ +#undef PASS_CONNECT_PACKETS /* Not needed ? Safe */ +#undef MISSING_PPP_API /* Stuff I wish I could do */ + +/* PPP side of the business */ +#define BLOCK_WHEN_CONNECT /* Block packets when connecting */ +#define CONNECT_IN_SEND /* Retry IrDA connection procedure */ +#undef FLUSH_TO_PPP /* Not sure about this one, let's play safe */ +#undef SECURE_DEVIRNET /* Bah... */ + +/****************************** DEBUG ******************************/ + +/* + * This set of flags enable and disable all the various warning, + * error and debug message of this driver. + * Each section can be enabled and disabled independently + */ +/* In the PPP part */ +#define DEBUG_CTRL_TRACE 0 /* Control channel */ +#define DEBUG_CTRL_INFO 0 /* various info */ +#define DEBUG_CTRL_ERROR 1 /* problems */ +#define DEBUG_FS_TRACE 0 /* filesystem callbacks */ +#define DEBUG_FS_INFO 0 /* various info */ +#define DEBUG_FS_ERROR 1 /* problems */ +#define DEBUG_PPP_TRACE 0 /* PPP related functions */ +#define DEBUG_PPP_INFO 0 /* various info */ +#define DEBUG_PPP_ERROR 1 /* problems */ +#define DEBUG_MODULE_TRACE 0 /* module insertion/removal */ +#define DEBUG_MODULE_ERROR 1 /* problems */ + +/* In the IrDA part */ +#define DEBUG_IRDA_SR_TRACE 0 /* IRDA subroutines */ +#define DEBUG_IRDA_SR_INFO 0 /* various info */ +#define DEBUG_IRDA_SR_ERROR 1 /* problems */ +#define DEBUG_IRDA_SOCK_TRACE 0 /* IRDA main socket functions */ +#define DEBUG_IRDA_SOCK_INFO 0 /* various info */ +#define DEBUG_IRDA_SOCK_ERROR 1 /* problems */ +#define DEBUG_IRDA_SERV_TRACE 0 /* The IrNET server */ +#define DEBUG_IRDA_SERV_INFO 0 /* various info */ +#define DEBUG_IRDA_SERV_ERROR 1 /* problems */ +#define DEBUG_IRDA_TCB_TRACE 0 /* IRDA IrTTP callbacks */ +#define DEBUG_IRDA_CB_INFO 0 /* various info */ +#define DEBUG_IRDA_CB_ERROR 1 /* problems */ +#define DEBUG_IRDA_OCB_TRACE 0 /* IRDA other callbacks */ +#define DEBUG_IRDA_OCB_INFO 0 /* various info */ +#define DEBUG_IRDA_OCB_ERROR 1 /* problems */ + +#define DEBUG_ASSERT 0 /* Verify all assertions */ + +/* + * These are the macros we are using to actually print the debug + * statements. Don't look at it, it's ugly... + * + * One of the trick is that, as the DEBUG_XXX are constant, the + * compiler will optimise away the if() in all cases. + */ +/* All error messages (will show up in the normal logs) */ +#define DERROR(dbg, format, args...) \ + {if(DEBUG_##dbg) \ + printk(KERN_INFO "irnet: %s(): " format, __func__ , ##args);} + +/* Normal debug message (will show up in /var/log/debug) */ +#define DEBUG(dbg, format, args...) \ + {if(DEBUG_##dbg) \ + printk(KERN_DEBUG "irnet: %s(): " format, __func__ , ##args);} + +/* Entering a function (trace) */ +#define DENTER(dbg, format, args...) \ + {if(DEBUG_##dbg) \ + printk(KERN_DEBUG "irnet: -> %s" format, __func__ , ##args);} + +/* Entering and exiting a function in one go (trace) */ +#define DPASS(dbg, format, args...) \ + {if(DEBUG_##dbg) \ + printk(KERN_DEBUG "irnet: <>%s" format, __func__ , ##args);} + +/* Exiting a function (trace) */ +#define DEXIT(dbg, format, args...) \ + {if(DEBUG_##dbg) \ + printk(KERN_DEBUG "irnet: <-%s()" format, __func__ , ##args);} + +/* Exit a function with debug */ +#define DRETURN(ret, dbg, args...) \ + {DEXIT(dbg, ": " args);\ + return ret; } + +/* Exit a function on failed condition */ +#define DABORT(cond, ret, dbg, args...) \ + {if(cond) {\ + DERROR(dbg, args);\ + return ret; }} + +/* Invalid assertion, print out an error and exit... */ +#define DASSERT(cond, ret, dbg, args...) \ + {if((DEBUG_ASSERT) && !(cond)) {\ + DERROR(dbg, "Invalid assertion: " args);\ + return ret; }} + +/************************ CONSTANTS & MACROS ************************/ + +/* Paranoia */ +#define IRNET_MAGIC 0xB00754 + +/* Number of control events in the control channel buffer... */ +#define IRNET_MAX_EVENTS 8 /* Should be more than enough... */ + +/****************************** TYPES ******************************/ + +/* + * This is the main structure where we store all the data pertaining to + * one instance of irnet. + * Note : in irnet functions, a pointer this structure is usually called + * "ap" or "self". If the code is borrowed from the IrDA stack, it tend + * to be called "self", and if it is borrowed from the PPP driver it is + * "ap". Apart from that, it's exactly the same structure ;-) + */ +typedef struct irnet_socket +{ + /* ------------------- Instance management ------------------- */ + /* We manage a linked list of IrNET socket instances */ + irda_queue_t q; /* Must be first - for hasbin */ + int magic; /* Paranoia */ + + /* --------------------- FileSystem part --------------------- */ + /* "pppd" interact directly with us on a /dev/ file */ + struct file * file; /* File descriptor of this instance */ + /* TTY stuff - to keep "pppd" happy */ + struct ktermios termios; /* Various tty flags */ + /* Stuff for the control channel */ + int event_index; /* Last read in the event log */ + + /* ------------------------- PPP part ------------------------- */ + /* We interface directly to the ppp_generic driver in the kernel */ + int ppp_open; /* registered with ppp_generic */ + struct ppp_channel chan; /* Interface to generic ppp layer */ + + int mru; /* Max size of PPP payload */ + u32 xaccm[8]; /* Asynchronous character map (just */ + u32 raccm; /* to please pppd - dummy) */ + unsigned int flags; /* PPP flags (compression, ...) */ + unsigned int rbits; /* Unused receive flags ??? */ + struct work_struct disconnect_work; /* Process context disconnection */ + /* ------------------------ IrTTP part ------------------------ */ + /* We create a pseudo "socket" over the IrDA tranport */ + unsigned long ttp_open; /* Set when IrTTP is ready */ + unsigned long ttp_connect; /* Set when IrTTP is connecting */ + struct tsap_cb * tsap; /* IrTTP instance (the connection) */ + + char rname[NICKNAME_MAX_LEN + 1]; + /* IrDA nickname of destination */ + __u32 rdaddr; /* Requested peer IrDA address */ + __u32 rsaddr; /* Requested local IrDA address */ + __u32 daddr; /* actual peer IrDA address */ + __u32 saddr; /* my local IrDA address */ + __u8 dtsap_sel; /* Remote TSAP selector */ + __u8 stsap_sel; /* Local TSAP selector */ + + __u32 max_sdu_size_rx;/* Socket parameters used for IrTTP */ + __u32 max_sdu_size_tx; + __u32 max_data_size; + __u8 max_header_size; + LOCAL_FLOW tx_flow; /* State of the Tx path in IrTTP */ + + /* ------------------- IrLMP and IrIAS part ------------------- */ + /* Used for IrDA Discovery and socket name resolution */ + void * ckey; /* IrLMP client handle */ + __u16 mask; /* Hint bits mask (filter discov.)*/ + int nslots; /* Number of slots for discovery */ + + struct iriap_cb * iriap; /* Used to query remote IAS */ + int errno; /* status of the IAS query */ + + /* -------------------- Discovery log part -------------------- */ + /* Used by initial discovery on the control channel + * and by irnet_discover_daddr_and_lsap_sel() */ + struct irda_device_info *discoveries; /* Copy of the discovery log */ + int disco_index; /* Last read in the discovery log */ + int disco_number; /* Size of the discovery log */ + + struct mutex lock; + +} irnet_socket; + +/* + * This is the various event that we will generate on the control channel + */ +typedef enum irnet_event +{ + IRNET_DISCOVER, /* New IrNET node discovered */ + IRNET_EXPIRE, /* IrNET node expired */ + IRNET_CONNECT_TO, /* IrNET socket has connected to other node */ + IRNET_CONNECT_FROM, /* Other node has connected to IrNET socket */ + IRNET_REQUEST_FROM, /* Non satisfied connection request */ + IRNET_NOANSWER_FROM, /* Failed connection request */ + IRNET_BLOCKED_LINK, /* Link (IrLAP) is blocked for > 3s */ + IRNET_DISCONNECT_FROM, /* IrNET socket has disconnected */ + IRNET_DISCONNECT_TO /* Closing IrNET socket */ +} irnet_event; + +/* + * This is the storage for an event and its arguments + */ +typedef struct irnet_log +{ + irnet_event event; + int unit; + __u32 saddr; + __u32 daddr; + char name[NICKNAME_MAX_LEN + 1]; /* 21 + 1 */ + __u16_host_order hints; /* Discovery hint bits */ +} irnet_log; + +/* + * This is the storage for all events and related stuff... + */ +typedef struct irnet_ctrl_channel +{ + irnet_log log[IRNET_MAX_EVENTS]; /* Event log */ + int index; /* Current index in log */ + spinlock_t spinlock; /* Serialize access to the event log */ + wait_queue_head_t rwait; /* processes blocked on read (or poll) */ +} irnet_ctrl_channel; + +/**************************** PROTOTYPES ****************************/ +/* + * Global functions of the IrNET module + * Note : we list here also functions called from one file to the other. + */ + +/* -------------------------- IRDA PART -------------------------- */ +int irda_irnet_create(irnet_socket *); /* Initialise an IrNET socket */ +int irda_irnet_connect(irnet_socket *); /* Try to connect over IrDA */ +void irda_irnet_destroy(irnet_socket *); /* Teardown an IrNET socket */ +int irda_irnet_init(void); /* Initialise IrDA part of IrNET */ +void irda_irnet_cleanup(void); /* Teardown IrDA part of IrNET */ + +/**************************** VARIABLES ****************************/ + +/* Control channel stuff - allocated in irnet_irda.h */ +extern struct irnet_ctrl_channel irnet_events; + +#endif /* IRNET_H */ diff --git a/drivers/staging/irda/net/irnet/irnet_irda.c b/drivers/staging/irda/net/irnet/irnet_irda.c new file mode 100644 index 000000000000..e390bceeb2f8 --- /dev/null +++ b/drivers/staging/irda/net/irnet/irnet_irda.c @@ -0,0 +1,1885 @@ +/* + * IrNET protocol module : Synchronous PPP over an IrDA socket. + * + * Jean II - HPL `00 - <jt@hpl.hp.com> + * + * This file implement the IRDA interface of IrNET. + * Basically, we sit on top of IrTTP. We set up IrTTP, IrIAS properly, + * and exchange frames with IrTTP. + */ + +#include "irnet_irda.h" /* Private header */ +#include <linux/sched.h> +#include <linux/seq_file.h> +#include <linux/slab.h> +#include <asm/unaligned.h> + +/* + * PPP disconnect work: we need to make sure we're in + * process context when calling ppp_unregister_channel(). + */ +static void irnet_ppp_disconnect(struct work_struct *work) +{ + irnet_socket * self = + container_of(work, irnet_socket, disconnect_work); + + if (self == NULL) + return; + /* + * If we were connected, cleanup & close the PPP + * channel, which will kill pppd (hangup) and the rest. + */ + if (self->ppp_open && !self->ttp_open && !self->ttp_connect) { + ppp_unregister_channel(&self->chan); + self->ppp_open = 0; + } +} + +/************************* CONTROL CHANNEL *************************/ +/* + * When ppp is not active, /dev/irnet act as a control channel. + * Writing allow to set up the IrDA destination of the IrNET channel, + * and any application may be read events happening on IrNET... + */ + +/*------------------------------------------------------------------*/ +/* + * Post an event to the control channel... + * Put the event in the log, and then wait all process blocked on read + * so they can read the log... + */ +static void +irnet_post_event(irnet_socket * ap, + irnet_event event, + __u32 saddr, + __u32 daddr, + char * name, + __u16 hints) +{ + int index; /* In the log */ + + DENTER(CTRL_TRACE, "(ap=0x%p, event=%d, daddr=%08x, name=``%s'')\n", + ap, event, daddr, name); + + /* Protect this section via spinlock. + * Note : as we are the only event producer, we only need to exclude + * ourself when touching the log, which is nice and easy. + */ + spin_lock_bh(&irnet_events.spinlock); + + /* Copy the event in the log */ + index = irnet_events.index; + irnet_events.log[index].event = event; + irnet_events.log[index].daddr = daddr; + irnet_events.log[index].saddr = saddr; + /* Try to copy IrDA nickname */ + if(name) + strcpy(irnet_events.log[index].name, name); + else + irnet_events.log[index].name[0] = '\0'; + /* Copy hints */ + irnet_events.log[index].hints.word = hints; + /* Try to get ppp unit number */ + if((ap != (irnet_socket *) NULL) && (ap->ppp_open)) + irnet_events.log[index].unit = ppp_unit_number(&ap->chan); + else + irnet_events.log[index].unit = -1; + + /* Increment the index + * Note that we increment the index only after the event is written, + * to make sure that the readers don't get garbage... */ + irnet_events.index = (index + 1) % IRNET_MAX_EVENTS; + + DEBUG(CTRL_INFO, "New event index is %d\n", irnet_events.index); + + /* Spin lock end */ + spin_unlock_bh(&irnet_events.spinlock); + + /* Now : wake up everybody waiting for events... */ + wake_up_interruptible_all(&irnet_events.rwait); + + DEXIT(CTRL_TRACE, "\n"); +} + +/************************* IRDA SUBROUTINES *************************/ +/* + * These are a bunch of subroutines called from other functions + * down there, mostly common code or to improve readability... + * + * Note : we duplicate quite heavily some routines of af_irda.c, + * because our input structure (self) is quite different + * (struct irnet instead of struct irda_sock), which make sharing + * the same code impossible (at least, without templates). + */ + +/*------------------------------------------------------------------*/ +/* + * Function irda_open_tsap (self) + * + * Open local Transport Service Access Point (TSAP) + * + * Create a IrTTP instance for us and set all the IrTTP callbacks. + */ +static inline int +irnet_open_tsap(irnet_socket * self) +{ + notify_t notify; /* Callback structure */ + + DENTER(IRDA_SR_TRACE, "(self=0x%p)\n", self); + + DABORT(self->tsap != NULL, -EBUSY, IRDA_SR_ERROR, "Already busy !\n"); + + /* Initialize IrTTP callbacks to be used by the IrDA stack */ + irda_notify_init(¬ify); + notify.connect_confirm = irnet_connect_confirm; + notify.connect_indication = irnet_connect_indication; + notify.disconnect_indication = irnet_disconnect_indication; + notify.data_indication = irnet_data_indication; + /*notify.udata_indication = NULL;*/ + notify.flow_indication = irnet_flow_indication; + notify.status_indication = irnet_status_indication; + notify.instance = self; + strlcpy(notify.name, IRNET_NOTIFY_NAME, sizeof(notify.name)); + + /* Open an IrTTP instance */ + self->tsap = irttp_open_tsap(LSAP_ANY, DEFAULT_INITIAL_CREDIT, + ¬ify); + DABORT(self->tsap == NULL, -ENOMEM, + IRDA_SR_ERROR, "Unable to allocate TSAP !\n"); + + /* Remember which TSAP selector we actually got */ + self->stsap_sel = self->tsap->stsap_sel; + + DEXIT(IRDA_SR_TRACE, " - tsap=0x%p, sel=0x%X\n", + self->tsap, self->stsap_sel); + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * Function irnet_ias_to_tsap (self, result, value) + * + * Examine an IAS object and extract TSAP + * + * We do an IAP query to find the TSAP associated with the IrNET service. + * When IrIAP pass us the result of the query, this function look at + * the return values to check for failures and extract the TSAP if + * possible. + * Also deallocate value + * The failure is in self->errno + * Return TSAP or -1 + */ +static inline __u8 +irnet_ias_to_tsap(irnet_socket * self, + int result, + struct ias_value * value) +{ + __u8 dtsap_sel = 0; /* TSAP we are looking for */ + + DENTER(IRDA_SR_TRACE, "(self=0x%p)\n", self); + + /* By default, no error */ + self->errno = 0; + + /* Check if request succeeded */ + switch(result) + { + /* Standard errors : service not available */ + case IAS_CLASS_UNKNOWN: + case IAS_ATTRIB_UNKNOWN: + DEBUG(IRDA_SR_INFO, "IAS object doesn't exist ! (%d)\n", result); + self->errno = -EADDRNOTAVAIL; + break; + + /* Other errors, most likely IrDA stack failure */ + default : + DEBUG(IRDA_SR_INFO, "IAS query failed ! (%d)\n", result); + self->errno = -EHOSTUNREACH; + break; + + /* Success : we got what we wanted */ + case IAS_SUCCESS: + break; + } + + /* Check what was returned to us */ + if(value != NULL) + { + /* What type of argument have we got ? */ + switch(value->type) + { + case IAS_INTEGER: + DEBUG(IRDA_SR_INFO, "result=%d\n", value->t.integer); + if(value->t.integer != -1) + /* Get the remote TSAP selector */ + dtsap_sel = value->t.integer; + else + self->errno = -EADDRNOTAVAIL; + break; + default: + self->errno = -EADDRNOTAVAIL; + DERROR(IRDA_SR_ERROR, "bad type ! (0x%X)\n", value->type); + break; + } + + /* Cleanup */ + irias_delete_value(value); + } + else /* value == NULL */ + { + /* Nothing returned to us - usually result != SUCCESS */ + if(!(self->errno)) + { + DERROR(IRDA_SR_ERROR, + "IrDA bug : result == SUCCESS && value == NULL\n"); + self->errno = -EHOSTUNREACH; + } + } + DEXIT(IRDA_SR_TRACE, "\n"); + + /* Return the TSAP */ + return dtsap_sel; +} + +/*------------------------------------------------------------------*/ +/* + * Function irnet_find_lsap_sel (self) + * + * Try to lookup LSAP selector in remote LM-IAS + * + * Basically, we start a IAP query, and then go to sleep. When the query + * return, irnet_getvalue_confirm will wake us up, and we can examine the + * result of the query... + * Note that in some case, the query fail even before we go to sleep, + * creating some races... + */ +static inline int +irnet_find_lsap_sel(irnet_socket * self) +{ + DENTER(IRDA_SR_TRACE, "(self=0x%p)\n", self); + + /* This should not happen */ + DABORT(self->iriap, -EBUSY, IRDA_SR_ERROR, "busy with a previous query.\n"); + + /* Create an IAP instance, will be closed in irnet_getvalue_confirm() */ + self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self, + irnet_getvalue_confirm); + + /* Treat unexpected signals as disconnect */ + self->errno = -EHOSTUNREACH; + + /* Query remote LM-IAS */ + iriap_getvaluebyclass_request(self->iriap, self->rsaddr, self->daddr, + IRNET_SERVICE_NAME, IRNET_IAS_VALUE); + + /* The above request is non-blocking. + * After a while, IrDA will call us back in irnet_getvalue_confirm() + * We will then call irnet_ias_to_tsap() and finish the + * connection procedure */ + + DEXIT(IRDA_SR_TRACE, "\n"); + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * Function irnet_connect_tsap (self) + * + * Initialise the TTP socket and initiate TTP connection + * + */ +static inline int +irnet_connect_tsap(irnet_socket * self) +{ + int err; + + DENTER(IRDA_SR_TRACE, "(self=0x%p)\n", self); + + /* Open a local TSAP (an IrTTP instance) */ + err = irnet_open_tsap(self); + if(err != 0) + { + clear_bit(0, &self->ttp_connect); + DERROR(IRDA_SR_ERROR, "connect aborted!\n"); + return err; + } + + /* Connect to remote device */ + err = irttp_connect_request(self->tsap, self->dtsap_sel, + self->rsaddr, self->daddr, NULL, + self->max_sdu_size_rx, NULL); + if(err != 0) + { + clear_bit(0, &self->ttp_connect); + DERROR(IRDA_SR_ERROR, "connect aborted!\n"); + return err; + } + + /* The above call is non-blocking. + * After a while, the IrDA stack will either call us back in + * irnet_connect_confirm() or irnet_disconnect_indication() + * See you there ;-) */ + + DEXIT(IRDA_SR_TRACE, "\n"); + return err; +} + +/*------------------------------------------------------------------*/ +/* + * Function irnet_discover_next_daddr (self) + * + * Query the IrNET TSAP of the next device in the log. + * + * Used in the TSAP discovery procedure. + */ +static inline int +irnet_discover_next_daddr(irnet_socket * self) +{ + /* Close the last instance of IrIAP, and open a new one. + * We can't reuse the IrIAP instance in the IrIAP callback */ + if(self->iriap) + { + iriap_close(self->iriap); + self->iriap = NULL; + } + /* Create a new IAP instance */ + self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self, + irnet_discovervalue_confirm); + if(self->iriap == NULL) + return -ENOMEM; + + /* Next discovery - before the call to avoid races */ + self->disco_index++; + + /* Check if we have one more address to try */ + if(self->disco_index < self->disco_number) + { + /* Query remote LM-IAS */ + iriap_getvaluebyclass_request(self->iriap, + self->discoveries[self->disco_index].saddr, + self->discoveries[self->disco_index].daddr, + IRNET_SERVICE_NAME, IRNET_IAS_VALUE); + /* The above request is non-blocking. + * After a while, IrDA will call us back in irnet_discovervalue_confirm() + * We will then call irnet_ias_to_tsap() and come back here again... */ + return 0; + } + else + return 1; +} + +/*------------------------------------------------------------------*/ +/* + * Function irnet_discover_daddr_and_lsap_sel (self) + * + * This try to find a device with the requested service. + * + * Initiate a TSAP discovery procedure. + * It basically look into the discovery log. For each address in the list, + * it queries the LM-IAS of the device to find if this device offer + * the requested service. + * If there is more than one node supporting the service, we complain + * to the user (it should move devices around). + * If we find one node which have the requested TSAP, we connect to it. + * + * This function just start the whole procedure. It request the discovery + * log and submit the first IAS query. + * The bulk of the job is handled in irnet_discovervalue_confirm() + * + * Note : this procedure fails if there is more than one device in range + * on the same dongle, because IrLMP doesn't disconnect the LAP when the + * last LSAP is closed. Moreover, we would need to wait the LAP + * disconnection... + */ +static inline int +irnet_discover_daddr_and_lsap_sel(irnet_socket * self) +{ + int ret; + + DENTER(IRDA_SR_TRACE, "(self=0x%p)\n", self); + + /* Ask lmp for the current discovery log */ + self->discoveries = irlmp_get_discoveries(&self->disco_number, self->mask, + DISCOVERY_DEFAULT_SLOTS); + + /* Check if the we got some results */ + if(self->discoveries == NULL) + { + self->disco_number = -1; + clear_bit(0, &self->ttp_connect); + DRETURN(-ENETUNREACH, IRDA_SR_INFO, "No Cachelog...\n"); + } + DEBUG(IRDA_SR_INFO, "Got the log (0x%p), size is %d\n", + self->discoveries, self->disco_number); + + /* Start with the first discovery */ + self->disco_index = -1; + self->daddr = DEV_ADDR_ANY; + + /* This will fail if the log is empty - this is non-blocking */ + ret = irnet_discover_next_daddr(self); + if(ret) + { + /* Close IAP */ + if(self->iriap) + iriap_close(self->iriap); + self->iriap = NULL; + + /* Cleanup our copy of the discovery log */ + kfree(self->discoveries); + self->discoveries = NULL; + + clear_bit(0, &self->ttp_connect); + DRETURN(-ENETUNREACH, IRDA_SR_INFO, "Cachelog empty...\n"); + } + + /* Follow me in irnet_discovervalue_confirm() */ + + DEXIT(IRDA_SR_TRACE, "\n"); + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * Function irnet_dname_to_daddr (self) + * + * Convert an IrDA nickname to a valid IrDA address + * + * It basically look into the discovery log until there is a match. + */ +static inline int +irnet_dname_to_daddr(irnet_socket * self) +{ + struct irda_device_info *discoveries; /* Copy of the discovery log */ + int number; /* Number of nodes in the log */ + int i; + + DENTER(IRDA_SR_TRACE, "(self=0x%p)\n", self); + + /* Ask lmp for the current discovery log */ + discoveries = irlmp_get_discoveries(&number, 0xffff, + DISCOVERY_DEFAULT_SLOTS); + /* Check if the we got some results */ + if(discoveries == NULL) + DRETURN(-ENETUNREACH, IRDA_SR_INFO, "Cachelog empty...\n"); + + /* + * Now, check all discovered devices (if any), and connect + * client only about the services that the client is + * interested in... + */ + for(i = 0; i < number; i++) + { + /* Does the name match ? */ + if(!strncmp(discoveries[i].info, self->rname, NICKNAME_MAX_LEN)) + { + /* Yes !!! Get it.. */ + self->daddr = discoveries[i].daddr; + DEBUG(IRDA_SR_INFO, "discovered device ``%s'' at address 0x%08x.\n", + self->rname, self->daddr); + kfree(discoveries); + DEXIT(IRDA_SR_TRACE, "\n"); + return 0; + } + } + /* No luck ! */ + DEBUG(IRDA_SR_INFO, "cannot discover device ``%s'' !!!\n", self->rname); + kfree(discoveries); + return -EADDRNOTAVAIL; +} + + +/************************* SOCKET ROUTINES *************************/ +/* + * This are the main operations on IrNET sockets, basically to create + * and destroy IrNET sockets. These are called from the PPP part... + */ + +/*------------------------------------------------------------------*/ +/* + * Create a IrNET instance : just initialise some parameters... + */ +int +irda_irnet_create(irnet_socket * self) +{ + DENTER(IRDA_SOCK_TRACE, "(self=0x%p)\n", self); + + self->magic = IRNET_MAGIC; /* Paranoia */ + + self->ttp_open = 0; /* Prevent higher layer from accessing IrTTP */ + self->ttp_connect = 0; /* Not connecting yet */ + self->rname[0] = '\0'; /* May be set via control channel */ + self->rdaddr = DEV_ADDR_ANY; /* May be set via control channel */ + self->rsaddr = DEV_ADDR_ANY; /* May be set via control channel */ + self->daddr = DEV_ADDR_ANY; /* Until we get connected */ + self->saddr = DEV_ADDR_ANY; /* Until we get connected */ + self->max_sdu_size_rx = TTP_SAR_UNBOUND; + + /* Register as a client with IrLMP */ + self->ckey = irlmp_register_client(0, NULL, NULL, NULL); +#ifdef DISCOVERY_NOMASK + self->mask = 0xffff; /* For W2k compatibility */ +#else /* DISCOVERY_NOMASK */ + self->mask = irlmp_service_to_hint(S_LAN); +#endif /* DISCOVERY_NOMASK */ + self->tx_flow = FLOW_START; /* Flow control from IrTTP */ + + INIT_WORK(&self->disconnect_work, irnet_ppp_disconnect); + + DEXIT(IRDA_SOCK_TRACE, "\n"); + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * Connect to the other side : + * o convert device name to an address + * o find the socket number (dlsap) + * o Establish the connection + * + * Note : We no longer mimic af_irda. The IAS query for finding the TSAP + * is done asynchronously, like the TTP connection. This allow us to + * call this function from any context (not only process). + * The downside is that following what's happening in there is tricky + * because it involve various functions all over the place... + */ +int +irda_irnet_connect(irnet_socket * self) +{ + int err; + + DENTER(IRDA_SOCK_TRACE, "(self=0x%p)\n", self); + + /* Check if we are already trying to connect. + * Because irda_irnet_connect() can be called directly by pppd plus + * packet retries in ppp_generic and connect may take time, plus we may + * race with irnet_connect_indication(), we need to be careful there... */ + if(test_and_set_bit(0, &self->ttp_connect)) + DRETURN(-EBUSY, IRDA_SOCK_INFO, "Already connecting...\n"); + if((self->iriap != NULL) || (self->tsap != NULL)) + DERROR(IRDA_SOCK_ERROR, "Socket not cleaned up...\n"); + + /* Insert ourselves in the hashbin so that the IrNET server can find us. + * Notes : 4th arg is string of 32 char max and must be null terminated + * When 4th arg is used (string), 3rd arg isn't (int) + * Can't re-insert (MUST remove first) so check for that... */ + if((irnet_server.running) && (self->q.q_next == NULL)) + { + spin_lock_bh(&irnet_server.spinlock); + hashbin_insert(irnet_server.list, (irda_queue_t *) self, 0, self->rname); + spin_unlock_bh(&irnet_server.spinlock); + DEBUG(IRDA_SOCK_INFO, "Inserted ``%s'' in hashbin...\n", self->rname); + } + + /* If we don't have anything (no address, no name) */ + if((self->rdaddr == DEV_ADDR_ANY) && (self->rname[0] == '\0')) + { + /* Try to find a suitable address */ + if((err = irnet_discover_daddr_and_lsap_sel(self)) != 0) + DRETURN(err, IRDA_SOCK_INFO, "auto-connect failed!\n"); + /* In most cases, the call above is non-blocking */ + } + else + { + /* If we have only the name (no address), try to get an address */ + if(self->rdaddr == DEV_ADDR_ANY) + { + if((err = irnet_dname_to_daddr(self)) != 0) + DRETURN(err, IRDA_SOCK_INFO, "name connect failed!\n"); + } + else + /* Use the requested destination address */ + self->daddr = self->rdaddr; + + /* Query remote LM-IAS to find LSAP selector */ + irnet_find_lsap_sel(self); + /* The above call is non blocking */ + } + + /* At this point, we are waiting for the IrDA stack to call us back, + * or we have already failed. + * We will finish the connection procedure in irnet_connect_tsap(). + */ + DEXIT(IRDA_SOCK_TRACE, "\n"); + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * Function irda_irnet_destroy(self) + * + * Destroy irnet instance + * + * Note : this need to be called from a process context. + */ +void +irda_irnet_destroy(irnet_socket * self) +{ + DENTER(IRDA_SOCK_TRACE, "(self=0x%p)\n", self); + if(self == NULL) + return; + + /* Remove ourselves from hashbin (if we are queued in hashbin) + * Note : `irnet_server.running' protect us from calls in hashbin_delete() */ + if((irnet_server.running) && (self->q.q_next != NULL)) + { + struct irnet_socket * entry; + DEBUG(IRDA_SOCK_INFO, "Removing from hash..\n"); + spin_lock_bh(&irnet_server.spinlock); + entry = hashbin_remove_this(irnet_server.list, (irda_queue_t *) self); + self->q.q_next = NULL; + spin_unlock_bh(&irnet_server.spinlock); + DASSERT(entry == self, , IRDA_SOCK_ERROR, "Can't remove from hash.\n"); + } + + /* If we were connected, post a message */ + if(test_bit(0, &self->ttp_open)) + { + /* Note : as the disconnect comes from ppp_generic, the unit number + * doesn't exist anymore when we post the event, so we need to pass + * NULL as the first arg... */ + irnet_post_event(NULL, IRNET_DISCONNECT_TO, + self->saddr, self->daddr, self->rname, 0); + } + + /* Prevent various IrDA callbacks from messing up things + * Need to be first */ + clear_bit(0, &self->ttp_connect); + + /* Prevent higher layer from accessing IrTTP */ + clear_bit(0, &self->ttp_open); + + /* Unregister with IrLMP */ + irlmp_unregister_client(self->ckey); + + /* Unregister with LM-IAS */ + if(self->iriap) + { + iriap_close(self->iriap); + self->iriap = NULL; + } + + /* Cleanup eventual discoveries from connection attempt or control channel */ + if(self->discoveries != NULL) + { + /* Cleanup our copy of the discovery log */ + kfree(self->discoveries); + self->discoveries = NULL; + } + + /* Close our IrTTP connection */ + if(self->tsap) + { + DEBUG(IRDA_SOCK_INFO, "Closing our TTP connection.\n"); + irttp_disconnect_request(self->tsap, NULL, P_NORMAL); + irttp_close_tsap(self->tsap); + self->tsap = NULL; + } + self->stsap_sel = 0; + + DEXIT(IRDA_SOCK_TRACE, "\n"); +} + + +/************************** SERVER SOCKET **************************/ +/* + * The IrNET service is composed of one server socket and a variable + * number of regular IrNET sockets. The server socket is supposed to + * handle incoming connections and redirect them to one IrNET sockets. + * It's a superset of the regular IrNET socket, but has a very distinct + * behaviour... + */ + +/*------------------------------------------------------------------*/ +/* + * Function irnet_daddr_to_dname (self) + * + * Convert an IrDA address to a IrDA nickname + * + * It basically look into the discovery log until there is a match. + */ +static inline int +irnet_daddr_to_dname(irnet_socket * self) +{ + struct irda_device_info *discoveries; /* Copy of the discovery log */ + int number; /* Number of nodes in the log */ + int i; + + DENTER(IRDA_SERV_TRACE, "(self=0x%p)\n", self); + + /* Ask lmp for the current discovery log */ + discoveries = irlmp_get_discoveries(&number, 0xffff, + DISCOVERY_DEFAULT_SLOTS); + /* Check if the we got some results */ + if (discoveries == NULL) + DRETURN(-ENETUNREACH, IRDA_SERV_INFO, "Cachelog empty...\n"); + + /* Now, check all discovered devices (if any) */ + for(i = 0; i < number; i++) + { + /* Does the name match ? */ + if(discoveries[i].daddr == self->daddr) + { + /* Yes !!! Get it.. */ + strlcpy(self->rname, discoveries[i].info, sizeof(self->rname)); + self->rname[sizeof(self->rname) - 1] = '\0'; + DEBUG(IRDA_SERV_INFO, "Device 0x%08x is in fact ``%s''.\n", + self->daddr, self->rname); + kfree(discoveries); + DEXIT(IRDA_SERV_TRACE, "\n"); + return 0; + } + } + /* No luck ! */ + DEXIT(IRDA_SERV_INFO, ": cannot discover device 0x%08x !!!\n", self->daddr); + kfree(discoveries); + return -EADDRNOTAVAIL; +} + +/*------------------------------------------------------------------*/ +/* + * Function irda_find_socket (self) + * + * Find the correct IrNET socket + * + * Look into the list of IrNET sockets and finds one with the right + * properties... + */ +static inline irnet_socket * +irnet_find_socket(irnet_socket * self) +{ + irnet_socket * new = (irnet_socket *) NULL; + int err; + + DENTER(IRDA_SERV_TRACE, "(self=0x%p)\n", self); + + /* Get the addresses of the requester */ + self->daddr = irttp_get_daddr(self->tsap); + self->saddr = irttp_get_saddr(self->tsap); + + /* Try to get the IrDA nickname of the requester */ + err = irnet_daddr_to_dname(self); + + /* Protect access to the instance list */ + spin_lock_bh(&irnet_server.spinlock); + + /* So now, try to get an socket having specifically + * requested that nickname */ + if(err == 0) + { + new = (irnet_socket *) hashbin_find(irnet_server.list, + 0, self->rname); + if(new) + DEBUG(IRDA_SERV_INFO, "Socket 0x%p matches rname ``%s''.\n", + new, new->rname); + } + + /* If no name matches, try to find an socket by the destination address */ + /* It can be either the requested destination address (set via the + * control channel), or the current destination address if the + * socket is in the middle of a connection request */ + if(new == (irnet_socket *) NULL) + { + new = (irnet_socket *) hashbin_get_first(irnet_server.list); + while(new !=(irnet_socket *) NULL) + { + /* Does it have the same address ? */ + if((new->rdaddr == self->daddr) || (new->daddr == self->daddr)) + { + /* Yes !!! Get it.. */ + DEBUG(IRDA_SERV_INFO, "Socket 0x%p matches daddr %#08x.\n", + new, self->daddr); + break; + } + new = (irnet_socket *) hashbin_get_next(irnet_server.list); + } + } + + /* If we don't have any socket, get the first unconnected socket */ + if(new == (irnet_socket *) NULL) + { + new = (irnet_socket *) hashbin_get_first(irnet_server.list); + while(new !=(irnet_socket *) NULL) + { + /* Is it available ? */ + if(!(test_bit(0, &new->ttp_open)) && (new->rdaddr == DEV_ADDR_ANY) && + (new->rname[0] == '\0') && (new->ppp_open)) + { + /* Yes !!! Get it.. */ + DEBUG(IRDA_SERV_INFO, "Socket 0x%p is free.\n", + new); + break; + } + new = (irnet_socket *) hashbin_get_next(irnet_server.list); + } + } + + /* Spin lock end */ + spin_unlock_bh(&irnet_server.spinlock); + + DEXIT(IRDA_SERV_TRACE, " - new = 0x%p\n", new); + return new; +} + +/*------------------------------------------------------------------*/ +/* + * Function irda_connect_socket (self) + * + * Connect an incoming connection to the socket + * + */ +static inline int +irnet_connect_socket(irnet_socket * server, + irnet_socket * new, + struct qos_info * qos, + __u32 max_sdu_size, + __u8 max_header_size) +{ + DENTER(IRDA_SERV_TRACE, "(server=0x%p, new=0x%p)\n", + server, new); + + /* Now attach up the new socket */ + new->tsap = irttp_dup(server->tsap, new); + DABORT(new->tsap == NULL, -1, IRDA_SERV_ERROR, "dup failed!\n"); + + /* Set up all the relevant parameters on the new socket */ + new->stsap_sel = new->tsap->stsap_sel; + new->dtsap_sel = new->tsap->dtsap_sel; + new->saddr = irttp_get_saddr(new->tsap); + new->daddr = irttp_get_daddr(new->tsap); + + new->max_header_size = max_header_size; + new->max_sdu_size_tx = max_sdu_size; + new->max_data_size = max_sdu_size; +#ifdef STREAM_COMPAT + /* If we want to receive "stream sockets" */ + if(max_sdu_size == 0) + new->max_data_size = irttp_get_max_seg_size(new->tsap); +#endif /* STREAM_COMPAT */ + + /* Clean up the original one to keep it in listen state */ + irttp_listen(server->tsap); + + /* Send a connection response on the new socket */ + irttp_connect_response(new->tsap, new->max_sdu_size_rx, NULL); + + /* Allow PPP to send its junk over the new socket... */ + set_bit(0, &new->ttp_open); + + /* Not connecting anymore, and clean up last possible remains + * of connection attempts on the socket */ + clear_bit(0, &new->ttp_connect); + if(new->iriap) + { + iriap_close(new->iriap); + new->iriap = NULL; + } + if(new->discoveries != NULL) + { + kfree(new->discoveries); + new->discoveries = NULL; + } + +#ifdef CONNECT_INDIC_KICK + /* As currently we don't block packets in ppp_irnet_send() while passive, + * this is not really needed... + * Also, not doing it give IrDA a chance to finish the setup properly + * before being swamped with packets... */ + ppp_output_wakeup(&new->chan); +#endif /* CONNECT_INDIC_KICK */ + + /* Notify the control channel */ + irnet_post_event(new, IRNET_CONNECT_FROM, + new->saddr, new->daddr, server->rname, 0); + + DEXIT(IRDA_SERV_TRACE, "\n"); + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * Function irda_disconnect_server (self) + * + * Cleanup the server socket when the incoming connection abort + * + */ +static inline void +irnet_disconnect_server(irnet_socket * self, + struct sk_buff *skb) +{ + DENTER(IRDA_SERV_TRACE, "(self=0x%p)\n", self); + + /* Put the received packet in the black hole */ + kfree_skb(skb); + +#ifdef FAIL_SEND_DISCONNECT + /* Tell the other party we don't want to be connected */ + /* Hum... Is it the right thing to do ? And do we need to send + * a connect response before ? It looks ok without this... */ + irttp_disconnect_request(self->tsap, NULL, P_NORMAL); +#endif /* FAIL_SEND_DISCONNECT */ + + /* Notify the control channel (see irnet_find_socket()) */ + irnet_post_event(NULL, IRNET_REQUEST_FROM, + self->saddr, self->daddr, self->rname, 0); + + /* Clean up the server to keep it in listen state */ + irttp_listen(self->tsap); + + DEXIT(IRDA_SERV_TRACE, "\n"); +} + +/*------------------------------------------------------------------*/ +/* + * Function irda_setup_server (self) + * + * Create a IrTTP server and set it up... + * + * Register the IrLAN hint bit, create a IrTTP instance for us, + * set all the IrTTP callbacks and create an IrIAS entry... + */ +static inline int +irnet_setup_server(void) +{ + __u16 hints; + + DENTER(IRDA_SERV_TRACE, "()\n"); + + /* Initialise the regular socket part of the server */ + irda_irnet_create(&irnet_server.s); + + /* Open a local TSAP (an IrTTP instance) for the server */ + irnet_open_tsap(&irnet_server.s); + + /* PPP part setup */ + irnet_server.s.ppp_open = 0; + irnet_server.s.chan.private = NULL; + irnet_server.s.file = NULL; + + /* Get the hint bit corresponding to IrLAN */ + /* Note : we overload the IrLAN hint bit. As it is only a "hint", and as + * we provide roughly the same functionality as IrLAN, this is ok. + * In fact, the situation is similar as JetSend overloading the Obex hint + */ + hints = irlmp_service_to_hint(S_LAN); + +#ifdef ADVERTISE_HINT + /* Register with IrLMP as a service (advertise our hint bit) */ + irnet_server.skey = irlmp_register_service(hints); +#endif /* ADVERTISE_HINT */ + + /* Register with LM-IAS (so that people can connect to us) */ + irnet_server.ias_obj = irias_new_object(IRNET_SERVICE_NAME, jiffies); + irias_add_integer_attrib(irnet_server.ias_obj, IRNET_IAS_VALUE, + irnet_server.s.stsap_sel, IAS_KERNEL_ATTR); + irias_insert_object(irnet_server.ias_obj); + +#ifdef DISCOVERY_EVENTS + /* Tell IrLMP we want to be notified of newly discovered nodes */ + irlmp_update_client(irnet_server.s.ckey, hints, + irnet_discovery_indication, irnet_expiry_indication, + (void *) &irnet_server.s); +#endif + + DEXIT(IRDA_SERV_TRACE, " - self=0x%p\n", &irnet_server.s); + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * Function irda_destroy_server (self) + * + * Destroy the IrTTP server... + * + * Reverse of the previous function... + */ +static inline void +irnet_destroy_server(void) +{ + DENTER(IRDA_SERV_TRACE, "()\n"); + +#ifdef ADVERTISE_HINT + /* Unregister with IrLMP */ + irlmp_unregister_service(irnet_server.skey); +#endif /* ADVERTISE_HINT */ + + /* Unregister with LM-IAS */ + if(irnet_server.ias_obj) + irias_delete_object(irnet_server.ias_obj); + + /* Cleanup the socket part */ + irda_irnet_destroy(&irnet_server.s); + + DEXIT(IRDA_SERV_TRACE, "\n"); +} + + +/************************ IRDA-TTP CALLBACKS ************************/ +/* + * When we create a IrTTP instance, we pass to it a set of callbacks + * that IrTTP will call in case of various events. + * We take care of those events here. + */ + +/*------------------------------------------------------------------*/ +/* + * Function irnet_data_indication (instance, sap, skb) + * + * Received some data from TinyTP. Just queue it on the receive queue + * + */ +static int +irnet_data_indication(void * instance, + void * sap, + struct sk_buff *skb) +{ + irnet_socket * ap = (irnet_socket *) instance; + unsigned char * p; + int code = 0; + + DENTER(IRDA_TCB_TRACE, "(self/ap=0x%p, skb=0x%p)\n", + ap, skb); + DASSERT(skb != NULL, 0, IRDA_CB_ERROR, "skb is NULL !!!\n"); + + /* Check is ppp is ready to receive our packet */ + if(!ap->ppp_open) + { + DERROR(IRDA_CB_ERROR, "PPP not ready, dropping packet...\n"); + /* When we return error, TTP will need to requeue the skb and + * will stop the sender. IrTTP will stall until we send it a + * flow control request... */ + return -ENOMEM; + } + + /* strip address/control field if present */ + p = skb->data; + if((p[0] == PPP_ALLSTATIONS) && (p[1] == PPP_UI)) + { + /* chop off address/control */ + if(skb->len < 3) + goto err_exit; + p = skb_pull(skb, 2); + } + + /* decompress protocol field if compressed */ + if(p[0] & 1) + { + /* protocol is compressed */ + *(u8 *)skb_push(skb, 1) = 0; + } + else + if(skb->len < 2) + goto err_exit; + + /* pass to generic ppp layer */ + /* Note : how do I know if ppp can accept or not the packet ? This is + * essential if I want to manage flow control smoothly... */ + ppp_input(&ap->chan, skb); + + DEXIT(IRDA_TCB_TRACE, "\n"); + return 0; + + err_exit: + DERROR(IRDA_CB_ERROR, "Packet too small, dropping...\n"); + kfree_skb(skb); + ppp_input_error(&ap->chan, code); + return 0; /* Don't return an error code, only for flow control... */ +} + +/*------------------------------------------------------------------*/ +/* + * Function irnet_disconnect_indication (instance, sap, reason, skb) + * + * Connection has been closed. Chech reason to find out why + * + * Note : there are many cases where we come here : + * o attempted to connect, timeout + * o connected, link is broken, LAP has timeout + * o connected, other side close the link + * o connection request on the server not handled + */ +static void +irnet_disconnect_indication(void * instance, + void * sap, + LM_REASON reason, + struct sk_buff *skb) +{ + irnet_socket * self = (irnet_socket *) instance; + int test_open; + int test_connect; + + DENTER(IRDA_TCB_TRACE, "(self=0x%p)\n", self); + DASSERT(self != NULL, , IRDA_CB_ERROR, "Self is NULL !!!\n"); + + /* Don't care about it, but let's not leak it */ + if(skb) + dev_kfree_skb(skb); + + /* Prevent higher layer from accessing IrTTP */ + test_open = test_and_clear_bit(0, &self->ttp_open); + /* Not connecting anymore... + * (note : TSAP is open, so IAP callbacks are no longer pending...) */ + test_connect = test_and_clear_bit(0, &self->ttp_connect); + + /* If both self->ttp_open and self->ttp_connect are NULL, it mean that we + * have a race condition with irda_irnet_destroy() or + * irnet_connect_indication(), so don't mess up tsap... + */ + if(!(test_open || test_connect)) + { + DERROR(IRDA_CB_ERROR, "Race condition detected...\n"); + return; + } + + /* If we were active, notify the control channel */ + if(test_open) + irnet_post_event(self, IRNET_DISCONNECT_FROM, + self->saddr, self->daddr, self->rname, 0); + else + /* If we were trying to connect, notify the control channel */ + if((self->tsap) && (self != &irnet_server.s)) + irnet_post_event(self, IRNET_NOANSWER_FROM, + self->saddr, self->daddr, self->rname, 0); + + /* Close our IrTTP connection, cleanup tsap */ + if((self->tsap) && (self != &irnet_server.s)) + { + DEBUG(IRDA_CB_INFO, "Closing our TTP connection.\n"); + irttp_close_tsap(self->tsap); + self->tsap = NULL; + } + /* Cleanup the socket in case we want to reconnect in ppp_output_wakeup() */ + self->stsap_sel = 0; + self->daddr = DEV_ADDR_ANY; + self->tx_flow = FLOW_START; + + /* Deal with the ppp instance if it's still alive */ + if(self->ppp_open) + { + if(test_open) + { + /* ppp_unregister_channel() wants a user context. */ + schedule_work(&self->disconnect_work); + } + else + { + /* If we were trying to connect, flush (drain) ppp_generic + * Tx queue (most often we have blocked it), which will + * trigger an other attempt to connect. If we are passive, + * this will empty the Tx queue after last try. */ + ppp_output_wakeup(&self->chan); + } + } + + DEXIT(IRDA_TCB_TRACE, "\n"); +} + +/*------------------------------------------------------------------*/ +/* + * Function irnet_connect_confirm (instance, sap, qos, max_sdu_size, skb) + * + * Connections has been confirmed by the remote device + * + */ +static void +irnet_connect_confirm(void * instance, + void * sap, + struct qos_info *qos, + __u32 max_sdu_size, + __u8 max_header_size, + struct sk_buff *skb) +{ + irnet_socket * self = (irnet_socket *) instance; + + DENTER(IRDA_TCB_TRACE, "(self=0x%p)\n", self); + + /* Check if socket is closing down (via irda_irnet_destroy()) */ + if(! test_bit(0, &self->ttp_connect)) + { + DERROR(IRDA_CB_ERROR, "Socket no longer connecting. Ouch !\n"); + return; + } + + /* How much header space do we need to reserve */ + self->max_header_size = max_header_size; + + /* IrTTP max SDU size in transmit direction */ + self->max_sdu_size_tx = max_sdu_size; + self->max_data_size = max_sdu_size; +#ifdef STREAM_COMPAT + if(max_sdu_size == 0) + self->max_data_size = irttp_get_max_seg_size(self->tsap); +#endif /* STREAM_COMPAT */ + + /* At this point, IrLMP has assigned our source address */ + self->saddr = irttp_get_saddr(self->tsap); + + /* Allow higher layer to access IrTTP */ + set_bit(0, &self->ttp_open); + clear_bit(0, &self->ttp_connect); /* Not racy, IrDA traffic is serial */ + /* Give a kick in the ass of ppp_generic so that he sends us some data */ + ppp_output_wakeup(&self->chan); + + /* Check size of received packet */ + if(skb->len > 0) + { +#ifdef PASS_CONNECT_PACKETS + DEBUG(IRDA_CB_INFO, "Passing connect packet to PPP.\n"); + /* Try to pass it to PPP */ + irnet_data_indication(instance, sap, skb); +#else /* PASS_CONNECT_PACKETS */ + DERROR(IRDA_CB_ERROR, "Dropping non empty packet.\n"); + kfree_skb(skb); /* Note : will be optimised with other kfree... */ +#endif /* PASS_CONNECT_PACKETS */ + } + else + kfree_skb(skb); + + /* Notify the control channel */ + irnet_post_event(self, IRNET_CONNECT_TO, + self->saddr, self->daddr, self->rname, 0); + + DEXIT(IRDA_TCB_TRACE, "\n"); +} + +/*------------------------------------------------------------------*/ +/* + * Function irnet_flow_indication (instance, sap, flow) + * + * Used by TinyTP to tell us if it can accept more data or not + * + */ +static void +irnet_flow_indication(void * instance, + void * sap, + LOCAL_FLOW flow) +{ + irnet_socket * self = (irnet_socket *) instance; + LOCAL_FLOW oldflow = self->tx_flow; + + DENTER(IRDA_TCB_TRACE, "(self=0x%p, flow=%d)\n", self, flow); + + /* Update our state */ + self->tx_flow = flow; + + /* Check what IrTTP want us to do... */ + switch(flow) + { + case FLOW_START: + DEBUG(IRDA_CB_INFO, "IrTTP wants us to start again\n"); + /* Check if we really need to wake up PPP */ + if(oldflow == FLOW_STOP) + ppp_output_wakeup(&self->chan); + else + DEBUG(IRDA_CB_INFO, "But we were already transmitting !!!\n"); + break; + case FLOW_STOP: + DEBUG(IRDA_CB_INFO, "IrTTP wants us to slow down\n"); + break; + default: + DEBUG(IRDA_CB_INFO, "Unknown flow command!\n"); + break; + } + + DEXIT(IRDA_TCB_TRACE, "\n"); +} + +/*------------------------------------------------------------------*/ +/* + * Function irnet_status_indication (instance, sap, reason, skb) + * + * Link (IrLAP) status report. + * + */ +static void +irnet_status_indication(void * instance, + LINK_STATUS link, + LOCK_STATUS lock) +{ + irnet_socket * self = (irnet_socket *) instance; + + DENTER(IRDA_TCB_TRACE, "(self=0x%p)\n", self); + DASSERT(self != NULL, , IRDA_CB_ERROR, "Self is NULL !!!\n"); + + /* We can only get this event if we are connected */ + switch(link) + { + case STATUS_NO_ACTIVITY: + irnet_post_event(self, IRNET_BLOCKED_LINK, + self->saddr, self->daddr, self->rname, 0); + break; + default: + DEBUG(IRDA_CB_INFO, "Unknown status...\n"); + } + + DEXIT(IRDA_TCB_TRACE, "\n"); +} + +/*------------------------------------------------------------------*/ +/* + * Function irnet_connect_indication(instance, sap, qos, max_sdu_size, userdata) + * + * Incoming connection + * + * In theory, this function is called only on the server socket. + * Some other node is attempting to connect to the IrNET service, and has + * sent a connection request on our server socket. + * We just redirect the connection to the relevant IrNET socket. + * + * Note : we also make sure that between 2 irnet nodes, there can + * exist only one irnet connection. + */ +static void +irnet_connect_indication(void * instance, + void * sap, + struct qos_info *qos, + __u32 max_sdu_size, + __u8 max_header_size, + struct sk_buff *skb) +{ + irnet_socket * server = &irnet_server.s; + irnet_socket * new = (irnet_socket *) NULL; + + DENTER(IRDA_TCB_TRACE, "(server=0x%p)\n", server); + DASSERT(instance == &irnet_server, , IRDA_CB_ERROR, + "Invalid instance (0x%p) !!!\n", instance); + DASSERT(sap == irnet_server.s.tsap, , IRDA_CB_ERROR, "Invalid sap !!!\n"); + + /* Try to find the most appropriate IrNET socket */ + new = irnet_find_socket(server); + + /* After all this hard work, do we have an socket ? */ + if(new == (irnet_socket *) NULL) + { + DEXIT(IRDA_CB_INFO, ": No socket waiting for this connection.\n"); + irnet_disconnect_server(server, skb); + return; + } + + /* Is the socket already busy ? */ + if(test_bit(0, &new->ttp_open)) + { + DEXIT(IRDA_CB_INFO, ": Socket already connected.\n"); + irnet_disconnect_server(server, skb); + return; + } + + /* The following code is a bit tricky, so need comments ;-) + */ + /* If ttp_connect is set, the socket is trying to connect to the other + * end and may have sent a IrTTP connection request and is waiting for + * a connection response (that may never come). + * Now, the pain is that the socket may have opened a tsap and is + * waiting on it, while the other end is trying to connect to it on + * another tsap. + * Because IrNET can be peer to peer, we need to workaround this. + * Furthermore, the way the irnetd script is implemented, the + * target will create a second IrNET connection back to the + * originator and expect the originator to bind this new connection + * to the original PPPD instance. + * And of course, if we don't use irnetd, we can have a race when + * both side try to connect simultaneously, which could leave both + * connections half closed (yuck). + * Conclusions : + * 1) The "originator" must accept the new connection and get rid + * of the old one so that irnetd works + * 2) One side must deny the new connection to avoid races, + * but both side must agree on which side it is... + * Most often, the originator is primary at the LAP layer. + * Jean II + */ + /* Now, let's look at the way I wrote the test... + * We need to clear up the ttp_connect flag atomically to prevent + * irnet_disconnect_indication() to mess up the tsap we are going to close. + * We want to clear the ttp_connect flag only if we close the tsap, + * otherwise we will never close it, so we need to check for primary + * *before* doing the test on the flag. + * And of course, ALLOW_SIMULT_CONNECT can disable this entirely... + * Jean II + */ + + /* Socket already connecting ? On primary ? */ + if(0 +#ifdef ALLOW_SIMULT_CONNECT + || ((irttp_is_primary(server->tsap) == 1) && /* primary */ + (test_and_clear_bit(0, &new->ttp_connect))) +#endif /* ALLOW_SIMULT_CONNECT */ + ) + { + DERROR(IRDA_CB_ERROR, "Socket already connecting, but going to reuse it !\n"); + + /* Cleanup the old TSAP if necessary - IrIAP will be cleaned up later */ + if(new->tsap != NULL) + { + /* Close the old connection the new socket was attempting, + * so that we can hook it up to the new connection. + * It's now safe to do it... */ + irttp_close_tsap(new->tsap); + new->tsap = NULL; + } + } + else + { + /* Three options : + * 1) socket was not connecting or connected : ttp_connect should be 0. + * 2) we don't want to connect the socket because we are secondary or + * ALLOW_SIMULT_CONNECT is undefined. ttp_connect should be 1. + * 3) we are half way in irnet_disconnect_indication(), and it's a + * nice race condition... Fortunately, we can detect that by checking + * if tsap is still alive. On the other hand, we can't be in + * irda_irnet_destroy() otherwise we would not have found this + * socket in the hashbin. + * Jean II */ + if((test_bit(0, &new->ttp_connect)) || (new->tsap != NULL)) + { + /* Don't mess this socket, somebody else in in charge... */ + DERROR(IRDA_CB_ERROR, "Race condition detected, socket in use, abort connect...\n"); + irnet_disconnect_server(server, skb); + return; + } + } + + /* So : at this point, we have a socket, and it is idle. Good ! */ + irnet_connect_socket(server, new, qos, max_sdu_size, max_header_size); + + /* Check size of received packet */ + if(skb->len > 0) + { +#ifdef PASS_CONNECT_PACKETS + DEBUG(IRDA_CB_INFO, "Passing connect packet to PPP.\n"); + /* Try to pass it to PPP */ + irnet_data_indication(new, new->tsap, skb); +#else /* PASS_CONNECT_PACKETS */ + DERROR(IRDA_CB_ERROR, "Dropping non empty packet.\n"); + kfree_skb(skb); /* Note : will be optimised with other kfree... */ +#endif /* PASS_CONNECT_PACKETS */ + } + else + kfree_skb(skb); + + DEXIT(IRDA_TCB_TRACE, "\n"); +} + + +/********************** IRDA-IAS/LMP CALLBACKS **********************/ +/* + * These are the callbacks called by other layers of the IrDA stack, + * mainly LMP for discovery and IAS for name queries. + */ + +/*------------------------------------------------------------------*/ +/* + * Function irnet_getvalue_confirm (result, obj_id, value, priv) + * + * Got answer from remote LM-IAS, just connect + * + * This is the reply to a IAS query we were doing to find the TSAP of + * the device we want to connect to. + * If we have found a valid TSAP, just initiate the TTP connection + * on this TSAP. + */ +static void +irnet_getvalue_confirm(int result, + __u16 obj_id, + struct ias_value *value, + void * priv) +{ + irnet_socket * self = (irnet_socket *) priv; + + DENTER(IRDA_OCB_TRACE, "(self=0x%p)\n", self); + DASSERT(self != NULL, , IRDA_OCB_ERROR, "Self is NULL !!!\n"); + + /* Check if already connected (via irnet_connect_socket()) + * or socket is closing down (via irda_irnet_destroy()) */ + if(! test_bit(0, &self->ttp_connect)) + { + DERROR(IRDA_OCB_ERROR, "Socket no longer connecting. Ouch !\n"); + return; + } + + /* We probably don't need to make any more queries */ + iriap_close(self->iriap); + self->iriap = NULL; + + /* Post process the IAS reply */ + self->dtsap_sel = irnet_ias_to_tsap(self, result, value); + + /* If error, just go out */ + if(self->errno) + { + clear_bit(0, &self->ttp_connect); + DERROR(IRDA_OCB_ERROR, "IAS connect failed ! (0x%X)\n", self->errno); + return; + } + + DEBUG(IRDA_OCB_INFO, "daddr = %08x, lsap = %d, starting IrTTP connection\n", + self->daddr, self->dtsap_sel); + + /* Start up TTP - non blocking */ + irnet_connect_tsap(self); + + DEXIT(IRDA_OCB_TRACE, "\n"); +} + +/*------------------------------------------------------------------*/ +/* + * Function irnet_discovervalue_confirm (result, obj_id, value, priv) + * + * Handle the TSAP discovery procedure state machine. + * Got answer from remote LM-IAS, try next device + * + * We are doing a TSAP discovery procedure, and we got an answer to + * a IAS query we were doing to find the TSAP on one of the address + * in the discovery log. + * + * If we have found a valid TSAP for the first time, save it. If it's + * not the first time we found one, complain. + * + * If we have more addresses in the log, just initiate a new query. + * Note that those query may fail (see irnet_discover_daddr_and_lsap_sel()) + * + * Otherwise, wrap up the procedure (cleanup), check if we have found + * any device and connect to it. + */ +static void +irnet_discovervalue_confirm(int result, + __u16 obj_id, + struct ias_value *value, + void * priv) +{ + irnet_socket * self = (irnet_socket *) priv; + __u8 dtsap_sel; /* TSAP we are looking for */ + + DENTER(IRDA_OCB_TRACE, "(self=0x%p)\n", self); + DASSERT(self != NULL, , IRDA_OCB_ERROR, "Self is NULL !!!\n"); + + /* Check if already connected (via irnet_connect_socket()) + * or socket is closing down (via irda_irnet_destroy()) */ + if(! test_bit(0, &self->ttp_connect)) + { + DERROR(IRDA_OCB_ERROR, "Socket no longer connecting. Ouch !\n"); + return; + } + + /* Post process the IAS reply */ + dtsap_sel = irnet_ias_to_tsap(self, result, value); + + /* Have we got something ? */ + if(self->errno == 0) + { + /* We found the requested service */ + if(self->daddr != DEV_ADDR_ANY) + { + DERROR(IRDA_OCB_ERROR, "More than one device in range supports IrNET...\n"); + } + else + { + /* First time we found that one, save it ! */ + self->daddr = self->discoveries[self->disco_index].daddr; + self->dtsap_sel = dtsap_sel; + } + } + + /* If no failure */ + if((self->errno == -EADDRNOTAVAIL) || (self->errno == 0)) + { + int ret; + + /* Search the next node */ + ret = irnet_discover_next_daddr(self); + if(!ret) + { + /* In this case, the above request was non-blocking. + * We will return here after a while... */ + return; + } + /* In this case, we have processed the last discovery item */ + } + + /* No more queries to be done (failure or last one) */ + + /* We probably don't need to make any more queries */ + iriap_close(self->iriap); + self->iriap = NULL; + + /* No more items : remove the log and signal termination */ + DEBUG(IRDA_OCB_INFO, "Cleaning up log (0x%p)\n", + self->discoveries); + if(self->discoveries != NULL) + { + /* Cleanup our copy of the discovery log */ + kfree(self->discoveries); + self->discoveries = NULL; + } + self->disco_number = -1; + + /* Check out what we found */ + if(self->daddr == DEV_ADDR_ANY) + { + self->daddr = DEV_ADDR_ANY; + clear_bit(0, &self->ttp_connect); + DEXIT(IRDA_OCB_TRACE, ": cannot discover IrNET in any device !!!\n"); + return; + } + + /* We have a valid address - just connect */ + + DEBUG(IRDA_OCB_INFO, "daddr = %08x, lsap = %d, starting IrTTP connection\n", + self->daddr, self->dtsap_sel); + + /* Start up TTP - non blocking */ + irnet_connect_tsap(self); + + DEXIT(IRDA_OCB_TRACE, "\n"); +} + +#ifdef DISCOVERY_EVENTS +/*------------------------------------------------------------------*/ +/* + * Function irnet_discovery_indication (discovery) + * + * Got a discovery indication from IrLMP, post an event + * + * Note : IrLMP take care of matching the hint mask for us, and also + * check if it is a "new" node for us... + * + * As IrLMP filter on the IrLAN hint bit, we get both IrLAN and IrNET + * nodes, so it's only at connection time that we will know if the + * node support IrNET, IrLAN or both. The other solution is to check + * in IAS the PNP ids and service name. + * Note : even if a node support IrNET (or IrLAN), it's no guarantee + * that we will be able to connect to it, the node might already be + * busy... + * + * One last thing : in some case, this function will trigger duplicate + * discovery events. On the other hand, we should catch all + * discoveries properly (i.e. not miss one). Filtering duplicate here + * is to messy, so we leave that to user space... + */ +static void +irnet_discovery_indication(discinfo_t * discovery, + DISCOVERY_MODE mode, + void * priv) +{ + irnet_socket * self = &irnet_server.s; + + DENTER(IRDA_OCB_TRACE, "(self=0x%p)\n", self); + DASSERT(priv == &irnet_server, , IRDA_OCB_ERROR, + "Invalid instance (0x%p) !!!\n", priv); + + DEBUG(IRDA_OCB_INFO, "Discovered new IrNET/IrLAN node %s...\n", + discovery->info); + + /* Notify the control channel */ + irnet_post_event(NULL, IRNET_DISCOVER, + discovery->saddr, discovery->daddr, discovery->info, + get_unaligned((__u16 *)discovery->hints)); + + DEXIT(IRDA_OCB_TRACE, "\n"); +} + +/*------------------------------------------------------------------*/ +/* + * Function irnet_expiry_indication (expiry) + * + * Got a expiry indication from IrLMP, post an event + * + * Note : IrLMP take care of matching the hint mask for us, we only + * check if it is a "new" node... + */ +static void +irnet_expiry_indication(discinfo_t * expiry, + DISCOVERY_MODE mode, + void * priv) +{ + irnet_socket * self = &irnet_server.s; + + DENTER(IRDA_OCB_TRACE, "(self=0x%p)\n", self); + DASSERT(priv == &irnet_server, , IRDA_OCB_ERROR, + "Invalid instance (0x%p) !!!\n", priv); + + DEBUG(IRDA_OCB_INFO, "IrNET/IrLAN node %s expired...\n", + expiry->info); + + /* Notify the control channel */ + irnet_post_event(NULL, IRNET_EXPIRE, + expiry->saddr, expiry->daddr, expiry->info, + get_unaligned((__u16 *)expiry->hints)); + + DEXIT(IRDA_OCB_TRACE, "\n"); +} +#endif /* DISCOVERY_EVENTS */ + + +/*********************** PROC ENTRY CALLBACKS ***********************/ +/* + * We create a instance in the /proc filesystem, and here we take care + * of that... + */ + +#ifdef CONFIG_PROC_FS +static int +irnet_proc_show(struct seq_file *m, void *v) +{ + irnet_socket * self; + char * state; + int i = 0; + + /* Get the IrNET server information... */ + seq_printf(m, "IrNET server - "); + seq_printf(m, "IrDA state: %s, ", + (irnet_server.running ? "running" : "dead")); + seq_printf(m, "stsap_sel: %02x, ", irnet_server.s.stsap_sel); + seq_printf(m, "dtsap_sel: %02x\n", irnet_server.s.dtsap_sel); + + /* Do we need to continue ? */ + if(!irnet_server.running) + return 0; + + /* Protect access to the instance list */ + spin_lock_bh(&irnet_server.spinlock); + + /* Get the sockets one by one... */ + self = (irnet_socket *) hashbin_get_first(irnet_server.list); + while(self != NULL) + { + /* Start printing info about the socket. */ + seq_printf(m, "\nIrNET socket %d - ", i++); + + /* First, get the requested configuration */ + seq_printf(m, "Requested IrDA name: \"%s\", ", self->rname); + seq_printf(m, "daddr: %08x, ", self->rdaddr); + seq_printf(m, "saddr: %08x\n", self->rsaddr); + + /* Second, get all the PPP info */ + seq_printf(m, " PPP state: %s", + (self->ppp_open ? "registered" : "unregistered")); + if(self->ppp_open) + { + seq_printf(m, ", unit: ppp%d", + ppp_unit_number(&self->chan)); + seq_printf(m, ", channel: %d", + ppp_channel_index(&self->chan)); + seq_printf(m, ", mru: %d", + self->mru); + /* Maybe add self->flags ? Later... */ + } + + /* Then, get all the IrDA specific info... */ + if(self->ttp_open) + state = "connected"; + else + if(self->tsap != NULL) + state = "connecting"; + else + if(self->iriap != NULL) + state = "searching"; + else + if(self->ttp_connect) + state = "weird"; + else + state = "idle"; + seq_printf(m, "\n IrDA state: %s, ", state); + seq_printf(m, "daddr: %08x, ", self->daddr); + seq_printf(m, "stsap_sel: %02x, ", self->stsap_sel); + seq_printf(m, "dtsap_sel: %02x\n", self->dtsap_sel); + + /* Next socket, please... */ + self = (irnet_socket *) hashbin_get_next(irnet_server.list); + } + + /* Spin lock end */ + spin_unlock_bh(&irnet_server.spinlock); + + return 0; +} + +static int irnet_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, irnet_proc_show, NULL); +} + +static const struct file_operations irnet_proc_fops = { + .owner = THIS_MODULE, + .open = irnet_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; +#endif /* PROC_FS */ + + +/********************** CONFIGURATION/CLEANUP **********************/ +/* + * Initialisation and teardown of the IrDA part, called at module + * insertion and removal... + */ + +/*------------------------------------------------------------------*/ +/* + * Prepare the IrNET layer for operation... + */ +int __init +irda_irnet_init(void) +{ + int err = 0; + + DENTER(MODULE_TRACE, "()\n"); + + /* Pure paranoia - should be redundant */ + memset(&irnet_server, 0, sizeof(struct irnet_root)); + + /* Setup start of irnet instance list */ + irnet_server.list = hashbin_new(HB_NOLOCK); + DABORT(irnet_server.list == NULL, -ENOMEM, + MODULE_ERROR, "Can't allocate hashbin!\n"); + /* Init spinlock for instance list */ + spin_lock_init(&irnet_server.spinlock); + + /* Initialise control channel */ + init_waitqueue_head(&irnet_events.rwait); + irnet_events.index = 0; + /* Init spinlock for event logging */ + spin_lock_init(&irnet_events.spinlock); + +#ifdef CONFIG_PROC_FS + /* Add a /proc file for irnet infos */ + proc_create("irnet", 0, proc_irda, &irnet_proc_fops); +#endif /* CONFIG_PROC_FS */ + + /* Setup the IrNET server */ + err = irnet_setup_server(); + + if(!err) + /* We are no longer functional... */ + irnet_server.running = 1; + + DEXIT(MODULE_TRACE, "\n"); + return err; +} + +/*------------------------------------------------------------------*/ +/* + * Cleanup at exit... + */ +void __exit +irda_irnet_cleanup(void) +{ + DENTER(MODULE_TRACE, "()\n"); + + /* We are no longer there... */ + irnet_server.running = 0; + +#ifdef CONFIG_PROC_FS + /* Remove our /proc file */ + remove_proc_entry("irnet", proc_irda); +#endif /* CONFIG_PROC_FS */ + + /* Remove our IrNET server from existence */ + irnet_destroy_server(); + + /* Remove all instances of IrNET socket still present */ + hashbin_delete(irnet_server.list, (FREE_FUNC) irda_irnet_destroy); + + DEXIT(MODULE_TRACE, "\n"); +} diff --git a/drivers/staging/irda/net/irnet/irnet_irda.h b/drivers/staging/irda/net/irnet/irnet_irda.h new file mode 100644 index 000000000000..3e408952a3f1 --- /dev/null +++ b/drivers/staging/irda/net/irnet/irnet_irda.h @@ -0,0 +1,178 @@ +/* + * IrNET protocol module : Synchronous PPP over an IrDA socket. + * + * Jean II - HPL `00 - <jt@hpl.hp.com> + * + * This file contains all definitions and declarations necessary for the + * IRDA part of the IrNET module (dealing with IrTTP, IrIAS and co). + * This file is a private header, so other modules don't want to know + * what's in there... + */ + +#ifndef IRNET_IRDA_H +#define IRNET_IRDA_H + +/***************************** INCLUDES *****************************/ +/* Please add other headers in irnet.h */ + +#include "irnet.h" /* Module global include */ + +/************************ CONSTANTS & MACROS ************************/ + +/* + * Name of the service (socket name) used by IrNET + */ +/* IAS object name (or part of it) */ +#define IRNET_SERVICE_NAME "IrNetv1" +/* IAS attribute */ +#define IRNET_IAS_VALUE "IrDA:TinyTP:LsapSel" +/* LMP notify name for client (only for /proc/net/irda/irlmp) */ +#define IRNET_NOTIFY_NAME "IrNET socket" +/* LMP notify name for server (only for /proc/net/irda/irlmp) */ +#define IRNET_NOTIFY_NAME_SERV "IrNET server" + +/****************************** TYPES ******************************/ + +/* + * This is the main structure where we store all the data pertaining to + * the IrNET server (listen for connection requests) and the root + * of the IrNET socket list + */ +typedef struct irnet_root +{ + irnet_socket s; /* To pretend we are a client... */ + + /* Generic stuff */ + int magic; /* Paranoia */ + int running; /* Are we operational ? */ + + /* Link list of all IrNET instances opened */ + hashbin_t * list; + spinlock_t spinlock; /* Serialize access to the list */ + /* Note : the way hashbin has been designed is absolutely not + * reentrant, beware... So, we blindly protect all with spinlock */ + + /* Handle for the hint bit advertised in IrLMP */ + void * skey; + + /* Server socket part */ + struct ias_object * ias_obj; /* Our service name + lsap in IAS */ + +} irnet_root; + + +/**************************** PROTOTYPES ****************************/ + +/* ----------------------- CONTROL CHANNEL ----------------------- */ +static void + irnet_post_event(irnet_socket *, + irnet_event, + __u32, + __u32, + char *, + __u16); +/* ----------------------- IRDA SUBROUTINES ----------------------- */ +static inline int + irnet_open_tsap(irnet_socket *); +static inline __u8 + irnet_ias_to_tsap(irnet_socket *, + int, + struct ias_value *); +static inline int + irnet_find_lsap_sel(irnet_socket *); +static inline int + irnet_connect_tsap(irnet_socket *); +static inline int + irnet_discover_next_daddr(irnet_socket *); +static inline int + irnet_discover_daddr_and_lsap_sel(irnet_socket *); +static inline int + irnet_dname_to_daddr(irnet_socket *); +/* ------------------------ SERVER SOCKET ------------------------ */ +static inline int + irnet_daddr_to_dname(irnet_socket *); +static inline irnet_socket * + irnet_find_socket(irnet_socket *); +static inline int + irnet_connect_socket(irnet_socket *, + irnet_socket *, + struct qos_info *, + __u32, + __u8); +static inline void + irnet_disconnect_server(irnet_socket *, + struct sk_buff *); +static inline int + irnet_setup_server(void); +static inline void + irnet_destroy_server(void); +/* ---------------------- IRDA-TTP CALLBACKS ---------------------- */ +static int + irnet_data_indication(void *, /* instance */ + void *, /* sap */ + struct sk_buff *); +static void + irnet_disconnect_indication(void *, + void *, + LM_REASON, + struct sk_buff *); +static void + irnet_connect_confirm(void *, + void *, + struct qos_info *, + __u32, + __u8, + struct sk_buff *); +static void + irnet_flow_indication(void *, + void *, + LOCAL_FLOW); +static void + irnet_status_indication(void *, + LINK_STATUS, + LOCK_STATUS); +static void + irnet_connect_indication(void *, + void *, + struct qos_info *, + __u32, + __u8, + struct sk_buff *); +/* -------------------- IRDA-IAS/LMP CALLBACKS -------------------- */ +static void + irnet_getvalue_confirm(int, + __u16, + struct ias_value *, + void *); +static void + irnet_discovervalue_confirm(int, + __u16, + struct ias_value *, + void *); +#ifdef DISCOVERY_EVENTS +static void + irnet_discovery_indication(discinfo_t *, + DISCOVERY_MODE, + void *); +static void + irnet_expiry_indication(discinfo_t *, + DISCOVERY_MODE, + void *); +#endif + +/**************************** VARIABLES ****************************/ + +/* + * The IrNET server. Listen to connection requests and co... + */ +static struct irnet_root irnet_server; + +/* Control channel stuff (note : extern) */ +struct irnet_ctrl_channel irnet_events; + +/* The /proc/net/irda directory, defined elsewhere... */ +#ifdef CONFIG_PROC_FS +extern struct proc_dir_entry *proc_irda; +#endif /* CONFIG_PROC_FS */ + +#endif /* IRNET_IRDA_H */ diff --git a/drivers/staging/irda/net/irnet/irnet_ppp.c b/drivers/staging/irda/net/irnet/irnet_ppp.c new file mode 100644 index 000000000000..7025dcb853d0 --- /dev/null +++ b/drivers/staging/irda/net/irnet/irnet_ppp.c @@ -0,0 +1,1189 @@ +/* + * IrNET protocol module : Synchronous PPP over an IrDA socket. + * + * Jean II - HPL `00 - <jt@hpl.hp.com> + * + * This file implement the PPP interface and /dev/irnet character device. + * The PPP interface hook to the ppp_generic module, handle all our + * relationship to the PPP code in the kernel (and by extension to pppd), + * and exchange PPP frames with this module (send/receive). + * The /dev/irnet device is used primarily for 2 functions : + * 1) as a stub for pppd (the ppp daemon), so that we can appropriately + * generate PPP sessions (we pretend we are a tty). + * 2) as a control channel (write commands, read events) + */ + +#include <linux/sched/signal.h> +#include <linux/slab.h> + +#include "irnet_ppp.h" /* Private header */ +/* Please put other headers in irnet.h - Thanks */ + +/* Generic PPP callbacks (to call us) */ +static const struct ppp_channel_ops irnet_ppp_ops = { + .start_xmit = ppp_irnet_send, + .ioctl = ppp_irnet_ioctl +}; + +/************************* CONTROL CHANNEL *************************/ +/* + * When a pppd instance is not active on /dev/irnet, it acts as a control + * channel. + * Writing allow to set up the IrDA destination of the IrNET channel, + * and any application may be read events happening in IrNET... + */ + +/*------------------------------------------------------------------*/ +/* + * Write is used to send a command to configure a IrNET channel + * before it is open by pppd. The syntax is : "command argument" + * Currently there is only two defined commands : + * o name : set the requested IrDA nickname of the IrNET peer. + * o addr : set the requested IrDA address of the IrNET peer. + * Note : the code is crude, but effective... + */ +static inline ssize_t +irnet_ctrl_write(irnet_socket * ap, + const char __user *buf, + size_t count) +{ + char command[IRNET_MAX_COMMAND]; + char * start; /* Current command being processed */ + char * next; /* Next command to process */ + int length; /* Length of current command */ + + DENTER(CTRL_TRACE, "(ap=0x%p, count=%zd)\n", ap, count); + + /* Check for overflow... */ + DABORT(count >= IRNET_MAX_COMMAND, -ENOMEM, + CTRL_ERROR, "Too much data !!!\n"); + + /* Get the data in the driver */ + if(copy_from_user(command, buf, count)) + { + DERROR(CTRL_ERROR, "Invalid user space pointer.\n"); + return -EFAULT; + } + + /* Safe terminate the string */ + command[count] = '\0'; + DEBUG(CTRL_INFO, "Command line received is ``%s'' (%zd).\n", + command, count); + + /* Check every commands in the command line */ + next = command; + while(next != NULL) + { + /* Look at the next command */ + start = next; + + /* Scrap whitespaces before the command */ + start = skip_spaces(start); + + /* ',' is our command separator */ + next = strchr(start, ','); + if(next) + { + *next = '\0'; /* Terminate command */ + length = next - start; /* Length */ + next++; /* Skip the '\0' */ + } + else + length = strlen(start); + + DEBUG(CTRL_INFO, "Found command ``%s'' (%d).\n", start, length); + + /* Check if we recognised one of the known command + * We can't use "switch" with strings, so hack with "continue" */ + + /* First command : name -> Requested IrDA nickname */ + if(!strncmp(start, "name", 4)) + { + /* Copy the name only if is included and not "any" */ + if((length > 5) && (strcmp(start + 5, "any"))) + { + /* Strip out trailing whitespaces */ + while(isspace(start[length - 1])) + length--; + + DABORT(length < 5 || length > NICKNAME_MAX_LEN + 5, + -EINVAL, CTRL_ERROR, "Invalid nickname.\n"); + + /* Copy the name for later reuse */ + memcpy(ap->rname, start + 5, length - 5); + ap->rname[length - 5] = '\0'; + } + else + ap->rname[0] = '\0'; + DEBUG(CTRL_INFO, "Got rname = ``%s''\n", ap->rname); + + /* Restart the loop */ + continue; + } + + /* Second command : addr, daddr -> Requested IrDA destination address + * Also process : saddr -> Requested IrDA source address */ + if((!strncmp(start, "addr", 4)) || + (!strncmp(start, "daddr", 5)) || + (!strncmp(start, "saddr", 5))) + { + __u32 addr = DEV_ADDR_ANY; + + /* Copy the address only if is included and not "any" */ + if((length > 5) && (strcmp(start + 5, "any"))) + { + char * begp = start + 5; + char * endp; + + /* Scrap whitespaces before the command */ + begp = skip_spaces(begp); + + /* Convert argument to a number (last arg is the base) */ + addr = simple_strtoul(begp, &endp, 16); + /* Has it worked ? (endp should be start + length) */ + DABORT(endp <= (start + 5), -EINVAL, + CTRL_ERROR, "Invalid address.\n"); + } + /* Which type of address ? */ + if(start[0] == 's') + { + /* Save it */ + ap->rsaddr = addr; + DEBUG(CTRL_INFO, "Got rsaddr = %08x\n", ap->rsaddr); + } + else + { + /* Save it */ + ap->rdaddr = addr; + DEBUG(CTRL_INFO, "Got rdaddr = %08x\n", ap->rdaddr); + } + + /* Restart the loop */ + continue; + } + + /* Other possible command : connect N (number of retries) */ + + /* No command matched -> Failed... */ + DABORT(1, -EINVAL, CTRL_ERROR, "Not a recognised IrNET command.\n"); + } + + /* Success : we have parsed all commands successfully */ + return count; +} + +#ifdef INITIAL_DISCOVERY +/*------------------------------------------------------------------*/ +/* + * Function irnet_get_discovery_log (self) + * + * Query the content on the discovery log if not done + * + * This function query the current content of the discovery log + * at the startup of the event channel and save it in the internal struct. + */ +static void +irnet_get_discovery_log(irnet_socket * ap) +{ + __u16 mask = irlmp_service_to_hint(S_LAN); + + /* Ask IrLMP for the current discovery log */ + ap->discoveries = irlmp_get_discoveries(&ap->disco_number, mask, + DISCOVERY_DEFAULT_SLOTS); + + /* Check if the we got some results */ + if(ap->discoveries == NULL) + ap->disco_number = -1; + + DEBUG(CTRL_INFO, "Got the log (0x%p), size is %d\n", + ap->discoveries, ap->disco_number); +} + +/*------------------------------------------------------------------*/ +/* + * Function irnet_read_discovery_log (self, event) + * + * Read the content on the discovery log + * + * This function dump the current content of the discovery log + * at the startup of the event channel. + * Return 1 if wrote an event on the control channel... + * + * State of the ap->disco_XXX variables : + * Socket creation : discoveries = NULL ; disco_index = 0 ; disco_number = 0 + * While reading : discoveries = ptr ; disco_index = X ; disco_number = Y + * After reading : discoveries = NULL ; disco_index = Y ; disco_number = -1 + */ +static inline int +irnet_read_discovery_log(irnet_socket *ap, char *event, int buf_size) +{ + int done_event = 0; + + DENTER(CTRL_TRACE, "(ap=0x%p, event=0x%p)\n", + ap, event); + + /* Test if we have some work to do or we have already finished */ + if(ap->disco_number == -1) + { + DEBUG(CTRL_INFO, "Already done\n"); + return 0; + } + + /* Test if it's the first time and therefore we need to get the log */ + if(ap->discoveries == NULL) + irnet_get_discovery_log(ap); + + /* Check if we have more item to dump */ + if(ap->disco_index < ap->disco_number) + { + /* Write an event */ + snprintf(event, buf_size, + "Found %08x (%s) behind %08x {hints %02X-%02X}\n", + ap->discoveries[ap->disco_index].daddr, + ap->discoveries[ap->disco_index].info, + ap->discoveries[ap->disco_index].saddr, + ap->discoveries[ap->disco_index].hints[0], + ap->discoveries[ap->disco_index].hints[1]); + DEBUG(CTRL_INFO, "Writing discovery %d : %s\n", + ap->disco_index, ap->discoveries[ap->disco_index].info); + + /* We have an event */ + done_event = 1; + /* Next discovery */ + ap->disco_index++; + } + + /* Check if we have done the last item */ + if(ap->disco_index >= ap->disco_number) + { + /* No more items : remove the log and signal termination */ + DEBUG(CTRL_INFO, "Cleaning up log (0x%p)\n", + ap->discoveries); + if(ap->discoveries != NULL) + { + /* Cleanup our copy of the discovery log */ + kfree(ap->discoveries); + ap->discoveries = NULL; + } + ap->disco_number = -1; + } + + return done_event; +} +#endif /* INITIAL_DISCOVERY */ + +/*------------------------------------------------------------------*/ +/* + * Read is used to get IrNET events + */ +static inline ssize_t +irnet_ctrl_read(irnet_socket * ap, + struct file * file, + char __user * buf, + size_t count) +{ + DECLARE_WAITQUEUE(wait, current); + char event[75]; + ssize_t ret = 0; + + DENTER(CTRL_TRACE, "(ap=0x%p, count=%zd)\n", ap, count); + +#ifdef INITIAL_DISCOVERY + /* Check if we have read the log */ + if (irnet_read_discovery_log(ap, event, sizeof(event))) + { + count = min(strlen(event), count); + if (copy_to_user(buf, event, count)) + { + DERROR(CTRL_ERROR, "Invalid user space pointer.\n"); + return -EFAULT; + } + + DEXIT(CTRL_TRACE, "\n"); + return count; + } +#endif /* INITIAL_DISCOVERY */ + + /* Put ourselves on the wait queue to be woken up */ + add_wait_queue(&irnet_events.rwait, &wait); + set_current_state(TASK_INTERRUPTIBLE); + for(;;) + { + /* If there is unread events */ + ret = 0; + if(ap->event_index != irnet_events.index) + break; + ret = -EAGAIN; + if(file->f_flags & O_NONBLOCK) + break; + ret = -ERESTARTSYS; + if(signal_pending(current)) + break; + /* Yield and wait to be woken up */ + schedule(); + } + __set_current_state(TASK_RUNNING); + remove_wait_queue(&irnet_events.rwait, &wait); + + /* Did we got it ? */ + if(ret != 0) + { + /* No, return the error code */ + DEXIT(CTRL_TRACE, " - ret %zd\n", ret); + return ret; + } + + /* Which event is it ? */ + switch(irnet_events.log[ap->event_index].event) + { + case IRNET_DISCOVER: + snprintf(event, sizeof(event), + "Discovered %08x (%s) behind %08x {hints %02X-%02X}\n", + irnet_events.log[ap->event_index].daddr, + irnet_events.log[ap->event_index].name, + irnet_events.log[ap->event_index].saddr, + irnet_events.log[ap->event_index].hints.byte[0], + irnet_events.log[ap->event_index].hints.byte[1]); + break; + case IRNET_EXPIRE: + snprintf(event, sizeof(event), + "Expired %08x (%s) behind %08x {hints %02X-%02X}\n", + irnet_events.log[ap->event_index].daddr, + irnet_events.log[ap->event_index].name, + irnet_events.log[ap->event_index].saddr, + irnet_events.log[ap->event_index].hints.byte[0], + irnet_events.log[ap->event_index].hints.byte[1]); + break; + case IRNET_CONNECT_TO: + snprintf(event, sizeof(event), "Connected to %08x (%s) on ppp%d\n", + irnet_events.log[ap->event_index].daddr, + irnet_events.log[ap->event_index].name, + irnet_events.log[ap->event_index].unit); + break; + case IRNET_CONNECT_FROM: + snprintf(event, sizeof(event), "Connection from %08x (%s) on ppp%d\n", + irnet_events.log[ap->event_index].daddr, + irnet_events.log[ap->event_index].name, + irnet_events.log[ap->event_index].unit); + break; + case IRNET_REQUEST_FROM: + snprintf(event, sizeof(event), "Request from %08x (%s) behind %08x\n", + irnet_events.log[ap->event_index].daddr, + irnet_events.log[ap->event_index].name, + irnet_events.log[ap->event_index].saddr); + break; + case IRNET_NOANSWER_FROM: + snprintf(event, sizeof(event), "No-answer from %08x (%s) on ppp%d\n", + irnet_events.log[ap->event_index].daddr, + irnet_events.log[ap->event_index].name, + irnet_events.log[ap->event_index].unit); + break; + case IRNET_BLOCKED_LINK: + snprintf(event, sizeof(event), "Blocked link with %08x (%s) on ppp%d\n", + irnet_events.log[ap->event_index].daddr, + irnet_events.log[ap->event_index].name, + irnet_events.log[ap->event_index].unit); + break; + case IRNET_DISCONNECT_FROM: + snprintf(event, sizeof(event), "Disconnection from %08x (%s) on ppp%d\n", + irnet_events.log[ap->event_index].daddr, + irnet_events.log[ap->event_index].name, + irnet_events.log[ap->event_index].unit); + break; + case IRNET_DISCONNECT_TO: + snprintf(event, sizeof(event), "Disconnected to %08x (%s)\n", + irnet_events.log[ap->event_index].daddr, + irnet_events.log[ap->event_index].name); + break; + default: + snprintf(event, sizeof(event), "Bug\n"); + } + /* Increment our event index */ + ap->event_index = (ap->event_index + 1) % IRNET_MAX_EVENTS; + + DEBUG(CTRL_INFO, "Event is :%s", event); + + count = min(strlen(event), count); + if (copy_to_user(buf, event, count)) + { + DERROR(CTRL_ERROR, "Invalid user space pointer.\n"); + return -EFAULT; + } + + DEXIT(CTRL_TRACE, "\n"); + return count; +} + +/*------------------------------------------------------------------*/ +/* + * Poll : called when someone do a select on /dev/irnet. + * Just check if there are new events... + */ +static inline unsigned int +irnet_ctrl_poll(irnet_socket * ap, + struct file * file, + poll_table * wait) +{ + unsigned int mask; + + DENTER(CTRL_TRACE, "(ap=0x%p)\n", ap); + + poll_wait(file, &irnet_events.rwait, wait); + mask = POLLOUT | POLLWRNORM; + /* If there is unread events */ + if(ap->event_index != irnet_events.index) + mask |= POLLIN | POLLRDNORM; +#ifdef INITIAL_DISCOVERY + if(ap->disco_number != -1) + { + /* Test if it's the first time and therefore we need to get the log */ + if(ap->discoveries == NULL) + irnet_get_discovery_log(ap); + /* Recheck */ + if(ap->disco_number != -1) + mask |= POLLIN | POLLRDNORM; + } +#endif /* INITIAL_DISCOVERY */ + + DEXIT(CTRL_TRACE, " - mask=0x%X\n", mask); + return mask; +} + + +/*********************** FILESYSTEM CALLBACKS ***********************/ +/* + * Implement the usual open, read, write functions that will be called + * by the file system when some action is performed on /dev/irnet. + * Most of those actions will in fact be performed by "pppd" or + * the control channel, we just act as a redirector... + */ + +/*------------------------------------------------------------------*/ +/* + * Open : when somebody open /dev/irnet + * We basically create a new instance of irnet and initialise it. + */ +static int +dev_irnet_open(struct inode * inode, + struct file * file) +{ + struct irnet_socket * ap; + int err; + + DENTER(FS_TRACE, "(file=0x%p)\n", file); + +#ifdef SECURE_DEVIRNET + /* This could (should?) be enforced by the permissions on /dev/irnet. */ + if(!capable(CAP_NET_ADMIN)) + return -EPERM; +#endif /* SECURE_DEVIRNET */ + + /* Allocate a private structure for this IrNET instance */ + ap = kzalloc(sizeof(*ap), GFP_KERNEL); + DABORT(ap == NULL, -ENOMEM, FS_ERROR, "Can't allocate struct irnet...\n"); + + /* initialize the irnet structure */ + ap->file = file; + + /* PPP channel setup */ + ap->ppp_open = 0; + ap->chan.private = ap; + ap->chan.ops = &irnet_ppp_ops; + ap->chan.mtu = (2048 - TTP_MAX_HEADER - 2 - PPP_HDRLEN); + ap->chan.hdrlen = 2 + TTP_MAX_HEADER; /* for A/C + Max IrDA hdr */ + /* PPP parameters */ + ap->mru = (2048 - TTP_MAX_HEADER - 2 - PPP_HDRLEN); + ap->xaccm[0] = ~0U; + ap->xaccm[3] = 0x60000000U; + ap->raccm = ~0U; + + /* Setup the IrDA part... */ + err = irda_irnet_create(ap); + if(err) + { + DERROR(FS_ERROR, "Can't setup IrDA link...\n"); + kfree(ap); + + return err; + } + + /* For the control channel */ + ap->event_index = irnet_events.index; /* Cancel all past events */ + + mutex_init(&ap->lock); + + /* Put our stuff where we will be able to find it later */ + file->private_data = ap; + + DEXIT(FS_TRACE, " - ap=0x%p\n", ap); + + return 0; +} + + +/*------------------------------------------------------------------*/ +/* + * Close : when somebody close /dev/irnet + * Destroy the instance of /dev/irnet + */ +static int +dev_irnet_close(struct inode * inode, + struct file * file) +{ + irnet_socket * ap = file->private_data; + + DENTER(FS_TRACE, "(file=0x%p, ap=0x%p)\n", + file, ap); + DABORT(ap == NULL, 0, FS_ERROR, "ap is NULL !!!\n"); + + /* Detach ourselves */ + file->private_data = NULL; + + /* Close IrDA stuff */ + irda_irnet_destroy(ap); + + /* Disconnect from the generic PPP layer if not already done */ + if(ap->ppp_open) + { + DERROR(FS_ERROR, "Channel still registered - deregistering !\n"); + ap->ppp_open = 0; + ppp_unregister_channel(&ap->chan); + } + + kfree(ap); + + DEXIT(FS_TRACE, "\n"); + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * Write does nothing. + * (we receive packet from ppp_generic through ppp_irnet_send()) + */ +static ssize_t +dev_irnet_write(struct file * file, + const char __user *buf, + size_t count, + loff_t * ppos) +{ + irnet_socket * ap = file->private_data; + + DPASS(FS_TRACE, "(file=0x%p, ap=0x%p, count=%zd)\n", + file, ap, count); + DABORT(ap == NULL, -ENXIO, FS_ERROR, "ap is NULL !!!\n"); + + /* If we are connected to ppp_generic, let it handle the job */ + if(ap->ppp_open) + return -EAGAIN; + else + return irnet_ctrl_write(ap, buf, count); +} + +/*------------------------------------------------------------------*/ +/* + * Read doesn't do much either. + * (pppd poll us, but ultimately reads through /dev/ppp) + */ +static ssize_t +dev_irnet_read(struct file * file, + char __user * buf, + size_t count, + loff_t * ppos) +{ + irnet_socket * ap = file->private_data; + + DPASS(FS_TRACE, "(file=0x%p, ap=0x%p, count=%zd)\n", + file, ap, count); + DABORT(ap == NULL, -ENXIO, FS_ERROR, "ap is NULL !!!\n"); + + /* If we are connected to ppp_generic, let it handle the job */ + if(ap->ppp_open) + return -EAGAIN; + else + return irnet_ctrl_read(ap, file, buf, count); +} + +/*------------------------------------------------------------------*/ +/* + * Poll : called when someone do a select on /dev/irnet + */ +static unsigned int +dev_irnet_poll(struct file * file, + poll_table * wait) +{ + irnet_socket * ap = file->private_data; + unsigned int mask; + + DENTER(FS_TRACE, "(file=0x%p, ap=0x%p)\n", + file, ap); + + mask = POLLOUT | POLLWRNORM; + DABORT(ap == NULL, mask, FS_ERROR, "ap is NULL !!!\n"); + + /* If we are connected to ppp_generic, let it handle the job */ + if(!ap->ppp_open) + mask |= irnet_ctrl_poll(ap, file, wait); + + DEXIT(FS_TRACE, " - mask=0x%X\n", mask); + return mask; +} + +/*------------------------------------------------------------------*/ +/* + * IOCtl : Called when someone does some ioctls on /dev/irnet + * This is the way pppd configure us and control us while the PPP + * instance is active. + */ +static long +dev_irnet_ioctl( + struct file * file, + unsigned int cmd, + unsigned long arg) +{ + irnet_socket * ap = file->private_data; + int err; + int val; + void __user *argp = (void __user *)arg; + + DENTER(FS_TRACE, "(file=0x%p, ap=0x%p, cmd=0x%X)\n", + file, ap, cmd); + + /* Basic checks... */ + DASSERT(ap != NULL, -ENXIO, PPP_ERROR, "ap is NULL...\n"); +#ifdef SECURE_DEVIRNET + if(!capable(CAP_NET_ADMIN)) + return -EPERM; +#endif /* SECURE_DEVIRNET */ + + err = -EFAULT; + switch(cmd) + { + /* Set discipline (should be N_SYNC_PPP or N_TTY) */ + case TIOCSETD: + if(get_user(val, (int __user *)argp)) + break; + if((val == N_SYNC_PPP) || (val == N_PPP)) + { + DEBUG(FS_INFO, "Entering PPP discipline.\n"); + /* PPP channel setup (ap->chan in configured in dev_irnet_open())*/ + if (mutex_lock_interruptible(&ap->lock)) + return -EINTR; + + err = ppp_register_channel(&ap->chan); + if(err == 0) + { + /* Our ppp side is active */ + ap->ppp_open = 1; + + DEBUG(FS_INFO, "Trying to establish a connection.\n"); + /* Setup the IrDA link now - may fail... */ + irda_irnet_connect(ap); + } + else + DERROR(FS_ERROR, "Can't setup PPP channel...\n"); + + mutex_unlock(&ap->lock); + } + else + { + /* In theory, should be N_TTY */ + DEBUG(FS_INFO, "Exiting PPP discipline.\n"); + /* Disconnect from the generic PPP layer */ + if (mutex_lock_interruptible(&ap->lock)) + return -EINTR; + + if(ap->ppp_open) + { + ap->ppp_open = 0; + ppp_unregister_channel(&ap->chan); + } + else + DERROR(FS_ERROR, "Channel not registered !\n"); + err = 0; + + mutex_unlock(&ap->lock); + } + break; + + /* Query PPP channel and unit number */ + case PPPIOCGCHAN: + if (mutex_lock_interruptible(&ap->lock)) + return -EINTR; + + if(ap->ppp_open && !put_user(ppp_channel_index(&ap->chan), + (int __user *)argp)) + err = 0; + + mutex_unlock(&ap->lock); + break; + case PPPIOCGUNIT: + if (mutex_lock_interruptible(&ap->lock)) + return -EINTR; + + if(ap->ppp_open && !put_user(ppp_unit_number(&ap->chan), + (int __user *)argp)) + err = 0; + + mutex_unlock(&ap->lock); + break; + + /* All these ioctls can be passed both directly and from ppp_generic, + * so we just deal with them in one place... + */ + case PPPIOCGFLAGS: + case PPPIOCSFLAGS: + case PPPIOCGASYNCMAP: + case PPPIOCSASYNCMAP: + case PPPIOCGRASYNCMAP: + case PPPIOCSRASYNCMAP: + case PPPIOCGXASYNCMAP: + case PPPIOCSXASYNCMAP: + case PPPIOCGMRU: + case PPPIOCSMRU: + DEBUG(FS_INFO, "Standard PPP ioctl.\n"); + if(!capable(CAP_NET_ADMIN)) + err = -EPERM; + else { + if (mutex_lock_interruptible(&ap->lock)) + return -EINTR; + + err = ppp_irnet_ioctl(&ap->chan, cmd, arg); + + mutex_unlock(&ap->lock); + } + break; + + /* TTY IOCTLs : Pretend that we are a tty, to keep pppd happy */ + /* Get termios */ + case TCGETS: + DEBUG(FS_INFO, "Get termios.\n"); + if (mutex_lock_interruptible(&ap->lock)) + return -EINTR; + +#ifndef TCGETS2 + if(!kernel_termios_to_user_termios((struct termios __user *)argp, &ap->termios)) + err = 0; +#else + if(kernel_termios_to_user_termios_1((struct termios __user *)argp, &ap->termios)) + err = 0; +#endif + + mutex_unlock(&ap->lock); + break; + /* Set termios */ + case TCSETSF: + DEBUG(FS_INFO, "Set termios.\n"); + if (mutex_lock_interruptible(&ap->lock)) + return -EINTR; + +#ifndef TCGETS2 + if(!user_termios_to_kernel_termios(&ap->termios, (struct termios __user *)argp)) + err = 0; +#else + if(!user_termios_to_kernel_termios_1(&ap->termios, (struct termios __user *)argp)) + err = 0; +#endif + + mutex_unlock(&ap->lock); + break; + + /* Set DTR/RTS */ + case TIOCMBIS: + case TIOCMBIC: + /* Set exclusive/non-exclusive mode */ + case TIOCEXCL: + case TIOCNXCL: + DEBUG(FS_INFO, "TTY compatibility.\n"); + err = 0; + break; + + case TCGETA: + DEBUG(FS_INFO, "TCGETA\n"); + break; + + case TCFLSH: + DEBUG(FS_INFO, "TCFLSH\n"); + /* Note : this will flush buffers in PPP, so it *must* be done + * We should also worry that we don't accept junk here and that + * we get rid of our own buffers */ +#ifdef FLUSH_TO_PPP + if (mutex_lock_interruptible(&ap->lock)) + return -EINTR; + ppp_output_wakeup(&ap->chan); + mutex_unlock(&ap->lock); +#endif /* FLUSH_TO_PPP */ + err = 0; + break; + + case FIONREAD: + DEBUG(FS_INFO, "FIONREAD\n"); + val = 0; + if(put_user(val, (int __user *)argp)) + break; + err = 0; + break; + + default: + DERROR(FS_ERROR, "Unsupported ioctl (0x%X)\n", cmd); + err = -ENOTTY; + } + + DEXIT(FS_TRACE, " - err = 0x%X\n", err); + return err; +} + +/************************** PPP CALLBACKS **************************/ +/* + * This are the functions that the generic PPP driver in the kernel + * will call to communicate to us. + */ + +/*------------------------------------------------------------------*/ +/* + * Prepare the ppp frame for transmission over the IrDA socket. + * We make sure that the header space is enough, and we change ppp header + * according to flags passed by pppd. + * This is not a callback, but just a helper function used in ppp_irnet_send() + */ +static inline struct sk_buff * +irnet_prepare_skb(irnet_socket * ap, + struct sk_buff * skb) +{ + unsigned char * data; + int proto; /* PPP protocol */ + int islcp; /* Protocol == LCP */ + int needaddr; /* Need PPP address */ + + DENTER(PPP_TRACE, "(ap=0x%p, skb=0x%p)\n", + ap, skb); + + /* Extract PPP protocol from the frame */ + data = skb->data; + proto = (data[0] << 8) + data[1]; + + /* LCP packets with codes between 1 (configure-request) + * and 7 (code-reject) must be sent as though no options + * have been negotiated. */ + islcp = (proto == PPP_LCP) && (1 <= data[2]) && (data[2] <= 7); + + /* compress protocol field if option enabled */ + if((data[0] == 0) && (ap->flags & SC_COMP_PROT) && (!islcp)) + skb_pull(skb,1); + + /* Check if we need address/control fields */ + needaddr = 2*((ap->flags & SC_COMP_AC) == 0 || islcp); + + /* Is the skb headroom large enough to contain all IrDA-headers? */ + if((skb_headroom(skb) < (ap->max_header_size + needaddr)) || + (skb_shared(skb))) + { + struct sk_buff * new_skb; + + DEBUG(PPP_INFO, "Reallocating skb\n"); + + /* Create a new skb */ + new_skb = skb_realloc_headroom(skb, ap->max_header_size + needaddr); + + /* We have to free the original skb anyway */ + dev_kfree_skb(skb); + + /* Did the realloc succeed ? */ + DABORT(new_skb == NULL, NULL, PPP_ERROR, "Could not realloc skb\n"); + + /* Use the new skb instead */ + skb = new_skb; + } + + /* prepend address/control fields if necessary */ + if(needaddr) + { + skb_push(skb, 2); + skb->data[0] = PPP_ALLSTATIONS; + skb->data[1] = PPP_UI; + } + + DEXIT(PPP_TRACE, "\n"); + + return skb; +} + +/*------------------------------------------------------------------*/ +/* + * Send a packet to the peer over the IrTTP connection. + * Returns 1 iff the packet was accepted. + * Returns 0 iff packet was not consumed. + * If the packet was not accepted, we will call ppp_output_wakeup + * at some later time to reactivate flow control in ppp_generic. + */ +static int +ppp_irnet_send(struct ppp_channel * chan, + struct sk_buff * skb) +{ + irnet_socket * self = (struct irnet_socket *) chan->private; + int ret; + + DENTER(PPP_TRACE, "(channel=0x%p, ap/self=0x%p)\n", + chan, self); + + /* Check if things are somewhat valid... */ + DASSERT(self != NULL, 0, PPP_ERROR, "Self is NULL !!!\n"); + + /* Check if we are connected */ + if(!(test_bit(0, &self->ttp_open))) + { +#ifdef CONNECT_IN_SEND + /* Let's try to connect one more time... */ + /* Note : we won't be connected after this call, but we should be + * ready for next packet... */ + /* If we are already connecting, this will fail */ + irda_irnet_connect(self); +#endif /* CONNECT_IN_SEND */ + + DEBUG(PPP_INFO, "IrTTP not ready ! (%ld-%ld)\n", + self->ttp_open, self->ttp_connect); + + /* Note : we can either drop the packet or block the packet. + * + * Blocking the packet allow us a better connection time, + * because by calling ppp_output_wakeup() we can have + * ppp_generic resending the LCP request immediately to us, + * rather than waiting for one of pppd periodic transmission of + * LCP request. + * + * On the other hand, if we block all packet, all those periodic + * transmissions of pppd accumulate in ppp_generic, creating a + * backlog of LCP request. When we eventually connect later on, + * we have to transmit all this backlog before we can connect + * proper (if we don't timeout before). + * + * The current strategy is as follow : + * While we are attempting to connect, we block packets to get + * a better connection time. + * If we fail to connect, we drain the queue and start dropping packets + */ +#ifdef BLOCK_WHEN_CONNECT + /* If we are attempting to connect */ + if(test_bit(0, &self->ttp_connect)) + { + /* Blocking packet, ppp_generic will retry later */ + return 0; + } +#endif /* BLOCK_WHEN_CONNECT */ + + /* Dropping packet, pppd will retry later */ + dev_kfree_skb(skb); + return 1; + } + + /* Check if the queue can accept any packet, otherwise block */ + if(self->tx_flow != FLOW_START) + DRETURN(0, PPP_INFO, "IrTTP queue full (%d skbs)...\n", + skb_queue_len(&self->tsap->tx_queue)); + + /* Prepare ppp frame for transmission */ + skb = irnet_prepare_skb(self, skb); + DABORT(skb == NULL, 1, PPP_ERROR, "Prepare skb for Tx failed.\n"); + + /* Send the packet to IrTTP */ + ret = irttp_data_request(self->tsap, skb); + if(ret < 0) + { + /* + * > IrTTPs tx queue is full, so we just have to + * > drop the frame! You might think that we should + * > just return -1 and don't deallocate the frame, + * > but that is dangerous since it's possible that + * > we have replaced the original skb with a new + * > one with larger headroom, and that would really + * > confuse do_dev_queue_xmit() in dev.c! I have + * > tried :-) DB + * Correction : we verify the flow control above (self->tx_flow), + * so we come here only if IrTTP doesn't like the packet (empty, + * too large, IrTTP not connected). In those rare cases, it's ok + * to drop it, we don't want to see it here again... + * Jean II + */ + DERROR(PPP_ERROR, "IrTTP doesn't like this packet !!! (0x%X)\n", ret); + /* irttp_data_request already free the packet */ + } + + DEXIT(PPP_TRACE, "\n"); + return 1; /* Packet has been consumed */ +} + +/*------------------------------------------------------------------*/ +/* + * Take care of the ioctls that ppp_generic doesn't want to deal with... + * Note : we are also called from dev_irnet_ioctl(). + */ +static int +ppp_irnet_ioctl(struct ppp_channel * chan, + unsigned int cmd, + unsigned long arg) +{ + irnet_socket * ap = (struct irnet_socket *) chan->private; + int err; + int val; + u32 accm[8]; + void __user *argp = (void __user *)arg; + + DENTER(PPP_TRACE, "(channel=0x%p, ap=0x%p, cmd=0x%X)\n", + chan, ap, cmd); + + /* Basic checks... */ + DASSERT(ap != NULL, -ENXIO, PPP_ERROR, "ap is NULL...\n"); + + err = -EFAULT; + switch(cmd) + { + /* PPP flags */ + case PPPIOCGFLAGS: + val = ap->flags | ap->rbits; + if(put_user(val, (int __user *) argp)) + break; + err = 0; + break; + case PPPIOCSFLAGS: + if(get_user(val, (int __user *) argp)) + break; + ap->flags = val & ~SC_RCV_BITS; + ap->rbits = val & SC_RCV_BITS; + err = 0; + break; + + /* Async map stuff - all dummy to please pppd */ + case PPPIOCGASYNCMAP: + if(put_user(ap->xaccm[0], (u32 __user *) argp)) + break; + err = 0; + break; + case PPPIOCSASYNCMAP: + if(get_user(ap->xaccm[0], (u32 __user *) argp)) + break; + err = 0; + break; + case PPPIOCGRASYNCMAP: + if(put_user(ap->raccm, (u32 __user *) argp)) + break; + err = 0; + break; + case PPPIOCSRASYNCMAP: + if(get_user(ap->raccm, (u32 __user *) argp)) + break; + err = 0; + break; + case PPPIOCGXASYNCMAP: + if(copy_to_user(argp, ap->xaccm, sizeof(ap->xaccm))) + break; + err = 0; + break; + case PPPIOCSXASYNCMAP: + if(copy_from_user(accm, argp, sizeof(accm))) + break; + accm[2] &= ~0x40000000U; /* can't escape 0x5e */ + accm[3] |= 0x60000000U; /* must escape 0x7d, 0x7e */ + memcpy(ap->xaccm, accm, sizeof(ap->xaccm)); + err = 0; + break; + + /* Max PPP frame size */ + case PPPIOCGMRU: + if(put_user(ap->mru, (int __user *) argp)) + break; + err = 0; + break; + case PPPIOCSMRU: + if(get_user(val, (int __user *) argp)) + break; + if(val < PPP_MRU) + val = PPP_MRU; + ap->mru = val; + err = 0; + break; + + default: + DEBUG(PPP_INFO, "Unsupported ioctl (0x%X)\n", cmd); + err = -ENOIOCTLCMD; + } + + DEXIT(PPP_TRACE, " - err = 0x%X\n", err); + return err; +} + +/************************** INITIALISATION **************************/ +/* + * Module initialisation and all that jazz... + */ + +/*------------------------------------------------------------------*/ +/* + * Hook our device callbacks in the filesystem, to connect our code + * to /dev/irnet + */ +static inline int __init +ppp_irnet_init(void) +{ + int err = 0; + + DENTER(MODULE_TRACE, "()\n"); + + /* Allocate ourselves as a minor in the misc range */ + err = misc_register(&irnet_misc_device); + + DEXIT(MODULE_TRACE, "\n"); + return err; +} + +/*------------------------------------------------------------------*/ +/* + * Cleanup at exit... + */ +static inline void __exit +ppp_irnet_cleanup(void) +{ + DENTER(MODULE_TRACE, "()\n"); + + /* De-allocate /dev/irnet minor in misc range */ + misc_deregister(&irnet_misc_device); + + DEXIT(MODULE_TRACE, "\n"); +} + +/*------------------------------------------------------------------*/ +/* + * Module main entry point + */ +static int __init +irnet_init(void) +{ + int err; + + /* Initialise both parts... */ + err = irda_irnet_init(); + if(!err) + err = ppp_irnet_init(); + return err; +} + +/*------------------------------------------------------------------*/ +/* + * Module exit + */ +static void __exit +irnet_cleanup(void) +{ + irda_irnet_cleanup(); + ppp_irnet_cleanup(); +} + +/*------------------------------------------------------------------*/ +/* + * Module magic + */ +module_init(irnet_init); +module_exit(irnet_cleanup); +MODULE_AUTHOR("Jean Tourrilhes <jt@hpl.hp.com>"); +MODULE_DESCRIPTION("IrNET : Synchronous PPP over IrDA"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_CHARDEV(10, 187); diff --git a/drivers/staging/irda/net/irnet/irnet_ppp.h b/drivers/staging/irda/net/irnet/irnet_ppp.h new file mode 100644 index 000000000000..32061442cc8e --- /dev/null +++ b/drivers/staging/irda/net/irnet/irnet_ppp.h @@ -0,0 +1,116 @@ +/* + * IrNET protocol module : Synchronous PPP over an IrDA socket. + * + * Jean II - HPL `00 - <jt@hpl.hp.com> + * + * This file contains all definitions and declarations necessary for the + * PPP part of the IrNET module. + * This file is a private header, so other modules don't want to know + * what's in there... + */ + +#ifndef IRNET_PPP_H +#define IRNET_PPP_H + +/***************************** INCLUDES *****************************/ + +#include "irnet.h" /* Module global include */ +#include <linux/miscdevice.h> + +/************************ CONSTANTS & MACROS ************************/ + +/* IrNET control channel stuff */ +#define IRNET_MAX_COMMAND 256 /* Max length of a command line */ + +/* PPP hardcore stuff */ + +/* Bits in rbits (PPP flags in irnet struct) */ +#define SC_RCV_BITS (SC_RCV_B7_1|SC_RCV_B7_0|SC_RCV_ODDP|SC_RCV_EVNP) + +/* Bit numbers in busy */ +#define XMIT_BUSY 0 +#define RECV_BUSY 1 +#define XMIT_WAKEUP 2 +#define XMIT_FULL 3 + +/* Queue management */ +#define PPPSYNC_MAX_RQLEN 32 /* arbitrary */ + +/****************************** TYPES ******************************/ + + +/**************************** PROTOTYPES ****************************/ + +/* ----------------------- CONTROL CHANNEL ----------------------- */ +static inline ssize_t + irnet_ctrl_write(irnet_socket *, + const char *, + size_t); +static inline ssize_t + irnet_ctrl_read(irnet_socket *, + struct file *, + char *, + size_t); +static inline unsigned int + irnet_ctrl_poll(irnet_socket *, + struct file *, + poll_table *); +/* ----------------------- CHARACTER DEVICE ----------------------- */ +static int + dev_irnet_open(struct inode *, /* fs callback : open */ + struct file *), + dev_irnet_close(struct inode *, + struct file *); +static ssize_t + dev_irnet_write(struct file *, + const char __user *, + size_t, + loff_t *), + dev_irnet_read(struct file *, + char __user *, + size_t, + loff_t *); +static unsigned int + dev_irnet_poll(struct file *, + poll_table *); +static long + dev_irnet_ioctl(struct file *, + unsigned int, + unsigned long); +/* ------------------------ PPP INTERFACE ------------------------ */ +static inline struct sk_buff * + irnet_prepare_skb(irnet_socket *, + struct sk_buff *); +static int + ppp_irnet_send(struct ppp_channel *, + struct sk_buff *); +static int + ppp_irnet_ioctl(struct ppp_channel *, + unsigned int, + unsigned long); + +/**************************** VARIABLES ****************************/ + +/* Filesystem callbacks (to call us) */ +static const struct file_operations irnet_device_fops = +{ + .owner = THIS_MODULE, + .read = dev_irnet_read, + .write = dev_irnet_write, + .poll = dev_irnet_poll, + .unlocked_ioctl = dev_irnet_ioctl, + .open = dev_irnet_open, + .release = dev_irnet_close, + .llseek = noop_llseek, + /* Also : llseek, readdir, mmap, flush, fsync, fasync, lock, readv, writev */ +}; + +/* Structure so that the misc major (drivers/char/misc.c) take care of us... */ +static struct miscdevice irnet_misc_device = +{ + .minor = IRNET_MINOR, + .name = "irnet", + .fops = &irnet_device_fops +}; + +#endif /* IRNET_PPP_H */ diff --git a/drivers/staging/irda/net/irnetlink.c b/drivers/staging/irda/net/irnetlink.c new file mode 100644 index 000000000000..7fc340e574cf --- /dev/null +++ b/drivers/staging/irda/net/irnetlink.c @@ -0,0 +1,162 @@ +/* + * IrDA netlink layer, for stack configuration. + * + * Copyright (c) 2007 Samuel Ortiz <samuel@sortiz.org> + * + * Partly based on the 802.11 nelink implementation + * (see net/wireless/nl80211.c) which is: + * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include <linux/socket.h> +#include <linux/irda.h> +#include <linux/gfp.h> +#include <net/net_namespace.h> +#include <net/sock.h> +#include <net/irda/irda.h> +#include <net/irda/irlap.h> +#include <net/genetlink.h> + + + +static struct genl_family irda_nl_family; + +static struct net_device * ifname_to_netdev(struct net *net, struct genl_info *info) +{ + char * ifname; + + if (!info->attrs[IRDA_NL_ATTR_IFNAME]) + return NULL; + + ifname = nla_data(info->attrs[IRDA_NL_ATTR_IFNAME]); + + pr_debug("%s(): Looking for %s\n", __func__, ifname); + + return dev_get_by_name(net, ifname); +} + +static int irda_nl_set_mode(struct sk_buff *skb, struct genl_info *info) +{ + struct net_device * dev; + struct irlap_cb * irlap; + u32 mode; + + if (!info->attrs[IRDA_NL_ATTR_MODE]) + return -EINVAL; + + mode = nla_get_u32(info->attrs[IRDA_NL_ATTR_MODE]); + + pr_debug("%s(): Switching to mode: %d\n", __func__, mode); + + dev = ifname_to_netdev(&init_net, info); + if (!dev) + return -ENODEV; + + irlap = (struct irlap_cb *)dev->atalk_ptr; + if (!irlap) { + dev_put(dev); + return -ENODEV; + } + + irlap->mode = mode; + + dev_put(dev); + + return 0; +} + +static int irda_nl_get_mode(struct sk_buff *skb, struct genl_info *info) +{ + struct net_device * dev; + struct irlap_cb * irlap; + struct sk_buff *msg; + void *hdr; + int ret = -ENOBUFS; + + dev = ifname_to_netdev(&init_net, info); + if (!dev) + return -ENODEV; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!msg) { + dev_put(dev); + return -ENOMEM; + } + + irlap = (struct irlap_cb *)dev->atalk_ptr; + if (!irlap) { + ret = -ENODEV; + goto err_out; + } + + hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq, + &irda_nl_family, 0, IRDA_NL_CMD_GET_MODE); + if (hdr == NULL) { + ret = -EMSGSIZE; + goto err_out; + } + + if(nla_put_string(msg, IRDA_NL_ATTR_IFNAME, + dev->name)) + goto err_out; + + if(nla_put_u32(msg, IRDA_NL_ATTR_MODE, irlap->mode)) + goto err_out; + + genlmsg_end(msg, hdr); + + return genlmsg_reply(msg, info); + + err_out: + nlmsg_free(msg); + dev_put(dev); + + return ret; +} + +static const struct nla_policy irda_nl_policy[IRDA_NL_ATTR_MAX + 1] = { + [IRDA_NL_ATTR_IFNAME] = { .type = NLA_NUL_STRING, + .len = IFNAMSIZ-1 }, + [IRDA_NL_ATTR_MODE] = { .type = NLA_U32 }, +}; + +static const struct genl_ops irda_nl_ops[] = { + { + .cmd = IRDA_NL_CMD_SET_MODE, + .doit = irda_nl_set_mode, + .policy = irda_nl_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = IRDA_NL_CMD_GET_MODE, + .doit = irda_nl_get_mode, + .policy = irda_nl_policy, + /* can be retrieved by unprivileged users */ + }, + +}; + +static struct genl_family irda_nl_family __ro_after_init = { + .name = IRDA_NL_NAME, + .hdrsize = 0, + .version = IRDA_NL_VERSION, + .maxattr = IRDA_NL_CMD_MAX, + .module = THIS_MODULE, + .ops = irda_nl_ops, + .n_ops = ARRAY_SIZE(irda_nl_ops), +}; + +int __init irda_nl_register(void) +{ + return genl_register_family(&irda_nl_family); +} + +void irda_nl_unregister(void) +{ + genl_unregister_family(&irda_nl_family); +} diff --git a/drivers/staging/irda/net/irproc.c b/drivers/staging/irda/net/irproc.c new file mode 100644 index 000000000000..77cfdde9d82f --- /dev/null +++ b/drivers/staging/irda/net/irproc.c @@ -0,0 +1,96 @@ +/********************************************************************* + * + * Filename: irproc.c + * Version: 1.0 + * Description: Various entries in the /proc file system + * Status: Experimental. + * Author: Thomas Davis, <ratbert@radiks.net> + * Created at: Sat Feb 21 21:33:24 1998 + * Modified at: Sun Nov 14 08:54:54 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1998-1999, Dag Brattli <dagb@cs.uit.no> + * Copyright (c) 1998, Thomas Davis, <ratbert@radiks.net>, + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * I, Thomas Davis, provide no warranty for any of this software. + * This material is provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#include <linux/proc_fs.h> +#include <linux/seq_file.h> +#include <linux/module.h> +#include <linux/init.h> +#include <net/net_namespace.h> + +#include <net/irda/irda.h> +#include <net/irda/irlap.h> +#include <net/irda/irlmp.h> + +extern const struct file_operations discovery_seq_fops; +extern const struct file_operations irlap_seq_fops; +extern const struct file_operations irlmp_seq_fops; +extern const struct file_operations irttp_seq_fops; +extern const struct file_operations irias_seq_fops; + +struct irda_entry { + const char *name; + const struct file_operations *fops; +}; + +struct proc_dir_entry *proc_irda; +EXPORT_SYMBOL(proc_irda); + +static const struct irda_entry irda_dirs[] = { + {"discovery", &discovery_seq_fops}, + {"irttp", &irttp_seq_fops}, + {"irlmp", &irlmp_seq_fops}, + {"irlap", &irlap_seq_fops}, + {"irias", &irias_seq_fops}, +}; + +/* + * Function irda_proc_register (void) + * + * Register irda entry in /proc file system + * + */ +void __init irda_proc_register(void) +{ + int i; + + proc_irda = proc_mkdir("irda", init_net.proc_net); + if (proc_irda == NULL) + return; + + for (i = 0; i < ARRAY_SIZE(irda_dirs); i++) + (void) proc_create(irda_dirs[i].name, 0, proc_irda, + irda_dirs[i].fops); +} + +/* + * Function irda_proc_unregister (void) + * + * Unregister irda entry in /proc file system + * + */ +void irda_proc_unregister(void) +{ + int i; + + if (proc_irda) { + for (i=0; i<ARRAY_SIZE(irda_dirs); i++) + remove_proc_entry(irda_dirs[i].name, proc_irda); + + remove_proc_entry("irda", init_net.proc_net); + proc_irda = NULL; + } +} + + diff --git a/drivers/staging/irda/net/irqueue.c b/drivers/staging/irda/net/irqueue.c new file mode 100644 index 000000000000..160dc89335e2 --- /dev/null +++ b/drivers/staging/irda/net/irqueue.c @@ -0,0 +1,911 @@ +/********************************************************************* + * + * Filename: irqueue.c + * Version: 0.3 + * Description: General queue implementation + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Tue Jun 9 13:29:31 1998 + * Modified at: Sun Dec 12 13:48:22 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * Modified at: Thu Jan 4 14:29:10 CET 2001 + * Modified by: Marc Zyngier <mzyngier@freesurf.fr> + * + * Copyright (C) 1998-1999, Aage Kvalnes <aage@cs.uit.no> + * Copyright (C) 1998, Dag Brattli, + * All Rights Reserved. + * + * This code is taken from the Vortex Operating System written by Aage + * Kvalnes. Aage has agreed that this code can use the GPL licence, + * although he does not use that licence in his own code. + * + * This copyright does however _not_ include the ELF hash() function + * which I currently don't know which licence or copyright it + * has. Please inform me if you know. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +/* + * NOTE : + * There are various problems with this package : + * o the hash function for ints is pathetic (but could be changed) + * o locking is sometime suspicious (especially during enumeration) + * o most users have only a few elements (== overhead) + * o most users never use search, so don't benefit from hashing + * Problem already fixed : + * o not 64 bit compliant (most users do hashv = (int) self) + * o hashbin_remove() is broken => use hashbin_remove_this() + * I think most users would be better served by a simple linked list + * (like include/linux/list.h) with a global spinlock per list. + * Jean II + */ + +/* + * Notes on the concurrent access to hashbin and other SMP issues + * ------------------------------------------------------------- + * Hashbins are very often in the IrDA stack a global repository of + * information, and therefore used in a very asynchronous manner following + * various events (driver calls, timers, user calls...). + * Therefore, very often it is highly important to consider the + * management of concurrent access to the hashbin and how to guarantee the + * consistency of the operations on it. + * + * First, we need to define the objective of locking : + * 1) Protect user data (content pointed by the hashbin) + * 2) Protect hashbin structure itself (linked list in each bin) + * + * OLD LOCKING + * ----------- + * + * The previous locking strategy, either HB_LOCAL or HB_GLOBAL were + * both inadequate in *both* aspect. + * o HB_GLOBAL was using a spinlock for each bin (local locking). + * o HB_LOCAL was disabling irq on *all* CPUs, so use a single + * global semaphore. + * The problems were : + * A) Global irq disabling is no longer supported by the kernel + * B) No protection for the hashbin struct global data + * o hashbin_delete() + * o hb_current + * C) No protection for user data in some cases + * + * A) HB_LOCAL use global irq disabling, so doesn't work on kernel + * 2.5.X. Even when it is supported (kernel 2.4.X and earlier), its + * performance is not satisfactory on SMP setups. Most hashbins were + * HB_LOCAL, so (A) definitely need fixing. + * B) HB_LOCAL could be modified to fix (B). However, because HB_GLOBAL + * lock only the individual bins, it will never be able to lock the + * global data, so can't do (B). + * C) Some functions return pointer to data that is still in the + * hashbin : + * o hashbin_find() + * o hashbin_get_first() + * o hashbin_get_next() + * As the data is still in the hashbin, it may be changed or free'd + * while the caller is examinimg the data. In those case, locking can't + * be done within the hashbin, but must include use of the data within + * the caller. + * The caller can easily do this with HB_LOCAL (just disable irqs). + * However, this is impossible with HB_GLOBAL because the caller has no + * way to know the proper bin, so don't know which spinlock to use. + * + * Quick summary : can no longer use HB_LOCAL, and HB_GLOBAL is + * fundamentally broken and will never work. + * + * NEW LOCKING + * ----------- + * + * To fix those problems, I've introduce a few changes in the + * hashbin locking : + * 1) New HB_LOCK scheme + * 2) hashbin->hb_spinlock + * 3) New hashbin usage policy + * + * HB_LOCK : + * ------- + * HB_LOCK is a locking scheme intermediate between the old HB_LOCAL + * and HB_GLOBAL. It uses a single spinlock to protect the whole content + * of the hashbin. As it is a single spinlock, it can protect the global + * data of the hashbin and not only the bins themselves. + * HB_LOCK can only protect some of the hashbin calls, so it only lock + * call that can be made 100% safe and leave other call unprotected. + * HB_LOCK in theory is slower than HB_GLOBAL, but as the hashbin + * content is always small contention is not high, so it doesn't matter + * much. HB_LOCK is probably faster than HB_LOCAL. + * + * hashbin->hb_spinlock : + * -------------------- + * The spinlock that HB_LOCK uses is available for caller, so that + * the caller can protect unprotected calls (see below). + * If the caller want to do entirely its own locking (HB_NOLOCK), he + * can do so and may use safely this spinlock. + * Locking is done like this : + * spin_lock_irqsave(&hashbin->hb_spinlock, flags); + * Releasing the lock : + * spin_unlock_irqrestore(&hashbin->hb_spinlock, flags); + * + * Safe & Protected calls : + * ---------------------- + * The following calls are safe or protected via HB_LOCK : + * o hashbin_new() -> safe + * o hashbin_delete() + * o hashbin_insert() + * o hashbin_remove_first() + * o hashbin_remove() + * o hashbin_remove_this() + * o HASHBIN_GET_SIZE() -> atomic + * + * The following calls only protect the hashbin itself : + * o hashbin_lock_find() + * o hashbin_find_next() + * + * Unprotected calls : + * ----------------- + * The following calls need to be protected by the caller : + * o hashbin_find() + * o hashbin_get_first() + * o hashbin_get_next() + * + * Locking Policy : + * -------------- + * If the hashbin is used only in a single thread of execution + * (explicitly or implicitely), you can use HB_NOLOCK + * If the calling module already provide concurrent access protection, + * you may use HB_NOLOCK. + * + * In all other cases, you need to use HB_LOCK and lock the hashbin + * every time before calling one of the unprotected calls. You also must + * use the pointer returned by the unprotected call within the locked + * region. + * + * Extra care for enumeration : + * -------------------------- + * hashbin_get_first() and hashbin_get_next() use the hashbin to + * store the current position, in hb_current. + * As long as the hashbin remains locked, this is safe. If you unlock + * the hashbin, the current position may change if anybody else modify + * or enumerate the hashbin. + * Summary : do the full enumeration while locked. + * + * Alternatively, you may use hashbin_find_next(). But, this will + * be slower, is more complex to use and doesn't protect the hashbin + * content. So, care is needed here as well. + * + * Other issues : + * ------------ + * I believe that we are overdoing it by using spin_lock_irqsave() + * and we should use only spin_lock_bh() or similar. But, I don't have + * the balls to try it out. + * Don't believe that because hashbin are now (somewhat) SMP safe + * that the rest of the code is. Higher layers tend to be safest, + * but LAP and LMP would need some serious dedicated love. + * + * Jean II + */ +#include <linux/module.h> +#include <linux/slab.h> + +#include <net/irda/irda.h> +#include <net/irda/irqueue.h> + +/************************ QUEUE SUBROUTINES ************************/ + +/* + * Hashbin + */ +#define GET_HASHBIN(x) ( x & HASHBIN_MASK ) + +/* + * Function hash (name) + * + * This function hash the input string 'name' using the ELF hash + * function for strings. + */ +static __u32 hash( const char* name) +{ + __u32 h = 0; + __u32 g; + + while(*name) { + h = (h<<4) + *name++; + if ((g = (h & 0xf0000000))) + h ^=g>>24; + h &=~g; + } + return h; +} + +/* + * Function enqueue_first (queue, proc) + * + * Insert item first in queue. + * + */ +static void enqueue_first(irda_queue_t **queue, irda_queue_t* element) +{ + + /* + * Check if queue is empty. + */ + if ( *queue == NULL ) { + /* + * Queue is empty. Insert one element into the queue. + */ + element->q_next = element->q_prev = *queue = element; + + } else { + /* + * Queue is not empty. Insert element into front of queue. + */ + element->q_next = (*queue); + (*queue)->q_prev->q_next = element; + element->q_prev = (*queue)->q_prev; + (*queue)->q_prev = element; + (*queue) = element; + } +} + + +/* + * Function dequeue (queue) + * + * Remove first entry in queue + * + */ +static irda_queue_t *dequeue_first(irda_queue_t **queue) +{ + irda_queue_t *ret; + + pr_debug("dequeue_first()\n"); + + /* + * Set return value + */ + ret = *queue; + + if ( *queue == NULL ) { + /* + * Queue was empty. + */ + } else if ( (*queue)->q_next == *queue ) { + /* + * Queue only contained a single element. It will now be + * empty. + */ + *queue = NULL; + } else { + /* + * Queue contained several element. Remove the first one. + */ + (*queue)->q_prev->q_next = (*queue)->q_next; + (*queue)->q_next->q_prev = (*queue)->q_prev; + *queue = (*queue)->q_next; + } + + /* + * Return the removed entry (or NULL of queue was empty). + */ + return ret; +} + +/* + * Function dequeue_general (queue, element) + * + * + */ +static irda_queue_t *dequeue_general(irda_queue_t **queue, irda_queue_t* element) +{ + irda_queue_t *ret; + + pr_debug("dequeue_general()\n"); + + /* + * Set return value + */ + ret = *queue; + + if ( *queue == NULL ) { + /* + * Queue was empty. + */ + } else if ( (*queue)->q_next == *queue ) { + /* + * Queue only contained a single element. It will now be + * empty. + */ + *queue = NULL; + + } else { + /* + * Remove specific element. + */ + element->q_prev->q_next = element->q_next; + element->q_next->q_prev = element->q_prev; + if ( (*queue) == element) + (*queue) = element->q_next; + } + + /* + * Return the removed entry (or NULL of queue was empty). + */ + return ret; +} + +/************************ HASHBIN MANAGEMENT ************************/ + +/* + * Function hashbin_create ( type, name ) + * + * Create hashbin! + * + */ +hashbin_t *hashbin_new(int type) +{ + hashbin_t* hashbin; + + /* + * Allocate new hashbin + */ + hashbin = kzalloc(sizeof(*hashbin), GFP_ATOMIC); + if (!hashbin) + return NULL; + + /* + * Initialize structure + */ + hashbin->hb_type = type; + hashbin->magic = HB_MAGIC; + //hashbin->hb_current = NULL; + + /* Make sure all spinlock's are unlocked */ + if ( hashbin->hb_type & HB_LOCK ) { + spin_lock_init(&hashbin->hb_spinlock); + } + + return hashbin; +} +EXPORT_SYMBOL(hashbin_new); + + +/* + * Function hashbin_delete (hashbin, free_func) + * + * Destroy hashbin, the free_func can be a user supplied special routine + * for deallocating this structure if it's complex. If not the user can + * just supply kfree, which should take care of the job. + */ +int hashbin_delete( hashbin_t* hashbin, FREE_FUNC free_func) +{ + irda_queue_t* queue; + unsigned long flags = 0; + int i; + + IRDA_ASSERT(hashbin != NULL, return -1;); + IRDA_ASSERT(hashbin->magic == HB_MAGIC, return -1;); + + /* Synchronize */ + if (hashbin->hb_type & HB_LOCK) + spin_lock_irqsave(&hashbin->hb_spinlock, flags); + + /* + * Free the entries in the hashbin, TODO: use hashbin_clear when + * it has been shown to work + */ + for (i = 0; i < HASHBIN_SIZE; i ++ ) { + while (1) { + queue = dequeue_first((irda_queue_t**) &hashbin->hb_queue[i]); + + if (!queue) + break; + + if (free_func) { + if (hashbin->hb_type & HB_LOCK) + spin_unlock_irqrestore(&hashbin->hb_spinlock, flags); + free_func(queue); + if (hashbin->hb_type & HB_LOCK) + spin_lock_irqsave(&hashbin->hb_spinlock, flags); + } + } + } + + /* Cleanup local data */ + hashbin->hb_current = NULL; + hashbin->magic = ~HB_MAGIC; + + /* Release lock */ + if (hashbin->hb_type & HB_LOCK) + spin_unlock_irqrestore(&hashbin->hb_spinlock, flags); + + /* + * Free the hashbin structure + */ + kfree(hashbin); + + return 0; +} +EXPORT_SYMBOL(hashbin_delete); + +/********************* HASHBIN LIST OPERATIONS *********************/ + +/* + * Function hashbin_insert (hashbin, entry, name) + * + * Insert an entry into the hashbin + * + */ +void hashbin_insert(hashbin_t* hashbin, irda_queue_t* entry, long hashv, + const char* name) +{ + unsigned long flags = 0; + int bin; + + IRDA_ASSERT( hashbin != NULL, return;); + IRDA_ASSERT( hashbin->magic == HB_MAGIC, return;); + + /* + * Locate hashbin + */ + if ( name ) + hashv = hash( name ); + bin = GET_HASHBIN( hashv ); + + /* Synchronize */ + if ( hashbin->hb_type & HB_LOCK ) { + spin_lock_irqsave(&hashbin->hb_spinlock, flags); + } /* Default is no-lock */ + + /* + * Store name and key + */ + entry->q_hash = hashv; + if ( name ) + strlcpy( entry->q_name, name, sizeof(entry->q_name)); + + /* + * Insert new entry first + */ + enqueue_first( (irda_queue_t**) &hashbin->hb_queue[ bin ], + entry); + hashbin->hb_size++; + + /* Release lock */ + if ( hashbin->hb_type & HB_LOCK ) { + spin_unlock_irqrestore(&hashbin->hb_spinlock, flags); + } /* Default is no-lock */ +} +EXPORT_SYMBOL(hashbin_insert); + +/* + * Function hashbin_remove_first (hashbin) + * + * Remove first entry of the hashbin + * + * Note : this function no longer use hashbin_remove(), but does things + * similar to hashbin_remove_this(), so can be considered safe. + * Jean II + */ +void *hashbin_remove_first( hashbin_t *hashbin) +{ + unsigned long flags = 0; + irda_queue_t *entry = NULL; + + /* Synchronize */ + if ( hashbin->hb_type & HB_LOCK ) { + spin_lock_irqsave(&hashbin->hb_spinlock, flags); + } /* Default is no-lock */ + + entry = hashbin_get_first( hashbin); + if ( entry != NULL) { + int bin; + long hashv; + /* + * Locate hashbin + */ + hashv = entry->q_hash; + bin = GET_HASHBIN( hashv ); + + /* + * Dequeue the entry... + */ + dequeue_general( (irda_queue_t**) &hashbin->hb_queue[ bin ], + entry); + hashbin->hb_size--; + entry->q_next = NULL; + entry->q_prev = NULL; + + /* + * Check if this item is the currently selected item, and in + * that case we must reset hb_current + */ + if ( entry == hashbin->hb_current) + hashbin->hb_current = NULL; + } + + /* Release lock */ + if ( hashbin->hb_type & HB_LOCK ) { + spin_unlock_irqrestore(&hashbin->hb_spinlock, flags); + } /* Default is no-lock */ + + return entry; +} + + +/* + * Function hashbin_remove (hashbin, hashv, name) + * + * Remove entry with the given name + * + * The use of this function is highly discouraged, because the whole + * concept behind hashbin_remove() is broken. In many cases, it's not + * possible to guarantee the unicity of the index (either hashv or name), + * leading to removing the WRONG entry. + * The only simple safe use is : + * hashbin_remove(hasbin, (int) self, NULL); + * In other case, you must think hard to guarantee unicity of the index. + * Jean II + */ +void* hashbin_remove( hashbin_t* hashbin, long hashv, const char* name) +{ + int bin, found = FALSE; + unsigned long flags = 0; + irda_queue_t* entry; + + IRDA_ASSERT( hashbin != NULL, return NULL;); + IRDA_ASSERT( hashbin->magic == HB_MAGIC, return NULL;); + + /* + * Locate hashbin + */ + if ( name ) + hashv = hash( name ); + bin = GET_HASHBIN( hashv ); + + /* Synchronize */ + if ( hashbin->hb_type & HB_LOCK ) { + spin_lock_irqsave(&hashbin->hb_spinlock, flags); + } /* Default is no-lock */ + + /* + * Search for entry + */ + entry = hashbin->hb_queue[ bin ]; + if ( entry ) { + do { + /* + * Check for key + */ + if ( entry->q_hash == hashv ) { + /* + * Name compare too? + */ + if ( name ) { + if ( strcmp( entry->q_name, name) == 0) + { + found = TRUE; + break; + } + } else { + found = TRUE; + break; + } + } + entry = entry->q_next; + } while ( entry != hashbin->hb_queue[ bin ] ); + } + + /* + * If entry was found, dequeue it + */ + if ( found ) { + dequeue_general( (irda_queue_t**) &hashbin->hb_queue[ bin ], + entry); + hashbin->hb_size--; + + /* + * Check if this item is the currently selected item, and in + * that case we must reset hb_current + */ + if ( entry == hashbin->hb_current) + hashbin->hb_current = NULL; + } + + /* Release lock */ + if ( hashbin->hb_type & HB_LOCK ) { + spin_unlock_irqrestore(&hashbin->hb_spinlock, flags); + } /* Default is no-lock */ + + + /* Return */ + if ( found ) + return entry; + else + return NULL; + +} +EXPORT_SYMBOL(hashbin_remove); + +/* + * Function hashbin_remove_this (hashbin, entry) + * + * Remove entry with the given name + * + * In some cases, the user of hashbin can't guarantee the unicity + * of either the hashv or name. + * In those cases, using the above function is guaranteed to cause troubles, + * so we use this one instead... + * And by the way, it's also faster, because we skip the search phase ;-) + */ +void* hashbin_remove_this( hashbin_t* hashbin, irda_queue_t* entry) +{ + unsigned long flags = 0; + int bin; + long hashv; + + IRDA_ASSERT( hashbin != NULL, return NULL;); + IRDA_ASSERT( hashbin->magic == HB_MAGIC, return NULL;); + IRDA_ASSERT( entry != NULL, return NULL;); + + /* Synchronize */ + if ( hashbin->hb_type & HB_LOCK ) { + spin_lock_irqsave(&hashbin->hb_spinlock, flags); + } /* Default is no-lock */ + + /* Check if valid and not already removed... */ + if((entry->q_next == NULL) || (entry->q_prev == NULL)) { + entry = NULL; + goto out; + } + + /* + * Locate hashbin + */ + hashv = entry->q_hash; + bin = GET_HASHBIN( hashv ); + + /* + * Dequeue the entry... + */ + dequeue_general( (irda_queue_t**) &hashbin->hb_queue[ bin ], + entry); + hashbin->hb_size--; + entry->q_next = NULL; + entry->q_prev = NULL; + + /* + * Check if this item is the currently selected item, and in + * that case we must reset hb_current + */ + if ( entry == hashbin->hb_current) + hashbin->hb_current = NULL; +out: + /* Release lock */ + if ( hashbin->hb_type & HB_LOCK ) { + spin_unlock_irqrestore(&hashbin->hb_spinlock, flags); + } /* Default is no-lock */ + + return entry; +} +EXPORT_SYMBOL(hashbin_remove_this); + +/*********************** HASHBIN ENUMERATION ***********************/ + +/* + * Function hashbin_common_find (hashbin, hashv, name) + * + * Find item with the given hashv or name + * + */ +void* hashbin_find( hashbin_t* hashbin, long hashv, const char* name ) +{ + int bin; + irda_queue_t* entry; + + pr_debug("hashbin_find()\n"); + + IRDA_ASSERT( hashbin != NULL, return NULL;); + IRDA_ASSERT( hashbin->magic == HB_MAGIC, return NULL;); + + /* + * Locate hashbin + */ + if ( name ) + hashv = hash( name ); + bin = GET_HASHBIN( hashv ); + + /* + * Search for entry + */ + entry = hashbin->hb_queue[ bin]; + if ( entry ) { + do { + /* + * Check for key + */ + if ( entry->q_hash == hashv ) { + /* + * Name compare too? + */ + if ( name ) { + if ( strcmp( entry->q_name, name ) == 0 ) { + return entry; + } + } else { + return entry; + } + } + entry = entry->q_next; + } while ( entry != hashbin->hb_queue[ bin ] ); + } + + return NULL; +} +EXPORT_SYMBOL(hashbin_find); + +/* + * Function hashbin_lock_find (hashbin, hashv, name) + * + * Find item with the given hashv or name + * + * Same, but with spinlock protection... + * I call it safe, but it's only safe with respect to the hashbin, not its + * content. - Jean II + */ +void* hashbin_lock_find( hashbin_t* hashbin, long hashv, const char* name ) +{ + unsigned long flags = 0; + irda_queue_t* entry; + + /* Synchronize */ + spin_lock_irqsave(&hashbin->hb_spinlock, flags); + + /* + * Search for entry + */ + entry = hashbin_find(hashbin, hashv, name); + + /* Release lock */ + spin_unlock_irqrestore(&hashbin->hb_spinlock, flags); + + return entry; +} +EXPORT_SYMBOL(hashbin_lock_find); + +/* + * Function hashbin_find (hashbin, hashv, name, pnext) + * + * Find an item with the given hashv or name, and its successor + * + * This function allow to do concurrent enumerations without the + * need to lock over the whole session, because the caller keep the + * context of the search. On the other hand, it might fail and return + * NULL if the entry is removed. - Jean II + */ +void* hashbin_find_next( hashbin_t* hashbin, long hashv, const char* name, + void ** pnext) +{ + unsigned long flags = 0; + irda_queue_t* entry; + + /* Synchronize */ + spin_lock_irqsave(&hashbin->hb_spinlock, flags); + + /* + * Search for current entry + * This allow to check if the current item is still in the + * hashbin or has been removed. + */ + entry = hashbin_find(hashbin, hashv, name); + + /* + * Trick hashbin_get_next() to return what we want + */ + if(entry) { + hashbin->hb_current = entry; + *pnext = hashbin_get_next( hashbin ); + } else + *pnext = NULL; + + /* Release lock */ + spin_unlock_irqrestore(&hashbin->hb_spinlock, flags); + + return entry; +} + +/* + * Function hashbin_get_first (hashbin) + * + * Get a pointer to first element in hashbin, this function must be + * called before any calls to hashbin_get_next()! + * + */ +irda_queue_t *hashbin_get_first( hashbin_t* hashbin) +{ + irda_queue_t *entry; + int i; + + IRDA_ASSERT( hashbin != NULL, return NULL;); + IRDA_ASSERT( hashbin->magic == HB_MAGIC, return NULL;); + + if ( hashbin == NULL) + return NULL; + + for ( i = 0; i < HASHBIN_SIZE; i ++ ) { + entry = hashbin->hb_queue[ i]; + if ( entry) { + hashbin->hb_current = entry; + return entry; + } + } + /* + * Did not find any item in hashbin + */ + return NULL; +} +EXPORT_SYMBOL(hashbin_get_first); + +/* + * Function hashbin_get_next (hashbin) + * + * Get next item in hashbin. A series of hashbin_get_next() calls must + * be started by a call to hashbin_get_first(). The function returns + * NULL when all items have been traversed + * + * The context of the search is stored within the hashbin, so you must + * protect yourself from concurrent enumerations. - Jean II + */ +irda_queue_t *hashbin_get_next( hashbin_t *hashbin) +{ + irda_queue_t* entry; + int bin; + int i; + + IRDA_ASSERT( hashbin != NULL, return NULL;); + IRDA_ASSERT( hashbin->magic == HB_MAGIC, return NULL;); + + if ( hashbin->hb_current == NULL) { + IRDA_ASSERT( hashbin->hb_current != NULL, return NULL;); + return NULL; + } + entry = hashbin->hb_current->q_next; + bin = GET_HASHBIN( entry->q_hash); + + /* + * Make sure that we are not back at the beginning of the queue + * again + */ + if ( entry != hashbin->hb_queue[ bin ]) { + hashbin->hb_current = entry; + + return entry; + } + + /* + * Check that this is not the last queue in hashbin + */ + if ( bin >= HASHBIN_SIZE) + return NULL; + + /* + * Move to next queue in hashbin + */ + bin++; + for ( i = bin; i < HASHBIN_SIZE; i++ ) { + entry = hashbin->hb_queue[ i]; + if ( entry) { + hashbin->hb_current = entry; + + return entry; + } + } + return NULL; +} +EXPORT_SYMBOL(hashbin_get_next); diff --git a/drivers/staging/irda/net/irsysctl.c b/drivers/staging/irda/net/irsysctl.c new file mode 100644 index 000000000000..873da5e7d428 --- /dev/null +++ b/drivers/staging/irda/net/irsysctl.c @@ -0,0 +1,258 @@ +/********************************************************************* + * + * Filename: irsysctl.c + * Version: 1.0 + * Description: Sysctl interface for IrDA + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Sun May 24 22:12:06 1998 + * Modified at: Fri Jun 4 02:50:15 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1997, 1999 Dag Brattli, All Rights Reserved. + * Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#include <linux/mm.h> +#include <linux/ctype.h> +#include <linux/sysctl.h> +#include <linux/init.h> + +#include <net/irda/irda.h> /* irda_debug */ +#include <net/irda/irlmp.h> +#include <net/irda/timer.h> +#include <net/irda/irias_object.h> + +extern int sysctl_discovery; +extern int sysctl_discovery_slots; +extern int sysctl_discovery_timeout; +extern int sysctl_slot_timeout; +extern int sysctl_fast_poll_increase; +extern char sysctl_devname[]; +extern int sysctl_max_baud_rate; +extern unsigned int sysctl_min_tx_turn_time; +extern unsigned int sysctl_max_tx_data_size; +extern unsigned int sysctl_max_tx_window; +extern int sysctl_max_noreply_time; +extern int sysctl_warn_noreply_time; +extern int sysctl_lap_keepalive_time; + +extern struct irlmp_cb *irlmp; + +/* this is needed for the proc_dointvec_minmax - Jean II */ +static int max_discovery_slots = 16; /* ??? */ +static int min_discovery_slots = 1; +/* IrLAP 6.13.2 says 25ms to 10+70ms - allow higher since some devices + * seems to require it. (from Dag's comment) */ +static int max_slot_timeout = 160; +static int min_slot_timeout = 20; +static int max_max_baud_rate = 16000000; /* See qos.c - IrLAP spec */ +static int min_max_baud_rate = 2400; +static int max_min_tx_turn_time = 10000; /* See qos.c - IrLAP spec */ +static int min_min_tx_turn_time; +static int max_max_tx_data_size = 2048; /* See qos.c - IrLAP spec */ +static int min_max_tx_data_size = 64; +static int max_max_tx_window = 7; /* See qos.c - IrLAP spec */ +static int min_max_tx_window = 1; +static int max_max_noreply_time = 40; /* See qos.c - IrLAP spec */ +static int min_max_noreply_time = 3; +static int max_warn_noreply_time = 3; /* 3s == standard */ +static int min_warn_noreply_time = 1; /* 1s == min WD_TIMER */ +static int max_lap_keepalive_time = 10000; /* 10s */ +static int min_lap_keepalive_time = 100; /* 100us */ +/* For other sysctl, I've no idea of the range. Maybe Dag could help + * us on that - Jean II */ + +static int do_devname(struct ctl_table *table, int write, + void __user *buffer, size_t *lenp, loff_t *ppos) +{ + int ret; + + ret = proc_dostring(table, write, buffer, lenp, ppos); + if (ret == 0 && write) { + struct ias_value *val; + + val = irias_new_string_value(sysctl_devname); + if (val) + irias_object_change_attribute("Device", "DeviceName", val); + } + return ret; +} + + +static int do_discovery(struct ctl_table *table, int write, + void __user *buffer, size_t *lenp, loff_t *ppos) +{ + int ret; + + ret = proc_dointvec(table, write, buffer, lenp, ppos); + if (ret) + return ret; + + if (irlmp == NULL) + return -ENODEV; + + if (sysctl_discovery) + irlmp_start_discovery_timer(irlmp, sysctl_discovery_timeout*HZ); + else + del_timer_sync(&irlmp->discovery_timer); + + return ret; +} + +/* One file */ +static struct ctl_table irda_table[] = { + { + .procname = "discovery", + .data = &sysctl_discovery, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = do_discovery, + }, + { + .procname = "devname", + .data = sysctl_devname, + .maxlen = 65, + .mode = 0644, + .proc_handler = do_devname, + }, +#ifdef CONFIG_IRDA_FAST_RR + { + .procname = "fast_poll_increase", + .data = &sysctl_fast_poll_increase, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec + }, +#endif + { + .procname = "discovery_slots", + .data = &sysctl_discovery_slots, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + .extra1 = &min_discovery_slots, + .extra2 = &max_discovery_slots + }, + { + .procname = "discovery_timeout", + .data = &sysctl_discovery_timeout, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec + }, + { + .procname = "slot_timeout", + .data = &sysctl_slot_timeout, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + .extra1 = &min_slot_timeout, + .extra2 = &max_slot_timeout + }, + { + .procname = "max_baud_rate", + .data = &sysctl_max_baud_rate, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + .extra1 = &min_max_baud_rate, + .extra2 = &max_max_baud_rate + }, + { + .procname = "min_tx_turn_time", + .data = &sysctl_min_tx_turn_time, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + .extra1 = &min_min_tx_turn_time, + .extra2 = &max_min_tx_turn_time + }, + { + .procname = "max_tx_data_size", + .data = &sysctl_max_tx_data_size, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + .extra1 = &min_max_tx_data_size, + .extra2 = &max_max_tx_data_size + }, + { + .procname = "max_tx_window", + .data = &sysctl_max_tx_window, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + .extra1 = &min_max_tx_window, + .extra2 = &max_max_tx_window + }, + { + .procname = "max_noreply_time", + .data = &sysctl_max_noreply_time, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + .extra1 = &min_max_noreply_time, + .extra2 = &max_max_noreply_time + }, + { + .procname = "warn_noreply_time", + .data = &sysctl_warn_noreply_time, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + .extra1 = &min_warn_noreply_time, + .extra2 = &max_warn_noreply_time + }, + { + .procname = "lap_keepalive_time", + .data = &sysctl_lap_keepalive_time, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + .extra1 = &min_lap_keepalive_time, + .extra2 = &max_lap_keepalive_time + }, + { } +}; + +static struct ctl_table_header *irda_table_header; + +/* + * Function irda_sysctl_register (void) + * + * Register our sysctl interface + * + */ +int __init irda_sysctl_register(void) +{ + irda_table_header = register_net_sysctl(&init_net, "net/irda", irda_table); + if (!irda_table_header) + return -ENOMEM; + + return 0; +} + +/* + * Function irda_sysctl_unregister (void) + * + * Unregister our sysctl interface + * + */ +void irda_sysctl_unregister(void) +{ + unregister_net_sysctl_table(irda_table_header); +} + + + diff --git a/drivers/staging/irda/net/irttp.c b/drivers/staging/irda/net/irttp.c new file mode 100644 index 000000000000..b6ab41d5b3a3 --- /dev/null +++ b/drivers/staging/irda/net/irttp.c @@ -0,0 +1,1891 @@ +/********************************************************************* + * + * Filename: irttp.c + * Version: 1.2 + * Description: Tiny Transport Protocol (TTP) implementation + * Status: Stable + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Sun Aug 31 20:14:31 1997 + * Modified at: Wed Jan 5 11:31:27 2000 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>, + * All Rights Reserved. + * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#include <linux/skbuff.h> +#include <linux/init.h> +#include <linux/fs.h> +#include <linux/seq_file.h> +#include <linux/slab.h> +#include <linux/export.h> + +#include <asm/byteorder.h> +#include <asm/unaligned.h> + +#include <net/irda/irda.h> +#include <net/irda/irlap.h> +#include <net/irda/irlmp.h> +#include <net/irda/parameters.h> +#include <net/irda/irttp.h> + +static struct irttp_cb *irttp; + +static void __irttp_close_tsap(struct tsap_cb *self); + +static int irttp_data_indication(void *instance, void *sap, + struct sk_buff *skb); +static int irttp_udata_indication(void *instance, void *sap, + struct sk_buff *skb); +static void irttp_disconnect_indication(void *instance, void *sap, + LM_REASON reason, struct sk_buff *); +static void irttp_connect_indication(void *instance, void *sap, + struct qos_info *qos, __u32 max_sdu_size, + __u8 header_size, struct sk_buff *skb); +static void irttp_connect_confirm(void *instance, void *sap, + struct qos_info *qos, __u32 max_sdu_size, + __u8 header_size, struct sk_buff *skb); +static void irttp_run_tx_queue(struct tsap_cb *self); +static void irttp_run_rx_queue(struct tsap_cb *self); + +static void irttp_flush_queues(struct tsap_cb *self); +static void irttp_fragment_skb(struct tsap_cb *self, struct sk_buff *skb); +static struct sk_buff *irttp_reassemble_skb(struct tsap_cb *self); +static void irttp_todo_expired(unsigned long data); +static int irttp_param_max_sdu_size(void *instance, irda_param_t *param, + int get); + +static void irttp_flow_indication(void *instance, void *sap, LOCAL_FLOW flow); +static void irttp_status_indication(void *instance, + LINK_STATUS link, LOCK_STATUS lock); + +/* Information for parsing parameters in IrTTP */ +static const pi_minor_info_t pi_minor_call_table[] = { + { NULL, 0 }, /* 0x00 */ + { irttp_param_max_sdu_size, PV_INTEGER | PV_BIG_ENDIAN } /* 0x01 */ +}; +static const pi_major_info_t pi_major_call_table[] = { + { pi_minor_call_table, 2 } +}; +static pi_param_info_t param_info = { pi_major_call_table, 1, 0x0f, 4 }; + +/************************ GLOBAL PROCEDURES ************************/ + +/* + * Function irttp_init (void) + * + * Initialize the IrTTP layer. Called by module initialization code + * + */ +int __init irttp_init(void) +{ + irttp = kzalloc(sizeof(struct irttp_cb), GFP_KERNEL); + if (irttp == NULL) + return -ENOMEM; + + irttp->magic = TTP_MAGIC; + + irttp->tsaps = hashbin_new(HB_LOCK); + if (!irttp->tsaps) { + net_err_ratelimited("%s: can't allocate IrTTP hashbin!\n", + __func__); + kfree(irttp); + return -ENOMEM; + } + + return 0; +} + +/* + * Function irttp_cleanup (void) + * + * Called by module destruction/cleanup code + * + */ +void irttp_cleanup(void) +{ + /* Check for main structure */ + IRDA_ASSERT(irttp->magic == TTP_MAGIC, return;); + + /* + * Delete hashbin and close all TSAP instances in it + */ + hashbin_delete(irttp->tsaps, (FREE_FUNC) __irttp_close_tsap); + + irttp->magic = 0; + + /* De-allocate main structure */ + kfree(irttp); + + irttp = NULL; +} + +/*************************** SUBROUTINES ***************************/ + +/* + * Function irttp_start_todo_timer (self, timeout) + * + * Start todo timer. + * + * Made it more effient and unsensitive to race conditions - Jean II + */ +static inline void irttp_start_todo_timer(struct tsap_cb *self, int timeout) +{ + /* Set new value for timer */ + mod_timer(&self->todo_timer, jiffies + timeout); +} + +/* + * Function irttp_todo_expired (data) + * + * Todo timer has expired! + * + * One of the restriction of the timer is that it is run only on the timer + * interrupt which run every 10ms. This mean that even if you set the timer + * with a delay of 0, it may take up to 10ms before it's run. + * So, to minimise latency and keep cache fresh, we try to avoid using + * it as much as possible. + * Note : we can't use tasklets, because they can't be asynchronously + * killed (need user context), and we can't guarantee that here... + * Jean II + */ +static void irttp_todo_expired(unsigned long data) +{ + struct tsap_cb *self = (struct tsap_cb *) data; + + /* Check that we still exist */ + if (!self || self->magic != TTP_TSAP_MAGIC) + return; + + pr_debug("%s(instance=%p)\n", __func__, self); + + /* Try to make some progress, especially on Tx side - Jean II */ + irttp_run_rx_queue(self); + irttp_run_tx_queue(self); + + /* Check if time for disconnect */ + if (test_bit(0, &self->disconnect_pend)) { + /* Check if it's possible to disconnect yet */ + if (skb_queue_empty(&self->tx_queue)) { + /* Make sure disconnect is not pending anymore */ + clear_bit(0, &self->disconnect_pend); /* FALSE */ + + /* Note : self->disconnect_skb may be NULL */ + irttp_disconnect_request(self, self->disconnect_skb, + P_NORMAL); + self->disconnect_skb = NULL; + } else { + /* Try again later */ + irttp_start_todo_timer(self, HZ/10); + + /* No reason to try and close now */ + return; + } + } + + /* Check if it's closing time */ + if (self->close_pend) + /* Finish cleanup */ + irttp_close_tsap(self); +} + +/* + * Function irttp_flush_queues (self) + * + * Flushes (removes all frames) in transitt-buffer (tx_list) + */ +static void irttp_flush_queues(struct tsap_cb *self) +{ + struct sk_buff *skb; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;); + + /* Deallocate frames waiting to be sent */ + while ((skb = skb_dequeue(&self->tx_queue)) != NULL) + dev_kfree_skb(skb); + + /* Deallocate received frames */ + while ((skb = skb_dequeue(&self->rx_queue)) != NULL) + dev_kfree_skb(skb); + + /* Deallocate received fragments */ + while ((skb = skb_dequeue(&self->rx_fragments)) != NULL) + dev_kfree_skb(skb); +} + +/* + * Function irttp_reassemble (self) + * + * Makes a new (continuous) skb of all the fragments in the fragment + * queue + * + */ +static struct sk_buff *irttp_reassemble_skb(struct tsap_cb *self) +{ + struct sk_buff *skb, *frag; + int n = 0; /* Fragment index */ + + IRDA_ASSERT(self != NULL, return NULL;); + IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return NULL;); + + pr_debug("%s(), self->rx_sdu_size=%d\n", __func__, + self->rx_sdu_size); + + skb = dev_alloc_skb(TTP_HEADER + self->rx_sdu_size); + if (!skb) + return NULL; + + /* + * Need to reserve space for TTP header in case this skb needs to + * be requeued in case delivery failes + */ + skb_reserve(skb, TTP_HEADER); + skb_put(skb, self->rx_sdu_size); + + /* + * Copy all fragments to a new buffer + */ + while ((frag = skb_dequeue(&self->rx_fragments)) != NULL) { + skb_copy_to_linear_data_offset(skb, n, frag->data, frag->len); + n += frag->len; + + dev_kfree_skb(frag); + } + + pr_debug("%s(), frame len=%d, rx_sdu_size=%d, rx_max_sdu_size=%d\n", + __func__, n, self->rx_sdu_size, self->rx_max_sdu_size); + /* Note : irttp_run_rx_queue() calculate self->rx_sdu_size + * by summing the size of all fragments, so we should always + * have n == self->rx_sdu_size, except in cases where we + * droped the last fragment (when self->rx_sdu_size exceed + * self->rx_max_sdu_size), where n < self->rx_sdu_size. + * Jean II */ + IRDA_ASSERT(n <= self->rx_sdu_size, n = self->rx_sdu_size;); + + /* Set the new length */ + skb_trim(skb, n); + + self->rx_sdu_size = 0; + + return skb; +} + +/* + * Function irttp_fragment_skb (skb) + * + * Fragments a frame and queues all the fragments for transmission + * + */ +static inline void irttp_fragment_skb(struct tsap_cb *self, + struct sk_buff *skb) +{ + struct sk_buff *frag; + __u8 *frame; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;); + IRDA_ASSERT(skb != NULL, return;); + + /* + * Split frame into a number of segments + */ + while (skb->len > self->max_seg_size) { + pr_debug("%s(), fragmenting ...\n", __func__); + + /* Make new segment */ + frag = alloc_skb(self->max_seg_size+self->max_header_size, + GFP_ATOMIC); + if (!frag) + return; + + skb_reserve(frag, self->max_header_size); + + /* Copy data from the original skb into this fragment. */ + skb_copy_from_linear_data(skb, skb_put(frag, self->max_seg_size), + self->max_seg_size); + + /* Insert TTP header, with the more bit set */ + frame = skb_push(frag, TTP_HEADER); + frame[0] = TTP_MORE; + + /* Hide the copied data from the original skb */ + skb_pull(skb, self->max_seg_size); + + /* Queue fragment */ + skb_queue_tail(&self->tx_queue, frag); + } + /* Queue what is left of the original skb */ + pr_debug("%s(), queuing last segment\n", __func__); + + frame = skb_push(skb, TTP_HEADER); + frame[0] = 0x00; /* Clear more bit */ + + /* Queue fragment */ + skb_queue_tail(&self->tx_queue, skb); +} + +/* + * Function irttp_param_max_sdu_size (self, param) + * + * Handle the MaxSduSize parameter in the connect frames, this function + * will be called both when this parameter needs to be inserted into, and + * extracted from the connect frames + */ +static int irttp_param_max_sdu_size(void *instance, irda_param_t *param, + int get) +{ + struct tsap_cb *self; + + self = instance; + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;); + + if (get) + param->pv.i = self->tx_max_sdu_size; + else + self->tx_max_sdu_size = param->pv.i; + + pr_debug("%s(), MaxSduSize=%d\n", __func__, param->pv.i); + + return 0; +} + +/*************************** CLIENT CALLS ***************************/ +/************************** LMP CALLBACKS **************************/ +/* Everything is happily mixed up. Waiting for next clean up - Jean II */ + +/* + * Initialization, that has to be done on new tsap + * instance allocation and on duplication + */ +static void irttp_init_tsap(struct tsap_cb *tsap) +{ + spin_lock_init(&tsap->lock); + init_timer(&tsap->todo_timer); + + skb_queue_head_init(&tsap->rx_queue); + skb_queue_head_init(&tsap->tx_queue); + skb_queue_head_init(&tsap->rx_fragments); +} + +/* + * Function irttp_open_tsap (stsap, notify) + * + * Create TSAP connection endpoint, + */ +struct tsap_cb *irttp_open_tsap(__u8 stsap_sel, int credit, notify_t *notify) +{ + struct tsap_cb *self; + struct lsap_cb *lsap; + notify_t ttp_notify; + + IRDA_ASSERT(irttp->magic == TTP_MAGIC, return NULL;); + + /* The IrLMP spec (IrLMP 1.1 p10) says that we have the right to + * use only 0x01-0x6F. Of course, we can use LSAP_ANY as well. + * JeanII */ + if ((stsap_sel != LSAP_ANY) && + ((stsap_sel < 0x01) || (stsap_sel >= 0x70))) { + pr_debug("%s(), invalid tsap!\n", __func__); + return NULL; + } + + self = kzalloc(sizeof(struct tsap_cb), GFP_ATOMIC); + if (self == NULL) + return NULL; + + /* Initialize internal objects */ + irttp_init_tsap(self); + + /* Initialise todo timer */ + self->todo_timer.data = (unsigned long) self; + self->todo_timer.function = &irttp_todo_expired; + + /* Initialize callbacks for IrLMP to use */ + irda_notify_init(&ttp_notify); + ttp_notify.connect_confirm = irttp_connect_confirm; + ttp_notify.connect_indication = irttp_connect_indication; + ttp_notify.disconnect_indication = irttp_disconnect_indication; + ttp_notify.data_indication = irttp_data_indication; + ttp_notify.udata_indication = irttp_udata_indication; + ttp_notify.flow_indication = irttp_flow_indication; + if (notify->status_indication != NULL) + ttp_notify.status_indication = irttp_status_indication; + ttp_notify.instance = self; + strncpy(ttp_notify.name, notify->name, NOTIFY_MAX_NAME); + + self->magic = TTP_TSAP_MAGIC; + self->connected = FALSE; + + /* + * Create LSAP at IrLMP layer + */ + lsap = irlmp_open_lsap(stsap_sel, &ttp_notify, 0); + if (lsap == NULL) { + pr_debug("%s: unable to allocate LSAP!!\n", __func__); + __irttp_close_tsap(self); + return NULL; + } + + /* + * If user specified LSAP_ANY as source TSAP selector, then IrLMP + * will replace it with whatever source selector which is free, so + * the stsap_sel we have might not be valid anymore + */ + self->stsap_sel = lsap->slsap_sel; + pr_debug("%s(), stsap_sel=%02x\n", __func__, self->stsap_sel); + + self->notify = *notify; + self->lsap = lsap; + + hashbin_insert(irttp->tsaps, (irda_queue_t *) self, (long) self, NULL); + + if (credit > TTP_RX_MAX_CREDIT) + self->initial_credit = TTP_RX_MAX_CREDIT; + else + self->initial_credit = credit; + + return self; +} +EXPORT_SYMBOL(irttp_open_tsap); + +/* + * Function irttp_close (handle) + * + * Remove an instance of a TSAP. This function should only deal with the + * deallocation of the TSAP, and resetting of the TSAPs values; + * + */ +static void __irttp_close_tsap(struct tsap_cb *self) +{ + /* First make sure we're connected. */ + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;); + + irttp_flush_queues(self); + + del_timer(&self->todo_timer); + + /* This one won't be cleaned up if we are disconnect_pend + close_pend + * and we receive a disconnect_indication */ + if (self->disconnect_skb) + dev_kfree_skb(self->disconnect_skb); + + self->connected = FALSE; + self->magic = ~TTP_TSAP_MAGIC; + + kfree(self); +} + +/* + * Function irttp_close (self) + * + * Remove TSAP from list of all TSAPs and then deallocate all resources + * associated with this TSAP + * + * Note : because we *free* the tsap structure, it is the responsibility + * of the caller to make sure we are called only once and to deal with + * possible race conditions. - Jean II + */ +int irttp_close_tsap(struct tsap_cb *self) +{ + struct tsap_cb *tsap; + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;); + + /* Make sure tsap has been disconnected */ + if (self->connected) { + /* Check if disconnect is not pending */ + if (!test_bit(0, &self->disconnect_pend)) { + net_warn_ratelimited("%s: TSAP still connected!\n", + __func__); + irttp_disconnect_request(self, NULL, P_NORMAL); + } + self->close_pend = TRUE; + irttp_start_todo_timer(self, HZ/10); + + return 0; /* Will be back! */ + } + + tsap = hashbin_remove(irttp->tsaps, (long) self, NULL); + + IRDA_ASSERT(tsap == self, return -1;); + + /* Close corresponding LSAP */ + if (self->lsap) { + irlmp_close_lsap(self->lsap); + self->lsap = NULL; + } + + __irttp_close_tsap(self); + + return 0; +} +EXPORT_SYMBOL(irttp_close_tsap); + +/* + * Function irttp_udata_request (self, skb) + * + * Send unreliable data on this TSAP + * + */ +int irttp_udata_request(struct tsap_cb *self, struct sk_buff *skb) +{ + int ret; + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;); + IRDA_ASSERT(skb != NULL, return -1;); + + /* Take shortcut on zero byte packets */ + if (skb->len == 0) { + ret = 0; + goto err; + } + + /* Check that nothing bad happens */ + if (!self->connected) { + net_warn_ratelimited("%s(), Not connected\n", __func__); + ret = -ENOTCONN; + goto err; + } + + if (skb->len > self->max_seg_size) { + net_err_ratelimited("%s(), UData is too large for IrLAP!\n", + __func__); + ret = -EMSGSIZE; + goto err; + } + + irlmp_udata_request(self->lsap, skb); + self->stats.tx_packets++; + + return 0; + +err: + dev_kfree_skb(skb); + return ret; +} +EXPORT_SYMBOL(irttp_udata_request); + + +/* + * Function irttp_data_request (handle, skb) + * + * Queue frame for transmission. If SAR is enabled, fragement the frame + * and queue the fragments for transmission + */ +int irttp_data_request(struct tsap_cb *self, struct sk_buff *skb) +{ + __u8 *frame; + int ret; + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;); + IRDA_ASSERT(skb != NULL, return -1;); + + pr_debug("%s() : queue len = %d\n", __func__, + skb_queue_len(&self->tx_queue)); + + /* Take shortcut on zero byte packets */ + if (skb->len == 0) { + ret = 0; + goto err; + } + + /* Check that nothing bad happens */ + if (!self->connected) { + net_warn_ratelimited("%s: Not connected\n", __func__); + ret = -ENOTCONN; + goto err; + } + + /* + * Check if SAR is disabled, and the frame is larger than what fits + * inside an IrLAP frame + */ + if ((self->tx_max_sdu_size == 0) && (skb->len > self->max_seg_size)) { + net_err_ratelimited("%s: SAR disabled, and data is too large for IrLAP!\n", + __func__); + ret = -EMSGSIZE; + goto err; + } + + /* + * Check if SAR is enabled, and the frame is larger than the + * TxMaxSduSize + */ + if ((self->tx_max_sdu_size != 0) && + (self->tx_max_sdu_size != TTP_SAR_UNBOUND) && + (skb->len > self->tx_max_sdu_size)) { + net_err_ratelimited("%s: SAR enabled, but data is larger than TxMaxSduSize!\n", + __func__); + ret = -EMSGSIZE; + goto err; + } + /* + * Check if transmit queue is full + */ + if (skb_queue_len(&self->tx_queue) >= TTP_TX_MAX_QUEUE) { + /* + * Give it a chance to empty itself + */ + irttp_run_tx_queue(self); + + /* Drop packet. This error code should trigger the caller + * to resend the data in the client code - Jean II */ + ret = -ENOBUFS; + goto err; + } + + /* Queue frame, or queue frame segments */ + if ((self->tx_max_sdu_size == 0) || (skb->len < self->max_seg_size)) { + /* Queue frame */ + IRDA_ASSERT(skb_headroom(skb) >= TTP_HEADER, return -1;); + frame = skb_push(skb, TTP_HEADER); + frame[0] = 0x00; /* Clear more bit */ + + skb_queue_tail(&self->tx_queue, skb); + } else { + /* + * Fragment the frame, this function will also queue the + * fragments, we don't care about the fact the transmit + * queue may be overfilled by all the segments for a little + * while + */ + irttp_fragment_skb(self, skb); + } + + /* Check if we can accept more data from client */ + if ((!self->tx_sdu_busy) && + (skb_queue_len(&self->tx_queue) > TTP_TX_HIGH_THRESHOLD)) { + /* Tx queue filling up, so stop client. */ + if (self->notify.flow_indication) { + self->notify.flow_indication(self->notify.instance, + self, FLOW_STOP); + } + /* self->tx_sdu_busy is the state of the client. + * Update state after notifying client to avoid + * race condition with irttp_flow_indication(). + * If the queue empty itself after our test but before + * we set the flag, we will fix ourselves below in + * irttp_run_tx_queue(). + * Jean II */ + self->tx_sdu_busy = TRUE; + } + + /* Try to make some progress */ + irttp_run_tx_queue(self); + + return 0; + +err: + dev_kfree_skb(skb); + return ret; +} +EXPORT_SYMBOL(irttp_data_request); + +/* + * Function irttp_run_tx_queue (self) + * + * Transmit packets queued for transmission (if possible) + * + */ +static void irttp_run_tx_queue(struct tsap_cb *self) +{ + struct sk_buff *skb; + unsigned long flags; + int n; + + pr_debug("%s() : send_credit = %d, queue_len = %d\n", + __func__, + self->send_credit, skb_queue_len(&self->tx_queue)); + + /* Get exclusive access to the tx queue, otherwise don't touch it */ + if (irda_lock(&self->tx_queue_lock) == FALSE) + return; + + /* Try to send out frames as long as we have credits + * and as long as LAP is not full. If LAP is full, it will + * poll us through irttp_flow_indication() - Jean II */ + while ((self->send_credit > 0) && + (!irlmp_lap_tx_queue_full(self->lsap)) && + (skb = skb_dequeue(&self->tx_queue))) { + /* + * Since we can transmit and receive frames concurrently, + * the code below is a critical region and we must assure that + * nobody messes with the credits while we update them. + */ + spin_lock_irqsave(&self->lock, flags); + + n = self->avail_credit; + self->avail_credit = 0; + + /* Only room for 127 credits in frame */ + if (n > 127) { + self->avail_credit = n-127; + n = 127; + } + self->remote_credit += n; + self->send_credit--; + + spin_unlock_irqrestore(&self->lock, flags); + + /* + * More bit must be set by the data_request() or fragment() + * functions + */ + skb->data[0] |= (n & 0x7f); + + /* Detach from socket. + * The current skb has a reference to the socket that sent + * it (skb->sk). When we pass it to IrLMP, the skb will be + * stored in in IrLAP (self->wx_list). When we are within + * IrLAP, we lose the notion of socket, so we should not + * have a reference to a socket. So, we drop it here. + * + * Why does it matter ? + * When the skb is freed (kfree_skb), if it is associated + * with a socket, it release buffer space on the socket + * (through sock_wfree() and sock_def_write_space()). + * If the socket no longer exist, we may crash. Hard. + * When we close a socket, we make sure that associated packets + * in IrTTP are freed. However, we have no way to cancel + * the packet that we have passed to IrLAP. So, if a packet + * remains in IrLAP (retry on the link or else) after we + * close the socket, we are dead ! + * Jean II */ + if (skb->sk != NULL) { + /* IrSOCK application, IrOBEX, ... */ + skb_orphan(skb); + } + /* IrCOMM over IrTTP, IrLAN, ... */ + + /* Pass the skb to IrLMP - done */ + irlmp_data_request(self->lsap, skb); + self->stats.tx_packets++; + } + + /* Check if we can accept more frames from client. + * We don't want to wait until the todo timer to do that, and we + * can't use tasklets (grr...), so we are obliged to give control + * to client. That's ok, this test will be true not too often + * (max once per LAP window) and we are called from places + * where we can spend a bit of time doing stuff. - Jean II */ + if ((self->tx_sdu_busy) && + (skb_queue_len(&self->tx_queue) < TTP_TX_LOW_THRESHOLD) && + (!self->close_pend)) { + if (self->notify.flow_indication) + self->notify.flow_indication(self->notify.instance, + self, FLOW_START); + + /* self->tx_sdu_busy is the state of the client. + * We don't really have a race here, but it's always safer + * to update our state after the client - Jean II */ + self->tx_sdu_busy = FALSE; + } + + /* Reset lock */ + self->tx_queue_lock = 0; +} + +/* + * Function irttp_give_credit (self) + * + * Send a dataless flowdata TTP-PDU and give available credit to peer + * TSAP + */ +static inline void irttp_give_credit(struct tsap_cb *self) +{ + struct sk_buff *tx_skb = NULL; + unsigned long flags; + int n; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;); + + pr_debug("%s() send=%d,avail=%d,remote=%d\n", + __func__, + self->send_credit, self->avail_credit, self->remote_credit); + + /* Give credit to peer */ + tx_skb = alloc_skb(TTP_MAX_HEADER, GFP_ATOMIC); + if (!tx_skb) + return; + + /* Reserve space for LMP, and LAP header */ + skb_reserve(tx_skb, LMP_MAX_HEADER); + + /* + * Since we can transmit and receive frames concurrently, + * the code below is a critical region and we must assure that + * nobody messes with the credits while we update them. + */ + spin_lock_irqsave(&self->lock, flags); + + n = self->avail_credit; + self->avail_credit = 0; + + /* Only space for 127 credits in frame */ + if (n > 127) { + self->avail_credit = n - 127; + n = 127; + } + self->remote_credit += n; + + spin_unlock_irqrestore(&self->lock, flags); + + skb_put(tx_skb, 1); + tx_skb->data[0] = (__u8) (n & 0x7f); + + irlmp_data_request(self->lsap, tx_skb); + self->stats.tx_packets++; +} + +/* + * Function irttp_udata_indication (instance, sap, skb) + * + * Received some unit-data (unreliable) + * + */ +static int irttp_udata_indication(void *instance, void *sap, + struct sk_buff *skb) +{ + struct tsap_cb *self; + int err; + + self = instance; + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;); + IRDA_ASSERT(skb != NULL, return -1;); + + self->stats.rx_packets++; + + /* Just pass data to layer above */ + if (self->notify.udata_indication) { + err = self->notify.udata_indication(self->notify.instance, + self, skb); + /* Same comment as in irttp_do_data_indication() */ + if (!err) + return 0; + } + /* Either no handler, or handler returns an error */ + dev_kfree_skb(skb); + + return 0; +} + +/* + * Function irttp_data_indication (instance, sap, skb) + * + * Receive segment from IrLMP. + * + */ +static int irttp_data_indication(void *instance, void *sap, + struct sk_buff *skb) +{ + struct tsap_cb *self; + unsigned long flags; + int n; + + self = instance; + + n = skb->data[0] & 0x7f; /* Extract the credits */ + + self->stats.rx_packets++; + + /* Deal with inbound credit + * Since we can transmit and receive frames concurrently, + * the code below is a critical region and we must assure that + * nobody messes with the credits while we update them. + */ + spin_lock_irqsave(&self->lock, flags); + self->send_credit += n; + if (skb->len > 1) + self->remote_credit--; + spin_unlock_irqrestore(&self->lock, flags); + + /* + * Data or dataless packet? Dataless frames contains only the + * TTP_HEADER. + */ + if (skb->len > 1) { + /* + * We don't remove the TTP header, since we must preserve the + * more bit, so the defragment routing knows what to do + */ + skb_queue_tail(&self->rx_queue, skb); + } else { + /* Dataless flowdata TTP-PDU */ + dev_kfree_skb(skb); + } + + + /* Push data to the higher layer. + * We do it synchronously because running the todo timer for each + * receive packet would be too much overhead and latency. + * By passing control to the higher layer, we run the risk that + * it may take time or grab a lock. Most often, the higher layer + * will only put packet in a queue. + * Anyway, packets are only dripping through the IrDA, so we can + * have time before the next packet. + * Further, we are run from NET_BH, so the worse that can happen is + * us missing the optimal time to send back the PF bit in LAP. + * Jean II */ + irttp_run_rx_queue(self); + + /* We now give credits to peer in irttp_run_rx_queue(). + * We need to send credit *NOW*, otherwise we are going + * to miss the next Tx window. The todo timer may take + * a while before it's run... - Jean II */ + + /* + * If the peer device has given us some credits and we didn't have + * anyone from before, then we need to shedule the tx queue. + * We need to do that because our Tx have stopped (so we may not + * get any LAP flow indication) and the user may be stopped as + * well. - Jean II + */ + if (self->send_credit == n) { + /* Restart pushing stuff to LAP */ + irttp_run_tx_queue(self); + /* Note : we don't want to schedule the todo timer + * because it has horrible latency. No tasklets + * because the tasklet API is broken. - Jean II */ + } + + return 0; +} + +/* + * Function irttp_status_indication (self, reason) + * + * Status_indication, just pass to the higher layer... + * + */ +static void irttp_status_indication(void *instance, + LINK_STATUS link, LOCK_STATUS lock) +{ + struct tsap_cb *self; + + self = instance; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;); + + /* Check if client has already closed the TSAP and gone away */ + if (self->close_pend) + return; + + /* + * Inform service user if he has requested it + */ + if (self->notify.status_indication != NULL) + self->notify.status_indication(self->notify.instance, + link, lock); + else + pr_debug("%s(), no handler\n", __func__); +} + +/* + * Function irttp_flow_indication (self, reason) + * + * Flow_indication : IrLAP tells us to send more data. + * + */ +static void irttp_flow_indication(void *instance, void *sap, LOCAL_FLOW flow) +{ + struct tsap_cb *self; + + self = instance; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;); + + pr_debug("%s(instance=%p)\n", __func__, self); + + /* We are "polled" directly from LAP, and the LAP want to fill + * its Tx window. We want to do our best to send it data, so that + * we maximise the window. On the other hand, we want to limit the + * amount of work here so that LAP doesn't hang forever waiting + * for packets. - Jean II */ + + /* Try to send some packets. Currently, LAP calls us every time + * there is one free slot, so we will send only one packet. + * This allow the scheduler to do its round robin - Jean II */ + irttp_run_tx_queue(self); + + /* Note regarding the interraction with higher layer. + * irttp_run_tx_queue() may call the client when its queue + * start to empty, via notify.flow_indication(). Initially. + * I wanted this to happen in a tasklet, to avoid client + * grabbing the CPU, but we can't use tasklets safely. And timer + * is definitely too slow. + * This will happen only once per LAP window, and usually at + * the third packet (unless window is smaller). LAP is still + * doing mtt and sending first packet so it's sort of OK + * to do that. Jean II */ + + /* If we need to send disconnect. try to do it now */ + if (self->disconnect_pend) + irttp_start_todo_timer(self, 0); +} + +/* + * Function irttp_flow_request (self, command) + * + * This function could be used by the upper layers to tell IrTTP to stop + * delivering frames if the receive queues are starting to get full, or + * to tell IrTTP to start delivering frames again. + */ +void irttp_flow_request(struct tsap_cb *self, LOCAL_FLOW flow) +{ + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;); + + switch (flow) { + case FLOW_STOP: + pr_debug("%s(), flow stop\n", __func__); + self->rx_sdu_busy = TRUE; + break; + case FLOW_START: + pr_debug("%s(), flow start\n", __func__); + self->rx_sdu_busy = FALSE; + + /* Client say he can accept more data, try to free our + * queues ASAP - Jean II */ + irttp_run_rx_queue(self); + + break; + default: + pr_debug("%s(), Unknown flow command!\n", __func__); + } +} +EXPORT_SYMBOL(irttp_flow_request); + +/* + * Function irttp_connect_request (self, dtsap_sel, daddr, qos) + * + * Try to connect to remote destination TSAP selector + * + */ +int irttp_connect_request(struct tsap_cb *self, __u8 dtsap_sel, + __u32 saddr, __u32 daddr, + struct qos_info *qos, __u32 max_sdu_size, + struct sk_buff *userdata) +{ + struct sk_buff *tx_skb; + __u8 *frame; + __u8 n; + + pr_debug("%s(), max_sdu_size=%d\n", __func__, max_sdu_size); + + IRDA_ASSERT(self != NULL, return -EBADR;); + IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -EBADR;); + + if (self->connected) { + if (userdata) + dev_kfree_skb(userdata); + return -EISCONN; + } + + /* Any userdata supplied? */ + if (userdata == NULL) { + tx_skb = alloc_skb(TTP_MAX_HEADER + TTP_SAR_HEADER, + GFP_ATOMIC); + if (!tx_skb) + return -ENOMEM; + + /* Reserve space for MUX_CONTROL and LAP header */ + skb_reserve(tx_skb, TTP_MAX_HEADER + TTP_SAR_HEADER); + } else { + tx_skb = userdata; + /* + * Check that the client has reserved enough space for + * headers + */ + IRDA_ASSERT(skb_headroom(userdata) >= TTP_MAX_HEADER, + { dev_kfree_skb(userdata); return -1; }); + } + + /* Initialize connection parameters */ + self->connected = FALSE; + self->avail_credit = 0; + self->rx_max_sdu_size = max_sdu_size; + self->rx_sdu_size = 0; + self->rx_sdu_busy = FALSE; + self->dtsap_sel = dtsap_sel; + + n = self->initial_credit; + + self->remote_credit = 0; + self->send_credit = 0; + + /* + * Give away max 127 credits for now + */ + if (n > 127) { + self->avail_credit = n - 127; + n = 127; + } + + self->remote_credit = n; + + /* SAR enabled? */ + if (max_sdu_size > 0) { + IRDA_ASSERT(skb_headroom(tx_skb) >= (TTP_MAX_HEADER + TTP_SAR_HEADER), + { dev_kfree_skb(tx_skb); return -1; }); + + /* Insert SAR parameters */ + frame = skb_push(tx_skb, TTP_HEADER + TTP_SAR_HEADER); + + frame[0] = TTP_PARAMETERS | n; + frame[1] = 0x04; /* Length */ + frame[2] = 0x01; /* MaxSduSize */ + frame[3] = 0x02; /* Value length */ + + put_unaligned(cpu_to_be16((__u16) max_sdu_size), + (__be16 *)(frame+4)); + } else { + /* Insert plain TTP header */ + frame = skb_push(tx_skb, TTP_HEADER); + + /* Insert initial credit in frame */ + frame[0] = n & 0x7f; + } + + /* Connect with IrLMP. No QoS parameters for now */ + return irlmp_connect_request(self->lsap, dtsap_sel, saddr, daddr, qos, + tx_skb); +} +EXPORT_SYMBOL(irttp_connect_request); + +/* + * Function irttp_connect_confirm (handle, qos, skb) + * + * Service user confirms TSAP connection with peer. + * + */ +static void irttp_connect_confirm(void *instance, void *sap, + struct qos_info *qos, __u32 max_seg_size, + __u8 max_header_size, struct sk_buff *skb) +{ + struct tsap_cb *self; + int parameters; + int ret; + __u8 plen; + __u8 n; + + self = instance; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;); + IRDA_ASSERT(skb != NULL, return;); + + self->max_seg_size = max_seg_size - TTP_HEADER; + self->max_header_size = max_header_size + TTP_HEADER; + + /* + * Check if we have got some QoS parameters back! This should be the + * negotiated QoS for the link. + */ + if (qos) { + pr_debug("IrTTP, Negotiated BAUD_RATE: %02x\n", + qos->baud_rate.bits); + pr_debug("IrTTP, Negotiated BAUD_RATE: %d bps.\n", + qos->baud_rate.value); + } + + n = skb->data[0] & 0x7f; + + pr_debug("%s(), Initial send_credit=%d\n", __func__, n); + + self->send_credit = n; + self->tx_max_sdu_size = 0; + self->connected = TRUE; + + parameters = skb->data[0] & 0x80; + + IRDA_ASSERT(skb->len >= TTP_HEADER, return;); + skb_pull(skb, TTP_HEADER); + + if (parameters) { + plen = skb->data[0]; + + ret = irda_param_extract_all(self, skb->data+1, + IRDA_MIN(skb->len-1, plen), + ¶m_info); + + /* Any errors in the parameter list? */ + if (ret < 0) { + net_warn_ratelimited("%s: error extracting parameters\n", + __func__); + dev_kfree_skb(skb); + + /* Do not accept this connection attempt */ + return; + } + /* Remove parameters */ + skb_pull(skb, IRDA_MIN(skb->len, plen+1)); + } + + pr_debug("%s() send=%d,avail=%d,remote=%d\n", __func__, + self->send_credit, self->avail_credit, self->remote_credit); + + pr_debug("%s(), MaxSduSize=%d\n", __func__, + self->tx_max_sdu_size); + + if (self->notify.connect_confirm) { + self->notify.connect_confirm(self->notify.instance, self, qos, + self->tx_max_sdu_size, + self->max_header_size, skb); + } else + dev_kfree_skb(skb); +} + +/* + * Function irttp_connect_indication (handle, skb) + * + * Some other device is connecting to this TSAP + * + */ +static void irttp_connect_indication(void *instance, void *sap, + struct qos_info *qos, __u32 max_seg_size, __u8 max_header_size, + struct sk_buff *skb) +{ + struct tsap_cb *self; + struct lsap_cb *lsap; + int parameters; + int ret; + __u8 plen; + __u8 n; + + self = instance; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;); + IRDA_ASSERT(skb != NULL, return;); + + lsap = sap; + + self->max_seg_size = max_seg_size - TTP_HEADER; + self->max_header_size = max_header_size+TTP_HEADER; + + pr_debug("%s(), TSAP sel=%02x\n", __func__, self->stsap_sel); + + /* Need to update dtsap_sel if its equal to LSAP_ANY */ + self->dtsap_sel = lsap->dlsap_sel; + + n = skb->data[0] & 0x7f; + + self->send_credit = n; + self->tx_max_sdu_size = 0; + + parameters = skb->data[0] & 0x80; + + IRDA_ASSERT(skb->len >= TTP_HEADER, return;); + skb_pull(skb, TTP_HEADER); + + if (parameters) { + plen = skb->data[0]; + + ret = irda_param_extract_all(self, skb->data+1, + IRDA_MIN(skb->len-1, plen), + ¶m_info); + + /* Any errors in the parameter list? */ + if (ret < 0) { + net_warn_ratelimited("%s: error extracting parameters\n", + __func__); + dev_kfree_skb(skb); + + /* Do not accept this connection attempt */ + return; + } + + /* Remove parameters */ + skb_pull(skb, IRDA_MIN(skb->len, plen+1)); + } + + if (self->notify.connect_indication) { + self->notify.connect_indication(self->notify.instance, self, + qos, self->tx_max_sdu_size, + self->max_header_size, skb); + } else + dev_kfree_skb(skb); +} + +/* + * Function irttp_connect_response (handle, userdata) + * + * Service user is accepting the connection, just pass it down to + * IrLMP! + * + */ +int irttp_connect_response(struct tsap_cb *self, __u32 max_sdu_size, + struct sk_buff *userdata) +{ + struct sk_buff *tx_skb; + __u8 *frame; + int ret; + __u8 n; + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;); + + pr_debug("%s(), Source TSAP selector=%02x\n", __func__, + self->stsap_sel); + + /* Any userdata supplied? */ + if (userdata == NULL) { + tx_skb = alloc_skb(TTP_MAX_HEADER + TTP_SAR_HEADER, + GFP_ATOMIC); + if (!tx_skb) + return -ENOMEM; + + /* Reserve space for MUX_CONTROL and LAP header */ + skb_reserve(tx_skb, TTP_MAX_HEADER + TTP_SAR_HEADER); + } else { + tx_skb = userdata; + /* + * Check that the client has reserved enough space for + * headers + */ + IRDA_ASSERT(skb_headroom(userdata) >= TTP_MAX_HEADER, + { dev_kfree_skb(userdata); return -1; }); + } + + self->avail_credit = 0; + self->remote_credit = 0; + self->rx_max_sdu_size = max_sdu_size; + self->rx_sdu_size = 0; + self->rx_sdu_busy = FALSE; + + n = self->initial_credit; + + /* Frame has only space for max 127 credits (7 bits) */ + if (n > 127) { + self->avail_credit = n - 127; + n = 127; + } + + self->remote_credit = n; + self->connected = TRUE; + + /* SAR enabled? */ + if (max_sdu_size > 0) { + IRDA_ASSERT(skb_headroom(tx_skb) >= (TTP_MAX_HEADER + TTP_SAR_HEADER), + { dev_kfree_skb(tx_skb); return -1; }); + + /* Insert TTP header with SAR parameters */ + frame = skb_push(tx_skb, TTP_HEADER + TTP_SAR_HEADER); + + frame[0] = TTP_PARAMETERS | n; + frame[1] = 0x04; /* Length */ + + /* irda_param_insert(self, IRTTP_MAX_SDU_SIZE, frame+1, */ +/* TTP_SAR_HEADER, ¶m_info) */ + + frame[2] = 0x01; /* MaxSduSize */ + frame[3] = 0x02; /* Value length */ + + put_unaligned(cpu_to_be16((__u16) max_sdu_size), + (__be16 *)(frame+4)); + } else { + /* Insert TTP header */ + frame = skb_push(tx_skb, TTP_HEADER); + + frame[0] = n & 0x7f; + } + + ret = irlmp_connect_response(self->lsap, tx_skb); + + return ret; +} +EXPORT_SYMBOL(irttp_connect_response); + +/* + * Function irttp_dup (self, instance) + * + * Duplicate TSAP, can be used by servers to confirm a connection on a + * new TSAP so it can keep listening on the old one. + */ +struct tsap_cb *irttp_dup(struct tsap_cb *orig, void *instance) +{ + struct tsap_cb *new; + unsigned long flags; + + /* Protect our access to the old tsap instance */ + spin_lock_irqsave(&irttp->tsaps->hb_spinlock, flags); + + /* Find the old instance */ + if (!hashbin_find(irttp->tsaps, (long) orig, NULL)) { + pr_debug("%s(), unable to find TSAP\n", __func__); + spin_unlock_irqrestore(&irttp->tsaps->hb_spinlock, flags); + return NULL; + } + + /* Allocate a new instance */ + new = kmemdup(orig, sizeof(struct tsap_cb), GFP_ATOMIC); + if (!new) { + pr_debug("%s(), unable to kmalloc\n", __func__); + spin_unlock_irqrestore(&irttp->tsaps->hb_spinlock, flags); + return NULL; + } + spin_lock_init(&new->lock); + + /* We don't need the old instance any more */ + spin_unlock_irqrestore(&irttp->tsaps->hb_spinlock, flags); + + /* Try to dup the LSAP (may fail if we were too slow) */ + new->lsap = irlmp_dup(orig->lsap, new); + if (!new->lsap) { + pr_debug("%s(), dup failed!\n", __func__); + kfree(new); + return NULL; + } + + /* Not everything should be copied */ + new->notify.instance = instance; + + /* Initialize internal objects */ + irttp_init_tsap(new); + + /* This is locked */ + hashbin_insert(irttp->tsaps, (irda_queue_t *) new, (long) new, NULL); + + return new; +} +EXPORT_SYMBOL(irttp_dup); + +/* + * Function irttp_disconnect_request (self) + * + * Close this connection please! If priority is high, the queued data + * segments, if any, will be deallocated first + * + */ +int irttp_disconnect_request(struct tsap_cb *self, struct sk_buff *userdata, + int priority) +{ + int ret; + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;); + + /* Already disconnected? */ + if (!self->connected) { + pr_debug("%s(), already disconnected!\n", __func__); + if (userdata) + dev_kfree_skb(userdata); + return -1; + } + + /* Disconnect already pending ? + * We need to use an atomic operation to prevent reentry. This + * function may be called from various context, like user, timer + * for following a disconnect_indication() (i.e. net_bh). + * Jean II */ + if (test_and_set_bit(0, &self->disconnect_pend)) { + pr_debug("%s(), disconnect already pending\n", + __func__); + if (userdata) + dev_kfree_skb(userdata); + + /* Try to make some progress */ + irttp_run_tx_queue(self); + return -1; + } + + /* + * Check if there is still data segments in the transmit queue + */ + if (!skb_queue_empty(&self->tx_queue)) { + if (priority == P_HIGH) { + /* + * No need to send the queued data, if we are + * disconnecting right now since the data will + * not have any usable connection to be sent on + */ + pr_debug("%s(): High priority!!()\n", __func__); + irttp_flush_queues(self); + } else if (priority == P_NORMAL) { + /* + * Must delay disconnect until after all data segments + * have been sent and the tx_queue is empty + */ + /* We'll reuse this one later for the disconnect */ + self->disconnect_skb = userdata; /* May be NULL */ + + irttp_run_tx_queue(self); + + irttp_start_todo_timer(self, HZ/10); + return -1; + } + } + /* Note : we don't need to check if self->rx_queue is full and the + * state of self->rx_sdu_busy because the disconnect response will + * be sent at the LMP level (so even if the peer has its Tx queue + * full of data). - Jean II */ + + pr_debug("%s(), Disconnecting ...\n", __func__); + self->connected = FALSE; + + if (!userdata) { + struct sk_buff *tx_skb; + tx_skb = alloc_skb(LMP_MAX_HEADER, GFP_ATOMIC); + if (!tx_skb) + return -ENOMEM; + + /* + * Reserve space for MUX and LAP header + */ + skb_reserve(tx_skb, LMP_MAX_HEADER); + + userdata = tx_skb; + } + ret = irlmp_disconnect_request(self->lsap, userdata); + + /* The disconnect is no longer pending */ + clear_bit(0, &self->disconnect_pend); /* FALSE */ + + return ret; +} +EXPORT_SYMBOL(irttp_disconnect_request); + +/* + * Function irttp_disconnect_indication (self, reason) + * + * Disconnect indication, TSAP disconnected by peer? + * + */ +static void irttp_disconnect_indication(void *instance, void *sap, + LM_REASON reason, struct sk_buff *skb) +{ + struct tsap_cb *self; + + self = instance; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;); + + /* Prevent higher layer to send more data */ + self->connected = FALSE; + + /* Check if client has already tried to close the TSAP */ + if (self->close_pend) { + /* In this case, the higher layer is probably gone. Don't + * bother it and clean up the remains - Jean II */ + if (skb) + dev_kfree_skb(skb); + irttp_close_tsap(self); + return; + } + + /* If we are here, we assume that is the higher layer is still + * waiting for the disconnect notification and able to process it, + * even if he tried to disconnect. Otherwise, it would have already + * attempted to close the tsap and self->close_pend would be TRUE. + * Jean II */ + + /* No need to notify the client if has already tried to disconnect */ + if (self->notify.disconnect_indication) + self->notify.disconnect_indication(self->notify.instance, self, + reason, skb); + else + if (skb) + dev_kfree_skb(skb); +} + +/* + * Function irttp_do_data_indication (self, skb) + * + * Try to deliver reassembled skb to layer above, and requeue it if that + * for some reason should fail. We mark rx sdu as busy to apply back + * pressure is necessary. + */ +static void irttp_do_data_indication(struct tsap_cb *self, struct sk_buff *skb) +{ + int err; + + /* Check if client has already closed the TSAP and gone away */ + if (self->close_pend) { + dev_kfree_skb(skb); + return; + } + + err = self->notify.data_indication(self->notify.instance, self, skb); + + /* Usually the layer above will notify that it's input queue is + * starting to get filled by using the flow request, but this may + * be difficult, so it can instead just refuse to eat it and just + * give an error back + */ + if (err) { + pr_debug("%s() requeueing skb!\n", __func__); + + /* Make sure we take a break */ + self->rx_sdu_busy = TRUE; + + /* Need to push the header in again */ + skb_push(skb, TTP_HEADER); + skb->data[0] = 0x00; /* Make sure MORE bit is cleared */ + + /* Put skb back on queue */ + skb_queue_head(&self->rx_queue, skb); + } +} + +/* + * Function irttp_run_rx_queue (self) + * + * Check if we have any frames to be transmitted, or if we have any + * available credit to give away. + */ +static void irttp_run_rx_queue(struct tsap_cb *self) +{ + struct sk_buff *skb; + int more = 0; + + pr_debug("%s() send=%d,avail=%d,remote=%d\n", __func__, + self->send_credit, self->avail_credit, self->remote_credit); + + /* Get exclusive access to the rx queue, otherwise don't touch it */ + if (irda_lock(&self->rx_queue_lock) == FALSE) + return; + + /* + * Reassemble all frames in receive queue and deliver them + */ + while (!self->rx_sdu_busy && (skb = skb_dequeue(&self->rx_queue))) { + /* This bit will tell us if it's the last fragment or not */ + more = skb->data[0] & 0x80; + + /* Remove TTP header */ + skb_pull(skb, TTP_HEADER); + + /* Add the length of the remaining data */ + self->rx_sdu_size += skb->len; + + /* + * If SAR is disabled, or user has requested no reassembly + * of received fragments then we just deliver them + * immediately. This can be requested by clients that + * implements byte streams without any message boundaries + */ + if (self->rx_max_sdu_size == TTP_SAR_DISABLE) { + irttp_do_data_indication(self, skb); + self->rx_sdu_size = 0; + + continue; + } + + /* Check if this is a fragment, and not the last fragment */ + if (more) { + /* + * Queue the fragment if we still are within the + * limits of the maximum size of the rx_sdu + */ + if (self->rx_sdu_size <= self->rx_max_sdu_size) { + pr_debug("%s(), queueing frag\n", + __func__); + skb_queue_tail(&self->rx_fragments, skb); + } else { + /* Free the part of the SDU that is too big */ + dev_kfree_skb(skb); + } + continue; + } + /* + * This is the last fragment, so time to reassemble! + */ + if ((self->rx_sdu_size <= self->rx_max_sdu_size) || + (self->rx_max_sdu_size == TTP_SAR_UNBOUND)) { + /* + * A little optimizing. Only queue the fragment if + * there are other fragments. Since if this is the + * last and only fragment, there is no need to + * reassemble :-) + */ + if (!skb_queue_empty(&self->rx_fragments)) { + skb_queue_tail(&self->rx_fragments, + skb); + + skb = irttp_reassemble_skb(self); + } + + /* Now we can deliver the reassembled skb */ + irttp_do_data_indication(self, skb); + } else { + pr_debug("%s(), Truncated frame\n", __func__); + + /* Free the part of the SDU that is too big */ + dev_kfree_skb(skb); + + /* Deliver only the valid but truncated part of SDU */ + skb = irttp_reassemble_skb(self); + + irttp_do_data_indication(self, skb); + } + self->rx_sdu_size = 0; + } + + /* + * It's not trivial to keep track of how many credits are available + * by incrementing at each packet, because delivery may fail + * (irttp_do_data_indication() may requeue the frame) and because + * we need to take care of fragmentation. + * We want the other side to send up to initial_credit packets. + * We have some frames in our queues, and we have already allowed it + * to send remote_credit. + * No need to spinlock, write is atomic and self correcting... + * Jean II + */ + self->avail_credit = (self->initial_credit - + (self->remote_credit + + skb_queue_len(&self->rx_queue) + + skb_queue_len(&self->rx_fragments))); + + /* Do we have too much credits to send to peer ? */ + if ((self->remote_credit <= TTP_RX_MIN_CREDIT) && + (self->avail_credit > 0)) { + /* Send explicit credit frame */ + irttp_give_credit(self); + /* Note : do *NOT* check if tx_queue is non-empty, that + * will produce deadlocks. I repeat : send a credit frame + * even if we have something to send in our Tx queue. + * If we have credits, it means that our Tx queue is blocked. + * + * Let's suppose the peer can't keep up with our Tx. He will + * flow control us by not sending us any credits, and we + * will stop Tx and start accumulating credits here. + * Up to the point where the peer will stop its Tx queue, + * for lack of credits. + * Let's assume the peer application is single threaded. + * It will block on Tx and never consume any Rx buffer. + * Deadlock. Guaranteed. - Jean II + */ + } + + /* Reset lock */ + self->rx_queue_lock = 0; +} + +#ifdef CONFIG_PROC_FS +struct irttp_iter_state { + int id; +}; + +static void *irttp_seq_start(struct seq_file *seq, loff_t *pos) +{ + struct irttp_iter_state *iter = seq->private; + struct tsap_cb *self; + + /* Protect our access to the tsap list */ + spin_lock_irq(&irttp->tsaps->hb_spinlock); + iter->id = 0; + + for (self = (struct tsap_cb *) hashbin_get_first(irttp->tsaps); + self != NULL; + self = (struct tsap_cb *) hashbin_get_next(irttp->tsaps)) { + if (iter->id == *pos) + break; + ++iter->id; + } + + return self; +} + +static void *irttp_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + struct irttp_iter_state *iter = seq->private; + + ++*pos; + ++iter->id; + return (void *) hashbin_get_next(irttp->tsaps); +} + +static void irttp_seq_stop(struct seq_file *seq, void *v) +{ + spin_unlock_irq(&irttp->tsaps->hb_spinlock); +} + +static int irttp_seq_show(struct seq_file *seq, void *v) +{ + const struct irttp_iter_state *iter = seq->private; + const struct tsap_cb *self = v; + + seq_printf(seq, "TSAP %d, ", iter->id); + seq_printf(seq, "stsap_sel: %02x, ", + self->stsap_sel); + seq_printf(seq, "dtsap_sel: %02x\n", + self->dtsap_sel); + seq_printf(seq, " connected: %s, ", + self->connected ? "TRUE" : "FALSE"); + seq_printf(seq, "avail credit: %d, ", + self->avail_credit); + seq_printf(seq, "remote credit: %d, ", + self->remote_credit); + seq_printf(seq, "send credit: %d\n", + self->send_credit); + seq_printf(seq, " tx packets: %lu, ", + self->stats.tx_packets); + seq_printf(seq, "rx packets: %lu, ", + self->stats.rx_packets); + seq_printf(seq, "tx_queue len: %u ", + skb_queue_len(&self->tx_queue)); + seq_printf(seq, "rx_queue len: %u\n", + skb_queue_len(&self->rx_queue)); + seq_printf(seq, " tx_sdu_busy: %s, ", + self->tx_sdu_busy ? "TRUE" : "FALSE"); + seq_printf(seq, "rx_sdu_busy: %s\n", + self->rx_sdu_busy ? "TRUE" : "FALSE"); + seq_printf(seq, " max_seg_size: %u, ", + self->max_seg_size); + seq_printf(seq, "tx_max_sdu_size: %u, ", + self->tx_max_sdu_size); + seq_printf(seq, "rx_max_sdu_size: %u\n", + self->rx_max_sdu_size); + + seq_printf(seq, " Used by (%s)\n\n", + self->notify.name); + return 0; +} + +static const struct seq_operations irttp_seq_ops = { + .start = irttp_seq_start, + .next = irttp_seq_next, + .stop = irttp_seq_stop, + .show = irttp_seq_show, +}; + +static int irttp_seq_open(struct inode *inode, struct file *file) +{ + return seq_open_private(file, &irttp_seq_ops, + sizeof(struct irttp_iter_state)); +} + +const struct file_operations irttp_seq_fops = { + .owner = THIS_MODULE, + .open = irttp_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release_private, +}; + +#endif /* PROC_FS */ diff --git a/drivers/staging/irda/net/parameters.c b/drivers/staging/irda/net/parameters.c new file mode 100644 index 000000000000..16ce32ffe004 --- /dev/null +++ b/drivers/staging/irda/net/parameters.c @@ -0,0 +1,584 @@ +/********************************************************************* + * + * Filename: parameters.c + * Version: 1.0 + * Description: A more general way to handle (pi,pl,pv) parameters + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Mon Jun 7 10:25:11 1999 + * Modified at: Sun Jan 30 14:08:39 2000 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1999-2000 Dag Brattli, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + ********************************************************************/ + +#include <linux/types.h> +#include <linux/module.h> + +#include <asm/unaligned.h> +#include <asm/byteorder.h> + +#include <net/irda/irda.h> +#include <net/irda/parameters.h> + +static int irda_extract_integer(void *self, __u8 *buf, int len, __u8 pi, + PV_TYPE type, PI_HANDLER func); +static int irda_extract_string(void *self, __u8 *buf, int len, __u8 pi, + PV_TYPE type, PI_HANDLER func); +static int irda_extract_octseq(void *self, __u8 *buf, int len, __u8 pi, + PV_TYPE type, PI_HANDLER func); +static int irda_extract_no_value(void *self, __u8 *buf, int len, __u8 pi, + PV_TYPE type, PI_HANDLER func); + +static int irda_insert_integer(void *self, __u8 *buf, int len, __u8 pi, + PV_TYPE type, PI_HANDLER func); +static int irda_insert_no_value(void *self, __u8 *buf, int len, __u8 pi, + PV_TYPE type, PI_HANDLER func); + +static int irda_param_unpack(__u8 *buf, char *fmt, ...); + +/* Parameter value call table. Must match PV_TYPE */ +static const PV_HANDLER pv_extract_table[] = { + irda_extract_integer, /* Handler for any length integers */ + irda_extract_integer, /* Handler for 8 bits integers */ + irda_extract_integer, /* Handler for 16 bits integers */ + irda_extract_string, /* Handler for strings */ + irda_extract_integer, /* Handler for 32 bits integers */ + irda_extract_octseq, /* Handler for octet sequences */ + irda_extract_no_value /* Handler for no value parameters */ +}; + +static const PV_HANDLER pv_insert_table[] = { + irda_insert_integer, /* Handler for any length integers */ + irda_insert_integer, /* Handler for 8 bits integers */ + irda_insert_integer, /* Handler for 16 bits integers */ + NULL, /* Handler for strings */ + irda_insert_integer, /* Handler for 32 bits integers */ + NULL, /* Handler for octet sequences */ + irda_insert_no_value /* Handler for no value parameters */ +}; + +/* + * Function irda_insert_no_value (self, buf, len, pi, type, func) + */ +static int irda_insert_no_value(void *self, __u8 *buf, int len, __u8 pi, + PV_TYPE type, PI_HANDLER func) +{ + irda_param_t p; + int ret; + + p.pi = pi; + p.pl = 0; + + /* Call handler for this parameter */ + ret = (*func)(self, &p, PV_GET); + + /* Extract values anyway, since handler may need them */ + irda_param_pack(buf, "bb", p.pi, p.pl); + + if (ret < 0) + return ret; + + return 2; /* Inserted pl+2 bytes */ +} + +/* + * Function irda_extract_no_value (self, buf, len, type, func) + * + * Extracts a parameter without a pv field (pl=0) + * + */ +static int irda_extract_no_value(void *self, __u8 *buf, int len, __u8 pi, + PV_TYPE type, PI_HANDLER func) +{ + irda_param_t p; + int ret; + + /* Extract values anyway, since handler may need them */ + irda_param_unpack(buf, "bb", &p.pi, &p.pl); + + /* Call handler for this parameter */ + ret = (*func)(self, &p, PV_PUT); + + if (ret < 0) + return ret; + + return 2; /* Extracted pl+2 bytes */ +} + +/* + * Function irda_insert_integer (self, buf, len, pi, type, func) + */ +static int irda_insert_integer(void *self, __u8 *buf, int len, __u8 pi, + PV_TYPE type, PI_HANDLER func) +{ + irda_param_t p; + int n = 0; + int err; + + p.pi = pi; /* In case handler needs to know */ + p.pl = type & PV_MASK; /* The integer type codes the length as well */ + p.pv.i = 0; /* Clear value */ + + /* Call handler for this parameter */ + err = (*func)(self, &p, PV_GET); + if (err < 0) + return err; + + /* + * If parameter length is still 0, then (1) this is an any length + * integer, and (2) the handler function does not care which length + * we choose to use, so we pick the one the gives the fewest bytes. + */ + if (p.pl == 0) { + if (p.pv.i < 0xff) { + pr_debug("%s(), using 1 byte\n", __func__); + p.pl = 1; + } else if (p.pv.i < 0xffff) { + pr_debug("%s(), using 2 bytes\n", __func__); + p.pl = 2; + } else { + pr_debug("%s(), using 4 bytes\n", __func__); + p.pl = 4; /* Default length */ + } + } + /* Check if buffer is long enough for insertion */ + if (len < (2+p.pl)) { + net_warn_ratelimited("%s: buffer too short for insertion!\n", + __func__); + return -1; + } + pr_debug("%s(), pi=%#x, pl=%d, pi=%d\n", __func__, + p.pi, p.pl, p.pv.i); + switch (p.pl) { + case 1: + n += irda_param_pack(buf, "bbb", p.pi, p.pl, (__u8) p.pv.i); + break; + case 2: + if (type & PV_BIG_ENDIAN) + p.pv.i = cpu_to_be16((__u16) p.pv.i); + else + p.pv.i = cpu_to_le16((__u16) p.pv.i); + n += irda_param_pack(buf, "bbs", p.pi, p.pl, (__u16) p.pv.i); + break; + case 4: + if (type & PV_BIG_ENDIAN) + cpu_to_be32s(&p.pv.i); + else + cpu_to_le32s(&p.pv.i); + n += irda_param_pack(buf, "bbi", p.pi, p.pl, p.pv.i); + + break; + default: + net_warn_ratelimited("%s: length %d not supported\n", + __func__, p.pl); + /* Skip parameter */ + return -1; + } + + return p.pl+2; /* Inserted pl+2 bytes */ +} + +/* + * Function irda_extract integer (self, buf, len, pi, type, func) + * + * Extract a possibly variable length integer from buffer, and call + * handler for processing of the parameter + */ +static int irda_extract_integer(void *self, __u8 *buf, int len, __u8 pi, + PV_TYPE type, PI_HANDLER func) +{ + irda_param_t p; + int n = 0; + int extract_len; /* Real length we extract */ + int err; + + p.pi = pi; /* In case handler needs to know */ + p.pl = buf[1]; /* Extract length of value */ + p.pv.i = 0; /* Clear value */ + extract_len = p.pl; /* Default : extract all */ + + /* Check if buffer is long enough for parsing */ + if (len < (2+p.pl)) { + net_warn_ratelimited("%s: buffer too short for parsing! Need %d bytes, but len is only %d\n", + __func__, p.pl, len); + return -1; + } + + /* + * Check that the integer length is what we expect it to be. If the + * handler want a 16 bits integer then a 32 bits is not good enough + * PV_INTEGER means that the handler is flexible. + */ + if (((type & PV_MASK) != PV_INTEGER) && ((type & PV_MASK) != p.pl)) { + net_err_ratelimited("%s: invalid parameter length! Expected %d bytes, but value had %d bytes!\n", + __func__, type & PV_MASK, p.pl); + + /* Most parameters are bit/byte fields or little endian, + * so it's ok to only extract a subset of it (the subset + * that the handler expect). This is necessary, as some + * broken implementations seems to add extra undefined bits. + * If the parameter is shorter than we expect or is big + * endian, we can't play those tricks. Jean II */ + if((p.pl < (type & PV_MASK)) || (type & PV_BIG_ENDIAN)) { + /* Skip parameter */ + return p.pl+2; + } else { + /* Extract subset of it, fallthrough */ + extract_len = type & PV_MASK; + } + } + + + switch (extract_len) { + case 1: + n += irda_param_unpack(buf+2, "b", &p.pv.i); + break; + case 2: + n += irda_param_unpack(buf+2, "s", &p.pv.i); + if (type & PV_BIG_ENDIAN) + p.pv.i = be16_to_cpu((__u16) p.pv.i); + else + p.pv.i = le16_to_cpu((__u16) p.pv.i); + break; + case 4: + n += irda_param_unpack(buf+2, "i", &p.pv.i); + if (type & PV_BIG_ENDIAN) + be32_to_cpus(&p.pv.i); + else + le32_to_cpus(&p.pv.i); + break; + default: + net_warn_ratelimited("%s: length %d not supported\n", + __func__, p.pl); + + /* Skip parameter */ + return p.pl+2; + } + + pr_debug("%s(), pi=%#x, pl=%d, pi=%d\n", __func__, + p.pi, p.pl, p.pv.i); + /* Call handler for this parameter */ + err = (*func)(self, &p, PV_PUT); + if (err < 0) + return err; + + return p.pl+2; /* Extracted pl+2 bytes */ +} + +/* + * Function irda_extract_string (self, buf, len, type, func) + */ +static int irda_extract_string(void *self, __u8 *buf, int len, __u8 pi, + PV_TYPE type, PI_HANDLER func) +{ + char str[33]; + irda_param_t p; + int err; + + p.pi = pi; /* In case handler needs to know */ + p.pl = buf[1]; /* Extract length of value */ + if (p.pl > 32) + p.pl = 32; + + pr_debug("%s(), pi=%#x, pl=%d\n", __func__, + p.pi, p.pl); + + /* Check if buffer is long enough for parsing */ + if (len < (2+p.pl)) { + net_warn_ratelimited("%s: buffer too short for parsing! Need %d bytes, but len is only %d\n", + __func__, p.pl, len); + return -1; + } + + /* Should be safe to copy string like this since we have already + * checked that the buffer is long enough */ + strncpy(str, buf+2, p.pl); + + pr_debug("%s(), str=0x%02x 0x%02x\n", + __func__, (__u8)str[0], (__u8)str[1]); + + /* Null terminate string */ + str[p.pl] = '\0'; + + p.pv.c = str; /* Handler will need to take a copy */ + + /* Call handler for this parameter */ + err = (*func)(self, &p, PV_PUT); + if (err < 0) + return err; + + return p.pl+2; /* Extracted pl+2 bytes */ +} + +/* + * Function irda_extract_octseq (self, buf, len, type, func) + */ +static int irda_extract_octseq(void *self, __u8 *buf, int len, __u8 pi, + PV_TYPE type, PI_HANDLER func) +{ + irda_param_t p; + + p.pi = pi; /* In case handler needs to know */ + p.pl = buf[1]; /* Extract length of value */ + + /* Check if buffer is long enough for parsing */ + if (len < (2+p.pl)) { + net_warn_ratelimited("%s: buffer too short for parsing! Need %d bytes, but len is only %d\n", + __func__, p.pl, len); + return -1; + } + + pr_debug("%s(), not impl\n", __func__); + + return p.pl+2; /* Extracted pl+2 bytes */ +} + +/* + * Function irda_param_pack (skb, fmt, ...) + * + * Format: + * 'i' = 32 bits integer + * 's' = string + * + */ +int irda_param_pack(__u8 *buf, char *fmt, ...) +{ + irda_pv_t arg; + va_list args; + char *p; + int n = 0; + + va_start(args, fmt); + + for (p = fmt; *p != '\0'; p++) { + switch (*p) { + case 'b': /* 8 bits unsigned byte */ + buf[n++] = (__u8)va_arg(args, int); + break; + case 's': /* 16 bits unsigned short */ + arg.i = (__u16)va_arg(args, int); + put_unaligned((__u16)arg.i, (__u16 *)(buf+n)); n+=2; + break; + case 'i': /* 32 bits unsigned integer */ + arg.i = va_arg(args, __u32); + put_unaligned(arg.i, (__u32 *)(buf+n)); n+=4; + break; +#if 0 + case 'c': /* \0 terminated string */ + arg.c = va_arg(args, char *); + strcpy(buf+n, arg.c); + n += strlen(arg.c) + 1; + break; +#endif + default: + va_end(args); + return -1; + } + } + va_end(args); + + return 0; +} +EXPORT_SYMBOL(irda_param_pack); + +/* + * Function irda_param_unpack (skb, fmt, ...) + */ +static int irda_param_unpack(__u8 *buf, char *fmt, ...) +{ + irda_pv_t arg; + va_list args; + char *p; + int n = 0; + + va_start(args, fmt); + + for (p = fmt; *p != '\0'; p++) { + switch (*p) { + case 'b': /* 8 bits byte */ + arg.ip = va_arg(args, __u32 *); + *arg.ip = buf[n++]; + break; + case 's': /* 16 bits short */ + arg.ip = va_arg(args, __u32 *); + *arg.ip = get_unaligned((__u16 *)(buf+n)); n+=2; + break; + case 'i': /* 32 bits unsigned integer */ + arg.ip = va_arg(args, __u32 *); + *arg.ip = get_unaligned((__u32 *)(buf+n)); n+=4; + break; +#if 0 + case 'c': /* \0 terminated string */ + arg.c = va_arg(args, char *); + strcpy(arg.c, buf+n); + n += strlen(arg.c) + 1; + break; +#endif + default: + va_end(args); + return -1; + } + + } + va_end(args); + + return 0; +} + +/* + * Function irda_param_insert (self, pi, buf, len, info) + * + * Insert the specified parameter (pi) into buffer. Returns number of + * bytes inserted + */ +int irda_param_insert(void *self, __u8 pi, __u8 *buf, int len, + pi_param_info_t *info) +{ + const pi_minor_info_t *pi_minor_info; + __u8 pi_minor; + __u8 pi_major; + int type; + int ret = -1; + int n = 0; + + IRDA_ASSERT(buf != NULL, return ret;); + IRDA_ASSERT(info != NULL, return ret;); + + pi_minor = pi & info->pi_mask; + pi_major = pi >> info->pi_major_offset; + + /* Check if the identifier value (pi) is valid */ + if ((pi_major > info->len-1) || + (pi_minor > info->tables[pi_major].len-1)) + { + pr_debug("%s(), no handler for parameter=0x%02x\n", + __func__, pi); + + /* Skip this parameter */ + return -1; + } + + /* Lookup the info on how to parse this parameter */ + pi_minor_info = &info->tables[pi_major].pi_minor_call_table[pi_minor]; + + /* Find expected data type for this parameter identifier (pi)*/ + type = pi_minor_info->type; + + /* Check if handler has been implemented */ + if (!pi_minor_info->func) { + net_info_ratelimited("%s: no handler for pi=%#x\n", + __func__, pi); + /* Skip this parameter */ + return -1; + } + + /* Insert parameter value */ + ret = (*pv_insert_table[type & PV_MASK])(self, buf+n, len, pi, type, + pi_minor_info->func); + return ret; +} +EXPORT_SYMBOL(irda_param_insert); + +/* + * Function irda_param_extract (self, buf, len, info) + * + * Parse all parameters. If len is correct, then everything should be + * safe. Returns the number of bytes that was parsed + * + */ +static int irda_param_extract(void *self, __u8 *buf, int len, + pi_param_info_t *info) +{ + const pi_minor_info_t *pi_minor_info; + __u8 pi_minor; + __u8 pi_major; + int type; + int ret = -1; + int n = 0; + + IRDA_ASSERT(buf != NULL, return ret;); + IRDA_ASSERT(info != NULL, return ret;); + + pi_minor = buf[n] & info->pi_mask; + pi_major = buf[n] >> info->pi_major_offset; + + /* Check if the identifier value (pi) is valid */ + if ((pi_major > info->len-1) || + (pi_minor > info->tables[pi_major].len-1)) + { + pr_debug("%s(), no handler for parameter=0x%02x\n", + __func__, buf[0]); + + /* Skip this parameter */ + return 2 + buf[n + 1]; /* Continue */ + } + + /* Lookup the info on how to parse this parameter */ + pi_minor_info = &info->tables[pi_major].pi_minor_call_table[pi_minor]; + + /* Find expected data type for this parameter identifier (pi)*/ + type = pi_minor_info->type; + + pr_debug("%s(), pi=[%d,%d], type=%d\n", __func__, + pi_major, pi_minor, type); + + /* Check if handler has been implemented */ + if (!pi_minor_info->func) { + net_info_ratelimited("%s: no handler for pi=%#x\n", + __func__, buf[n]); + /* Skip this parameter */ + return 2 + buf[n + 1]; /* Continue */ + } + + /* Parse parameter value */ + ret = (*pv_extract_table[type & PV_MASK])(self, buf+n, len, buf[n], + type, pi_minor_info->func); + return ret; +} + +/* + * Function irda_param_extract_all (self, buf, len, info) + * + * Parse all parameters. If len is correct, then everything should be + * safe. Returns the number of bytes that was parsed + * + */ +int irda_param_extract_all(void *self, __u8 *buf, int len, + pi_param_info_t *info) +{ + int ret = -1; + int n = 0; + + IRDA_ASSERT(buf != NULL, return ret;); + IRDA_ASSERT(info != NULL, return ret;); + + /* + * Parse all parameters. Each parameter must be at least two bytes + * long or else there is no point in trying to parse it + */ + while (len > 2) { + ret = irda_param_extract(self, buf+n, len, info); + if (ret < 0) + return ret; + + n += ret; + len -= ret; + } + return n; +} +EXPORT_SYMBOL(irda_param_extract_all); diff --git a/drivers/staging/irda/net/qos.c b/drivers/staging/irda/net/qos.c new file mode 100644 index 000000000000..25ba8509ad3e --- /dev/null +++ b/drivers/staging/irda/net/qos.c @@ -0,0 +1,771 @@ +/********************************************************************* + * + * Filename: qos.c + * Version: 1.0 + * Description: IrLAP QoS parameter negotiation + * Status: Stable + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Tue Sep 9 00:00:26 1997 + * Modified at: Sun Jan 30 14:29:16 2000 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>, + * All Rights Reserved. + * Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + ********************************************************************/ + +#include <linux/export.h> + +#include <asm/byteorder.h> + +#include <net/irda/irda.h> +#include <net/irda/parameters.h> +#include <net/irda/qos.h> +#include <net/irda/irlap.h> +#include <net/irda/irlap_frame.h> + +/* + * Maximum values of the baud rate we negotiate with the other end. + * Most often, you don't have to change that, because Linux-IrDA will + * use the maximum offered by the link layer, which usually works fine. + * In some very rare cases, you may want to limit it to lower speeds... + */ +int sysctl_max_baud_rate = 16000000; +/* + * Maximum value of the lap disconnect timer we negotiate with the other end. + * Most often, the value below represent the best compromise, but some user + * may want to keep the LAP alive longer or shorter in case of link failure. + * Remember that the threshold time (early warning) is fixed to 3s... + */ +int sysctl_max_noreply_time = 12; +/* + * Minimum turn time to be applied before transmitting to the peer. + * Nonzero values (usec) are used as lower limit to the per-connection + * mtt value which was announced by the other end during negotiation. + * Might be helpful if the peer device provides too short mtt. + * Default is 10us which means using the unmodified value given by the + * peer except if it's 0 (0 is likely a bug in the other stack). + */ +unsigned int sysctl_min_tx_turn_time = 10; +/* + * Maximum data size to be used in transmission in payload of LAP frame. + * There is a bit of confusion in the IrDA spec : + * The LAP spec defines the payload of a LAP frame (I field) to be + * 2048 bytes max (IrLAP 1.1, chapt 6.6.5, p40). + * On the other hand, the PHY mention frames of 2048 bytes max (IrPHY + * 1.2, chapt 5.3.2.1, p41). But, this number includes the LAP header + * (2 bytes), and CRC (32 bits at 4 Mb/s). So, for the I field (LAP + * payload), that's only 2042 bytes. Oups ! + * My nsc-ircc hardware has troubles receiving 2048 bytes frames at 4 Mb/s, + * so adjust to 2042... I don't know if this bug applies only for 2048 + * bytes frames or all negotiated frame sizes, but you can use the sysctl + * to play with this value anyway. + * Jean II */ +unsigned int sysctl_max_tx_data_size = 2042; +/* + * Maximum transmit window, i.e. number of LAP frames between turn-around. + * This allow to override what the peer told us. Some peers are buggy and + * don't always support what they tell us. + * Jean II */ +unsigned int sysctl_max_tx_window = 7; + +static int irlap_param_baud_rate(void *instance, irda_param_t *param, int get); +static int irlap_param_link_disconnect(void *instance, irda_param_t *parm, + int get); +static int irlap_param_max_turn_time(void *instance, irda_param_t *param, + int get); +static int irlap_param_data_size(void *instance, irda_param_t *param, int get); +static int irlap_param_window_size(void *instance, irda_param_t *param, + int get); +static int irlap_param_additional_bofs(void *instance, irda_param_t *parm, + int get); +static int irlap_param_min_turn_time(void *instance, irda_param_t *param, + int get); + +#ifndef CONFIG_IRDA_DYNAMIC_WINDOW +static __u32 irlap_requested_line_capacity(struct qos_info *qos); +#endif + +static __u32 min_turn_times[] = { 10000, 5000, 1000, 500, 100, 50, 10, 0 }; /* us */ +static __u32 baud_rates[] = { 2400, 9600, 19200, 38400, 57600, 115200, 576000, + 1152000, 4000000, 16000000 }; /* bps */ +static __u32 data_sizes[] = { 64, 128, 256, 512, 1024, 2048 }; /* bytes */ +static __u32 add_bofs[] = { 48, 24, 12, 5, 3, 2, 1, 0 }; /* bytes */ +static __u32 max_turn_times[] = { 500, 250, 100, 50 }; /* ms */ +static __u32 link_disc_times[] = { 3, 8, 12, 16, 20, 25, 30, 40 }; /* secs */ + +static __u32 max_line_capacities[10][4] = { + /* 500 ms 250 ms 100 ms 50 ms (max turn time) */ + { 100, 0, 0, 0 }, /* 2400 bps */ + { 400, 0, 0, 0 }, /* 9600 bps */ + { 800, 0, 0, 0 }, /* 19200 bps */ + { 1600, 0, 0, 0 }, /* 38400 bps */ + { 2360, 0, 0, 0 }, /* 57600 bps */ + { 4800, 2400, 960, 480 }, /* 115200 bps */ + { 28800, 11520, 5760, 2880 }, /* 576000 bps */ + { 57600, 28800, 11520, 5760 }, /* 1152000 bps */ + { 200000, 100000, 40000, 20000 }, /* 4000000 bps */ + { 800000, 400000, 160000, 80000 }, /* 16000000 bps */ +}; + +static const pi_minor_info_t pi_minor_call_table_type_0[] = { + { NULL, 0 }, +/* 01 */{ irlap_param_baud_rate, PV_INTEGER | PV_LITTLE_ENDIAN }, + { NULL, 0 }, + { NULL, 0 }, + { NULL, 0 }, + { NULL, 0 }, + { NULL, 0 }, + { NULL, 0 }, +/* 08 */{ irlap_param_link_disconnect, PV_INT_8_BITS } +}; + +static const pi_minor_info_t pi_minor_call_table_type_1[] = { + { NULL, 0 }, + { NULL, 0 }, +/* 82 */{ irlap_param_max_turn_time, PV_INT_8_BITS }, +/* 83 */{ irlap_param_data_size, PV_INT_8_BITS }, +/* 84 */{ irlap_param_window_size, PV_INT_8_BITS }, +/* 85 */{ irlap_param_additional_bofs, PV_INT_8_BITS }, +/* 86 */{ irlap_param_min_turn_time, PV_INT_8_BITS }, +}; + +static const pi_major_info_t pi_major_call_table[] = { + { pi_minor_call_table_type_0, 9 }, + { pi_minor_call_table_type_1, 7 }, +}; + +static pi_param_info_t irlap_param_info = { pi_major_call_table, 2, 0x7f, 7 }; + +/* ---------------------- LOCAL SUBROUTINES ---------------------- */ +/* Note : we start with a bunch of local subroutines. + * As the compiler is "one pass", this is the only way to get them to + * inline properly... + * Jean II + */ +/* + * Function value_index (value, array, size) + * + * Returns the index to the value in the specified array + */ +static inline int value_index(__u32 value, __u32 *array, int size) +{ + int i; + + for (i=0; i < size; i++) + if (array[i] == value) + break; + return i; +} + +/* + * Function index_value (index, array) + * + * Returns value to index in array, easy! + * + */ +static inline __u32 index_value(int index, __u32 *array) +{ + return array[index]; +} + +/* + * Function msb_index (word) + * + * Returns index to most significant bit (MSB) in word + * + */ +static int msb_index (__u16 word) +{ + __u16 msb = 0x8000; + int index = 15; /* Current MSB */ + + /* Check for buggy peers. + * Note : there is a small probability that it could be us, but I + * would expect driver authors to catch that pretty early and be + * able to check precisely what's going on. If a end user sees this, + * it's very likely the peer. - Jean II */ + if (word == 0) { + net_warn_ratelimited("%s(), Detected buggy peer, adjust null PV to 0x1!\n", + __func__); + /* The only safe choice (we don't know the array size) */ + word = 0x1; + } + + while (msb) { + if (word & msb) + break; /* Found it! */ + msb >>=1; + index--; + } + return index; +} + +/* + * Function value_lower_bits (value, array) + * + * Returns a bit field marking all possibility lower than value. + */ +static inline int value_lower_bits(__u32 value, __u32 *array, int size, __u16 *field) +{ + int i; + __u16 mask = 0x1; + __u16 result = 0x0; + + for (i=0; i < size; i++) { + /* Add the current value to the bit field, shift mask */ + result |= mask; + mask <<= 1; + /* Finished ? */ + if (array[i] >= value) + break; + } + /* Send back a valid index */ + if(i >= size) + i = size - 1; /* Last item */ + *field = result; + return i; +} + +/* + * Function value_highest_bit (value, array) + * + * Returns a bit field marking the highest possibility lower than value. + */ +static inline int value_highest_bit(__u32 value, __u32 *array, int size, __u16 *field) +{ + int i; + __u16 mask = 0x1; + __u16 result = 0x0; + + for (i=0; i < size; i++) { + /* Finished ? */ + if (array[i] <= value) + break; + /* Shift mask */ + mask <<= 1; + } + /* Set the current value to the bit field */ + result |= mask; + /* Send back a valid index */ + if(i >= size) + i = size - 1; /* Last item */ + *field = result; + return i; +} + +/* -------------------------- MAIN CALLS -------------------------- */ + +/* + * Function irda_qos_compute_intersection (qos, new) + * + * Compute the intersection of the old QoS capabilities with new ones + * + */ +void irda_qos_compute_intersection(struct qos_info *qos, struct qos_info *new) +{ + IRDA_ASSERT(qos != NULL, return;); + IRDA_ASSERT(new != NULL, return;); + + /* Apply */ + qos->baud_rate.bits &= new->baud_rate.bits; + qos->window_size.bits &= new->window_size.bits; + qos->min_turn_time.bits &= new->min_turn_time.bits; + qos->max_turn_time.bits &= new->max_turn_time.bits; + qos->data_size.bits &= new->data_size.bits; + qos->link_disc_time.bits &= new->link_disc_time.bits; + qos->additional_bofs.bits &= new->additional_bofs.bits; + + irda_qos_bits_to_value(qos); +} + +/* + * Function irda_init_max_qos_capabilies (qos) + * + * The purpose of this function is for layers and drivers to be able to + * set the maximum QoS possible and then "and in" their own limitations + * + */ +void irda_init_max_qos_capabilies(struct qos_info *qos) +{ + int i; + /* + * These are the maximum supported values as specified on pages + * 39-43 in IrLAP + */ + + /* Use sysctl to set some configurable values... */ + /* Set configured max speed */ + i = value_lower_bits(sysctl_max_baud_rate, baud_rates, 10, + &qos->baud_rate.bits); + sysctl_max_baud_rate = index_value(i, baud_rates); + + /* Set configured max disc time */ + i = value_lower_bits(sysctl_max_noreply_time, link_disc_times, 8, + &qos->link_disc_time.bits); + sysctl_max_noreply_time = index_value(i, link_disc_times); + + /* LSB is first byte, MSB is second byte */ + qos->baud_rate.bits &= 0x03ff; + + qos->window_size.bits = 0x7f; + qos->min_turn_time.bits = 0xff; + qos->max_turn_time.bits = 0x0f; + qos->data_size.bits = 0x3f; + qos->link_disc_time.bits &= 0xff; + qos->additional_bofs.bits = 0xff; +} +EXPORT_SYMBOL(irda_init_max_qos_capabilies); + +/* + * Function irlap_adjust_qos_settings (qos) + * + * Adjust QoS settings in case some values are not possible to use because + * of other settings + */ +static void irlap_adjust_qos_settings(struct qos_info *qos) +{ + __u32 line_capacity; + int index; + + /* + * Make sure the mintt is sensible. + * Main culprit : Ericsson T39. - Jean II + */ + if (sysctl_min_tx_turn_time > qos->min_turn_time.value) { + int i; + + net_warn_ratelimited("%s(), Detected buggy peer, adjust mtt to %dus!\n", + __func__, sysctl_min_tx_turn_time); + + /* We don't really need bits, but easier this way */ + i = value_highest_bit(sysctl_min_tx_turn_time, min_turn_times, + 8, &qos->min_turn_time.bits); + sysctl_min_tx_turn_time = index_value(i, min_turn_times); + qos->min_turn_time.value = sysctl_min_tx_turn_time; + } + + /* + * Not allowed to use a max turn time less than 500 ms if the baudrate + * is less than 115200 + */ + if ((qos->baud_rate.value < 115200) && + (qos->max_turn_time.value < 500)) + { + pr_debug("%s(), adjusting max turn time from %d to 500 ms\n", + __func__, qos->max_turn_time.value); + qos->max_turn_time.value = 500; + } + + /* + * The data size must be adjusted according to the baud rate and max + * turn time + */ + index = value_index(qos->data_size.value, data_sizes, 6); + line_capacity = irlap_max_line_capacity(qos->baud_rate.value, + qos->max_turn_time.value); + +#ifdef CONFIG_IRDA_DYNAMIC_WINDOW + while ((qos->data_size.value > line_capacity) && (index > 0)) { + qos->data_size.value = data_sizes[index--]; + pr_debug("%s(), reducing data size to %d\n", + __func__, qos->data_size.value); + } +#else /* Use method described in section 6.6.11 of IrLAP */ + while (irlap_requested_line_capacity(qos) > line_capacity) { + IRDA_ASSERT(index != 0, return;); + + /* Must be able to send at least one frame */ + if (qos->window_size.value > 1) { + qos->window_size.value--; + pr_debug("%s(), reducing window size to %d\n", + __func__, qos->window_size.value); + } else if (index > 1) { + qos->data_size.value = data_sizes[index--]; + pr_debug("%s(), reducing data size to %d\n", + __func__, qos->data_size.value); + } else { + net_warn_ratelimited("%s(), nothing more we can do!\n", + __func__); + } + } +#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */ + /* + * Fix tx data size according to user limits - Jean II + */ + if (qos->data_size.value > sysctl_max_tx_data_size) + /* Allow non discrete adjustement to avoid losing capacity */ + qos->data_size.value = sysctl_max_tx_data_size; + /* + * Override Tx window if user request it. - Jean II + */ + if (qos->window_size.value > sysctl_max_tx_window) + qos->window_size.value = sysctl_max_tx_window; +} + +/* + * Function irlap_negotiate (qos_device, qos_session, skb) + * + * Negotiate QoS values, not really that much negotiation :-) + * We just set the QoS capabilities for the peer station + * + */ +int irlap_qos_negotiate(struct irlap_cb *self, struct sk_buff *skb) +{ + int ret; + + ret = irda_param_extract_all(self, skb->data, skb->len, + &irlap_param_info); + + /* Convert the negotiated bits to values */ + irda_qos_bits_to_value(&self->qos_tx); + irda_qos_bits_to_value(&self->qos_rx); + + irlap_adjust_qos_settings(&self->qos_tx); + + pr_debug("Setting BAUD_RATE to %d bps.\n", + self->qos_tx.baud_rate.value); + pr_debug("Setting DATA_SIZE to %d bytes\n", + self->qos_tx.data_size.value); + pr_debug("Setting WINDOW_SIZE to %d\n", + self->qos_tx.window_size.value); + pr_debug("Setting XBOFS to %d\n", + self->qos_tx.additional_bofs.value); + pr_debug("Setting MAX_TURN_TIME to %d ms.\n", + self->qos_tx.max_turn_time.value); + pr_debug("Setting MIN_TURN_TIME to %d usecs.\n", + self->qos_tx.min_turn_time.value); + pr_debug("Setting LINK_DISC to %d secs.\n", + self->qos_tx.link_disc_time.value); + return ret; +} + +/* + * Function irlap_insert_negotiation_params (qos, fp) + * + * Insert QoS negotiaion pararameters into frame + * + */ +int irlap_insert_qos_negotiation_params(struct irlap_cb *self, + struct sk_buff *skb) +{ + int ret; + + /* Insert data rate */ + ret = irda_param_insert(self, PI_BAUD_RATE, skb_tail_pointer(skb), + skb_tailroom(skb), &irlap_param_info); + if (ret < 0) + return ret; + skb_put(skb, ret); + + /* Insert max turnaround time */ + ret = irda_param_insert(self, PI_MAX_TURN_TIME, skb_tail_pointer(skb), + skb_tailroom(skb), &irlap_param_info); + if (ret < 0) + return ret; + skb_put(skb, ret); + + /* Insert data size */ + ret = irda_param_insert(self, PI_DATA_SIZE, skb_tail_pointer(skb), + skb_tailroom(skb), &irlap_param_info); + if (ret < 0) + return ret; + skb_put(skb, ret); + + /* Insert window size */ + ret = irda_param_insert(self, PI_WINDOW_SIZE, skb_tail_pointer(skb), + skb_tailroom(skb), &irlap_param_info); + if (ret < 0) + return ret; + skb_put(skb, ret); + + /* Insert additional BOFs */ + ret = irda_param_insert(self, PI_ADD_BOFS, skb_tail_pointer(skb), + skb_tailroom(skb), &irlap_param_info); + if (ret < 0) + return ret; + skb_put(skb, ret); + + /* Insert minimum turnaround time */ + ret = irda_param_insert(self, PI_MIN_TURN_TIME, skb_tail_pointer(skb), + skb_tailroom(skb), &irlap_param_info); + if (ret < 0) + return ret; + skb_put(skb, ret); + + /* Insert link disconnect/threshold time */ + ret = irda_param_insert(self, PI_LINK_DISC, skb_tail_pointer(skb), + skb_tailroom(skb), &irlap_param_info); + if (ret < 0) + return ret; + skb_put(skb, ret); + + return 0; +} + +/* + * Function irlap_param_baud_rate (instance, param, get) + * + * Negotiate data-rate + * + */ +static int irlap_param_baud_rate(void *instance, irda_param_t *param, int get) +{ + __u16 final; + + struct irlap_cb *self = (struct irlap_cb *) instance; + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); + + if (get) { + param->pv.i = self->qos_rx.baud_rate.bits; + pr_debug("%s(), baud rate = 0x%02x\n", + __func__, param->pv.i); + } else { + /* + * Stations must agree on baud rate, so calculate + * intersection + */ + pr_debug("Requested BAUD_RATE: 0x%04x\n", (__u16)param->pv.i); + final = (__u16) param->pv.i & self->qos_rx.baud_rate.bits; + + pr_debug("Final BAUD_RATE: 0x%04x\n", final); + self->qos_tx.baud_rate.bits = final; + self->qos_rx.baud_rate.bits = final; + } + + return 0; +} + +/* + * Function irlap_param_link_disconnect (instance, param, get) + * + * Negotiate link disconnect/threshold time. + * + */ +static int irlap_param_link_disconnect(void *instance, irda_param_t *param, + int get) +{ + __u16 final; + + struct irlap_cb *self = (struct irlap_cb *) instance; + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); + + if (get) + param->pv.i = self->qos_rx.link_disc_time.bits; + else { + /* + * Stations must agree on link disconnect/threshold + * time. + */ + pr_debug("LINK_DISC: %02x\n", (__u8)param->pv.i); + final = (__u8) param->pv.i & self->qos_rx.link_disc_time.bits; + + pr_debug("Final LINK_DISC: %02x\n", final); + self->qos_tx.link_disc_time.bits = final; + self->qos_rx.link_disc_time.bits = final; + } + return 0; +} + +/* + * Function irlap_param_max_turn_time (instance, param, get) + * + * Negotiate the maximum turnaround time. This is a type 1 parameter and + * will be negotiated independently for each station + * + */ +static int irlap_param_max_turn_time(void *instance, irda_param_t *param, + int get) +{ + struct irlap_cb *self = (struct irlap_cb *) instance; + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); + + if (get) + param->pv.i = self->qos_rx.max_turn_time.bits; + else + self->qos_tx.max_turn_time.bits = (__u8) param->pv.i; + + return 0; +} + +/* + * Function irlap_param_data_size (instance, param, get) + * + * Negotiate the data size. This is a type 1 parameter and + * will be negotiated independently for each station + * + */ +static int irlap_param_data_size(void *instance, irda_param_t *param, int get) +{ + struct irlap_cb *self = (struct irlap_cb *) instance; + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); + + if (get) + param->pv.i = self->qos_rx.data_size.bits; + else + self->qos_tx.data_size.bits = (__u8) param->pv.i; + + return 0; +} + +/* + * Function irlap_param_window_size (instance, param, get) + * + * Negotiate the window size. This is a type 1 parameter and + * will be negotiated independently for each station + * + */ +static int irlap_param_window_size(void *instance, irda_param_t *param, + int get) +{ + struct irlap_cb *self = (struct irlap_cb *) instance; + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); + + if (get) + param->pv.i = self->qos_rx.window_size.bits; + else + self->qos_tx.window_size.bits = (__u8) param->pv.i; + + return 0; +} + +/* + * Function irlap_param_additional_bofs (instance, param, get) + * + * Negotiate additional BOF characters. This is a type 1 parameter and + * will be negotiated independently for each station. + */ +static int irlap_param_additional_bofs(void *instance, irda_param_t *param, int get) +{ + struct irlap_cb *self = (struct irlap_cb *) instance; + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); + + if (get) + param->pv.i = self->qos_rx.additional_bofs.bits; + else + self->qos_tx.additional_bofs.bits = (__u8) param->pv.i; + + return 0; +} + +/* + * Function irlap_param_min_turn_time (instance, param, get) + * + * Negotiate the minimum turn around time. This is a type 1 parameter and + * will be negotiated independently for each station + */ +static int irlap_param_min_turn_time(void *instance, irda_param_t *param, + int get) +{ + struct irlap_cb *self = (struct irlap_cb *) instance; + + IRDA_ASSERT(self != NULL, return -1;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); + + if (get) + param->pv.i = self->qos_rx.min_turn_time.bits; + else + self->qos_tx.min_turn_time.bits = (__u8) param->pv.i; + + return 0; +} + +/* + * Function irlap_max_line_capacity (speed, max_turn_time, min_turn_time) + * + * Calculate the maximum line capacity + * + */ +__u32 irlap_max_line_capacity(__u32 speed, __u32 max_turn_time) +{ + __u32 line_capacity; + int i,j; + + pr_debug("%s(), speed=%d, max_turn_time=%d\n", + __func__, speed, max_turn_time); + + i = value_index(speed, baud_rates, 10); + j = value_index(max_turn_time, max_turn_times, 4); + + IRDA_ASSERT(((i >=0) && (i <10)), return 0;); + IRDA_ASSERT(((j >=0) && (j <4)), return 0;); + + line_capacity = max_line_capacities[i][j]; + + pr_debug("%s(), line capacity=%d bytes\n", + __func__, line_capacity); + + return line_capacity; +} + +#ifndef CONFIG_IRDA_DYNAMIC_WINDOW +static __u32 irlap_requested_line_capacity(struct qos_info *qos) +{ + __u32 line_capacity; + + line_capacity = qos->window_size.value * + (qos->data_size.value + 6 + qos->additional_bofs.value) + + irlap_min_turn_time_in_bytes(qos->baud_rate.value, + qos->min_turn_time.value); + + pr_debug("%s(), requested line capacity=%d\n", + __func__, line_capacity); + + return line_capacity; +} +#endif + +void irda_qos_bits_to_value(struct qos_info *qos) +{ + int index; + + IRDA_ASSERT(qos != NULL, return;); + + index = msb_index(qos->baud_rate.bits); + qos->baud_rate.value = baud_rates[index]; + + index = msb_index(qos->data_size.bits); + qos->data_size.value = data_sizes[index]; + + index = msb_index(qos->window_size.bits); + qos->window_size.value = index+1; + + index = msb_index(qos->min_turn_time.bits); + qos->min_turn_time.value = min_turn_times[index]; + + index = msb_index(qos->max_turn_time.bits); + qos->max_turn_time.value = max_turn_times[index]; + + index = msb_index(qos->link_disc_time.bits); + qos->link_disc_time.value = link_disc_times[index]; + + index = msb_index(qos->additional_bofs.bits); + qos->additional_bofs.value = add_bofs[index]; +} +EXPORT_SYMBOL(irda_qos_bits_to_value); diff --git a/drivers/staging/irda/net/timer.c b/drivers/staging/irda/net/timer.c new file mode 100644 index 000000000000..f2280f73b057 --- /dev/null +++ b/drivers/staging/irda/net/timer.c @@ -0,0 +1,231 @@ +/********************************************************************* + * + * Filename: timer.c + * Version: + * Description: + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Sat Aug 16 00:59:29 1997 + * Modified at: Wed Dec 8 12:50:34 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1997, 1999 Dag Brattli <dagb@cs.uit.no>, + * All Rights Reserved. + * Copyright (c) 2000-2002 Jean Tourrilhes <jt@hpl.hp.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#include <linux/delay.h> + +#include <net/irda/timer.h> +#include <net/irda/irda.h> +#include <net/irda/irda_device.h> +#include <net/irda/irlap.h> +#include <net/irda/irlmp.h> + +extern int sysctl_slot_timeout; + +static void irlap_slot_timer_expired(void* data); +static void irlap_query_timer_expired(void* data); +static void irlap_final_timer_expired(void* data); +static void irlap_wd_timer_expired(void* data); +static void irlap_backoff_timer_expired(void* data); +static void irlap_media_busy_expired(void* data); + +void irlap_start_slot_timer(struct irlap_cb *self, int timeout) +{ + irda_start_timer(&self->slot_timer, timeout, (void *) self, + irlap_slot_timer_expired); +} + +void irlap_start_query_timer(struct irlap_cb *self, int S, int s) +{ + int timeout; + + /* Calculate when the peer discovery should end. Normally, we + * get the end-of-discovery frame, so this is just in case + * we miss it. + * Basically, we multiply the number of remaining slots by our + * slot time, plus add some extra time to properly receive the last + * discovery packet (which is longer due to extra discovery info), + * to avoid messing with for incoming connections requests and + * to accommodate devices that perform discovery slower than us. + * Jean II */ + timeout = msecs_to_jiffies(sysctl_slot_timeout) * (S - s) + + XIDEXTRA_TIMEOUT + SMALLBUSY_TIMEOUT; + + /* Set or re-set the timer. We reset the timer for each received + * discovery query, which allow us to automatically adjust to + * the speed of the peer discovery (faster or slower). Jean II */ + irda_start_timer( &self->query_timer, timeout, (void *) self, + irlap_query_timer_expired); +} + +void irlap_start_final_timer(struct irlap_cb *self, int timeout) +{ + irda_start_timer(&self->final_timer, timeout, (void *) self, + irlap_final_timer_expired); +} + +void irlap_start_wd_timer(struct irlap_cb *self, int timeout) +{ + irda_start_timer(&self->wd_timer, timeout, (void *) self, + irlap_wd_timer_expired); +} + +void irlap_start_backoff_timer(struct irlap_cb *self, int timeout) +{ + irda_start_timer(&self->backoff_timer, timeout, (void *) self, + irlap_backoff_timer_expired); +} + +void irlap_start_mbusy_timer(struct irlap_cb *self, int timeout) +{ + irda_start_timer(&self->media_busy_timer, timeout, + (void *) self, irlap_media_busy_expired); +} + +void irlap_stop_mbusy_timer(struct irlap_cb *self) +{ + /* If timer is activated, kill it! */ + del_timer(&self->media_busy_timer); + + /* If we are in NDM, there is a bunch of events in LAP that + * that be pending due to the media_busy condition, such as + * CONNECT_REQUEST and SEND_UI_FRAME. If we don't generate + * an event, they will wait forever... + * Jean II */ + if (self->state == LAP_NDM) + irlap_do_event(self, MEDIA_BUSY_TIMER_EXPIRED, NULL, NULL); +} + +void irlmp_start_watchdog_timer(struct lsap_cb *self, int timeout) +{ + irda_start_timer(&self->watchdog_timer, timeout, (void *) self, + irlmp_watchdog_timer_expired); +} + +void irlmp_start_discovery_timer(struct irlmp_cb *self, int timeout) +{ + irda_start_timer(&self->discovery_timer, timeout, (void *) self, + irlmp_discovery_timer_expired); +} + +void irlmp_start_idle_timer(struct lap_cb *self, int timeout) +{ + irda_start_timer(&self->idle_timer, timeout, (void *) self, + irlmp_idle_timer_expired); +} + +void irlmp_stop_idle_timer(struct lap_cb *self) +{ + /* If timer is activated, kill it! */ + del_timer(&self->idle_timer); +} + +/* + * Function irlap_slot_timer_expired (data) + * + * IrLAP slot timer has expired + * + */ +static void irlap_slot_timer_expired(void *data) +{ + struct irlap_cb *self = (struct irlap_cb *) data; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return;); + + irlap_do_event(self, SLOT_TIMER_EXPIRED, NULL, NULL); +} + +/* + * Function irlap_query_timer_expired (data) + * + * IrLAP query timer has expired + * + */ +static void irlap_query_timer_expired(void *data) +{ + struct irlap_cb *self = (struct irlap_cb *) data; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return;); + + irlap_do_event(self, QUERY_TIMER_EXPIRED, NULL, NULL); +} + +/* + * Function irda_final_timer_expired (data) + * + * + * + */ +static void irlap_final_timer_expired(void *data) +{ + struct irlap_cb *self = (struct irlap_cb *) data; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return;); + + irlap_do_event(self, FINAL_TIMER_EXPIRED, NULL, NULL); +} + +/* + * Function irda_wd_timer_expired (data) + * + * + * + */ +static void irlap_wd_timer_expired(void *data) +{ + struct irlap_cb *self = (struct irlap_cb *) data; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return;); + + irlap_do_event(self, WD_TIMER_EXPIRED, NULL, NULL); +} + +/* + * Function irda_backoff_timer_expired (data) + * + * + * + */ +static void irlap_backoff_timer_expired(void *data) +{ + struct irlap_cb *self = (struct irlap_cb *) data; + + IRDA_ASSERT(self != NULL, return;); + IRDA_ASSERT(self->magic == LAP_MAGIC, return;); + + irlap_do_event(self, BACKOFF_TIMER_EXPIRED, NULL, NULL); +} + + +/* + * Function irtty_media_busy_expired (data) + * + * + */ +static void irlap_media_busy_expired(void *data) +{ + struct irlap_cb *self = (struct irlap_cb *) data; + + IRDA_ASSERT(self != NULL, return;); + + irda_device_set_media_busy(self->netdev, FALSE); + /* Note : the LAP event will be send in irlap_stop_mbusy_timer(), + * to catch other cases where the flag is cleared (for example + * after a discovery) - Jean II */ +} diff --git a/drivers/staging/irda/net/wrapper.c b/drivers/staging/irda/net/wrapper.c new file mode 100644 index 000000000000..40a0f993bf13 --- /dev/null +++ b/drivers/staging/irda/net/wrapper.c @@ -0,0 +1,492 @@ +/********************************************************************* + * + * Filename: wrapper.c + * Version: 1.2 + * Description: IrDA SIR async wrapper layer + * Status: Stable + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Mon Aug 4 20:40:53 1997 + * Modified at: Fri Jan 28 13:21:09 2000 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * Modified at: Fri May 28 3:11 CST 1999 + * Modified by: Horst von Brand <vonbrand@sleipnir.valparaiso.cl> + * + * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>, + * All Rights Reserved. + * Copyright (c) 2000-2002 Jean Tourrilhes <jt@hpl.hp.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#include <linux/skbuff.h> +#include <linux/string.h> +#include <linux/module.h> +#include <asm/byteorder.h> + +#include <net/irda/irda.h> +#include <net/irda/wrapper.h> +#include <net/irda/crc.h> +#include <net/irda/irlap.h> +#include <net/irda/irlap_frame.h> +#include <net/irda/irda_device.h> + +/************************** FRAME WRAPPING **************************/ +/* + * Unwrap and unstuff SIR frames + * + * Note : at FIR and MIR, HDLC framing is used and usually handled + * by the controller, so we come here only for SIR... Jean II + */ + +/* + * Function stuff_byte (byte, buf) + * + * Byte stuff one single byte and put the result in buffer pointed to by + * buf. The buffer must at all times be able to have two bytes inserted. + * + * This is in a tight loop, better inline it, so need to be prior to callers. + * (2000 bytes on P6 200MHz, non-inlined ~370us, inline ~170us) - Jean II + */ +static inline int stuff_byte(__u8 byte, __u8 *buf) +{ + switch (byte) { + case BOF: /* FALLTHROUGH */ + case EOF: /* FALLTHROUGH */ + case CE: + /* Insert transparently coded */ + buf[0] = CE; /* Send link escape */ + buf[1] = byte^IRDA_TRANS; /* Complement bit 5 */ + return 2; + /* break; */ + default: + /* Non-special value, no transparency required */ + buf[0] = byte; + return 1; + /* break; */ + } +} + +/* + * Function async_wrap (skb, *tx_buff, buffsize) + * + * Makes a new buffer with wrapping and stuffing, should check that + * we don't get tx buffer overflow. + */ +int async_wrap_skb(struct sk_buff *skb, __u8 *tx_buff, int buffsize) +{ + struct irda_skb_cb *cb = (struct irda_skb_cb *) skb->cb; + int xbofs; + int i; + int n; + union { + __u16 value; + __u8 bytes[2]; + } fcs; + + /* Initialize variables */ + fcs.value = INIT_FCS; + n = 0; + + /* + * Send XBOF's for required min. turn time and for the negotiated + * additional XBOFS + */ + + if (cb->magic != LAP_MAGIC) { + /* + * This will happen for all frames sent from user-space. + * Nothing to worry about, but we set the default number of + * BOF's + */ + pr_debug("%s(), wrong magic in skb!\n", __func__); + xbofs = 10; + } else + xbofs = cb->xbofs + cb->xbofs_delay; + + pr_debug("%s(), xbofs=%d\n", __func__, xbofs); + + /* Check that we never use more than 115 + 48 xbofs */ + if (xbofs > 163) { + pr_debug("%s(), too many xbofs (%d)\n", __func__, + xbofs); + xbofs = 163; + } + + memset(tx_buff + n, XBOF, xbofs); + n += xbofs; + + /* Start of packet character BOF */ + tx_buff[n++] = BOF; + + /* Insert frame and calc CRC */ + for (i=0; i < skb->len; i++) { + /* + * Check for the possibility of tx buffer overflow. We use + * bufsize-5 since the maximum number of bytes that can be + * transmitted after this point is 5. + */ + if(n >= (buffsize-5)) { + net_err_ratelimited("%s(), tx buffer overflow (n=%d)\n", + __func__, n); + return n; + } + + n += stuff_byte(skb->data[i], tx_buff+n); + fcs.value = irda_fcs(fcs.value, skb->data[i]); + } + + /* Insert CRC in little endian format (LSB first) */ + fcs.value = ~fcs.value; +#ifdef __LITTLE_ENDIAN + n += stuff_byte(fcs.bytes[0], tx_buff+n); + n += stuff_byte(fcs.bytes[1], tx_buff+n); +#else /* ifdef __BIG_ENDIAN */ + n += stuff_byte(fcs.bytes[1], tx_buff+n); + n += stuff_byte(fcs.bytes[0], tx_buff+n); +#endif + tx_buff[n++] = EOF; + + return n; +} +EXPORT_SYMBOL(async_wrap_skb); + +/************************* FRAME UNWRAPPING *************************/ +/* + * Unwrap and unstuff SIR frames + * + * Complete rewrite by Jean II : + * More inline, faster, more compact, more logical. Jean II + * (16 bytes on P6 200MHz, old 5 to 7 us, new 4 to 6 us) + * (24 bytes on P6 200MHz, old 9 to 10 us, new 7 to 8 us) + * (for reference, 115200 b/s is 1 byte every 69 us) + * And reduce wrapper.o by ~900B in the process ;-) + * + * Then, we have the addition of ZeroCopy, which is optional + * (i.e. the driver must initiate it) and improve final processing. + * (2005 B frame + EOF on P6 200MHz, without 30 to 50 us, with 10 to 25 us) + * + * Note : at FIR and MIR, HDLC framing is used and usually handled + * by the controller, so we come here only for SIR... Jean II + */ + +/* + * We can also choose where we want to do the CRC calculation. We can + * do it "inline", as we receive the bytes, or "postponed", when + * receiving the End-Of-Frame. + * (16 bytes on P6 200MHz, inlined 4 to 6 us, postponed 4 to 5 us) + * (24 bytes on P6 200MHz, inlined 7 to 8 us, postponed 5 to 7 us) + * With ZeroCopy : + * (2005 B frame on P6 200MHz, inlined 10 to 25 us, postponed 140 to 180 us) + * Without ZeroCopy : + * (2005 B frame on P6 200MHz, inlined 30 to 50 us, postponed 150 to 180 us) + * (Note : numbers taken with irq disabled) + * + * From those numbers, it's not clear which is the best strategy, because + * we end up running through a lot of data one way or another (i.e. cache + * misses). I personally prefer to avoid the huge latency spike of the + * "postponed" solution, because it come just at the time when we have + * lot's of protocol processing to do and it will hurt our ability to + * reach low link turnaround times... Jean II + */ +//#define POSTPONE_RX_CRC + +/* + * Function async_bump (buf, len, stats) + * + * Got a frame, make a copy of it, and pass it up the stack! We can try + * to inline it since it's only called from state_inside_frame + */ +static inline void +async_bump(struct net_device *dev, + struct net_device_stats *stats, + iobuff_t *rx_buff) +{ + struct sk_buff *newskb; + struct sk_buff *dataskb; + int docopy; + + /* Check if we need to copy the data to a new skb or not. + * If the driver doesn't use ZeroCopy Rx, we have to do it. + * With ZeroCopy Rx, the rx_buff already point to a valid + * skb. But, if the frame is small, it is more efficient to + * copy it to save memory (copy will be fast anyway - that's + * called Rx-copy-break). Jean II */ + docopy = ((rx_buff->skb == NULL) || + (rx_buff->len < IRDA_RX_COPY_THRESHOLD)); + + /* Allocate a new skb */ + newskb = dev_alloc_skb(docopy ? rx_buff->len + 1 : rx_buff->truesize); + if (!newskb) { + stats->rx_dropped++; + /* We could deliver the current skb if doing ZeroCopy Rx, + * but this would stall the Rx path. Better drop the + * packet... Jean II */ + return; + } + + /* Align IP header to 20 bytes (i.e. increase skb->data) + * Note this is only useful with IrLAN, as PPP has a variable + * header size (2 or 1 bytes) - Jean II */ + skb_reserve(newskb, 1); + + if(docopy) { + /* Copy data without CRC (length already checked) */ + skb_copy_to_linear_data(newskb, rx_buff->data, + rx_buff->len - 2); + /* Deliver this skb */ + dataskb = newskb; + } else { + /* We are using ZeroCopy. Deliver old skb */ + dataskb = rx_buff->skb; + /* And hook the new skb to the rx_buff */ + rx_buff->skb = newskb; + rx_buff->head = newskb->data; /* NOT newskb->head */ + //printk(KERN_DEBUG "ZeroCopy : len = %d, dataskb = %p, newskb = %p\n", rx_buff->len, dataskb, newskb); + } + + /* Set proper length on skb (without CRC) */ + skb_put(dataskb, rx_buff->len - 2); + + /* Feed it to IrLAP layer */ + dataskb->dev = dev; + skb_reset_mac_header(dataskb); + dataskb->protocol = htons(ETH_P_IRDA); + + netif_rx(dataskb); + + stats->rx_packets++; + stats->rx_bytes += rx_buff->len; + + /* Clean up rx_buff (redundant with async_unwrap_bof() ???) */ + rx_buff->data = rx_buff->head; + rx_buff->len = 0; +} + +/* + * Function async_unwrap_bof(dev, byte) + * + * Handle Beginning Of Frame character received within a frame + * + */ +static inline void +async_unwrap_bof(struct net_device *dev, + struct net_device_stats *stats, + iobuff_t *rx_buff, __u8 byte) +{ + switch(rx_buff->state) { + case LINK_ESCAPE: + case INSIDE_FRAME: + /* Not supposed to happen, the previous frame is not + * finished - Jean II */ + pr_debug("%s(), Discarding incomplete frame\n", + __func__); + stats->rx_errors++; + stats->rx_missed_errors++; + irda_device_set_media_busy(dev, TRUE); + break; + + case OUTSIDE_FRAME: + case BEGIN_FRAME: + default: + /* We may receive multiple BOF at the start of frame */ + break; + } + + /* Now receiving frame */ + rx_buff->state = BEGIN_FRAME; + rx_buff->in_frame = TRUE; + + /* Time to initialize receive buffer */ + rx_buff->data = rx_buff->head; + rx_buff->len = 0; + rx_buff->fcs = INIT_FCS; +} + +/* + * Function async_unwrap_eof(dev, byte) + * + * Handle End Of Frame character received within a frame + * + */ +static inline void +async_unwrap_eof(struct net_device *dev, + struct net_device_stats *stats, + iobuff_t *rx_buff, __u8 byte) +{ +#ifdef POSTPONE_RX_CRC + int i; +#endif + + switch(rx_buff->state) { + case OUTSIDE_FRAME: + /* Probably missed the BOF */ + stats->rx_errors++; + stats->rx_missed_errors++; + irda_device_set_media_busy(dev, TRUE); + break; + + case BEGIN_FRAME: + case LINK_ESCAPE: + case INSIDE_FRAME: + default: + /* Note : in the case of BEGIN_FRAME and LINK_ESCAPE, + * the fcs will most likely not match and generate an + * error, as expected - Jean II */ + rx_buff->state = OUTSIDE_FRAME; + rx_buff->in_frame = FALSE; + +#ifdef POSTPONE_RX_CRC + /* If we haven't done the CRC as we receive bytes, we + * must do it now... Jean II */ + for(i = 0; i < rx_buff->len; i++) + rx_buff->fcs = irda_fcs(rx_buff->fcs, + rx_buff->data[i]); +#endif + + /* Test FCS and signal success if the frame is good */ + if (rx_buff->fcs == GOOD_FCS) { + /* Deliver frame */ + async_bump(dev, stats, rx_buff); + break; + } else { + /* Wrong CRC, discard frame! */ + irda_device_set_media_busy(dev, TRUE); + + pr_debug("%s(), crc error\n", __func__); + stats->rx_errors++; + stats->rx_crc_errors++; + } + break; + } +} + +/* + * Function async_unwrap_ce(dev, byte) + * + * Handle Character Escape character received within a frame + * + */ +static inline void +async_unwrap_ce(struct net_device *dev, + struct net_device_stats *stats, + iobuff_t *rx_buff, __u8 byte) +{ + switch(rx_buff->state) { + case OUTSIDE_FRAME: + /* Activate carrier sense */ + irda_device_set_media_busy(dev, TRUE); + break; + + case LINK_ESCAPE: + net_warn_ratelimited("%s: state not defined\n", __func__); + break; + + case BEGIN_FRAME: + case INSIDE_FRAME: + default: + /* Stuffed byte coming */ + rx_buff->state = LINK_ESCAPE; + break; + } +} + +/* + * Function async_unwrap_other(dev, byte) + * + * Handle other characters received within a frame + * + */ +static inline void +async_unwrap_other(struct net_device *dev, + struct net_device_stats *stats, + iobuff_t *rx_buff, __u8 byte) +{ + switch(rx_buff->state) { + /* This is on the critical path, case are ordered by + * probability (most frequent first) - Jean II */ + case INSIDE_FRAME: + /* Must be the next byte of the frame */ + if (rx_buff->len < rx_buff->truesize) { + rx_buff->data[rx_buff->len++] = byte; +#ifndef POSTPONE_RX_CRC + rx_buff->fcs = irda_fcs(rx_buff->fcs, byte); +#endif + } else { + pr_debug("%s(), Rx buffer overflow, aborting\n", + __func__); + rx_buff->state = OUTSIDE_FRAME; + } + break; + + case LINK_ESCAPE: + /* + * Stuffed char, complement bit 5 of byte + * following CE, IrLAP p.114 + */ + byte ^= IRDA_TRANS; + if (rx_buff->len < rx_buff->truesize) { + rx_buff->data[rx_buff->len++] = byte; +#ifndef POSTPONE_RX_CRC + rx_buff->fcs = irda_fcs(rx_buff->fcs, byte); +#endif + rx_buff->state = INSIDE_FRAME; + } else { + pr_debug("%s(), Rx buffer overflow, aborting\n", + __func__); + rx_buff->state = OUTSIDE_FRAME; + } + break; + + case OUTSIDE_FRAME: + /* Activate carrier sense */ + if(byte != XBOF) + irda_device_set_media_busy(dev, TRUE); + break; + + case BEGIN_FRAME: + default: + rx_buff->data[rx_buff->len++] = byte; +#ifndef POSTPONE_RX_CRC + rx_buff->fcs = irda_fcs(rx_buff->fcs, byte); +#endif + rx_buff->state = INSIDE_FRAME; + break; + } +} + +/* + * Function async_unwrap_char (dev, rx_buff, byte) + * + * Parse and de-stuff frame received from the IrDA-port + * + * This is the main entry point for SIR drivers. + */ +void async_unwrap_char(struct net_device *dev, + struct net_device_stats *stats, + iobuff_t *rx_buff, __u8 byte) +{ + switch(byte) { + case CE: + async_unwrap_ce(dev, stats, rx_buff, byte); + break; + case BOF: + async_unwrap_bof(dev, stats, rx_buff, byte); + break; + case EOF: + async_unwrap_eof(dev, stats, rx_buff, byte); + break; + default: + async_unwrap_other(dev, stats, rx_buff, byte); + break; + } +} +EXPORT_SYMBOL(async_unwrap_char); + diff --git a/drivers/staging/ks7010/ks7010_sdio.c b/drivers/staging/ks7010/ks7010_sdio.c index 9b28ee1cfb1e..8cfdff198334 100644 --- a/drivers/staging/ks7010/ks7010_sdio.c +++ b/drivers/staging/ks7010/ks7010_sdio.c @@ -834,8 +834,6 @@ static int ks7010_sdio_probe(struct sdio_func *func, unsigned char byte; int ret; - DPRINTK(5, "ks7010_sdio_probe()\n"); - priv = NULL; netdev = NULL; @@ -1008,8 +1006,6 @@ static void ks7010_sdio_remove(struct sdio_func *func) struct ks_sdio_card *card; struct ks_wlan_private *priv; - DPRINTK(1, "ks7010_sdio_remove()\n"); - card = sdio_get_drvdata(func); if (!card) diff --git a/drivers/staging/ks7010/ks_hostif.c b/drivers/staging/ks7010/ks_hostif.c index 24a63161f92c..975dbbb3abd0 100644 --- a/drivers/staging/ks7010/ks_hostif.c +++ b/drivers/staging/ks7010/ks_hostif.c @@ -1658,8 +1658,8 @@ void hostif_phy_information_request(struct ks_wlan_private *priv) static void hostif_power_mgmt_request(struct ks_wlan_private *priv, - unsigned long mode, unsigned long wake_up, - unsigned long receive_dtims) + unsigned long mode, unsigned long wake_up, + unsigned long receive_dtims) { struct hostif_power_mgmt_request_t *pp; diff --git a/drivers/staging/ks7010/ks_wlan_net.c b/drivers/staging/ks7010/ks_wlan_net.c index 8aa12e813bd7..0f9348ba5d84 100644 --- a/drivers/staging/ks7010/ks_wlan_net.c +++ b/drivers/staging/ks7010/ks_wlan_net.c @@ -1356,7 +1356,7 @@ static inline char *ks_wlan_translate_scan(struct net_device *dev, /* Add mode */ iwe.cmd = SIOCGIWMODE; - capabilities = le16_to_cpu(ap->capability); + capabilities = ap->capability; if (capabilities & (BSS_CAP_ESS | BSS_CAP_IBSS)) { if (capabilities & BSS_CAP_ESS) iwe.u.mode = IW_MODE_INFRA; diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs.h b/drivers/staging/lustre/include/linux/libcfs/libcfs.h index cc2c0e97bb7e..b48e2f093bcc 100644 --- a/drivers/staging/lustre/include/linux/libcfs/libcfs.h +++ b/drivers/staging/lustre/include/linux/libcfs/libcfs.h @@ -33,10 +33,21 @@ #ifndef __LIBCFS_LIBCFS_H__ #define __LIBCFS_LIBCFS_H__ -#include "linux/libcfs.h" #include <linux/gfp.h> +#include <linux/list.h> -#include "curproc.h" +#include <uapi/linux/lnet/libcfs_ioctl.h> +#include <linux/libcfs/linux/libcfs.h> +#include <linux/libcfs/libcfs_debug.h> +#include <linux/libcfs/libcfs_private.h> +#include <linux/libcfs/libcfs_cpu.h> +#include <linux/libcfs/libcfs_prim.h> +#include <linux/libcfs/libcfs_time.h> +#include <linux/libcfs/libcfs_string.h> +#include <linux/libcfs/libcfs_workitem.h> +#include <linux/libcfs/libcfs_hash.h> +#include <linux/libcfs/libcfs_fail.h> +#include <linux/libcfs/curproc.h> #define LIBCFS_VERSION "0.7.0" @@ -49,8 +60,6 @@ #define LERRCHKSUM(hexnum) (((hexnum) & 0xf) ^ ((hexnum) >> 4 & 0xf) ^ \ ((hexnum) >> 8 & 0xf)) -#include <linux/list.h> - /* need both kernel and user-land acceptor */ #define LNET_ACCEPTOR_MIN_RESERVED_PORT 512 #define LNET_ACCEPTOR_MAX_RESERVED_PORT 1023 @@ -74,17 +83,6 @@ unsigned int cfs_rand(void); void cfs_srand(unsigned int seed1, unsigned int seed2); void cfs_get_random_bytes(void *buf, int size); -#include "libcfs_debug.h" -#include "libcfs_cpu.h" -#include "libcfs_private.h" -#include "libcfs_ioctl.h" -#include "libcfs_prim.h" -#include "libcfs_time.h" -#include "libcfs_string.h" -#include "libcfs_workitem.h" -#include "libcfs_hash.h" -#include "libcfs_fail.h" - struct libcfs_ioctl_handler { struct list_head item; int (*handle_ioctl)(unsigned int cmd, struct libcfs_ioctl_hdr *hdr); diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_debug.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_debug.h index b7bd6e8ab33f..e7c37415a0c7 100644 --- a/drivers/staging/lustre/include/linux/libcfs/libcfs_debug.h +++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_debug.h @@ -38,6 +38,8 @@ #ifndef __LIBCFS_DEBUG_H__ #define __LIBCFS_DEBUG_H__ +#include <uapi/linux/lnet/libcfs_debug.h> + /* * Debugging */ @@ -59,108 +61,6 @@ int libcfs_debug_str2mask(int *mask, const char *str, int is_subsys); extern unsigned int libcfs_catastrophe; extern unsigned int libcfs_panic_on_lbug; -/** - * Format for debug message headers - */ -struct ptldebug_header { - __u32 ph_len; - __u32 ph_flags; - __u32 ph_subsys; - __u32 ph_mask; - __u16 ph_cpu_id; - __u16 ph_type; - /* time_t overflow in 2106 */ - __u32 ph_sec; - __u64 ph_usec; - __u32 ph_stack; - __u32 ph_pid; - __u32 ph_extern_pid; - __u32 ph_line_num; -} __packed; - -#define PH_FLAG_FIRST_RECORD 1 - -/* Debugging subsystems (32 bits, non-overlapping) */ -#define S_UNDEFINED 0x00000001 -#define S_MDC 0x00000002 -#define S_MDS 0x00000004 -#define S_OSC 0x00000008 -#define S_OST 0x00000010 -#define S_CLASS 0x00000020 -#define S_LOG 0x00000040 -#define S_LLITE 0x00000080 -#define S_RPC 0x00000100 -#define S_MGMT 0x00000200 -#define S_LNET 0x00000400 -#define S_LND 0x00000800 /* ALL LNDs */ -#define S_PINGER 0x00001000 -#define S_FILTER 0x00002000 -/* unused */ -#define S_ECHO 0x00008000 -#define S_LDLM 0x00010000 -#define S_LOV 0x00020000 -#define S_LQUOTA 0x00040000 -#define S_OSD 0x00080000 -#define S_LFSCK 0x00100000 -/* unused */ -/* unused */ -#define S_LMV 0x00800000 /* b_new_cmd */ -/* unused */ -#define S_SEC 0x02000000 /* upcall cache */ -#define S_GSS 0x04000000 /* b_new_cmd */ -/* unused */ -#define S_MGC 0x10000000 -#define S_MGS 0x20000000 -#define S_FID 0x40000000 /* b_new_cmd */ -#define S_FLD 0x80000000 /* b_new_cmd */ - -#define LIBCFS_DEBUG_SUBSYS_NAMES { \ - "undefined", "mdc", "mds", "osc", "ost", "class", "log", \ - "llite", "rpc", "mgmt", "lnet", "lnd", "pinger", "filter", "", \ - "echo", "ldlm", "lov", "lquota", "osd", "lfsck", "", "", "lmv", \ - "", "sec", "gss", "", "mgc", "mgs", "fid", "fld", NULL } - -/* Debugging masks (32 bits, non-overlapping) */ -#define D_TRACE 0x00000001 /* ENTRY/EXIT markers */ -#define D_INODE 0x00000002 -#define D_SUPER 0x00000004 -#define D_EXT2 0x00000008 /* anything from ext2_debug */ -#define D_MALLOC 0x00000010 /* print malloc, free information */ -#define D_CACHE 0x00000020 /* cache-related items */ -#define D_INFO 0x00000040 /* general information */ -#define D_IOCTL 0x00000080 /* ioctl related information */ -#define D_NETERROR 0x00000100 /* network errors */ -#define D_NET 0x00000200 /* network communications */ -#define D_WARNING 0x00000400 /* CWARN(...) == CDEBUG (D_WARNING, ...) */ -#define D_BUFFS 0x00000800 -#define D_OTHER 0x00001000 -#define D_DENTRY 0x00002000 -#define D_NETTRACE 0x00004000 -#define D_PAGE 0x00008000 /* bulk page handling */ -#define D_DLMTRACE 0x00010000 -#define D_ERROR 0x00020000 /* CERROR(...) == CDEBUG (D_ERROR, ...) */ -#define D_EMERG 0x00040000 /* CEMERG(...) == CDEBUG (D_EMERG, ...) */ -#define D_HA 0x00080000 /* recovery and failover */ -#define D_RPCTRACE 0x00100000 /* for distributed debugging */ -#define D_VFSTRACE 0x00200000 -#define D_READA 0x00400000 /* read-ahead */ -#define D_MMAP 0x00800000 -#define D_CONFIG 0x01000000 -#define D_CONSOLE 0x02000000 -#define D_QUOTA 0x04000000 -#define D_SEC 0x08000000 -#define D_LFSCK 0x10000000 /* For both OI scrub and LFSCK */ -#define D_HSM 0x20000000 - -#define LIBCFS_DEBUG_MASKS_NAMES { \ - "trace", "inode", "super", "ext2", "malloc", "cache", "info", \ - "ioctl", "neterror", "net", "warning", "buffs", "other", \ - "dentry", "nettrace", "page", "dlmtrace", "error", "emerg", \ - "ha", "rpctrace", "vfstrace", "reada", "mmap", "config", \ - "console", "quota", "sec", "lfsck", "hsm", NULL } - -#define D_CANTMASK (D_ERROR | D_EMERG | D_WARNING | D_CONSOLE) - #ifndef DEBUG_SUBSYSTEM # define DEBUG_SUBSYSTEM S_UNDEFINED #endif diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_private.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_private.h index e774c75ecadd..709771d27f89 100644 --- a/drivers/staging/lustre/include/linux/libcfs/libcfs_private.h +++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_private.h @@ -154,18 +154,6 @@ do { \ /******************************************************************************/ -/* htonl hack - either this, or compile with -O2. Stupid byteorder/generic.h */ -#if defined(__GNUC__) && (__GNUC__ >= 2) && !defined(__OPTIMIZE__) -#define ___htonl(x) __cpu_to_be32(x) -#define ___htons(x) __cpu_to_be16(x) -#define ___ntohl(x) __be32_to_cpu(x) -#define ___ntohs(x) __be16_to_cpu(x) -#define htonl(x) ___htonl(x) -#define ntohl(x) ___ntohl(x) -#define htons(x) ___htons(x) -#define ntohs(x) ___ntohs(x) -#endif - void libcfs_debug_dumplog(void); int libcfs_debug_init(unsigned long bufsize); int libcfs_debug_cleanup(void); @@ -308,18 +296,4 @@ static inline size_t cfs_round_strlen(char *fset) return cfs_size_round((int)strlen(fset) + 1); } -#define LOGL(var, len, ptr) \ -do { \ - if (var) \ - memcpy((char *)ptr, (const char *)var, len); \ - ptr += cfs_size_round(len); \ -} while (0) - -#define LOGU(var, len, ptr) \ -do { \ - if (var) \ - memcpy((char *)var, (const char *)ptr, len); \ - ptr += cfs_size_round(len); \ -} while (0) - #endif diff --git a/drivers/staging/lustre/include/linux/lnet/api.h b/drivers/staging/lustre/include/linux/lnet/api.h index f4b6de2ec0ff..9c37f3e4b134 100644 --- a/drivers/staging/lustre/include/linux/lnet/api.h +++ b/drivers/staging/lustre/include/linux/lnet/api.h @@ -44,7 +44,7 @@ * @{ */ -#include "../lnet/types.h" +#include <uapi/linux/lnet/lnet-types.h> /** \defgroup lnet_init_fini Initialization and cleanup * The LNet must be properly initialized before any LNet calls can be made. diff --git a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h index 8ae7423b4543..e0968ab8d95e 100644 --- a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h +++ b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h @@ -35,11 +35,13 @@ #ifndef __LNET_LIB_LNET_H__ #define __LNET_LIB_LNET_H__ -#include "../libcfs/libcfs.h" -#include "api.h" -#include "lnet.h" -#include "lib-types.h" -#include "lib-dlc.h" +#include <linux/libcfs/libcfs.h> +#include <linux/lnet/api.h> +#include <linux/lnet/lib-types.h> +#include <uapi/linux/lnet/lnet-dlc.h> +#include <uapi/linux/lnet/lnet-types.h> +#include <uapi/linux/lnet/lnetctl.h> +#include <uapi/linux/lnet/nidstr.h> extern struct lnet the_lnet; /* THE network */ @@ -453,7 +455,8 @@ extern int portal_rotor; int lnet_lib_init(void); void lnet_lib_exit(void); -int lnet_notify(struct lnet_ni *ni, lnet_nid_t peer, int alive, unsigned long when); +int lnet_notify(struct lnet_ni *ni, lnet_nid_t peer, int alive, + unsigned long when); void lnet_notify_locked(struct lnet_peer *lp, int notifylnd, int alive, unsigned long when); int lnet_add_route(__u32 net, __u32 hops, lnet_nid_t gateway_nid, diff --git a/drivers/staging/lustre/include/linux/lnet/lib-types.h b/drivers/staging/lustre/include/linux/lnet/lib-types.h index 321752dfe58b..eea3b8e5e406 100644 --- a/drivers/staging/lustre/include/linux/lnet/lib-types.h +++ b/drivers/staging/lustre/include/linux/lnet/lib-types.h @@ -40,8 +40,8 @@ #include <linux/types.h> #include <linux/completion.h> -#include "types.h" -#include "lnetctl.h" +#include <uapi/linux/lnet/lnet-types.h> +#include <uapi/linux/lnet/lnetctl.h> /* Max payload size */ #define LNET_MAX_PAYLOAD CONFIG_LNET_MAX_PAYLOAD @@ -308,9 +308,11 @@ struct lnet_rc_data { struct lnet_peer { struct list_head lp_hashlist; /* chain on peer hash */ struct list_head lp_txq; /* messages blocking for - tx credits */ + * tx credits + */ struct list_head lp_rtrq; /* messages blocking for - router credits */ + * router credits + */ struct list_head lp_rtr_list; /* chain on router list */ int lp_txcredits; /* # tx credits available */ int lp_mintxcredits; /* low water mark */ @@ -319,23 +321,31 @@ struct lnet_peer { unsigned int lp_alive:1; /* alive/dead? */ unsigned int lp_notify:1; /* notification outstanding? */ unsigned int lp_notifylnd:1;/* outstanding notification - for LND? */ + * for LND? + */ unsigned int lp_notifying:1; /* some thread is handling - notification */ + * notification + */ unsigned int lp_ping_notsent;/* SEND event outstanding - from ping */ + * from ping + */ int lp_alive_count; /* # times router went - dead<->alive */ - long lp_txqnob; /* bytes queued for sending */ + * dead<->alive + */ + long lp_txqnob; /* ytes queued for sending */ unsigned long lp_timestamp; /* time of last aliveness - news */ + * news + */ unsigned long lp_ping_timestamp;/* time of last ping - attempt */ + * attempt + */ unsigned long lp_ping_deadline; /* != 0 if ping reply - expected */ + * expected + */ unsigned long lp_last_alive; /* when I was last alive */ unsigned long lp_last_query; /* when lp_ni was queried - last time */ + * last time + */ struct lnet_ni *lp_ni; /* interface peer is on */ lnet_nid_t lp_nid; /* peer's NID */ int lp_refcount; /* # refs */ @@ -386,7 +396,8 @@ struct lnet_route { struct lnet_remotenet { struct list_head lrn_list; /* chain on - ln_remote_nets_hash */ + * ln_remote_nets_hash + */ struct list_head lrn_routes; /* routes to me */ __u32 lrn_net; /* my net number */ }; @@ -399,14 +410,16 @@ struct lnet_remotenet { struct lnet_rtrbufpool { struct list_head rbp_bufs; /* my free buffer pool */ struct list_head rbp_msgs; /* messages blocking - for a buffer */ + * for a buffer + */ int rbp_npages; /* # pages in each buffer */ /* requested number of buffers */ int rbp_req_nbuffers; /* # buffers actually allocated */ int rbp_nbuffers; - int rbp_credits; /* # free buffers / - blocked messages */ + int rbp_credits; /* # free buffers + * blocked messages + */ int rbp_mincredits; /* low water mark */ }; @@ -442,7 +455,8 @@ enum lnet_match_flags { #define LNET_PTL_LAZY (1 << 0) #define LNET_PTL_MATCH_UNIQUE (1 << 1) /* unique match, for RDMA */ #define LNET_PTL_MATCH_WILDCARD (1 << 2) /* wildcard match, - request portal */ + * request portal + */ /* parameter for matching operations (GET, PUT) */ struct lnet_match_info { diff --git a/drivers/staging/lustre/include/linux/lnet/socklnd.h b/drivers/staging/lustre/include/linux/lnet/socklnd.h index dd5bc0e46560..553fb64b3e80 100644 --- a/drivers/staging/lustre/include/linux/lnet/socklnd.h +++ b/drivers/staging/lustre/include/linux/lnet/socklnd.h @@ -34,16 +34,8 @@ #ifndef __LNET_LNET_SOCKLND_H__ #define __LNET_LNET_SOCKLND_H__ -#include "types.h" - -#define SOCKLND_CONN_NONE (-1) -#define SOCKLND_CONN_ANY 0 -#define SOCKLND_CONN_CONTROL 1 -#define SOCKLND_CONN_BULK_IN 2 -#define SOCKLND_CONN_BULK_OUT 3 -#define SOCKLND_CONN_NTYPES 4 - -#define SOCKLND_CONN_ACK SOCKLND_CONN_BULK_IN +#include <uapi/linux/lnet/lnet-types.h> +#include <uapi/linux/lnet/socklnd.h> struct ksock_hello_msg { __u32 kshm_magic; /* magic number of socklnd message */ @@ -76,7 +68,8 @@ struct ksock_msg { __u64 ksm_zc_cookies[2]; /* Zero-Copy request/ACK cookie */ union { struct ksock_lnet_msg lnetmsg; /* lnet message, it's empty if - * it's NOOP */ + * it's NOOP + */ } WIRE_ATTR ksm_u; } WIRE_ATTR; diff --git a/drivers/staging/lustre/include/uapi/linux/lnet/libcfs_debug.h b/drivers/staging/lustre/include/uapi/linux/lnet/libcfs_debug.h new file mode 100644 index 000000000000..c4d9472b374f --- /dev/null +++ b/drivers/staging/lustre/include/uapi/linux/lnet/libcfs_debug.h @@ -0,0 +1,149 @@ +/* + * GPL HEADER START + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 only, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 for more details (a copy is included + * in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; If not, see + * http://www.gnu.org/licenses/gpl-2.0.html + * + * GPL HEADER END + */ +/* + * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. + * Use is subject to license terms. + * + * Copyright (c) 2012, 2014, Intel Corporation. + */ +/* + * This file is part of Lustre, http://www.lustre.org/ + * Lustre is a trademark of Sun Microsystems, Inc. + * + * libcfs/include/libcfs/libcfs_debug.h + * + * Debug messages and assertions + * + */ + +#ifndef __UAPI_LIBCFS_DEBUG_H__ +#define __UAPI_LIBCFS_DEBUG_H__ + +/** + * Format for debug message headers + */ +struct ptldebug_header { + __u32 ph_len; + __u32 ph_flags; + __u32 ph_subsys; + __u32 ph_mask; + __u16 ph_cpu_id; + __u16 ph_type; + /* time_t overflow in 2106 */ + __u32 ph_sec; + __u64 ph_usec; + __u32 ph_stack; + __u32 ph_pid; + __u32 ph_extern_pid; + __u32 ph_line_num; +} __attribute__((packed)); + +#define PH_FLAG_FIRST_RECORD 1 + +/* Debugging subsystems (32 bits, non-overlapping) */ +#define S_UNDEFINED 0x00000001 +#define S_MDC 0x00000002 +#define S_MDS 0x00000004 +#define S_OSC 0x00000008 +#define S_OST 0x00000010 +#define S_CLASS 0x00000020 +#define S_LOG 0x00000040 +#define S_LLITE 0x00000080 +#define S_RPC 0x00000100 +#define S_MGMT 0x00000200 +#define S_LNET 0x00000400 +#define S_LND 0x00000800 /* ALL LNDs */ +#define S_PINGER 0x00001000 +#define S_FILTER 0x00002000 +#define S_LIBCFS 0x00004000 +#define S_ECHO 0x00008000 +#define S_LDLM 0x00010000 +#define S_LOV 0x00020000 +#define S_LQUOTA 0x00040000 +#define S_OSD 0x00080000 +#define S_LFSCK 0x00100000 +#define S_SNAPSHOT 0x00200000 +/* unused */ +#define S_LMV 0x00800000 /* b_new_cmd */ +/* unused */ +#define S_SEC 0x02000000 /* upcall cache */ +#define S_GSS 0x04000000 /* b_new_cmd */ +/* unused */ +#define S_MGC 0x10000000 +#define S_MGS 0x20000000 +#define S_FID 0x40000000 /* b_new_cmd */ +#define S_FLD 0x80000000 /* b_new_cmd */ + +#define LIBCFS_DEBUG_SUBSYS_NAMES { \ + "undefined", "mdc", "mds", "osc", "ost", "class", "log", \ + "llite", "rpc", "mgmt", "lnet", "lnd", "pinger", "filter", \ + "libcfs", "echo", "ldlm", "lov", "lquota", "osd", "lfsck", \ + "snapshot", "", "lmv", "", "sec", "gss", "", "mgc", "mgs", \ + "fid", "fld", NULL } + +/* Debugging masks (32 bits, non-overlapping) */ +#define D_TRACE 0x00000001 /* ENTRY/EXIT markers */ +#define D_INODE 0x00000002 +#define D_SUPER 0x00000004 +#define D_EXT2 0x00000008 /* anything from ext2_debug */ +#define D_MALLOC 0x00000010 /* print malloc, free information */ +#define D_CACHE 0x00000020 /* cache-related items */ +#define D_INFO 0x00000040 /* general information */ +#define D_IOCTL 0x00000080 /* ioctl related information */ +#define D_NETERROR 0x00000100 /* network errors */ +#define D_NET 0x00000200 /* network communications */ +#define D_WARNING 0x00000400 /* CWARN(...) == CDEBUG (D_WARNING, ...) */ +#define D_BUFFS 0x00000800 +#define D_OTHER 0x00001000 +#define D_DENTRY 0x00002000 +#define D_NETTRACE 0x00004000 +#define D_PAGE 0x00008000 /* bulk page handling */ +#define D_DLMTRACE 0x00010000 +#define D_ERROR 0x00020000 /* CERROR(...) == CDEBUG (D_ERROR, ...) */ +#define D_EMERG 0x00040000 /* CEMERG(...) == CDEBUG (D_EMERG, ...) */ +#define D_HA 0x00080000 /* recovery and failover */ +#define D_RPCTRACE 0x00100000 /* for distributed debugging */ +#define D_VFSTRACE 0x00200000 +#define D_READA 0x00400000 /* read-ahead */ +#define D_MMAP 0x00800000 +#define D_CONFIG 0x01000000 +#define D_CONSOLE 0x02000000 +#define D_QUOTA 0x04000000 +#define D_SEC 0x08000000 +#define D_LFSCK 0x10000000 /* For both OI scrub and LFSCK */ +#define D_HSM 0x20000000 +#define D_SNAPSHOT 0x40000000 /* snapshot */ +#define D_LAYOUT 0x80000000 + +#define LIBCFS_DEBUG_MASKS_NAMES { \ + "trace", "inode", "super", "ext2", "malloc", "cache", "info", \ + "ioctl", "neterror", "net", "warning", "buffs", "other", \ + "dentry", "nettrace", "page", "dlmtrace", "error", "emerg", \ + "ha", "rpctrace", "vfstrace", "reada", "mmap", "config", \ + "console", "quota", "sec", "lfsck", "hsm", "snapshot", "layout",\ + NULL } + +#define D_CANTMASK (D_ERROR | D_EMERG | D_WARNING | D_CONSOLE) + +#define LIBCFS_DEBUG_FILE_PATH_DEFAULT "/tmp/lustre-log" + +#endif /* __UAPI_LIBCFS_DEBUG_H__ */ diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_ioctl.h b/drivers/staging/lustre/include/uapi/linux/lnet/libcfs_ioctl.h index cce6b58e3682..cce6b58e3682 100644 --- a/drivers/staging/lustre/include/linux/libcfs/libcfs_ioctl.h +++ b/drivers/staging/lustre/include/uapi/linux/lnet/libcfs_ioctl.h diff --git a/drivers/staging/lustre/include/linux/lnet/lib-dlc.h b/drivers/staging/lustre/include/uapi/linux/lnet/lnet-dlc.h index dfff17088403..e45d828bfd1b 100644 --- a/drivers/staging/lustre/include/linux/lnet/lib-dlc.h +++ b/drivers/staging/lustre/include/uapi/linux/lnet/lnet-dlc.h @@ -29,8 +29,8 @@ #ifndef LNET_DLC_H #define LNET_DLC_H -#include "../libcfs/libcfs_ioctl.h" -#include "types.h" +#include <uapi/linux/lnet/libcfs_ioctl.h> +#include <uapi/linux/lnet/lnet-types.h> #define MAX_NUM_SHOW_ENTRIES 32 #define LNET_MAX_STR_LEN 128 diff --git a/drivers/staging/lustre/include/linux/lnet/types.h b/drivers/staging/lustre/include/uapi/linux/lnet/lnet-types.h index 1be9b7aa7326..1be9b7aa7326 100644 --- a/drivers/staging/lustre/include/linux/lnet/types.h +++ b/drivers/staging/lustre/include/uapi/linux/lnet/lnet-types.h diff --git a/drivers/staging/lustre/include/linux/lnet/lnetctl.h b/drivers/staging/lustre/include/uapi/linux/lnet/lnetctl.h index 39575073b00b..d9da625d70de 100644 --- a/drivers/staging/lustre/include/linux/lnet/lnetctl.h +++ b/drivers/staging/lustre/include/uapi/linux/lnet/lnetctl.h @@ -15,7 +15,7 @@ #ifndef _LNETCTL_H_ #define _LNETCTL_H_ -#include "types.h" +#include <uapi/linux/lnet/lnet-types.h> /** \addtogroup lnet_fault_simulation * @{ @@ -32,10 +32,10 @@ enum { LNET_CTL_DELAY_LIST, }; -#define LNET_ACK_BIT BIT(0) -#define LNET_PUT_BIT BIT(1) -#define LNET_GET_BIT BIT(2) -#define LNET_REPLY_BIT BIT(3) +#define LNET_ACK_BIT (1 << 0) +#define LNET_PUT_BIT (1 << 1) +#define LNET_GET_BIT (1 << 2) +#define LNET_REPLY_BIT (1 << 3) /** ioctl parameter for LNet fault simulation */ struct lnet_fault_attr { @@ -131,45 +131,4 @@ struct lnet_fault_stat { #define SMFS_DEV_MAJOR 10 #define SMFS_DEV_MINOR 242 -int ptl_initialize(int argc, char **argv); -int jt_ptl_network(int argc, char **argv); -int jt_ptl_list_nids(int argc, char **argv); -int jt_ptl_which_nid(int argc, char **argv); -int jt_ptl_print_interfaces(int argc, char **argv); -int jt_ptl_add_interface(int argc, char **argv); -int jt_ptl_del_interface(int argc, char **argv); -int jt_ptl_print_peers(int argc, char **argv); -int jt_ptl_add_peer(int argc, char **argv); -int jt_ptl_del_peer(int argc, char **argv); -int jt_ptl_print_connections(int argc, char **argv); -int jt_ptl_disconnect(int argc, char **argv); -int jt_ptl_push_connection(int argc, char **argv); -int jt_ptl_print_active_txs(int argc, char **argv); -int jt_ptl_ping(int argc, char **argv); -int jt_ptl_mynid(int argc, char **argv); -int jt_ptl_add_uuid(int argc, char **argv); -int jt_ptl_add_uuid_old(int argc, char **argv); /* backwards compatibility */ -int jt_ptl_close_uuid(int argc, char **argv); -int jt_ptl_del_uuid(int argc, char **argv); -int jt_ptl_add_route(int argc, char **argv); -int jt_ptl_del_route(int argc, char **argv); -int jt_ptl_notify_router(int argc, char **argv); -int jt_ptl_print_routes(int argc, char **argv); -int jt_ptl_fail_nid(int argc, char **argv); -int jt_ptl_lwt(int argc, char **argv); -int jt_ptl_testprotocompat(int argc, char **argv); -int jt_ptl_memhog(int argc, char **argv); - -int dbg_initialize(int argc, char **argv); -int jt_dbg_filter(int argc, char **argv); -int jt_dbg_show(int argc, char **argv); -int jt_dbg_list(int argc, char **argv); -int jt_dbg_debug_kernel(int argc, char **argv); -int jt_dbg_debug_daemon(int argc, char **argv); -int jt_dbg_debug_file(int argc, char **argv); -int jt_dbg_clear_debug_buf(int argc, char **argv); -int jt_dbg_mark_debug_buf(int argc, char **argv); -int jt_dbg_modules(int argc, char **argv); -int jt_dbg_panic(int argc, char **argv); - #endif diff --git a/drivers/staging/lustre/include/linux/lnet/lnetst.h b/drivers/staging/lustre/include/uapi/linux/lnet/lnetst.h index ea736f8d5231..a4f9ff01d458 100644 --- a/drivers/staging/lustre/include/linux/lnet/lnetst.h +++ b/drivers/staging/lustre/include/uapi/linux/lnet/lnetst.h @@ -54,7 +54,8 @@ #define LSTIO_GROUP_ADD 0xC10 /* add group */ #define LSTIO_GROUP_LIST 0xC11 /* list all groups in session */ #define LSTIO_GROUP_INFO 0xC12 /* query default information of - * specified group */ + * specified group + */ #define LSTIO_GROUP_DEL 0xC13 /* delete group */ #define LSTIO_NODES_ADD 0xC14 /* add nodes to specified group */ #define LSTIO_GROUP_UPDATE 0xC15 /* update group */ @@ -102,27 +103,32 @@ struct lstcon_test_ent { int tse_type; /* test type */ int tse_loop; /* loop count */ int tse_concur; /* concurrency of test */ -}; /*** test summary entry, for - *** list_batch command */ +}; /* test summary entry, for + * list_batch command + */ struct lstcon_batch_ent { int bae_state; /* batch status */ int bae_timeout; /* batch timeout */ int bae_ntest; /* # of tests in the batch */ -}; /*** batch summary entry, for - *** list_batch command */ +}; /* batch summary entry, for + * list_batch command + */ struct lstcon_test_batch_ent { struct lstcon_ndlist_ent tbe_cli_nle; /* client (group) node_list - * entry */ + * entry + */ struct lstcon_ndlist_ent tbe_srv_nle; /* server (group) node_list - * entry */ + * entry + */ union { struct lstcon_test_ent tbe_test; /* test entry */ struct lstcon_batch_ent tbe_batch;/* batch entry */ } u; -}; /*** test/batch verbose information entry, - *** for list_batch command */ +}; /* test/batch verbose information entry, + * for list_batch command + */ struct lstcon_rpc_ent { struct list_head rpe_link; /* link chain */ @@ -138,10 +144,10 @@ struct lstcon_rpc_ent { }; struct lstcon_trans_stat { - int trs_rpc_stat[4]; /* RPCs stat (0: total - 1: failed - 2: finished - 4: reserved */ + int trs_rpc_stat[4]; /* RPCs stat (0: total 1: failed + * 2: finished + * 4: reserved + */ int trs_rpc_errno; /* RPC errno */ int trs_fwk_stat[8]; /* framework stat */ int trs_fwk_errno; /* errno of the first remote error */ @@ -275,22 +281,28 @@ struct lstio_session_end_args { struct lstio_debug_args { int lstio_dbg_key; /* IN: session key */ int lstio_dbg_type; /* IN: debug - session|batch| - group|nodes - list */ + * session|batch| + * group|nodes list + */ int lstio_dbg_flags; /* IN: reserved debug - flags */ + * flags + */ int lstio_dbg_timeout; /* IN: timeout of - debug */ + * debug + */ int lstio_dbg_nmlen; /* IN: len of name */ char __user *lstio_dbg_namep; /* IN: name of - group|batch */ + * group|batch + */ int lstio_dbg_count; /* IN: # of test nodes - to debug */ + * to debug + */ struct lnet_process_id __user *lstio_dbg_idsp; /* IN: id of test - nodes */ + * nodes + */ struct list_head __user *lstio_dbg_resultp; /* OUT: list head of - result buffer */ + * result buffer + */ }; struct lstio_group_add_args { @@ -307,7 +319,8 @@ struct lstio_group_del_args { #define LST_GROUP_CLEAN 1 /* remove inactive nodes in the group */ #define LST_GROUP_REFRESH 2 /* refresh inactive nodes - * in the group */ + * in the group + */ #define LST_GROUP_RMND 3 /* delete nodes from the group */ struct lstio_group_update_args { @@ -319,7 +332,8 @@ struct lstio_group_update_args { int lstio_grp_count; /* IN: # of nodes id */ struct lnet_process_id __user *lstio_grp_idsp; /* IN: array of nodes */ struct list_head __user *lstio_grp_resultp; /* OUT: list head of - result buffer */ + * result buffer + */ }; struct lstio_group_nodes_args { @@ -331,7 +345,8 @@ struct lstio_group_nodes_args { unsigned int __user *lstio_grp_featp; struct lnet_process_id __user *lstio_grp_idsp; /* IN: nodes */ struct list_head __user *lstio_grp_resultp; /* OUT: list head of - result buffer */ + * result buffer + */ }; struct lstio_group_list_args { @@ -345,8 +360,9 @@ struct lstio_group_info_args { int lstio_grp_key; /* IN: session key */ int lstio_grp_nmlen; /* IN: name len */ char __user *lstio_grp_namep; /* IN: name */ - struct lstcon_ndlist_ent __user *lstio_grp_entp;/* OUT: description of - group */ + struct lstcon_ndlist_ent __user *lstio_grp_entp;/* OUT: description + * of group + */ int __user *lstio_grp_idxp; /* IN/OUT: node index */ int __user *lstio_grp_ndentp; /* IN/OUT: # of nodent */ struct lstcon_node_ent __user *lstio_grp_dentsp;/* OUT: nodent array */ @@ -369,34 +385,41 @@ struct lstio_batch_del_args { struct lstio_batch_run_args { int lstio_bat_key; /* IN: session key */ int lstio_bat_timeout; /* IN: timeout for - the batch */ + * the batch + */ int lstio_bat_nmlen; /* IN: name length */ char __user *lstio_bat_namep; /* IN: batch name */ struct list_head __user *lstio_bat_resultp; /* OUT: list head of - result buffer */ + * result buffer + */ }; struct lstio_batch_stop_args { int lstio_bat_key; /* IN: session key */ int lstio_bat_force; /* IN: abort unfinished - test RPC */ + * test RPC + */ int lstio_bat_nmlen; /* IN: name length */ char __user *lstio_bat_namep; /* IN: batch name */ struct list_head __user *lstio_bat_resultp; /* OUT: list head of - result buffer */ + * result buffer + */ }; struct lstio_batch_query_args { int lstio_bat_key; /* IN: session key */ int lstio_bat_testidx; /* IN: test index */ int lstio_bat_client; /* IN: we testing - client? */ + * client? + */ int lstio_bat_timeout; /* IN: timeout for - waiting */ + * waiting + */ int lstio_bat_nmlen; /* IN: name length */ char __user *lstio_bat_namep; /* IN: batch name */ struct list_head __user *lstio_bat_resultp; /* OUT: list head of - result buffer */ + * result buffer + */ }; struct lstio_batch_list_args { @@ -411,7 +434,8 @@ struct lstio_batch_info_args { int lstio_bat_nmlen; /* IN: name length */ char __user *lstio_bat_namep; /* IN: name */ int lstio_bat_server; /* IN: query server - or not */ + * or not + */ int lstio_bat_testidx; /* IN: test index */ struct lstcon_test_batch_ent __user *lstio_bat_entp;/* OUT: batch ent */ @@ -424,14 +448,17 @@ struct lstio_batch_info_args { struct lstio_stat_args { int lstio_sta_key; /* IN: session key */ int lstio_sta_timeout; /* IN: timeout for - stat request */ + * stat request + */ int lstio_sta_nmlen; /* IN: group name - length */ + * length + */ char __user *lstio_sta_namep; /* IN: group name */ int lstio_sta_count; /* IN: # of pid */ struct lnet_process_id __user *lstio_sta_idsp; /* IN: pid */ struct list_head __user *lstio_sta_resultp; /* OUT: list head of - result buffer */ + * result buffer + */ }; enum lst_test_type { @@ -452,26 +479,32 @@ struct lstio_test_args { int lstio_tes_concur; /* IN: concurrency */ int lstio_tes_dist; /* IN: node distribution in - destination groups */ + * destination groups + */ int lstio_tes_span; /* IN: node span in - destination groups */ + * destination groups + */ int lstio_tes_sgrp_nmlen; /* IN: source group - name length */ + * name length + */ char __user *lstio_tes_sgrp_name; /* IN: group name */ int lstio_tes_dgrp_nmlen; /* IN: destination group - name length */ + * name length + */ char __user *lstio_tes_dgrp_name; /* IN: group name */ int lstio_tes_param_len; /* IN: param buffer len */ void __user *lstio_tes_param; /* IN: parameter for specified - test: - lstio_bulk_param_t, - lstio_ping_param_t, - ... more */ + * test: lstio_bulk_param_t, + * lstio_ping_param_t, + * ... more + */ int __user *lstio_tes_retp; /* OUT: private returned - value */ + * value + */ struct list_head __user *lstio_tes_resultp;/* OUT: list head of - result buffer */ + * result buffer + */ }; enum lst_brw_type { diff --git a/drivers/staging/lustre/include/linux/lnet/nidstr.h b/drivers/staging/lustre/include/uapi/linux/lnet/nidstr.h index ecdd0db04d0a..882074ed6021 100644 --- a/drivers/staging/lustre/include/linux/lnet/nidstr.h +++ b/drivers/staging/lustre/include/uapi/linux/lnet/nidstr.h @@ -28,7 +28,7 @@ #ifndef _LNET_NIDSTRINGS_H #define _LNET_NIDSTRINGS_H -#include "types.h" +#include <uapi/linux/lnet/lnet-types.h> /** * Lustre Network Driver types. diff --git a/drivers/staging/lustre/include/linux/lnet/lnet.h b/drivers/staging/lustre/include/uapi/linux/lnet/socklnd.h index 5d1559a26638..6453e053fa99 100644 --- a/drivers/staging/lustre/include/linux/lnet/lnet.h +++ b/drivers/staging/lustre/include/uapi/linux/lnet/socklnd.h @@ -22,23 +22,23 @@ /* * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * Use is subject to license terms. - * - * Copyright (c) 2012 - 2015, Intel Corporation. */ /* * This file is part of Lustre, http://www.lustre.org/ - * Lustre is a trademark of Seagate, Inc. + * Lustre is a trademark of Sun Microsystems, Inc. + * + * #defines shared between socknal implementation and utilities */ +#ifndef __UAPI_LNET_SOCKLND_H__ +#define __UAPI_LNET_SOCKLND_H__ -#ifndef __LNET_H__ -#define __LNET_H__ +#define SOCKLND_CONN_NONE (-1) +#define SOCKLND_CONN_ANY 0 +#define SOCKLND_CONN_CONTROL 1 +#define SOCKLND_CONN_BULK_IN 2 +#define SOCKLND_CONN_BULK_OUT 3 +#define SOCKLND_CONN_NTYPES 4 -/* - * lnet.h - * - * User application interface file - */ -#include "types.h" -#include "nidstr.h" +#define SOCKLND_CONN_ACK SOCKLND_CONN_BULK_IN #endif diff --git a/drivers/staging/lustre/lustre/include/lustre_cfg.h b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_cfg.h index 8eb394e64b25..11b51d93f64c 100644 --- a/drivers/staging/lustre/lustre/include/lustre_cfg.h +++ b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_cfg.h @@ -30,8 +30,12 @@ * Lustre is a trademark of Sun Microsystems, Inc. */ -#ifndef _LUSTRE_CFG_H -#define _LUSTRE_CFG_H +#ifndef _UAPI_LUSTRE_CFG_H_ +#define _UAPI_LUSTRE_CFG_H_ + +#include <linux/errno.h> +#include <linux/kernel.h> +#include <uapi/linux/lustre/lustre_user.h> /** \defgroup cfg cfg * @@ -46,55 +50,68 @@ #define LUSTRE_CFG_MAX_BUFCOUNT 8 #define LCFG_HDR_SIZE(count) \ - cfs_size_round(offsetof(struct lustre_cfg, lcfg_buflens[(count)])) + __ALIGN_KERNEL(offsetof(struct lustre_cfg, lcfg_buflens[(count)]), 8) /** If the LCFG_REQUIRED bit is set in a configuration command, * then the client is required to understand this parameter * in order to mount the filesystem. If it does not understand * a REQUIRED command the client mount will fail. */ -#define LCFG_REQUIRED 0x0001000 +#define LCFG_REQUIRED 0x0001000 enum lcfg_command_type { - LCFG_ATTACH = 0x00cf001, /**< create a new obd instance */ - LCFG_DETACH = 0x00cf002, /**< destroy obd instance */ - LCFG_SETUP = 0x00cf003, /**< call type-specific setup */ - LCFG_CLEANUP = 0x00cf004, /**< call type-specific cleanup */ - LCFG_ADD_UUID = 0x00cf005, /**< add a nid to a niduuid */ - LCFG_DEL_UUID = 0x00cf006, /**< remove a nid from a niduuid */ - LCFG_MOUNTOPT = 0x00cf007, /**< create a profile (mdc, osc) */ - LCFG_DEL_MOUNTOPT = 0x00cf008, /**< destroy a profile */ - LCFG_SET_TIMEOUT = 0x00cf009, /**< set obd_timeout */ - LCFG_SET_UPCALL = 0x00cf00a, /**< deprecated */ - LCFG_ADD_CONN = 0x00cf00b, /**< add a failover niduuid to an obd */ - LCFG_DEL_CONN = 0x00cf00c, /**< remove a failover niduuid */ - LCFG_LOV_ADD_OBD = 0x00cf00d, /**< add an osc to a lov */ - LCFG_LOV_DEL_OBD = 0x00cf00e, /**< remove an osc from a lov */ - LCFG_PARAM = 0x00cf00f, /**< set a proc parameter */ - LCFG_MARKER = 0x00cf010, /**< metadata about next cfg rec */ - LCFG_LOG_START = 0x00ce011, /**< mgc only, process a cfg log */ - LCFG_LOG_END = 0x00ce012, /**< stop processing updates */ - LCFG_LOV_ADD_INA = 0x00ce013, /**< like LOV_ADD_OBD, inactive */ - LCFG_ADD_MDC = 0x00cf014, /**< add an mdc to a lmv */ - LCFG_DEL_MDC = 0x00cf015, /**< remove an mdc from a lmv */ - LCFG_SPTLRPC_CONF = 0x00ce016, /**< security */ - LCFG_POOL_NEW = 0x00ce020, /**< create an ost pool name */ - LCFG_POOL_ADD = 0x00ce021, /**< add an ost to a pool */ - LCFG_POOL_REM = 0x00ce022, /**< remove an ost from a pool */ - LCFG_POOL_DEL = 0x00ce023, /**< destroy an ost pool name */ - LCFG_SET_LDLM_TIMEOUT = 0x00ce030, /**< set ldlm_timeout */ - LCFG_PRE_CLEANUP = 0x00cf031, /**< call type-specific pre - * cleanup cleanup - */ - LCFG_SET_PARAM = 0x00ce032, /**< use set_param syntax to set - * a proc parameters - */ + LCFG_ATTACH = 0x00cf001, /**< create a new obd instance */ + LCFG_DETACH = 0x00cf002, /**< destroy obd instance */ + LCFG_SETUP = 0x00cf003, /**< call type-specific setup */ + LCFG_CLEANUP = 0x00cf004, /**< call type-specific cleanup + */ + LCFG_ADD_UUID = 0x00cf005, /**< add a nid to a niduuid */ + LCFG_DEL_UUID = 0x00cf006, /**< remove a nid from + * a niduuid + */ + LCFG_MOUNTOPT = 0x00cf007, /**< create a profile + * (mdc, osc) + */ + LCFG_DEL_MOUNTOPT = 0x00cf008, /**< destroy a profile */ + LCFG_SET_TIMEOUT = 0x00cf009, /**< set obd_timeout */ + LCFG_SET_UPCALL = 0x00cf00a, /**< deprecated */ + LCFG_ADD_CONN = 0x00cf00b, /**< add a failover niduuid to + * an obd + */ + LCFG_DEL_CONN = 0x00cf00c, /**< remove a failover niduuid */ + LCFG_LOV_ADD_OBD = 0x00cf00d, /**< add an osc to a lov */ + LCFG_LOV_DEL_OBD = 0x00cf00e, /**< remove an osc from a lov */ + LCFG_PARAM = 0x00cf00f, /**< set a proc parameter */ + LCFG_MARKER = 0x00cf010, /**< metadata about next + * cfg rec + */ + LCFG_LOG_START = 0x00ce011, /**< mgc only, process a + * cfg log + */ + LCFG_LOG_END = 0x00ce012, /**< stop processing updates */ + LCFG_LOV_ADD_INA = 0x00ce013, /**< like LOV_ADD_OBD, + * inactive + */ + LCFG_ADD_MDC = 0x00cf014, /**< add an mdc to a lmv */ + LCFG_DEL_MDC = 0x00cf015, /**< remove an mdc from a lmv */ + LCFG_SPTLRPC_CONF = 0x00ce016, /**< security */ + LCFG_POOL_NEW = 0x00ce020, /**< create an ost pool name */ + LCFG_POOL_ADD = 0x00ce021, /**< add an ost to a pool */ + LCFG_POOL_REM = 0x00ce022, /**< remove an ost from a pool */ + LCFG_POOL_DEL = 0x00ce023, /**< destroy an ost pool name */ + LCFG_SET_LDLM_TIMEOUT = 0x00ce030, /**< set ldlm_timeout */ + LCFG_PRE_CLEANUP = 0x00cf031, /**< call type-specific pre + * cleanup cleanup + */ + LCFG_SET_PARAM = 0x00ce032, /**< use set_param syntax to set + * a proc parameters + */ }; struct lustre_cfg_bufs { - void *lcfg_buf[LUSTRE_CFG_MAX_BUFCOUNT]; - __u32 lcfg_buflen[LUSTRE_CFG_MAX_BUFCOUNT]; - __u32 lcfg_bufcount; + void *lcfg_buf[LUSTRE_CFG_MAX_BUFCOUNT]; + __u32 lcfg_buflen[LUSTRE_CFG_MAX_BUFCOUNT]; + __u32 lcfg_bufcount; }; struct lustre_cfg { @@ -111,40 +128,37 @@ struct lustre_cfg { }; enum cfg_record_type { - PORTALS_CFG_TYPE = 1, - LUSTRE_CFG_TYPE = 123, + PORTALS_CFG_TYPE = 1, + LUSTRE_CFG_TYPE = 123, }; -#define LUSTRE_CFG_BUFLEN(lcfg, idx) \ - ((lcfg)->lcfg_bufcount <= (idx) \ - ? 0 \ - : (lcfg)->lcfg_buflens[(idx)]) +#define LUSTRE_CFG_BUFLEN(lcfg, idx) \ + ((lcfg)->lcfg_bufcount <= (idx) ? 0 : (lcfg)->lcfg_buflens[(idx)]) static inline void lustre_cfg_bufs_set(struct lustre_cfg_bufs *bufs, - __u32 index, - void *buf, - __u32 buflen) + __u32 index, void *buf, __u32 buflen) { if (index >= LUSTRE_CFG_MAX_BUFCOUNT) return; + if (!bufs) return; if (bufs->lcfg_bufcount <= index) bufs->lcfg_bufcount = index + 1; - bufs->lcfg_buf[index] = buf; + bufs->lcfg_buf[index] = buf; bufs->lcfg_buflen[index] = buflen; } static inline void lustre_cfg_bufs_set_string(struct lustre_cfg_bufs *bufs, - __u32 index, - char *str) + __u32 index, char *str) { lustre_cfg_bufs_set(bufs, index, str, str ? strlen(str) + 1 : 0); } -static inline void lustre_cfg_bufs_reset(struct lustre_cfg_bufs *bufs, char *name) +static inline void lustre_cfg_bufs_reset(struct lustre_cfg_bufs *bufs, + char *name) { memset((bufs), 0, sizeof(*bufs)); if (name) @@ -157,13 +171,16 @@ static inline void *lustre_cfg_buf(struct lustre_cfg *lcfg, __u32 index) size_t offset; __u32 bufcount; + if (!lcfg) + return NULL; + bufcount = lcfg->lcfg_bufcount; if (index >= bufcount) return NULL; offset = LCFG_HDR_SIZE(lcfg->lcfg_bufcount); for (i = 0; i < index; i++) - offset += cfs_size_round(lcfg->lcfg_buflens[i]); + offset += __ALIGN_KERNEL(lcfg->lcfg_buflens[i], 8); return (char *)lcfg + offset; } @@ -179,35 +196,6 @@ static inline void lustre_cfg_bufs_init(struct lustre_cfg_bufs *bufs, } } -static inline char *lustre_cfg_string(struct lustre_cfg *lcfg, __u32 index) -{ - char *s; - - if (lcfg->lcfg_buflens[index] == 0) - return NULL; - - s = lustre_cfg_buf(lcfg, index); - if (!s) - return NULL; - - /* - * make sure it's NULL terminated, even if this kills a char - * of data. Try to use the padding first though. - */ - if (s[lcfg->lcfg_buflens[index] - 1] != '\0') { - size_t last = min((size_t)lcfg->lcfg_buflens[index], - cfs_size_round(lcfg->lcfg_buflens[index]) - 1); - char lost = s[last]; - - s[last] = '\0'; - if (lost != '\0') { - CWARN("Truncated buf %d to '%s' (lost '%c'...)\n", - index, s, lost); - } - } - return s; -} - static inline __u32 lustre_cfg_len(__u32 bufcount, __u32 *buflens) { __u32 i; @@ -215,24 +203,16 @@ static inline __u32 lustre_cfg_len(__u32 bufcount, __u32 *buflens) len = LCFG_HDR_SIZE(bufcount); for (i = 0; i < bufcount; i++) - len += cfs_size_round(buflens[i]); + len += __ALIGN_KERNEL(buflens[i], 8); - return cfs_size_round(len); + return __ALIGN_KERNEL(len, 8); } -#include "obd_support.h" - -static inline struct lustre_cfg *lustre_cfg_new(int cmd, - struct lustre_cfg_bufs *bufs) +static inline void lustre_cfg_init(struct lustre_cfg *lcfg, int cmd, + struct lustre_cfg_bufs *bufs) { - struct lustre_cfg *lcfg; char *ptr; - int i; - - lcfg = kzalloc(lustre_cfg_len(bufs->lcfg_bufcount, bufs->lcfg_buflen), - GFP_NOFS); - if (!lcfg) - return ERR_PTR(-ENOMEM); + __u32 i; lcfg->lcfg_version = LUSTRE_CFG_VERSION; lcfg->lcfg_command = cmd; @@ -241,15 +221,11 @@ static inline struct lustre_cfg *lustre_cfg_new(int cmd, ptr = (char *)lcfg + LCFG_HDR_SIZE(lcfg->lcfg_bufcount); for (i = 0; i < lcfg->lcfg_bufcount; i++) { lcfg->lcfg_buflens[i] = bufs->lcfg_buflen[i]; - LOGL((char *)bufs->lcfg_buf[i], bufs->lcfg_buflen[i], ptr); + if (bufs->lcfg_buf[i]) { + memcpy(ptr, bufs->lcfg_buf[i], bufs->lcfg_buflen[i]); + ptr += __ALIGN_KERNEL(bufs->lcfg_buflen[i], 8); + } } - return lcfg; -} - -static inline void lustre_cfg_free(struct lustre_cfg *lcfg) -{ - kfree(lcfg); - return; } static inline int lustre_cfg_sanity_check(void *buf, size_t len) @@ -280,8 +256,6 @@ static inline int lustre_cfg_sanity_check(void *buf, size_t len) return 0; } -#include "lustre/lustre_user.h" - /** @} cfg */ -#endif /* _LUSTRE_CFG_H */ +#endif /* _UAPI_LUSTRE_CFG_H_ */ diff --git a/drivers/staging/lustre/include/uapi/linux/lustre/lustre_fid.h b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_fid.h new file mode 100644 index 000000000000..2e7a8d103777 --- /dev/null +++ b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_fid.h @@ -0,0 +1,293 @@ +/* + * GPL HEADER START + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 only, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 for more details (a copy is included + * in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; If not, see + * http://www.gnu.org/licenses/gpl-2.0.html + * + * GPL HEADER END + */ +/* + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. + * Use is subject to license terms. + * + * Copyright (c) 2011, 2014, Intel Corporation. + * + * Copyright 2016 Cray Inc, all rights reserved. + * Author: Ben Evans. + * + * all fid manipulation functions go here + * + * FIDS are globally unique within a Lustre filessytem, and are made up + * of three parts: sequence, Object ID, and version. + * + */ +#ifndef _UAPI_LUSTRE_FID_H_ +#define _UAPI_LUSTRE_FID_H_ + +#include <uapi/linux/lustre/lustre_idl.h> + +/** returns fid object sequence */ +static inline __u64 fid_seq(const struct lu_fid *fid) +{ + return fid->f_seq; +} + +/** returns fid object id */ +static inline __u32 fid_oid(const struct lu_fid *fid) +{ + return fid->f_oid; +} + +/** returns fid object version */ +static inline __u32 fid_ver(const struct lu_fid *fid) +{ + return fid->f_ver; +} + +static inline void fid_zero(struct lu_fid *fid) +{ + memset(fid, 0, sizeof(*fid)); +} + +static inline __u64 fid_ver_oid(const struct lu_fid *fid) +{ + return (__u64)fid_ver(fid) << 32 | fid_oid(fid); +} + +static inline bool fid_seq_is_mdt0(__u64 seq) +{ + return seq == FID_SEQ_OST_MDT0; +} + +static inline bool fid_seq_is_mdt(__u64 seq) +{ + return seq == FID_SEQ_OST_MDT0 || seq >= FID_SEQ_NORMAL; +}; + +static inline bool fid_seq_is_echo(__u64 seq) +{ + return seq == FID_SEQ_ECHO; +} + +static inline bool fid_is_echo(const struct lu_fid *fid) +{ + return fid_seq_is_echo(fid_seq(fid)); +} + +static inline bool fid_seq_is_llog(__u64 seq) +{ + return seq == FID_SEQ_LLOG; +} + +static inline bool fid_is_llog(const struct lu_fid *fid) +{ + /* file with OID == 0 is not llog but contains last oid */ + return fid_seq_is_llog(fid_seq(fid)) && fid_oid(fid) > 0; +} + +static inline bool fid_seq_is_rsvd(__u64 seq) +{ + return seq > FID_SEQ_OST_MDT0 && seq <= FID_SEQ_RSVD; +}; + +static inline bool fid_seq_is_special(__u64 seq) +{ + return seq == FID_SEQ_SPECIAL; +}; + +static inline bool fid_seq_is_local_file(__u64 seq) +{ + return seq == FID_SEQ_LOCAL_FILE || + seq == FID_SEQ_LOCAL_NAME; +}; + +static inline bool fid_seq_is_root(__u64 seq) +{ + return seq == FID_SEQ_ROOT; +} + +static inline bool fid_seq_is_dot(__u64 seq) +{ + return seq == FID_SEQ_DOT_LUSTRE; +} + +static inline bool fid_seq_is_default(__u64 seq) +{ + return seq == FID_SEQ_LOV_DEFAULT; +} + +static inline bool fid_is_mdt0(const struct lu_fid *fid) +{ + return fid_seq_is_mdt0(fid_seq(fid)); +} + +/** + * Check if a fid is igif or not. + * \param fid the fid to be tested. + * \return true if the fid is an igif; otherwise false. + */ +static inline bool fid_seq_is_igif(__u64 seq) +{ + return seq >= FID_SEQ_IGIF && seq <= FID_SEQ_IGIF_MAX; +} + +static inline bool fid_is_igif(const struct lu_fid *fid) +{ + return fid_seq_is_igif(fid_seq(fid)); +} + +/** + * Check if a fid is idif or not. + * \param fid the fid to be tested. + * \return true if the fid is an idif; otherwise false. + */ +static inline bool fid_seq_is_idif(__u64 seq) +{ + return seq >= FID_SEQ_IDIF && seq <= FID_SEQ_IDIF_MAX; +} + +static inline bool fid_is_idif(const struct lu_fid *fid) +{ + return fid_seq_is_idif(fid_seq(fid)); +} + +static inline bool fid_is_local_file(const struct lu_fid *fid) +{ + return fid_seq_is_local_file(fid_seq(fid)); +} + +static inline bool fid_seq_is_norm(__u64 seq) +{ + return (seq >= FID_SEQ_NORMAL); +} + +static inline bool fid_is_norm(const struct lu_fid *fid) +{ + return fid_seq_is_norm(fid_seq(fid)); +} + +/* convert an OST objid into an IDIF FID SEQ number */ +static inline __u64 fid_idif_seq(__u64 id, __u32 ost_idx) +{ + return FID_SEQ_IDIF | (ost_idx << 16) | ((id >> 32) & 0xffff); +} + +/* convert a packed IDIF FID into an OST objid */ +static inline __u64 fid_idif_id(__u64 seq, __u32 oid, __u32 ver) +{ + return ((__u64)ver << 48) | ((seq & 0xffff) << 32) | oid; +} + +static inline __u32 idif_ost_idx(__u64 seq) +{ + return (seq >> 16) & 0xffff; +} + +/* extract ost index from IDIF FID */ +static inline __u32 fid_idif_ost_idx(const struct lu_fid *fid) +{ + return idif_ost_idx(fid_seq(fid)); +} + +/** + * Get inode number from an igif. + * \param fid an igif to get inode number from. + * \return inode number for the igif. + */ +static inline ino_t lu_igif_ino(const struct lu_fid *fid) +{ + return fid_seq(fid); +} + +/** + * Get inode generation from an igif. + * \param fid an igif to get inode generation from. + * \return inode generation for the igif. + */ +static inline __u32 lu_igif_gen(const struct lu_fid *fid) +{ + return fid_oid(fid); +} + +/** + * Build igif from the inode number/generation. + */ +static inline void lu_igif_build(struct lu_fid *fid, __u32 ino, __u32 gen) +{ + fid->f_seq = ino; + fid->f_oid = gen; + fid->f_ver = 0; +} + +/* + * Fids are transmitted across network (in the sender byte-ordering), + * and stored on disk in big-endian order. + */ +static inline void fid_cpu_to_le(struct lu_fid *dst, const struct lu_fid *src) +{ + dst->f_seq = __cpu_to_le64(fid_seq(src)); + dst->f_oid = __cpu_to_le32(fid_oid(src)); + dst->f_ver = __cpu_to_le32(fid_ver(src)); +} + +static inline void fid_le_to_cpu(struct lu_fid *dst, const struct lu_fid *src) +{ + dst->f_seq = __le64_to_cpu(fid_seq(src)); + dst->f_oid = __le32_to_cpu(fid_oid(src)); + dst->f_ver = __le32_to_cpu(fid_ver(src)); +} + +static inline void fid_cpu_to_be(struct lu_fid *dst, const struct lu_fid *src) +{ + dst->f_seq = __cpu_to_be64(fid_seq(src)); + dst->f_oid = __cpu_to_be32(fid_oid(src)); + dst->f_ver = __cpu_to_be32(fid_ver(src)); +} + +static inline void fid_be_to_cpu(struct lu_fid *dst, const struct lu_fid *src) +{ + dst->f_seq = __be64_to_cpu(fid_seq(src)); + dst->f_oid = __be32_to_cpu(fid_oid(src)); + dst->f_ver = __be32_to_cpu(fid_ver(src)); +} + +static inline bool fid_is_sane(const struct lu_fid *fid) +{ + return fid && ((fid_seq(fid) >= FID_SEQ_START && !fid_ver(fid)) || + fid_is_igif(fid) || fid_is_idif(fid) || + fid_seq_is_rsvd(fid_seq(fid))); +} + +static inline bool lu_fid_eq(const struct lu_fid *f0, const struct lu_fid *f1) +{ + return !memcmp(f0, f1, sizeof(*f0)); +} + +static inline int lu_fid_cmp(const struct lu_fid *f0, + const struct lu_fid *f1) +{ + if (fid_seq(f0) != fid_seq(f1)) + return fid_seq(f0) > fid_seq(f1) ? 1 : -1; + + if (fid_oid(f0) != fid_oid(f1)) + return fid_oid(f0) > fid_oid(f1) ? 1 : -1; + + if (fid_ver(f0) != fid_ver(f1)) + return fid_ver(f0) > fid_ver(f1) ? 1 : -1; + + return 0; +} +#endif diff --git a/drivers/staging/lustre/lustre/include/lustre/ll_fiemap.h b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_fiemap.h index b8ad5559a3b9..f5214dc33c60 100644 --- a/drivers/staging/lustre/lustre/include/lustre/ll_fiemap.h +++ b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_fiemap.h @@ -29,8 +29,6 @@ * This file is part of Lustre, http://www.lustre.org/ * Lustre is a trademark of Sun Microsystems, Inc. * - * lustre/include/lustre/ll_fiemap.h - * * FIEMAP data structures and flags. This header file will be used until * fiemap.h is available in the upstream kernel. * @@ -41,10 +39,8 @@ #ifndef _LUSTRE_FIEMAP_H #define _LUSTRE_FIEMAP_H -#ifndef __KERNEL__ #include <stddef.h> -#include <fiemap.h> -#endif +#include <linux/fiemap.h> /* XXX: We use fiemap_extent::fe_reserved[0] */ #define fe_device fe_reserved[0] diff --git a/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_idl.h index 77995fa47691..aac98dbcf6e3 100644 --- a/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h +++ b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_idl.h @@ -29,8 +29,6 @@ * This file is part of Lustre, http://www.lustre.org/ * Lustre is a trademark of Sun Microsystems, Inc. * - * lustre/include/lustre/lustre_idl.h - * * Lustre wire protocol definitions. */ @@ -69,13 +67,13 @@ #ifndef _LUSTRE_IDL_H_ #define _LUSTRE_IDL_H_ -#include "../../../include/linux/libcfs/libcfs.h" -#include "../../../include/linux/lnet/types.h" +#include <asm/byteorder.h> +#include <linux/types.h> +#include <uapi/linux/lnet/lnet-types.h> /* Defn's shared with user-space. */ -#include "lustre_user.h" -#include "lustre_errno.h" -#include "../lustre_ver.h" +#include <uapi/linux/lustre/lustre_user.h> +#include <uapi/linux/lustre/lustre_ver.h> /* * GENERAL STUFF @@ -217,34 +215,6 @@ enum { LUSTRE_FID_INIT_OID = 1UL }; -/** returns fid object sequence */ -static inline __u64 fid_seq(const struct lu_fid *fid) -{ - return fid->f_seq; -} - -/** returns fid object id */ -static inline __u32 fid_oid(const struct lu_fid *fid) -{ - return fid->f_oid; -} - -/** returns fid object version */ -static inline __u32 fid_ver(const struct lu_fid *fid) -{ - return fid->f_ver; -} - -static inline void fid_zero(struct lu_fid *fid) -{ - memset(fid, 0, sizeof(*fid)); -} - -static inline __u64 fid_ver_oid(const struct lu_fid *fid) -{ - return ((__u64)fid_ver(fid) << 32 | fid_oid(fid)); -} - /* copytool uses a 32b bitmask field to encode archive-Ids during register * with MDT thru kuc. * archive num = 0 => all @@ -313,458 +283,12 @@ enum dot_lustre_oid { FID_OID_DOT_LUSTRE_OBF = 2UL, }; -static inline bool fid_seq_is_mdt0(__u64 seq) -{ - return (seq == FID_SEQ_OST_MDT0); -} - -static inline bool fid_seq_is_mdt(__u64 seq) -{ - return seq == FID_SEQ_OST_MDT0 || seq >= FID_SEQ_NORMAL; +/** OID for FID_SEQ_ROOT */ +enum root_oid { + FID_OID_ROOT = 1UL, + FID_OID_ECHO_ROOT = 2UL, }; -static inline bool fid_seq_is_echo(__u64 seq) -{ - return (seq == FID_SEQ_ECHO); -} - -static inline bool fid_is_echo(const struct lu_fid *fid) -{ - return fid_seq_is_echo(fid_seq(fid)); -} - -static inline bool fid_seq_is_llog(__u64 seq) -{ - return (seq == FID_SEQ_LLOG); -} - -static inline bool fid_is_llog(const struct lu_fid *fid) -{ - /* file with OID == 0 is not llog but contains last oid */ - return fid_seq_is_llog(fid_seq(fid)) && fid_oid(fid) > 0; -} - -static inline bool fid_seq_is_rsvd(__u64 seq) -{ - return (seq > FID_SEQ_OST_MDT0 && seq <= FID_SEQ_RSVD); -}; - -static inline bool fid_seq_is_special(__u64 seq) -{ - return seq == FID_SEQ_SPECIAL; -}; - -static inline bool fid_seq_is_local_file(__u64 seq) -{ - return seq == FID_SEQ_LOCAL_FILE || - seq == FID_SEQ_LOCAL_NAME; -}; - -static inline bool fid_seq_is_root(__u64 seq) -{ - return seq == FID_SEQ_ROOT; -} - -static inline bool fid_seq_is_dot(__u64 seq) -{ - return seq == FID_SEQ_DOT_LUSTRE; -} - -static inline bool fid_seq_is_default(__u64 seq) -{ - return seq == FID_SEQ_LOV_DEFAULT; -} - -static inline bool fid_is_mdt0(const struct lu_fid *fid) -{ - return fid_seq_is_mdt0(fid_seq(fid)); -} - -static inline void lu_root_fid(struct lu_fid *fid) -{ - fid->f_seq = FID_SEQ_ROOT; - fid->f_oid = 1; - fid->f_ver = 0; -} - -/** - * Check if a fid is igif or not. - * \param fid the fid to be tested. - * \return true if the fid is a igif; otherwise false. - */ -static inline bool fid_seq_is_igif(__u64 seq) -{ - return seq >= FID_SEQ_IGIF && seq <= FID_SEQ_IGIF_MAX; -} - -static inline bool fid_is_igif(const struct lu_fid *fid) -{ - return fid_seq_is_igif(fid_seq(fid)); -} - -/** - * Check if a fid is idif or not. - * \param fid the fid to be tested. - * \return true if the fid is a idif; otherwise false. - */ -static inline bool fid_seq_is_idif(__u64 seq) -{ - return seq >= FID_SEQ_IDIF && seq <= FID_SEQ_IDIF_MAX; -} - -static inline bool fid_is_idif(const struct lu_fid *fid) -{ - return fid_seq_is_idif(fid_seq(fid)); -} - -static inline bool fid_is_local_file(const struct lu_fid *fid) -{ - return fid_seq_is_local_file(fid_seq(fid)); -} - -static inline bool fid_seq_is_norm(__u64 seq) -{ - return (seq >= FID_SEQ_NORMAL); -} - -static inline bool fid_is_norm(const struct lu_fid *fid) -{ - return fid_seq_is_norm(fid_seq(fid)); -} - -/* convert an OST objid into an IDIF FID SEQ number */ -static inline __u64 fid_idif_seq(__u64 id, __u32 ost_idx) -{ - return FID_SEQ_IDIF | (ost_idx << 16) | ((id >> 32) & 0xffff); -} - -/* convert a packed IDIF FID into an OST objid */ -static inline __u64 fid_idif_id(__u64 seq, __u32 oid, __u32 ver) -{ - return ((__u64)ver << 48) | ((seq & 0xffff) << 32) | oid; -} - -/* extract ost index from IDIF FID */ -static inline __u32 fid_idif_ost_idx(const struct lu_fid *fid) -{ - return (fid_seq(fid) >> 16) & 0xffff; -} - -/* extract OST sequence (group) from a wire ost_id (id/seq) pair */ -static inline __u64 ostid_seq(const struct ost_id *ostid) -{ - if (fid_seq_is_mdt0(ostid->oi.oi_seq)) - return FID_SEQ_OST_MDT0; - - if (unlikely(fid_seq_is_default(ostid->oi.oi_seq))) - return FID_SEQ_LOV_DEFAULT; - - if (fid_is_idif(&ostid->oi_fid)) - return FID_SEQ_OST_MDT0; - - return fid_seq(&ostid->oi_fid); -} - -/* extract OST objid from a wire ost_id (id/seq) pair */ -static inline __u64 ostid_id(const struct ost_id *ostid) -{ - if (fid_seq_is_mdt0(ostid->oi.oi_seq)) - return ostid->oi.oi_id & IDIF_OID_MASK; - - if (unlikely(fid_seq_is_default(ostid->oi.oi_seq))) - return ostid->oi.oi_id; - - if (fid_is_idif(&ostid->oi_fid)) - return fid_idif_id(fid_seq(&ostid->oi_fid), - fid_oid(&ostid->oi_fid), 0); - - return fid_oid(&ostid->oi_fid); -} - -static inline void ostid_set_seq(struct ost_id *oi, __u64 seq) -{ - if (fid_seq_is_mdt0(seq) || fid_seq_is_default(seq)) { - oi->oi.oi_seq = seq; - } else { - oi->oi_fid.f_seq = seq; - /* Note: if f_oid + f_ver is zero, we need init it - * to be 1, otherwise, ostid_seq will treat this - * as old ostid (oi_seq == 0) - */ - if (oi->oi_fid.f_oid == 0 && oi->oi_fid.f_ver == 0) - oi->oi_fid.f_oid = LUSTRE_FID_INIT_OID; - } -} - -static inline void ostid_set_seq_mdt0(struct ost_id *oi) -{ - ostid_set_seq(oi, FID_SEQ_OST_MDT0); -} - -static inline void ostid_set_seq_echo(struct ost_id *oi) -{ - ostid_set_seq(oi, FID_SEQ_ECHO); -} - -static inline void ostid_set_seq_llog(struct ost_id *oi) -{ - ostid_set_seq(oi, FID_SEQ_LLOG); -} - -/** - * Note: we need check oi_seq to decide where to set oi_id, - * so oi_seq should always be set ahead of oi_id. - */ -static inline void ostid_set_id(struct ost_id *oi, __u64 oid) -{ - if (fid_seq_is_mdt0(oi->oi.oi_seq)) { - if (oid >= IDIF_MAX_OID) { - CERROR("Too large OID %#llx to set MDT0 " DOSTID "\n", - oid, POSTID(oi)); - return; - } - oi->oi.oi_id = oid; - } else if (fid_is_idif(&oi->oi_fid)) { - if (oid >= IDIF_MAX_OID) { - CERROR("Too large OID %#llx to set IDIF " DOSTID "\n", - oid, POSTID(oi)); - return; - } - oi->oi_fid.f_seq = fid_idif_seq(oid, - fid_idif_ost_idx(&oi->oi_fid)); - oi->oi_fid.f_oid = oid; - oi->oi_fid.f_ver = oid >> 48; - } else { - if (oid >= OBIF_MAX_OID) { - CERROR("Bad %llu to set " DOSTID "\n", oid, POSTID(oi)); - return; - } - oi->oi_fid.f_oid = oid; - } -} - -static inline int fid_set_id(struct lu_fid *fid, __u64 oid) -{ - if (unlikely(fid_seq_is_igif(fid->f_seq))) { - CERROR("bad IGIF, " DFID "\n", PFID(fid)); - return -EBADF; - } - - if (fid_is_idif(fid)) { - if (oid >= IDIF_MAX_OID) { - CERROR("Too large OID %#llx to set IDIF " DFID "\n", - (unsigned long long)oid, PFID(fid)); - return -EBADF; - } - fid->f_seq = fid_idif_seq(oid, fid_idif_ost_idx(fid)); - fid->f_oid = oid; - fid->f_ver = oid >> 48; - } else { - if (oid >= OBIF_MAX_OID) { - CERROR("Too large OID %#llx to set REG " DFID "\n", - (unsigned long long)oid, PFID(fid)); - return -EBADF; - } - fid->f_oid = oid; - } - return 0; -} - -/** - * Unpack an OST object id/seq (group) into a FID. This is needed for - * converting all obdo, lmm, lsm, etc. 64-bit id/seq pairs into proper - * FIDs. Note that if an id/seq is already in FID/IDIF format it will - * be passed through unchanged. Only legacy OST objects in "group 0" - * will be mapped into the IDIF namespace so that they can fit into the - * struct lu_fid fields without loss. For reference see: - * http://wiki.old.lustre.org/index.php/Architecture_-_Interoperability_fids_zfs - */ -static inline int ostid_to_fid(struct lu_fid *fid, struct ost_id *ostid, - __u32 ost_idx) -{ - __u64 seq = ostid_seq(ostid); - - if (ost_idx > 0xffff) { - CERROR("bad ost_idx, " DOSTID " ost_idx:%u\n", POSTID(ostid), - ost_idx); - return -EBADF; - } - - if (fid_seq_is_mdt0(seq)) { - __u64 oid = ostid_id(ostid); - - /* This is a "legacy" (old 1.x/2.early) OST object in "group 0" - * that we map into the IDIF namespace. It allows up to 2^48 - * objects per OST, as this is the object namespace that has - * been in production for years. This can handle create rates - * of 1M objects/s/OST for 9 years, or combinations thereof. - */ - if (oid >= IDIF_MAX_OID) { - CERROR("bad MDT0 id, " DOSTID " ost_idx:%u\n", - POSTID(ostid), ost_idx); - return -EBADF; - } - fid->f_seq = fid_idif_seq(oid, ost_idx); - /* truncate to 32 bits by assignment */ - fid->f_oid = oid; - /* in theory, not currently used */ - fid->f_ver = oid >> 48; - } else if (likely(!fid_seq_is_default(seq))) { - /* This is either an IDIF object, which identifies objects across - * all OSTs, or a regular FID. The IDIF namespace maps legacy - * OST objects into the FID namespace. In both cases, we just - * pass the FID through, no conversion needed. - */ - if (ostid->oi_fid.f_ver != 0) { - CERROR("bad MDT0 id, " DOSTID " ost_idx:%u\n", - POSTID(ostid), ost_idx); - return -EBADF; - } - *fid = ostid->oi_fid; - } - - return 0; -} - -/* pack any OST FID into an ostid (id/seq) for the wire/disk */ -static inline int fid_to_ostid(const struct lu_fid *fid, struct ost_id *ostid) -{ - if (unlikely(fid_seq_is_igif(fid->f_seq))) { - CERROR("bad IGIF, " DFID "\n", PFID(fid)); - return -EBADF; - } - - if (fid_is_idif(fid)) { - ostid_set_seq_mdt0(ostid); - ostid_set_id(ostid, fid_idif_id(fid_seq(fid), fid_oid(fid), - fid_ver(fid))); - } else { - ostid->oi_fid = *fid; - } - - return 0; -} - -/* Check whether the fid is for LAST_ID */ -static inline bool fid_is_last_id(const struct lu_fid *fid) -{ - return (fid_oid(fid) == 0); -} - -/** - * Get inode number from a igif. - * \param fid a igif to get inode number from. - * \return inode number for the igif. - */ -static inline ino_t lu_igif_ino(const struct lu_fid *fid) -{ - return fid_seq(fid); -} - -/** - * Get inode generation from a igif. - * \param fid a igif to get inode generation from. - * \return inode generation for the igif. - */ -static inline __u32 lu_igif_gen(const struct lu_fid *fid) -{ - return fid_oid(fid); -} - -/** - * Build igif from the inode number/generation. - */ -static inline void lu_igif_build(struct lu_fid *fid, __u32 ino, __u32 gen) -{ - fid->f_seq = ino; - fid->f_oid = gen; - fid->f_ver = 0; -} - -/* - * Fids are transmitted across network (in the sender byte-ordering), - * and stored on disk in big-endian order. - */ -static inline void fid_cpu_to_le(struct lu_fid *dst, const struct lu_fid *src) -{ - dst->f_seq = cpu_to_le64(fid_seq(src)); - dst->f_oid = cpu_to_le32(fid_oid(src)); - dst->f_ver = cpu_to_le32(fid_ver(src)); -} - -static inline void fid_le_to_cpu(struct lu_fid *dst, const struct lu_fid *src) -{ - dst->f_seq = le64_to_cpu(fid_seq(src)); - dst->f_oid = le32_to_cpu(fid_oid(src)); - dst->f_ver = le32_to_cpu(fid_ver(src)); -} - -static inline void fid_cpu_to_be(struct lu_fid *dst, const struct lu_fid *src) -{ - dst->f_seq = cpu_to_be64(fid_seq(src)); - dst->f_oid = cpu_to_be32(fid_oid(src)); - dst->f_ver = cpu_to_be32(fid_ver(src)); -} - -static inline void fid_be_to_cpu(struct lu_fid *dst, const struct lu_fid *src) -{ - dst->f_seq = be64_to_cpu(fid_seq(src)); - dst->f_oid = be32_to_cpu(fid_oid(src)); - dst->f_ver = be32_to_cpu(fid_ver(src)); -} - -static inline bool fid_is_sane(const struct lu_fid *fid) -{ - return fid && - ((fid_seq(fid) >= FID_SEQ_START && fid_ver(fid) == 0) || - fid_is_igif(fid) || fid_is_idif(fid) || - fid_seq_is_rsvd(fid_seq(fid))); -} - -static inline bool lu_fid_eq(const struct lu_fid *f0, const struct lu_fid *f1) -{ - return memcmp(f0, f1, sizeof(*f0)) == 0; -} - -#define __diff_normalize(val0, val1) \ -({ \ - typeof(val0) __val0 = (val0); \ - typeof(val1) __val1 = (val1); \ - \ - (__val0 == __val1 ? 0 : __val0 > __val1 ? 1 : -1); \ -}) - -static inline int lu_fid_cmp(const struct lu_fid *f0, - const struct lu_fid *f1) -{ - return - __diff_normalize(fid_seq(f0), fid_seq(f1)) ?: - __diff_normalize(fid_oid(f0), fid_oid(f1)) ?: - __diff_normalize(fid_ver(f0), fid_ver(f1)); -} - -static inline void ostid_cpu_to_le(const struct ost_id *src_oi, - struct ost_id *dst_oi) -{ - if (fid_seq_is_mdt0(ostid_seq(src_oi))) { - dst_oi->oi.oi_id = cpu_to_le64(src_oi->oi.oi_id); - dst_oi->oi.oi_seq = cpu_to_le64(src_oi->oi.oi_seq); - } else { - fid_cpu_to_le(&dst_oi->oi_fid, &src_oi->oi_fid); - } -} - -static inline void ostid_le_to_cpu(const struct ost_id *src_oi, - struct ost_id *dst_oi) -{ - if (fid_seq_is_mdt0(ostid_seq(src_oi))) { - dst_oi->oi.oi_id = le64_to_cpu(src_oi->oi.oi_id); - dst_oi->oi.oi_seq = le64_to_cpu(src_oi->oi.oi_seq); - } else { - fid_le_to_cpu(&dst_oi->oi_fid, &src_oi->oi_fid); - } -} - /** @} lu_fid */ /** \defgroup lu_dir lu_dir @@ -866,7 +390,7 @@ enum lu_dirpage_flags { static inline struct lu_dirent *lu_dirent_start(struct lu_dirpage *dp) { - if (le32_to_cpu(dp->ldp_flags) & LDF_EMPTY) + if (__le32_to_cpu(dp->ldp_flags) & LDF_EMPTY) return NULL; else return dp->ldp_entries; @@ -876,8 +400,8 @@ static inline struct lu_dirent *lu_dirent_next(struct lu_dirent *ent) { struct lu_dirent *next; - if (le16_to_cpu(ent->lde_reclen) != 0) - next = ((void *)ent) + le16_to_cpu(ent->lde_reclen); + if (__le16_to_cpu(ent->lde_reclen) != 0) + next = ((void *)ent) + __le16_to_cpu(ent->lde_reclen); else next = NULL; @@ -1122,7 +646,7 @@ struct ptlrpc_body_v2 { #define OBD_CONNECT_AT 0x1000000ULL /*client uses AT */ #define OBD_CONNECT_LRU_RESIZE 0x2000000ULL /*LRU resize feature. */ #define OBD_CONNECT_MDS_MDS 0x4000000ULL /*MDS-MDS connection */ -#define OBD_CONNECT_REAL 0x8000000ULL /*real connection */ +#define OBD_CONNECT_REAL 0x8000000ULL /* obsolete since 2.8 */ #define OBD_CONNECT_CHANGE_QS 0x10000000ULL /*Not used since 2.4 */ #define OBD_CONNECT_CKSUM 0x20000000ULL /*support several cksum algos*/ #define OBD_CONNECT_FID 0x40000000ULL /*FID is supported by server */ @@ -1384,71 +908,6 @@ struct lov_mds_md_v1 { /* LOV EA mds/wire data (little-endian) */ struct lov_ost_data_v1 lmm_objects[0]; /* per-stripe data */ }; -/** - * Sigh, because pre-2.4 uses - * struct lov_mds_md_v1 { - * ........ - * __u64 lmm_object_id; - * __u64 lmm_object_seq; - * ...... - * } - * to identify the LOV(MDT) object, and lmm_object_seq will - * be normal_fid, which make it hard to combine these conversion - * to ostid_to FID. so we will do lmm_oi/fid conversion separately - * - * We can tell the lmm_oi by this way, - * 1.8: lmm_object_id = {inode}, lmm_object_gr = 0 - * 2.1: lmm_object_id = {oid < 128k}, lmm_object_seq = FID_SEQ_NORMAL - * 2.4: lmm_oi.f_seq = FID_SEQ_NORMAL, lmm_oi.f_oid = {oid < 128k}, - * lmm_oi.f_ver = 0 - * - * But currently lmm_oi/lsm_oi does not have any "real" usages, - * except for printing some information, and the user can always - * get the real FID from LMA, besides this multiple case check might - * make swab more complicate. So we will keep using id/seq for lmm_oi. - */ - -static inline void fid_to_lmm_oi(const struct lu_fid *fid, - struct ost_id *oi) -{ - oi->oi.oi_id = fid_oid(fid); - oi->oi.oi_seq = fid_seq(fid); -} - -static inline void lmm_oi_set_seq(struct ost_id *oi, __u64 seq) -{ - oi->oi.oi_seq = seq; -} - -static inline void lmm_oi_set_id(struct ost_id *oi, __u64 oid) -{ - oi->oi.oi_id = oid; -} - -static inline __u64 lmm_oi_id(const struct ost_id *oi) -{ - return oi->oi.oi_id; -} - -static inline __u64 lmm_oi_seq(const struct ost_id *oi) -{ - return oi->oi.oi_seq; -} - -static inline void lmm_oi_le_to_cpu(struct ost_id *dst_oi, - const struct ost_id *src_oi) -{ - dst_oi->oi.oi_id = le64_to_cpu(src_oi->oi.oi_id); - dst_oi->oi.oi_seq = le64_to_cpu(src_oi->oi.oi_seq); -} - -static inline void lmm_oi_cpu_to_le(struct ost_id *dst_oi, - const struct ost_id *src_oi) -{ - dst_oi->oi.oi_id = cpu_to_le64(src_oi->oi.oi_id); - dst_oi->oi.oi_seq = cpu_to_le64(src_oi->oi.oi_seq); -} - #define MAX_MD_SIZE \ (sizeof(struct lov_mds_md) + 4 * sizeof(struct lov_ost_data)) #define MIN_MD_SIZE \ @@ -2095,8 +1554,8 @@ enum mds_op_bias { MDS_CREATE_VOLATILE = 1 << 10, MDS_OWNEROVERRIDE = 1 << 11, MDS_HSM_RELEASE = 1 << 12, - MDS_RENAME_MIGRATE = BIT(13), - MDS_CLOSE_LAYOUT_SWAP = BIT(14), + MDS_RENAME_MIGRATE = 1 << 13, + MDS_CLOSE_LAYOUT_SWAP = 1 << 14, }; /* instance of mdt_reint_rec */ @@ -2130,17 +1589,6 @@ struct mdt_rec_create { __u32 cr_padding_4; /* rr_padding_4 */ }; -static inline void set_mrc_cr_flags(struct mdt_rec_create *mrc, __u64 flags) -{ - mrc->cr_flags_l = (__u32)(flags & 0xFFFFFFFFUll); - mrc->cr_flags_h = (__u32)(flags >> 32); -} - -static inline __u64 get_mrc_cr_flags(struct mdt_rec_create *mrc) -{ - return ((__u64)(mrc->cr_flags_l) | ((__u64)mrc->cr_flags_h << 32)); -} - /* instance of mdt_reint_rec */ struct mdt_rec_link { __u32 lk_opcode; @@ -2393,35 +1841,16 @@ static inline ssize_t lmv_mds_md_size(int stripe_count, unsigned int lmm_magic) static inline int lmv_mds_md_stripe_count_get(const union lmv_mds_md *lmm) { - switch (le32_to_cpu(lmm->lmv_magic)) { + switch (__le32_to_cpu(lmm->lmv_magic)) { case LMV_MAGIC_V1: - return le32_to_cpu(lmm->lmv_md_v1.lmv_stripe_count); + return __le32_to_cpu(lmm->lmv_md_v1.lmv_stripe_count); case LMV_USER_MAGIC: - return le32_to_cpu(lmm->lmv_user_md.lum_stripe_count); + return __le32_to_cpu(lmm->lmv_user_md.lum_stripe_count); default: return -EINVAL; } } -static inline int lmv_mds_md_stripe_count_set(union lmv_mds_md *lmm, - unsigned int stripe_count) -{ - int rc = 0; - - switch (le32_to_cpu(lmm->lmv_magic)) { - case LMV_MAGIC_V1: - lmm->lmv_md_v1.lmv_stripe_count = cpu_to_le32(stripe_count); - break; - case LMV_USER_MAGIC: - lmm->lmv_user_md.lum_stripe_count = cpu_to_le32(stripe_count); - break; - default: - rc = -EINVAL; - break; - } - return rc; -} - enum fld_rpc_opc { FLD_QUERY = 900, FLD_READ = 901, @@ -2502,12 +1931,6 @@ struct ldlm_res_id { #define PLDLMRES(res) (res)->lr_name.name[0], (res)->lr_name.name[1], \ (res)->lr_name.name[2], (res)->lr_name.name[3] -static inline bool ldlm_res_eq(const struct ldlm_res_id *res0, - const struct ldlm_res_id *res1) -{ - return !memcmp(res0, res1, sizeof(*res0)); -} - /* lock types */ enum ldlm_mode { LCK_MINMODE = 0, @@ -2540,19 +1963,6 @@ struct ldlm_extent { __u64 gid; }; -static inline int ldlm_extent_overlap(const struct ldlm_extent *ex1, - const struct ldlm_extent *ex2) -{ - return (ex1->start <= ex2->end) && (ex2->start <= ex1->end); -} - -/* check if @ex1 contains @ex2 */ -static inline int ldlm_extent_contain(const struct ldlm_extent *ex1, - const struct ldlm_extent *ex2) -{ - return (ex1->start <= ex2->start) && (ex1->end >= ex2->end); -} - struct ldlm_inodebits { __u64 bits; }; @@ -2583,21 +1993,21 @@ union ldlm_gl_desc { }; enum ldlm_intent_flags { - IT_OPEN = BIT(0), - IT_CREAT = BIT(1), - IT_OPEN_CREAT = BIT(1) | BIT(0), - IT_READDIR = BIT(2), - IT_GETATTR = BIT(3), - IT_LOOKUP = BIT(4), - IT_UNLINK = BIT(5), - IT_TRUNC = BIT(6), - IT_GETXATTR = BIT(7), - IT_EXEC = BIT(8), - IT_PIN = BIT(9), - IT_LAYOUT = BIT(10), - IT_QUOTA_DQACQ = BIT(11), - IT_QUOTA_CONN = BIT(12), - IT_SETXATTR = BIT(13), + IT_OPEN = 0x00000001, + IT_CREAT = 0x00000002, + IT_OPEN_CREAT = 0x00000003, + IT_READDIR = 0x00000004, + IT_GETATTR = 0x00000008, + IT_LOOKUP = 0x00000010, + IT_UNLINK = 0x00000020, + IT_TRUNC = 0x00000040, + IT_GETXATTR = 0x00000080, + IT_EXEC = 0x00000100, + IT_PIN = 0x00000200, + IT_LAYOUT = 0x00000400, + IT_QUOTA_DQACQ = 0x00000800, + IT_QUOTA_CONN = 0x00001000, + IT_SETXATTR = 0x00002000, }; struct ldlm_intent { @@ -2627,18 +2037,6 @@ struct ldlm_request { struct lustre_handle lock_handle[LDLM_LOCKREQ_HANDLES]; }; -/* If LDLM_ENQUEUE, 1 slot is already occupied, 1 is available. - * Otherwise, 2 are available. - */ -#define ldlm_request_bufsize(count, type) \ -({ \ - int _avail = LDLM_LOCKREQ_HANDLES; \ - _avail -= (type == LDLM_ENQUEUE ? LDLM_ENQUEUE_CANCEL_OFF : 0); \ - sizeof(struct ldlm_request) + \ - (count > _avail ? count - _avail : 0) * \ - sizeof(struct lustre_handle); \ -}) - struct ldlm_reply { __u32 lock_flags; __u32 lock_padding; /* also fix lustre_swab_ldlm_reply */ @@ -2942,12 +2340,6 @@ static inline const char *agent_req_status2name(const enum agent_req_status ars) } } -static inline bool agent_req_in_final_state(enum agent_req_status ars) -{ - return ((ars == ARS_SUCCEED) || (ars == ARS_FAILED) || - (ars == ARS_CANCELED)); -} - struct llog_agent_req_rec { struct llog_rec_hdr arr_hdr; /**< record header */ __u32 arr_status; /**< status of the request */ @@ -2983,8 +2375,8 @@ enum llog_flag { LLOG_F_ZAP_WHEN_EMPTY = 0x1, LLOG_F_IS_CAT = 0x2, LLOG_F_IS_PLAIN = 0x4, - LLOG_F_EXT_JOBID = BIT(3), - LLOG_F_IS_FIXSIZE = BIT(4), + LLOG_F_EXT_JOBID = 0x8, + LLOG_F_IS_FIXSIZE = 0x10, /* * Note: Flags covered by LLOG_F_EXT_MASK will be inherited from @@ -3142,12 +2534,6 @@ struct ll_fiemap_info_key { struct fiemap lfik_fiemap; }; -/* Functions for dumping PTLRPC fields */ -void dump_rniobuf(struct niobuf_remote *rnb); -void dump_ioo(struct obd_ioobj *nb); -void dump_ost_body(struct ost_body *ob); -void dump_rcs(__u32 *rc); - /* security opcodes */ enum sec_cmd { SEC_CTX_INIT = 801, @@ -3217,9 +2603,8 @@ struct link_ea_header { __u32 leh_magic; __u32 leh_reccount; __u64 leh_len; /* total size */ - /* future use */ - __u32 padding1; - __u32 padding2; + __u32 leh_overflow_time; + __u32 leh_padding; }; /** Hardlink data is name and parent fid. diff --git a/drivers/staging/lustre/lustre/include/lustre/lustre_ioctl.h b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_ioctl.h index eb08df33b2db..9590864e0b50 100644 --- a/drivers/staging/lustre/lustre/include/lustre/lustre_ioctl.h +++ b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_ioctl.h @@ -25,22 +25,13 @@ * * Copyright (c) 2011, 2015, Intel Corporation. */ -#ifndef LUSTRE_IOCTL_H_ -#define LUSTRE_IOCTL_H_ +#ifndef _UAPI_LUSTRE_IOCTL_H_ +#define _UAPI_LUSTRE_IOCTL_H_ +#include <linux/ioctl.h> +#include <linux/kernel.h> #include <linux/types.h> -#include "../../../include/linux/libcfs/libcfs.h" -#include "lustre_idl.h" - -#ifdef __KERNEL__ -# include <linux/ioctl.h> -# include <linux/string.h> -# include "../obd_support.h" -#else /* __KERNEL__ */ -# include <malloc.h> -# include <string.h> -#include <libcfs/util/ioctl.h> -#endif /* !__KERNEL__ */ +#include <uapi/linux/lustre/lustre_idl.h> #if !defined(__KERNEL__) && !defined(LUSTRE_UTILS) # error This file is for Lustre internal use only. @@ -65,7 +56,6 @@ enum md_echo_cmd { #define OBD_IOCTL_VERSION 0x00010004 #define OBD_DEV_BY_DEVNAME 0xffffd0de -#define OBD_MAX_IOCTL_BUFFER CONFIG_LUSTRE_OBD_MAX_IOCTL_BUFFER struct obd_ioctl_data { __u32 ioc_len; @@ -122,187 +112,16 @@ struct obd_ioctl_hdr { static inline __u32 obd_ioctl_packlen(struct obd_ioctl_data *data) { - __u32 len = cfs_size_round(sizeof(*data)); + __u32 len = __ALIGN_KERNEL(sizeof(*data), 8); - len += cfs_size_round(data->ioc_inllen1); - len += cfs_size_round(data->ioc_inllen2); - len += cfs_size_round(data->ioc_inllen3); - len += cfs_size_round(data->ioc_inllen4); + len += __ALIGN_KERNEL(data->ioc_inllen1, 8); + len += __ALIGN_KERNEL(data->ioc_inllen2, 8); + len += __ALIGN_KERNEL(data->ioc_inllen3, 8); + len += __ALIGN_KERNEL(data->ioc_inllen4, 8); return len; } -static inline int obd_ioctl_is_invalid(struct obd_ioctl_data *data) -{ - if (data->ioc_len > (1 << 30)) { - CERROR("OBD ioctl: ioc_len larger than 1<<30\n"); - return 1; - } - - if (data->ioc_inllen1 > (1 << 30)) { - CERROR("OBD ioctl: ioc_inllen1 larger than 1<<30\n"); - return 1; - } - - if (data->ioc_inllen2 > (1 << 30)) { - CERROR("OBD ioctl: ioc_inllen2 larger than 1<<30\n"); - return 1; - } - - if (data->ioc_inllen3 > (1 << 30)) { - CERROR("OBD ioctl: ioc_inllen3 larger than 1<<30\n"); - return 1; - } - - if (data->ioc_inllen4 > (1 << 30)) { - CERROR("OBD ioctl: ioc_inllen4 larger than 1<<30\n"); - return 1; - } - - if (data->ioc_inlbuf1 && !data->ioc_inllen1) { - CERROR("OBD ioctl: inlbuf1 pointer but 0 length\n"); - return 1; - } - - if (data->ioc_inlbuf2 && !data->ioc_inllen2) { - CERROR("OBD ioctl: inlbuf2 pointer but 0 length\n"); - return 1; - } - - if (data->ioc_inlbuf3 && !data->ioc_inllen3) { - CERROR("OBD ioctl: inlbuf3 pointer but 0 length\n"); - return 1; - } - - if (data->ioc_inlbuf4 && !data->ioc_inllen4) { - CERROR("OBD ioctl: inlbuf4 pointer but 0 length\n"); - return 1; - } - - if (data->ioc_pbuf1 && !data->ioc_plen1) { - CERROR("OBD ioctl: pbuf1 pointer but 0 length\n"); - return 1; - } - - if (data->ioc_pbuf2 && !data->ioc_plen2) { - CERROR("OBD ioctl: pbuf2 pointer but 0 length\n"); - return 1; - } - - if (!data->ioc_pbuf1 && data->ioc_plen1) { - CERROR("OBD ioctl: plen1 set but NULL pointer\n"); - return 1; - } - - if (!data->ioc_pbuf2 && data->ioc_plen2) { - CERROR("OBD ioctl: plen2 set but NULL pointer\n"); - return 1; - } - - if (obd_ioctl_packlen(data) > data->ioc_len) { - CERROR("OBD ioctl: packlen exceeds ioc_len (%d > %d)\n", - obd_ioctl_packlen(data), data->ioc_len); - return 1; - } - - return 0; -} - -#ifdef __KERNEL__ - -int obd_ioctl_getdata(char **buf, int *len, void __user *arg); -int obd_ioctl_popdata(void __user *arg, void *data, int len); - -static inline void obd_ioctl_freedata(char *buf, size_t len) -{ - kvfree(buf); -} - -#else /* __KERNEL__ */ - -static inline int obd_ioctl_pack(struct obd_ioctl_data *data, char **pbuf, - int max_len) -{ - char *ptr; - struct obd_ioctl_data *overlay; - - data->ioc_len = obd_ioctl_packlen(data); - data->ioc_version = OBD_IOCTL_VERSION; - - if (*pbuf && data->ioc_len > max_len) { - fprintf(stderr, "pbuf = %p, ioc_len = %u, max_len = %d\n", - *pbuf, data->ioc_len, max_len); - return -EINVAL; - } - - if (!*pbuf) - *pbuf = malloc(data->ioc_len); - - if (!*pbuf) - return -ENOMEM; - - overlay = (struct obd_ioctl_data *)*pbuf; - memcpy(*pbuf, data, sizeof(*data)); - - ptr = overlay->ioc_bulk; - if (data->ioc_inlbuf1) - LOGL(data->ioc_inlbuf1, data->ioc_inllen1, ptr); - - if (data->ioc_inlbuf2) - LOGL(data->ioc_inlbuf2, data->ioc_inllen2, ptr); - - if (data->ioc_inlbuf3) - LOGL(data->ioc_inlbuf3, data->ioc_inllen3, ptr); - - if (data->ioc_inlbuf4) - LOGL(data->ioc_inlbuf4, data->ioc_inllen4, ptr); - - if (obd_ioctl_is_invalid(overlay)) { - fprintf(stderr, "invalid ioctl data: ioc_len = %u, max_len = %d\n", - data->ioc_len, max_len); - return -EINVAL; - } - - return 0; -} - -static inline int -obd_ioctl_unpack(struct obd_ioctl_data *data, char *pbuf, int max_len) -{ - char *ptr; - struct obd_ioctl_data *overlay; - - if (!pbuf) - return 1; - - overlay = (struct obd_ioctl_data *)pbuf; - - /* Preserve the caller's buffer pointers */ - overlay->ioc_inlbuf1 = data->ioc_inlbuf1; - overlay->ioc_inlbuf2 = data->ioc_inlbuf2; - overlay->ioc_inlbuf3 = data->ioc_inlbuf3; - overlay->ioc_inlbuf4 = data->ioc_inlbuf4; - - memcpy(data, pbuf, sizeof(*data)); - - ptr = overlay->ioc_bulk; - if (data->ioc_inlbuf1) - LOGU(data->ioc_inlbuf1, data->ioc_inllen1, ptr); - - if (data->ioc_inlbuf2) - LOGU(data->ioc_inlbuf2, data->ioc_inllen2, ptr); - - if (data->ioc_inlbuf3) - LOGU(data->ioc_inlbuf3, data->ioc_inllen3, ptr); - - if (data->ioc_inlbuf4) - LOGU(data->ioc_inlbuf4, data->ioc_inllen4, ptr); - - return 0; -} - -#endif /* !__KERNEL__ */ - /* * OBD_IOC_DATA_TYPE is only for compatibility reasons with older * Linux Lustre user tools. New ioctls should NOT use this macro as @@ -409,4 +228,4 @@ obd_ioctl_unpack(struct obd_ioctl_data *data, char *pbuf, int max_len) #define IOC_OSC_SET_ACTIVE _IOWR('h', 21, void *) -#endif /* LUSTRE_IOCTL_H_ */ +#endif /* _UAPI_LUSTRE_IOCTL_H_ */ diff --git a/drivers/staging/lustre/lustre/include/uapi_kernelcomm.h b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_kernelcomm.h index 5e998362e44b..94dadbe8e069 100644 --- a/drivers/staging/lustre/lustre/include/uapi_kernelcomm.h +++ b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_kernelcomm.h @@ -34,8 +34,8 @@ * The definitions below are used in the kernel and userspace. */ -#ifndef __UAPI_KERNELCOMM_H__ -#define __UAPI_KERNELCOMM_H__ +#ifndef __UAPI_LUSTRE_KERNELCOMM_H__ +#define __UAPI_LUSTRE_KERNELCOMM_H__ #include <linux/types.h> @@ -91,4 +91,4 @@ struct lustre_kernelcomm { __u32 lk_flags; } __packed; -#endif /* __UAPI_KERNELCOMM_H__ */ +#endif /* __UAPI_LUSTRE_KERNELCOMM_H__ */ diff --git a/drivers/staging/lustre/include/uapi/linux/lustre/lustre_ostid.h b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_ostid.h new file mode 100644 index 000000000000..3343b602219b --- /dev/null +++ b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_ostid.h @@ -0,0 +1,236 @@ +/* + * GPL HEADER START + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 only, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 for more details (a copy is included + * in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; If not, see + * http://www.gnu.org/licenses/gpl-2.0.html + * + * GPL HEADER END + */ +/* + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. + * Use is subject to license terms. + * + * Copyright (c) 2011, 2014, Intel Corporation. + * + * Copyright 2015 Cray Inc, all rights reserved. + * Author: Ben Evans. + * + * Define ost_id associated functions + */ + +#ifndef _UAPI_LUSTRE_OSTID_H_ +#define _UAPI_LUSTRE_OSTID_H_ + +#include <linux/errno.h> +#include <uapi/linux/lustre/lustre_fid.h> + +static inline __u64 lmm_oi_id(const struct ost_id *oi) +{ + return oi->oi.oi_id; +} + +static inline __u64 lmm_oi_seq(const struct ost_id *oi) +{ + return oi->oi.oi_seq; +} + +static inline void lmm_oi_set_seq(struct ost_id *oi, __u64 seq) +{ + oi->oi.oi_seq = seq; +} + +static inline void lmm_oi_set_id(struct ost_id *oi, __u64 oid) +{ + oi->oi.oi_id = oid; +} + +static inline void lmm_oi_le_to_cpu(struct ost_id *dst_oi, + const struct ost_id *src_oi) +{ + dst_oi->oi.oi_id = __le64_to_cpu(src_oi->oi.oi_id); + dst_oi->oi.oi_seq = __le64_to_cpu(src_oi->oi.oi_seq); +} + +static inline void lmm_oi_cpu_to_le(struct ost_id *dst_oi, + const struct ost_id *src_oi) +{ + dst_oi->oi.oi_id = __cpu_to_le64(src_oi->oi.oi_id); + dst_oi->oi.oi_seq = __cpu_to_le64(src_oi->oi.oi_seq); +} + +/* extract OST sequence (group) from a wire ost_id (id/seq) pair */ +static inline __u64 ostid_seq(const struct ost_id *ostid) +{ + if (fid_seq_is_mdt0(ostid->oi.oi_seq)) + return FID_SEQ_OST_MDT0; + + if (fid_seq_is_default(ostid->oi.oi_seq)) + return FID_SEQ_LOV_DEFAULT; + + if (fid_is_idif(&ostid->oi_fid)) + return FID_SEQ_OST_MDT0; + + return fid_seq(&ostid->oi_fid); +} + +/* extract OST objid from a wire ost_id (id/seq) pair */ +static inline __u64 ostid_id(const struct ost_id *ostid) +{ + if (fid_seq_is_mdt0(ostid->oi.oi_seq)) + return ostid->oi.oi_id & IDIF_OID_MASK; + + if (fid_seq_is_default(ostid->oi.oi_seq)) + return ostid->oi.oi_id; + + if (fid_is_idif(&ostid->oi_fid)) + return fid_idif_id(fid_seq(&ostid->oi_fid), + fid_oid(&ostid->oi_fid), 0); + + return fid_oid(&ostid->oi_fid); +} + +static inline void ostid_set_seq(struct ost_id *oi, __u64 seq) +{ + if (fid_seq_is_mdt0(seq) || fid_seq_is_default(seq)) { + oi->oi.oi_seq = seq; + } else { + oi->oi_fid.f_seq = seq; + /* + * Note: if f_oid + f_ver is zero, we need init it + * to be 1, otherwise, ostid_seq will treat this + * as old ostid (oi_seq == 0) + */ + if (!oi->oi_fid.f_oid && !oi->oi_fid.f_ver) + oi->oi_fid.f_oid = LUSTRE_FID_INIT_OID; + } +} + +static inline void ostid_set_seq_mdt0(struct ost_id *oi) +{ + ostid_set_seq(oi, FID_SEQ_OST_MDT0); +} + +static inline void ostid_set_seq_echo(struct ost_id *oi) +{ + ostid_set_seq(oi, FID_SEQ_ECHO); +} + +static inline void ostid_set_seq_llog(struct ost_id *oi) +{ + ostid_set_seq(oi, FID_SEQ_LLOG); +} + +static inline void ostid_cpu_to_le(const struct ost_id *src_oi, + struct ost_id *dst_oi) +{ + if (fid_seq_is_mdt0(src_oi->oi.oi_seq)) { + dst_oi->oi.oi_id = __cpu_to_le64(src_oi->oi.oi_id); + dst_oi->oi.oi_seq = __cpu_to_le64(src_oi->oi.oi_seq); + } else { + fid_cpu_to_le(&dst_oi->oi_fid, &src_oi->oi_fid); + } +} + +static inline void ostid_le_to_cpu(const struct ost_id *src_oi, + struct ost_id *dst_oi) +{ + if (fid_seq_is_mdt0(src_oi->oi.oi_seq)) { + dst_oi->oi.oi_id = __le64_to_cpu(src_oi->oi.oi_id); + dst_oi->oi.oi_seq = __le64_to_cpu(src_oi->oi.oi_seq); + } else { + fid_le_to_cpu(&dst_oi->oi_fid, &src_oi->oi_fid); + } +} + +/** + * Sigh, because pre-2.4 uses + * struct lov_mds_md_v1 { + * ........ + * __u64 lmm_object_id; + * __u64 lmm_object_seq; + * ...... + * } + * to identify the LOV(MDT) object, and lmm_object_seq will + * be normal_fid, which make it hard to combine these conversion + * to ostid_to FID. so we will do lmm_oi/fid conversion separately + * + * We can tell the lmm_oi by this way, + * 1.8: lmm_object_id = {inode}, lmm_object_gr = 0 + * 2.1: lmm_object_id = {oid < 128k}, lmm_object_seq = FID_SEQ_NORMAL + * 2.4: lmm_oi.f_seq = FID_SEQ_NORMAL, lmm_oi.f_oid = {oid < 128k}, + * lmm_oi.f_ver = 0 + * + * But currently lmm_oi/lsm_oi does not have any "real" usages, + * except for printing some information, and the user can always + * get the real FID from LMA, besides this multiple case check might + * make swab more complicate. So we will keep using id/seq for lmm_oi. + */ + +static inline void fid_to_lmm_oi(const struct lu_fid *fid, + struct ost_id *oi) +{ + oi->oi.oi_id = fid_oid(fid); + oi->oi.oi_seq = fid_seq(fid); +} + +/** + * Unpack an OST object id/seq (group) into a FID. This is needed for + * converting all obdo, lmm, lsm, etc. 64-bit id/seq pairs into proper + * FIDs. Note that if an id/seq is already in FID/IDIF format it will + * be passed through unchanged. Only legacy OST objects in "group 0" + * will be mapped into the IDIF namespace so that they can fit into the + * struct lu_fid fields without loss. + */ +static inline int ostid_to_fid(struct lu_fid *fid, const struct ost_id *ostid, + __u32 ost_idx) +{ + __u64 seq = ostid_seq(ostid); + + if (ost_idx > 0xffff) + return -EBADF; + + if (fid_seq_is_mdt0(seq)) { + __u64 oid = ostid_id(ostid); + + /* This is a "legacy" (old 1.x/2.early) OST object in "group 0" + * that we map into the IDIF namespace. It allows up to 2^48 + * objects per OST, as this is the object namespace that has + * been in production for years. This can handle create rates + * of 1M objects/s/OST for 9 years, or combinations thereof. + */ + if (oid >= IDIF_MAX_OID) + return -EBADF; + + fid->f_seq = fid_idif_seq(oid, ost_idx); + /* truncate to 32 bits by assignment */ + fid->f_oid = oid; + /* in theory, not currently used */ + fid->f_ver = oid >> 48; + } else if (!fid_seq_is_default(seq)) { + /* This is either an IDIF object, which identifies objects + * across all OSTs, or a regular FID. The IDIF namespace + * maps legacy OST objects into the FID namespace. In both + * cases, we just pass the FID through, no conversion needed. + */ + if (ostid->oi_fid.f_ver) + return -EBADF; + + *fid = ostid->oi_fid; + } + + return 0; +} +#endif /* _UAPI_LUSTRE_OSTID_H_ */ diff --git a/drivers/staging/lustre/include/uapi/linux/lustre/lustre_param.h b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_param.h new file mode 100644 index 000000000000..1eab2ceca338 --- /dev/null +++ b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_param.h @@ -0,0 +1,94 @@ +/* + * GPL HEADER START + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 only, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 for more details (a copy is included + * in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; If not, see + * http://www.gnu.org/licenses/gpl-2.0.html + * + * GPL HEADER END + */ +/* + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. + * Use is subject to license terms. + * + * Copyright (c) 2011, 2015, Intel Corporation. + */ +/* + * This file is part of Lustre, http://www.lustre.org/ + * Lustre is a trademark of Sun Microsystems, Inc. + * + * User-settable parameter keys + * + * Author: Nathan Rutman <nathan@clusterfs.com> + */ + +#ifndef _UAPI_LUSTRE_PARAM_H_ +#define _UAPI_LUSTRE_PARAM_H_ + +/** \defgroup param param + * + * @{ + */ + +/****************** User-settable parameter keys *********************/ +/* e.g. + * tunefs.lustre --param="failover.node=192.168.0.13@tcp0" /dev/sda + * lctl conf_param testfs-OST0000 failover.node=3@elan,192.168.0.3@tcp0 + * ... testfs-MDT0000.lov.stripesize=4M + * ... testfs-OST0000.ost.client_cache_seconds=15 + * ... testfs.sys.timeout=<secs> + * ... testfs.llite.max_read_ahead_mb=16 + */ + +/* System global or special params not handled in obd's proc + * See mgs_write_log_sys() + */ +#define PARAM_TIMEOUT "timeout=" /* global */ +#define PARAM_LDLM_TIMEOUT "ldlm_timeout=" /* global */ +#define PARAM_AT_MIN "at_min=" /* global */ +#define PARAM_AT_MAX "at_max=" /* global */ +#define PARAM_AT_EXTRA "at_extra=" /* global */ +#define PARAM_AT_EARLY_MARGIN "at_early_margin=" /* global */ +#define PARAM_AT_HISTORY "at_history=" /* global */ +#define PARAM_JOBID_VAR "jobid_var=" /* global */ +#define PARAM_MGSNODE "mgsnode=" /* only at mounttime */ +#define PARAM_FAILNODE "failover.node=" /* add failover nid */ +#define PARAM_FAILMODE "failover.mode=" /* initial mount only */ +#define PARAM_ACTIVE "active=" /* activate/deactivate */ +#define PARAM_NETWORK "network=" /* bind on nid */ +#define PARAM_ID_UPCALL "identity_upcall=" /* identity upcall */ + +/* Prefixes for parameters handled by obd's proc methods (XXX_process_config) */ +#define PARAM_OST "ost." +#define PARAM_OSD "osd." +#define PARAM_OSC "osc." +#define PARAM_MDT "mdt." +#define PARAM_HSM "mdt.hsm." +#define PARAM_MDD "mdd." +#define PARAM_MDC "mdc." +#define PARAM_LLITE "llite." +#define PARAM_LOV "lov." +#define PARAM_LOD "lod." +#define PARAM_OSP "osp." +#define PARAM_SYS "sys." /* global */ +#define PARAM_SRPC "srpc." +#define PARAM_SRPC_FLVR "srpc.flavor." +#define PARAM_SRPC_UDESC "srpc.udesc.cli2mdt" +#define PARAM_SEC "security." +#define PARAM_QUOTA "quota." /* global */ + +/** @} param */ + +#endif /* _UAPI_LUSTRE_PARAM_H_ */ diff --git a/drivers/staging/lustre/lustre/include/lustre/lustre_user.h b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_user.h index edff8dc34430..5e332e3af68a 100644 --- a/drivers/staging/lustre/lustre/include/lustre/lustre_user.h +++ b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_user.h @@ -43,6 +43,7 @@ */ #ifdef __KERNEL__ +# include <linux/fs.h> # include <linux/quota.h> # include <linux/sched/signal.h> # include <linux/string.h> /* snprintf() */ @@ -54,7 +55,7 @@ # include <sys/quota.h> # include <sys/stat.h> #endif /* __KERNEL__ */ -#include "ll_fiemap.h" +#include <uapi/linux/lustre/lustre_fiemap.h> /* * We need to always use 64bit version because the structure @@ -644,7 +645,7 @@ struct if_quotactl { #define SWAP_LAYOUTS_CHECK_DV2 (1 << 1) #define SWAP_LAYOUTS_KEEP_MTIME (1 << 2) #define SWAP_LAYOUTS_KEEP_ATIME (1 << 3) -#define SWAP_LAYOUTS_CLOSE BIT(4) +#define SWAP_LAYOUTS_CLOSE (1 << 4) /* Swap XATTR_NAME_HSM as well, only on the MDT so far */ #define SWAP_LAYOUTS_MDS_HSM (1 << 31) @@ -791,15 +792,15 @@ static inline void hsm_set_cl_error(int *flags, int error) enum changelog_send_flag { /* Not yet implemented */ - CHANGELOG_FLAG_FOLLOW = BIT(0), + CHANGELOG_FLAG_FOLLOW = 0x01, /* * Blocking IO makes sense in case of slow user parsing of the records, * but it also prevents us from cleaning up if the records are not * consumed. */ - CHANGELOG_FLAG_BLOCK = BIT(1), + CHANGELOG_FLAG_BLOCK = 0x02, /* Pack jobid into the changelog records if available. */ - CHANGELOG_FLAG_JOBID = BIT(2), + CHANGELOG_FLAG_JOBID = 0x04, }; #define CR_MAXSIZE cfs_size_round(2 * NAME_MAX + 2 + \ @@ -980,8 +981,8 @@ struct ioc_data_version { __u64 idv_flags; /* See LL_DV_xxx */ }; -#define LL_DV_RD_FLUSH BIT(0) /* Flush dirty pages from clients */ -#define LL_DV_WR_FLUSH BIT(1) /* Flush all caching pages from clients */ +#define LL_DV_RD_FLUSH (1 << 0) /* Flush dirty pages from clients */ +#define LL_DV_WR_FLUSH (1 << 1) /* Flush all caching pages from clients */ #ifndef offsetof # define offsetof(typ, memb) ((unsigned long)((char *)&(((typ *)0)->memb))) diff --git a/drivers/staging/lustre/lustre/include/lustre_ver.h b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_ver.h index 19c9135e2273..19c9135e2273 100644 --- a/drivers/staging/lustre/lustre/include/lustre_ver.h +++ b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_ver.h diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/Makefile b/drivers/staging/lustre/lnet/klnds/o2iblnd/Makefile index e0a7aa72b7d5..4affe1d79948 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/Makefile +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/Makefile @@ -1,2 +1,5 @@ +subdir-ccflags-y += -I$(srctree)/drivers/staging/lustre/include +subdir-ccflags-y += -I$(srctree)/drivers/staging/lustre/lustre/include + obj-$(CONFIG_LNET_XPRT_IB) += ko2iblnd.o ko2iblnd-y := o2iblnd.o o2iblnd_cb.o o2iblnd_modparams.o diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c index 0520f02f670d..64763aacda57 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c @@ -2936,7 +2936,7 @@ failed: net_failed: kiblnd_shutdown(ni); - CDEBUG(D_NET, "kiblnd_startup failed\n"); + CDEBUG(D_NET, "%s failed\n", __func__); return -ENETDOWN; } diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h index 16e437b3ad1e..a1e994a1cc84 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h @@ -63,9 +63,8 @@ #define DEBUG_SUBSYSTEM S_LND -#include "../../../include/linux/libcfs/libcfs.h" -#include "../../../include/linux/lnet/lnet.h" -#include "../../../include/linux/lnet/lib-lnet.h" +#include <linux/libcfs/libcfs.h> +#include <linux/lnet/lib-lnet.h> #define IBLND_PEER_HASH_SIZE 101 /* # peer lists */ /* # scheduler loops before reschedule */ diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/Makefile b/drivers/staging/lustre/lnet/klnds/socklnd/Makefile index c011581d3453..a7da1abfc804 100644 --- a/drivers/staging/lustre/lnet/klnds/socklnd/Makefile +++ b/drivers/staging/lustre/lnet/klnds/socklnd/Makefile @@ -1,3 +1,6 @@ +subdir-ccflags-y += -I$(srctree)/drivers/staging/lustre/include +subdir-ccflags-y += -I$(srctree)/drivers/staging/lustre/lustre/include + obj-$(CONFIG_LNET) += ksocklnd.o ksocklnd-y := socklnd.o socklnd_cb.o socklnd_proto.o socklnd_modparams.o socklnd_lib.o diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.h b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.h index 5540de65f9a2..e6428c4b7aec 100644 --- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.h +++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.h @@ -46,10 +46,9 @@ #include <net/sock.h> #include <net/tcp.h> -#include "../../../include/linux/libcfs/libcfs.h" -#include "../../../include/linux/lnet/lnet.h" -#include "../../../include/linux/lnet/lib-lnet.h" -#include "../../../include/linux/lnet/socklnd.h" +#include <linux/libcfs/libcfs.h> +#include <linux/lnet/lib-lnet.h> +#include <linux/lnet/socklnd.h> /* assume one thread for each connection type */ #define SOCKNAL_NSCHEDS 3 @@ -519,17 +518,6 @@ extern struct ksock_proto ksocknal_protocol_v3x; #define CPU_MASK_NONE 0UL #endif -static inline __u32 ksocknal_csum(__u32 crc, unsigned char const *p, size_t len) -{ -#if 1 - return crc32_le(crc, p, len); -#else - while (len-- > 0) - crc = ((crc + 0x100) & ~0xff) | ((crc + *p++) & 0xff) ; - return crc; -#endif -} - static inline int ksocknal_route_mask(void) { diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib.c index 8a036f4eb8d8..9c328dc6537b 100644 --- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib.c +++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib.c @@ -201,9 +201,9 @@ ksocknal_lib_recv_iov(struct ksock_conn *conn) if (fragnob > sum) fragnob = sum; - conn->ksnc_rx_csum = ksocknal_csum(conn->ksnc_rx_csum, - iov[i].iov_base, - fragnob); + conn->ksnc_rx_csum = crc32_le(conn->ksnc_rx_csum, + iov[i].iov_base, + fragnob); } conn->ksnc_msg.ksm_csum = saved_csum; } @@ -243,8 +243,8 @@ ksocknal_lib_recv_kiov(struct ksock_conn *conn) if (fragnob > sum) fragnob = sum; - conn->ksnc_rx_csum = ksocknal_csum(conn->ksnc_rx_csum, - base, fragnob); + conn->ksnc_rx_csum = crc32_le(conn->ksnc_rx_csum, + base, fragnob); kunmap(kiov[i].bv_page); } @@ -265,22 +265,22 @@ ksocknal_lib_csum_tx(struct ksock_tx *tx) tx->tx_msg.ksm_csum = 0; - csum = ksocknal_csum(~0, tx->tx_iov[0].iov_base, - tx->tx_iov[0].iov_len); + csum = crc32_le(~0, tx->tx_iov[0].iov_base, + tx->tx_iov[0].iov_len); if (tx->tx_kiov) { for (i = 0; i < tx->tx_nkiov; i++) { base = kmap(tx->tx_kiov[i].bv_page) + tx->tx_kiov[i].bv_offset; - csum = ksocknal_csum(csum, base, tx->tx_kiov[i].bv_len); + csum = crc32_le(csum, base, tx->tx_kiov[i].bv_len); kunmap(tx->tx_kiov[i].bv_page); } } else { for (i = 1; i < tx->tx_niov; i++) - csum = ksocknal_csum(csum, tx->tx_iov[i].iov_base, - tx->tx_iov[i].iov_len); + csum = crc32_le(csum, tx->tx_iov[i].iov_base, + tx->tx_iov[i].iov_len); } if (*ksocknal_tunables.ksnd_inject_csum_error) { diff --git a/drivers/staging/lustre/lnet/libcfs/Makefile b/drivers/staging/lustre/lnet/libcfs/Makefile index 8c8945545375..215fa23827d1 100644 --- a/drivers/staging/lustre/lnet/libcfs/Makefile +++ b/drivers/staging/lustre/lnet/libcfs/Makefile @@ -1,3 +1,6 @@ +subdir-ccflags-y += -I$(srctree)/drivers/staging/lustre/include +subdir-ccflags-y += -I$(srctree)/drivers/staging/lustre/lustre/include + obj-$(CONFIG_LNET) += libcfs.o libcfs-linux-objs := linux-tracefile.o linux-debug.o diff --git a/drivers/staging/lustre/lnet/libcfs/debug.c b/drivers/staging/lustre/lnet/libcfs/debug.c index 49deb448b044..1ab394c1fabc 100644 --- a/drivers/staging/lustre/lnet/libcfs/debug.c +++ b/drivers/staging/lustre/lnet/libcfs/debug.c @@ -37,7 +37,7 @@ # define DEBUG_SUBSYSTEM S_LNET -#include "../../include/linux/libcfs/libcfs.h" +#include <linux/libcfs/libcfs.h> #include "tracefile.h" static char debug_file_name[1024]; diff --git a/drivers/staging/lustre/lnet/libcfs/fail.c b/drivers/staging/lustre/lnet/libcfs/fail.c index 12dd50ad4efb..24f4701a7a1e 100644 --- a/drivers/staging/lustre/lnet/libcfs/fail.c +++ b/drivers/staging/lustre/lnet/libcfs/fail.c @@ -29,7 +29,7 @@ * Lustre is a trademark of Oracle Corporation, Inc. */ -#include "../../include/linux/libcfs/libcfs.h" +#include <linux/libcfs/libcfs.h> unsigned long cfs_fail_loc; EXPORT_SYMBOL(cfs_fail_loc); diff --git a/drivers/staging/lustre/lnet/libcfs/hash.c b/drivers/staging/lustre/lnet/libcfs/hash.c index 5c2ce2ee6fd9..49a04a2b4ec4 100644 --- a/drivers/staging/lustre/lnet/libcfs/hash.c +++ b/drivers/staging/lustre/lnet/libcfs/hash.c @@ -105,7 +105,7 @@ #include <linux/seq_file.h> #include <linux/log2.h> -#include "../../include/linux/libcfs/libcfs.h" +#include <linux/libcfs/libcfs.h> #if CFS_HASH_DEBUG_LEVEL >= CFS_HASH_DEBUG_1 static unsigned int warn_on_depth = 8; @@ -1008,7 +1008,7 @@ cfs_hash_create(char *name, unsigned int cur_bits, unsigned int max_bits, LASSERT(ops->hs_object); LASSERT(ops->hs_keycmp); LASSERT(ops->hs_get); - LASSERT(ops->hs_put_locked); + LASSERT(ops->hs_put || ops->hs_put_locked); if (flags & CFS_HASH_REHASH) flags |= CFS_HASH_COUNTER; /* must have counter */ @@ -1553,19 +1553,20 @@ static int cfs_hash_for_each_relax(struct cfs_hash *hs, cfs_hash_for_each_cb_t func, void *data, int start) { + struct hlist_node *next = NULL; struct hlist_node *hnode; - struct hlist_node *tmp; struct cfs_hash_bd bd; u32 version; int count = 0; int stop_on_change; + int has_put_locked; int end = -1; int rc = 0; int i; stop_on_change = cfs_hash_with_rehash_key(hs) || - !cfs_hash_with_no_itemref(hs) || - !hs->hs_ops->hs_put_locked; + !cfs_hash_with_no_itemref(hs); + has_put_locked = hs->hs_ops->hs_put_locked != NULL; cfs_hash_lock(hs, 0); again: LASSERT(!cfs_hash_is_rehashing(hs)); @@ -1582,38 +1583,52 @@ again: version = cfs_hash_bd_version_get(&bd); cfs_hash_bd_for_each_hlist(hs, &bd, hhead) { - for (hnode = hhead->first; hnode;) { + hnode = hhead->first; + if (!hnode) + continue; + cfs_hash_get(hs, hnode); + + for (; hnode; hnode = next) { cfs_hash_bucket_validate(hs, &bd, hnode); - cfs_hash_get(hs, hnode); + next = hnode->next; + if (next) + cfs_hash_get(hs, next); cfs_hash_bd_unlock(hs, &bd, 0); cfs_hash_unlock(hs, 0); rc = func(hs, &bd, hnode, data); - if (stop_on_change) + if (stop_on_change || !has_put_locked) cfs_hash_put(hs, hnode); cond_resched(); count++; cfs_hash_lock(hs, 0); cfs_hash_bd_lock(hs, &bd, 0); - if (!stop_on_change) { - tmp = hnode->next; - cfs_hash_put_locked(hs, hnode); - hnode = tmp; - } else { /* bucket changed? */ + if (stop_on_change) { if (version != cfs_hash_bd_version_get(&bd)) - break; - /* safe to continue because no change */ - hnode = hnode->next; + rc = -EINTR; + } else if (has_put_locked) { + cfs_hash_put_locked(hs, hnode); } if (rc) /* callback wants to break iteration */ break; } - if (rc) /* callback wants to break iteration */ + if (next) { + if (has_put_locked) { + cfs_hash_put_locked(hs, next); + next = NULL; + } break; + } else if (rc) { + break; + } } cfs_hash_bd_unlock(hs, &bd, 0); + if (next && !has_put_locked) { + cfs_hash_put(hs, next); + next = NULL; + } if (rc) /* callback wants to break iteration */ break; } diff --git a/drivers/staging/lustre/lnet/libcfs/libcfs_cpu.c b/drivers/staging/lustre/lnet/libcfs/libcfs_cpu.c index 55caa19def51..2ddd09a83cd0 100644 --- a/drivers/staging/lustre/lnet/libcfs/libcfs_cpu.c +++ b/drivers/staging/lustre/lnet/libcfs/libcfs_cpu.c @@ -30,7 +30,7 @@ #define DEBUG_SUBSYSTEM S_LNET -#include "../../include/linux/libcfs/libcfs.h" +#include <linux/libcfs/libcfs.h> /** Global CPU partition table */ struct cfs_cpt_table *cfs_cpt_table __read_mostly; diff --git a/drivers/staging/lustre/lnet/libcfs/libcfs_lock.c b/drivers/staging/lustre/lnet/libcfs/libcfs_lock.c index 1967b97c4afc..77fd3d06cde9 100644 --- a/drivers/staging/lustre/lnet/libcfs/libcfs_lock.c +++ b/drivers/staging/lustre/lnet/libcfs/libcfs_lock.c @@ -27,7 +27,7 @@ #define DEBUG_SUBSYSTEM S_LNET -#include "../../include/linux/libcfs/libcfs.h" +#include <linux/libcfs/libcfs.h> /** destroy cpu-partition lock, see libcfs_private.h for more detail */ void diff --git a/drivers/staging/lustre/lnet/libcfs/libcfs_mem.c b/drivers/staging/lustre/lnet/libcfs/libcfs_mem.c index ef085ba23194..1a0c7cad5983 100644 --- a/drivers/staging/lustre/lnet/libcfs/libcfs_mem.c +++ b/drivers/staging/lustre/lnet/libcfs/libcfs_mem.c @@ -28,7 +28,7 @@ #define DEBUG_SUBSYSTEM S_LNET -#include "../../include/linux/libcfs/libcfs.h" +#include <linux/libcfs/libcfs.h> struct cfs_var_array { unsigned int va_count; /* # of buffers */ diff --git a/drivers/staging/lustre/lnet/libcfs/libcfs_string.c b/drivers/staging/lustre/lnet/libcfs/libcfs_string.c index 02de1ee720fd..333e47febf87 100644 --- a/drivers/staging/lustre/lnet/libcfs/libcfs_string.c +++ b/drivers/staging/lustre/lnet/libcfs/libcfs_string.c @@ -36,7 +36,7 @@ * Author: Nathan Rutman <nathan.rutman@sun.com> */ -#include "../../include/linux/libcfs/libcfs.h" +#include <linux/libcfs/libcfs.h> /* Convert a text string to a bitmask */ int cfs_str2mask(const char *str, const char *(*bit2str)(int bit), diff --git a/drivers/staging/lustre/lnet/libcfs/linux/linux-cpu.c b/drivers/staging/lustre/lnet/libcfs/linux/linux-cpu.c index 4d35a371216c..2da051c0d251 100644 --- a/drivers/staging/lustre/lnet/libcfs/linux/linux-cpu.c +++ b/drivers/staging/lustre/lnet/libcfs/linux/linux-cpu.c @@ -31,7 +31,7 @@ #include <linux/cpu.h> #include <linux/sched.h> -#include "../../../include/linux/libcfs/libcfs.h" +#include <linux/libcfs/libcfs.h> #ifdef CONFIG_SMP diff --git a/drivers/staging/lustre/lnet/libcfs/linux/linux-crypto.c b/drivers/staging/lustre/lnet/libcfs/linux/linux-crypto.c index 68e34b4a76c9..55663390b608 100644 --- a/drivers/staging/lustre/lnet/libcfs/linux/linux-crypto.c +++ b/drivers/staging/lustre/lnet/libcfs/linux/linux-crypto.c @@ -29,8 +29,8 @@ #include <crypto/hash.h> #include <linux/scatterlist.h> -#include "../../../include/linux/libcfs/libcfs.h" -#include "../../../include/linux/libcfs/libcfs_crypto.h" +#include <linux/libcfs/libcfs.h> +#include <linux/libcfs/libcfs_crypto.h> #include "linux-crypto.h" /** diff --git a/drivers/staging/lustre/lnet/libcfs/linux/linux-curproc.c b/drivers/staging/lustre/lnet/libcfs/linux/linux-curproc.c index 3e22cad18a8b..528d49794881 100644 --- a/drivers/staging/lustre/lnet/libcfs/linux/linux-curproc.c +++ b/drivers/staging/lustre/lnet/libcfs/linux/linux-curproc.c @@ -44,7 +44,7 @@ #define DEBUG_SUBSYSTEM S_LNET -#include "../../../include/linux/libcfs/libcfs.h" +#include <linux/libcfs/libcfs.h> /* * Implementation of cfs_curproc API (see portals/include/libcfs/curproc.h) diff --git a/drivers/staging/lustre/lnet/libcfs/linux/linux-debug.c b/drivers/staging/lustre/lnet/libcfs/linux/linux-debug.c index 7035356e56b3..972677bdf6bc 100644 --- a/drivers/staging/lustre/lnet/libcfs/linux/linux-debug.c +++ b/drivers/staging/lustre/lnet/libcfs/linux/linux-debug.c @@ -51,7 +51,7 @@ # define DEBUG_SUBSYSTEM S_LNET -#include "../../../include/linux/libcfs/libcfs.h" +#include <linux/libcfs/libcfs.h> #include "../tracefile.h" diff --git a/drivers/staging/lustre/lnet/libcfs/linux/linux-mem.c b/drivers/staging/lustre/lnet/libcfs/linux/linux-mem.c index 8f638267e704..3f5dec153571 100644 --- a/drivers/staging/lustre/lnet/libcfs/linux/linux-mem.c +++ b/drivers/staging/lustre/lnet/libcfs/linux/linux-mem.c @@ -29,7 +29,7 @@ #include <linux/slab.h> #include <linux/vmalloc.h> -#include "../../../include/linux/libcfs/libcfs.h" +#include <linux/libcfs/libcfs.h> void *libcfs_kvzalloc(size_t size, gfp_t flags) { diff --git a/drivers/staging/lustre/lnet/libcfs/linux/linux-module.c b/drivers/staging/lustre/lnet/libcfs/linux/linux-module.c index 075826bd3a2a..435722175cce 100644 --- a/drivers/staging/lustre/lnet/libcfs/linux/linux-module.c +++ b/drivers/staging/lustre/lnet/libcfs/linux/linux-module.c @@ -32,7 +32,7 @@ #define DEBUG_SUBSYSTEM S_LNET -#include "../../../include/linux/libcfs/libcfs.h" +#include <linux/libcfs/libcfs.h> #define LNET_MINOR 240 @@ -134,7 +134,7 @@ int libcfs_ioctl_getdata(struct libcfs_ioctl_hdr **hdr_pp, return -EINVAL; } - if (hdr.ioc_len < sizeof(struct libcfs_ioctl_data)) { + if (hdr.ioc_len < sizeof(hdr)) { CERROR("libcfs ioctl: user buffer too small for ioctl\n"); return -EINVAL; } diff --git a/drivers/staging/lustre/lnet/libcfs/linux/linux-prim.c b/drivers/staging/lustre/lnet/libcfs/linux/linux-prim.c index bcf9f3dd0310..4e331e71083d 100644 --- a/drivers/staging/lustre/lnet/libcfs/linux/linux-prim.c +++ b/drivers/staging/lustre/lnet/libcfs/linux/linux-prim.c @@ -36,7 +36,7 @@ #include <linux/fs_struct.h> #include <linux/sched/signal.h> -#include "../../../include/linux/libcfs/libcfs.h" +#include <linux/libcfs/libcfs.h> #if defined(CONFIG_KGDB) #include <linux/kgdb.h> diff --git a/drivers/staging/lustre/lnet/libcfs/linux/linux-tracefile.c b/drivers/staging/lustre/lnet/libcfs/linux/linux-tracefile.c index a5a94788f11f..16a3ae791bb6 100644 --- a/drivers/staging/lustre/lnet/libcfs/linux/linux-tracefile.c +++ b/drivers/staging/lustre/lnet/libcfs/linux/linux-tracefile.c @@ -33,7 +33,7 @@ #define DEBUG_SUBSYSTEM S_LNET #define LUSTRE_TRACEFILE_PRIVATE -#include "../../../include/linux/libcfs/libcfs.h" +#include <linux/libcfs/libcfs.h> #include "../tracefile.h" /* percents to share the total debug memory for each type */ diff --git a/drivers/staging/lustre/lnet/libcfs/module.c b/drivers/staging/lustre/lnet/libcfs/module.c index c388550c2d10..6aed98fc9688 100644 --- a/drivers/staging/lustre/lnet/libcfs/module.c +++ b/drivers/staging/lustre/lnet/libcfs/module.c @@ -50,13 +50,12 @@ # define DEBUG_SUBSYSTEM S_LNET -#include "../../include/linux/libcfs/libcfs.h" +#include <linux/libcfs/libcfs.h> #include <asm/div64.h> -#include "../../include/linux/libcfs/libcfs_crypto.h" -#include "../../include/linux/lnet/lib-lnet.h" -#include "../../include/linux/lnet/lib-dlc.h" -#include "../../include/linux/lnet/lnet.h" +#include <linux/libcfs/libcfs_crypto.h> +#include <linux/lnet/lib-lnet.h> +#include <uapi/linux/lnet/lnet-dlc.h> #include "tracefile.h" static struct dentry *lnet_debugfs_root; diff --git a/drivers/staging/lustre/lnet/libcfs/prng.c b/drivers/staging/lustre/lnet/libcfs/prng.c index 21d5a3912c5f..963ef4ae93b1 100644 --- a/drivers/staging/lustre/lnet/libcfs/prng.c +++ b/drivers/staging/lustre/lnet/libcfs/prng.c @@ -35,7 +35,7 @@ * algorithm recommended by Marsaglia */ -#include "../../include/linux/libcfs/libcfs.h" +#include <linux/libcfs/libcfs.h> /* * From: George Marsaglia <geo@stat.fsu.edu> diff --git a/drivers/staging/lustre/lnet/libcfs/tracefile.c b/drivers/staging/lustre/lnet/libcfs/tracefile.c index d1aa79bb2017..f916b475e767 100644 --- a/drivers/staging/lustre/lnet/libcfs/tracefile.c +++ b/drivers/staging/lustre/lnet/libcfs/tracefile.c @@ -40,7 +40,7 @@ #define pr_fmt(fmt) "Lustre: " fmt #include "tracefile.h" -#include "../../include/linux/libcfs/libcfs.h" +#include <linux/libcfs/libcfs.h> /* XXX move things up to the top, comment */ union cfs_trace_data_union (*cfs_trace_data[TCD_MAX_TYPES])[NR_CPUS] __cacheline_aligned; @@ -731,8 +731,7 @@ int cfs_tracefile_dump_all_pages(char *filename) __LASSERT_TAGE_INVARIANT(tage); buf = kmap(tage->page); - rc = vfs_write(filp, (__force const char __user *)buf, - tage->used, &filp->f_pos); + rc = kernel_write(filp, buf, tage->used, &filp->f_pos); kunmap(tage->page); if (rc != (int)tage->used) { @@ -976,7 +975,6 @@ static int tracefiled(void *arg) struct tracefiled_ctl *tctl = arg; struct cfs_trace_page *tage; struct cfs_trace_page *tmp; - mm_segment_t __oldfs; struct file *filp; char *buf; int last_loop = 0; @@ -1014,8 +1012,6 @@ static int tracefiled(void *arg) __LASSERT(list_empty(&pc.pc_pages)); goto end_loop; } - __oldfs = get_fs(); - set_fs(get_ds()); list_for_each_entry_safe(tage, tmp, &pc.pc_pages, linkage) { static loff_t f_pos; @@ -1028,8 +1024,7 @@ static int tracefiled(void *arg) f_pos = i_size_read(file_inode(filp)); buf = kmap(tage->page); - rc = vfs_write(filp, (__force const char __user *)buf, - tage->used, &f_pos); + rc = kernel_write(filp, buf, tage->used, &f_pos); kunmap(tage->page); if (rc != (int)tage->used) { @@ -1040,7 +1035,6 @@ static int tracefiled(void *arg) break; } } - set_fs(__oldfs); filp_close(filp, NULL); put_pages_on_daemon_list(&pc); diff --git a/drivers/staging/lustre/lnet/libcfs/tracefile.h b/drivers/staging/lustre/lnet/libcfs/tracefile.h index f644cbc5a277..c3547cd4c72c 100644 --- a/drivers/staging/lustre/lnet/libcfs/tracefile.h +++ b/drivers/staging/lustre/lnet/libcfs/tracefile.h @@ -33,7 +33,7 @@ #ifndef __LIBCFS_TRACEFILE_H__ #define __LIBCFS_TRACEFILE_H__ -#include "../../include/linux/libcfs/libcfs.h" +#include <linux/libcfs/libcfs.h> enum cfs_trace_buf_type { CFS_TCD_TYPE_PROC = 0, diff --git a/drivers/staging/lustre/lnet/libcfs/workitem.c b/drivers/staging/lustre/lnet/libcfs/workitem.c index dbc2a9b8dff8..038ed8c52107 100644 --- a/drivers/staging/lustre/lnet/libcfs/workitem.c +++ b/drivers/staging/lustre/lnet/libcfs/workitem.c @@ -37,7 +37,7 @@ #define DEBUG_SUBSYSTEM S_LNET -#include "../../include/linux/libcfs/libcfs.h" +#include <linux/libcfs/libcfs.h> #define CFS_WS_NAME_LEN 16 diff --git a/drivers/staging/lustre/lnet/lnet/Makefile b/drivers/staging/lustre/lnet/lnet/Makefile index 4c81fa19429a..fd8585cd0ce2 100644 --- a/drivers/staging/lustre/lnet/lnet/Makefile +++ b/drivers/staging/lustre/lnet/lnet/Makefile @@ -1,3 +1,6 @@ +subdir-ccflags-y += -I$(srctree)/drivers/staging/lustre/include +subdir-ccflags-y += -I$(srctree)/drivers/staging/lustre/lustre/include + obj-$(CONFIG_LNET) += lnet.o lnet-y := api-ni.o config.o nidstrings.o net_fault.o \ diff --git a/drivers/staging/lustre/lnet/lnet/acceptor.c b/drivers/staging/lustre/lnet/lnet/acceptor.c index a6f60c3e1184..be2823f8eb02 100644 --- a/drivers/staging/lustre/lnet/lnet/acceptor.c +++ b/drivers/staging/lustre/lnet/lnet/acceptor.c @@ -33,7 +33,7 @@ #define DEBUG_SUBSYSTEM S_LNET #include <linux/completion.h> #include <net/sock.h> -#include "../../include/linux/lnet/lib-lnet.h" +#include <linux/lnet/lib-lnet.h> static int accept_port = 988; static int accept_backlog = 127; diff --git a/drivers/staging/lustre/lnet/lnet/api-ni.c b/drivers/staging/lustre/lnet/lnet/api-ni.c index 0b91d1809cb1..ad835035fffa 100644 --- a/drivers/staging/lustre/lnet/lnet/api-ni.c +++ b/drivers/staging/lustre/lnet/lnet/api-ni.c @@ -34,8 +34,8 @@ #include <linux/log2.h> #include <linux/ktime.h> -#include "../../include/linux/lnet/lib-lnet.h" -#include "../../include/linux/lnet/lib-dlc.h" +#include <linux/lnet/lib-lnet.h> +#include <uapi/linux/lnet/lnet-dlc.h> #define D_LNI D_CONSOLE diff --git a/drivers/staging/lustre/lnet/lnet/config.c b/drivers/staging/lustre/lnet/lnet/config.c index 933988da7fe2..26841a7b6213 100644 --- a/drivers/staging/lustre/lnet/lnet/config.c +++ b/drivers/staging/lustre/lnet/lnet/config.c @@ -33,7 +33,7 @@ #define DEBUG_SUBSYSTEM S_LNET #include <linux/nsproxy.h> #include <net/net_namespace.h> -#include "../../include/linux/lnet/lib-lnet.h" +#include <linux/lnet/lib-lnet.h> struct lnet_text_buf { /* tmp struct for parsing routes */ struct list_head ltb_list; /* stash on lists */ diff --git a/drivers/staging/lustre/lnet/lnet/lib-eq.c b/drivers/staging/lustre/lnet/lnet/lib-eq.c index 9ebba4ef5f90..6b446a51eeac 100644 --- a/drivers/staging/lustre/lnet/lnet/lib-eq.c +++ b/drivers/staging/lustre/lnet/lnet/lib-eq.c @@ -35,7 +35,8 @@ */ #define DEBUG_SUBSYSTEM S_LNET -#include "../../include/linux/lnet/lib-lnet.h" + +#include <linux/lnet/lib-lnet.h> /** * Create an event queue that has room for \a count number of events. diff --git a/drivers/staging/lustre/lnet/lnet/lib-md.c b/drivers/staging/lustre/lnet/lnet/lib-md.c index f08e944f412b..a0aef4b9bce3 100644 --- a/drivers/staging/lustre/lnet/lnet/lib-md.c +++ b/drivers/staging/lustre/lnet/lnet/lib-md.c @@ -36,7 +36,7 @@ #define DEBUG_SUBSYSTEM S_LNET -#include "../../include/linux/lnet/lib-lnet.h" +#include <linux/lnet/lib-lnet.h> /* must be called with lnet_res_lock held */ void diff --git a/drivers/staging/lustre/lnet/lnet/lib-me.c b/drivers/staging/lustre/lnet/lnet/lib-me.c index e9b3eedca4db..f52a5e8ed386 100644 --- a/drivers/staging/lustre/lnet/lnet/lib-me.c +++ b/drivers/staging/lustre/lnet/lnet/lib-me.c @@ -36,7 +36,7 @@ #define DEBUG_SUBSYSTEM S_LNET -#include "../../include/linux/lnet/lib-lnet.h" +#include <linux/lnet/lib-lnet.h> /** * Create and attach a match entry to the match list of \a portal. The new diff --git a/drivers/staging/lustre/lnet/lnet/lib-move.c b/drivers/staging/lustre/lnet/lnet/lib-move.c index 20ebe247071f..bc0779c02d97 100644 --- a/drivers/staging/lustre/lnet/lnet/lib-move.c +++ b/drivers/staging/lustre/lnet/lnet/lib-move.c @@ -36,7 +36,7 @@ #define DEBUG_SUBSYSTEM S_LNET -#include "../../include/linux/lnet/lib-lnet.h" +#include <linux/lnet/lib-lnet.h> #include <linux/nsproxy.h> #include <net/net_namespace.h> @@ -2034,7 +2034,7 @@ LNetPut(lnet_nid_t self, struct lnet_handle_md mdh, enum lnet_ack_req ack, return -ENOENT; } - CDEBUG(D_NET, "LNetPut -> %s\n", libcfs_id2str(target)); + CDEBUG(D_NET, "%s -> %s\n", __func__, libcfs_id2str(target)); lnet_msg_attach_md(msg, md, 0, 0); @@ -2239,7 +2239,7 @@ LNetGet(lnet_nid_t self, struct lnet_handle_md mdh, return -ENOENT; } - CDEBUG(D_NET, "LNetGet -> %s\n", libcfs_id2str(target)); + CDEBUG(D_NET, "%s -> %s\n", __func__, libcfs_id2str(target)); lnet_msg_attach_md(msg, md, 0, 0); diff --git a/drivers/staging/lustre/lnet/lnet/lib-msg.c b/drivers/staging/lustre/lnet/lnet/lib-msg.c index 008ac503f27d..d04875e3956f 100644 --- a/drivers/staging/lustre/lnet/lnet/lib-msg.c +++ b/drivers/staging/lustre/lnet/lnet/lib-msg.c @@ -36,7 +36,7 @@ #define DEBUG_SUBSYSTEM S_LNET -#include "../../include/linux/lnet/lib-lnet.h" +#include <linux/lnet/lib-lnet.h> void lnet_build_unlink_event(struct lnet_libmd *md, struct lnet_event *ev) diff --git a/drivers/staging/lustre/lnet/lnet/lib-ptl.c b/drivers/staging/lustre/lnet/lnet/lib-ptl.c index 33332724ab94..5946848a7846 100644 --- a/drivers/staging/lustre/lnet/lnet/lib-ptl.c +++ b/drivers/staging/lustre/lnet/lnet/lib-ptl.c @@ -31,7 +31,7 @@ #define DEBUG_SUBSYSTEM S_LNET -#include "../../include/linux/lnet/lib-lnet.h" +#include <linux/lnet/lib-lnet.h> /* NB: add /proc interfaces in upcoming patches */ int portal_rotor = LNET_PTL_ROTOR_HASH_RT; diff --git a/drivers/staging/lustre/lnet/lnet/lib-socket.c b/drivers/staging/lustre/lnet/lnet/lib-socket.c index 800f4f6c6593..7d0add0c0de3 100644 --- a/drivers/staging/lustre/lnet/lnet/lib-socket.c +++ b/drivers/staging/lustre/lnet/lnet/lib-socket.c @@ -40,8 +40,8 @@ #include <linux/syscalls.h> #include <net/sock.h> -#include "../../include/linux/libcfs/libcfs.h" -#include "../../include/linux/lnet/lib-lnet.h" +#include <linux/libcfs/libcfs.h> +#include <linux/lnet/lib-lnet.h> static int kernel_sock_unlocked_ioctl(struct file *filp, int cmd, unsigned long arg) diff --git a/drivers/staging/lustre/lnet/lnet/lo.c b/drivers/staging/lustre/lnet/lnet/lo.c index a7504b8edf6d..80c06f4b0c8d 100644 --- a/drivers/staging/lustre/lnet/lnet/lo.c +++ b/drivers/staging/lustre/lnet/lnet/lo.c @@ -29,7 +29,8 @@ */ #define DEBUG_SUBSYSTEM S_LNET -#include "../../include/linux/lnet/lib-lnet.h" + +#include <linux/lnet/lib-lnet.h> static int lolnd_send(struct lnet_ni *ni, void *private, struct lnet_msg *lntmsg) diff --git a/drivers/staging/lustre/lnet/lnet/module.c b/drivers/staging/lustre/lnet/lnet/module.c index 4ffbd3e441e8..7d12a7fb36a4 100644 --- a/drivers/staging/lustre/lnet/lnet/module.c +++ b/drivers/staging/lustre/lnet/lnet/module.c @@ -31,8 +31,9 @@ */ #define DEBUG_SUBSYSTEM S_LNET -#include "../../include/linux/lnet/lib-lnet.h" -#include "../../include/linux/lnet/lib-dlc.h" + +#include <linux/lnet/lib-lnet.h> +#include <uapi/linux/lnet/lnet-dlc.h> static int config_on_load; module_param(config_on_load, int, 0444); diff --git a/drivers/staging/lustre/lnet/lnet/net_fault.c b/drivers/staging/lustre/lnet/lnet/net_fault.c index 18183cbb9859..03f3d18a1a29 100644 --- a/drivers/staging/lustre/lnet/lnet/net_fault.c +++ b/drivers/staging/lustre/lnet/lnet/net_fault.c @@ -35,8 +35,8 @@ #define DEBUG_SUBSYSTEM S_LNET -#include "../../include/linux/lnet/lib-lnet.h" -#include "../../include/linux/lnet/lnetctl.h" +#include <linux/lnet/lib-lnet.h> +#include <uapi/linux/lnet/lnetctl.h> #define LNET_MSG_MASK (LNET_PUT_BIT | LNET_ACK_BIT | \ LNET_GET_BIT | LNET_REPLY_BIT) diff --git a/drivers/staging/lustre/lnet/lnet/nidstrings.c b/drivers/staging/lustre/lnet/lnet/nidstrings.c index 298533d7b04c..7bd1e6f389aa 100644 --- a/drivers/staging/lustre/lnet/lnet/nidstrings.c +++ b/drivers/staging/lustre/lnet/lnet/nidstrings.c @@ -36,8 +36,8 @@ #define DEBUG_SUBSYSTEM S_LNET -#include "../../include/linux/libcfs/libcfs.h" -#include "../../include/linux/lnet/lnet.h" +#include <linux/libcfs/libcfs.h> +#include <uapi/linux/lnet/nidstr.h> /* max value for numeric network address */ #define MAX_NUMERIC_VALUE 0xffffffff diff --git a/drivers/staging/lustre/lnet/lnet/peer.c b/drivers/staging/lustre/lnet/lnet/peer.c index e62b21f3ab4d..4d55df8ff74e 100644 --- a/drivers/staging/lustre/lnet/lnet/peer.c +++ b/drivers/staging/lustre/lnet/lnet/peer.c @@ -34,8 +34,8 @@ #define DEBUG_SUBSYSTEM S_LNET -#include "../../include/linux/lnet/lib-lnet.h" -#include "../../include/linux/lnet/lib-dlc.h" +#include <linux/lnet/lib-lnet.h> +#include <uapi/linux/lnet/lnet-dlc.h> int lnet_peer_tables_create(void) diff --git a/drivers/staging/lustre/lnet/lnet/router.c b/drivers/staging/lustre/lnet/lnet/router.c index 12dd1043f9fa..3df101bafd9f 100644 --- a/drivers/staging/lustre/lnet/lnet/router.c +++ b/drivers/staging/lustre/lnet/lnet/router.c @@ -18,8 +18,9 @@ */ #define DEBUG_SUBSYSTEM S_LNET + #include <linux/completion.h> -#include "../../include/linux/lnet/lib-lnet.h" +#include <linux/lnet/lib-lnet.h> #define LNET_NRB_TINY_MIN 512 /* min value for each CPT */ #define LNET_NRB_TINY (LNET_NRB_TINY_MIN * 4) diff --git a/drivers/staging/lustre/lnet/lnet/router_proc.c b/drivers/staging/lustre/lnet/lnet/router_proc.c index 72b80c594108..4a994d113c7d 100644 --- a/drivers/staging/lustre/lnet/lnet/router_proc.c +++ b/drivers/staging/lustre/lnet/lnet/router_proc.c @@ -18,8 +18,9 @@ */ #define DEBUG_SUBSYSTEM S_LNET -#include "../../include/linux/libcfs/libcfs.h" -#include "../../include/linux/lnet/lib-lnet.h" + +#include <linux/libcfs/libcfs.h> +#include <linux/lnet/lib-lnet.h> /* * This is really lnet_proc.c. You might need to update sanity test 215 diff --git a/drivers/staging/lustre/lnet/selftest/Makefile b/drivers/staging/lustre/lnet/selftest/Makefile index c0de6e2d96d0..3ccc8966b566 100644 --- a/drivers/staging/lustre/lnet/selftest/Makefile +++ b/drivers/staging/lustre/lnet/selftest/Makefile @@ -1,3 +1,6 @@ +subdir-ccflags-y += -I$(srctree)/drivers/staging/lustre/include +subdir-ccflags-y += -I$(srctree)/drivers/staging/lustre/lustre/include + obj-$(CONFIG_LNET_SELFTEST) := lnet_selftest.o lnet_selftest-y := console.o conrpc.o conctl.o framework.o timer.o rpc.o \ diff --git a/drivers/staging/lustre/lnet/selftest/conctl.c b/drivers/staging/lustre/lnet/selftest/conctl.c index 6ca7192b03b7..9619ecbf8bdf 100644 --- a/drivers/staging/lustre/lnet/selftest/conctl.c +++ b/drivers/staging/lustre/lnet/selftest/conctl.c @@ -36,9 +36,9 @@ * Author: Liang Zhen <liangzhen@clusterfs.com> */ -#include "../../include/linux/libcfs/libcfs.h" -#include "../../include/linux/lnet/lib-lnet.h" -#include "../../include/linux/lnet/lnetst.h" +#include <linux/libcfs/libcfs.h> +#include <linux/lnet/lib-lnet.h> +#include <uapi/linux/lnet/lnetst.h> #include "console.h" static int @@ -69,8 +69,8 @@ lst_session_new_ioctl(struct lstio_session_new_args *args) rc = lstcon_session_new(name, args->lstio_ses_key, args->lstio_ses_feats, - args->lstio_ses_force, args->lstio_ses_timeout, + args->lstio_ses_force, args->lstio_ses_idp); LIBCFS_FREE(name, args->lstio_ses_nmlen + 1); diff --git a/drivers/staging/lustre/lnet/selftest/conrpc.c b/drivers/staging/lustre/lnet/selftest/conrpc.c index da36c55b86d3..196d23c10921 100644 --- a/drivers/staging/lustre/lnet/selftest/conrpc.c +++ b/drivers/staging/lustre/lnet/selftest/conrpc.c @@ -36,8 +36,8 @@ * Author: Liang Zhen <liang@whamcloud.com> */ -#include "../../include/linux/libcfs/libcfs.h" -#include "../../include/linux/lnet/lib-lnet.h" +#include <linux/libcfs/libcfs.h> +#include <linux/lnet/lib-lnet.h> #include "timer.h" #include "conrpc.h" #include "console.h" @@ -487,10 +487,9 @@ lstcon_rpc_trans_interpreter(struct lstcon_rpc_trans *trans, sizeof(struct list_head))) return -EFAULT; - if (tmp.next == head_up) - return 0; - next = tmp.next; + if (next == head_up) + return 0; ent = list_entry(next, struct lstcon_rpc_ent, rpe_link); diff --git a/drivers/staging/lustre/lnet/selftest/conrpc.h b/drivers/staging/lustre/lnet/selftest/conrpc.h index 7141d2c902a5..239323679baa 100644 --- a/drivers/staging/lustre/lnet/selftest/conrpc.h +++ b/drivers/staging/lustre/lnet/selftest/conrpc.h @@ -39,10 +39,9 @@ #ifndef __LST_CONRPC_H__ #define __LST_CONRPC_H__ -#include "../../include/linux/libcfs/libcfs.h" -#include "../../include/linux/lnet/lnet.h" -#include "../../include/linux/lnet/lib-types.h" -#include "../../include/linux/lnet/lnetst.h" +#include <linux/libcfs/libcfs.h> +#include <linux/lnet/lib-types.h> +#include <uapi/linux/lnet/lnetst.h> #include "rpc.h" #include "selftest.h" diff --git a/drivers/staging/lustre/lnet/selftest/console.c b/drivers/staging/lustre/lnet/selftest/console.c index d62c448ecf8a..289b202c3b36 100644 --- a/drivers/staging/lustre/lnet/selftest/console.c +++ b/drivers/staging/lustre/lnet/selftest/console.c @@ -36,8 +36,8 @@ * Author: Liang Zhen <liangzhen@clusterfs.com> */ -#include "../../include/linux/libcfs/libcfs.h" -#include "../../include/linux/lnet/lib-lnet.h" +#include <linux/libcfs/libcfs.h> +#include <linux/lnet/lib-lnet.h> #include "console.h" #include "conrpc.h" diff --git a/drivers/staging/lustre/lnet/selftest/console.h b/drivers/staging/lustre/lnet/selftest/console.h index e3e11aa52526..143eae9b8d71 100644 --- a/drivers/staging/lustre/lnet/selftest/console.h +++ b/drivers/staging/lustre/lnet/selftest/console.h @@ -39,10 +39,9 @@ #ifndef __LST_CONSOLE_H__ #define __LST_CONSOLE_H__ -#include "../../include/linux/libcfs/libcfs.h" -#include "../../include/linux/lnet/lnet.h" -#include "../../include/linux/lnet/lib-types.h" -#include "../../include/linux/lnet/lnetst.h" +#include <linux/libcfs/libcfs.h> +#include <linux/lnet/lib-types.h> +#include <uapi/linux/lnet/lnetst.h> #include "selftest.h" #include "conrpc.h" diff --git a/drivers/staging/lustre/lnet/selftest/rpc.h b/drivers/staging/lustre/lnet/selftest/rpc.h index a765537a79c4..7bb442a8e698 100644 --- a/drivers/staging/lustre/lnet/selftest/rpc.h +++ b/drivers/staging/lustre/lnet/selftest/rpc.h @@ -33,7 +33,7 @@ #ifndef __SELFTEST_RPC_H__ #define __SELFTEST_RPC_H__ -#include "../../include/linux/lnet/lnetst.h" +#include <uapi/linux/lnet/lnetst.h> /* * LST wired structures diff --git a/drivers/staging/lustre/lnet/selftest/selftest.h b/drivers/staging/lustre/lnet/selftest/selftest.h index b614e6f23a70..7adad4302dcf 100644 --- a/drivers/staging/lustre/lnet/selftest/selftest.h +++ b/drivers/staging/lustre/lnet/selftest/selftest.h @@ -38,11 +38,10 @@ #define LNET_ONLY -#include "../../include/linux/libcfs/libcfs.h" -#include "../../include/linux/lnet/lnet.h" -#include "../../include/linux/lnet/lib-lnet.h" -#include "../../include/linux/lnet/lib-types.h" -#include "../../include/linux/lnet/lnetst.h" +#include <linux/libcfs/libcfs.h> +#include <linux/lnet/lib-lnet.h> +#include <linux/lnet/lib-types.h> +#include <uapi/linux/lnet/lnetst.h> #include "rpc.h" #include "timer.h" diff --git a/drivers/staging/lustre/lustre/Kconfig b/drivers/staging/lustre/lustre/Kconfig index 9f5d75f166e7..90d826946c6a 100644 --- a/drivers/staging/lustre/lustre/Kconfig +++ b/drivers/staging/lustre/lustre/Kconfig @@ -31,16 +31,6 @@ config LUSTRE_FS See also http://wiki.lustre.org/ -config LUSTRE_OBD_MAX_IOCTL_BUFFER - int "Lustre obd max ioctl buffer bytes (default 8KB)" - depends on LUSTRE_FS - default 8192 - help - This option defines the maximum size of buffer in bytes that user space - applications can pass to Lustre kernel module through ioctl interface. - - If unsure, use default. - config LUSTRE_DEBUG_EXPENSIVE_CHECK bool "Enable Lustre DEBUG checks" depends on LUSTRE_FS diff --git a/drivers/staging/lustre/lustre/fid/Makefile b/drivers/staging/lustre/lustre/fid/Makefile index b7ef314b4b84..77b65b92667d 100644 --- a/drivers/staging/lustre/lustre/fid/Makefile +++ b/drivers/staging/lustre/lustre/fid/Makefile @@ -1,2 +1,5 @@ +subdir-ccflags-y += -I$(srctree)/drivers/staging/lustre/include +subdir-ccflags-y += -I$(srctree)/drivers/staging/lustre/lustre/include/ + obj-$(CONFIG_LUSTRE_FS) += fid.o fid-y := fid_request.o fid_lib.o lproc_fid.o diff --git a/drivers/staging/lustre/lustre/fid/fid_internal.h b/drivers/staging/lustre/lustre/fid/fid_internal.h index 5c53773ecc5a..f48ab9d21428 100644 --- a/drivers/staging/lustre/lustre/fid/fid_internal.h +++ b/drivers/staging/lustre/lustre/fid/fid_internal.h @@ -36,8 +36,8 @@ #ifndef __FID_INTERNAL_H #define __FID_INTERNAL_H -#include "../include/lustre/lustre_idl.h" -#include "../../include/linux/libcfs/libcfs.h" +#include <uapi/linux/lustre/lustre_idl.h> +#include <linux/libcfs/libcfs.h> /* Functions used internally in module. */ diff --git a/drivers/staging/lustre/lustre/fid/fid_lib.c b/drivers/staging/lustre/lustre/fid/fid_lib.c index 9eb405905d1a..c21a5f5b7621 100644 --- a/drivers/staging/lustre/lustre/fid/fid_lib.c +++ b/drivers/staging/lustre/lustre/fid/fid_lib.c @@ -39,10 +39,9 @@ #define DEBUG_SUBSYSTEM S_FID -#include "../../include/linux/libcfs/libcfs.h" +#include <linux/libcfs/libcfs.h> #include <linux/module.h> -#include "../include/lustre/lustre_idl.h" -#include "../include/lustre_fid.h" +#include <lustre_fid.h> /** * A cluster-wide range from which fid-sequences are granted to servers and diff --git a/drivers/staging/lustre/lustre/fid/fid_request.c b/drivers/staging/lustre/lustre/fid/fid_request.c index 19895faf7626..ba736239243c 100644 --- a/drivers/staging/lustre/lustre/fid/fid_request.c +++ b/drivers/staging/lustre/lustre/fid/fid_request.c @@ -38,15 +38,15 @@ #define DEBUG_SUBSYSTEM S_FID -#include "../../include/linux/libcfs/libcfs.h" +#include <linux/libcfs/libcfs.h> #include <linux/module.h> -#include "../include/obd.h" -#include "../include/obd_class.h" -#include "../include/obd_support.h" -#include "../include/lustre_fid.h" +#include <obd.h> +#include <obd_class.h> +#include <obd_support.h> +#include <lustre_fid.h> /* mdc RPC locks */ -#include "../include/lustre_mdc.h" +#include <lustre_mdc.h> #include "fid_internal.h" static struct dentry *seq_debugfs_dir; diff --git a/drivers/staging/lustre/lustre/fid/lproc_fid.c b/drivers/staging/lustre/lustre/fid/lproc_fid.c index 3eed83808545..1a269fbc4b47 100644 --- a/drivers/staging/lustre/lustre/fid/lproc_fid.c +++ b/drivers/staging/lustre/lustre/fid/lproc_fid.c @@ -38,14 +38,14 @@ #define DEBUG_SUBSYSTEM S_FID -#include "../../include/linux/libcfs/libcfs.h" +#include <linux/libcfs/libcfs.h> #include <linux/module.h> -#include "../include/obd.h" -#include "../include/obd_class.h" -#include "../include/obd_support.h" -#include "../include/lustre_req_layout.h" -#include "../include/lustre_fid.h" +#include <obd.h> +#include <obd_class.h> +#include <obd_support.h> +#include <lustre_req_layout.h> +#include <lustre_fid.h> #include "fid_internal.h" /* Format: [0x64BIT_INT - 0x64BIT_INT] + 32 bytes just in case */ diff --git a/drivers/staging/lustre/lustre/fld/Makefile b/drivers/staging/lustre/lustre/fld/Makefile index 646e315d1aa8..426deba8b815 100644 --- a/drivers/staging/lustre/lustre/fld/Makefile +++ b/drivers/staging/lustre/lustre/fld/Makefile @@ -1,2 +1,5 @@ +subdir-ccflags-y += -I$(srctree)/drivers/staging/lustre/include +subdir-ccflags-y += -I$(srctree)/drivers/staging/lustre/lustre/include/ + obj-$(CONFIG_LUSTRE_FS) += fld.o fld-y := fld_request.o fld_cache.o lproc_fld.o diff --git a/drivers/staging/lustre/lustre/fld/fld_cache.c b/drivers/staging/lustre/lustre/fld/fld_cache.c index b852fed0b10f..b723ece02eff 100644 --- a/drivers/staging/lustre/lustre/fld/fld_cache.c +++ b/drivers/staging/lustre/lustre/fld/fld_cache.c @@ -39,18 +39,18 @@ #define DEBUG_SUBSYSTEM S_FLD -#include "../../include/linux/libcfs/libcfs.h" +#include <linux/libcfs/libcfs.h> #include <linux/module.h> #include <asm/div64.h> -#include "../include/obd.h" -#include "../include/obd_class.h" -#include "../include/lustre_ver.h" -#include "../include/obd_support.h" -#include "../include/lprocfs_status.h" +#include <obd.h> +#include <obd_class.h> +#include <uapi/linux/lustre/lustre_ver.h> +#include <obd_support.h> +#include <lprocfs_status.h> -#include "../include/lustre_req_layout.h" -#include "../include/lustre_fld.h" +#include <lustre_req_layout.h> +#include <lustre_fld.h> #include "fld_internal.h" /** @@ -348,9 +348,10 @@ static void fld_cache_overlap_handle(struct fld_cache *cache, f_curr->fce_range.lsr_end = new_start; fld_cache_entry_add(cache, f_new, &f_curr->fce_list); - } else + } else { CERROR("NEW range =" DRANGE " curr = " DRANGE "\n", PRANGE(range), PRANGE(&f_curr->fce_range)); + } } struct fld_cache_entry diff --git a/drivers/staging/lustre/lustre/fld/fld_internal.h b/drivers/staging/lustre/lustre/fld/fld_internal.h index 4a7f0b71c48d..fe6f278a7d9f 100644 --- a/drivers/staging/lustre/lustre/fld/fld_internal.h +++ b/drivers/staging/lustre/lustre/fld/fld_internal.h @@ -56,11 +56,11 @@ #ifndef __FLD_INTERNAL_H #define __FLD_INTERNAL_H -#include "../include/lustre/lustre_idl.h" +#include <uapi/linux/lustre/lustre_idl.h> -#include "../../include/linux/libcfs/libcfs.h" -#include "../include/lustre_req_layout.h" -#include "../include/lustre_fld.h" +#include <linux/libcfs/libcfs.h> +#include <lustre_req_layout.h> +#include <lustre_fld.h> struct fld_stats { __u64 fst_count; diff --git a/drivers/staging/lustre/lustre/fld/fld_request.c b/drivers/staging/lustre/lustre/fld/fld_request.c index 4cade7a16800..5b180830eec0 100644 --- a/drivers/staging/lustre/lustre/fld/fld_request.c +++ b/drivers/staging/lustre/lustre/fld/fld_request.c @@ -38,19 +38,19 @@ #define DEBUG_SUBSYSTEM S_FLD -#include "../../include/linux/libcfs/libcfs.h" +#include <linux/libcfs/libcfs.h> #include <linux/module.h> #include <asm/div64.h> -#include "../include/obd.h" -#include "../include/obd_class.h" -#include "../include/lustre_ver.h" -#include "../include/obd_support.h" -#include "../include/lprocfs_status.h" +#include <obd.h> +#include <obd_class.h> +#include <uapi/linux/lustre/lustre_ver.h> +#include <obd_support.h> +#include <lprocfs_status.h> -#include "../include/lustre_req_layout.h" -#include "../include/lustre_fld.h" -#include "../include/lustre_mdc.h" +#include <lustre_req_layout.h> +#include <lustre_fld.h> +#include <lustre_mdc.h> #include "fld_internal.h" static int fld_rrb_hash(struct lu_client_fld *fld, u64 seq) diff --git a/drivers/staging/lustre/lustre/fld/lproc_fld.c b/drivers/staging/lustre/lustre/fld/lproc_fld.c index b83d7ebb2d18..6cae803fc8d2 100644 --- a/drivers/staging/lustre/lustre/fld/lproc_fld.c +++ b/drivers/staging/lustre/lustre/fld/lproc_fld.c @@ -39,15 +39,15 @@ #define DEBUG_SUBSYSTEM S_FLD -#include "../../include/linux/libcfs/libcfs.h" +#include <linux/libcfs/libcfs.h> #include <linux/module.h> -#include "../include/obd.h" -#include "../include/obd_class.h" -#include "../include/obd_support.h" -#include "../include/lustre_req_layout.h" -#include "../include/lustre_fld.h" -#include "../include/lustre_fid.h" +#include <obd.h> +#include <obd_class.h> +#include <obd_support.h> +#include <lustre_req_layout.h> +#include <lustre_fld.h> +#include <lustre_fid.h> #include "fld_internal.h" static int diff --git a/drivers/staging/lustre/lustre/include/cl_object.h b/drivers/staging/lustre/lustre/include/cl_object.h index 90a0c501e1ea..9ba184b6017f 100644 --- a/drivers/staging/lustre/lustre/include/cl_object.h +++ b/drivers/staging/lustre/lustre/include/cl_object.h @@ -88,8 +88,8 @@ /* * super-class definitions. */ -#include "lu_object.h" -#include "lustre_compat.h" +#include <lu_object.h> +#include <lustre_compat.h> #include <linux/atomic.h> #include <linux/mutex.h> #include <linux/radix-tree.h> @@ -1358,7 +1358,7 @@ struct cl_2queue { /** IO types */ enum cl_io_type { /** read system call */ - CIT_READ, + CIT_READ = 1, /** write system call */ CIT_WRITE, /** truncate, utime system calls */ diff --git a/drivers/staging/lustre/lustre/include/interval_tree.h b/drivers/staging/lustre/lustre/include/interval_tree.h index 0d4f92ec8334..a4d7280e1fa4 100644 --- a/drivers/staging/lustre/lustre/include/interval_tree.h +++ b/drivers/staging/lustre/lustre/include/interval_tree.h @@ -111,4 +111,8 @@ enum interval_iter interval_search(struct interval_node *root, struct interval_node_extent *ex, interval_callback_t func, void *data); +enum interval_iter interval_iterate_reverse(struct interval_node *root, + interval_callback_t func, + void *data); + #endif diff --git a/drivers/staging/lustre/lustre/include/llog_swab.h b/drivers/staging/lustre/lustre/include/llog_swab.h index fd7ffb154ad1..925271db4554 100644 --- a/drivers/staging/lustre/lustre/include/llog_swab.h +++ b/drivers/staging/lustre/lustre/include/llog_swab.h @@ -48,7 +48,8 @@ #ifndef _LLOG_SWAB_H_ #define _LLOG_SWAB_H_ -#include "lustre/lustre_idl.h" +#include <uapi/linux/lustre/lustre_idl.h> + struct lustre_cfg; void lustre_swab_lu_fid(struct lu_fid *fid); diff --git a/drivers/staging/lustre/lustre/include/lprocfs_status.h b/drivers/staging/lustre/lustre/include/lprocfs_status.h index 915283c04094..98d6b1364c21 100644 --- a/drivers/staging/lustre/lustre/include/lprocfs_status.h +++ b/drivers/staging/lustre/lustre/include/lprocfs_status.h @@ -43,9 +43,9 @@ #include <linux/spinlock.h> #include <linux/types.h> -#include "../../include/linux/libcfs/libcfs.h" -#include "lustre_cfg.h" -#include "lustre/lustre_idl.h" +#include <linux/libcfs/libcfs.h> +#include <uapi/linux/lustre/lustre_cfg.h> +#include <uapi/linux/lustre/lustre_idl.h> struct lprocfs_vars { const char *name; @@ -59,7 +59,7 @@ struct lprocfs_vars { struct lprocfs_static_vars { struct lprocfs_vars *obd_vars; - struct attribute_group *sysfs_vars; + const struct attribute_group *sysfs_vars; }; /* if we find more consumers this could be generalized */ @@ -468,7 +468,7 @@ struct dentry *ldebugfs_register(const char *name, void ldebugfs_remove(struct dentry **entryp); int lprocfs_obd_setup(struct obd_device *obd, struct lprocfs_vars *list, - struct attribute_group *attrs); + const struct attribute_group *attrs); int lprocfs_obd_cleanup(struct obd_device *obd); int ldebugfs_seq_create(struct dentry *parent, diff --git a/drivers/staging/lustre/lustre/include/lu_object.h b/drivers/staging/lustre/lustre/include/lu_object.h index 2e70602dc2e2..4f213c408cfa 100644 --- a/drivers/staging/lustre/lustre/include/lu_object.h +++ b/drivers/staging/lustre/lustre/include/lu_object.h @@ -35,9 +35,9 @@ #include <stdarg.h> #include <linux/percpu_counter.h> -#include "../../include/linux/libcfs/libcfs.h" -#include "lustre/lustre_idl.h" -#include "lu_ref.h" +#include <linux/libcfs/libcfs.h> +#include <uapi/linux/lustre/lustre_idl.h> +#include <lu_ref.h> struct seq_file; struct lustre_cfg; diff --git a/drivers/staging/lustre/lustre/include/lustre_compat.h b/drivers/staging/lustre/lustre/include/lustre_compat.h index da9ce195c52e..69bfd6a6e0f9 100644 --- a/drivers/staging/lustre/lustre/include/lustre_compat.h +++ b/drivers/staging/lustre/lustre/include/lustre_compat.h @@ -37,7 +37,7 @@ #include <linux/namei.h> #include <linux/cred.h> -#include "lustre_patchless_compat.h" +#include <lustre_patchless_compat.h> /* * set ATTR_BLOCKS to a high value to avoid any risk of collision with other diff --git a/drivers/staging/lustre/lustre/include/lustre_debug.h b/drivers/staging/lustre/lustre/include/lustre_debug.h index 93c1bdaf71a4..0be6a534f712 100644 --- a/drivers/staging/lustre/lustre/include/lustre_debug.h +++ b/drivers/staging/lustre/lustre/include/lustre_debug.h @@ -38,8 +38,8 @@ * @{ */ -#include "lustre_net.h" -#include "obd.h" +#include <lustre_net.h> +#include <obd.h> /* lib/debug.c */ int dump_req(struct ptlrpc_request *req); diff --git a/drivers/staging/lustre/lustre/include/lustre_disk.h b/drivers/staging/lustre/lustre/include/lustre_disk.h index a676bccabd43..2d862b32265b 100644 --- a/drivers/staging/lustre/lustre/include/lustre_disk.h +++ b/drivers/staging/lustre/lustre/include/lustre_disk.h @@ -44,9 +44,10 @@ * @{ */ -#include "../../include/linux/libcfs/libcfs.h" -#include "../../include/linux/lnet/types.h" +#include <asm/byteorder.h> +#include <linux/types.h> #include <linux/backing-dev.h> +#include <linux/libcfs/libcfs.h> /****************** persistent mount data *********************/ @@ -108,14 +109,6 @@ struct lustre_mount_data { #define lmd_is_client(x) ((x)->lmd_flags & LMD_FLG_CLIENT) -/****************** last_rcvd file *********************/ - -/** version recovery epoch */ -#define LR_EPOCH_BITS 32 -#define lr_epoch(a) ((a) >> LR_EPOCH_BITS) -#define LR_EXPIRE_INTERVALS 16 /**< number of intervals to track transno */ -#define ENOENT_VERSION 1 /** 'virtual' version of non-existent object */ - /****************** superblock additional info *********************/ struct ll_sb_info; @@ -141,16 +134,6 @@ struct lustre_sb_info { #define s2lsi_nocast(sb) ((sb)->s_fs_info) #define get_profile_name(sb) (s2lsi(sb)->lsi_lmd->lmd_profile) -#define get_mount_flags(sb) (s2lsi(sb)->lsi_lmd->lmd_flags) -#define get_mntdev_name(sb) (s2lsi(sb)->lsi_lmd->lmd_dev) - -/****************** mount lookup info *********************/ - -struct lustre_mount_info { - char *lmi_name; - struct super_block *lmi_sb; - struct list_head lmi_list_chain; -}; /****************** prototypes *********************/ diff --git a/drivers/staging/lustre/lustre/include/lustre_dlm.h b/drivers/staging/lustre/lustre/include/lustre_dlm.h index 1e86fb53388a..13c3d2fd31a8 100644 --- a/drivers/staging/lustre/lustre/include/lustre_dlm.h +++ b/drivers/staging/lustre/lustre/include/lustre_dlm.h @@ -44,12 +44,12 @@ #ifndef _LUSTRE_DLM_H__ #define _LUSTRE_DLM_H__ -#include "lustre_lib.h" -#include "lustre_net.h" -#include "lustre_import.h" -#include "lustre_handles.h" -#include "interval_tree.h" /* for interval_node{}, ldlm_extent */ -#include "lu_ref.h" +#include <lustre_lib.h> +#include <lustre_net.h> +#include <lustre_import.h> +#include <lustre_handles.h> +#include <interval_tree.h> /* for interval_node{}, ldlm_extent */ +#include <lu_ref.h> #include "lustre_dlm_flags.h" @@ -1336,5 +1336,18 @@ void ldlm_pool_add(struct ldlm_pool *pl, struct ldlm_lock *lock); void ldlm_pool_del(struct ldlm_pool *pl, struct ldlm_lock *lock); /** @} */ +static inline int ldlm_extent_overlap(const struct ldlm_extent *ex1, + const struct ldlm_extent *ex2) +{ + return ex1->start <= ex2->end && ex2->start <= ex1->end; +} + +/* check if @ex1 contains @ex2 */ +static inline int ldlm_extent_contain(const struct ldlm_extent *ex1, + const struct ldlm_extent *ex2) +{ + return ex1->start <= ex2->start && ex1->end >= ex2->end; +} + #endif /** @} LDLM */ diff --git a/drivers/staging/lustre/lustre/include/lustre/lustre_errno.h b/drivers/staging/lustre/lustre/include/lustre_errno.h index 35aefa2cdad1..35aefa2cdad1 100644 --- a/drivers/staging/lustre/lustre/include/lustre/lustre_errno.h +++ b/drivers/staging/lustre/lustre/include/lustre_errno.h diff --git a/drivers/staging/lustre/lustre/include/lustre_export.h b/drivers/staging/lustre/lustre/include/lustre_export.h index 6e7cc4689fb8..3631a69a5c6f 100644 --- a/drivers/staging/lustre/lustre/include/lustre_export.h +++ b/drivers/staging/lustre/lustre/include/lustre_export.h @@ -42,9 +42,9 @@ * @{ */ -#include "lprocfs_status.h" -#include "lustre/lustre_idl.h" -#include "lustre_dlm.h" +#include <lprocfs_status.h> +#include <uapi/linux/lustre/lustre_idl.h> +#include <lustre_dlm.h> enum obd_option { OBD_OPT_FORCE = 0x0001, diff --git a/drivers/staging/lustre/lustre/include/lustre_fid.h b/drivers/staging/lustre/lustre/include/lustre_fid.h index 6dc24a76ddb6..e0f2b8295775 100644 --- a/drivers/staging/lustre/lustre/include/lustre_fid.h +++ b/drivers/staging/lustre/lustre/include/lustre_fid.h @@ -41,7 +41,7 @@ * * @{ * - * http://wiki.old.lustre.org/index.php/Architecture_-_Interoperability_fids_zfs + * http://wiki.lustre.org/index.php/Architecture_-_Interoperability_fids_zfs * describes the FID namespace and interoperability requirements for FIDs. * The important parts of that document are included here for reference. * @@ -148,9 +148,10 @@ * Even so, the MDT and OST resources are also in different LDLM namespaces. */ -#include "../../include/linux/libcfs/libcfs.h" -#include "lustre/lustre_idl.h" -#include "seq_range.h" +#include <linux/libcfs/libcfs.h> +#include <uapi/linux/lustre/lustre_fid.h> +#include <uapi/linux/lustre/lustre_idl.h> +#include <uapi/linux/lustre/lustre_ostid.h> struct lu_env; struct lu_site; @@ -288,18 +289,6 @@ static inline int fid_is_quota(const struct lu_fid *fid) fid_seq(fid) == FID_SEQ_QUOTA_GLB; } -static inline int fid_is_namespace_visible(const struct lu_fid *fid) -{ - const __u64 seq = fid_seq(fid); - - /* Here, we cannot distinguish whether the normal FID is for OST - * object or not. It is caller's duty to check more if needed. - */ - return (!fid_is_last_id(fid) && - (fid_seq_is_norm(seq) || fid_seq_is_igif(seq))) || - fid_is_root(fid) || fid_is_dot_lustre(fid); -} - static inline int fid_seq_in_fldb(__u64 seq) { return fid_seq_is_igif(seq) || fid_seq_is_norm(seq) || @@ -506,6 +495,52 @@ static inline int ostid_res_name_eq(const struct ost_id *oi, } } +/** + * Note: we need check oi_seq to decide where to set oi_id, + * so oi_seq should always be set ahead of oi_id. + */ +static inline int ostid_set_id(struct ost_id *oi, __u64 oid) +{ + if (fid_seq_is_mdt0(oi->oi.oi_seq)) { + if (oid >= IDIF_MAX_OID) + return -E2BIG; + oi->oi.oi_id = oid; + } else if (fid_is_idif(&oi->oi_fid)) { + if (oid >= IDIF_MAX_OID) + return -E2BIG; + oi->oi_fid.f_seq = fid_idif_seq(oid, + fid_idif_ost_idx(&oi->oi_fid)); + oi->oi_fid.f_oid = oid; + oi->oi_fid.f_ver = oid >> 48; + } else { + if (oid >= OBIF_MAX_OID) + return -E2BIG; + oi->oi_fid.f_oid = oid; + } + return 0; +} + +/* pack any OST FID into an ostid (id/seq) for the wire/disk */ +static inline int fid_to_ostid(const struct lu_fid *fid, struct ost_id *ostid) +{ + int rc = 0; + + if (fid_seq_is_igif(fid->f_seq)) + return -EBADF; + + if (fid_is_idif(fid)) { + u64 objid = fid_idif_id(fid_seq(fid), fid_oid(fid), + fid_ver(fid)); + + ostid_set_seq_mdt0(ostid); + rc = ostid_set_id(ostid, objid); + } else { + ostid->oi_fid = *fid; + } + + return rc; +} + /* The same as osc_build_res_name() */ static inline void ost_fid_build_resid(const struct lu_fid *fid, struct ldlm_res_id *resname) @@ -522,23 +557,6 @@ static inline void ost_fid_build_resid(const struct lu_fid *fid, } } -static inline void ost_fid_from_resid(struct lu_fid *fid, - const struct ldlm_res_id *name, - int ost_idx) -{ - if (fid_seq_is_mdt0(name->name[LUSTRE_RES_ID_VER_OID_OFF])) { - /* old resid */ - struct ost_id oi; - - ostid_set_seq(&oi, name->name[LUSTRE_RES_ID_VER_OID_OFF]); - ostid_set_id(&oi, name->name[LUSTRE_RES_ID_SEQ_OFF]); - ostid_to_fid(fid, &oi, ost_idx); - } else { - /* new resid */ - fid_extract_from_res_name(fid, name); - } -} - /** * Flatten 128-bit FID values into a 64-bit value for use as an inode number. * For non-IGIF FIDs this starts just over 2^32, and continues without diff --git a/drivers/staging/lustre/lustre/include/lustre_fld.h b/drivers/staging/lustre/lustre/include/lustre_fld.h index 6ef1b03cb986..6125eb0d3395 100644 --- a/drivers/staging/lustre/lustre/include/lustre_fld.h +++ b/drivers/staging/lustre/lustre/include/lustre_fld.h @@ -38,8 +38,9 @@ * @{ */ -#include "lustre/lustre_idl.h" -#include "../../include/linux/libcfs/libcfs.h" +#include <uapi/linux/lustre/lustre_idl.h> +#include <linux/libcfs/libcfs.h> +#include <seq_range.h> struct lu_client_fld; struct lu_server_fld; diff --git a/drivers/staging/lustre/lustre/include/lustre_handles.h b/drivers/staging/lustre/lustre/include/lustre_handles.h index e071bac9df57..d49932628f32 100644 --- a/drivers/staging/lustre/lustre/include/lustre_handles.h +++ b/drivers/staging/lustre/lustre/include/lustre_handles.h @@ -44,7 +44,7 @@ #include <linux/spinlock.h> #include <linux/types.h> -#include "../../include/linux/libcfs/libcfs.h" +#include <linux/libcfs/libcfs.h> struct portals_handle_ops { void (*hop_addref)(void *object); diff --git a/drivers/staging/lustre/lustre/include/lustre_import.h b/drivers/staging/lustre/lustre/include/lustre_import.h index f0c931ce1a67..d71d0473a4eb 100644 --- a/drivers/staging/lustre/lustre/include/lustre_import.h +++ b/drivers/staging/lustre/lustre/include/lustre_import.h @@ -43,8 +43,8 @@ * @{ */ -#include "lustre_handles.h" -#include "lustre/lustre_idl.h" +#include <lustre_handles.h> +#include <uapi/linux/lustre/lustre_idl.h> /** * Adaptive Timeout stuff diff --git a/drivers/staging/lustre/lustre/include/lustre_kernelcomm.h b/drivers/staging/lustre/lustre/include/lustre_kernelcomm.h index 970610b6de89..f1899a3d7a40 100644 --- a/drivers/staging/lustre/lustre/include/lustre_kernelcomm.h +++ b/drivers/staging/lustre/lustre/include/lustre_kernelcomm.h @@ -38,7 +38,7 @@ #define __LUSTRE_KERNELCOMM_H__ /* For declarations shared with userspace */ -#include "uapi_kernelcomm.h" +#include <uapi/linux/lustre/lustre_kernelcomm.h> /* prototype for callback function on kuc groups */ typedef int (*libcfs_kkuc_cb_t)(void *data, void *cb_arg); diff --git a/drivers/staging/lustre/lustre/include/lustre_lib.h b/drivers/staging/lustre/lustre/include/lustre_lib.h index f24970da8323..81b9cbffc050 100644 --- a/drivers/staging/lustre/lustre/include/lustre_lib.h +++ b/drivers/staging/lustre/lustre/include/lustre_lib.h @@ -45,18 +45,18 @@ #include <linux/sched/signal.h> #include <linux/signal.h> #include <linux/types.h> -#include "../../include/linux/libcfs/libcfs.h" -#include "lustre/lustre_idl.h" -#include "lustre_ver.h" -#include "lustre_cfg.h" +#include <linux/libcfs/libcfs.h> +#include <uapi/linux/lustre/lustre_idl.h> +#include <uapi/linux/lustre/lustre_ver.h> +#include <uapi/linux/lustre/lustre_cfg.h> /* target.c */ struct ptlrpc_request; struct obd_export; struct lu_target; struct l_wait_info; -#include "lustre_ha.h" -#include "lustre_net.h" +#include <lustre_ha.h> +#include <lustre_net.h> #define LI_POISON 0x5a5a5a5a #if BITS_PER_LONG > 32 diff --git a/drivers/staging/lustre/lustre/include/lustre_linkea.h b/drivers/staging/lustre/lustre/include/lustre_linkea.h index 249e8bf4fa22..3ff008fee13d 100644 --- a/drivers/staging/lustre/lustre/include/lustre_linkea.h +++ b/drivers/staging/lustre/lustre/include/lustre_linkea.h @@ -26,7 +26,19 @@ * Author: di wang <di.wang@intel.com> */ -#define DEFAULT_LINKEA_SIZE 4096 +/* There are several reasons to restrict the linkEA size: + * + * 1. Under DNE mode, if we do not restrict the linkEA size, and if there + * are too many cross-MDTs hard links to the same object, then it will + * casue the llog overflow. + * + * 2. Some backend has limited size for EA. For example, if without large + * EA enabled, the ldiskfs will make all EAs to share one (4K) EA block. + * + * 3. Too many entries in linkEA will seriously affect linkEA performance + * because we only support to locate linkEA entry consecutively. + */ +#define MAX_LINKEA_SIZE 4096 struct linkea_data { /** @@ -43,6 +55,7 @@ struct linkea_data { int linkea_data_new(struct linkea_data *ldata, struct lu_buf *buf); int linkea_init(struct linkea_data *ldata); +int linkea_init_with_rec(struct linkea_data *ldata); void linkea_entry_unpack(const struct link_ea_entry *lee, int *reclen, struct lu_name *lname, struct lu_fid *pfid); int linkea_entry_pack(struct link_ea_entry *lee, const struct lu_name *lname, diff --git a/drivers/staging/lustre/lustre/include/lustre_lmv.h b/drivers/staging/lustre/lustre/include/lustre_lmv.h index 5aa3645e64dc..98a82be2037f 100644 --- a/drivers/staging/lustre/lustre/include/lustre_lmv.h +++ b/drivers/staging/lustre/lustre/include/lustre_lmv.h @@ -32,7 +32,7 @@ #ifndef _LUSTRE_LMV_H #define _LUSTRE_LMV_H -#include "lustre/lustre_idl.h" +#include <uapi/linux/lustre/lustre_idl.h> struct lmv_oinfo { struct lu_fid lmo_fid; diff --git a/drivers/staging/lustre/lustre/include/lustre_log.h b/drivers/staging/lustre/lustre/include/lustre_log.h index 35e37eb1bc2c..24a7777424f6 100644 --- a/drivers/staging/lustre/lustre/include/lustre_log.h +++ b/drivers/staging/lustre/lustre/include/lustre_log.h @@ -52,8 +52,8 @@ * @{ */ -#include "obd_class.h" -#include "lustre/lustre_idl.h" +#include <obd_class.h> +#include <uapi/linux/lustre/lustre_idl.h> #define LOG_NAME_LIMIT(logname, name) \ snprintf(logname, sizeof(logname), "LOGS/%s", name) diff --git a/drivers/staging/lustre/lustre/include/lustre_mdc.h b/drivers/staging/lustre/lustre/include/lustre_mdc.h index 198ceb0c66f9..c0c44974cb1c 100644 --- a/drivers/staging/lustre/lustre/include/lustre_mdc.h +++ b/drivers/staging/lustre/lustre/include/lustre_mdc.h @@ -46,14 +46,13 @@ #include <linux/fs.h> #include <linux/dcache.h> -#include "lustre_intent.h" -#include "lustre_handles.h" -#include "../../include/linux/libcfs/libcfs.h" -#include "obd_class.h" -#include "lustre/lustre_idl.h" -#include "lustre_lib.h" -#include "lustre_dlm.h" -#include "lustre_export.h" +#include <lustre_intent.h> +#include <lustre_handles.h> +#include <linux/libcfs/libcfs.h> +#include <obd_class.h> +#include <lustre_lib.h> +#include <lustre_dlm.h> +#include <lustre_export.h> struct ptlrpc_client; struct obd_export; diff --git a/drivers/staging/lustre/lustre/include/lustre_mds.h b/drivers/staging/lustre/lustre/include/lustre_mds.h index 23a7e4f78e9a..c424e1239fd5 100644 --- a/drivers/staging/lustre/lustre/include/lustre_mds.h +++ b/drivers/staging/lustre/lustre/include/lustre_mds.h @@ -43,12 +43,11 @@ * @{ */ -#include "lustre_handles.h" -#include "../../include/linux/libcfs/libcfs.h" -#include "lustre/lustre_idl.h" -#include "lustre_lib.h" -#include "lustre_dlm.h" -#include "lustre_export.h" +#include <lustre_handles.h> +#include <linux/libcfs/libcfs.h> +#include <lustre_lib.h> +#include <lustre_dlm.h> +#include <lustre_export.h> struct mds_group_info { struct obd_uuid *uuid; diff --git a/drivers/staging/lustre/lustre/include/lustre_net.h b/drivers/staging/lustre/lustre/include/lustre_net.h index d61b000dac2c..c6d1646f102a 100644 --- a/drivers/staging/lustre/lustre/include/lustre_net.h +++ b/drivers/staging/lustre/lustre/include/lustre_net.h @@ -51,19 +51,20 @@ */ #include <linux/uio.h> -#include "../../include/linux/libcfs/libcfs.h" -#include "../../include/linux/lnet/nidstr.h" -#include "../../include/linux/lnet/api.h" -#include "lustre/lustre_idl.h" -#include "lustre_ha.h" -#include "lustre_sec.h" -#include "lustre_import.h" -#include "lprocfs_status.h" -#include "lu_object.h" -#include "lustre_req_layout.h" - -#include "obd_support.h" -#include "lustre_ver.h" +#include <linux/libcfs/libcfs.h> +#include <uapi/linux/lnet/nidstr.h> +#include <linux/lnet/api.h> +#include <uapi/linux/lustre/lustre_idl.h> +#include <lustre_errno.h> +#include <lustre_ha.h> +#include <lustre_sec.h> +#include <lustre_import.h> +#include <lprocfs_status.h> +#include <lu_object.h> +#include <lustre_req_layout.h> + +#include <obd_support.h> +#include <uapi/linux/lustre/lustre_ver.h> /* MD flags we _always_ use */ #define PTLRPC_MD_OPTIONS 0 @@ -521,7 +522,7 @@ struct lu_env; struct ldlm_lock; -#include "lustre_nrs.h" +#include <lustre_nrs.h> /** * Basic request prioritization operations structure. @@ -558,13 +559,13 @@ struct ptlrpc_cli_req { /** request sent timeval */ struct timespec64 cr_sent_tv; /** time for request really sent out */ - time_t cr_sent_out; + time64_t cr_sent_out; /** when req reply unlink must finish. */ - time_t cr_reply_deadline; + time64_t cr_reply_deadline; /** when req bulk unlink must finish. */ - time_t cr_bulk_deadline; + time64_t cr_bulk_deadline; /** when req unlink must finish. */ - time_t cr_req_deadline; + time64_t cr_req_deadline; /** Portal to which this request would be sent */ short cr_req_ptl; /** Portal where to wait for reply and where reply would be sent */ @@ -663,7 +664,7 @@ struct ptlrpc_srv_req { /** history sequence # */ __u64 sr_hist_seq; /** the index of service's srv_at_array into which request is linked */ - time_t sr_at_index; + time64_t sr_at_index; /** authed uid */ uid_t sr_auth_uid; /** authed uid mapped to */ diff --git a/drivers/staging/lustre/lustre/include/lustre_nrs.h b/drivers/staging/lustre/lustre/include/lustre_nrs.h index a5028aaa19cd..51f45f7776df 100644 --- a/drivers/staging/lustre/lustre/include/lustre_nrs.h +++ b/drivers/staging/lustre/lustre/include/lustre_nrs.h @@ -669,7 +669,7 @@ enum { NRS_RES_MAX }; -#include "lustre_nrs_fifo.h" +#include <lustre_nrs_fifo.h> /** * NRS request diff --git a/drivers/staging/lustre/lustre/include/lustre_obdo.h b/drivers/staging/lustre/lustre/include/lustre_obdo.h index 1e12f8c0f157..53379f861161 100644 --- a/drivers/staging/lustre/lustre/include/lustre_obdo.h +++ b/drivers/staging/lustre/lustre/include/lustre_obdo.h @@ -35,7 +35,7 @@ #ifndef _LUSTRE_OBDO_H_ #define _LUSTRE_OBDO_H_ -#include "lustre/lustre_idl.h" +#include <uapi/linux/lustre/lustre_idl.h> /** * Create an obdo to send over the wire diff --git a/drivers/staging/lustre/lustre/include/lustre_param.h b/drivers/staging/lustre/lustre/include/lustre_param.h deleted file mode 100644 index 8061a04ee806..000000000000 --- a/drivers/staging/lustre/lustre/include/lustre_param.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * GPL HEADER START - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 only, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License version 2 for more details (a copy is included - * in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; If not, see - * http://www.gnu.org/licenses/gpl-2.0.html - * - * GPL HEADER END - */ -/* - * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. - * Use is subject to license terms. - * - * Copyright (c) 2011, 2015, Intel Corporation. - */ -/* - * This file is part of Lustre, http://www.lustre.org/ - * Lustre is a trademark of Sun Microsystems, Inc. - * - * lustre/include/lustre_param.h - * - * User-settable parameter keys - * - * Author: Nathan Rutman <nathan@clusterfs.com> - */ - -#ifndef _LUSTRE_PARAM_H -#define _LUSTRE_PARAM_H - -#include "../../include/linux/libcfs/libcfs.h" -#include "../../include/linux/lnet/types.h" - -/** \defgroup param param - * - * @{ - */ - -/* For interoperability */ -struct cfg_interop_param { - char *old_param; - char *new_param; -}; - -/* obd_config.c */ -int class_find_param(char *buf, char *key, char **valp); -int class_parse_nid(char *buf, lnet_nid_t *nid, char **endh); -int class_parse_nid_quiet(char *buf, lnet_nid_t *nid, char **endh); - -/****************** User-settable parameter keys *********************/ -/* e.g. - tunefs.lustre --param="failover.node=192.168.0.13@tcp0" /dev/sda - lctl conf_param testfs-OST0000 failover.node=3@elan,192.168.0.3@tcp0 - ... testfs-MDT0000.lov.stripesize=4M - ... testfs-OST0000.ost.client_cache_seconds=15 - ... testfs.sys.timeout=<secs> - ... testfs.llite.max_read_ahead_mb=16 -*/ - -/* System global or special params not handled in obd's proc - * See mgs_write_log_sys() - */ -#define PARAM_TIMEOUT "timeout=" /* global */ -#define PARAM_LDLM_TIMEOUT "ldlm_timeout=" /* global */ -#define PARAM_AT_MIN "at_min=" /* global */ -#define PARAM_AT_MAX "at_max=" /* global */ -#define PARAM_AT_EXTRA "at_extra=" /* global */ -#define PARAM_AT_EARLY_MARGIN "at_early_margin=" /* global */ -#define PARAM_AT_HISTORY "at_history=" /* global */ -#define PARAM_JOBID_VAR "jobid_var=" /* global */ -#define PARAM_MGSNODE "mgsnode=" /* only at mounttime */ -#define PARAM_FAILNODE "failover.node=" /* add failover nid */ -#define PARAM_FAILMODE "failover.mode=" /* initial mount only */ -#define PARAM_ACTIVE "active=" /* activate/deactivate */ -#define PARAM_NETWORK "network=" /* bind on nid */ -#define PARAM_ID_UPCALL "identity_upcall=" /* identity upcall */ - -/* Prefixes for parameters handled by obd's proc methods (XXX_process_config) */ -#define PARAM_OST "ost." -#define PARAM_OSD "osd." -#define PARAM_OSC "osc." -#define PARAM_MDT "mdt." -#define PARAM_MDD "mdd." -#define PARAM_MDC "mdc." -#define PARAM_LLITE "llite." -#define PARAM_LOV "lov." -#define PARAM_LOD "lod." -#define PARAM_OSP "osp." -#define PARAM_SYS "sys." /* global */ -#define PARAM_SRPC "srpc." -#define PARAM_SRPC_FLVR "srpc.flavor." -#define PARAM_SRPC_UDESC "srpc.udesc.cli2mdt" -#define PARAM_SEC "security." -#define PARAM_QUOTA "quota." /* global */ - -/** @} param */ - -#endif /* _LUSTRE_PARAM_H */ diff --git a/drivers/staging/lustre/lustre/include/lustre_swab.h b/drivers/staging/lustre/lustre/include/lustre_swab.h index 26d01c2d6633..765e923c2fc9 100644 --- a/drivers/staging/lustre/lustre/include/lustre_swab.h +++ b/drivers/staging/lustre/lustre/include/lustre_swab.h @@ -48,7 +48,7 @@ #ifndef _LUSTRE_SWAB_H_ #define _LUSTRE_SWAB_H_ -#include "lustre/lustre_idl.h" +#include <uapi/linux/lustre/lustre_idl.h> void lustre_swab_ptlrpc_body(struct ptlrpc_body *pb); void lustre_swab_connect(struct obd_connect_data *ocd); @@ -99,4 +99,10 @@ void lustre_swab_swap_layouts(struct mdc_swap_layouts *msl); void lustre_swab_close_data(struct close_data *data); void lustre_swab_lmv_user_md(struct lmv_user_md *lum); +/* Functions for dumping PTLRPC fields */ +void dump_rniobuf(struct niobuf_remote *rnb); +void dump_ioo(struct obd_ioobj *nb); +void dump_ost_body(struct ost_body *ob); +void dump_rcs(__u32 *rc); + #endif diff --git a/drivers/staging/lustre/lustre/include/obd.h b/drivers/staging/lustre/lustre/include/obd.h index 4ce85064f9d0..a986737ec010 100644 --- a/drivers/staging/lustre/lustre/include/obd.h +++ b/drivers/staging/lustre/lustre/include/obd.h @@ -35,15 +35,15 @@ #include <linux/spinlock.h> -#include "lustre/lustre_idl.h" -#include "lustre_lib.h" -#include "lu_ref.h" -#include "lustre_export.h" -#include "lustre_fid.h" -#include "lustre_fld.h" -#include "lustre_handles.h" -#include "lustre_intent.h" -#include "cl_object.h" +#include <uapi/linux/lustre/lustre_idl.h> +#include <lustre_lib.h> +#include <lu_ref.h> +#include <lustre_export.h> +#include <lustre_fid.h> +#include <lustre_fld.h> +#include <lustre_handles.h> +#include <lustre_intent.h> +#include <cl_object.h> #define MAX_OBD_DEVICES 8192 @@ -404,12 +404,10 @@ struct lmv_tgt_desc { }; struct lmv_obd { - int refcount; struct lu_client_fld lmv_fld; spinlock_t lmv_lock; struct lmv_desc desc; struct obd_uuid cluuid; - struct obd_export *exp; struct mutex lmv_init_mutex; int connected; diff --git a/drivers/staging/lustre/lustre/include/obd_cksum.h b/drivers/staging/lustre/lustre/include/obd_cksum.h index a8a81e662a56..cda3d2808d2f 100644 --- a/drivers/staging/lustre/lustre/include/obd_cksum.h +++ b/drivers/staging/lustre/lustre/include/obd_cksum.h @@ -30,9 +30,9 @@ #ifndef __OBD_CKSUM #define __OBD_CKSUM -#include "../../include/linux/libcfs/libcfs.h" -#include "../../include/linux/libcfs/libcfs_crypto.h" -#include "lustre/lustre_idl.h" +#include <linux/libcfs/libcfs.h> +#include <linux/libcfs/libcfs_crypto.h> +#include <uapi/linux/lustre/lustre_idl.h> static inline unsigned char cksum_obd2cfs(enum cksum_type cksum_type) { diff --git a/drivers/staging/lustre/lustre/include/obd_class.h b/drivers/staging/lustre/lustre/include/obd_class.h index 083a6ff56a05..976005a1e0b2 100644 --- a/drivers/staging/lustre/lustre/include/obd_class.h +++ b/drivers/staging/lustre/lustre/include/obd_class.h @@ -32,13 +32,12 @@ #ifndef __CLASS_OBD_H #define __CLASS_OBD_H -#include "obd_support.h" -#include "lustre_import.h" -#include "lustre_net.h" -#include "obd.h" -#include "lustre_lib.h" -#include "lustre/lustre_idl.h" -#include "lprocfs_status.h" +#include <obd_support.h> +#include <lustre_import.h> +#include <lustre_net.h> +#include <obd.h> +#include <lustre_lib.h> +#include <lprocfs_status.h> #define OBD_STATFS_NODELAY 0x0001 /* requests should be send without delay * and resends for avoid deadlocks @@ -46,14 +45,7 @@ #define OBD_STATFS_FROM_CACHE 0x0002 /* the statfs callback should not update * obd_osfs_age */ -#define OBD_STATFS_PTLRPCD 0x0004 /* requests will be sent via ptlrpcd - * instead of a specific set. This - * means that we cannot rely on the set - * interpret routine to be called. - * lov_statfs_fini() must thus be called - * by the request interpret routine - */ -#define OBD_STATFS_FOR_MDT0 0x0008 /* The statfs is only for retrieving +#define OBD_STATFS_FOR_MDT0 0x0004 /* The statfs is only for retrieving * information from MDT0. */ @@ -112,10 +104,29 @@ struct llog_handle; struct llog_rec_hdr; typedef int (*llog_cb_t)(const struct lu_env *, struct llog_handle *, struct llog_rec_hdr *, void *); + /* obd_config.c */ +char *lustre_cfg_string(struct lustre_cfg *lcfg, u32 index); int class_process_config(struct lustre_cfg *lcfg); int class_process_proc_param(char *prefix, struct lprocfs_vars *lvars, struct lustre_cfg *lcfg, void *data); + +/* For interoperability */ +struct cfg_interop_param { + char *old_param; + char *new_param; +}; + +int class_find_param(char *buf, char *key, char **valp); +struct cfg_interop_param *class_find_old_param(const char *param, + struct cfg_interop_param *ptr); +int class_get_next_param(char **params, char *copy); +int class_parse_nid(char *buf, lnet_nid_t *nid, char **endh); +int class_parse_nid_quiet(char *buf, lnet_nid_t *nid, char **endh); +int class_parse_net(char *buf, u32 *net, char **endh); +int class_match_nid(char *buf, char *key, lnet_nid_t nid); +int class_match_net(char *buf, char *key, u32 net); + struct obd_device *class_incref(struct obd_device *obd, const char *scope, const void *source); void class_decref(struct obd_device *obd, @@ -1566,4 +1577,7 @@ struct root_squash_info { struct rw_semaphore rsi_sem; }; +/* linux-module.c */ +int obd_ioctl_getdata(char **buf, int *len, void __user *arg); + #endif /* __LINUX_OBD_CLASS_H */ diff --git a/drivers/staging/lustre/lustre/include/obd_support.h b/drivers/staging/lustre/lustre/include/obd_support.h index 33304041bb63..aea193a882a2 100644 --- a/drivers/staging/lustre/lustre/include/obd_support.h +++ b/drivers/staging/lustre/lustre/include/obd_support.h @@ -36,9 +36,9 @@ #include <linux/slab.h> #include <linux/sched/signal.h> -#include "../../include/linux/libcfs/libcfs.h" -#include "lustre_compat.h" -#include "lprocfs_status.h" +#include <linux/libcfs/libcfs.h> +#include <lustre_compat.h> +#include <lprocfs_status.h> /* global variables */ extern unsigned int obd_debug_peer_on_timeout; diff --git a/drivers/staging/lustre/lustre/include/seq_range.h b/drivers/staging/lustre/lustre/include/seq_range.h index 30c4dd66d5c4..d7175485944d 100644 --- a/drivers/staging/lustre/lustre/include/seq_range.h +++ b/drivers/staging/lustre/lustre/include/seq_range.h @@ -34,7 +34,7 @@ #ifndef _SEQ_RANGE_H_ #define _SEQ_RANGE_H_ -#include "lustre/lustre_idl.h" +#include <uapi/linux/lustre/lustre_idl.h> /** * computes the sequence range type \a range diff --git a/drivers/staging/lustre/lustre/ldlm/interval_tree.c b/drivers/staging/lustre/lustre/ldlm/interval_tree.c index e1069021420d..19e285dd2ee1 100644 --- a/drivers/staging/lustre/lustre/ldlm/interval_tree.c +++ b/drivers/staging/lustre/lustre/ldlm/interval_tree.c @@ -34,9 +34,9 @@ * Author: Huang Wei <huangwei@clusterfs.com> * Author: Jay Xiong <jinshan.xiong@sun.com> */ -#include "../include/lustre_dlm.h" -#include "../include/obd_support.h" -#include "../include/interval_tree.h" +#include <lustre_dlm.h> +#include <obd_support.h> +#include <interval_tree.h> enum { INTERVAL_RED = 0, @@ -110,6 +110,15 @@ static struct interval_node *interval_first(struct interval_node *node) return node; } +static struct interval_node *interval_last(struct interval_node *node) +{ + if (!node) + return NULL; + while (node->in_right) + node = node->in_right; + return node; +} + static struct interval_node *interval_next(struct interval_node *node) { if (!node) @@ -121,6 +130,37 @@ static struct interval_node *interval_next(struct interval_node *node) return node->in_parent; } +static struct interval_node *interval_prev(struct interval_node *node) +{ + if (!node) + return NULL; + + if (node->in_left) + return interval_last(node->in_left); + + while (node->in_parent && node_is_left_child(node)) + node = node->in_parent; + + return node->in_parent; +} + +enum interval_iter interval_iterate_reverse(struct interval_node *root, + interval_callback_t func, + void *data) +{ + enum interval_iter rc = INTERVAL_ITER_CONT; + struct interval_node *node; + + for (node = interval_last(root); node; node = interval_prev(node)) { + rc = func(node, data); + if (rc == INTERVAL_ITER_STOP) + break; + } + + return rc; +} +EXPORT_SYMBOL(interval_iterate_reverse); + static void __rotate_change_maxhigh(struct interval_node *node, struct interval_node *rotate) { diff --git a/drivers/staging/lustre/lustre/ldlm/l_lock.c b/drivers/staging/lustre/lustre/ldlm/l_lock.c index 3845f386f1db..57fd84effdfa 100644 --- a/drivers/staging/lustre/lustre/ldlm/l_lock.c +++ b/drivers/staging/lustre/lustre/ldlm/l_lock.c @@ -31,10 +31,10 @@ */ #define DEBUG_SUBSYSTEM S_LDLM -#include "../../include/linux/libcfs/libcfs.h" +#include <linux/libcfs/libcfs.h> -#include "../include/lustre_dlm.h" -#include "../include/lustre_lib.h" +#include <lustre_dlm.h> +#include <lustre_lib.h> /** * Lock a lock and its resource. diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_extent.c b/drivers/staging/lustre/lustre/ldlm/ldlm_extent.c index 08f97e2117ed..2cc6dc2b281f 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_extent.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_extent.c @@ -46,12 +46,12 @@ */ #define DEBUG_SUBSYSTEM S_LDLM -#include "../../include/linux/libcfs/libcfs.h" -#include "../include/lustre_dlm.h" -#include "../include/obd_support.h" -#include "../include/obd.h" -#include "../include/obd_class.h" -#include "../include/lustre_lib.h" +#include <linux/libcfs/libcfs.h> +#include <lustre_dlm.h> +#include <obd_support.h> +#include <obd.h> +#include <obd_class.h> +#include <lustre_lib.h> #include "ldlm_internal.h" /* When a lock is cancelled by a client, the KMS may undergo change if this diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_flock.c b/drivers/staging/lustre/lustre/ldlm/ldlm_flock.c index b7f28b39c7b3..cb826e9e840e 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_flock.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_flock.c @@ -52,10 +52,10 @@ #define DEBUG_SUBSYSTEM S_LDLM -#include "../include/lustre_dlm.h" -#include "../include/obd_support.h" -#include "../include/obd_class.h" -#include "../include/lustre_lib.h" +#include <lustre_dlm.h> +#include <obd_support.h> +#include <obd_class.h> +#include <lustre_lib.h> #include <linux/list.h> #include "ldlm_internal.h" @@ -90,8 +90,8 @@ ldlm_flocks_overlap(struct ldlm_lock *lock, struct ldlm_lock *new) static inline void ldlm_flock_destroy(struct ldlm_lock *lock, enum ldlm_mode mode, __u64 flags) { - LDLM_DEBUG(lock, "ldlm_flock_destroy(mode: %d, flags: 0x%llx)", - mode, flags); + LDLM_DEBUG(lock, "%s(mode: %d, flags: 0x%llx)", + __func__, mode, flags); /* Safe to not lock here, since it should be empty anyway */ LASSERT(hlist_unhashed(&lock->l_exp_flock_hash)); @@ -596,7 +596,7 @@ granted: default: getlk->fl_type = F_UNLCK; } - getlk->fl_pid = (pid_t)lock->l_policy_data.l_flock.pid; + getlk->fl_pid = -(pid_t)lock->l_policy_data.l_flock.pid; getlk->fl_start = (loff_t)lock->l_policy_data.l_flock.start; getlk->fl_end = (loff_t)lock->l_policy_data.l_flock.end; } else { diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_inodebits.c b/drivers/staging/lustre/lustre/ldlm/ldlm_inodebits.c index ae37c3686b1b..fcb6e44bd319 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_inodebits.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_inodebits.c @@ -49,9 +49,9 @@ #define DEBUG_SUBSYSTEM S_LDLM -#include "../include/lustre_dlm.h" -#include "../include/obd_support.h" -#include "../include/lustre_lib.h" +#include <lustre_dlm.h> +#include <obd_support.h> +#include <lustre_lib.h> #include "ldlm_internal.h" void ldlm_ibits_policy_wire_to_local(const union ldlm_wire_policy_data *wpolicy, diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h b/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h index ec3b23cd09ec..36808dbe8790 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h @@ -106,9 +106,6 @@ int ldlm_cancel_lru_local(struct ldlm_namespace *ns, extern unsigned int ldlm_enqueue_min; extern unsigned int ldlm_cancel_unused_locks_before_replay; -/* ldlm_resource.c */ -int ldlm_resource_putref_locked(struct ldlm_resource *res); - /* ldlm_lock.c */ struct ldlm_cb_set_arg { @@ -336,3 +333,9 @@ void ldlm_flock_policy_wire_to_local(const union ldlm_wire_policy_data *wpolicy, union ldlm_policy_data *lpolicy); void ldlm_flock_policy_local_to_wire(const union ldlm_policy_data *lpolicy, union ldlm_wire_policy_data *wpolicy); + +static inline bool ldlm_res_eq(const struct ldlm_res_id *res0, + const struct ldlm_res_id *res1) +{ + return memcmp(res0, res1, sizeof(*res0)) == 0; +} diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_lib.c b/drivers/staging/lustre/lustre/ldlm/ldlm_lib.c index 4dc7baee1f28..22600c2a73ea 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_lib.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_lib.c @@ -39,12 +39,12 @@ #define DEBUG_SUBSYSTEM S_LDLM -#include "../../include/linux/libcfs/libcfs.h" -#include "../include/obd.h" -#include "../include/obd_class.h" -#include "../include/lustre_dlm.h" -#include "../include/lustre_net.h" -#include "../include/lustre_sec.h" +#include <linux/libcfs/libcfs.h> +#include <obd.h> +#include <obd_class.h> +#include <lustre_dlm.h> +#include <lustre_net.h> +#include <lustre_sec.h> #include "ldlm_internal.h" /* @priority: If non-zero, move the selected connection to the list head. diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c b/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c index ddb46428093f..b5d84f3f6071 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c @@ -37,10 +37,10 @@ #define DEBUG_SUBSYSTEM S_LDLM -#include "../../include/linux/libcfs/libcfs.h" -#include "../include/lustre_intent.h" -#include "../include/lustre_swab.h" -#include "../include/obd_class.h" +#include <linux/libcfs/libcfs.h> +#include <lustre_intent.h> +#include <lustre_swab.h> +#include <obd_class.h> #include "ldlm_internal.h" /* lock types */ @@ -1029,11 +1029,11 @@ void ldlm_grant_lock(struct ldlm_lock *lock, struct list_head *work_list) if (work_list && lock->l_completion_ast) ldlm_add_ast_work_item(lock, NULL, work_list); - if (res->lr_type == LDLM_PLAIN || res->lr_type == LDLM_IBITS) + if (res->lr_type == LDLM_PLAIN || res->lr_type == LDLM_IBITS) { ldlm_grant_lock_with_skiplist(lock); - else if (res->lr_type == LDLM_EXTENT) + } else if (res->lr_type == LDLM_EXTENT) { ldlm_extent_add_lock(res, lock); - else if (res->lr_type == LDLM_FLOCK) { + } else if (res->lr_type == LDLM_FLOCK) { /* * We should not add locks to granted list in the following cases: * - this is an UNLOCK but not a real lock; @@ -1045,8 +1045,9 @@ void ldlm_grant_lock(struct ldlm_lock *lock, struct list_head *work_list) ldlm_is_test_lock(lock) || ldlm_is_flock_deadlock(lock)) return; ldlm_resource_add_lock(res, &res->lr_granted, lock); - } else + } else { LBUG(); + } ldlm_pool_add(&ldlm_res_to_ns(res)->ns_pool, lock); } diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c b/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c index fff930fc3cff..e2707336586c 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c @@ -37,9 +37,9 @@ #define DEBUG_SUBSYSTEM S_LDLM -#include "../../include/linux/libcfs/libcfs.h" -#include "../include/lustre_dlm.h" -#include "../include/obd_class.h" +#include <linux/libcfs/libcfs.h> +#include <lustre_dlm.h> +#include <obd_class.h> #include <linux/list.h> #include "ldlm_internal.h" @@ -926,7 +926,7 @@ static struct attribute *ldlm_attrs[] = { NULL, }; -static struct attribute_group ldlm_attr_group = { +static const struct attribute_group ldlm_attr_group = { .attrs = ldlm_attrs, }; @@ -1138,7 +1138,7 @@ int ldlm_init(void) void ldlm_exit(void) { if (ldlm_refcount) - CERROR("ldlm_refcount is %d in ldlm_exit!\n", ldlm_refcount); + CERROR("ldlm_refcount is %d in %s!\n", ldlm_refcount, __func__); kmem_cache_destroy(ldlm_resource_slab); /* ldlm_lock_put() use RCU to call ldlm_lock_free, so need call * synchronize_rcu() to wait a grace period elapsed, so that diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_plain.c b/drivers/staging/lustre/lustre/ldlm/ldlm_plain.c index 862ea0a1dc97..1ca605fe25ff 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_plain.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_plain.c @@ -48,9 +48,9 @@ #define DEBUG_SUBSYSTEM S_LDLM -#include "../include/lustre_dlm.h" -#include "../include/obd_support.h" -#include "../include/lustre_lib.h" +#include <lustre_dlm.h> +#include <obd_support.h> +#include <lustre_lib.h> #include "ldlm_internal.h" diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c b/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c index cf3fc5793377..d77bf0baa84f 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c @@ -94,10 +94,10 @@ #define DEBUG_SUBSYSTEM S_LDLM -#include "../include/lustre_dlm.h" -#include "../include/cl_object.h" -#include "../include/obd_class.h" -#include "../include/obd_support.h" +#include <lustre_dlm.h> +#include <cl_object.h> +#include <obd_class.h> +#include <obd_support.h> #include "ldlm_internal.h" /* diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_request.c b/drivers/staging/lustre/lustre/ldlm/ldlm_request.c index 4028e11249a2..f3bf238d0748 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_request.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_request.c @@ -57,9 +57,10 @@ #define DEBUG_SUBSYSTEM S_LDLM -#include "../include/lustre_dlm.h" -#include "../include/obd_class.h" -#include "../include/obd.h" +#include <lustre_errno.h> +#include <lustre_dlm.h> +#include <obd_class.h> +#include <obd.h> #include "ldlm_internal.h" @@ -83,6 +84,33 @@ struct ldlm_async_args { struct lustre_handle lock_handle; }; +/** + * ldlm_request_bufsize + * + * @count: number of ldlm handles + * @type: ldlm opcode + * + * If opcode=LDLM_ENQUEUE, 1 slot is already occupied, + * LDLM_LOCKREQ_HANDLE -1 slots are available. + * Otherwise, LDLM_LOCKREQ_HANDLE slots are available. + * + * Return: size of the request buffer + */ +static int ldlm_request_bufsize(int count, int type) +{ + int avail = LDLM_LOCKREQ_HANDLES; + + if (type == LDLM_ENQUEUE) + avail -= LDLM_ENQUEUE_CANCEL_OFF; + + if (count > avail) + avail = (count - avail) * sizeof(struct lustre_handle); + else + avail = 0; + + return sizeof(struct ldlm_request) + avail; +} + static int ldlm_expired_completion_wait(void *data) { struct lock_wait_data *lwd = data; @@ -1635,7 +1663,7 @@ int ldlm_cli_cancel_list(struct list_head *cancels, int count, if (res < 0) { CDEBUG_LIMIT(res == -ESHUTDOWN ? D_DLMTRACE : D_ERROR, - "ldlm_cli_cancel_list: %d\n", res); + "%s: %d\n", __func__, res); res = count; } diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c b/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c index c9ef247d9be4..c2ddf7312571 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c @@ -36,9 +36,9 @@ */ #define DEBUG_SUBSYSTEM S_LDLM -#include "../include/lustre_dlm.h" -#include "../include/lustre_fid.h" -#include "../include/obd_class.h" +#include <lustre_dlm.h> +#include <lustre_fid.h> +#include <obd_class.h> #include "ldlm_internal.h" struct kmem_cache *ldlm_resource_slab, *ldlm_lock_slab; @@ -223,7 +223,7 @@ static ssize_t lru_size_show(struct kobject *kobj, struct attribute *attr, if (ns_connect_lru_resize(ns)) nr = &ns->ns_nr_unused; - return sprintf(buf, "%u", *nr); + return sprintf(buf, "%u\n", *nr); } static ssize_t lru_size_store(struct kobject *kobj, struct attribute *attr, @@ -318,7 +318,7 @@ static ssize_t lru_max_age_show(struct kobject *kobj, struct attribute *attr, struct ldlm_namespace *ns = container_of(kobj, struct ldlm_namespace, ns_kobj); - return sprintf(buf, "%u", ns->ns_max_age); + return sprintf(buf, "%u\n", ns->ns_max_age); } static ssize_t lru_max_age_store(struct kobject *kobj, struct attribute *attr, @@ -536,16 +536,6 @@ static void ldlm_res_hop_get_locked(struct cfs_hash *hs, ldlm_resource_getref(res); } -static void ldlm_res_hop_put_locked(struct cfs_hash *hs, - struct hlist_node *hnode) -{ - struct ldlm_resource *res; - - res = hlist_entry(hnode, struct ldlm_resource, lr_hash); - /* cfs_hash_for_each_nolock is the only chance we call it */ - ldlm_resource_putref_locked(res); -} - static void ldlm_res_hop_put(struct cfs_hash *hs, struct hlist_node *hnode) { struct ldlm_resource *res; @@ -561,7 +551,6 @@ static struct cfs_hash_ops ldlm_ns_hash_ops = { .hs_keycpy = NULL, .hs_object = ldlm_res_hop_object, .hs_get = ldlm_res_hop_get_locked, - .hs_put_locked = ldlm_res_hop_put_locked, .hs_put = ldlm_res_hop_put }; @@ -572,7 +561,6 @@ static struct cfs_hash_ops ldlm_ns_fid_hash_ops = { .hs_keycpy = NULL, .hs_object = ldlm_res_hop_object, .hs_get = ldlm_res_hop_get_locked, - .hs_put_locked = ldlm_res_hop_put_locked, .hs_put = ldlm_res_hop_put }; @@ -1249,37 +1237,6 @@ int ldlm_resource_putref(struct ldlm_resource *res) } EXPORT_SYMBOL(ldlm_resource_putref); -/* Returns 1 if the resource was freed, 0 if it remains. */ -int ldlm_resource_putref_locked(struct ldlm_resource *res) -{ - struct ldlm_namespace *ns = ldlm_res_to_ns(res); - - LASSERT_ATOMIC_GT_LT(&res->lr_refcount, 0, LI_POISON); - CDEBUG(D_INFO, "putref res: %p count: %d\n", - res, atomic_read(&res->lr_refcount) - 1); - - if (atomic_dec_and_test(&res->lr_refcount)) { - struct cfs_hash_bd bd; - - cfs_hash_bd_get(ldlm_res_to_ns(res)->ns_rs_hash, - &res->lr_name, &bd); - __ldlm_resource_putref_final(&bd, res); - cfs_hash_bd_unlock(ns->ns_rs_hash, &bd, 1); - /* NB: ns_rs_hash is created with CFS_HASH_NO_ITEMREF, - * so we should never be here while calling cfs_hash_del, - * cfs_hash_for_each_nolock is the only case we can get - * here, which is safe to release cfs_hash_bd_lock. - */ - if (ns->ns_lvbo && ns->ns_lvbo->lvbo_free) - ns->ns_lvbo->lvbo_free(res); - kmem_cache_free(ldlm_resource_slab, res); - - cfs_hash_bd_lock(ns->ns_rs_hash, &bd, 1); - return 1; - } - return 0; -} - /** * Add a lock into a given resource into specified lock list. */ diff --git a/drivers/staging/lustre/lustre/llite/Makefile b/drivers/staging/lustre/lustre/llite/Makefile index 322d4fa63f5d..ef7adef4ccc5 100644 --- a/drivers/staging/lustre/lustre/llite/Makefile +++ b/drivers/staging/lustre/lustre/llite/Makefile @@ -1,3 +1,6 @@ +subdir-ccflags-y += -I$(srctree)/drivers/staging/lustre/include +subdir-ccflags-y += -I$(srctree)/drivers/staging/lustre/lustre/include + obj-$(CONFIG_LUSTRE_FS) += lustre.o lustre-y := dcache.o dir.o file.o llite_lib.o llite_nfs.o \ rw.o rw26.o namei.o symlink.o llite_mmap.o range_lock.o \ diff --git a/drivers/staging/lustre/lustre/llite/dcache.c b/drivers/staging/lustre/lustre/llite/dcache.c index d20425fb8cbe..3670fcaf373f 100644 --- a/drivers/staging/lustre/lustre/llite/dcache.c +++ b/drivers/staging/lustre/lustre/llite/dcache.c @@ -36,9 +36,9 @@ #define DEBUG_SUBSYSTEM S_LLITE -#include "../include/obd_support.h" -#include "../include/lustre/lustre_idl.h" -#include "../include/lustre_dlm.h" +#include <obd_support.h> +#include <uapi/linux/lustre/lustre_idl.h> +#include <lustre_dlm.h> #include "llite_internal.h" diff --git a/drivers/staging/lustre/lustre/llite/dir.c b/drivers/staging/lustre/lustre/llite/dir.c index 03a72c07f57c..1db3e7f345c5 100644 --- a/drivers/staging/lustre/lustre/llite/dir.c +++ b/drivers/staging/lustre/lustre/llite/dir.c @@ -44,14 +44,14 @@ #define DEBUG_SUBSYSTEM S_LLITE -#include "../include/obd_support.h" -#include "../include/obd_class.h" -#include "../include/lustre/lustre_ioctl.h" -#include "../include/lustre_lib.h" -#include "../include/lustre_dlm.h" -#include "../include/lustre_fid.h" -#include "../include/lustre_kernelcomm.h" -#include "../include/lustre_swab.h" +#include <obd_support.h> +#include <obd_class.h> +#include <uapi/linux/lustre/lustre_ioctl.h> +#include <lustre_lib.h> +#include <lustre_dlm.h> +#include <lustre_fid.h> +#include <lustre_kernelcomm.h> +#include <lustre_swab.h> #include "llite_internal.h" @@ -1097,7 +1097,7 @@ static long ll_dir_ioctl(struct file *file, unsigned int cmd, unsigned long arg) goto out_free; } out_free: - obd_ioctl_freedata(buf, len); + kvfree(buf); return rc; } case LL_IOC_LMV_SETSTRIPE: { @@ -1147,7 +1147,7 @@ out_free: #endif rc = ll_dir_setdirstripe(inode, lum, filename, mode); lmv_out_free: - obd_ioctl_freedata(buf, len); + kvfree(buf); return rc; } case LL_IOC_LMV_SET_DEFAULT_STRIPE: { @@ -1626,7 +1626,7 @@ out_quotactl: rc = ll_migrate(inode, file, mdtidx, filename, namelen - 1); migrate_free: - obd_ioctl_freedata(buf, len); + kvfree(buf); return rc; } diff --git a/drivers/staging/lustre/lustre/llite/file.c b/drivers/staging/lustre/lustre/llite/file.c index ab1c85c1ed38..be665454f407 100644 --- a/drivers/staging/lustre/lustre/llite/file.c +++ b/drivers/staging/lustre/lustre/llite/file.c @@ -37,16 +37,16 @@ */ #define DEBUG_SUBSYSTEM S_LLITE -#include "../include/lustre_dlm.h" +#include <lustre_dlm.h> #include <linux/pagemap.h> #include <linux/file.h> #include <linux/sched.h> #include <linux/mount.h> -#include "../include/lustre/ll_fiemap.h" -#include "../include/lustre/lustre_ioctl.h" -#include "../include/lustre_swab.h" +#include <uapi/linux/lustre/lustre_fiemap.h> +#include <uapi/linux/lustre/lustre_ioctl.h> +#include <lustre_swab.h> -#include "../include/cl_object.h" +#include <cl_object.h> #include "llite_internal.h" static int @@ -2364,7 +2364,7 @@ int ll_fsync(struct file *file, loff_t start, loff_t end, int datasync) PFID(ll_inode2fid(inode)), inode); ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_FSYNC, 1); - rc = filemap_write_and_wait_range(inode->i_mapping, start, end); + rc = file_write_and_wait_range(file, start, end); inode_lock(inode); /* catch async errors that were recorded back when async writeback @@ -3035,9 +3035,6 @@ struct posix_acl *ll_get_acl(struct inode *inode, int type) spin_lock(&lli->lli_lock); /* VFS' acl_permission_check->check_acl will release the refcount */ acl = posix_acl_dup(lli->lli_posix_acl); -#ifdef CONFIG_FS_POSIX_ACL - forget_cached_acl(inode, type); -#endif spin_unlock(&lli->lli_lock); return acl; diff --git a/drivers/staging/lustre/lustre/llite/glimpse.c b/drivers/staging/lustre/lustre/llite/glimpse.c index 0143112e672d..34c2cfecf4b8 100644 --- a/drivers/staging/lustre/lustre/llite/glimpse.c +++ b/drivers/staging/lustre/lustre/llite/glimpse.c @@ -36,18 +36,18 @@ * Author: Oleg Drokin <oleg.drokin@sun.com> */ -#include "../../include/linux/libcfs/libcfs.h" -#include "../include/obd_class.h" -#include "../include/obd_support.h" -#include "../include/obd.h" +#include <linux/libcfs/libcfs.h> +#include <obd_class.h> +#include <obd_support.h> +#include <obd.h> -#include "../include/lustre_dlm.h" -#include "../include/lustre_mdc.h" +#include <lustre_dlm.h> +#include <lustre_mdc.h> #include <linux/pagemap.h> #include <linux/file.h> -#include "../include/cl_object.h" -#include "../llite/llite_internal.h" +#include <cl_object.h> +#include "llite_internal.h" static const struct cl_lock_descr whole_file = { .cld_start = 0, diff --git a/drivers/staging/lustre/lustre/llite/lcommon_cl.c b/drivers/staging/lustre/lustre/llite/lcommon_cl.c index 96515b839436..d2392e4c6872 100644 --- a/drivers/staging/lustre/lustre/llite/lcommon_cl.c +++ b/drivers/staging/lustre/lustre/llite/lcommon_cl.c @@ -37,24 +37,23 @@ #define DEBUG_SUBSYSTEM S_LLITE -#include "../../include/linux/libcfs/libcfs.h" -# include <linux/fs.h> -# include <linux/sched.h> -# include <linux/mm.h> -# include <linux/quotaops.h> -# include <linux/highmem.h> -# include <linux/pagemap.h> -# include <linux/rbtree.h> - -#include "../include/obd.h" -#include "../include/obd_support.h" -#include "../include/lustre_fid.h" -#include "../include/lustre_dlm.h" -#include "../include/lustre_ver.h" -#include "../include/lustre_mdc.h" -#include "../include/cl_object.h" - -#include "../llite/llite_internal.h" +#include <linux/libcfs/libcfs.h> +#include <linux/fs.h> +#include <linux/sched.h> +#include <linux/mm.h> +#include <linux/quotaops.h> +#include <linux/highmem.h> +#include <linux/pagemap.h> +#include <linux/rbtree.h> + +#include <obd.h> +#include <obd_support.h> +#include <lustre_fid.h> +#include <lustre_dlm.h> +#include <lustre_mdc.h> +#include <cl_object.h> + +#include "llite_internal.h" /* * ccc_ prefix stands for "Common Client Code". diff --git a/drivers/staging/lustre/lustre/llite/lcommon_misc.c b/drivers/staging/lustre/lustre/llite/lcommon_misc.c index 7f7f3f1648ef..422f410d95c1 100644 --- a/drivers/staging/lustre/lustre/llite/lcommon_misc.c +++ b/drivers/staging/lustre/lustre/llite/lcommon_misc.c @@ -34,10 +34,10 @@ * */ #define DEBUG_SUBSYSTEM S_LLITE -#include "../include/obd_class.h" -#include "../include/obd_support.h" -#include "../include/obd.h" -#include "../include/cl_object.h" +#include <obd_class.h> +#include <obd_support.h> +#include <obd.h> +#include <cl_object.h> #include "llite_internal.h" diff --git a/drivers/staging/lustre/lustre/llite/llite_internal.h b/drivers/staging/lustre/lustre/llite/llite_internal.h index cd3311abf999..0287c751e1cd 100644 --- a/drivers/staging/lustre/lustre/llite/llite_internal.h +++ b/drivers/staging/lustre/lustre/llite/llite_internal.h @@ -32,18 +32,18 @@ #ifndef LLITE_INTERNAL_H #define LLITE_INTERNAL_H -#include "../include/lustre_debug.h" -#include "../include/lustre_ver.h" -#include "../include/lustre_disk.h" /* for s2sbi */ -#include "../include/lustre_linkea.h" +#include <lustre_debug.h> +#include <uapi/linux/lustre/lustre_ver.h> +#include <lustre_disk.h> /* for s2sbi */ +#include <lustre_linkea.h> /* for struct cl_lock_descr and struct cl_io */ -#include "../include/lustre_patchless_compat.h" -#include "../include/lustre_compat.h" -#include "../include/cl_object.h" -#include "../include/lustre_lmv.h" -#include "../include/lustre_mdc.h" -#include "../include/lustre_intent.h" +#include <lustre_patchless_compat.h> +#include <lustre_compat.h> +#include <cl_object.h> +#include <lustre_lmv.h> +#include <lustre_mdc.h> +#include <lustre_intent.h> #include <linux/compat.h> #include <linux/namei.h> #include <linux/xattr.h> diff --git a/drivers/staging/lustre/lustre/llite/llite_lib.c b/drivers/staging/lustre/lustre/llite/llite_lib.c index 974a05d6c969..25393e3a0fe8 100644 --- a/drivers/staging/lustre/lustre/llite/llite_lib.c +++ b/drivers/staging/lustre/lustre/llite/llite_lib.c @@ -41,15 +41,15 @@ #include <linux/types.h> #include <linux/mm.h> -#include "../include/lustre/lustre_ioctl.h" -#include "../include/lustre_ha.h" -#include "../include/lustre_dlm.h" -#include "../include/lprocfs_status.h" -#include "../include/lustre_disk.h" -#include "../include/lustre_param.h" -#include "../include/lustre_log.h" -#include "../include/cl_object.h" -#include "../include/obd_cksum.h" +#include <uapi/linux/lustre/lustre_ioctl.h> +#include <lustre_ha.h> +#include <lustre_dlm.h> +#include <lprocfs_status.h> +#include <lustre_disk.h> +#include <uapi/linux/lustre/lustre_param.h> +#include <lustre_log.h> +#include <cl_object.h> +#include <obd_cksum.h> #include "llite_internal.h" struct kmem_cache *ll_file_data_slab; @@ -210,7 +210,7 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt, data->ocd_ibits_known = MDS_INODELOCK_FULL; data->ocd_version = LUSTRE_VERSION_CODE; - if (sb->s_flags & MS_RDONLY) + if (sb_rdonly(sb)) data->ocd_connect_flags |= OBD_CONNECT_RDONLY; if (sbi->ll_flags & LL_SBI_USER_XATTR) data->ocd_connect_flags |= OBD_CONNECT_XATTR; @@ -222,9 +222,6 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt, else sbi->ll_fop = &ll_file_operations_noflock; - /* real client */ - data->ocd_connect_flags |= OBD_CONNECT_REAL; - /* always ping even if server suppress_pings */ if (sbi->ll_flags & LL_SBI_ALWAYS_PING) data->ocd_connect_flags &= ~OBD_CONNECT_PINGLESS; @@ -1319,6 +1316,7 @@ void ll_clear_inode(struct inode *inode) ll_xattr_cache_destroy(inode); #ifdef CONFIG_FS_POSIX_ACL + forget_all_cached_acls(inode); if (lli->lli_posix_acl) { posix_acl_release(lli->lli_posix_acl); lli->lli_posix_acl = NULL; @@ -2033,7 +2031,7 @@ int ll_remount_fs(struct super_block *sb, int *flags, char *data) int err; __u32 read_only; - if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY)) { + if ((bool)(*flags & MS_RDONLY) != sb_rdonly(sb)) { read_only = *flags & MS_RDONLY; err = obd_set_info_async(NULL, sbi->ll_md_exp, sizeof(KEY_READ_ONLY), @@ -2233,8 +2231,7 @@ int ll_obd_statfs(struct inode *inode, void __user *arg) if (rc) goto out_statfs; out_statfs: - if (buf) - obd_ioctl_freedata(buf, len); + kvfree(buf); return rc; } @@ -2543,7 +2540,7 @@ static int ll_linkea_decode(struct linkea_data *ldata, unsigned int linkno, unsigned int idx; int rc; - rc = linkea_init(ldata); + rc = linkea_init_with_rec(ldata); if (rc < 0) return rc; diff --git a/drivers/staging/lustre/lustre/llite/lproc_llite.c b/drivers/staging/lustre/lustre/llite/lproc_llite.c index aeae6670e262..e3bd2d18eac5 100644 --- a/drivers/staging/lustre/lustre/llite/lproc_llite.c +++ b/drivers/staging/lustre/lustre/llite/lproc_llite.c @@ -31,9 +31,9 @@ */ #define DEBUG_SUBSYSTEM S_LLITE -#include "../include/lprocfs_status.h" +#include <lprocfs_status.h> #include <linux/seq_file.h> -#include "../include/obd_support.h" +#include <obd_support.h> #include "llite_internal.h" #include "vvp_internal.h" diff --git a/drivers/staging/lustre/lustre/llite/namei.c b/drivers/staging/lustre/lustre/llite/namei.c index a208a8b02c2c..5cc2b3255207 100644 --- a/drivers/staging/lustre/lustre/llite/namei.c +++ b/drivers/staging/lustre/lustre/llite/namei.c @@ -40,10 +40,9 @@ #define DEBUG_SUBSYSTEM S_LLITE -#include "../include/obd_support.h" -#include "../include/lustre_fid.h" -#include "../include/lustre_dlm.h" -#include "../include/lustre_ver.h" +#include <obd_support.h> +#include <lustre_fid.h> +#include <lustre_dlm.h> #include "llite_internal.h" static int ll_create_it(struct inode *dir, struct dentry *dentry, @@ -490,7 +489,7 @@ static int ll_lookup_it_finish(struct ptlrpc_request *request, *de = alias; if (!it_disposition(it, DISP_LOOKUP_NEG)) { - /* we have lookup look - unhide dentry */ + /* We have the "lookup" lock, so unhide dentry */ if (bits & MDS_INODELOCK_LOOKUP) d_lustre_revalidate(*de); } else if (!it_disposition(it, DISP_OPEN_CREATE)) { @@ -562,8 +561,7 @@ static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry, } } - if (it->it_op & IT_OPEN && it->it_flags & FMODE_WRITE && - dentry->d_sb->s_flags & MS_RDONLY) + if (it->it_op & IT_OPEN && it->it_flags & FMODE_WRITE && sb_rdonly(dentry->d_sb)) return ERR_PTR(-EROFS); if (it->it_op & IT_CREAT) diff --git a/drivers/staging/lustre/lustre/llite/range_lock.c b/drivers/staging/lustre/lustre/llite/range_lock.c index 161391b6fb36..a32598bacdfb 100644 --- a/drivers/staging/lustre/lustre/llite/range_lock.c +++ b/drivers/staging/lustre/lustre/llite/range_lock.c @@ -34,7 +34,7 @@ * Author: Bobi Jam <bobijam.xu@intel.com> */ #include "range_lock.h" -#include "../include/lustre/lustre_user.h" +#include <uapi/linux/lustre/lustre_idl.h> /** * Initialize a range lock tree diff --git a/drivers/staging/lustre/lustre/llite/range_lock.h b/drivers/staging/lustre/lustre/llite/range_lock.h index 779091ccec4e..1e1519b1e006 100644 --- a/drivers/staging/lustre/lustre/llite/range_lock.h +++ b/drivers/staging/lustre/lustre/llite/range_lock.h @@ -36,8 +36,8 @@ #ifndef _RANGE_LOCK_H #define _RANGE_LOCK_H -#include "../../include/linux/libcfs/libcfs.h" -#include "../include/interval_tree.h" +#include <linux/libcfs/libcfs.h> +#include <interval_tree.h> struct range_lock { struct interval_node rl_node; diff --git a/drivers/staging/lustre/lustre/llite/rw.c b/drivers/staging/lustre/lustre/llite/rw.c index 1bac51f882a7..e72090572bcc 100644 --- a/drivers/staging/lustre/lustre/llite/rw.c +++ b/drivers/staging/lustre/lustre/llite/rw.c @@ -51,7 +51,7 @@ #define DEBUG_SUBSYSTEM S_LLITE -#include "../include/obd_cksum.h" +#include <obd_cksum.h> #include "llite_internal.h" static void ll_ra_stats_inc_sbi(struct ll_sb_info *sbi, enum ra_stat which); @@ -115,7 +115,7 @@ void ll_ra_count_put(struct ll_sb_info *sbi, unsigned long len) static void ll_ra_stats_inc_sbi(struct ll_sb_info *sbi, enum ra_stat which) { - LASSERTF(which >= 0 && which < _NR_RA_STAT, "which: %u\n", which); + LASSERTF(which < _NR_RA_STAT, "which: %u\n", which); lprocfs_counter_incr(sbi->ll_ra_stats, which); } diff --git a/drivers/staging/lustre/lustre/llite/statahead.c b/drivers/staging/lustre/lustre/llite/statahead.c index 9bbca018a5fe..ea9d59f07b78 100644 --- a/drivers/staging/lustre/lustre/llite/statahead.c +++ b/drivers/staging/lustre/lustre/llite/statahead.c @@ -38,8 +38,8 @@ #define DEBUG_SUBSYSTEM S_LLITE -#include "../include/obd_support.h" -#include "../include/lustre_dlm.h" +#include <obd_support.h> +#include <lustre_dlm.h> #include "llite_internal.h" #define SA_OMITTED_ENTRY_MAX 8ULL diff --git a/drivers/staging/lustre/lustre/llite/super25.c b/drivers/staging/lustre/lustre/llite/super25.c index 56f4b10624ce..0da4af81b830 100644 --- a/drivers/staging/lustre/lustre/llite/super25.c +++ b/drivers/staging/lustre/lustre/llite/super25.c @@ -34,11 +34,11 @@ #include <linux/module.h> #include <linux/types.h> -#include "../include/lustre_ha.h" -#include "../include/lustre_dlm.h" +#include <lustre_ha.h> +#include <lustre_dlm.h> #include <linux/init.h> #include <linux/fs.h> -#include "../include/lprocfs_status.h" +#include <lprocfs_status.h> #include "llite_internal.h" static struct kmem_cache *ll_inode_cachep; diff --git a/drivers/staging/lustre/lustre/llite/vvp_dev.c b/drivers/staging/lustre/lustre/llite/vvp_dev.c index 8e45672b4617..f9d9a161bd4e 100644 --- a/drivers/staging/lustre/lustre/llite/vvp_dev.c +++ b/drivers/staging/lustre/lustre/llite/vvp_dev.c @@ -37,7 +37,7 @@ #define DEBUG_SUBSYSTEM S_LLITE -#include "../include/obd.h" +#include <obd.h> #include "llite_internal.h" #include "vvp_internal.h" @@ -591,9 +591,10 @@ static void *vvp_pgcache_start(struct seq_file *f, loff_t *pos) env = cl_env_get(&refcheck); if (!IS_ERR(env)) { sbi = f->private; - if (sbi->ll_site->ls_obj_hash->hs_cur_bits > 64 - PGC_OBJ_SHIFT) + if (sbi->ll_site->ls_obj_hash->hs_cur_bits > + 64 - PGC_OBJ_SHIFT) { pos = ERR_PTR(-EFBIG); - else { + } else { *pos = vvp_pgcache_find(env, &sbi->ll_cl->cd_lu_dev, *pos); if (*pos == ~0ULL) diff --git a/drivers/staging/lustre/lustre/llite/vvp_internal.h b/drivers/staging/lustre/lustre/llite/vvp_internal.h index f40fd7f115d1..adce0ff4ae44 100644 --- a/drivers/staging/lustre/lustre/llite/vvp_internal.h +++ b/drivers/staging/lustre/lustre/llite/vvp_internal.h @@ -37,8 +37,8 @@ #ifndef VVP_INTERNAL_H #define VVP_INTERNAL_H -#include "../include/lustre/lustre_idl.h" -#include "../include/cl_object.h" +#include <uapi/linux/lustre/lustre_idl.h> +#include <cl_object.h> enum obd_notify_event; struct inode; diff --git a/drivers/staging/lustre/lustre/llite/vvp_io.c b/drivers/staging/lustre/lustre/llite/vvp_io.c index c5ba265ef6ad..c83853fa1bb4 100644 --- a/drivers/staging/lustre/lustre/llite/vvp_io.c +++ b/drivers/staging/lustre/lustre/llite/vvp_io.c @@ -37,7 +37,7 @@ #define DEBUG_SUBSYSTEM S_LLITE -#include "../include/obd.h" +#include <obd.h> #include "llite_internal.h" #include "vvp_internal.h" diff --git a/drivers/staging/lustre/lustre/llite/vvp_lock.c b/drivers/staging/lustre/lustre/llite/vvp_lock.c index 07eb26cc43f5..e522f7c00617 100644 --- a/drivers/staging/lustre/lustre/llite/vvp_lock.c +++ b/drivers/staging/lustre/lustre/llite/vvp_lock.c @@ -36,7 +36,7 @@ #define DEBUG_SUBSYSTEM S_LLITE -#include "../include/obd_support.h" +#include <obd_support.h> #include "vvp_internal.h" diff --git a/drivers/staging/lustre/lustre/llite/vvp_object.c b/drivers/staging/lustre/lustre/llite/vvp_object.c index 9bfd72e514d1..3953750b334e 100644 --- a/drivers/staging/lustre/lustre/llite/vvp_object.c +++ b/drivers/staging/lustre/lustre/llite/vvp_object.c @@ -36,9 +36,9 @@ #define DEBUG_SUBSYSTEM S_LLITE -#include "../../include/linux/libcfs/libcfs.h" +#include <linux/libcfs/libcfs.h> -#include "../include/obd.h" +#include <obd.h> #include "llite_internal.h" #include "vvp_internal.h" diff --git a/drivers/staging/lustre/lustre/llite/xattr.c b/drivers/staging/lustre/lustre/llite/xattr.c index bd30abdecfb9..0be55623bac4 100644 --- a/drivers/staging/lustre/lustre/llite/xattr.c +++ b/drivers/staging/lustre/lustre/llite/xattr.c @@ -33,13 +33,13 @@ #include <linux/fs.h> #include <linux/sched.h> #include <linux/mm.h> +#include <linux/xattr.h> #include <linux/selinux.h> #define DEBUG_SUBSYSTEM S_LLITE -#include "../include/obd_support.h" -#include "../include/lustre_dlm.h" -#include "../include/lustre_ver.h" +#include <obd_support.h> +#include <lustre_dlm.h> #include "llite_internal.h" diff --git a/drivers/staging/lustre/lustre/llite/xattr_cache.c b/drivers/staging/lustre/lustre/llite/xattr_cache.c index 82cf4211cc0f..80ee3920481a 100644 --- a/drivers/staging/lustre/lustre/llite/xattr_cache.c +++ b/drivers/staging/lustre/lustre/llite/xattr_cache.c @@ -12,9 +12,8 @@ #include <linux/fs.h> #include <linux/sched.h> #include <linux/mm.h> -#include "../include/obd_support.h" -#include "../include/lustre_dlm.h" -#include "../include/lustre_ver.h" +#include <obd_support.h> +#include <lustre_dlm.h> #include "llite_internal.h" /* If we ever have hundreds of extended attributes, we might want to consider diff --git a/drivers/staging/lustre/lustre/llite/xattr_security.c b/drivers/staging/lustre/lustre/llite/xattr_security.c index d61d8018001a..391fb25ac31d 100644 --- a/drivers/staging/lustre/lustre/llite/xattr_security.c +++ b/drivers/staging/lustre/lustre/llite/xattr_security.c @@ -28,7 +28,10 @@ * lustre/llite/xattr_security.c * Handler for storing security labels as extended attributes. */ + +#include <linux/types.h> #include <linux/security.h> +#include <linux/selinux.h> #include <linux/xattr.h> #include "llite_internal.h" @@ -48,19 +51,23 @@ static int ll_initxattrs(struct inode *inode, const struct xattr *xattr_array, void *fs_info) { - const struct xattr_handler *handler; struct dentry *dentry = fs_info; const struct xattr *xattr; int err = 0; - handler = get_xattr_type(XATTR_SECURITY_PREFIX); - if (!handler) - return -ENXIO; - for (xattr = xattr_array; xattr->name; xattr++) { - err = handler->set(handler, dentry, inode, xattr->name, - xattr->value, xattr->value_len, - XATTR_CREATE); + char *full_name; + + full_name = kasprintf(GFP_KERNEL, "%s%s", + XATTR_SECURITY_PREFIX, xattr->name); + if (!full_name) { + err = -ENOMEM; + break; + } + + err = __vfs_setxattr(dentry, inode, full_name, xattr->value, + xattr->value_len, XATTR_CREATE); + kfree(full_name); if (err < 0) break; } diff --git a/drivers/staging/lustre/lustre/lmv/Makefile b/drivers/staging/lustre/lustre/lmv/Makefile index 1a24299791d7..91c99114aa13 100644 --- a/drivers/staging/lustre/lustre/lmv/Makefile +++ b/drivers/staging/lustre/lustre/lmv/Makefile @@ -1,2 +1,5 @@ +subdir-ccflags-y += -I$(srctree)/drivers/staging/lustre/include +subdir-ccflags-y += -I$(srctree)/drivers/staging/lustre/lustre/include + obj-$(CONFIG_LUSTRE_FS) += lmv.o lmv-y := lmv_obd.o lmv_intent.o lmv_fld.o lproc_lmv.o diff --git a/drivers/staging/lustre/lustre/lmv/lmv_fld.c b/drivers/staging/lustre/lustre/lmv/lmv_fld.c index 6f8070fb3226..5937468080b8 100644 --- a/drivers/staging/lustre/lustre/lmv/lmv_fld.c +++ b/drivers/staging/lustre/lustre/lmv/lmv_fld.c @@ -37,14 +37,13 @@ #include <asm/div64.h> #include <linux/seq_file.h> -#include "../include/obd_support.h" -#include "../include/lustre/lustre_idl.h" -#include "../include/lustre_fid.h" -#include "../include/lustre_lib.h" -#include "../include/lustre_net.h" -#include "../include/lustre_dlm.h" -#include "../include/obd_class.h" -#include "../include/lprocfs_status.h" +#include <obd_support.h> +#include <lustre_fid.h> +#include <lustre_lib.h> +#include <lustre_net.h> +#include <lustre_dlm.h> +#include <obd_class.h> +#include <lprocfs_status.h> #include "lmv_internal.h" int lmv_fld_lookup(struct lmv_obd *lmv, const struct lu_fid *fid, u32 *mds) diff --git a/drivers/staging/lustre/lustre/lmv/lmv_intent.c b/drivers/staging/lustre/lustre/lmv/lmv_intent.c index f49db6c23217..22c247a7d8ca 100644 --- a/drivers/staging/lustre/lustre/lmv/lmv_intent.c +++ b/drivers/staging/lustre/lustre/lmv/lmv_intent.c @@ -37,15 +37,14 @@ #include <asm/div64.h> #include <linux/seq_file.h> #include <linux/namei.h> -#include "../include/lustre_intent.h" -#include "../include/obd_support.h" -#include "../include/lustre/lustre_idl.h" -#include "../include/lustre_lib.h" -#include "../include/lustre_net.h" -#include "../include/lustre_dlm.h" -#include "../include/lustre_mdc.h" -#include "../include/obd_class.h" -#include "../include/lprocfs_status.h" +#include <lustre_intent.h> +#include <obd_support.h> +#include <lustre_lib.h> +#include <lustre_net.h> +#include <lustre_dlm.h> +#include <lustre_mdc.h> +#include <obd_class.h> +#include <lprocfs_status.h> #include "lmv_internal.h" static int lmv_intent_remote(struct obd_export *exp, struct lookup_intent *it, @@ -474,7 +473,6 @@ int lmv_intent_lock(struct obd_export *exp, struct md_op_data *op_data, ldlm_blocking_callback cb_blocking, __u64 extra_lock_flags) { - struct obd_device *obd = exp->exp_obd; int rc; LASSERT(fid_is_sane(&op_data->op_fid1)); @@ -484,10 +482,6 @@ int lmv_intent_lock(struct obd_export *exp, struct md_op_data *op_data, (int)op_data->op_namelen, op_data->op_name, PFID(&op_data->op_fid1)); - rc = lmv_check_connect(obd); - if (rc) - return rc; - if (it->it_op & (IT_LOOKUP | IT_GETATTR | IT_LAYOUT)) rc = lmv_intent_lookup(exp, op_data, it, reqp, cb_blocking, extra_lock_flags); diff --git a/drivers/staging/lustre/lustre/lmv/lmv_internal.h b/drivers/staging/lustre/lustre/lmv/lmv_internal.h index 12731a17e263..a0475231dd90 100644 --- a/drivers/staging/lustre/lustre/lmv/lmv_internal.h +++ b/drivers/staging/lustre/lustre/lmv/lmv_internal.h @@ -33,17 +33,15 @@ #ifndef _LMV_INTERNAL_H_ #define _LMV_INTERNAL_H_ -#include "../include/lustre/lustre_idl.h" -#include "../include/obd.h" -#include "../include/lustre_lmv.h" +#include <uapi/linux/lustre/lustre_idl.h> +#include <obd.h> +#include <lustre_lmv.h> #define LMV_MAX_TGT_COUNT 128 #define LL_IT2STR(it) \ ((it) ? ldlm_it2str((it)->it_op) : "0") -int lmv_check_connect(struct obd_device *obd); - int lmv_intent_lock(struct obd_export *exp, struct md_op_data *op_data, struct lookup_intent *it, struct ptlrpc_request **reqp, ldlm_blocking_callback cb_blocking, diff --git a/drivers/staging/lustre/lustre/lmv/lmv_obd.c b/drivers/staging/lustre/lustre/lmv/lmv_obd.c index 64fcaef0bacd..6e16c930a021 100644 --- a/drivers/staging/lustre/lustre/lmv/lmv_obd.c +++ b/drivers/staging/lustre/lustre/lmv/lmv_obd.c @@ -41,18 +41,19 @@ #include <linux/namei.h> #include <linux/uaccess.h> -#include "../include/lustre/lustre_idl.h" -#include "../include/obd_support.h" -#include "../include/lustre_net.h" -#include "../include/obd_class.h" -#include "../include/lustre_lmv.h" -#include "../include/lprocfs_status.h" -#include "../include/cl_object.h" -#include "../include/lustre_fid.h" -#include "../include/lustre/lustre_ioctl.h" -#include "../include/lustre_kernelcomm.h" +#include <obd_support.h> +#include <lustre_net.h> +#include <obd_class.h> +#include <lustre_lmv.h> +#include <lprocfs_status.h> +#include <cl_object.h> +#include <lustre_fid.h> +#include <uapi/linux/lustre/lustre_ioctl.h> +#include <lustre_kernelcomm.h> #include "lmv_internal.h" +static int lmv_check_connect(struct obd_device *obd); + static void lmv_activate_target(struct lmv_obd *lmv, struct lmv_tgt_desc *tgt, int activate) @@ -183,59 +184,44 @@ static int lmv_notify(struct obd_device *obd, struct obd_device *watched, return rc; } -/** - * This is fake connect function. Its purpose is to initialize lmv and say - * caller that everything is okay. Real connection will be performed later. - */ static int lmv_connect(const struct lu_env *env, - struct obd_export **exp, struct obd_device *obd, + struct obd_export **pexp, struct obd_device *obd, struct obd_uuid *cluuid, struct obd_connect_data *data, void *localdata) { struct lmv_obd *lmv = &obd->u.lmv; struct lustre_handle conn = { 0 }; + struct obd_export *exp; int rc = 0; - /* - * We don't want to actually do the underlying connections more than - * once, so keep track. - */ - lmv->refcount++; - if (lmv->refcount > 1) { - *exp = NULL; - return 0; - } - rc = class_connect(&conn, obd, cluuid); if (rc) { CERROR("class_connection() returned %d\n", rc); return rc; } - *exp = class_conn2export(&conn); - class_export_get(*exp); + exp = class_conn2export(&conn); - lmv->exp = *exp; lmv->connected = 0; lmv->cluuid = *cluuid; - - if (data) - lmv->conn_data = *data; + lmv->conn_data = *data; lmv->lmv_tgts_kobj = kobject_create_and_add("target_obds", &obd->obd_kobj); - /* - * All real clients should perform actual connection right away, because - * it is possible, that LMV will not have opportunity to connect targets - * and MDC stuff will be called directly, for instance while reading - * ../mdc/../kbytesfree procfs file, etc. - */ - if (data && data->ocd_connect_flags & OBD_CONNECT_REAL) - rc = lmv_check_connect(obd); + rc = lmv_check_connect(obd); + if (rc) + goto out_sysfs; + + *pexp = exp; - if (rc && lmv->lmv_tgts_kobj) + return rc; + +out_sysfs: + if (lmv->lmv_tgts_kobj) kobject_put(lmv->lmv_tgts_kobj); + class_disconnect(exp); + return rc; } @@ -475,7 +461,7 @@ static int lmv_add_target(struct obd_device *obd, struct obd_uuid *uuidp, return rc; } -int lmv_check_connect(struct obd_device *obd) +static int lmv_check_connect(struct obd_device *obd) { struct lmv_obd *lmv = &obd->u.lmv; struct lmv_tgt_desc *tgt; @@ -519,7 +505,6 @@ int lmv_check_connect(struct obd_device *obd) goto out_disc; } - class_export_put(lmv->exp); lmv->connected = 1; easize = lmv_mds_md_size(lmv->desc.ld_tgt_count, LMV_MAGIC); lmv_init_ea_size(obd->obd_self_export, easize, 0); @@ -543,7 +528,7 @@ int lmv_check_connect(struct obd_device *obd) } } } - class_disconnect(lmv->exp); + mutex_unlock(&lmv->lmv_init_mutex); return rc; } @@ -598,13 +583,6 @@ static int lmv_disconnect(struct obd_export *exp) if (!lmv->tgts) goto out_local; - /* - * Only disconnect the underlying layers on the final disconnect. - */ - lmv->refcount--; - if (lmv->refcount != 0) - goto out_local; - for (i = 0; i < lmv->desc.ld_tgt_count; i++) { if (!lmv->tgts[i] || !lmv->tgts[i]->ltd_exp) continue; @@ -623,8 +601,7 @@ out_local: if (!lmv->connected) class_export_put(exp); rc = class_disconnect(exp); - if (lmv->refcount == 0) - lmv->connected = 0; + lmv->connected = 0; return rc; } @@ -657,8 +634,8 @@ repeat_fid2path: char *ptr; ori_gf = karg; - if (strlen(ori_gf->gf_path) + - strlen(gf->gf_path) > ori_gf->gf_pathlen) { + if (strlen(ori_gf->gf_path) + 1 + + strlen(gf->gf_path) + 1 > ori_gf->gf_pathlen) { rc = -EOVERFLOW; goto out_fid2path; } @@ -1122,7 +1099,8 @@ hsm_req_err: err = obd_iocontrol(cmd, tgt->ltd_exp, len, karg, uarg); if (err) { if (tgt->ltd_active) { - CERROR("error: iocontrol MDC %s on MDTidx %d cmd %x: err = %d\n", + CERROR("%s: error: iocontrol MDC %s on MDTidx %d cmd %x: err = %d\n", + lmv2obd_dev(lmv)->obd_name, tgt->ltd_uuid.uuid, i, cmd, err); if (!rc) rc = err; @@ -1368,10 +1346,6 @@ static int lmv_statfs(const struct lu_env *env, struct obd_export *exp, int rc = 0; u32 i; - rc = lmv_check_connect(obd); - if (rc) - return rc; - temp = kzalloc(sizeof(*temp), GFP_NOFS); if (!temp) return -ENOMEM; @@ -1418,11 +1392,6 @@ static int lmv_getstatus(struct obd_export *exp, { struct obd_device *obd = exp->exp_obd; struct lmv_obd *lmv = &obd->u.lmv; - int rc; - - rc = lmv_check_connect(obd); - if (rc) - return rc; return md_getstatus(lmv->tgts[0]->ltd_exp, fid); } @@ -1435,11 +1404,6 @@ static int lmv_getxattr(struct obd_export *exp, const struct lu_fid *fid, struct obd_device *obd = exp->exp_obd; struct lmv_obd *lmv = &obd->u.lmv; struct lmv_tgt_desc *tgt; - int rc; - - rc = lmv_check_connect(obd); - if (rc) - return rc; tgt = lmv_find_target(lmv, fid); if (IS_ERR(tgt)) @@ -1458,11 +1422,6 @@ static int lmv_setxattr(struct obd_export *exp, const struct lu_fid *fid, struct obd_device *obd = exp->exp_obd; struct lmv_obd *lmv = &obd->u.lmv; struct lmv_tgt_desc *tgt; - int rc; - - rc = lmv_check_connect(obd); - if (rc) - return rc; tgt = lmv_find_target(lmv, fid); if (IS_ERR(tgt)) @@ -1479,11 +1438,6 @@ static int lmv_getattr(struct obd_export *exp, struct md_op_data *op_data, struct obd_device *obd = exp->exp_obd; struct lmv_obd *lmv = &obd->u.lmv; struct lmv_tgt_desc *tgt; - int rc; - - rc = lmv_check_connect(obd); - if (rc) - return rc; tgt = lmv_find_target(lmv, &op_data->op_fid1); if (IS_ERR(tgt)) @@ -1502,11 +1456,6 @@ static int lmv_null_inode(struct obd_export *exp, const struct lu_fid *fid) struct obd_device *obd = exp->exp_obd; struct lmv_obd *lmv = &obd->u.lmv; u32 i; - int rc; - - rc = lmv_check_connect(obd); - if (rc) - return rc; CDEBUG(D_INODE, "CBDATA for " DFID "\n", PFID(fid)); @@ -1530,11 +1479,6 @@ static int lmv_close(struct obd_export *exp, struct md_op_data *op_data, struct obd_device *obd = exp->exp_obd; struct lmv_obd *lmv = &obd->u.lmv; struct lmv_tgt_desc *tgt; - int rc; - - rc = lmv_check_connect(obd); - if (rc) - return rc; tgt = lmv_find_target(lmv, &op_data->op_fid1); if (IS_ERR(tgt)) @@ -1661,10 +1605,6 @@ static int lmv_create(struct obd_export *exp, struct md_op_data *op_data, struct lmv_tgt_desc *tgt; int rc; - rc = lmv_check_connect(obd); - if (rc) - return rc; - if (!lmv->desc.ld_active_tgt_count) return -EIO; @@ -1718,11 +1658,6 @@ lmv_enqueue(struct obd_export *exp, struct ldlm_enqueue_info *einfo, struct obd_device *obd = exp->exp_obd; struct lmv_obd *lmv = &obd->u.lmv; struct lmv_tgt_desc *tgt; - int rc; - - rc = lmv_check_connect(obd); - if (rc) - return rc; CDEBUG(D_INODE, "ENQUEUE '%s' on " DFID "\n", LL_IT2STR(it), PFID(&op_data->op_fid1)); @@ -1749,10 +1684,6 @@ lmv_getattr_name(struct obd_export *exp, struct md_op_data *op_data, struct mdt_body *body; int rc; - rc = lmv_check_connect(obd); - if (rc) - return rc; - tgt = lmv_locate_mds(lmv, op_data, &op_data->op_fid1); if (IS_ERR(tgt)) return PTR_ERR(tgt); @@ -1845,10 +1776,6 @@ static int lmv_link(struct obd_export *exp, struct md_op_data *op_data, struct lmv_tgt_desc *tgt; int rc; - rc = lmv_check_connect(obd); - if (rc) - return rc; - LASSERT(op_data->op_namelen != 0); CDEBUG(D_INODE, "LINK " DFID ":%*s to " DFID "\n", @@ -1907,10 +1834,6 @@ static int lmv_rename(struct obd_export *exp, struct md_op_data *op_data, (int)newlen, new, PFID(&op_data->op_fid2), op_data->op_mea2 ? op_data->op_mea2->lsm_md_stripe_count : 0); - rc = lmv_check_connect(obd); - if (rc) - return rc; - op_data->op_fsuid = from_kuid(&init_user_ns, current_fsuid()); op_data->op_fsgid = from_kgid(&init_user_ns, current_fsgid()); op_data->op_cap = cfs_curproc_cap_pack(); @@ -2063,11 +1986,6 @@ static int lmv_setattr(struct obd_export *exp, struct md_op_data *op_data, struct obd_device *obd = exp->exp_obd; struct lmv_obd *lmv = &obd->u.lmv; struct lmv_tgt_desc *tgt; - int rc; - - rc = lmv_check_connect(obd); - if (rc) - return rc; CDEBUG(D_INODE, "SETATTR for " DFID ", valid 0x%x\n", PFID(&op_data->op_fid1), op_data->op_attr.ia_valid); @@ -2086,11 +2004,6 @@ static int lmv_sync(struct obd_export *exp, const struct lu_fid *fid, struct obd_device *obd = exp->exp_obd; struct lmv_obd *lmv = &obd->u.lmv; struct lmv_tgt_desc *tgt; - int rc; - - rc = lmv_check_connect(obd); - if (rc) - return rc; tgt = lmv_find_target(lmv, fid); if (IS_ERR(tgt)) @@ -2272,7 +2185,6 @@ static int lmv_read_striped_page(struct obd_export *exp, { struct inode *master_inode = op_data->op_data; struct lu_fid master_fid = op_data->op_fid1; - struct obd_device *obd = exp->exp_obd; __u64 hash_offset = offset; __u32 ldp_flags; struct page *min_ent_page = NULL; @@ -2286,10 +2198,6 @@ static int lmv_read_striped_page(struct obd_export *exp, void *area; int rc; - rc = lmv_check_connect(obd); - if (rc) - return rc; - /* * Allocate a page and read entries from all of stripes and fill * the page by hash order @@ -2408,11 +2316,6 @@ static int lmv_read_page(struct obd_export *exp, struct md_op_data *op_data, struct obd_device *obd = exp->exp_obd; struct lmv_obd *lmv = &obd->u.lmv; struct lmv_tgt_desc *tgt; - int rc; - - rc = lmv_check_connect(obd); - if (rc) - return rc; if (unlikely(lsm)) return lmv_read_striped_page(exp, op_data, cb_op, offset, ppage); @@ -2460,9 +2363,6 @@ static int lmv_unlink(struct obd_export *exp, struct md_op_data *op_data, int stripe_index = 0; int rc; - rc = lmv_check_connect(obd); - if (rc) - return rc; retry_unlink: /* For striped dir, we need to locate the parent as well */ if (lsm) { @@ -2647,10 +2547,6 @@ static int lmv_get_info(const struct lu_env *env, struct obd_export *exp, if (keylen >= strlen("remote_flag") && !strcmp(key, "remote_flag")) { int i; - rc = lmv_check_connect(obd); - if (rc) - return rc; - LASSERT(*vallen == sizeof(__u32)); for (i = 0; i < lmv->desc.ld_tgt_count; i++) { struct lmv_tgt_desc *tgt = lmv->tgts[i]; @@ -2669,10 +2565,6 @@ static int lmv_get_info(const struct lu_env *env, struct obd_export *exp, } else if (KEY_IS(KEY_MAX_EASIZE) || KEY_IS(KEY_DEFAULT_EASIZE) || KEY_IS(KEY_CONN_DATA)) { - rc = lmv_check_connect(obd); - if (rc) - return rc; - /* * Forwarding this request to first MDS, it should know LOV * desc. @@ -3021,15 +2913,10 @@ static int lmv_intent_getattr_async(struct obd_export *exp, struct lmv_obd *lmv = &obd->u.lmv; struct lmv_tgt_desc *ptgt = NULL; struct lmv_tgt_desc *ctgt = NULL; - int rc; if (!fid_is_sane(&op_data->op_fid2)) return -EINVAL; - rc = lmv_check_connect(obd); - if (rc) - return rc; - ptgt = lmv_locate_mds(lmv, op_data, &op_data->op_fid1); if (IS_ERR(ptgt)) return PTR_ERR(ptgt); @@ -3056,11 +2943,6 @@ static int lmv_revalidate_lock(struct obd_export *exp, struct lookup_intent *it, struct obd_device *obd = exp->exp_obd; struct lmv_obd *lmv = &obd->u.lmv; struct lmv_tgt_desc *tgt; - int rc; - - rc = lmv_check_connect(obd); - if (rc) - return rc; tgt = lmv_find_target(lmv, fid); if (IS_ERR(tgt)) diff --git a/drivers/staging/lustre/lustre/lmv/lproc_lmv.c b/drivers/staging/lustre/lustre/lmv/lproc_lmv.c index bf25f887062d..f16cfa435f77 100644 --- a/drivers/staging/lustre/lustre/lmv/lproc_lmv.c +++ b/drivers/staging/lustre/lustre/lmv/lproc_lmv.c @@ -34,8 +34,8 @@ #include <linux/seq_file.h> #include <linux/statfs.h> -#include "../include/lprocfs_status.h" -#include "../include/obd_class.h" +#include <lprocfs_status.h> +#include <obd_class.h> #include "lmv_internal.h" static ssize_t numobd_show(struct kobject *kobj, struct attribute *attr, @@ -161,7 +161,7 @@ static struct attribute *lmv_attrs[] = { NULL, }; -static struct attribute_group lmv_attr_group = { +static const struct attribute_group lmv_attr_group = { .attrs = lmv_attrs, }; diff --git a/drivers/staging/lustre/lustre/lov/Makefile b/drivers/staging/lustre/lustre/lov/Makefile index e4cc0db21014..3abfb4eab3d3 100644 --- a/drivers/staging/lustre/lustre/lov/Makefile +++ b/drivers/staging/lustre/lustre/lov/Makefile @@ -1,5 +1,8 @@ +subdir-ccflags-y += -I$(srctree)/drivers/staging/lustre/include +subdir-ccflags-y += -I$(srctree)/drivers/staging/lustre/lustre/include + obj-$(CONFIG_LUSTRE_FS) += lov.o lov-y := lov_obd.o lov_pack.o lov_offset.o lov_merge.o \ lov_request.o lov_ea.o lov_dev.o lov_object.o lov_page.o \ lov_lock.o lov_io.o lovsub_dev.o lovsub_object.o lovsub_page.o \ - lovsub_lock.o lovsub_io.o lov_pool.o lproc_lov.o + lovsub_lock.o lov_pool.o lproc_lov.o diff --git a/drivers/staging/lustre/lustre/lov/lov_cl_internal.h b/drivers/staging/lustre/lustre/lov/lov_cl_internal.h index e889d3a7de9c..89d92b05b48c 100644 --- a/drivers/staging/lustre/lustre/lov/lov_cl_internal.h +++ b/drivers/staging/lustre/lustre/lov/lov_cl_internal.h @@ -42,10 +42,10 @@ #ifndef LOV_CL_INTERNAL_H #define LOV_CL_INTERNAL_H -#include "../../include/linux/libcfs/libcfs.h" +#include <linux/libcfs/libcfs.h> -#include "../include/obd.h" -#include "../include/cl_object.h" +#include <obd.h> +#include <cl_object.h> #include "lov_internal.h" /** \defgroup lov lov @@ -92,35 +92,6 @@ enum lov_device_flags { * Upper half. */ -/** - * Resources that are used in memory-cleaning path, and whose allocation - * cannot fail even when memory is tight. They are preallocated in sufficient - * quantities in lov_device::ld_emerg[], and access to them is serialized - * lov_device::ld_mutex. - */ -struct lov_device_emerg { - /** - * Page list used to submit IO when memory is in pressure. - */ - struct cl_page_list emrg_page_list; - /** - * sub-io's shared by all threads accessing this device when memory is - * too low to allocate sub-io's dynamically. - */ - struct cl_io emrg_subio; - /** - * Environments used by sub-io's in - * lov_device_emerg::emrg_subio. - */ - struct lu_env *emrg_env; - /** - * Refchecks for lov_device_emerg::emrg_env. - * - * \see cl_env_get() - */ - u16 emrg_refcheck; -}; - struct lov_device { /* * XXX Locking of lov-private data is missing. @@ -131,14 +102,6 @@ struct lov_device { __u32 ld_target_nr; struct lovsub_device **ld_target; __u32 ld_flags; - - /** Emergency resources used in memory-cleansing paths. */ - struct lov_device_emerg **ld_emrg; - /** - * Serializes access to lov_device::ld_emrg in low-memory - * conditions. - */ - struct mutex ld_mutex; }; /** @@ -299,8 +262,6 @@ struct lov_page { struct lovsub_device { struct cl_device acid_cl; - struct lov_device *acid_super; - int acid_idx; struct cl_device *acid_next; }; @@ -312,42 +273,10 @@ struct lovsub_object { }; /** - * A link between a top-lock and a sub-lock. Separate data-structure is - * necessary, because top-locks and sub-locks are in M:N relationship. - * - * \todo This can be optimized for a (by far) most frequent case of a single - * top-lock per sub-lock. - */ -struct lov_lock_link { - struct lov_lock *lll_super; - /** An index within parent lock. */ - int lll_idx; - /** - * A linkage into per sub-lock list of all corresponding top-locks, - * hanging off lovsub_lock::lss_parents. - */ - struct list_head lll_list; -}; - -/** * Lock state at lovsub layer. */ struct lovsub_lock { struct cl_lock_slice lss_cl; - /** - * List of top-locks that have given sub-lock as their part. Protected - * by cl_lock::cll_guard mutex. - */ - struct list_head lss_parents; - /** - * Top-lock that initiated current operation on this sub-lock. This is - * only set during top-to-bottom lock operations like enqueue, and is - * used to optimize state change notification. Protected by - * cl_lock::cll_guard mutex. - * - * \see lovsub_lock_state_one(). - */ - struct cl_lock *lss_active; }; /** @@ -356,7 +285,6 @@ struct lovsub_lock { struct lov_sublock_env { const struct lu_env *lse_env; struct cl_io *lse_io; - struct lov_io_sub *lse_sub; }; struct lovsub_page { @@ -366,12 +294,10 @@ struct lovsub_page { struct lov_thread_info { struct cl_object_conf lti_stripe_conf; struct lu_fid lti_fid; - struct cl_lock_descr lti_ldescr; struct ost_lvb lti_lvb; struct cl_2queue lti_cl2q; struct cl_page_list lti_plist; wait_queue_entry_t lti_waiter; - struct cl_attr lti_attr; }; /** @@ -385,7 +311,6 @@ struct lov_io_sub { * \see cl_env_get() */ u16 sub_refcheck; - u16 sub_reenter; /** * true, iff cl_io_init() was successfully executed against * lov_io_sub::sub_io. @@ -445,7 +370,6 @@ struct lov_io { */ u64 lis_endpos; - int lis_mem_frozen; int lis_stripe_count; int lis_active_subios; @@ -485,8 +409,6 @@ extern struct kmem_cache *lov_session_kmem; extern struct kmem_cache *lovsub_lock_kmem; extern struct kmem_cache *lovsub_object_kmem; -extern struct kmem_cache *lov_lock_link_kmem; - int lov_object_init(const struct lu_env *env, struct lu_object *obj, const struct lu_object_conf *conf); int lovsub_object_init(const struct lu_env *env, struct lu_object *obj, @@ -508,15 +430,9 @@ int lov_io_init_empty(const struct lu_env *env, struct cl_object *obj, struct cl_io *io); int lov_io_init_released(const struct lu_env *env, struct cl_object *obj, struct cl_io *io); -void lov_lock_unlink(const struct lu_env *env, struct lov_lock_link *link, - struct lovsub_lock *sub); struct lov_io_sub *lov_sub_get(const struct lu_env *env, struct lov_io *lio, int stripe); -void lov_sub_put(struct lov_io_sub *sub); -int lov_sublock_modify(const struct lu_env *env, struct lov_lock *lov, - struct lovsub_lock *sublock, - const struct cl_lock_descr *d, int idx); int lov_page_init(const struct lu_env *env, struct cl_object *ob, struct cl_page *page, pgoff_t index); @@ -533,12 +449,6 @@ struct lu_object *lovsub_object_alloc(const struct lu_env *env, const struct lu_object_header *hdr, struct lu_device *dev); -struct lov_lock_link *lov_lock_link_find(const struct lu_env *env, - struct lov_lock *lck, - struct lovsub_lock *sub); -struct lov_io_sub *lov_page_subio(const struct lu_env *env, struct lov_io *lio, - const struct cl_page_slice *slice); - struct lov_stripe_md *lov_lsm_addref(struct lov_object *lov); int lov_page_stripe(const struct cl_page *page); diff --git a/drivers/staging/lustre/lustre/lov/lov_dev.c b/drivers/staging/lustre/lustre/lov/lov_dev.c index 7301f6e579a1..cea5f9dcd04e 100644 --- a/drivers/staging/lustre/lustre/lov/lov_dev.c +++ b/drivers/staging/lustre/lustre/lov/lov_dev.c @@ -37,7 +37,7 @@ #define DEBUG_SUBSYSTEM S_LOV /* class_name2obd() */ -#include "../include/obd_class.h" +#include <obd_class.h> #include "lov_cl_internal.h" #include "lov_internal.h" @@ -50,11 +50,6 @@ struct kmem_cache *lov_session_kmem; struct kmem_cache *lovsub_lock_kmem; struct kmem_cache *lovsub_object_kmem; -struct kmem_cache *lov_lock_link_kmem; - -/** Lock class of lov_device::ld_mutex. */ -static struct lock_class_key cl_lov_device_mutex_class; - struct lu_kmem_descr lov_caches[] = { { .ckd_cache = &lov_lock_kmem, @@ -87,11 +82,6 @@ struct lu_kmem_descr lov_caches[] = { .ckd_size = sizeof(struct lovsub_object) }, { - .ckd_cache = &lov_lock_link_kmem, - .ckd_name = "lov_lock_link_kmem", - .ckd_size = sizeof(struct lov_lock_link) - }, - { .ckd_cache = NULL } }; @@ -204,8 +194,6 @@ static int lov_device_init(const struct lu_env *env, struct lu_device *d, break; } lsd = cl2lovsub_dev(cl); - lsd->acid_idx = i; - lsd->acid_super = ld; ld->ld_target[i] = lsd; } @@ -217,34 +205,13 @@ static int lov_device_init(const struct lu_env *env, struct lu_device *d, return rc; } -static void lov_emerg_free(struct lov_device_emerg **emrg, int nr) -{ - int i; - - for (i = 0; i < nr; ++i) { - struct lov_device_emerg *em; - - em = emrg[i]; - if (em) { - LASSERT(em->emrg_page_list.pl_nr == 0); - if (em->emrg_env) - cl_env_put(em->emrg_env, &em->emrg_refcheck); - kfree(em); - } - } - kfree(emrg); -} - static struct lu_device *lov_device_free(const struct lu_env *env, struct lu_device *d) { struct lov_device *ld = lu2lov_dev(d); - const int nr = ld->ld_target_nr; cl_device_fini(lu2cl_dev(d)); kfree(ld->ld_target); - if (ld->ld_emrg) - lov_emerg_free(ld->ld_emrg, nr); kfree(ld); return NULL; } @@ -260,41 +227,6 @@ static void lov_cl_del_target(const struct lu_env *env, struct lu_device *dev, } } -static struct lov_device_emerg **lov_emerg_alloc(int nr) -{ - struct lov_device_emerg **emerg; - int i; - int result; - - emerg = kcalloc(nr, sizeof(emerg[0]), GFP_NOFS); - if (!emerg) - return ERR_PTR(-ENOMEM); - for (result = i = 0; i < nr && result == 0; i++) { - struct lov_device_emerg *em; - - em = kzalloc(sizeof(*em), GFP_NOFS); - if (em) { - emerg[i] = em; - cl_page_list_init(&em->emrg_page_list); - em->emrg_env = cl_env_alloc(&em->emrg_refcheck, - LCT_REMEMBER | LCT_NOREF); - if (!IS_ERR(em->emrg_env)) { - em->emrg_env->le_ctx.lc_cookie = 0x2; - } else { - result = PTR_ERR(em->emrg_env); - em->emrg_env = NULL; - } - } else { - result = -ENOMEM; - } - } - if (result != 0) { - lov_emerg_free(emerg, nr); - emerg = ERR_PTR(result); - } - return emerg; -} - static int lov_expand_targets(const struct lu_env *env, struct lov_device *dev) { int result; @@ -306,29 +238,17 @@ static int lov_expand_targets(const struct lu_env *env, struct lov_device *dev) sub_size = dev->ld_target_nr; if (sub_size < tgt_size) { struct lovsub_device **newd; - struct lov_device_emerg **emerg; const size_t sz = sizeof(newd[0]); - emerg = lov_emerg_alloc(tgt_size); - if (IS_ERR(emerg)) - return PTR_ERR(emerg); - newd = kcalloc(tgt_size, sz, GFP_NOFS); if (newd) { - mutex_lock(&dev->ld_mutex); if (sub_size > 0) { memcpy(newd, dev->ld_target, sub_size * sz); kfree(dev->ld_target); } dev->ld_target = newd; dev->ld_target_nr = tgt_size; - - if (dev->ld_emrg) - lov_emerg_free(dev->ld_emrg, sub_size); - dev->ld_emrg = emerg; - mutex_unlock(&dev->ld_mutex); } else { - lov_emerg_free(emerg, tgt_size); result = -ENOMEM; } } @@ -362,8 +282,6 @@ static int lov_cl_add_target(const struct lu_env *env, struct lu_device *dev, tgt->ltd_obd->obd_lu_dev); if (!IS_ERR(cl)) { lsd = cl2lovsub_dev(cl); - lsd->acid_idx = index; - lsd->acid_super = ld; ld->ld_target[index] = lsd; } else { CERROR("add failed (%d), deleting %s\n", rc, @@ -428,9 +346,6 @@ static struct lu_device *lov_device_alloc(const struct lu_env *env, d = lov2lu_dev(ld); d->ld_ops = &lov_lu_ops; - mutex_init(&ld->ld_mutex); - lockdep_set_class(&ld->ld_mutex, &cl_lov_device_mutex_class); - /* setup the LOV OBD */ obd = class_name2obd(lustre_cfg_string(cfg, 0)); LASSERT(obd); diff --git a/drivers/staging/lustre/lustre/lov/lov_ea.c b/drivers/staging/lustre/lustre/lov/lov_ea.c index ac0bf64c08c1..1124fd5ab32f 100644 --- a/drivers/staging/lustre/lustre/lov/lov_ea.c +++ b/drivers/staging/lustre/lustre/lov/lov_ea.c @@ -37,10 +37,10 @@ #define DEBUG_SUBSYSTEM S_LOV #include <asm/div64.h> -#include "../../include/linux/libcfs/libcfs.h" +#include <linux/libcfs/libcfs.h> -#include "../include/obd_class.h" -#include "../include/lustre/lustre_idl.h" +#include <obd_class.h> +#include <uapi/linux/lustre/lustre_idl.h> #include "lov_internal.h" @@ -150,9 +150,10 @@ static int lsm_unpackmd_common(struct lov_obd *lov, struct lov_mds_md *lmm, struct lov_ost_data_v1 *objects) { - loff_t stripe_maxbytes = LLONG_MAX; + loff_t min_stripe_maxbytes = 0; unsigned int stripe_count; struct lov_oinfo *loi; + loff_t lov_bytes; unsigned int i; /* @@ -168,8 +169,6 @@ static int lsm_unpackmd_common(struct lov_obd *lov, stripe_count = lsm_is_released(lsm) ? 0 : lsm->lsm_stripe_count; for (i = 0; i < stripe_count; i++) { - loff_t tgt_bytes; - loi = lsm->lsm_oinfo[i]; ostid_le_to_cpu(&objects[i].l_ost_oi, &loi->loi_oi); loi->loi_ost_idx = le32_to_cpu(objects[i].l_ost_idx); @@ -194,17 +193,21 @@ static int lsm_unpackmd_common(struct lov_obd *lov, continue; } - tgt_bytes = lov_tgt_maxbytes(lov->lov_tgts[loi->loi_ost_idx]); - stripe_maxbytes = min_t(loff_t, stripe_maxbytes, tgt_bytes); + lov_bytes = lov_tgt_maxbytes(lov->lov_tgts[loi->loi_ost_idx]); + if (min_stripe_maxbytes == 0 || lov_bytes < min_stripe_maxbytes) + min_stripe_maxbytes = lov_bytes; } - if (stripe_maxbytes == LLONG_MAX) - stripe_maxbytes = LUSTRE_EXT3_STRIPE_MAXBYTES; + if (min_stripe_maxbytes == 0) + min_stripe_maxbytes = LUSTRE_EXT3_STRIPE_MAXBYTES; + + stripe_count = lsm->lsm_stripe_count ?: lov->desc.ld_tgt_count; + lov_bytes = min_stripe_maxbytes * stripe_count; - if (!lsm->lsm_stripe_count) - lsm->lsm_maxbytes = stripe_maxbytes * lov->desc.ld_tgt_count; + if (lov_bytes < min_stripe_maxbytes) /* handle overflow */ + lsm->lsm_maxbytes = MAX_LFS_FILESIZE; else - lsm->lsm_maxbytes = stripe_maxbytes * lsm->lsm_stripe_count; + lsm->lsm_maxbytes = lov_bytes; return 0; } diff --git a/drivers/staging/lustre/lustre/lov/lov_internal.h b/drivers/staging/lustre/lustre/lov/lov_internal.h index 774499c74daa..a21f074008af 100644 --- a/drivers/staging/lustre/lustre/lov/lov_internal.h +++ b/drivers/staging/lustre/lustre/lov/lov_internal.h @@ -33,8 +33,8 @@ #ifndef LOV_INTERNAL_H #define LOV_INTERNAL_H -#include "../include/obd_class.h" -#include "../include/lustre/lustre_user.h" +#include <obd_class.h> +#include <uapi/linux/lustre/lustre_idl.h> /* * If we are unable to get the maximum object size from the OST in @@ -161,42 +161,21 @@ struct lov_request { struct list_head rq_link; int rq_idx; /* index in lov->tgts array */ - int rq_stripe; /* stripe number */ - int rq_complete; - int rq_rc; - - u32 rq_oabufs; - u32 rq_pgaidx; }; struct lov_request_set { struct obd_info *set_oi; - atomic_t set_refcount; - struct obd_export *set_exp; - /* XXX: There is @set_exp already, however obd_statfs gets obd_device - * only. - */ struct obd_device *set_obd; int set_count; atomic_t set_completes; atomic_t set_success; - atomic_t set_finish_checked; struct list_head set_list; - wait_queue_head_t set_waitq; }; extern struct kmem_cache *lov_oinfo_slab; extern struct lu_kmem_descr lov_caches[]; -void lov_finish_set(struct lov_request_set *set); - -static inline void lov_put_reqset(struct lov_request_set *set) -{ - if (atomic_dec_and_test(&set->set_refcount)) - lov_finish_set(set); -} - #define lov_uuid2str(lv, index) \ (char *)((lv)->lov_tgts[index]->ltd_uuid.uuid) @@ -217,15 +196,9 @@ pgoff_t lov_stripe_pgoff(struct lov_stripe_md *lsm, pgoff_t stripe_index, int stripe); /* lov_request.c */ -int lov_prep_getattr_set(struct obd_export *exp, struct obd_info *oinfo, - struct lov_request_set **reqset); -int lov_fini_getattr_set(struct lov_request_set *set); int lov_prep_statfs_set(struct obd_device *obd, struct obd_info *oinfo, struct lov_request_set **reqset); -int lov_fini_statfs(struct obd_device *obd, struct obd_statfs *osfs, - int success); int lov_fini_statfs_set(struct lov_request_set *set); -int lov_statfs_interpret(struct ptlrpc_request_set *rqset, void *data, int rc); /* lov_obd.c */ void lov_stripe_lock(struct lov_stripe_md *md); diff --git a/drivers/staging/lustre/lustre/lov/lov_io.c b/drivers/staging/lustre/lustre/lov/lov_io.c index babf39adef85..9e3b150967b4 100644 --- a/drivers/staging/lustre/lustre/lov/lov_io.c +++ b/drivers/staging/lustre/lustre/lov/lov_io.c @@ -43,24 +43,12 @@ * @{ */ -static inline void lov_sub_enter(struct lov_io_sub *sub) -{ - sub->sub_reenter++; -} - -static inline void lov_sub_exit(struct lov_io_sub *sub) -{ - sub->sub_reenter--; -} - static void lov_io_sub_fini(const struct lu_env *env, struct lov_io *lio, struct lov_io_sub *sub) { if (sub->sub_io) { if (sub->sub_io_initialized) { - lov_sub_enter(sub); cl_io_fini(sub->sub_env, sub->sub_io); - lov_sub_exit(sub); sub->sub_io_initialized = 0; lio->lis_active_subios--; } @@ -142,13 +130,11 @@ static int lov_io_sub_init(const struct lu_env *env, struct lov_io *lio, struct lov_io_sub *sub) { struct lov_object *lov = lio->lis_object; - struct lov_device *ld = lu2lov_dev(lov2cl(lov)->co_lu.lo_dev); struct cl_io *sub_io; struct cl_object *sub_obj; struct cl_io *io = lio->lis_cl.cis_io; - int stripe = sub->sub_stripe; - int result; + int rc; LASSERT(!sub->sub_io); LASSERT(!sub->sub_env); @@ -157,63 +143,53 @@ static int lov_io_sub_init(const struct lu_env *env, struct lov_io *lio, if (unlikely(!lov_r0(lov)->lo_sub[stripe])) return -EIO; - result = 0; sub->sub_io_initialized = 0; sub->sub_borrowed = 0; - if (lio->lis_mem_frozen) { - LASSERT(mutex_is_locked(&ld->ld_mutex)); - sub->sub_io = &ld->ld_emrg[stripe]->emrg_subio; - sub->sub_env = ld->ld_emrg[stripe]->emrg_env; - sub->sub_borrowed = 1; - } else { - sub->sub_env = cl_env_get(&sub->sub_refcheck); - if (IS_ERR(sub->sub_env)) - result = PTR_ERR(sub->sub_env); + /* obtain new environment */ + sub->sub_env = cl_env_get(&sub->sub_refcheck); + if (IS_ERR(sub->sub_env)) { + rc = PTR_ERR(sub->sub_env); + goto fini_lov_io; + } - if (result == 0) { - /* - * First sub-io. Use ->lis_single_subio to - * avoid dynamic allocation. - */ - if (lio->lis_active_subios == 0) { - sub->sub_io = &lio->lis_single_subio; - lio->lis_single_subio_index = stripe; - } else { - sub->sub_io = kzalloc(sizeof(*sub->sub_io), - GFP_NOFS); - if (!sub->sub_io) - result = -ENOMEM; - } + /* + * First sub-io. Use ->lis_single_subio to + * avoid dynamic allocation. + */ + if (lio->lis_active_subios == 0) { + sub->sub_io = &lio->lis_single_subio; + lio->lis_single_subio_index = stripe; + } else { + sub->sub_io = kzalloc(sizeof(*sub->sub_io), + GFP_NOFS); + if (!sub->sub_io) { + rc = -ENOMEM; + goto fini_lov_io; } } - if (result == 0) { - sub_obj = lovsub2cl(lov_r0(lov)->lo_sub[stripe]); - sub_io = sub->sub_io; - - sub_io->ci_obj = sub_obj; - sub_io->ci_result = 0; - - sub_io->ci_parent = io; - sub_io->ci_lockreq = io->ci_lockreq; - sub_io->ci_type = io->ci_type; - sub_io->ci_no_srvlock = io->ci_no_srvlock; - sub_io->ci_noatime = io->ci_noatime; - - lov_sub_enter(sub); - result = cl_io_sub_init(sub->sub_env, sub_io, - io->ci_type, sub_obj); - lov_sub_exit(sub); - if (result >= 0) { - lio->lis_active_subios++; - sub->sub_io_initialized = 1; - result = 0; - } + sub_obj = lovsub2cl(lov_r0(lov)->lo_sub[stripe]); + sub_io = sub->sub_io; + + sub_io->ci_obj = sub_obj; + sub_io->ci_result = 0; + sub_io->ci_parent = io; + sub_io->ci_lockreq = io->ci_lockreq; + sub_io->ci_type = io->ci_type; + sub_io->ci_no_srvlock = io->ci_no_srvlock; + sub_io->ci_noatime = io->ci_noatime; + + rc = cl_io_sub_init(sub->sub_env, sub_io, io->ci_type, sub_obj); + if (rc >= 0) { + lio->lis_active_subios++; + sub->sub_io_initialized = 1; + rc = 0; } - if (result != 0) +fini_lov_io: + if (rc) lov_io_sub_fini(env, lio, sub); - return result; + return rc; } struct lov_io_sub *lov_sub_get(const struct lu_env *env, @@ -230,16 +206,10 @@ struct lov_io_sub *lov_sub_get(const struct lu_env *env, } else { rc = 0; } - if (rc == 0) - lov_sub_enter(sub); - else + if (rc < 0) sub = ERR_PTR(rc); - return sub; -} -void lov_sub_put(struct lov_io_sub *sub) -{ - lov_sub_exit(sub); + return sub; } /***************************************************************************** @@ -258,22 +228,6 @@ int lov_page_stripe(const struct cl_page *page) return cl2lov_page(slice)->lps_stripe; } -struct lov_io_sub *lov_page_subio(const struct lu_env *env, struct lov_io *lio, - const struct cl_page_slice *slice) -{ - struct lov_stripe_md *lsm = lio->lis_object->lo_lsm; - struct cl_page *page = slice->cpl_page; - int stripe; - - LASSERT(lio->lis_cl.cis_io); - LASSERT(cl2lov(slice->cpl_obj) == lio->lis_object); - LASSERT(lsm); - LASSERT(lio->lis_nr_subios > 0); - - stripe = lov_page_stripe(page); - return lov_sub_get(env, lio, stripe); -} - static int lov_io_subio_init(const struct lu_env *env, struct lov_io *lio, struct cl_io *io) { @@ -431,12 +385,10 @@ static int lov_io_iter_init(const struct lu_env *env, lov_io_sub_inherit(sub->sub_io, lio, stripe, start, end); rc = cl_io_iter_init(sub->sub_env, sub->sub_io); - if (rc) + if (rc) { cl_io_iter_fini(sub->sub_env, sub->sub_io); - lov_sub_put(sub); - if (rc) break; - + } CDEBUG(D_VFSTRACE, "shrink: %d [%llu, %llu)\n", stripe, start, end); @@ -488,9 +440,7 @@ static int lov_io_call(const struct lu_env *env, struct lov_io *lio, int rc = 0; list_for_each_entry(sub, &lio->lis_active, sub_linkage) { - lov_sub_enter(sub); rc = iofunc(sub->sub_env, sub->sub_io); - lov_sub_exit(sub); if (rc) break; @@ -610,7 +560,6 @@ static int lov_io_read_ahead(const struct lu_env *env, rc = cl_io_read_ahead(sub->sub_env, sub->sub_io, cl_index(lovsub2cl(r0->lo_sub[stripe]), suboff), ra); - lov_sub_put(sub); CDEBUG(D_READA, DFID " cra_end = %lu, stripes = %d, rc = %d\n", PFID(lu_object_fid(lov2lu(loo))), ra->cra_end, r0->lo_nr, rc); @@ -679,7 +628,6 @@ static int lov_io_submit(const struct lu_env *env, LASSERT(sub->sub_io == &lio->lis_single_subio); rc = cl_io_submit_rw(sub->sub_env, sub->sub_io, crt, queue); - lov_sub_put(sub); return rc; } @@ -707,7 +655,6 @@ static int lov_io_submit(const struct lu_env *env, if (!IS_ERR(sub)) { rc = cl_io_submit_rw(sub->sub_env, sub->sub_io, crt, cl2q); - lov_sub_put(sub); } else { rc = PTR_ERR(sub); } @@ -746,7 +693,6 @@ static int lov_io_commit_async(const struct lu_env *env, LASSERT(sub->sub_io == &lio->lis_single_subio); rc = cl_io_commit_async(sub->sub_env, sub->sub_io, queue, from, to, cb); - lov_sub_put(sub); return rc; } @@ -777,7 +723,6 @@ static int lov_io_commit_async(const struct lu_env *env, if (!IS_ERR(sub)) { rc = cl_io_commit_async(sub->sub_env, sub->sub_io, plist, from, stripe_to, cb); - lov_sub_put(sub); } else { rc = PTR_ERR(sub); break; @@ -813,7 +758,6 @@ static int lov_io_fault_start(const struct lu_env *env, if (IS_ERR(sub)) return PTR_ERR(sub); sub->sub_io->u.ci_fault.ft_nob = fio->ft_nob; - lov_sub_put(sub); return lov_io_start(env, ios); } @@ -828,9 +772,7 @@ static void lov_io_fsync_end(const struct lu_env *env, list_for_each_entry(sub, &lio->lis_active, sub_linkage) { struct cl_io *subio = sub->sub_io; - lov_sub_enter(sub); lov_io_end_wrapper(sub->sub_env, subio); - lov_sub_exit(sub); if (subio->ci_result == 0) *written += subio->u.ci_fsync.fi_nr_written; @@ -939,12 +881,6 @@ static const struct cl_io_operations lov_empty_io_ops = { .op = { [CIT_READ] = { .cio_fini = lov_empty_io_fini, -#if 0 - .cio_iter_init = LOV_EMPTY_IMPOSSIBLE, - .cio_lock = LOV_EMPTY_IMPOSSIBLE, - .cio_start = LOV_EMPTY_IMPOSSIBLE, - .cio_end = LOV_EMPTY_IMPOSSIBLE -#endif }, [CIT_WRITE] = { .cio_fini = lov_empty_io_fini, @@ -1047,6 +983,8 @@ int lov_io_init_released(const struct lu_env *env, struct cl_object *obj, switch (io->ci_type) { default: LASSERTF(0, "invalid type %d\n", io->ci_type); + result = -EOPNOTSUPP; + break; case CIT_MISC: case CIT_FSYNC: case CIT_DATA_VERSION: diff --git a/drivers/staging/lustre/lustre/lov/lov_lock.c b/drivers/staging/lustre/lustre/lov/lov_lock.c index 8502128e8248..e12dc5afc14f 100644 --- a/drivers/staging/lustre/lustre/lov/lov_lock.c +++ b/drivers/staging/lustre/lustre/lov/lov_lock.c @@ -71,13 +71,11 @@ static struct lov_sublock_env *lov_sublock_env_get(const struct lu_env *env, if (!io || !cl_object_same(io->ci_obj, parent->cll_descr.cld_obj)) { subenv->lse_env = env; subenv->lse_io = io; - subenv->lse_sub = NULL; } else { sub = lov_sub_get(env, lio, lls->sub_stripe); if (!IS_ERR(sub)) { subenv->lse_env = sub->sub_env; subenv->lse_io = sub->sub_io; - subenv->lse_sub = sub; } else { subenv = (void *)sub; } @@ -85,12 +83,6 @@ static struct lov_sublock_env *lov_sublock_env_get(const struct lu_env *env, return subenv; } -static void lov_sublock_env_put(struct lov_sublock_env *subenv) -{ - if (subenv && subenv->lse_sub) - lov_sub_put(subenv->lse_sub); -} - static int lov_sublock_init(const struct lu_env *env, const struct cl_lock *parent, struct lov_lock_sub *lls) @@ -102,7 +94,6 @@ static int lov_sublock_init(const struct lu_env *env, if (!IS_ERR(subenv)) { result = cl_lock_init(subenv->lse_env, &lls->sub_lock, subenv->lse_io); - lov_sublock_env_put(subenv); } else { /* error occurs. */ result = PTR_ERR(subenv); @@ -244,7 +235,6 @@ static int lov_lock_enqueue(const struct lu_env *env, } rc = cl_lock_enqueue(subenv->lse_env, subenv->lse_io, &lls->sub_lock, anchor); - lov_sublock_env_put(subenv); if (rc != 0) break; @@ -272,11 +262,10 @@ static void lov_lock_cancel(const struct lu_env *env, subenv = lov_sublock_env_get(env, lock, lls); if (!IS_ERR(subenv)) { cl_lock_cancel(subenv->lse_env, sublock); - lov_sublock_env_put(subenv); } else { CL_LOCK_DEBUG(D_ERROR, env, slice->cls_lock, - "lov_lock_cancel fails with %ld.\n", - PTR_ERR(subenv)); + "%s fails with %ld.\n", + __func__, PTR_ERR(subenv)); } } } diff --git a/drivers/staging/lustre/lustre/lov/lov_merge.c b/drivers/staging/lustre/lustre/lov/lov_merge.c index 034b4fcb38f5..916336115989 100644 --- a/drivers/staging/lustre/lustre/lov/lov_merge.c +++ b/drivers/staging/lustre/lustre/lov/lov_merge.c @@ -32,9 +32,9 @@ #define DEBUG_SUBSYSTEM S_LOV -#include "../../include/linux/libcfs/libcfs.h" +#include <linux/libcfs/libcfs.h> -#include "../include/obd_class.h" +#include <obd_class.h> #include "lov_internal.h" /** Merge the lock value block(&lvb) attributes and KMS from each of the diff --git a/drivers/staging/lustre/lustre/lov/lov_obd.c b/drivers/staging/lustre/lustre/lov/lov_obd.c index 25f15da6e189..fefd3c588681 100644 --- a/drivers/staging/lustre/lustre/lov/lov_obd.c +++ b/drivers/staging/lustre/lustre/lov/lov_obd.c @@ -38,22 +38,22 @@ */ #define DEBUG_SUBSYSTEM S_LOV -#include "../../include/linux/libcfs/libcfs.h" - -#include "../include/lustre/lustre_idl.h" -#include "../include/lustre/lustre_ioctl.h" - -#include "../include/cl_object.h" -#include "../include/lustre_dlm.h" -#include "../include/lustre_fid.h" -#include "../include/lustre_lib.h" -#include "../include/lustre_mds.h" -#include "../include/lustre_net.h" -#include "../include/lustre_param.h" -#include "../include/lustre_swab.h" -#include "../include/lprocfs_status.h" -#include "../include/obd_class.h" -#include "../include/obd_support.h" +#include <linux/libcfs/libcfs.h> + +#include <uapi/linux/lustre/lustre_idl.h> +#include <uapi/linux/lustre/lustre_ioctl.h> + +#include <cl_object.h> +#include <lustre_dlm.h> +#include <lustre_fid.h> +#include <lustre_lib.h> +#include <lustre_mds.h> +#include <lustre_net.h> +#include <uapi/linux/lustre/lustre_param.h> +#include <lustre_swab.h> +#include <lprocfs_status.h> +#include <obd_class.h> +#include <obd_support.h> #include "lov_internal.h" @@ -947,7 +947,8 @@ out: return rc; } -int lov_statfs_interpret(struct ptlrpc_request_set *rqset, void *data, int rc) +static int +lov_statfs_interpret(struct ptlrpc_request_set *rqset, void *data, int rc) { struct lov_request_set *lovset = (struct lov_request_set *)data; int err; @@ -1086,17 +1087,17 @@ static int lov_iocontrol(unsigned int cmd, struct obd_export *exp, int len, data = (struct obd_ioctl_data *)buf; if (sizeof(*desc) > data->ioc_inllen1) { - obd_ioctl_freedata(buf, len); + kvfree(buf); return -EINVAL; } if (sizeof(uuidp->uuid) * count > data->ioc_inllen2) { - obd_ioctl_freedata(buf, len); + kvfree(buf); return -EINVAL; } if (sizeof(__u32) * count > data->ioc_inllen3) { - obd_ioctl_freedata(buf, len); + kvfree(buf); return -EINVAL; } @@ -1115,7 +1116,7 @@ static int lov_iocontrol(unsigned int cmd, struct obd_export *exp, int len, if (copy_to_user(uarg, buf, len)) rc = -EFAULT; - obd_ioctl_freedata(buf, len); + kvfree(buf); break; } case OBD_IOC_QUOTACTL: { diff --git a/drivers/staging/lustre/lustre/lov/lov_object.c b/drivers/staging/lustre/lustre/lov/lov_object.c index 14f38268d414..334ecb1bc049 100644 --- a/drivers/staging/lustre/lustre/lov/lov_object.c +++ b/drivers/staging/lustre/lustre/lov/lov_object.c @@ -638,7 +638,7 @@ static const struct lov_layout_operations lov_dispatch[] = { enum lov_layout_type __llt; \ \ __llt = __obj->lo_type; \ - LASSERT(0 <= __llt && __llt < ARRAY_SIZE(lov_dispatch)); \ + LASSERT(__llt < ARRAY_SIZE(lov_dispatch)); \ lov_dispatch[__llt].op(__VA_ARGS__); \ }) @@ -697,7 +697,7 @@ do { \ \ lov_conf_freeze(__obj); \ __llt = __obj->lo_type; \ - LASSERT(0 <= __llt && __llt < ARRAY_SIZE(lov_dispatch)); \ + LASSERT(__llt < ARRAY_SIZE(lov_dispatch)); \ lov_dispatch[__llt].op(__VA_ARGS__); \ lov_conf_thaw(__obj); \ } while (0) @@ -748,13 +748,13 @@ static int lov_layout_change(const struct lu_env *unused, u16 refcheck; int rc; - LASSERT(0 <= lov->lo_type && lov->lo_type < ARRAY_SIZE(lov_dispatch)); + LASSERT(lov->lo_type < ARRAY_SIZE(lov_dispatch)); env = cl_env_get(&refcheck); if (IS_ERR(env)) return PTR_ERR(env); - LASSERT(0 <= llt && llt < ARRAY_SIZE(lov_dispatch)); + LASSERT(llt < ARRAY_SIZE(lov_dispatch)); CDEBUG(D_INODE, DFID " from %s to %s\n", PFID(lu_object_fid(lov2lu(lov))), @@ -1003,12 +1003,12 @@ int lov_lock_init(const struct lu_env *env, struct cl_object *obj, * \retval last_stripe return the last stripe of the mapping */ static int fiemap_calc_last_stripe(struct lov_stripe_md *lsm, - loff_t fm_start, loff_t fm_end, + u64 fm_start, u64 fm_end, int start_stripe, int *stripe_count) { int last_stripe; - loff_t obd_start; - loff_t obd_end; + u64 obd_start; + u64 obd_end; int i, j; if (fm_end - fm_start > lsm->lsm_stripe_size * lsm->lsm_stripe_count) { @@ -1076,14 +1076,14 @@ static void fiemap_prepare_and_copy_exts(struct fiemap *fiemap, * \param fm_end [in] logical end of mapping * \param start_stripe [out] starting stripe will be returned in this */ -static loff_t fiemap_calc_fm_end_offset(struct fiemap *fiemap, - struct lov_stripe_md *lsm, - loff_t fm_start, loff_t fm_end, - int *start_stripe) +static u64 fiemap_calc_fm_end_offset(struct fiemap *fiemap, + struct lov_stripe_md *lsm, + u64 fm_start, u64 fm_end, + int *start_stripe) { - loff_t local_end = fiemap->fm_extents[0].fe_logical; - loff_t lun_start, lun_end; - loff_t fm_end_offset; + u64 local_end = fiemap->fm_extents[0].fe_logical; + u64 lun_start, lun_end; + u64 fm_end_offset; int stripe_no = -1; int i; @@ -1126,6 +1126,190 @@ static loff_t fiemap_calc_fm_end_offset(struct fiemap *fiemap, return fm_end_offset; } +struct fiemap_state { + struct fiemap *fs_fm; + u64 fs_start; + u64 fs_length; + u64 fs_end; + u64 fs_end_offset; + int fs_cur_extent; + int fs_cnt_need; + int fs_start_stripe; + int fs_last_stripe; + bool fs_device_done; + bool fs_finish; + bool fs_enough; +}; + +static int fiemap_for_stripe(const struct lu_env *env, struct cl_object *obj, + struct lov_stripe_md *lsm, + struct fiemap *fiemap, size_t *buflen, + struct ll_fiemap_info_key *fmkey, int stripeno, + struct fiemap_state *fs) +{ + struct cl_object *subobj; + struct lov_obd *lov = lu2lov_dev(obj->co_lu.lo_dev)->ld_lov; + struct fiemap_extent *fm_ext = &fs->fs_fm->fm_extents[0]; + u64 req_fm_len; /* Stores length of required mapping */ + u64 len_mapped_single_call; + u64 lun_start; + u64 lun_end; + u64 obd_object_end; + unsigned int ext_count; + /* EOF for object */ + bool ost_eof = false; + /* done with required mapping for this OST? */ + bool ost_done = false; + int ost_index; + int rc = 0; + + fs->fs_device_done = false; + /* Find out range of mapping on this stripe */ + if ((lov_stripe_intersects(lsm, stripeno, fs->fs_start, fs->fs_end, + &lun_start, &obd_object_end)) == 0) + return 0; + + if (lov_oinfo_is_dummy(lsm->lsm_oinfo[stripeno])) + return -EIO; + + /* If this is a continuation FIEMAP call and we are on + * starting stripe then lun_start needs to be set to + * end_offset */ + if (fs->fs_end_offset != 0 && stripeno == fs->fs_start_stripe) + lun_start = fs->fs_end_offset; + + lun_end = fs->fs_length; + if (lun_end != ~0ULL) { + /* Handle fs->fs_start + fs->fs_length overflow */ + if (fs->fs_start + fs->fs_length < fs->fs_start) + fs->fs_length = ~0ULL - fs->fs_start; + lun_end = lov_size_to_stripe(lsm, fs->fs_start + fs->fs_length, + stripeno); + } + + if (lun_start == lun_end) + return 0; + + req_fm_len = obd_object_end - lun_start; + fs->fs_fm->fm_length = 0; + len_mapped_single_call = 0; + + /* find lobsub object */ + subobj = lov_find_subobj(env, cl2lov(obj), lsm, stripeno); + if (IS_ERR(subobj)) + return PTR_ERR(subobj); + /* If the output buffer is very large and the objects have many + * extents we may need to loop on a single OST repeatedly */ + do { + if (fiemap->fm_extent_count > 0) { + /* Don't get too many extents. */ + if (fs->fs_cur_extent + fs->fs_cnt_need > + fiemap->fm_extent_count) + fs->fs_cnt_need = fiemap->fm_extent_count - + fs->fs_cur_extent; + } + + lun_start += len_mapped_single_call; + fs->fs_fm->fm_length = req_fm_len - len_mapped_single_call; + req_fm_len = fs->fs_fm->fm_length; + fs->fs_fm->fm_extent_count = fs->fs_enough ? + 1 : fs->fs_cnt_need; + fs->fs_fm->fm_mapped_extents = 0; + fs->fs_fm->fm_flags = fiemap->fm_flags; + + ost_index = lsm->lsm_oinfo[stripeno]->loi_ost_idx; + + if (ost_index < 0 || ost_index >= lov->desc.ld_tgt_count) { + rc = -EINVAL; + goto obj_put; + } + /* If OST is inactive, return extent with UNKNOWN flag. */ + if (!lov->lov_tgts[ost_index]->ltd_active) { + fs->fs_fm->fm_flags |= FIEMAP_EXTENT_LAST; + fs->fs_fm->fm_mapped_extents = 1; + + fm_ext[0].fe_logical = lun_start; + fm_ext[0].fe_length = obd_object_end - lun_start; + fm_ext[0].fe_flags |= FIEMAP_EXTENT_UNKNOWN; + + goto inactive_tgt; + } + + fs->fs_fm->fm_start = lun_start; + fs->fs_fm->fm_flags &= ~FIEMAP_FLAG_DEVICE_ORDER; + memcpy(&fmkey->lfik_fiemap, fs->fs_fm, sizeof(*fs->fs_fm)); + *buflen = fiemap_count_to_size(fs->fs_fm->fm_extent_count); + + rc = cl_object_fiemap(env, subobj, fmkey, fs->fs_fm, buflen); + if (rc) + goto obj_put; +inactive_tgt: + ext_count = fs->fs_fm->fm_mapped_extents; + if (ext_count == 0) { + ost_done = true; + fs->fs_device_done = true; + /* If last stripe has hold at the end, + * we need to return */ + if (stripeno == fs->fs_last_stripe) { + fiemap->fm_mapped_extents = 0; + fs->fs_finish = true; + goto obj_put; + } + break; + } else if (fs->fs_enough) { + /* + * We've collected enough extents and there are + * more extents after it. + */ + fs->fs_finish = true; + goto obj_put; + } + + /* If we just need num of extents, got to next device */ + if (fiemap->fm_extent_count == 0) { + fs->fs_cur_extent += ext_count; + break; + } + + /* prepare to copy retrived map extents */ + len_mapped_single_call = fm_ext[ext_count - 1].fe_logical + + fm_ext[ext_count - 1].fe_length - + lun_start; + + /* Have we finished mapping on this device? */ + if (req_fm_len <= len_mapped_single_call) { + ost_done = true; + fs->fs_device_done = true; + } + + /* Clear the EXTENT_LAST flag which can be present on + * the last extent */ + if (fm_ext[ext_count - 1].fe_flags & FIEMAP_EXTENT_LAST) + fm_ext[ext_count - 1].fe_flags &= ~FIEMAP_EXTENT_LAST; + if (lov_stripe_size(lsm, fm_ext[ext_count - 1].fe_logical + + fm_ext[ext_count - 1].fe_length, + stripeno) >= fmkey->lfik_oa.o_size) { + ost_eof = true; + fs->fs_device_done = true; + } + + fiemap_prepare_and_copy_exts(fiemap, fm_ext, ost_index, + ext_count, fs->fs_cur_extent); + fs->fs_cur_extent += ext_count; + + /* Ran out of available extents? */ + if (fs->fs_cur_extent >= fiemap->fm_extent_count) + fs->fs_enough = true; + } while (!ost_done && !ost_eof); + + if (stripeno == fs->fs_last_stripe) + fs->fs_finish = true; +obj_put: + cl_object_put(env, subobj); + + return rc; +} + /** * Break down the FIEMAP request and send appropriate calls to individual OSTs. * This also handles the restarting of FIEMAP calls in case mapping overflows @@ -1144,31 +1328,13 @@ static int lov_object_fiemap(const struct lu_env *env, struct cl_object *obj, struct ll_fiemap_info_key *fmkey, struct fiemap *fiemap, size_t *buflen) { - struct lov_obd *lov = lu2lov_dev(obj->co_lu.lo_dev)->ld_lov; unsigned int buffer_size = FIEMAP_BUFFER_SIZE; - struct fiemap_extent *lcl_fm_ext; - struct cl_object *subobj = NULL; struct fiemap *fm_local = NULL; struct lov_stripe_md *lsm; - loff_t fm_start; - loff_t fm_end; - loff_t fm_length; - loff_t fm_end_offset; - int count_local; - int ost_index = 0; - int start_stripe; - int current_extent = 0; int rc = 0; - int last_stripe; - int cur_stripe = 0; - int cur_stripe_wrap = 0; + int cur_stripe; int stripe_count; - /* Whether have we collected enough extents */ - bool enough = false; - /* EOF for object */ - bool ost_eof = false; - /* done with required mapping for this OST? */ - bool ost_done = false; + struct fiemap_state fs = { 0 }; lsm = lov_lsm_addref(cl2lov(obj)); if (!lsm) @@ -1215,28 +1381,37 @@ static int lov_object_fiemap(const struct lu_env *env, struct cl_object *obj, rc = -ENOMEM; goto out; } - lcl_fm_ext = &fm_local->fm_extents[0]; - count_local = fiemap_size_to_count(buffer_size); + fs.fs_fm = fm_local; + fs.fs_cnt_need = fiemap_size_to_count(buffer_size); - fm_start = fiemap->fm_start; - fm_length = fiemap->fm_length; + fs.fs_start = fiemap->fm_start; + /* fs_start is beyond the end of the file */ + if (fs.fs_start > fmkey->lfik_oa.o_size) { + rc = -EINVAL; + goto out; + } /* Calculate start stripe, last stripe and length of mapping */ - start_stripe = lov_stripe_number(lsm, fm_start); - fm_end = (fm_length == ~0ULL) ? fmkey->lfik_oa.o_size : - fm_start + fm_length - 1; - /* If fm_length != ~0ULL but fm_start_fm_length-1 exceeds file size */ - if (fm_end > fmkey->lfik_oa.o_size) - fm_end = fmkey->lfik_oa.o_size; - - last_stripe = fiemap_calc_last_stripe(lsm, fm_start, fm_end, - start_stripe, &stripe_count); - fm_end_offset = fiemap_calc_fm_end_offset(fiemap, lsm, fm_start, fm_end, - &start_stripe); - if (fm_end_offset == -EINVAL) { + fs.fs_start_stripe = lov_stripe_number(lsm, fs.fs_start); + fs.fs_end = (fs.fs_length == ~0ULL) ? fmkey->lfik_oa.o_size : + fs.fs_start + fs.fs_length - 1; + /* If fs_length != ~0ULL but fs_start+fs_length-1 exceeds file size */ + if (fs.fs_end > fmkey->lfik_oa.o_size) { + fs.fs_end = fmkey->lfik_oa.o_size; + fs.fs_length = fs.fs_end - fs.fs_start; + } + + fs.fs_last_stripe = fiemap_calc_last_stripe(lsm, fs.fs_start, fs.fs_end, + fs.fs_start_stripe, + &stripe_count); + fs.fs_end_offset = fiemap_calc_fm_end_offset(fiemap, lsm, fs.fs_start, + fs.fs_end, + &fs.fs_start_stripe); + if (fs.fs_end_offset == -EINVAL) { rc = -EINVAL; goto out; } + /** * Requested extent count exceeds the fiemap buffer size, shrink our * ambition. @@ -1244,186 +1419,23 @@ static int lov_object_fiemap(const struct lu_env *env, struct cl_object *obj, if (fiemap_count_to_size(fiemap->fm_extent_count) > *buflen) fiemap->fm_extent_count = fiemap_size_to_count(*buflen); if (!fiemap->fm_extent_count) - count_local = 0; + fs.fs_cnt_need = 0; + + fs.fs_finish = false; + fs.fs_enough = false; + fs.fs_cur_extent = 0; /* Check each stripe */ - for (cur_stripe = start_stripe; stripe_count > 0; + for (cur_stripe = fs.fs_start_stripe; stripe_count > 0; --stripe_count, cur_stripe = (cur_stripe + 1) % lsm->lsm_stripe_count) { - loff_t req_fm_len; /* Stores length of required mapping */ - loff_t len_mapped_single_call; - loff_t lun_start; - loff_t lun_end; - loff_t obd_object_end; - unsigned int ext_count; - - cur_stripe_wrap = cur_stripe; - - /* Find out range of mapping on this stripe */ - if (!(lov_stripe_intersects(lsm, cur_stripe, fm_start, fm_end, - &lun_start, &obd_object_end))) - continue; - - if (lov_oinfo_is_dummy(lsm->lsm_oinfo[cur_stripe])) { - rc = -EIO; - goto out; - } - - /* - * If this is a continuation FIEMAP call and we are on - * starting stripe then lun_start needs to be set to - * fm_end_offset - */ - if (fm_end_offset && cur_stripe == start_stripe) - lun_start = fm_end_offset; - - if (fm_length != ~0ULL) { - /* Handle fm_start + fm_length overflow */ - if (fm_start + fm_length < fm_start) - fm_length = ~0ULL - fm_start; - lun_end = lov_size_to_stripe(lsm, fm_start + fm_length, - cur_stripe); - } else { - lun_end = ~0ULL; - } - - if (lun_start == lun_end) - continue; - - req_fm_len = obd_object_end - lun_start; - fm_local->fm_length = 0; - len_mapped_single_call = 0; - - /* find lobsub object */ - subobj = lov_find_subobj(env, cl2lov(obj), lsm, - cur_stripe); - if (IS_ERR(subobj)) { - rc = PTR_ERR(subobj); + rc = fiemap_for_stripe(env, obj, lsm, fiemap, buflen, fmkey, + cur_stripe, &fs); + if (rc < 0) goto out; - } - /* - * If the output buffer is very large and the objects have many - * extents we may need to loop on a single OST repeatedly - */ - ost_eof = false; - ost_done = false; - do { - if (fiemap->fm_extent_count > 0) { - /* Don't get too many extents. */ - if (current_extent + count_local > - fiemap->fm_extent_count) - count_local = fiemap->fm_extent_count - - current_extent; - } - - lun_start += len_mapped_single_call; - fm_local->fm_length = req_fm_len - - len_mapped_single_call; - req_fm_len = fm_local->fm_length; - fm_local->fm_extent_count = enough ? 1 : count_local; - fm_local->fm_mapped_extents = 0; - fm_local->fm_flags = fiemap->fm_flags; - - ost_index = lsm->lsm_oinfo[cur_stripe]->loi_ost_idx; - - if (ost_index < 0 || - ost_index >= lov->desc.ld_tgt_count) { - rc = -EINVAL; - goto obj_put; - } - /* - * If OST is inactive, return extent with UNKNOWN - * flag. - */ - if (!lov->lov_tgts[ost_index]->ltd_active) { - fm_local->fm_flags |= FIEMAP_EXTENT_LAST; - fm_local->fm_mapped_extents = 1; - - lcl_fm_ext[0].fe_logical = lun_start; - lcl_fm_ext[0].fe_length = obd_object_end - - lun_start; - lcl_fm_ext[0].fe_flags |= FIEMAP_EXTENT_UNKNOWN; - - goto inactive_tgt; - } - - fm_local->fm_start = lun_start; - fm_local->fm_flags &= ~FIEMAP_FLAG_DEVICE_ORDER; - memcpy(&fmkey->lfik_fiemap, fm_local, sizeof(*fm_local)); - *buflen = fiemap_count_to_size(fm_local->fm_extent_count); - - rc = cl_object_fiemap(env, subobj, fmkey, fm_local, - buflen); - if (rc) - goto obj_put; -inactive_tgt: - ext_count = fm_local->fm_mapped_extents; - if (!ext_count) { - ost_done = true; - /* - * If last stripe has hold at the end, - * we need to return - */ - if (cur_stripe_wrap == last_stripe) { - fiemap->fm_mapped_extents = 0; - goto finish; - } - break; - } else if (enough) { - /* - * We've collected enough extents and there are - * more extents after it. - */ - goto finish; - } - - /* If we just need num of extents, got to next device */ - if (!fiemap->fm_extent_count) { - current_extent += ext_count; - break; - } - - /* prepare to copy retrived map extents */ - len_mapped_single_call = - lcl_fm_ext[ext_count - 1].fe_logical - - lun_start + lcl_fm_ext[ext_count - 1].fe_length; - - /* Have we finished mapping on this device? */ - if (req_fm_len <= len_mapped_single_call) - ost_done = true; - - /* - * Clear the EXTENT_LAST flag which can be present on - * the last extent - */ - if (lcl_fm_ext[ext_count - 1].fe_flags & - FIEMAP_EXTENT_LAST) - lcl_fm_ext[ext_count - 1].fe_flags &= - ~FIEMAP_EXTENT_LAST; - - if (lov_stripe_size(lsm, - lcl_fm_ext[ext_count - 1].fe_logical + - lcl_fm_ext[ext_count - 1].fe_length, - cur_stripe) >= fmkey->lfik_oa.o_size) - ost_eof = true; - - fiemap_prepare_and_copy_exts(fiemap, lcl_fm_ext, - ost_index, ext_count, - current_extent); - current_extent += ext_count; - - /* Ran out of available extents? */ - if (current_extent >= fiemap->fm_extent_count) - enough = true; - } while (!ost_done && !ost_eof); - - cl_object_put(env, subobj); - subobj = NULL; - - if (cur_stripe_wrap == last_stripe) - goto finish; + if (fs.fs_finish) + break; } /* for each stripe */ -finish: /* * Indicate that we are returning device offsets unless file just has * single stripe @@ -1438,14 +1450,11 @@ finish: * Check if we have reached the last stripe and whether mapping for that * stripe is done. */ - if ((cur_stripe_wrap == last_stripe) && (ost_done || ost_eof)) - fiemap->fm_extents[current_extent - 1].fe_flags |= + if ((cur_stripe == fs.fs_last_stripe) && fs.fs_device_done) + fiemap->fm_extents[fs.fs_cur_extent - 1].fe_flags |= FIEMAP_EXTENT_LAST; skip_last_device_calc: - fiemap->fm_mapped_extents = current_extent; -obj_put: - if (subobj) - cl_object_put(env, subobj); + fiemap->fm_mapped_extents = fs.fs_cur_extent; out: kvfree(fm_local); lov_lsm_put(lsm); diff --git a/drivers/staging/lustre/lustre/lov/lov_offset.c b/drivers/staging/lustre/lustre/lov/lov_offset.c index ecca74fbff00..899d12c41aab 100644 --- a/drivers/staging/lustre/lustre/lov/lov_offset.c +++ b/drivers/staging/lustre/lustre/lov/lov_offset.c @@ -32,9 +32,9 @@ #define DEBUG_SUBSYSTEM S_LOV -#include "../../include/linux/libcfs/libcfs.h" +#include <linux/libcfs/libcfs.h> -#include "../include/obd_class.h" +#include <obd_class.h> #include "lov_internal.h" diff --git a/drivers/staging/lustre/lustre/lov/lov_pack.c b/drivers/staging/lustre/lustre/lov/lov_pack.c index 638b7646ca2c..24fb2a97532b 100644 --- a/drivers/staging/lustre/lustre/lov/lov_pack.c +++ b/drivers/staging/lustre/lustre/lov/lov_pack.c @@ -38,14 +38,11 @@ #define DEBUG_SUBSYSTEM S_LOV -#include "../include/lustre/lustre_idl.h" -#include "../include/lustre/lustre_user.h" - -#include "../include/lustre_net.h" -#include "../include/lustre_swab.h" -#include "../include/obd.h" -#include "../include/obd_class.h" -#include "../include/obd_support.h" +#include <lustre_net.h> +#include <lustre_swab.h> +#include <obd.h> +#include <obd_class.h> +#include <obd_support.h> #include "lov_cl_internal.h" #include "lov_internal.h" diff --git a/drivers/staging/lustre/lustre/lov/lov_page.c b/drivers/staging/lustre/lustre/lov/lov_page.c index 62ceb6dfdfdf..de43c609cf3d 100644 --- a/drivers/staging/lustre/lustre/lov/lov_page.c +++ b/drivers/staging/lustre/lustre/lov/lov_page.c @@ -100,7 +100,6 @@ int lov_page_init_raid0(const struct lu_env *env, struct cl_object *obj, break; } } - lov_sub_put(sub); return rc; } diff --git a/drivers/staging/lustre/lustre/lov/lov_pool.c b/drivers/staging/lustre/lustre/lov/lov_pool.c index 39daa17e0736..d774ee2a3675 100644 --- a/drivers/staging/lustre/lustre/lov/lov_pool.c +++ b/drivers/staging/lustre/lustre/lov/lov_pool.c @@ -40,9 +40,9 @@ #define DEBUG_SUBSYSTEM S_LOV -#include "../../include/linux/libcfs/libcfs.h" +#include <linux/libcfs/libcfs.h> -#include "../include/obd.h" +#include <obd.h> #include "lov_internal.h" #define pool_tgt(_p, _i) \ diff --git a/drivers/staging/lustre/lustre/lov/lov_request.c b/drivers/staging/lustre/lustre/lov/lov_request.c index 3a747913fb4f..9d3b3f3e9f10 100644 --- a/drivers/staging/lustre/lustre/lov/lov_request.c +++ b/drivers/staging/lustre/lustre/lov/lov_request.c @@ -32,10 +32,10 @@ #define DEBUG_SUBSYSTEM S_LOV -#include "../../include/linux/libcfs/libcfs.h" +#include <linux/libcfs/libcfs.h> -#include "../include/obd_class.h" -#include "../include/lustre/lustre_idl.h" +#include <obd_class.h> +#include <uapi/linux/lustre/lustre_idl.h> #include "lov_internal.h" static void lov_init_set(struct lov_request_set *set) @@ -43,13 +43,10 @@ static void lov_init_set(struct lov_request_set *set) set->set_count = 0; atomic_set(&set->set_completes, 0); atomic_set(&set->set_success, 0); - atomic_set(&set->set_finish_checked, 0); INIT_LIST_HEAD(&set->set_list); - atomic_set(&set->set_refcount, 1); - init_waitqueue_head(&set->set_waitq); } -void lov_finish_set(struct lov_request_set *set) +static void lov_finish_set(struct lov_request_set *set) { struct list_head *pos, *n; @@ -66,32 +63,12 @@ void lov_finish_set(struct lov_request_set *set) kfree(set); } -static int lov_set_finished(struct lov_request_set *set, int idempotent) -{ - int completes = atomic_read(&set->set_completes); - - CDEBUG(D_INFO, "check set %d/%d\n", completes, set->set_count); - - if (completes == set->set_count) { - if (idempotent) - return 1; - if (atomic_inc_return(&set->set_finish_checked) == 1) - return 1; - } - return 0; -} - static void lov_update_set(struct lov_request_set *set, struct lov_request *req, int rc) { - req->rq_complete = 1; - req->rq_rc = rc; - atomic_inc(&set->set_completes); if (rc == 0) atomic_inc(&set->set_success); - - wake_up(&set->set_waitq); } static void lov_set_add_req(struct lov_request *req, @@ -173,8 +150,8 @@ out: (tot) += (add); \ } while (0) -int lov_fini_statfs(struct obd_device *obd, struct obd_statfs *osfs, - int success) +static int lov_fini_statfs(struct obd_device *obd, struct obd_statfs *osfs, + int success) { if (success) { __u32 expected_stripes = lov_get_stripecnt(&obd->u.lov, @@ -205,7 +182,9 @@ int lov_fini_statfs_set(struct lov_request_set *set) rc = lov_fini_statfs(set->set_obd, set->set_oi->oi_osfs, atomic_read(&set->set_success)); } - lov_put_reqset(set); + + lov_finish_set(set); + return rc; } @@ -307,14 +286,7 @@ static int cb_statfs_update(void *cookie, int rc) out_update: lov_update_statfs(osfs, lov_sfs, success); obd_putref(lovobd); - out: - if (set->set_oi->oi_flags & OBD_STATFS_PTLRPCD && - lov_set_finished(set, 0)) { - lov_statfs_interpret(NULL, set, set->set_count != - atomic_read(&set->set_success)); - } - return 0; } diff --git a/drivers/staging/lustre/lustre/lov/lovsub_dev.c b/drivers/staging/lustre/lustre/lov/lovsub_dev.c index 5d6536f8a4f7..d4646a0949d2 100644 --- a/drivers/staging/lustre/lustre/lov/lovsub_dev.c +++ b/drivers/staging/lustre/lustre/lov/lovsub_dev.c @@ -77,7 +77,6 @@ static struct lu_device *lovsub_device_fini(const struct lu_env *env, lsd = lu2lovsub_dev(d); next = cl2lu_dev(lsd->acid_next); - lsd->acid_super = NULL; lsd->acid_next = NULL; return next; } diff --git a/drivers/staging/lustre/lustre/lov/lovsub_io.c b/drivers/staging/lustre/lustre/lov/lovsub_io.c deleted file mode 100644 index 6a9820218a3e..000000000000 --- a/drivers/staging/lustre/lustre/lov/lovsub_io.c +++ /dev/null @@ -1,51 +0,0 @@ -/* - * GPL HEADER START - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 only, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License version 2 for more details (a copy is included - * in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; If not, see - * http://www.gnu.org/licenses/gpl-2.0.html - * - * GPL HEADER END - */ -/* - * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. - * Use is subject to license terms. - */ -/* - * This file is part of Lustre, http://www.lustre.org/ - * Lustre is a trademark of Sun Microsystems, Inc. - * - * Implementation of cl_io for LOVSUB layer. - * - * Author: Nikita Danilov <nikita.danilov@sun.com> - */ - -#define DEBUG_SUBSYSTEM S_LOV - -#include "lov_cl_internal.h" - -/** \addtogroup lov - * @{ - */ - -/***************************************************************************** - * - * Lovsub io operations. - * - */ - -/* All trivial */ - -/** @} lov */ diff --git a/drivers/staging/lustre/lustre/lov/lovsub_lock.c b/drivers/staging/lustre/lustre/lov/lovsub_lock.c index 38f9b735c241..d29f0bb33980 100644 --- a/drivers/staging/lustre/lustre/lov/lovsub_lock.c +++ b/drivers/staging/lustre/lustre/lov/lovsub_lock.c @@ -54,7 +54,6 @@ static void lovsub_lock_fini(const struct lu_env *env, struct lovsub_lock *lsl; lsl = cl2lovsub_lock(slice); - LASSERT(list_empty(&lsl->lss_parents)); kmem_cache_free(lovsub_lock_kmem, lsl); } @@ -70,7 +69,6 @@ int lovsub_lock_init(const struct lu_env *env, struct cl_object *obj, lsk = kmem_cache_zalloc(lovsub_lock_kmem, GFP_NOFS); if (lsk) { - INIT_LIST_HEAD(&lsk->lss_parents); cl_lock_slice_add(lock, &lsk->lss_cl, obj, &lovsub_lock_ops); result = 0; } else { diff --git a/drivers/staging/lustre/lustre/lov/lproc_lov.c b/drivers/staging/lustre/lustre/lov/lproc_lov.c index eb6d30d34e3a..9bb7e9ea0a6a 100644 --- a/drivers/staging/lustre/lustre/lov/lproc_lov.c +++ b/drivers/staging/lustre/lustre/lov/lproc_lov.c @@ -32,8 +32,8 @@ #define DEBUG_SUBSYSTEM S_CLASS #include <linux/statfs.h> -#include "../include/lprocfs_status.h" -#include "../include/obd_class.h" +#include <lprocfs_status.h> +#include <obd_class.h> #include <linux/seq_file.h> #include "lov_internal.h" @@ -279,7 +279,7 @@ static struct attribute *lov_attrs[] = { NULL, }; -static struct attribute_group lov_attr_group = { +static const struct attribute_group lov_attr_group = { .attrs = lov_attrs, }; diff --git a/drivers/staging/lustre/lustre/mdc/Makefile b/drivers/staging/lustre/lustre/mdc/Makefile index 99ba9ff0d83a..c7bc3351ccb0 100644 --- a/drivers/staging/lustre/lustre/mdc/Makefile +++ b/drivers/staging/lustre/lustre/mdc/Makefile @@ -1,2 +1,5 @@ +subdir-ccflags-y += -I$(srctree)/drivers/staging/lustre/include +subdir-ccflags-y += -I$(srctree)/drivers/staging/lustre/lustre/include + obj-$(CONFIG_LUSTRE_FS) += mdc.o mdc-y := mdc_request.o mdc_reint.o mdc_lib.o mdc_locks.o lproc_mdc.o diff --git a/drivers/staging/lustre/lustre/mdc/lproc_mdc.c b/drivers/staging/lustre/lustre/mdc/lproc_mdc.c index 9021c465c044..f68513771527 100644 --- a/drivers/staging/lustre/lustre/mdc/lproc_mdc.c +++ b/drivers/staging/lustre/lustre/mdc/lproc_mdc.c @@ -32,8 +32,8 @@ #define DEBUG_SUBSYSTEM S_CLASS #include <linux/vfs.h> -#include "../include/obd_class.h" -#include "../include/lprocfs_status.h" +#include <obd_class.h> +#include <lprocfs_status.h> #include "mdc_internal.h" static ssize_t active_show(struct kobject *kobj, struct attribute *attr, @@ -57,7 +57,7 @@ static ssize_t active_store(struct kobject *kobj, struct attribute *attr, if (rc) return rc; - if (val < 0 || val > 1) + if (val > 1) return -ERANGE; /* opposite senses */ @@ -219,7 +219,7 @@ static struct attribute *mdc_attrs[] = { NULL, }; -static struct attribute_group mdc_attr_group = { +static const struct attribute_group mdc_attr_group = { .attrs = mdc_attrs, }; diff --git a/drivers/staging/lustre/lustre/mdc/mdc_internal.h b/drivers/staging/lustre/lustre/mdc/mdc_internal.h index fecedc8819ed..cbf011501005 100644 --- a/drivers/staging/lustre/lustre/mdc/mdc_internal.h +++ b/drivers/staging/lustre/lustre/mdc/mdc_internal.h @@ -33,7 +33,7 @@ #ifndef _MDC_INTERNAL_H #define _MDC_INTERNAL_H -#include "../include/lustre_mdc.h" +#include <lustre_mdc.h> void lprocfs_mdc_init_vars(struct lprocfs_static_vars *lvars); diff --git a/drivers/staging/lustre/lustre/mdc/mdc_lib.c b/drivers/staging/lustre/lustre/mdc/mdc_lib.c index b1853ff7f8b9..ba13f0894e0d 100644 --- a/drivers/staging/lustre/lustre/mdc/mdc_lib.c +++ b/drivers/staging/lustre/lustre/mdc/mdc_lib.c @@ -31,10 +31,16 @@ */ #define DEBUG_SUBSYSTEM S_MDC -#include "../include/lustre_net.h" -#include "../include/lustre/lustre_idl.h" +#include <lustre_net.h> +#include <uapi/linux/lustre/lustre_idl.h> #include "mdc_internal.h" +static void set_mrc_cr_flags(struct mdt_rec_create *mrc, u64 flags) +{ + mrc->cr_flags_l = (u32)(flags & 0xFFFFFFFFUll); + mrc->cr_flags_h = (u32)(flags >> 32); +} + static void __mdc_pack_body(struct mdt_body *b, __u32 suppgid) { b->mbo_suppgid = suppgid; diff --git a/drivers/staging/lustre/lustre/mdc/mdc_locks.c b/drivers/staging/lustre/lustre/mdc/mdc_locks.c index 3eb66cea65db..cbfea3dd0319 100644 --- a/drivers/staging/lustre/lustre/mdc/mdc_locks.c +++ b/drivers/staging/lustre/lustre/mdc/mdc_locks.c @@ -32,17 +32,17 @@ #define DEBUG_SUBSYSTEM S_MDC -# include <linux/module.h> - -#include "../include/lustre_intent.h" -#include "../include/obd.h" -#include "../include/obd_class.h" -#include "../include/lustre_dlm.h" -#include "../include/lustre_fid.h" -#include "../include/lustre_mdc.h" -#include "../include/lustre_net.h" -#include "../include/lustre_req_layout.h" -#include "../include/lustre_swab.h" +#include <linux/module.h> + +#include <lustre_intent.h> +#include <obd.h> +#include <obd_class.h> +#include <lustre_dlm.h> +#include <lustre_fid.h> +#include <lustre_mdc.h> +#include <lustre_net.h> +#include <lustre_req_layout.h> +#include <lustre_swab.h> #include "mdc_internal.h" @@ -1030,7 +1030,7 @@ int mdc_revalidate_lock(struct obd_export *exp, struct lookup_intent *it, * If we're performing a creation, that means that unless the creation * failed with EEXIST, we should fake up a negative dentry. * - * For everything else, we want to lookup to succeed. + * For everything else, we want the lookup to succeed. * * One additional note: if CREATE or OPEN succeeded, we add an extra * reference to the request because we need to keep it around until @@ -1040,7 +1040,7 @@ int mdc_revalidate_lock(struct obd_export *exp, struct lookup_intent *it, * exactly what it_status refers to. * * If DISP_OPEN_OPEN is set, then it_status refers to the open() call, - * otherwise if DISP_OPEN_CREATE is set, then it status is the + * otherwise if DISP_OPEN_CREATE is set, then it_status is the * creation failure mode. In either case, one of DISP_LOOKUP_NEG or * DISP_LOOKUP_POS will be set, indicating whether the child lookup * was successful. diff --git a/drivers/staging/lustre/lustre/mdc/mdc_reint.c b/drivers/staging/lustre/lustre/mdc/mdc_reint.c index 2287bd46d527..f45c91d1b4ae 100644 --- a/drivers/staging/lustre/lustre/mdc/mdc_reint.c +++ b/drivers/staging/lustre/lustre/mdc/mdc_reint.c @@ -35,9 +35,9 @@ # include <linux/module.h> # include <linux/kernel.h> -#include "../include/obd_class.h" +#include <obd_class.h> #include "mdc_internal.h" -#include "../include/lustre_fid.h" +#include <lustre_fid.h> /* mdc_setattr does its own semaphore handling */ static int mdc_reint(struct ptlrpc_request *request, int level) diff --git a/drivers/staging/lustre/lustre/mdc/mdc_request.c b/drivers/staging/lustre/lustre/mdc/mdc_request.c index 1a3fa1bb7f25..6ef8ddec4ab6 100644 --- a/drivers/staging/lustre/lustre/mdc/mdc_request.c +++ b/drivers/staging/lustre/lustre/mdc/mdc_request.c @@ -38,18 +38,19 @@ # include <linux/init.h> # include <linux/utsname.h> -#include "../include/cl_object.h" -#include "../include/llog_swab.h" -#include "../include/lprocfs_status.h" -#include "../include/lustre_acl.h" -#include "../include/lustre_fid.h" -#include "../include/lustre/lustre_ioctl.h" -#include "../include/lustre_kernelcomm.h" -#include "../include/lustre_lmv.h" -#include "../include/lustre_log.h" -#include "../include/lustre_param.h" -#include "../include/lustre_swab.h" -#include "../include/obd_class.h" +#include <lustre_errno.h> +#include <cl_object.h> +#include <llog_swab.h> +#include <lprocfs_status.h> +#include <lustre_acl.h> +#include <lustre_fid.h> +#include <uapi/linux/lustre/lustre_ioctl.h> +#include <lustre_kernelcomm.h> +#include <lustre_lmv.h> +#include <lustre_log.h> +#include <uapi/linux/lustre/lustre_param.h> +#include <lustre_swab.h> +#include <obd_class.h> #include "mdc_internal.h" diff --git a/drivers/staging/lustre/lustre/mgc/Makefile b/drivers/staging/lustre/lustre/mgc/Makefile index 8ea29a89cf50..8abf108dbcf7 100644 --- a/drivers/staging/lustre/lustre/mgc/Makefile +++ b/drivers/staging/lustre/lustre/mgc/Makefile @@ -1,2 +1,5 @@ +subdir-ccflags-y += -I$(srctree)/drivers/staging/lustre/include +subdir-ccflags-y += -I$(srctree)/drivers/staging/lustre/lustre/include + obj-$(CONFIG_LUSTRE_FS) += mgc.o mgc-y := mgc_request.o lproc_mgc.o diff --git a/drivers/staging/lustre/lustre/mgc/lproc_mgc.c b/drivers/staging/lustre/lustre/mgc/lproc_mgc.c index 0735220b2a18..2ec2d7f731d3 100644 --- a/drivers/staging/lustre/lustre/mgc/lproc_mgc.c +++ b/drivers/staging/lustre/lustre/mgc/lproc_mgc.c @@ -32,8 +32,8 @@ #define DEBUG_SUBSYSTEM S_CLASS #include <linux/vfs.h> -#include "../include/obd_class.h" -#include "../include/lprocfs_status.h" +#include <obd_class.h> +#include <lprocfs_status.h> #include "mgc_internal.h" LPROC_SEQ_FOPS_RO_TYPE(mgc, connect_flags); diff --git a/drivers/staging/lustre/lustre/mgc/mgc_internal.h b/drivers/staging/lustre/lustre/mgc/mgc_internal.h index f146f7521c92..7a2f2b7bc6b1 100644 --- a/drivers/staging/lustre/lustre/mgc/mgc_internal.h +++ b/drivers/staging/lustre/lustre/mgc/mgc_internal.h @@ -33,12 +33,11 @@ #ifndef _MGC_INTERNAL_H #define _MGC_INTERNAL_H -#include "../../include/linux/libcfs/libcfs.h" -#include "../include/lustre/lustre_idl.h" -#include "../include/lustre_lib.h" -#include "../include/lustre_dlm.h" -#include "../include/lustre_log.h" -#include "../include/lustre_export.h" +#include <linux/libcfs/libcfs.h> +#include <lustre_lib.h> +#include <lustre_dlm.h> +#include <lustre_log.h> +#include <lustre_export.h> void lprocfs_mgc_init_vars(struct lprocfs_static_vars *lvars); int lprocfs_mgc_rd_ir_state(struct seq_file *m, void *data); diff --git a/drivers/staging/lustre/lustre/mgc/mgc_request.c b/drivers/staging/lustre/lustre/mgc/mgc_request.c index eee0b667a33c..3d2b969c90a7 100644 --- a/drivers/staging/lustre/lustre/mgc/mgc_request.c +++ b/drivers/staging/lustre/lustre/mgc/mgc_request.c @@ -39,12 +39,12 @@ #include <linux/module.h> -#include "../include/lprocfs_status.h" -#include "../include/lustre_dlm.h" -#include "../include/lustre_disk.h" -#include "../include/lustre_log.h" -#include "../include/lustre_swab.h" -#include "../include/obd_class.h" +#include <lprocfs_status.h> +#include <lustre_dlm.h> +#include <lustre_disk.h> +#include <lustre_log.h> +#include <lustre_swab.h> +#include <obd_class.h> #include "mgc_internal.h" @@ -288,7 +288,7 @@ config_log_add(struct obd_device *obd, char *logname, struct config_llog_data *cld; struct config_llog_data *sptlrpc_cld; struct config_llog_data *params_cld; - bool locked = false; + struct config_llog_data *recover_cld = NULL; char seclogname[32]; char *ptr; int rc; @@ -333,20 +333,14 @@ config_log_add(struct obd_device *obd, char *logname, goto out_params; } - cld->cld_sptlrpc = sptlrpc_cld; - cld->cld_params = params_cld; - LASSERT(lsi->lsi_lmd); if (!(lsi->lsi_lmd->lmd_flags & LMD_FLG_NOIR)) { - struct config_llog_data *recover_cld; - ptr = strrchr(seclogname, '-'); if (ptr) { *ptr = 0; } else { CERROR("%s: sptlrpc log name not correct, %s: rc = %d\n", obd->obd_name, seclogname, -EINVAL); - config_log_put(cld); rc = -EINVAL; goto out_cld; } @@ -355,14 +349,10 @@ config_log_add(struct obd_device *obd, char *logname, rc = PTR_ERR(recover_cld); goto out_cld; } - - mutex_lock(&cld->cld_lock); - locked = true; - cld->cld_recover = recover_cld; } - if (!locked) - mutex_lock(&cld->cld_lock); + mutex_lock(&cld->cld_lock); + cld->cld_recover = recover_cld; cld->cld_params = params_cld; cld->cld_sptlrpc = sptlrpc_cld; mutex_unlock(&cld->cld_lock); @@ -1165,6 +1155,7 @@ static int mgc_apply_recover_logs(struct obd_device *mgc, char *cname; char *params; char *uuid; + size_t len; rc = -EINVAL; if (datalen < sizeof(*entry)) @@ -1293,17 +1284,19 @@ static int mgc_apply_recover_logs(struct obd_device *mgc, lustre_cfg_bufs_set_string(&bufs, 1, params); rc = -ENOMEM; - lcfg = lustre_cfg_new(LCFG_PARAM, &bufs); - if (IS_ERR(lcfg)) { - CERROR("mgc: cannot allocate memory\n"); + len = lustre_cfg_len(bufs.lcfg_bufcount, bufs.lcfg_buflen); + lcfg = kzalloc(len, GFP_NOFS); + if (!lcfg) { + rc = -ENOMEM; break; } + lustre_cfg_init(lcfg, LCFG_PARAM, &bufs); CDEBUG(D_INFO, "ir apply logs %lld/%lld for %s -> %s\n", prev_version, max_version, obdname, params); rc = class_process_config(lcfg); - lustre_cfg_free(lcfg); + kfree(lcfg); if (rc) CDEBUG(D_INFO, "process config for %s error %d\n", obdname, rc); diff --git a/drivers/staging/lustre/lustre/obdclass/Makefile b/drivers/staging/lustre/lustre/obdclass/Makefile index af570c0db15b..fa0ad6548ecd 100644 --- a/drivers/staging/lustre/lustre/obdclass/Makefile +++ b/drivers/staging/lustre/lustre/obdclass/Makefile @@ -1,3 +1,6 @@ +subdir-ccflags-y += -I$(srctree)/drivers/staging/lustre/include +subdir-ccflags-y += -I$(srctree)/drivers/staging/lustre/lustre/include + obj-$(CONFIG_LUSTRE_FS) += obdclass.o obdclass-y := linux/linux-module.o linux/linux-sysctl.o \ diff --git a/drivers/staging/lustre/lustre/obdclass/cl_io.c b/drivers/staging/lustre/lustre/obdclass/cl_io.c index ee7d67761191..2a70e21ae07f 100644 --- a/drivers/staging/lustre/lustre/obdclass/cl_io.c +++ b/drivers/staging/lustre/lustre/obdclass/cl_io.c @@ -37,12 +37,12 @@ #define DEBUG_SUBSYSTEM S_CLASS -#include "../include/obd_class.h" -#include "../include/obd_support.h" -#include "../include/lustre_fid.h" +#include <obd_class.h> +#include <obd_support.h> +#include <lustre_fid.h> #include <linux/list.h> #include <linux/sched.h> -#include "../include/cl_object.h" +#include <cl_object.h> #include "cl_internal.h" /***************************************************************************** diff --git a/drivers/staging/lustre/lustre/obdclass/cl_lock.c b/drivers/staging/lustre/lustre/obdclass/cl_lock.c index a343e3ab2257..20e64051d2d6 100644 --- a/drivers/staging/lustre/lustre/obdclass/cl_lock.c +++ b/drivers/staging/lustre/lustre/obdclass/cl_lock.c @@ -37,11 +37,11 @@ #define DEBUG_SUBSYSTEM S_CLASS -#include "../include/obd_class.h" -#include "../include/obd_support.h" -#include "../include/lustre_fid.h" +#include <obd_class.h> +#include <obd_support.h> +#include <lustre_fid.h> #include <linux/list.h> -#include "../include/cl_object.h" +#include <cl_object.h> #include "cl_internal.h" static void cl_lock_trace0(int level, const struct lu_env *env, diff --git a/drivers/staging/lustre/lustre/obdclass/cl_object.c b/drivers/staging/lustre/lustre/obdclass/cl_object.c index 08e55d418537..95c7fa3b532c 100644 --- a/drivers/staging/lustre/lustre/obdclass/cl_object.c +++ b/drivers/staging/lustre/lustre/obdclass/cl_object.c @@ -46,15 +46,15 @@ #define DEBUG_SUBSYSTEM S_CLASS -#include "../../include/linux/libcfs/libcfs.h" +#include <linux/libcfs/libcfs.h> /* class_put_type() */ -#include "../include/obd_class.h" -#include "../include/obd_support.h" -#include "../include/lustre_fid.h" +#include <obd_class.h> +#include <obd_support.h> +#include <lustre_fid.h> #include <linux/list.h> -#include "../../include/linux/libcfs/libcfs_hash.h" /* for cfs_hash stuff */ -#include "../include/cl_object.h" -#include "../include/lu_object.h" +#include <linux/libcfs/libcfs_hash.h> /* for cfs_hash stuff */ +#include <cl_object.h> +#include <lu_object.h> #include "cl_internal.h" static struct kmem_cache *cl_env_kmem; diff --git a/drivers/staging/lustre/lustre/obdclass/cl_page.c b/drivers/staging/lustre/lustre/obdclass/cl_page.c index 6b8c41b6f379..3dc084cb93bc 100644 --- a/drivers/staging/lustre/lustre/obdclass/cl_page.c +++ b/drivers/staging/lustre/lustre/obdclass/cl_page.c @@ -37,12 +37,12 @@ #define DEBUG_SUBSYSTEM S_CLASS -#include "../../include/linux/libcfs/libcfs.h" -#include "../include/obd_class.h" -#include "../include/obd_support.h" +#include <linux/libcfs/libcfs.h> +#include <obd_class.h> +#include <obd_support.h> #include <linux/list.h> -#include "../include/cl_object.h" +#include <cl_object.h> #include "cl_internal.h" static void cl_page_delete0(const struct lu_env *env, struct cl_page *pg); diff --git a/drivers/staging/lustre/lustre/obdclass/class_obd.c b/drivers/staging/lustre/lustre/obdclass/class_obd.c index 76e1ee83a723..2df218b010e1 100644 --- a/drivers/staging/lustre/lustre/obdclass/class_obd.c +++ b/drivers/staging/lustre/lustre/obdclass/class_obd.c @@ -33,14 +33,14 @@ #define DEBUG_SUBSYSTEM S_CLASS # include <linux/atomic.h> -#include "../include/obd_support.h" -#include "../include/obd_class.h" -#include "../../include/linux/lnet/lnetctl.h" -#include "../include/lustre_debug.h" -#include "../include/lprocfs_status.h" +#include <obd_support.h> +#include <obd_class.h> +#include <uapi/linux/lnet/lnetctl.h> +#include <lustre_debug.h> +#include <lprocfs_status.h> #include <linux/list.h> -#include "../include/cl_object.h" -#include "../include/lustre/lustre_ioctl.h" +#include <cl_object.h> +#include <uapi/linux/lustre/lustre_ioctl.h> #include "llog_internal.h" struct obd_device *obd_devs[MAX_OBD_DEVICES]; @@ -180,7 +180,8 @@ int class_handle_ioctl(unsigned int cmd, unsigned long arg) err = -ENOMEM; goto out; } - err = copy_from_user(lcfg, data->ioc_pbuf1, data->ioc_plen1); + if (copy_from_user(lcfg, data->ioc_pbuf1, data->ioc_plen1)) + err = -EFAULT; if (!err) err = lustre_cfg_sanity_check(lcfg, data->ioc_plen1); if (!err) @@ -206,8 +207,7 @@ int class_handle_ioctl(unsigned int cmd, unsigned long arg) memcpy(data->ioc_bulk, LUSTRE_VERSION_STRING, strlen(LUSTRE_VERSION_STRING) + 1); - err = obd_ioctl_popdata((void __user *)arg, data, len); - if (err) + if (copy_to_user((void __user *)arg, data, len)) err = -EFAULT; goto out; @@ -225,9 +225,7 @@ int class_handle_ioctl(unsigned int cmd, unsigned long arg) goto out; } - err = obd_ioctl_popdata((void __user *)arg, data, - sizeof(*data)); - if (err) + if (copy_to_user((void __user *)arg, data, sizeof(*data))) err = -EFAULT; goto out; } @@ -263,9 +261,8 @@ int class_handle_ioctl(unsigned int cmd, unsigned long arg) CDEBUG(D_IOCTL, "device name %s, dev %d\n", data->ioc_inlbuf1, dev); - err = obd_ioctl_popdata((void __user *)arg, data, - sizeof(*data)); - if (err) + + if (copy_to_user((void __user *)arg, data, sizeof(*data))) err = -EFAULT; goto out; } @@ -304,9 +301,9 @@ int class_handle_ioctl(unsigned int cmd, unsigned long arg) (int)index, status, obd->obd_type->typ_name, obd->obd_name, obd->obd_uuid.uuid, atomic_read(&obd->obd_refcount)); - err = obd_ioctl_popdata((void __user *)arg, data, len); - err = 0; + if (copy_to_user((void __user *)arg, data, len)) + err = -EFAULT; goto out; } } @@ -361,16 +358,14 @@ int class_handle_ioctl(unsigned int cmd, unsigned long arg) if (err) goto out; - err = obd_ioctl_popdata((void __user *)arg, data, len); - if (err) + if (copy_to_user((void __user *)arg, data, len)) err = -EFAULT; goto out; } } out: - if (buf) - obd_ioctl_freedata(buf, len); + kvfree(buf); return err; } /* class_handle_ioctl */ @@ -453,7 +448,7 @@ static int __init obdclass_init(void) obd_zombie_impexp_init(); err = obd_init_checks(); - if (err == -EOVERFLOW) + if (err) return err; class_init_uuidlist(); diff --git a/drivers/staging/lustre/lustre/obdclass/debug.c b/drivers/staging/lustre/lustre/obdclass/debug.c index 0bd4ad20aba7..7964cad7e780 100644 --- a/drivers/staging/lustre/lustre/obdclass/debug.c +++ b/drivers/staging/lustre/lustre/obdclass/debug.c @@ -38,9 +38,9 @@ #include <asm/unaligned.h> -#include "../include/obd_support.h" -#include "../include/lustre_debug.h" -#include "../include/lustre_net.h" +#include <obd_support.h> +#include <lustre_debug.h> +#include <lustre_net.h> #define LPDS sizeof(__u64) int block_debug_setup(void *addr, int len, __u64 off, __u64 id) diff --git a/drivers/staging/lustre/lustre/obdclass/genops.c b/drivers/staging/lustre/lustre/obdclass/genops.c index fa0d38ddccb2..739bfb9421ca 100644 --- a/drivers/staging/lustre/lustre/obdclass/genops.c +++ b/drivers/staging/lustre/lustre/obdclass/genops.c @@ -36,9 +36,9 @@ */ #define DEBUG_SUBSYSTEM S_CLASS -#include "../include/obd_class.h" -#include "../include/lprocfs_status.h" -#include "../include/lustre_kernelcomm.h" +#include <obd_class.h> +#include <lprocfs_status.h> +#include <lustre_kernelcomm.h> spinlock_t obd_types_lock; diff --git a/drivers/staging/lustre/lustre/obdclass/kernelcomm.c b/drivers/staging/lustre/lustre/obdclass/kernelcomm.c index a0f65c470f4d..4f0a42633d5a 100644 --- a/drivers/staging/lustre/lustre/obdclass/kernelcomm.c +++ b/drivers/staging/lustre/lustre/obdclass/kernelcomm.c @@ -38,8 +38,8 @@ #define DEBUG_SUBSYSTEM S_CLASS #define D_KUC D_OTHER -#include "../include/obd_support.h" -#include "../include/lustre_kernelcomm.h" +#include <obd_support.h> +#include <lustre_kernelcomm.h> /** * libcfs_kkuc_msg_put - send an message from kernel to userspace @@ -52,7 +52,6 @@ int libcfs_kkuc_msg_put(struct file *filp, void *payload) struct kuc_hdr *kuch = (struct kuc_hdr *)payload; ssize_t count = kuch->kuc_msglen; loff_t offset = 0; - mm_segment_t fs; int rc = -ENXIO; if (IS_ERR_OR_NULL(filp)) @@ -63,18 +62,14 @@ int libcfs_kkuc_msg_put(struct file *filp, void *payload) return rc; } - fs = get_fs(); - set_fs(KERNEL_DS); while (count > 0) { - rc = vfs_write(filp, (void __force __user *)payload, - count, &offset); + rc = kernel_write(filp, payload, count, &offset); if (rc < 0) break; count -= rc; payload += rc; rc = 0; } - set_fs(fs); if (rc < 0) CWARN("message send failed (%d)\n", rc); diff --git a/drivers/staging/lustre/lustre/obdclass/linkea.c b/drivers/staging/lustre/lustre/obdclass/linkea.c index 0b1d2f0a422c..9af86d3d56e4 100644 --- a/drivers/staging/lustre/lustre/obdclass/linkea.c +++ b/drivers/staging/lustre/lustre/obdclass/linkea.c @@ -26,9 +26,9 @@ * Author: Di Wang <di.wang@intel.com> */ -#include "../include/lustre/lustre_idl.h" -#include "../include/obd.h" -#include "../include/lustre_linkea.h" +#include <uapi/linux/lustre/lustre_idl.h> +#include <obd.h> +#include <lustre_linkea.h> int linkea_data_new(struct linkea_data *ldata, struct lu_buf *buf) { @@ -39,6 +39,8 @@ int linkea_data_new(struct linkea_data *ldata, struct lu_buf *buf) ldata->ld_leh->leh_magic = LINK_EA_MAGIC; ldata->ld_leh->leh_len = sizeof(struct link_ea_header); ldata->ld_leh->leh_reccount = 0; + ldata->ld_leh->leh_overflow_time = 0; + ldata->ld_leh->leh_padding = 0; return 0; } EXPORT_SYMBOL(linkea_data_new); @@ -53,11 +55,15 @@ int linkea_init(struct linkea_data *ldata) leh->leh_magic = LINK_EA_MAGIC; leh->leh_reccount = __swab32(leh->leh_reccount); leh->leh_len = __swab64(leh->leh_len); - /* entries are swabbed by linkea_entry_unpack */ + leh->leh_overflow_time = __swab32(leh->leh_overflow_time); + leh->leh_padding = __swab32(leh->leh_padding); + /* individual entries are swabbed by linkea_entry_unpack() */ } + if (leh->leh_magic != LINK_EA_MAGIC) return -EINVAL; - if (leh->leh_reccount == 0) + + if (leh->leh_reccount == 0 && leh->leh_overflow_time == 0) return -ENODATA; ldata->ld_leh = leh; @@ -65,6 +71,18 @@ int linkea_init(struct linkea_data *ldata) } EXPORT_SYMBOL(linkea_init); +int linkea_init_with_rec(struct linkea_data *ldata) +{ + int rc; + + rc = linkea_init(ldata); + if (!rc && ldata->ld_leh->leh_reccount == 0) + rc = -ENODATA; + + return rc; +} +EXPORT_SYMBOL(linkea_init_with_rec); + /** * Pack a link_ea_entry. * All elements are stored as chars to avoid alignment issues. @@ -94,6 +112,8 @@ EXPORT_SYMBOL(linkea_entry_pack); void linkea_entry_unpack(const struct link_ea_entry *lee, int *reclen, struct lu_name *lname, struct lu_fid *pfid) { + LASSERT(lee); + *reclen = (lee->lee_reclen[0] << 8) | lee->lee_reclen[1]; memcpy(pfid, &lee->lee_parent_fid, sizeof(*pfid)); fid_be_to_cpu(pfid, pfid); @@ -110,25 +130,44 @@ EXPORT_SYMBOL(linkea_entry_unpack); int linkea_add_buf(struct linkea_data *ldata, const struct lu_name *lname, const struct lu_fid *pfid) { - LASSERT(ldata->ld_leh); + struct link_ea_header *leh = ldata->ld_leh; + int reclen; + + LASSERT(leh); if (!lname || !pfid) return -EINVAL; - ldata->ld_reclen = lname->ln_namelen + sizeof(struct link_ea_entry); - if (ldata->ld_leh->leh_len + ldata->ld_reclen > - ldata->ld_buf->lb_len) { + reclen = lname->ln_namelen + sizeof(struct link_ea_entry); + if (unlikely(leh->leh_len + reclen > MAX_LINKEA_SIZE)) { + /* + * Use 32-bits to save the overflow time, although it will + * shrink the ktime_get_real_seconds() returned 64-bits value + * to 32-bits value, it is still quite large and can be used + * for about 140 years. That is enough. + */ + leh->leh_overflow_time = ktime_get_real_seconds(); + if (unlikely(leh->leh_overflow_time == 0)) + leh->leh_overflow_time++; + + CDEBUG(D_INODE, "No enough space to hold linkea entry '" DFID ": %.*s' at %u\n", + PFID(pfid), lname->ln_namelen, + lname->ln_name, leh->leh_overflow_time); + return 0; + } + + if (leh->leh_len + reclen > ldata->ld_buf->lb_len) { if (lu_buf_check_and_grow(ldata->ld_buf, - ldata->ld_leh->leh_len + - ldata->ld_reclen) < 0) + leh->leh_len + reclen) < 0) return -ENOMEM; + + leh = ldata->ld_leh = ldata->ld_buf->lb_buf; } - ldata->ld_leh = ldata->ld_buf->lb_buf; - ldata->ld_lee = ldata->ld_buf->lb_buf + ldata->ld_leh->leh_len; + ldata->ld_lee = ldata->ld_buf->lb_buf + leh->leh_len; ldata->ld_reclen = linkea_entry_pack(ldata->ld_lee, lname, pfid); - ldata->ld_leh->leh_len += ldata->ld_reclen; - ldata->ld_leh->leh_reccount++; + leh->leh_len += ldata->ld_reclen; + leh->leh_reccount++; CDEBUG(D_INODE, "New link_ea name '" DFID ":%.*s' is added\n", PFID(pfid), lname->ln_namelen, lname->ln_name); return 0; @@ -139,6 +178,7 @@ EXPORT_SYMBOL(linkea_add_buf); void linkea_del_buf(struct linkea_data *ldata, const struct lu_name *lname) { LASSERT(ldata->ld_leh && ldata->ld_lee); + LASSERT(ldata->ld_leh->leh_reccount > 0); ldata->ld_leh->leh_reccount--; ldata->ld_leh->leh_len -= ldata->ld_reclen; @@ -174,8 +214,9 @@ int linkea_links_find(struct linkea_data *ldata, const struct lu_name *lname, LASSERT(ldata->ld_leh); - /* link #0 */ - ldata->ld_lee = (struct link_ea_entry *)(ldata->ld_leh + 1); + /* link #0, if leh_reccount == 0 we skip the loop and return -ENOENT */ + if (likely(ldata->ld_leh->leh_reccount > 0)) + ldata->ld_lee = (struct link_ea_entry *)(ldata->ld_leh + 1); for (count = 0; count < ldata->ld_leh->leh_reccount; count++) { linkea_entry_unpack(ldata->ld_lee, &ldata->ld_reclen, diff --git a/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c b/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c index 9f5e8299d7e4..6df911112731 100644 --- a/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c +++ b/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c @@ -60,13 +60,91 @@ #include <linux/seq_file.h> #include <linux/kobject.h> -#include "../../../include/linux/libcfs/libcfs.h" -#include "../../../include/linux/lnet/lnetctl.h" -#include "../../include/obd_support.h" -#include "../../include/obd_class.h" -#include "../../include/lprocfs_status.h" -#include "../../include/lustre/lustre_ioctl.h" -#include "../../include/lustre_ver.h" +#include <linux/libcfs/libcfs.h> +#include <uapi/linux/lnet/lnetctl.h> +#include <obd_support.h> +#include <obd_class.h> +#include <lprocfs_status.h> +#include <uapi/linux/lustre/lustre_ioctl.h> +#include <uapi/linux/lustre/lustre_ver.h> + +#define OBD_MAX_IOCTL_BUFFER 8192 + +static int obd_ioctl_is_invalid(struct obd_ioctl_data *data) +{ + if (data->ioc_len > BIT(30)) { + CERROR("OBD ioctl: ioc_len larger than 1<<30\n"); + return 1; + } + + if (data->ioc_inllen1 > BIT(30)) { + CERROR("OBD ioctl: ioc_inllen1 larger than 1<<30\n"); + return 1; + } + + if (data->ioc_inllen2 > BIT(30)) { + CERROR("OBD ioctl: ioc_inllen2 larger than 1<<30\n"); + return 1; + } + + if (data->ioc_inllen3 > BIT(30)) { + CERROR("OBD ioctl: ioc_inllen3 larger than 1<<30\n"); + return 1; + } + + if (data->ioc_inllen4 > BIT(30)) { + CERROR("OBD ioctl: ioc_inllen4 larger than 1<<30\n"); + return 1; + } + + if (data->ioc_inlbuf1 && data->ioc_inllen1 == 0) { + CERROR("OBD ioctl: inlbuf1 pointer but 0 length\n"); + return 1; + } + + if (data->ioc_inlbuf2 && data->ioc_inllen2 == 0) { + CERROR("OBD ioctl: inlbuf2 pointer but 0 length\n"); + return 1; + } + + if (data->ioc_inlbuf3 && data->ioc_inllen3 == 0) { + CERROR("OBD ioctl: inlbuf3 pointer but 0 length\n"); + return 1; + } + + if (data->ioc_inlbuf4 && data->ioc_inllen4 == 0) { + CERROR("OBD ioctl: inlbuf4 pointer but 0 length\n"); + return 1; + } + + if (data->ioc_pbuf1 && data->ioc_plen1 == 0) { + CERROR("OBD ioctl: pbuf1 pointer but 0 length\n"); + return 1; + } + + if (data->ioc_pbuf2 && data->ioc_plen2 == 0) { + CERROR("OBD ioctl: pbuf2 pointer but 0 length\n"); + return 1; + } + + if (!data->ioc_pbuf1 && data->ioc_plen1 != 0) { + CERROR("OBD ioctl: plen1 set but NULL pointer\n"); + return 1; + } + + if (!data->ioc_pbuf2 && data->ioc_plen2 != 0) { + CERROR("OBD ioctl: plen2 set but NULL pointer\n"); + return 1; + } + + if (obd_ioctl_packlen(data) > data->ioc_len) { + CERROR("OBD ioctl: packlen exceeds ioc_len (%d > %d)\n", + obd_ioctl_packlen(data), data->ioc_len); + return 1; + } + + return 0; +} /* buffer MUST be at least the size of obd_ioctl_hdr */ int obd_ioctl_getdata(char **buf, int *len, void __user *arg) @@ -151,14 +229,6 @@ free_buf: } EXPORT_SYMBOL(obd_ioctl_getdata); -int obd_ioctl_popdata(void __user *arg, void *data, int len) -{ - int err; - - err = copy_to_user(arg, data, len) ? -EFAULT : 0; - return err; -} - /* opening /dev/obd */ static int obd_class_open(struct inode *inode, struct file *file) { @@ -405,7 +475,7 @@ static const struct file_operations obd_device_list_fops = { struct kobject *lustre_kobj; EXPORT_SYMBOL_GPL(lustre_kobj); -static struct attribute_group lustre_attr_group = { +static const struct attribute_group lustre_attr_group = { .attrs = lustre_attrs, }; diff --git a/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c b/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c index e6c785afceba..e92cccceefa1 100644 --- a/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c +++ b/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c @@ -43,9 +43,9 @@ #define DEBUG_SUBSYSTEM S_CLASS -#include "../../include/obd_support.h" -#include "../../include/lprocfs_status.h" -#include "../../include/obd_class.h" +#include <obd_support.h> +#include <lprocfs_status.h> +#include <obd_class.h> struct static_lustre_uintvalue_attr { struct { @@ -151,7 +151,7 @@ static struct attribute *lustre_attrs[] = { NULL, }; -static struct attribute_group lustre_attr_group = { +static const struct attribute_group lustre_attr_group = { .attrs = lustre_attrs, }; diff --git a/drivers/staging/lustre/lustre/obdclass/llog.c b/drivers/staging/lustre/lustre/obdclass/llog.c index 736ea1067c93..98021a2d7238 100644 --- a/drivers/staging/lustre/lustre/obdclass/llog.c +++ b/drivers/staging/lustre/lustre/obdclass/llog.c @@ -43,9 +43,9 @@ #define DEBUG_SUBSYSTEM S_LOG -#include "../include/llog_swab.h" -#include "../include/lustre_log.h" -#include "../include/obd_class.h" +#include <llog_swab.h> +#include <lustre_log.h> +#include <obd_class.h> #include "llog_internal.h" /* diff --git a/drivers/staging/lustre/lustre/obdclass/llog_cat.c b/drivers/staging/lustre/lustre/obdclass/llog_cat.c index 8f1533c127a8..8fa969101650 100644 --- a/drivers/staging/lustre/lustre/obdclass/llog_cat.c +++ b/drivers/staging/lustre/lustre/obdclass/llog_cat.c @@ -44,7 +44,7 @@ #define DEBUG_SUBSYSTEM S_LOG -#include "../include/obd_class.h" +#include <obd_class.h> #include "llog_internal.h" diff --git a/drivers/staging/lustre/lustre/obdclass/llog_internal.h b/drivers/staging/lustre/lustre/obdclass/llog_internal.h index 21a93c73756a..8de90bc638b4 100644 --- a/drivers/staging/lustre/lustre/obdclass/llog_internal.h +++ b/drivers/staging/lustre/lustre/obdclass/llog_internal.h @@ -33,7 +33,7 @@ #ifndef __LLOG_INTERNAL_H__ #define __LLOG_INTERNAL_H__ -#include "../include/lustre_log.h" +#include <lustre_log.h> struct llog_process_info { struct llog_handle *lpi_loghandle; diff --git a/drivers/staging/lustre/lustre/obdclass/llog_obd.c b/drivers/staging/lustre/lustre/obdclass/llog_obd.c index 8574ad401f66..3c42de966077 100644 --- a/drivers/staging/lustre/lustre/obdclass/llog_obd.c +++ b/drivers/staging/lustre/lustre/obdclass/llog_obd.c @@ -32,8 +32,8 @@ #define DEBUG_SUBSYSTEM S_LOG -#include "../include/obd_class.h" -#include "../include/lustre_log.h" +#include <obd_class.h> +#include <lustre_log.h> #include "llog_internal.h" /* helper functions for calling the llog obd methods */ diff --git a/drivers/staging/lustre/lustre/obdclass/llog_swab.c b/drivers/staging/lustre/lustre/obdclass/llog_swab.c index 016046d26010..d2d3114ce008 100644 --- a/drivers/staging/lustre/lustre/obdclass/llog_swab.c +++ b/drivers/staging/lustre/lustre/obdclass/llog_swab.c @@ -38,8 +38,8 @@ #define DEBUG_SUBSYSTEM S_LOG -#include "../include/llog_swab.h" -#include "../include/lustre_log.h" +#include <llog_swab.h> +#include <lustre_log.h> static void print_llogd_body(struct llogd_body *d) { diff --git a/drivers/staging/lustre/lustre/obdclass/lprocfs_counters.c b/drivers/staging/lustre/lustre/obdclass/lprocfs_counters.c index 13aca5b93c6a..e4829880dc10 100644 --- a/drivers/staging/lustre/lustre/obdclass/lprocfs_counters.c +++ b/drivers/staging/lustre/lustre/obdclass/lprocfs_counters.c @@ -38,8 +38,8 @@ */ #include <linux/module.h> -#include "../include/lprocfs_status.h" -#include "../include/obd_support.h" +#include <lprocfs_status.h> +#include <obd_support.h> void lprocfs_counter_add(struct lprocfs_stats *stats, int idx, long amount) { diff --git a/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c b/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c index bc19f19d38d9..e79485b4bf7f 100644 --- a/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c +++ b/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c @@ -36,9 +36,9 @@ #define DEBUG_SUBSYSTEM S_CLASS -#include "../include/obd_class.h" -#include "../include/lprocfs_status.h" -#include "../include/lustre/lustre_idl.h" +#include <obd_class.h> +#include <lprocfs_status.h> +#include <uapi/linux/lustre/lustre_idl.h> #include <linux/seq_file.h> #include <linux/ctype.h> @@ -1031,7 +1031,7 @@ static struct kobj_type obd_ktype = { }; int lprocfs_obd_setup(struct obd_device *obd, struct lprocfs_vars *list, - struct attribute_group *attrs) + const struct attribute_group *attrs) { int rc = 0; diff --git a/drivers/staging/lustre/lustre/obdclass/lu_object.c b/drivers/staging/lustre/lustre/obdclass/lu_object.c index bb9d514525ce..09c98184a291 100644 --- a/drivers/staging/lustre/lustre/obdclass/lu_object.c +++ b/drivers/staging/lustre/lustre/obdclass/lu_object.c @@ -40,19 +40,19 @@ #define DEBUG_SUBSYSTEM S_CLASS -#include "../../include/linux/libcfs/libcfs.h" +#include <linux/libcfs/libcfs.h> -# include <linux/module.h> +#include <linux/module.h> /* hash_long() */ -#include "../../include/linux/libcfs/libcfs_hash.h" -#include "../include/obd_class.h" -#include "../include/obd_support.h" -#include "../include/lustre_disk.h" -#include "../include/lustre_fid.h" -#include "../include/lu_object.h" -#include "../include/cl_object.h" -#include "../include/lu_ref.h" +#include <linux/libcfs/libcfs_hash.h> +#include <obd_class.h> +#include <obd_support.h> +#include <lustre_disk.h> +#include <lustre_fid.h> +#include <lu_object.h> +#include <cl_object.h> +#include <lu_ref.h> #include <linux/list.h> enum { @@ -1409,9 +1409,9 @@ void lu_context_key_degister(struct lu_context_key *key) */ while (atomic_read(&key->lct_used) > 1) { spin_unlock(&lu_keys_guard); - CDEBUG(D_INFO, "lu_context_key_degister: \"%s\" %p, %d\n", - key->lct_owner ? key->lct_owner->name : "", key, - atomic_read(&key->lct_used)); + CDEBUG(D_INFO, "%s: \"%s\" %p, %d\n", + __func__, key->lct_owner ? key->lct_owner->name : "", + key, atomic_read(&key->lct_used)); schedule(); spin_lock(&lu_keys_guard); } @@ -1548,7 +1548,8 @@ void lu_context_key_quiesce(struct lu_context_key *key) */ while (atomic_read(&lu_key_initing_cnt) > 0) { spin_unlock(&lu_keys_guard); - CDEBUG(D_INFO, "lu_context_key_quiesce: \"%s\" %p, %d (%d)\n", + CDEBUG(D_INFO, "%s: \"%s\" %p, %d (%d)\n", + __func__, key->lct_owner ? key->lct_owner->name : "", key, atomic_read(&key->lct_used), atomic_read(&lu_key_initing_cnt)); diff --git a/drivers/staging/lustre/lustre/obdclass/lu_ref.c b/drivers/staging/lustre/lustre/obdclass/lu_ref.c index e9f6040d19eb..fa690b2bd643 100644 --- a/drivers/staging/lustre/lustre/obdclass/lu_ref.c +++ b/drivers/staging/lustre/lustre/obdclass/lu_ref.c @@ -38,9 +38,9 @@ #define DEBUG_SUBSYSTEM S_CLASS -#include "../../include/linux/libcfs/libcfs.h" +#include <linux/libcfs/libcfs.h> -#include "../include/obd.h" -#include "../include/obd_class.h" -#include "../include/obd_support.h" -#include "../include/lu_ref.h" +#include <obd.h> +#include <obd_class.h> +#include <obd_support.h> +#include <lu_ref.h> diff --git a/drivers/staging/lustre/lustre/obdclass/lustre_handles.c b/drivers/staging/lustre/lustre/obdclass/lustre_handles.c index c9445e5ec271..e1273c997b5f 100644 --- a/drivers/staging/lustre/lustre/obdclass/lustre_handles.c +++ b/drivers/staging/lustre/lustre/obdclass/lustre_handles.c @@ -36,9 +36,9 @@ #define DEBUG_SUBSYSTEM S_CLASS -#include "../include/obd_support.h" -#include "../include/lustre_handles.h" -#include "../include/lustre_lib.h" +#include <obd_support.h> +#include <lustre_handles.h> +#include <lustre_lib.h> static __u64 handle_base; #define HANDLE_INCR 7 diff --git a/drivers/staging/lustre/lustre/obdclass/lustre_peer.c b/drivers/staging/lustre/lustre/obdclass/lustre_peer.c index ffa740aa861c..2798d35ad318 100644 --- a/drivers/staging/lustre/lustre/obdclass/lustre_peer.c +++ b/drivers/staging/lustre/lustre/obdclass/lustre_peer.c @@ -32,13 +32,13 @@ #define DEBUG_SUBSYSTEM S_RPC -#include "../include/obd.h" -#include "../include/obd_support.h" -#include "../include/obd_class.h" -#include "../include/lustre_lib.h" -#include "../include/lustre_ha.h" -#include "../include/lustre_net.h" -#include "../include/lprocfs_status.h" +#include <obd.h> +#include <obd_support.h> +#include <obd_class.h> +#include <lustre_lib.h> +#include <lustre_ha.h> +#include <lustre_net.h> +#include <lprocfs_status.h> #define NIDS_MAX 32 diff --git a/drivers/staging/lustre/lustre/obdclass/obd_config.c b/drivers/staging/lustre/lustre/obdclass/obd_config.c index 6a7e7a7d2af1..94a940faca5d 100644 --- a/drivers/staging/lustre/lustre/obdclass/obd_config.c +++ b/drivers/staging/lustre/lustre/obdclass/obd_config.c @@ -38,12 +38,12 @@ #include <linux/string.h> -#include "../include/lustre/lustre_ioctl.h" -#include "../include/llog_swab.h" -#include "../include/lprocfs_status.h" -#include "../include/lustre_log.h" -#include "../include/lustre_param.h" -#include "../include/obd_class.h" +#include <uapi/linux/lustre/lustre_ioctl.h> +#include <llog_swab.h> +#include <lprocfs_status.h> +#include <lustre_log.h> +#include <uapi/linux/lustre/lustre_param.h> +#include <obd_class.h> #include "llog_internal.h" @@ -170,6 +170,40 @@ int class_parse_nid_quiet(char *buf, lnet_nid_t *nid, char **endh) } EXPORT_SYMBOL(class_parse_nid_quiet); +char *lustre_cfg_string(struct lustre_cfg *lcfg, u32 index) +{ + char *s; + + if (!lcfg->lcfg_buflens[index]) + return NULL; + + s = lustre_cfg_buf(lcfg, index); + if (!s) + return NULL; + + /* + * make sure it's NULL terminated, even if this kills a char + * of data. Try to use the padding first though. + */ + if (s[lcfg->lcfg_buflens[index] - 1] != '\0') { + size_t last = ALIGN(lcfg->lcfg_buflens[index], 8) - 1; + char lost; + + /* Use the smaller value */ + if (last > lcfg->lcfg_buflens[index]) + last = lcfg->lcfg_buflens[index]; + + lost = s[last]; + s[last] = '\0'; + if (lost != '\0') { + CWARN("Truncated buf %d to '%s' (lost '%c'...)\n", + index, s, lost); + } + } + return s; +} +EXPORT_SYMBOL(lustre_cfg_string); + /********************** class fns **********************/ /** @@ -1107,7 +1141,8 @@ int class_config_llog_handler(const struct lu_env *env, struct lustre_cfg_bufs bufs; char *inst_name = NULL; int inst_len = 0; - int inst = 0, swab = 0; + size_t lcfg_len; + int swab = 0; lcfg = (struct lustre_cfg *)cfg_buf; if (lcfg->lcfg_version == __swab32(LUSTRE_CFG_VERSION)) { @@ -1198,7 +1233,6 @@ int class_config_llog_handler(const struct lu_env *env, if (clli && clli->cfg_instance && LUSTRE_CFG_BUFLEN(lcfg, 0) > 0) { - inst = 1; inst_len = LUSTRE_CFG_BUFLEN(lcfg, 0) + sizeof(clli->cfg_instance) * 2 + 4; inst_name = kasprintf(GFP_NOFS, "%s-%p", @@ -1238,8 +1272,14 @@ int class_config_llog_handler(const struct lu_env *env, clli->cfg_obdname); } - lcfg_new = lustre_cfg_new(lcfg->lcfg_command, &bufs); + lcfg_len = lustre_cfg_len(bufs.lcfg_bufcount, bufs.lcfg_buflen); + lcfg_new = kzalloc(lcfg_len, GFP_NOFS); + if (!lcfg_new) { + rc = -ENOMEM; + goto out; + } + lustre_cfg_init(lcfg_new, lcfg->lcfg_command, &bufs); lcfg_new->lcfg_num = lcfg->lcfg_num; lcfg_new->lcfg_flags = lcfg->lcfg_flags; @@ -1262,10 +1302,8 @@ int class_config_llog_handler(const struct lu_env *env, lcfg_new->lcfg_nal = 0; /* illegal value for obsolete field */ rc = class_process_config(lcfg_new); - lustre_cfg_free(lcfg_new); - - if (inst) - kfree(inst_name); + kfree(lcfg_new); + kfree(inst_name); break; } default: @@ -1426,9 +1464,11 @@ int class_manual_cleanup(struct obd_device *obd) lustre_cfg_bufs_reset(&bufs, obd->obd_name); lustre_cfg_bufs_set_string(&bufs, 1, flags); - lcfg = lustre_cfg_new(LCFG_CLEANUP, &bufs); - if (IS_ERR(lcfg)) - return PTR_ERR(lcfg); + lcfg = kzalloc(lustre_cfg_len(bufs.lcfg_bufcount, bufs.lcfg_buflen), + GFP_NOFS); + if (!lcfg) + return -ENOMEM; + lustre_cfg_init(lcfg, LCFG_CLEANUP, &bufs); rc = class_process_config(lcfg); if (rc) { @@ -1442,7 +1482,7 @@ int class_manual_cleanup(struct obd_device *obd) if (rc) CERROR("detach failed %d: %s\n", rc, obd->obd_name); out: - lustre_cfg_free(lcfg); + kfree(lcfg); return rc; } EXPORT_SYMBOL(class_manual_cleanup); diff --git a/drivers/staging/lustre/lustre/obdclass/obd_mount.c b/drivers/staging/lustre/lustre/obdclass/obd_mount.c index 8e0d4b1d86dc..1256034b60c1 100644 --- a/drivers/staging/lustre/lustre/obdclass/obd_mount.c +++ b/drivers/staging/lustre/lustre/obdclass/obd_mount.c @@ -40,13 +40,13 @@ #define D_MOUNT (D_SUPER | D_CONFIG/*|D_WARNING */) #define PRINT_CMD CDEBUG -#include "../include/obd.h" -#include "../include/lustre_compat.h" -#include "../include/obd_class.h" -#include "../include/lustre/lustre_user.h" -#include "../include/lustre_log.h" -#include "../include/lustre_disk.h" -#include "../include/lustre_param.h" +#include <obd.h> +#include <lustre_compat.h> +#include <obd_class.h> +#include <uapi/linux/lustre/lustre_idl.h> +#include <lustre_log.h> +#include <lustre_disk.h> +#include <uapi/linux/lustre/lustre_param.h> static int (*client_fill_super)(struct super_block *sb, struct vfsmount *mnt); @@ -88,10 +88,17 @@ int lustre_process_log(struct super_block *sb, char *logname, lustre_cfg_bufs_set_string(bufs, 1, logname); lustre_cfg_bufs_set(bufs, 2, cfg, sizeof(*cfg)); lustre_cfg_bufs_set(bufs, 3, &sb, sizeof(sb)); - lcfg = lustre_cfg_new(LCFG_LOG_START, bufs); - rc = obd_process_config(mgc, sizeof(*lcfg), lcfg); - lustre_cfg_free(lcfg); + lcfg = kzalloc(lustre_cfg_len(bufs->lcfg_bufcount, bufs->lcfg_buflen), + GFP_NOFS); + if (!lcfg) { + rc = -ENOMEM; + goto out; + } + lustre_cfg_init(lcfg, LCFG_LOG_START, bufs); + rc = obd_process_config(mgc, sizeof(*lcfg), lcfg); + kfree(lcfg); +out: kfree(bufs); if (rc == -EINVAL) @@ -126,9 +133,14 @@ int lustre_end_log(struct super_block *sb, char *logname, lustre_cfg_bufs_set_string(&bufs, 1, logname); if (cfg) lustre_cfg_bufs_set(&bufs, 2, cfg, sizeof(*cfg)); - lcfg = lustre_cfg_new(LCFG_LOG_END, &bufs); + lcfg = kzalloc(lustre_cfg_len(bufs.lcfg_bufcount, bufs.lcfg_buflen), + GFP_NOFS); + if (!lcfg) + return -ENOMEM; + lustre_cfg_init(lcfg, LCFG_LOG_END, &bufs); + rc = obd_process_config(mgc, sizeof(*lcfg), lcfg); - lustre_cfg_free(lcfg); + kfree(lcfg); return rc; } EXPORT_SYMBOL(lustre_end_log); @@ -158,10 +170,14 @@ static int do_lcfg(char *cfgname, lnet_nid_t nid, int cmd, if (s4) lustre_cfg_bufs_set_string(&bufs, 4, s4); - lcfg = lustre_cfg_new(cmd, &bufs); + lcfg = kzalloc(lustre_cfg_len(bufs.lcfg_bufcount, bufs.lcfg_buflen), + GFP_NOFS); + if (!lcfg) + return -ENOMEM; + lustre_cfg_init(lcfg, cmd, &bufs); lcfg->lcfg_nid = nid; rc = class_process_config(lcfg); - lustre_cfg_free(lcfg); + kfree(lcfg); return rc; } diff --git a/drivers/staging/lustre/lustre/obdclass/obdo.c b/drivers/staging/lustre/lustre/obdclass/obdo.c index b1dfa1622ae7..7083f8786e9a 100644 --- a/drivers/staging/lustre/lustre/obdclass/obdo.c +++ b/drivers/staging/lustre/lustre/obdclass/obdo.c @@ -38,9 +38,9 @@ #define DEBUG_SUBSYSTEM S_CLASS -#include "../include/obd_class.h" -#include "../include/lustre/lustre_idl.h" -#include "../include/lustre_obdo.h" +#include <obd_class.h> +#include <uapi/linux/lustre/lustre_idl.h> +#include <lustre_obdo.h> void obdo_set_parent_fid(struct obdo *dst, const struct lu_fid *parent) { diff --git a/drivers/staging/lustre/lustre/obdclass/statfs_pack.c b/drivers/staging/lustre/lustre/obdclass/statfs_pack.c index 4bad1fa27d40..89abea26a1f8 100644 --- a/drivers/staging/lustre/lustre/obdclass/statfs_pack.c +++ b/drivers/staging/lustre/lustre/obdclass/statfs_pack.c @@ -37,10 +37,10 @@ #define DEBUG_SUBSYSTEM S_CLASS #include <linux/statfs.h> -#include "../include/lustre_export.h" -#include "../include/lustre_net.h" -#include "../include/obd_support.h" -#include "../include/obd_class.h" +#include <lustre_export.h> +#include <lustre_net.h> +#include <obd_support.h> +#include <obd_class.h> void statfs_unpack(struct kstatfs *sfs, struct obd_statfs *osfs) { diff --git a/drivers/staging/lustre/lustre/obdclass/uuid.c b/drivers/staging/lustre/lustre/obdclass/uuid.c index abd9b1ae72cd..9b1872b99f2a 100644 --- a/drivers/staging/lustre/lustre/obdclass/uuid.c +++ b/drivers/staging/lustre/lustre/obdclass/uuid.c @@ -34,10 +34,10 @@ #define DEBUG_SUBSYSTEM S_CLASS -#include "../../include/linux/libcfs/libcfs.h" +#include <linux/libcfs/libcfs.h> -#include "../include/obd_support.h" -#include "../include/obd_class.h" +#include <obd_support.h> +#include <obd_class.h> void class_uuid_unparse(class_uuid_t uu, struct obd_uuid *out) { diff --git a/drivers/staging/lustre/lustre/obdecho/Makefile b/drivers/staging/lustre/lustre/obdecho/Makefile index a659a37a7e93..6be66fbab872 100644 --- a/drivers/staging/lustre/lustre/obdecho/Makefile +++ b/drivers/staging/lustre/lustre/obdecho/Makefile @@ -1,2 +1,5 @@ +subdir-ccflags-y += -I$(srctree)/drivers/staging/lustre/include +subdir-ccflags-y += -I$(srctree)/drivers/staging/lustre/lustre/include + obj-$(CONFIG_LUSTRE_FS) += obdecho.o obdecho-y := echo_client.o diff --git a/drivers/staging/lustre/lustre/obdecho/echo_client.c b/drivers/staging/lustre/lustre/obdecho/echo_client.c index 1c4a8fe87dd8..f9808d1cc352 100644 --- a/drivers/staging/lustre/lustre/obdecho/echo_client.c +++ b/drivers/staging/lustre/lustre/obdecho/echo_client.c @@ -31,18 +31,18 @@ */ #define DEBUG_SUBSYSTEM S_ECHO -#include "../../include/linux/libcfs/libcfs.h" - -#include "../include/obd.h" -#include "../include/obd_support.h" -#include "../include/obd_class.h" -#include "../include/lustre_debug.h" -#include "../include/lprocfs_status.h" -#include "../include/cl_object.h" -#include "../include/lustre_fid.h" -#include "../include/lustre_acl.h" -#include "../include/lustre/lustre_ioctl.h" -#include "../include/lustre_net.h" +#include <linux/libcfs/libcfs.h> + +#include <obd.h> +#include <obd_support.h> +#include <obd_class.h> +#include <lustre_debug.h> +#include <lprocfs_status.h> +#include <cl_object.h> +#include <lustre_fid.h> +#include <lustre_acl.h> +#include <uapi/linux/lustre/lustre_ioctl.h> +#include <lustre_net.h> #include "echo_internal.h" @@ -319,7 +319,7 @@ static void echo_lock_fini(const struct lu_env *env, kmem_cache_free(echo_lock_kmem, ecl); } -static struct cl_lock_operations echo_lock_ops = { +static const struct cl_lock_operations echo_lock_ops = { .clo_fini = echo_lock_fini, }; @@ -1102,8 +1102,11 @@ static int echo_create_object(const struct lu_env *env, struct echo_device *ed, return -EINVAL; } - if (!ostid_id(&oa->o_oi)) - ostid_set_id(&oa->o_oi, ++last_object_id); + if (!ostid_id(&oa->o_oi)) { + rc = ostid_set_id(&oa->o_oi, ++last_object_id); + if (rc) + goto failed; + } rc = obd_create(env, ec->ec_exp, oa); if (rc != 0) { diff --git a/drivers/staging/lustre/lustre/osc/Makefile b/drivers/staging/lustre/lustre/osc/Makefile index 37cdeea9ac49..30dec90e64e8 100644 --- a/drivers/staging/lustre/lustre/osc/Makefile +++ b/drivers/staging/lustre/lustre/osc/Makefile @@ -1,3 +1,6 @@ +subdir-ccflags-y += -I$(srctree)/drivers/staging/lustre/include +subdir-ccflags-y += -I$(srctree)/drivers/staging/lustre/lustre/include + obj-$(CONFIG_LUSTRE_FS) += osc.o osc-y := osc_request.o osc_dev.o osc_object.o \ osc_page.o osc_lock.o osc_io.o osc_quota.o osc_cache.o lproc_osc.o diff --git a/drivers/staging/lustre/lustre/osc/lproc_osc.c b/drivers/staging/lustre/lustre/osc/lproc_osc.c index 86f252d6adbd..ae13eb055229 100644 --- a/drivers/staging/lustre/lustre/osc/lproc_osc.c +++ b/drivers/staging/lustre/lustre/osc/lproc_osc.c @@ -32,9 +32,9 @@ #define DEBUG_SUBSYSTEM S_CLASS #include <linux/statfs.h> -#include "../include/obd_cksum.h" -#include "../include/obd_class.h" -#include "../include/lprocfs_status.h" +#include <obd_cksum.h> +#include <obd_class.h> +#include <lprocfs_status.h> #include <linux/seq_file.h> #include "osc_internal.h" @@ -831,7 +831,7 @@ static struct attribute *osc_attrs[] = { NULL, }; -static struct attribute_group osc_attr_group = { +static const struct attribute_group osc_attr_group = { .attrs = osc_attrs, }; diff --git a/drivers/staging/lustre/lustre/osc/osc_cache.c b/drivers/staging/lustre/lustre/osc/osc_cache.c index d8a95f8fe1ff..e1207c227b79 100644 --- a/drivers/staging/lustre/lustre/osc/osc_cache.c +++ b/drivers/staging/lustre/lustre/osc/osc_cache.c @@ -783,6 +783,7 @@ restart: /* pull ext's start back to cover cur */ ext->oe_start = cur->oe_start; ext->oe_grants += chunksize; + LASSERT(*grants >= chunksize); *grants -= chunksize; found = osc_extent_hold(ext); @@ -790,6 +791,7 @@ restart: /* rear merge */ ext->oe_end = cur->oe_end; ext->oe_grants += chunksize; + LASSERT(*grants >= chunksize); *grants -= chunksize; /* try to merge with the next one because we just fill @@ -819,8 +821,8 @@ restart: /* create a new extent */ EASSERT(osc_extent_is_overlapped(obj, cur) == 0, cur); cur->oe_grants = chunksize + cli->cl_extent_tax; + LASSERT(*grants >= cur->oe_grants); *grants -= cur->oe_grants; - LASSERT(*grants >= 0); cur->oe_state = OES_CACHE; found = osc_extent_hold(cur); @@ -849,7 +851,6 @@ restart: out: osc_extent_put(env, cur); - LASSERT(*grants >= 0); return found; } @@ -1219,8 +1220,8 @@ static int osc_extent_expand(struct osc_extent *ext, pgoff_t index, ext->oe_end = end_index; ext->oe_grants += chunksize; + LASSERT(*grants >= chunksize); *grants -= chunksize; - LASSERT(*grants >= 0); EASSERTF(osc_extent_is_overlapped(obj, ext) == 0, ext, "overlapped after expanding for %lu.\n", index); @@ -1887,6 +1888,7 @@ struct extent_rpc_data { unsigned int erd_page_count; unsigned int erd_max_pages; unsigned int erd_max_chunks; + unsigned int erd_max_extents; }; static inline unsigned int osc_extent_chunks(const struct osc_extent *ext) @@ -1915,11 +1917,23 @@ static int try_to_add_extent_for_io(struct client_obd *cli, EASSERT((ext->oe_state == OES_CACHE || ext->oe_state == OES_LOCK_DONE), ext); + if (!data->erd_max_extents) + return 0; + chunk_count = osc_extent_chunks(ext); + EASSERTF(data->erd_page_count != 0 || + chunk_count <= data->erd_max_chunks, ext, + "The first extent to be fit in a RPC contains %u chunks, which is over the limit %u.\n", + chunk_count, data->erd_max_chunks); + if (chunk_count > data->erd_max_chunks) return 0; data->erd_max_pages = max(ext->oe_mppr, data->erd_max_pages); + EASSERTF(data->erd_page_count != 0 || + ext->oe_nr_pages <= data->erd_max_pages, ext, + "The first extent to be fit in a RPC contains %u pages, which is over the limit %u.\n", + ext->oe_nr_pages, data->erd_max_pages); if (data->erd_page_count + ext->oe_nr_pages > data->erd_max_pages) return 0; @@ -1943,6 +1957,7 @@ static int try_to_add_extent_for_io(struct client_obd *cli, break; } + data->erd_max_extents--; data->erd_max_chunks -= chunk_count; data->erd_page_count += ext->oe_nr_pages; list_move_tail(&ext->oe_link, data->erd_rpc_list); @@ -1972,10 +1987,12 @@ static inline unsigned int osc_max_write_chunks(const struct client_obd *cli) * * This limitation doesn't apply to ldiskfs, which allows as many * chunks in one RPC as we want. However, it won't have any benefits - * to have too many discontiguous pages in one RPC. Therefore, it - * can only have 256 chunks at most in one RPC. + * to have too many discontiguous pages in one RPC. + * + * An osc_extent won't cover over a RPC size, so the chunks in an + * osc_extent won't bigger than PTLRPC_MAX_BRW_SIZE >> chunkbits. */ - return min(PTLRPC_MAX_BRW_SIZE >> cli->cl_chunkbits, 256); + return PTLRPC_MAX_BRW_SIZE >> cli->cl_chunkbits; } /** @@ -2002,6 +2019,7 @@ static unsigned int get_write_extents(struct osc_object *obj, .erd_page_count = 0, .erd_max_pages = cli->cl_max_pages_per_rpc, .erd_max_chunks = osc_max_write_chunks(cli), + .erd_max_extents = 256, }; LASSERT(osc_object_is_locked(obj)); @@ -2140,6 +2158,7 @@ osc_send_read_rpc(const struct lu_env *env, struct client_obd *cli, .erd_page_count = 0, .erd_max_pages = cli->cl_max_pages_per_rpc, .erd_max_chunks = UINT_MAX, + .erd_max_extents = UINT_MAX, }; int rc = 0; diff --git a/drivers/staging/lustre/lustre/osc/osc_cl_internal.h b/drivers/staging/lustre/lustre/osc/osc_cl_internal.h index 270212f4e5cf..35bdbfb8660d 100644 --- a/drivers/staging/lustre/lustre/osc/osc_cl_internal.h +++ b/drivers/staging/lustre/lustre/osc/osc_cl_internal.h @@ -42,11 +42,11 @@ #ifndef OSC_CL_INTERNAL_H #define OSC_CL_INTERNAL_H -#include "../../include/linux/libcfs/libcfs.h" +#include <linux/libcfs/libcfs.h> -#include "../include/obd.h" +#include <obd.h> /* osc_build_res_name() */ -#include "../include/cl_object.h" +#include <cl_object.h> #include "osc_internal.h" /** \defgroup osc osc diff --git a/drivers/staging/lustre/lustre/osc/osc_dev.c b/drivers/staging/lustre/lustre/osc/osc_dev.c index c5d62aeaeab5..cf7b8879d7f0 100644 --- a/drivers/staging/lustre/lustre/osc/osc_dev.c +++ b/drivers/staging/lustre/lustre/osc/osc_dev.c @@ -37,7 +37,7 @@ #define DEBUG_SUBSYSTEM S_OSC /* class_name2obd() */ -#include "../include/obd_class.h" +#include <obd_class.h> #include "osc_cl_internal.h" diff --git a/drivers/staging/lustre/lustre/osc/osc_internal.h b/drivers/staging/lustre/lustre/osc/osc_internal.h index 13a40f6423ff..a536908fb26a 100644 --- a/drivers/staging/lustre/lustre/osc/osc_internal.h +++ b/drivers/staging/lustre/lustre/osc/osc_internal.h @@ -99,7 +99,7 @@ void osc_update_next_shrink(struct client_obd *cli); /* * cl integration. */ -#include "../include/cl_object.h" +#include <cl_object.h> extern struct ptlrpc_request_set *PTLRPCD_SET; diff --git a/drivers/staging/lustre/lustre/osc/osc_io.c b/drivers/staging/lustre/lustre/osc/osc_io.c index cbab80092442..f7969e33f28a 100644 --- a/drivers/staging/lustre/lustre/osc/osc_io.c +++ b/drivers/staging/lustre/lustre/osc/osc_io.c @@ -37,7 +37,7 @@ #define DEBUG_SUBSYSTEM S_OSC -#include "../include/lustre_obdo.h" +#include <lustre_obdo.h> #include "osc_cl_internal.h" diff --git a/drivers/staging/lustre/lustre/osc/osc_lock.c b/drivers/staging/lustre/lustre/osc/osc_lock.c index 940c10c1d7a1..b4f1f74dead8 100644 --- a/drivers/staging/lustre/lustre/osc/osc_lock.c +++ b/drivers/staging/lustre/lustre/osc/osc_lock.c @@ -37,9 +37,9 @@ #define DEBUG_SUBSYSTEM S_OSC -#include "../../include/linux/libcfs/libcfs.h" +#include <linux/libcfs/libcfs.h> /* fid_build_reg_res_name() */ -#include "../include/lustre_fid.h" +#include <lustre_fid.h> #include "osc_cl_internal.h" diff --git a/drivers/staging/lustre/lustre/osc/osc_object.c b/drivers/staging/lustre/lustre/osc/osc_object.c index fa621bda1ffe..945ae6e5a8b1 100644 --- a/drivers/staging/lustre/lustre/osc/osc_object.c +++ b/drivers/staging/lustre/lustre/osc/osc_object.c @@ -369,7 +369,14 @@ static void osc_req_attr_set(const struct lu_env *env, struct cl_object *obj, oa->o_valid |= OBD_MD_FLGROUP; } if (flags & OBD_MD_FLID) { - ostid_set_id(&oa->o_oi, ostid_id(&oinfo->loi_oi)); + int rc; + + rc = ostid_set_id(&oa->o_oi, ostid_id(&oinfo->loi_oi)); + if (rc) { + CERROR("Bad %llu to set " DOSTID " : rc %d\n", + (unsigned long long)ostid_id(&oinfo->loi_oi), + POSTID(&oa->o_oi), rc); + } oa->o_valid |= OBD_MD_FLID; } if (flags & OBD_MD_FLHANDLE) { diff --git a/drivers/staging/lustre/lustre/osc/osc_quota.c b/drivers/staging/lustre/lustre/osc/osc_quota.c index fed4da63ee45..a6118f8ba446 100644 --- a/drivers/staging/lustre/lustre/osc/osc_quota.c +++ b/drivers/staging/lustre/lustre/osc/osc_quota.c @@ -23,7 +23,7 @@ * Code originally extracted from quota directory */ -#include "../include/obd_class.h" +#include <obd_class.h> #include "osc_internal.h" static inline struct osc_quota_info *osc_oqi_alloc(u32 id) diff --git a/drivers/staging/lustre/lustre/osc/osc_request.c b/drivers/staging/lustre/lustre/osc/osc_request.c index 922d0cbe83dc..4c68c42b2281 100644 --- a/drivers/staging/lustre/lustre/osc/osc_request.c +++ b/drivers/staging/lustre/lustre/osc/osc_request.c @@ -32,22 +32,22 @@ #define DEBUG_SUBSYSTEM S_OSC -#include "../../include/linux/libcfs/libcfs.h" - -#include "../include/lustre_dlm.h" -#include "../include/lustre_net.h" -#include "../include/lustre/lustre_user.h" -#include "../include/obd_cksum.h" - -#include "../include/lustre_ha.h" -#include "../include/lprocfs_status.h" -#include "../include/lustre/lustre_ioctl.h" -#include "../include/lustre_debug.h" -#include "../include/lustre_obdo.h" -#include "../include/lustre_param.h" -#include "../include/lustre_fid.h" -#include "../include/obd_class.h" -#include "../include/obd.h" +#include <linux/libcfs/libcfs.h> + +#include <lustre_dlm.h> +#include <lustre_net.h> +#include <uapi/linux/lustre/lustre_idl.h> +#include <obd_cksum.h> + +#include <lustre_ha.h> +#include <lprocfs_status.h> +#include <uapi/linux/lustre/lustre_ioctl.h> +#include <lustre_debug.h> +#include <lustre_obdo.h> +#include <uapi/linux/lustre/lustre_param.h> +#include <lustre_fid.h> +#include <obd_class.h> +#include <obd.h> #include "osc_internal.h" #include "osc_cl_internal.h" diff --git a/drivers/staging/lustre/lustre/ptlrpc/Makefile b/drivers/staging/lustre/lustre/ptlrpc/Makefile index 24bbac19ddd1..a518001cdfe8 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/Makefile +++ b/drivers/staging/lustre/lustre/ptlrpc/Makefile @@ -1,3 +1,6 @@ +subdir-ccflags-y += -I$(srctree)/drivers/staging/lustre/include +subdir-ccflags-y += -I$(srctree)/drivers/staging/lustre/lustre/include + obj-$(CONFIG_LUSTRE_FS) += ptlrpc.o LDLM := ../../lustre/ldlm/ diff --git a/drivers/staging/lustre/lustre/ptlrpc/client.c b/drivers/staging/lustre/lustre/ptlrpc/client.c index 1c7779215eed..b1d379a6a70f 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/client.c +++ b/drivers/staging/lustre/lustre/ptlrpc/client.c @@ -34,12 +34,12 @@ #define DEBUG_SUBSYSTEM S_RPC -#include "../include/obd_support.h" -#include "../include/obd_class.h" -#include "../include/lustre_lib.h" -#include "../include/lustre_ha.h" -#include "../include/lustre_import.h" -#include "../include/lustre_req_layout.h" +#include <obd_support.h> +#include <obd_class.h> +#include <lustre_lib.h> +#include <lustre_ha.h> +#include <lustre_import.h> +#include <lustre_req_layout.h> #include "ptlrpc_internal.h" @@ -367,9 +367,8 @@ void ptlrpc_at_adj_net_latency(struct ptlrpc_request *req, */ CDEBUG((lustre_msg_get_flags(req->rq_reqmsg) & MSG_RESENT) ? D_ADAPTTO : D_WARNING, - "Reported service time %u > total measured time " CFS_DURATION_T "\n", - service_time, - (long)(now - req->rq_sent)); + "Reported service time %u > total measured time %lld\n", + service_time, now - req->rq_sent); return; } @@ -742,7 +741,7 @@ int ptlrpc_request_bufs_pack(struct ptlrpc_request *request, /* Let's setup deadline for req/reply/bulk unlink for opcode. */ if (cfs_fail_val == opcode) { - time_t *fail_t = NULL, *fail2_t = NULL; + time64_t *fail_t = NULL, *fail2_t = NULL; if (CFS_FAIL_CHECK(OBD_FAIL_PTLRPC_LONG_BULK_UNLINK)) { fail_t = &request->rq_bulk_deadline; @@ -3116,13 +3115,20 @@ void ptlrpc_set_bulk_mbits(struct ptlrpc_request *req) LASSERT(bd); - if (!req->rq_resend) { - /* this request has a new xid, just use it as bulk matchbits */ - req->rq_mbits = req->rq_xid; - - } else { /* needs to generate a new matchbits for resend */ + /* + * Generate new matchbits for all resend requests, including + * resend replay. + */ + if (req->rq_resend) { u64 old_mbits = req->rq_mbits; + /* + * First time resend on -EINPROGRESS will generate new xid, + * so we can actually use the rq_xid as rq_mbits in such case, + * however, it's bit hard to distinguish such resend with a + * 'resend for the -EINPROGRESS resend'. To make it simple, + * we opt to generate mbits for all resend cases. + */ if ((bd->bd_import->imp_connect_data.ocd_connect_flags & OBD_CONNECT_BULK_MBITS)) { req->rq_mbits = ptlrpc_next_xid(); @@ -3131,12 +3137,21 @@ void ptlrpc_set_bulk_mbits(struct ptlrpc_request *req) spin_lock(&req->rq_import->imp_lock); list_del_init(&req->rq_unreplied_list); ptlrpc_assign_next_xid_nolock(req); - req->rq_mbits = req->rq_xid; spin_unlock(&req->rq_import->imp_lock); + req->rq_mbits = req->rq_xid; } CDEBUG(D_HA, "resend bulk old x%llu new x%llu\n", old_mbits, req->rq_mbits); + } else if (!(lustre_msg_get_flags(req->rq_reqmsg) & MSG_REPLAY)) { + /* Request being sent first time, use xid as matchbits. */ + req->rq_mbits = req->rq_xid; + } else { + /* + * Replay request, xid and matchbits have already been + * correctly assigned. + */ + return; } /* diff --git a/drivers/staging/lustre/lustre/ptlrpc/connection.c b/drivers/staging/lustre/lustre/ptlrpc/connection.c index 73a2dbbeb7e6..cfdcbcec2779 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/connection.c +++ b/drivers/staging/lustre/lustre/ptlrpc/connection.c @@ -31,9 +31,9 @@ */ #define DEBUG_SUBSYSTEM S_RPC -#include "../include/obd_support.h" -#include "../include/obd_class.h" -#include "../include/lustre_net.h" +#include <obd_support.h> +#include <obd_class.h> +#include <lustre_net.h> #include "ptlrpc_internal.h" diff --git a/drivers/staging/lustre/lustre/ptlrpc/errno.c b/drivers/staging/lustre/lustre/ptlrpc/errno.c index 73f8374f190e..cb788364a553 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/errno.c +++ b/drivers/staging/lustre/lustre/ptlrpc/errno.c @@ -25,8 +25,8 @@ * Copyright (c) 2013, Intel Corporation. */ -#include "../../include/linux/libcfs/libcfs.h" -#include "../include/lustre/lustre_errno.h" +#include <linux/libcfs/libcfs.h> +#include <lustre_errno.h> /* * The two translation tables below must define a one-to-one mapping between diff --git a/drivers/staging/lustre/lustre/ptlrpc/events.c b/drivers/staging/lustre/lustre/ptlrpc/events.c index 978bdaca3cdd..62951f19b2ce 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/events.c +++ b/drivers/staging/lustre/lustre/ptlrpc/events.c @@ -32,14 +32,14 @@ #define DEBUG_SUBSYSTEM S_RPC -#include "../../include/linux/libcfs/libcfs.h" +#include <linux/libcfs/libcfs.h> # ifdef __mips64__ # include <linux/kernel.h> # endif -#include "../include/obd_class.h" -#include "../include/lustre_net.h" -#include "../include/lustre_sec.h" +#include <obd_class.h> +#include <lustre_net.h> +#include <lustre_sec.h> #include "ptlrpc_internal.h" struct lnet_handle_eq ptlrpc_eq_h; diff --git a/drivers/staging/lustre/lustre/ptlrpc/import.c b/drivers/staging/lustre/lustre/ptlrpc/import.c index 52cb1f0c9c94..21f528957b73 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/import.c +++ b/drivers/staging/lustre/lustre/ptlrpc/import.c @@ -36,14 +36,14 @@ #define DEBUG_SUBSYSTEM S_RPC -#include "../include/obd_support.h" -#include "../include/lustre_ha.h" -#include "../include/lustre_net.h" -#include "../include/lustre_import.h" -#include "../include/lustre_export.h" -#include "../include/obd.h" -#include "../include/obd_cksum.h" -#include "../include/obd_class.h" +#include <obd_support.h> +#include <lustre_ha.h> +#include <lustre_net.h> +#include <lustre_import.h> +#include <lustre_export.h> +#include <obd.h> +#include <obd_cksum.h> +#include <obd_class.h> #include "ptlrpc_internal.h" @@ -1026,7 +1026,7 @@ static int ptlrpc_connect_interpret(const struct lu_env *env, /* check that server granted subset of flags we asked for. */ if ((ocd->ocd_connect_flags & imp->imp_connect_flags_orig) != ocd->ocd_connect_flags) { - CERROR("%s: Server didn't granted asked subset of flags: asked=%#llx grranted=%#llx\n", + CERROR("%s: Server didn't grant the asked for subset of flags: asked=%#llx granted=%#llx\n", imp->imp_obd->obd_name, imp->imp_connect_flags_orig, ocd->ocd_connect_flags); rc = -EPROTO; diff --git a/drivers/staging/lustre/lustre/ptlrpc/layout.c b/drivers/staging/lustre/lustre/ptlrpc/layout.c index 5810bbab6585..85854d9a376d 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/layout.c +++ b/drivers/staging/lustre/lustre/ptlrpc/layout.c @@ -46,18 +46,18 @@ #include <linux/module.h> -#include "../include/lustre/lustre_idl.h" +#include <uapi/linux/lustre/lustre_idl.h> -#include "../include/llog_swab.h" -#include "../include/lustre_debug.h" -#include "../include/lustre_swab.h" -#include "../include/lustre_ver.h" -#include "../include/obd.h" -#include "../include/obd_support.h" +#include <llog_swab.h> +#include <lustre_debug.h> +#include <lustre_swab.h> +#include <uapi/linux/lustre/lustre_ver.h> +#include <obd.h> +#include <obd_support.h> /* struct ptlrpc_request, lustre_msg* */ -#include "../include/lustre_req_layout.h" -#include "../include/lustre_acl.h" +#include <lustre_req_layout.h> +#include <lustre_acl.h> /* * RQFs (see below) refer to two struct req_msg_field arrays describing the diff --git a/drivers/staging/lustre/lustre/ptlrpc/llog_client.c b/drivers/staging/lustre/lustre/ptlrpc/llog_client.c index 110d9f505787..480c20a6a792 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/llog_client.c +++ b/drivers/staging/lustre/lustre/ptlrpc/llog_client.c @@ -38,11 +38,11 @@ #define DEBUG_SUBSYSTEM S_LOG -#include "../../include/linux/libcfs/libcfs.h" +#include <linux/libcfs/libcfs.h> -#include "../include/obd_class.h" -#include "../include/lustre_log.h" -#include "../include/lustre_net.h" +#include <obd_class.h> +#include <lustre_log.h> +#include <lustre_net.h> #include <linux/list.h> #define LLOG_CLIENT_ENTRY(ctxt, imp) do { \ diff --git a/drivers/staging/lustre/lustre/ptlrpc/llog_net.c b/drivers/staging/lustre/lustre/ptlrpc/llog_net.c index bccdace7e51f..bc5aa7bcdba8 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/llog_net.c +++ b/drivers/staging/lustre/lustre/ptlrpc/llog_net.c @@ -42,10 +42,10 @@ #define DEBUG_SUBSYSTEM S_LOG -#include "../../include/linux/libcfs/libcfs.h" +#include <linux/libcfs/libcfs.h> -#include "../include/obd_class.h" -#include "../include/lustre_log.h" +#include <obd_class.h> +#include <lustre_log.h> #include <linux/list.h> int llog_initiator_connect(struct llog_ctxt *ctxt) diff --git a/drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c b/drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c index f87478180013..1392ae9747bd 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c +++ b/drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c @@ -31,12 +31,12 @@ */ #define DEBUG_SUBSYSTEM S_CLASS -#include "../include/obd_support.h" -#include "../include/obd.h" -#include "../include/lprocfs_status.h" -#include "../include/lustre/lustre_idl.h" -#include "../include/lustre_net.h" -#include "../include/obd_class.h" +#include <obd_support.h> +#include <obd.h> +#include <lprocfs_status.h> +#include <uapi/linux/lustre/lustre_idl.h> +#include <lustre_net.h> +#include <obd_class.h> #include "ptlrpc_internal.h" static struct ll_rpc_opcode { @@ -905,11 +905,18 @@ static int ptlrpc_lprocfs_svc_req_history_show(struct seq_file *s, void *iter) rc = ptlrpc_lprocfs_svc_req_history_seek(svcpt, srhi, srhi->srhi_seq); if (rc == 0) { + struct timespec64 arrival, sent, arrivaldiff; char nidstr[LNET_NIDSTR_SIZE]; req = srhi->srhi_req; libcfs_nid2str_r(req->rq_self, nidstr, sizeof(nidstr)); + arrival.tv_sec = req->rq_arrival_time.tv_sec; + arrival.tv_nsec = req->rq_arrival_time.tv_nsec; + sent.tv_sec = req->rq_sent; + sent.tv_nsec = 0; + arrivaldiff = timespec64_sub(sent, arrival); + /* Print common req fields. * CAVEAT EMPTOR: we're racing with the service handler * here. The request could contain any old crap, so you @@ -917,13 +924,15 @@ static int ptlrpc_lprocfs_svc_req_history_show(struct seq_file *s, void *iter) * parser. Currently I only print stuff here I know is OK * to look at coz it was set up in request_in_callback()!!! */ - seq_printf(s, "%lld:%s:%s:x%llu:%d:%s:%lld:%lds(%+lds) ", + seq_printf(s, "%lld:%s:%s:x%llu:%d:%s:%lld.%06lld:%lld.%06llds(%+lld.0s) ", req->rq_history_seq, nidstr, libcfs_id2str(req->rq_peer), req->rq_xid, req->rq_reqlen, ptlrpc_rqphase2str(req), (s64)req->rq_arrival_time.tv_sec, - (long)(req->rq_sent - req->rq_arrival_time.tv_sec), - (long)(req->rq_sent - req->rq_deadline)); + (s64)req->rq_arrival_time.tv_nsec / NSEC_PER_USEC, + (s64)arrivaldiff.tv_sec, + (s64)(arrivaldiff.tv_nsec / NSEC_PER_USEC), + (s64)(req->rq_sent - req->rq_deadline)); if (!svc->srv_ops.so_req_printer) seq_putc(s, '\n'); else diff --git a/drivers/staging/lustre/lustre/ptlrpc/niobuf.c b/drivers/staging/lustre/lustre/ptlrpc/niobuf.c index eddc1927a8d2..12149fb64719 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/niobuf.c +++ b/drivers/staging/lustre/lustre/ptlrpc/niobuf.c @@ -31,11 +31,11 @@ */ #define DEBUG_SUBSYSTEM S_RPC -#include "../include/obd_support.h" -#include "../include/lustre_net.h" -#include "../include/lustre_lib.h" -#include "../include/obd.h" -#include "../include/obd_class.h" +#include <obd_support.h> +#include <lustre_net.h> +#include <lustre_lib.h> +#include <obd.h> +#include <obd_class.h> #include "ptlrpc_internal.h" /** diff --git a/drivers/staging/lustre/lustre/ptlrpc/nrs.c b/drivers/staging/lustre/lustre/ptlrpc/nrs.c index ef19dbe2ea5c..2969d8da270e 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/nrs.c +++ b/drivers/staging/lustre/lustre/ptlrpc/nrs.c @@ -36,11 +36,11 @@ */ #define DEBUG_SUBSYSTEM S_RPC -#include "../include/obd_support.h" -#include "../include/obd_class.h" -#include "../include/lustre_net.h" -#include "../include/lprocfs_status.h" -#include "../../include/linux/libcfs/libcfs.h" +#include <obd_support.h> +#include <obd_class.h> +#include <lustre_net.h> +#include <lprocfs_status.h> +#include <linux/libcfs/libcfs.h> #include "ptlrpc_internal.h" /** diff --git a/drivers/staging/lustre/lustre/ptlrpc/nrs_fifo.c b/drivers/staging/lustre/lustre/ptlrpc/nrs_fifo.c index b123a93242ba..df330e43bfe5 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/nrs_fifo.c +++ b/drivers/staging/lustre/lustre/ptlrpc/nrs_fifo.c @@ -43,9 +43,9 @@ */ #define DEBUG_SUBSYSTEM S_RPC -#include "../include/obd_support.h" -#include "../include/obd_class.h" -#include "../../include/linux/libcfs/libcfs.h" +#include <obd_support.h> +#include <obd_class.h> +#include <linux/libcfs/libcfs.h> #include "ptlrpc_internal.h" /** diff --git a/drivers/staging/lustre/lustre/ptlrpc/pack_generic.c b/drivers/staging/lustre/lustre/ptlrpc/pack_generic.c index 55e8696e7d86..aad4ff191d95 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/pack_generic.c +++ b/drivers/staging/lustre/lustre/ptlrpc/pack_generic.c @@ -40,16 +40,16 @@ #define DEBUG_SUBSYSTEM S_RPC -#include "../../include/linux/libcfs/libcfs.h" +#include <linux/libcfs/libcfs.h> -#include "../include/lustre/ll_fiemap.h" +#include <uapi/linux/lustre/lustre_fiemap.h> -#include "../include/llog_swab.h" -#include "../include/lustre_net.h" -#include "../include/lustre_swab.h" -#include "../include/obd_cksum.h" -#include "../include/obd_support.h" -#include "../include/obd_class.h" +#include <llog_swab.h> +#include <lustre_net.h> +#include <lustre_swab.h> +#include <obd_cksum.h> +#include <obd_support.h> +#include <obd_class.h> #include "ptlrpc_internal.h" @@ -186,7 +186,9 @@ void lustre_init_msg_v2(struct lustre_msg_v2 *msg, int count, __u32 *lens, for (i = 0; i < count; i++) { char *tmp = bufs[i]; - LOGL(tmp, lens[i], ptr); + if (tmp) + memcpy(ptr, tmp, lens[i]); + ptr += cfs_size_round(lens[i]); } } EXPORT_SYMBOL(lustre_init_msg_v2); diff --git a/drivers/staging/lustre/lustre/ptlrpc/pers.c b/drivers/staging/lustre/lustre/ptlrpc/pers.c index df4994f406e9..643388b03af7 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/pers.c +++ b/drivers/staging/lustre/lustre/ptlrpc/pers.c @@ -32,11 +32,11 @@ #define DEBUG_SUBSYSTEM S_RPC -#include "../include/obd_support.h" -#include "../include/obd_class.h" -#include "../include/lustre_lib.h" -#include "../include/lustre_ha.h" -#include "../include/lustre_import.h" +#include <obd_support.h> +#include <obd_class.h> +#include <lustre_lib.h> +#include <lustre_ha.h> +#include <lustre_import.h> #include "ptlrpc_internal.h" diff --git a/drivers/staging/lustre/lustre/ptlrpc/pinger.c b/drivers/staging/lustre/lustre/ptlrpc/pinger.c index 5504fc2363ac..e4de50e18d08 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/pinger.c +++ b/drivers/staging/lustre/lustre/ptlrpc/pinger.c @@ -36,8 +36,8 @@ #define DEBUG_SUBSYSTEM S_RPC -#include "../include/obd_support.h" -#include "../include/obd_class.h" +#include <obd_support.h> +#include <obd_class.h> #include "ptlrpc_internal.h" struct mutex pinger_mutex; diff --git a/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_module.c b/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_module.c index a70d5843f30e..38e488dd5409 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_module.c +++ b/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_module.c @@ -32,10 +32,10 @@ #define DEBUG_SUBSYSTEM S_RPC -#include "../include/obd_support.h" -#include "../include/obd_class.h" -#include "../include/lustre_net.h" -#include "../include/lustre_req_layout.h" +#include <obd_support.h> +#include <obd_class.h> +#include <lustre_net.h> +#include <lustre_req_layout.h> #include "ptlrpc_internal.h" diff --git a/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c b/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c index 59b5813bd559..0e476828cf75 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c +++ b/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c @@ -51,15 +51,15 @@ #define DEBUG_SUBSYSTEM S_RPC -#include "../../include/linux/libcfs/libcfs.h" - -#include "../include/lustre_net.h" -#include "../include/lustre_lib.h" -#include "../include/lustre_ha.h" -#include "../include/obd_class.h" /* for obd_zombie */ -#include "../include/obd_support.h" /* for OBD_FAIL_CHECK */ -#include "../include/cl_object.h" /* cl_env_{get,put}() */ -#include "../include/lprocfs_status.h" +#include <linux/libcfs/libcfs.h> + +#include <lustre_net.h> +#include <lustre_lib.h> +#include <lustre_ha.h> +#include <obd_class.h> /* for obd_zombie */ +#include <obd_support.h> /* for OBD_FAIL_CHECK */ +#include <cl_object.h> /* cl_env_{get,put}() */ +#include <lprocfs_status.h> #include "ptlrpc_internal.h" diff --git a/drivers/staging/lustre/lustre/ptlrpc/recover.c b/drivers/staging/lustre/lustre/ptlrpc/recover.c index 7b58545c2de4..72a19a379e2f 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/recover.c +++ b/drivers/staging/lustre/lustre/ptlrpc/recover.c @@ -35,15 +35,15 @@ */ #define DEBUG_SUBSYSTEM S_RPC -#include "../../include/linux/libcfs/libcfs.h" - -#include "../include/obd_support.h" -#include "../include/lustre_ha.h" -#include "../include/lustre_net.h" -#include "../include/lustre_import.h" -#include "../include/lustre_export.h" -#include "../include/obd.h" -#include "../include/obd_class.h" +#include <linux/libcfs/libcfs.h> + +#include <obd_support.h> +#include <lustre_ha.h> +#include <lustre_net.h> +#include <lustre_import.h> +#include <lustre_export.h> +#include <obd.h> +#include <obd_class.h> #include <linux/list.h> #include "ptlrpc_internal.h" diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec.c b/drivers/staging/lustre/lustre/ptlrpc/sec.c index 366f2ce20f5e..cd7a5391a574 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/sec.c +++ b/drivers/staging/lustre/lustre/ptlrpc/sec.c @@ -36,19 +36,19 @@ #define DEBUG_SUBSYSTEM S_SEC -#include "../../include/linux/libcfs/libcfs.h" +#include <linux/libcfs/libcfs.h> #include <linux/crypto.h> #include <linux/cred.h> #include <linux/key.h> #include <linux/sched/task.h> -#include "../include/obd.h" -#include "../include/obd_class.h" -#include "../include/obd_support.h" -#include "../include/lustre_net.h" -#include "../include/lustre_import.h" -#include "../include/lustre_dlm.h" -#include "../include/lustre_sec.h" +#include <obd.h> +#include <obd_class.h> +#include <obd_support.h> +#include <lustre_net.h> +#include <lustre_import.h> +#include <lustre_dlm.h> +#include <lustre_sec.h> #include "ptlrpc_internal.h" diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c b/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c index 128838a695e0..059294aad172 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c +++ b/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c @@ -36,16 +36,16 @@ #define DEBUG_SUBSYSTEM S_SEC -#include "../../include/linux/libcfs/libcfs.h" - -#include "../include/obd.h" -#include "../include/obd_cksum.h" -#include "../include/obd_class.h" -#include "../include/obd_support.h" -#include "../include/lustre_net.h" -#include "../include/lustre_import.h" -#include "../include/lustre_dlm.h" -#include "../include/lustre_sec.h" +#include <linux/libcfs/libcfs.h> + +#include <obd.h> +#include <obd_cksum.h> +#include <obd_class.h> +#include <obd_support.h> +#include <lustre_net.h> +#include <lustre_import.h> +#include <lustre_dlm.h> +#include <lustre_sec.h> #include "ptlrpc_internal.h" diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_config.c b/drivers/staging/lustre/lustre/ptlrpc/sec_config.c index 2181a85efd49..0f4af66688a3 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/sec_config.c +++ b/drivers/staging/lustre/lustre/ptlrpc/sec_config.c @@ -32,15 +32,16 @@ #define DEBUG_SUBSYSTEM S_SEC -#include "../../include/linux/libcfs/libcfs.h" +#include <linux/libcfs/libcfs.h> #include <linux/crypto.h> #include <linux/key.h> -#include "../include/obd.h" -#include "../include/obd_support.h" -#include "../include/lustre_import.h" -#include "../include/lustre_param.h" -#include "../include/lustre_sec.h" +#include <obd.h> +#include <obd_class.h> +#include <obd_support.h> +#include <lustre_import.h> +#include <uapi/linux/lustre/lustre_param.h> +#include <lustre_sec.h> #include "ptlrpc_internal.h" diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_gc.c b/drivers/staging/lustre/lustre/ptlrpc/sec_gc.c index 8ffd000eafac..d10a8053d04f 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/sec_gc.c +++ b/drivers/staging/lustre/lustre/ptlrpc/sec_gc.c @@ -36,12 +36,12 @@ #define DEBUG_SUBSYSTEM S_SEC -#include "../../include/linux/libcfs/libcfs.h" +#include <linux/libcfs/libcfs.h> -#include "../include/obd_support.h" -#include "../include/obd_class.h" -#include "../include/lustre_net.h" -#include "../include/lustre_sec.h" +#include <obd_support.h> +#include <obd_class.h> +#include <lustre_net.h> +#include <lustre_sec.h> #include "ptlrpc_internal.h" @@ -66,7 +66,7 @@ void sptlrpc_gc_add_sec(struct ptlrpc_sec *sec) sec->ps_gc_next = ktime_get_real_seconds() + sec->ps_gc_interval; spin_lock(&sec_gc_list_lock); - list_add_tail(&sec_gc_list, &sec->ps_gc_list); + list_add_tail(&sec->ps_gc_list, &sec_gc_list); spin_unlock(&sec_gc_list_lock); CDEBUG(D_SEC, "added sec %p(%s)\n", sec, sec->ps_policy->sp_name); diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_lproc.c b/drivers/staging/lustre/lustre/ptlrpc/sec_lproc.c index 07273f577969..7792132eb145 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/sec_lproc.c +++ b/drivers/staging/lustre/lustre/ptlrpc/sec_lproc.c @@ -34,16 +34,16 @@ #define DEBUG_SUBSYSTEM S_SEC -#include "../../include/linux/libcfs/libcfs.h" +#include <linux/libcfs/libcfs.h> #include <linux/crypto.h> -#include "../include/obd.h" -#include "../include/obd_class.h" -#include "../include/obd_support.h" -#include "../include/lustre_net.h" -#include "../include/lustre_import.h" -#include "../include/lustre_dlm.h" -#include "../include/lustre_sec.h" +#include <obd.h> +#include <obd_class.h> +#include <obd_support.h> +#include <lustre_net.h> +#include <lustre_import.h> +#include <lustre_dlm.h> +#include <lustre_sec.h> #include "ptlrpc_internal.h" diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_null.c b/drivers/staging/lustre/lustre/ptlrpc/sec_null.c index 70a61e12bb7b..dc39a54c5e1a 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/sec_null.c +++ b/drivers/staging/lustre/lustre/ptlrpc/sec_null.c @@ -36,11 +36,11 @@ #define DEBUG_SUBSYSTEM S_SEC -#include "../include/obd_support.h" -#include "../include/obd_cksum.h" -#include "../include/obd_class.h" -#include "../include/lustre_net.h" -#include "../include/lustre_sec.h" +#include <obd_support.h> +#include <obd_cksum.h> +#include <obd_class.h> +#include <lustre_net.h> +#include <lustre_sec.h> #include "ptlrpc_internal.h" diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_plain.c b/drivers/staging/lustre/lustre/ptlrpc/sec_plain.c index c5e7a2309fce..6aa9b65b1926 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/sec_plain.c +++ b/drivers/staging/lustre/lustre/ptlrpc/sec_plain.c @@ -36,11 +36,11 @@ #define DEBUG_SUBSYSTEM S_SEC -#include "../include/obd_support.h" -#include "../include/obd_cksum.h" -#include "../include/obd_class.h" -#include "../include/lustre_net.h" -#include "../include/lustre_sec.h" +#include <obd_support.h> +#include <obd_cksum.h> +#include <obd_class.h> +#include <lustre_net.h> +#include <lustre_sec.h> #include "ptlrpc_internal.h" struct plain_sec { diff --git a/drivers/staging/lustre/lustre/ptlrpc/service.c b/drivers/staging/lustre/lustre/ptlrpc/service.c index 759aa6c16e28..155f6a45cc8b 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/service.c +++ b/drivers/staging/lustre/lustre/ptlrpc/service.c @@ -31,11 +31,12 @@ */ #define DEBUG_SUBSYSTEM S_RPC -#include "../include/obd_support.h" -#include "../include/obd_class.h" -#include "../include/lustre_net.h" -#include "../include/lu_object.h" -#include "../../include/linux/lnet/types.h" + +#include <obd_support.h> +#include <obd_class.h> +#include <lustre_net.h> +#include <lu_object.h> +#include <uapi/linux/lnet/lnet-types.h> #include "ptlrpc_internal.h" /* The following are visible and mutable through /sys/module/ptlrpc */ @@ -1565,9 +1566,9 @@ ptlrpc_server_handle_req_in(struct ptlrpc_service_part *svcpt, /* req_in handling should/must be fast */ if (ktime_get_real_seconds() - req->rq_arrival_time.tv_sec > 5) - DEBUG_REQ(D_WARNING, req, "Slow req_in handling " CFS_DURATION_T "s", - (long)(ktime_get_real_seconds() - - req->rq_arrival_time.tv_sec)); + DEBUG_REQ(D_WARNING, req, "Slow req_in handling %llds", + (s64)(ktime_get_real_seconds() - + req->rq_arrival_time.tv_sec)); /* Set rpc server deadline and add it to the timed list */ deadline = (lustre_msghdr_get_flags(req->rq_reqmsg) & @@ -1674,12 +1675,11 @@ ptlrpc_server_handle_request(struct ptlrpc_service_part *svcpt, * The deadline is increased if we send an early reply. */ if (ktime_get_real_seconds() > request->rq_deadline) { - DEBUG_REQ(D_ERROR, request, "Dropping timed-out request from %s: deadline " CFS_DURATION_T ":" CFS_DURATION_T "s ago\n", + DEBUG_REQ(D_ERROR, request, "Dropping timed-out request from %s: deadline %lld:%llds ago\n", libcfs_id2str(request->rq_peer), - (long)(request->rq_deadline - - request->rq_arrival_time.tv_sec), - (long)(ktime_get_real_seconds() - - request->rq_deadline)); + request->rq_deadline - + request->rq_arrival_time.tv_sec, + ktime_get_real_seconds() - request->rq_deadline); goto put_conn; } diff --git a/drivers/staging/lustre/lustre/ptlrpc/wiretest.c b/drivers/staging/lustre/lustre/ptlrpc/wiretest.c index 367f7e24e3da..07b86a1b6550 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/wiretest.c +++ b/drivers/staging/lustre/lustre/ptlrpc/wiretest.c @@ -35,10 +35,10 @@ #include <linux/fs.h> #include <linux/posix_acl_xattr.h> -#include "../include/obd_support.h" -#include "../include/obd_class.h" -#include "../include/lustre_net.h" -#include "../include/lustre_disk.h" +#include <obd_support.h> +#include <obd_class.h> +#include <lustre_net.h> +#include <lustre_disk.h> #include "ptlrpc_internal.h" void lustre_assert_wire_constants(void) @@ -3820,14 +3820,14 @@ void lustre_assert_wire_constants(void) (long long)(int)offsetof(struct link_ea_header, leh_len)); LASSERTF((int)sizeof(((struct link_ea_header *)0)->leh_len) == 8, "found %lld\n", (long long)(int)sizeof(((struct link_ea_header *)0)->leh_len)); - LASSERTF((int)offsetof(struct link_ea_header, padding1) == 16, "found %lld\n", - (long long)(int)offsetof(struct link_ea_header, padding1)); - LASSERTF((int)sizeof(((struct link_ea_header *)0)->padding1) == 4, "found %lld\n", - (long long)(int)sizeof(((struct link_ea_header *)0)->padding1)); - LASSERTF((int)offsetof(struct link_ea_header, padding2) == 20, "found %lld\n", - (long long)(int)offsetof(struct link_ea_header, padding2)); - LASSERTF((int)sizeof(((struct link_ea_header *)0)->padding2) == 4, "found %lld\n", - (long long)(int)sizeof(((struct link_ea_header *)0)->padding2)); + LASSERTF((int)offsetof(struct link_ea_header, leh_overflow_time) == 16, "found %lld\n", + (long long)(int)offsetof(struct link_ea_header, leh_overflow_time)); + LASSERTF((int)sizeof(((struct link_ea_header *)0)->leh_overflow_time) == 4, "found %lld\n", + (long long)(int)sizeof(((struct link_ea_header *)0)->leh_overflow_time)); + LASSERTF((int)offsetof(struct link_ea_header, leh_padding) == 20, "found %lld\n", + (long long)(int)offsetof(struct link_ea_header, leh_padding)); + LASSERTF((int)sizeof(((struct link_ea_header *)0)->leh_padding) == 4, "found %lld\n", + (long long)(int)sizeof(((struct link_ea_header *)0)->leh_padding)); BUILD_BUG_ON(LINK_EA_MAGIC != 0x11EAF1DFUL); /* Checks for struct link_ea_entry */ diff --git a/drivers/staging/media/atomisp/i2c/ap1302.c b/drivers/staging/media/atomisp/i2c/ap1302.c index bacffbe962d4..2f772a020c8b 100644 --- a/drivers/staging/media/atomisp/i2c/ap1302.c +++ b/drivers/staging/media/atomisp/i2c/ap1302.c @@ -11,11 +11,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * */ #include "../include/linux/atomisp.h" @@ -1098,7 +1093,7 @@ static const struct v4l2_ctrl_config ctrls[] = { }, }; -static struct v4l2_subdev_sensor_ops ap1302_sensor_ops = { +static const struct v4l2_subdev_sensor_ops ap1302_sensor_ops = { .g_skip_frames = ap1302_g_skip_frames, }; diff --git a/drivers/staging/media/atomisp/i2c/gc0310.c b/drivers/staging/media/atomisp/i2c/gc0310.c index 350fd7fd5b86..35ed51ffe944 100644 --- a/drivers/staging/media/atomisp/i2c/gc0310.c +++ b/drivers/staging/media/atomisp/i2c/gc0310.c @@ -118,9 +118,8 @@ static int gc0310_write_reg(struct i2c_client *client, u16 data_length, /* high byte goes out first */ *wreg = (u8)(reg & 0xff); - if (data_length == GC0310_8BIT) { + if (data_length == GC0310_8BIT) data[1] = (u8)(val); - } ret = gc0310_i2c_write(client, len, data); if (ret) @@ -1453,7 +1452,7 @@ out_free: return ret; } -static struct acpi_device_id gc0310_acpi_match[] = { +static const struct acpi_device_id gc0310_acpi_match[] = { {"XXGC0310"}, {"INT0310"}, {}, diff --git a/drivers/staging/media/atomisp/i2c/gc2235.c b/drivers/staging/media/atomisp/i2c/gc2235.c index 50f431729b6c..e43d31ea9676 100644 --- a/drivers/staging/media/atomisp/i2c/gc2235.c +++ b/drivers/staging/media/atomisp/i2c/gc2235.c @@ -480,7 +480,7 @@ static const struct v4l2_ctrl_ops ctrl_ops = { .g_volatile_ctrl = gc2235_g_volatile_ctrl }; -struct v4l2_ctrl_config gc2235_controls[] = { +static struct v4l2_ctrl_config gc2235_controls[] = { { .ops = &ctrl_ops, .id = V4L2_CID_EXPOSURE_ABSOLUTE, @@ -1183,7 +1183,7 @@ out_free: return ret; } -static struct acpi_device_id gc2235_acpi_match[] = { +static const struct acpi_device_id gc2235_acpi_match[] = { { "INT33F8" }, {}, }; diff --git a/drivers/staging/media/atomisp/i2c/gc2235.h b/drivers/staging/media/atomisp/i2c/gc2235.h index 7c3d994180cc..a8d6aa9c9a5d 100644 --- a/drivers/staging/media/atomisp/i2c/gc2235.h +++ b/drivers/staging/media/atomisp/i2c/gc2235.h @@ -530,7 +530,7 @@ static struct gc2235_reg const gc2235_1616_1216_30fps[] = { { GC2235_TOK_TERM, 0, 0 } }; -struct gc2235_resolution gc2235_res_preview[] = { +static struct gc2235_resolution gc2235_res_preview[] = { { .desc = "gc2235_1600_900_30fps", @@ -582,7 +582,7 @@ struct gc2235_resolution gc2235_res_preview[] = { }; #define N_RES_PREVIEW (ARRAY_SIZE(gc2235_res_preview)) -struct gc2235_resolution gc2235_res_still[] = { +static struct gc2235_resolution gc2235_res_still[] = { { .desc = "gc2235_1600_900_30fps", .width = 1600, @@ -632,7 +632,7 @@ struct gc2235_resolution gc2235_res_still[] = { }; #define N_RES_STILL (ARRAY_SIZE(gc2235_res_still)) -struct gc2235_resolution gc2235_res_video[] = { +static struct gc2235_resolution gc2235_res_video[] = { { .desc = "gc2235_1296_736_30fps", .width = 1296, diff --git a/drivers/staging/media/atomisp/i2c/imx/ad5816g.c b/drivers/staging/media/atomisp/i2c/imx/ad5816g.c index d68ebb49f002..558dcdf135d9 100644 --- a/drivers/staging/media/atomisp/i2c/imx/ad5816g.c +++ b/drivers/staging/media/atomisp/i2c/imx/ad5816g.c @@ -136,7 +136,7 @@ int ad5816g_vcm_power_down(struct v4l2_subdev *sd) } -int ad5816g_t_focus_vcm(struct v4l2_subdev *sd, u16 val) +static int ad5816g_t_focus_vcm(struct v4l2_subdev *sd, u16 val) { struct i2c_client *client = v4l2_get_subdevdata(sd); u16 data = val & VCM_CODE_MASK; @@ -214,12 +214,3 @@ int ad5816g_t_vcm_timing(struct v4l2_subdev *sd, s32 value) { return 0; } - -int ad5816g_vcm_init(struct v4l2_subdev *sd) -{ - ad5816g_dev.platform_data = camera_get_af_platform_data(); - return (NULL == ad5816g_dev.platform_data) ? -ENODEV : 0; - -} - - diff --git a/drivers/staging/media/atomisp/i2c/imx/drv201.c b/drivers/staging/media/atomisp/i2c/imx/drv201.c index 915e4019cfeb..6d9d4c968722 100644 --- a/drivers/staging/media/atomisp/i2c/imx/drv201.c +++ b/drivers/staging/media/atomisp/i2c/imx/drv201.c @@ -128,7 +128,7 @@ int drv201_vcm_power_down(struct v4l2_subdev *sd) } -int drv201_t_focus_vcm(struct v4l2_subdev *sd, u16 val) +static int drv201_t_focus_vcm(struct v4l2_subdev *sd, u16 val) { struct i2c_client *client = v4l2_get_subdevdata(sd); u16 data = val & VCM_CODE_MASK; @@ -207,12 +207,3 @@ int drv201_t_vcm_timing(struct v4l2_subdev *sd, s32 value) { return 0; } - -int drv201_vcm_init(struct v4l2_subdev *sd) -{ - drv201_dev.platform_data = camera_get_af_platform_data(); - return (NULL == drv201_dev.platform_data) ? -ENODEV : 0; -} - - - diff --git a/drivers/staging/media/atomisp/i2c/imx/dw9714.c b/drivers/staging/media/atomisp/i2c/imx/dw9714.c index b7dee1b6bb37..6397a7ee0af6 100644 --- a/drivers/staging/media/atomisp/i2c/imx/dw9714.c +++ b/drivers/staging/media/atomisp/i2c/imx/dw9714.c @@ -56,7 +56,7 @@ int dw9714_vcm_power_down(struct v4l2_subdev *sd) } -int dw9714_t_focus_vcm(struct v4l2_subdev *sd, u16 val) +static int dw9714_t_focus_vcm(struct v4l2_subdev *sd, u16 val) { struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = -EINVAL; @@ -221,15 +221,3 @@ int dw9714_t_vcm_timing(struct v4l2_subdev *sd, s32 value) return 0; } - -int dw9714_vcm_init(struct v4l2_subdev *sd) -{ - - /* set VCM to home position and vcm mode to direct*/ - dw9714_dev.vcm_mode = DW9714_DIRECT; - dw9714_dev.vcm_settings.update = false; - dw9714_dev.platform_data = camera_get_af_platform_data(); - return (NULL == dw9714_dev.platform_data) ? -ENODEV : 0; - -} - diff --git a/drivers/staging/media/atomisp/i2c/imx/dw9718.c b/drivers/staging/media/atomisp/i2c/imx/dw9718.c index 65a1fcf187d5..c02b9f0a2440 100644 --- a/drivers/staging/media/atomisp/i2c/imx/dw9718.c +++ b/drivers/staging/media/atomisp/i2c/imx/dw9718.c @@ -204,11 +204,6 @@ int dw9718_q_focus_status(struct v4l2_subdev *sd, s32 *value) return 0; } -int dw9718_t_focus_vcm(struct v4l2_subdev *sd, u16 val) -{ - return -EINVAL; -} - int dw9718_t_focus_rel(struct v4l2_subdev *sd, s32 value) { return dw9718_t_focus_abs(sd, dw9718_dev.focus + value); diff --git a/drivers/staging/media/atomisp/i2c/imx/dw9719.c b/drivers/staging/media/atomisp/i2c/imx/dw9719.c index eca2d7640030..565237796bb4 100644 --- a/drivers/staging/media/atomisp/i2c/imx/dw9719.c +++ b/drivers/staging/media/atomisp/i2c/imx/dw9719.c @@ -161,11 +161,6 @@ int dw9719_q_focus_status(struct v4l2_subdev *sd, s32 *value) return 0; } -int dw9719_t_focus_vcm(struct v4l2_subdev *sd, u16 val) -{ - return -EINVAL; -} - int dw9719_t_focus_abs(struct v4l2_subdev *sd, s32 value) { struct i2c_client *client = v4l2_get_subdevdata(sd); @@ -201,9 +196,3 @@ int dw9719_t_vcm_timing(struct v4l2_subdev *sd, s32 value) { return 0; } - -int dw9719_vcm_init(struct v4l2_subdev *sd) -{ - dw9719_dev.platform_data = camera_get_af_platform_data(); - return (NULL == dw9719_dev.platform_data) ? -ENODEV : 0; -} diff --git a/drivers/staging/media/atomisp/i2c/imx/imx.c b/drivers/staging/media/atomisp/i2c/imx/imx.c index 408a7b945153..49ab0af87096 100644 --- a/drivers/staging/media/atomisp/i2c/imx/imx.c +++ b/drivers/staging/media/atomisp/i2c/imx/imx.c @@ -1084,46 +1084,15 @@ static int imx_g_bin_factor_y(struct v4l2_subdev *sd, s32 *val) return 0; } -int imx_vcm_power_up(struct v4l2_subdev *sd) -{ - struct imx_device *dev = to_imx_sensor(sd); - if (dev->vcm_driver && dev->vcm_driver->power_up) - return dev->vcm_driver->power_up(sd); - return 0; -} - -int imx_vcm_power_down(struct v4l2_subdev *sd) -{ - struct imx_device *dev = to_imx_sensor(sd); - if (dev->vcm_driver && dev->vcm_driver->power_down) - return dev->vcm_driver->power_down(sd); - return 0; -} - -int imx_vcm_init(struct v4l2_subdev *sd) -{ - struct imx_device *dev = to_imx_sensor(sd); - if (dev->vcm_driver && dev->vcm_driver->init) - return dev->vcm_driver->init(sd); - return 0; -} - -int imx_t_focus_vcm(struct v4l2_subdev *sd, u16 val) -{ - struct imx_device *dev = to_imx_sensor(sd); - if (dev->vcm_driver && dev->vcm_driver->t_focus_vcm) - return dev->vcm_driver->t_focus_vcm(sd, val); - return 0; -} - -int imx_t_focus_abs(struct v4l2_subdev *sd, s32 value) +static int imx_t_focus_abs(struct v4l2_subdev *sd, s32 value) { struct imx_device *dev = to_imx_sensor(sd); if (dev->vcm_driver && dev->vcm_driver->t_focus_abs) return dev->vcm_driver->t_focus_abs(sd, value); return 0; } -int imx_t_focus_rel(struct v4l2_subdev *sd, s32 value) + +static int imx_t_focus_rel(struct v4l2_subdev *sd, s32 value) { struct imx_device *dev = to_imx_sensor(sd); if (dev->vcm_driver && dev->vcm_driver->t_focus_rel) @@ -1131,7 +1100,7 @@ int imx_t_focus_rel(struct v4l2_subdev *sd, s32 value) return 0; } -int imx_q_focus_status(struct v4l2_subdev *sd, s32 *value) +static int imx_q_focus_status(struct v4l2_subdev *sd, s32 *value) { struct imx_device *dev = to_imx_sensor(sd); if (dev->vcm_driver && dev->vcm_driver->q_focus_status) @@ -1139,7 +1108,7 @@ int imx_q_focus_status(struct v4l2_subdev *sd, s32 *value) return 0; } -int imx_q_focus_abs(struct v4l2_subdev *sd, s32 *value) +static int imx_q_focus_abs(struct v4l2_subdev *sd, s32 *value) { struct imx_device *dev = to_imx_sensor(sd); if (dev->vcm_driver && dev->vcm_driver->q_focus_abs) @@ -1147,7 +1116,7 @@ int imx_q_focus_abs(struct v4l2_subdev *sd, s32 *value) return 0; } -int imx_t_vcm_slew(struct v4l2_subdev *sd, s32 value) +static int imx_t_vcm_slew(struct v4l2_subdev *sd, s32 value) { struct imx_device *dev = to_imx_sensor(sd); if (dev->vcm_driver && dev->vcm_driver->t_vcm_slew) @@ -1155,7 +1124,7 @@ int imx_t_vcm_slew(struct v4l2_subdev *sd, s32 value) return 0; } -int imx_t_vcm_timing(struct v4l2_subdev *sd, s32 value) +static int imx_t_vcm_timing(struct v4l2_subdev *sd, s32 value) { struct imx_device *dev = to_imx_sensor(sd); if (dev->vcm_driver && dev->vcm_driver->t_vcm_timing) @@ -2105,8 +2074,7 @@ imx_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *param) return 0; } -int -imx_g_frame_interval(struct v4l2_subdev *sd, +static int imx_g_frame_interval(struct v4l2_subdev *sd, struct v4l2_subdev_frame_interval *interval) { struct imx_device *dev = to_imx_sensor(sd); diff --git a/drivers/staging/media/atomisp/i2c/imx/imx.h b/drivers/staging/media/atomisp/i2c/imx/imx.h index 41b4133ca995..30beb2a0ed93 100644 --- a/drivers/staging/media/atomisp/i2c/imx/imx.h +++ b/drivers/staging/media/atomisp/i2c/imx/imx.h @@ -222,8 +222,6 @@ struct imx_vcm { int (*power_up)(struct v4l2_subdev *sd); int (*power_down)(struct v4l2_subdev *sd); - int (*init)(struct v4l2_subdev *sd); - int (*t_focus_vcm)(struct v4l2_subdev *sd, u16 val); int (*t_focus_abs)(struct v4l2_subdev *sd, s32 value); int (*t_focus_abs_init)(struct v4l2_subdev *sd); int (*t_focus_rel)(struct v4l2_subdev *sd, s32 value); @@ -549,9 +547,6 @@ static const struct imx_reg imx219_param_update[] = { extern int ad5816g_vcm_power_up(struct v4l2_subdev *sd); extern int ad5816g_vcm_power_down(struct v4l2_subdev *sd); -extern int ad5816g_vcm_init(struct v4l2_subdev *sd); - -extern int ad5816g_t_focus_vcm(struct v4l2_subdev *sd, u16 val); extern int ad5816g_t_focus_abs(struct v4l2_subdev *sd, s32 value); extern int ad5816g_t_focus_rel(struct v4l2_subdev *sd, s32 value); extern int ad5816g_q_focus_status(struct v4l2_subdev *sd, s32 *value); @@ -561,9 +556,6 @@ extern int ad5816g_t_vcm_timing(struct v4l2_subdev *sd, s32 value); extern int drv201_vcm_power_up(struct v4l2_subdev *sd); extern int drv201_vcm_power_down(struct v4l2_subdev *sd); -extern int drv201_vcm_init(struct v4l2_subdev *sd); - -extern int drv201_t_focus_vcm(struct v4l2_subdev *sd, u16 val); extern int drv201_t_focus_abs(struct v4l2_subdev *sd, s32 value); extern int drv201_t_focus_rel(struct v4l2_subdev *sd, s32 value); extern int drv201_q_focus_status(struct v4l2_subdev *sd, s32 *value); @@ -573,9 +565,6 @@ extern int drv201_t_vcm_timing(struct v4l2_subdev *sd, s32 value); extern int dw9714_vcm_power_up(struct v4l2_subdev *sd); extern int dw9714_vcm_power_down(struct v4l2_subdev *sd); -extern int dw9714_vcm_init(struct v4l2_subdev *sd); - -extern int dw9714_t_focus_vcm(struct v4l2_subdev *sd, u16 val); extern int dw9714_t_focus_abs(struct v4l2_subdev *sd, s32 value); extern int dw9714_t_focus_abs_init(struct v4l2_subdev *sd); extern int dw9714_t_focus_rel(struct v4l2_subdev *sd, s32 value); @@ -586,9 +575,6 @@ extern int dw9714_t_vcm_timing(struct v4l2_subdev *sd, s32 value); extern int dw9719_vcm_power_up(struct v4l2_subdev *sd); extern int dw9719_vcm_power_down(struct v4l2_subdev *sd); -extern int dw9719_vcm_init(struct v4l2_subdev *sd); - -extern int dw9719_t_focus_vcm(struct v4l2_subdev *sd, u16 val); extern int dw9719_t_focus_abs(struct v4l2_subdev *sd, s32 value); extern int dw9719_t_focus_rel(struct v4l2_subdev *sd, s32 value); extern int dw9719_q_focus_status(struct v4l2_subdev *sd, s32 *value); @@ -598,9 +584,6 @@ extern int dw9719_t_vcm_timing(struct v4l2_subdev *sd, s32 value); extern int dw9718_vcm_power_up(struct v4l2_subdev *sd); extern int dw9718_vcm_power_down(struct v4l2_subdev *sd); -extern int dw9718_vcm_init(struct v4l2_subdev *sd); - -extern int dw9718_t_focus_vcm(struct v4l2_subdev *sd, u16 val); extern int dw9718_t_focus_abs(struct v4l2_subdev *sd, s32 value); extern int dw9718_t_focus_rel(struct v4l2_subdev *sd, s32 value); extern int dw9718_q_focus_status(struct v4l2_subdev *sd, s32 *value); @@ -615,8 +598,6 @@ struct imx_vcm imx_vcms[] = { [IMX175_MERRFLD] = { .power_up = drv201_vcm_power_up, .power_down = drv201_vcm_power_down, - .init = drv201_vcm_init, - .t_focus_vcm = drv201_t_focus_vcm, .t_focus_abs = drv201_t_focus_abs, .t_focus_abs_init = NULL, .t_focus_rel = drv201_t_focus_rel, @@ -628,8 +609,6 @@ struct imx_vcm imx_vcms[] = { [IMX175_VALLEYVIEW] = { .power_up = dw9714_vcm_power_up, .power_down = dw9714_vcm_power_down, - .init = dw9714_vcm_init, - .t_focus_vcm = dw9714_t_focus_vcm, .t_focus_abs = dw9714_t_focus_abs, .t_focus_abs_init = NULL, .t_focus_rel = dw9714_t_focus_rel, @@ -641,8 +620,6 @@ struct imx_vcm imx_vcms[] = { [IMX135_SALTBAY] = { .power_up = ad5816g_vcm_power_up, .power_down = ad5816g_vcm_power_down, - .init = ad5816g_vcm_init, - .t_focus_vcm = ad5816g_t_focus_vcm, .t_focus_abs = ad5816g_t_focus_abs, .t_focus_abs_init = NULL, .t_focus_rel = ad5816g_t_focus_rel, @@ -654,8 +631,6 @@ struct imx_vcm imx_vcms[] = { [IMX135_VICTORIABAY] = { .power_up = dw9719_vcm_power_up, .power_down = dw9719_vcm_power_down, - .init = dw9719_vcm_init, - .t_focus_vcm = dw9719_t_focus_vcm, .t_focus_abs = dw9719_t_focus_abs, .t_focus_abs_init = NULL, .t_focus_rel = dw9719_t_focus_rel, @@ -667,8 +642,6 @@ struct imx_vcm imx_vcms[] = { [IMX134_VALLEYVIEW] = { .power_up = dw9714_vcm_power_up, .power_down = dw9714_vcm_power_down, - .init = dw9714_vcm_init, - .t_focus_vcm = dw9714_t_focus_vcm, .t_focus_abs = dw9714_t_focus_abs, .t_focus_abs_init = dw9714_t_focus_abs_init, .t_focus_rel = dw9714_t_focus_rel, @@ -680,8 +653,6 @@ struct imx_vcm imx_vcms[] = { [IMX219_MFV0_PRH] = { .power_up = dw9718_vcm_power_up, .power_down = dw9718_vcm_power_down, - .init = dw9718_vcm_init, - .t_focus_vcm = dw9718_t_focus_vcm, .t_focus_abs = dw9718_t_focus_abs, .t_focus_abs_init = NULL, .t_focus_rel = dw9718_t_focus_rel, diff --git a/drivers/staging/media/atomisp/i2c/lm3554.c b/drivers/staging/media/atomisp/i2c/lm3554.c index 2b170c07aaba..679176f7c542 100644 --- a/drivers/staging/media/atomisp/i2c/lm3554.c +++ b/drivers/staging/media/atomisp/i2c/lm3554.c @@ -974,7 +974,7 @@ static const struct dev_pm_ops lm3554_pm_ops = { .resume = lm3554_resume, }; -static struct acpi_device_id lm3554_acpi_match[] = { +static const struct acpi_device_id lm3554_acpi_match[] = { { "INTCF1C" }, {}, }; diff --git a/drivers/staging/media/atomisp/i2c/mt9m114.c b/drivers/staging/media/atomisp/i2c/mt9m114.c index 3fa915313e53..3c837cb8859c 100644 --- a/drivers/staging/media/atomisp/i2c/mt9m114.c +++ b/drivers/staging/media/atomisp/i2c/mt9m114.c @@ -1209,10 +1209,10 @@ static int mt9m114_s_exposure_selection(struct v4l2_subdev *sd, return -EINVAL; } - clamp_t(int, win_left, 0, 4); - clamp_t(int, win_top, 0, 4); - clamp_t(int, win_right, 0, 4); - clamp_t(int, win_bottom, 0, 4); + win_left = clamp_t(int, win_left, 0, 4); + win_top = clamp_t(int, win_top, 0, 4); + win_right = clamp_t(int, win_right, 0, 4); + win_bottom = clamp_t(int, win_bottom, 0, 4); ret = mt9m114_write_reg_array(client, mt9m114_exp_average, NO_POLLING); if (ret) { @@ -1806,7 +1806,7 @@ static const struct v4l2_subdev_video_ops mt9m114_video_ops = { .g_frame_interval = mt9m114_g_frame_interval, }; -static struct v4l2_subdev_sensor_ops mt9m114_sensor_ops = { +static const struct v4l2_subdev_sensor_ops mt9m114_sensor_ops = { .g_skip_frames = mt9m114_g_skip_frames, }; @@ -1928,7 +1928,7 @@ static int mt9m114_probe(struct i2c_client *client, MODULE_DEVICE_TABLE(i2c, mt9m114_id); -static struct acpi_device_id mt9m114_acpi_match[] = { +static const struct acpi_device_id mt9m114_acpi_match[] = { { "INT33F0" }, { "CRMT1040" }, {}, diff --git a/drivers/staging/media/atomisp/i2c/ov2680.c b/drivers/staging/media/atomisp/i2c/ov2680.c index 3cabfe54c669..51b7d61df0f5 100644 --- a/drivers/staging/media/atomisp/i2c/ov2680.c +++ b/drivers/staging/media/atomisp/i2c/ov2680.c @@ -89,7 +89,7 @@ static int ov2680_read_reg(struct i2c_client *client, "read from offset 0x%x error %d", reg, err); return err; } - + *val = 0; /* high byte comes first */ if (data_length == OV2680_8BIT) @@ -285,7 +285,6 @@ static int ov2680_g_fnumber(struct v4l2_subdev *sd, s32 *val) static int ov2680_g_fnumber_range(struct v4l2_subdev *sd, s32 *val) { - *val = (OV2680_F_NUMBER_DEFAULT_NUM << 24) | (OV2680_F_NUMBER_DEM << 16) | (OV2680_F_NUMBER_DEFAULT_NUM << 8) | OV2680_F_NUMBER_DEM; @@ -306,7 +305,7 @@ static int ov2680_g_bin_factor_y(struct v4l2_subdev *sd, s32 *val) { struct ov2680_device *dev = to_ov2680_sensor(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); - + *val = ov2680_res[dev->fmt_idx].bin_factor_y; dev_dbg(&client->dev, "++++ov2680_g_bin_factor_y\n"); return 0; @@ -399,7 +398,7 @@ static long __ov2680_set_exposure(struct v4l2_subdev *sd, int coarse_itg, struct ov2680_device *dev = to_ov2680_sensor(sd); u16 vts,hts; int ret,exp_val; - + dev_dbg(&client->dev, "+++++++__ov2680_set_exposure coarse_itg %d, gain %d, digitgain %d++\n",coarse_itg, gain, digitgain); hts = ov2680_res[dev->fmt_idx].pixels_per_line; @@ -542,7 +541,7 @@ static long ov2680_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) switch (cmd) { case ATOMISP_IOC_S_EXPOSURE: return ov2680_s_exposure(sd, arg); - + default: return -EINVAL; } @@ -983,7 +982,7 @@ static int ov2680_s_power(struct v4l2_subdev *sd, int on) if (on == 0){ ret = power_down(sd); } else { - ret = power_up(sd); + ret = power_up(sd); if (!ret) return ov2680_init(sd); } @@ -1207,7 +1206,7 @@ static int ov2680_s_stream(struct v4l2_subdev *sd, int enable) dev_dbg(&client->dev, "ov2680_s_stream one \n"); else dev_dbg(&client->dev, "ov2680_s_stream off \n"); - + ret = ov2680_write_reg(client, OV2680_8BIT, OV2680_SW_STREAM, enable ? OV2680_START_STREAMING : OV2680_STOP_STREAMING); @@ -1267,7 +1266,7 @@ static int ov2680_s_config(struct v4l2_subdev *sd, dev_err(&client->dev, "ov2680_detect err s_config.\n"); goto fail_csi_cfg; } - + /* turn off sensor, after probed */ ret = power_down(sd); if (ret) { @@ -1385,7 +1384,7 @@ static int ov2680_enum_frame_size(struct v4l2_subdev *sd, static int ov2680_g_skip_frames(struct v4l2_subdev *sd, u32 *frames) { struct ov2680_device *dev = to_ov2680_sensor(sd); - + mutex_lock(&dev->input_lock); *frames = ov2680_res[dev->fmt_idx].skip_frames; mutex_unlock(&dev->input_lock); @@ -1517,7 +1516,7 @@ out_free: return ret; } -static struct acpi_device_id ov2680_acpi_match[] = { +static const struct acpi_device_id ov2680_acpi_match[] = { {"XXOV2680"}, {"OVTI2680"}, {}, diff --git a/drivers/staging/media/atomisp/i2c/ov2722.c b/drivers/staging/media/atomisp/i2c/ov2722.c index b7afadebdf89..10094ac56561 100644 --- a/drivers/staging/media/atomisp/i2c/ov2722.c +++ b/drivers/staging/media/atomisp/i2c/ov2722.c @@ -1337,7 +1337,7 @@ out_free: MODULE_DEVICE_TABLE(i2c, ov2722_id); -static struct acpi_device_id ov2722_acpi_match[] = { +static const struct acpi_device_id ov2722_acpi_match[] = { { "INT33FB" }, {}, }; diff --git a/drivers/staging/media/atomisp/i2c/ov5693/ov5693.c b/drivers/staging/media/atomisp/i2c/ov5693/ov5693.c index d6447398f5ef..123642557aa8 100644 --- a/drivers/staging/media/atomisp/i2c/ov5693/ov5693.c +++ b/drivers/staging/media/atomisp/i2c/ov5693/ov5693.c @@ -146,7 +146,7 @@ static int ov5693_read_reg(struct i2c_client *client, return -EINVAL; } - memset(msg, 0 , sizeof(msg)); + memset(msg, 0, sizeof(msg)); msg[0].addr = client->addr; msg[0].flags = 0; @@ -702,7 +702,7 @@ static long ov5693_s_exposure(struct v4l2_subdev *sd, } static int ov5693_read_otp_reg_array(struct i2c_client *client, u16 size, - u16 addr, u8 * buf) + u16 addr, u8 *buf) { u16 index; int ret; @@ -720,7 +720,7 @@ static int ov5693_read_otp_reg_array(struct i2c_client *client, u16 size, return 0; } -static int __ov5693_otp_read(struct v4l2_subdev *sd, u8 * buf) +static int __ov5693_otp_read(struct v4l2_subdev *sd, u8 *buf) { struct i2c_client *client = v4l2_get_subdevdata(sd); struct ov5693_device *dev = to_ov5693_sensor(sd); @@ -913,7 +913,7 @@ err: return ret; } -int ad5823_t_focus_vcm(struct v4l2_subdev *sd, u16 val) +static int ad5823_t_focus_vcm(struct v4l2_subdev *sd, u16 val) { struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = -EINVAL; @@ -2032,7 +2032,7 @@ out_free: MODULE_DEVICE_TABLE(i2c, ov5693_id); -static struct acpi_device_id ov5693_acpi_match[] = { +static const struct acpi_device_id ov5693_acpi_match[] = { {"INT33BE"}, {}, }; diff --git a/drivers/staging/media/atomisp/i2c/ov8858.c b/drivers/staging/media/atomisp/i2c/ov8858.c index 9574bc49113c..43e1638fd674 100644 --- a/drivers/staging/media/atomisp/i2c/ov8858.c +++ b/drivers/staging/media/atomisp/i2c/ov8858.c @@ -2189,7 +2189,7 @@ static const struct i2c_device_id ov8858_id[] = { MODULE_DEVICE_TABLE(i2c, ov8858_id); -static struct acpi_device_id ov8858_acpi_match[] = { +static const struct acpi_device_id ov8858_acpi_match[] = { {"INT3477"}, {}, }; diff --git a/drivers/staging/media/atomisp/i2c/ov8858.h b/drivers/staging/media/atomisp/i2c/ov8858.h index d3fde200c013..638d1a803a2b 100644 --- a/drivers/staging/media/atomisp/i2c/ov8858.h +++ b/drivers/staging/media/atomisp/i2c/ov8858.h @@ -164,7 +164,6 @@ struct ov8858_vcm { int (*power_up)(struct v4l2_subdev *sd); int (*power_down)(struct v4l2_subdev *sd); int (*init)(struct v4l2_subdev *sd); - int (*t_focus_vcm)(struct v4l2_subdev *sd, u16 val); int (*t_focus_abs)(struct v4l2_subdev *sd, s32 value); int (*t_focus_rel)(struct v4l2_subdev *sd, s32 value); int (*q_focus_status)(struct v4l2_subdev *sd, s32 *value); @@ -312,7 +311,6 @@ static const struct ov8858_reg ov8858_param_update[] = { extern int dw9718_vcm_power_up(struct v4l2_subdev *sd); extern int dw9718_vcm_power_down(struct v4l2_subdev *sd); extern int dw9718_vcm_init(struct v4l2_subdev *sd); -extern int dw9718_t_focus_vcm(struct v4l2_subdev *sd, u16 val); extern int dw9718_t_focus_abs(struct v4l2_subdev *sd, s32 value); extern int dw9718_t_focus_rel(struct v4l2_subdev *sd, s32 value); extern int dw9718_q_focus_status(struct v4l2_subdev *sd, s32 *value); @@ -328,7 +326,6 @@ static struct ov8858_vcm ov8858_vcms[] = { .power_up = dw9718_vcm_power_up, .power_down = dw9718_vcm_power_down, .init = dw9718_vcm_init, - .t_focus_vcm = dw9718_t_focus_vcm, .t_focus_abs = dw9718_t_focus_abs, .t_focus_rel = dw9718_t_focus_rel, .q_focus_status = dw9718_q_focus_status, diff --git a/drivers/staging/media/atomisp/i2c/ov8858_btns.h b/drivers/staging/media/atomisp/i2c/ov8858_btns.h index f9a3cf8fbf1a..7d74a8899fae 100644 --- a/drivers/staging/media/atomisp/i2c/ov8858_btns.h +++ b/drivers/staging/media/atomisp/i2c/ov8858_btns.h @@ -164,7 +164,6 @@ struct ov8858_vcm { int (*power_up)(struct v4l2_subdev *sd); int (*power_down)(struct v4l2_subdev *sd); int (*init)(struct v4l2_subdev *sd); - int (*t_focus_vcm)(struct v4l2_subdev *sd, u16 val); int (*t_focus_abs)(struct v4l2_subdev *sd, s32 value); int (*t_focus_rel)(struct v4l2_subdev *sd, s32 value); int (*q_focus_status)(struct v4l2_subdev *sd, s32 *value); @@ -312,7 +311,6 @@ static const struct ov8858_reg ov8858_param_update[] = { extern int dw9718_vcm_power_up(struct v4l2_subdev *sd); extern int dw9718_vcm_power_down(struct v4l2_subdev *sd); extern int dw9718_vcm_init(struct v4l2_subdev *sd); -extern int dw9718_t_focus_vcm(struct v4l2_subdev *sd, u16 val); extern int dw9718_t_focus_abs(struct v4l2_subdev *sd, s32 value); extern int dw9718_t_focus_rel(struct v4l2_subdev *sd, s32 value); extern int dw9718_q_focus_status(struct v4l2_subdev *sd, s32 *value); @@ -328,7 +326,6 @@ static struct ov8858_vcm ov8858_vcms[] = { .power_up = dw9718_vcm_power_up, .power_down = dw9718_vcm_power_down, .init = dw9718_vcm_init, - .t_focus_vcm = dw9718_t_focus_vcm, .t_focus_abs = dw9718_t_focus_abs, .t_focus_rel = dw9718_t_focus_rel, .q_focus_status = dw9718_q_focus_status, diff --git a/drivers/staging/media/atomisp/include/linux/atomisp.h b/drivers/staging/media/atomisp/include/linux/atomisp.h index 35865462ccf9..d67dd658cff9 100644 --- a/drivers/staging/media/atomisp/include/linux/atomisp.h +++ b/drivers/staging/media/atomisp/include/linux/atomisp.h @@ -28,12 +28,6 @@ #include <linux/types.h> #include <linux/version.h> -/* struct media_device_info.driver_version */ -#define ATOMISP_CSS_VERSION_MASK 0x00ffffff -#define ATOMISP_CSS_VERSION_15 KERNEL_VERSION(1, 5, 0) -#define ATOMISP_CSS_VERSION_20 KERNEL_VERSION(2, 0, 0) -#define ATOMISP_CSS_VERSION_21 KERNEL_VERSION(2, 1, 0) - /* struct media_device_info.hw_revision */ #define ATOMISP_HW_REVISION_MASK 0x0000ff00 #define ATOMISP_HW_REVISION_SHIFT 8 diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_cmd.c b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_cmd.c index 97093baf28ac..f48bf451c1f5 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_cmd.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_cmd.c @@ -83,48 +83,6 @@ union host { }; /* - * atomisp_kernel_malloc: chooses whether kmalloc() or vmalloc() is preferable. - * - * It is also a wrap functions to pass into css framework. - */ -void *atomisp_kernel_malloc(size_t bytes) -{ - /* vmalloc() is preferable if allocating more than 1 page */ - if (bytes > PAGE_SIZE) - return vmalloc(bytes); - - return kmalloc(bytes, GFP_KERNEL); -} - -/* - * atomisp_kernel_zalloc: chooses whether set 0 to the allocated memory. - * - * It is also a wrap functions to pass into css framework. - */ -void *atomisp_kernel_zalloc(size_t bytes, bool zero_mem) -{ - void *ptr = atomisp_kernel_malloc(bytes); - - if (ptr && zero_mem) - memset(ptr, 0, bytes); - - return ptr; -} - -/* - * Free buffer allocated with atomisp_kernel_malloc()/atomisp_kernel_zalloc - * helper - */ -void atomisp_kernel_free(void *ptr) -{ - /* Verify if buffer was allocated by vmalloc() or kmalloc() */ - if (is_vmalloc_addr(ptr)) - vfree(ptr); - else - kfree(ptr); -} - -/* * get sensor:dis71430/ov2720 related info from v4l2_subdev->priv data field. * subdev->priv is set in mrst.c */ @@ -785,7 +743,7 @@ void atomisp_flush_params_queue(struct atomisp_video_pipe *pipe) struct atomisp_css_params_with_list, list); list_del(¶m->list); atomisp_free_css_parameters(¶m->params); - atomisp_kernel_free(param); + kvfree(param); } } @@ -1132,7 +1090,7 @@ void atomisp_buf_done(struct atomisp_sub_device *asd, int error, asd->params.dvs_6axis = NULL; atomisp_free_css_parameters( &pipe->frame_params[vb->i]->params); - atomisp_kernel_free(pipe->frame_params[vb->i]); + kvfree(pipe->frame_params[vb->i]); pipe->frame_params[vb->i] = NULL; } @@ -4329,7 +4287,7 @@ int atomisp_set_parameters(struct video_device *vdev, * are ready, the parameters will be set to CSS. * per-frame setting only works for the main output frame. */ - param = atomisp_kernel_zalloc(sizeof(*param), true); + param = kvzalloc(sizeof(*param), GFP_KERNEL); if (!param) { dev_err(asd->isp->dev, "%s: failed to alloc params buffer\n", __func__); @@ -4375,7 +4333,7 @@ apply_parameter_failed: if (css_param) atomisp_free_css_parameters(css_param); if (param) - atomisp_kernel_free(param); + kvfree(param); return ret; } diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_cmd.h b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_cmd.h index 8e6d9df7ad1a..31ba4e613d13 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_cmd.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_cmd.h @@ -78,9 +78,6 @@ static inline void __iomem *atomisp_get_io_virt_addr(unsigned int address) return ret; } */ -void *atomisp_kernel_malloc(size_t bytes); -void *atomisp_kernel_zalloc(size_t bytes, bool zero_mem); -void atomisp_kernel_free(void *ptr); /* * Interrupt functions diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_css20.c b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_css20.c index ad2c610d2ce3..05897b747349 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_css20.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_css20.c @@ -1671,12 +1671,12 @@ int atomisp_alloc_metadata_output_buf(struct atomisp_sub_device *asd) /* We allocate the cpu-side buffer used for communication with user * space */ for (i = 0; i < ATOMISP_METADATA_TYPE_NUM; i++) { - asd->params.metadata_user[i] = atomisp_kernel_malloc( + asd->params.metadata_user[i] = kvmalloc( asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]. - stream_info.metadata_info.size); + stream_info.metadata_info.size, GFP_KERNEL); if (!asd->params.metadata_user[i]) { while (--i >= 0) { - atomisp_kernel_free(asd->params.metadata_user[i]); + kvfree(asd->params.metadata_user[i]); asd->params.metadata_user[i] = NULL; } return -ENOMEM; @@ -1692,7 +1692,7 @@ void atomisp_free_metadata_output_buf(struct atomisp_sub_device *asd) for (i = 0; i < ATOMISP_METADATA_TYPE_NUM; i++) { if (asd->params.metadata_user[i]) { - atomisp_kernel_free(asd->params.metadata_user[i]); + kvfree(asd->params.metadata_user[i]); asd->params.metadata_user[i] = NULL; } } diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_fops.c b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_fops.c index c151c848cf8f..d8cfed358d55 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_fops.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_fops.c @@ -643,14 +643,14 @@ static void atomisp_buf_release_output(struct videobuf_queue *vq, vb->state = VIDEOBUF_NEEDS_INIT; } -static struct videobuf_queue_ops videobuf_qops = { +static const struct videobuf_queue_ops videobuf_qops = { .buf_setup = atomisp_buf_setup, .buf_prepare = atomisp_buf_prepare, .buf_queue = atomisp_buf_queue, .buf_release = atomisp_buf_release, }; -static struct videobuf_queue_ops videobuf_qops_output = { +static const struct videobuf_queue_ops videobuf_qops_output = { .buf_setup = atomisp_buf_setup_output, .buf_prepare = atomisp_buf_prepare_output, .buf_queue = atomisp_buf_queue_output, diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_internal.h b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_internal.h index c8e0c4fe3717..7542a72f1d0f 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_internal.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_internal.h @@ -75,15 +75,6 @@ #define ATOMISP_PCI_REV_MRFLD_A0_MAX 0 #define ATOMISP_PCI_REV_BYT_A0_MAX 4 -#define ATOMISP_MAJOR 0 -#define ATOMISP_MINOR 5 -#define ATOMISP_PATCHLEVEL 1 - -#define DRIVER_VERSION_STR __stringify(ATOMISP_MAJOR) \ - "." __stringify(ATOMISP_MINOR) "." __stringify(ATOMISP_PATCHLEVEL) -#define DRIVER_VERSION KERNEL_VERSION(ATOMISP_MAJOR, \ - ATOMISP_MINOR, ATOMISP_PATCHLEVEL) - #define ATOM_ISP_STEP_WIDTH 2 #define ATOM_ISP_STEP_HEIGHT 2 @@ -310,10 +301,6 @@ struct atomisp_device { extern struct device *atomisp_dev; -extern void *atomisp_kernel_malloc(size_t bytes); - -extern void atomisp_kernel_free(void *ptr); - #define atomisp_is_wdt_running(a) timer_pending(&(a)->wdt) #ifdef ISP2401 extern void atomisp_wdt_refresh_pipe(struct atomisp_video_pipe *pipe, diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_ioctl.c b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_ioctl.c index aa0526ebaff1..717647951fb6 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_ioctl.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_ioctl.c @@ -51,7 +51,6 @@ static const char *DRIVER = "atomisp"; /* max size 15 */ static const char *CARD = "ATOM ISP"; /* max size 31 */ static const char *BUS_INFO = "PCI-3"; /* max size 31 */ -static const u32 VERSION = DRIVER_VERSION; /* * FIXME: ISP should not know beforehand all CIDs supported by sensor. @@ -562,8 +561,6 @@ static int atomisp_querycap(struct file *file, void *fh, strncpy(cap->card, CARD, sizeof(cap->card) - 1); strncpy(cap->bus_info, BUS_INFO, sizeof(cap->card) - 1); - cap->version = VERSION; - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_OUTPUT; cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_subdev.c b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_subdev.c index 3d6bb166927c..744ab6eb42a0 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_subdev.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_subdev.c @@ -1253,8 +1253,7 @@ int atomisp_create_pads_links(struct atomisp_device *isp) { struct atomisp_sub_device *asd; int i, j, ret = 0; - isp->num_of_streams = isp->media_dev.driver_version >= - ATOMISP_CSS_VERSION_20 ? 2 : 1; + isp->num_of_streams = 2; for (i = 0; i < ATOMISP_CAMERA_NR_PORTS; i++) { for (j = 0; j < isp->num_of_streams; j++) { ret = @@ -1414,8 +1413,7 @@ int atomisp_subdev_init(struct atomisp_device *isp) * CSS2.0 running ISP2400 support * multiple streams */ - isp->num_of_streams = isp->media_dev.driver_version >= - ATOMISP_CSS_VERSION_20 ? 2 : 1; + isp->num_of_streams = 2; isp->asd = devm_kzalloc(isp->dev, sizeof(struct atomisp_sub_device) * isp->num_of_streams, GFP_KERNEL); if (!isp->asd) diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_v4l2.c b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_v4l2.c index a543def739fc..663aa916e3ca 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_v4l2.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_v4l2.c @@ -1083,27 +1083,23 @@ atomisp_load_firmware(struct atomisp_device *isp) if (skip_fwload) return NULL; - if (isp->media_dev.driver_version == ATOMISP_CSS_VERSION_21) { - if (isp->media_dev.hw_revision == - ((ATOMISP_HW_REVISION_ISP2401 << ATOMISP_HW_REVISION_SHIFT) - | ATOMISP_HW_STEPPING_A0)) - fw_path = "shisp_2401a0_v21.bin"; - - if (isp->media_dev.hw_revision == - ((ATOMISP_HW_REVISION_ISP2401_LEGACY << ATOMISP_HW_REVISION_SHIFT) - | ATOMISP_HW_STEPPING_A0)) - fw_path = "shisp_2401a0_legacy_v21.bin"; - - if (isp->media_dev.hw_revision == - ((ATOMISP_HW_REVISION_ISP2400 << ATOMISP_HW_REVISION_SHIFT) - | ATOMISP_HW_STEPPING_B0)) - fw_path = "shisp_2400b0_v21.bin"; - } + if (isp->media_dev.hw_revision == + ((ATOMISP_HW_REVISION_ISP2401 << ATOMISP_HW_REVISION_SHIFT) + | ATOMISP_HW_STEPPING_A0)) + fw_path = "shisp_2401a0_v21.bin"; + + if (isp->media_dev.hw_revision == + ((ATOMISP_HW_REVISION_ISP2401_LEGACY << ATOMISP_HW_REVISION_SHIFT) + | ATOMISP_HW_STEPPING_A0)) + fw_path = "shisp_2401a0_legacy_v21.bin"; + + if (isp->media_dev.hw_revision == + ((ATOMISP_HW_REVISION_ISP2400 << ATOMISP_HW_REVISION_SHIFT) + | ATOMISP_HW_STEPPING_B0)) + fw_path = "shisp_2400b0_v21.bin"; if (!fw_path) { - dev_err(isp->dev, - "Unsupported driver_version 0x%x, hw_revision 0x%x\n", - isp->media_dev.driver_version, + dev_err(isp->dev, "Unsupported hw_revision 0x%x\n", isp->media_dev.hw_revision); return NULL; } @@ -1251,7 +1247,6 @@ static int atomisp_pci_probe(struct pci_dev *dev, /* This is not a true PCI device on SoC, so the delay is not needed. */ isp->pdev->d3_delay = 0; - isp->media_dev.driver_version = ATOMISP_CSS_VERSION_21; switch (id->device & ATOMISP_PCI_DEVICE_SOC_MASK) { case ATOMISP_PCI_DEVICE_SOC_MRFLD: isp->media_dev.hw_revision = diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/isys/src/ibuf_ctrl_rmgr.c b/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/isys/src/ibuf_ctrl_rmgr.c index 76d9142fd37e..faef97672eac 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/isys/src/ibuf_ctrl_rmgr.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/isys/src/ibuf_ctrl_rmgr.c @@ -14,18 +14,18 @@ */ #else /** -Support for Intel Camera Imaging ISP subsystem. -Copyright (c) 2010 - 2015, Intel Corporation. - -This program is free software; you can redistribute it and/or modify it -under the terms and conditions of the GNU General Public License, -version 2, as published by the Free Software Foundation. - -This program is distributed in the hope it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -more details. -*/ + * Support for Intel Camera Imaging ISP subsystem. + * Copyright (c) 2010 - 2015, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ #endif #include "system_global.h" @@ -130,8 +130,7 @@ void ia_css_isys_ibuf_rmgr_release( for (i = 0; i < ibuf_rsrc.num_allocated; i++) { handle = getHandle(i); - if ((handle->start_addr == *start_addr) - && ( true == handle->active)) { + if (handle->active && handle->start_addr == *start_addr) { handle->active = false; ibuf_rsrc.num_active--; break; diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css.c b/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css.c index 471f2be974e2..e882b5596813 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css.c @@ -1939,6 +1939,7 @@ void *sh_css_calloc(size_t N, size_t size) p = sh_css_malloc(N*size); if (p) memset(p, 0, size); + return p; } return NULL; } diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_firmware.c b/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_firmware.c index eecd8cf71951..63582161050a 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_firmware.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_firmware.c @@ -131,14 +131,10 @@ sh_css_load_blob_info(const char *fw, const struct ia_css_fw_info *bi, struct ia if (bi->type == ia_css_isp_firmware || bi->type == ia_css_sp_firmware) { char *namebuffer; - int namelength = (int)strlen(name); - namebuffer = (char *) kmalloc(namelength + 1, GFP_KERNEL); - if (namebuffer == NULL) + namebuffer = kstrdup(name, GFP_KERNEL); + if (!namebuffer) return IA_CSS_ERR_CANNOT_ALLOCATE_MEMORY; - - memcpy(namebuffer, name, namelength + 1); - bd->name = fw_minibuffer[index].name = namebuffer; } else { bd->name = name; diff --git a/drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm.c b/drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm.c index 05eeff58a229..b8aae4ba5a78 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm.c @@ -46,14 +46,16 @@ static ia_css_ptr dummy_ptr; static bool hmm_initialized; struct _hmm_mem_stat hmm_mem_stat; -/* p: private - s: shared - u: user - i: ion */ +/* + * p: private + * s: shared + * u: user + * i: ion + */ static const char hmm_bo_type_string[] = "psui"; static ssize_t bo_show(struct device *dev, struct device_attribute *attr, - char *buf, struct list_head *bo_list, bool active) + char *buf, struct list_head *bo_list, bool active) { ssize_t ret = 0; struct hmm_buffer_object *bo; @@ -73,10 +75,10 @@ static ssize_t bo_show(struct device *dev, struct device_attribute *attr, spin_lock_irqsave(&bo_device.list_lock, flags); list_for_each_entry(bo, bo_list, list) { if ((active && (bo->status & HMM_BO_ALLOCED)) || - (!active && !(bo->status & HMM_BO_ALLOCED))) { + (!active && !(bo->status & HMM_BO_ALLOCED))) { ret = scnprintf(buf + index1, PAGE_SIZE - index1, - "%c %d\n", - hmm_bo_type_string[bo->type], bo->pgnr); + "%c %d\n", + hmm_bo_type_string[bo->type], bo->pgnr); total[bo->type] += bo->pgnr; count[bo->type]++; @@ -89,9 +91,10 @@ static ssize_t bo_show(struct device *dev, struct device_attribute *attr, for (i = 0; i < HMM_BO_LAST; i++) { if (count[i]) { ret = scnprintf(buf + index1 + index2, - PAGE_SIZE - index1 - index2, - "%ld %c buffer objects: %ld KB\n", - count[i], hmm_bo_type_string[i], total[i] * 4); + PAGE_SIZE - index1 - index2, + "%ld %c buffer objects: %ld KB\n", + count[i], hmm_bo_type_string[i], + total[i] * 4); if (ret > 0) index2 += ret; } @@ -101,23 +104,21 @@ static ssize_t bo_show(struct device *dev, struct device_attribute *attr, return index1 + index2 + 1; } -static ssize_t active_bo_show(struct device *dev, - struct device_attribute *attr, - char *buf) +static ssize_t active_bo_show(struct device *dev, struct device_attribute *attr, + char *buf) { return bo_show(dev, attr, buf, &bo_device.entire_bo_list, true); } -static ssize_t free_bo_show(struct device *dev, - struct device_attribute *attr, - char *buf) +static ssize_t free_bo_show(struct device *dev, struct device_attribute *attr, + char *buf) { return bo_show(dev, attr, buf, &bo_device.entire_bo_list, false); } static ssize_t reserved_pool_show(struct device *dev, - struct device_attribute *attr, - char *buf) + struct device_attribute *attr, + char *buf) { ssize_t ret = 0; @@ -129,7 +130,7 @@ static ssize_t reserved_pool_show(struct device *dev, spin_lock_irqsave(&pinfo->list_lock, flags); ret = scnprintf(buf, PAGE_SIZE, "%d out of %d pages available\n", - pinfo->index, pinfo->pgnr); + pinfo->index, pinfo->pgnr); spin_unlock_irqrestore(&pinfo->list_lock, flags); if (ret > 0) @@ -139,8 +140,8 @@ static ssize_t reserved_pool_show(struct device *dev, }; static ssize_t dynamic_pool_show(struct device *dev, - struct device_attribute *attr, - char *buf) + struct device_attribute *attr, + char *buf) { ssize_t ret = 0; @@ -152,7 +153,7 @@ static ssize_t dynamic_pool_show(struct device *dev, spin_lock_irqsave(&pinfo->list_lock, flags); ret = scnprintf(buf, PAGE_SIZE, "%d (max %d) pages available\n", - pinfo->pgnr, pinfo->pool_size); + pinfo->pgnr, pinfo->pool_size); spin_unlock_irqrestore(&pinfo->list_lock, flags); if (ret > 0) @@ -200,7 +201,7 @@ int hmm_init(void) if (!ret) { ret = sysfs_create_group(&atomisp_dev->kobj, - atomisp_attribute_group); + atomisp_attribute_group); if (ret) dev_err(atomisp_dev, "%s Failed to create sysfs\n", __func__); @@ -213,9 +214,7 @@ void hmm_cleanup(void) { sysfs_remove_group(&atomisp_dev->kobj, atomisp_attribute_group); - /* - * free dummy memory first - */ + /* free dummy memory first */ hmm_free(dummy_ptr); dummy_ptr = 0; @@ -224,36 +223,37 @@ void hmm_cleanup(void) } ia_css_ptr hmm_alloc(size_t bytes, enum hmm_bo_type type, - int from_highmem, void *userptr, bool cached) + int from_highmem, void *userptr, bool cached) { unsigned int pgnr; struct hmm_buffer_object *bo; int ret; - /* Check if we are initialized. In the ideal world we wouldn't need - this but we can tackle it once the driver is a lot cleaner */ + /* + * Check if we are initialized. In the ideal world we wouldn't need + * this but we can tackle it once the driver is a lot cleaner + */ if (!hmm_initialized) hmm_init(); - /*Get page number from size*/ + /* Get page number from size */ pgnr = size_to_pgnr_ceil(bytes); - /*Buffer object structure init*/ + /* Buffer object structure init */ bo = hmm_bo_alloc(&bo_device, pgnr); if (!bo) { dev_err(atomisp_dev, "hmm_bo_create failed.\n"); goto create_bo_err; } - /*Allocate pages for memory*/ + /* Allocate pages for memory */ ret = hmm_bo_alloc_pages(bo, type, from_highmem, userptr, cached); if (ret) { - dev_err(atomisp_dev, - "hmm_bo_alloc_pages failed.\n"); + dev_err(atomisp_dev, "hmm_bo_alloc_pages failed.\n"); goto alloc_page_err; } - /*Combind the virtual address and pages togather*/ + /* Combind the virtual address and pages togather */ ret = hmm_bo_bind(bo); if (ret) { dev_err(atomisp_dev, "hmm_bo_bind failed.\n"); @@ -282,8 +282,8 @@ void hmm_free(ia_css_ptr virt) if (!bo) { dev_err(atomisp_dev, - "can not find buffer object start with " - "address 0x%x\n", (unsigned int)virt); + "can not find buffer object start with address 0x%x\n", + (unsigned int)virt); return; } @@ -298,29 +298,29 @@ static inline int hmm_check_bo(struct hmm_buffer_object *bo, unsigned int ptr) { if (!bo) { dev_err(atomisp_dev, - "can not find buffer object contains " - "address 0x%x\n", ptr); + "can not find buffer object contains address 0x%x\n", + ptr); return -EINVAL; } if (!hmm_bo_page_allocated(bo)) { dev_err(atomisp_dev, - "buffer object has no page allocated.\n"); + "buffer object has no page allocated.\n"); return -EINVAL; } if (!hmm_bo_allocated(bo)) { dev_err(atomisp_dev, - "buffer object has no virtual address" - " space allocated.\n"); + "buffer object has no virtual address space allocated.\n"); return -EINVAL; } return 0; } -/*Read function in ISP memory management*/ -static int load_and_flush_by_kmap(ia_css_ptr virt, void *data, unsigned int bytes) +/* Read function in ISP memory management */ +static int load_and_flush_by_kmap(ia_css_ptr virt, void *data, + unsigned int bytes) { struct hmm_buffer_object *bo; unsigned int idx, offset, len; @@ -362,7 +362,7 @@ static int load_and_flush_by_kmap(ia_css_ptr virt, void *data, unsigned int byte return 0; } -/*Read function in ISP memory management*/ +/* Read function in ISP memory management */ static int load_and_flush(ia_css_ptr virt, void *data, unsigned int bytes) { struct hmm_buffer_object *bo; @@ -397,24 +397,24 @@ static int load_and_flush(ia_css_ptr virt, void *data, unsigned int bytes) return 0; } -/*Read function in ISP memory management*/ +/* Read function in ISP memory management */ int hmm_load(ia_css_ptr virt, void *data, unsigned int bytes) { if (!data) { dev_err(atomisp_dev, - "hmm_load NULL argument\n"); + "hmm_load NULL argument\n"); return -EINVAL; } return load_and_flush(virt, data, bytes); } -/*Flush hmm data from the data cache*/ +/* Flush hmm data from the data cache */ int hmm_flush(ia_css_ptr virt, unsigned int bytes) { return load_and_flush(virt, NULL, bytes); } -/*Write function in ISP memory management*/ +/* Write function in ISP memory management */ int hmm_store(ia_css_ptr virt, const void *data, unsigned int bytes) { struct hmm_buffer_object *bo; @@ -460,8 +460,8 @@ int hmm_store(ia_css_ptr virt, const void *data, unsigned int bytes) if (!des) { dev_err(atomisp_dev, - "kmap buffer object page failed: " - "pg_idx = %d\n", idx); + "kmap buffer object page failed: pg_idx = %d\n", + idx); return -EINVAL; } @@ -496,7 +496,7 @@ int hmm_store(ia_css_ptr virt, const void *data, unsigned int bytes) return 0; } -/*memset function in ISP memory management*/ +/* memset function in ISP memory management */ int hmm_set(ia_css_ptr virt, int c, unsigned int bytes) { struct hmm_buffer_object *bo; @@ -556,7 +556,7 @@ int hmm_set(ia_css_ptr virt, int c, unsigned int bytes) return 0; } -/*Virtual address to physical address convert*/ +/* Virtual address to physical address convert */ phys_addr_t hmm_virt_to_phys(ia_css_ptr virt) { unsigned int idx, offset; @@ -591,7 +591,7 @@ int hmm_mmap(struct vm_area_struct *vma, ia_css_ptr virt) return hmm_bo_mmap(vma, bo); } -/*Map ISP virtual address into IA virtual address*/ +/* Map ISP virtual address into IA virtual address */ void *hmm_vmap(ia_css_ptr virt, bool cached) { struct hmm_buffer_object *bo; @@ -600,8 +600,8 @@ void *hmm_vmap(ia_css_ptr virt, bool cached) bo = hmm_bo_device_search_in_range(&bo_device, virt); if (!bo) { dev_err(atomisp_dev, - "can not find buffer object contains address 0x%x\n", - virt); + "can not find buffer object contains address 0x%x\n", + virt); return NULL; } @@ -620,8 +620,8 @@ void hmm_flush_vmap(ia_css_ptr virt) bo = hmm_bo_device_search_in_range(&bo_device, virt); if (!bo) { dev_warn(atomisp_dev, - "can not find buffer object contains address 0x%x\n", - virt); + "can not find buffer object contains address 0x%x\n", + virt); return; } @@ -635,26 +635,25 @@ void hmm_vunmap(ia_css_ptr virt) bo = hmm_bo_device_search_in_range(&bo_device, virt); if (!bo) { dev_warn(atomisp_dev, - "can not find buffer object contains address 0x%x\n", - virt); + "can not find buffer object contains address 0x%x\n", + virt); return; } - return hmm_bo_vunmap(bo); + hmm_bo_vunmap(bo); } -int hmm_pool_register(unsigned int pool_size, - enum hmm_pool_type pool_type) +int hmm_pool_register(unsigned int pool_size, enum hmm_pool_type pool_type) { switch (pool_type) { case HMM_POOL_TYPE_RESERVED: reserved_pool.pops = &reserved_pops; return reserved_pool.pops->pool_init(&reserved_pool.pool_info, - pool_size); + pool_size); case HMM_POOL_TYPE_DYNAMIC: dynamic_pool.pops = &dynamic_pops; return dynamic_pool.pops->pool_init(&dynamic_pool.pool_info, - pool_size); + pool_size); default: dev_err(atomisp_dev, "invalid pool type.\n"); return -EINVAL; @@ -703,10 +702,10 @@ ia_css_ptr hmm_host_vaddr_to_hrt_vaddr(const void *ptr) void hmm_show_mem_stat(const char *func, const int line) { trace_printk("tol_cnt=%d usr_size=%d res_size=%d res_cnt=%d sys_size=%d dyc_thr=%d dyc_size=%d.\n", - hmm_mem_stat.tol_cnt, - hmm_mem_stat.usr_size, hmm_mem_stat.res_size, - hmm_mem_stat.res_cnt, hmm_mem_stat.sys_size, - hmm_mem_stat.dyc_thr, hmm_mem_stat.dyc_size); + hmm_mem_stat.tol_cnt, + hmm_mem_stat.usr_size, hmm_mem_stat.res_size, + hmm_mem_stat.res_cnt, hmm_mem_stat.sys_size, + hmm_mem_stat.dyc_thr, hmm_mem_stat.dyc_size); } void hmm_init_mem_stat(int res_pgnr, int dyc_en, int dyc_pgnr) diff --git a/drivers/staging/media/bcm2048/radio-bcm2048.c b/drivers/staging/media/bcm2048/radio-bcm2048.c index 38f72d069e27..58adaea44eb5 100644 --- a/drivers/staging/media/bcm2048/radio-bcm2048.c +++ b/drivers/staging/media/bcm2048/radio-bcm2048.c @@ -48,7 +48,6 @@ /* driver definitions */ #define BCM2048_DRIVER_AUTHOR "Eero Nurkkala <ext-eero.nurkkala@nokia.com>" #define BCM2048_DRIVER_NAME BCM2048_NAME -#define BCM2048_DRIVER_VERSION KERNEL_VERSION(0, 0, 1) #define BCM2048_DRIVER_CARD "Broadcom bcm2048 FM Radio Receiver" #define BCM2048_DRIVER_DESC "I2C driver for BCM2048 FM Radio Receiver" @@ -2565,7 +2564,7 @@ static const struct v4l2_ioctl_ops bcm2048_ioctl_ops = { /* * bcm2048_viddev_template - video device interface */ -static struct video_device bcm2048_viddev_template = { +static const struct video_device bcm2048_viddev_template = { .fops = &bcm2048_fops, .name = BCM2048_DRIVER_NAME, .release = video_device_release_empty, diff --git a/drivers/staging/media/cxd2099/cxd2099.c b/drivers/staging/media/cxd2099/cxd2099.c index f28916ea69f1..3e30f4864e2b 100644 --- a/drivers/staging/media/cxd2099/cxd2099.c +++ b/drivers/staging/media/cxd2099/cxd2099.c @@ -33,8 +33,9 @@ #include "cxd2099.h" -/* comment this line to deactivate the cxd2099ar buffer mode */ -#define BUFFER_MODE 1 +static int buffermode; +module_param(buffermode, int, 0444); +MODULE_PARM_DESC(buffermode, "Enable use of the CXD2099AR buffer mode (default: disabled)"); static int read_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount); @@ -221,7 +222,6 @@ static int write_reg(struct cxd *ci, u8 reg, u8 val) return write_regm(ci, reg, val, 0xff); } -#ifdef BUFFER_MODE static int write_block(struct cxd *ci, u8 adr, u8 *data, u16 n) { int status = 0; @@ -248,7 +248,6 @@ static int write_block(struct cxd *ci, u8 adr, u8 *data, u16 n) } return status; } -#endif static void set_mode(struct cxd *ci, int mode) { @@ -642,8 +641,6 @@ static int read_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount) return len; } -#ifdef BUFFER_MODE - static int write_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount) { struct cxd *ci = ca->data; @@ -658,7 +655,6 @@ static int write_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount) mutex_unlock(&ci->lock); return ecount; } -#endif static struct dvb_ca_en50221 en_templ = { .read_attribute_mem = read_attribute_mem, @@ -669,11 +665,8 @@ static struct dvb_ca_en50221 en_templ = { .slot_shutdown = slot_shutdown, .slot_ts_enable = slot_ts_enable, .poll_slot_status = poll_slot_status, -#ifdef BUFFER_MODE .read_data = read_data, .write_data = write_data, -#endif - }; struct dvb_ca_en50221 *cxd2099_attach(struct cxd2099_cfg *cfg, @@ -703,6 +696,14 @@ struct dvb_ca_en50221 *cxd2099_attach(struct cxd2099_cfg *cfg, ci->en.data = ci; init(ci); dev_info(&i2c->dev, "Attached CXD2099AR at %02x\n", ci->cfg.adr); + + if (!buffermode) { + ci->en.read_data = NULL; + ci->en.write_data = NULL; + } else { + dev_info(&i2c->dev, "Using CXD2099AR buffer mode"); + } + return &ci->en; } EXPORT_SYMBOL(cxd2099_attach); diff --git a/drivers/staging/media/davinci_vpfe/vpfe_video.c b/drivers/staging/media/davinci_vpfe/vpfe_video.c index 8b2117ee0f60..155e8c758e4b 100644 --- a/drivers/staging/media/davinci_vpfe/vpfe_video.c +++ b/drivers/staging/media/davinci_vpfe/vpfe_video.c @@ -1304,7 +1304,7 @@ static void vpfe_buf_cleanup(struct vb2_buffer *vb) list_del_init(&buf->list); } -static struct vb2_ops video_qops = { +static const struct vb2_ops video_qops = { .queue_setup = vpfe_buffer_queue_setup, .buf_init = vpfe_buffer_init, .buf_prepare = vpfe_buffer_prepare, diff --git a/drivers/staging/media/imx/Kconfig b/drivers/staging/media/imx/Kconfig index 7eff50bcea39..2be921cd0d55 100644 --- a/drivers/staging/media/imx/Kconfig +++ b/drivers/staging/media/imx/Kconfig @@ -1,6 +1,8 @@ config VIDEO_IMX_MEDIA tristate "i.MX5/6 V4L2 media core driver" depends on MEDIA_CONTROLLER && VIDEO_V4L2 && ARCH_MXC && IMX_IPUV3_CORE + depends on VIDEO_V4L2_SUBDEV_API + select VIDEOBUF2_DMA_CONTIG select V4L2_FWNODE ---help--- Say yes here to enable support for video4linux media controller @@ -12,7 +14,6 @@ menu "i.MX5/6 Media Sub devices" config VIDEO_IMX_CSI tristate "i.MX5/6 Camera Sensor Interface driver" depends on VIDEO_IMX_MEDIA && VIDEO_DEV && I2C - select VIDEOBUF2_DMA_CONTIG default y ---help--- A video4linux camera sensor interface driver for i.MX5/6. diff --git a/drivers/staging/media/imx/imx-ic-prpencvf.c b/drivers/staging/media/imx/imx-ic-prpencvf.c index ed363fe3b3d0..0790b3d9e255 100644 --- a/drivers/staging/media/imx/imx-ic-prpencvf.c +++ b/drivers/staging/media/imx/imx-ic-prpencvf.c @@ -134,19 +134,19 @@ static inline struct prp_priv *sd_to_priv(struct v4l2_subdev *sd) static void prp_put_ipu_resources(struct prp_priv *priv) { - if (!IS_ERR_OR_NULL(priv->ic)) + if (priv->ic) ipu_ic_put(priv->ic); priv->ic = NULL; - if (!IS_ERR_OR_NULL(priv->out_ch)) + if (priv->out_ch) ipu_idmac_put(priv->out_ch); priv->out_ch = NULL; - if (!IS_ERR_OR_NULL(priv->rot_in_ch)) + if (priv->rot_in_ch) ipu_idmac_put(priv->rot_in_ch); priv->rot_in_ch = NULL; - if (!IS_ERR_OR_NULL(priv->rot_out_ch)) + if (priv->rot_out_ch) ipu_idmac_put(priv->rot_out_ch); priv->rot_out_ch = NULL; } @@ -154,43 +154,46 @@ static void prp_put_ipu_resources(struct prp_priv *priv) static int prp_get_ipu_resources(struct prp_priv *priv) { struct imx_ic_priv *ic_priv = priv->ic_priv; + struct ipu_ic *ic; + struct ipuv3_channel *out_ch, *rot_in_ch, *rot_out_ch; int ret, task = ic_priv->task_id; priv->ipu = priv->md->ipu[ic_priv->ipu_id]; - priv->ic = ipu_ic_get(priv->ipu, task); - if (IS_ERR(priv->ic)) { + ic = ipu_ic_get(priv->ipu, task); + if (IS_ERR(ic)) { v4l2_err(&ic_priv->sd, "failed to get IC\n"); - ret = PTR_ERR(priv->ic); + ret = PTR_ERR(ic); goto out; } + priv->ic = ic; - priv->out_ch = ipu_idmac_get(priv->ipu, - prp_channel[task].out_ch); - if (IS_ERR(priv->out_ch)) { + out_ch = ipu_idmac_get(priv->ipu, prp_channel[task].out_ch); + if (IS_ERR(out_ch)) { v4l2_err(&ic_priv->sd, "could not get IDMAC channel %u\n", prp_channel[task].out_ch); - ret = PTR_ERR(priv->out_ch); + ret = PTR_ERR(out_ch); goto out; } + priv->out_ch = out_ch; - priv->rot_in_ch = ipu_idmac_get(priv->ipu, - prp_channel[task].rot_in_ch); - if (IS_ERR(priv->rot_in_ch)) { + rot_in_ch = ipu_idmac_get(priv->ipu, prp_channel[task].rot_in_ch); + if (IS_ERR(rot_in_ch)) { v4l2_err(&ic_priv->sd, "could not get IDMAC channel %u\n", prp_channel[task].rot_in_ch); - ret = PTR_ERR(priv->rot_in_ch); + ret = PTR_ERR(rot_in_ch); goto out; } + priv->rot_in_ch = rot_in_ch; - priv->rot_out_ch = ipu_idmac_get(priv->ipu, - prp_channel[task].rot_out_ch); - if (IS_ERR(priv->rot_out_ch)) { + rot_out_ch = ipu_idmac_get(priv->ipu, prp_channel[task].rot_out_ch); + if (IS_ERR(rot_out_ch)) { v4l2_err(&ic_priv->sd, "could not get IDMAC channel %u\n", prp_channel[task].rot_out_ch); - ret = PTR_ERR(priv->rot_out_ch); + ret = PTR_ERR(rot_out_ch); goto out; } + priv->rot_out_ch = rot_out_ch; return 0; out: @@ -374,6 +377,17 @@ static int prp_setup_channel(struct prp_priv *priv, image.phys0 = addr0; image.phys1 = addr1; + if (channel == priv->out_ch || channel == priv->rot_out_ch) { + switch (image.pix.pixelformat) { + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_YVU420: + case V4L2_PIX_FMT_NV12: + /* Skip writing U and V components to odd rows */ + ipu_cpmem_skip_odd_chroma_rows(channel); + break; + } + } + ret = ipu_cpmem_set_image(channel, &image); if (ret) return ret; @@ -1278,9 +1292,8 @@ static int prp_init(struct imx_ic_priv *ic_priv) priv->ic_priv = ic_priv; spin_lock_init(&priv->irqlock); - init_timer(&priv->eof_timeout_timer); - priv->eof_timeout_timer.data = (unsigned long)priv; - priv->eof_timeout_timer.function = prp_eof_timeout; + setup_timer(&priv->eof_timeout_timer, prp_eof_timeout, + (unsigned long)priv); priv->vdev = imx_media_capture_device_init(&ic_priv->sd, PRPENCVF_SRC_PAD); diff --git a/drivers/staging/media/imx/imx-media-capture.c b/drivers/staging/media/imx/imx-media-capture.c index ddab4c249da2..ea145bafb880 100644 --- a/drivers/staging/media/imx/imx-media-capture.c +++ b/drivers/staging/media/imx/imx-media-capture.c @@ -62,7 +62,7 @@ struct capture_priv { /* In bytes, per queue */ #define VID_MEM_LIMIT SZ_64M -static struct vb2_ops capture_qops; +static const struct vb2_ops capture_qops; /* * Video ioctls follow @@ -503,7 +503,7 @@ static void capture_stop_streaming(struct vb2_queue *vq) spin_unlock_irqrestore(&priv->q_lock, flags); } -static struct vb2_ops capture_qops = { +static const struct vb2_ops capture_qops = { .queue_setup = capture_queue_setup, .buf_init = capture_buf_init, .buf_prepare = capture_buf_prepare, diff --git a/drivers/staging/media/imx/imx-media-csi.c b/drivers/staging/media/imx/imx-media-csi.c index a2d26693912e..6d856118c223 100644 --- a/drivers/staging/media/imx/imx-media-csi.c +++ b/drivers/staging/media/imx/imx-media-csi.c @@ -122,11 +122,11 @@ static inline struct csi_priv *sd_to_dev(struct v4l2_subdev *sdev) static void csi_idmac_put_ipu_resources(struct csi_priv *priv) { - if (!IS_ERR_OR_NULL(priv->idmac_ch)) + if (priv->idmac_ch) ipu_idmac_put(priv->idmac_ch); priv->idmac_ch = NULL; - if (!IS_ERR_OR_NULL(priv->smfc)) + if (priv->smfc) ipu_smfc_put(priv->smfc); priv->smfc = NULL; } @@ -134,23 +134,27 @@ static void csi_idmac_put_ipu_resources(struct csi_priv *priv) static int csi_idmac_get_ipu_resources(struct csi_priv *priv) { int ch_num, ret; + struct ipu_smfc *smfc; + struct ipuv3_channel *idmac_ch; ch_num = IPUV3_CHANNEL_CSI0 + priv->smfc_id; - priv->smfc = ipu_smfc_get(priv->ipu, ch_num); - if (IS_ERR(priv->smfc)) { + smfc = ipu_smfc_get(priv->ipu, ch_num); + if (IS_ERR(smfc)) { v4l2_err(&priv->sd, "failed to get SMFC\n"); - ret = PTR_ERR(priv->smfc); + ret = PTR_ERR(smfc); goto out; } + priv->smfc = smfc; - priv->idmac_ch = ipu_idmac_get(priv->ipu, ch_num); - if (IS_ERR(priv->idmac_ch)) { + idmac_ch = ipu_idmac_get(priv->ipu, ch_num); + if (IS_ERR(idmac_ch)) { v4l2_err(&priv->sd, "could not get IDMAC channel %u\n", ch_num); - ret = PTR_ERR(priv->idmac_ch); + ret = PTR_ERR(idmac_ch); goto out; } + priv->idmac_ch = idmac_ch; return 0; out: @@ -357,6 +361,8 @@ static int csi_idmac_setup_channel(struct csi_priv *priv) passthrough = (sensor_ep->bus_type != V4L2_MBUS_CSI2 && sensor_ep->bus.parallel.bus_width >= 16); passthrough_bits = 16; + /* Skip writing U and V components to odd rows */ + ipu_cpmem_skip_odd_chroma_rows(priv->idmac_ch); break; case V4L2_PIX_FMT_YUYV: case V4L2_PIX_FMT_UYVY: @@ -1583,6 +1589,7 @@ static int csi_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, static int csi_registered(struct v4l2_subdev *sd) { struct csi_priv *priv = v4l2_get_subdevdata(sd); + struct ipu_csi *csi; int i, ret; u32 code; @@ -1590,11 +1597,12 @@ static int csi_registered(struct v4l2_subdev *sd) priv->md = dev_get_drvdata(sd->v4l2_dev->dev); /* get handle to IPU CSI */ - priv->csi = ipu_csi_get(priv->ipu, priv->csi_id); - if (IS_ERR(priv->csi)) { + csi = ipu_csi_get(priv->ipu, priv->csi_id); + if (IS_ERR(csi)) { v4l2_err(&priv->sd, "failed to get CSI%d\n", priv->csi_id); - return PTR_ERR(priv->csi); + return PTR_ERR(csi); } + priv->csi = csi; for (i = 0; i < CSI_NUM_PADS; i++) { priv->pad[i].flags = (i == CSI_SINK_PAD) ? @@ -1663,7 +1671,7 @@ static void csi_unregistered(struct v4l2_subdev *sd) if (priv->fim) imx_media_fim_free(priv->fim); - if (!IS_ERR_OR_NULL(priv->csi)) + if (priv->csi) ipu_csi_put(priv->csi); } @@ -1731,9 +1739,8 @@ static int imx_csi_probe(struct platform_device *pdev) priv->csi_id = pdata->csi; priv->smfc_id = (priv->csi_id == 0) ? 0 : 2; - init_timer(&priv->eof_timeout_timer); - priv->eof_timeout_timer.data = (unsigned long)priv; - priv->eof_timeout_timer.function = csi_idmac_eof_timeout; + setup_timer(&priv->eof_timeout_timer, csi_idmac_eof_timeout, + (unsigned long)priv); spin_lock_init(&priv->irqlock); v4l2_subdev_init(&priv->sd, &csi_subdev_ops); diff --git a/drivers/staging/media/imx/imx-media-dev.c b/drivers/staging/media/imx/imx-media-dev.c index 48cbc7716758..d96f4512224f 100644 --- a/drivers/staging/media/imx/imx-media-dev.c +++ b/drivers/staging/media/imx/imx-media-dev.c @@ -87,11 +87,11 @@ imx_media_add_async_subdev(struct imx_media_dev *imxmd, if (pdev) devname = dev_name(&pdev->dev); - /* return NULL if this subdev already added */ + /* return -EEXIST if this subdev already added */ if (imx_media_find_async_subdev(imxmd, np, devname)) { dev_dbg(imxmd->md.dev, "%s: already added %s\n", __func__, np ? np->name : devname); - imxsd = NULL; + imxsd = ERR_PTR(-EEXIST); goto out; } diff --git a/drivers/staging/media/imx/imx-media-of.c b/drivers/staging/media/imx/imx-media-of.c index b026fe66467c..12df09f52490 100644 --- a/drivers/staging/media/imx/imx-media-of.c +++ b/drivers/staging/media/imx/imx-media-of.c @@ -100,9 +100,9 @@ static void of_get_remote_pad(struct device_node *epnode, } } -static struct imx_media_subdev * +static int of_parse_subdev(struct imx_media_dev *imxmd, struct device_node *sd_np, - bool is_csi_port) + bool is_csi_port, struct imx_media_subdev **subdev) { struct imx_media_subdev *imxsd; int i, num_pads, ret; @@ -110,13 +110,25 @@ of_parse_subdev(struct imx_media_dev *imxmd, struct device_node *sd_np, if (!of_device_is_available(sd_np)) { dev_dbg(imxmd->md.dev, "%s: %s not enabled\n", __func__, sd_np->name); - return NULL; + *subdev = NULL; + /* unavailable is not an error */ + return 0; } /* register this subdev with async notifier */ imxsd = imx_media_add_async_subdev(imxmd, sd_np, NULL); - if (IS_ERR_OR_NULL(imxsd)) - return imxsd; + ret = PTR_ERR_OR_ZERO(imxsd); + if (ret) { + if (ret == -EEXIST) { + /* already added, everything is fine */ + *subdev = NULL; + return 0; + } + + /* other error, can't continue */ + return ret; + } + *subdev = imxsd; if (is_csi_port) { /* @@ -137,10 +149,11 @@ of_parse_subdev(struct imx_media_dev *imxmd, struct device_node *sd_np, } else { num_pads = of_get_port_count(sd_np); if (num_pads != 1) { + /* confused, but no reason to give up here */ dev_warn(imxmd->md.dev, "%s: unknown device %s with %d ports\n", __func__, sd_np->name, num_pads); - return NULL; + return 0; } /* @@ -151,7 +164,7 @@ of_parse_subdev(struct imx_media_dev *imxmd, struct device_node *sd_np, } if (imxsd->num_sink_pads >= num_pads) - return ERR_PTR(-EINVAL); + return -EINVAL; imxsd->num_src_pads = num_pads - imxsd->num_sink_pads; @@ -191,20 +204,15 @@ of_parse_subdev(struct imx_media_dev *imxmd, struct device_node *sd_np, ret = of_add_pad_link(imxmd, pad, sd_np, remote_np, i, remote_pad); - if (ret) { - imxsd = ERR_PTR(ret); + if (ret) break; - } if (i < imxsd->num_sink_pads) { /* follow sink endpoints upstream */ - remote_imxsd = of_parse_subdev(imxmd, - remote_np, - false); - if (IS_ERR(remote_imxsd)) { - imxsd = remote_imxsd; + ret = of_parse_subdev(imxmd, remote_np, + false, &remote_imxsd); + if (ret) break; - } } of_node_put(remote_np); @@ -212,14 +220,14 @@ of_parse_subdev(struct imx_media_dev *imxmd, struct device_node *sd_np, if (port != sd_np) of_node_put(port); - if (IS_ERR(imxsd)) { + if (ret) { of_node_put(remote_np); of_node_put(epnode); break; } } - return imxsd; + return ret; } int imx_media_of_parse(struct imx_media_dev *imxmd, @@ -236,11 +244,9 @@ int imx_media_of_parse(struct imx_media_dev *imxmd, if (!csi_np) break; - lcsi = of_parse_subdev(imxmd, csi_np, true); - if (IS_ERR(lcsi)) { - ret = PTR_ERR(lcsi); + ret = of_parse_subdev(imxmd, csi_np, true, &lcsi); + if (ret) goto err_put; - } ret = of_property_read_u32(csi_np, "reg", &csi_id); if (ret) { diff --git a/drivers/staging/media/imx/imx-media-vdic.c b/drivers/staging/media/imx/imx-media-vdic.c index 7eabdc4aa79f..433474d58e3e 100644 --- a/drivers/staging/media/imx/imx-media-vdic.c +++ b/drivers/staging/media/imx/imx-media-vdic.c @@ -126,15 +126,15 @@ struct vdic_priv { static void vdic_put_ipu_resources(struct vdic_priv *priv) { - if (!IS_ERR_OR_NULL(priv->vdi_in_ch_p)) + if (priv->vdi_in_ch_p) ipu_idmac_put(priv->vdi_in_ch_p); priv->vdi_in_ch_p = NULL; - if (!IS_ERR_OR_NULL(priv->vdi_in_ch)) + if (priv->vdi_in_ch) ipu_idmac_put(priv->vdi_in_ch); priv->vdi_in_ch = NULL; - if (!IS_ERR_OR_NULL(priv->vdi_in_ch_n)) + if (priv->vdi_in_ch_n) ipu_idmac_put(priv->vdi_in_ch_n); priv->vdi_in_ch_n = NULL; @@ -146,40 +146,43 @@ static void vdic_put_ipu_resources(struct vdic_priv *priv) static int vdic_get_ipu_resources(struct vdic_priv *priv) { int ret, err_chan; + struct ipuv3_channel *ch; + struct ipu_vdi *vdi; priv->ipu = priv->md->ipu[priv->ipu_id]; - priv->vdi = ipu_vdi_get(priv->ipu); - if (IS_ERR(priv->vdi)) { + vdi = ipu_vdi_get(priv->ipu); + if (IS_ERR(vdi)) { v4l2_err(&priv->sd, "failed to get VDIC\n"); - ret = PTR_ERR(priv->vdi); + ret = PTR_ERR(vdi); goto out; } + priv->vdi = vdi; if (!priv->csi_direct) { - priv->vdi_in_ch_p = ipu_idmac_get(priv->ipu, - IPUV3_CHANNEL_MEM_VDI_PREV); - if (IS_ERR(priv->vdi_in_ch_p)) { + ch = ipu_idmac_get(priv->ipu, IPUV3_CHANNEL_MEM_VDI_PREV); + if (IS_ERR(ch)) { err_chan = IPUV3_CHANNEL_MEM_VDI_PREV; - ret = PTR_ERR(priv->vdi_in_ch_p); + ret = PTR_ERR(ch); goto out_err_chan; } + priv->vdi_in_ch_p = ch; - priv->vdi_in_ch = ipu_idmac_get(priv->ipu, - IPUV3_CHANNEL_MEM_VDI_CUR); - if (IS_ERR(priv->vdi_in_ch)) { + ch = ipu_idmac_get(priv->ipu, IPUV3_CHANNEL_MEM_VDI_CUR); + if (IS_ERR(ch)) { err_chan = IPUV3_CHANNEL_MEM_VDI_CUR; - ret = PTR_ERR(priv->vdi_in_ch); + ret = PTR_ERR(ch); goto out_err_chan; } + priv->vdi_in_ch = ch; - priv->vdi_in_ch_n = ipu_idmac_get(priv->ipu, - IPUV3_CHANNEL_MEM_VDI_NEXT); + ch = ipu_idmac_get(priv->ipu, IPUV3_CHANNEL_MEM_VDI_NEXT); if (IS_ERR(priv->vdi_in_ch_n)) { err_chan = IPUV3_CHANNEL_MEM_VDI_NEXT; - ret = PTR_ERR(priv->vdi_in_ch_n); + ret = PTR_ERR(ch); goto out_err_chan; } + priv->vdi_in_ch_n = ch; } return 0; diff --git a/drivers/staging/media/lirc/lirc_zilog.c b/drivers/staging/media/lirc/lirc_zilog.c index 015e41bd036e..71af13bd0ebd 100644 --- a/drivers/staging/media/lirc/lirc_zilog.c +++ b/drivers/staging/media/lirc/lirc_zilog.c @@ -288,7 +288,7 @@ static void release_ir_tx(struct kref *ref) struct IR_tx *tx = container_of(ref, struct IR_tx, ref); struct IR *ir = tx->ir; - ir->l.features &= ~LIRC_CAN_SEND_PULSE; + ir->l.features &= ~LIRC_CAN_SEND_LIRCCODE; /* Don't put_ir_device(tx->ir) here, so our lock doesn't get freed */ ir->tx = NULL; kfree(tx); @@ -1249,7 +1249,7 @@ static long ioctl(struct file *filep, unsigned int cmd, unsigned long arg) break; case LIRC_GET_REC_MODE: if (!(features & LIRC_CAN_REC_MASK)) - return -ENOSYS; + return -ENOTTY; result = put_user(LIRC_REC2MODE (features & LIRC_CAN_REC_MASK), @@ -1257,24 +1257,24 @@ static long ioctl(struct file *filep, unsigned int cmd, unsigned long arg) break; case LIRC_SET_REC_MODE: if (!(features & LIRC_CAN_REC_MASK)) - return -ENOSYS; + return -ENOTTY; result = get_user(mode, uptr); if (!result && !(LIRC_MODE2REC(mode) & features)) - result = -EINVAL; + result = -ENOTTY; break; case LIRC_GET_SEND_MODE: if (!(features & LIRC_CAN_SEND_MASK)) - return -ENOSYS; + return -ENOTTY; - result = put_user(LIRC_MODE_PULSE, uptr); + result = put_user(LIRC_MODE_LIRCCODE, uptr); break; case LIRC_SET_SEND_MODE: if (!(features & LIRC_CAN_SEND_MASK)) - return -ENOSYS; + return -ENOTTY; result = get_user(mode, uptr); - if (!result && mode != LIRC_MODE_PULSE) + if (!result && mode != LIRC_MODE_LIRCCODE) return -EINVAL; break; default: @@ -1512,7 +1512,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) kref_init(&tx->ref); ir->tx = tx; - ir->l.features |= LIRC_CAN_SEND_PULSE; + ir->l.features |= LIRC_CAN_SEND_LIRCCODE; mutex_init(&tx->client_lock); tx->c = client; tx->need_boot = 1; diff --git a/drivers/staging/media/omap4iss/iss_video.c b/drivers/staging/media/omap4iss/iss_video.c index 0bac58241a22..9e2f0421a01e 100644 --- a/drivers/staging/media/omap4iss/iss_video.c +++ b/drivers/staging/media/omap4iss/iss_video.c @@ -1199,7 +1199,7 @@ static int iss_video_mmap(struct file *file, struct vm_area_struct *vma) return vb2_mmap(&vfh->queue, vma); } -static struct v4l2_file_operations iss_video_fops = { +static const struct v4l2_file_operations iss_video_fops = { .owner = THIS_MODULE, .unlocked_ioctl = video_ioctl2, .open = iss_video_open, diff --git a/drivers/staging/most/hdm-dim2/dim2_hdm.c b/drivers/staging/most/hdm-dim2/dim2_hdm.c index 4607d03c577b..df7021c522b3 100644 --- a/drivers/staging/most/hdm-dim2/dim2_hdm.c +++ b/drivers/staging/most/hdm-dim2/dim2_hdm.c @@ -761,8 +761,8 @@ static int dim2_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) { - dev_err(&pdev->dev, "failed to get ahb0_int irq\n"); - return -ENODEV; + dev_err(&pdev->dev, "failed to get ahb0_int irq: %d\n", irq); + return irq; } ret = devm_request_irq(&pdev->dev, irq, dim2_ahb_isr, 0, @@ -774,8 +774,8 @@ static int dim2_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 1); if (irq < 0) { - dev_err(&pdev->dev, "failed to get mlb_int irq\n"); - return -ENODEV; + dev_err(&pdev->dev, "failed to get mlb_int irq: %d\n", irq); + return irq; } ret = devm_request_irq(&pdev->dev, irq, dim2_mlb_isr, 0, @@ -894,7 +894,7 @@ static int dim2_remove(struct platform_device *pdev) return 0; } -static struct platform_device_id dim2_id[] = { +static const struct platform_device_id dim2_id[] = { { "medialb_dim2" }, { }, /* Terminating entry */ }; diff --git a/drivers/staging/most/hdm-usb/hdm_usb.c b/drivers/staging/most/hdm-usb/hdm_usb.c index d0f68cb3c173..85775da293fb 100644 --- a/drivers/staging/most/hdm-usb/hdm_usb.c +++ b/drivers/staging/most/hdm-usb/hdm_usb.c @@ -832,7 +832,7 @@ static const struct file_operations hdm_usb_fops = { /** * usb_device_id - ID table for HCD device probing */ -static struct usb_device_id usbid[] = { +static const struct usb_device_id usbid[] = { { USB_DEVICE(USB_VENDOR_ID_SMSC, USB_DEV_ID_BRDG), }, { USB_DEVICE(USB_VENDOR_ID_SMSC, USB_DEV_ID_OS81118), }, { USB_DEVICE(USB_VENDOR_ID_SMSC, USB_DEV_ID_OS81119), }, @@ -1301,25 +1301,7 @@ static struct usb_driver hdm_usb = { .disconnect = hdm_disconnect, }; -static int __init hdm_usb_init(void) -{ - pr_info("hdm_usb_init()\n"); - if (usb_register(&hdm_usb)) { - pr_err("could not register hdm_usb driver\n"); - return -EIO; - } - - return 0; -} - -static void __exit hdm_usb_exit(void) -{ - pr_info("hdm_usb_exit()\n"); - usb_deregister(&hdm_usb); -} - -module_init(hdm_usb_init); -module_exit(hdm_usb_exit); +module_usb_driver(hdm_usb); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Christian Gromm <christian.gromm@microchip.com>"); MODULE_DESCRIPTION("HDM_4_USB"); diff --git a/drivers/staging/mt29f_spinand/mt29f_spinand.c b/drivers/staging/mt29f_spinand/mt29f_spinand.c index a4e3ae8f0c85..13eaf16ecd16 100644 --- a/drivers/staging/mt29f_spinand/mt29f_spinand.c +++ b/drivers/staging/mt29f_spinand/mt29f_spinand.c @@ -18,7 +18,7 @@ #include <linux/delay.h> #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> -#include <linux/mtd/nand.h> +#include <linux/mtd/rawnand.h> #include <linux/spi/spi.h> #include "mt29f_spinand.h" diff --git a/drivers/staging/nvec/nvec.c b/drivers/staging/nvec/nvec.c index c1feccf8d94a..4ff8f47385da 100644 --- a/drivers/staging/nvec/nvec.c +++ b/drivers/staging/nvec/nvec.c @@ -831,7 +831,7 @@ static int tegra_nvec_probe(struct platform_device *pdev) return -ENODEV; } - nvec->rst = devm_reset_control_get(&pdev->dev, "i2c"); + nvec->rst = devm_reset_control_get_exclusive(&pdev->dev, "i2c"); if (IS_ERR(nvec->rst)) { dev_err(nvec->dev, "failed to get controller reset\n"); return PTR_ERR(nvec->rst); diff --git a/drivers/staging/octeon/ethernet-rx.c b/drivers/staging/octeon/ethernet-rx.c index 72baedefa0f1..1a44291318ee 100644 --- a/drivers/staging/octeon/ethernet-rx.c +++ b/drivers/staging/octeon/ethernet-rx.c @@ -149,6 +149,46 @@ static inline int cvm_oct_check_rcv_error(cvmx_wqe_t *work) return 0; } +static void copy_segments_to_skb(cvmx_wqe_t *work, struct sk_buff *skb) +{ + int segments = work->word2.s.bufs; + union cvmx_buf_ptr segment_ptr = work->packet_ptr; + int len = work->word1.len; + int segment_size; + + while (segments--) { + union cvmx_buf_ptr next_ptr; + + next_ptr = *(union cvmx_buf_ptr *) + cvmx_phys_to_ptr(segment_ptr.s.addr - 8); + + /* + * Octeon Errata PKI-100: The segment size is wrong. + * + * Until it is fixed, calculate the segment size based on + * the packet pool buffer size. + * When it is fixed, the following line should be replaced + * with this one: + * int segment_size = segment_ptr.s.size; + */ + segment_size = + CVMX_FPA_PACKET_POOL_SIZE - + (segment_ptr.s.addr - + (((segment_ptr.s.addr >> 7) - + segment_ptr.s.back) << 7)); + + /* Don't copy more than what is left in the packet */ + if (segment_size > len) + segment_size = len; + + /* Copy the data into the packet */ + skb_put_data(skb, cvmx_phys_to_ptr(segment_ptr.s.addr), + segment_size); + len -= segment_size; + segment_ptr = next_ptr; + } +} + static int cvm_oct_poll(struct oct_rx_group *rx_group, int budget) { const int coreid = cvmx_get_core_num(); @@ -290,44 +330,7 @@ static int cvm_oct_poll(struct oct_rx_group *rx_group, int budget) skb_put_data(skb, ptr, work->word1.len); /* No packet buffers to free */ } else { - int segments = work->word2.s.bufs; - union cvmx_buf_ptr segment_ptr = - work->packet_ptr; - int len = work->word1.len; - - while (segments--) { - union cvmx_buf_ptr next_ptr = - *(union cvmx_buf_ptr *) - cvmx_phys_to_ptr( - segment_ptr.s.addr - 8); - - /* - * Octeon Errata PKI-100: The segment size is - * wrong. Until it is fixed, calculate the - * segment size based on the packet pool - * buffer size. When it is fixed, the - * following line should be replaced with this - * one: int segment_size = - * segment_ptr.s.size; - */ - int segment_size = - CVMX_FPA_PACKET_POOL_SIZE - - (segment_ptr.s.addr - - (((segment_ptr.s.addr >> 7) - - segment_ptr.s.back) << 7)); - /* - * Don't copy more than what - * is left in the packet. - */ - if (segment_size > len) - segment_size = len; - /* Copy the data into the packet */ - skb_put_data(skb, - cvmx_phys_to_ptr(segment_ptr.s.addr), - segment_size); - len -= segment_size; - segment_ptr = next_ptr; - } + copy_segments_to_skb(work, skb); } packet_not_copied = 0; } diff --git a/drivers/staging/olpc_dcon/olpc_dcon.c b/drivers/staging/olpc_dcon/olpc_dcon.c index f7f3a780ec10..82bffd911435 100644 --- a/drivers/staging/olpc_dcon/olpc_dcon.c +++ b/drivers/staging/olpc_dcon/olpc_dcon.c @@ -456,8 +456,6 @@ static ssize_t dcon_freeze_store(struct device *dev, if (ret) return ret; - pr_info("dcon_freeze_store: %lu\n", output); - switch (output) { case 0: dcon_set_source(dcon, DCON_SOURCE_CPU); diff --git a/drivers/staging/pi433/Documentation/devicetree/pi433-overlay.dts b/drivers/staging/pi433/Documentation/devicetree/pi433-overlay.dts new file mode 100644 index 000000000000..004b5027a934 --- /dev/null +++ b/drivers/staging/pi433/Documentation/devicetree/pi433-overlay.dts @@ -0,0 +1,53 @@ +// Definitions for Pi433 +/dts-v1/; +/plugin/; + +/ { + compatible = "bcm,bcm2835", "bcm,bcm2708", "bcm,bcm2709"; + + fragment@0 { + target = <&spi0>; + __overlay__ { + status = "okay"; + + spidev@0{ + status = "disabled"; + }; + + spidev@1{ + status = "disabled"; + }; + }; + }; + + fragment@1 { + target = <&gpio>; + __overlay__ { + pi433_pins: pi433_pins { + brcm,pins = <7 25 24>; + brcm,function = <0 0 0>; // in in in + }; + }; + }; + + fragment@2 { + target = <&spi0>; + __overlay__ { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + pi433: pi433@0 { + compatible = "Smarthome-Wolf,pi433"; + reg = <0>; + spi-max-frequency = <10000000>; + status = "okay"; + + pinctrl-0 = <&pi433_pins>; + DIO0-gpio = <&gpio 24 0>; + DIO1-gpio = <&gpio 25 0>; + DIO2-gpio = <&gpio 7 0>; + }; + }; + }; +}; diff --git a/drivers/staging/pi433/Documentation/devicetree/pi433.txt b/drivers/staging/pi433/Documentation/devicetree/pi433.txt new file mode 100644 index 000000000000..9ff217fbcbbd --- /dev/null +++ b/drivers/staging/pi433/Documentation/devicetree/pi433.txt @@ -0,0 +1,62 @@ +* Smarthome-Wolf Pi433 - a 433MHz radio module/shield for Raspberry Pi (see www.pi433.de) + +Required properties: +- compatible: must be "Smarthome-Wolf,pi433" +- reg: chip select of SPI Interface +- DIOx-gpio must be dedicated to the GPIO, connected with DIOx of the RFM69 module + + +Example: + +With the following lines in gpio-section, the gpio pins, connected with pi433 are +reserved/declared. + +&gpio{ + [...] + + pi433_pins: pi433_pins { + brcm,pins = <7 25 24>; + brcm,function = <0 0 0>; // in in in + }; + + [...] +} + +With the following lines in spi section, the device pi433 is declared. +It consists of the three gpio pins and an spi interface (here chip select 0) + +&spi0{ + [...] + + pi433: pi433@0 { + compatible = "Smarthome-Wolf,pi433"; + reg = <0>; /* CE 0 */ + #address-cells = <1>; + #size-cells = <0>; + spi-max-frequency = <10000000>; + + pinctrl-0 = <&pi433_pins>; + DIO0-gpio = <&gpio 24 0>; + DIO1-gpio = <&gpio 25 0>; + DIO2-gpio = <&gpio 7 0>; + }; +} + + + +For Raspbian users only +======================= +Since Raspbian supports device tree overlays, you may use and overlay, instead +of editing your boards device tree. +For using the overlay, you need to compile the file pi433-overlay.dts you can +find aside to this documentation. +The file needs to be compiled - either manually or by integration in your kernel +source tree. For a manual compile, you may use a command line like the following: +'linux/scripts/dtc/dtc -@ -I dts -O dtb -o pi433.dtbo pi433-overlay.dts' + +For compiling inside of the kernel tree, you need to copy pi433-overlay.dts to +arch/arm/boot/dts/overlays and you need to add the file to the list of files +in the Makefile over there. Execute 'make dtbs' in kernel tree root to make the +kernel make files compile the device tree overlay for you. + + diff --git a/drivers/staging/pi433/Documentation/pi433.txt b/drivers/staging/pi433/Documentation/pi433.txt new file mode 100644 index 000000000000..38b83b86c334 --- /dev/null +++ b/drivers/staging/pi433/Documentation/pi433.txt @@ -0,0 +1,274 @@ +===== +Pi433 +===== + + +Introduction +============ +This driver is for controlling pi433, a radio module for the Raspberry Pi +(www.pi433.de). It supports transmission and reception. It can be opened +by multiple applications for transmission and reception. While transmit +jobs were queued and process automatically in the background, the first +application asking for reception will block out all other applications +until something gets received terminates the read request. +The driver supports on the fly reloading of the hardware fifo of the rf +chip, thus enabling for much longer telegrams then hardware fifo size. + +Discription of driver operation +=============================== + +a) transmission + +Each transmission can take place with a different configuration of the rf +module. Therfore each application can set its own set of parameters. The driver +takes care, that each transmission takes place with the parameterset of the +application, that requests the transmission. To allow the transmission to take +place in the background, a tx thread is introduced. +The transfer of data from the main thread to the tx thread is realised by a +kfifo. With each write request of an application, the passed in data and the +corresponding parameter set gets written to the kfifo. +On the other "side" of the kfifo, the tx thread continuously checks, whether the +kfifo is empty. If not, it gets one set of config and data from the kfifo. If +there is no receive request or the receiver is still waiting for something in +the air, the rf module is set to standby, the parameters for transmission gets +set, the hardware fifo of the rf chip gets preloaded and the transmission gets +started. Upon hardware fifo threshold interrupt it gets reloaded, thus enabling +much longer telegrams then hardware fifo size. If the telegram is send and there +is more data available in the kfifo, the procedure is repeated. If not the +transmission cycle ends. + +b) reception + +Since there is only one application allowed to receive data at a time, for +reception there is only one configuration set. +As soon as an application sets an request for receiving a telegram, the reception +configuration set is written to the rf module and it gets set into receiving mode. +Now the driver is waiting, that a predefined RSSI level (signal strength at the +receiver) is reached. Until this hasn't happened, the reception can be +interrupted by the transmission thread at any time to insert a transmission cycle. +As soon as the predefined RSSI level is meat, a receiving cycle starts. Similar +as described for the transmission cycle the read out of the hardware fifo is done +dynamically. Upon each hardware fifo threshold interrupt, a portion of data gets +read. So also for reception it is possible to receive more data then the hardware +fifo can hold. + + +Driver API +========== + +The driver is currently implemented as a character device. Therefore it supports +the calls open, ioctl, read, write and close. + + +params for ioctl +---------------- + +There are four options: +PI433_IOC_RD_TX_CFG - get the transmission parameters from the driver +PI433_IOC_WR_TX_CFG - set the transmission parameters +PI433_IOC_RD_RX_CFG - get the receiving parameters from the driver +PI433_IOC_WR_RX_CFG - set the receiving parameters + +The tx configuration is transfered via struct pi433_tx_cfg, the parameterset for transmission. +It is devided into two sections: rf parameters and packet format. + +rf params: + frequency + frequency used for transmission. + Allowed values: 433050000...434790000 + bit_rate + bit rate used for transmission. + Allowed values: ##### + dev_frequency + frequency deviation in case of FSK. + Allowed values: 600...500000 + modulation + FSK - frequency shift key + OOK - On-Off-key + modShaping + shapingOff - no shaping + shaping1_0 - gauss filter with BT 1 (FSK only) + shaping0_5 - gauss filter with BT 0.5 (FSK only) + shaping0_3 - gauss filter with BT 0.3 (FSK only) + shapingBR - filter cut off at BR (OOK only) + shaping2BR - filter cut off at 2*BR (OOK only) + paRamp (FSK only) + ramp3400 - amp ramps up in 3.4ms + ramp2000 - amp ramps up in 2.0ms + ramp1000 - amp ramps up in 1ms + ramp500 - amp ramps up in 500us + ramp250 - amp ramps up in 250us + ramp125 - amp ramps up in 125us + ramp100 - amp ramps up in 100us + ramp62 - amp ramps up in 62us + ramp50 - amp ramps up in 50us + ramp40 - amp ramps up in 40us + ramp31 - amp ramps up in 31us + ramp25 - amp ramps up in 25us + ramp20 - amp ramps up in 20us + ramp15 - amp ramps up in 15us + ramp12 - amp ramps up in 12us + ramp10 - amp ramps up in 10us + tx_start_condition + fifoLevel - transmission starts, if fifo is filled to + threshold level + fifoNotEmpty - transmission starts, as soon as there is one + byte in internal fifo + repetitions + This gives the option, to send a telegram multiple times. Default: 1 + +packet format: + enable_preamble + optionOn - a preamble will be automatically generated + optionOff - no preamble will be generated + enable_sync + optionOn - a sync word will be automatically added to + the telegram after preamble + optionOff - no sync word will be added + Attention: While possible to generate sync without preamble, the + receiver won't be able to detect the sync without preamble. + enable_length_byte + optionOn - the length of the telegram will be automatically + added to the telegram. It's part of the payload + optionOff - no length information will be automatically added + to the telegram. + Attention: For telegram length over 255 bytes, this option can't be used + Attention: should be used in combination with sync, only + enable_address_byte + optionOn - the address byte will be automatically added to the + telgram. It's part of the payload + optionOff - the address byte will not be added to the telegram. + The address byte can be used for address filtering, so the receiver + will only receive telegrams with a given address byte. + Attention: should be used in combination with sync, only + enable_crc + optionOn - an crc will be automatically calculated over the + payload of the telegram and added to the telegram + after payload. + optionOff - no crc will be calculated + preamble_length + length of the preamble. Allowed values: 0...65536 + sync_length + length of the sync word. Allowed values: 0...8 + fixed_message_length + length of the payload of the telegram. Will override the length + given by the buffer, passed in with the write command. Will be + ignored if set to zero. + sync_pattern[8] + contains up to eight values, that are used as the sync pattern + on sync option + address_byte + one byte, used as address byte on address byte option. + + +The rx configuration is transfered via struct pi433_rx_cfg, the parameterset for receiving. It is devided into two sections: rf parameters and packet format. + +rf params: + frequency + frequency used for transmission. + Allowed values: 433050000...434790000 + bit_rate + bit rate used for transmission. + Allowed values: ##### + dev_frequency + frequency deviation in case of FSK. + Allowed values: 600...500000 + modulation + FSK - frequency shift key + OOK - on off key + rssi_threshold + threshold value for the signal strength on the receiver input. + If this value is exeeded, a reception cycle starts + Allowed values: 0...255 + thresholdDecrement + in order to adapt to different levels of singnal strength, over + time the receiver gets more and more sensitive. This value + determs, how fast the sensitivity increases. + step_0_5db - increase in 0,5dB steps + step_1_0db - increase in 1 db steps + step_1_5db - increase in 1,5dB steps + step_2_0db - increase in 2 db steps + step_3_0db - increase in 3 db steps + step_4_0db - increase in 4 db steps + step_5_0db - increase in 5 db steps + step_6_0db - increase in 6 db steps + antennaImpedance + sets the electrical adoption of the antenna + fiftyOhm - for antennas with an impedance of 50Ohm + twohundretOhm - for antennas with an impedance of 200Ohm + lnaGain + sets the gain of the low noise amp + automatic - lna gain is determed by an agc + max - lna gain is set to maximum + maxMinus6 - lna gain is set to 6db below max + maxMinus12 - lna gain is set to 12db below max + maxMinus24 - lna gain is set to 24db below max + maxMinus36 - lna gain is set to 36db below max + maxMinus48 - lna gain is set to 48db below max + bw_mantisse + sets the bandwidth of the channel filter - part one: mantisse. + mantisse16 - mantisse is set to 16 + mantisse20 - mantisse is set to 20 + mantisse24 - mantisse is set to 24 + bw_exponent + sets the bandwidth of the channel filter - part two: exponent. + Allowd values: 0...7 + dagc; + operation mode of the digital automatic gain control + normalMode + improve + improve4LowModulationIndex + + packet format: + enable_sync + optionOn - sync detection is enabled. If configured sync pattern + isn't found, telegram will be internally discarded + optionOff - sync detection is disabled. + enable_length_byte + optionOn - First byte of payload will be used as length byte, + regardless of the amount of bytes that were requested + by the read request. + optionOff - Number of bytes to be read will be set according to + amount of bytes that were requested by the read request. + Attention: should be used in combination with sync, only + enable_address_filtering; + filteringOff - no adress filtering will take place + nodeAddress - all telegrams, not matching the node + address will be internally discarded + nodeOrBroadcastAddress - all telegrams, neither matching the + node, nor the broadcast address will + be internally discarded + Attention: Sync option must be enabled in order to use this feature + enable_crc + optionOn - a crc will be calculated over the payload of + the telegram, that was received. If the + calculated crc doesn't match to two bytes, + that follow the payload, the telegram will be + internally discarded. + Attention: This option is only operational, if sync on and fixed length + or length byte is used + sync_length + Gives the length of the payload. + Attention: This setting must meet the setting of the transmitter, + if sync option is used. + fixed_message_length + Overrides the telegram length either given by the first byte of + payload or by the read request. + bytes_to_drop + gives the number of bytes, that will be dropped before transfering + data to the read buffer + This option is only usefull, if all packet helper are switched + off and the rf chip is used in raw receiving mode. This may be + needed, if a telegram of a third party device should be received, + using a protocol not compatible with the packet engine of the rf69 chip. + sync_pattern[8] + contains up to eight values, that are used as the sync pattern + on sync option. + This setting must meet the configuration of the transmitting device, + if sync option is enabled. + node_address + one byte, used as node address byte on address byte option. + broadcast_address + one byte, used as broadcast address byte on address byte option. + + diff --git a/drivers/staging/pi433/Kconfig b/drivers/staging/pi433/Kconfig new file mode 100644 index 000000000000..87c2ee192cca --- /dev/null +++ b/drivers/staging/pi433/Kconfig @@ -0,0 +1,16 @@ +config PI433 + tristate "Pi433 - a 433MHz radio module for Raspberry Pi" + depends on SPI + ---help--- + This option allows you to enable support for the radio module Pi433. + + Pi433 is a shield that fits onto the GPIO header of a Raspberry Pi + or compatible. It extends the Raspberry Pi with the option, to + send and receive data in the 433MHz ISM band - for example to + communicate between two systems without using ethernet or bluetooth + or for control or read sockets, actors, sensors, widely available + for low price. + + For details or the option to buy, please visit https://pi433.de/en.html + + If in doubt, say N here, but saying yes most probably won't hurt diff --git a/drivers/staging/pi433/Makefile b/drivers/staging/pi433/Makefile new file mode 100644 index 000000000000..417f3e4d12b1 --- /dev/null +++ b/drivers/staging/pi433/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_PI433) += pi433.o + +pi433-objs := pi433_if.o rf69.o diff --git a/drivers/staging/pi433/TODO b/drivers/staging/pi433/TODO new file mode 100644 index 000000000000..63a40bfcc67e --- /dev/null +++ b/drivers/staging/pi433/TODO @@ -0,0 +1,5 @@ +* coding style does not fully comply with the kernel style guide. +* still TODOs, annotated in the code +* currently the code introduces new IOCTLs. I'm afraid this is a bad idea. + -> Replace this with another interface, hints are welcome! +* Some missing data (marked with ###) needs to be added in the documentation diff --git a/drivers/staging/pi433/pi433_if.c b/drivers/staging/pi433/pi433_if.c new file mode 100644 index 000000000000..93c01680f016 --- /dev/null +++ b/drivers/staging/pi433/pi433_if.c @@ -0,0 +1,1338 @@ +/* + * userspace interface for pi433 radio module + * + * Pi433 is a 433MHz radio module for the Raspberry Pi. + * It is based on the HopeRf Module RFM69CW. Therefore inside of this + * driver, you'll find an abstraction of the rf69 chip. + * + * If needed, this driver could be extended, to also support other + * devices, basing on HopeRfs rf69. + * + * The driver can also be extended, to support other modules of + * HopeRf with a similar interace - e. g. RFM69HCW, RFM12, RFM95, ... + * + * Copyright (C) 2016 Wolf-Entwicklungen + * Marcus Wolf <linux@wolf-entwicklungen.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#undef DEBUG + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/idr.h> +#include <linux/ioctl.h> +#include <linux/uaccess.h> +#include <linux/fs.h> +#include <linux/device.h> +#include <linux/cdev.h> +#include <linux/err.h> +#include <linux/kfifo.h> +#include <linux/errno.h> +#include <linux/mutex.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/gpio/consumer.h> +#include <linux/kthread.h> +#include <linux/wait.h> +#include <linux/spi/spi.h> +#ifdef CONFIG_COMPAT +#include <asm/compat.h> +#endif + +#include "pi433_if.h" +#include "rf69.h" + + +#define N_PI433_MINORS (1U << MINORBITS) /*32*/ /* ... up to 256 */ +#define MAX_MSG_SIZE 900 /* min: FIFO_SIZE! */ +#define MSG_FIFO_SIZE 65536 /* 65536 = 2^16 */ +#define NUM_DIO 2 + +static dev_t pi433_dev; +static DEFINE_IDR(pi433_idr); +static DEFINE_MUTEX(minor_lock); /* Protect idr accesses */ + +static struct class *pi433_class; /* mainly for udev to create /dev/pi433 */ + +/* tx config is instance specific + * so with each open a new tx config struct is needed + */ +/* rx config is device specific + * so we have just one rx config, ebedded in device struct + */ +struct pi433_device { + /* device handling related values */ + dev_t devt; + int minor; + struct device *dev; + struct cdev *cdev; + struct spi_device *spi; + unsigned users; + + /* irq related values */ + struct gpio_desc *gpiod[NUM_DIO]; + int irq_num[NUM_DIO]; + u8 irq_state[NUM_DIO]; + + /* tx related values */ + STRUCT_KFIFO_REC_1(MSG_FIFO_SIZE) tx_fifo; + struct mutex tx_fifo_lock; // TODO: check, whether necessary or obsolete + struct task_struct *tx_task_struct; + wait_queue_head_t tx_wait_queue; + u8 free_in_fifo; + char buffer[MAX_MSG_SIZE]; + + /* rx related values */ + struct pi433_rx_cfg rx_cfg; + u8 *rx_buffer; + unsigned int rx_buffer_size; + u32 rx_bytes_to_drop; + u32 rx_bytes_dropped; + unsigned int rx_position; + struct mutex rx_lock; + wait_queue_head_t rx_wait_queue; + + /* fifo wait queue */ + struct task_struct *fifo_task_struct; + wait_queue_head_t fifo_wait_queue; + + /* flags */ + bool rx_active; + bool tx_active; + bool interrupt_rx_allowed; +}; + +struct pi433_instance { + struct pi433_device *device; + struct pi433_tx_cfg tx_cfg; +}; + +/*-------------------------------------------------------------------------*/ + +/* macro for checked access of registers of radio module */ +#define SET_CHECKED(retval) \ + if (retval < 0) \ + return retval; + +/*-------------------------------------------------------------------------*/ + +/* GPIO interrupt handlers */ +static irqreturn_t DIO0_irq_handler(int irq, void *dev_id) +{ + struct pi433_device *device = dev_id; + + if (device->irq_state[DIO0] == DIO_PacketSent) + { + device->free_in_fifo = FIFO_SIZE; + printk("DIO0 irq: Packet sent\n"); // TODO: printk() should include KERN_ facility level + wake_up_interruptible(&device->fifo_wait_queue); + } + else if (device->irq_state[DIO0] == DIO_Rssi_DIO0) + { + printk("DIO0 irq: RSSI level over threshold\n"); + wake_up_interruptible(&device->rx_wait_queue); + } + else if (device->irq_state[DIO0] == DIO_PayloadReady) + { + printk("DIO0 irq: PayloadReady\n"); + device->free_in_fifo = 0; + wake_up_interruptible(&device->fifo_wait_queue); + } + + return IRQ_HANDLED; +} + +static irqreturn_t DIO1_irq_handler(int irq, void *dev_id) +{ + struct pi433_device *device = dev_id; + + if (device->irq_state[DIO1] == DIO_FifoNotEmpty_DIO1) + { + device->free_in_fifo = FIFO_SIZE; + } + else if (device->irq_state[DIO1] == DIO_FifoLevel) + { + if (device->rx_active) device->free_in_fifo = FIFO_THRESHOLD - 1; + else device->free_in_fifo = FIFO_SIZE - FIFO_THRESHOLD - 1; + } + printk("DIO1 irq: %d bytes free in fifo\n", device->free_in_fifo); // TODO: printk() should include KERN_ facility level + wake_up_interruptible(&device->fifo_wait_queue); + + return IRQ_HANDLED; +} + +/*-------------------------------------------------------------------------*/ + +static int +rf69_set_rx_cfg(struct pi433_device *dev, struct pi433_rx_cfg *rx_cfg) +{ + int ret; + int payload_length; + + /* receiver config */ + SET_CHECKED(rf69_set_frequency (dev->spi, rx_cfg->frequency)); + SET_CHECKED(rf69_set_bit_rate (dev->spi, rx_cfg->bit_rate)); + SET_CHECKED(rf69_set_modulation (dev->spi, rx_cfg->modulation)); + SET_CHECKED(rf69_set_antenna_impedance (dev->spi, rx_cfg->antenna_impedance)); + SET_CHECKED(rf69_set_rssi_threshold (dev->spi, rx_cfg->rssi_threshold)); + SET_CHECKED(rf69_set_ook_threshold_dec (dev->spi, rx_cfg->thresholdDecrement)); + SET_CHECKED(rf69_set_bandwidth (dev->spi, rx_cfg->bw_mantisse, rx_cfg->bw_exponent)); + SET_CHECKED(rf69_set_bandwidth_during_afc(dev->spi, rx_cfg->bw_mantisse, rx_cfg->bw_exponent)); + SET_CHECKED(rf69_set_dagc (dev->spi, rx_cfg->dagc)); + + dev->rx_bytes_to_drop = rx_cfg->bytes_to_drop; + + /* packet config */ + /* enable */ + SET_CHECKED(rf69_set_sync_enable(dev->spi, rx_cfg->enable_sync)); + if (rx_cfg->enable_sync == optionOn) + { + SET_CHECKED(rf69_set_fifo_fill_condition(dev->spi, afterSyncInterrupt)); + } + else + { + SET_CHECKED(rf69_set_fifo_fill_condition(dev->spi, always)); + } + if (rx_cfg->enable_length_byte == optionOn) { + ret = rf69_set_packet_format(dev->spi, packetLengthVar); + if (ret < 0) + return ret; + } else { + ret = rf69_set_packet_format(dev->spi, packetLengthFix); + if (ret < 0) + return ret; + } + SET_CHECKED(rf69_set_adressFiltering(dev->spi, rx_cfg->enable_address_filtering)); + SET_CHECKED(rf69_set_crc_enable (dev->spi, rx_cfg->enable_crc)); + + /* lengths */ + SET_CHECKED(rf69_set_sync_size(dev->spi, rx_cfg->sync_length)); + if (rx_cfg->enable_length_byte == optionOn) + { + SET_CHECKED(rf69_set_payload_length(dev->spi, 0xff)); + } + else if (rx_cfg->fixed_message_length != 0) + { + payload_length = rx_cfg->fixed_message_length; + if (rx_cfg->enable_length_byte == optionOn) payload_length++; + if (rx_cfg->enable_address_filtering != filteringOff) payload_length++; + SET_CHECKED(rf69_set_payload_length(dev->spi, payload_length)); + } + else + { + SET_CHECKED(rf69_set_payload_length(dev->spi, 0)); + } + + /* values */ + if (rx_cfg->enable_sync == optionOn) + { + SET_CHECKED(rf69_set_sync_values(dev->spi, rx_cfg->sync_pattern)); + } + if (rx_cfg->enable_address_filtering != filteringOff) + { + SET_CHECKED(rf69_set_node_address (dev->spi, rx_cfg->node_address)); + SET_CHECKED(rf69_set_broadcast_address(dev->spi, rx_cfg->broadcast_address)); + } + + return 0; +} + +static int +rf69_set_tx_cfg(struct pi433_device *dev, struct pi433_tx_cfg *tx_cfg) +{ + int ret; + + SET_CHECKED(rf69_set_frequency (dev->spi, tx_cfg->frequency)); + SET_CHECKED(rf69_set_bit_rate (dev->spi, tx_cfg->bit_rate)); + SET_CHECKED(rf69_set_modulation (dev->spi, tx_cfg->modulation)); + SET_CHECKED(rf69_set_deviation (dev->spi, tx_cfg->dev_frequency)); + SET_CHECKED(rf69_set_pa_ramp (dev->spi, tx_cfg->pa_ramp)); + SET_CHECKED(rf69_set_modulation_shaping(dev->spi, tx_cfg->modShaping)); + SET_CHECKED(rf69_set_tx_start_condition(dev->spi, tx_cfg->tx_start_condition)); + + /* packet format enable */ + if (tx_cfg->enable_preamble == optionOn) + { + SET_CHECKED(rf69_set_preamble_length(dev->spi, tx_cfg->preamble_length)); + } + else + { + SET_CHECKED(rf69_set_preamble_length(dev->spi, 0)); + } + SET_CHECKED(rf69_set_sync_enable (dev->spi, tx_cfg->enable_sync)); + if (tx_cfg->enable_length_byte == optionOn) { + ret = rf69_set_packet_format(dev->spi, packetLengthVar); + if (ret < 0) + return ret; + } else { + ret = rf69_set_packet_format(dev->spi, packetLengthFix); + if (ret < 0) + return ret; + } + SET_CHECKED(rf69_set_crc_enable (dev->spi, tx_cfg->enable_crc)); + + /* configure sync, if enabled */ + if (tx_cfg->enable_sync == optionOn) + { + SET_CHECKED(rf69_set_sync_size(dev->spi, tx_cfg->sync_length)); + SET_CHECKED(rf69_set_sync_values(dev->spi, tx_cfg->sync_pattern)); + } + + return 0; +} + +/*-------------------------------------------------------------------------*/ + +static int +pi433_start_rx(struct pi433_device *dev) +{ + int retval; + + /* return without action, if no pending read request */ + if (!dev->rx_active) + return 0; + + /* setup for receiving */ + retval = rf69_set_rx_cfg(dev, &dev->rx_cfg); + if (retval) return retval; + + /* setup rssi irq */ + SET_CHECKED(rf69_set_dio_mapping(dev->spi, DIO0, DIO_Rssi_DIO0)); + dev->irq_state[DIO0] = DIO_Rssi_DIO0; + irq_set_irq_type(dev->irq_num[DIO0], IRQ_TYPE_EDGE_RISING); + + /* setup fifo level interrupt */ + SET_CHECKED(rf69_set_fifo_threshold(dev->spi, FIFO_SIZE - FIFO_THRESHOLD)); + SET_CHECKED(rf69_set_dio_mapping(dev->spi, DIO1, DIO_FifoLevel)); + dev->irq_state[DIO1] = DIO_FifoLevel; + irq_set_irq_type(dev->irq_num[DIO1], IRQ_TYPE_EDGE_RISING); + + /* set module to receiving mode */ + SET_CHECKED(rf69_set_mode(dev->spi, receive)); + + return 0; +} + + +/*-------------------------------------------------------------------------*/ + +static int +pi433_receive(void *data) +{ + struct pi433_device *dev = data; + struct spi_device *spi = dev->spi; /* needed for SET_CHECKED */ + int bytes_to_read, bytes_total; + int retval; + + dev->interrupt_rx_allowed = false; + + /* wait for any tx to finish */ + dev_dbg(dev->dev,"rx: going to wait for any tx to finish"); + retval = wait_event_interruptible(dev->rx_wait_queue, !dev->tx_active); + if(retval) /* wait was interrupted */ + { + dev->interrupt_rx_allowed = true; + wake_up_interruptible(&dev->tx_wait_queue); + return retval; + } + + /* prepare status vars */ + dev->free_in_fifo = FIFO_SIZE; + dev->rx_position = 0; + dev->rx_bytes_dropped = 0; + + /* setup radio module to listen for something "in the air" */ + retval = pi433_start_rx(dev); + if (retval) + return retval; + + /* now check RSSI, if low wait for getting high (RSSI interrupt) */ + while ( !rf69_get_flag(dev->spi, rssiExceededThreshold) ) + { + /* allow tx to interrupt us while waiting for high RSSI */ + dev->interrupt_rx_allowed = true; + wake_up_interruptible(&dev->tx_wait_queue); + + /* wait for RSSI level to become high */ + dev_dbg(dev->dev, "rx: going to wait for high RSSI level"); + retval = wait_event_interruptible(dev->rx_wait_queue, + rf69_get_flag(dev->spi, + rssiExceededThreshold)); + if (retval) goto abort; /* wait was interrupted */ + dev->interrupt_rx_allowed = false; + + /* cross check for ongoing tx */ + if (!dev->tx_active) break; + } + + /* configure payload ready irq */ + SET_CHECKED(rf69_set_dio_mapping(spi, DIO0, DIO_PayloadReady)); + dev->irq_state[DIO0] = DIO_PayloadReady; + irq_set_irq_type(dev->irq_num[DIO0], IRQ_TYPE_EDGE_RISING); + + /* fixed or unlimited length? */ + if (dev->rx_cfg.fixed_message_length != 0) + { + if (dev->rx_cfg.fixed_message_length > dev->rx_buffer_size) + { + retval = -1; + goto abort; + } + bytes_total = dev->rx_cfg.fixed_message_length; + dev_dbg(dev->dev,"rx: msg len set to %d by fixed length", bytes_total); + } + else + { + bytes_total = dev->rx_buffer_size; + dev_dbg(dev->dev, "rx: msg len set to %d as requested by read", bytes_total); + } + + /* length byte enabled? */ + if (dev->rx_cfg.enable_length_byte == optionOn) + { + retval = wait_event_interruptible(dev->fifo_wait_queue, + dev->free_in_fifo < FIFO_SIZE); + if (retval) goto abort; /* wait was interrupted */ + + rf69_read_fifo(spi, (u8 *)&bytes_total, 1); + if (bytes_total > dev->rx_buffer_size) + { + retval = -1; + goto abort; + } + dev->free_in_fifo++; + dev_dbg(dev->dev, "rx: msg len reset to %d due to length byte", bytes_total); + } + + /* address byte enabled? */ + if (dev->rx_cfg.enable_address_filtering != filteringOff) + { + u8 dummy; + + bytes_total--; + + retval = wait_event_interruptible(dev->fifo_wait_queue, + dev->free_in_fifo < FIFO_SIZE); + if (retval) goto abort; /* wait was interrupted */ + + rf69_read_fifo(spi, &dummy, 1); + dev->free_in_fifo++; + dev_dbg(dev->dev, "rx: address byte stripped off"); + } + + /* get payload */ + while (dev->rx_position < bytes_total) + { + if ( !rf69_get_flag(dev->spi, payloadReady) ) + { + retval = wait_event_interruptible(dev->fifo_wait_queue, + dev->free_in_fifo < FIFO_SIZE); + if (retval) goto abort; /* wait was interrupted */ + } + + /* need to drop bytes or acquire? */ + if (dev->rx_bytes_to_drop > dev->rx_bytes_dropped) + bytes_to_read = dev->rx_bytes_to_drop - dev->rx_bytes_dropped; + else + bytes_to_read = bytes_total - dev->rx_position; + + + /* access the fifo */ + if (bytes_to_read > FIFO_SIZE - dev->free_in_fifo) + bytes_to_read = FIFO_SIZE - dev->free_in_fifo; + retval = rf69_read_fifo(spi, + &dev->rx_buffer[dev->rx_position], + bytes_to_read); + if (retval) goto abort; /* read failed */ + dev->free_in_fifo += bytes_to_read; + + /* adjust status vars */ + if (dev->rx_bytes_to_drop > dev->rx_bytes_dropped) + dev->rx_bytes_dropped += bytes_to_read; + else + dev->rx_position += bytes_to_read; + } + + + /* rx done, wait was interrupted or error occured */ +abort: + dev->interrupt_rx_allowed = true; + SET_CHECKED(rf69_set_mode(dev->spi, standby)); + wake_up_interruptible(&dev->tx_wait_queue); + + if (retval) + return retval; + else + return bytes_total; +} + +static int +pi433_tx_thread(void *data) +{ + struct pi433_device *device = data; + struct spi_device *spi = device->spi; /* needed for SET_CHECKED */ + struct pi433_tx_cfg tx_cfg; + u8 *buffer = device->buffer; + size_t size; + bool rx_interrupted = false; + int position, repetitions; + int retval; + + while (1) + { + /* wait for fifo to be populated or for request to terminate*/ + dev_dbg(device->dev, "thread: going to wait for new messages"); + wait_event_interruptible(device->tx_wait_queue, + ( !kfifo_is_empty(&device->tx_fifo) || + kthread_should_stop() )); + if ( kthread_should_stop() ) + return 0; + + /* get data from fifo in the following order: + * - tx_cfg + * - size of message + * - message + */ + mutex_lock(&device->tx_fifo_lock); + + retval = kfifo_out(&device->tx_fifo, &tx_cfg, sizeof(tx_cfg)); + if (retval != sizeof(tx_cfg)) + { + dev_dbg(device->dev, "reading tx_cfg from fifo failed: got %d byte(s), expected %d", retval, (unsigned int)sizeof(tx_cfg) ); + mutex_unlock(&device->tx_fifo_lock); + continue; + } + + retval = kfifo_out(&device->tx_fifo, &size, sizeof(size_t)); + if (retval != sizeof(size_t)) + { + dev_dbg(device->dev, "reading msg size from fifo failed: got %d, expected %d", retval, (unsigned int)sizeof(size_t) ); + mutex_unlock(&device->tx_fifo_lock); + continue; + } + + /* use fixed message length, if requested */ + if (tx_cfg.fixed_message_length != 0) + size = tx_cfg.fixed_message_length; + + /* increase size, if len byte is requested */ + if (tx_cfg.enable_length_byte == optionOn) + size++; + + /* increase size, if adr byte is requested */ + if (tx_cfg.enable_address_byte == optionOn) + size++; + + /* prime buffer */ + memset(buffer, 0, size); + position = 0; + + /* add length byte, if requested */ + if (tx_cfg.enable_length_byte == optionOn) + buffer[position++] = size-1; /* according to spec length byte itself must be excluded from the length calculation */ + + /* add adr byte, if requested */ + if (tx_cfg.enable_address_byte == optionOn) + buffer[position++] = tx_cfg.address_byte; + + /* finally get message data from fifo */ + retval = kfifo_out(&device->tx_fifo, &buffer[position], sizeof(buffer)-position ); + dev_dbg(device->dev, "read %d message byte(s) from fifo queue.", retval); + mutex_unlock(&device->tx_fifo_lock); + + /* if rx is active, we need to interrupt the waiting for + * incoming telegrams, to be able to send something. + * We are only allowed, if currently no reception takes + * place otherwise we need to wait for the incoming telegram + * to finish + */ + wait_event_interruptible(device->tx_wait_queue, + !device->rx_active || + device->interrupt_rx_allowed == true); + + /* prevent race conditions + * irq will be reenabled after tx config is set + */ + disable_irq(device->irq_num[DIO0]); + device->tx_active = true; + + if (device->rx_active && rx_interrupted == false) + { + /* rx is currently waiting for a telegram; + * we need to set the radio module to standby + */ + SET_CHECKED(rf69_set_mode(device->spi, standby)); + rx_interrupted = true; + } + + /* clear fifo, set fifo threshold, set payload length */ + SET_CHECKED(rf69_set_mode(spi, standby)); /* this clears the fifo */ + SET_CHECKED(rf69_set_fifo_threshold(spi, FIFO_THRESHOLD)); + if (tx_cfg.enable_length_byte == optionOn) + { + SET_CHECKED(rf69_set_payload_length(spi, size * tx_cfg.repetitions)); + } + else + { + SET_CHECKED(rf69_set_payload_length(spi, 0)); + } + + /* configure the rf chip */ + rf69_set_tx_cfg(device, &tx_cfg); + + /* enable fifo level interrupt */ + SET_CHECKED(rf69_set_dio_mapping(spi, DIO1, DIO_FifoLevel)); + device->irq_state[DIO1] = DIO_FifoLevel; + irq_set_irq_type(device->irq_num[DIO1], IRQ_TYPE_EDGE_FALLING); + + /* enable packet sent interrupt */ + SET_CHECKED(rf69_set_dio_mapping(spi, DIO0, DIO_PacketSent)); + device->irq_state[DIO0] = DIO_PacketSent; + irq_set_irq_type(device->irq_num[DIO0], IRQ_TYPE_EDGE_RISING); + enable_irq(device->irq_num[DIO0]); /* was disabled by rx active check */ + + /* enable transmission */ + SET_CHECKED(rf69_set_mode(spi, transmit)); + + /* transfer this msg (and repetitions) to chip fifo */ + device->free_in_fifo = FIFO_SIZE; + position = 0; + repetitions = tx_cfg.repetitions; + while( (repetitions > 0) && (size > position) ) + { + if ( (size - position) > device->free_in_fifo) + { /* msg to big for fifo - take a part */ + int temp = device->free_in_fifo; + device->free_in_fifo = 0; + rf69_write_fifo(spi, + &buffer[position], + temp); + position +=temp; + } + else + { /* msg fits into fifo - take all */ + device->free_in_fifo -= size; + repetitions--; + rf69_write_fifo(spi, + &buffer[position], + (size - position) ); + position = 0; /* reset for next repetition */ + } + + retval = wait_event_interruptible(device->fifo_wait_queue, + device->free_in_fifo > 0); + if (retval) { printk("ABORT\n"); goto abort; } + } + + /* we are done. Wait for packet to get sent */ + dev_dbg(device->dev, "thread: wait for packet to get sent/fifo to be empty"); + wait_event_interruptible(device->fifo_wait_queue, + device->free_in_fifo == FIFO_SIZE || + kthread_should_stop() ); + if ( kthread_should_stop() ) printk("ABORT\n"); + + + /* STOP_TRANSMISSION */ + dev_dbg(device->dev, "thread: Packet sent. Set mode to stby."); + SET_CHECKED(rf69_set_mode(spi, standby)); + + /* everything sent? */ + if ( kfifo_is_empty(&device->tx_fifo) ) + { +abort: + if (rx_interrupted) + { + rx_interrupted = false; + pi433_start_rx(device); + } + device->tx_active = false; + wake_up_interruptible(&device->rx_wait_queue); + } + } +} + +/*-------------------------------------------------------------------------*/ + +static ssize_t +pi433_read(struct file *filp, char __user *buf, size_t size, loff_t *f_pos) +{ + struct pi433_instance *instance; + struct pi433_device *device; + int bytes_received; + ssize_t retval; + + /* check, whether internal buffer is big enough for requested size */ + if (size > MAX_MSG_SIZE) + return -EMSGSIZE; + + instance = filp->private_data; + device = instance->device; + + /* just one read request at a time */ + mutex_lock(&device->rx_lock); + if (device->rx_active) + { + mutex_unlock(&device->rx_lock); + return -EAGAIN; + } + else + { + device->rx_active = true; + mutex_unlock(&device->rx_lock); + } + + /* start receiving */ + /* will block until something was received*/ + device->rx_buffer_size = size; + bytes_received = pi433_receive(device); + + /* release rx */ + mutex_lock(&device->rx_lock); + device->rx_active = false; + mutex_unlock(&device->rx_lock); + + /* if read was successful copy to user space*/ + if (bytes_received > 0) + { + retval = copy_to_user(buf, device->rx_buffer, bytes_received); + if (retval) + return -EFAULT; + } + + return bytes_received; +} + + +static ssize_t +pi433_write(struct file *filp, const char __user *buf, + size_t count, loff_t *f_pos) +{ + struct pi433_instance *instance; + struct pi433_device *device; + int copied, retval; + + instance = filp->private_data; + device = instance->device; + + /* check, whether internal buffer (tx thread) is big enough for requested size */ + if (count > MAX_MSG_SIZE) + return -EMSGSIZE; + + /* write the following sequence into fifo: + * - tx_cfg + * - size of message + * - message + */ + mutex_lock(&device->tx_fifo_lock); + retval = kfifo_in(&device->tx_fifo, &instance->tx_cfg, sizeof(instance->tx_cfg)); + if ( retval != sizeof(instance->tx_cfg) ) + goto abort; + + retval = kfifo_in (&device->tx_fifo, &count, sizeof(size_t)); + if ( retval != sizeof(size_t) ) + goto abort; + + retval = kfifo_from_user(&device->tx_fifo, buf, count, &copied); + if (retval || copied != count) + goto abort; + + mutex_unlock(&device->tx_fifo_lock); + + /* start transfer */ + wake_up_interruptible(&device->tx_wait_queue); + dev_dbg(device->dev, "write: generated new msg with %d bytes.", copied); + + return 0; + +abort: + dev_dbg(device->dev, "write to fifo failed: 0x%x", retval); + kfifo_reset(&device->tx_fifo); // TODO: maybe find a solution, not to discard already stored, valid entries + mutex_unlock(&device->tx_fifo_lock); + return -EAGAIN; +} + + +static long +pi433_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + int err = 0; + int retval = 0; + struct pi433_instance *instance; + struct pi433_device *device; + u32 tmp; + + /* Check type and command number */ + if (_IOC_TYPE(cmd) != PI433_IOC_MAGIC) + return -ENOTTY; + + /* Check access direction once here; don't repeat below. + * IOC_DIR is from the user perspective, while access_ok is + * from the kernel perspective; so they look reversed. + */ + if (_IOC_DIR(cmd) & _IOC_READ) + err = !access_ok(VERIFY_WRITE, + (void __user *)arg, + _IOC_SIZE(cmd)); + + if (err == 0 && _IOC_DIR(cmd) & _IOC_WRITE) + err = !access_ok(VERIFY_READ, + (void __user *)arg, + _IOC_SIZE(cmd)); + if (err) + return -EFAULT; + + /* TODO? guard against device removal before, or while, + * we issue this ioctl. --> device_get() + */ + instance = filp->private_data; + device = instance->device; + + if (device == NULL) + return -ESHUTDOWN; + + switch (cmd) { + case PI433_IOC_RD_TX_CFG: + tmp = _IOC_SIZE(cmd); + if ( (tmp == 0) || ((tmp % sizeof(struct pi433_tx_cfg)) != 0) ) + { + retval = -EINVAL; + break; + } + + if (__copy_to_user((void __user *)arg, + &instance->tx_cfg, + tmp)) + { + retval = -EFAULT; + break; + } + + break; + case PI433_IOC_WR_TX_CFG: + tmp = _IOC_SIZE(cmd); + if ( (tmp == 0) || ((tmp % sizeof(struct pi433_tx_cfg)) != 0) ) + { + retval = -EINVAL; + break; + } + + if (__copy_from_user(&instance->tx_cfg, + (void __user *)arg, + tmp)) + { + retval = -EFAULT; + break; + } + + break; + + case PI433_IOC_RD_RX_CFG: + tmp = _IOC_SIZE(cmd); + if ( (tmp == 0) || ((tmp % sizeof(struct pi433_rx_cfg)) != 0) ) { + retval = -EINVAL; + break; + } + + if (__copy_to_user((void __user *)arg, + &device->rx_cfg, + tmp)) + { + retval = -EFAULT; + break; + } + + break; + case PI433_IOC_WR_RX_CFG: + tmp = _IOC_SIZE(cmd); + mutex_lock(&device->rx_lock); + + /* during pendig read request, change of config not allowed */ + if (device->rx_active) { + retval = -EAGAIN; + mutex_unlock(&device->rx_lock); + break; + } + + if ( (tmp == 0) || ((tmp % sizeof(struct pi433_rx_cfg)) != 0) ) { + retval = -EINVAL; + mutex_unlock(&device->rx_lock); + break; + } + + if (__copy_from_user(&device->rx_cfg, + (void __user *)arg, + tmp)) + { + retval = -EFAULT; + mutex_unlock(&device->rx_lock); + break; + } + + mutex_unlock(&device->rx_lock); + break; + default: + retval = -EINVAL; + } + + return retval; +} + +#ifdef CONFIG_COMPAT +static long +pi433_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + return pi433_ioctl(filp, cmd, (unsigned long)compat_ptr(arg)); +} +#else +#define pi433_compat_ioctl NULL +#endif /* CONFIG_COMPAT */ + +/*-------------------------------------------------------------------------*/ + +static int pi433_open(struct inode *inode, struct file *filp) +{ + struct pi433_device *device; + struct pi433_instance *instance; + + mutex_lock(&minor_lock); + device = idr_find(&pi433_idr, iminor(inode)); + mutex_unlock(&minor_lock); + if (!device) { + pr_debug("device: minor %d unknown.\n", iminor(inode)); + return -ENODEV; + } + + if (!device->rx_buffer) { + device->rx_buffer = kmalloc(MAX_MSG_SIZE, GFP_KERNEL); + if (!device->rx_buffer) + { + dev_dbg(device->dev, "open/ENOMEM\n"); + return -ENOMEM; + } + } + + device->users++; + instance = kzalloc(sizeof(*instance), GFP_KERNEL); + if (!instance) + { + kfree(device->rx_buffer); + device->rx_buffer = NULL; + return -ENOMEM; + } + + /* setup instance data*/ + instance->device = device; + instance->tx_cfg.bit_rate = 4711; + // TODO: fill instance->tx_cfg; + + /* instance data as context */ + filp->private_data = instance; + nonseekable_open(inode, filp); + + return 0; +} + +static int pi433_release(struct inode *inode, struct file *filp) +{ + struct pi433_instance *instance; + struct pi433_device *device; + + instance = filp->private_data; + device = instance->device; + kfree(instance); + filp->private_data = NULL; + + /* last close? */ + device->users--; + + if (!device->users) { + kfree(device->rx_buffer); + device->rx_buffer = NULL; + if (device->spi == NULL) + kfree(device); + } + + return 0; +} + + +/*-------------------------------------------------------------------------*/ + +static int setup_GPIOs(struct pi433_device *device) +{ + char name[5]; + int retval; + int i; + const irq_handler_t DIO_irq_handler[NUM_DIO] = { + DIO0_irq_handler, + DIO1_irq_handler + }; + + for (i=0; i<NUM_DIO; i++) + { + /* "construct" name and get the gpio descriptor */ + snprintf(name, sizeof(name), "DIO%d", i); + device->gpiod[i] = gpiod_get(&device->spi->dev, name, 0 /*GPIOD_IN*/); + + if (device->gpiod[i] == ERR_PTR(-ENOENT)) + { + dev_dbg(&device->spi->dev, "Could not find entry for %s. Ignoring.", name); + continue; + } + + if (device->gpiod[i] == ERR_PTR(-EBUSY)) + dev_dbg(&device->spi->dev, "%s is busy.", name); + + if ( IS_ERR(device->gpiod[i]) ) + { + retval = PTR_ERR(device->gpiod[i]); + /* release already allocated gpios */ + for (i--; i>=0; i--) + { + free_irq(device->irq_num[i], device); + gpiod_put(device->gpiod[i]); + } + return retval; + } + + + /* configure the pin */ + gpiod_unexport(device->gpiod[i]); + retval = gpiod_direction_input(device->gpiod[i]); + if (retval) return retval; + + + /* configure irq */ + device->irq_num[i] = gpiod_to_irq(device->gpiod[i]); + if (device->irq_num[i] < 0) + { + device->gpiod[i] = ERR_PTR(-EINVAL);//(struct gpio_desc *)device->irq_num[i]; + return device->irq_num[i]; + } + retval = request_irq(device->irq_num[i], + DIO_irq_handler[i], + 0, /* flags */ + name, + device); + + if (retval) + return retval; + + dev_dbg(&device->spi->dev, "%s succesfully configured", name); + } + + return 0; +} + +static void free_GPIOs(struct pi433_device *device) +{ + int i; + + for (i=0; i<NUM_DIO; i++) + { + /* check if gpiod is valid */ + if ( IS_ERR(device->gpiod[i]) ) + continue; + + free_irq(device->irq_num[i], device); + gpiod_put(device->gpiod[i]); + } + return; +} + +static int pi433_get_minor(struct pi433_device *device) +{ + int retval = -ENOMEM; + + mutex_lock(&minor_lock); + retval = idr_alloc(&pi433_idr, device, 0, N_PI433_MINORS, GFP_KERNEL); + if (retval >= 0) { + device->minor = retval; + retval = 0; + } else if (retval == -ENOSPC) { + dev_err(device->dev, "too many pi433 devices\n"); + retval = -EINVAL; + } + mutex_unlock(&minor_lock); + return retval; +} + +static void pi433_free_minor(struct pi433_device *dev) +{ + mutex_lock(&minor_lock); + idr_remove(&pi433_idr, dev->minor); + mutex_unlock(&minor_lock); +} +/*-------------------------------------------------------------------------*/ + +static const struct file_operations pi433_fops = { + .owner = THIS_MODULE, + /* REVISIT switch to aio primitives, so that userspace + * gets more complete API coverage. It'll simplify things + * too, except for the locking. + */ + .write = pi433_write, + .read = pi433_read, + .unlocked_ioctl = pi433_ioctl, + .compat_ioctl = pi433_compat_ioctl, + .open = pi433_open, + .release = pi433_release, + .llseek = no_llseek, +}; + +/*-------------------------------------------------------------------------*/ + +static int pi433_probe(struct spi_device *spi) +{ + struct pi433_device *device; + int retval; + + /* setup spi parameters */ + spi->mode = 0x00; + spi->bits_per_word = 8; + /* spi->max_speed_hz = 10000000; 1MHz already set by device tree overlay */ + + retval = spi_setup(spi); + if (retval) + { + dev_dbg(&spi->dev, "configuration of SPI interface failed!\n"); + return retval; + } + else + { + dev_dbg(&spi->dev, + "spi interface setup: mode 0x%2x, %d bits per word, %dhz max speed", + spi->mode, spi->bits_per_word, spi->max_speed_hz); + } + + /* Ping the chip by reading the version register */ + retval = spi_w8r8(spi, 0x10); + if (retval < 0) + return retval; + + switch (retval) { + case 0x24: + dev_dbg(&spi->dev, "found pi433 (ver. 0x%x)", retval); + break; + default: + dev_dbg(&spi->dev, "unknown chip version: 0x%x", retval); + return -ENODEV; + } + + /* Allocate driver data */ + device = kzalloc(sizeof(*device), GFP_KERNEL); + if (!device) + return -ENOMEM; + + /* Initialize the driver data */ + device->spi = spi; + device->rx_active = false; + device->tx_active = false; + device->interrupt_rx_allowed = false; + + /* init wait queues */ + init_waitqueue_head(&device->tx_wait_queue); + init_waitqueue_head(&device->rx_wait_queue); + init_waitqueue_head(&device->fifo_wait_queue); + + /* init fifo */ + INIT_KFIFO(device->tx_fifo); + + /* init mutexes and locks */ + mutex_init(&device->tx_fifo_lock); + mutex_init(&device->rx_lock); + + /* setup GPIO (including irq_handler) for the different DIOs */ + retval = setup_GPIOs(device); + if (retval) + { + dev_dbg(&spi->dev, "setup of GPIOs failed"); + goto GPIO_failed; + } + + /* setup the radio module */ + SET_CHECKED(rf69_set_mode (spi, standby)); + SET_CHECKED(rf69_set_data_mode (spi, packet)); + SET_CHECKED(rf69_set_amplifier_0 (spi, optionOn)); + SET_CHECKED(rf69_set_amplifier_1 (spi, optionOff)); + SET_CHECKED(rf69_set_amplifier_2 (spi, optionOff)); + SET_CHECKED(rf69_set_output_power_level (spi, 13)); + SET_CHECKED(rf69_set_antenna_impedance (spi, fiftyOhm)); + + /* start tx thread */ + device->tx_task_struct = kthread_run(pi433_tx_thread, + device, + "pi433_tx_task"); + if (IS_ERR(device->tx_task_struct)) + { + dev_dbg(device->dev, "start of send thread failed"); + goto send_thread_failed; + } + + /* determ minor number */ + retval = pi433_get_minor(device); + if (retval) + { + dev_dbg(device->dev, "get of minor number failed"); + goto minor_failed; + } + + /* create device */ + device->devt = MKDEV(MAJOR(pi433_dev), device->minor); + device->dev = device_create(pi433_class, + &spi->dev, + device->devt, + device, + "pi433"); + if (IS_ERR(device->dev)) { + pr_err("pi433: device register failed\n"); + retval = PTR_ERR(device->dev); + goto device_create_failed; + } + else { + dev_dbg(device->dev, + "created device for major %d, minor %d\n", + MAJOR(pi433_dev), + device->minor); + } + + /* create cdev */ + device->cdev = cdev_alloc(); + device->cdev->owner = THIS_MODULE; + cdev_init(device->cdev, &pi433_fops); + retval = cdev_add(device->cdev, device->devt, 1); + if (retval) + { + dev_dbg(device->dev, "register of cdev failed"); + goto cdev_failed; + } + + /* spi setup */ + spi_set_drvdata(spi, device); + + return 0; + +cdev_failed: + device_destroy(pi433_class, device->devt); +device_create_failed: + pi433_free_minor(device); +minor_failed: + kthread_stop(device->tx_task_struct); +send_thread_failed: + free_GPIOs(device); +GPIO_failed: + kfree(device); + + return retval; +} + +static int pi433_remove(struct spi_device *spi) +{ + struct pi433_device *device = spi_get_drvdata(spi); + + /* free GPIOs */ + free_GPIOs(device); + + /* make sure ops on existing fds can abort cleanly */ + device->spi = NULL; + + kthread_stop(device->tx_task_struct); + + device_destroy(pi433_class, device->devt); + + cdev_del(device->cdev); + + pi433_free_minor(device); + + if (device->users == 0) + kfree(device); + + return 0; +} + +static const struct of_device_id pi433_dt_ids[] = { + { .compatible = "Smarthome-Wolf,pi433" }, + {}, +}; + +MODULE_DEVICE_TABLE(of, pi433_dt_ids); + +static struct spi_driver pi433_spi_driver = { + .driver = { + .name = "pi433", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(pi433_dt_ids), + }, + .probe = pi433_probe, + .remove = pi433_remove, + + /* NOTE: suspend/resume methods are not necessary here. + * We don't do anything except pass the requests to/from + * the underlying controller. The refrigerator handles + * most issues; the controller driver handles the rest. + */ +}; + +/*-------------------------------------------------------------------------*/ + +static int __init pi433_init(void) +{ + int status; + + /* If MAX_MSG_SIZE is smaller then FIFO_SIZE, the driver won't + * work stable - risk of buffer overflow + */ + if (MAX_MSG_SIZE < FIFO_SIZE) + return -EINVAL; + + /* Claim device numbers. Then register a class + * that will key udev/mdev to add/remove /dev nodes. Last, register + * Last, register the driver which manages those device numbers. + */ + status = alloc_chrdev_region(&pi433_dev, 0 /*firstminor*/, N_PI433_MINORS /*count*/, "pi433" /*name*/); + if (status < 0) + return status; + + pi433_class = class_create(THIS_MODULE, "pi433"); + if (IS_ERR(pi433_class)) + { + unregister_chrdev(MAJOR(pi433_dev), pi433_spi_driver.driver.name); + return PTR_ERR(pi433_class); + } + + status = spi_register_driver(&pi433_spi_driver); + if (status < 0) + { + class_destroy(pi433_class); + unregister_chrdev(MAJOR(pi433_dev), pi433_spi_driver.driver.name); + } + + return status; +} + +module_init(pi433_init); + +static void __exit pi433_exit(void) +{ + spi_unregister_driver(&pi433_spi_driver); + class_destroy(pi433_class); + unregister_chrdev(MAJOR(pi433_dev), pi433_spi_driver.driver.name); +} +module_exit(pi433_exit); + +MODULE_AUTHOR("Marcus Wolf, <linux@wolf-entwicklungen.de>"); +MODULE_DESCRIPTION("Driver for Pi433"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("spi:pi433"); diff --git a/drivers/staging/pi433/pi433_if.h b/drivers/staging/pi433/pi433_if.h new file mode 100644 index 000000000000..e6ed3cd9b2e2 --- /dev/null +++ b/drivers/staging/pi433/pi433_if.h @@ -0,0 +1,152 @@ +/* + * include/linux/TODO + * + * userspace interface for pi433 radio module + * + * Pi433 is a 433MHz radio module for the Raspberry Pi. + * It is based on the HopeRf Module RFM69CW. Therefore inside of this + * driver, you'll find an abstraction of the rf69 chip. + * + * If needed, this driver could be extended, to also support other + * devices, basing on HopeRfs rf69. + * + * The driver can also be extended, to support other modules of + * HopeRf with a similar interace - e. g. RFM69HCW, RFM12, RFM95, ... + * Copyright (C) 2016 Wolf-Entwicklungen + * Marcus Wolf <linux@wolf-entwicklungen.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef PI433_H +#define PI433_H + +#include <linux/types.h> +#include "rf69_enum.h" + +/*---------------------------------------------------------------------------*/ + + +/*---------------------------------------------------------------------------*/ + +/* IOCTL structs and commands */ + +/** + * struct pi433_tx_config - describes the configuration of the radio module for sending + * @frequency: + * @bit_rate: + * @modulation: + * @data_mode: + * @preamble_length: + * @sync_pattern: + * @tx_start_condition: + * @payload_length: + * @repetitions: + * + * ATTENTION: + * If the contents of 'pi433_tx_config' ever change + * incompatibly, then the ioctl number (see define below) must change. + * + * NOTE: struct layout is the same in 64bit and 32bit userspace. + */ +#define PI433_TX_CFG_IOCTL_NR 0 +struct pi433_tx_cfg +{ + __u32 frequency; + __u16 bit_rate; + __u32 dev_frequency; + enum modulation modulation; + enum modShaping modShaping; + + enum paRamp pa_ramp; + + enum txStartCondition tx_start_condition; + + __u16 repetitions; + + + /* packet format */ + enum optionOnOff enable_preamble; + enum optionOnOff enable_sync; + enum optionOnOff enable_length_byte; + enum optionOnOff enable_address_byte; + enum optionOnOff enable_crc; + + __u16 preamble_length; + __u8 sync_length; + __u8 fixed_message_length; + + __u8 sync_pattern[8]; + __u8 address_byte; +}; + + +/** + * struct pi433_rx_config - describes the configuration of the radio module for sending + * @frequency: + * @bit_rate: + * @modulation: + * @data_mode: + * @preamble_length: + * @sync_pattern: + * @tx_start_condition: + * @payload_length: + * @repetitions: + * + * ATTENTION: + * If the contents of 'pi433_rx_config' ever change + * incompatibly, then the ioctl number (see define below) must change + * + * NOTE: struct layout is the same in 64bit and 32bit userspace. + */ +#define PI433_RX_CFG_IOCTL_NR 1 +struct pi433_rx_cfg { + __u32 frequency; + __u16 bit_rate; + __u32 dev_frequency; + + enum modulation modulation; + + __u8 rssi_threshold; + enum thresholdDecrement thresholdDecrement; + enum antennaImpedance antenna_impedance; + enum lnaGain lna_gain; + enum mantisse bw_mantisse; /* normal: 0x50 */ + __u8 bw_exponent; /* during AFC: 0x8b */ + enum dagc dagc; + + + + /* packet format */ + enum optionOnOff enable_sync; + enum optionOnOff enable_length_byte; /* should be used in combination with sync, only */ + enum addressFiltering enable_address_filtering; /* operational with sync, only */ + enum optionOnOff enable_crc; /* only operational, if sync on and fixed length or length byte is used */ + + __u8 sync_length; + __u8 fixed_message_length; + __u32 bytes_to_drop; + + __u8 sync_pattern[8]; + __u8 node_address; + __u8 broadcast_address; +}; + + +#define PI433_IOC_MAGIC 'r' + +#define PI433_IOC_RD_TX_CFG _IOR(PI433_IOC_MAGIC, PI433_TX_CFG_IOCTL_NR, char[sizeof(struct pi433_tx_cfg)]) +#define PI433_IOC_WR_TX_CFG _IOW(PI433_IOC_MAGIC, PI433_TX_CFG_IOCTL_NR, char[sizeof(struct pi433_tx_cfg)]) + +#define PI433_IOC_RD_RX_CFG _IOR(PI433_IOC_MAGIC, PI433_RX_CFG_IOCTL_NR, char[sizeof(struct pi433_rx_cfg)]) +#define PI433_IOC_WR_RX_CFG _IOW(PI433_IOC_MAGIC, PI433_RX_CFG_IOCTL_NR, char[sizeof(struct pi433_rx_cfg)]) + +#endif /* PI433_H */ diff --git a/drivers/staging/pi433/rf69.c b/drivers/staging/pi433/rf69.c new file mode 100644 index 000000000000..c4b1b218ea38 --- /dev/null +++ b/drivers/staging/pi433/rf69.c @@ -0,0 +1,1032 @@ +/* + * abstraction of the spi interface of HopeRf rf69 radio module + * + * Copyright (C) 2016 Wolf-Entwicklungen + * Marcus Wolf <linux@wolf-entwicklungen.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* enable prosa debug info */ +#undef DEBUG +/* enable print of values on reg access */ +#undef DEBUG_VALUES +/* enable print of values on fifo access */ +#undef DEBUG_FIFO_ACCESS + +#include <linux/types.h> +#include <linux/spi/spi.h> + +#include "rf69.h" +#include "rf69_registers.h" + +#define F_OSC 32000000 /* in Hz */ +#define FIFO_SIZE 66 /* in byte */ + +/*-------------------------------------------------------------------------*/ + +#define READ_REG(x) rf69_read_reg (spi, x) +#define WRITE_REG(x,y) rf69_write_reg(spi, x, y) + +/*-------------------------------------------------------------------------*/ + +int rf69_set_mode(struct spi_device *spi, enum mode mode) +{ + #ifdef DEBUG + dev_dbg(&spi->dev, "set: mode"); + #endif + + switch (mode) { + case transmit: return WRITE_REG(REG_OPMODE, (READ_REG(REG_OPMODE) & ~MASK_OPMODE_MODE) | OPMODE_MODE_TRANSMIT); + case receive: return WRITE_REG(REG_OPMODE, (READ_REG(REG_OPMODE) & ~MASK_OPMODE_MODE) | OPMODE_MODE_RECEIVE); + case synthesizer: return WRITE_REG(REG_OPMODE, (READ_REG(REG_OPMODE) & ~MASK_OPMODE_MODE) | OPMODE_MODE_SYNTHESIZER); + case standby: return WRITE_REG(REG_OPMODE, (READ_REG(REG_OPMODE) & ~MASK_OPMODE_MODE) | OPMODE_MODE_STANDBY); + case mode_sleep: return WRITE_REG(REG_OPMODE, (READ_REG(REG_OPMODE) & ~MASK_OPMODE_MODE) | OPMODE_MODE_SLEEP); + default: + dev_dbg(&spi->dev, "set: illegal input param"); + return -EINVAL; + } + + // we are using packet mode, so this check is not really needed + // but waiting for mode ready is necessary when going from sleep because the FIFO may not be immediately available from previous mode + //while (_mode == RF69_MODE_SLEEP && (READ_REG(REG_IRQFLAGS1) & RF_IRQFLAGS1_MODEREADY) == 0x00); // Wait for ModeReady + +} + +int rf69_set_data_mode(struct spi_device *spi, enum dataMode dataMode) +{ + #ifdef DEBUG + dev_dbg(&spi->dev, "set: data mode"); + #endif + + switch (dataMode) { + case packet: return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODE) | DATAMODUL_MODE_PACKET); + case continuous: return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODE) | DATAMODUL_MODE_CONTINUOUS); + case continuousNoSync: return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODE) | DATAMODUL_MODE_CONTINUOUS_NOSYNC); + default: + dev_dbg(&spi->dev, "set: illegal input param"); + return -EINVAL; + } +} + +int rf69_set_modulation(struct spi_device *spi, enum modulation modulation) +{ + #ifdef DEBUG + dev_dbg(&spi->dev, "set: modulation"); + #endif + + switch (modulation) { + case OOK: return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_TYPE) | DATAMODUL_MODULATION_TYPE_OOK); + case FSK: return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_TYPE) | DATAMODUL_MODULATION_TYPE_FSK); + default: + dev_dbg(&spi->dev, "set: illegal input param"); + return -EINVAL; + } +} + +enum modulation rf69_get_modulation(struct spi_device *spi) +{ + u8 currentValue; + + #ifdef DEBUG + dev_dbg(&spi->dev, "get: mode"); + #endif + + currentValue = READ_REG(REG_DATAMODUL); + + switch (currentValue & MASK_DATAMODUL_MODULATION_TYPE >> 3) { // TODO improvement: change 3 to define + case DATAMODUL_MODULATION_TYPE_OOK: return OOK; + case DATAMODUL_MODULATION_TYPE_FSK: return FSK; + default: return undefined; + } +} + +int rf69_set_modulation_shaping(struct spi_device *spi, enum modShaping modShaping) +{ + #ifdef DEBUG + dev_dbg(&spi->dev, "set: mod shaping"); + #endif + + if (rf69_get_modulation(spi) == FSK) { + switch (modShaping) { + case shapingOff: return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) | DATAMODUL_MODULATION_SHAPE_NONE); + case shaping1_0: return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) | DATAMODUL_MODULATION_SHAPE_1_0); + case shaping0_5: return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) | DATAMODUL_MODULATION_SHAPE_0_3); + case shaping0_3: return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) | DATAMODUL_MODULATION_SHAPE_0_5); + default: + dev_dbg(&spi->dev, "set: illegal input param"); + return -EINVAL; + } + } else { + switch (modShaping) { + case shapingOff: return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) | DATAMODUL_MODULATION_SHAPE_NONE); + case shapingBR: return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) | DATAMODUL_MODULATION_SHAPE_BR); + case shaping2BR: return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) | DATAMODUL_MODULATION_SHAPE_2BR); + default: + dev_dbg(&spi->dev, "set: illegal input param"); + return -EINVAL; + } + } +} + +int rf69_set_bit_rate(struct spi_device *spi, u16 bitRate) +{ + int retval; + u32 bitRate_min; + u32 bitRate_reg; + u8 msb; + u8 lsb; + + #ifdef DEBUG + dev_dbg(&spi->dev, "set: bit rate"); + #endif + + // check input value + bitRate_min = F_OSC / 8388608; // 8388608 = 2^23; + if (bitRate < bitRate_min) { + dev_dbg(&spi->dev, "setBitRate: illegal input param"); + return -EINVAL; + } + + // calculate reg settings + bitRate_reg = (F_OSC / bitRate); + + msb = (bitRate_reg&0xff00) >> 8; + lsb = (bitRate_reg&0xff); + + // transmit to RF 69 + retval = WRITE_REG(REG_BITRATE_MSB, msb); + if (retval) return retval; + retval = WRITE_REG(REG_BITRATE_LSB, lsb); + if (retval) return retval; + + return 0; +} + +int rf69_set_deviation(struct spi_device *spi, u32 deviation) +{ + int retval; +// u32 f_max; TODO: Abhängigkeit von Bitrate beachten!! + u64 f_reg; + u64 f_step; + u8 msb; + u8 lsb; + u64 factor = 1000000; // to improve precision of calculation + + #ifdef DEBUG + dev_dbg(&spi->dev, "set: deviation"); + #endif + + if (deviation < 600 || deviation > 500000) { //TODO: Abhängigkeit von Bitrate beachten!! + dev_dbg(&spi->dev, "set_deviation: illegal input param"); + return -EINVAL; + } + + // calculat f step + f_step = F_OSC * factor; + do_div(f_step, 524288); // 524288 = 2^19 + + // calculate register settings + f_reg = deviation * factor; + do_div(f_reg , f_step); + + msb = (f_reg&0xff00) >> 8; + lsb = (f_reg&0xff); + + // check msb + if (msb & ~FDEVMASB_MASK) { + dev_dbg(&spi->dev, "set_deviation: err in calc of msb"); + return -EINVAL; + } + + // write to chip + retval = WRITE_REG(REG_FDEV_MSB, msb); + if (retval) return retval; + retval = WRITE_REG(REG_FDEV_LSB, lsb); + if (retval) return retval; + + return 0; +} + +int rf69_set_frequency(struct spi_device *spi, u32 frequency) +{ + int retval; + u32 f_max; + u64 f_reg; + u64 f_step; + u8 msb; + u8 mid; + u8 lsb; + u64 factor = 1000000; // to improve precision of calculation + + #ifdef DEBUG + dev_dbg(&spi->dev, "set: frequency"); + #endif + + // calculat f step + f_step = F_OSC * factor; + do_div(f_step, 524288); // 524288 = 2^19 + + // check input value + f_max = div_u64(f_step * 8388608, factor); + if (frequency > f_max) { + dev_dbg(&spi->dev, "setFrequency: illegal input param"); + return -EINVAL; + } + + // calculate reg settings + f_reg = frequency * factor; + do_div(f_reg , f_step); + + msb = (f_reg&0xff0000) >> 16; + mid = (f_reg&0xff00) >> 8; + lsb = (f_reg&0xff); + + // write to chip + retval = WRITE_REG(REG_FRF_MSB, msb); + if (retval) return retval; + retval = WRITE_REG(REG_FRF_MID, mid); + if (retval) return retval; + retval = WRITE_REG(REG_FRF_LSB, lsb); + if (retval) return retval; + + return 0; +} + +int rf69_set_amplifier_0(struct spi_device *spi, enum optionOnOff optionOnOff) +{ + #ifdef DEBUG + dev_dbg(&spi->dev, "set: amp #0"); + #endif + + switch(optionOnOff) { + case optionOn: return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) | MASK_PALEVEL_PA0) ); + case optionOff: return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) & ~MASK_PALEVEL_PA0) ); + default: + dev_dbg(&spi->dev, "set: illegal input param"); + return -EINVAL; + } +} + +int rf69_set_amplifier_1(struct spi_device *spi, enum optionOnOff optionOnOff) +{ + #ifdef DEBUG + dev_dbg(&spi->dev, "set: amp #1"); + #endif + + switch(optionOnOff) { + case optionOn: return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) | MASK_PALEVEL_PA1) ); + case optionOff: return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) & ~MASK_PALEVEL_PA1) ); + default: + dev_dbg(&spi->dev, "set: illegal input param"); + return -EINVAL; + } +} + +int rf69_set_amplifier_2(struct spi_device *spi, enum optionOnOff optionOnOff) +{ + #ifdef DEBUG + dev_dbg(&spi->dev, "set: amp #2"); + #endif + + switch(optionOnOff) { + case optionOn: return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) | MASK_PALEVEL_PA2) ); + case optionOff: return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) & ~MASK_PALEVEL_PA2) ); + default: + dev_dbg(&spi->dev, "set: illegal input param"); + return -EINVAL; + } +} + +int rf69_set_output_power_level(struct spi_device *spi, u8 powerLevel) +{ + #ifdef DEBUG + dev_dbg(&spi->dev, "set: power level"); + #endif + + powerLevel +=18; // TODO Abhängigkeit von PA0,1,2 setting + + // check input value + if (powerLevel > 0x1f) { + dev_dbg(&spi->dev, "set: illegal input param"); + return -EINVAL; + } + + // write value + return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) & ~MASK_PALEVEL_OUTPUT_POWER) | powerLevel); +} + +int rf69_set_pa_ramp(struct spi_device *spi, enum paRamp paRamp) +{ + #ifdef DEBUG + dev_dbg(&spi->dev, "set: pa ramp"); + #endif + + switch(paRamp) { + case ramp3400: return WRITE_REG(REG_PARAMP, PARAMP_3400); + case ramp2000: return WRITE_REG(REG_PARAMP, PARAMP_2000); + case ramp1000: return WRITE_REG(REG_PARAMP, PARAMP_1000); + case ramp500: return WRITE_REG(REG_PARAMP, PARAMP_500); + case ramp250: return WRITE_REG(REG_PARAMP, PARAMP_250); + case ramp125: return WRITE_REG(REG_PARAMP, PARAMP_125); + case ramp100: return WRITE_REG(REG_PARAMP, PARAMP_100); + case ramp62: return WRITE_REG(REG_PARAMP, PARAMP_62); + case ramp50: return WRITE_REG(REG_PARAMP, PARAMP_50); + case ramp40: return WRITE_REG(REG_PARAMP, PARAMP_40); + case ramp31: return WRITE_REG(REG_PARAMP, PARAMP_31); + case ramp25: return WRITE_REG(REG_PARAMP, PARAMP_25); + case ramp20: return WRITE_REG(REG_PARAMP, PARAMP_20); + case ramp15: return WRITE_REG(REG_PARAMP, PARAMP_15); + case ramp12: return WRITE_REG(REG_PARAMP, PARAMP_12); + case ramp10: return WRITE_REG(REG_PARAMP, PARAMP_10); + default: + dev_dbg(&spi->dev, "set: illegal input param"); + return -EINVAL; + } +} + +int rf69_set_antenna_impedance(struct spi_device *spi, enum antennaImpedance antennaImpedance) +{ + #ifdef DEBUG + dev_dbg(&spi->dev, "set: antenna impedance"); + #endif + + switch(antennaImpedance) { + case fiftyOhm: return WRITE_REG(REG_LNA, (READ_REG(REG_LNA) & ~MASK_LNA_ZIN) ); + case twohundretOhm: return WRITE_REG(REG_LNA, (READ_REG(REG_LNA) | MASK_LNA_ZIN) ); + default: + dev_dbg(&spi->dev, "set: illegal input param"); + return -EINVAL; + } +} + +int rf69_set_lna_gain(struct spi_device *spi, enum lnaGain lnaGain) +{ + #ifdef DEBUG + dev_dbg(&spi->dev, "set: lna gain"); + #endif + + switch(lnaGain) { + case automatic: return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) & ~MASK_LNA_GAIN) & LNA_GAIN_AUTO) ); + case max: return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) & ~MASK_LNA_GAIN) & LNA_GAIN_MAX) ); + case maxMinus6: return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) & ~MASK_LNA_GAIN) & LNA_GAIN_MAX_MINUS_6) ); + case maxMinus12: return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) & ~MASK_LNA_GAIN) & LNA_GAIN_MAX_MINUS_12) ); + case maxMinus24: return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) & ~MASK_LNA_GAIN) & LNA_GAIN_MAX_MINUS_24) ); + case maxMinus36: return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) & ~MASK_LNA_GAIN) & LNA_GAIN_MAX_MINUS_36) ); + case maxMinus48: return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) & ~MASK_LNA_GAIN) & LNA_GAIN_MAX_MINUS_48) ); + default: + dev_dbg(&spi->dev, "set: illegal input param"); + return -EINVAL; + } +} + +enum lnaGain rf69_get_lna_gain(struct spi_device *spi) +{ + u8 currentValue; + + #ifdef DEBUG + dev_dbg(&spi->dev, "get: lna gain"); + #endif + + currentValue = READ_REG(REG_LNA); + + switch (currentValue & MASK_LNA_CURRENT_GAIN >> 3) { // improvement: change 3 to define + case LNA_GAIN_AUTO: return automatic; + case LNA_GAIN_MAX: return max; + case LNA_GAIN_MAX_MINUS_6: return maxMinus6; + case LNA_GAIN_MAX_MINUS_12: return maxMinus12; + case LNA_GAIN_MAX_MINUS_24: return maxMinus24; + case LNA_GAIN_MAX_MINUS_36: return maxMinus36; + case LNA_GAIN_MAX_MINUS_48: return maxMinus48; + default: return undefined; + } +} + +int rf69_set_dc_cut_off_frequency_intern(struct spi_device *spi ,u8 reg, enum dccPercent dccPercent) +{ + switch (dccPercent) { + case dcc16Percent: return WRITE_REG(reg, ( (READ_REG(reg) & ~MASK_BW_DCC_FREQ) | BW_DCC_16_PERCENT) ); + case dcc8Percent: return WRITE_REG(reg, ( (READ_REG(reg) & ~MASK_BW_DCC_FREQ) | BW_DCC_8_PERCENT) ); + case dcc4Percent: return WRITE_REG(reg, ( (READ_REG(reg) & ~MASK_BW_DCC_FREQ) | BW_DCC_4_PERCENT) ); + case dcc2Percent: return WRITE_REG(reg, ( (READ_REG(reg) & ~MASK_BW_DCC_FREQ) | BW_DCC_2_PERCENT) ); + case dcc1Percent: return WRITE_REG(reg, ( (READ_REG(reg) & ~MASK_BW_DCC_FREQ) | BW_DCC_1_PERCENT) ); + case dcc0_5Percent: return WRITE_REG(reg, ( (READ_REG(reg) & ~MASK_BW_DCC_FREQ) | BW_DCC_0_5_PERCENT) ); + case dcc0_25Percent: return WRITE_REG(reg, ( (READ_REG(reg) & ~MASK_BW_DCC_FREQ) | BW_DCC_0_25_PERCENT) ); + case dcc0_125Percent: return WRITE_REG(reg, ( (READ_REG(reg) & ~MASK_BW_DCC_FREQ) | BW_DCC_0_125_PERCENT) ); + default: + dev_dbg(&spi->dev, "set: illegal input param"); + return -EINVAL; + } +} + +int rf69_set_dc_cut_off_frequency(struct spi_device *spi, enum dccPercent dccPercent) +{ + #ifdef DEBUG + dev_dbg(&spi->dev, "set: cut off freq"); + #endif + + return rf69_set_dc_cut_off_frequency_intern(spi, REG_RXBW, dccPercent); +} + +int rf69_set_dc_cut_off_frequency_during_afc(struct spi_device *spi, enum dccPercent dccPercent) +{ + #ifdef DEBUG + dev_dbg(&spi->dev, "set: cut off freq during afc"); + #endif + + return rf69_set_dc_cut_off_frequency_intern(spi, REG_AFCBW, dccPercent); +} + +static int rf69_set_bandwidth_intern(struct spi_device *spi, u8 reg, + enum mantisse mantisse, u8 exponent) +{ + u8 newValue; + + // check value for mantisse and exponent + if (exponent > 7) { + dev_dbg(&spi->dev, "set: illegal input param"); + return -EINVAL; + } + + if ((mantisse != mantisse16) && + (mantisse != mantisse20) && + (mantisse != mantisse24)) { + dev_dbg(&spi->dev, "set: illegal input param"); + return -EINVAL; + } + + // read old value + newValue = READ_REG(reg); + + // "delete" mantisse and exponent = just keep the DCC setting + newValue = newValue & MASK_BW_DCC_FREQ; + + // add new mantisse + switch(mantisse) { + case mantisse16: newValue = newValue | BW_MANT_16; break; + case mantisse20: newValue = newValue | BW_MANT_20; break; + case mantisse24: newValue = newValue | BW_MANT_24; break; + } + + // add new exponent + newValue = newValue | exponent; + + // write back + return WRITE_REG(reg, newValue); +} + +int rf69_set_bandwidth(struct spi_device *spi, enum mantisse mantisse, u8 exponent) +{ + #ifdef DEBUG + dev_dbg(&spi->dev, "set: band width"); + #endif + + return rf69_set_bandwidth_intern(spi, REG_RXBW, mantisse, exponent); +} + +int rf69_set_bandwidth_during_afc(struct spi_device *spi, enum mantisse mantisse, u8 exponent) +{ + #ifdef DEBUG + dev_dbg(&spi->dev, "set: band width during afc"); + #endif + + return rf69_set_bandwidth_intern(spi, REG_AFCBW, mantisse, exponent); +} + +int rf69_set_ook_threshold_type(struct spi_device *spi, enum thresholdType thresholdType) +{ + #ifdef DEBUG + dev_dbg(&spi->dev, "set: threshold type"); + #endif + + switch (thresholdType) { + case fixed: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESTYPE) | OOKPEAK_THRESHTYPE_FIXED) ); + case peak: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESTYPE) | OOKPEAK_THRESHTYPE_PEAK) ); + case average: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESTYPE) | OOKPEAK_THRESHTYPE_AVERAGE) ); + default: + dev_dbg(&spi->dev, "set: illegal input param"); + return -EINVAL; + } +} + +int rf69_set_ook_threshold_step(struct spi_device *spi, enum thresholdStep thresholdStep) +{ + #ifdef DEBUG + dev_dbg(&spi->dev, "set: threshold step"); + #endif + + switch (thresholdStep) { + case step_0_5db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_0_5_DB) ); + case step_1_0db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_1_0_DB) ); + case step_1_5db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_1_5_DB) ); + case step_2_0db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_2_0_DB) ); + case step_3_0db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_3_0_DB) ); + case step_4_0db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_4_0_DB) ); + case step_5_0db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_5_0_DB) ); + case step_6_0db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_6_0_DB) ); + default: + dev_dbg(&spi->dev, "set: illegal input param"); + return -EINVAL; + } +} + +int rf69_set_ook_threshold_dec(struct spi_device *spi, enum thresholdDecrement thresholdDecrement) +{ + #ifdef DEBUG + dev_dbg(&spi->dev, "set: threshold decrement"); + #endif + + switch (thresholdDecrement) { + case dec_every8th: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_EVERY_8TH) ); + case dec_every4th: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_EVERY_4TH) ); + case dec_every2nd: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_EVERY_2ND) ); + case dec_once: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_ONCE) ); + case dec_twice: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_TWICE) ); + case dec_4times: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_4_TIMES) ); + case dec_8times: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_8_TIMES) ); + case dec_16times: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_16_TIMES) ); + default: + dev_dbg(&spi->dev, "set: illegal input param"); + return -EINVAL; + } +} + +int rf69_set_dio_mapping(struct spi_device *spi, u8 DIONumber, u8 value) +{ + u8 mask; + u8 shift; + u8 regaddr; + u8 regValue; + + #ifdef DEBUG + dev_dbg(&spi->dev, "set: DIO mapping"); + #endif + + // check DIO number + if (DIONumber > 5) { + dev_dbg(&spi->dev, "set: illegal input param"); + return -EINVAL; + } + + switch (DIONumber) { + case 0: mask=MASK_DIO0; shift=SHIFT_DIO0; regaddr=REG_DIOMAPPING1; break; + case 1: mask=MASK_DIO1; shift=SHIFT_DIO1; regaddr=REG_DIOMAPPING1; break; + case 2: mask=MASK_DIO2; shift=SHIFT_DIO2; regaddr=REG_DIOMAPPING1; break; + case 3: mask=MASK_DIO3; shift=SHIFT_DIO3; regaddr=REG_DIOMAPPING1; break; + case 4: mask=MASK_DIO4; shift=SHIFT_DIO4; regaddr=REG_DIOMAPPING2; break; + case 5: mask=MASK_DIO5; shift=SHIFT_DIO5; regaddr=REG_DIOMAPPING2; break; + } + + // read reg + regValue=READ_REG(regaddr); + // delete old value + regValue = regValue & ~mask; + // add new value + regValue = regValue | value << shift; + // write back + return WRITE_REG(regaddr,regValue); +} + +bool rf69_get_flag(struct spi_device *spi, enum flag flag) +{ + #ifdef DEBUG + dev_dbg(&spi->dev, "get: flag"); + #endif + + switch(flag) { + case modeSwitchCompleted: return (READ_REG(REG_IRQFLAGS1) & MASK_IRQFLAGS1_MODE_READY); + case readyToReceive: return (READ_REG(REG_IRQFLAGS1) & MASK_IRQFLAGS1_RX_READY); + case readyToSend: return (READ_REG(REG_IRQFLAGS1) & MASK_IRQFLAGS1_TX_READY); + case pllLocked: return (READ_REG(REG_IRQFLAGS1) & MASK_IRQFLAGS1_PLL_LOCK); + case rssiExceededThreshold: return (READ_REG(REG_IRQFLAGS1) & MASK_IRQFLAGS1_RSSI); + case timeout: return (READ_REG(REG_IRQFLAGS1) & MASK_IRQFLAGS1_TIMEOUT); + case automode: return (READ_REG(REG_IRQFLAGS1) & MASK_IRQFLAGS1_AUTOMODE); + case syncAddressMatch: return (READ_REG(REG_IRQFLAGS1) & MASK_IRQFLAGS1_SYNC_ADDRESS_MATCH); + case fifoFull: return (READ_REG(REG_IRQFLAGS2) & MASK_IRQFLAGS2_FIFO_FULL); +/* case fifoNotEmpty: return (READ_REG(REG_IRQFLAGS2) & MASK_IRQFLAGS2_FIFO_NOT_EMPTY); */ + case fifoEmpty: return !(READ_REG(REG_IRQFLAGS2) & MASK_IRQFLAGS2_FIFO_NOT_EMPTY); + case fifoLevelBelowThreshold: return (READ_REG(REG_IRQFLAGS2) & MASK_IRQFLAGS2_FIFO_LEVEL); + case fifoOverrun: return (READ_REG(REG_IRQFLAGS2) & MASK_IRQFLAGS2_FIFO_OVERRUN); + case packetSent: return (READ_REG(REG_IRQFLAGS2) & MASK_IRQFLAGS2_PACKET_SENT); + case payloadReady: return (READ_REG(REG_IRQFLAGS2) & MASK_IRQFLAGS2_PAYLOAD_READY); + case crcOk: return (READ_REG(REG_IRQFLAGS2) & MASK_IRQFLAGS2_CRC_OK); + case batteryLow: return (READ_REG(REG_IRQFLAGS2) & MASK_IRQFLAGS2_LOW_BAT); + default: return false; + } +} + +int rf69_reset_flag(struct spi_device *spi, enum flag flag) +{ + #ifdef DEBUG + dev_dbg(&spi->dev, "reset: flag"); + #endif + + switch(flag) { + case rssiExceededThreshold: return WRITE_REG(REG_IRQFLAGS1, MASK_IRQFLAGS1_RSSI); + case syncAddressMatch: return WRITE_REG(REG_IRQFLAGS1, MASK_IRQFLAGS1_SYNC_ADDRESS_MATCH); + case fifoOverrun: return WRITE_REG(REG_IRQFLAGS2, MASK_IRQFLAGS2_FIFO_OVERRUN); + default: + dev_dbg(&spi->dev, "set: illegal input param"); + return -EINVAL; + } +} + +int rf69_set_rssi_threshold(struct spi_device *spi, u8 threshold) +{ + #ifdef DEBUG + dev_dbg(&spi->dev, "set: rssi threshold"); + #endif + + /* no value check needed - u8 exactly matches register size */ + + return WRITE_REG(REG_RSSITHRESH, threshold); +} + +int rf69_set_rx_start_timeout(struct spi_device *spi, u8 timeout) +{ + #ifdef DEBUG + dev_dbg(&spi->dev, "set: start timeout"); + #endif + + /* no value check needed - u8 exactly matches register size */ + + return WRITE_REG(REG_RXTIMEOUT1, timeout); +} + +int rf69_set_rssi_timeout(struct spi_device *spi, u8 timeout) +{ + #ifdef DEBUG + dev_dbg(&spi->dev, "set: rssi timeout"); + #endif + + /* no value check needed - u8 exactly matches register size */ + + return WRITE_REG(REG_RXTIMEOUT2, timeout); +} + +int rf69_set_preamble_length(struct spi_device *spi, u16 preambleLength) +{ + int retval; + u8 msb, lsb; + + #ifdef DEBUG + dev_dbg(&spi->dev, "set: preamble length"); + #endif + + /* no value check needed - u16 exactly matches register size */ + + /* calculate reg settings */ + msb = (preambleLength&0xff00) >> 8; + lsb = (preambleLength&0xff); + + /* transmit to chip */ + retval = WRITE_REG(REG_PREAMBLE_MSB, msb); + if (retval) return retval; + retval = WRITE_REG(REG_PREAMBLE_LSB, lsb); + + return retval; +} + +int rf69_set_sync_enable(struct spi_device *spi, enum optionOnOff optionOnOff) +{ + #ifdef DEBUG + dev_dbg(&spi->dev, "set: sync enable"); + #endif + + switch(optionOnOff) { + case optionOn: return WRITE_REG(REG_SYNC_CONFIG, (READ_REG(REG_SYNC_CONFIG) | MASK_SYNC_CONFIG_SYNC_ON) ); + case optionOff: return WRITE_REG(REG_SYNC_CONFIG, (READ_REG(REG_SYNC_CONFIG) & ~MASK_SYNC_CONFIG_SYNC_ON) ); + default: + dev_dbg(&spi->dev, "set: illegal input param"); + return -EINVAL; + } +} + +int rf69_set_fifo_fill_condition(struct spi_device *spi, enum fifoFillCondition fifoFillCondition) +{ + #ifdef DEBUG + dev_dbg(&spi->dev, "set: fifo fill condition"); + #endif + + switch(fifoFillCondition) { + case always: return WRITE_REG(REG_SYNC_CONFIG, (READ_REG(REG_SYNC_CONFIG) | MASK_SYNC_CONFIG_FIFO_FILL_CONDITION) ); + case afterSyncInterrupt: return WRITE_REG(REG_SYNC_CONFIG, (READ_REG(REG_SYNC_CONFIG) & ~MASK_SYNC_CONFIG_FIFO_FILL_CONDITION) ); + default: + dev_dbg(&spi->dev, "set: illegal input param"); + return -EINVAL; + } +} + +int rf69_set_sync_size(struct spi_device *spi, u8 syncSize) +{ + #ifdef DEBUG + dev_dbg(&spi->dev, "set: sync size"); + #endif + + // check input value + if (syncSize > 0x07) { + dev_dbg(&spi->dev, "set: illegal input param"); + return -EINVAL; + } + + // write value + return WRITE_REG(REG_SYNC_CONFIG, (READ_REG(REG_SYNC_CONFIG) & ~MASK_SYNC_CONFIG_SYNC_SIZE) | (syncSize << 3) ); +} + +int rf69_set_sync_tolerance(struct spi_device *spi, u8 syncTolerance) +{ + #ifdef DEBUG + dev_dbg(&spi->dev, "set: sync tolerance"); + #endif + + // check input value + if (syncTolerance > 0x07) { + dev_dbg(&spi->dev, "set: illegal input param"); + return -EINVAL; + } + + // write value + return WRITE_REG(REG_SYNC_CONFIG, (READ_REG(REG_SYNC_CONFIG) & ~MASK_SYNC_CONFIG_SYNC_SIZE) | syncTolerance); +} + +int rf69_set_sync_values(struct spi_device *spi, u8 syncValues[8]) +{ + int retval = 0; + + #ifdef DEBUG + dev_dbg(&spi->dev, "set: sync values"); + #endif + + retval += WRITE_REG(REG_SYNCVALUE1, syncValues[0]); + retval += WRITE_REG(REG_SYNCVALUE2, syncValues[1]); + retval += WRITE_REG(REG_SYNCVALUE3, syncValues[2]); + retval += WRITE_REG(REG_SYNCVALUE4, syncValues[3]); + retval += WRITE_REG(REG_SYNCVALUE5, syncValues[4]); + retval += WRITE_REG(REG_SYNCVALUE6, syncValues[5]); + retval += WRITE_REG(REG_SYNCVALUE7, syncValues[6]); + retval += WRITE_REG(REG_SYNCVALUE8, syncValues[7]); + + return retval; +} + +int rf69_set_packet_format(struct spi_device *spi, enum packetFormat packetFormat) +{ + #ifdef DEBUG + dev_dbg(&spi->dev, "set: packet format"); + #endif + + switch(packetFormat) { + case packetLengthVar: return WRITE_REG(REG_PACKETCONFIG1, (READ_REG(REG_PACKETCONFIG1) | MASK_PACKETCONFIG1_PAKET_FORMAT_VARIABLE) ); + case packetLengthFix: return WRITE_REG(REG_PACKETCONFIG1, (READ_REG(REG_PACKETCONFIG1) & ~MASK_PACKETCONFIG1_PAKET_FORMAT_VARIABLE) ); + default: + dev_dbg(&spi->dev, "set: illegal input param"); + return -EINVAL; + } +} + +int rf69_set_crc_enable(struct spi_device *spi, enum optionOnOff optionOnOff) +{ + #ifdef DEBUG + dev_dbg(&spi->dev, "set: crc enable"); + #endif + + switch(optionOnOff) { + case optionOn: return WRITE_REG(REG_PACKETCONFIG1, (READ_REG(REG_PACKETCONFIG1) | MASK_PACKETCONFIG1_CRC_ON) ); + case optionOff: return WRITE_REG(REG_PACKETCONFIG1, (READ_REG(REG_PACKETCONFIG1) & ~MASK_PACKETCONFIG1_CRC_ON) ); + default: + dev_dbg(&spi->dev, "set: illegal input param"); + return -EINVAL; + } +} + +int rf69_set_adressFiltering(struct spi_device *spi, enum addressFiltering addressFiltering) +{ + #ifdef DEBUG + dev_dbg(&spi->dev, "set: address filtering"); + #endif + + switch (addressFiltering) { + case filteringOff: return WRITE_REG(REG_PACKETCONFIG1, ( (READ_REG(REG_PACKETCONFIG1) & ~MASK_PACKETCONFIG1_ADDRESSFILTERING) | PACKETCONFIG1_ADDRESSFILTERING_OFF) ); + case nodeAddress: return WRITE_REG(REG_PACKETCONFIG1, ( (READ_REG(REG_PACKETCONFIG1) & ~MASK_PACKETCONFIG1_ADDRESSFILTERING) | PACKETCONFIG1_ADDRESSFILTERING_NODE) ); + case nodeOrBroadcastAddress: return WRITE_REG(REG_PACKETCONFIG1, ( (READ_REG(REG_PACKETCONFIG1) & ~MASK_PACKETCONFIG1_ADDRESSFILTERING) | PACKETCONFIG1_ADDRESSFILTERING_NODEBROADCAST) ); + default: + dev_dbg(&spi->dev, "set: illegal input param"); + return -EINVAL; + } +} + +int rf69_set_payload_length(struct spi_device *spi, u8 payloadLength) +{ + #ifdef DEBUG + dev_dbg(&spi->dev, "set: payload length"); + #endif + + return WRITE_REG(REG_PAYLOAD_LENGTH, payloadLength); +} + +u8 rf69_get_payload_length(struct spi_device *spi) +{ + #ifdef DEBUG + dev_dbg(&spi->dev, "get: payload length"); + #endif + + return (u8) READ_REG(REG_PAYLOAD_LENGTH); +} + +int rf69_set_node_address(struct spi_device *spi, u8 nodeAddress) +{ + #ifdef DEBUG + dev_dbg(&spi->dev, "set: node address"); + #endif + + return WRITE_REG(REG_NODEADRS, nodeAddress); +} + +int rf69_set_broadcast_address(struct spi_device *spi, u8 broadcastAddress) +{ + #ifdef DEBUG + dev_dbg(&spi->dev, "set: broadcast address"); + #endif + + return WRITE_REG(REG_BROADCASTADRS, broadcastAddress); +} + +int rf69_set_tx_start_condition(struct spi_device *spi, enum txStartCondition txStartCondition) +{ + #ifdef DEBUG + dev_dbg(&spi->dev, "set: start condition"); + #endif + + switch(txStartCondition) { + case fifoLevel: return WRITE_REG(REG_FIFO_THRESH, (READ_REG(REG_FIFO_THRESH) & ~MASK_FIFO_THRESH_TXSTART) ); + case fifoNotEmpty: return WRITE_REG(REG_FIFO_THRESH, (READ_REG(REG_FIFO_THRESH) | MASK_FIFO_THRESH_TXSTART) ); + default: + dev_dbg(&spi->dev, "set: illegal input param"); + return -EINVAL; + } +} + +int rf69_set_fifo_threshold(struct spi_device *spi, u8 threshold) +{ + int retval; + + #ifdef DEBUG + dev_dbg(&spi->dev, "set: fifo threshold"); + #endif + + // check input value + if (threshold & 0x80) { + dev_dbg(&spi->dev, "set: illegal input param"); + return -EINVAL; + } + + // write value + retval = WRITE_REG(REG_FIFO_THRESH, (READ_REG(REG_FIFO_THRESH) & ~MASK_FIFO_THRESH_VALUE) | threshold); + if (retval) + return retval; + + // access the fifo to activate new threshold + return rf69_read_fifo (spi, (u8*) &retval, 1); // retval used as buffer +} + +int rf69_set_dagc(struct spi_device *spi, enum dagc dagc) +{ + #ifdef DEBUG + dev_dbg(&spi->dev, "set: dagc"); + #endif + + switch(dagc) { + case normalMode: return WRITE_REG(REG_TESTDAGC, DAGC_NORMAL); + case improve: return WRITE_REG(REG_TESTDAGC, DAGC_IMPROVED_LOWBETA0); + case improve4LowModulationIndex: return WRITE_REG(REG_TESTDAGC, DAGC_IMPROVED_LOWBETA1); + default: + dev_dbg(&spi->dev, "set: illegal input param"); + return -EINVAL; + } +} + +/*-------------------------------------------------------------------------*/ + +int rf69_read_fifo (struct spi_device *spi, u8 *buffer, unsigned int size) +{ + #ifdef DEBUG_FIFO_ACCESS + int i; + #endif + struct spi_transfer transfer; + u8 local_buffer[FIFO_SIZE + 1]; + int retval; + + if (size > FIFO_SIZE) { + #ifdef DEBUG + dev_dbg(&spi->dev, "read fifo: passed in buffer bigger then internal buffer \n"); + #endif + return -EMSGSIZE; + } + + /* prepare a bidirectional transfer */ + local_buffer[0] = REG_FIFO; + memset(&transfer, 0, sizeof(transfer)); + transfer.tx_buf = local_buffer; + transfer.rx_buf = local_buffer; + transfer.len = size+1; + + retval = spi_sync_transfer(spi, &transfer, 1); + + #ifdef DEBUG_FIFO_ACCESS + for (i=0; i<size; i++) + dev_dbg(&spi->dev, "%d - 0x%x\n", i, local_buffer[i+1]); + #endif + + memcpy(buffer, &local_buffer[1], size); // TODO: ohne memcopy wäre schöner + + return retval; +} + +int rf69_write_fifo(struct spi_device *spi, u8 *buffer, unsigned int size) +{ + #ifdef DEBUG_FIFO_ACCESS + int i; + #endif + char spi_address = REG_FIFO | WRITE_BIT; + u8 local_buffer[FIFO_SIZE + 1]; + + if (size > FIFO_SIZE) { + #ifdef DEBUG + dev_dbg(&spi->dev, "read fifo: passed in buffer bigger then internal buffer \n"); + #endif + return -EMSGSIZE; + } + + local_buffer[0] = spi_address; + memcpy(&local_buffer[1], buffer, size); // TODO: ohne memcopy wäre schöner + + #ifdef DEBUG_FIFO_ACCESS + for (i=0; i<size; i++) + dev_dbg(&spi->dev, "0x%x\n",buffer[i]); + #endif + + return spi_write (spi, local_buffer, size + 1); +} + +/*-------------------------------------------------------------------------*/ + +u8 rf69_read_reg(struct spi_device *spi, u8 addr) +{ + int retval; + + retval = spi_w8r8(spi, addr); + + #ifdef DEBUG_VALUES + if (retval < 0) + /* should never happen, since we already checked, + * that module is connected. Therefore no error + * handling, just an optional error message... + */ + dev_dbg(&spi->dev, "read 0x%x FAILED\n", + addr); + else + dev_dbg(&spi->dev, "read 0x%x from reg 0x%x\n", + retval, + addr); + #endif + + return retval; +} + +int rf69_write_reg(struct spi_device *spi, u8 addr, u8 value) +{ + int retval; + char buffer[2]; + + buffer[0] = addr | WRITE_BIT; + buffer[1] = value; + + retval = spi_write(spi, &buffer, 2); + + #ifdef DEBUG_VALUES + if (retval < 0) + /* should never happen, since we already checked, + * that module is connected. Therefore no error + * handling, just an optional error message... + */ + dev_dbg(&spi->dev, "write 0x%x to 0x%x FAILED\n", + value, + addr); + else + dev_dbg(&spi->dev, "wrote 0x%x to reg 0x%x\n", + value, + addr); + #endif + + return retval; +} + + diff --git a/drivers/staging/pi433/rf69.h b/drivers/staging/pi433/rf69.h new file mode 100644 index 000000000000..5c0c95628f2f --- /dev/null +++ b/drivers/staging/pi433/rf69.h @@ -0,0 +1,82 @@ +/* + * hardware abstraction/register access for HopeRf rf69 radio module + * + * Copyright (C) 2016 Wolf-Entwicklungen + * Marcus Wolf <linux@wolf-entwicklungen.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef RF69_H +#define RF69_H + +#include "rf69_enum.h" +#include "rf69_registers.h" + +#define F_OSC 32000000 /* in Hz */ +#define FREQUENCY 433920000 /* in Hz, modifying this value impacts CE certification */ +#define FIFO_SIZE 66 /* in byte */ +#define FIFO_THRESHOLD 15 /* in byte */ + +int rf69_set_mode(struct spi_device *spi, enum mode mode); +int rf69_set_data_mode(struct spi_device *spi, enum dataMode dataMode); +int rf69_set_modulation(struct spi_device *spi, enum modulation modulation); +enum modulation rf69_get_modulation(struct spi_device *spi); +int rf69_set_modulation_shaping(struct spi_device *spi, enum modShaping modShaping); +int rf69_set_bit_rate(struct spi_device *spi, u16 bitRate); +int rf69_set_deviation(struct spi_device *spi, u32 deviation); +int rf69_set_frequency(struct spi_device *spi, u32 frequency); +int rf69_set_amplifier_0(struct spi_device *spi, enum optionOnOff optionOnOff); +int rf69_set_amplifier_1(struct spi_device *spi, enum optionOnOff optionOnOff); +int rf69_set_amplifier_2(struct spi_device *spi, enum optionOnOff optionOnOff); +int rf69_set_output_power_level(struct spi_device *spi, u8 powerLevel); +int rf69_set_pa_ramp(struct spi_device *spi, enum paRamp paRamp); +int rf69_set_antenna_impedance(struct spi_device *spi, enum antennaImpedance antennaImpedance); +int rf69_set_lna_gain(struct spi_device *spi, enum lnaGain lnaGain); +enum lnaGain rf69_get_lna_gain(struct spi_device *spi); +int rf69_set_dc_cut_off_frequency_intern(struct spi_device *spi, u8 reg, enum dccPercent dccPercent); +int rf69_set_dc_cut_off_frequency(struct spi_device *spi, enum dccPercent dccPercent); +int rf69_set_dc_cut_off_frequency_during_afc(struct spi_device *spi, enum dccPercent dccPercent); +int rf69_set_bandwidth(struct spi_device *spi, enum mantisse mantisse, u8 exponent); +int rf69_set_bandwidth_during_afc(struct spi_device *spi, enum mantisse mantisse, u8 exponent); +int rf69_set_ook_threshold_type(struct spi_device *spi, enum thresholdType thresholdType); +int rf69_set_ook_threshold_step(struct spi_device *spi, enum thresholdStep thresholdStep); +int rf69_set_ook_threshold_dec(struct spi_device *spi, enum thresholdDecrement thresholdDecrement); +int rf69_set_dio_mapping(struct spi_device *spi, u8 DIONumber, u8 value); +bool rf69_get_flag(struct spi_device *spi, enum flag flag); +int rf69_reset_flag(struct spi_device *spi, enum flag flag); +int rf69_set_rssi_threshold(struct spi_device *spi, u8 threshold); +int rf69_set_rx_start_timeout(struct spi_device *spi, u8 timeout); +int rf69_set_rssi_timeout(struct spi_device *spi, u8 timeout); +int rf69_set_preamble_length(struct spi_device *spi, u16 preambleLength); +int rf69_set_sync_enable(struct spi_device *spi, enum optionOnOff optionOnOff); +int rf69_set_fifo_fill_condition(struct spi_device *spi, enum fifoFillCondition fifoFillCondition); +int rf69_set_sync_size(struct spi_device *spi, u8 sync_size); +int rf69_set_sync_tolerance(struct spi_device *spi, u8 syncTolerance); +int rf69_set_sync_values(struct spi_device *spi, u8 syncValues[8]); +int rf69_set_packet_format(struct spi_device *spi, enum packetFormat packetFormat); +int rf69_set_crc_enable(struct spi_device *spi, enum optionOnOff optionOnOff); +int rf69_set_adressFiltering(struct spi_device *spi, enum addressFiltering addressFiltering); +int rf69_set_payload_length(struct spi_device *spi, u8 payloadLength); +u8 rf69_get_payload_length(struct spi_device *spi); +int rf69_set_node_address(struct spi_device *spi, u8 nodeAddress); +int rf69_set_broadcast_address(struct spi_device *spi, u8 broadcastAddress); +int rf69_set_tx_start_condition(struct spi_device *spi, enum txStartCondition txStartCondition); +int rf69_set_fifo_threshold(struct spi_device *spi, u8 threshold); +int rf69_set_dagc(struct spi_device *spi, enum dagc dagc); + +int rf69_read_fifo (struct spi_device *spi, u8 *buffer, unsigned int size); +int rf69_write_fifo(struct spi_device *spi, u8 *buffer, unsigned int size); + +u8 rf69_read_reg (struct spi_device *spi, u8 addr); +int rf69_write_reg(struct spi_device *spi, u8 addr, u8 value); + + +#endif diff --git a/drivers/staging/pi433/rf69_enum.h b/drivers/staging/pi433/rf69_enum.h new file mode 100644 index 000000000000..fbfb59bd3f3d --- /dev/null +++ b/drivers/staging/pi433/rf69_enum.h @@ -0,0 +1,201 @@ +/* + * enumerations for HopeRf rf69 radio module + * + * Copyright (C) 2016 Wolf-Entwicklungen + * Marcus Wolf <linux@wolf-entwicklungen.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef RF69_ENUM_H +#define RF69_ENUM_H + +enum optionOnOff +{ + optionOff, + optionOn +}; + +enum mode +{ + mode_sleep, + standby, + synthesizer, + transmit, + receive +}; + +enum dataMode +{ + packet, + continuous, + continuousNoSync +}; + +enum modulation +{ + OOK, + FSK +}; + +enum modShaping +{ + shapingOff, + shaping1_0, + shaping0_5, + shaping0_3, + shapingBR, + shaping2BR +}; + +enum paRamp +{ + ramp3400, + ramp2000, + ramp1000, + ramp500, + ramp250, + ramp125, + ramp100, + ramp62, + ramp50, + ramp40, + ramp31, + ramp25, + ramp20, + ramp15, + ramp12, + ramp10 +}; + +enum antennaImpedance +{ + fiftyOhm, + twohundretOhm +}; + +enum lnaGain +{ + automatic, + max, + maxMinus6, + maxMinus12, + maxMinus24, + maxMinus36, + maxMinus48, + undefined +}; + +enum dccPercent +{ + dcc16Percent, + dcc8Percent, + dcc4Percent, + dcc2Percent, + dcc1Percent, + dcc0_5Percent, + dcc0_25Percent, + dcc0_125Percent +}; + +enum mantisse +{ + mantisse16, + mantisse20, + mantisse24 +}; + +enum thresholdType +{ + fixed, + peak, + average +}; + +enum thresholdStep +{ + step_0_5db, + step_1_0db, + step_1_5db, + step_2_0db, + step_3_0db, + step_4_0db, + step_5_0db, + step_6_0db +}; + +enum thresholdDecrement +{ + dec_every8th, + dec_every4th, + dec_every2nd, + dec_once, + dec_twice, + dec_4times, + dec_8times, + dec_16times +}; + +enum flag +{ + modeSwitchCompleted, + readyToReceive, + readyToSend, + pllLocked, + rssiExceededThreshold, + timeout, + automode, + syncAddressMatch, + fifoFull, +// fifoNotEmpty, collision with next enum; replaced by following enum... + fifoEmpty, + fifoLevelBelowThreshold, + fifoOverrun, + packetSent, + payloadReady, + crcOk, + batteryLow +}; + +enum fifoFillCondition +{ + afterSyncInterrupt, + always +}; + +enum packetFormat +{ + packetLengthFix, + packetLengthVar +}; + +enum txStartCondition +{ + fifoLevel, + fifoNotEmpty +}; + +enum addressFiltering +{ + filteringOff, + nodeAddress, + nodeOrBroadcastAddress +}; + +enum dagc +{ + normalMode, + improve, + improve4LowModulationIndex +}; + + +#endif diff --git a/drivers/staging/pi433/rf69_registers.h b/drivers/staging/pi433/rf69_registers.h new file mode 100644 index 000000000000..6335d42142fe --- /dev/null +++ b/drivers/staging/pi433/rf69_registers.h @@ -0,0 +1,489 @@ +/* + * register description for HopeRf rf69 radio module + * + * Copyright (C) 2016 Wolf-Entwicklungen + * Marcus Wolf <linux@wolf-entwicklungen.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/*******************************************/ +/* RF69 register addresses */ +/*******************************************/ +#define REG_FIFO 0x00 +#define REG_OPMODE 0x01 +#define REG_DATAMODUL 0x02 +#define REG_BITRATE_MSB 0x03 +#define REG_BITRATE_LSB 0x04 +#define REG_FDEV_MSB 0x05 +#define REG_FDEV_LSB 0x06 +#define REG_FRF_MSB 0x07 +#define REG_FRF_MID 0x08 +#define REG_FRF_LSB 0x09 +#define REG_OSC1 0x0A +#define REG_AFCCTRL 0x0B +#define REG_LOWBAT 0x0C +#define REG_LISTEN1 0x0D +#define REG_LISTEN2 0x0E +#define REG_LISTEN3 0x0F +#define REG_VERSION 0x10 +#define REG_PALEVEL 0x11 +#define REG_PARAMP 0x12 +#define REG_OCP 0x13 +#define REG_AGCREF 0x14 /* not available on RF69 */ +#define REG_AGCTHRESH1 0x15 /* not available on RF69 */ +#define REG_AGCTHRESH2 0x16 /* not available on RF69 */ +#define REG_AGCTHRESH3 0x17 /* not available on RF69 */ +#define REG_LNA 0x18 +#define REG_RXBW 0x19 +#define REG_AFCBW 0x1A +#define REG_OOKPEAK 0x1B +#define REG_OOKAVG 0x1C +#define REG_OOKFIX 0x1D +#define REG_AFCFEI 0x1E +#define REG_AFCMSB 0x1F +#define REG_AFCLSB 0x20 +#define REG_FEIMSB 0x21 +#define REG_FEILSB 0x22 +#define REG_RSSICONFIG 0x23 +#define REG_RSSIVALUE 0x24 +#define REG_DIOMAPPING1 0x25 +#define REG_DIOMAPPING2 0x26 +#define REG_IRQFLAGS1 0x27 +#define REG_IRQFLAGS2 0x28 +#define REG_RSSITHRESH 0x29 +#define REG_RXTIMEOUT1 0x2A +#define REG_RXTIMEOUT2 0x2B +#define REG_PREAMBLE_MSB 0x2C +#define REG_PREAMBLE_LSB 0x2D +#define REG_SYNC_CONFIG 0x2E +#define REG_SYNCVALUE1 0x2F +#define REG_SYNCVALUE2 0x30 +#define REG_SYNCVALUE3 0x31 +#define REG_SYNCVALUE4 0x32 +#define REG_SYNCVALUE5 0x33 +#define REG_SYNCVALUE6 0x34 +#define REG_SYNCVALUE7 0x35 +#define REG_SYNCVALUE8 0x36 +#define REG_PACKETCONFIG1 0x37 +#define REG_PAYLOAD_LENGTH 0x38 +#define REG_NODEADRS 0x39 +#define REG_BROADCASTADRS 0x3A +#define REG_AUTOMODES 0x3B +#define REG_FIFO_THRESH 0x3C +#define REG_PACKETCONFIG2 0x3D +#define REG_AESKEY1 0x3E +#define REG_AESKEY2 0x3F +#define REG_AESKEY3 0x40 +#define REG_AESKEY4 0x41 +#define REG_AESKEY5 0x42 +#define REG_AESKEY6 0x43 +#define REG_AESKEY7 0x44 +#define REG_AESKEY8 0x45 +#define REG_AESKEY9 0x46 +#define REG_AESKEY10 0x47 +#define REG_AESKEY11 0x48 +#define REG_AESKEY12 0x49 +#define REG_AESKEY13 0x4A +#define REG_AESKEY14 0x4B +#define REG_AESKEY15 0x4C +#define REG_AESKEY16 0x4D +#define REG_TEMP1 0x4E +#define REG_TEMP2 0x4F +#define REG_TESTPA1 0x5A /* only present on RFM69HW */ +#define REG_TESTPA2 0x5C /* only present on RFM69HW */ +#define REG_TESTDAGC 0x6F + +/******************************************************/ +/* RF69/SX1231 bit definition */ +/******************************************************/ +/* write bit */ +#define WRITE_BIT 0x80 + +/* RegOpMode */ +#define MASK_OPMODE_SEQUENCER_OFF 0x80 +#define MASK_OPMODE_LISTEN_ON 0x40 +#define MASK_OPMODE_LISTEN_ABORT 0x20 +#define MASK_OPMODE_MODE 0x1C + +#define OPMODE_MODE_SLEEP 0x00 +#define OPMODE_MODE_STANDBY 0x04 /* default */ +#define OPMODE_MODE_SYNTHESIZER 0x08 +#define OPMODE_MODE_TRANSMIT 0x0C +#define OPMODE_MODE_RECEIVE 0x10 + +/* RegDataModul */ +#define MASK_DATAMODUL_MODE 0x06 +#define MASK_DATAMODUL_MODULATION_TYPE 0x18 +#define MASK_DATAMODUL_MODULATION_SHAPE 0x03 + +#define DATAMODUL_MODE_PACKET 0x00 /* default */ +#define DATAMODUL_MODE_CONTINUOUS 0x40 +#define DATAMODUL_MODE_CONTINUOUS_NOSYNC 0x60 + +#define DATAMODUL_MODULATION_TYPE_FSK 0x00 /* default */ +#define DATAMODUL_MODULATION_TYPE_OOK 0x08 + +#define DATAMODUL_MODULATION_SHAPE_NONE 0x00 /* default */ +#define DATAMODUL_MODULATION_SHAPE_1_0 0x01 +#define DATAMODUL_MODULATION_SHAPE_0_5 0x02 +#define DATAMODUL_MODULATION_SHAPE_0_3 0x03 +#define DATAMODUL_MODULATION_SHAPE_BR 0x01 +#define DATAMODUL_MODULATION_SHAPE_2BR 0x02 + +/* RegFDevMsb (0x05)*/ +#define FDEVMASB_MASK 0x3f + +/* + * // RegOsc1 + * #define OSC1_RCCAL_START 0x80 + * #define OSC1_RCCAL_DONE 0x40 + * + * // RegLowBat + * #define LOWBAT_MONITOR 0x10 + * #define LOWBAT_ON 0x08 + * #define LOWBAT_OFF 0x00 // Default + * + * #define LOWBAT_TRIM_1695 0x00 + * #define LOWBAT_TRIM_1764 0x01 + * #define LOWBAT_TRIM_1835 0x02 // Default + * #define LOWBAT_TRIM_1905 0x03 + * #define LOWBAT_TRIM_1976 0x04 + * #define LOWBAT_TRIM_2045 0x05 + * #define LOWBAT_TRIM_2116 0x06 + * #define LOWBAT_TRIM_2185 0x07 + * + * + * // RegListen1 + * #define LISTEN1_RESOL_64 0x50 + * #define LISTEN1_RESOL_4100 0xA0 // Default + * #define LISTEN1_RESOL_262000 0xF0 + * + * #define LISTEN1_CRITERIA_RSSI 0x00 // Default + * #define LISTEN1_CRITERIA_RSSIANDSYNC 0x08 + * + * #define LISTEN1_END_00 0x00 + * #define LISTEN1_END_01 0x02 // Default + * #define LISTEN1_END_10 0x04 + * + * + * // RegListen2 + * #define LISTEN2_COEFIDLE_VALUE 0xF5 // Default + * + * // RegListen3 + * #define LISTEN3_COEFRX_VALUE 0x20 // Default + */ + +// RegPaLevel +#define MASK_PALEVEL_PA0 0x80 +#define MASK_PALEVEL_PA1 0x40 +#define MASK_PALEVEL_PA2 0x20 +#define MASK_PALEVEL_OUTPUT_POWER 0x1F + + + +// RegPaRamp +#define PARAMP_3400 0x00 +#define PARAMP_2000 0x01 +#define PARAMP_1000 0x02 +#define PARAMP_500 0x03 +#define PARAMP_250 0x04 +#define PARAMP_125 0x05 +#define PARAMP_100 0x06 +#define PARAMP_62 0x07 +#define PARAMP_50 0x08 +#define PARAMP_40 0x09 /* default */ +#define PARAMP_31 0x0A +#define PARAMP_25 0x0B +#define PARAMP_20 0x0C +#define PARAMP_15 0x0D +#define PARAMP_12 0x0E +#define PARAMP_10 0x0F + +#define MASK_PARAMP 0x0F + +/* + * // RegOcp + * #define OCP_OFF 0x0F + * #define OCP_ON 0x1A // Default + * + * #define OCP_TRIM_45 0x00 + * #define OCP_TRIM_50 0x01 + * #define OCP_TRIM_55 0x02 + * #define OCP_TRIM_60 0x03 + * #define OCP_TRIM_65 0x04 + * #define OCP_TRIM_70 0x05 + * #define OCP_TRIM_75 0x06 + * #define OCP_TRIM_80 0x07 + * #define OCP_TRIM_85 0x08 + * #define OCP_TRIM_90 0x09 + * #define OCP_TRIM_95 0x0A + * #define OCP_TRIM_100 0x0B // Default + * #define OCP_TRIM_105 0x0C + * #define OCP_TRIM_110 0x0D + * #define OCP_TRIM_115 0x0E + * #define OCP_TRIM_120 0x0F + */ + +/* RegLna (0x18) */ +#define MASK_LNA_ZIN 0x80 +#define MASK_LNA_CURRENT_GAIN 0x38 +#define MASK_LNA_GAIN 0x07 + +#define LNA_GAIN_AUTO 0x00 /* default */ +#define LNA_GAIN_MAX 0x01 +#define LNA_GAIN_MAX_MINUS_6 0x02 +#define LNA_GAIN_MAX_MINUS_12 0x03 +#define LNA_GAIN_MAX_MINUS_24 0x04 +#define LNA_GAIN_MAX_MINUS_36 0x05 +#define LNA_GAIN_MAX_MINUS_48 0x06 + + +/* RegRxBw (0x19) and RegAfcBw (0x1A) */ +#define MASK_BW_DCC_FREQ 0xE0 +#define MASK_BW_MANTISSE 0x18 +#define MASK_BW_EXPONENT 0x07 + +#define BW_DCC_16_PERCENT 0x00 +#define BW_DCC_8_PERCENT 0x20 +#define BW_DCC_4_PERCENT 0x40 /* default */ +#define BW_DCC_2_PERCENT 0x60 +#define BW_DCC_1_PERCENT 0x80 +#define BW_DCC_0_5_PERCENT 0xA0 +#define BW_DCC_0_25_PERCENT 0xC0 +#define BW_DCC_0_125_PERCENT 0xE0 + +#define BW_MANT_16 0x00 +#define BW_MANT_20 0x08 +#define BW_MANT_24 0x10 /* default */ + + +/* RegOokPeak (0x1B) */ +#define MASK_OOKPEAK_THRESTYPE 0xc0 +#define MASK_OOKPEAK_THRESSTEP 0x38 +#define MASK_OOKPEAK_THRESDEC 0x07 + +#define OOKPEAK_THRESHTYPE_FIXED 0x00 +#define OOKPEAK_THRESHTYPE_PEAK 0x40 /* default */ +#define OOKPEAK_THRESHTYPE_AVERAGE 0x80 + +#define OOKPEAK_THRESHSTEP_0_5_DB 0x00 /* default */ +#define OOKPEAK_THRESHSTEP_1_0_DB 0x08 +#define OOKPEAK_THRESHSTEP_1_5_DB 0x10 +#define OOKPEAK_THRESHSTEP_2_0_DB 0x18 +#define OOKPEAK_THRESHSTEP_3_0_DB 0x20 +#define OOKPEAK_THRESHSTEP_4_0_DB 0x28 +#define OOKPEAK_THRESHSTEP_5_0_DB 0x30 +#define OOKPEAK_THRESHSTEP_6_0_DB 0x38 + +#define OOKPEAK_THRESHDEC_ONCE 0x00 /* default */ +#define OOKPEAK_THRESHDEC_EVERY_2ND 0x01 +#define OOKPEAK_THRESHDEC_EVERY_4TH 0x02 +#define OOKPEAK_THRESHDEC_EVERY_8TH 0x03 +#define OOKPEAK_THRESHDEC_TWICE 0x04 +#define OOKPEAK_THRESHDEC_4_TIMES 0x05 +#define OOKPEAK_THRESHDEC_8_TIMES 0x06 +#define OOKPEAK_THRESHDEC_16_TIMES 0x07 + +/* + * // RegOokAvg + * #define OOKAVG_AVERAGETHRESHFILT_00 0x00 + * #define OOKAVG_AVERAGETHRESHFILT_01 0x40 + * #define OOKAVG_AVERAGETHRESHFILT_10 0x80 // Default + * #define OOKAVG_AVERAGETHRESHFILT_11 0xC0 + * + * + * // RegAfcFei + * #define AFCFEI_FEI_DONE 0x40 + * #define AFCFEI_FEI_START 0x20 + * #define AFCFEI_AFC_DONE 0x10 + * #define AFCFEI_AFCAUTOCLEAR_ON 0x08 + * #define AFCFEI_AFCAUTOCLEAR_OFF 0x00 // Default + * + * #define AFCFEI_AFCAUTO_ON 0x04 + * #define AFCFEI_AFCAUTO_OFF 0x00 // Default + * + * #define AFCFEI_AFC_CLEAR 0x02 + * #define AFCFEI_AFC_START 0x01 + * + * // RegRssiConfig + * #define RSSI_FASTRX_ON 0x08 + * #define RSSI_FASTRX_OFF 0x00 // Default + * #define RSSI_DONE 0x02 + * #define RSSI_START 0x01 + */ + +/* RegDioMapping1 */ +#define MASK_DIO0 0xC0 +#define MASK_DIO1 0x30 +#define MASK_DIO2 0x0C +#define MASK_DIO3 0x03 +#define SHIFT_DIO0 6 +#define SHIFT_DIO1 4 +#define SHIFT_DIO2 2 +#define SHIFT_DIO3 0 + +/* RegDioMapping2 */ +#define MASK_DIO4 0xC0 +#define MASK_DIO5 0x30 +#define SHIFT_DIO4 6 +#define SHIFT_DIO5 4 + +/* DIO numbers */ +#define DIO0 0 +#define DIO1 1 +#define DIO2 2 +#define DIO3 3 +#define DIO4 4 +#define DIO5 5 + +/* DIO Mapping values (packet mode) */ +#define DIO_ModeReady_DIO4 0x00 +#define DIO_ModeReady_DIO5 0x03 +#define DIO_ClkOut 0x00 +#define DIO_Data 0x01 +#define DIO_TimeOut_DIO1 0x03 +#define DIO_TimeOut_DIO4 0x00 +#define DIO_Rssi_DIO0 0x03 +#define DIO_Rssi_DIO3_4 0x01 +#define DIO_RxReady 0x02 +#define DIO_PLLLock 0x03 +#define DIO_TxReady 0x01 +#define DIO_FifoFull_DIO1 0x01 +#define DIO_FifoFull_DIO3 0x00 +#define DIO_SyncAddress 0x02 +#define DIO_FifoNotEmpty_DIO1 0x02 +#define DIO_FifoNotEmpty_FIO2 0x00 +#define DIO_Automode 0x04 +#define DIO_FifoLevel 0x00 +#define DIO_CrcOk 0x00 +#define DIO_PayloadReady 0x01 +#define DIO_PacketSent 0x00 +#define DIO_Dclk 0x00 + +/* RegDioMapping2 CLK_OUT part */ +#define MASK_DIOMAPPING2_CLK_OUT 0x07 + +#define DIOMAPPING2_CLK_OUT_NO_DIV 0x00 +#define DIOMAPPING2_CLK_OUT_DIV_2 0x01 +#define DIOMAPPING2_CLK_OUT_DIV_4 0x02 +#define DIOMAPPING2_CLK_OUT_DIV_8 0x03 +#define DIOMAPPING2_CLK_OUT_DIV_16 0x04 +#define DIOMAPPING2_CLK_OUT_DIV_32 0x05 +#define DIOMAPPING2_CLK_OUT_RC 0x06 +#define DIOMAPPING2_CLK_OUT_OFF 0x07 /* default */ + +/* RegIrqFlags1 */ +#define MASK_IRQFLAGS1_MODE_READY 0x80 +#define MASK_IRQFLAGS1_RX_READY 0x40 +#define MASK_IRQFLAGS1_TX_READY 0x20 +#define MASK_IRQFLAGS1_PLL_LOCK 0x10 +#define MASK_IRQFLAGS1_RSSI 0x08 +#define MASK_IRQFLAGS1_TIMEOUT 0x04 +#define MASK_IRQFLAGS1_AUTOMODE 0x02 +#define MASK_IRQFLAGS1_SYNC_ADDRESS_MATCH 0x01 + +/* RegIrqFlags2 */ +#define MASK_IRQFLAGS2_FIFO_FULL 0x80 +#define MASK_IRQFLAGS2_FIFO_NOT_EMPTY 0x40 +#define MASK_IRQFLAGS2_FIFO_LEVEL 0x20 +#define MASK_IRQFLAGS2_FIFO_OVERRUN 0x10 +#define MASK_IRQFLAGS2_PACKET_SENT 0x08 +#define MASK_IRQFLAGS2_PAYLOAD_READY 0x04 +#define MASK_IRQFLAGS2_CRC_OK 0x02 +#define MASK_IRQFLAGS2_LOW_BAT 0x01 + +/* RegSyncConfig */ +#define MASK_SYNC_CONFIG_SYNC_ON 0x80 /* default */ +#define MASK_SYNC_CONFIG_FIFO_FILL_CONDITION 0x40 +#define MASK_SYNC_CONFIG_SYNC_SIZE 0x38 +#define MASK_SYNC_CONFIG_SYNC_TOLERANCE 0x07 + +/* RegPacketConfig1 */ +#define MASK_PACKETCONFIG1_PAKET_FORMAT_VARIABLE 0x80 +#define MASK_PACKETCONFIG1_DCFREE 0x60 +#define MASK_PACKETCONFIG1_CRC_ON 0x10 /* default */ +#define MASK_PACKETCONFIG1_CRCAUTOCLEAR_OFF 0x08 +#define MASK_PACKETCONFIG1_ADDRESSFILTERING 0x06 + +#define PACKETCONFIG1_DCFREE_OFF 0x00 /* default */ +#define PACKETCONFIG1_DCFREE_MANCHESTER 0x20 +#define PACKETCONFIG1_DCFREE_WHITENING 0x40 +#define PACKETCONFIG1_ADDRESSFILTERING_OFF 0x00 /* default */ +#define PACKETCONFIG1_ADDRESSFILTERING_NODE 0x02 +#define PACKETCONFIG1_ADDRESSFILTERING_NODEBROADCAST 0x04 + +/* + * // RegAutoModes + * #define AUTOMODES_ENTER_OFF 0x00 // Default + * #define AUTOMODES_ENTER_FIFONOTEMPTY 0x20 + * #define AUTOMODES_ENTER_FIFOLEVEL 0x40 + * #define AUTOMODES_ENTER_CRCOK 0x60 + * #define AUTOMODES_ENTER_PAYLOADREADY 0x80 + * #define AUTOMODES_ENTER_SYNCADRSMATCH 0xA0 + * #define AUTOMODES_ENTER_PACKETSENT 0xC0 + * #define AUTOMODES_ENTER_FIFOEMPTY 0xE0 + * + * #define AUTOMODES_EXIT_OFF 0x00 // Default + * #define AUTOMODES_EXIT_FIFOEMPTY 0x04 + * #define AUTOMODES_EXIT_FIFOLEVEL 0x08 + * #define AUTOMODES_EXIT_CRCOK 0x0C + * #define AUTOMODES_EXIT_PAYLOADREADY 0x10 + * #define AUTOMODES_EXIT_SYNCADRSMATCH 0x14 + * #define AUTOMODES_EXIT_PACKETSENT 0x18 + * #define AUTOMODES_EXIT_RXTIMEOUT 0x1C + * + * #define AUTOMODES_INTERMEDIATE_SLEEP 0x00 // Default + * #define AUTOMODES_INTERMEDIATE_STANDBY 0x01 + * #define AUTOMODES_INTERMEDIATE_RECEIVER 0x02 + * #define AUTOMODES_INTERMEDIATE_TRANSMITTER 0x03 + * + */ +/* RegFifoThresh (0x3c) */ +#define MASK_FIFO_THRESH_TXSTART 0x80 +#define MASK_FIFO_THRESH_VALUE 0x7F + +/* + * + * // RegPacketConfig2 + * #define PACKET2_RXRESTARTDELAY_1BIT 0x00 // Default + * #define PACKET2_RXRESTARTDELAY_2BITS 0x10 + * #define PACKET2_RXRESTARTDELAY_4BITS 0x20 + * #define PACKET2_RXRESTARTDELAY_8BITS 0x30 + * #define PACKET2_RXRESTARTDELAY_16BITS 0x40 + * #define PACKET2_RXRESTARTDELAY_32BITS 0x50 + * #define PACKET2_RXRESTARTDELAY_64BITS 0x60 + * #define PACKET2_RXRESTARTDELAY_128BITS 0x70 + * #define PACKET2_RXRESTARTDELAY_256BITS 0x80 + * #define PACKET2_RXRESTARTDELAY_512BITS 0x90 + * #define PACKET2_RXRESTARTDELAY_1024BITS 0xA0 + * #define PACKET2_RXRESTARTDELAY_2048BITS 0xB0 + * #define PACKET2_RXRESTARTDELAY_NONE 0xC0 + * #define PACKET2_RXRESTART 0x04 + * + * #define PACKET2_AUTORXRESTART_ON 0x02 // Default + * #define PACKET2_AUTORXRESTART_OFF 0x00 + * + * #define PACKET2_AES_ON 0x01 + * #define PACKET2_AES_OFF 0x00 // Default + * + * + * // RegTemp1 + * #define TEMP1_MEAS_START 0x08 + * #define TEMP1_MEAS_RUNNING 0x04 + * #define TEMP1_ADCLOWPOWER_ON 0x01 // Default + * #define TEMP1_ADCLOWPOWER_OFF 0x00 + */ + +// RegTestDagc (0x6F) +#define DAGC_NORMAL 0x00 /* Reset value */ +#define DAGC_IMPROVED_LOWBETA1 0x20 +#define DAGC_IMPROVED_LOWBETA0 0x30 /* Recommended val */ diff --git a/drivers/staging/rtl8188eu/core/rtw_ap.c b/drivers/staging/rtl8188eu/core/rtw_ap.c index 647a922d79d1..32a483769975 100644 --- a/drivers/staging/rtl8188eu/core/rtw_ap.c +++ b/drivers/staging/rtl8188eu/core/rtw_ap.c @@ -119,7 +119,7 @@ static void update_BCNTIM(struct adapter *padapter) } *dst_ie++ = _TIM_IE_; - if ((pstapriv->tim_bitmap&0xff00) && (pstapriv->tim_bitmap&0x00fc)) + if ((pstapriv->tim_bitmap & 0xff00) && (pstapriv->tim_bitmap & 0x00fc)) tim_ielen = 5; else tim_ielen = 4; @@ -129,7 +129,7 @@ static void update_BCNTIM(struct adapter *padapter) *dst_ie++ = 0;/* DTIM count */ *dst_ie++ = 1;/* DTIM period */ - if (pstapriv->tim_bitmap&BIT(0))/* for bc/mc frames */ + if (pstapriv->tim_bitmap & BIT(0))/* for bc/mc frames */ *dst_ie++ = BIT(0);/* bitmap ctrl */ else *dst_ie++ = 0; @@ -583,10 +583,10 @@ static void update_bmc_sta(struct adapter *padapter) { u8 arg = 0; - arg = psta->mac_id&0x1f; + arg = psta->mac_id & 0x1f; arg |= BIT(7); tx_ra_bitmap |= ((raid << 28) & 0xf0000000); - DBG_88E("update_bmc_sta, mask = 0x%x, arg = 0x%x\n", tx_ra_bitmap, arg); + DBG_88E("%s, mask = 0x%x, arg = 0x%x\n", __func__, tx_ra_bitmap, arg); /* bitmap[0:27] = tx_rate_bitmap */ /* bitmap[28:31]= Rate Adaptive id */ @@ -1043,7 +1043,7 @@ int rtw_check_beacon_data(struct adapter *padapter, u8 *pbuf, int len) (psecuritypriv->wpa2_pairwise_cipher & WPA_CIPHER_CCMP)) pht_cap->ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_DENSITY & (0x07 << 2)); else - pht_cap->ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_DENSITY&0x00); + pht_cap->ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_DENSITY & 0x00); /* set Max Rx AMPDU size to 64K */ pht_cap->ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_FACTOR & 0x03); @@ -1719,7 +1719,7 @@ int rtw_sta_flush(struct adapter *padapter) DBG_88E(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(padapter->pnetdev)); - if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE) + if ((pmlmeinfo->state & 0x03) != WIFI_FW_AP_STATE) return 0; spin_lock_bh(&pstapriv->asoc_list_lock); @@ -1754,7 +1754,7 @@ void sta_info_update(struct adapter *padapter, struct sta_info *psta) struct mlme_priv *pmlmepriv = &padapter->mlmepriv; /* update wmm cap. */ - if (WLAN_STA_WME&flags) + if (WLAN_STA_WME & flags) psta->qos_option = 1; else psta->qos_option = 0; @@ -1763,7 +1763,7 @@ void sta_info_update(struct adapter *padapter, struct sta_info *psta) psta->qos_option = 0; /* update 802.11n ht cap. */ - if (WLAN_STA_HT&flags) { + if (WLAN_STA_HT & flags) { psta->htpriv.ht_option = true; psta->qos_option = 1; } else { diff --git a/drivers/staging/rtl8188eu/core/rtw_cmd.c b/drivers/staging/rtl8188eu/core/rtw_cmd.c index a69007ef77bf..9461bce883ea 100644 --- a/drivers/staging/rtl8188eu/core/rtw_cmd.c +++ b/drivers/staging/rtl8188eu/core/rtw_cmd.c @@ -186,7 +186,7 @@ _next: pcmd->res = H2C_DROPPED; } else { if (pcmd->cmdcode < ARRAY_SIZE(wlancmds)) { - cmd_hdl = wlancmds[pcmd->cmdcode].h2cfuns; + cmd_hdl = wlancmds[pcmd->cmdcode].h2cfuns; if (cmd_hdl) { ret = cmd_hdl(pcmd->padapter, pcmd->parmbuf); diff --git a/drivers/staging/rtl8188eu/core/rtw_ioctl_set.c b/drivers/staging/rtl8188eu/core/rtw_ioctl_set.c index d8d88b5f68e5..767928a2cbb4 100644 --- a/drivers/staging/rtl8188eu/core/rtw_ioctl_set.c +++ b/drivers/staging/rtl8188eu/core/rtw_ioctl_set.c @@ -56,7 +56,7 @@ u8 rtw_do_join(struct adapter *padapter) RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("rtw_do_join(): site survey if scanned_queue is empty\n.")); /* submit site_survey_cmd */ ret = rtw_sitesurvey_cmd(padapter, &pmlmepriv->assoc_ssid, 1, NULL, 0); - if (_SUCCESS != ret) { + if (ret != _SUCCESS) { pmlmepriv->to_join = false; RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("rtw_do_join(): site survey return error\n.")); } @@ -110,7 +110,7 @@ u8 rtw_do_join(struct adapter *padapter) if (!pmlmepriv->LinkDetectInfo.bBusyTraffic || pmlmepriv->to_roaming > 0) { ret = rtw_sitesurvey_cmd(padapter, &pmlmepriv->assoc_ssid, 1, NULL, 0); - if (_SUCCESS != ret) { + if (ret != _SUCCESS) { pmlmepriv->to_join = false; RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("do_join(): site survey return error\n.")); } @@ -621,7 +621,7 @@ int rtw_set_country(struct adapter *adapter, const char *country_code) DBG_88E("%s country_code:%s\n", __func__, country_code); for (i = 0; i < ARRAY_SIZE(channel_table); i++) { - if (0 == strcmp(channel_table[i].name, country_code)) { + if (strcmp(channel_table[i].name, country_code) == 0) { channel_plan = channel_table[i].channel_plan; break; } diff --git a/drivers/staging/rtl8188eu/core/rtw_mlme.c b/drivers/staging/rtl8188eu/core/rtw_mlme.c index fde306087844..f663e6c41f8a 100644 --- a/drivers/staging/rtl8188eu/core/rtw_mlme.c +++ b/drivers/staging/rtl8188eu/core/rtw_mlme.c @@ -1502,7 +1502,7 @@ int rtw_select_and_join_from_scanned_queue(struct mlme_priv *pmlmepriv) pmlmepriv->pscanned = phead->next; while (phead != pmlmepriv->pscanned) { pnetwork = container_of(pmlmepriv->pscanned, struct wlan_network, list); - if (pnetwork == NULL) { + if (!pnetwork) { RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("%s return _FAIL:(pnetwork==NULL)\n", __func__)); ret = _FAIL; goto exit; @@ -1566,7 +1566,6 @@ int rtw_set_auth(struct adapter *adapter, struct security_priv *psecuritypriv) res = _FAIL; goto exit; } - memset(psetauthparm, 0, sizeof(struct setauth_parm)); psetauthparm->mode = (unsigned char)psecuritypriv->dot11AuthAlgrthm; pcmd->cmdcode = _SetAuth_CMD_; pcmd->parmbuf = (unsigned char *)psetauthparm; @@ -1601,8 +1600,6 @@ int rtw_set_key(struct adapter *adapter, struct security_priv *psecuritypriv, in goto err_free_cmd; } - memset(psetkeyparm, 0, sizeof(struct setkey_parm)); - if (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) { psetkeyparm->algorithm = (unsigned char)psecuritypriv->dot118021XGrpPrivacy; RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, @@ -1708,14 +1705,9 @@ static int SecIsInPMKIDList(struct adapter *Adapter, u8 *bssid) do { if ((psecuritypriv->PMKIDList[i].bUsed) && - (!memcmp(psecuritypriv->PMKIDList[i].Bssid, bssid, ETH_ALEN))) { + (!memcmp(psecuritypriv->PMKIDList[i].Bssid, bssid, ETH_ALEN))) break; - } else { - i++; - /* continue; */ - } - - } while (i < NUM_PMKID_CACHE); + } while (++i < NUM_PMKID_CACHE); if (i == NUM_PMKID_CACHE) i = -1;/* Could not find. */ diff --git a/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c b/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c index 88a3a2b9c144..611c9409bb98 100644 --- a/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c +++ b/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c @@ -3961,7 +3961,8 @@ static void init_mlme_ext_priv_value(struct adapter *padapter) static int has_channel(struct rt_channel_info *channel_set, u8 chanset_size, - u8 chan) { + u8 chan) +{ int i; for (i = 0; i < chanset_size; i++) { @@ -3973,7 +3974,8 @@ static int has_channel(struct rt_channel_info *channel_set, static void init_channel_list(struct adapter *padapter, struct rt_channel_info *channel_set, u8 chanset_size, - struct p2p_channels *channel_list) { + struct p2p_channels *channel_list) +{ struct p2p_oper_class_map op_class[] = { { IEEE80211G, 81, 1, 13, 1, BW20 }, { IEEE80211G, 82, 14, 14, 1, BW20 }, diff --git a/drivers/staging/rtl8188eu/include/rtw_ioctl.h b/drivers/staging/rtl8188eu/include/rtw_ioctl.h index 0fa78ed2c1ab..4c925e610997 100644 --- a/drivers/staging/rtl8188eu/include/rtw_ioctl.h +++ b/drivers/staging/rtl8188eu/include/rtw_ioctl.h @@ -75,7 +75,8 @@ struct oid_par_priv { }; #if defined(_RTW_MP_IOCTL_C_) -static int oid_null_function(struct oid_par_priv *poid_par_priv) { +static int oid_null_function(struct oid_par_priv *poid_par_priv) +{ return NDIS_STATUS_SUCCESS; } #endif diff --git a/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c b/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c index 763eccd0c7c9..c0664dc80bf2 100644 --- a/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c +++ b/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c @@ -2166,8 +2166,6 @@ static int set_group_key(struct adapter *padapter, u8 *key, u8 alg, int keyid) goto exit; } - memset(psetkeyparm, 0, sizeof(struct setkey_parm)); - psetkeyparm->keyid = (u8)keyid; psetkeyparm->algorithm = alg; diff --git a/drivers/staging/rtl8188eu/os_dep/usb_intf.c b/drivers/staging/rtl8188eu/os_dep/usb_intf.c index d283341cfe43..32c7225a831e 100644 --- a/drivers/staging/rtl8188eu/os_dep/usb_intf.c +++ b/drivers/staging/rtl8188eu/os_dep/usb_intf.c @@ -32,7 +32,7 @@ #define USB_VENDER_ID_REALTEK 0x0bda /* DID_USB_v916_20130116 */ -static struct usb_device_id rtw_usb_id_tbl[] = { +static const struct usb_device_id rtw_usb_id_tbl[] = { /*=== Realtek demoboard ===*/ {USB_DEVICE(USB_VENDER_ID_REALTEK, 0x8179)}, /* 8188EUS */ {USB_DEVICE(USB_VENDER_ID_REALTEK, 0x0179)}, /* 8188ETV */ @@ -45,6 +45,7 @@ static struct usb_device_id rtw_usb_id_tbl[] = { {USB_DEVICE(0x2001, 0x3311)}, /* DLink GO-USB-N150 REV B1 */ {USB_DEVICE(0x2357, 0x010c)}, /* TP-Link TL-WN722N v2 */ {USB_DEVICE(0x0df6, 0x0076)}, /* Sitecom N150 v2 */ + {USB_DEVICE(USB_VENDER_ID_REALTEK, 0xffef)}, /* Rosewill RNX-N150NUB */ {} /* Terminating entry */ }; diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c index a4aedb489e92..cbf8eb4a049d 100644 --- a/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c +++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c @@ -2385,7 +2385,7 @@ static inline void ieee80211_process_probe_response( struct ieee80211_probe_response *beacon, struct ieee80211_rx_stats *stats) { - struct ieee80211_network network; + struct ieee80211_network *network; struct ieee80211_network *target; struct ieee80211_network *oldest = NULL; #ifdef CONFIG_IEEE80211_DEBUG @@ -2397,7 +2397,10 @@ static inline void ieee80211_process_probe_response( u16 capability; //u8 wmm_info; - memset(&network, 0, sizeof(struct ieee80211_network)); + network = kzalloc(sizeof(*network), GFP_ATOMIC); + if (!network) + goto out; + capability = le16_to_cpu(beacon->capability); IEEE80211_DEBUG_SCAN( "'%s' (%pM): %c%c%c%c %c%c%c%c-%c%c%c%c %c%c%c%c\n", @@ -2420,14 +2423,14 @@ static inline void ieee80211_process_probe_response( (capability & (1 << 0x1)) ? '1' : '0', (capability & (1 << 0x0)) ? '1' : '0'); - if (ieee80211_network_init(ieee, beacon, &network, stats)) { + if (ieee80211_network_init(ieee, beacon, network, stats)) { IEEE80211_DEBUG_SCAN("Dropped '%s' (%pM) via %s.\n", escape_essid(info_element->data, info_element->len), beacon->header.addr3, fc == IEEE80211_STYPE_PROBE_RESP ? "PROBE RESPONSE" : "BEACON"); - return; + goto out; } // For Asus EeePc request, @@ -2437,8 +2440,8 @@ static inline void ieee80211_process_probe_response( // then wireless adapter should do active scan from ch1~11 and // passive scan from ch12~14 - if (!IsLegalChannel(ieee, network.channel)) - return; + if (!IsLegalChannel(ieee, network->channel)) + goto out; if (ieee->bGlobalDomain) { if (fc == IEEE80211_STYPE_PROBE_RESP) @@ -2446,19 +2449,19 @@ static inline void ieee80211_process_probe_response( // Case 1: Country code if(IS_COUNTRY_IE_VALID(ieee) ) { - if (!IsLegalChannel(ieee, network.channel)) { - printk("GetScanInfo(): For Country code, filter probe response at channel(%d).\n", network.channel); - return; + if (!IsLegalChannel(ieee, network->channel)) { + printk("GetScanInfo(): For Country code, filter probe response at channel(%d).\n", network->channel); + goto out; } } // Case 2: No any country code. else { // Filter over channel ch12~14 - if (network.channel > 11) + if (network->channel > 11) { - printk("GetScanInfo(): For Global Domain, filter probe response at channel(%d).\n", network.channel); - return; + printk("GetScanInfo(): For Global Domain, filter probe response at channel(%d).\n", network->channel); + goto out; } } } @@ -2467,19 +2470,19 @@ static inline void ieee80211_process_probe_response( // Case 1: Country code if(IS_COUNTRY_IE_VALID(ieee) ) { - if (!IsLegalChannel(ieee, network.channel)) { - printk("GetScanInfo(): For Country code, filter beacon at channel(%d).\n",network.channel); - return; + if (!IsLegalChannel(ieee, network->channel)) { + printk("GetScanInfo(): For Country code, filter beacon at channel(%d).\n",network->channel); + goto out; } } // Case 2: No any country code. else { // Filter over channel ch12~14 - if (network.channel > 14) + if (network->channel > 14) { - printk("GetScanInfo(): For Global Domain, filter beacon at channel(%d).\n",network.channel); - return; + printk("GetScanInfo(): For Global Domain, filter beacon at channel(%d).\n",network->channel); + goto out; } } } @@ -2497,8 +2500,8 @@ static inline void ieee80211_process_probe_response( spin_lock_irqsave(&ieee->lock, flags); - if (is_same_network(&ieee->current_network, &network, ieee)) { - update_network(&ieee->current_network, &network); + if (is_same_network(&ieee->current_network, network, ieee)) { + update_network(&ieee->current_network, network); if ((ieee->current_network.mode == IEEE_N_24G || ieee->current_network.mode == IEEE_G) && ieee->current_network.berp_info_valid){ if(ieee->current_network.erp_value& ERP_UseProtection) @@ -2512,11 +2515,11 @@ static inline void ieee80211_process_probe_response( ieee->LinkDetectInfo.NumRecvBcnInPeriod++; } else //hidden AP - network.flags = (~NETWORK_EMPTY_ESSID & network.flags)|(NETWORK_EMPTY_ESSID & ieee->current_network.flags); + network->flags = (~NETWORK_EMPTY_ESSID & network->flags)|(NETWORK_EMPTY_ESSID & ieee->current_network.flags); } list_for_each_entry(target, &ieee->network_list, list) { - if (is_same_network(target, &network, ieee)) + if (is_same_network(target, network, ieee)) break; if ((oldest == NULL) || (target->last_scanned < oldest->last_scanned)) @@ -2545,16 +2548,16 @@ static inline void ieee80211_process_probe_response( #ifdef CONFIG_IEEE80211_DEBUG IEEE80211_DEBUG_SCAN("Adding '%s' (%pM) via %s.\n", - escape_essid(network.ssid, - network.ssid_len), - network.bssid, + escape_essid(network->ssid, + network->ssid_len), + network->bssid, fc == IEEE80211_STYPE_PROBE_RESP ? "PROBE RESPONSE" : "BEACON"); #endif - memcpy(target, &network, sizeof(*target)); + memcpy(target, network, sizeof(*target)); list_add_tail(&target->list, &ieee->network_list); if(ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) - ieee80211_softmac_new_net(ieee,&network); + ieee80211_softmac_new_net(ieee,network); } else { IEEE80211_DEBUG_SCAN("Updating '%s' (%pM) via %s.\n", escape_essid(target->ssid, @@ -2570,27 +2573,30 @@ static inline void ieee80211_process_probe_response( renew = !time_after(target->last_scanned + ieee->scan_age, jiffies); //YJ,add,080819,for hidden ap if(is_beacon(beacon->header.frame_ctl) == 0) - network.flags = (~NETWORK_EMPTY_ESSID & network.flags)|(NETWORK_EMPTY_ESSID & target->flags); - //if(strncmp(network.ssid, "linksys-c",9) == 0) - // printk("====>2 network.ssid=%s FLAG=%d target.ssid=%s FLAG=%d\n", network.ssid, network.flags, target->ssid, target->flags); - if(((network.flags & NETWORK_EMPTY_ESSID) == NETWORK_EMPTY_ESSID) \ - && (((network.ssid_len > 0) && (strncmp(target->ssid, network.ssid, network.ssid_len)))\ - ||((ieee->current_network.ssid_len == network.ssid_len)&&(strncmp(ieee->current_network.ssid, network.ssid, network.ssid_len) == 0)&&(ieee->state == IEEE80211_NOLINK)))) + network->flags = (~NETWORK_EMPTY_ESSID & network->flags)|(NETWORK_EMPTY_ESSID & target->flags); + //if(strncmp(network->ssid, "linksys-c",9) == 0) + // printk("====>2 network->ssid=%s FLAG=%d target.ssid=%s FLAG=%d\n", network->ssid, network->flags, target->ssid, target->flags); + if(((network->flags & NETWORK_EMPTY_ESSID) == NETWORK_EMPTY_ESSID) \ + && (((network->ssid_len > 0) && (strncmp(target->ssid, network->ssid, network->ssid_len)))\ + ||((ieee->current_network.ssid_len == network->ssid_len)&&(strncmp(ieee->current_network.ssid, network->ssid, network->ssid_len) == 0)&&(ieee->state == IEEE80211_NOLINK)))) renew = 1; //YJ,add,080819,for hidden ap,end - update_network(target, &network); + update_network(target, network); if(renew && (ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE)) - ieee80211_softmac_new_net(ieee,&network); + ieee80211_softmac_new_net(ieee,network); } spin_unlock_irqrestore(&ieee->lock, flags); - if (is_beacon(beacon->header.frame_ctl)&&is_same_network(&ieee->current_network, &network, ieee)&&\ + if (is_beacon(beacon->header.frame_ctl)&&is_same_network(&ieee->current_network, network, ieee)&&\ (ieee->state == IEEE80211_LINKED)) { if (ieee->handle_beacon != NULL) { ieee->handle_beacon(ieee->dev,beacon,&ieee->current_network); } } + +out: + kfree(network); } void ieee80211_rx_mgt(struct ieee80211_device *ieee, diff --git a/drivers/staging/rtl8192u/ieee80211/rtl819x_HTProc.c b/drivers/staging/rtl8192u/ieee80211/rtl819x_HTProc.c index 60720997784b..9248dbcf3370 100644 --- a/drivers/staging/rtl8192u/ieee80211/rtl819x_HTProc.c +++ b/drivers/staging/rtl8192u/ieee80211/rtl819x_HTProc.c @@ -176,7 +176,7 @@ void HTDebugHTInfo(u8 *InfoIE, u8 *TitleString) IEEE80211_DEBUG(IEEE80211_DL_HT, "<Log HT Information Element>. Called by %s\n", TitleString); IEEE80211_DEBUG(IEEE80211_DL_HT, "\tPrimary channel = %d\n", pHTInfoEle->ControlChl); - IEEE80211_DEBUG(IEEE80211_DL_HT, "\tSenondary channel ="); + IEEE80211_DEBUG(IEEE80211_DL_HT, "\tSecondary channel ="); switch (pHTInfoEle->ExtChlOffset) { case 0: diff --git a/drivers/staging/rtl8192u/r8192U_core.c b/drivers/staging/rtl8192u/r8192U_core.c index 779ecdbc4e17..46b3f19e0878 100644 --- a/drivers/staging/rtl8192u/r8192U_core.c +++ b/drivers/staging/rtl8192u/r8192U_core.c @@ -270,8 +270,7 @@ int write_nic_byte_E(struct net_device *dev, int indx, u8 data) kfree(usbdata); if (status < 0) { - netdev_err(dev, "write_nic_byte_E TimeOut! status: %d\n", - status); + netdev_err(dev, "%s TimeOut! status: %d\n", __func__, status); return status; } return 0; @@ -321,7 +320,7 @@ int write_nic_byte(struct net_device *dev, int indx, u8 data) kfree(usbdata); if (status < 0) { - netdev_err(dev, "write_nic_byte TimeOut! status: %d\n", status); + netdev_err(dev, "%s TimeOut! status: %d\n", __func__, status); return status; } @@ -348,7 +347,7 @@ int write_nic_word(struct net_device *dev, int indx, u16 data) kfree(usbdata); if (status < 0) { - netdev_err(dev, "write_nic_word TimeOut! status: %d\n", status); + netdev_err(dev, "%s TimeOut! status: %d\n", __func__, status); return status; } @@ -376,8 +375,7 @@ int write_nic_dword(struct net_device *dev, int indx, u32 data) if (status < 0) { - netdev_err(dev, "write_nic_dword TimeOut! status: %d\n", - status); + netdev_err(dev, "%s TimeOut! status: %d\n", __func__, status); return status; } @@ -3095,7 +3093,8 @@ static RESET_TYPE TxCheckStuck(struct net_device *dev) if (bCheckFwTxCnt) { if (HalTxCheckStuck819xUsb(dev)) { RT_TRACE(COMP_RESET, - "TxCheckStuck(): Fw indicates no Tx condition!\n"); + "%s: Fw indicates no Tx condition!\n", + __func__); return RESET_TYPE_SILENT; } } @@ -3237,7 +3236,7 @@ static void CamRestoreAllEntry(struct net_device *dev) static u8 CAM_CONST_BROAD[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - RT_TRACE(COMP_SEC, "CamRestoreAllEntry:\n"); + RT_TRACE(COMP_SEC, "%s:\n", __func__); if ((priv->ieee80211->pairwise_key_type == KEY_TYPE_WEP40) || @@ -3835,8 +3834,8 @@ static u8 HwRateToMRate90(bool bIsHT, u8 rate) default: ret_rate = 0xff; RT_TRACE(COMP_RECV, - "HwRateToMRate90(): Non supported Rate [%x], bIsHT = %d!!!\n", - rate, bIsHT); + "%s: Non supported Rate [%x], bIsHT = %d!!!\n", + __func__, rate, bIsHT); break; } @@ -3897,8 +3896,8 @@ static u8 HwRateToMRate90(bool bIsHT, u8 rate) default: ret_rate = 0xff; RT_TRACE(COMP_RECV, - "HwRateToMRate90(): Non supported Rate [%x], bIsHT = %d!!!\n", - rate, bIsHT); + "%s: Non supported Rate [%x], bIsHT = %d!!!\n", + __func__, rate, bIsHT); break; } } diff --git a/drivers/staging/rtl8192u/r8192U_hw.h b/drivers/staging/rtl8192u/r8192U_hw.h index 174ccf618d3e..00a123d44207 100644 --- a/drivers/staging/rtl8192u/r8192U_hw.h +++ b/drivers/staging/rtl8192u/r8192U_hw.h @@ -20,25 +20,24 @@ #ifndef R8192_HW #define R8192_HW -typedef enum _VERSION_819xU{ +typedef enum _VERSION_819xU { VERSION_819xU_A, // A-cut VERSION_819xU_B, // B-cut VERSION_819xU_C,// C-cut } VERSION_819xU, *PVERSION_819xU; //added for different RF type -typedef enum _RT_RF_TYPE_DEF -{ +typedef enum _RT_RF_TYPE_DEF { RF_1T2R = 0, RF_2T4R, RF_819X_MAX_TYPE -}RT_RF_TYPE_DEF; +} RT_RF_TYPE_DEF; -typedef enum _BaseBand_Config_Type{ +typedef enum _BaseBand_Config_Type { BaseBand_Config_PHY_REG = 0, //Radio Path A BaseBand_Config_AGC_TAB = 1, //Radio Path B -}BaseBand_Config_Type, *PBaseBand_Config_Type; +} BaseBand_Config_Type, *PBaseBand_Config_Type; #define RTL8187_REQT_READ 0xc0 #define RTL8187_REQT_WRITE 0x40 #define RTL8187_REQ_GET_REGS 0x05 diff --git a/drivers/staging/rtl8192u/r819xU_cmdpkt.c b/drivers/staging/rtl8192u/r819xU_cmdpkt.c index 87ab3ba760fc..ae9a4f1ac8fd 100644 --- a/drivers/staging/rtl8192u/r819xU_cmdpkt.c +++ b/drivers/staging/rtl8192u/r819xU_cmdpkt.c @@ -294,7 +294,7 @@ static void cmpk_handle_query_config_rx(struct net_device *dev, u8 *pmsg) * windows OS. So we have to read the content byte by byte or transfer * endian type before copy the message copy. */ - rx_query_cfg.cfg_action = (pmsg[4] & 0x80000000) >> 31; + rx_query_cfg.cfg_action = (pmsg[4] & 0x80) >> 7; rx_query_cfg.cfg_type = (pmsg[4] & 0x60) >> 5; rx_query_cfg.cfg_size = (pmsg[4] & 0x18) >> 3; rx_query_cfg.cfg_page = (pmsg[6] & 0x0F) >> 0; diff --git a/drivers/staging/rtl8712/mlme_linux.c b/drivers/staging/rtl8712/mlme_linux.c index 20372659d15d..a077069d6227 100644 --- a/drivers/staging/rtl8712/mlme_linux.c +++ b/drivers/staging/rtl8712/mlme_linux.c @@ -111,8 +111,8 @@ void r8712_os_indicate_disconnect(struct _adapter *adapter) */ memcpy(&backupPMKIDList[0], - &adapter->securitypriv.PMKIDList[0], - sizeof(struct RT_PMKID_LIST) * NUM_PMKID_CACHE); + &adapter->securitypriv.PMKIDList[0], + sizeof(struct RT_PMKID_LIST) * NUM_PMKID_CACHE); backupPMKIDIndex = adapter->securitypriv.PMKIDIndex; backupTKIPCountermeasure = adapter->securitypriv.btkip_countermeasure; diff --git a/drivers/staging/rtl8712/rtl8712_cmd.c b/drivers/staging/rtl8712/rtl8712_cmd.c index 5346c657485d..0104aced113e 100644 --- a/drivers/staging/rtl8712/rtl8712_cmd.c +++ b/drivers/staging/rtl8712/rtl8712_cmd.c @@ -385,7 +385,7 @@ _next: if (blnPending) wr_sz += 8; /* Append 8 bytes */ r8712_write_mem(padapter, RTL8712_DMA_H2CCMD, wr_sz, - (u8 *)pdesc); + (u8 *)pdesc); pcmdpriv->cmd_seq++; if (pcmd->cmdcode == GEN_CMD_CODE(_CreateBss)) { pcmd->res = H2C_SUCCESS; diff --git a/drivers/staging/rtl8712/rtl8712_efuse.c b/drivers/staging/rtl8712/rtl8712_efuse.c index 205298e23656..d90213eb5e20 100644 --- a/drivers/staging/rtl8712/rtl8712_efuse.c +++ b/drivers/staging/rtl8712/rtl8712_efuse.c @@ -347,7 +347,7 @@ static u8 fix_header(struct _adapter *padapter, u8 header, u16 header_addr) ret = false; if (value == 0xFF) /* write again */ efuse_one_byte_write(padapter, addr, - pkt.data[i * 2]); + pkt.data[i * 2]); } if (!efuse_one_byte_read(padapter, addr + 1, &value)) { ret = false; diff --git a/drivers/staging/rtl8712/rtl8712_xmit.c b/drivers/staging/rtl8712/rtl8712_xmit.c index 7fe626583c8a..42d014007764 100644 --- a/drivers/staging/rtl8712/rtl8712_xmit.c +++ b/drivers/staging/rtl8712/rtl8712_xmit.c @@ -640,7 +640,7 @@ int r8712_xmitframe_complete(struct _adapter *padapter, /* 1st frame dequeued */ pxmitframe = dequeue_xframe_ex(pxmitpriv, phwxmits, hwentry); /* need to remember the 1st frame */ - if (pxmitframe != NULL) { + if (pxmitframe) { #ifdef CONFIG_R8712_TX_AGGR /* 1. dequeue 2nd frame @@ -653,13 +653,13 @@ int r8712_xmitframe_complete(struct _adapter *padapter, r8712_free_xmitbuf(pxmitpriv, pxmitbuf); return false; } - if (p2ndxmitframe != NULL) + if (p2ndxmitframe) if (p2ndxmitframe->frame_tag != DATA_FRAMETAG) { r8712_free_xmitbuf(pxmitpriv, pxmitbuf); return false; } r8712_xmitframe_aggr_1st(pxmitbuf, pxmitframe); - if (p2ndxmitframe != NULL) { + if (p2ndxmitframe) { u16 total_length; total_length = r8712_xmitframe_aggr_next( @@ -667,7 +667,7 @@ int r8712_xmitframe_complete(struct _adapter *padapter, do { p2ndxmitframe = dequeue_xframe_ex( pxmitpriv, phwxmits, hwentry); - if (p2ndxmitframe != NULL) + if (p2ndxmitframe) total_length = r8712_xmitframe_aggr_next( pxmitbuf, diff --git a/drivers/staging/rtl8712/usb_intf.c b/drivers/staging/rtl8712/usb_intf.c index 897d4621a5ce..b3e266bd57ab 100644 --- a/drivers/staging/rtl8712/usb_intf.c +++ b/drivers/staging/rtl8712/usb_intf.c @@ -47,7 +47,7 @@ static int r871xu_drv_init(struct usb_interface *pusb_intf, static void r871xu_dev_remove(struct usb_interface *pusb_intf); -static struct usb_device_id rtl871x_usb_id_tbl[] = { +static const struct usb_device_id rtl871x_usb_id_tbl[] = { /* RTL8188SU */ /* Realtek */ diff --git a/drivers/staging/rtl8723bs/core/rtw_btcoex.c b/drivers/staging/rtl8723bs/core/rtw_btcoex.c index 3c5cb78b52ea..01f78d1671de 100644 --- a/drivers/staging/rtl8723bs/core/rtw_btcoex.c +++ b/drivers/staging/rtl8723bs/core/rtw_btcoex.c @@ -55,7 +55,7 @@ void rtw_btcoex_ConnectNotify(struct adapter *padapter, u8 action) void rtw_btcoex_MediaStatusNotify(struct adapter *padapter, u8 mediaStatus) { - if ((RT_MEDIA_CONNECT == mediaStatus) + if ((mediaStatus == RT_MEDIA_CONNECT) && (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == true)) { rtw_hal_set_hwreg(padapter, HW_VAR_DL_RSVD_PAGE, NULL); } diff --git a/drivers/staging/rtl8723bs/core/rtw_cmd.c b/drivers/staging/rtl8723bs/core/rtw_cmd.c index 080c81b9aa94..d381827dba3b 100644 --- a/drivers/staging/rtl8723bs/core/rtw_cmd.c +++ b/drivers/staging/rtl8723bs/core/rtw_cmd.c @@ -432,7 +432,7 @@ int rtw_cmd_thread(void *context) unsigned long cmd_process_time; u8 (*cmd_hdl)(struct adapter *padapter, u8 *pbuf); void (*pcmd_callback)(struct adapter *dev, struct cmd_obj *pcmd); - struct adapter *padapter = (struct adapter *)context; + struct adapter *padapter = context; struct cmd_priv *pcmdpriv = &(padapter->cmdpriv); struct drvextra_cmd_parm *extra_parm = NULL; diff --git a/drivers/staging/rtl8723bs/core/rtw_efuse.c b/drivers/staging/rtl8723bs/core/rtw_efuse.c index 8e29802fc67f..44b92ef5db92 100644 --- a/drivers/staging/rtl8723bs/core/rtw_efuse.c +++ b/drivers/staging/rtl8723bs/core/rtw_efuse.c @@ -163,7 +163,7 @@ Efuse_CalculateWordCnts(u8 word_en) /* Description: */ /* 1. Execute E-Fuse read byte operation according as map offset and */ /* save to E-Fuse table. */ -/* 2. Refered from SD1 Richard. */ +/* 2. Referred from SD1 Richard. */ /* */ /* Assumption: */ /* 1. Boot from E-Fuse and successfully auto-load. */ diff --git a/drivers/staging/rtl8723bs/core/rtw_ioctl_set.c b/drivers/staging/rtl8723bs/core/rtw_ioctl_set.c index e0793f8d329d..d815a693fa64 100644 --- a/drivers/staging/rtl8723bs/core/rtw_ioctl_set.c +++ b/drivers/staging/rtl8723bs/core/rtw_ioctl_set.c @@ -127,7 +127,6 @@ u8 rtw_do_join(struct adapter *padapter) pibss = padapter->registrypriv.dev_network.MacAddress; - memset(&pdev_network->Ssid, 0, sizeof(struct ndis_802_11_ssid)); memcpy(&pdev_network->Ssid, &pmlmepriv->assoc_ssid, sizeof(struct ndis_802_11_ssid)); rtw_update_registrypriv_dev_network(padapter); diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme.c b/drivers/staging/rtl8723bs/core/rtw_mlme.c index d5ab12305e59..6b778206a1a3 100644 --- a/drivers/staging/rtl8723bs/core/rtw_mlme.c +++ b/drivers/staging/rtl8723bs/core/rtw_mlme.c @@ -922,7 +922,6 @@ void rtw_surveydone_event_callback(struct adapter *adapter, u8 *pbuf) RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("switching to adhoc master\n")); - memset(&pdev_network->Ssid, 0, sizeof(struct ndis_802_11_ssid)); memcpy(&pdev_network->Ssid, &pmlmepriv->assoc_ssid, sizeof(struct ndis_802_11_ssid)); rtw_update_registrypriv_dev_network(adapter); @@ -1384,7 +1383,7 @@ static void rtw_joinbss_update_network(struct adapter *padapter, struct wlan_net /* define REJOIN */ void rtw_joinbss_event_prehandle(struct adapter *adapter, u8 *pbuf) { - static u8 retry = 0; + static u8 retry; u8 timer_cancelled; struct sta_info *ptarget_sta = NULL, *pcur_sta = NULL; struct sta_priv *pstapriv = &adapter->stapriv; @@ -1774,7 +1773,6 @@ void rtw_stadel_event_callback(struct adapter *adapter, u8 *pbuf) memcpy(pdev_network, &tgt_network->network, get_wlan_bssid_ex_sz(&tgt_network->network)); - memset(&pdev_network->Ssid, 0, sizeof(struct ndis_802_11_ssid)); memcpy(&pdev_network->Ssid, &pmlmepriv->assoc_ssid, sizeof(struct ndis_802_11_ssid)); rtw_update_registrypriv_dev_network(adapter); @@ -2498,8 +2496,7 @@ sint rtw_restruct_sec_ie(struct adapter *adapter, u8 *in_ie, u8 *out_ie, uint in uint ndisauthmode = psecuritypriv->ndisauthtype; RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, - ("+rtw_restruct_sec_ie: ndisauthmode =%d ndissecuritytype =%d\n", - ndisauthmode, ndissecuritytype)); + ("+rtw_restruct_sec_ie: ndisauthmode =%d\n", ndisauthmode)); /* copy fixed ie only */ memcpy(out_ie, in_ie, 12); diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c index 17d881d66910..b6d137f505e1 100644 --- a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c +++ b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c @@ -1228,7 +1228,7 @@ unsigned int OnAssocReq(struct adapter *padapter, union recv_frame *precv_frame) } pstat = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe)); - if (pstat == (struct sta_info *)NULL) { + if (pstat == NULL) { status = _RSON_CLS2_; goto asoc_class2_error; } @@ -2392,7 +2392,7 @@ s32 dump_mgntframe_and_wait(struct adapter *padapter, struct xmit_frame *pmgntfr s32 dump_mgntframe_and_wait_ack(struct adapter *padapter, struct xmit_frame *pmgntframe) { - static u8 seq_no = 0; + static u8 seq_no; s32 ret = _FAIL; u32 timeout_ms = 500;/* 500ms */ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; diff --git a/drivers/staging/rtl8723bs/core/rtw_odm.c b/drivers/staging/rtl8723bs/core/rtw_odm.c index 3144e8ec2fa2..edbcaeb9f8c2 100644 --- a/drivers/staging/rtl8723bs/core/rtw_odm.c +++ b/drivers/staging/rtl8723bs/core/rtw_odm.c @@ -18,7 +18,7 @@ #include <rtw_odm.h> #include <hal_data.h> -static const char *odm_comp_str[] = { +static const char * const odm_comp_str[] = { /* BIT0 */"ODM_COMP_DIG", /* BIT1 */"ODM_COMP_RA_MASK", /* BIT2 */"ODM_COMP_DYNAMIC_TXPWR", @@ -55,7 +55,7 @@ static const char *odm_comp_str[] = { #define RTW_ODM_COMP_MAX 32 -static const char *odm_ability_str[] = { +static const char * const odm_ability_str[] = { /* BIT0 */"ODM_BB_DIG", /* BIT1 */"ODM_BB_RA_MASK", /* BIT2 */"ODM_BB_DYNAMIC_TXPWR", @@ -87,7 +87,7 @@ static const char *odm_ability_str[] = { #define RTW_ODM_ABILITY_MAX 27 -static const char *odm_dbg_level_str[] = { +static const char * const odm_dbg_level_str[] = { NULL, "ODM_DBG_OFF", "ODM_DBG_SERIOUS", @@ -127,7 +127,8 @@ void rtw_odm_dbg_level_msg(void *sel, struct adapter *adapter) DBG_871X_SEL_NL(sel, "odm.DebugLevel = %u\n", dbg_level); for (i = 0; i < RTW_ODM_DBG_LEVEL_NUM; i++) { if (odm_dbg_level_str[i]) - DBG_871X_SEL_NL(sel, "%u %s\n", i, odm_dbg_level_str[i]); + DBG_871X_SEL_NL(sel, "%u %s\n", + i, odm_dbg_level_str[i]); } } @@ -161,20 +162,23 @@ void rtw_odm_adaptivity_parm_msg(void *sel, struct adapter *adapter) struct hal_com_data *pHalData = GET_HAL_DATA(adapter); DM_ODM_T *odm = &pHalData->odmpriv; - DBG_871X_SEL_NL(sel, "%10s %16s %8s %10s %11s %14s\n" - , "TH_L2H_ini", "TH_EDCCA_HL_diff", "IGI_Base", "ForceEDCCA", "AdapEn_RSSI", "IGI_LowerBound"); - DBG_871X_SEL_NL(sel, "0x%-8x %-16d 0x%-6x %-10d %-11u %-14u\n" - , (u8)odm->TH_L2H_ini - , odm->TH_EDCCA_HL_diff - , odm->IGI_Base - , odm->ForceEDCCA - , odm->AdapEn_RSSI - , odm->IGI_LowerBound + DBG_871X_SEL_NL(sel, "%10s %16s %8s %10s %11s %14s\n", + "TH_L2H_ini", "TH_EDCCA_HL_diff", "IGI_Base", + "ForceEDCCA", "AdapEn_RSSI", "IGI_LowerBound"); + DBG_871X_SEL_NL(sel, "0x%-8x %-16d 0x%-6x %-10d %-11u %-14u\n", + (u8)odm->TH_L2H_ini, + odm->TH_EDCCA_HL_diff, + odm->IGI_Base, + odm->ForceEDCCA, + odm->AdapEn_RSSI, + odm->IGI_LowerBound ); } -void rtw_odm_adaptivity_parm_set(struct adapter *adapter, s8 TH_L2H_ini, s8 TH_EDCCA_HL_diff, - s8 IGI_Base, bool ForceEDCCA, u8 AdapEn_RSSI, u8 IGI_LowerBound) +void rtw_odm_adaptivity_parm_set(struct adapter *adapter, s8 TH_L2H_ini, + s8 TH_EDCCA_HL_diff, s8 IGI_Base, + bool ForceEDCCA, u8 AdapEn_RSSI, + u8 IGI_LowerBound) { struct hal_com_data *pHalData = GET_HAL_DATA(adapter); DM_ODM_T *odm = &pHalData->odmpriv; @@ -190,8 +194,8 @@ void rtw_odm_adaptivity_parm_set(struct adapter *adapter, s8 TH_L2H_ini, s8 TH_E void rtw_odm_get_perpkt_rssi(void *sel, struct adapter *adapter) { struct hal_com_data *hal_data = GET_HAL_DATA(adapter); - DM_ODM_T *odm = &(hal_data->odmpriv); + DM_ODM_T *odm = &hal_data->odmpriv; DBG_871X_SEL_NL(sel, "RxRate = %s, RSSI_A = %d(%%), RSSI_B = %d(%%)\n", - HDATA_RATE(odm->RxRate), odm->RSSI_A, odm->RSSI_B); + HDATA_RATE(odm->RxRate), odm->RSSI_A, odm->RSSI_B); } diff --git a/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c b/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c index f708dbf5bfd4..aabdaafcbdd3 100644 --- a/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c +++ b/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c @@ -210,8 +210,8 @@ void pwr_state_check_handler(RTW_TIMER_HDL_ARGS) void traffic_check_for_leave_lps(struct adapter *padapter, u8 tx, u32 tx_packets) { - static unsigned long start_time = 0; - static u32 xmit_cnt = 0; + static unsigned long start_time; + static u32 xmit_cnt; u8 bLeaveLPS = false; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; @@ -829,7 +829,7 @@ static void pwr_rpwm_timeout_handler(void *FunctionContext) struct pwrctrl_priv *pwrpriv; - padapter = (struct adapter *)FunctionContext; + padapter = FunctionContext; pwrpriv = adapter_to_pwrctl(padapter); DBG_871X("+%s: rpwm = 0x%02X cpwm = 0x%02X\n", __func__, pwrpriv->rpwm, pwrpriv->cpwm); diff --git a/drivers/staging/rtl8723bs/core/rtw_recv.c b/drivers/staging/rtl8723bs/core/rtw_recv.c index 695a5c958c80..68a6303e2754 100644 --- a/drivers/staging/rtl8723bs/core/rtw_recv.c +++ b/drivers/staging/rtl8723bs/core/rtw_recv.c @@ -1005,7 +1005,7 @@ sint ap2sta_data_frame( if (*psta == NULL) { /* for AP multicast issue , modify by yiwei */ - static unsigned long send_issue_deauth_time = 0; + static unsigned long send_issue_deauth_time; /* DBG_871X("After send deauth , %u ms has elapsed.\n", jiffies_to_msecs(jiffies - send_issue_deauth_time)); */ @@ -2360,7 +2360,7 @@ _err_exit: void rtw_reordering_ctrl_timeout_handler(void *pcontext) { - struct recv_reorder_ctrl *preorder_ctrl = (struct recv_reorder_ctrl *)pcontext; + struct recv_reorder_ctrl *preorder_ctrl = pcontext; struct adapter *padapter = preorder_ctrl->padapter; struct __queue *ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue; diff --git a/drivers/staging/rtl8723bs/core/rtw_security.c b/drivers/staging/rtl8723bs/core/rtw_security.c index e832f16997b7..06a7e4059fbb 100644 --- a/drivers/staging/rtl8723bs/core/rtw_security.c +++ b/drivers/staging/rtl8723bs/core/rtw_security.c @@ -162,7 +162,7 @@ static void arcfour_encrypt( dest[i] = src[i] ^ (unsigned char)arcfour_byte(parc4ctx); } -static sint bcrc32initialized = 0; +static sint bcrc32initialized; static u32 crc32_table[256]; @@ -791,9 +791,9 @@ u32 rtw_tkip_decrypt(struct adapter *padapter, u8 *precvframe) stainfo = rtw_get_stainfo(&padapter->stapriv, &prxattrib->ta[0]); if (stainfo != NULL) { if (IS_MCAST(prxattrib->ra)) { - static unsigned long start = 0; - static u32 no_gkey_bc_cnt = 0; - static u32 no_gkey_mc_cnt = 0; + static unsigned long start; + static u32 no_gkey_bc_cnt; + static u32 no_gkey_mc_cnt; if (psecuritypriv->binstallGrpkey == false) { res = _FAIL; @@ -1882,9 +1882,9 @@ u32 rtw_aes_decrypt(struct adapter *padapter, u8 *precvframe) RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_aes_decrypt: stainfo!= NULL!!!\n")); if (IS_MCAST(prxattrib->ra)) { - static unsigned long start = 0; - static u32 no_gkey_bc_cnt = 0; - static u32 no_gkey_mc_cnt = 0; + static unsigned long start; + static u32 no_gkey_bc_cnt; + static u32 no_gkey_mc_cnt; /* DBG_871X("rx bc/mc packets, to perform sw rtw_aes_decrypt\n"); */ /* prwskey = psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey; */ diff --git a/drivers/staging/rtl8723bs/core/rtw_xmit.c b/drivers/staging/rtl8723bs/core/rtw_xmit.c index 8f2c9a6658bf..022f654419e4 100644 --- a/drivers/staging/rtl8723bs/core/rtw_xmit.c +++ b/drivers/staging/rtl8723bs/core/rtw_xmit.c @@ -2301,8 +2301,8 @@ static void do_queue_select(struct adapter *padapter, struct pkt_attrib *pattrib */ s32 rtw_xmit(struct adapter *padapter, _pkt **ppkt) { - static unsigned long start = 0; - static u32 drop_cnt = 0; + static unsigned long start; + static u32 drop_cnt; struct xmit_priv *pxmitpriv = &padapter->xmitpriv; struct xmit_frame *pxmitframe = NULL; @@ -3002,7 +3002,7 @@ int rtw_xmit_thread(void *context) err = _SUCCESS; - padapter = (struct adapter *)context; + padapter = context; thread_enter("RTW_XMIT_THREAD"); diff --git a/drivers/staging/rtl8723bs/hal/hal_btcoex.c b/drivers/staging/rtl8723bs/hal/hal_btcoex.c index 9e08a4de4895..86fee109e42d 100644 --- a/drivers/staging/rtl8723bs/hal/hal_btcoex.c +++ b/drivers/staging/rtl8723bs/hal/hal_btcoex.c @@ -419,10 +419,10 @@ static u8 halbtcoutsrc_Get(void *pBtcContext, u8 getType, void *pOutBuf) padapter = pBtCoexist->Adapter; pHalData = GET_HAL_DATA(padapter); mlmeext = &padapter->mlmeextpriv; - pu8 = (u8 *)pOutBuf; - pS4Tmp = (s32 *)pOutBuf; - pU4Tmp = (u32 *)pOutBuf; - pU1Tmp = (u8 *)pOutBuf; + pu8 = pOutBuf; + pS4Tmp = pOutBuf; + pU4Tmp = pOutBuf; + pU1Tmp = pOutBuf; ret = true; switch (getType) { @@ -585,9 +585,9 @@ static u8 halbtcoutsrc_Set(void *pBtcContext, u8 setType, void *pInBuf) pBtCoexist = (PBTC_COEXIST)pBtcContext; padapter = pBtCoexist->Adapter; pHalData = GET_HAL_DATA(padapter); - pu8 = (u8 *)pInBuf; - pU1Tmp = (u8 *)pInBuf; - pU4Tmp = (u32 *)pInBuf; + pu8 = pInBuf; + pU1Tmp = pInBuf; + pU4Tmp = pInBuf; ret = true; if (!halbtcoutsrc_IsBtCoexistAvailable(pBtCoexist)) diff --git a/drivers/staging/rtl8723bs/hal/hal_com.c b/drivers/staging/rtl8723bs/hal/hal_com.c index e3a98322f475..3e63b6d9c097 100644 --- a/drivers/staging/rtl8723bs/hal/hal_com.c +++ b/drivers/staging/rtl8723bs/hal/hal_com.c @@ -1311,7 +1311,7 @@ void SetHalODMVar( switch (eVariable) { case HAL_ODM_STA_INFO: { - struct sta_info *psta = (struct sta_info *)pValue1; + struct sta_info *psta = pValue1; if (bSet) { DBG_8192C("### Set STA_(%d) info ###\n", psta->mac_id); ODM_CmnInfoPtrArrayHook(podmpriv, ODM_CMNINFO_STA_STATUS, psta->mac_id, psta); @@ -1333,7 +1333,7 @@ void SetHalODMVar( #if defined(CONFIG_SIGNAL_DISPLAY_DBM) && defined(CONFIG_BACKGROUND_NOISE_MONITOR) case HAL_ODM_NOISE_MONITOR: { - struct noise_info *pinfo = (struct noise_info *)pValue1; + struct noise_info *pinfo = pValue1; #ifdef DBG_NOISE_MONITOR DBG_8192C("### Noise monitor chan(%d)-bPauseDIG:%d, IGIValue:0x%02x, max_time:%d (ms) ###\n", diff --git a/drivers/staging/rtl8723bs/hal/odm.c b/drivers/staging/rtl8723bs/hal/odm.c index 2dbf19971e04..ff43bb26950b 100644 --- a/drivers/staging/rtl8723bs/hal/odm.c +++ b/drivers/staging/rtl8723bs/hal/odm.c @@ -592,95 +592,95 @@ void ODM_CmnInfoHook(PDM_ODM_T pDM_Odm, ODM_CMNINFO_E CmnInfo, void *pValue) /* Dynamic call by reference pointer. */ /* */ case ODM_CMNINFO_MAC_PHY_MODE: - pDM_Odm->pMacPhyMode = (u8 *)pValue; + pDM_Odm->pMacPhyMode = pValue; break; case ODM_CMNINFO_TX_UNI: - pDM_Odm->pNumTxBytesUnicast = (u64 *)pValue; + pDM_Odm->pNumTxBytesUnicast = pValue; break; case ODM_CMNINFO_RX_UNI: - pDM_Odm->pNumRxBytesUnicast = (u64 *)pValue; + pDM_Odm->pNumRxBytesUnicast = pValue; break; case ODM_CMNINFO_WM_MODE: - pDM_Odm->pwirelessmode = (u8 *)pValue; + pDM_Odm->pwirelessmode = pValue; break; case ODM_CMNINFO_BAND: - pDM_Odm->pBandType = (u8 *)pValue; + pDM_Odm->pBandType = pValue; break; case ODM_CMNINFO_SEC_CHNL_OFFSET: - pDM_Odm->pSecChOffset = (u8 *)pValue; + pDM_Odm->pSecChOffset = pValue; break; case ODM_CMNINFO_SEC_MODE: - pDM_Odm->pSecurity = (u8 *)pValue; + pDM_Odm->pSecurity = pValue; break; case ODM_CMNINFO_BW: - pDM_Odm->pBandWidth = (u8 *)pValue; + pDM_Odm->pBandWidth = pValue; break; case ODM_CMNINFO_CHNL: - pDM_Odm->pChannel = (u8 *)pValue; + pDM_Odm->pChannel = pValue; break; case ODM_CMNINFO_DMSP_GET_VALUE: - pDM_Odm->pbGetValueFromOtherMac = (bool *)pValue; + pDM_Odm->pbGetValueFromOtherMac = pValue; break; case ODM_CMNINFO_BUDDY_ADAPTOR: - pDM_Odm->pBuddyAdapter = (struct adapter **)pValue; + pDM_Odm->pBuddyAdapter = pValue; break; case ODM_CMNINFO_DMSP_IS_MASTER: - pDM_Odm->pbMasterOfDMSP = (bool *)pValue; + pDM_Odm->pbMasterOfDMSP = pValue; break; case ODM_CMNINFO_SCAN: - pDM_Odm->pbScanInProcess = (bool *)pValue; + pDM_Odm->pbScanInProcess = pValue; break; case ODM_CMNINFO_POWER_SAVING: - pDM_Odm->pbPowerSaving = (bool *)pValue; + pDM_Odm->pbPowerSaving = pValue; break; case ODM_CMNINFO_ONE_PATH_CCA: - pDM_Odm->pOnePathCCA = (u8 *)pValue; + pDM_Odm->pOnePathCCA = pValue; break; case ODM_CMNINFO_DRV_STOP: - pDM_Odm->pbDriverStopped = (bool *)pValue; + pDM_Odm->pbDriverStopped = pValue; break; case ODM_CMNINFO_PNP_IN: - pDM_Odm->pbDriverIsGoingToPnpSetPowerSleep = (bool *)pValue; + pDM_Odm->pbDriverIsGoingToPnpSetPowerSleep = pValue; break; case ODM_CMNINFO_INIT_ON: - pDM_Odm->pinit_adpt_in_progress = (bool *)pValue; + pDM_Odm->pinit_adpt_in_progress = pValue; break; case ODM_CMNINFO_ANT_TEST: - pDM_Odm->pAntennaTest = (u8 *)pValue; + pDM_Odm->pAntennaTest = pValue; break; case ODM_CMNINFO_NET_CLOSED: - pDM_Odm->pbNet_closed = (bool *)pValue; + pDM_Odm->pbNet_closed = pValue; break; case ODM_CMNINFO_FORCED_RATE: - pDM_Odm->pForcedDataRate = (u16 *)pValue; + pDM_Odm->pForcedDataRate = pValue; break; case ODM_CMNINFO_FORCED_IGI_LB: - pDM_Odm->pu1ForcedIgiLb = (u8 *)pValue; + pDM_Odm->pu1ForcedIgiLb = pValue; break; case ODM_CMNINFO_MP_MODE: - pDM_Odm->mp_mode = (u8 *)pValue; + pDM_Odm->mp_mode = pValue; break; /* case ODM_CMNINFO_RTSTA_AID: */ diff --git a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c index 84a89ef74169..1565f2d67ea4 100644 --- a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c +++ b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c @@ -63,7 +63,7 @@ static int _BlockWrite(struct adapter *padapter, void *buffer, u32 buffSize) u32 blockSize_p3 = 1; /* Phase #3 : Use 1-byte, the remnant of FW image. */ u32 blockCount_p1 = 0, blockCount_p2 = 0, blockCount_p3 = 0; u32 remainSize_p1 = 0, remainSize_p2 = 0; - u8 *bufferPtr = (u8 *)buffer; + u8 *bufferPtr = buffer; u32 i = 0, offset = 0; /* printk("====>%s %d\n", __func__, __LINE__); */ @@ -163,7 +163,7 @@ static int _WriteFW(struct adapter *padapter, void *buffer, u32 size) int ret = _SUCCESS; u32 pageNums, remainSize; u32 page, offset; - u8 *bufferPtr = (u8 *)buffer; + u8 *bufferPtr = buffer; pageNums = size / MAX_DLFW_PAGE_SIZE; /* RT_ASSERT((pageNums <= 4), ("Page numbers should not greater then 4\n")); */ @@ -643,7 +643,7 @@ static void Hal_GetEfuseDefinition( case TYPE_EFUSE_MAX_SECTION: { u8 *pMax_section; - pMax_section = (u8 *)pOut; + pMax_section = pOut; if (efuseType == EFUSE_WIFI) *pMax_section = EFUSE_MAX_SECTION_8723B; @@ -655,7 +655,7 @@ static void Hal_GetEfuseDefinition( case TYPE_EFUSE_REAL_CONTENT_LEN: { u16 *pu2Tmp; - pu2Tmp = (u16 *)pOut; + pu2Tmp = pOut; if (efuseType == EFUSE_WIFI) *pu2Tmp = EFUSE_REAL_CONTENT_LEN_8723B; @@ -667,7 +667,7 @@ static void Hal_GetEfuseDefinition( case TYPE_AVAILABLE_EFUSE_BYTES_BANK: { u16 *pu2Tmp; - pu2Tmp = (u16 *)pOut; + pu2Tmp = pOut; if (efuseType == EFUSE_WIFI) *pu2Tmp = (EFUSE_REAL_CONTENT_LEN_8723B-EFUSE_OOB_PROTECT_BYTES); @@ -679,7 +679,7 @@ static void Hal_GetEfuseDefinition( case TYPE_AVAILABLE_EFUSE_BYTES_TOTAL: { u16 *pu2Tmp; - pu2Tmp = (u16 *)pOut; + pu2Tmp = pOut; if (efuseType == EFUSE_WIFI) *pu2Tmp = (EFUSE_REAL_CONTENT_LEN_8723B-EFUSE_OOB_PROTECT_BYTES); @@ -691,7 +691,7 @@ static void Hal_GetEfuseDefinition( case TYPE_EFUSE_MAP_LEN: { u16 *pu2Tmp; - pu2Tmp = (u16 *)pOut; + pu2Tmp = pOut; if (efuseType == EFUSE_WIFI) *pu2Tmp = EFUSE_MAX_MAP_LEN; @@ -703,7 +703,7 @@ static void Hal_GetEfuseDefinition( case TYPE_EFUSE_PROTECT_BYTES_BANK: { u8 *pu1Tmp; - pu1Tmp = (u8 *)pOut; + pu1Tmp = pOut; if (efuseType == EFUSE_WIFI) *pu1Tmp = EFUSE_OOB_PROTECT_BYTES; @@ -715,7 +715,7 @@ static void Hal_GetEfuseDefinition( case TYPE_EFUSE_CONTENT_LEN_BANK: { u16 *pu2Tmp; - pu2Tmp = (u16 *)pOut; + pu2Tmp = pOut; if (efuseType == EFUSE_WIFI) *pu2Tmp = EFUSE_REAL_CONTENT_LEN_8723B; @@ -727,7 +727,7 @@ static void Hal_GetEfuseDefinition( default: { u8 *pu1Tmp; - pu1Tmp = (u8 *)pOut; + pu1Tmp = pOut; *pu1Tmp = 0; } break; diff --git a/drivers/staging/rtl8723bs/hal/rtl8723b_rxdesc.c b/drivers/staging/rtl8723bs/hal/rtl8723b_rxdesc.c index 92e5a0e7aa59..14bfbe3be0ca 100644 --- a/drivers/staging/rtl8723bs/hal/rtl8723b_rxdesc.c +++ b/drivers/staging/rtl8723bs/hal/rtl8723b_rxdesc.c @@ -64,7 +64,7 @@ static void process_link_qual(struct adapter *padapter, union recv_frame *prfram void rtl8723b_process_phy_info(struct adapter *padapter, void *prframe) { - union recv_frame *precvframe = (union recv_frame *)prframe; + union recv_frame *precvframe = prframe; /* */ /* Check RSSI */ /* */ diff --git a/drivers/staging/rtl8723bs/hal/rtl8723bs_recv.c b/drivers/staging/rtl8723bs/hal/rtl8723bs_recv.c index b002eb446b2c..d9a4567ca721 100644 --- a/drivers/staging/rtl8723bs/hal/rtl8723bs_recv.c +++ b/drivers/staging/rtl8723bs/hal/rtl8723bs_recv.c @@ -190,7 +190,7 @@ static void rtl8723bs_recv_tasklet(void *priv) u8 shift_sz = 0, rx_report_sz = 0; - padapter = (struct adapter *)priv; + padapter = priv; pHalData = GET_HAL_DATA(padapter); precvpriv = &padapter->recvpriv; diff --git a/drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c b/drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c index 9bee2e40be32..d0b317077511 100644 --- a/drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c +++ b/drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c @@ -490,7 +490,7 @@ int rtl8723bs_xmit_thread(void *context) ret = _SUCCESS; - padapter = (struct adapter *)context; + padapter = context; pxmitpriv = &padapter->xmitpriv; rtw_sprintf(thread_name, 20, "%s-"ADPT_FMT, thread_name, ADPT_ARG(padapter)); diff --git a/drivers/staging/rtl8723bs/hal/sdio_ops.c b/drivers/staging/rtl8723bs/hal/sdio_ops.c index 6285b72faa9a..1d1b14dedd35 100644 --- a/drivers/staging/rtl8723bs/hal/sdio_ops.c +++ b/drivers/staging/rtl8723bs/hal/sdio_ops.c @@ -1121,7 +1121,7 @@ void sd_int_dpc(struct adapter *padapter) } } else { /* Error handling for malloc fail */ - if (rtw_cbuf_push(padapter->evtpriv.c2h_queue, (void *)NULL) != _SUCCESS) + if (rtw_cbuf_push(padapter->evtpriv.c2h_queue, NULL) != _SUCCESS) DBG_871X("%s rtw_cbuf_push fail\n", __func__); _set_workitem(&padapter->evtpriv.c2h_wk); } diff --git a/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c b/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c index 79d8383d4b9b..d5e5f830f2a1 100644 --- a/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c +++ b/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c @@ -19,7 +19,7 @@ #include <rtw_mp.h> #include <linux/jiffies.h> -#define RTL_IOCTL_WPA_SUPPLICANT SIOCIWFIRSTPRIV+30 +#define RTL_IOCTL_WPA_SUPPLICANT (SIOCIWFIRSTPRIV+30) #define SCAN_ITEM_SIZE 768 #define MAX_CUSTOM_LEN 64 @@ -44,8 +44,7 @@ extern u8 key_2char2num(u8 hch, u8 lch); static u32 rtw_rates[] = {1000000, 2000000, 5500000, 11000000, 6000000, 9000000, 12000000, 18000000, 24000000, 36000000, 48000000, 54000000}; -static const char * const iw_operation_mode[] = -{ +static const char * const iw_operation_mode[] = { "Auto", "Ad-Hoc", "Managed", "Master", "Repeater", "Secondary", "Monitor" }; @@ -190,16 +189,12 @@ static char *translate_scan(struct adapter *padapter, start = iwe_stream_add_point(info, start, stop, &iwe, pnetwork->network.Ssid.Ssid); /* parsing HT_CAP_IE */ - if (pnetwork->network.Reserved[0] == 2) /* Probe Request */ - { + if (pnetwork->network.Reserved[0] == 2) { /* Probe Request */ p = rtw_get_ie(&pnetwork->network.IEs[0], _HT_CAPABILITY_IE_, &ht_ielen, pnetwork->network.IELength); - } - else - { + } else { p = rtw_get_ie(&pnetwork->network.IEs[12], _HT_CAPABILITY_IE_, &ht_ielen, pnetwork->network.IELength-12); } - if (p && ht_ielen>0) - { + if (p && ht_ielen>0) { struct rtw_ieee80211_ht_cap *pht_capie; ht_cap = true; pht_capie = (struct rtw_ieee80211_ht_cap *)(p+2); @@ -210,33 +205,25 @@ static char *translate_scan(struct adapter *padapter, /* Add the protocol name */ iwe.cmd = SIOCGIWNAME; - if ((rtw_is_cckratesonly_included((u8 *)&pnetwork->network.SupportedRates)) == true) - { + if ((rtw_is_cckratesonly_included((u8 *)&pnetwork->network.SupportedRates)) == true) { if (ht_cap == true) snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11bn"); else snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11b"); - } - else if ((rtw_is_cckrates_included((u8 *)&pnetwork->network.SupportedRates)) == true) - { + } else if ((rtw_is_cckrates_included((u8 *)&pnetwork->network.SupportedRates)) == true) { if (ht_cap == true) snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11bgn"); else snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11bg"); - } - else - { - if (pnetwork->network.Configuration.DSConfig > 14) - { + } else { + if (pnetwork->network.Configuration.DSConfig > 14) { if (vht_cap == true) snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11AC"); else if (ht_cap == true) snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11an"); else snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11a"); - } - else - { + } else { if (ht_cap == true) snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11gn"); else @@ -247,12 +234,9 @@ static char *translate_scan(struct adapter *padapter, start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_CHAR_LEN); /* Add mode */ - if (pnetwork->network.Reserved[0] == 2) /* Probe Request */ - { + if (pnetwork->network.Reserved[0] == 2) { /* Probe Request */ cap = 0; - } - else - { + } else { __le16 le_tmp; iwe.cmd = SIOCGIWMODE; @@ -295,8 +279,7 @@ static char *translate_scan(struct adapter *padapter, return start; p = custom; p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Rates (Mb/s): "); - while (pnetwork->network.SupportedRates[i]!= 0) - { + while (pnetwork->network.SupportedRates[i]!= 0) { rate = pnetwork->network.SupportedRates[i]&0x7F; if (rate > max_rate) max_rate = rate; @@ -307,20 +290,12 @@ static char *translate_scan(struct adapter *padapter, if (vht_cap == true) { max_rate = vht_data_rate; - } - else if (ht_cap == true) - { - if (mcs_rate&0x8000)/* MCS15 */ - { + } else if (ht_cap == true) { + if (mcs_rate&0x8000) { /* MCS15 */ max_rate = (bw_40MHz) ? ((short_GI)?300:270):((short_GI)?144:130); - - } - else if (mcs_rate&0x0080)/* MCS7 */ - { + } else if (mcs_rate&0x0080) { /* MCS7 */ max_rate = (bw_40MHz) ? ((short_GI)?150:135):((short_GI)?72:65); - } - else/* default MCS7 */ - { + } else { /* default MCS7 */ /* DBG_871X("wx_get_scan, mcs_rate_bitmap = 0x%x\n", mcs_rate); */ max_rate = (bw_40MHz) ? ((short_GI)?150:135):((short_GI)?72:65); } @@ -334,8 +309,7 @@ static char *translate_scan(struct adapter *padapter, start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_PARAM_LEN); /* parsing WPA/WPA2 IE */ - if (pnetwork->network.Reserved[0] != 2) /* Probe Request */ - { + if (pnetwork->network.Reserved[0] != 2) { /* Probe Request */ u8 *buf; u8 wpa_ie[255], rsn_ie[255]; u16 wpa_len = 0, rsn_len = 0; @@ -351,15 +325,13 @@ static char *translate_scan(struct adapter *padapter, if (wpa_len > 0) { p =buf; p += sprintf(p, "wpa_ie ="); - for (i = 0; i < wpa_len; i++) { + for (i = 0; i < wpa_len; i++) p += sprintf(p, "%02x", wpa_ie[i]); - } if (wpa_len > 100) { printk("-----------------Len %d----------------\n", wpa_len); - for (i = 0; i < wpa_len; i++) { + for (i = 0; i < wpa_len; i++) printk("%02x ", wpa_ie[i]); - } printk("\n"); printk("-----------------Len %d----------------\n", wpa_len); } @@ -401,21 +373,16 @@ static char *translate_scan(struct adapter *padapter, u8 *ie_ptr = pnetwork->network.IEs + ie_offset; total_ielen = pnetwork->network.IELength - ie_offset; - if (pnetwork->network.Reserved[0] == 2) /* Probe Request */ - { + if (pnetwork->network.Reserved[0] == 2) { /* Probe Request */ ie_ptr = pnetwork->network.IEs; total_ielen = pnetwork->network.IELength; - } - else /* Beacon or Probe Respones */ - { + } else { /* Beacon or Probe Respones */ ie_ptr = pnetwork->network.IEs + _FIXED_IE_LENGTH_; total_ielen = pnetwork->network.IELength - _FIXED_IE_LENGTH_; } - while (cnt < total_ielen) - { - if (rtw_is_wps_ie(&ie_ptr[cnt], &wps_ielen) && (wps_ielen>2)) - { + while (cnt < total_ielen) { + if (rtw_is_wps_ie(&ie_ptr[cnt], &wps_ielen) && (wps_ielen>2)) { wpsie_ptr = &ie_ptr[cnt]; iwe.cmd =IWEVGENIE; iwe.u.data.length = (u16)wps_ielen; @@ -507,38 +474,27 @@ static int wpa_set_auth_algs(struct net_device *dev, u32 value) struct adapter *padapter = (struct adapter *) rtw_netdev_priv(dev); int ret = 0; - if ((value & AUTH_ALG_SHARED_KEY) && (value & AUTH_ALG_OPEN_SYSTEM)) - { + if ((value & AUTH_ALG_SHARED_KEY) && (value & AUTH_ALG_OPEN_SYSTEM)) { DBG_871X("wpa_set_auth_algs, AUTH_ALG_SHARED_KEY and AUTH_ALG_OPEN_SYSTEM [value:0x%x]\n", value); padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeAutoSwitch; padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Auto; - } - else if (value & AUTH_ALG_SHARED_KEY) - { + } else if (value & AUTH_ALG_SHARED_KEY) { DBG_871X("wpa_set_auth_algs, AUTH_ALG_SHARED_KEY [value:0x%x]\n", value); padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeShared; padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Shared; - } - else if (value & AUTH_ALG_OPEN_SYSTEM) - { + } else if (value & AUTH_ALG_OPEN_SYSTEM) { DBG_871X("wpa_set_auth_algs, AUTH_ALG_OPEN_SYSTEM\n"); /* padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled; */ - if (padapter->securitypriv.ndisauthtype < Ndis802_11AuthModeWPAPSK) - { + if (padapter->securitypriv.ndisauthtype < Ndis802_11AuthModeWPAPSK) { padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeOpen; padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Open; } - - } - else if (value & AUTH_ALG_LEAP) - { + } else if (value & AUTH_ALG_LEAP) { DBG_871X("wpa_set_auth_algs, AUTH_ALG_LEAP\n"); - } - else - { + } else { DBG_871X("wpa_set_auth_algs, error!\n"); ret = -EINVAL; } @@ -559,33 +515,27 @@ static int wpa_set_encryption(struct net_device *dev, struct ieee_param *param, param->u.crypt.err = 0; param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0'; - if (param_len < (u32) ((u8 *) param->u.crypt.key - (u8 *) param) + param->u.crypt.key_len) - { + if (param_len < (u32) ((u8 *) param->u.crypt.key - (u8 *) param) + param->u.crypt.key_len) { ret = -EINVAL; goto exit; } if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff && param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && - param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) - { - + param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) { if (param->u.crypt.idx >= WEP_KEYS || param->u.crypt.idx >= BIP_MAX_KEYID) { ret = -EINVAL; goto exit; } - } - else - { + } else { { ret = -EINVAL; goto exit; } } - if (strcmp(param->u.crypt.alg, "WEP") == 0) - { + if (strcmp(param->u.crypt.alg, "WEP") == 0) { RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_err_, ("wpa_set_encryption, crypt.alg = WEP\n")); DBG_871X("wpa_set_encryption, crypt.alg = WEP\n"); @@ -604,8 +554,7 @@ static int wpa_set_encryption(struct net_device *dev, struct ieee_param *param, RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, ("(2)wep_key_idx =%d\n", wep_key_idx)); - if (wep_key_len > 0) - { + if (wep_key_len > 0) { wep_key_len = wep_key_len <= 5 ? 5 : 13; wep_total_len = wep_key_len + FIELD_OFFSET(struct ndis_802_11_wep, KeyMaterial); pwep =(struct ndis_802_11_wep *) rtw_malloc(wep_total_len); @@ -619,13 +568,11 @@ static int wpa_set_encryption(struct net_device *dev, struct ieee_param *param, pwep->KeyLength = wep_key_len; pwep->Length = wep_total_len; - if (wep_key_len == 13) - { + if (wep_key_len == 13) { padapter->securitypriv.dot11PrivacyAlgrthm = _WEP104_; padapter->securitypriv.dot118021XGrpPrivacy = _WEP104_; } - } - else { + } else { ret = -EINVAL; goto exit; } @@ -635,17 +582,12 @@ static int wpa_set_encryption(struct net_device *dev, struct ieee_param *param, memcpy(pwep->KeyMaterial, param->u.crypt.key, pwep->KeyLength); - if (param->u.crypt.set_tx) - { + if (param->u.crypt.set_tx) { DBG_871X("wep, set_tx = 1\n"); if (rtw_set_802_11_add_wep(padapter, pwep) == (u8)_FAIL) - { ret = -EOPNOTSUPP ; - } - } - else - { + } else { DBG_871X("wep, set_tx = 0\n"); /* don't update "psecuritypriv->dot11PrivacyAlgrthm" and */ @@ -664,35 +606,28 @@ static int wpa_set_encryption(struct net_device *dev, struct ieee_param *param, goto exit; } - if (padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) /* 802_1x */ - { + if (padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) { /* 802_1x */ struct sta_info * psta,*pbcmc_sta; struct sta_priv * pstapriv = &padapter->stapriv; - if (check_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_MP_STATE) == true) /* sta mode */ - { + if (check_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_MP_STATE) == true) { /* sta mode */ psta = rtw_get_stainfo(pstapriv, get_bssid(pmlmepriv)); if (psta == NULL) { /* DEBUG_ERR(("Set wpa_set_encryption: Obtain Sta_info fail\n")); */ - } - else - { + } else { /* Jeff: don't disable ieee8021x_blocked while clearing key */ if (strcmp(param->u.crypt.alg, "none") != 0) psta->ieee8021x_blocked = false; if ((padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption2Enabled)|| - (padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption3Enabled)) - { + (padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption3Enabled)) { psta->dot118021XPrivacy = padapter->securitypriv.dot11PrivacyAlgrthm; } - if (param->u.crypt.set_tx == 1)/* pairwise key */ - { + if (param->u.crypt.set_tx == 1) { /* pairwise key */ memcpy(psta->dot118021x_UncstKey.skey, param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len)); - if (strcmp(param->u.crypt.alg, "TKIP") == 0)/* set mic key */ - { + if (strcmp(param->u.crypt.alg, "TKIP") == 0) { /* set mic key */ /* DEBUG_ERR(("\nset key length :param->u.crypt.key_len =%d\n", param->u.crypt.key_len)); */ memcpy(psta->dot11tkiptxmickey.skey, &(param->u.crypt.key[16]), 8); memcpy(psta->dot11tkiprxmickey.skey, &(param->u.crypt.key[24]), 8); @@ -705,15 +640,11 @@ static int wpa_set_encryption(struct net_device *dev, struct ieee_param *param, DBG_871X(" ~~~~set sta key:unicastkey\n"); rtw_setstakey_cmd(padapter, psta, true, true); - } - else/* group key */ - { - if (strcmp(param->u.crypt.alg, "TKIP") == 0 || strcmp(param->u.crypt.alg, "CCMP") == 0) - { + } else { /* group key */ + if (strcmp(param->u.crypt.alg, "TKIP") == 0 || strcmp(param->u.crypt.alg, "CCMP") == 0) { memcpy(padapter->securitypriv.dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len)); /* only TKIP group key need to install this */ - if (param->u.crypt.key_len > 16) - { + if (param->u.crypt.key_len > 16) { memcpy(padapter->securitypriv.dot118021XGrptxmickey[param->u.crypt.idx].skey,&(param->u.crypt.key[16]), 8); memcpy(padapter->securitypriv.dot118021XGrprxmickey[param->u.crypt.idx].skey,&(param->u.crypt.key[24]), 8); } @@ -724,9 +655,7 @@ static int wpa_set_encryption(struct net_device *dev, struct ieee_param *param, padapter->securitypriv.dot118021XGrpKeyid = param->u.crypt.idx; rtw_set_key(padapter,&padapter->securitypriv, param->u.crypt.idx, 1, true); - } - else if (strcmp(param->u.crypt.alg, "BIP") == 0) - { + } else if (strcmp(param->u.crypt.alg, "BIP") == 0) { /* printk("BIP key_len =%d , index =%d @@@@@@@@@@@@@@@@@@\n", param->u.crypt.key_len, param->u.crypt.idx); */ /* save the IGTK key, length 16 bytes */ memcpy(padapter->securitypriv.dot11wBIPKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len)); @@ -742,25 +671,20 @@ static int wpa_set_encryption(struct net_device *dev, struct ieee_param *param, } pbcmc_sta =rtw_get_bcmc_stainfo(padapter); - if (pbcmc_sta == NULL) - { + if (pbcmc_sta == NULL) { /* DEBUG_ERR(("Set OID_802_11_ADD_KEY: bcmc stainfo is null\n")); */ - } - else - { + } else { /* Jeff: don't disable ieee8021x_blocked while clearing key */ if (strcmp(param->u.crypt.alg, "none") != 0) pbcmc_sta->ieee8021x_blocked = false; if ((padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption2Enabled)|| - (padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption3Enabled)) - { + (padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption3Enabled)) { pbcmc_sta->dot118021XPrivacy = padapter->securitypriv.dot11PrivacyAlgrthm; } } - } - else if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) /* adhoc mode */ - { + } else if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) { + /* adhoc mode */ } } @@ -785,8 +709,7 @@ static int rtw_set_wpa_ie(struct adapter *padapter, char *pie, unsigned short ie return -EINVAL; } - if (ielen) - { + if (ielen) { buf = rtw_zmalloc(ielen); if (buf == NULL) { ret = -ENOMEM; @@ -810,31 +733,24 @@ static int rtw_set_wpa_ie(struct adapter *padapter, char *pie, unsigned short ie goto exit; } - if (rtw_parse_wpa_ie(buf, ielen, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) - { + if (rtw_parse_wpa_ie(buf, ielen, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) { padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_8021X; padapter->securitypriv.ndisauthtype =Ndis802_11AuthModeWPAPSK; memcpy(padapter->securitypriv.supplicant_ie, &buf[0], ielen); } - if (rtw_parse_wpa2_ie(buf, ielen, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) - { + if (rtw_parse_wpa2_ie(buf, ielen, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) { padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_8021X; padapter->securitypriv.ndisauthtype =Ndis802_11AuthModeWPA2PSK; memcpy(padapter->securitypriv.supplicant_ie, &buf[0], ielen); } if (group_cipher == 0) - { group_cipher = WPA_CIPHER_NONE; - } if (pairwise_cipher == 0) - { pairwise_cipher = WPA_CIPHER_NONE; - } - switch (group_cipher) - { + switch (group_cipher) { case WPA_CIPHER_NONE: padapter->securitypriv.dot118021XGrpPrivacy = _NO_PRIVACY_; padapter->securitypriv.ndisencryptstatus =Ndis802_11EncryptionDisabled; @@ -857,8 +773,7 @@ static int rtw_set_wpa_ie(struct adapter *padapter, char *pie, unsigned short ie break; } - switch (pairwise_cipher) - { + switch (pairwise_cipher) { case WPA_CIPHER_NONE: padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_; padapter->securitypriv.ndisencryptstatus =Ndis802_11EncryptionDisabled; @@ -886,12 +801,10 @@ static int rtw_set_wpa_ie(struct adapter *padapter, char *pie, unsigned short ie u16 cnt = 0; u8 eid, wps_oui[4]={0x0, 0x50, 0xf2, 0x04}; - while (cnt < ielen) - { + while (cnt < ielen) { eid = buf[cnt]; - if ((eid == _VENDOR_SPECIFIC_IE_) && (!memcmp(&buf[cnt+2], wps_oui, 4))) - { + if ((eid == _VENDOR_SPECIFIC_IE_) && (!memcmp(&buf[cnt+2], wps_oui, 4))) { DBG_871X("SET WPS_IE\n"); padapter->securitypriv.wps_ie_len = ((buf[cnt+1]+2) < MAX_WPS_IE_LEN) ? (buf[cnt+1]+2):MAX_WPS_IE_LEN; @@ -947,48 +860,36 @@ static int rtw_wx_get_name(struct net_device *dev, /* parsing HT_CAP_IE */ p = rtw_get_ie(&pcur_bss->IEs[12], _HT_CAPABILITY_IE_, &ht_ielen, pcur_bss->IELength-12); if (p && ht_ielen>0) - { ht_cap = true; - } prates = &pcur_bss->SupportedRates; - if (rtw_is_cckratesonly_included((u8 *)prates) == true) - { + if (rtw_is_cckratesonly_included((u8 *)prates) == true) { if (ht_cap == true) snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11bn"); else snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11b"); - } - else if ((rtw_is_cckrates_included((u8 *)prates)) == true) - { + } else if ((rtw_is_cckrates_included((u8 *)prates)) == true) { if (ht_cap == true) snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11bgn"); else snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11bg"); - } - else - { - if (pcur_bss->Configuration.DSConfig > 14) - { + } else { + if (pcur_bss->Configuration.DSConfig > 14) { if (vht_cap == true) snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11AC"); else if (ht_cap == true) snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11an"); else snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11a"); - } - else - { + } else { if (ht_cap == true) snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11gn"); else snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11g"); } } - } - else - { + } else { /* prates = &padapter->registrypriv.dev_network.SupportedRates; */ /* snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11g"); */ snprintf(wrqu->name, IFNAMSIZ, "unassociated"); @@ -1013,15 +914,13 @@ static int rtw_wx_get_freq(struct net_device *dev, struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); struct wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network; - if (check_fwstate(pmlmepriv, _FW_LINKED) == true) - { + if (check_fwstate(pmlmepriv, _FW_LINKED) == true) { /* wrqu->freq.m = ieee80211_wlan_frequencies[pcur_bss->Configuration.DSConfig-1] * 100000; */ wrqu->freq.m = rtw_ch2freq(pcur_bss->Configuration.DSConfig) * 100000; wrqu->freq.e = 1; wrqu->freq.i = pcur_bss->Configuration.DSConfig; - } - else { + } else { wrqu->freq.m = rtw_ch2freq(padapter->mlmeextpriv.cur_channel) * 100000; wrqu->freq.e = 1; wrqu->freq.i = padapter->mlmeextpriv.cur_channel; @@ -1047,8 +946,7 @@ static int rtw_wx_set_mode(struct net_device *dev, struct iw_request_info *a, goto exit; } - switch (wrqu->mode) - { + switch (wrqu->mode) { case IW_MODE_AUTO: networkType = Ndis802_11AutoUnknown; DBG_871X("set_mode = IW_MODE_AUTO\n"); @@ -1105,22 +1003,14 @@ static int rtw_wx_get_mode(struct net_device *dev, struct iw_request_info *a, RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, (" rtw_wx_get_mode\n")); - if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) - { + if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) { wrqu->mode = IW_MODE_INFRA; - } - else if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true) || - (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true)) - - { + } else if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true) || + (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true)) { wrqu->mode = IW_MODE_ADHOC; - } - else if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) - { + } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) { wrqu->mode = IW_MODE_MASTER; - } - else - { + } else { wrqu->mode = IW_MODE_AUTO; } return 0; @@ -1147,25 +1037,19 @@ static int rtw_wx_set_pmkid(struct net_device *dev, */ memcpy(strIssueBssid, pPMK->bssid.sa_data, ETH_ALEN); - if (pPMK->cmd == IW_PMKSA_ADD) - { + if (pPMK->cmd == IW_PMKSA_ADD) { DBG_871X("[rtw_wx_set_pmkid] IW_PMKSA_ADD!\n"); if (!memcmp(strIssueBssid, strZeroMacAddress, ETH_ALEN)) - { return(intReturn); - } else - { intReturn = true; - } + blInserted = false; /* overwrite PMKID */ - for (j = 0 ; j<NUM_PMKID_CACHE; j++) - { - if (!memcmp(psecuritypriv->PMKIDList[j].Bssid, strIssueBssid, ETH_ALEN)) - { /* BSSID is matched, the same AP => rewrite with new PMKID. */ - + for (j = 0 ; j<NUM_PMKID_CACHE; j++) { + if (!memcmp(psecuritypriv->PMKIDList[j].Bssid, strIssueBssid, ETH_ALEN)) { + /* BSSID is matched, the same AP => rewrite with new PMKID. */ DBG_871X("[rtw_wx_set_pmkid] BSSID exists in the PMKList.\n"); memcpy(psecuritypriv->PMKIDList[j].PMKID, pPMK->pmkid, IW_PMKID_LEN); @@ -1176,8 +1060,7 @@ static int rtw_wx_set_pmkid(struct net_device *dev, } } - if (!blInserted) - { + if (!blInserted) { /* Find a new entry */ DBG_871X("[rtw_wx_set_pmkid] Use the new entry index = %d for this PMKID.\n", psecuritypriv->PMKIDIndex); @@ -1188,27 +1071,20 @@ static int rtw_wx_set_pmkid(struct net_device *dev, psecuritypriv->PMKIDList[ psecuritypriv->PMKIDIndex ].bUsed = true; psecuritypriv->PMKIDIndex++ ; if (psecuritypriv->PMKIDIndex == 16) - { psecuritypriv->PMKIDIndex = 0; - } } - } - else if (pPMK->cmd == IW_PMKSA_REMOVE) - { + } else if (pPMK->cmd == IW_PMKSA_REMOVE) { DBG_871X("[rtw_wx_set_pmkid] IW_PMKSA_REMOVE!\n"); intReturn = true; - for (j = 0 ; j<NUM_PMKID_CACHE; j++) - { - if (!memcmp(psecuritypriv->PMKIDList[j].Bssid, strIssueBssid, ETH_ALEN)) - { /* BSSID is matched, the same AP => Remove this PMKID information and reset it. */ + for (j = 0 ; j<NUM_PMKID_CACHE; j++) { + if (!memcmp(psecuritypriv->PMKIDList[j].Bssid, strIssueBssid, ETH_ALEN)) { + /* BSSID is matched, the same AP => Remove this PMKID information and reset it. */ memset(psecuritypriv->PMKIDList[ j ].Bssid, 0x00, ETH_ALEN); psecuritypriv->PMKIDList[ j ].bUsed = false; break; } } - } - else if (pPMK->cmd == IW_PMKSA_FLUSH) - { + } else if (pPMK->cmd == IW_PMKSA_FLUSH) { DBG_871X("[rtw_wx_set_pmkid] IW_PMKSA_FLUSH!\n"); memset(&psecuritypriv->PMKIDList[ 0 ], 0x00, sizeof(RT_PMKID_LIST) * NUM_PMKID_CACHE); psecuritypriv->PMKIDIndex = 0; @@ -1273,9 +1149,8 @@ static int rtw_wx_get_range(struct net_device *dev, range->num_bitrates = RATE_COUNT; - for (i = 0; i < RATE_COUNT && i < IW_MAX_BITRATES; i++) { + for (i = 0; i < RATE_COUNT && i < IW_MAX_BITRATES; i++) range->bitrate[i] = rtw_rates[i]; - } range->min_frag = MIN_FRAG_THRESHOLD; range->max_frag = MAX_FRAG_THRESHOLD; @@ -1288,8 +1163,7 @@ static int rtw_wx_get_range(struct net_device *dev, for (i = 0, val = 0; i < MAX_CHANNEL_NUM; i++) { /* Include only legal frequencies for some countries */ - if (pmlmeext->channel_set[i].ChannelNum != 0) - { + if (pmlmeext->channel_set[i].ChannelNum != 0) { range->freq[val].i = pmlmeext->channel_set[i].ChannelNum; range->freq[val].m = rtw_ch2freq(pmlmeext->channel_set[i].ChannelNum) * 100000; range->freq[val].e = 1; @@ -1349,8 +1223,7 @@ static int rtw_wx_set_wap(struct net_device *dev, enum NDIS_802_11_AUTHENTICATION_MODE authmode; rtw_ps_deny(padapter, PS_DENY_JOIN); - if (_FAIL == rtw_pwr_wakeup(padapter)) - { + if (_FAIL == rtw_pwr_wakeup(padapter)) { ret = -1; goto exit; } @@ -1383,15 +1256,12 @@ static int rtw_wx_set_wap(struct net_device *dev, src_bssid = temp->sa_data; - if ((!memcmp(dst_bssid, src_bssid, ETH_ALEN))) - { - if (!rtw_set_802_11_infrastructure_mode(padapter, pnetwork->network.InfrastructureMode)) - { + if ((!memcmp(dst_bssid, src_bssid, ETH_ALEN))) { + if (!rtw_set_802_11_infrastructure_mode(padapter, pnetwork->network.InfrastructureMode)) { ret = -1; spin_unlock_bh(&queue->lock); goto exit; } - break; } @@ -1429,13 +1299,9 @@ static int rtw_wx_get_wap(struct net_device *dev, if (((check_fwstate(pmlmepriv, _FW_LINKED)) == true) || ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) == true) || - ((check_fwstate(pmlmepriv, WIFI_AP_STATE)) == true)) - { - + ((check_fwstate(pmlmepriv, WIFI_AP_STATE)) == true)) { memcpy(wrqu->ap_addr.sa_data, pcur_bss->MacAddress, ETH_ALEN); - } - else - { + } else { memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN); } @@ -1461,8 +1327,7 @@ static int rtw_wx_set_mlme(struct net_device *dev, DBG_871X("%s, cmd =%d, reason =%d\n", __func__, mlme->cmd, reason); - switch (mlme->cmd) - { + switch (mlme->cmd) { case IW_MLME_DEAUTH: if (!rtw_set_802_11_disassociate(padapter)) ret = -1; @@ -1493,8 +1358,7 @@ static int rtw_wx_set_scan(struct net_device *dev, struct iw_request_info *a, #endif rtw_ps_deny(padapter, PS_DENY_SCAN); - if (_FAIL == rtw_pwr_wakeup(padapter)) - { + if (_FAIL == rtw_pwr_wakeup(padapter)) { ret = -1; goto exit; } @@ -1518,26 +1382,22 @@ static int rtw_wx_set_scan(struct net_device *dev, struct iw_request_info *a, /* When Busy Traffic, driver do not site survey. So driver return success. */ /* wpa_supplicant will not issue SIOCSIWSCAN cmd again after scan timeout. */ /* modify by thomas 2011-02-22. */ - if (pmlmepriv->LinkDetectInfo.bBusyTraffic == true) - { + if (pmlmepriv->LinkDetectInfo.bBusyTraffic == true) { indicate_wx_scan_complete_event(padapter); goto exit; } - if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY|_FW_UNDER_LINKING) == true) - { + if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY|_FW_UNDER_LINKING) == true) { indicate_wx_scan_complete_event(padapter); goto exit; } memset(ssid, 0, sizeof(struct ndis_802_11_ssid)*RTW_SSID_SCAN_AMOUNT); - if (wrqu->data.length == sizeof(struct iw_scan_req)) - { + if (wrqu->data.length == sizeof(struct iw_scan_req)) { struct iw_scan_req *req = (struct iw_scan_req *)extra; - if (wrqu->data.flags & IW_SCAN_THIS_ESSID) - { + if (wrqu->data.flags & IW_SCAN_THIS_ESSID) { int len = min((int)req->essid_len, IW_ESSID_MAX_SIZE); memcpy(ssid[0].Ssid, req->essid, len); @@ -1551,17 +1411,12 @@ static int rtw_wx_set_scan(struct net_device *dev, struct iw_request_info *a, spin_unlock_bh(&pmlmepriv->lock); - } - else if (req->scan_type == IW_SCAN_TYPE_PASSIVE) - { + } else if (req->scan_type == IW_SCAN_TYPE_PASSIVE) { DBG_871X("rtw_wx_set_scan, req->scan_type == IW_SCAN_TYPE_PASSIVE\n"); } - } - else if (wrqu->data.length >= WEXT_CSCAN_HEADER_SIZE - && !memcmp(extra, WEXT_CSCAN_HEADER, WEXT_CSCAN_HEADER_SIZE) - ) - { + } else if (wrqu->data.length >= WEXT_CSCAN_HEADER_SIZE + && !memcmp(extra, WEXT_CSCAN_HEADER, WEXT_CSCAN_HEADER_SIZE)) { int len = wrqu->data.length -WEXT_CSCAN_HEADER_SIZE; char *pos = extra+WEXT_CSCAN_HEADER_SIZE; char section; @@ -1626,9 +1481,7 @@ static int rtw_wx_set_scan(struct net_device *dev, struct iw_request_info *a, /* jeff: it has still some scan paramater to parse, we only do this now... */ _status = rtw_set_802_11_bssid_list_scan(padapter, ssid, RTW_SSID_SCAN_AMOUNT); - } else - - { + } else { _status = rtw_set_802_11_bssid_list_scan(padapter, NULL, 0); } @@ -1666,8 +1519,7 @@ static int rtw_wx_get_scan(struct net_device *dev, struct iw_request_info *a, DBG_871X("DBG_IOCTL %s:%d\n", __func__, __LINE__); #endif - if (adapter_to_pwrctl(padapter)->brfoffbyhw && padapter->bDriverStopped) - { + if (adapter_to_pwrctl(padapter)->brfoffbyhw && padapter->bDriverStopped) { ret = -EINVAL; goto exit; } @@ -1682,8 +1534,7 @@ static int rtw_wx_get_scan(struct net_device *dev, struct iw_request_info *a, phead = get_list_head(queue); plist = get_next(phead); - while (1) - { + while (1) { if (phead == plist) break; @@ -1697,9 +1548,8 @@ static int rtw_wx_get_scan(struct net_device *dev, struct iw_request_info *a, /* report network only if the current channel set contains the channel to which this network belongs */ if (rtw_ch_set_search_ch(padapter->mlmeextpriv.channel_set, pnetwork->network.Configuration.DSConfig) >= 0 && rtw_mlme_band_check(padapter, pnetwork->network.Configuration.DSConfig) == true - && true == rtw_validate_ssid(&(pnetwork->network.Ssid)) - ) - { + && true == rtw_validate_ssid(&(pnetwork->network.Ssid))) { + ev =translate_scan(padapter, a, pnetwork, ev, stop); } @@ -1750,8 +1600,7 @@ static int rtw_wx_set_essid(struct net_device *dev, ("+rtw_wx_set_essid: fw_state = 0x%08x\n", get_fwstate(pmlmepriv))); rtw_ps_deny(padapter, PS_DENY_JOIN); - if (_FAIL == rtw_pwr_wakeup(padapter)) - { + if (_FAIL == rtw_pwr_wakeup(padapter)) { ret = -1; goto exit; } @@ -1773,8 +1622,7 @@ static int rtw_wx_set_essid(struct net_device *dev, authmode = padapter->securitypriv.ndisauthtype; DBG_871X("=>%s\n", __func__); - if (wrqu->essid.flags && wrqu->essid.length) - { + if (wrqu->essid.flags && wrqu->essid.length) { len = (wrqu->essid.length < IW_ESSID_MAX_SIZE) ? wrqu->essid.length : IW_ESSID_MAX_SIZE; if (wrqu->essid.length != 33) @@ -1791,8 +1639,7 @@ static int rtw_wx_set_essid(struct net_device *dev, pmlmepriv->pscanned = get_next(phead); while (1) { - if (phead == pmlmepriv->pscanned) - { + if (phead == pmlmepriv->pscanned) { RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_warning_, ("rtw_wx_set_essid: scan_q is empty, set ssid to check if scanning again!\n")); @@ -1810,19 +1657,16 @@ static int rtw_wx_set_essid(struct net_device *dev, pnetwork->network.Ssid.Ssid)); if ((!memcmp(dst_ssid, src_ssid, ndis_ssid.SsidLength)) && - (pnetwork->network.Ssid.SsidLength ==ndis_ssid.SsidLength)) - { + (pnetwork->network.Ssid.SsidLength ==ndis_ssid.SsidLength)) { RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, ("rtw_wx_set_essid: find match, set infra mode\n")); - if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true) - { + if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true) { if (pnetwork->network.InfrastructureMode != pmlmepriv->cur_network.network.InfrastructureMode) continue; } - if (rtw_set_802_11_infrastructure_mode(padapter, pnetwork->network.InfrastructureMode) == false) - { + if (rtw_set_802_11_infrastructure_mode(padapter, pnetwork->network.InfrastructureMode) == false) { ret = -1; spin_unlock_bh(&queue->lock); goto exit; @@ -1867,8 +1711,7 @@ static int rtw_wx_get_essid(struct net_device *dev, RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_wx_get_essid\n")); if ((check_fwstate(pmlmepriv, _FW_LINKED) == true) || - (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true)) - { + (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true)) { len = pcur_bss->Ssid.SsidLength; wrqu->essid.length = len; @@ -1876,9 +1719,7 @@ static int rtw_wx_get_essid(struct net_device *dev, memcpy(extra, pcur_bss->Ssid.Ssid, len); wrqu->essid.flags = 1; - } - else - { + } else { ret = -1; goto exit; } @@ -1952,15 +1793,12 @@ static int rtw_wx_set_rate(struct net_device *dev, set_rate: - for (i = 0; i<NumRates; i++) - { - if (ratevalue ==mpdatarate[i]) - { + for (i = 0; i<NumRates; i++) { + if (ratevalue ==mpdatarate[i]) { datarates[i] = mpdatarate[i]; if (fixed == 0) break; - } - else { + } else { datarates[i] = 0xff; } @@ -2097,8 +1935,7 @@ static int rtw_wx_set_enc(struct net_device *dev, key = erq->flags & IW_ENCODE_INDEX; - if (erq->flags & IW_ENCODE_DISABLED) - { + if (erq->flags & IW_ENCODE_DISABLED) { DBG_871X("EncryptionDisabled\n"); padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled; padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_; @@ -2115,17 +1952,14 @@ static int rtw_wx_set_enc(struct net_device *dev, return -EINVAL; key--; keyindex_provided = 1; - } - else - { + } else { keyindex_provided = 0; key = padapter->securitypriv.dot11PrivacyKeyIndex; DBG_871X("rtw_wx_set_enc, key =%d\n", key); } /* set authentication mode */ - if (erq->flags & IW_ENCODE_OPEN) - { + if (erq->flags & IW_ENCODE_OPEN) { DBG_871X("rtw_wx_set_enc():IW_ENCODE_OPEN\n"); padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;/* Ndis802_11EncryptionDisabled; */ @@ -2135,9 +1969,7 @@ static int rtw_wx_set_enc(struct net_device *dev, padapter->securitypriv.dot118021XGrpPrivacy = _NO_PRIVACY_; authmode = Ndis802_11AuthModeOpen; padapter->securitypriv.ndisauthtype =authmode; - } - else if (erq->flags & IW_ENCODE_RESTRICTED) - { + } else if (erq->flags & IW_ENCODE_RESTRICTED) { DBG_871X("rtw_wx_set_enc():IW_ENCODE_RESTRICTED\n"); padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; @@ -2147,9 +1979,7 @@ static int rtw_wx_set_enc(struct net_device *dev, padapter->securitypriv.dot118021XGrpPrivacy = _WEP40_; authmode = Ndis802_11AuthModeShared; padapter->securitypriv.ndisauthtype =authmode; - } - else - { + } else { DBG_871X("rtw_wx_set_enc():erq->flags = 0x%x\n", erq->flags); padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;/* Ndis802_11EncryptionDisabled; */ @@ -2161,24 +1991,19 @@ static int rtw_wx_set_enc(struct net_device *dev, } wep.KeyIndex = key; - if (erq->length > 0) - { + if (erq->length > 0) { wep.KeyLength = erq->length <= 5 ? 5 : 13; wep.Length = wep.KeyLength + FIELD_OFFSET(struct ndis_802_11_wep, KeyMaterial); - } - else - { + } else { wep.KeyLength = 0 ; - if (keyindex_provided == 1)/* set key_id only, no given KeyMaterial(erq->length == 0). */ - { + if (keyindex_provided == 1) { /* set key_id only, no given KeyMaterial(erq->length == 0). */ padapter->securitypriv.dot11PrivacyKeyIndex = key; DBG_871X("(keyindex_provided == 1), keyid =%d, key_len =%d\n", key, padapter->securitypriv.dot11DefKeylen[key]); - switch (padapter->securitypriv.dot11DefKeylen[key]) - { + switch (padapter->securitypriv.dot11DefKeylen[key]) { case 5: padapter->securitypriv.dot11PrivacyAlgrthm = _WEP40_; break; @@ -2219,14 +2044,12 @@ static int rtw_wx_get_enc(struct net_device *dev, struct iw_point *erq = &(wrqu->encoding); struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); - if (check_fwstate(pmlmepriv, _FW_LINKED) != true) - { - if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) != true) - { - erq->length = 0; - erq->flags |= IW_ENCODE_DISABLED; - return 0; - } + if (check_fwstate(pmlmepriv, _FW_LINKED) != true) { + if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) != true) { + erq->length = 0; + erq->flags |= IW_ENCODE_DISABLED; + return 0; + } } @@ -2236,8 +2059,7 @@ static int rtw_wx_get_enc(struct net_device *dev, if (key > WEP_KEYS) return -EINVAL; key--; - } else - { + } else { key = padapter->securitypriv.dot11PrivacyKeyIndex; } @@ -2248,8 +2070,7 @@ static int rtw_wx_get_enc(struct net_device *dev, /* erq->flags |= IW_ENCODE_OPEN; */ /* */ - switch (padapter->securitypriv.ndisencryptstatus) - { + switch (padapter->securitypriv.ndisencryptstatus) { case Ndis802_11EncryptionNotSupported: case Ndis802_11EncryptionDisabled: erq->length = 0; @@ -2258,23 +2079,16 @@ static int rtw_wx_get_enc(struct net_device *dev, case Ndis802_11Encryption1Enabled: erq->length = padapter->securitypriv.dot11DefKeylen[key]; - if (erq->length) - { + if (erq->length) { memcpy(keybuf, padapter->securitypriv.dot11DefKey[key].skey, padapter->securitypriv.dot11DefKeylen[key]); erq->flags |= IW_ENCODE_ENABLED; if (padapter->securitypriv.ndisauthtype == Ndis802_11AuthModeOpen) - { erq->flags |= IW_ENCODE_OPEN; - } else if (padapter->securitypriv.ndisauthtype == Ndis802_11AuthModeShared) - { - erq->flags |= IW_ENCODE_RESTRICTED; - } - } - else - { + erq->flags |= IW_ENCODE_RESTRICTED; + } else { erq->length = 0; erq->flags |= IW_ENCODE_DISABLED; } @@ -2343,14 +2157,13 @@ static int rtw_wx_set_auth(struct net_device *dev, case IW_AUTH_TKIP_COUNTERMEASURES: { - if (param->value) - { /* wpa_supplicant is enabling the tkip countermeasure. */ - padapter->securitypriv.btkip_countermeasure = true; - } - else - { /* wpa_supplicant is disabling the tkip countermeasure. */ - padapter->securitypriv.btkip_countermeasure = false; - } + if (param->value) { + /* wpa_supplicant is enabling the tkip countermeasure. */ + padapter->securitypriv.btkip_countermeasure = true; + } else { + /* wpa_supplicant is disabling the tkip countermeasure. */ + padapter->securitypriv.btkip_countermeasure = false; + } break; } case IW_AUTH_DROP_UNENCRYPTED: @@ -2367,8 +2180,7 @@ static int rtw_wx_set_auth(struct net_device *dev, * be set. */ - if (padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption1Enabled) - { + if (padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption1Enabled) { break;/* it means init value, or using wep, ndisencryptstatus = Ndis802_11Encryption1Enabled, */ /* then it needn't reset it; */ } @@ -2462,37 +2274,29 @@ static int rtw_wx_set_enc_ext(struct net_device *dev, strncpy((char *)param->u.crypt.alg, alg_name, IEEE_CRYPT_ALG_NAME_LEN); if (pext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) - { param->u.crypt.set_tx = 1; - } /* cliW: WEP does not have group key * just not checking GROUP key setting */ if ((pext->alg != IW_ENCODE_ALG_WEP) && ((pext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) - || (pext->ext_flags & IW_ENCODE_ALG_AES_CMAC) - )) - { + || (pext->ext_flags & IW_ENCODE_ALG_AES_CMAC))) { param->u.crypt.set_tx = 0; } param->u.crypt.idx = (pencoding->flags&0x00FF) -1 ; if (pext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) - { memcpy(param->u.crypt.seq, pext->rx_seq, 8); - } - if (pext->key_len) - { + if (pext->key_len) { param->u.crypt.key_len = pext->key_len; /* memcpy(param + 1, pext + 1, pext->key_len); */ memcpy(param->u.crypt.key, pext + 1, pext->key_len); } - if (pencoding->flags & IW_ENCODE_DISABLED) - { + if (pencoding->flags & IW_ENCODE_DISABLED) { /* todo: remove key */ /* remove = 1; */ } @@ -2514,8 +2318,7 @@ static int rtw_wx_get_nick(struct net_device *dev, /* struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); */ /* struct security_priv *psecuritypriv = &padapter->securitypriv; */ - if (extra) - { + if (extra) { wrqu->data.length = 14; wrqu->data.flags = 1; memcpy(extra, "<WIFI@REALTEK>", 14); @@ -2683,9 +2486,9 @@ static int rtw_wx_set_channel_plan(struct net_device *dev, struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); u8 channel_plan_req = (u8) (*((int *)wrqu)); - if (_SUCCESS == rtw_set_chplan_cmd(padapter, channel_plan_req, 1, 1)) { + if (_SUCCESS == rtw_set_chplan_cmd(padapter, channel_plan_req, 1, 1)) DBG_871X("%s set channel_plan = 0x%02X\n", __func__, channel_plan_req); - } else + else return -EPERM; return 0; @@ -2751,14 +2554,12 @@ static int rtw_get_ap_info(struct net_device *dev, DBG_871X("+rtw_get_aplist_info\n"); - if ((padapter->bDriverStopped) || (pdata == NULL)) - { + if ((padapter->bDriverStopped) || (pdata == NULL)) { ret = -EINVAL; goto exit; } - while ((check_fwstate(pmlmepriv, (_FW_UNDER_SURVEY|_FW_UNDER_LINKING))) == true) - { + while ((check_fwstate(pmlmepriv, (_FW_UNDER_SURVEY|_FW_UNDER_LINKING))) == true) { msleep(30); cnt++; if (cnt > 100) @@ -2768,16 +2569,12 @@ static int rtw_get_ap_info(struct net_device *dev, /* pdata->length = 0;? */ pdata->flags = 0; - if (pdata->length>=32) - { - if (copy_from_user(data, pdata->pointer, 32)) - { + if (pdata->length>=32) { + if (copy_from_user(data, pdata->pointer, 32)) { ret = -EINVAL; goto exit; } - } - else - { + } else { ret = -EINVAL; goto exit; } @@ -2787,8 +2584,7 @@ static int rtw_get_ap_info(struct net_device *dev, phead = get_list_head(queue); plist = get_next(phead); - while (1) - { + while (1) { if (phead == plist) break; @@ -2796,32 +2592,27 @@ static int rtw_get_ap_info(struct net_device *dev, pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list); /* if (hwaddr_aton_i(pdata->pointer, bssid)) */ - if (hwaddr_aton_i(data, bssid)) - { + if (hwaddr_aton_i(data, bssid)) { DBG_871X("Invalid BSSID '%s'.\n", (u8 *)data); spin_unlock_bh(&(pmlmepriv->scanned_queue.lock)); return -EINVAL; } - if (!memcmp(bssid, pnetwork->network.MacAddress, ETH_ALEN))/* BSSID match, then check if supporting wpa/wpa2 */ - { + if (!memcmp(bssid, pnetwork->network.MacAddress, ETH_ALEN)) { /* BSSID match, then check if supporting wpa/wpa2 */ DBG_871X("BSSID:" MAC_FMT "\n", MAC_ARG(bssid)); pbuf = rtw_get_wpa_ie(&pnetwork->network.IEs[12], &wpa_ielen, pnetwork->network.IELength-12); - if (pbuf && (wpa_ielen>0)) - { + if (pbuf && (wpa_ielen>0)) { pdata->flags = 1; break; } pbuf = rtw_get_wpa2_ie(&pnetwork->network.IEs[12], &wpa_ielen, pnetwork->network.IELength-12); - if (pbuf && (wpa_ielen>0)) - { + if (pbuf && (wpa_ielen>0)) { pdata->flags = 2; break; } - } plist = get_next(plist); @@ -2830,10 +2621,8 @@ static int rtw_get_ap_info(struct net_device *dev, spin_unlock_bh(&(pmlmepriv->scanned_queue.lock)); - if (pdata->length>=34) - { - if (copy_to_user((u8 __force __user *)pdata->pointer+32, (u8 *)&pdata->flags, 1)) - { + if (pdata->length>=34) { + if (copy_to_user((u8 __force __user *)pdata->pointer+32, (u8 *)&pdata->flags, 1)) { ret = -EINVAL; goto exit; } @@ -2855,8 +2644,7 @@ static int rtw_set_pid(struct net_device *dev, int *pdata = (int *)wrqu; int selector; - if ((padapter->bDriverStopped) || (pdata == NULL)) - { + if ((padapter->bDriverStopped) || (pdata == NULL)) { ret = -EINVAL; goto exit; } @@ -2886,17 +2674,14 @@ static int rtw_wps_start(struct net_device *dev, u32 u32wps_start = 0; unsigned int uintRet = 0; - if ((true == padapter->bDriverStopped) ||(true ==padapter->bSurpriseRemoved) || (NULL == pdata)) - { + if ((true == padapter->bDriverStopped) ||(true ==padapter->bSurpriseRemoved) || (NULL == pdata)) { ret = -EINVAL; goto exit; } uintRet = copy_from_user((void*) &u32wps_start, pdata->pointer, 4); if (u32wps_start == 0) - { u32wps_start = *extra; - } DBG_871X("[%s] wps_start = %d\n", __func__, u32wps_start); @@ -2964,18 +2749,15 @@ static int rtw_rereg_nd_name(struct net_device *dev, if (wrqu->data.length > IFNAMSIZ) return -EFAULT; - if (copy_from_user(new_ifname, wrqu->data.pointer, IFNAMSIZ)) { + if (copy_from_user(new_ifname, wrqu->data.pointer, IFNAMSIZ)) return -EFAULT; - } - if (0 == strcmp(rereg_priv->old_ifname, new_ifname)) { + if (0 == strcmp(rereg_priv->old_ifname, new_ifname)) return ret; - } DBG_871X("%s new_ifname:%s\n", __func__, new_ifname); - if (0 != (ret = rtw_change_ifname(padapter, new_ifname))) { + if (0 != (ret = rtw_change_ifname(padapter, new_ifname))) goto exit; - } strncpy(rereg_priv->old_ifname, new_ifname, IFNAMSIZ); rereg_priv->old_ifname[IFNAMSIZ-1] = 0; @@ -3021,11 +2803,9 @@ static int rtw_dbg_port(struct net_device *dev, extra_arg = *(pdata+1); - switch (major_cmd) - { + switch (major_cmd) { case 0x70:/* read_reg */ - switch (minor_cmd) - { + switch (minor_cmd) { case 1: DBG_871X("rtw_read8(0x%x) = 0x%02x\n", arg, rtw_read8(padapter, arg)); break; @@ -3038,8 +2818,7 @@ static int rtw_dbg_port(struct net_device *dev, } break; case 0x71:/* write_reg */ - switch (minor_cmd) - { + switch (minor_cmd) { case 1: rtw_write8(padapter, arg, extra_arg); DBG_871X("rtw_write8(0x%x) = 0x%02x\n", arg, rtw_read8(padapter, arg)); @@ -3070,8 +2849,7 @@ static int rtw_dbg_port(struct net_device *dev, break; case 0x76: - switch (minor_cmd) - { + switch (minor_cmd) { case 0x00: /* normal mode, */ padapter->recvpriv.is_signal_dbg = 0; break; @@ -3108,8 +2886,7 @@ static int rtw_dbg_port(struct net_device *dev, , WLAN_REASON_EXPIRATION_CHK); break; case 0x7F: - switch (minor_cmd) - { + switch (minor_cmd) { case 0x0: DBG_871X("fwstate = 0x%x\n", get_fwstate(pmlmepriv)); break; @@ -3137,8 +2914,7 @@ static int rtw_dbg_port(struct net_device *dev, break; case 0x05: psta = rtw_get_stainfo(pstapriv, cur_network->network.MacAddress); - if (psta) - { + if (psta) { int i; struct recv_reorder_ctrl *preorder_ctrl; @@ -3152,18 +2928,13 @@ static int rtw_dbg_port(struct net_device *dev, DBG_871X("ampdu_enable = %d\n", psta->htpriv.ampdu_enable); DBG_871X("agg_enable_bitmap =%x, candidate_tid_bitmap =%x\n", psta->htpriv.agg_enable_bitmap, psta->htpriv.candidate_tid_bitmap); - for (i = 0;i<16;i++) - { + for (i = 0;i<16;i++) { preorder_ctrl = &psta->recvreorder_ctrl[i]; if (preorder_ctrl->enable) - { DBG_871X("tid =%d, indicate_seq =%d\n", i, preorder_ctrl->indicate_seq); - } } - } - else - { + } else { DBG_871X("can't get sta's macaddr, cur_network's macaddr:" MAC_FMT "\n", MAC_ARG(cur_network->network.MacAddress)); } break; @@ -3196,19 +2967,16 @@ static int rtw_dbg_port(struct net_device *dev, spin_lock_bh(&pstapriv->sta_hash_lock); - for (i = 0; i< NUM_STA; i++) - { + for (i = 0; i< NUM_STA; i++) { phead = &(pstapriv->sta_hash[i]); plist = get_next(phead); - while (phead != plist) - { + while (phead != plist) { psta = LIST_CONTAINOR(plist, struct sta_info, hash_list); plist = get_next(plist); - if (extra_arg == psta->aid) - { + if (extra_arg == psta->aid) { DBG_871X("sta's macaddr:" MAC_FMT "\n", MAC_ARG(psta->hwaddr)); DBG_871X("rtsen =%d, cts2slef =%d\n", psta->rtsen, psta->cts2self); DBG_871X("state = 0x%x, aid =%d, macid =%d, raid =%d\n", psta->state, psta->aid, psta->mac_id, psta->raid); @@ -3226,17 +2994,12 @@ static int rtw_dbg_port(struct net_device *dev, - for (j = 0;j<16;j++) - { + for (j = 0;j<16;j++) { preorder_ctrl = &psta->recvreorder_ctrl[j]; if (preorder_ctrl->enable) - { DBG_871X("tid =%d, indicate_seq =%d\n", j, preorder_ctrl->indicate_seq); - } } - } - } } @@ -3255,8 +3018,7 @@ static int rtw_dbg_port(struct net_device *dev, if (arg == 0) { DBG_871X("disable driver ctrl vcs\n"); padapter->driver_vcs_en = 0; - } - else if (arg == 1) { + } else if (arg == 1) { DBG_871X("enable driver ctrl vcs = %d\n", extra_arg); padapter->driver_vcs_en = 1; @@ -3272,8 +3034,7 @@ static int rtw_dbg_port(struct net_device *dev, DBG_871X("dump rx packet (%d)\n", extra_arg); /* pHalData->bDumpRxPkt =extra_arg; */ rtw_hal_set_def_var(padapter, HAL_DEF_DBG_DUMP_RXPKT, &(extra_arg)); - } - else if (arg == 1) { + } else if (arg == 1) { DBG_871X("dump tx packet (%d)\n", extra_arg); rtw_hal_set_def_var(padapter, HAL_DEF_DBG_DUMP_TXPKT, &(extra_arg)); } @@ -3284,8 +3045,7 @@ static int rtw_dbg_port(struct net_device *dev, if (arg == 0) { DBG_871X("disable driver ctrl rx_ampdu_factor\n"); padapter->driver_rx_ampdu_factor = 0xFF; - } - else if (arg == 1) { + } else if (arg == 1) { DBG_871X("enable driver ctrl rx_ampdu_factor = %d\n", extra_arg); @@ -3310,12 +3070,10 @@ static int rtw_dbg_port(struct net_device *dev, struct registry_priv *pregpriv = &padapter->registrypriv; /* 0: disable, bit(0):enable 2.4g, bit(1):enable 5g, 0x3: enable both 2.4g and 5g */ /* default is set to enable 2.4GHZ for IOT issue with bufflao's AP at 5GHZ */ - if (pregpriv && (extra_arg == 0 || extra_arg == 1|| extra_arg == 2 || extra_arg == 3)) - { + if (pregpriv && (extra_arg == 0 || extra_arg == 1|| extra_arg == 2 || extra_arg == 3)) { pregpriv->rx_stbc = extra_arg; DBG_871X("set rx_stbc =%d\n", pregpriv->rx_stbc); - } - else + } else DBG_871X("get rx_stbc =%d\n", pregpriv->rx_stbc); } @@ -3324,12 +3082,10 @@ static int rtw_dbg_port(struct net_device *dev, { struct registry_priv *pregpriv = &padapter->registrypriv; /* 0: disable, 0x1:enable (but wifi_spec should be 0), 0x2: force enable (don't care wifi_spec) */ - if (pregpriv && extra_arg < 3) - { + if (pregpriv && extra_arg < 3) { pregpriv->ampdu_enable = extra_arg; DBG_871X("set ampdu_enable =%d\n", pregpriv->ampdu_enable); - } - else + } else DBG_871X("get ampdu_enable =%d\n", pregpriv->ampdu_enable); } @@ -3343,8 +3099,7 @@ static int rtw_dbg_port(struct net_device *dev, { if (arg == 0xff) { rtw_odm_dbg_comp_msg(RTW_DBGDUMP, padapter); - } - else { + } else { u64 dbg_comp = (u64)extra_arg; rtw_odm_dbg_comp_set(padapter, dbg_comp); } @@ -3375,8 +3130,7 @@ static int rtw_dbg_port(struct net_device *dev, if (arg == 0) { DBG_871X("driver disable LDPC\n"); pregistrypriv->ldpc_cap = 0x00; - } - else if (arg == 1) { + } else if (arg == 1) { DBG_871X("driver set LDPC cap = 0x%x\n", extra_arg); pregistrypriv->ldpc_cap = (u8)(extra_arg&0x33); } @@ -3391,8 +3145,7 @@ static int rtw_dbg_port(struct net_device *dev, if (arg == 0) { DBG_871X("driver disable STBC\n"); pregistrypriv->stbc_cap = 0x00; - } - else if (arg == 1) { + } else if (arg == 1) { DBG_871X("driver set STBC cap = 0x%x\n", extra_arg); pregistrypriv->stbc_cap = (u8)(extra_arg&0x33); } @@ -3406,8 +3159,7 @@ static int rtw_dbg_port(struct net_device *dev, DBG_871X("disable driver ctrl max_rx_rate, reset to default_rate_set\n"); init_mlme_default_rate_set(padapter); pregistrypriv->ht_enable = (u8)rtw_ht_enable; - } - else if (arg == 1) { + } else if (arg == 1) { int i; u8 max_rx_rate; @@ -3416,18 +3168,15 @@ static int rtw_dbg_port(struct net_device *dev, max_rx_rate = (u8)extra_arg; - if (max_rx_rate < 0xc) /* max_rx_rate < MSC0 -> B or G -> disable HT */ - { + if (max_rx_rate < 0xc) { /* max_rx_rate < MSC0 -> B or G -> disable HT */ pregistrypriv->ht_enable = 0; - for (i = 0; i<NumRates; i++) - { + for (i = 0; i<NumRates; i++) { if (pmlmeext->datarate[i] > max_rx_rate) pmlmeext->datarate[i] = 0xff; } } - else if (max_rx_rate < 0x1c) /* mcs0~mcs15 */ - { + else if (max_rx_rate < 0x1c) { /* mcs0~mcs15 */ u32 mcs_bitmap = 0x0; for (i = 0; i<((max_rx_rate+1)-0xc); i++) @@ -3443,8 +3192,7 @@ static int rtw_dbg_port(struct net_device *dev, if (arg == 0) { DBG_871X("disable driver ctrl ampdu density\n"); padapter->driver_ampdu_spacing = 0xFF; - } - else if (arg == 1) { + } else if (arg == 1) { DBG_871X("enable driver ctrl ampdu density = %d\n", extra_arg); @@ -3531,15 +3279,12 @@ static int rtw_dbg_port(struct net_device *dev, break; case 0xdd:/* registers dump , 0 for mac reg, 1 for bb reg, 2 for rf reg */ { - if (extra_arg == 0) { + if (extra_arg == 0) mac_reg_dump(RTW_DBGDUMP, padapter); - } - else if (extra_arg == 1) { + else if (extra_arg == 1) bb_reg_dump(RTW_DBGDUMP, padapter); - } - else if (extra_arg ==2) { + else if (extra_arg ==2) rf_reg_dump(RTW_DBGDUMP, padapter); - } } break; @@ -3557,8 +3302,7 @@ static int rtw_dbg_port(struct net_device *dev, DBG_871X("extra_arg = 4 - disable BT coexistence - BIT(3)\n"); DBG_871X("extra_arg = 5 - disable antenna diversity - BIT(4)\n"); DBG_871X("extra_arg = 6 - enable all dynamic func\n"); - } - else { + } else { /*extra_arg = 0 - disable all dynamic func extra_arg = 1 - disable DIG extra_arg = 2 - disable tx power tracking @@ -3634,8 +3378,7 @@ static int wpa_set_param(struct net_device *dev, u8 name, u32 value) /* ret = ieee80211_wpa_enable(ieee, value); */ - switch ((value)&0xff) - { + switch ((value)&0xff) { case 1 : /* WPA */ padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeWPAPSK; /* WPA_PSK */ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption2Enabled; @@ -3721,8 +3464,7 @@ static int wpa_mlme(struct net_device *dev, u32 command, u32 reason) int ret = 0; struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); - switch (command) - { + switch (command) { case IEEE_MLME_STA_DEAUTH: if (!rtw_set_802_11_disassociate(padapter)) @@ -3759,14 +3501,12 @@ static int wpa_supplicant_ioctl(struct net_device *dev, struct iw_point *p) } param = (struct ieee_param *)rtw_malloc(p->length); - if (param == NULL) - { + if (param == NULL) { ret = -ENOMEM; goto out; } - if (copy_from_user(param, p->pointer, p->length)) - { + if (copy_from_user(param, p->pointer, p->length)) { kfree(param); ret = -EFAULT; goto out; @@ -3829,35 +3569,28 @@ static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param, /* sizeof(struct ieee_param) = 64 bytes; */ /* if (param_len != (u32) ((u8 *) param->u.crypt.key - (u8 *) param) + param->u.crypt.key_len) */ - if (param_len != sizeof(struct ieee_param) + param->u.crypt.key_len) - { + if (param_len != sizeof(struct ieee_param) + param->u.crypt.key_len) { ret = -EINVAL; goto exit; } if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff && param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && - param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) - { - if (param->u.crypt.idx >= WEP_KEYS) - { + param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) { + if (param->u.crypt.idx >= WEP_KEYS) { ret = -EINVAL; goto exit; } - } - else - { + } else { psta = rtw_get_stainfo(pstapriv, param->sta_addr); - if (!psta) - { + if (!psta) { /* ret = -EINVAL; */ DBG_871X("rtw_set_encryption(), sta has already been removed or never been added\n"); goto exit; } } - if (strcmp(param->u.crypt.alg, "none") == 0 && (psta == NULL)) - { + if (strcmp(param->u.crypt.alg, "none") == 0 && (psta == NULL)) { /* todo:clear default encryption keys */ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Open; @@ -3871,8 +3604,7 @@ static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param, } - if (strcmp(param->u.crypt.alg, "WEP") == 0 && (psta == NULL)) - { + if (strcmp(param->u.crypt.alg, "WEP") == 0 && (psta == NULL)) { DBG_871X("r871x_set_encryption, crypt.alg = WEP\n"); wep_key_idx = param->u.crypt.idx; @@ -3880,15 +3612,13 @@ static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param, DBG_871X("r871x_set_encryption, wep_key_idx =%d, len =%d\n", wep_key_idx, wep_key_len); - if ((wep_key_idx >= WEP_KEYS) || (wep_key_len<= 0)) - { + if ((wep_key_idx >= WEP_KEYS) || (wep_key_len<= 0)) { ret = -EINVAL; goto exit; } - if (wep_key_len > 0) - { + if (wep_key_len > 0) { wep_key_len = wep_key_len <= 5 ? 5 : 13; wep_total_len = wep_key_len + FIELD_OFFSET(struct ndis_802_11_wep, KeyMaterial); pwep =(struct ndis_802_11_wep *)rtw_malloc(wep_total_len); @@ -3908,8 +3638,7 @@ static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param, memcpy(pwep->KeyMaterial, param->u.crypt.key, pwep->KeyLength); - if (param->u.crypt.set_tx) - { + if (param->u.crypt.set_tx) { DBG_871X("wep, set_tx = 1\n"); psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Auto; @@ -3917,8 +3646,7 @@ static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param, psecuritypriv->dot11PrivacyAlgrthm = _WEP40_; psecuritypriv->dot118021XGrpPrivacy = _WEP40_; - if (pwep->KeyLength == 13) - { + if (pwep->KeyLength == 13) { psecuritypriv->dot11PrivacyAlgrthm = _WEP104_; psecuritypriv->dot118021XGrpPrivacy = _WEP104_; } @@ -3931,9 +3659,7 @@ static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param, psecuritypriv->dot11DefKeylen[wep_key_idx]=pwep->KeyLength; rtw_ap_set_wep_key(padapter, pwep->KeyMaterial, pwep->KeyLength, wep_key_idx, 1); - } - else - { + } else { DBG_871X("wep, set_tx = 0\n"); /* don't update "psecuritypriv->dot11PrivacyAlgrthm" and */ @@ -3951,25 +3677,18 @@ static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param, } - if (!psta && check_fwstate(pmlmepriv, WIFI_AP_STATE)) /* group key */ - { - if (param->u.crypt.set_tx == 1) - { - if (strcmp(param->u.crypt.alg, "WEP") == 0) - { + if (!psta && check_fwstate(pmlmepriv, WIFI_AP_STATE)) { /* group key */ + if (param->u.crypt.set_tx == 1) { + if (strcmp(param->u.crypt.alg, "WEP") == 0) { DBG_871X("%s, set group_key, WEP\n", __func__); memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len)); psecuritypriv->dot118021XGrpPrivacy = _WEP40_; if (param->u.crypt.key_len == 13) - { psecuritypriv->dot118021XGrpPrivacy = _WEP104_; - } - } - else if (strcmp(param->u.crypt.alg, "TKIP") == 0) - { + } else if (strcmp(param->u.crypt.alg, "TKIP") == 0) { DBG_871X("%s, set group_key, TKIP\n", __func__); psecuritypriv->dot118021XGrpPrivacy = _TKIP_; @@ -3984,16 +3703,13 @@ static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param, psecuritypriv->busetkipkey = true; } - else if (strcmp(param->u.crypt.alg, "CCMP") == 0) - { + else if (strcmp(param->u.crypt.alg, "CCMP") == 0) { DBG_871X("%s, set group_key, CCMP\n", __func__); psecuritypriv->dot118021XGrpPrivacy = _AES_; memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len)); - } - else - { + } else { DBG_871X("%s, set group_key, none\n", __func__); psecuritypriv->dot118021XGrpPrivacy = _NO_PRIVACY_; @@ -4008,38 +3724,28 @@ static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param, rtw_ap_set_group_key(padapter, param->u.crypt.key, psecuritypriv->dot118021XGrpPrivacy, param->u.crypt.idx); pbcmc_sta =rtw_get_bcmc_stainfo(padapter); - if (pbcmc_sta) - { + if (pbcmc_sta) { pbcmc_sta->ieee8021x_blocked = false; pbcmc_sta->dot118021XPrivacy = psecuritypriv->dot118021XGrpPrivacy;/* rx will use bmc_sta's dot118021XPrivacy */ } - } goto exit; } - if (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X && psta) /* psk/802_1x */ - { - if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) - { - if (param->u.crypt.set_tx == 1) - { + if (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X && psta) { /* psk/802_1x */ + if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { + if (param->u.crypt.set_tx == 1) { memcpy(psta->dot118021x_UncstKey.skey, param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len)); - if (strcmp(param->u.crypt.alg, "WEP") == 0) - { + if (strcmp(param->u.crypt.alg, "WEP") == 0) { DBG_871X("%s, set pairwise key, WEP\n", __func__); psta->dot118021XPrivacy = _WEP40_; if (param->u.crypt.key_len == 13) - { psta->dot118021XPrivacy = _WEP104_; - } - } - else if (strcmp(param->u.crypt.alg, "TKIP") == 0) - { + } else if (strcmp(param->u.crypt.alg, "TKIP") == 0) { DBG_871X("%s, set pairwise key, TKIP\n", __func__); psta->dot118021XPrivacy = _TKIP_; @@ -4051,16 +3757,12 @@ static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param, psecuritypriv->busetkipkey = true; - } - else if (strcmp(param->u.crypt.alg, "CCMP") == 0) - { + } else if (strcmp(param->u.crypt.alg, "CCMP") == 0) { DBG_871X("%s, set pairwise key, CCMP\n", __func__); psta->dot118021XPrivacy = _AES_; - } - else - { + } else { DBG_871X("%s, set pairwise key, none\n", __func__); psta->dot118021XPrivacy = _NO_PRIVACY_; @@ -4070,21 +3772,14 @@ static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param, psta->ieee8021x_blocked = false; - } - else/* group key??? */ - { - if (strcmp(param->u.crypt.alg, "WEP") == 0) - { + } else { /* group key??? */ + if (strcmp(param->u.crypt.alg, "WEP") == 0) { memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len)); psecuritypriv->dot118021XGrpPrivacy = _WEP40_; if (param->u.crypt.key_len == 13) - { psecuritypriv->dot118021XGrpPrivacy = _WEP104_; - } - } - else if (strcmp(param->u.crypt.alg, "TKIP") == 0) - { + } else if (strcmp(param->u.crypt.alg, "TKIP") == 0) { psecuritypriv->dot118021XGrpPrivacy = _TKIP_; memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len)); @@ -4096,15 +3791,11 @@ static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param, psecuritypriv->busetkipkey = true; - } - else if (strcmp(param->u.crypt.alg, "CCMP") == 0) - { + } else if (strcmp(param->u.crypt.alg, "CCMP") == 0) { psecuritypriv->dot118021XGrpPrivacy = _AES_; memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len)); - } - else - { + } else { psecuritypriv->dot118021XGrpPrivacy = _NO_PRIVACY_; } @@ -4117,16 +3808,12 @@ static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param, rtw_ap_set_group_key(padapter, param->u.crypt.key, psecuritypriv->dot118021XGrpPrivacy, param->u.crypt.idx); pbcmc_sta =rtw_get_bcmc_stainfo(padapter); - if (pbcmc_sta) - { + if (pbcmc_sta) { pbcmc_sta->ieee8021x_blocked = false; pbcmc_sta->dot118021XPrivacy = psecuritypriv->dot118021XGrpPrivacy;/* rx will use bmc_sta's dot118021XPrivacy */ } - } - } - } exit: @@ -4196,14 +3883,11 @@ static int rtw_add_sta(struct net_device *dev, struct ieee_param *param) DBG_871X("rtw_add_sta(aid =%d) =" MAC_FMT "\n", param->u.add_sta.aid, MAC_ARG(param->sta_addr)); if (check_fwstate(pmlmepriv, (_FW_LINKED|WIFI_AP_STATE)) != true) - { return -EINVAL; - } if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff && param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && - param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) - { + param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) { return -EINVAL; } @@ -4221,8 +3905,7 @@ static int rtw_add_sta(struct net_device *dev, struct ieee_param *param) */ /* psta = rtw_alloc_stainfo(pstapriv, param->sta_addr); */ psta = rtw_get_stainfo(pstapriv, param->sta_addr); - if (psta) - { + if (psta) { int flags = param->u.add_sta.flags; /* DBG_871X("rtw_add_sta(), init sta's variables, psta =%p\n", psta); */ @@ -4242,14 +3925,11 @@ static int rtw_add_sta(struct net_device *dev, struct ieee_param *param) psta->qos_option = 0; /* chec 802.11n ht cap. */ - if (WLAN_STA_HT&flags) - { + if (WLAN_STA_HT&flags) { psta->htpriv.ht_option = true; psta->qos_option = 1; memcpy((void*)&psta->htpriv.ht_cap, (void*)¶m->u.add_sta.ht_cap, sizeof(struct rtw_ieee80211_ht_cap)); - } - else - { + } else { psta->htpriv.ht_option = false; } @@ -4259,9 +3939,7 @@ static int rtw_add_sta(struct net_device *dev, struct ieee_param *param) update_sta_info_apmode(padapter, psta); - } - else - { + } else { ret = -ENOMEM; } @@ -4280,27 +3958,22 @@ static int rtw_del_sta(struct net_device *dev, struct ieee_param *param) DBG_871X("rtw_del_sta =" MAC_FMT "\n", MAC_ARG(param->sta_addr)); if (check_fwstate(pmlmepriv, (_FW_LINKED|WIFI_AP_STATE)) != true) - { return -EINVAL; - } if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff && param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && - param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) - { + param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) { return -EINVAL; } psta = rtw_get_stainfo(pstapriv, param->sta_addr); - if (psta) - { + if (psta) { u8 updated =false; /* DBG_871X("free psta =%p, aid =%d\n", psta, psta->aid); */ spin_lock_bh(&pstapriv->asoc_list_lock); - if (list_empty(&psta->asoc_list) ==false) - { + if (list_empty(&psta->asoc_list) ==false) { list_del_init(&psta->asoc_list); pstapriv->asoc_list_cnt--; updated = ap_free_sta(padapter, psta, true, WLAN_REASON_DEAUTH_LEAVING); @@ -4312,9 +3985,7 @@ static int rtw_del_sta(struct net_device *dev, struct ieee_param *param) psta = NULL; - } - else - { + } else { DBG_871X("rtw_del_sta(), sta has already been removed or never been added\n"); /* ret = -1; */ @@ -4338,20 +4009,16 @@ static int rtw_ioctl_get_sta_data(struct net_device *dev, struct ieee_param *par DBG_871X("rtw_ioctl_get_sta_info, sta_addr: " MAC_FMT "\n", MAC_ARG(param_ex->sta_addr)); if (check_fwstate(pmlmepriv, (_FW_LINKED|WIFI_AP_STATE)) != true) - { return -EINVAL; - } if (param_ex->sta_addr[0] == 0xff && param_ex->sta_addr[1] == 0xff && param_ex->sta_addr[2] == 0xff && param_ex->sta_addr[3] == 0xff && - param_ex->sta_addr[4] == 0xff && param_ex->sta_addr[5] == 0xff) - { + param_ex->sta_addr[4] == 0xff && param_ex->sta_addr[5] == 0xff) { return -EINVAL; } psta = rtw_get_stainfo(pstapriv, param_ex->sta_addr); - if (psta) - { + if (psta) { psta_data->aid = (u16)psta->aid; psta_data->capability = psta->capability; psta_data->flags = psta->flags; @@ -4384,9 +4051,7 @@ static int rtw_ioctl_get_sta_data(struct net_device *dev, struct ieee_param *par psta_data->tx_drops = psta->sta_stats.tx_drops; - } - else - { + } else { ret = -1; } @@ -4405,22 +4070,17 @@ static int rtw_get_sta_wpaie(struct net_device *dev, struct ieee_param *param) DBG_871X("rtw_get_sta_wpaie, sta_addr: " MAC_FMT "\n", MAC_ARG(param->sta_addr)); if (check_fwstate(pmlmepriv, (_FW_LINKED|WIFI_AP_STATE)) != true) - { return -EINVAL; - } if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff && param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && - param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) - { + param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) { return -EINVAL; } psta = rtw_get_stainfo(pstapriv, param->sta_addr); - if (psta) - { - if ((psta->wpa_ie[0] == WLAN_EID_RSN) || (psta->wpa_ie[0] == WLAN_EID_GENERIC)) - { + if (psta) { + if ((psta->wpa_ie[0] == WLAN_EID_RSN) || (psta->wpa_ie[0] == WLAN_EID_GENERIC)) { int wpa_ie_len; int copy_len; @@ -4431,15 +4091,11 @@ static int rtw_get_sta_wpaie(struct net_device *dev, struct ieee_param *param) param->u.wpa_ie.len = copy_len; memcpy(param->u.wpa_ie.reserved, psta->wpa_ie, copy_len); - } - else - { + } else { /* ret = -1; */ DBG_871X("sta's wpa_ie is NONE\n"); } - } - else - { + } else { ret = -1; } @@ -4464,14 +4120,10 @@ static int rtw_set_wps_beacon(struct net_device *dev, struct ieee_param *param, ie_len = len-12-2;/* 12 = param header, 2:no packed */ - if (pmlmepriv->wps_beacon_ie) - { - kfree(pmlmepriv->wps_beacon_ie); - pmlmepriv->wps_beacon_ie = NULL; - } + kfree(pmlmepriv->wps_beacon_ie); + pmlmepriv->wps_beacon_ie = NULL; - if (ie_len>0) - { + if (ie_len>0) { pmlmepriv->wps_beacon_ie = rtw_malloc(ie_len); pmlmepriv->wps_beacon_ie_len = ie_len; if (pmlmepriv->wps_beacon_ie == NULL) { @@ -4484,7 +4136,6 @@ static int rtw_set_wps_beacon(struct net_device *dev, struct ieee_param *param, update_beacon(padapter, _VENDOR_SPECIFIC_IE_, wps_oui, true); pmlmeext->bstart_bss = true; - } @@ -4507,14 +4158,10 @@ static int rtw_set_wps_probe_resp(struct net_device *dev, struct ieee_param *par ie_len = len-12-2;/* 12 = param header, 2:no packed */ - if (pmlmepriv->wps_probe_resp_ie) - { - kfree(pmlmepriv->wps_probe_resp_ie); - pmlmepriv->wps_probe_resp_ie = NULL; - } + kfree(pmlmepriv->wps_probe_resp_ie); + pmlmepriv->wps_probe_resp_ie = NULL; - if (ie_len>0) - { + if (ie_len>0) { pmlmepriv->wps_probe_resp_ie = rtw_malloc(ie_len); pmlmepriv->wps_probe_resp_ie_len = ie_len; if (pmlmepriv->wps_probe_resp_ie == NULL) { @@ -4544,14 +4191,10 @@ static int rtw_set_wps_assoc_resp(struct net_device *dev, struct ieee_param *par ie_len = len-12-2;/* 12 = param header, 2:no packed */ - if (pmlmepriv->wps_assoc_resp_ie) - { - kfree(pmlmepriv->wps_assoc_resp_ie); - pmlmepriv->wps_assoc_resp_ie = NULL; - } + kfree(pmlmepriv->wps_assoc_resp_ie); + pmlmepriv->wps_assoc_resp_ie = NULL; - if (ie_len>0) - { + if (ie_len>0) { pmlmepriv->wps_assoc_resp_ie = rtw_malloc(ie_len); pmlmepriv->wps_assoc_resp_ie_len = ie_len; if (pmlmepriv->wps_assoc_resp_ie == NULL) { @@ -4632,8 +4275,7 @@ static int rtw_ioctl_acl_remove_sta(struct net_device *dev, struct ieee_param *p if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff && param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && - param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) - { + param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) { return -EINVAL; } @@ -4654,8 +4296,7 @@ static int rtw_ioctl_acl_add_sta(struct net_device *dev, struct ieee_param *para if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff && param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && - param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) - { + param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) { return -EINVAL; } @@ -4705,14 +4346,12 @@ static int rtw_hostapd_ioctl(struct net_device *dev, struct iw_point *p) } param = (struct ieee_param *)rtw_malloc(p->length); - if (param == NULL) - { + if (param == NULL) { ret = -ENOMEM; goto out; } - if (copy_from_user(param, p->pointer, p->length)) - { + if (copy_from_user(param, p->pointer, p->length)) { kfree(param); ret = -EFAULT; goto out; @@ -4720,8 +4359,7 @@ static int rtw_hostapd_ioctl(struct net_device *dev, struct iw_point *p) /* DBG_871X("%s, cmd =%d\n", __func__, param->cmd); */ - switch (param->cmd) - { + switch (param->cmd) { case RTL871X_HOSTAPD_FLUSH: ret = rtw_hostapd_sta_flush(dev); @@ -4861,8 +4499,7 @@ static int rtw_wx_set_priv(struct net_device *dev, /* dev->name, ext)); */ #ifdef DEBUG_RTW_WX_SET_PRIV - if (!(ext_dbg = vmalloc(len))) - { + if (!(ext_dbg = vmalloc(len))) { vfree(ext, len); return -ENOMEM; } @@ -4871,8 +4508,7 @@ static int rtw_wx_set_priv(struct net_device *dev, #endif /* added for wps2.0 @20110524 */ - if (dwrq->flags == 0x8766 && len > 8) - { + if (dwrq->flags == 0x8766 && len > 8) { u32 cp_sz; struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); u8 *probereq_wpsie = ext; @@ -4880,12 +4516,10 @@ static int rtw_wx_set_priv(struct net_device *dev, u8 wps_oui[4]={0x0, 0x50, 0xf2, 0x04}; if ((_VENDOR_SPECIFIC_IE_ == probereq_wpsie[0]) && - (!memcmp(&probereq_wpsie[2], wps_oui, 4))) - { + (!memcmp(&probereq_wpsie[2], wps_oui, 4))) { cp_sz = probereq_wpsie_len>MAX_WPS_IE_LEN ? MAX_WPS_IE_LEN:probereq_wpsie_len; - if (pmlmepriv->wps_probe_req_ie) - { + if (pmlmepriv->wps_probe_req_ie) { pmlmepriv->wps_probe_req_ie_len = 0; kfree(pmlmepriv->wps_probe_req_ie); pmlmepriv->wps_probe_req_ie = NULL; @@ -4909,8 +4543,7 @@ static int rtw_wx_set_priv(struct net_device *dev, } if (len >= WEXT_CSCAN_HEADER_SIZE - && !memcmp(ext, WEXT_CSCAN_HEADER, WEXT_CSCAN_HEADER_SIZE) - ) { + && !memcmp(ext, WEXT_CSCAN_HEADER, WEXT_CSCAN_HEADER_SIZE)) { ret = rtw_wx_set_scan(dev, info, awrq, ext); goto FREE_EXT; } @@ -4939,17 +4572,13 @@ static int rtw_pm_set(struct net_device *dev, DBG_871X("[%s] extra = %s\n", __func__, extra); - if (!memcmp(extra, "lps =", 4)) - { + if (!memcmp(extra, "lps =", 4)) { sscanf(extra+4, "%u", &mode); ret = rtw_pm_set_lps(padapter, mode); - } - else if (!memcmp(extra, "ips =", 4)) - { + } else if (!memcmp(extra, "ips =", 4)) { sscanf(extra+4, "%u", &mode); ret = rtw_pm_set_ips(padapter, mode); - } - else { + } else { ret = -EINVAL; } @@ -5015,8 +4644,7 @@ static int rtw_widi_set_probe_request(struct net_device *dev, struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); pbuf = rtw_malloc(sizeof(l2_msg_t)); - if (pbuf) - { + if (pbuf) { if (copy_from_user(pbuf, wrqu->data.pointer, wrqu->data.length)) ret = -EFAULT; /* memcpy(pbuf, wrqu->data.pointer, wrqu->data.length); */ @@ -5067,17 +4695,12 @@ static int rtw_test( } if (strcmp(pch, "bton") == 0) - { rtw_btcoex_SetManualControl(padapter, false); - } if (strcmp(pch, "btoff") == 0) - { rtw_btcoex_SetManualControl(padapter, true); - } - if (strcmp(pch, "h2c") == 0) - { + if (strcmp(pch, "h2c") == 0) { u8 param[8]; u8 count = 0; u32 tmp; @@ -5104,9 +4727,8 @@ static int rtw_test( ret = rtw_hal_fill_h2c_cmd(padapter, param[0], count-1, ¶m[1]); pos = sprintf(extra, "H2C ID = 0x%02x content =", param[0]); - for (i = 1; i<count; i++) { + for (i = 1; i<count; i++) pos += sprintf(extra+pos, "%02x,", param[i]); - } extra[pos] = 0; pos--; pos += sprintf(extra+pos, " %s", ret == _FAIL?"FAIL":"OK"); @@ -5118,8 +4740,7 @@ static int rtw_test( return 0; } -static iw_handler rtw_handlers[] = -{ +static iw_handler rtw_handlers[] = { NULL, /* SIOCSIWCOMMIT */ rtw_wx_get_name, /* SIOCGIWNAME */ dummy, /* SIOCSIWNWID */ @@ -5293,8 +4914,7 @@ static const struct iw_priv_args rtw_private_args[] = { #endif }; -static iw_handler rtw_private_handler[] = -{ +static iw_handler rtw_private_handler[] = { rtw_wx_write32, /* 0x00 */ rtw_wx_read32, /* 0x01 */ rtw_drvext_hdl, /* 0x02 */ @@ -5350,14 +4970,12 @@ static struct iw_statistics *rtw_get_wireless_stats(struct net_device *dev) int tmp_qual = 0; int tmp_noise = 0; - if (check_fwstate(&padapter->mlmepriv, _FW_LINKED) != true) - { + if (check_fwstate(&padapter->mlmepriv, _FW_LINKED) != true) { piwstats->qual.qual = 0; piwstats->qual.level = 0; piwstats->qual.noise = 0; /* DBG_871X("No link level:%d, qual:%d, noise:%d\n", tmp_level, tmp_qual, tmp_noise); */ - } - else { + } else { #ifdef CONFIG_SIGNAL_DISPLAY_DBM tmp_level = translate_percentage_to_dbm(padapter->recvpriv.signal_strength); #else @@ -5409,8 +5027,7 @@ static struct iw_statistics *rtw_get_wireless_stats(struct net_device *dev) return &padapter->iwstats; } -struct iw_handler_def rtw_handlers_def = -{ +struct iw_handler_def rtw_handlers_def = { .standard = rtw_handlers, .num_standard = sizeof(rtw_handlers) / sizeof(iw_handler), #if defined(CONFIG_WEXT_PRIV) @@ -5523,8 +5140,7 @@ static int rtw_ioctl_wext_private(struct net_device *dev, union iwreq_data *wrq_ } /* Watch out for sub-ioctls ! */ - if (priv_args[k].cmd < SIOCDEVPRIVATE) - { + if (priv_args[k].cmd < SIOCDEVPRIVATE) { int j = -1; /* Find the matching *real* ioctl */ @@ -5554,12 +5170,10 @@ static int rtw_ioctl_wext_private(struct net_device *dev, union iwreq_data *wrq_ /* If we have to set some data */ if ((priv_args[k].set_args & IW_PRIV_TYPE_MASK) && - (priv_args[k].set_args & IW_PRIV_SIZE_MASK)) - { + (priv_args[k].set_args & IW_PRIV_SIZE_MASK)) { u8 *str; - switch (priv_args[k].set_args & IW_PRIV_TYPE_MASK) - { + switch (priv_args[k].set_args & IW_PRIV_TYPE_MASK) { case IW_PRIV_TYPE_BYTE: /* Fetch args */ count = 0; @@ -5597,8 +5211,7 @@ static int rtw_ioctl_wext_private(struct net_device *dev, union iwreq_data *wrq_ break; case IW_PRIV_TYPE_CHAR: - if (len > 0) - { + if (len > 0) { /* Size of the string to fetch */ wdata.data.length = len; if (wdata.data.length > (priv_args[k].set_args & IW_PRIV_SIZE_MASK)) @@ -5606,9 +5219,7 @@ static int rtw_ioctl_wext_private(struct net_device *dev, union iwreq_data *wrq_ /* Fetch string */ memcpy(buffer, ptr, wdata.data.length); - } - else - { + } else { wdata.data.length = 1; buffer[0] = '\0'; } @@ -5622,41 +5233,32 @@ static int rtw_ioctl_wext_private(struct net_device *dev, union iwreq_data *wrq_ } if ((priv_args[k].set_args & IW_PRIV_SIZE_FIXED) && - (wdata.data.length != (priv_args[k].set_args & IW_PRIV_SIZE_MASK))) - { + (wdata.data.length != (priv_args[k].set_args & IW_PRIV_SIZE_MASK))) { DBG_8192C("%s: The command %s needs exactly %d argument(s)...\n", __func__, cmdname, priv_args[k].set_args & IW_PRIV_SIZE_MASK); err = -EINVAL; goto exit; } - } /* if args to set */ - else - { + } else { /* if args to set */ wdata.data.length = 0L; } /* Those two tests are important. They define how the driver * will have to handle the data */ if ((priv_args[k].set_args & IW_PRIV_SIZE_FIXED) && - ((get_priv_size(priv_args[k].set_args) + offset) <= IFNAMSIZ)) - { + ((get_priv_size(priv_args[k].set_args) + offset) <= IFNAMSIZ)) { /* First case : all SET args fit within wrq */ if (offset) wdata.mode = subcmd; memcpy(wdata.name + offset, buffer, IFNAMSIZ - offset); - } - else - { + } else { if ((priv_args[k].set_args == 0) && (priv_args[k].get_args & IW_PRIV_SIZE_FIXED) && - (get_priv_size(priv_args[k].get_args) <= IFNAMSIZ)) - { + (get_priv_size(priv_args[k].get_args) <= IFNAMSIZ)) { /* Second case : no SET args, GET args fit within wrq */ if (offset) wdata.mode = subcmd; - } - else - { + } else { /* Third case : args won't fit in wrq, or variable number of args */ if (copy_to_user(wdata.data.pointer, buffer, buffer_len)) { err = -EFAULT; @@ -5670,8 +5272,7 @@ static int rtw_ioctl_wext_private(struct net_device *dev, union iwreq_data *wrq_ input = NULL; extra_size = 0; - if (IW_IS_SET(priv_args[k].cmd)) - { + if (IW_IS_SET(priv_args[k].cmd)) { /* Size of set arguments */ extra_size = get_priv_size(priv_args[k].set_args); @@ -5701,8 +5302,7 @@ static int rtw_ioctl_wext_private(struct net_device *dev, union iwreq_data *wrq_ /* If we have to get some data */ if ((priv_args[k].get_args & IW_PRIV_TYPE_MASK) && - (priv_args[k].get_args & IW_PRIV_SIZE_MASK)) - { + (priv_args[k].get_args & IW_PRIV_SIZE_MASK)) { int j; int n = 0; /* number of args */ u8 str[20] = {0}; @@ -5720,12 +5320,10 @@ static int rtw_ioctl_wext_private(struct net_device *dev, union iwreq_data *wrq_ goto exit; } - switch (priv_args[k].get_args & IW_PRIV_TYPE_MASK) - { + switch (priv_args[k].get_args & IW_PRIV_TYPE_MASK) { case IW_PRIV_TYPE_BYTE: /* Display args */ - for (j = 0; j < n; j++) - { + for (j = 0; j < n; j++) { sprintf(str, "%d ", extra[j]); len = strlen(str); output_len = strlen(output); @@ -5739,8 +5337,7 @@ static int rtw_ioctl_wext_private(struct net_device *dev, union iwreq_data *wrq_ case IW_PRIV_TYPE_INT: /* Display args */ - for (j = 0; j < n; j++) - { + for (j = 0; j < n; j++) { sprintf(str, "%d ", ((__s32*)extra)[j]); len = strlen(str); output_len = strlen(output); @@ -5769,9 +5366,7 @@ static int rtw_ioctl_wext_private(struct net_device *dev, union iwreq_data *wrq_ err = -EFAULT; goto exit; } - } /* if args to set */ - else - { + } else { /* if args to set */ wrq_data->data.length = 0; } @@ -5788,8 +5383,7 @@ int rtw_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) struct iwreq *wrq = (struct iwreq *)rq; int ret = 0; - switch (cmd) - { + switch (cmd) { case RTL_IOCTL_WPA_SUPPLICANT: ret = wpa_supplicant_ioctl(dev, &wrq->u.data); break; diff --git a/drivers/staging/rtl8723bs/os_dep/mlme_linux.c b/drivers/staging/rtl8723bs/os_dep/mlme_linux.c index 46315d1a82f7..80ca2d781c5d 100644 --- a/drivers/staging/rtl8723bs/os_dep/mlme_linux.c +++ b/drivers/staging/rtl8723bs/os_dep/mlme_linux.c @@ -21,7 +21,7 @@ static void _dynamic_check_timer_handlder (void *FunctionContext) { - struct adapter *adapter = (struct adapter *)FunctionContext; + struct adapter *adapter = FunctionContext; rtw_dynamic_check_timer_handlder(adapter); @@ -30,7 +30,7 @@ static void _dynamic_check_timer_handlder (void *FunctionContext) static void _rtw_set_scan_deny_timer_hdl(void *FunctionContext) { - struct adapter *adapter = (struct adapter *)FunctionContext; + struct adapter *adapter = FunctionContext; rtw_set_scan_deny_timer_hdl(adapter); } @@ -91,8 +91,6 @@ void rtw_reset_securitypriv(struct adapter *adapter) /* Backup the btkip_countermeasure information. */ /* When the countermeasure is trigger, the driver have to disconnect with AP for 60 seconds. */ - memset(&backupPMKIDList[ 0 ], 0x00, sizeof(RT_PMKID_LIST) * NUM_PMKID_CACHE); - memcpy(&backupPMKIDList[ 0 ], &adapter->securitypriv.PMKIDList[ 0 ], sizeof(RT_PMKID_LIST) * NUM_PMKID_CACHE); backupPMKIDIndex = adapter->securitypriv.PMKIDIndex; backupTKIPCountermeasure = adapter->securitypriv.btkip_countermeasure; diff --git a/drivers/staging/rtl8723bs/os_dep/osdep_service.c b/drivers/staging/rtl8723bs/os_dep/osdep_service.c index aa16d1ab955b..a05daf06a870 100644 --- a/drivers/staging/rtl8723bs/os_dep/osdep_service.c +++ b/drivers/staging/rtl8723bs/os_dep/osdep_service.c @@ -73,7 +73,7 @@ inline int _rtw_netif_rx(_nic_hdl ndev, struct sk_buff *skb) void rtw_init_timer(_timer *ptimer, void *padapter, void *pfunc) { - struct adapter *adapter = (struct adapter *)padapter; + struct adapter *adapter = padapter; _init_timer(ptimer, adapter->pnetdev, pfunc, adapter); } diff --git a/drivers/staging/rtl8723bs/os_dep/sdio_intf.c b/drivers/staging/rtl8723bs/os_dep/sdio_intf.c index d2fb489d2e83..943324877707 100644 --- a/drivers/staging/rtl8723bs/os_dep/sdio_intf.c +++ b/drivers/staging/rtl8723bs/os_dep/sdio_intf.c @@ -138,7 +138,7 @@ static void sdio_free_irq(struct dvobj_priv *dvobj) extern unsigned int oob_irq; static irqreturn_t gpio_hostwakeup_irq_thread(int irq, void *data) { - struct adapter *padapter = (struct adapter *)data; + struct adapter *padapter = data; DBG_871X_LEVEL(_drv_always_, "gpio_hostwakeup_irq_thread\n"); /* Disable interrupt before calling handler */ /* disable_irq_nosync(oob_irq); */ diff --git a/drivers/staging/rtl8723bs/os_dep/sdio_ops_linux.c b/drivers/staging/rtl8723bs/os_dep/sdio_ops_linux.c index 3aa3e6548fd5..3108a625ada3 100644 --- a/drivers/staging/rtl8723bs/os_dep/sdio_ops_linux.c +++ b/drivers/staging/rtl8723bs/os_dep/sdio_ops_linux.c @@ -431,7 +431,7 @@ s32 _sd_read(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, void *pdata) if (unlikely((cnt == 1) || (cnt == 2))) { int i; - u8 *pbuf = (u8 *)pdata; + u8 *pbuf = pdata; for (i = 0; i < cnt; i++) { @@ -534,7 +534,7 @@ s32 _sd_write(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, void *pdata) if (unlikely((cnt == 1) || (cnt == 2))) { int i; - u8 *pbuf = (u8 *)pdata; + u8 *pbuf = pdata; for (i = 0; i < cnt; i++) { diff --git a/drivers/staging/rtl8723bs/os_dep/xmit_linux.c b/drivers/staging/rtl8723bs/os_dep/xmit_linux.c index 76968161f936..f29e110f9bdb 100644 --- a/drivers/staging/rtl8723bs/os_dep/xmit_linux.c +++ b/drivers/staging/rtl8723bs/os_dep/xmit_linux.c @@ -37,7 +37,7 @@ uint _rtw_pktfile_read (struct pkt_file *pfile, u8 *rmem, uint rlen) uint len = 0; len = rtw_remainder_len(pfile); - len = (rlen > len)? len: rlen; + len = (rlen > len) ? len : rlen; if (rmem) skb_copy_bits(pfile->pkt, pfile->buf_len-pfile->pkt_len, rmem, len); @@ -134,7 +134,7 @@ static void rtw_check_xmit_resource(struct adapter *padapter, _pkt *pkt) netif_stop_subqueue(padapter->pnetdev, queue); } } else { - if (pxmitpriv->free_xmitframe_cnt<=4) { + if (pxmitpriv->free_xmitframe_cnt <= 4) { if (!netif_tx_queue_stopped(netdev_get_tx_queue(padapter->pnetdev, queue))) netif_stop_subqueue(padapter->pnetdev, queue); } @@ -150,8 +150,8 @@ static int rtw_mlcst2unicst(struct adapter *padapter, struct sk_buff *skb) struct sta_info *psta = NULL; u8 chk_alive_num = 0; char chk_alive_list[NUM_STA]; - u8 bc_addr[6]={0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - u8 null_addr[6]={0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + u8 bc_addr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + u8 null_addr[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; int i; s32 res; @@ -177,7 +177,7 @@ static int rtw_mlcst2unicst(struct adapter *padapter, struct sk_buff *skb) for (i = 0; i < chk_alive_num; i++) { psta = rtw_get_stainfo_by_offset(pstapriv, chk_alive_list[i]); - if (!(psta->state &_FW_LINKED)) + if (!(psta->state & _FW_LINKED)) { DBG_COUNTER(padapter->tx_logs.os_tx_m2u_ignore_fw_linked); continue; diff --git a/drivers/staging/rtlwifi/Kconfig b/drivers/staging/rtlwifi/Kconfig new file mode 100644 index 000000000000..cb3a29ae764b --- /dev/null +++ b/drivers/staging/rtlwifi/Kconfig @@ -0,0 +1,22 @@ +config R8822BE + tristate "Realtek RTL8822BE Wireless Network Adapter" + depends on PCI && MAC80211 && m + select FW_LOADER + ---help--- + This is the staging driver for Realtek RTL8822BE 802.11ac PCIe + wireless network adapters. + +config RTLHALMAC_ST + tristate + depends on R8822BE + default m + +config RTLPHYDM_ST + tristate + depends on R8822BE + default m + +config RTLWIFI_DEBUG_ST + boolean + depends on R8822BE + default y diff --git a/drivers/staging/rtlwifi/Makefile b/drivers/staging/rtlwifi/Makefile new file mode 100644 index 000000000000..0d738c18b29c --- /dev/null +++ b/drivers/staging/rtlwifi/Makefile @@ -0,0 +1,70 @@ +obj-$(CONFIG_R8822BE) += r8822be.o + +r8822be-objs := \ + base.o \ + cam.o \ + core.o \ + debug.o \ + efuse.o \ + ps.o \ + rc.o \ + regd.o \ + stats.o \ + pci.o \ + rtl8822be/fw.o \ + rtl8822be/hw.o \ + rtl8822be/led.o \ + rtl8822be/phy.o \ + rtl8822be/sw.o \ + rtl8822be/trx.o \ + btcoexist/halbtc8822b2ant.o \ + btcoexist/halbtc8822b1ant.o \ + btcoexist/halbtc8822bwifionly.o \ + btcoexist/halbtcoutsrc.o \ + btcoexist/rtl_btc.o \ + halmac/halmac_api.o \ + halmac/halmac_88xx/halmac_api_88xx_usb.o \ + halmac/halmac_88xx/halmac_api_88xx_sdio.o \ + halmac/halmac_88xx/halmac_api_88xx.o \ + halmac/halmac_88xx/halmac_api_88xx_pcie.o \ + halmac/halmac_88xx/halmac_func_88xx.o \ + halmac/halmac_88xx/halmac_8822b/halmac_api_8822b_pcie.o \ + halmac/halmac_88xx/halmac_8822b/halmac_func_8822b.o \ + halmac/halmac_88xx/halmac_8822b/halmac_api_8822b_sdio.o \ + halmac/halmac_88xx/halmac_8822b/halmac_api_8822b.o \ + halmac/halmac_88xx/halmac_8822b/halmac_8822b_phy.o \ + halmac/halmac_88xx/halmac_8822b/halmac_8822b_pwr_seq.o \ + halmac/halmac_88xx/halmac_8822b/halmac_api_8822b_usb.o \ + halmac/rtl_halmac.o \ + phydm/phydm_debug.o \ + phydm/phydm_antdiv.o\ + phydm/phydm_interface.o\ + phydm/phydm_hwconfig.o\ + phydm/phydm.o\ + phydm/halphyrf_ce.o\ + phydm/phydm_edcaturbocheck.o\ + phydm/phydm_dig.o\ + phydm/phydm_rainfo.o\ + phydm/phydm_dynamicbbpowersaving.o\ + phydm/phydm_powertracking_ce.o\ + phydm/phydm_dynamictxpower.o\ + phydm/phydm_adaptivity.o\ + phydm/phydm_cfotracking.o\ + phydm/phydm_noisemonitor.o\ + phydm/phydm_acs.o\ + phydm/phydm_psd.o\ + phydm/phydm_adc_sampling.o\ + phydm/phydm_kfree.o\ + phydm/phydm_ccx.o \ + phydm/rtl8822b/halhwimg8822b_bb.o\ + phydm/rtl8822b/halhwimg8822b_mac.o\ + phydm/rtl8822b/halhwimg8822b_rf.o\ + phydm/rtl8822b/halphyrf_8822b.o\ + phydm/rtl8822b/phydm_hal_api8822b.o\ + phydm/rtl8822b/phydm_iqk_8822b.o\ + phydm/rtl8822b/phydm_regconfig8822b.o\ + phydm/rtl8822b/phydm_rtl8822b.o \ + phydm/rtl_phydm.o + + +obj-$(CONFIG_R8822BE) += rtl8822be/ diff --git a/drivers/staging/rtlwifi/TODO b/drivers/staging/rtlwifi/TODO new file mode 100644 index 000000000000..4a084f2fc5d0 --- /dev/null +++ b/drivers/staging/rtlwifi/TODO @@ -0,0 +1,11 @@ +TODO: +- find and remove code blocks guarded by never set CONFIG_FOO defines +- convert any remaining unusual variable types +- find codes that can use %pM and %Nph formatting +- checkpatch.pl fixes - most of the remaining ones are lines too long. Many + of them will require refactoring +- merge Realtek's bugfixes and new features into the driver +- address any reviewers comments + +Please send any patches to Greg Kroah-Hartman <gregkh@linuxfoundation.org>, +and Larry Finger <Larry.Finger@lwfinger.net>. diff --git a/drivers/staging/rtlwifi/base.c b/drivers/staging/rtlwifi/base.c new file mode 100644 index 000000000000..b88b0e8edd3d --- /dev/null +++ b/drivers/staging/rtlwifi/base.c @@ -0,0 +1,2826 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include "wifi.h" +#include "rc.h" +#include "base.h" +#include "efuse.h" +#include "cam.h" +#include "ps.h" +#include "regd.h" +#include "pci.h" +#include <linux/ip.h> +#include <linux/module.h> +#include <linux/udp.h> + +/* + *NOTICE!!!: This file will be very big, we should + *keep it clear under following roles: + * + *This file include following parts, so, if you add new + *functions into this file, please check which part it + *should includes. or check if you should add new part + *for this file: + * + *1) mac80211 init functions + *2) tx information functions + *3) functions called by core.c + *4) wq & timer callback functions + *5) frame process functions + *6) IOT functions + *7) sysfs functions + *8) vif functions + *9) ... + */ + +/********************************************************* + * + * mac80211 init functions + * + *********************************************************/ +static struct ieee80211_channel rtl_channeltable_2g[] = { + {.center_freq = 2412, .hw_value = 1,}, + {.center_freq = 2417, .hw_value = 2,}, + {.center_freq = 2422, .hw_value = 3,}, + {.center_freq = 2427, .hw_value = 4,}, + {.center_freq = 2432, .hw_value = 5,}, + {.center_freq = 2437, .hw_value = 6,}, + {.center_freq = 2442, .hw_value = 7,}, + {.center_freq = 2447, .hw_value = 8,}, + {.center_freq = 2452, .hw_value = 9,}, + {.center_freq = 2457, .hw_value = 10,}, + {.center_freq = 2462, .hw_value = 11,}, + {.center_freq = 2467, .hw_value = 12,}, + {.center_freq = 2472, .hw_value = 13,}, + {.center_freq = 2484, .hw_value = 14,}, +}; + +static struct ieee80211_channel rtl_channeltable_5g[] = { + {.center_freq = 5180, .hw_value = 36,}, + {.center_freq = 5200, .hw_value = 40,}, + {.center_freq = 5220, .hw_value = 44,}, + {.center_freq = 5240, .hw_value = 48,}, + {.center_freq = 5260, .hw_value = 52,}, + {.center_freq = 5280, .hw_value = 56,}, + {.center_freq = 5300, .hw_value = 60,}, + {.center_freq = 5320, .hw_value = 64,}, + {.center_freq = 5500, .hw_value = 100,}, + {.center_freq = 5520, .hw_value = 104,}, + {.center_freq = 5540, .hw_value = 108,}, + {.center_freq = 5560, .hw_value = 112,}, + {.center_freq = 5580, .hw_value = 116,}, + {.center_freq = 5600, .hw_value = 120,}, + {.center_freq = 5620, .hw_value = 124,}, + {.center_freq = 5640, .hw_value = 128,}, + {.center_freq = 5660, .hw_value = 132,}, + {.center_freq = 5680, .hw_value = 136,}, + {.center_freq = 5700, .hw_value = 140,}, + {.center_freq = 5745, .hw_value = 149,}, + {.center_freq = 5765, .hw_value = 153,}, + {.center_freq = 5785, .hw_value = 157,}, + {.center_freq = 5805, .hw_value = 161,}, + {.center_freq = 5825, .hw_value = 165,}, +}; + +static struct ieee80211_rate rtl_ratetable_2g[] = { + {.bitrate = 10, .hw_value = 0x00,}, + {.bitrate = 20, .hw_value = 0x01,}, + {.bitrate = 55, .hw_value = 0x02,}, + {.bitrate = 110, .hw_value = 0x03,}, + {.bitrate = 60, .hw_value = 0x04,}, + {.bitrate = 90, .hw_value = 0x05,}, + {.bitrate = 120, .hw_value = 0x06,}, + {.bitrate = 180, .hw_value = 0x07,}, + {.bitrate = 240, .hw_value = 0x08,}, + {.bitrate = 360, .hw_value = 0x09,}, + {.bitrate = 480, .hw_value = 0x0a,}, + {.bitrate = 540, .hw_value = 0x0b,}, +}; + +static struct ieee80211_rate rtl_ratetable_5g[] = { + {.bitrate = 60, .hw_value = 0x04,}, + {.bitrate = 90, .hw_value = 0x05,}, + {.bitrate = 120, .hw_value = 0x06,}, + {.bitrate = 180, .hw_value = 0x07,}, + {.bitrate = 240, .hw_value = 0x08,}, + {.bitrate = 360, .hw_value = 0x09,}, + {.bitrate = 480, .hw_value = 0x0a,}, + {.bitrate = 540, .hw_value = 0x0b,}, +}; + +static const struct ieee80211_supported_band rtl_band_2ghz = { + .band = NL80211_BAND_2GHZ, + + .channels = rtl_channeltable_2g, + .n_channels = ARRAY_SIZE(rtl_channeltable_2g), + + .bitrates = rtl_ratetable_2g, + .n_bitrates = ARRAY_SIZE(rtl_ratetable_2g), + + .ht_cap = {0}, +}; + +static struct ieee80211_supported_band rtl_band_5ghz = { + .band = NL80211_BAND_5GHZ, + + .channels = rtl_channeltable_5g, + .n_channels = ARRAY_SIZE(rtl_channeltable_5g), + + .bitrates = rtl_ratetable_5g, + .n_bitrates = ARRAY_SIZE(rtl_ratetable_5g), + + .ht_cap = {0}, +}; + +static const u8 tid_to_ac[] = { + 2, /* IEEE80211_AC_BE */ + 3, /* IEEE80211_AC_BK */ + 3, /* IEEE80211_AC_BK */ + 2, /* IEEE80211_AC_BE */ + 1, /* IEEE80211_AC_VI */ + 1, /* IEEE80211_AC_VI */ + 0, /* IEEE80211_AC_VO */ + 0, /* IEEE80211_AC_VO */ +}; + +u8 rtl_tid_to_ac(u8 tid) +{ + return tid_to_ac[tid]; +} + +static void _rtl_init_hw_ht_capab(struct ieee80211_hw *hw, + struct ieee80211_sta_ht_cap *ht_cap) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &rtlpriv->phy; + + ht_cap->ht_supported = true; + ht_cap->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | + IEEE80211_HT_CAP_SGI_40 | + IEEE80211_HT_CAP_SGI_20 | + IEEE80211_HT_CAP_DSSSCCK40 | IEEE80211_HT_CAP_MAX_AMSDU; + + if (rtlpriv->rtlhal.disable_amsdu_8k) + ht_cap->cap &= ~IEEE80211_HT_CAP_MAX_AMSDU; + + /* + *Maximum length of AMPDU that the STA can receive. + *Length = 2 ^ (13 + max_ampdu_length_exp) - 1 (octets) + */ + ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; + + /*Minimum MPDU start spacing , */ + ht_cap->ampdu_density = IEEE80211_HT_MPDU_DENSITY_16; + + ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; + + /*hw->wiphy->bands[NL80211_BAND_2GHZ] + *base on ant_num + *rx_mask: RX mask + *if rx_ant = 1 rx_mask[0]= 0xff;==>MCS0-MCS7 + *if rx_ant = 2 rx_mask[1]= 0xff;==>MCS8-MCS15 + *if rx_ant >= 3 rx_mask[2]= 0xff; + *if BW_40 rx_mask[4]= 0x01; + *highest supported RX rate + */ + if (rtlpriv->dm.supp_phymode_switch) { + pr_info("Support phy mode switch\n"); + + ht_cap->mcs.rx_mask[0] = 0xFF; + ht_cap->mcs.rx_mask[1] = 0xFF; + ht_cap->mcs.rx_mask[4] = 0x01; + + ht_cap->mcs.rx_highest = cpu_to_le16(MAX_BIT_RATE_40MHZ_MCS15); + } else { + if (get_rf_type(rtlphy) == RF_1T2R || + get_rf_type(rtlphy) == RF_2T2R) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "1T2R or 2T2R\n"); + ht_cap->mcs.rx_mask[0] = 0xFF; + ht_cap->mcs.rx_mask[1] = 0xFF; + ht_cap->mcs.rx_mask[4] = 0x01; + + ht_cap->mcs.rx_highest = + cpu_to_le16(MAX_BIT_RATE_40MHZ_MCS15); + } else if (get_rf_type(rtlphy) == RF_1T1R) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "1T1R\n"); + + ht_cap->mcs.rx_mask[0] = 0xFF; + ht_cap->mcs.rx_mask[1] = 0x00; + ht_cap->mcs.rx_mask[4] = 0x01; + + ht_cap->mcs.rx_highest = + cpu_to_le16(MAX_BIT_RATE_40MHZ_MCS7); + } + } +} + +static void _rtl_init_hw_vht_capab(struct ieee80211_hw *hw, + struct ieee80211_sta_vht_cap *vht_cap) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE || + rtlhal->hw_type == HARDWARE_TYPE_RTL8822BE) { + u16 mcs_map; + + vht_cap->vht_supported = true; + vht_cap->cap = + IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 | + IEEE80211_VHT_CAP_SHORT_GI_80 | + IEEE80211_VHT_CAP_TXSTBC | + IEEE80211_VHT_CAP_RXSTBC_1 | + IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE | + IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | + IEEE80211_VHT_CAP_HTC_VHT | + IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK | + IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN | + IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN | + 0; + + mcs_map = IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 | + IEEE80211_VHT_MCS_SUPPORT_0_9 << 2 | + IEEE80211_VHT_MCS_NOT_SUPPORTED << 4 | + IEEE80211_VHT_MCS_NOT_SUPPORTED << 6 | + IEEE80211_VHT_MCS_NOT_SUPPORTED << 8 | + IEEE80211_VHT_MCS_NOT_SUPPORTED << 10 | + IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 | + IEEE80211_VHT_MCS_NOT_SUPPORTED << 14; + + vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map); + vht_cap->vht_mcs.rx_highest = + cpu_to_le16(MAX_BIT_RATE_SHORT_GI_2NSS_80MHZ_MCS9); + vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map); + vht_cap->vht_mcs.tx_highest = + cpu_to_le16(MAX_BIT_RATE_SHORT_GI_2NSS_80MHZ_MCS9); + } else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) { + u16 mcs_map; + + vht_cap->vht_supported = true; + vht_cap->cap = + IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 | + IEEE80211_VHT_CAP_SHORT_GI_80 | + IEEE80211_VHT_CAP_TXSTBC | + IEEE80211_VHT_CAP_RXSTBC_1 | + IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE | + IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | + IEEE80211_VHT_CAP_HTC_VHT | + IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK | + IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN | + IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN | + 0; + + mcs_map = IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 | + IEEE80211_VHT_MCS_NOT_SUPPORTED << 2 | + IEEE80211_VHT_MCS_NOT_SUPPORTED << 4 | + IEEE80211_VHT_MCS_NOT_SUPPORTED << 6 | + IEEE80211_VHT_MCS_NOT_SUPPORTED << 8 | + IEEE80211_VHT_MCS_NOT_SUPPORTED << 10 | + IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 | + IEEE80211_VHT_MCS_NOT_SUPPORTED << 14; + + vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map); + vht_cap->vht_mcs.rx_highest = + cpu_to_le16(MAX_BIT_RATE_SHORT_GI_1NSS_80MHZ_MCS9); + vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map); + vht_cap->vht_mcs.tx_highest = + cpu_to_le16(MAX_BIT_RATE_SHORT_GI_1NSS_80MHZ_MCS9); + } +} + +static void _rtl_init_mac80211(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + struct rtl_mac *rtlmac = rtl_mac(rtl_priv(hw)); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct ieee80211_supported_band *sband; + + if (rtlhal->macphymode == SINGLEMAC_SINGLEPHY && + rtlhal->bandset == BAND_ON_BOTH) { + /* 1: 2.4 G bands */ + /* <1> use mac->bands as mem for hw->wiphy->bands */ + sband = &rtlmac->bands[NL80211_BAND_2GHZ]; + + /* <2> set hw->wiphy->bands[NL80211_BAND_2GHZ] + * to default value(1T1R) + */ + memcpy(&rtlmac->bands[NL80211_BAND_2GHZ], &rtl_band_2ghz, + sizeof(struct ieee80211_supported_band)); + + /* <3> init ht cap base on ant_num */ + _rtl_init_hw_ht_capab(hw, &sband->ht_cap); + + /* <4> set mac->sband to wiphy->sband */ + hw->wiphy->bands[NL80211_BAND_2GHZ] = sband; + + /* 2: 5 G bands */ + /* <1> use mac->bands as mem for hw->wiphy->bands */ + sband = &rtlmac->bands[NL80211_BAND_5GHZ]; + + /* <2> set hw->wiphy->bands[NL80211_BAND_5GHZ] + * to default value(1T1R) + */ + memcpy(&rtlmac->bands[NL80211_BAND_5GHZ], &rtl_band_5ghz, + sizeof(struct ieee80211_supported_band)); + + /* <3> init ht cap base on ant_num */ + _rtl_init_hw_ht_capab(hw, &sband->ht_cap); + + _rtl_init_hw_vht_capab(hw, &sband->vht_cap); + /* <4> set mac->sband to wiphy->sband */ + hw->wiphy->bands[NL80211_BAND_5GHZ] = sband; + } else { + if (rtlhal->current_bandtype == BAND_ON_2_4G) { + /* <1> use mac->bands as mem for hw->wiphy->bands */ + sband = &rtlmac->bands[NL80211_BAND_2GHZ]; + + /* <2> set hw->wiphy->bands[NL80211_BAND_2GHZ] + * to default value(1T1R) + */ + memcpy(&rtlmac->bands[NL80211_BAND_2GHZ], + &rtl_band_2ghz, + sizeof(struct ieee80211_supported_band)); + + /* <3> init ht cap base on ant_num */ + _rtl_init_hw_ht_capab(hw, &sband->ht_cap); + + /* <4> set mac->sband to wiphy->sband */ + hw->wiphy->bands[NL80211_BAND_2GHZ] = sband; + } else if (rtlhal->current_bandtype == BAND_ON_5G) { + /* <1> use mac->bands as mem for hw->wiphy->bands */ + sband = &rtlmac->bands[NL80211_BAND_5GHZ]; + + /* <2> set hw->wiphy->bands[NL80211_BAND_5GHZ] + * to default value(1T1R) + */ + memcpy(&rtlmac->bands[NL80211_BAND_5GHZ], + &rtl_band_5ghz, + sizeof(struct ieee80211_supported_band)); + + /* <3> init ht cap base on ant_num */ + _rtl_init_hw_ht_capab(hw, &sband->ht_cap); + + _rtl_init_hw_vht_capab(hw, &sband->vht_cap); + /* <4> set mac->sband to wiphy->sband */ + hw->wiphy->bands[NL80211_BAND_5GHZ] = sband; + } else { + pr_err("Err BAND %d\n", + rtlhal->current_bandtype); + } + } + /* <5> set hw caps */ + ieee80211_hw_set(hw, SIGNAL_DBM); + ieee80211_hw_set(hw, RX_INCLUDES_FCS); + ieee80211_hw_set(hw, AMPDU_AGGREGATION); + ieee80211_hw_set(hw, CONNECTION_MONITOR); + ieee80211_hw_set(hw, MFP_CAPABLE); + ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); + ieee80211_hw_set(hw, SUPPORTS_TX_FRAG); + ieee80211_hw_set(hw, SUPPORT_FAST_XMIT); + ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU); + + /* swlps or hwlps has been set in diff chip in init_sw_vars */ + if (rtlpriv->psc.swctrl_lps) { + ieee80211_hw_set(hw, SUPPORTS_PS); + ieee80211_hw_set(hw, PS_NULLFUNC_STACK); + } + if (rtlpriv->psc.fwctrl_lps) { + ieee80211_hw_set(hw, SUPPORTS_PS); + ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS); + } + hw->wiphy->interface_modes = + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC) | + BIT(NL80211_IFTYPE_MESH_POINT) | + BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_P2P_GO); + hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; + + hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; + + hw->wiphy->rts_threshold = 2347; + + hw->queues = AC_MAX; + hw->extra_tx_headroom = RTL_TX_HEADER_SIZE; + + /* TODO: Correct this value for our hw */ + hw->max_listen_interval = MAX_LISTEN_INTERVAL; + hw->max_rate_tries = MAX_RATE_TRIES; + /* hw->max_rates = 1; */ + hw->sta_data_size = sizeof(struct rtl_sta_info); + +/* wowlan is not supported by kernel if CONFIG_PM is not defined */ +#ifdef CONFIG_PM + if (rtlpriv->psc.wo_wlan_mode) { + if (rtlpriv->psc.wo_wlan_mode & WAKE_ON_MAGIC_PACKET) + rtlpriv->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT; + if (rtlpriv->psc.wo_wlan_mode & WAKE_ON_PATTERN_MATCH) { + rtlpriv->wowlan.n_patterns = + MAX_SUPPORT_WOL_PATTERN_NUM; + rtlpriv->wowlan.pattern_min_len = MIN_WOL_PATTERN_SIZE; + rtlpriv->wowlan.pattern_max_len = MAX_WOL_PATTERN_SIZE; + } + hw->wiphy->wowlan = &rtlpriv->wowlan; + } +#endif + + /* <6> mac address */ + if (is_valid_ether_addr(rtlefuse->dev_addr)) { + SET_IEEE80211_PERM_ADDR(hw, rtlefuse->dev_addr); + } else { + u8 rtlmac1[] = { 0x00, 0xe0, 0x4c, 0x81, 0x92, 0x00 }; + + get_random_bytes((rtlmac1 + (ETH_ALEN - 1)), 1); + SET_IEEE80211_PERM_ADDR(hw, rtlmac1); + } +} + +static void _rtl_init_deferred_work(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + /* <1> timer */ + setup_timer(&rtlpriv->works.watchdog_timer, + rtl_watch_dog_timer_callback, (unsigned long)hw); + setup_timer(&rtlpriv->works.dualmac_easyconcurrent_retrytimer, + rtl_easy_concurrent_retrytimer_callback, (unsigned long)hw); + /* <2> work queue */ + rtlpriv->works.hw = hw; + rtlpriv->works.rtl_wq = alloc_workqueue("%s", 0, 0, rtlpriv->cfg->name); + INIT_DELAYED_WORK(&rtlpriv->works.watchdog_wq, + (void *)rtl_watchdog_wq_callback); + INIT_DELAYED_WORK(&rtlpriv->works.ips_nic_off_wq, + (void *)rtl_ips_nic_off_wq_callback); + INIT_DELAYED_WORK(&rtlpriv->works.ps_work, + (void *)rtl_swlps_wq_callback); + INIT_DELAYED_WORK(&rtlpriv->works.ps_rfon_wq, + (void *)rtl_swlps_rfon_wq_callback); + INIT_DELAYED_WORK(&rtlpriv->works.fwevt_wq, + (void *)rtl_fwevt_wq_callback); + INIT_DELAYED_WORK(&rtlpriv->works.c2hcmd_wq, + (void *)rtl_c2hcmd_wq_callback); +} + +void rtl_deinit_deferred_work(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + del_timer_sync(&rtlpriv->works.watchdog_timer); + + cancel_delayed_work(&rtlpriv->works.watchdog_wq); + cancel_delayed_work(&rtlpriv->works.ips_nic_off_wq); + cancel_delayed_work(&rtlpriv->works.ps_work); + cancel_delayed_work(&rtlpriv->works.ps_rfon_wq); + cancel_delayed_work(&rtlpriv->works.fwevt_wq); + cancel_delayed_work(&rtlpriv->works.c2hcmd_wq); +} + +void rtl_init_rfkill(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + bool radio_state; + bool blocked; + u8 valid = 0; + + /*set init state to on */ + rtlpriv->rfkill.rfkill_state = true; + wiphy_rfkill_set_hw_state(hw->wiphy, 0); + + radio_state = rtlpriv->cfg->ops->radio_onoff_checking(hw, &valid); + + if (valid) { + pr_info("rtlwifi: wireless switch is %s\n", + rtlpriv->rfkill.rfkill_state ? "on" : "off"); + + rtlpriv->rfkill.rfkill_state = radio_state; + + blocked = (rtlpriv->rfkill.rfkill_state == 1) ? 0 : 1; + wiphy_rfkill_set_hw_state(hw->wiphy, blocked); + } + + wiphy_rfkill_start_polling(hw->wiphy); +} + +void rtl_deinit_rfkill(struct ieee80211_hw *hw) +{ + wiphy_rfkill_stop_polling(hw->wiphy); +} + +int rtl_init_core(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *rtlmac = rtl_mac(rtl_priv(hw)); + + /* <1> init mac80211 */ + _rtl_init_mac80211(hw); + rtlmac->hw = hw; + + /* <2> rate control register */ + hw->rate_control_algorithm = "rtl_rc"; + + /* + * <3> init CRDA must come after init + * mac80211 hw in _rtl_init_mac80211. + */ + if (rtl_regd_init(hw, rtl_reg_notifier)) { + pr_err("REGD init failed\n"); + return 1; + } + + /* <4> locks */ + mutex_init(&rtlpriv->locks.conf_mutex); + mutex_init(&rtlpriv->locks.ips_mutex); + mutex_init(&rtlpriv->locks.lps_mutex); + spin_lock_init(&rtlpriv->locks.irq_th_lock); + spin_lock_init(&rtlpriv->locks.h2c_lock); + spin_lock_init(&rtlpriv->locks.rf_ps_lock); + spin_lock_init(&rtlpriv->locks.rf_lock); + spin_lock_init(&rtlpriv->locks.waitq_lock); + spin_lock_init(&rtlpriv->locks.entry_list_lock); + spin_lock_init(&rtlpriv->locks.c2hcmd_lock); + spin_lock_init(&rtlpriv->locks.scan_list_lock); + spin_lock_init(&rtlpriv->locks.cck_and_rw_pagea_lock); + spin_lock_init(&rtlpriv->locks.fw_ps_lock); + spin_lock_init(&rtlpriv->locks.iqk_lock); + /* <5> init list */ + INIT_LIST_HEAD(&rtlpriv->entry_list); + INIT_LIST_HEAD(&rtlpriv->c2hcmd_list); + INIT_LIST_HEAD(&rtlpriv->scan_list.list); + + rtlmac->link_state = MAC80211_NOLINK; + + /* <6> init deferred work */ + _rtl_init_deferred_work(hw); + + return 0; +} + +static void rtl_free_entries_from_scan_list(struct ieee80211_hw *hw); + +void rtl_deinit_core(struct ieee80211_hw *hw) +{ + rtl_c2hcmd_launcher(hw, 0); + rtl_free_entries_from_scan_list(hw); +} + +void rtl_init_rx_config(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + + rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RCR, (u8 *)&mac->rx_conf); +} + +/********************************************************* + * + * tx information functions + * + *********************************************************/ +static void _rtl_qurey_shortpreamble_mode(struct ieee80211_hw *hw, + struct rtl_tcb_desc *tcb_desc, + struct ieee80211_tx_info *info) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 rate_flag = info->control.rates[0].flags; + + tcb_desc->use_shortpreamble = false; + + /* 1M can only use Long Preamble. 11B spec */ + if (tcb_desc->hw_rate == rtlpriv->cfg->maps[RTL_RC_CCK_RATE1M]) + return; + else if (rate_flag & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) + tcb_desc->use_shortpreamble = true; +} + +static void _rtl_query_shortgi(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, + struct rtl_tcb_desc *tcb_desc, + struct ieee80211_tx_info *info) +{ + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + u8 rate_flag = info->control.rates[0].flags; + u8 sgi_40 = 0, sgi_20 = 0, bw_40 = 0; + u8 sgi_80 = 0, bw_80 = 0; + + tcb_desc->use_shortgi = false; + + if (!sta) + return; + + sgi_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40; + sgi_20 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20; + sgi_80 = sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80; + + if ((!sta->ht_cap.ht_supported) && (!sta->vht_cap.vht_supported)) + return; + + if (!sgi_40 && !sgi_20) + return; + + if (mac->opmode == NL80211_IFTYPE_STATION) { + bw_40 = mac->bw_40; + bw_80 = mac->bw_80; + } else if (mac->opmode == NL80211_IFTYPE_AP || + mac->opmode == NL80211_IFTYPE_ADHOC || + mac->opmode == NL80211_IFTYPE_MESH_POINT) { + bw_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40; + bw_80 = sta->vht_cap.vht_supported; + } + + if (bw_80) { + if (sgi_80) + tcb_desc->use_shortgi = true; + else + tcb_desc->use_shortgi = false; + } else { + if (bw_40 && sgi_40) + tcb_desc->use_shortgi = true; + else if (!bw_40 && sgi_20) + tcb_desc->use_shortgi = true; + } + + if (!(rate_flag & IEEE80211_TX_RC_SHORT_GI)) + tcb_desc->use_shortgi = false; +} + +static void _rtl_query_protection_mode(struct ieee80211_hw *hw, + struct rtl_tcb_desc *tcb_desc, + struct ieee80211_tx_info *info) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 rate_flag = info->control.rates[0].flags; + + /* Common Settings */ + tcb_desc->rts_stbc = false; + tcb_desc->cts_enable = false; + tcb_desc->rts_sc = 0; + tcb_desc->rts_bw = false; + tcb_desc->rts_use_shortpreamble = false; + tcb_desc->rts_use_shortgi = false; + + if (rate_flag & IEEE80211_TX_RC_USE_CTS_PROTECT) { + /* Use CTS-to-SELF in protection mode. */ + tcb_desc->rts_enable = true; + tcb_desc->cts_enable = true; + tcb_desc->rts_rate = rtlpriv->cfg->maps[RTL_RC_OFDM_RATE24M]; + } else if (rate_flag & IEEE80211_TX_RC_USE_RTS_CTS) { + /* Use RTS-CTS in protection mode. */ + tcb_desc->rts_enable = true; + tcb_desc->rts_rate = rtlpriv->cfg->maps[RTL_RC_OFDM_RATE24M]; + } +} + +u8 rtl_mrate_idx_to_arfr_id( + struct ieee80211_hw *hw, u8 rate_index, + enum wireless_mode wirelessmode) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &rtlpriv->phy; + u8 ret = 0; + + switch (rate_index) { + case RATR_INX_WIRELESS_NGB: + if (rtlphy->rf_type == RF_1T1R) + ret = RATEID_IDX_BGN_40M_1SS; + else + ret = RATEID_IDX_BGN_40M_2SS; + ; break; + case RATR_INX_WIRELESS_N: + case RATR_INX_WIRELESS_NG: + if (rtlphy->rf_type == RF_1T1R) + ret = RATEID_IDX_GN_N1SS; + else + ret = RATEID_IDX_GN_N2SS; + ; break; + case RATR_INX_WIRELESS_NB: + if (rtlphy->rf_type == RF_1T1R) + ret = RATEID_IDX_BGN_20M_1SS_BN; + else + ret = RATEID_IDX_BGN_20M_2SS_BN; + ; break; + case RATR_INX_WIRELESS_GB: + ret = RATEID_IDX_BG; + break; + case RATR_INX_WIRELESS_G: + ret = RATEID_IDX_G; + break; + case RATR_INX_WIRELESS_B: + ret = RATEID_IDX_B; + break; + case RATR_INX_WIRELESS_MC: + if ((wirelessmode == WIRELESS_MODE_B) || + (wirelessmode == WIRELESS_MODE_G) || + (wirelessmode == WIRELESS_MODE_N_24G) || + (wirelessmode == WIRELESS_MODE_AC_24G)) + ret = RATEID_IDX_BG; + else + ret = RATEID_IDX_G; + break; + case RATR_INX_WIRELESS_AC_5N: + if (rtlphy->rf_type == RF_1T1R) + ret = RATEID_IDX_VHT_1SS; + else + ret = RATEID_IDX_VHT_2SS; + break; + case RATR_INX_WIRELESS_AC_24N: + if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_80) { + if (rtlphy->rf_type == RF_1T1R) + ret = RATEID_IDX_VHT_1SS; + else + ret = RATEID_IDX_VHT_2SS; + } else { + if (rtlphy->rf_type == RF_1T1R) + ret = RATEID_IDX_MIX1; + else + ret = RATEID_IDX_MIX2; + } + break; + default: + ret = RATEID_IDX_BGN_40M_2SS; + break; + } + return ret; +} + +static void _rtl_txrate_selectmode(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, + struct rtl_tcb_desc *tcb_desc) +{ +#define SET_RATE_ID(rate_id) \ + ((rtlpriv->cfg->spec_ver & RTL_SPEC_NEW_RATEID) ? \ + rtl_mrate_idx_to_arfr_id(hw, rate_id, \ + (sta_entry ? sta_entry->wireless_mode : \ + WIRELESS_MODE_G)) : \ + rate_id) + + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_sta_info *sta_entry = NULL; + u8 ratr_index = SET_RATE_ID(RATR_INX_WIRELESS_MC); + + if (sta) { + sta_entry = (struct rtl_sta_info *)sta->drv_priv; + ratr_index = sta_entry->ratr_index; + } + if (!tcb_desc->disable_ratefallback || !tcb_desc->use_driver_rate) { + if (mac->opmode == NL80211_IFTYPE_STATION) { + tcb_desc->ratr_index = 0; + } else if (mac->opmode == NL80211_IFTYPE_ADHOC || + mac->opmode == NL80211_IFTYPE_MESH_POINT) { + if (tcb_desc->multicast || tcb_desc->broadcast) { + tcb_desc->hw_rate = + rtlpriv->cfg->maps[RTL_RC_CCK_RATE2M]; + tcb_desc->use_driver_rate = 1; + tcb_desc->ratr_index = + SET_RATE_ID(RATR_INX_WIRELESS_MC); + } else { + tcb_desc->ratr_index = ratr_index; + } + } else if (mac->opmode == NL80211_IFTYPE_AP) { + tcb_desc->ratr_index = ratr_index; + } + } + + if (rtlpriv->dm.useramask) { + tcb_desc->ratr_index = ratr_index; + /* TODO we will differentiate adhoc and station future */ + if (mac->opmode == NL80211_IFTYPE_STATION || + mac->opmode == NL80211_IFTYPE_MESH_POINT) { + tcb_desc->mac_id = 0; + + if (sta && + (rtlpriv->cfg->spec_ver & RTL_SPEC_NEW_RATEID)) + ; /* use sta_entry->ratr_index */ + else if (mac->mode == WIRELESS_MODE_AC_5G) + tcb_desc->ratr_index = + SET_RATE_ID(RATR_INX_WIRELESS_AC_5N); + else if (mac->mode == WIRELESS_MODE_AC_24G) + tcb_desc->ratr_index = + SET_RATE_ID(RATR_INX_WIRELESS_AC_24N); + else if (mac->mode == WIRELESS_MODE_N_24G) + tcb_desc->ratr_index = + SET_RATE_ID(RATR_INX_WIRELESS_NGB); + else if (mac->mode == WIRELESS_MODE_N_5G) + tcb_desc->ratr_index = + SET_RATE_ID(RATR_INX_WIRELESS_NG); + else if (mac->mode & WIRELESS_MODE_G) + tcb_desc->ratr_index = + SET_RATE_ID(RATR_INX_WIRELESS_GB); + else if (mac->mode & WIRELESS_MODE_B) + tcb_desc->ratr_index = + SET_RATE_ID(RATR_INX_WIRELESS_B); + else if (mac->mode & WIRELESS_MODE_A) + tcb_desc->ratr_index = + SET_RATE_ID(RATR_INX_WIRELESS_G); + + } else if (mac->opmode == NL80211_IFTYPE_AP || + mac->opmode == NL80211_IFTYPE_ADHOC) { + if (sta) { + if (sta->aid > 0) + tcb_desc->mac_id = sta->aid + 1; + else + tcb_desc->mac_id = 1; + } else { + tcb_desc->mac_id = 0; + } + } + } +#undef SET_RATE_ID +} + +static void _rtl_query_bandwidth_mode(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, + struct rtl_tcb_desc *tcb_desc) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + + tcb_desc->packet_bw = false; + if (!sta) + return; + if (mac->opmode == NL80211_IFTYPE_AP || + mac->opmode == NL80211_IFTYPE_ADHOC || + mac->opmode == NL80211_IFTYPE_MESH_POINT) { + if (!(sta->ht_cap.ht_supported) || + !(sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) + return; + } else if (mac->opmode == NL80211_IFTYPE_STATION) { + if (!mac->bw_40 || !(sta->ht_cap.ht_supported)) + return; + } + if (tcb_desc->multicast || tcb_desc->broadcast) + return; + + /*use legency rate, shall use 20MHz */ + if (tcb_desc->hw_rate <= rtlpriv->cfg->maps[RTL_RC_OFDM_RATE54M]) + return; + + tcb_desc->packet_bw = HT_CHANNEL_WIDTH_20_40; + + if (rtlpriv->rtlhal.hw_type == HARDWARE_TYPE_RTL8812AE || + rtlpriv->rtlhal.hw_type == HARDWARE_TYPE_RTL8821AE || + (rtlpriv->cfg->spec_ver & RTL_SPEC_SUPPORT_VHT)) { + if (mac->opmode == NL80211_IFTYPE_AP || + mac->opmode == NL80211_IFTYPE_ADHOC || + mac->opmode == NL80211_IFTYPE_MESH_POINT) { + if (!(sta->vht_cap.vht_supported)) + return; + } else if (mac->opmode == NL80211_IFTYPE_STATION) { + if (!mac->bw_80 || + !(sta->vht_cap.vht_supported)) + return; + } + if (tcb_desc->hw_rate <= + rtlpriv->cfg->maps[RTL_RC_HT_RATEMCS15]) + return; + tcb_desc->packet_bw = HT_CHANNEL_WIDTH_80; + } +} + +static u8 _rtl_get_vht_highest_n_rate(struct ieee80211_hw *hw, + struct ieee80211_sta *sta) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &rtlpriv->phy; + u8 hw_rate; + u16 tx_mcs_map = le16_to_cpu(sta->vht_cap.vht_mcs.tx_mcs_map); + + if ((get_rf_type(rtlphy) == RF_2T2R) && + (tx_mcs_map & 0x000c) != 0x000c) { + if ((tx_mcs_map & 0x000c) >> 2 == + IEEE80211_VHT_MCS_SUPPORT_0_7) + hw_rate = + rtlpriv->cfg->maps[RTL_RC_VHT_RATE_2SS_MCS7]; + else if ((tx_mcs_map & 0x000c) >> 2 == + IEEE80211_VHT_MCS_SUPPORT_0_8) + hw_rate = + rtlpriv->cfg->maps[RTL_RC_VHT_RATE_2SS_MCS9]; + else + hw_rate = + rtlpriv->cfg->maps[RTL_RC_VHT_RATE_2SS_MCS9]; + } else { + if ((tx_mcs_map & 0x0003) == + IEEE80211_VHT_MCS_SUPPORT_0_7) + hw_rate = + rtlpriv->cfg->maps[RTL_RC_VHT_RATE_1SS_MCS7]; + else if ((tx_mcs_map & 0x0003) == + IEEE80211_VHT_MCS_SUPPORT_0_8) + hw_rate = + rtlpriv->cfg->maps[RTL_RC_VHT_RATE_1SS_MCS9]; + else + hw_rate = + rtlpriv->cfg->maps[RTL_RC_VHT_RATE_1SS_MCS9]; + } + + return hw_rate; +} + +static u8 _rtl_get_highest_n_rate(struct ieee80211_hw *hw, + struct ieee80211_sta *sta) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &rtlpriv->phy; + u8 hw_rate; + + if ((get_rf_type(rtlphy) == RF_2T2R) && + (sta->ht_cap.mcs.rx_mask[1] != 0)) + hw_rate = rtlpriv->cfg->maps[RTL_RC_HT_RATEMCS15]; + else + hw_rate = rtlpriv->cfg->maps[RTL_RC_HT_RATEMCS7]; + + return hw_rate; +} + +/* mac80211's rate_idx is like this: + * + * 2.4G band:rx_status->band == NL80211_BAND_2GHZ + * + * B/G rate: + * (rx_status->flag & RX_FLAG_HT) = 0, + * DESC_RATE1M-->DESC_RATE54M ==> idx is 0-->11, + * + * N rate: + * (rx_status->flag & RX_FLAG_HT) = 1, + * DESC_RATEMCS0-->DESC_RATEMCS15 ==> idx is 0-->15 + * + * 5G band:rx_status->band == NL80211_BAND_5GHZ + * A rate: + * (rx_status->flag & RX_FLAG_HT) = 0, + * DESC_RATE6M-->DESC_RATE54M ==> idx is 0-->7, + * + * N rate: + * (rx_status->flag & RX_FLAG_HT) = 1, + * DESC_RATEMCS0-->DESC_RATEMCS15 ==> idx is 0-->15 + * + * VHT rates: + * DESC_RATEVHT1SS_MCS0-->DESC_RATEVHT1SS_MCS9 ==> idx is 0-->9 + * DESC_RATEVHT2SS_MCS0-->DESC_RATEVHT2SS_MCS9 ==> idx is 0-->9 + */ +int rtlwifi_rate_mapping(struct ieee80211_hw *hw, bool isht, bool isvht, + u8 desc_rate) +{ + int rate_idx; + + if (isvht) { + switch (desc_rate) { + case DESC_RATEVHT1SS_MCS0: + rate_idx = 0; + break; + case DESC_RATEVHT1SS_MCS1: + rate_idx = 1; + break; + case DESC_RATEVHT1SS_MCS2: + rate_idx = 2; + break; + case DESC_RATEVHT1SS_MCS3: + rate_idx = 3; + break; + case DESC_RATEVHT1SS_MCS4: + rate_idx = 4; + break; + case DESC_RATEVHT1SS_MCS5: + rate_idx = 5; + break; + case DESC_RATEVHT1SS_MCS6: + rate_idx = 6; + break; + case DESC_RATEVHT1SS_MCS7: + rate_idx = 7; + break; + case DESC_RATEVHT1SS_MCS8: + rate_idx = 8; + break; + case DESC_RATEVHT1SS_MCS9: + rate_idx = 9; + break; + case DESC_RATEVHT2SS_MCS0: + rate_idx = 0; + break; + case DESC_RATEVHT2SS_MCS1: + rate_idx = 1; + break; + case DESC_RATEVHT2SS_MCS2: + rate_idx = 2; + break; + case DESC_RATEVHT2SS_MCS3: + rate_idx = 3; + break; + case DESC_RATEVHT2SS_MCS4: + rate_idx = 4; + break; + case DESC_RATEVHT2SS_MCS5: + rate_idx = 5; + break; + case DESC_RATEVHT2SS_MCS6: + rate_idx = 6; + break; + case DESC_RATEVHT2SS_MCS7: + rate_idx = 7; + break; + case DESC_RATEVHT2SS_MCS8: + rate_idx = 8; + break; + case DESC_RATEVHT2SS_MCS9: + rate_idx = 9; + break; + default: + rate_idx = 0; + break; + } + return rate_idx; + } + if (!isht) { + if (hw->conf.chandef.chan->band == NL80211_BAND_2GHZ) { + switch (desc_rate) { + case DESC_RATE1M: + rate_idx = 0; + break; + case DESC_RATE2M: + rate_idx = 1; + break; + case DESC_RATE5_5M: + rate_idx = 2; + break; + case DESC_RATE11M: + rate_idx = 3; + break; + case DESC_RATE6M: + rate_idx = 4; + break; + case DESC_RATE9M: + rate_idx = 5; + break; + case DESC_RATE12M: + rate_idx = 6; + break; + case DESC_RATE18M: + rate_idx = 7; + break; + case DESC_RATE24M: + rate_idx = 8; + break; + case DESC_RATE36M: + rate_idx = 9; + break; + case DESC_RATE48M: + rate_idx = 10; + break; + case DESC_RATE54M: + rate_idx = 11; + break; + default: + rate_idx = 0; + break; + } + } else { + switch (desc_rate) { + case DESC_RATE6M: + rate_idx = 0; + break; + case DESC_RATE9M: + rate_idx = 1; + break; + case DESC_RATE12M: + rate_idx = 2; + break; + case DESC_RATE18M: + rate_idx = 3; + break; + case DESC_RATE24M: + rate_idx = 4; + break; + case DESC_RATE36M: + rate_idx = 5; + break; + case DESC_RATE48M: + rate_idx = 6; + break; + case DESC_RATE54M: + rate_idx = 7; + break; + default: + rate_idx = 0; + break; + } + } + } else { + switch (desc_rate) { + case DESC_RATEMCS0: + rate_idx = 0; + break; + case DESC_RATEMCS1: + rate_idx = 1; + break; + case DESC_RATEMCS2: + rate_idx = 2; + break; + case DESC_RATEMCS3: + rate_idx = 3; + break; + case DESC_RATEMCS4: + rate_idx = 4; + break; + case DESC_RATEMCS5: + rate_idx = 5; + break; + case DESC_RATEMCS6: + rate_idx = 6; + break; + case DESC_RATEMCS7: + rate_idx = 7; + break; + case DESC_RATEMCS8: + rate_idx = 8; + break; + case DESC_RATEMCS9: + rate_idx = 9; + break; + case DESC_RATEMCS10: + rate_idx = 10; + break; + case DESC_RATEMCS11: + rate_idx = 11; + break; + case DESC_RATEMCS12: + rate_idx = 12; + break; + case DESC_RATEMCS13: + rate_idx = 13; + break; + case DESC_RATEMCS14: + rate_idx = 14; + break; + case DESC_RATEMCS15: + rate_idx = 15; + break; + default: + rate_idx = 0; + break; + } + } + return rate_idx; +} + +static u8 _rtl_get_tx_hw_rate(struct ieee80211_hw *hw, + struct ieee80211_tx_info *info) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct ieee80211_tx_rate *r = &info->status.rates[0]; + struct ieee80211_rate *txrate; + u8 hw_value = 0x0; + + if (r->flags & IEEE80211_TX_RC_MCS) { + /* HT MCS0-15 */ + hw_value = rtlpriv->cfg->maps[RTL_RC_HT_RATEMCS15] - 15 + + r->idx; + } else if (r->flags & IEEE80211_TX_RC_VHT_MCS) { + /* VHT MCS0-9, NSS */ + if (ieee80211_rate_get_vht_nss(r) == 2) + hw_value = rtlpriv->cfg->maps[RTL_RC_VHT_RATE_2SS_MCS9]; + else + hw_value = rtlpriv->cfg->maps[RTL_RC_VHT_RATE_1SS_MCS9]; + + hw_value = hw_value - 9 + ieee80211_rate_get_vht_mcs(r); + } else { + /* legacy */ + txrate = ieee80211_get_tx_rate(hw, info); + + if (txrate) + hw_value = txrate->hw_value; + } + + /* check 5G band */ + if (rtlpriv->rtlhal.current_bandtype == BAND_ON_5G && + hw_value < rtlpriv->cfg->maps[RTL_RC_OFDM_RATE6M]) + hw_value = rtlpriv->cfg->maps[RTL_RC_OFDM_RATE6M]; + + return hw_value; +} + +void rtl_get_tcb_desc(struct ieee80211_hw *hw, + struct ieee80211_tx_info *info, + struct ieee80211_sta *sta, + struct sk_buff *skb, struct rtl_tcb_desc *tcb_desc) +{ +#define SET_RATE_ID(rate_id) \ + ((rtlpriv->cfg->spec_ver & RTL_SPEC_NEW_RATEID) ? \ + rtl_mrate_idx_to_arfr_id(hw, rate_id, \ + (sta_entry ? sta_entry->wireless_mode : \ + WIRELESS_MODE_G)) : \ + rate_id) + + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *rtlmac = rtl_mac(rtl_priv(hw)); + struct ieee80211_hdr *hdr = rtl_get_hdr(skb); + struct rtl_sta_info *sta_entry = + (sta ? (struct rtl_sta_info *)sta->drv_priv : NULL); + + __le16 fc = rtl_get_fc(skb); + + tcb_desc->hw_rate = _rtl_get_tx_hw_rate(hw, info); + + if (rtl_is_tx_report_skb(hw, skb)) + tcb_desc->use_spe_rpt = 1; + + if (ieee80211_is_data(fc)) { + /* + *we set data rate INX 0 + *in rtl_rc.c if skb is special data or + *mgt which need low data rate. + */ + + /* + *So tcb_desc->hw_rate is just used for + *special data and mgt frames + */ + if (info->control.rates[0].idx == 0 || + ieee80211_is_nullfunc(fc)) { + tcb_desc->use_driver_rate = true; + tcb_desc->ratr_index = + SET_RATE_ID(RATR_INX_WIRELESS_MC); + + tcb_desc->disable_ratefallback = 1; + } else { + /* because hw will never use hw_rate + * when tcb_desc->use_driver_rate = false + * so we never set highest N rate here, + * and N rate will all be controlled by FW + * when tcb_desc->use_driver_rate = false + */ + if (sta && sta->vht_cap.vht_supported) { + tcb_desc->hw_rate = + _rtl_get_vht_highest_n_rate(hw, sta); + } else { + if (sta && (sta->ht_cap.ht_supported)) { + tcb_desc->hw_rate = + _rtl_get_highest_n_rate(hw, sta); + } else { + if (rtlmac->mode == WIRELESS_MODE_B) { + tcb_desc->hw_rate = + rtlpriv->cfg->maps[RTL_RC_CCK_RATE11M]; + } else { + tcb_desc->hw_rate = + rtlpriv->cfg->maps[RTL_RC_OFDM_RATE54M]; + } + } + } + } + + if (is_multicast_ether_addr(hdr->addr1)) + tcb_desc->multicast = 1; + else if (is_broadcast_ether_addr(hdr->addr1)) + tcb_desc->broadcast = 1; + + _rtl_txrate_selectmode(hw, sta, tcb_desc); + _rtl_query_bandwidth_mode(hw, sta, tcb_desc); + _rtl_qurey_shortpreamble_mode(hw, tcb_desc, info); + _rtl_query_shortgi(hw, sta, tcb_desc, info); + _rtl_query_protection_mode(hw, tcb_desc, info); + } else { + tcb_desc->use_driver_rate = true; + tcb_desc->ratr_index = SET_RATE_ID(RATR_INX_WIRELESS_MC); + tcb_desc->disable_ratefallback = 1; + tcb_desc->mac_id = 0; + tcb_desc->packet_bw = false; + } +#undef SET_RATE_ID +} + +bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb) +{ + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_priv *rtlpriv = rtl_priv(hw); + __le16 fc = rtl_get_fc(skb); + + if (rtlpriv->dm.supp_phymode_switch && + mac->link_state < MAC80211_LINKED && + (ieee80211_is_auth(fc) || ieee80211_is_probe_req(fc))) { + if (rtlpriv->cfg->ops->chk_switch_dmdp) + rtlpriv->cfg->ops->chk_switch_dmdp(hw); + } + if (ieee80211_is_auth(fc)) { + RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, "MAC80211_LINKING\n"); + + mac->link_state = MAC80211_LINKING; + /* Dul mac */ + rtlpriv->phy.need_iqk = true; + } + return true; +} + +struct sk_buff *rtl_make_del_ba(struct ieee80211_hw *hw, u8 *sa, + u8 *bssid, u16 tid); + +static void process_agg_start(struct ieee80211_hw *hw, + struct ieee80211_hdr *hdr, u16 tid) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct ieee80211_rx_status rx_status = { 0 }; + struct sk_buff *skb_delba = NULL; + + skb_delba = rtl_make_del_ba(hw, hdr->addr2, hdr->addr3, tid); + if (skb_delba) { + rx_status.freq = hw->conf.chandef.chan->center_freq; + rx_status.band = hw->conf.chandef.chan->band; + rx_status.flag |= RX_FLAG_DECRYPTED; + rx_status.flag |= RX_FLAG_MACTIME_START; + rx_status.rate_idx = 0; + rx_status.signal = 50 + 10; + memcpy(IEEE80211_SKB_RXCB(skb_delba), + &rx_status, sizeof(rx_status)); + RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, + "fake del\n", + skb_delba->data, + skb_delba->len); + ieee80211_rx_irqsafe(hw, skb_delba); + } +} + +bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) +{ + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct ieee80211_hdr *hdr = rtl_get_hdr(skb); + struct rtl_priv *rtlpriv = rtl_priv(hw); + __le16 fc = rtl_get_fc(skb); + u8 *act = (u8 *)(((u8 *)skb->data + MAC80211_3ADDR_LEN)); + u8 category; + + if (!ieee80211_is_action(fc)) + return true; + + category = *act; + act++; + switch (category) { + case ACT_CAT_BA: + switch (*act) { + case ACT_ADDBAREQ: + if (mac->act_scanning) + return false; + + RT_TRACE(rtlpriv, (COMP_SEND | COMP_RECV), DBG_DMESG, + "%s ACT_ADDBAREQ From :%pM\n", + is_tx ? "Tx" : "Rx", hdr->addr2); + RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, "req\n", + skb->data, skb->len); + if (!is_tx) { + struct ieee80211_sta *sta = NULL; + struct rtl_sta_info *sta_entry = NULL; + struct rtl_tid_data *tid_data; + struct ieee80211_mgmt *mgmt = (void *)skb->data; + u16 capab = 0, tid = 0; + + rcu_read_lock(); + sta = rtl_find_sta(hw, hdr->addr3); + if (!sta) { + RT_TRACE(rtlpriv, COMP_SEND | COMP_RECV, + DBG_DMESG, "sta is NULL\n"); + rcu_read_unlock(); + return true; + } + + sta_entry = + (struct rtl_sta_info *)sta->drv_priv; + if (!sta_entry) { + rcu_read_unlock(); + return true; + } + capab = + le16_to_cpu(mgmt->u.action.u.addba_req.capab); + tid = (capab & + IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; + if (tid >= MAX_TID_COUNT) { + rcu_read_unlock(); + return true; + } + tid_data = &sta_entry->tids[tid]; + if (tid_data->agg.rx_agg_state == + RTL_RX_AGG_START) + process_agg_start(hw, hdr, tid); + rcu_read_unlock(); + } + break; + case ACT_ADDBARSP: + RT_TRACE(rtlpriv, (COMP_SEND | COMP_RECV), DBG_DMESG, + "%s ACT_ADDBARSP From :%pM\n", + is_tx ? "Tx" : "Rx", hdr->addr2); + break; + case ACT_DELBA: + RT_TRACE(rtlpriv, (COMP_SEND | COMP_RECV), DBG_DMESG, + "ACT_ADDBADEL From :%pM\n", hdr->addr2); + break; + } + break; + default: + break; + } + + return true; +} + +static void setup_special_tx(struct rtl_priv *rtlpriv, struct rtl_ps_ctl *ppsc, + int type) +{ + struct ieee80211_hw *hw = rtlpriv->hw; + + rtlpriv->ra.is_special_data = true; + if (rtlpriv->cfg->ops->get_btc_status()) + rtlpriv->btcoexist.btc_ops->btc_special_packet_notify( + rtlpriv, type); + rtl_lps_leave(hw); + ppsc->last_delaylps_stamp_jiffies = jiffies; +} + +static const u8 *rtl_skb_ether_type_ptr(struct ieee80211_hw *hw, + struct sk_buff *skb, bool is_enc) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 mac_hdr_len = ieee80211_get_hdrlen_from_skb(skb); + u8 encrypt_header_len = 0; + u8 offset; + + switch (rtlpriv->sec.pairwise_enc_algorithm) { + case WEP40_ENCRYPTION: + case WEP104_ENCRYPTION: + encrypt_header_len = 4;/*WEP_IV_LEN*/ + break; + case TKIP_ENCRYPTION: + encrypt_header_len = 8;/*TKIP_IV_LEN*/ + break; + case AESCCMP_ENCRYPTION: + encrypt_header_len = 8;/*CCMP_HDR_LEN;*/ + break; + default: + break; + } + + offset = mac_hdr_len + SNAP_SIZE; + if (is_enc) + offset += encrypt_header_len; + + return skb->data + offset; +} + +/*should call before software enc*/ +u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx, + bool is_enc) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + __le16 fc = rtl_get_fc(skb); + u16 ether_type; + const u8 *ether_type_ptr; + const struct iphdr *ip; + + if (!ieee80211_is_data(fc)) + goto end; + + ether_type_ptr = rtl_skb_ether_type_ptr(hw, skb, is_enc); + ether_type = be16_to_cpup((__be16 *)ether_type_ptr); + + if (ether_type == ETH_P_IP) { + ip = (struct iphdr *)((u8 *)ether_type_ptr + + PROTOC_TYPE_SIZE); + if (ip->protocol == IPPROTO_UDP) { + struct udphdr *udp = (struct udphdr *)((u8 *)ip + + (ip->ihl << 2)); + if (((((u8 *)udp)[1] == 68) && + (((u8 *)udp)[3] == 67)) || + ((((u8 *)udp)[1] == 67) && + (((u8 *)udp)[3] == 68))) { + /* 68 : UDP BOOTP client + * 67 : UDP BOOTP server + */ + RT_TRACE(rtlpriv, (COMP_SEND | COMP_RECV), + DBG_DMESG, "dhcp %s !!\n", + (is_tx) ? "Tx" : "Rx"); + + if (is_tx) + setup_special_tx(rtlpriv, ppsc, + PACKET_DHCP); + + return true; + } + } + } else if (ether_type == ETH_P_ARP) { + if (is_tx) + setup_special_tx(rtlpriv, ppsc, PACKET_ARP); + + return true; + } else if (ether_type == ETH_P_PAE) { + /* EAPOL is seen as in-4way */ + rtlpriv->btcoexist.btc_info.in_4way = true; + rtlpriv->btcoexist.btc_info.in_4way_ts = jiffies; + rtlpriv->btcoexist.btc_info.in_4way_ts = jiffies; + + RT_TRACE(rtlpriv, (COMP_SEND | COMP_RECV), DBG_DMESG, + "802.1X %s EAPOL pkt!!\n", (is_tx) ? "Tx" : "Rx"); + + if (is_tx) { + rtlpriv->ra.is_special_data = true; + rtl_lps_leave(hw); + ppsc->last_delaylps_stamp_jiffies = jiffies; + + setup_special_tx(rtlpriv, ppsc, PACKET_EAPOL); + } + + return true; + } else if (ether_type == ETH_P_IPV6) { + /* TODO: Handle any IPv6 cases that need special handling. + * For now, always return false + */ + goto end; + } + +end: + rtlpriv->ra.is_special_data = false; + return false; +} + +bool rtl_is_tx_report_skb(struct ieee80211_hw *hw, struct sk_buff *skb) +{ + u16 ether_type; + const u8 *ether_type_ptr; + + ether_type_ptr = rtl_skb_ether_type_ptr(hw, skb, true); + ether_type = be16_to_cpup((__be16 *)ether_type_ptr); + + /* EAPOL */ + if (ether_type == ETH_P_PAE) + return true; + + return false; +} + +static u16 rtl_get_tx_report_sn(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_tx_report *tx_report = &rtlpriv->tx_report; + u16 sn; + + /* + * SW_DEFINE[11:8] are reserved (driver fills zeros) + * SW_DEFINE[7:2] are used by driver + * SW_DEFINE[1:0] are reserved for firmware (driver fills zeros) + */ + sn = (atomic_inc_return(&tx_report->sn) & 0x003F) << 2; + + tx_report->last_sent_sn = sn; + tx_report->last_sent_time = jiffies; + + RT_TRACE(rtlpriv, COMP_TX_REPORT, DBG_DMESG, + "Send TX-Report sn=0x%X\n", sn); + + return sn; +} + +void rtl_get_tx_report(struct rtl_tcb_desc *ptcb_desc, u8 *pdesc, + struct ieee80211_hw *hw) +{ + if (ptcb_desc->use_spe_rpt) { + u16 sn = rtl_get_tx_report_sn(hw); + + SET_TX_DESC_SPE_RPT(pdesc, 1); + SET_TX_DESC_SW_DEFINE(pdesc, sn); + } +} + +void rtl_tx_report_handler(struct ieee80211_hw *hw, u8 *tmp_buf, u8 c2h_cmd_len) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_tx_report *tx_report = &rtlpriv->tx_report; + u16 sn; + u8 st, retry; + + if (rtlpriv->cfg->spec_ver & RTL_SPEC_NEW_FW_C2H) { + sn = tmp_buf[6]; + st = tmp_buf[7] & 0xC0; + retry = tmp_buf[8] & 0x3F; + } else { + sn = ((tmp_buf[7] & 0x0F) << 8) | tmp_buf[6]; + st = tmp_buf[0] & 0xC0; + retry = tmp_buf[2] & 0x3F; + } + + tx_report->last_recv_sn = sn; + + RT_TRACE(rtlpriv, COMP_TX_REPORT, DBG_DMESG, + "Recv TX-Report st=0x%02X sn=0x%X retry=0x%X\n", + st, sn, retry); +} + +bool rtl_check_tx_report_acked(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_tx_report *tx_report = &rtlpriv->tx_report; + + if (tx_report->last_sent_sn == tx_report->last_recv_sn) + return true; + + if (time_before(tx_report->last_sent_time + 3 * HZ, jiffies)) { + RT_TRACE(rtlpriv, COMP_TX_REPORT, DBG_WARNING, + "Check TX-Report timeout!! s_sn=0x%X r_sn=0x%X\n", + tx_report->last_sent_sn, tx_report->last_recv_sn); + return true; /* 3 sec. (timeout) seen as acked */ + } + + return false; +} + +void rtl_wait_tx_report_acked(struct ieee80211_hw *hw, u32 wait_ms) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + int i; + + for (i = 0; i < wait_ms; i++) { + if (rtl_check_tx_report_acked(hw)) + break; + usleep_range(1000, 2000); + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + "Wait 1ms (%d/%d) to disable key.\n", i, wait_ms); + } +} + +u32 rtl_get_hal_edca_param(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + enum wireless_mode wirelessmode, + struct ieee80211_tx_queue_params *param) +{ + u32 reg = 0; + u8 sifstime = 10; + u8 slottime = 20; + + /* AIFS = AIFSN * slot time + SIFS */ + switch (wirelessmode) { + case WIRELESS_MODE_A: + case WIRELESS_MODE_N_24G: + case WIRELESS_MODE_N_5G: + case WIRELESS_MODE_AC_5G: + case WIRELESS_MODE_AC_24G: + sifstime = 16; + slottime = 9; + break; + case WIRELESS_MODE_G: + slottime = (vif->bss_conf.use_short_slot ? 9 : 20); + break; + default: + break; + } + + reg |= (param->txop & 0x7FF) << 16; + reg |= (fls(param->cw_max) & 0xF) << 12; + reg |= (fls(param->cw_min) & 0xF) << 8; + reg |= (param->aifs & 0x0F) * slottime + sifstime; + + return reg; +} + +/********************************************************* + * + * functions called by core.c + * + *********************************************************/ +int rtl_tx_agg_start(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, u16 tid, u16 *ssn) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_tid_data *tid_data; + struct rtl_sta_info *sta_entry = NULL; + + if (!sta) + return -EINVAL; + + if (unlikely(tid >= MAX_TID_COUNT)) + return -EINVAL; + + sta_entry = (struct rtl_sta_info *)sta->drv_priv; + if (!sta_entry) + return -ENXIO; + tid_data = &sta_entry->tids[tid]; + + RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, + "on ra = %pM tid = %d seq:%d\n", sta->addr, tid, + tid_data->seq_number); + + *ssn = tid_data->seq_number; + tid_data->agg.agg_state = RTL_AGG_START; + + ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); + return 0; +} + +int rtl_tx_agg_stop(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, u16 tid) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_tid_data *tid_data; + struct rtl_sta_info *sta_entry = NULL; + + if (!sta) + return -EINVAL; + + RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, + "on ra = %pM tid = %d\n", sta->addr, tid); + + if (unlikely(tid >= MAX_TID_COUNT)) + return -EINVAL; + + sta_entry = (struct rtl_sta_info *)sta->drv_priv; + tid_data = &sta_entry->tids[tid]; + sta_entry->tids[tid].agg.agg_state = RTL_AGG_STOP; + + ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); + return 0; +} + +int rtl_rx_agg_start(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u16 tid) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_tid_data *tid_data; + struct rtl_sta_info *sta_entry = NULL; + u8 reject_agg; + + if (!sta) + return -EINVAL; + + if (unlikely(tid >= MAX_TID_COUNT)) + return -EINVAL; + + if (rtlpriv->cfg->ops->get_btc_status()) { + rtlpriv->btcoexist.btc_ops->btc_get_ampdu_cfg(rtlpriv, + &reject_agg, + NULL, NULL); + if (reject_agg) + return -EINVAL; + } + + sta_entry = (struct rtl_sta_info *)sta->drv_priv; + if (!sta_entry) + return -ENXIO; + tid_data = &sta_entry->tids[tid]; + + RT_TRACE(rtlpriv, COMP_RECV, DBG_DMESG, + "on ra = %pM tid = %d seq:%d\n", sta->addr, tid, + tid_data->seq_number); + + tid_data->agg.rx_agg_state = RTL_RX_AGG_START; + return 0; +} + +int rtl_rx_agg_stop(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u16 tid) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_sta_info *sta_entry = NULL; + + if (!sta) + return -EINVAL; + + RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, + "on ra = %pM tid = %d\n", sta->addr, tid); + + if (unlikely(tid >= MAX_TID_COUNT)) + return -EINVAL; + + sta_entry = (struct rtl_sta_info *)sta->drv_priv; + sta_entry->tids[tid].agg.rx_agg_state = RTL_RX_AGG_STOP; + + return 0; +} + +int rtl_tx_agg_oper(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u16 tid) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_sta_info *sta_entry = NULL; + + if (!sta) + return -EINVAL; + + RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, + "on ra = %pM tid = %d\n", sta->addr, tid); + + if (unlikely(tid >= MAX_TID_COUNT)) + return -EINVAL; + + sta_entry = (struct rtl_sta_info *)sta->drv_priv; + sta_entry->tids[tid].agg.agg_state = RTL_AGG_OPERATIONAL; + + return 0; +} + +void rtl_rx_ampdu_apply(struct rtl_priv *rtlpriv) +{ + struct rtl_btc_ops *btc_ops = rtlpriv->btcoexist.btc_ops; + u8 reject_agg = 0, ctrl_agg_size = 0, agg_size = 0; + + if (rtlpriv->cfg->ops->get_btc_status()) + btc_ops->btc_get_ampdu_cfg(rtlpriv, &reject_agg, + &ctrl_agg_size, &agg_size); + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, + "Set RX AMPDU: coex - reject=%d, ctrl_agg_size=%d, size=%d", + reject_agg, ctrl_agg_size, agg_size); + + rtlpriv->hw->max_rx_aggregation_subframes = + (ctrl_agg_size ? agg_size : IEEE80211_MAX_AMPDU_BUF); +} + +/********************************************************* + * + * wq & timer callback functions + * + *********************************************************/ +/* this function is used for roaming */ +void rtl_beacon_statistic(struct ieee80211_hw *hw, struct sk_buff *skb) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + + if (rtlpriv->mac80211.opmode != NL80211_IFTYPE_STATION) + return; + + if (rtlpriv->mac80211.link_state < MAC80211_LINKED) + return; + + /* check if this really is a beacon */ + if (!ieee80211_is_beacon(hdr->frame_control) && + !ieee80211_is_probe_resp(hdr->frame_control)) + return; + + /* min. beacon length + FCS_LEN */ + if (skb->len <= 40 + FCS_LEN) + return; + + /* and only beacons from the associated BSSID, please */ + if (!ether_addr_equal(hdr->addr3, rtlpriv->mac80211.bssid)) + return; + + rtlpriv->link_info.bcn_rx_inperiod++; +} + +static void rtl_free_entries_from_scan_list(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_bssid_entry *entry, *next; + + list_for_each_entry_safe(entry, next, &rtlpriv->scan_list.list, list) { + list_del(&entry->list); + kfree(entry); + rtlpriv->scan_list.num--; + } +} + +void rtl_scan_list_expire(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_bssid_entry *entry, *next; + unsigned long flags; + + spin_lock_irqsave(&rtlpriv->locks.scan_list_lock, flags); + + list_for_each_entry_safe(entry, next, &rtlpriv->scan_list.list, list) { + /* 180 seconds */ + if (jiffies_to_msecs(jiffies - entry->age) < 180000) + continue; + + list_del(&entry->list); + rtlpriv->scan_list.num--; + + RT_TRACE(rtlpriv, COMP_SCAN, DBG_LOUD, + "BSSID=%pM is expire in scan list (total=%d)\n", + entry->bssid, rtlpriv->scan_list.num); + kfree(entry); + } + + spin_unlock_irqrestore(&rtlpriv->locks.scan_list_lock, flags); + + rtlpriv->btcoexist.btc_info.ap_num = rtlpriv->scan_list.num; +} + +void rtl_collect_scan_list(struct ieee80211_hw *hw, struct sk_buff *skb) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + unsigned long flags; + + struct rtl_bssid_entry *entry; + bool entry_found = false; + + /* check if it is scanning */ + if (!mac->act_scanning) + return; + + /* check if this really is a beacon */ + if (!ieee80211_is_beacon(hdr->frame_control) && + !ieee80211_is_probe_resp(hdr->frame_control)) + return; + + spin_lock_irqsave(&rtlpriv->locks.scan_list_lock, flags); + + list_for_each_entry(entry, &rtlpriv->scan_list.list, list) { + if (memcmp(entry->bssid, hdr->addr3, ETH_ALEN) == 0) { + list_del_init(&entry->list); + entry_found = true; + RT_TRACE(rtlpriv, COMP_SCAN, DBG_LOUD, + "Update BSSID=%pM to scan list (total=%d)\n", + hdr->addr3, rtlpriv->scan_list.num); + break; + } + } + + if (!entry_found) { + entry = kmalloc(sizeof(*entry), GFP_ATOMIC); + + if (!entry) + goto label_err; + + memcpy(entry->bssid, hdr->addr3, ETH_ALEN); + rtlpriv->scan_list.num++; + + RT_TRACE(rtlpriv, COMP_SCAN, DBG_LOUD, + "Add BSSID=%pM to scan list (total=%d)\n", + hdr->addr3, rtlpriv->scan_list.num); + } + + entry->age = jiffies; + + list_add_tail(&entry->list, &rtlpriv->scan_list.list); + +label_err: + spin_unlock_irqrestore(&rtlpriv->locks.scan_list_lock, flags); +} + +void rtl_watchdog_wq_callback(void *data) +{ + struct rtl_works *rtlworks = container_of_dwork_rtl(data, + struct rtl_works, + watchdog_wq); + struct ieee80211_hw *hw = rtlworks->hw; + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + bool busytraffic = false; + bool tx_busy_traffic = false; + bool rx_busy_traffic = false; + bool higher_busytraffic = false; + bool higher_busyrxtraffic = false; + u8 idx, tid; + u32 rx_cnt_inp4eriod = 0; + u32 tx_cnt_inp4eriod = 0; + u32 aver_rx_cnt_inperiod = 0; + u32 aver_tx_cnt_inperiod = 0; + u32 aver_tidtx_inperiod[MAX_TID_COUNT] = {0}; + u32 tidtx_inp4eriod[MAX_TID_COUNT] = {0}; + + if (is_hal_stop(rtlhal)) + return; + + /* <1> Determine if action frame is allowed */ + if (mac->link_state > MAC80211_NOLINK) { + if (mac->cnt_after_linked < 20) + mac->cnt_after_linked++; + } else { + mac->cnt_after_linked = 0; + } + + /* <2> to check if traffic busy, if + * busytraffic we don't change channel + */ + if (mac->link_state >= MAC80211_LINKED) { + /* (1) get aver_rx_cnt_inperiod & aver_tx_cnt_inperiod */ + for (idx = 0; idx <= 2; idx++) { + rtlpriv->link_info.num_rx_in4period[idx] = + rtlpriv->link_info.num_rx_in4period[idx + 1]; + rtlpriv->link_info.num_tx_in4period[idx] = + rtlpriv->link_info.num_tx_in4period[idx + 1]; + } + rtlpriv->link_info.num_rx_in4period[3] = + rtlpriv->link_info.num_rx_inperiod; + rtlpriv->link_info.num_tx_in4period[3] = + rtlpriv->link_info.num_tx_inperiod; + for (idx = 0; idx <= 3; idx++) { + rx_cnt_inp4eriod += + rtlpriv->link_info.num_rx_in4period[idx]; + tx_cnt_inp4eriod += + rtlpriv->link_info.num_tx_in4period[idx]; + } + aver_rx_cnt_inperiod = rx_cnt_inp4eriod / 4; + aver_tx_cnt_inperiod = tx_cnt_inp4eriod / 4; + + /* (2) check traffic busy */ + if (aver_rx_cnt_inperiod > 100 || aver_tx_cnt_inperiod > 100) { + busytraffic = true; + if (aver_rx_cnt_inperiod > aver_tx_cnt_inperiod) + rx_busy_traffic = true; + else + tx_busy_traffic = false; + } + + /* Higher Tx/Rx data. */ + if (aver_rx_cnt_inperiod > 4000 || + aver_tx_cnt_inperiod > 4000) { + higher_busytraffic = true; + + /* Extremely high Rx data. */ + if (aver_rx_cnt_inperiod > 5000) + higher_busyrxtraffic = true; + } + + /* check every tid's tx traffic */ + for (tid = 0; tid <= 7; tid++) { + for (idx = 0; idx <= 2; idx++) + rtlpriv->link_info.tidtx_in4period[tid][idx] = + rtlpriv->link_info.tidtx_in4period[tid] + [idx + 1]; + rtlpriv->link_info.tidtx_in4period[tid][3] = + rtlpriv->link_info.tidtx_inperiod[tid]; + + for (idx = 0; idx <= 3; idx++) + tidtx_inp4eriod[tid] += + rtlpriv->link_info.tidtx_in4period[tid][idx]; + aver_tidtx_inperiod[tid] = tidtx_inp4eriod[tid] / 4; + if (aver_tidtx_inperiod[tid] > 5000) + rtlpriv->link_info.higher_busytxtraffic[tid] = + true; + else + rtlpriv->link_info.higher_busytxtraffic[tid] = + false; + } + + /* PS is controlled by coex. */ + if (rtlpriv->cfg->ops->get_btc_status() && + rtlpriv->btcoexist.btc_ops->btc_is_bt_ctrl_lps(rtlpriv)) + goto label_lps_done; + + if (((rtlpriv->link_info.num_rx_inperiod + + rtlpriv->link_info.num_tx_inperiod) > 8) || + (rtlpriv->link_info.num_rx_inperiod > 2)) + rtl_lps_leave(hw); + else + rtl_lps_enter(hw); + +label_lps_done: + ; + } + + rtlpriv->link_info.num_rx_inperiod = 0; + rtlpriv->link_info.num_tx_inperiod = 0; + for (tid = 0; tid <= 7; tid++) + rtlpriv->link_info.tidtx_inperiod[tid] = 0; + + rtlpriv->link_info.busytraffic = busytraffic; + rtlpriv->link_info.higher_busytraffic = higher_busytraffic; + rtlpriv->link_info.rx_busy_traffic = rx_busy_traffic; + rtlpriv->link_info.tx_busy_traffic = tx_busy_traffic; + rtlpriv->link_info.higher_busyrxtraffic = higher_busyrxtraffic; + + rtlpriv->stats.txbytesunicast_inperiod = + rtlpriv->stats.txbytesunicast - + rtlpriv->stats.txbytesunicast_last; + rtlpriv->stats.rxbytesunicast_inperiod = + rtlpriv->stats.rxbytesunicast - + rtlpriv->stats.rxbytesunicast_last; + rtlpriv->stats.txbytesunicast_last = rtlpriv->stats.txbytesunicast; + rtlpriv->stats.rxbytesunicast_last = rtlpriv->stats.rxbytesunicast; + + rtlpriv->stats.txbytesunicast_inperiod_tp = + (u32)(rtlpriv->stats.txbytesunicast_inperiod * 8 / 2 / + 1024 / 1024); + rtlpriv->stats.rxbytesunicast_inperiod_tp = + (u32)(rtlpriv->stats.rxbytesunicast_inperiod * 8 / 2 / + 1024 / 1024); + + /* <3> DM */ + if (!rtlpriv->cfg->mod_params->disable_watchdog) + rtlpriv->cfg->ops->dm_watchdog(hw); + + /* <4> roaming */ + if (mac->link_state == MAC80211_LINKED && + mac->opmode == NL80211_IFTYPE_STATION) { + if ((rtlpriv->link_info.bcn_rx_inperiod + + rtlpriv->link_info.num_rx_inperiod) == 0) { + rtlpriv->link_info.roam_times++; + RT_TRACE(rtlpriv, COMP_ERR, DBG_DMESG, + "AP off for %d s\n", + (rtlpriv->link_info.roam_times * 2)); + + /* if we can't recv beacon for 10s, + * we should reconnect this AP + */ + if (rtlpriv->link_info.roam_times >= 5) { + pr_err("AP off, try to reconnect now\n"); + rtlpriv->link_info.roam_times = 0; + ieee80211_connection_loss( + rtlpriv->mac80211.vif); + } + } else { + rtlpriv->link_info.roam_times = 0; + } + } + + if (rtlpriv->cfg->ops->get_btc_status()) + rtlpriv->btcoexist.btc_ops->btc_periodical(rtlpriv); + + if (rtlpriv->btcoexist.btc_info.in_4way) { + if (time_after(jiffies, rtlpriv->btcoexist.btc_info.in_4way_ts + + msecs_to_jiffies(IN_4WAY_TIMEOUT_TIME))) + rtlpriv->btcoexist.btc_info.in_4way = false; + } + + rtlpriv->link_info.bcn_rx_inperiod = 0; + + /* <6> scan list */ + rtl_scan_list_expire(hw); +} + +void rtl_watch_dog_timer_callback(unsigned long data) +{ + struct ieee80211_hw *hw = (struct ieee80211_hw *)data; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + queue_delayed_work(rtlpriv->works.rtl_wq, + &rtlpriv->works.watchdog_wq, 0); + + mod_timer(&rtlpriv->works.watchdog_timer, + jiffies + MSECS(RTL_WATCH_DOG_TIME)); +} + +void rtl_fwevt_wq_callback(void *data) +{ + struct rtl_works *rtlworks = + container_of_dwork_rtl(data, struct rtl_works, fwevt_wq); + struct ieee80211_hw *hw = rtlworks->hw; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtlpriv->cfg->ops->c2h_command_handle(hw); +} + +void rtl_c2hcmd_enqueue(struct ieee80211_hw *hw, u8 tag, u8 len, u8 *val) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + unsigned long flags; + struct rtl_c2hcmd *c2hcmd; + + c2hcmd = kmalloc(sizeof(*c2hcmd), + in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); + + if (!c2hcmd) + goto label_err; + + c2hcmd->val = kmalloc(len, + in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); + + if (!c2hcmd->val) + goto label_err2; + + /* fill data */ + c2hcmd->tag = tag; + c2hcmd->len = len; + memcpy(c2hcmd->val, val, len); + + /* enqueue */ + spin_lock_irqsave(&rtlpriv->locks.c2hcmd_lock, flags); + + list_add_tail(&c2hcmd->list, &rtlpriv->c2hcmd_list); + + spin_unlock_irqrestore(&rtlpriv->locks.c2hcmd_lock, flags); + + /* wake up wq */ + queue_delayed_work(rtlpriv->works.rtl_wq, &rtlpriv->works.c2hcmd_wq, 0); + + return; + +label_err2: + kfree(c2hcmd); + +label_err: + RT_TRACE(rtlpriv, COMP_CMD, DBG_WARNING, + "C2H cmd enqueue fail.\n"); +} + +void rtl_c2hcmd_launcher(struct ieee80211_hw *hw, int exec) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + unsigned long flags; + struct rtl_c2hcmd *c2hcmd; + int i; + + for (i = 0; i < 200; i++) { + /* dequeue a task */ + spin_lock_irqsave(&rtlpriv->locks.c2hcmd_lock, flags); + + c2hcmd = list_first_entry_or_null(&rtlpriv->c2hcmd_list, + struct rtl_c2hcmd, list); + + if (c2hcmd) + list_del(&c2hcmd->list); + + spin_unlock_irqrestore(&rtlpriv->locks.c2hcmd_lock, flags); + + /* do it */ + if (!c2hcmd) + break; + + if (rtlpriv->cfg->ops->c2h_content_parsing && exec) + rtlpriv->cfg->ops->c2h_content_parsing(hw, + c2hcmd->tag, c2hcmd->len, c2hcmd->val); + + /* free */ + kfree(c2hcmd->val); + + kfree(c2hcmd); + } +} + +void rtl_c2hcmd_wq_callback(void *data) +{ + struct rtl_works *rtlworks = container_of_dwork_rtl(data, + struct rtl_works, + c2hcmd_wq); + struct ieee80211_hw *hw = rtlworks->hw; + + rtl_c2hcmd_launcher(hw, 1); +} + +void rtl_easy_concurrent_retrytimer_callback(unsigned long data) +{ + struct ieee80211_hw *hw = (struct ieee80211_hw *)data; + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_priv *buddy_priv = rtlpriv->buddy_priv; + + if (!buddy_priv) + return; + + rtlpriv->cfg->ops->dualmac_easy_concurrent(hw); +} + +/********************************************************* + * + * frame process functions + * + *********************************************************/ +u8 *rtl_find_ie(u8 *data, unsigned int len, u8 ie) +{ + struct ieee80211_mgmt *mgmt = (void *)data; + u8 *pos, *end; + + pos = (u8 *)mgmt->u.beacon.variable; + end = data + len; + while (pos < end) { + if (pos + 2 + pos[1] > end) + return NULL; + + if (pos[0] == ie) + return pos; + + pos += 2 + pos[1]; + } + return NULL; +} + +/* when we use 2 rx ants we send IEEE80211_SMPS_OFF */ +/* when we use 1 rx ant we send IEEE80211_SMPS_STATIC */ +static struct sk_buff *rtl_make_smps_action(struct ieee80211_hw *hw, + enum ieee80211_smps_mode smps, + u8 *da, u8 *bssid) +{ + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct sk_buff *skb; + struct ieee80211_mgmt *action_frame; + + /* 27 = header + category + action + smps mode */ + skb = dev_alloc_skb(27 + hw->extra_tx_headroom); + if (!skb) + return NULL; + + skb_reserve(skb, hw->extra_tx_headroom); + action_frame = skb_put_zero(skb, 27); + memcpy(action_frame->da, da, ETH_ALEN); + memcpy(action_frame->sa, rtlefuse->dev_addr, ETH_ALEN); + memcpy(action_frame->bssid, bssid, ETH_ALEN); + action_frame->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | + IEEE80211_STYPE_ACTION); + action_frame->u.action.category = WLAN_CATEGORY_HT; + action_frame->u.action.u.ht_smps.action = WLAN_HT_ACTION_SMPS; + switch (smps) { + case IEEE80211_SMPS_AUTOMATIC:/* 0 */ + case IEEE80211_SMPS_NUM_MODES:/* 4 */ + WARN_ON(1); + /* Here will get a 'MISSING_BREAK' in Coverity Test, just ignore it. + * According to Kernel Code, here is right. + */ + case IEEE80211_SMPS_OFF:/* 1 */ /*MIMO_PS_NOLIMIT*/ + action_frame->u.action.u.ht_smps.smps_control = + WLAN_HT_SMPS_CONTROL_DISABLED;/* 0 */ + break; + case IEEE80211_SMPS_STATIC:/* 2 */ /*MIMO_PS_STATIC*/ + action_frame->u.action.u.ht_smps.smps_control = + WLAN_HT_SMPS_CONTROL_STATIC;/* 1 */ + break; + case IEEE80211_SMPS_DYNAMIC:/* 3 */ /*MIMO_PS_DYNAMIC*/ + action_frame->u.action.u.ht_smps.smps_control = + WLAN_HT_SMPS_CONTROL_DYNAMIC;/* 3 */ + break; + } + + return skb; +} + +int rtl_send_smps_action(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, + enum ieee80211_smps_mode smps) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct sk_buff *skb = NULL; + struct rtl_tcb_desc tcb_desc; + u8 bssid[ETH_ALEN] = {0}; + + memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc)); + + if (rtlpriv->mac80211.act_scanning) + goto err_free; + + if (!sta) + goto err_free; + + if (unlikely(is_hal_stop(rtlhal) || ppsc->rfpwr_state != ERFON)) + goto err_free; + + if (!test_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status)) + goto err_free; + + if (rtlpriv->mac80211.opmode == NL80211_IFTYPE_AP) + memcpy(bssid, rtlpriv->efuse.dev_addr, ETH_ALEN); + else + memcpy(bssid, rtlpriv->mac80211.bssid, ETH_ALEN); + + skb = rtl_make_smps_action(hw, smps, sta->addr, bssid); + /* this is a type = mgmt * stype = action frame */ + if (skb) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct rtl_sta_info *sta_entry = + (struct rtl_sta_info *)sta->drv_priv; + sta_entry->mimo_ps = smps; + /* rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0, true); */ + + info->control.rates[0].idx = 0; + info->band = hw->conf.chandef.chan->band; + rtlpriv->intf_ops->adapter_tx(hw, sta, skb, &tcb_desc); + } + return 1; + +err_free: + return 0; +} + +void rtl_phy_scan_operation_backup(struct ieee80211_hw *hw, u8 operation) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + enum io_type iotype; + + if (!is_hal_stop(rtlhal)) { + switch (operation) { + case SCAN_OPT_BACKUP: + iotype = IO_CMD_PAUSE_DM_BY_SCAN; + rtlpriv->cfg->ops->set_hw_reg(hw, + HW_VAR_IO_CMD, + (u8 *)&iotype); + break; + case SCAN_OPT_RESTORE: + iotype = IO_CMD_RESUME_DM_BY_SCAN; + rtlpriv->cfg->ops->set_hw_reg(hw, + HW_VAR_IO_CMD, + (u8 *)&iotype); + break; + default: + pr_err("Unknown Scan Backup operation.\n"); + break; + } + } +} + +/* because mac80211 have issues when can receive del ba + * so here we just make a fake del_ba if we receive a ba_req + * but rx_agg was opened to let mac80211 release some ba + * related resources, so please this del_ba for tx + */ +struct sk_buff *rtl_make_del_ba(struct ieee80211_hw *hw, + u8 *sa, u8 *bssid, u16 tid) +{ + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct sk_buff *skb; + struct ieee80211_mgmt *action_frame; + u16 params; + + /* 27 = header + category + action + smps mode */ + skb = dev_alloc_skb(34 + hw->extra_tx_headroom); + if (!skb) + return NULL; + + skb_reserve(skb, hw->extra_tx_headroom); + action_frame = skb_put_zero(skb, 34); + memcpy(action_frame->sa, sa, ETH_ALEN); + memcpy(action_frame->da, rtlefuse->dev_addr, ETH_ALEN); + memcpy(action_frame->bssid, bssid, ETH_ALEN); + action_frame->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | + IEEE80211_STYPE_ACTION); + action_frame->u.action.category = WLAN_CATEGORY_BACK; + action_frame->u.action.u.delba.action_code = WLAN_ACTION_DELBA; + params = (u16)(1 << 11); /* bit 11 initiator */ + params |= (u16)(tid << 12); /* bit 15:12 TID number */ + + action_frame->u.action.u.delba.params = cpu_to_le16(params); + action_frame->u.action.u.delba.reason_code = + cpu_to_le16(WLAN_REASON_QSTA_TIMEOUT); + + return skb; +} + +bool rtl_check_beacon_key(struct ieee80211_hw *hw, void *data, unsigned int len) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_phy *rtlphy = &rtlpriv->phy; + struct ieee80211_hdr *hdr = data; + struct ieee80211_ht_cap *ht_cap_ie; + struct ieee80211_ht_operation *ht_oper_ie = NULL; + struct rtl_beacon_keys bcn_key = {}; + struct rtl_beacon_keys *cur_bcn_key; + u8 *ht_cap; + u8 ht_cap_len; + u8 *ht_oper; + u8 ht_oper_len; + u8 *ds_param; + u8 ds_param_len; + + if (mac->opmode != NL80211_IFTYPE_STATION) + return false; + + /* check if this really is a beacon*/ + if (!ieee80211_is_beacon(hdr->frame_control)) + return false; + + /* min. beacon length + FCS_LEN */ + if (len <= 40 + FCS_LEN) + return false; + + cur_bcn_key = &mac->cur_beacon_keys; + + if (rtlpriv->mac80211.link_state == MAC80211_NOLINK) { + if (cur_bcn_key->valid) { + cur_bcn_key->valid = false; + RT_TRACE(rtlpriv, COMP_BEACON, DBG_LOUD, + "Reset cur_beacon_keys.valid to false!\n"); + } + return false; + } + + /* and only beacons from the associated BSSID, please */ + if (!ether_addr_equal(hdr->addr3, rtlpriv->mac80211.bssid)) + return false; + + /***** Parsing DS Param IE ******/ + ds_param = rtl_find_ie(data, len - FCS_LEN, WLAN_EID_DS_PARAMS); + + if (ds_param && !(ds_param[1] < sizeof(*ds_param))) { + ds_param_len = ds_param[1]; + bcn_key.bcn_channel = ds_param[2]; + } else { + ds_param = NULL; + } + + /***** Parsing HT Cap. IE ******/ + ht_cap = rtl_find_ie(data, len - FCS_LEN, WLAN_EID_HT_CAPABILITY); + + if (ht_cap && !(ht_cap[1] < sizeof(*ht_cap))) { + ht_cap_len = ht_cap[1]; + ht_cap_ie = (struct ieee80211_ht_cap *)&ht_cap[2]; + bcn_key.ht_cap_info = ht_cap_ie->cap_info; + } else { + ht_cap = NULL; + } + + /***** Parsing HT Info. IE ******/ + ht_oper = rtl_find_ie(data, len - FCS_LEN, WLAN_EID_HT_OPERATION); + + if (ht_oper && !(ht_oper[1] < sizeof(*ht_oper))) { + ht_oper_len = ht_oper[1]; + ht_oper_ie = (struct ieee80211_ht_operation *)&ht_oper[2]; + } else { + ht_oper = NULL; + } + + /* update bcn_key */ + + if (!ds_param && ht_oper && ht_oper_ie) + bcn_key.bcn_channel = ht_oper_ie->primary_chan; + + if (ht_oper && ht_oper_ie) + bcn_key.ht_info_infos_0_sco = ht_oper_ie->ht_param & 0x03; + + bcn_key.valid = true; + + /* update cur_beacon_keys or compare beacon key */ + if ((rtlpriv->mac80211.link_state != MAC80211_LINKED) && + (rtlpriv->mac80211.link_state != MAC80211_LINKED_SCANNING)) + return true; + + if (!cur_bcn_key->valid) { + /* update cur_beacon_keys */ + memcpy(cur_bcn_key, &bcn_key, sizeof(bcn_key)); + cur_bcn_key->valid = true; + + RT_TRACE(rtlpriv, COMP_BEACON, DBG_LOUD, + "Beacon key update!ch=%d, ht_cap_info=0x%x, sco=0x%x\n", + cur_bcn_key->bcn_channel, + cur_bcn_key->ht_cap_info, + cur_bcn_key->ht_info_infos_0_sco); + return true; + } + + /* compare beacon key */ + if (!memcmp(cur_bcn_key, &bcn_key, sizeof(bcn_key))) { + /* same beacon key */ + mac->new_beacon_cnt = 0; + goto chk_exit; + } + + if ((cur_bcn_key->bcn_channel == bcn_key.bcn_channel) && + (cur_bcn_key->ht_cap_info == bcn_key.ht_cap_info)) { + /* Beacon HT info IE, secondary channel offset check */ + /* 40M -> 20M */ + if (cur_bcn_key->ht_info_infos_0_sco > + bcn_key.ht_info_infos_0_sco) { + /* Not a new beacon */ + RT_TRACE(rtlpriv, COMP_BEACON, DBG_DMESG, + "Beacon BW change! sco:0x%x -> 0x%x\n", + cur_bcn_key->ht_info_infos_0_sco, + bcn_key.ht_info_infos_0_sco); + + cur_bcn_key->ht_info_infos_0_sco = + bcn_key.ht_info_infos_0_sco; + } else { + /* 20M -> 40M */ + if (rtlphy->max_ht_chan_bw >= HT_CHANNEL_WIDTH_20_40) { + /* Not a new beacon */ + RT_TRACE(rtlpriv, COMP_BEACON, DBG_DMESG, + "Beacon BW change! sco:0x%x -> 0x%x\n", + cur_bcn_key->ht_info_infos_0_sco, + bcn_key.ht_info_infos_0_sco); + + cur_bcn_key->ht_info_infos_0_sco = + bcn_key.ht_info_infos_0_sco; + } else { + mac->new_beacon_cnt++; + } + } + } else { + mac->new_beacon_cnt++; + } + + if (mac->new_beacon_cnt == 1) { + RT_TRACE(rtlpriv, COMP_BEACON, DBG_DMESG, + "Get new beacon.\n"); + RT_TRACE(rtlpriv, COMP_BEACON, DBG_DMESG, + "Cur : ch=%d, ht_cap=0x%x, sco=0x%x\n", + cur_bcn_key->bcn_channel, + cur_bcn_key->ht_cap_info, + cur_bcn_key->ht_info_infos_0_sco); + RT_TRACE(rtlpriv, COMP_BEACON, DBG_DMESG, + "New RX : ch=%d, ht_cap=0x%x, sco=0x%x\n", + bcn_key.bcn_channel, + bcn_key.ht_cap_info, + bcn_key.ht_info_infos_0_sco); + + } else if (mac->new_beacon_cnt > 1) { + RT_TRACE(rtlpriv, COMP_BEACON, DBG_DMESG, + "new beacon cnt: %d\n", + mac->new_beacon_cnt); + } + + if (mac->new_beacon_cnt > 3) { + ieee80211_connection_loss(rtlpriv->mac80211.vif); + RT_TRACE(rtlpriv, COMP_BEACON, DBG_DMESG, + "new beacon cnt >3, disconnect !\n"); + } + +chk_exit: + + return true; +} + +/********************************************************* + * + * IOT functions + * + *********************************************************/ +static bool rtl_chk_vendor_ouisub(struct ieee80211_hw *hw, + struct octet_string vendor_ie) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + bool matched = false; + static u8 athcap_1[] = { 0x00, 0x03, 0x7F }; + static u8 athcap_2[] = { 0x00, 0x13, 0x74 }; + static u8 broadcap_1[] = { 0x00, 0x10, 0x18 }; + static u8 broadcap_2[] = { 0x00, 0x0a, 0xf7 }; + static u8 broadcap_3[] = { 0x00, 0x05, 0xb5 }; + static u8 racap[] = { 0x00, 0x0c, 0x43 }; + static u8 ciscocap[] = { 0x00, 0x40, 0x96 }; + static u8 marvcap[] = { 0x00, 0x50, 0x43 }; + + if (memcmp(vendor_ie.octet, athcap_1, 3) == 0 || + memcmp(vendor_ie.octet, athcap_2, 3) == 0) { + rtlpriv->mac80211.vendor = PEER_ATH; + matched = true; + } else if (memcmp(vendor_ie.octet, broadcap_1, 3) == 0 || + memcmp(vendor_ie.octet, broadcap_2, 3) == 0 || + memcmp(vendor_ie.octet, broadcap_3, 3) == 0) { + rtlpriv->mac80211.vendor = PEER_BROAD; + matched = true; + } else if (memcmp(vendor_ie.octet, racap, 3) == 0) { + rtlpriv->mac80211.vendor = PEER_RAL; + matched = true; + } else if (memcmp(vendor_ie.octet, ciscocap, 3) == 0) { + rtlpriv->mac80211.vendor = PEER_CISCO; + matched = true; + } else if (memcmp(vendor_ie.octet, marvcap, 3) == 0) { + rtlpriv->mac80211.vendor = PEER_MARV; + matched = true; + } + + return matched; +} + +static bool rtl_find_221_ie(struct ieee80211_hw *hw, u8 *data, + unsigned int len) +{ + struct ieee80211_mgmt *mgmt = (void *)data; + struct octet_string vendor_ie; + u8 *pos, *end; + + pos = (u8 *)mgmt->u.beacon.variable; + end = data + len; + while (pos < end) { + if (pos[0] == 221) { + vendor_ie.length = pos[1]; + vendor_ie.octet = &pos[2]; + if (rtl_chk_vendor_ouisub(hw, vendor_ie)) + return true; + } + + if (pos + 2 + pos[1] > end) + return false; + + pos += 2 + pos[1]; + } + return false; +} + +void rtl_recognize_peer(struct ieee80211_hw *hw, u8 *data, unsigned int len) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct ieee80211_hdr *hdr = (void *)data; + u32 vendor = PEER_UNKNOWN; + + static u8 ap3_1[3] = { 0x00, 0x14, 0xbf }; + static u8 ap3_2[3] = { 0x00, 0x1a, 0x70 }; + static u8 ap3_3[3] = { 0x00, 0x1d, 0x7e }; + static u8 ap4_1[3] = { 0x00, 0x90, 0xcc }; + static u8 ap4_2[3] = { 0x00, 0x0e, 0x2e }; + static u8 ap4_3[3] = { 0x00, 0x18, 0x02 }; + static u8 ap4_4[3] = { 0x00, 0x17, 0x3f }; + static u8 ap4_5[3] = { 0x00, 0x1c, 0xdf }; + static u8 ap5_1[3] = { 0x00, 0x1c, 0xf0 }; + static u8 ap5_2[3] = { 0x00, 0x21, 0x91 }; + static u8 ap5_3[3] = { 0x00, 0x24, 0x01 }; + static u8 ap5_4[3] = { 0x00, 0x15, 0xe9 }; + static u8 ap5_5[3] = { 0x00, 0x17, 0x9A }; + static u8 ap5_6[3] = { 0x00, 0x18, 0xE7 }; + static u8 ap6_1[3] = { 0x00, 0x17, 0x94 }; + static u8 ap7_1[3] = { 0x00, 0x14, 0xa4 }; + + if (mac->opmode != NL80211_IFTYPE_STATION) + return; + + if (mac->link_state == MAC80211_NOLINK) { + mac->vendor = PEER_UNKNOWN; + return; + } + + if (mac->cnt_after_linked > 2) + return; + + /* check if this really is a beacon */ + if (!ieee80211_is_beacon(hdr->frame_control)) + return; + + /* min. beacon length + FCS_LEN */ + if (len <= 40 + FCS_LEN) + return; + + /* and only beacons from the associated BSSID, please */ + if (!ether_addr_equal_64bits(hdr->addr3, rtlpriv->mac80211.bssid)) + return; + + if (rtl_find_221_ie(hw, data, len)) + vendor = mac->vendor; + + if ((memcmp(mac->bssid, ap5_1, 3) == 0) || + (memcmp(mac->bssid, ap5_2, 3) == 0) || + (memcmp(mac->bssid, ap5_3, 3) == 0) || + (memcmp(mac->bssid, ap5_4, 3) == 0) || + (memcmp(mac->bssid, ap5_5, 3) == 0) || + (memcmp(mac->bssid, ap5_6, 3) == 0) || + vendor == PEER_ATH) { + vendor = PEER_ATH; + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, "=>ath find\n"); + } else if ((memcmp(mac->bssid, ap4_4, 3) == 0) || + (memcmp(mac->bssid, ap4_5, 3) == 0) || + (memcmp(mac->bssid, ap4_1, 3) == 0) || + (memcmp(mac->bssid, ap4_2, 3) == 0) || + (memcmp(mac->bssid, ap4_3, 3) == 0) || + vendor == PEER_RAL) { + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, "=>ral find\n"); + vendor = PEER_RAL; + } else if (memcmp(mac->bssid, ap6_1, 3) == 0 || + vendor == PEER_CISCO) { + vendor = PEER_CISCO; + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, "=>cisco find\n"); + } else if ((memcmp(mac->bssid, ap3_1, 3) == 0) || + (memcmp(mac->bssid, ap3_2, 3) == 0) || + (memcmp(mac->bssid, ap3_3, 3) == 0) || + vendor == PEER_BROAD) { + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, "=>broad find\n"); + vendor = PEER_BROAD; + } else if (memcmp(mac->bssid, ap7_1, 3) == 0 || + vendor == PEER_MARV) { + vendor = PEER_MARV; + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, "=>marv find\n"); + } + + mac->vendor = vendor; +} + +MODULE_AUTHOR("lizhaoming <chaoming_li@realsil.com.cn>"); +MODULE_AUTHOR("Realtek WlanFAE <wlanfae@realtek.com>"); +MODULE_AUTHOR("Larry Finger <Larry.FInger@lwfinger.net>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Realtek 802.11n PCI wireless core"); + +struct rtl_global_var rtl_global_var = {}; + +int rtl_core_module_init(void) +{ + if (rtl_rate_control_register()) + pr_err("rtl: Unable to register rtl_rc, use default RC !!\n"); + + /* add debugfs */ + rtl_debugfs_add_topdir(); + + /* init some global vars */ + INIT_LIST_HEAD(&rtl_global_var.glb_priv_list); + spin_lock_init(&rtl_global_var.glb_list_lock); + + return 0; +} + +void rtl_core_module_exit(void) +{ + /*RC*/ + rtl_rate_control_unregister(); + + /* remove debugfs */ + rtl_debugfs_remove_topdir(); +} diff --git a/drivers/staging/rtlwifi/base.h b/drivers/staging/rtlwifi/base.h new file mode 100644 index 000000000000..1829712dc4e2 --- /dev/null +++ b/drivers/staging/rtlwifi/base.h @@ -0,0 +1,186 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL_BASE_H__ +#define __RTL_BASE_H__ + +enum ap_peer { + PEER_UNKNOWN = 0, + PEER_RTL = 1, + PEER_RTL_92SE = 2, + PEER_BROAD = 3, + PEER_RAL = 4, + PEER_ATH = 5, + PEER_CISCO = 6, + PEER_MARV = 7, + PEER_AIRGO = 9, + PEER_MAX = 10, +}; + +#define RTL_DUMMY_OFFSET 0 +#define RTL_DUMMY_UNIT 8 +#define RTL_TX_DUMMY_SIZE (RTL_DUMMY_OFFSET * RTL_DUMMY_UNIT) +#define RTL_TX_DESC_SIZE 32 +#define RTL_TX_HEADER_SIZE (RTL_TX_DESC_SIZE + RTL_TX_DUMMY_SIZE) + +#define MAX_BIT_RATE_40MHZ_MCS15 300 /* Mbps */ +#define MAX_BIT_RATE_40MHZ_MCS7 150 /* Mbps */ + +#define MAX_BIT_RATE_SHORT_GI_2NSS_80MHZ_MCS9 867 /* Mbps */ +#define MAX_BIT_RATE_SHORT_GI_2NSS_80MHZ_MCS7 650 /* Mbps */ +#define MAX_BIT_RATE_LONG_GI_2NSS_80MHZ_MCS9 780 /* Mbps */ +#define MAX_BIT_RATE_LONG_GI_2NSS_80MHZ_MCS7 585 /* Mbps */ + +#define MAX_BIT_RATE_SHORT_GI_1NSS_80MHZ_MCS9 434 /* Mbps */ +#define MAX_BIT_RATE_SHORT_GI_1NSS_80MHZ_MCS7 325 /* Mbps */ +#define MAX_BIT_RATE_LONG_GI_1NSS_80MHZ_MCS9 390 /* Mbps */ +#define MAX_BIT_RATE_LONG_GI_1NSS_80MHZ_MCS7 293 /* Mbps */ + +#define FRAME_OFFSET_FRAME_CONTROL 0 +#define FRAME_OFFSET_DURATION 2 +#define FRAME_OFFSET_ADDRESS1 4 +#define FRAME_OFFSET_ADDRESS2 10 +#define FRAME_OFFSET_ADDRESS3 16 +#define FRAME_OFFSET_SEQUENCE 22 +#define FRAME_OFFSET_ADDRESS4 24 +#define MAX_LISTEN_INTERVAL 10 +#define MAX_RATE_TRIES 4 + +#define SET_80211_HDR_FRAME_CONTROL(_hdr, _val) \ + WRITEEF2BYTE(_hdr, _val) +#define SET_80211_HDR_TYPE_AND_SUBTYPE(_hdr, _val) \ + WRITEEF1BYTE(_hdr, _val) +#define SET_80211_HDR_PWR_MGNT(_hdr, _val) \ + SET_BITS_TO_LE_2BYTE(_hdr, 12, 1, _val) +#define SET_80211_HDR_TO_DS(_hdr, _val) \ + SET_BITS_TO_LE_2BYTE(_hdr, 8, 1, _val) + +#define SET_80211_PS_POLL_AID(_hdr, _val) \ + (*(u16 *)((u8 *)(_hdr) + 2) = _val) +#define SET_80211_PS_POLL_BSSID(_hdr, _val) \ + ether_addr_copy(((u8 *)(_hdr)) + 4, (u8 *)(_val)) +#define SET_80211_PS_POLL_TA(_hdr, _val) \ + ether_addr_copy(((u8 *)(_hdr)) + 10, (u8 *)(_val)) + +#define SET_80211_HDR_DURATION(_hdr, _val) \ + (*(u16 *)((u8 *)(_hdr) + FRAME_OFFSET_DURATION) = le16_to_cpu(_val)) +#define SET_80211_HDR_ADDRESS1(_hdr, _val) \ + CP_MACADDR((u8 *)(_hdr) + FRAME_OFFSET_ADDRESS1, (u8 *)(_val)) +#define SET_80211_HDR_ADDRESS2(_hdr, _val) \ + CP_MACADDR((u8 *)(_hdr) + FRAME_OFFSET_ADDRESS2, (u8 *)(_val)) +#define SET_80211_HDR_ADDRESS3(_hdr, _val) \ + CP_MACADDR((u8 *)(_hdr) + FRAME_OFFSET_ADDRESS3, (u8 *)(_val)) +#define SET_80211_HDR_FRAGMENT_SEQUENCE(_hdr, _val) \ + WRITEEF2BYTE((u8 *)(_hdr) + FRAME_OFFSET_SEQUENCE, _val) + +#define SET_BEACON_PROBE_RSP_TIME_STAMP_LOW(__phdr, __val) \ + WRITEEF4BYTE(((u8 *)(__phdr)) + 24, __val) +#define SET_BEACON_PROBE_RSP_TIME_STAMP_HIGH(__phdr, __val) \ + WRITEEF4BYTE(((u8 *)(__phdr)) + 28, __val) +#define SET_BEACON_PROBE_RSP_BEACON_INTERVAL(__phdr, __val) \ + WRITEEF2BYTE(((u8 *)(__phdr)) + 32, __val) +#define GET_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr) \ + READEF2BYTE(((u8 *)(__phdr)) + 34) +#define SET_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr, __val) \ + WRITEEF2BYTE(((u8 *)(__phdr)) + 34, __val) +#define MASK_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr, __val) \ + SET_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr, \ + (GET_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr) & (~(__val)))) + +#define SET_TX_DESC_SPE_RPT(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE((__pdesc) + 8, 19, 1, __val) +#define SET_TX_DESC_SW_DEFINE(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE((__pdesc) + 24, 0, 12, __val) + +int rtl_init_core(struct ieee80211_hw *hw); +void rtl_deinit_core(struct ieee80211_hw *hw); +void rtl_init_rx_config(struct ieee80211_hw *hw); +void rtl_init_rfkill(struct ieee80211_hw *hw); +void rtl_deinit_rfkill(struct ieee80211_hw *hw); + +void rtl_watch_dog_timer_callback(unsigned long data); +void rtl_deinit_deferred_work(struct ieee80211_hw *hw); + +bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx); +int rtlwifi_rate_mapping(struct ieee80211_hw *hw, bool isht, + bool isvht, u8 desc_rate); +bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb); +u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx, + bool is_enc); + +bool rtl_is_tx_report_skb(struct ieee80211_hw *hw, struct sk_buff *skb); +void rtl_get_tx_report(struct rtl_tcb_desc *ptcb_desc, u8 *pdesc, + struct ieee80211_hw *hw); +void rtl_tx_report_handler(struct ieee80211_hw *hw, u8 *tmp_buf, + u8 c2h_cmd_len); +bool rtl_check_tx_report_acked(struct ieee80211_hw *hw); +void rtl_wait_tx_report_acked(struct ieee80211_hw *hw, u32 wait_ms); +u32 rtl_get_hal_edca_param(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + enum wireless_mode wirelessmode, + struct ieee80211_tx_queue_params *param); + +void rtl_beacon_statistic(struct ieee80211_hw *hw, struct sk_buff *skb); +void rtl_collect_scan_list(struct ieee80211_hw *hw, struct sk_buff *skb); +void rtl_scan_list_expire(struct ieee80211_hw *hw); +int rtl_tx_agg_start(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, u16 tid, u16 *ssn); +int rtl_tx_agg_stop(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, u16 tid); +int rtl_tx_agg_oper(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u16 tid); +int rtl_rx_agg_start(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u16 tid); +int rtl_rx_agg_stop(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u16 tid); +void rtl_rx_ampdu_apply(struct rtl_priv *rtlpriv); +void rtl_watchdog_wq_callback(void *data); +void rtl_fwevt_wq_callback(void *data); +void rtl_c2hcmd_wq_callback(void *data); +void rtl_c2hcmd_launcher(struct ieee80211_hw *hw, int exec); +void rtl_c2hcmd_enqueue(struct ieee80211_hw *hw, u8 tag, u8 len, u8 *val); + +u8 rtl_mrate_idx_to_arfr_id( + struct ieee80211_hw *hw, u8 rate_index, + enum wireless_mode wirelessmode); +void rtl_get_tcb_desc(struct ieee80211_hw *hw, + struct ieee80211_tx_info *info, + struct ieee80211_sta *sta, + struct sk_buff *skb, struct rtl_tcb_desc *tcb_desc); + +int rtl_send_smps_action(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, + enum ieee80211_smps_mode smps); +u8 *rtl_find_ie(u8 *data, unsigned int len, u8 ie); +void rtl_recognize_peer(struct ieee80211_hw *hw, u8 *data, unsigned int len); +u8 rtl_tid_to_ac(u8 tid); +void rtl_easy_concurrent_retrytimer_callback(unsigned long data); +extern struct rtl_global_var rtl_global_var; +void rtl_phy_scan_operation_backup(struct ieee80211_hw *hw, u8 operation); +bool rtl_check_beacon_key(struct ieee80211_hw *hw, void *data, + unsigned int len); +int rtl_core_module_init(void); +void rtl_core_module_exit(void); +#endif diff --git a/drivers/staging/rtlwifi/btcoexist/Makefile b/drivers/staging/rtlwifi/btcoexist/Makefile new file mode 100644 index 000000000000..f600bcc38a15 --- /dev/null +++ b/drivers/staging/rtlwifi/btcoexist/Makefile @@ -0,0 +1,8 @@ +btcoexist-objs := \ + halbtc8822b1ant.o \ + halbtc8822b2ant.o \ + halbtc8822bwifionly.o \ + halbtcoutsrc.o \ + rtl_btc.o + +obj-$(CONFIG_RTLBTCOEXIST) += btcoexist.o diff --git a/drivers/staging/rtlwifi/btcoexist/halbt_precomp.h b/drivers/staging/rtlwifi/btcoexist/halbt_precomp.h new file mode 100644 index 000000000000..d78cd9394373 --- /dev/null +++ b/drivers/staging/rtlwifi/btcoexist/halbt_precomp.h @@ -0,0 +1,85 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ + +#ifndef __HALBT_PRECOMP_H__ +#define __HALBT_PRECOMP_H__ +/************************************************************* + * include files + *************************************************************/ +#include "../wifi.h" +#include "../efuse.h" +#include "../base.h" +#include "../regd.h" +#include "../cam.h" +#include "../ps.h" +#include "../pci.h" + +#include "halbtcoutsrc.h" + +/* Interface type */ +#define RT_PCI_INTERFACE 1 +#define RT_USB_INTERFACE 2 +#define RT_SDIO_INTERFACE 3 +#define DEV_BUS_TYPE RT_PCI_INTERFACE + +#include "halbtc8822b1ant.h" +#include "halbtc8822b2ant.h" +#include "halbtc8822bwifionly.h" + +#define GETDEFAULTADAPTER(padapter) padapter + +#define BIT0 0x00000001 +#define BIT1 0x00000002 +#define BIT2 0x00000004 +#define BIT3 0x00000008 +#define BIT4 0x00000010 +#define BIT5 0x00000020 +#define BIT6 0x00000040 +#define BIT7 0x00000080 +#define BIT8 0x00000100 +#define BIT9 0x00000200 +#define BIT10 0x00000400 +#define BIT11 0x00000800 +#define BIT12 0x00001000 +#define BIT13 0x00002000 +#define BIT14 0x00004000 +#define BIT15 0x00008000 +#define BIT16 0x00010000 +#define BIT17 0x00020000 +#define BIT18 0x00040000 +#define BIT19 0x00080000 +#define BIT20 0x00100000 +#define BIT21 0x00200000 +#define BIT22 0x00400000 +#define BIT23 0x00800000 +#define BIT24 0x01000000 +#define BIT25 0x02000000 +#define BIT26 0x04000000 +#define BIT27 0x08000000 +#define BIT28 0x10000000 +#define BIT29 0x20000000 +#define BIT30 0x40000000 +#define BIT31 0x80000000 + +#endif /* __HALBT_PRECOMP_H__ */ diff --git a/drivers/staging/rtlwifi/btcoexist/halbtc8822b1ant.c b/drivers/staging/rtlwifi/btcoexist/halbtc8822b1ant.c new file mode 100644 index 000000000000..157395b85405 --- /dev/null +++ b/drivers/staging/rtlwifi/btcoexist/halbtc8822b1ant.c @@ -0,0 +1,5244 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +/* ************************************************************ + * Description: + * + * This file is for RTL8822B Co-exist mechanism + * + * History + * 2012/11/15 Cosa first check in. + * + * *************************************************************/ + +/* ************************************************************ + * include files + * *************************************************************/ +/*only for rf4ce*/ +#include "halbt_precomp.h" + +/* ************************************************************ + * Global variables, these are static variables + * *************************************************************/ +static struct coex_dm_8822b_1ant glcoex_dm_8822b_1ant; +static struct coex_dm_8822b_1ant *coex_dm = &glcoex_dm_8822b_1ant; +static struct coex_sta_8822b_1ant glcoex_sta_8822b_1ant; +static struct coex_sta_8822b_1ant *coex_sta = &glcoex_sta_8822b_1ant; +static struct psdscan_sta_8822b_1ant gl_psd_scan_8822b_1ant; +static struct psdscan_sta_8822b_1ant *psd_scan = &gl_psd_scan_8822b_1ant; +static struct rfe_type_8822b_1ant gl_rfe_type_8822b_1ant; +static struct rfe_type_8822b_1ant *rfe_type = &gl_rfe_type_8822b_1ant; + +static const char *const glbt_info_src_8822b_1ant[] = { + "BT Info[wifi fw]", "BT Info[bt rsp]", "BT Info[bt auto report]", +}; + +static u32 glcoex_ver_date_8822b_1ant = 20170327; +static u32 glcoex_ver_8822b_1ant = 0x44; +static u32 glcoex_ver_btdesired_8822b_1ant = 0x42; + +/* ************************************************************ + * local function proto type if needed + * ************************************************************ + * ************************************************************ + * local function start with halbtc8822b1ant_ + * *************************************************************/ + +static u8 halbtc8822b1ant_wifi_rssi_state(struct btc_coexist *btcoexist, + u8 index, u8 level_num, + u8 rssi_thresh, u8 rssi_thresh1) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + s32 wifi_rssi = 0; + u8 wifi_rssi_state = coex_sta->pre_wifi_rssi_state[index]; + + btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); + + if (level_num == 2) { + if ((coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_LOW) || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_LOW)) { + if (wifi_rssi >= + (rssi_thresh + BTC_RSSI_COEX_THRESH_TOL_8822B_1ANT)) + wifi_rssi_state = BTC_RSSI_STATE_HIGH; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else { + if (wifi_rssi < rssi_thresh) + wifi_rssi_state = BTC_RSSI_STATE_LOW; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } else if (level_num == 3) { + if (rssi_thresh > rssi_thresh1) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], wifi RSSI thresh error!!\n"); + return coex_sta->pre_wifi_rssi_state[index]; + } + + if ((coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_LOW) || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_LOW)) { + if (wifi_rssi >= + (rssi_thresh + BTC_RSSI_COEX_THRESH_TOL_8822B_1ANT)) + wifi_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else if ((coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_MEDIUM) || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_MEDIUM)) { + if (wifi_rssi >= (rssi_thresh1 + + BTC_RSSI_COEX_THRESH_TOL_8822B_1ANT)) + wifi_rssi_state = BTC_RSSI_STATE_HIGH; + else if (wifi_rssi < rssi_thresh) + wifi_rssi_state = BTC_RSSI_STATE_LOW; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM; + } else { + if (wifi_rssi < rssi_thresh1) + wifi_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } + + coex_sta->pre_wifi_rssi_state[index] = wifi_rssi_state; + + return wifi_rssi_state; +} + +static void halbtc8822b1ant_update_ra_mask(struct btc_coexist *btcoexist, + bool force_exec, u32 dis_rate_mask) +{ + coex_dm->cur_ra_mask = dis_rate_mask; + + if (force_exec || (coex_dm->pre_ra_mask != coex_dm->cur_ra_mask)) + btcoexist->btc_set(btcoexist, BTC_SET_ACT_UPDATE_RAMASK, + &coex_dm->cur_ra_mask); + coex_dm->pre_ra_mask = coex_dm->cur_ra_mask; +} + +static void +halbtc8822b1ant_auto_rate_fallback_retry(struct btc_coexist *btcoexist, + bool force_exec, u8 type) +{ + bool wifi_under_b_mode = false; + + coex_dm->cur_arfr_type = type; + + if (force_exec || (coex_dm->pre_arfr_type != coex_dm->cur_arfr_type)) { + switch (coex_dm->cur_arfr_type) { + case 0: /* normal mode */ + btcoexist->btc_write_4byte(btcoexist, 0x430, + coex_dm->backup_arfr_cnt1); + btcoexist->btc_write_4byte(btcoexist, 0x434, + coex_dm->backup_arfr_cnt2); + break; + case 1: + btcoexist->btc_get(btcoexist, + BTC_GET_BL_WIFI_UNDER_B_MODE, + &wifi_under_b_mode); + if (wifi_under_b_mode) { + btcoexist->btc_write_4byte(btcoexist, 0x430, + 0x0); + btcoexist->btc_write_4byte(btcoexist, 0x434, + 0x01010101); + } else { + btcoexist->btc_write_4byte(btcoexist, 0x430, + 0x0); + btcoexist->btc_write_4byte(btcoexist, 0x434, + 0x04030201); + } + break; + default: + break; + } + } + + coex_dm->pre_arfr_type = coex_dm->cur_arfr_type; +} + +static void halbtc8822b1ant_retry_limit(struct btc_coexist *btcoexist, + bool force_exec, u8 type) +{ + coex_dm->cur_retry_limit_type = type; + + if (force_exec || + (coex_dm->pre_retry_limit_type != coex_dm->cur_retry_limit_type)) { + switch (coex_dm->cur_retry_limit_type) { + case 0: /* normal mode */ + btcoexist->btc_write_2byte(btcoexist, 0x42a, + coex_dm->backup_retry_limit); + break; + case 1: /* retry limit=8 */ + btcoexist->btc_write_2byte(btcoexist, 0x42a, 0x0808); + break; + default: + break; + } + } + + coex_dm->pre_retry_limit_type = coex_dm->cur_retry_limit_type; +} + +static void halbtc8822b1ant_ampdu_max_time(struct btc_coexist *btcoexist, + bool force_exec, u8 type) +{ + coex_dm->cur_ampdu_time_type = type; + + if (force_exec || + (coex_dm->pre_ampdu_time_type != coex_dm->cur_ampdu_time_type)) { + switch (coex_dm->cur_ampdu_time_type) { + case 0: /* normal mode */ + btcoexist->btc_write_1byte( + btcoexist, 0x456, + coex_dm->backup_ampdu_max_time); + break; + case 1: /* AMPDU timw = 0x38 * 32us */ + btcoexist->btc_write_1byte(btcoexist, 0x456, 0x38); + break; + default: + break; + } + } + + coex_dm->pre_ampdu_time_type = coex_dm->cur_ampdu_time_type; +} + +static void halbtc8822b1ant_limited_tx(struct btc_coexist *btcoexist, + bool force_exec, u8 ra_mask_type, + u8 arfr_type, u8 retry_limit_type, + u8 ampdu_time_type) +{ + switch (ra_mask_type) { + case 0: /* normal mode */ + halbtc8822b1ant_update_ra_mask(btcoexist, force_exec, 0x0); + break; + case 1: /* disable cck 1/2 */ + halbtc8822b1ant_update_ra_mask(btcoexist, force_exec, + 0x00000003); + break; + case 2: /* disable cck 1/2/5.5, ofdm 6/9/12/18/24, mcs 0/1/2/3/4 */ + halbtc8822b1ant_update_ra_mask(btcoexist, force_exec, + 0x0001f1f7); + break; + default: + break; + } + + halbtc8822b1ant_auto_rate_fallback_retry(btcoexist, force_exec, + arfr_type); + halbtc8822b1ant_retry_limit(btcoexist, force_exec, retry_limit_type); + halbtc8822b1ant_ampdu_max_time(btcoexist, force_exec, ampdu_time_type); +} + +/* + * rx agg size setting : + * 1: true / don't care / don't care + * max: false / false / don't care + * 7: false / true / 7 + */ + +static void halbtc8822b1ant_limited_rx(struct btc_coexist *btcoexist, + bool force_exec, bool rej_ap_agg_pkt, + bool bt_ctrl_agg_buf_size, + u8 agg_buf_size) +{ + bool reject_rx_agg = rej_ap_agg_pkt; + bool bt_ctrl_rx_agg_size = bt_ctrl_agg_buf_size; + u8 rx_agg_size = agg_buf_size; + + /* ============================================ */ + /* Rx Aggregation related setting */ + /* ============================================ */ + btcoexist->btc_set(btcoexist, BTC_SET_BL_TO_REJ_AP_AGG_PKT, + &reject_rx_agg); + /* decide BT control aggregation buf size or not */ + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_CTRL_AGG_SIZE, + &bt_ctrl_rx_agg_size); + /* aggregation buf size, only work when BT control Rx aggregation size*/ + btcoexist->btc_set(btcoexist, BTC_SET_U1_AGG_BUF_SIZE, &rx_agg_size); + /* real update aggregation setting */ + btcoexist->btc_set(btcoexist, BTC_SET_ACT_AGGREGATE_CTRL, NULL); +} + +static void halbtc8822b1ant_query_bt_info(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + u8 h2c_parameter[1] = {0}; + + if (coex_sta->bt_disabled) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], No query BT info because BT is disabled!\n"); + return; + } + + h2c_parameter[0] |= BIT(0); /* trigger */ + + btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter); + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], WL query BT info!!\n"); +} + +static void halbtc8822b1ant_monitor_bt_ctr(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + u32 reg_hp_txrx, reg_lp_txrx, u32tmp; + u32 reg_hp_tx = 0, reg_hp_rx = 0, reg_lp_tx = 0, reg_lp_rx = 0; + static u8 num_of_bt_counter_chk, cnt_slave, cnt_autoslot_hang; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + reg_hp_txrx = 0x770; + reg_lp_txrx = 0x774; + + u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_hp_txrx); + reg_hp_tx = u32tmp & MASKLWORD; + reg_hp_rx = (u32tmp & MASKHWORD) >> 16; + + u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_lp_txrx); + reg_lp_tx = u32tmp & MASKLWORD; + reg_lp_rx = (u32tmp & MASKHWORD) >> 16; + + coex_sta->high_priority_tx = reg_hp_tx; + coex_sta->high_priority_rx = reg_hp_rx; + coex_sta->low_priority_tx = reg_lp_tx; + coex_sta->low_priority_rx = reg_lp_rx; + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Hi-Pri Rx/Tx: %d/%d, Lo-Pri Rx/Tx: %d/%d\n", + reg_hp_rx, reg_hp_tx, reg_lp_rx, reg_lp_tx); + + /* reset counter */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc); + + if ((coex_sta->low_priority_tx > 1150) && + (!coex_sta->c2h_bt_inquiry_page)) + coex_sta->pop_event_cnt++; + + if ((coex_sta->low_priority_rx >= 1150) && + (coex_sta->low_priority_rx >= coex_sta->low_priority_tx) && + (!coex_sta->under_ips) && (!coex_sta->c2h_bt_inquiry_page) && + (coex_sta->bt_link_exist)) { + if (cnt_slave >= 3) { + bt_link_info->slave_role = true; + cnt_slave = 3; + } else { + cnt_slave++; + } + } else { + if (cnt_slave == 0) { + bt_link_info->slave_role = false; + cnt_slave = 0; + } else { + cnt_slave--; + } + } + + if (coex_sta->is_tdma_btautoslot) { + if ((coex_sta->low_priority_tx >= 1300) && + (coex_sta->low_priority_rx <= 150)) { + if (cnt_autoslot_hang >= 2) { + coex_sta->is_tdma_btautoslot_hang = true; + cnt_autoslot_hang = 2; + } else { + cnt_autoslot_hang++; + } + } else { + if (cnt_autoslot_hang == 0) { + coex_sta->is_tdma_btautoslot_hang = false; + cnt_autoslot_hang = 0; + } else { + cnt_autoslot_hang--; + } + } + } + + if (bt_link_info->hid_only) { + if (coex_sta->low_priority_rx > 50) + coex_sta->is_hid_low_pri_tx_overhead = true; + else + coex_sta->is_hid_low_pri_tx_overhead = false; + } + + if ((coex_sta->high_priority_tx == 0) && + (coex_sta->high_priority_rx == 0) && + (coex_sta->low_priority_tx == 0) && + (coex_sta->low_priority_rx == 0)) { + num_of_bt_counter_chk++; + + if (num_of_bt_counter_chk >= 3) { + halbtc8822b1ant_query_bt_info(btcoexist); + num_of_bt_counter_chk = 0; + } + } +} + +static void halbtc8822b1ant_monitor_wifi_ctr(struct btc_coexist *btcoexist) +{ + s32 wifi_rssi = 0; + bool wifi_busy = false, wifi_under_b_mode = false, wifi_scan = false; + static u8 cck_lock_counter, wl_noisy_count0, wl_noisy_count1 = 3, + wl_noisy_count2; + u32 total_cnt, cck_cnt; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_B_MODE, + &wifi_under_b_mode); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &wifi_scan); + + coex_sta->crc_ok_cck = btcoexist->btc_phydm_query_phy_counter( + btcoexist, "PHYDM_INFO_CRC32_OK_CCK"); + coex_sta->crc_ok_11g = btcoexist->btc_phydm_query_phy_counter( + btcoexist, "PHYDM_INFO_CRC32_OK_LEGACY"); + coex_sta->crc_ok_11n = btcoexist->btc_phydm_query_phy_counter( + btcoexist, "PHYDM_INFO_CRC32_OK_HT"); + coex_sta->crc_ok_11n_vht = btcoexist->btc_phydm_query_phy_counter( + btcoexist, "PHYDM_INFO_CRC32_OK_VHT"); + + coex_sta->crc_err_cck = btcoexist->btc_phydm_query_phy_counter( + btcoexist, "PHYDM_INFO_CRC32_ERROR_CCK"); + coex_sta->crc_err_11g = btcoexist->btc_phydm_query_phy_counter( + btcoexist, "PHYDM_INFO_CRC32_ERROR_LEGACY"); + coex_sta->crc_err_11n = btcoexist->btc_phydm_query_phy_counter( + btcoexist, "PHYDM_INFO_CRC32_ERROR_HT"); + coex_sta->crc_err_11n_vht = btcoexist->btc_phydm_query_phy_counter( + btcoexist, "PHYDM_INFO_CRC32_ERROR_VHT"); + + cck_cnt = coex_sta->crc_ok_cck + coex_sta->crc_err_cck; + + if (cck_cnt > 250) { + if (wl_noisy_count2 < 3) + wl_noisy_count2++; + + if (wl_noisy_count2 == 3) { + wl_noisy_count0 = 0; + wl_noisy_count1 = 0; + } + + } else if (cck_cnt < 50) { + if (wl_noisy_count0 < 3) + wl_noisy_count0++; + + if (wl_noisy_count0 == 3) { + wl_noisy_count1 = 0; + wl_noisy_count2 = 0; + } + + } else { + if (wl_noisy_count1 < 3) + wl_noisy_count1++; + + if (wl_noisy_count1 == 3) { + wl_noisy_count0 = 0; + wl_noisy_count2 = 0; + } + } + + if (wl_noisy_count2 == 3) + coex_sta->wl_noisy_level = 2; + else if (wl_noisy_count1 == 3) + coex_sta->wl_noisy_level = 1; + else + coex_sta->wl_noisy_level = 0; + + if ((wifi_busy) && (wifi_rssi >= 30) && (!wifi_under_b_mode)) { + total_cnt = coex_sta->crc_ok_cck + coex_sta->crc_ok_11g + + coex_sta->crc_ok_11n + coex_sta->crc_ok_11n_vht; + + if ((coex_dm->bt_status == BT_8822B_1ANT_BT_STATUS_ACL_BUSY) || + (coex_dm->bt_status == + BT_8822B_1ANT_BT_STATUS_ACL_SCO_BUSY) || + (coex_dm->bt_status == BT_8822B_1ANT_BT_STATUS_SCO_BUSY)) { + if (coex_sta->crc_ok_cck > + (total_cnt - coex_sta->crc_ok_cck)) { + if (cck_lock_counter < 3) + cck_lock_counter++; + } else { + if (cck_lock_counter > 0) + cck_lock_counter--; + } + + } else { + if (cck_lock_counter > 0) + cck_lock_counter--; + } + } else { + if (cck_lock_counter > 0) + cck_lock_counter--; + } + + if (!coex_sta->pre_ccklock) { + if (cck_lock_counter >= 3) + coex_sta->cck_lock = true; + else + coex_sta->cck_lock = false; + } else { + if (cck_lock_counter == 0) + coex_sta->cck_lock = false; + else + coex_sta->cck_lock = true; + } + + if (coex_sta->cck_lock) + coex_sta->cck_ever_lock = true; + + coex_sta->pre_ccklock = coex_sta->cck_lock; +} + +static bool +halbtc8822b1ant_is_wifi_status_changed(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + static bool pre_wifi_busy, pre_under_4way, pre_bt_hs_on, + pre_rf4ce_enabled, pre_bt_off, pre_bt_slave, + pre_hid_low_pri_tx_overhead, pre_wifi_under_lps, + pre_bt_setup_link; + static u8 pre_hid_busy_num, pre_wl_noisy_level; + bool wifi_busy = false, under_4way = false, bt_hs_on = false, + rf4ce_enabled = false; + bool wifi_connected = false; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, + &under_4way); + + if (coex_sta->bt_disabled != pre_bt_off) { + pre_bt_off = coex_sta->bt_disabled; + + if (coex_sta->bt_disabled) + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BT is disabled !!\n"); + else + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BT is enabled !!\n"); + + coex_sta->bt_coex_supported_feature = 0; + coex_sta->bt_coex_supported_version = 0; + return true; + } + btcoexist->btc_get(btcoexist, BTC_GET_BL_RF4CE_CONNECTED, + &rf4ce_enabled); + + if (rf4ce_enabled != pre_rf4ce_enabled) { + pre_rf4ce_enabled = rf4ce_enabled; + + if (rf4ce_enabled) + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], rf4ce is enabled !!\n"); + else + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], rf4ce is disabled !!\n"); + + return true; + } + + if (wifi_connected) { + if (wifi_busy != pre_wifi_busy) { + pre_wifi_busy = wifi_busy; + return true; + } + if (under_4way != pre_under_4way) { + pre_under_4way = under_4way; + return true; + } + if (bt_hs_on != pre_bt_hs_on) { + pre_bt_hs_on = bt_hs_on; + return true; + } + if (coex_sta->wl_noisy_level != pre_wl_noisy_level) { + pre_wl_noisy_level = coex_sta->wl_noisy_level; + return true; + } + if (coex_sta->under_lps != pre_wifi_under_lps) { + pre_wifi_under_lps = coex_sta->under_lps; + if (coex_sta->under_lps) + return true; + } + } + + if (!coex_sta->bt_disabled) { + if (coex_sta->hid_busy_num != pre_hid_busy_num) { + pre_hid_busy_num = coex_sta->hid_busy_num; + return true; + } + + if (bt_link_info->slave_role != pre_bt_slave) { + pre_bt_slave = bt_link_info->slave_role; + return true; + } + + if (pre_hid_low_pri_tx_overhead != + coex_sta->is_hid_low_pri_tx_overhead) { + pre_hid_low_pri_tx_overhead = + coex_sta->is_hid_low_pri_tx_overhead; + return true; + } + + if (pre_bt_setup_link != coex_sta->is_setup_link) { + pre_bt_setup_link = coex_sta->is_setup_link; + return true; + } + } + + return false; +} + +static void halbtc8822b1ant_update_bt_link_info(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + bool bt_hs_on = false; + bool bt_busy = false; + + coex_sta->num_of_profile = 0; + + /* set link exist status */ + if (!(coex_sta->bt_info & BT_INFO_8822B_1ANT_B_CONNECTION)) { + coex_sta->bt_link_exist = false; + coex_sta->pan_exist = false; + coex_sta->a2dp_exist = false; + coex_sta->hid_exist = false; + coex_sta->sco_exist = false; + } else { /* connection exists */ + coex_sta->bt_link_exist = true; + if (coex_sta->bt_info & BT_INFO_8822B_1ANT_B_FTP) { + coex_sta->pan_exist = true; + coex_sta->num_of_profile++; + } else { + coex_sta->pan_exist = false; + } + + if (coex_sta->bt_info & BT_INFO_8822B_1ANT_B_A2DP) { + coex_sta->a2dp_exist = true; + coex_sta->num_of_profile++; + } else { + coex_sta->a2dp_exist = false; + } + + if (coex_sta->bt_info & BT_INFO_8822B_1ANT_B_HID) { + coex_sta->hid_exist = true; + coex_sta->num_of_profile++; + } else { + coex_sta->hid_exist = false; + } + + if (coex_sta->bt_info & BT_INFO_8822B_1ANT_B_SCO_ESCO) { + coex_sta->sco_exist = true; + coex_sta->num_of_profile++; + } else { + coex_sta->sco_exist = false; + } + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + + bt_link_info->bt_link_exist = coex_sta->bt_link_exist; + bt_link_info->sco_exist = coex_sta->sco_exist; + bt_link_info->a2dp_exist = coex_sta->a2dp_exist; + bt_link_info->pan_exist = coex_sta->pan_exist; + bt_link_info->hid_exist = coex_sta->hid_exist; + bt_link_info->acl_busy = coex_sta->acl_busy; + + /* work around for HS mode. */ + if (bt_hs_on) { + bt_link_info->pan_exist = true; + bt_link_info->bt_link_exist = true; + } + + /* check if Sco only */ + if (bt_link_info->sco_exist && !bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && !bt_link_info->hid_exist) + bt_link_info->sco_only = true; + else + bt_link_info->sco_only = false; + + /* check if A2dp only */ + if (!bt_link_info->sco_exist && bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && !bt_link_info->hid_exist) + bt_link_info->a2dp_only = true; + else + bt_link_info->a2dp_only = false; + + /* check if Pan only */ + if (!bt_link_info->sco_exist && !bt_link_info->a2dp_exist && + bt_link_info->pan_exist && !bt_link_info->hid_exist) + bt_link_info->pan_only = true; + else + bt_link_info->pan_only = false; + + /* check if Hid only */ + if (!bt_link_info->sco_exist && !bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && bt_link_info->hid_exist) + bt_link_info->hid_only = true; + else + bt_link_info->hid_only = false; + + if (coex_sta->bt_info & BT_INFO_8822B_1ANT_B_INQ_PAGE) { + coex_dm->bt_status = BT_8822B_1ANT_BT_STATUS_INQ_PAGE; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BtInfoNotify(), BT Inq/page!!!\n"); + } else if (!(coex_sta->bt_info & BT_INFO_8822B_1ANT_B_CONNECTION)) { + coex_dm->bt_status = BT_8822B_1ANT_BT_STATUS_NON_CONNECTED_IDLE; + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BtInfoNotify(), BT Non-Connected idle!!!\n"); + } else if (coex_sta->bt_info == BT_INFO_8822B_1ANT_B_CONNECTION) { + /* connection exists but no busy */ + coex_dm->bt_status = BT_8822B_1ANT_BT_STATUS_CONNECTED_IDLE; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BtInfoNotify(), BT Connected-idle!!!\n"); + } else if (((coex_sta->bt_info & BT_INFO_8822B_1ANT_B_SCO_ESCO) || + (coex_sta->bt_info & BT_INFO_8822B_1ANT_B_SCO_BUSY)) && + (coex_sta->bt_info & BT_INFO_8822B_1ANT_B_ACL_BUSY)) { + coex_dm->bt_status = BT_8822B_1ANT_BT_STATUS_ACL_SCO_BUSY; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BtInfoNotify(), BT ACL SCO busy!!!\n"); + } else if ((coex_sta->bt_info & BT_INFO_8822B_1ANT_B_SCO_ESCO) || + (coex_sta->bt_info & BT_INFO_8822B_1ANT_B_SCO_BUSY)) { + coex_dm->bt_status = BT_8822B_1ANT_BT_STATUS_SCO_BUSY; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BtInfoNotify(), BT SCO busy!!!\n"); + } else if (coex_sta->bt_info & BT_INFO_8822B_1ANT_B_ACL_BUSY) { + coex_dm->bt_status = BT_8822B_1ANT_BT_STATUS_ACL_BUSY; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BtInfoNotify(), BT ACL busy!!!\n"); + } else { + coex_dm->bt_status = BT_8822B_1ANT_BT_STATUS_MAX; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BtInfoNotify(), BT Non-Defined state!!!\n"); + } + + if ((coex_dm->bt_status == BT_8822B_1ANT_BT_STATUS_ACL_BUSY) || + (coex_dm->bt_status == BT_8822B_1ANT_BT_STATUS_SCO_BUSY) || + (coex_dm->bt_status == BT_8822B_1ANT_BT_STATUS_ACL_SCO_BUSY)) + bt_busy = true; + else + bt_busy = false; + + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy); +} + +static void halbtc8822b1ant_update_wifi_ch_info(struct btc_coexist *btcoexist, + u8 type) +{ + u8 h2c_parameter[3] = {0}; + u32 wifi_bw; + u8 wifi_central_chnl; + + /* only 2.4G we need to inform bt the chnl mask */ + btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL, + &wifi_central_chnl); + if ((type == BTC_MEDIA_CONNECT) && (wifi_central_chnl <= 14)) { + /* enable BT AFH skip WL channel for 8822b + * because BT Rx LO interference + */ + h2c_parameter[0] = 0x1; + h2c_parameter[1] = wifi_central_chnl; + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + if (wifi_bw == BTC_WIFI_BW_HT40) + h2c_parameter[2] = 0x30; + else + h2c_parameter[2] = 0x20; + } + + coex_dm->wifi_chnl_info[0] = h2c_parameter[0]; + coex_dm->wifi_chnl_info[1] = h2c_parameter[1]; + coex_dm->wifi_chnl_info[2] = h2c_parameter[2]; + + btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, h2c_parameter); +} + +static u8 halbtc8822b1ant_action_algorithm(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + bool bt_hs_on = false; + u8 algorithm = BT_8822B_1ANT_COEX_ALGO_UNDEFINED; + u8 num_of_diff_profile = 0; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + + if (!bt_link_info->bt_link_exist) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], No BT link exists!!!\n"); + return algorithm; + } + + if (bt_link_info->sco_exist) + num_of_diff_profile++; + if (bt_link_info->hid_exist) + num_of_diff_profile++; + if (bt_link_info->pan_exist) + num_of_diff_profile++; + if (bt_link_info->a2dp_exist) + num_of_diff_profile++; + + if (num_of_diff_profile == 1) { + if (bt_link_info->sco_exist) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BT Profile = SCO only\n"); + algorithm = BT_8822B_1ANT_COEX_ALGO_SCO; + } else { + if (bt_link_info->hid_exist) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BT Profile = HID only\n"); + algorithm = BT_8822B_1ANT_COEX_ALGO_HID; + } else if (bt_link_info->a2dp_exist) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BT Profile = A2DP only\n"); + algorithm = BT_8822B_1ANT_COEX_ALGO_A2DP; + } else if (bt_link_info->pan_exist) { + if (bt_hs_on) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, + DBG_LOUD, + "[BTCoex], BT Profile = PAN(HS) only\n"); + algorithm = + BT_8822B_1ANT_COEX_ALGO_PANHS; + } else { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, + DBG_LOUD, + "[BTCoex], BT Profile = PAN(EDR) only\n"); + algorithm = + BT_8822B_1ANT_COEX_ALGO_PANEDR; + } + } + } + } else if (num_of_diff_profile == 2) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BT Profile = SCO + HID\n"); + algorithm = BT_8822B_1ANT_COEX_ALGO_HID; + } else if (bt_link_info->a2dp_exist) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BT Profile = SCO + A2DP ==> SCO\n"); + algorithm = BT_8822B_1ANT_COEX_ALGO_SCO; + } else if (bt_link_info->pan_exist) { + if (bt_hs_on) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, + DBG_LOUD, + "[BTCoex], BT Profile = SCO + PAN(HS)\n"); + algorithm = BT_8822B_1ANT_COEX_ALGO_SCO; + } else { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, + DBG_LOUD, + "[BTCoex], BT Profile = SCO + PAN(EDR)\n"); + algorithm = + BT_8822B_1ANT_COEX_ALGO_PANEDR_HID; + } + } + } else { + if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BT Profile = HID + A2DP\n"); + algorithm = BT_8822B_1ANT_COEX_ALGO_HID_A2DP; + } else if (bt_link_info->hid_exist && + bt_link_info->pan_exist) { + if (bt_hs_on) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, + DBG_LOUD, + "[BTCoex], BT Profile = HID + PAN(HS)\n"); + algorithm = + BT_8822B_1ANT_COEX_ALGO_HID_A2DP; + } else { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, + DBG_LOUD, + "[BTCoex], BT Profile = HID + PAN(EDR)\n"); + algorithm = + BT_8822B_1ANT_COEX_ALGO_PANEDR_HID; + } + } else if (bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, + DBG_LOUD, + "[BTCoex], BT Profile = A2DP + PAN(HS)\n"); + algorithm = + BT_8822B_1ANT_COEX_ALGO_A2DP_PANHS; + } else { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, + DBG_LOUD, + "[BTCoex], BT Profile = A2DP + PAN(EDR)\n"); + algorithm = + BT_8822B_1ANT_COEX_ALGO_PANEDR_A2DP; + } + } + } + } else if (num_of_diff_profile == 3) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BT Profile = SCO + HID + A2DP ==> HID\n"); + algorithm = BT_8822B_1ANT_COEX_ALGO_HID; + } else if (bt_link_info->hid_exist && + bt_link_info->pan_exist) { + if (bt_hs_on) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, + DBG_LOUD, + "[BTCoex], BT Profile = SCO + HID + PAN(HS)\n"); + algorithm = + BT_8822B_1ANT_COEX_ALGO_HID_A2DP; + } else { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, + DBG_LOUD, + "[BTCoex], BT Profile = SCO + HID + PAN(EDR)\n"); + algorithm = + BT_8822B_1ANT_COEX_ALGO_PANEDR_HID; + } + } else if (bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, + DBG_LOUD, + "[BTCoex], BT Profile = SCO + A2DP + PAN(HS)\n"); + algorithm = BT_8822B_1ANT_COEX_ALGO_SCO; + } else { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, + DBG_LOUD, + "[BTCoex], BT Profile = SCO + A2DP + PAN(EDR) ==> HID\n"); + algorithm = + BT_8822B_1ANT_COEX_ALGO_PANEDR_HID; + } + } + } else { + if (bt_link_info->hid_exist && + bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, + DBG_LOUD, + "[BTCoex], BT Profile = HID + A2DP + PAN(HS)\n"); + algorithm = + BT_8822B_1ANT_COEX_ALGO_HID_A2DP; + } else { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, + DBG_LOUD, + "[BTCoex], BT Profile = HID + A2DP + PAN(EDR)\n"); + algorithm = + BT_8822B_1ANT_COEX_ALGO_HID_A2DP_PANEDR; + } + } + } + } else if (num_of_diff_profile >= 3) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist && + bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, + DBG_LOUD, + "[BTCoex], Error!!! BT Profile = SCO + HID + A2DP + PAN(HS)\n"); + + } else { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, + DBG_LOUD, + "[BTCoex], BT Profile = SCO + HID + A2DP + PAN(EDR)==>PAN(EDR)+HID\n"); + algorithm = + BT_8822B_1ANT_COEX_ALGO_PANEDR_HID; + } + } + } + } + + return algorithm; +} + +static void halbtc8822b1ant_low_penalty_ra(struct btc_coexist *btcoexist, + bool force_exec, bool low_penalty_ra) +{ + coex_dm->cur_low_penalty_ra = low_penalty_ra; + + if (!force_exec) { + if (coex_dm->pre_low_penalty_ra == coex_dm->cur_low_penalty_ra) + return; + } + + if (low_penalty_ra) + btcoexist->btc_phydm_modify_ra_pcr_threshold(btcoexist, 0, 25); + else + btcoexist->btc_phydm_modify_ra_pcr_threshold(btcoexist, 0, 0); + + coex_dm->pre_low_penalty_ra = coex_dm->cur_low_penalty_ra; +} + +static void halbtc8822b1ant_write_score_board(struct btc_coexist *btcoexist, + u16 bitpos, bool state) +{ + static u16 originalval = 0x8002; + + if (state) + originalval = originalval | bitpos; + else + originalval = originalval & (~bitpos); + + btcoexist->btc_write_2byte(btcoexist, 0xaa, originalval); +} + +static void halbtc8822b1ant_read_score_board(struct btc_coexist *btcoexist, + u16 *score_board_val) +{ + *score_board_val = + (btcoexist->btc_read_2byte(btcoexist, 0xaa)) & 0x7fff; +} + +static void halbtc8822b1ant_post_state_to_bt(struct btc_coexist *btcoexist, + u16 type, bool state) +{ + halbtc8822b1ant_write_score_board(btcoexist, (u16)type, state); +} + +static void +halbtc8822b1ant_monitor_bt_enable_disable(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + static u32 bt_disable_cnt; + bool bt_active = true, bt_disabled = false, wifi_under_5g = false; + u16 u16tmp; + + /* This function check if bt is disabled */ + + /* Read BT on/off status from scoreboard[1], + * enable this only if BT patch support this feature + */ + halbtc8822b1ant_read_score_board(btcoexist, &u16tmp); + + bt_active = u16tmp & BIT(1); + + if (bt_active) { + bt_disable_cnt = 0; + bt_disabled = false; + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE, + &bt_disabled); + } else { + bt_disable_cnt++; + if (bt_disable_cnt >= 2) { + bt_disabled = true; + bt_disable_cnt = 2; + } + + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE, + &bt_disabled); + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + + if ((wifi_under_5g) || (bt_disabled)) + halbtc8822b1ant_low_penalty_ra(btcoexist, NORMAL_EXEC, false); + else + halbtc8822b1ant_low_penalty_ra(btcoexist, NORMAL_EXEC, true); + + if (coex_sta->bt_disabled != bt_disabled) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BT is from %s to %s!!\n", + (coex_sta->bt_disabled ? "disabled" : "enabled"), + (bt_disabled ? "disabled" : "enabled")); + coex_sta->bt_disabled = bt_disabled; + } +} + +static void halbtc8822b1ant_enable_gnt_to_gpio(struct btc_coexist *btcoexist, + bool isenable) +{ + static u8 bit_val[5] = {0, 0, 0, 0, 0}; + static bool state; + + if (!btcoexist->dbg_mode_1ant) + return; + + if (state == isenable) + return; + + state = isenable; + + if (isenable) { + /* enable GNT_WL, GNT_BT to GPIO for debug */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x73, 0x8, 0x1); + + /* store original value */ + bit_val[0] = + (btcoexist->btc_read_1byte(btcoexist, 0x66) & BIT(4)) >> + 4; /*0x66[4] */ + bit_val[1] = (btcoexist->btc_read_1byte(btcoexist, 0x67) & + BIT(0)); /*0x66[8] */ + bit_val[2] = + (btcoexist->btc_read_1byte(btcoexist, 0x42) & BIT(3)) >> + 3; /*0x40[19] */ + bit_val[3] = + (btcoexist->btc_read_1byte(btcoexist, 0x65) & BIT(7)) >> + 7; /*0x64[15] */ + bit_val[4] = + (btcoexist->btc_read_1byte(btcoexist, 0x72) & BIT(2)) >> + 2; /*0x70[18] */ + + /* switch GPIO Mux */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x66, BIT(4), + 0x0); /*0x66[4] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, BIT(0), + 0x0); /*0x66[8] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x42, BIT(3), + 0x0); /*0x40[19] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x65, BIT(7), + 0x0); /*0x64[15] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x72, BIT(2), + 0x0); /*0x70[18] = 0 */ + + } else { + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x73, 0x8, 0x0); + + /* Restore original value */ + /* switch GPIO Mux */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x66, BIT(4), + bit_val[0]); /*0x66[4] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, BIT(0), + bit_val[1]); /*0x66[8] = 0 */ + btcoexist->btc_write_1byte_bitmask( + btcoexist, 0x42, BIT(3), bit_val[2]); /*0x40[19] = 0 */ + btcoexist->btc_write_1byte_bitmask( + btcoexist, 0x65, BIT(7), bit_val[3]); /*0x64[15] = 0 */ + btcoexist->btc_write_1byte_bitmask( + btcoexist, 0x72, BIT(2), bit_val[4]); /*0x70[18] = 0 */ + } +} + +static u32 +halbtc8822b1ant_ltecoex_indirect_read_reg(struct btc_coexist *btcoexist, + u16 reg_addr) +{ + u32 delay_count = 0; + + /* wait for ready bit before access 0x1700 */ + while (1) { + if ((btcoexist->btc_read_1byte(btcoexist, 0x1703) & BIT(5)) == + 0) { + mdelay(50); + delay_count++; + if (delay_count >= 10) { + delay_count = 0; + break; + } + } else { + break; + } + } + + btcoexist->btc_write_4byte(btcoexist, 0x1700, 0x800F0000 | reg_addr); + + return btcoexist->btc_read_4byte(btcoexist, 0x1708); /* get read data */ +} + +static void +halbtc8822b1ant_ltecoex_indirect_write_reg(struct btc_coexist *btcoexist, + u16 reg_addr, u32 bit_mask, + u32 reg_value) +{ + u32 val, i = 0, bitpos = 0, delay_count = 0; + + if (bit_mask == 0x0) + return; + + if (bit_mask == 0xffffffff) { + /* wait for ready bit before access 0x1700/0x1704 */ + while (1) { + if ((btcoexist->btc_read_1byte(btcoexist, 0x1703) & + BIT(5)) == 0) { + mdelay(50); + delay_count++; + if (delay_count >= 10) { + delay_count = 0; + break; + } + } else { + break; + } + } + + btcoexist->btc_write_4byte(btcoexist, 0x1704, + reg_value); /* put write data */ + + btcoexist->btc_write_4byte(btcoexist, 0x1700, + 0xc00F0000 | reg_addr); + } else { + for (i = 0; i <= 31; i++) { + if (((bit_mask >> i) & 0x1) == 0x1) { + bitpos = i; + break; + } + } + + /* read back register value before write */ + val = halbtc8822b1ant_ltecoex_indirect_read_reg(btcoexist, + reg_addr); + val = (val & (~bit_mask)) | (reg_value << bitpos); + + /* wait for ready bit before access 0x1700/0x1704 */ + while (1) { + if ((btcoexist->btc_read_1byte(btcoexist, 0x1703) & + BIT(5)) == 0) { + mdelay(50); + delay_count++; + if (delay_count >= 10) { + delay_count = 0; + break; + } + } else { + break; + } + } + + btcoexist->btc_write_4byte(btcoexist, 0x1704, + val); /* put write data */ + + btcoexist->btc_write_4byte(btcoexist, 0x1700, + 0xc00F0000 | reg_addr); + } +} + +static void halbtc8822b1ant_ltecoex_enable(struct btc_coexist *btcoexist, + bool enable) +{ + u8 val; + + val = (enable) ? 1 : 0; + /* 0x38[7] */ + halbtc8822b1ant_ltecoex_indirect_write_reg(btcoexist, 0x38, 0x80, val); +} + +static void +halbtc8822b1ant_ltecoex_pathcontrol_owner(struct btc_coexist *btcoexist, + bool wifi_control) +{ + u8 val; + + val = (wifi_control) ? 1 : 0; + /* 0x70[26] */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x73, 0x4, val); +} + +static void halbtc8822b1ant_ltecoex_set_gnt_bt(struct btc_coexist *btcoexist, + u8 control_block, + bool sw_control, u8 state) +{ + u32 val = 0, bit_mask; + + state = state & 0x1; + /*LTE indirect 0x38=0xccxx (sw : gnt_wl=1,sw gnt_bt=1) + *0x38=0xddxx (sw : gnt_bt=1 , sw gnt_wl=0) + *0x38=0x55xx(hw pta :gnt_wl /gnt_bt ) + */ + val = (sw_control) ? ((state << 1) | 0x1) : 0; + + switch (control_block) { + case BT_8822B_1ANT_GNT_BLOCK_RFC_BB: + default: + bit_mask = 0xc000; + halbtc8822b1ant_ltecoex_indirect_write_reg( + btcoexist, 0x38, bit_mask, val); /* 0x38[15:14] */ + bit_mask = 0x0c00; + halbtc8822b1ant_ltecoex_indirect_write_reg( + btcoexist, 0x38, bit_mask, val); /* 0x38[11:10] */ + break; + case BT_8822B_1ANT_GNT_BLOCK_RFC: + bit_mask = 0xc000; + halbtc8822b1ant_ltecoex_indirect_write_reg( + btcoexist, 0x38, bit_mask, val); /* 0x38[15:14] */ + break; + case BT_8822B_1ANT_GNT_BLOCK_BB: + bit_mask = 0x0c00; + halbtc8822b1ant_ltecoex_indirect_write_reg( + btcoexist, 0x38, bit_mask, val); /* 0x38[11:10] */ + break; + } +} + +static void halbtc8822b1ant_ltecoex_set_gnt_wl(struct btc_coexist *btcoexist, + u8 control_block, + bool sw_control, u8 state) +{ + u32 val = 0, bit_mask; + /*LTE indirect 0x38=0xccxx (sw : gnt_wl=1,sw gnt_bt=1) + *0x38=0xddxx (sw : gnt_bt=1 , sw gnt_wl=0) + *0x38=0x55xx(hw pta :gnt_wl /gnt_bt ) + */ + + state = state & 0x1; + val = (sw_control) ? ((state << 1) | 0x1) : 0; + + switch (control_block) { + case BT_8822B_1ANT_GNT_BLOCK_RFC_BB: + default: + bit_mask = 0x3000; + halbtc8822b1ant_ltecoex_indirect_write_reg( + btcoexist, 0x38, bit_mask, val); /* 0x38[13:12] */ + bit_mask = 0x0300; + halbtc8822b1ant_ltecoex_indirect_write_reg( + btcoexist, 0x38, bit_mask, val); /* 0x38[9:8] */ + break; + case BT_8822B_1ANT_GNT_BLOCK_RFC: + bit_mask = 0x3000; + halbtc8822b1ant_ltecoex_indirect_write_reg( + btcoexist, 0x38, bit_mask, val); /* 0x38[13:12] */ + break; + case BT_8822B_1ANT_GNT_BLOCK_BB: + bit_mask = 0x0300; + halbtc8822b1ant_ltecoex_indirect_write_reg( + btcoexist, 0x38, bit_mask, val); /* 0x38[9:8] */ + break; + } +} + +static void +halbtc8822b1ant_ltecoex_set_coex_table(struct btc_coexist *btcoexist, + u8 table_type, u16 table_content) +{ + u16 reg_addr = 0x0000; + + switch (table_type) { + case BT_8822B_1ANT_CTT_WL_VS_LTE: + reg_addr = 0xa0; + break; + case BT_8822B_1ANT_CTT_BT_VS_LTE: + reg_addr = 0xa4; + break; + } + + if (reg_addr != 0x0000) + halbtc8822b1ant_ltecoex_indirect_write_reg( + btcoexist, reg_addr, 0xffff, + table_content); /* 0xa0[15:0] or 0xa4[15:0] */ +} + +static void halbtc8822b1ant_set_wltoggle_coex_table( + struct btc_coexist *btcoexist, bool force_exec, u8 interval, + u8 val0x6c4_b0, u8 val0x6c4_b1, u8 val0x6c4_b2, u8 val0x6c4_b3) +{ + static u8 pre_h2c_parameter[6] = {0}; + u8 cur_h2c_parameter[6] = {0}; + u8 i, match_cnt = 0; + + cur_h2c_parameter[0] = 0x7; /* op_code, 0x7= wlan toggle slot*/ + + cur_h2c_parameter[1] = interval; + cur_h2c_parameter[2] = val0x6c4_b0; + cur_h2c_parameter[3] = val0x6c4_b1; + cur_h2c_parameter[4] = val0x6c4_b2; + cur_h2c_parameter[5] = val0x6c4_b3; + + if (!force_exec) { + for (i = 1; i <= 5; i++) { + if (cur_h2c_parameter[i] != pre_h2c_parameter[i]) + break; + + match_cnt++; + } + + if (match_cnt == 5) + return; + } + + for (i = 1; i <= 5; i++) + pre_h2c_parameter[i] = cur_h2c_parameter[i]; + + btcoexist->btc_fill_h2c(btcoexist, 0x69, 6, cur_h2c_parameter); +} + +static void halbtc8822b1ant_set_coex_table(struct btc_coexist *btcoexist, + u32 val0x6c0, u32 val0x6c4, + u32 val0x6c8, u8 val0x6cc) +{ + btcoexist->btc_write_4byte(btcoexist, 0x6c0, val0x6c0); + + btcoexist->btc_write_4byte(btcoexist, 0x6c4, val0x6c4); + + btcoexist->btc_write_4byte(btcoexist, 0x6c8, val0x6c8); + + btcoexist->btc_write_1byte(btcoexist, 0x6cc, val0x6cc); +} + +static void halbtc8822b1ant_coex_table(struct btc_coexist *btcoexist, + bool force_exec, u32 val0x6c0, + u32 val0x6c4, u32 val0x6c8, u8 val0x6cc) +{ + coex_dm->cur_val0x6c0 = val0x6c0; + coex_dm->cur_val0x6c4 = val0x6c4; + coex_dm->cur_val0x6c8 = val0x6c8; + coex_dm->cur_val0x6cc = val0x6cc; + + if (!force_exec) { + if ((coex_dm->pre_val0x6c0 == coex_dm->cur_val0x6c0) && + (coex_dm->pre_val0x6c4 == coex_dm->cur_val0x6c4) && + (coex_dm->pre_val0x6c8 == coex_dm->cur_val0x6c8) && + (coex_dm->pre_val0x6cc == coex_dm->cur_val0x6cc)) + return; + } + halbtc8822b1ant_set_coex_table(btcoexist, val0x6c0, val0x6c4, val0x6c8, + val0x6cc); + + coex_dm->pre_val0x6c0 = coex_dm->cur_val0x6c0; + coex_dm->pre_val0x6c4 = coex_dm->cur_val0x6c4; + coex_dm->pre_val0x6c8 = coex_dm->cur_val0x6c8; + coex_dm->pre_val0x6cc = coex_dm->cur_val0x6cc; +} + +static void halbtc8822b1ant_coex_table_with_type(struct btc_coexist *btcoexist, + bool force_exec, u8 type) +{ + u32 break_table; + u8 select_table; + + coex_sta->coex_table_type = type; + + if (coex_sta->concurrent_rx_mode_on) { + break_table = 0xf0ffffff; /* set WL hi-pri can break BT */ + select_table = 0x3; /* set Tx response = Hi-Pri + * (ex: Transmitting ACK,BA,CTS) + */ + } else { + break_table = 0xffffff; + select_table = 0x3; + } + + switch (type) { + case 0: + halbtc8822b1ant_coex_table(btcoexist, force_exec, 0x55555555, + 0x55555555, break_table, + select_table); + break; + case 1: + halbtc8822b1ant_coex_table(btcoexist, force_exec, 0x55555555, + 0x5a5a5a5a, break_table, + select_table); + break; + case 2: + halbtc8822b1ant_coex_table(btcoexist, force_exec, 0xaa5a5a5a, + 0xaa5a5a5a, break_table, + select_table); + break; + case 3: + halbtc8822b1ant_coex_table(btcoexist, force_exec, 0x55555555, + 0xaa5a5a5a, break_table, + select_table); + break; + case 4: + halbtc8822b1ant_coex_table(btcoexist, force_exec, 0xaa555555, + 0xaa5a5a5a, break_table, + select_table); + break; + case 5: + halbtc8822b1ant_coex_table(btcoexist, force_exec, 0x5a5a5a5a, + 0x5a5a5a5a, break_table, + select_table); + break; + case 6: + halbtc8822b1ant_coex_table(btcoexist, force_exec, 0x55555555, + 0xaaaaaaaa, break_table, + select_table); + break; + case 7: + halbtc8822b1ant_coex_table(btcoexist, force_exec, 0xaaaaaaaa, + 0xaaaaaaaa, break_table, + select_table); + break; + case 8: + halbtc8822b1ant_coex_table(btcoexist, force_exec, 0xffffffff, + 0xffffffff, break_table, + select_table); + break; + case 9: + halbtc8822b1ant_coex_table(btcoexist, force_exec, 0x5a5a5555, + 0xaaaa5a5a, break_table, + select_table); + break; + case 10: + halbtc8822b1ant_coex_table(btcoexist, force_exec, 0xaaaa5aaa, + 0xaaaa5aaa, break_table, + select_table); + break; + case 11: + halbtc8822b1ant_coex_table(btcoexist, force_exec, 0xaaaaa5aa, + 0xaaaaaaaa, break_table, + select_table); + break; + case 12: + halbtc8822b1ant_coex_table(btcoexist, force_exec, 0xaaaaa5aa, + 0xaaaaa5aa, break_table, + select_table); + break; + case 13: + halbtc8822b1ant_coex_table(btcoexist, force_exec, 0x55555555, + 0xaaaa5a5a, break_table, + select_table); + break; + case 14: + halbtc8822b1ant_coex_table(btcoexist, force_exec, 0x5a5a555a, + 0xaaaa5a5a, break_table, + select_table); + break; + case 15: + halbtc8822b1ant_coex_table(btcoexist, force_exec, 0x55555555, + 0xaaaa55aa, break_table, + select_table); + break; + case 16: + halbtc8822b1ant_coex_table(btcoexist, force_exec, 0x5a5a555a, + 0x5a5a555a, break_table, + select_table); + break; + case 17: + halbtc8822b1ant_coex_table(btcoexist, force_exec, 0xaaaa55aa, + 0xaaaa55aa, break_table, + select_table); + break; + case 18: + halbtc8822b1ant_coex_table(btcoexist, force_exec, 0x55555555, + 0x5aaa5a5a, break_table, + select_table); + break; + case 19: + halbtc8822b1ant_coex_table(btcoexist, force_exec, 0xa5555555, + 0xaaaa5aaa, break_table, + select_table); + break; + case 20: + halbtc8822b1ant_coex_table(btcoexist, force_exec, 0x55555555, + 0xaaaa5aaa, break_table, + select_table); + break; + default: + break; + } +} + +static void +halbtc8822b1ant_set_fw_ignore_wlan_act(struct btc_coexist *btcoexist, + bool enable) +{ + u8 h2c_parameter[1] = {0}; + + if (enable) + h2c_parameter[0] |= BIT(0); /* function enable */ + + btcoexist->btc_fill_h2c(btcoexist, 0x63, 1, h2c_parameter); +} + +static void halbtc8822b1ant_ignore_wlan_act(struct btc_coexist *btcoexist, + bool force_exec, bool enable) +{ + coex_dm->cur_ignore_wlan_act = enable; + + if (!force_exec) { + if (coex_dm->pre_ignore_wlan_act == + coex_dm->cur_ignore_wlan_act) { + coex_dm->pre_ignore_wlan_act = + coex_dm->cur_ignore_wlan_act; + return; + } + } + + halbtc8822b1ant_set_fw_ignore_wlan_act(btcoexist, enable); + + coex_dm->pre_ignore_wlan_act = coex_dm->cur_ignore_wlan_act; +} + +static void halbtc8822b1ant_set_lps_rpwm(struct btc_coexist *btcoexist, + u8 lps_val, u8 rpwm_val) +{ + u8 lps = lps_val; + u8 rpwm = rpwm_val; + + btcoexist->btc_set(btcoexist, BTC_SET_U1_LPS_VAL, &lps); + btcoexist->btc_set(btcoexist, BTC_SET_U1_RPWM_VAL, &rpwm); +} + +static void halbtc8822b1ant_lps_rpwm(struct btc_coexist *btcoexist, + bool force_exec, u8 lps_val, u8 rpwm_val) +{ + coex_dm->cur_lps = lps_val; + coex_dm->cur_rpwm = rpwm_val; + + if (!force_exec) { + if ((coex_dm->pre_lps == coex_dm->cur_lps) && + (coex_dm->pre_rpwm == coex_dm->cur_rpwm)) + return; + } + halbtc8822b1ant_set_lps_rpwm(btcoexist, lps_val, rpwm_val); + + coex_dm->pre_lps = coex_dm->cur_lps; + coex_dm->pre_rpwm = coex_dm->cur_rpwm; +} + +static void halbtc8822b1ant_ps_tdma_check_for_power_save_state( + struct btc_coexist *btcoexist, bool new_ps_state) +{ + u8 lps_mode = 0x0; + u8 h2c_parameter[5] = {0x8, 0, 0, 0, 0}; + + btcoexist->btc_get(btcoexist, BTC_GET_U1_LPS_MODE, &lps_mode); + + if (lps_mode) { /* already under LPS state */ + if (new_ps_state) { + /* keep state under LPS, do nothing. */ + } else { + /* will leave LPS state, turn off psTdma first */ + + btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, + h2c_parameter); + } + } else { /* NO PS state */ + if (new_ps_state) { + /* will enter LPS state, turn off psTdma first */ + + btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, + h2c_parameter); + } else { + /* keep state under NO PS state, do nothing. */ + } + } +} + +static bool halbtc8822b1ant_power_save_state(struct btc_coexist *btcoexist, + u8 ps_type, u8 lps_val, + u8 rpwm_val) +{ + bool low_pwr_disable = false, result = true; + + switch (ps_type) { + case BTC_PS_WIFI_NATIVE: + /* recover to original 32k low power setting */ + coex_sta->force_lps_ctrl = false; + low_pwr_disable = false; + btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_NORMAL_LPS, NULL); + break; + case BTC_PS_LPS_ON: + + coex_sta->force_lps_ctrl = true; + halbtc8822b1ant_ps_tdma_check_for_power_save_state(btcoexist, + true); + halbtc8822b1ant_lps_rpwm(btcoexist, NORMAL_EXEC, lps_val, + rpwm_val); + /* when coex force to enter LPS, do not enter 32k low power. */ + low_pwr_disable = true; + btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + /* power save must executed before psTdma. */ + btcoexist->btc_set(btcoexist, BTC_SET_ACT_ENTER_LPS, NULL); + + break; + case BTC_PS_LPS_OFF: + + coex_sta->force_lps_ctrl = true; + halbtc8822b1ant_ps_tdma_check_for_power_save_state(btcoexist, + false); + result = btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS, + NULL); + + break; + default: + break; + } + + return result; +} + +static void halbtc8822b1ant_set_fw_pstdma(struct btc_coexist *btcoexist, + u8 byte1, u8 byte2, u8 byte3, + u8 byte4, u8 byte5) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + u8 h2c_parameter[5] = {0}; + u8 real_byte1 = byte1, real_byte5 = byte5; + bool ap_enable = false, result = false; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + if (byte5 & BIT(2)) + coex_sta->is_tdma_btautoslot = true; + else + coex_sta->is_tdma_btautoslot = false; + + /* release bt-auto slot for auto-slot hang is detected!! */ + if (coex_sta->is_tdma_btautoslot) + if ((coex_sta->is_tdma_btautoslot_hang) || + (bt_link_info->slave_role)) + byte5 = byte5 & 0xfb; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, + &ap_enable); + + if ((ap_enable) && (byte1 & BIT(4) && !(byte1 & BIT(5)))) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], %s == FW for 1Ant AP mode\n", __func__); + + real_byte1 &= ~BIT(4); + real_byte1 |= BIT(5); + + real_byte5 |= BIT(5); + real_byte5 &= ~BIT(6); + + halbtc8822b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + + } else if (byte1 & BIT(4) && !(byte1 & BIT(5))) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], %s == Force LPS (byte1 = 0x%x)\n", + __func__, byte1); + if (!halbtc8822b1ant_power_save_state(btcoexist, BTC_PS_LPS_OFF, + 0x50, 0x4)) + result = true; + } else { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], %s == native power save (byte1 = 0x%x)\n", + __func__, byte1); + halbtc8822b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + } + + coex_sta->is_set_ps_state_fail = result; + + if (!coex_sta->is_set_ps_state_fail) { + h2c_parameter[0] = real_byte1; + h2c_parameter[1] = byte2; + h2c_parameter[2] = byte3; + h2c_parameter[3] = byte4; + h2c_parameter[4] = real_byte5; + + coex_dm->ps_tdma_para[0] = real_byte1; + coex_dm->ps_tdma_para[1] = byte2; + coex_dm->ps_tdma_para[2] = byte3; + coex_dm->ps_tdma_para[3] = byte4; + coex_dm->ps_tdma_para[4] = real_byte5; + + btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, h2c_parameter); + + } else { + coex_sta->cnt_set_ps_state_fail++; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], %s == Force Leave LPS Fail (cnt = %d)\n", + __func__, coex_sta->cnt_set_ps_state_fail); + } +} + +static void halbtc8822b1ant_ps_tdma(struct btc_coexist *btcoexist, + bool force_exec, bool turn_on, u8 type) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + bool wifi_busy = false; + static u8 ps_tdma_byte4_modify, pre_ps_tdma_byte4_modify; + static bool pre_wifi_busy; + + coex_dm->cur_ps_tdma_on = turn_on; + coex_dm->cur_ps_tdma = type; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + if (wifi_busy != pre_wifi_busy) { + force_exec = true; + pre_wifi_busy = wifi_busy; + } + + /* 0x778 = 0x1 at wifi slot (no blocking BT Low-Pri pkts) */ + if (bt_link_info->slave_role) + ps_tdma_byte4_modify = 0x1; + else + ps_tdma_byte4_modify = 0x0; + + if (pre_ps_tdma_byte4_modify != ps_tdma_byte4_modify) { + force_exec = true; + pre_ps_tdma_byte4_modify = ps_tdma_byte4_modify; + } + + if (!force_exec) { + if ((coex_dm->pre_ps_tdma_on == coex_dm->cur_ps_tdma_on) && + (coex_dm->pre_ps_tdma == coex_dm->cur_ps_tdma)) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Skip TDMA because no change TDMA(%s, %d)\n", + (coex_dm->cur_ps_tdma_on ? "on" : "off"), + coex_dm->cur_ps_tdma); + return; + } + } + + if (coex_dm->cur_ps_tdma_on) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** TDMA(on, %d) **********\n", + coex_dm->cur_ps_tdma); + + btcoexist->btc_write_1byte_bitmask( + btcoexist, 0x550, 0x8, 0x1); /* enable TBTT nterrupt */ + } else { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** TDMA(off, %d) **********\n", + coex_dm->cur_ps_tdma); + } + + if (turn_on) { + /* enable TBTT nterrupt */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x550, 0x8, 0x1); + + switch (type) { + default: + halbtc8822b1ant_set_fw_pstdma(btcoexist, 0x61, 0x35, + 0x03, 0x11, 0x11); + break; + case 1: + halbtc8822b1ant_set_fw_pstdma(btcoexist, 0x61, 0x3a, + 0x03, 0x11, 0x10); + break; + case 3: + halbtc8822b1ant_set_fw_pstdma(btcoexist, 0x51, 0x30, + 0x03, 0x10, 0x50); + break; + case 4: + halbtc8822b1ant_set_fw_pstdma(btcoexist, 0x51, 0x21, + 0x03, 0x10, 0x50); + break; + case 5: + halbtc8822b1ant_set_fw_pstdma(btcoexist, 0x61, 0x15, + 0x3, 0x11, 0x11); + break; + case 6: + halbtc8822b1ant_set_fw_pstdma(btcoexist, 0x61, 0x20, + 0x3, 0x11, 0x10); + break; + case 7: + halbtc8822b1ant_set_fw_pstdma( + btcoexist, 0x51, 0x10, 0x03, 0x10, + 0x54 | ps_tdma_byte4_modify); + break; + case 8: + halbtc8822b1ant_set_fw_pstdma( + btcoexist, 0x51, 0x10, 0x03, 0x10, + 0x14 | ps_tdma_byte4_modify); + break; + case 11: + halbtc8822b1ant_set_fw_pstdma( + btcoexist, 0x61, 0x25, 0x03, 0x11, + 0x10 | ps_tdma_byte4_modify); + break; + case 12: + halbtc8822b1ant_set_fw_pstdma( + btcoexist, 0x51, 0x30, 0x03, 0x10, + 0x50 | ps_tdma_byte4_modify); + break; + case 13: + halbtc8822b1ant_set_fw_pstdma( + btcoexist, 0x51, 0x10, 0x07, 0x10, + 0x54 | ps_tdma_byte4_modify); + break; + case 14: + halbtc8822b1ant_set_fw_pstdma( + btcoexist, 0x51, 0x15, 0x03, 0x10, + 0x50 | ps_tdma_byte4_modify); + break; + case 15: + halbtc8822b1ant_set_fw_pstdma( + btcoexist, 0x51, 0x20, 0x03, 0x10, + 0x10 | ps_tdma_byte4_modify); + break; + case 17: + halbtc8822b1ant_set_fw_pstdma( + btcoexist, 0x61, 0x10, 0x03, 0x11, + 0x14 | ps_tdma_byte4_modify); + break; + case 18: + halbtc8822b1ant_set_fw_pstdma( + btcoexist, 0x51, 0x10, 0x03, 0x10, + 0x50 | ps_tdma_byte4_modify); + break; + + case 20: + halbtc8822b1ant_set_fw_pstdma(btcoexist, 0x61, 0x30, + 0x03, 0x11, 0x10); + break; + case 22: + halbtc8822b1ant_set_fw_pstdma(btcoexist, 0x61, 0x25, + 0x03, 0x11, 0x10); + break; + case 27: + halbtc8822b1ant_set_fw_pstdma(btcoexist, 0x61, 0x10, + 0x03, 0x11, 0x15); + break; + case 32: + halbtc8822b1ant_set_fw_pstdma(btcoexist, 0x61, 0x35, + 0x3, 0x11, 0x11); + break; + case 33: + halbtc8822b1ant_set_fw_pstdma(btcoexist, 0x61, 0x35, + 0x03, 0x11, 0x10); + break; + case 41: + halbtc8822b1ant_set_fw_pstdma(btcoexist, 0x51, 0x45, + 0x3, 0x11, 0x11); + break; + case 42: + halbtc8822b1ant_set_fw_pstdma( + btcoexist, 0x51, 0x1e, 0x3, 0x10, + 0x14 | ps_tdma_byte4_modify); + break; + case 43: + halbtc8822b1ant_set_fw_pstdma(btcoexist, 0x51, 0x45, + 0x3, 0x10, 0x14); + break; + case 44: + halbtc8822b1ant_set_fw_pstdma(btcoexist, 0x51, 0x25, + 0x3, 0x10, 0x10); + break; + case 45: + halbtc8822b1ant_set_fw_pstdma(btcoexist, 0x51, 0x29, + 0x3, 0x10, 0x10); + break; + case 46: + halbtc8822b1ant_set_fw_pstdma(btcoexist, 0x51, 0x1a, + 0x3, 0x10, 0x10); + break; + case 47: + halbtc8822b1ant_set_fw_pstdma(btcoexist, 0x51, 0x32, + 0x3, 0x10, 0x10); + break; + case 48: + halbtc8822b1ant_set_fw_pstdma(btcoexist, 0x51, 0x29, + 0x3, 0x10, 0x10); + break; + case 49: + halbtc8822b1ant_set_fw_pstdma(btcoexist, 0x55, 0x10, + 0x3, 0x10, 0x54); + break; + case 50: + halbtc8822b1ant_set_fw_pstdma(btcoexist, 0x51, 0x4a, + 0x3, 0x10, 0x10); + break; + case 51: + halbtc8822b1ant_set_fw_pstdma(btcoexist, 0x61, 0x35, + 0x3, 0x10, 0x11); + break; + } + } else { + switch (type) { + case 0: + default: /* Software control, Antenna at BT side */ + halbtc8822b1ant_set_fw_pstdma(btcoexist, 0x0, 0x0, 0x0, + 0x0, 0x0); + break; + case 8: /* PTA Control */ + halbtc8822b1ant_set_fw_pstdma(btcoexist, 0x8, 0x0, 0x0, + 0x0, 0x0); + break; + case 9: /* Software control, Antenna at WiFi side */ + halbtc8822b1ant_set_fw_pstdma(btcoexist, 0x0, 0x0, 0x0, + 0x0, 0x0); + break; + case 10: /* under 5G , 0x778=1*/ + halbtc8822b1ant_set_fw_pstdma(btcoexist, 0x0, 0x0, 0x0, + 0x0, 0x0); + + break; + } + } + + if (!coex_sta->is_set_ps_state_fail) { + /* update pre state */ + coex_dm->pre_ps_tdma_on = coex_dm->cur_ps_tdma_on; + coex_dm->pre_ps_tdma = coex_dm->cur_ps_tdma; + } +} + +static void halbtc8822b1ant_sw_mechanism(struct btc_coexist *btcoexist, + bool low_penalty_ra) +{ + halbtc8822b1ant_low_penalty_ra(btcoexist, NORMAL_EXEC, low_penalty_ra); +} + +/* rf4 type by efuse, and for ant at main aux inverse use, + * because is 2x2, and control types are the same, does not need + */ + +static void halbtc8822b1ant_set_rfe_type(struct btc_coexist *btcoexist) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + + /* Ext switch buffer mux */ + btcoexist->btc_write_1byte(btcoexist, 0x974, 0xff); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x1991, 0x3, 0x0); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcbe, 0x8, 0x0); + + /* the following setup should be got from Efuse in the future */ + rfe_type->rfe_module_type = board_info->rfe_type; + + rfe_type->ext_ant_switch_ctrl_polarity = 0; + + switch (rfe_type->rfe_module_type) { + case 0: + default: + rfe_type->ext_ant_switch_exist = true; + rfe_type->ext_ant_switch_type = + BT_8822B_1ANT_EXT_ANT_SWITCH_USE_SPDT; + break; + case 1: + rfe_type->ext_ant_switch_exist = true; + rfe_type->ext_ant_switch_type = + BT_8822B_1ANT_EXT_ANT_SWITCH_USE_SPDT; + break; + case 2: + rfe_type->ext_ant_switch_exist = true; + rfe_type->ext_ant_switch_type = + BT_8822B_1ANT_EXT_ANT_SWITCH_USE_SPDT; + break; + case 3: + rfe_type->ext_ant_switch_exist = true; + rfe_type->ext_ant_switch_type = + BT_8822B_1ANT_EXT_ANT_SWITCH_USE_SPDT; + break; + case 4: + rfe_type->ext_ant_switch_exist = true; + rfe_type->ext_ant_switch_type = + BT_8822B_1ANT_EXT_ANT_SWITCH_USE_SPDT; + break; + case 5: + rfe_type->ext_ant_switch_exist = true; + rfe_type->ext_ant_switch_type = + BT_8822B_1ANT_EXT_ANT_SWITCH_USE_SPDT; + break; + case 6: + rfe_type->ext_ant_switch_exist = true; + rfe_type->ext_ant_switch_type = + BT_8822B_1ANT_EXT_ANT_SWITCH_USE_SPDT; + break; + case 7: + rfe_type->ext_ant_switch_exist = true; + rfe_type->ext_ant_switch_type = + BT_8822B_1ANT_EXT_ANT_SWITCH_USE_SPDT; + break; + } +} + +/*anttenna control by bb mac bt antdiv pta to write 0x4c 0xcb4,0xcbd*/ + +static void halbtc8822b1ant_set_ext_ant_switch(struct btc_coexist *btcoexist, + bool force_exec, u8 ctrl_type, + u8 pos_type) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + bool switch_polatiry_inverse = false; + u8 regval_0xcbd = 0, regval_0x64; + u32 u32tmp1 = 0, u32tmp2 = 0, u32tmp3 = 0; + + /* Ext switch buffer mux */ + btcoexist->btc_write_1byte(btcoexist, 0x974, 0xff); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x1991, 0x3, 0x0); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcbe, 0x8, 0x0); + + if (!rfe_type->ext_ant_switch_exist) + return; + + coex_dm->cur_ext_ant_switch_status = (ctrl_type << 8) + pos_type; + + if (!force_exec) { + if (coex_dm->pre_ext_ant_switch_status == + coex_dm->cur_ext_ant_switch_status) + return; + } + + coex_dm->pre_ext_ant_switch_status = coex_dm->cur_ext_ant_switch_status; + + /* swap control polarity if use different switch control polarity*/ + /* Normal switch polarity for SPDT, + * 0xcbd[1:0] = 2b'01 => Ant to BTG, + * 0xcbd[1:0] = 2b'10 => Ant to WLG + */ + switch_polatiry_inverse = rfe_type->ext_ant_switch_ctrl_polarity == 1; + + switch (pos_type) { + default: + case BT_8822B_1ANT_EXT_ANT_SWITCH_TO_BT: + case BT_8822B_1ANT_EXT_ANT_SWITCH_TO_NOCARE: + + break; + case BT_8822B_1ANT_EXT_ANT_SWITCH_TO_WLG: + break; + case BT_8822B_1ANT_EXT_ANT_SWITCH_TO_WLA: + break; + } + + if (rfe_type->ext_ant_switch_type == + BT_8822B_1ANT_EXT_ANT_SWITCH_USE_SPDT) { + switch (ctrl_type) { + default: + case BT_8822B_1ANT_EXT_ANT_SWITCH_CTRL_BY_BBSW: + /* 0x4c[23] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4e, + 0x80, 0x0); + /* 0x4c[24] = 1 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4f, + 0x01, 0x1); + /* BB SW, DPDT use RFE_ctrl8 and RFE_ctrl9 as ctrl pin*/ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb4, + 0xff, 0x77); + + /* 0xcbd[1:0] = 2b'01 for no switch_polatiry_inverse, + * ANTSWB =1, ANTSW =0 + */ + regval_0xcbd = (!switch_polatiry_inverse ? 0x1 : 0x2); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcbd, + 0x3, regval_0xcbd); + + break; + case BT_8822B_1ANT_EXT_ANT_SWITCH_CTRL_BY_PTA: + /* 0x4c[23] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4e, + 0x80, 0x0); + /* 0x4c[24] = 1 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4f, + 0x01, 0x1); + /* PTA, DPDT use RFE_ctrl8 and RFE_ctrl9 as ctrl pin */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb4, + 0xff, 0x66); + + /* 0xcbd[1:0] = 2b'10 for no switch_polatiry_inverse, + * ANTSWB =1, ANTSW =0 @ GNT_BT=1 + */ + regval_0xcbd = (!switch_polatiry_inverse ? 0x2 : 0x1); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcbd, + 0x3, regval_0xcbd); + + break; + case BT_8822B_1ANT_EXT_ANT_SWITCH_CTRL_BY_ANTDIV: + /* 0x4c[23] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4e, + 0x80, 0x0); + /* 0x4c[24] = 1 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4f, + 0x01, 0x1); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb4, + 0xff, 0x88); + + /* no regval_0xcbd setup required, because + * antenna switch control value by antenna diversity + */ + + break; + case BT_8822B_1ANT_EXT_ANT_SWITCH_CTRL_BY_MAC: + /* 0x4c[23] = 1 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4e, + 0x80, 0x1); + + /* 0x64[0] = 1b'0 for no switch_polatiry_inverse, + * DPDT_SEL_N =1, DPDT_SEL_P =0 + */ + regval_0x64 = (!switch_polatiry_inverse ? 0x0 : 0x1); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x64, 0x1, + regval_0x64); + break; + case BT_8822B_1ANT_EXT_ANT_SWITCH_CTRL_BY_BT: + /* 0x4c[23] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4e, + 0x80, 0x0); + /* 0x4c[24] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4f, + 0x01, 0x0); + + /* no setup required, because antenna switch control + * value by BT vendor 0xac[1:0] + */ + break; + } + } + + u32tmp1 = btcoexist->btc_read_4byte(btcoexist, 0xcbc); + u32tmp2 = btcoexist->btc_read_4byte(btcoexist, 0x4c); + u32tmp3 = btcoexist->btc_read_4byte(btcoexist, 0x64) & 0xff; + + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** (After Ext Ant switch setup) 0xcbc = 0x%08x, 0x4c = 0x%08x, 0x64= 0x%02x**********\n", + u32tmp1, u32tmp2, u32tmp3); +} + +/* set gnt_wl gnt_bt control by sw high low, or + * hwpta while in power on, ini, wlan off, wlan only, wl2g non-currrent, + * wl2g current, wl5g + */ + +static void halbtc8822b1ant_set_ant_path(struct btc_coexist *btcoexist, + u8 ant_pos_type, bool force_exec, + u8 phase) + +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + u8 u8tmp = 0; + u32 u32tmp1 = 0; + u32 u32tmp2 = 0, u32tmp3 = 0; + + u32tmp1 = halbtc8822b1ant_ltecoex_indirect_read_reg(btcoexist, 0x38); + + /* To avoid indirect access fail */ + if (((u32tmp1 & 0xf000) >> 12) != ((u32tmp1 & 0x0f00) >> 8)) { + force_exec = true; + coex_sta->gnt_error_cnt++; + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex],(Before Ant Setup) 0x38= 0x%x\n", u32tmp1); + } + + /* Ext switch buffer mux */ + btcoexist->btc_write_1byte(btcoexist, 0x974, 0xff); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x1991, 0x3, 0x0); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcbe, 0x8, 0x0); + + coex_dm->cur_ant_pos_type = (ant_pos_type << 8) + phase; + + if (!force_exec) { + if (coex_dm->cur_ant_pos_type == coex_dm->pre_ant_pos_type) + return; + } + + coex_dm->pre_ant_pos_type = coex_dm->cur_ant_pos_type; + + if (btcoexist->dbg_mode_1ant) { + u32tmp1 = halbtc8822b1ant_ltecoex_indirect_read_reg(btcoexist, + 0x38); + u32tmp2 = halbtc8822b1ant_ltecoex_indirect_read_reg(btcoexist, + 0x54); + u32tmp3 = btcoexist->btc_read_4byte(btcoexist, 0xcb4); + + u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x73); + + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** (Before Ant Setup) 0xcb4 = 0x%x, 0x73 = 0x%x, 0x38= 0x%x, 0x54= 0x%x**********\n", + u32tmp3, u8tmp, u32tmp1, u32tmp2); + } + + switch (phase) { + case BT_8822B_1ANT_PHASE_COEX_INIT: + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** (set_ant_path - 1ANT_PHASE_COEX_INIT) **********\n"); + + /* Disable LTE Coex Function in WiFi side + * (this should be on if LTE coex is required) + */ + halbtc8822b1ant_ltecoex_enable(btcoexist, 0x0); + + /* GNT_WL_LTE always = 1 + * (this should be config if LTE coex is required) + */ + halbtc8822b1ant_ltecoex_set_coex_table( + btcoexist, BT_8822B_1ANT_CTT_WL_VS_LTE, 0xffff); + + /* GNT_BT_LTE always = 1 + * (this should be config if LTE coex is required) + */ + halbtc8822b1ant_ltecoex_set_coex_table( + btcoexist, BT_8822B_1ANT_CTT_BT_VS_LTE, 0xffff); + + /* set GNT_BT to SW high */ + halbtc8822b1ant_ltecoex_set_gnt_bt( + btcoexist, BT_8822B_1ANT_GNT_BLOCK_RFC_BB, + BT_8822B_1ANT_GNT_CTRL_BY_SW, + BT_8822B_1ANT_SIG_STA_SET_TO_HIGH); + + /* set GNT_WL to SW low */ + halbtc8822b1ant_ltecoex_set_gnt_wl( + btcoexist, BT_8822B_1ANT_GNT_BLOCK_RFC_BB, + BT_8822B_1ANT_GNT_CTRL_BY_SW, + BT_8822B_1ANT_SIG_STA_SET_TO_LOW); + + /* set Path control owner to WL at initial step */ + halbtc8822b1ant_ltecoex_pathcontrol_owner( + btcoexist, BT_8822B_1ANT_PCO_WLSIDE); + + coex_sta->run_time_state = false; + + /* Ext switch buffer mux */ + btcoexist->btc_write_1byte(btcoexist, 0x974, 0xff); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x1991, 0x3, 0x0); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcbe, 0x8, 0x0); + + if (ant_pos_type == BTC_ANT_PATH_AUTO) + ant_pos_type = BTC_ANT_PATH_BT; + + break; + case BT_8822B_1ANT_PHASE_WLANONLY_INIT: + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** (set_ant_path - 1ANT_PHASE_WLANONLY_INIT) **********\n"); + + /* Disable LTE Coex Function in WiFi side + * (this should be on if LTE coex is required) + */ + halbtc8822b1ant_ltecoex_enable(btcoexist, 0x0); + + /* GNT_WL_LTE always = 1 + * (this should be config if LTE coex is required) + */ + halbtc8822b1ant_ltecoex_set_coex_table( + btcoexist, BT_8822B_1ANT_CTT_WL_VS_LTE, 0xffff); + + /* GNT_BT_LTE always = 1 + * (this should be config if LTE coex is required) + */ + halbtc8822b1ant_ltecoex_set_coex_table( + btcoexist, BT_8822B_1ANT_CTT_BT_VS_LTE, 0xffff); + + /* set GNT_BT to SW Low */ + halbtc8822b1ant_ltecoex_set_gnt_bt( + btcoexist, BT_8822B_1ANT_GNT_BLOCK_RFC_BB, + BT_8822B_1ANT_GNT_CTRL_BY_SW, + BT_8822B_1ANT_SIG_STA_SET_TO_LOW); + + /* Set GNT_WL to SW high */ + halbtc8822b1ant_ltecoex_set_gnt_wl( + btcoexist, BT_8822B_1ANT_GNT_BLOCK_RFC_BB, + BT_8822B_1ANT_GNT_CTRL_BY_SW, + BT_8822B_1ANT_SIG_STA_SET_TO_HIGH); + + /* set Path control owner to WL at initial step */ + halbtc8822b1ant_ltecoex_pathcontrol_owner( + btcoexist, BT_8822B_1ANT_PCO_WLSIDE); + + coex_sta->run_time_state = false; + + /* Ext switch buffer mux */ + btcoexist->btc_write_1byte(btcoexist, 0x974, 0xff); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x1991, 0x3, 0x0); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcbe, 0x8, 0x0); + + if (ant_pos_type == BTC_ANT_PATH_AUTO) + ant_pos_type = BTC_ANT_PATH_WIFI; + + break; + case BT_8822B_1ANT_PHASE_WLAN_OFF: + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** (set_ant_path - 1ANT_PHASE_WLAN_OFF) **********\n"); + + /* Disable LTE Coex Function in WiFi side */ + halbtc8822b1ant_ltecoex_enable(btcoexist, 0x0); + + /* set Path control owner to BT */ + halbtc8822b1ant_ltecoex_pathcontrol_owner( + btcoexist, BT_8822B_1ANT_PCO_BTSIDE); + + /* Set Ext Ant Switch to BT control at wifi off step */ + halbtc8822b1ant_set_ext_ant_switch( + btcoexist, FORCE_EXEC, + BT_8822B_1ANT_EXT_ANT_SWITCH_CTRL_BY_BT, + BT_8822B_1ANT_EXT_ANT_SWITCH_TO_NOCARE); + + coex_sta->run_time_state = false; + + break; + case BT_8822B_1ANT_PHASE_2G_RUNTIME: + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** (set_ant_path - 1ANT_PHASE_2G_RUNTIME) **********\n"); + + /* set GNT_BT to PTA */ + halbtc8822b1ant_ltecoex_set_gnt_bt( + btcoexist, BT_8822B_1ANT_GNT_BLOCK_RFC_BB, + BT_8822B_1ANT_GNT_CTRL_BY_PTA, + BT_8822B_1ANT_SIG_STA_SET_BY_HW); + + /* Set GNT_WL to PTA */ + halbtc8822b1ant_ltecoex_set_gnt_wl( + btcoexist, BT_8822B_1ANT_GNT_BLOCK_RFC_BB, + BT_8822B_1ANT_GNT_CTRL_BY_PTA, + BT_8822B_1ANT_SIG_STA_SET_BY_HW); + + /* set Path control owner to WL at runtime step */ + halbtc8822b1ant_ltecoex_pathcontrol_owner( + btcoexist, BT_8822B_1ANT_PCO_WLSIDE); + + coex_sta->run_time_state = true; + + if (ant_pos_type == BTC_ANT_PATH_AUTO) + ant_pos_type = BTC_ANT_PATH_PTA; + + break; + case BT_8822B_1ANT_PHASE_5G_RUNTIME: + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** (set_ant_path - 1ANT_PHASE_5G_RUNTIME) **********\n"); + + /* set GNT_BT to SW Hi */ + halbtc8822b1ant_ltecoex_set_gnt_bt( + btcoexist, BT_8822B_1ANT_GNT_BLOCK_RFC_BB, + BT_8822B_1ANT_GNT_CTRL_BY_SW, + BT_8822B_1ANT_SIG_STA_SET_TO_HIGH); + + /* Set GNT_WL to SW Hi */ + halbtc8822b1ant_ltecoex_set_gnt_wl( + btcoexist, BT_8822B_1ANT_GNT_BLOCK_RFC_BB, + BT_8822B_1ANT_GNT_CTRL_BY_SW, + BT_8822B_1ANT_SIG_STA_SET_TO_HIGH); + + /* set Path control owner to WL at runtime step */ + halbtc8822b1ant_ltecoex_pathcontrol_owner( + btcoexist, BT_8822B_1ANT_PCO_WLSIDE); + + coex_sta->run_time_state = true; + + if (ant_pos_type == BTC_ANT_PATH_AUTO) + ant_pos_type = BTC_ANT_PATH_WIFI5G; + + break; + case BT_8822B_1ANT_PHASE_BTMPMODE: + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** (set_ant_path - 1ANT_PHASE_BTMPMODE) **********\n"); + + /* Disable LTE Coex Function in WiFi side */ + halbtc8822b1ant_ltecoex_enable(btcoexist, 0x0); + + /* set GNT_BT to SW Hi */ + halbtc8822b1ant_ltecoex_set_gnt_bt( + btcoexist, BT_8822B_1ANT_GNT_BLOCK_RFC_BB, + BT_8822B_1ANT_GNT_CTRL_BY_SW, + BT_8822B_1ANT_SIG_STA_SET_TO_HIGH); + + /* Set GNT_WL to SW Lo */ + halbtc8822b1ant_ltecoex_set_gnt_wl( + btcoexist, BT_8822B_1ANT_GNT_BLOCK_RFC_BB, + BT_8822B_1ANT_GNT_CTRL_BY_SW, + BT_8822B_1ANT_SIG_STA_SET_TO_LOW); + + /* set Path control owner to WL */ + halbtc8822b1ant_ltecoex_pathcontrol_owner( + btcoexist, BT_8822B_1ANT_PCO_WLSIDE); + + coex_sta->run_time_state = false; + + /* Set Ext Ant Switch to BT side at BT MP mode */ + if (ant_pos_type == BTC_ANT_PATH_AUTO) + ant_pos_type = BTC_ANT_PATH_BT; + + break; + } + + if (phase != BT_8822B_1ANT_PHASE_WLAN_OFF) { + switch (ant_pos_type) { + case BTC_ANT_PATH_WIFI: + halbtc8822b1ant_set_ext_ant_switch( + btcoexist, force_exec, + BT_8822B_1ANT_EXT_ANT_SWITCH_CTRL_BY_BBSW, + BT_8822B_1ANT_EXT_ANT_SWITCH_TO_WLG); + break; + case BTC_ANT_PATH_WIFI5G: + halbtc8822b1ant_set_ext_ant_switch( + btcoexist, force_exec, + BT_8822B_1ANT_EXT_ANT_SWITCH_CTRL_BY_BBSW, + BT_8822B_1ANT_EXT_ANT_SWITCH_TO_WLA); + break; + case BTC_ANT_PATH_BT: + halbtc8822b1ant_set_ext_ant_switch( + btcoexist, force_exec, + BT_8822B_1ANT_EXT_ANT_SWITCH_CTRL_BY_BBSW, + BT_8822B_1ANT_EXT_ANT_SWITCH_TO_BT); + break; + default: + case BTC_ANT_PATH_PTA: + halbtc8822b1ant_set_ext_ant_switch( + btcoexist, force_exec, + BT_8822B_1ANT_EXT_ANT_SWITCH_CTRL_BY_PTA, + BT_8822B_1ANT_EXT_ANT_SWITCH_TO_NOCARE); + break; + } + } + + if (btcoexist->dbg_mode_1ant) { + u32tmp1 = halbtc8822b1ant_ltecoex_indirect_read_reg(btcoexist, + 0x38); + u32tmp2 = halbtc8822b1ant_ltecoex_indirect_read_reg(btcoexist, + 0x54); + u32tmp3 = btcoexist->btc_read_4byte(btcoexist, 0xcb4); + + u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x73); + + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** (After Ant Setup) 0xcb4 = 0x%x, 0x73 = 0x%x, 0x38= 0x%x, 0x54= 0x%x**********\n", + u32tmp3, u8tmp, u32tmp1, u32tmp2); + } +} + +static bool halbtc8822b1ant_is_common_action(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + bool common = false, wifi_connected = false, wifi_busy = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + if (!wifi_connected && + coex_dm->bt_status == BT_8822B_1ANT_BT_STATUS_NON_CONNECTED_IDLE) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Wifi non connected-idle + BT non connected-idle!!\n"); + + /* halbtc8822b1ant_sw_mechanism(btcoexist, false); */ + + common = true; + } else if (wifi_connected && + (coex_dm->bt_status == + BT_8822B_1ANT_BT_STATUS_NON_CONNECTED_IDLE)) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Wifi connected + BT non connected-idle!!\n"); + + /* halbtc8822b1ant_sw_mechanism(btcoexist, false); */ + + common = true; + } else if (!wifi_connected && (BT_8822B_1ANT_BT_STATUS_CONNECTED_IDLE == + coex_dm->bt_status)) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Wifi non connected-idle + BT connected-idle!!\n"); + + /* halbtc8822b1ant_sw_mechanism(btcoexist, false); */ + + common = true; + } else if (wifi_connected && (BT_8822B_1ANT_BT_STATUS_CONNECTED_IDLE == + coex_dm->bt_status)) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Wifi connected + BT connected-idle!!\n"); + + /* halbtc8822b1ant_sw_mechanism(btcoexist, false); */ + + common = true; + } else if (!wifi_connected && (BT_8822B_1ANT_BT_STATUS_CONNECTED_IDLE != + coex_dm->bt_status)) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Wifi non connected-idle + BT Busy!!\n"); + + /* halbtc8822b1ant_sw_mechanism(btcoexist, false); */ + + common = true; + } else { + if (wifi_busy) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Wifi Connected-Busy + BT Busy!!\n"); + } else { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Wifi Connected-Idle + BT Busy!!\n"); + } + + common = false; + } + + return common; +} + +static void halbtc8822b1ant_action_wifi_under5g(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], under 5g start\n"); + /* for test : s3 bt disappear , fail rate 1/600*/ + /*set sw gnt wl bt high*/ + halbtc8822b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, FORCE_EXEC, + BT_8822B_1ANT_PHASE_5G_RUNTIME); + + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcbd, 0x3, 1); +} + +static void halbtc8822b1ant_action_wifi_only(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + bool wifi_under_5g = false, rf4ce_enabled = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + if (wifi_under_5g) { + halbtc8822b1ant_action_wifi_under5g(btcoexist); + + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** (wlan only -- under 5g ) **********\n"); + return; + } + + if (rf4ce_enabled) { + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x45e, 0x8, 0x1); + + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 50); + + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + return; + } + halbtc8822b1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0); + halbtc8822b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8); + + halbtc8822b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, FORCE_EXEC, + BT_8822B_1ANT_PHASE_2G_RUNTIME); + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** (wlan only -- under 2g ) **********\n"); +} + +static void +halbtc8822b1ant_action_wifi_native_lps(struct btc_coexist *btcoexist) +{ + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 5); + + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); +} + +/* ********************************************* + * + * Non-Software Coex Mechanism start + * + * **********************************************/ + +static void halbtc8822b1ant_action_bt_whck_test(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex],action_bt_whck_test\n"); + + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + + halbtc8822b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, NORMAL_EXEC, + BT_8822B_1ANT_PHASE_2G_RUNTIME); + + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); +} + +static void +halbtc8822b1ant_action_wifi_multi_port(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex],action_wifi_multi_port\n"); + + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + + halbtc8822b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, NORMAL_EXEC, + BT_8822B_1ANT_PHASE_2G_RUNTIME); + + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); +} + +static void halbtc8822b1ant_action_hs(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], action_hs\n"); + + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5); + + halbtc8822b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, NORMAL_EXEC, + BT_8822B_1ANT_PHASE_2G_RUNTIME); + + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 5); +} + +static void halbtc8822b1ant_action_bt_relink(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], run bt multi link function\n"); + + if (coex_sta->is_bt_multi_link) + return; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], run bt_re-link function\n"); + + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); +} + +/*"""bt inquiry"""" + wifi any + bt any*/ + +static void halbtc8822b1ant_action_bt_inquiry(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + bool wifi_connected = false, ap_enable = false, wifi_busy = false, + bt_busy = false, rf4ce_enabled = false; + + bool wifi_scan = false, link = false, roam = false; + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** (bt inquiry) **********\n"); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, + &ap_enable); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &wifi_scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** scan = %d, link =%d, roam = %d**********\n", + wifi_scan, link, roam); + + if ((link) || (roam) || (coex_sta->wifi_is_high_pri_task)) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** (bt inquiry wifi connect or scan ) **********\n"); + + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 1); + + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 6); + + } else if ((wifi_scan) && (coex_sta->bt_create_connection)) { + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 22); + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 6); + + } else if ((!wifi_connected) && (!wifi_scan)) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** (bt inquiry wifi non connect) **********\n"); + + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + } else if ((bt_link_info->a2dp_exist) && (bt_link_info->pan_exist)) { + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 22); + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } else if (bt_link_info->a2dp_exist) { + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 32); + + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 3); + } else if (wifi_scan) { + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); + + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } else if (wifi_busy) { + /* for BT inquiry/page fail after S4 resume */ + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 32); + /*aaaa->55aa for bt connect while wl busy*/ + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 15); + if (rf4ce_enabled) { + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x45e, + 0x8, 0x1); + + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 50); + + halbtc8822b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 0); + } + } else { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** (bt inquiry wifi connect) **********\n"); + + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 22); + + halbtc8822b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + NORMAL_EXEC, + BT_8822B_1ANT_PHASE_2G_RUNTIME); + + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } +} + +static void +halbtc8822b1ant_action_bt_sco_hid_only_busy(struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + bool wifi_connected = false, wifi_busy = false; + u32 wifi_bw = 1; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + if (bt_link_info->sco_exist) { + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5); + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 5); + } else { + if (coex_sta->is_hid_low_pri_tx_overhead) { + halbtc8822b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 6); + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 18); + } else if (wifi_bw == 0) { /* if 11bg mode */ + + if (coex_sta->is_bt_multi_link) { + halbtc8822b1ant_coex_table_with_type( + btcoexist, NORMAL_EXEC, 11); + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 11); + } else { + halbtc8822b1ant_coex_table_with_type( + btcoexist, NORMAL_EXEC, 6); + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 11); + } + } else { + halbtc8822b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 6); + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 11); + } + } +} + +static void +halbtc8822b1ant_action_wifi_connected_bt_acl_busy(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + bool wifi_busy = false, wifi_turbo = false; + u32 wifi_bw = 1; + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, + &coex_sta->scan_ap_num); + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "############# [BTCoex], scan_ap_num = %d, wl_noisy_level = %d\n", + coex_sta->scan_ap_num, coex_sta->wl_noisy_level); + + if ((wifi_busy) && (coex_sta->wl_noisy_level == 0)) + wifi_turbo = true; + + if ((coex_sta->bt_relink_downcount != 0) && + (!bt_link_info->pan_exist) && (wifi_busy)) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "############# [BTCoex], BT Re-Link + A2DP + WL busy\n"); + + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + } else if ((bt_link_info->a2dp_exist) && (coex_sta->is_bt_a2dp_sink)) { + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 12); + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 6); + } else if (bt_link_info->a2dp_only) { /* A2DP */ + + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 7); + + if (wifi_turbo) + halbtc8822b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 19); + else + halbtc8822b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + } else if (((bt_link_info->a2dp_exist) && (bt_link_info->pan_exist)) || + (bt_link_info->hid_exist && bt_link_info->a2dp_exist && + bt_link_info->pan_exist)) { + /* A2DP+PAN(OPP,FTP), HID+A2DP+PAN(OPP,FTP) */ + + if (wifi_busy) + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 13); + else + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 14); + + if (bt_link_info->hid_exist) + halbtc8822b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + else if (wifi_turbo) + halbtc8822b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 19); + else + halbtc8822b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + } else if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { /* HID+A2DP */ + + if (wifi_bw == 0) { /* if 11bg mode */ + halbtc8822b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + halbtc8822b1ant_set_wltoggle_coex_table( + btcoexist, NORMAL_EXEC, 1, 0xaa, 0x5a, 0xaa, + 0xaa); + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 49); + } else { + halbtc8822b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + halbtc8822b1ant_limited_rx(btcoexist, NORMAL_EXEC, + false, true, 8); + halbtc8822b1ant_set_wltoggle_coex_table( + btcoexist, NORMAL_EXEC, 1, 0xaa, 0x5a, 0xaa, + 0xaa); + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 49); + } + /* PAN(OPP,FTP), HID+PAN(OPP,FTP) */ + + } else if ((bt_link_info->pan_only) || + (bt_link_info->hid_exist && bt_link_info->pan_exist)) { + if (!wifi_busy) + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 4); + else + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 3); + + if (bt_link_info->hid_exist) + halbtc8822b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + else if (wifi_turbo) + halbtc8822b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 19); + else + halbtc8822b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + } else { + /* BT no-profile busy (0x9) */ + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 33); + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } +} + +/*wifi not connected + bt action*/ + +static void +halbtc8822b1ant_action_wifi_not_connected(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + bool rf4ce_enabled = false; + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** (wifi not connect) **********\n"); + + /* tdma and coex table */ + if (rf4ce_enabled) { + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x45e, 0x8, 0x1); + + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 50); + + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + return; + } + halbtc8822b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8); + + halbtc8822b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, NORMAL_EXEC, + BT_8822B_1ANT_PHASE_2G_RUNTIME); + + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); +} + +/*""""wl not connected scan"""" + bt action*/ +static void +halbtc8822b1ant_action_wifi_not_connected_scan(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + bool bt_hs_on = false; + u32 wifi_link_status = 0; + u32 num_of_wifi_link = 0; + bool bt_ctrl_agg_buf_size = false; + u8 agg_buf_size = 5; + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** (wifi non connect scan) **********\n"); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, + &wifi_link_status); + + num_of_wifi_link = wifi_link_status >> 16; + + if (num_of_wifi_link >= 2) { + halbtc8822b1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + halbtc8822b1ant_limited_rx(btcoexist, NORMAL_EXEC, false, + bt_ctrl_agg_buf_size, agg_buf_size); + + if (coex_sta->c2h_bt_inquiry_page) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "############# [BTCoex], BT Is Inquirying\n"); + halbtc8822b1ant_action_bt_inquiry(btcoexist); + } else { + halbtc8822b1ant_action_wifi_multi_port(btcoexist); + } + return; + } + + if (coex_sta->c2h_bt_inquiry_page) { + halbtc8822b1ant_action_bt_inquiry(btcoexist); + return; + } else if (bt_hs_on) { + halbtc8822b1ant_action_hs(btcoexist); + return; + } + + /* tdma and coex table */ + if (coex_dm->bt_status == BT_8822B_1ANT_BT_STATUS_ACL_BUSY) { + if (bt_link_info->a2dp_exist) { + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 32); + halbtc8822b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + } else if (bt_link_info->a2dp_exist && + bt_link_info->pan_exist) { + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 22); + halbtc8822b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + } else { + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 20); + halbtc8822b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + } + } else if ((coex_dm->bt_status == BT_8822B_1ANT_BT_STATUS_SCO_BUSY) || + (BT_8822B_1ANT_BT_STATUS_ACL_SCO_BUSY == + coex_dm->bt_status)) { + halbtc8822b1ant_action_bt_sco_hid_only_busy(btcoexist); + } else { + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + + halbtc8822b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + NORMAL_EXEC, + BT_8822B_1ANT_PHASE_2G_RUNTIME); + + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 5); + } +} + +/*""""wl not connected asso"""" + bt action*/ + +static void halbtc8822b1ant_action_wifi_not_connected_asso_auth( + struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + bool bt_hs_on = false; + u32 wifi_link_status = 0; + u32 num_of_wifi_link = 0; + bool bt_ctrl_agg_buf_size = false; + u8 agg_buf_size = 5; + + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** (wifi non connect asso_auth) **********\n"); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, + &wifi_link_status); + + num_of_wifi_link = wifi_link_status >> 16; + + if (num_of_wifi_link >= 2) { + halbtc8822b1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + halbtc8822b1ant_limited_rx(btcoexist, NORMAL_EXEC, false, + bt_ctrl_agg_buf_size, agg_buf_size); + + if (coex_sta->c2h_bt_inquiry_page) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "############# [BTCoex], BT Is Inquirying\n"); + halbtc8822b1ant_action_bt_inquiry(btcoexist); + } else { + halbtc8822b1ant_action_wifi_multi_port(btcoexist); + } + return; + } + + if (coex_sta->c2h_bt_inquiry_page) { + halbtc8822b1ant_action_bt_inquiry(btcoexist); + return; + } else if (bt_hs_on) { + halbtc8822b1ant_action_hs(btcoexist); + return; + } + + /* tdma and coex table */ + if ((bt_link_info->sco_exist) || (bt_link_info->hid_exist) || + (bt_link_info->a2dp_exist)) { + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 32); + halbtc8822b1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 4); + } else if (bt_link_info->pan_exist) { + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); + halbtc8822b1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 4); + } else { + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + + halbtc8822b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + NORMAL_EXEC, + BT_8822B_1ANT_PHASE_2G_RUNTIME); + + halbtc8822b1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 2); + } +} + +/*""""wl connected scan"""" + bt action*/ + +static void +halbtc8822b1ant_action_wifi_connected_scan(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + bool bt_hs_on = false; + u32 wifi_link_status = 0; + u32 num_of_wifi_link = 0; + bool bt_ctrl_agg_buf_size = false; + u8 agg_buf_size = 5; + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** (wifi connect scan) **********\n"); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, + &wifi_link_status); + + num_of_wifi_link = wifi_link_status >> 16; + + if (num_of_wifi_link >= 2) { + halbtc8822b1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + halbtc8822b1ant_limited_rx(btcoexist, NORMAL_EXEC, false, + bt_ctrl_agg_buf_size, agg_buf_size); + + if (coex_sta->c2h_bt_inquiry_page) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "############# [BTCoex], BT Is Inquirying\n"); + halbtc8822b1ant_action_bt_inquiry(btcoexist); + } else { + halbtc8822b1ant_action_wifi_multi_port(btcoexist); + } + return; + } + + if (coex_sta->c2h_bt_inquiry_page) { + halbtc8822b1ant_action_bt_inquiry(btcoexist); + return; + } else if (bt_hs_on) { + halbtc8822b1ant_action_hs(btcoexist); + return; + } + + /* tdma and coex table */ + if (coex_dm->bt_status == BT_8822B_1ANT_BT_STATUS_ACL_BUSY) { + if (bt_link_info->a2dp_exist) { + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 32); + halbtc8822b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + } else if (bt_link_info->a2dp_exist && + bt_link_info->pan_exist) { + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 22); + halbtc8822b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + } else { + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 20); + halbtc8822b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + } + } else if ((coex_dm->bt_status == BT_8822B_1ANT_BT_STATUS_SCO_BUSY) || + (BT_8822B_1ANT_BT_STATUS_ACL_SCO_BUSY == + coex_dm->bt_status)) { + halbtc8822b1ant_action_bt_sco_hid_only_busy(btcoexist); + } else { + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + + halbtc8822b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + NORMAL_EXEC, + BT_8822B_1ANT_PHASE_2G_RUNTIME); + + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 6); + } +} + +/*""""wl connected specific packet"""" + bt action*/ + +static void halbtc8822b1ant_action_wifi_connected_specific_packet( + struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + bool bt_hs_on = false; + u32 wifi_link_status = 0; + u32 num_of_wifi_link = 0; + bool bt_ctrl_agg_buf_size = false; + u8 agg_buf_size = 5; + bool wifi_busy = false; + + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** (wifi connect specific packet) **********\n"); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, + &wifi_link_status); + + num_of_wifi_link = wifi_link_status >> 16; + + if (num_of_wifi_link >= 2) { + halbtc8822b1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + halbtc8822b1ant_limited_rx(btcoexist, NORMAL_EXEC, false, + bt_ctrl_agg_buf_size, agg_buf_size); + + if (coex_sta->c2h_bt_inquiry_page) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "############# [BTCoex], BT Is Inquirying\n"); + halbtc8822b1ant_action_bt_inquiry(btcoexist); + } else { + halbtc8822b1ant_action_wifi_multi_port(btcoexist); + } + return; + } + + if (coex_sta->c2h_bt_inquiry_page) { + halbtc8822b1ant_action_bt_inquiry(btcoexist); + return; + } else if (bt_hs_on) { + halbtc8822b1ant_action_hs(btcoexist); + return; + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + /* no specific packet process for both WiFi and BT very busy */ + if ((wifi_busy) && + ((bt_link_info->pan_exist) || (coex_sta->num_of_profile >= 2))) + return; + + /* tdma and coex table */ + if ((bt_link_info->sco_exist) || (bt_link_info->hid_exist)) { + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 32); + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 5); + } else if (bt_link_info->a2dp_exist) { + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 32); + /*for a2dp glitch,change from 1 to 15*/ + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 15); + } else if (bt_link_info->pan_exist) { + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + } else { + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + + halbtc8822b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + NORMAL_EXEC, + BT_8822B_1ANT_PHASE_2G_RUNTIME); + + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 5); + } +} + +/* wifi connected input point: + * to set different ps and tdma case (+bt different case) + */ + +static void halbtc8822b1ant_action_wifi_connected(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + bool wifi_busy = false, rf4ce_enabled = false; + bool scan = false, link = false, roam = false; + bool under_4way = false, ap_enable = false, wifi_under_5g = false; + u8 wifi_rssi_state; + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], CoexForWifiConnect()===>\n"); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + + if (wifi_under_5g) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], CoexForWifiConnect(), return for wifi is under 5g<===\n"); + + halbtc8822b1ant_action_wifi_under5g(btcoexist); + + return; + } + + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], CoexForWifiConnect(), return for wifi is under 2g<===\n"); + + halbtc8822b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, NORMAL_EXEC, + BT_8822B_1ANT_PHASE_2G_RUNTIME); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, + &under_4way); + + if (under_4way) { + halbtc8822b1ant_action_wifi_connected_specific_packet( + btcoexist); + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], CoexForWifiConnect(), return for wifi is under 4way<===\n"); + return; + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + if (scan || link || roam) { + if (scan) + halbtc8822b1ant_action_wifi_connected_scan(btcoexist); + else + halbtc8822b1ant_action_wifi_connected_specific_packet( + btcoexist); + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], CoexForWifiConnect(), return for wifi is under scan<===\n"); + return; + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, + &ap_enable); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + /* tdma and coex table */ + if (!wifi_busy) { + if (coex_dm->bt_status == BT_8822B_1ANT_BT_STATUS_ACL_BUSY) { + halbtc8822b1ant_action_wifi_connected_bt_acl_busy( + btcoexist); + } else if ((BT_8822B_1ANT_BT_STATUS_SCO_BUSY == + coex_dm->bt_status) || + (BT_8822B_1ANT_BT_STATUS_ACL_SCO_BUSY == + coex_dm->bt_status)) { + halbtc8822b1ant_action_bt_sco_hid_only_busy(btcoexist); + } else { + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 8); + + halbtc8822b1ant_set_ant_path( + btcoexist, BTC_ANT_PATH_AUTO, NORMAL_EXEC, + BT_8822B_1ANT_PHASE_2G_RUNTIME); + + if ((coex_sta->high_priority_tx) + + (coex_sta->high_priority_rx) <= + 60) + /*sy modify case16 -> case17*/ + halbtc8822b1ant_coex_table_with_type( + btcoexist, NORMAL_EXEC, 1); + else + halbtc8822b1ant_coex_table_with_type( + btcoexist, NORMAL_EXEC, 1); + } + } else { + if (coex_dm->bt_status == BT_8822B_1ANT_BT_STATUS_ACL_BUSY) { + halbtc8822b1ant_action_wifi_connected_bt_acl_busy( + btcoexist); + } else if ((BT_8822B_1ANT_BT_STATUS_SCO_BUSY == + coex_dm->bt_status) || + (BT_8822B_1ANT_BT_STATUS_ACL_SCO_BUSY == + coex_dm->bt_status)) { + halbtc8822b1ant_action_bt_sco_hid_only_busy(btcoexist); + } else { + if (rf4ce_enabled) { + btcoexist->btc_write_1byte_bitmask( + btcoexist, 0x45e, 0x8, 0x1); + + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 50); + + halbtc8822b1ant_coex_table_with_type( + btcoexist, NORMAL_EXEC, 1); + return; + } + + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 8); + + halbtc8822b1ant_set_ant_path( + btcoexist, BTC_ANT_PATH_AUTO, NORMAL_EXEC, + BT_8822B_1ANT_PHASE_2G_RUNTIME); + + wifi_rssi_state = halbtc8822b1ant_wifi_rssi_state( + btcoexist, 1, 2, 25, 0); + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** before **********\n"); + if (BT_8822B_1ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) { + if (rf4ce_enabled) { + btcoexist->btc_write_1byte_bitmask( + btcoexist, 0x45e, 0x8, 0x1); + + halbtc8822b1ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 50); + + halbtc8822b1ant_coex_table_with_type( + btcoexist, NORMAL_EXEC, 1); + return; + } + + halbtc8822b1ant_coex_table_with_type( + btcoexist, NORMAL_EXEC, 1); + } else { + halbtc8822b1ant_coex_table_with_type( + btcoexist, NORMAL_EXEC, 1); + } + } + } +} + +static void +halbtc8822b1ant_run_sw_coexist_mechanism(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + u8 algorithm = 0; + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** (run sw coexmech) **********\n"); + algorithm = halbtc8822b1ant_action_algorithm(btcoexist); + coex_dm->cur_algorithm = algorithm; + + if (halbtc8822b1ant_is_common_action(btcoexist)) { + } else { + switch (coex_dm->cur_algorithm) { + case BT_8822B_1ANT_COEX_ALGO_SCO: + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Action algorithm = SCO.\n"); + break; + case BT_8822B_1ANT_COEX_ALGO_HID: + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Action algorithm = HID.\n"); + break; + case BT_8822B_1ANT_COEX_ALGO_A2DP: + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Action algorithm = A2DP.\n"); + break; + case BT_8822B_1ANT_COEX_ALGO_A2DP_PANHS: + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Action algorithm = A2DP+PAN(HS).\n"); + break; + case BT_8822B_1ANT_COEX_ALGO_PANEDR: + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Action algorithm = PAN(EDR).\n"); + break; + case BT_8822B_1ANT_COEX_ALGO_PANHS: + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Action algorithm = HS mode.\n"); + break; + case BT_8822B_1ANT_COEX_ALGO_PANEDR_A2DP: + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Action algorithm = PAN+A2DP.\n"); + break; + case BT_8822B_1ANT_COEX_ALGO_PANEDR_HID: + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Action algorithm = PAN(EDR)+HID.\n"); + break; + case BT_8822B_1ANT_COEX_ALGO_HID_A2DP_PANEDR: + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Action algorithm = HID+A2DP+PAN.\n"); + break; + case BT_8822B_1ANT_COEX_ALGO_HID_A2DP: + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Action algorithm = HID+A2DP.\n"); + break; + default: + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Action algorithm = coexist All Off!!\n"); + break; + } + coex_dm->pre_algorithm = coex_dm->cur_algorithm; + } +} + +static void halbtc8822b1ant_run_coexist_mechanism(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + bool wifi_connected = false, bt_hs_on = false; + bool increase_scan_dev_num = false; + bool bt_ctrl_agg_buf_size = false; + bool miracast_plus_bt = false; + u8 agg_buf_size = 5; + u32 wifi_link_status = 0; + u32 num_of_wifi_link = 0, wifi_bw; + u8 iot_peer = BTC_IOT_PEER_UNKNOWN; + bool wifi_under_5g = false; + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], RunCoexistMechanism()===>\n"); + + if (btcoexist->manual_control) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], RunCoexistMechanism(), return for Manual CTRL <===\n"); + return; + } + + if (btcoexist->stop_coex_dm) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], RunCoexistMechanism(), return for Stop Coex DM <===\n"); + return; + } + + if (coex_sta->under_ips) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], wifi is under IPS !!!\n"); + return; + } + + if ((coex_sta->under_lps) && + (coex_dm->bt_status != BT_8822B_1ANT_BT_STATUS_ACL_BUSY)) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], RunCoexistMechanism(), wifi is under LPS !!!\n"); + halbtc8822b1ant_action_wifi_native_lps(btcoexist); + return; + } + + if (!coex_sta->run_time_state) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], return for run_time_state = false !!!\n"); + return; + } + + if (coex_sta->freeze_coexrun_by_btinfo) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BtInfoNotify(), return for freeze_coexrun_by_btinfo\n"); + return; + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + if (wifi_under_5g) { + halbtc8822b1ant_action_wifi_under5g(btcoexist); + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], WiFi is under 5G!!!\n"); + return; + } + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], WiFi is under 2G!!!\n"); + + halbtc8822b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, NORMAL_EXEC, + BT_8822B_1ANT_PHASE_2G_RUNTIME); + + if (coex_sta->bt_whck_test) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BT is under WHCK TEST!!!\n"); + halbtc8822b1ant_action_bt_whck_test(btcoexist); + return; + } + + if (coex_sta->bt_disabled) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BT is disabled !!!\n"); + halbtc8822b1ant_action_wifi_only(btcoexist); + return; + } + + if (coex_sta->is_setup_link) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BT is re-link !!!\n"); + halbtc8822b1ant_action_bt_relink(btcoexist); + return; + } + + if ((coex_dm->bt_status == BT_8822B_1ANT_BT_STATUS_ACL_BUSY) || + (coex_dm->bt_status == BT_8822B_1ANT_BT_STATUS_SCO_BUSY) || + (coex_dm->bt_status == BT_8822B_1ANT_BT_STATUS_ACL_SCO_BUSY)) + increase_scan_dev_num = true; + + btcoexist->btc_set(btcoexist, BTC_SET_BL_INC_SCAN_DEV_NUM, + &increase_scan_dev_num); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, + &wifi_link_status); + num_of_wifi_link = wifi_link_status >> 16; + + if ((num_of_wifi_link >= 2) || + (wifi_link_status & WIFI_P2P_GO_CONNECTED)) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "############# [BTCoex], Multi-Port num_of_wifi_link = %d, wifi_link_status = 0x%x\n", + num_of_wifi_link, wifi_link_status); + + if (bt_link_info->bt_link_exist) { + halbtc8822b1ant_limited_tx(btcoexist, NORMAL_EXEC, 1, 1, + 0, 1); + miracast_plus_bt = true; + } else { + halbtc8822b1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, + 0, 0); + miracast_plus_bt = false; + } + btcoexist->btc_set(btcoexist, BTC_SET_BL_MIRACAST_PLUS_BT, + &miracast_plus_bt); + halbtc8822b1ant_limited_rx(btcoexist, NORMAL_EXEC, false, + bt_ctrl_agg_buf_size, agg_buf_size); + + if ((bt_link_info->a2dp_exist) && + (coex_sta->c2h_bt_inquiry_page)) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "############# [BTCoex], BT Is Inquirying\n"); + halbtc8822b1ant_action_bt_inquiry(btcoexist); + } else { + halbtc8822b1ant_action_wifi_multi_port(btcoexist); + } + + return; + } + + miracast_plus_bt = false; + btcoexist->btc_set(btcoexist, BTC_SET_BL_MIRACAST_PLUS_BT, + &miracast_plus_bt); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + if ((bt_link_info->bt_link_exist) && (wifi_connected)) { + halbtc8822b1ant_limited_tx(btcoexist, NORMAL_EXEC, 1, 1, 0, 1); + + btcoexist->btc_get(btcoexist, BTC_GET_U1_IOT_PEER, &iot_peer); + + if (iot_peer != BTC_IOT_PEER_CISCO) { + if (bt_link_info->sco_exist) + halbtc8822b1ant_limited_rx(btcoexist, + NORMAL_EXEC, true, + false, 0x5); + else + halbtc8822b1ant_limited_rx(btcoexist, + NORMAL_EXEC, false, + false, 0x5); + } else { + if (bt_link_info->sco_exist) { + halbtc8822b1ant_limited_rx(btcoexist, + NORMAL_EXEC, true, + false, 0x5); + } else { + if (wifi_bw == BTC_WIFI_BW_HT40) + halbtc8822b1ant_limited_rx( + btcoexist, NORMAL_EXEC, false, + true, 0x10); + else + halbtc8822b1ant_limited_rx( + btcoexist, NORMAL_EXEC, false, + true, 0x8); + } + } + + halbtc8822b1ant_sw_mechanism(btcoexist, true); + halbtc8822b1ant_run_sw_coexist_mechanism( + btcoexist); /* just print debug message */ + } else { + halbtc8822b1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + + halbtc8822b1ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, + 0x5); + + halbtc8822b1ant_sw_mechanism(btcoexist, false); + halbtc8822b1ant_run_sw_coexist_mechanism( + btcoexist); /* just print debug message */ + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + if (coex_sta->c2h_bt_inquiry_page) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "############# [BTCoex], BT Is Inquirying\n"); + halbtc8822b1ant_action_bt_inquiry(btcoexist); + return; + } else if (bt_hs_on) { + halbtc8822b1ant_action_hs(btcoexist); + return; + } + + if (!wifi_connected) { + bool scan = false, link = false, roam = false; + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], wifi is non connected-idle !!!\n"); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + + if (scan) + halbtc8822b1ant_action_wifi_not_connected_scan( + btcoexist); + else if (link || roam) + halbtc8822b1ant_action_wifi_not_connected_asso_auth( + btcoexist); + else + halbtc8822b1ant_action_wifi_not_connected(btcoexist); + } else { /* wifi LPS/Busy */ + halbtc8822b1ant_action_wifi_connected(btcoexist); + } +} + +static void halbtc8822b1ant_init_coex_dm(struct btc_coexist *btcoexist) +{ + /* force to reset coex mechanism */ + + halbtc8822b1ant_low_penalty_ra(btcoexist, NORMAL_EXEC, false); + + /* sw all off */ + halbtc8822b1ant_sw_mechanism(btcoexist, false); + + coex_sta->pop_event_cnt = 0; +} + +static void halbtc8822b1ant_init_hw_config(struct btc_coexist *btcoexist, + bool back_up, bool wifi_only) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + u8 u8tmp = 0, i = 0; + u32 u32tmp1 = 0, u32tmp2 = 0, u32tmp3 = 0; + + u32tmp3 = btcoexist->btc_read_4byte(btcoexist, 0xcb4); + u32tmp1 = halbtc8822b1ant_ltecoex_indirect_read_reg(btcoexist, 0x38); + u32tmp2 = halbtc8822b1ant_ltecoex_indirect_read_reg(btcoexist, 0x54); + + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** (Before Init HW config) 0xcb4 = 0x%x, 0x38= 0x%x, 0x54= 0x%x**********\n", + u32tmp3, u32tmp1, u32tmp2); + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], 1Ant Init HW Config!!\n"); + + coex_sta->bt_coex_supported_feature = 0; + coex_sta->bt_coex_supported_version = 0; + coex_sta->bt_ble_scan_type = 0; + coex_sta->bt_ble_scan_para[0] = 0; + coex_sta->bt_ble_scan_para[1] = 0; + coex_sta->bt_ble_scan_para[2] = 0; + coex_sta->bt_reg_vendor_ac = 0xffff; + coex_sta->bt_reg_vendor_ae = 0xffff; + coex_sta->isolation_btween_wb = BT_8822B_1ANT_DEFAULT_ISOLATION; + coex_sta->gnt_error_cnt = 0; + coex_sta->bt_relink_downcount = 0; + coex_sta->is_set_ps_state_fail = false; + coex_sta->cnt_set_ps_state_fail = 0; + + for (i = 0; i <= 9; i++) + coex_sta->bt_afh_map[i] = 0; + + /* Setup RF front end type */ + halbtc8822b1ant_set_rfe_type(btcoexist); + + /* 0xf0[15:12] --> Chip Cut information */ + coex_sta->cut_version = + (btcoexist->btc_read_1byte(btcoexist, 0xf1) & 0xf0) >> 4; + + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x550, 0x8, + 0x1); /* enable TBTT nterrupt */ + + /* BT report packet sample rate */ + /* 0x790[5:0]=0x5 */ + u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x790); + u8tmp &= 0xc0; + u8tmp |= 0x5; + btcoexist->btc_write_1byte(btcoexist, 0x790, u8tmp); + + /* Enable BT counter statistics */ + btcoexist->btc_write_1byte(btcoexist, 0x778, 0x1); + + /* Enable PTA (3-wire function form BT side) */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x40, 0x20, 0x1); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x41, 0x02, 0x1); + + /* Enable PTA (tx/rx signal form WiFi side) */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4c6, 0x10, 0x1); + /*GNT_BT=1 while select both */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x763, 0x10, 0x1); + + /* enable GNT_WL */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4e, 0x40, 0x0); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x1, 0x0); + + if (btcoexist->btc_read_1byte(btcoexist, 0x80) == 0xc6) + halbtc8822b1ant_post_state_to_bt( + btcoexist, BT_8822B_1ANT_SCOREBOARD_ONOFF, true); + + /* Antenna config */ + if (coex_sta->is_rf_state_off) { + halbtc8822b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8822B_1ANT_PHASE_WLAN_OFF); + + btcoexist->stop_coex_dm = true; + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** %s (RF Off)**********\n", + __func__); + } else if (wifi_only) { + coex_sta->concurrent_rx_mode_on = false; + halbtc8822b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_WIFI, + FORCE_EXEC, + BT_8822B_1ANT_PHASE_WLANONLY_INIT); + } else { + coex_sta->concurrent_rx_mode_on = true; + + halbtc8822b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8822B_1ANT_PHASE_COEX_INIT); + } + + /* PTA parameter */ + halbtc8822b1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0); + + halbtc8822b1ant_enable_gnt_to_gpio(btcoexist, true); +} + +void ex_btc8822b1ant_power_on_setting(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct btc_board_info *board_info = &btcoexist->board_info; + u8 u8tmp = 0x0; + u16 u16tmp = 0x0; + + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "xxxxxxxxxxxxxxxx Execute 8822b 1-Ant PowerOn Setting!! xxxxxxxxxxxxxxxx\n"); + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "Ant Det Finish = %s, Ant Det Number = %d\n", + board_info->btdm_ant_det_finish ? "Yes" : "No", + board_info->btdm_ant_num_by_ant_det); + + btcoexist->dbg_mode_1ant = false; + btcoexist->stop_coex_dm = true; + + /* enable BB, REG_SYS_FUNC_EN such that we can write 0x948 correctly. */ + u16tmp = btcoexist->btc_read_2byte(btcoexist, 0x2); + btcoexist->btc_write_2byte(btcoexist, 0x2, u16tmp | BIT(0) | BIT(1)); + + /* set Path control owner to WiFi */ + halbtc8822b1ant_ltecoex_pathcontrol_owner(btcoexist, + BT_8822B_1ANT_PCO_WLSIDE); + + /* set GNT_BT to high */ + halbtc8822b1ant_ltecoex_set_gnt_bt(btcoexist, + BT_8822B_1ANT_GNT_BLOCK_RFC_BB, + BT_8822B_1ANT_GNT_CTRL_BY_SW, + BT_8822B_1ANT_SIG_STA_SET_TO_HIGH); + /* Set GNT_WL to low */ + halbtc8822b1ant_ltecoex_set_gnt_wl( + btcoexist, BT_8822B_1ANT_GNT_BLOCK_RFC_BB, + BT_8822B_1ANT_GNT_CTRL_BY_SW, BT_8822B_1ANT_SIG_STA_SET_TO_LOW); + + /* set WLAN_ACT = 0 */ + /* btcoexist->btc_write_1byte(btcoexist, 0x76e, 0x4); */ + + /* SD1 Chunchu red x issue */ + btcoexist->btc_write_1byte(btcoexist, 0xff1a, 0x0); + + halbtc8822b1ant_enable_gnt_to_gpio(btcoexist, true); + + /* */ + /* S0 or S1 setting and Local register setting + * (By the setting fw can get ant number, S0/S1, ... info) + */ + /* Local setting bit define */ + /* BIT0: "0" for no antenna inverse; "1" for antenna inverse */ + /* BIT1: "0" for internal switch; "1" for external switch */ + /* BIT2: "0" for one antenna; "1" for two antenna */ + /* NOTE: here default all internal switch and 1-antenna ==> + * BIT1=0 and BIT2=0 + */ + + u8tmp = 0; + board_info->btdm_ant_pos = BTC_ANTENNA_AT_MAIN_PORT; + + if (btcoexist->chip_interface == BTC_INTF_USB) + btcoexist->btc_write_local_reg_1byte(btcoexist, 0xfe08, u8tmp); + else if (btcoexist->chip_interface == BTC_INTF_SDIO) + btcoexist->btc_write_local_reg_1byte(btcoexist, 0x60, u8tmp); +} + +void ex_btc8822b1ant_pre_load_firmware(struct btc_coexist *btcoexist) {} + +void ex_btc8822b1ant_init_hw_config(struct btc_coexist *btcoexist, + bool wifi_only) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** (ini hw config) **********\n"); + + halbtc8822b1ant_init_hw_config(btcoexist, true, wifi_only); + btcoexist->stop_coex_dm = false; + btcoexist->auto_report_1ant = true; +} + +void ex_btc8822b1ant_init_coex_dm(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Coex Mechanism Init!!\n"); + + btcoexist->stop_coex_dm = false; + + halbtc8822b1ant_init_coex_dm(btcoexist); + + halbtc8822b1ant_query_bt_info(btcoexist); +} + +void ex_btc8822b1ant_display_coex_info(struct btc_coexist *btcoexist, + struct seq_file *m) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + u8 u8tmp[4], i, ps_tdma_case = 0; + u16 u16tmp[4]; + u32 u32tmp[4]; + u32 fa_ofdm, fa_cck, cca_ofdm, cca_cck; + u32 fw_ver = 0, bt_patch_ver = 0, bt_coex_ver = 0; + static u8 pop_report_in_10s; + u32 phyver = 0; + bool lte_coex_on = false; + static u8 cnt; + + seq_puts(m, "\r\n ============[BT Coexist info]============"); + + if (btcoexist->manual_control) { + seq_puts(m, + "\r\n ============[Under Manual Control]============"); + seq_puts(m, "\r\n =========================================="); + } + if (btcoexist->stop_coex_dm) { + seq_puts(m, "\r\n ============[Coex is STOPPED]============"); + seq_puts(m, "\r\n =========================================="); + } + + if (!coex_sta->bt_disabled) { + if (coex_sta->bt_coex_supported_feature == 0) + btcoexist->btc_get( + btcoexist, BTC_GET_U4_SUPPORTED_FEATURE, + &coex_sta->bt_coex_supported_feature); + + if ((coex_sta->bt_coex_supported_version == 0) || + (coex_sta->bt_coex_supported_version == 0xffff)) + btcoexist->btc_get( + btcoexist, BTC_GET_U4_SUPPORTED_VERSION, + &coex_sta->bt_coex_supported_version); + + if (coex_sta->bt_reg_vendor_ac == 0xffff) + coex_sta->bt_reg_vendor_ac = (u16)( + btcoexist->btc_get_bt_reg(btcoexist, 3, 0xac) & + 0xffff); + + if (coex_sta->bt_reg_vendor_ae == 0xffff) + coex_sta->bt_reg_vendor_ae = (u16)( + btcoexist->btc_get_bt_reg(btcoexist, 3, 0xae) & + 0xffff); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER, + &bt_patch_ver); + btcoexist->bt_info.bt_get_fw_ver = bt_patch_ver; + + if (coex_sta->num_of_profile > 0) { + cnt++; + + if (cnt >= 3) { + btcoexist->btc_get_bt_afh_map_from_bt( + btcoexist, 0, &coex_sta->bt_afh_map[0]); + cnt = 0; + } + } + } + + if (psd_scan->ant_det_try_count == 0) { + seq_printf( + m, "\r\n %-35s = %d/ %d/ %s / %d", + "Ant PG Num/ Mech/ Pos/ RFE", board_info->pg_ant_num, + board_info->btdm_ant_num, + (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT ? + "Main" : + "Aux"), + rfe_type->rfe_module_type); + } else { + seq_printf( + m, "\r\n %-35s = %d/ %d/ %s/ %d (%d/%d/%d)", + "Ant PG Num/ Mech(Ant_Det)/ Pos/ RFE", + board_info->pg_ant_num, + board_info->btdm_ant_num_by_ant_det, + (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT ? + "Main" : + "Aux"), + rfe_type->rfe_module_type, psd_scan->ant_det_try_count, + psd_scan->ant_det_fail_count, psd_scan->ant_det_result); + + if (board_info->btdm_ant_det_finish) { + if (psd_scan->ant_det_result != 12) + seq_printf(m, "\r\n %-35s = %s", + "Ant Det PSD Value", + psd_scan->ant_det_peak_val); + else + seq_printf(m, "\r\n %-35s = %d", + "Ant Det PSD Value", + psd_scan->ant_det_psd_scan_peak_val / + 100); + } + } + + bt_patch_ver = btcoexist->bt_info.bt_get_fw_ver; + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver); + phyver = btcoexist->btc_get_bt_phydm_version(btcoexist); + + bt_coex_ver = ((coex_sta->bt_coex_supported_version & 0xff00) >> 8); + + seq_printf( + m, "\r\n %-35s = %d_%02x/ 0x%02x/ 0x%02x (%s)", + "CoexVer WL/ BT_Desired/ BT_Report", + glcoex_ver_date_8822b_1ant, glcoex_ver_8822b_1ant, + glcoex_ver_btdesired_8822b_1ant, bt_coex_ver, + (bt_coex_ver == 0xff ? + "Unknown" : + (coex_sta->bt_disabled ? "BT-disable" : + (bt_coex_ver >= glcoex_ver_btdesired_8822b_1ant ? + "Match" : + "Mis-Match")))); + + seq_printf(m, "\r\n %-35s = 0x%x/ 0x%x/ v%d/ %c", "W_FW/ B_FW/ Phy/ Kt", + fw_ver, bt_patch_ver, phyver, coex_sta->cut_version + 65); + + seq_printf(m, "\r\n %-35s = %02x %02x %02x ", "AFH Map to BT", + coex_dm->wifi_chnl_info[0], coex_dm->wifi_chnl_info[1], + coex_dm->wifi_chnl_info[2]); + + /* wifi status */ + seq_printf(m, "\r\n %-35s", "============[Wifi Status]============"); + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_WIFI_STATUS, m); + + seq_printf(m, "\r\n %-35s", "============[BT Status]============"); + + pop_report_in_10s++; + seq_printf( + m, "\r\n %-35s = [%s/ %d dBm/ %d/ %d] ", + "BT [status/ rssi/ retryCnt/ popCnt]", + ((coex_sta->bt_disabled) ? + ("disabled") : + ((coex_sta->c2h_bt_inquiry_page) ? ("inquiry/page") : + ((BT_8822B_1ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) ? + "non-connected idle" : + ((coex_dm->bt_status == + BT_8822B_1ANT_BT_STATUS_CONNECTED_IDLE) ? + "connected-idle" : + "busy")))), + coex_sta->bt_rssi - 100, coex_sta->bt_retry_cnt, + coex_sta->pop_event_cnt); + + if (pop_report_in_10s >= 5) { + coex_sta->pop_event_cnt = 0; + pop_report_in_10s = 0; + } + + if (coex_sta->num_of_profile != 0) + seq_printf( + m, "\r\n %-35s = %s%s%s%s%s", "Profiles", + ((bt_link_info->a2dp_exist) ? + ((coex_sta->is_bt_a2dp_sink) ? "A2DP sink," : + "A2DP,") : + ""), + ((bt_link_info->sco_exist) ? "HFP," : ""), + ((bt_link_info->hid_exist) ? + ((coex_sta->hid_busy_num >= 2) ? + "HID(4/18)," : + "HID(2/18),") : + ""), + ((bt_link_info->pan_exist) ? "PAN," : ""), + ((coex_sta->voice_over_HOGP) ? "Voice" : "")); + else + seq_printf(m, "\r\n %-35s = None", "Profiles"); + + if (bt_link_info->a2dp_exist) { + seq_printf(m, "\r\n %-35s = %s/ %d/ %s", + "A2DP Rate/Bitpool/Auto_Slot", + ((coex_sta->is_A2DP_3M) ? "3M" : "No_3M"), + coex_sta->a2dp_bit_pool, + ((coex_sta->is_autoslot) ? "On" : "Off")); + } + + if (bt_link_info->hid_exist) { + seq_printf(m, "\r\n %-35s = %d/ %d", "HID PairNum/Forbid_Slot", + coex_sta->hid_pair_cnt, coex_sta->forbidden_slot); + } + + seq_printf(m, "\r\n %-35s = %s/ %d/ %s/ 0x%x", + "Role/RoleSwCnt/IgnWlact/Feature", + ((bt_link_info->slave_role) ? "Slave" : "Master"), + coex_sta->cnt_role_switch, + ((coex_dm->cur_ignore_wlan_act) ? "Yes" : "No"), + coex_sta->bt_coex_supported_feature); + + if ((coex_sta->bt_ble_scan_type & 0x7) != 0x0) { + seq_printf(m, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", + "BLEScan Type/TV/Init/Ble", + coex_sta->bt_ble_scan_type, + (coex_sta->bt_ble_scan_type & 0x1 ? + coex_sta->bt_ble_scan_para[0] : + 0x0), + (coex_sta->bt_ble_scan_type & 0x2 ? + coex_sta->bt_ble_scan_para[1] : + 0x0), + (coex_sta->bt_ble_scan_type & 0x4 ? + coex_sta->bt_ble_scan_para[2] : + 0x0)); + } + + seq_printf(m, "\r\n %-35s = %d/ %d/ %d/ %d/ %d", + "ReInit/ReLink/IgnWlact/Page/NameReq", coex_sta->cnt_reinit, + coex_sta->cnt_setup_link, coex_sta->cnt_ign_wlan_act, + coex_sta->cnt_page, coex_sta->cnt_remote_name_req); + + halbtc8822b1ant_read_score_board(btcoexist, &u16tmp[0]); + + if ((coex_sta->bt_reg_vendor_ae == 0xffff) || + (coex_sta->bt_reg_vendor_ac == 0xffff)) + seq_printf(m, "\r\n %-35s = x/ x/ %04x", + "0xae[4]/0xac[1:0]/Scoreboard", u16tmp[0]); + else + seq_printf(m, "\r\n %-35s = 0x%x/ 0x%x/ %04x", + "0xae[4]/0xac[1:0]/Scoreboard", + (int)((coex_sta->bt_reg_vendor_ae & BIT(4)) >> 4), + coex_sta->bt_reg_vendor_ac & 0x3, u16tmp[0]); + + if (coex_sta->num_of_profile > 0) { + seq_printf( + m, + "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", + "AFH MAP", coex_sta->bt_afh_map[0], + coex_sta->bt_afh_map[1], coex_sta->bt_afh_map[2], + coex_sta->bt_afh_map[3], coex_sta->bt_afh_map[4], + coex_sta->bt_afh_map[5], coex_sta->bt_afh_map[6], + coex_sta->bt_afh_map[7], coex_sta->bt_afh_map[8], + coex_sta->bt_afh_map[9]); + } + + for (i = 0; i < BT_INFO_SRC_8822B_1ANT_MAX; i++) { + if (coex_sta->bt_info_c2h_cnt[i]) { + seq_printf( + m, + "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x(%d)", + glbt_info_src_8822b_1ant[i], + coex_sta->bt_info_c2h[i][0], + coex_sta->bt_info_c2h[i][1], + coex_sta->bt_info_c2h[i][2], + coex_sta->bt_info_c2h[i][3], + coex_sta->bt_info_c2h[i][4], + coex_sta->bt_info_c2h[i][5], + coex_sta->bt_info_c2h[i][6], + coex_sta->bt_info_c2h_cnt[i]); + } + } + + if (btcoexist->manual_control) + seq_printf( + m, "\r\n %-35s", + "============[mechanisms] (before Manual)============"); + else + seq_printf(m, "\r\n %-35s", + "============[Mechanisms]============"); + + ps_tdma_case = coex_dm->cur_ps_tdma; + seq_printf(m, "\r\n %-35s = %02x %02x %02x %02x %02x (case-%d, %s)", + "TDMA", coex_dm->ps_tdma_para[0], coex_dm->ps_tdma_para[1], + coex_dm->ps_tdma_para[2], coex_dm->ps_tdma_para[3], + coex_dm->ps_tdma_para[4], ps_tdma_case, + (coex_dm->cur_ps_tdma_on ? "TDMA On" : "TDMA Off")); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6c0); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x6c4); + u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x6c8); + seq_printf(m, "\r\n %-35s = %d/ 0x%x/ 0x%x/ 0x%x", + "Table/0x6c0/0x6c4/0x6c8", coex_sta->coex_table_type, + u32tmp[0], u32tmp[1], u32tmp[2]); + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778); + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6cc); + seq_printf(m, "\r\n %-35s = 0x%x/ 0x%x", "0x778/0x6cc", u8tmp[0], + u32tmp[0]); + + seq_printf(m, "\r\n %-35s = %s/ %s/ %s/ %d", + "AntDiv/BtCtrlLPS/LPRA/PsFail", + ((board_info->ant_div_cfg) ? "On" : "Off"), + ((coex_sta->force_lps_ctrl) ? "On" : "Off"), + ((coex_dm->cur_low_penalty_ra) ? "On" : "Off"), + coex_sta->cnt_set_ps_state_fail); + + u32tmp[0] = halbtc8822b1ant_ltecoex_indirect_read_reg(btcoexist, 0x38); + lte_coex_on = ((u32tmp[0] & BIT(7)) >> 7) ? true : false; + + if (lte_coex_on) { + u32tmp[0] = halbtc8822b1ant_ltecoex_indirect_read_reg(btcoexist, + 0xa0); + u32tmp[1] = halbtc8822b1ant_ltecoex_indirect_read_reg(btcoexist, + 0xa4); + + seq_printf(m, "\r\n %-35s = 0x%x/ 0x%x", + "LTE Coex Table W_L/B_L", u32tmp[0] & 0xffff, + u32tmp[1] & 0xffff); + + u32tmp[0] = halbtc8822b1ant_ltecoex_indirect_read_reg(btcoexist, + 0xa8); + u32tmp[1] = halbtc8822b1ant_ltecoex_indirect_read_reg(btcoexist, + 0xac); + u32tmp[2] = halbtc8822b1ant_ltecoex_indirect_read_reg(btcoexist, + 0xb0); + u32tmp[3] = halbtc8822b1ant_ltecoex_indirect_read_reg(btcoexist, + 0xb4); + + seq_printf(m, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", + "LTE Break Table W_L/B_L/L_W/L_B", + u32tmp[0] & 0xffff, u32tmp[1] & 0xffff, + u32tmp[2] & 0xffff, u32tmp[3] & 0xffff); + } + + /* Hw setting */ + seq_printf(m, "\r\n %-35s", "============[Hw setting]============"); + + u32tmp[0] = halbtc8822b1ant_ltecoex_indirect_read_reg(btcoexist, 0x38); + u32tmp[1] = halbtc8822b1ant_ltecoex_indirect_read_reg(btcoexist, 0x54); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x73); + + seq_printf(m, "\r\n %-35s = %s/ %s", "LTE Coex/Path Owner", + ((lte_coex_on) ? "On" : "Off"), + ((u8tmp[0] & BIT(2)) ? "WL" : "BT")); + + if (lte_coex_on) { + seq_printf(m, "\r\n %-35s = %d/ %d/ %d/ %d", + "LTE 3Wire/OPMode/UART/UARTMode", + (int)((u32tmp[0] & BIT(6)) >> 6), + (int)((u32tmp[0] & (BIT(5) | BIT(4))) >> 4), + (int)((u32tmp[0] & BIT(3)) >> 3), + (int)(u32tmp[0] & (BIT(2) | BIT(1) | BIT(0)))); + + seq_printf(m, "\r\n %-35s = %d/ %d", "LTE_Busy/UART_Busy", + (int)((u32tmp[1] & BIT(1)) >> 1), + (int)(u32tmp[1] & BIT(0))); + } + seq_printf(m, "\r\n %-35s = %s (BB:%s)/ %s (BB:%s)/ %s %d", + "GNT_WL_Ctrl/GNT_BT_Ctrl/Dbg", + ((u32tmp[0] & BIT(12)) ? "SW" : "HW"), + ((u32tmp[0] & BIT(8)) ? "SW" : "HW"), + ((u32tmp[0] & BIT(14)) ? "SW" : "HW"), + ((u32tmp[0] & BIT(10)) ? "SW" : "HW"), + ((u8tmp[0] & BIT(3)) ? "On" : "Off"), + coex_sta->gnt_error_cnt); + + seq_printf(m, "\r\n %-35s = %d/ %d", "GNT_WL/GNT_BT", + (int)((u32tmp[1] & BIT(2)) >> 2), + (int)((u32tmp[1] & BIT(3)) >> 3)); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xcb0); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0xcb4); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0xcba); + + seq_printf(m, "\r\n %-35s = 0x%04x/ 0x%04x/ 0x%02x %s", + "0xcb0/0xcb4/0xcb8[23:16]", u32tmp[0], u32tmp[1], u8tmp[0], + ((u8tmp[0] & 0x1) == 0x1 ? "(BTG)" : "(WL_A+G)")); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x4c); + u8tmp[2] = btcoexist->btc_read_1byte(btcoexist, 0x64); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x4c6); + u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x40); + + seq_printf(m, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", + "4c[24:23]/64[0]/4c6[4]/40[5]", + (int)((u32tmp[0] & (BIT(24) | BIT(23))) >> 23), + u8tmp[2] & 0x1, (int)((u8tmp[0] & BIT(4)) >> 4), + (int)((u8tmp[1] & BIT(5)) >> 5)); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522); + u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x953); + u8tmp[2] = btcoexist->btc_read_1byte(btcoexist, 0xc50); + + seq_printf(m, "\r\n %-35s = 0x%x/ 0x%x/ %s/ 0x%x", + "0x550/0x522/4-RxAGC/0xc50", u32tmp[0], u8tmp[0], + (u8tmp[1] & 0x2) ? "On" : "Off", u8tmp[2]); + + fa_ofdm = btcoexist->btc_phydm_query_phy_counter(btcoexist, + "PHYDM_INFO_FA_OFDM"); + fa_cck = btcoexist->btc_phydm_query_phy_counter(btcoexist, + "PHYDM_INFO_FA_CCK"); + cca_ofdm = btcoexist->btc_phydm_query_phy_counter( + btcoexist, "PHYDM_INFO_CCA_OFDM"); + cca_cck = btcoexist->btc_phydm_query_phy_counter(btcoexist, + "PHYDM_INFO_CCA_CCK"); + + seq_printf(m, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", + "CCK-CCA/CCK-FA/OFDM-CCA/OFDM-FA", cca_cck, fa_cck, cca_ofdm, + fa_ofdm); + + seq_printf(m, "\r\n %-35s = %d/ %d/ %d/ %d", "CRC_OK CCK/11g/11n/11ac", + coex_sta->crc_ok_cck, coex_sta->crc_ok_11g, + coex_sta->crc_ok_11n, coex_sta->crc_ok_11n_vht); + + seq_printf(m, "\r\n %-35s = %d/ %d/ %d/ %d", "CRC_Err CCK/11g/11n/11ac", + coex_sta->crc_err_cck, coex_sta->crc_err_11g, + coex_sta->crc_err_11n, coex_sta->crc_err_11n_vht); + + seq_printf(m, "\r\n %-35s = %s/ %s/ %s/ %d", + "WlHiPri/ Locking/ Locked/ Noisy", + (coex_sta->wifi_is_high_pri_task ? "Yes" : "No"), + (coex_sta->cck_lock ? "Yes" : "No"), + (coex_sta->cck_ever_lock ? "Yes" : "No"), + coex_sta->wl_noisy_level); + + seq_printf(m, "\r\n %-35s = %d/ %d", "0x770(Hi-pri rx/tx)", + coex_sta->high_priority_rx, coex_sta->high_priority_tx); + + seq_printf(m, "\r\n %-35s = %d/ %d %s", "0x774(Lo-pri rx/tx)", + coex_sta->low_priority_rx, coex_sta->low_priority_tx, + (bt_link_info->slave_role ? + "(Slave!!)" : + (coex_sta->is_tdma_btautoslot_hang ? + "(auto-slot hang!!)" : + ""))); + + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_COEX_STATISTICS, m); +} + +void ex_btc8822b1ant_ips_notify(struct btc_coexist *btcoexist, u8 type) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + + if (btcoexist->manual_control || btcoexist->stop_coex_dm) + return; + + if (type == BTC_IPS_ENTER) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], IPS ENTER notify\n"); + coex_sta->under_ips = true; + + /* Write WL "Active" in Score-board for LPS off */ + halbtc8822b1ant_post_state_to_bt( + btcoexist, BT_8822B_1ANT_SCOREBOARD_ACTIVE, false); + + halbtc8822b1ant_post_state_to_bt( + btcoexist, BT_8822B_1ANT_SCOREBOARD_ONOFF, false); + + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + + halbtc8822b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8822B_1ANT_PHASE_WLAN_OFF); + + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + } else if (type == BTC_IPS_LEAVE) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], IPS LEAVE notify\n"); + halbtc8822b1ant_post_state_to_bt( + btcoexist, BT_8822B_1ANT_SCOREBOARD_ACTIVE, true); + + halbtc8822b1ant_post_state_to_bt( + btcoexist, BT_8822B_1ANT_SCOREBOARD_ONOFF, true); + + /*leave IPS : run ini hw config (exclude wifi only)*/ + halbtc8822b1ant_init_hw_config(btcoexist, false, false); + /*sw all off*/ + halbtc8822b1ant_init_coex_dm(btcoexist); + /*leave IPS : Query bt info*/ + halbtc8822b1ant_query_bt_info(btcoexist); + + coex_sta->under_ips = false; + } +} + +void ex_btc8822b1ant_lps_notify(struct btc_coexist *btcoexist, u8 type) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + static bool pre_force_lps_on; + + if (btcoexist->manual_control || btcoexist->stop_coex_dm) + return; + + if (type == BTC_LPS_ENABLE) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], LPS ENABLE notify\n"); + coex_sta->under_lps = true; + + if (coex_sta->force_lps_ctrl) { /* LPS No-32K */ + /* Write WL "Active" in Score-board for PS-TDMA */ + pre_force_lps_on = true; + halbtc8822b1ant_post_state_to_bt( + btcoexist, BT_8822B_1ANT_SCOREBOARD_ACTIVE, + true); + } else { + /* LPS-32K, need check if this h2c 0x71 can work?? + * (2015/08/28) + */ + /* Write WL "Non-Active" in Score-board for Native-PS */ + pre_force_lps_on = false; + halbtc8822b1ant_post_state_to_bt( + btcoexist, BT_8822B_1ANT_SCOREBOARD_ACTIVE, + false); + } + } else if (type == BTC_LPS_DISABLE) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], LPS DISABLE notify\n"); + coex_sta->under_lps = false; + + /* Write WL "Active" in Score-board for LPS off */ + halbtc8822b1ant_post_state_to_bt( + btcoexist, BT_8822B_1ANT_SCOREBOARD_ACTIVE, true); + + if ((!pre_force_lps_on) && (!coex_sta->force_lps_ctrl)) + halbtc8822b1ant_query_bt_info(btcoexist); + } +} + +void ex_btc8822b1ant_scan_notify(struct btc_coexist *btcoexist, u8 type) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + bool wifi_connected = false; + bool wifi_under_5g = false; + + if (btcoexist->manual_control || btcoexist->stop_coex_dm) + return; + + coex_sta->freeze_coexrun_by_btinfo = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + if (wifi_connected) + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** WL connected before SCAN\n"); + else + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** WL is not connected before SCAN\n"); + + halbtc8822b1ant_query_bt_info(btcoexist); + + /*2.4 g 1*/ + if (type == BTC_SCAN_START) { + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, + &wifi_under_5g); + /*5 g 1*/ + + if (wifi_under_5g) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** (scan_notify_5g_scan_start) **********\n"); + halbtc8822b1ant_action_wifi_under5g(btcoexist); + return; + } + + /* 2.4G.2.3*/ + coex_sta->wifi_is_high_pri_task = true; + + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** (scan_notify_2g_scan_start) **********\n"); + + if (!wifi_connected) { /* non-connected scan */ + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** wifi is not connected scan **********\n"); + halbtc8822b1ant_action_wifi_not_connected_scan( + btcoexist); + } else { /* wifi is connected */ + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** wifi is connected scan **********\n"); + halbtc8822b1ant_action_wifi_connected_scan(btcoexist); + } + + return; + } + + if (type == BTC_SCAN_START_2G) { + coex_sta->wifi_is_high_pri_task = true; + + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** (scan_notify_2g_sacn_start_for_switch_band_used) **********\n"); + + if (!wifi_connected) { /* non-connected scan */ + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** wifi is not connected **********\n"); + + halbtc8822b1ant_action_wifi_not_connected_scan( + btcoexist); + } else { /* wifi is connected */ + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** wifi is connected **********\n"); + halbtc8822b1ant_action_wifi_connected_scan(btcoexist); + } + } else { + coex_sta->wifi_is_high_pri_task = false; + + /* 2.4G 5 WL scan finish, then get and update sacn ap numbers */ + /*5 g 4*/ + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, + &coex_sta->scan_ap_num); + + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** (scan_finish_notify) **********\n"); + + if (!wifi_connected) { /* non-connected scan */ + halbtc8822b1ant_action_wifi_not_connected(btcoexist); + } else { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** scan_finish_notify wifi is connected **********\n"); + halbtc8822b1ant_action_wifi_connected(btcoexist); + } + } +} + +void ex_btc8822b1ant_scan_notify_without_bt(struct btc_coexist *btcoexist, + u8 type) +{ + bool wifi_under_5g = false; + + if (type == BTC_SCAN_START) { + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, + &wifi_under_5g); + + if (wifi_under_5g) { + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcbd, + 0x3, 1); + return; + } + + /* under 2.4G */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcbd, 0x3, 2); + return; + } + if (type == BTC_SCAN_START_2G) + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcbd, 0x3, 2); +} + +void ex_btc8822b1ant_switchband_notify(struct btc_coexist *btcoexist, u8 type) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** (switchband_notify) **********\n"); + + if (btcoexist->manual_control || btcoexist->stop_coex_dm) + return; + + coex_sta->switch_band_notify_to = type; + /*2.4g 4.*/ /*5 g 2*/ + if (type == BTC_SWITCH_TO_5G) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** (switchband_notify BTC_SWITCH_TO_5G) **********\n"); + + halbtc8822b1ant_action_wifi_under5g(btcoexist); + return; + } else if (type == BTC_SWITCH_TO_24G_NOFORSCAN) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** (switchband_notify BTC_SWITCH_TO_2G (no for scan)) **********\n"); + + halbtc8822b1ant_run_coexist_mechanism(btcoexist); + /*5 g 3*/ + + } else { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** (switchband_notify BTC_SWITCH_TO_2G) **********\n"); + + ex_btc8822b1ant_scan_notify(btcoexist, BTC_SCAN_START_2G); + } + coex_sta->switch_band_notify_to = BTC_NOT_SWITCH; +} + +void ex_btc8822b1ant_switchband_notify_without_bt(struct btc_coexist *btcoexist, + u8 type) +{ + bool wifi_under_5g = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + + if (type == BTC_SWITCH_TO_5G) { + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcbd, 0x3, 1); + return; + } else if (type == BTC_SWITCH_TO_24G_NOFORSCAN) { + if (wifi_under_5g) + + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcbd, + 0x3, 1); + + else + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcbd, + 0x3, 2); + } else { + ex_btc8822b1ant_scan_notify_without_bt(btcoexist, + BTC_SCAN_START_2G); + } +} + +void ex_btc8822b1ant_connect_notify(struct btc_coexist *btcoexist, u8 type) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + bool wifi_connected = false; + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** (connect notify) **********\n"); + + halbtc8822b1ant_post_state_to_bt(btcoexist, + BT_8822B_1ANT_SCOREBOARD_SCAN, true); + + if (btcoexist->manual_control || btcoexist->stop_coex_dm) + return; + + if ((type == BTC_ASSOCIATE_5G_START) || + (type == BTC_ASSOCIATE_5G_FINISH)) { + if (type == BTC_ASSOCIATE_5G_START) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** (5G associate start notify) **********\n"); + + halbtc8822b1ant_action_wifi_under5g(btcoexist); + + } else if (type == BTC_ASSOCIATE_5G_FINISH) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** (5G associate finish notify) **********\n"); + } + + return; + } + + if (type == BTC_ASSOCIATE_START) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], 2G CONNECT START notify\n"); + + coex_sta->wifi_is_high_pri_task = true; + + halbtc8822b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8822B_1ANT_PHASE_2G_RUNTIME); + + coex_dm->arp_cnt = 0; + + halbtc8822b1ant_action_wifi_not_connected_asso_auth(btcoexist); + + coex_sta->freeze_coexrun_by_btinfo = true; + + } else { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], 2G CONNECT Finish notify\n"); + coex_sta->wifi_is_high_pri_task = false; + coex_sta->freeze_coexrun_by_btinfo = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + if (!wifi_connected) /* non-connected scan */ + halbtc8822b1ant_action_wifi_not_connected(btcoexist); + else + halbtc8822b1ant_action_wifi_connected(btcoexist); + } +} + +void ex_btc8822b1ant_media_status_notify(struct btc_coexist *btcoexist, u8 type) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + bool wifi_under_b_mode = false; + bool wifi_under_5g = false; + + if (btcoexist->manual_control || btcoexist->stop_coex_dm) + return; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + + if (type == BTC_MEDIA_CONNECT) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], 2g media connect notify"); + + halbtc8822b1ant_post_state_to_bt( + btcoexist, BT_8822B_1ANT_SCOREBOARD_ACTIVE, true); + + if (wifi_under_5g) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], 5g media notify\n"); + + halbtc8822b1ant_action_wifi_under5g(btcoexist); + return; + } + /* Force antenna setup for no scan result issue */ + halbtc8822b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8822B_1ANT_PHASE_2G_RUNTIME); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_B_MODE, + &wifi_under_b_mode); + + /* Set CCK Tx/Rx high Pri except 11b mode */ + if (wifi_under_b_mode) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** (media status notity under b mode) **********\n"); + btcoexist->btc_write_1byte(btcoexist, 0x6cd, + 0x00); /* CCK Tx */ + btcoexist->btc_write_1byte(btcoexist, 0x6cf, + 0x00); /* CCK Rx */ + } else { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** (media status notity not under b mode) **********\n"); + btcoexist->btc_write_1byte(btcoexist, 0x6cd, + 0x00); /* CCK Tx */ + btcoexist->btc_write_1byte(btcoexist, 0x6cf, + 0x10); /* CCK Rx */ + } + + coex_dm->backup_arfr_cnt1 = + btcoexist->btc_read_4byte(btcoexist, 0x430); + coex_dm->backup_arfr_cnt2 = + btcoexist->btc_read_4byte(btcoexist, 0x434); + coex_dm->backup_retry_limit = + btcoexist->btc_read_2byte(btcoexist, 0x42a); + coex_dm->backup_ampdu_max_time = + btcoexist->btc_read_1byte(btcoexist, 0x456); + } else { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], 2g media disconnect notify\n"); + coex_dm->arp_cnt = 0; + + halbtc8822b1ant_post_state_to_bt( + btcoexist, BT_8822B_1ANT_SCOREBOARD_ACTIVE, false); + + btcoexist->btc_write_1byte(btcoexist, 0x6cd, 0x0); /* CCK Tx */ + btcoexist->btc_write_1byte(btcoexist, 0x6cf, 0x0); /* CCK Rx */ + + coex_sta->cck_ever_lock = false; + } + + halbtc8822b1ant_update_wifi_ch_info(btcoexist, type); +} + +void ex_btc8822b1ant_specific_packet_notify(struct btc_coexist *btcoexist, + u8 type) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + bool under_4way = false, wifi_under_5g = false; + + if (btcoexist->manual_control || btcoexist->stop_coex_dm) + return; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + if (wifi_under_5g) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], 5g special packet notify\n"); + + halbtc8822b1ant_action_wifi_under5g(btcoexist); + return; + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, + &under_4way); + + if (under_4way) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], specific Packet ---- under_4way!!\n"); + + coex_sta->wifi_is_high_pri_task = true; + coex_sta->specific_pkt_period_cnt = 2; + } else if (type == BTC_PACKET_ARP) { + coex_dm->arp_cnt++; + + if (coex_sta->wifi_is_high_pri_task) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], specific Packet ARP notify -cnt = %d\n", + coex_dm->arp_cnt); + } + + } else { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], specific Packet DHCP or EAPOL notify [Type = %d]\n", + type); + + coex_sta->wifi_is_high_pri_task = true; + coex_sta->specific_pkt_period_cnt = 2; + } + + if (coex_sta->wifi_is_high_pri_task) + halbtc8822b1ant_action_wifi_connected_specific_packet( + btcoexist); +} + +void ex_btc8822b1ant_bt_info_notify(struct btc_coexist *btcoexist, u8 *tmp_buf, + u8 length) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + u8 i, rsp_source = 0; + bool wifi_connected = false; + bool wifi_scan = false, wifi_link = false, wifi_roam = false, + wifi_busy = false; + static bool is_scoreboard_scan; + + if (psd_scan->is_ant_det_running) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], bt_info_notify return for AntDet is running\n"); + return; + } + + rsp_source = tmp_buf[0] & 0xf; + if (rsp_source >= BT_INFO_SRC_8822B_1ANT_MAX) + rsp_source = BT_INFO_SRC_8822B_1ANT_WIFI_FW; + coex_sta->bt_info_c2h_cnt[rsp_source]++; + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Bt_info[%d], len=%d, data=[", rsp_source, length); + + for (i = 0; i < length; i++) { + coex_sta->bt_info_c2h[rsp_source][i] = tmp_buf[i]; + + if (i == length - 1) { + /* last one */ + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "0x%02x]\n", tmp_buf[i]); + } else { + /* normal */ + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "0x%02x, ", + tmp_buf[i]); + } + } + + coex_sta->bt_info = coex_sta->bt_info_c2h[rsp_source][1]; + coex_sta->bt_info_ext = coex_sta->bt_info_c2h[rsp_source][4]; + coex_sta->bt_info_ext2 = coex_sta->bt_info_c2h[rsp_source][5]; + + if (rsp_source != BT_INFO_SRC_8822B_1ANT_WIFI_FW) { + /* if 0xff, it means BT is under WHCK test */ + coex_sta->bt_whck_test = + ((coex_sta->bt_info == 0xff) ? true : false); + + coex_sta->bt_create_connection = + ((coex_sta->bt_info_c2h[rsp_source][2] & 0x80) ? true : + false); + + /* unit: %, value-100 to translate to unit: dBm */ + coex_sta->bt_rssi = + coex_sta->bt_info_c2h[rsp_source][3] * 2 + 10; + + coex_sta->c2h_bt_remote_name_req = + ((coex_sta->bt_info_c2h[rsp_source][2] & 0x20) ? true : + false); + + coex_sta->is_A2DP_3M = + ((coex_sta->bt_info_c2h[rsp_source][2] & 0x10) ? true : + false); + + coex_sta->acl_busy = + ((coex_sta->bt_info_c2h[rsp_source][1] & 0x9) ? true : + false); + + coex_sta->voice_over_HOGP = + ((coex_sta->bt_info_ext & 0x10) ? true : false); + + coex_sta->c2h_bt_inquiry_page = + ((coex_sta->bt_info & BT_INFO_8822B_1ANT_B_INQ_PAGE) ? + true : + false); + + coex_sta->a2dp_bit_pool = + (((coex_sta->bt_info_c2h[rsp_source][1] & 0x49) == + 0x49) ? + (coex_sta->bt_info_c2h[rsp_source][6] & 0x7f) : + 0); + + coex_sta->is_bt_a2dp_sink = + (coex_sta->bt_info_c2h[rsp_source][6] & 0x80) ? true : + false; + + coex_sta->bt_retry_cnt = + coex_sta->bt_info_c2h[rsp_source][2] & 0xf; + + coex_sta->is_autoslot = coex_sta->bt_info_ext2 & 0x8; + + coex_sta->forbidden_slot = coex_sta->bt_info_ext2 & 0x7; + + coex_sta->hid_busy_num = (coex_sta->bt_info_ext2 & 0x30) >> 4; + + coex_sta->hid_pair_cnt = (coex_sta->bt_info_ext2 & 0xc0) >> 6; + if (coex_sta->bt_retry_cnt >= 1) + coex_sta->pop_event_cnt++; + + if (coex_sta->c2h_bt_remote_name_req) + coex_sta->cnt_remote_name_req++; + + if (coex_sta->bt_info_ext & BIT(1)) + coex_sta->cnt_reinit++; + + if (coex_sta->bt_info_ext & BIT(2)) { + coex_sta->cnt_setup_link++; + coex_sta->is_setup_link = true; + coex_sta->bt_relink_downcount = 2; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Re-Link start in BT info!!\n"); + } else { + coex_sta->is_setup_link = false; + coex_sta->bt_relink_downcount = 0; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Re-Link stop in BT info!!\n"); + } + + if (coex_sta->bt_info_ext & BIT(3)) + coex_sta->cnt_ign_wlan_act++; + + if (coex_sta->bt_info_ext & BIT(6)) + coex_sta->cnt_role_switch++; + + if (coex_sta->bt_info_ext & BIT(7)) + coex_sta->is_bt_multi_link = true; + else + coex_sta->is_bt_multi_link = false; + + if (coex_sta->bt_create_connection) { + coex_sta->cnt_page++; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, + &wifi_busy); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, + &wifi_scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, + &wifi_link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, + &wifi_roam); + + if ((wifi_link) || (wifi_roam) || (wifi_scan) || + (coex_sta->wifi_is_high_pri_task) || (wifi_busy)) { + is_scoreboard_scan = true; + halbtc8822b1ant_post_state_to_bt( + btcoexist, + BT_8822B_1ANT_SCOREBOARD_SCAN, true); + + } else { + halbtc8822b1ant_post_state_to_bt( + btcoexist, + BT_8822B_1ANT_SCOREBOARD_SCAN, false); + } + } else { + if (is_scoreboard_scan) { + halbtc8822b1ant_post_state_to_bt( + btcoexist, + BT_8822B_1ANT_SCOREBOARD_SCAN, false); + is_scoreboard_scan = false; + } + } + + /* Here we need to resend some wifi info to BT */ + /* because bt is reset and loss of the info. */ + + if ((!btcoexist->manual_control) && + (!btcoexist->stop_coex_dm)) { + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + /* Re-Init */ + if ((coex_sta->bt_info_ext & BIT(1))) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BT ext info bit1 check, send wifi BW&Chnl to BT!!\n"); + if (wifi_connected) + halbtc8822b1ant_update_wifi_ch_info( + btcoexist, BTC_MEDIA_CONNECT); + else + halbtc8822b1ant_update_wifi_ch_info( + btcoexist, + BTC_MEDIA_DISCONNECT); + } + + /* If Ignore_WLanAct && not SetUp_Link */ + if ((coex_sta->bt_info_ext & BIT(3)) && + (!(coex_sta->bt_info_ext & BIT(2)))) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BT ext info bit3 check, set BT NOT to ignore Wlan active!!\n"); + halbtc8822b1ant_ignore_wlan_act( + btcoexist, FORCE_EXEC, false); + } + } + } + + if ((coex_sta->bt_info_ext & BIT(5))) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BT ext info bit4 check, query BLE Scan type!!\n"); + coex_sta->bt_ble_scan_type = + btcoexist->btc_get_ble_scan_type_from_bt(btcoexist); + + if ((coex_sta->bt_ble_scan_type & 0x1) == 0x1) + coex_sta->bt_ble_scan_para[0] = + btcoexist->btc_get_ble_scan_para_from_bt( + btcoexist, 0x1); + if ((coex_sta->bt_ble_scan_type & 0x2) == 0x2) + coex_sta->bt_ble_scan_para[1] = + btcoexist->btc_get_ble_scan_para_from_bt( + btcoexist, 0x2); + if ((coex_sta->bt_ble_scan_type & 0x4) == 0x4) + coex_sta->bt_ble_scan_para[2] = + btcoexist->btc_get_ble_scan_para_from_bt( + btcoexist, 0x4); + } + + halbtc8822b1ant_update_bt_link_info(btcoexist); + + halbtc8822b1ant_run_coexist_mechanism(btcoexist); +} + +void ex_btc8822b1ant_rf_status_notify(struct btc_coexist *btcoexist, u8 type) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], RF Status notify\n"); + + if (type == BTC_RF_ON) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], RF is turned ON!!\n"); + btcoexist->stop_coex_dm = false; + + halbtc8822b1ant_post_state_to_bt( + btcoexist, BT_8822B_1ANT_SCOREBOARD_ACTIVE, true); + halbtc8822b1ant_post_state_to_bt( + btcoexist, BT_8822B_1ANT_SCOREBOARD_ONOFF, true); + + } else if (type == BTC_RF_OFF) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], RF is turned OFF!!\n"); + + halbtc8822b1ant_post_state_to_bt( + btcoexist, BT_8822B_1ANT_SCOREBOARD_ACTIVE, false); + halbtc8822b1ant_post_state_to_bt( + btcoexist, BT_8822B_1ANT_SCOREBOARD_ONOFF, false); + halbtc8822b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 0); + + halbtc8822b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8822B_1ANT_PHASE_WLAN_OFF); + /* for test : s3 bt disppear , fail rate 1/600*/ + + halbtc8822b1ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true); + + btcoexist->stop_coex_dm = true; + } +} + +void ex_btc8822b1ant_halt_notify(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], Halt notify\n"); + + halbtc8822b1ant_post_state_to_bt( + btcoexist, BT_8822B_1ANT_SCOREBOARD_ACTIVE, false); + halbtc8822b1ant_post_state_to_bt(btcoexist, + BT_8822B_1ANT_SCOREBOARD_ONOFF, false); + + halbtc8822b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 0); + + halbtc8822b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, FORCE_EXEC, + BT_8822B_1ANT_PHASE_WLAN_OFF); + /* for test : s3 bt disppear , fail rate 1/600*/ + + halbtc8822b1ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true); + + ex_btc8822b1ant_media_status_notify(btcoexist, BTC_MEDIA_DISCONNECT); + btcoexist->stop_coex_dm = true; +} + +void ex_btc8822b1ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + bool wifi_under_5g = false; + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], Pnp notify\n"); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + + if ((pnp_state == BTC_WIFI_PNP_SLEEP) || + (pnp_state == BTC_WIFI_PNP_SLEEP_KEEP_ANT)) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Pnp notify to SLEEP\n"); + + halbtc8822b1ant_post_state_to_bt( + btcoexist, BT_8822B_1ANT_SCOREBOARD_ACTIVE | + BT_8822B_1ANT_SCOREBOARD_ONOFF | + BT_8822B_1ANT_SCOREBOARD_SCAN | + BT_8822B_1ANT_SCOREBOARD_UNDERTEST, + false); + + if (pnp_state == BTC_WIFI_PNP_SLEEP_KEEP_ANT) { + if (wifi_under_5g) + halbtc8822b1ant_set_ant_path( + btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8822B_1ANT_PHASE_5G_RUNTIME); + else + halbtc8822b1ant_set_ant_path( + btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8822B_1ANT_PHASE_2G_RUNTIME); + } else { + halbtc8822b1ant_set_ant_path( + btcoexist, BTC_ANT_PATH_AUTO, FORCE_EXEC, + BT_8822B_1ANT_PHASE_WLAN_OFF); + } + + btcoexist->stop_coex_dm = true; + } else if (pnp_state == BTC_WIFI_PNP_WAKE_UP) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Pnp notify to WAKE UP\n"); + btcoexist->stop_coex_dm = false; + } +} + +void ex_btc8822b1ant_coex_dm_reset(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], *****************Coex DM Reset*****************\n"); + + halbtc8822b1ant_init_hw_config(btcoexist, false, false); + halbtc8822b1ant_init_coex_dm(btcoexist); +} + +void ex_btc8822b1ant_periodical(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + bool bt_relink_finish = false; + + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ==========================Periodical===========================\n"); + + if (!btcoexist->auto_report_1ant) + halbtc8822b1ant_query_bt_info(btcoexist); + + halbtc8822b1ant_monitor_bt_ctr(btcoexist); + halbtc8822b1ant_monitor_wifi_ctr(btcoexist); + + halbtc8822b1ant_monitor_bt_enable_disable(btcoexist); + + if (coex_sta->bt_relink_downcount != 0) { + coex_sta->bt_relink_downcount--; + + if (coex_sta->bt_relink_downcount == 0) { + coex_sta->is_setup_link = false; + bt_relink_finish = true; + } + } + + /* for 4-way, DHCP, EAPOL packet */ + if (coex_sta->specific_pkt_period_cnt > 0) { + coex_sta->specific_pkt_period_cnt--; + + if ((coex_sta->specific_pkt_period_cnt == 0) && + (coex_sta->wifi_is_high_pri_task)) + coex_sta->wifi_is_high_pri_task = false; + + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ***************** Hi-Pri Task = %s*****************\n", + (coex_sta->wifi_is_high_pri_task ? "Yes" : "No")); + } + + if (halbtc8822b1ant_is_wifi_status_changed(btcoexist) || + (bt_relink_finish) || (coex_sta->is_set_ps_state_fail)) + halbtc8822b1ant_run_coexist_mechanism(btcoexist); +} + +void ex_btc8822b1ant_antenna_detection(struct btc_coexist *btcoexist, + u32 cent_freq, u32 offset, u32 span, + u32 seconds) +{ +} + +void ex_btc8822b1ant_antenna_isolation(struct btc_coexist *btcoexist, + u32 cent_freq, u32 offset, u32 span, + u32 seconds) +{ +} + +void ex_btc8822b1ant_psd_scan(struct btc_coexist *btcoexist, u32 cent_freq, + u32 offset, u32 span, u32 seconds) +{ +} + +void ex_btc8822b1ant_display_ant_detection(struct btc_coexist *btcoexist) {} + +void ex_btc8822b1ant_dbg_control(struct btc_coexist *btcoexist, u8 op_code, + u8 op_len, u8 *pdata) +{ +} diff --git a/drivers/staging/rtlwifi/btcoexist/halbtc8822b1ant.h b/drivers/staging/rtlwifi/btcoexist/halbtc8822b1ant.h new file mode 100644 index 000000000000..583e99dc5cc9 --- /dev/null +++ b/drivers/staging/rtlwifi/btcoexist/halbtc8822b1ant.h @@ -0,0 +1,444 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +/* ******************************************* + * The following is for 8822B 1ANT BT Co-exist definition + * ********************************************/ +#define BT_INFO_8822B_1ANT_B_FTP BIT(7) +#define BT_INFO_8822B_1ANT_B_A2DP BIT(6) +#define BT_INFO_8822B_1ANT_B_HID BIT(5) +#define BT_INFO_8822B_1ANT_B_SCO_BUSY BIT(4) +#define BT_INFO_8822B_1ANT_B_ACL_BUSY BIT(3) +#define BT_INFO_8822B_1ANT_B_INQ_PAGE BIT(2) +#define BT_INFO_8822B_1ANT_B_SCO_ESCO BIT(1) +#define BT_INFO_8822B_1ANT_B_CONNECTION BIT(0) + +#define BT_INFO_8822B_1ANT_A2DP_BASIC_RATE(_BT_INFO_EXT_) \ + (((_BT_INFO_EXT_ & BIT(0))) ? true : false) + +#define BTC_RSSI_COEX_THRESH_TOL_8822B_1ANT 2 + +#define BT_8822B_1ANT_WIFI_NOISY_THRESH 150 /* max: 255 */ +#define BT_8822B_1ANT_DEFAULT_ISOLATION 15 /* unit: dB */ + +/* for Antenna detection */ +#define BT_8822B_1ANT_ANTDET_PSDTHRES_BACKGROUND 50 +#define BT_8822B_1ANT_ANTDET_PSDTHRES_2ANT_BADISOLATION 70 +#define BT_8822B_1ANT_ANTDET_PSDTHRES_2ANT_GOODISOLATION 55 +#define BT_8822B_1ANT_ANTDET_PSDTHRES_1ANT 35 +#define BT_8822B_1ANT_ANTDET_RETRY_INTERVAL \ + 10 /* retry timer if ant det is fail, unit: second */ +#define BT_8822B_1ANT_ANTDET_ENABLE 0 +#define BT_8822B_1ANT_ANTDET_COEXMECHANISMSWITCH_ENABLE 0 + +#define BT_8822B_1ANT_LTECOEX_INDIRECTREG_ACCESS_TIMEOUT 30000 + +enum bt_8822b_1ant_signal_state { + BT_8822B_1ANT_SIG_STA_SET_TO_LOW = 0x0, + BT_8822B_1ANT_SIG_STA_SET_BY_HW = 0x0, + BT_8822B_1ANT_SIG_STA_SET_TO_HIGH = 0x1, + BT_8822B_1ANT_SIG_STA_MAX +}; + +enum bt_8822b_1ant_path_ctrl_owner { + BT_8822B_1ANT_PCO_BTSIDE = 0x0, + BT_8822B_1ANT_PCO_WLSIDE = 0x1, + BT_8822B_1ANT_PCO_MAX +}; + +enum bt_8822b_1ant_gnt_ctrl_type { + BT_8822B_1ANT_GNT_CTRL_BY_PTA = 0x0, + BT_8822B_1ANT_GNT_CTRL_BY_SW = 0x1, + BT_8822B_1ANT_GNT_CTRL_MAX +}; + +enum bt_8822b_1ant_gnt_ctrl_block { + BT_8822B_1ANT_GNT_BLOCK_RFC_BB = 0x0, + BT_8822B_1ANT_GNT_BLOCK_RFC = 0x1, + BT_8822B_1ANT_GNT_BLOCK_BB = 0x2, + BT_8822B_1ANT_GNT_BLOCK_MAX +}; + +enum bt_8822b_1ant_lte_coex_table_type { + BT_8822B_1ANT_CTT_WL_VS_LTE = 0x0, + BT_8822B_1ANT_CTT_BT_VS_LTE = 0x1, + BT_8822B_1ANT_CTT_MAX +}; + +enum bt_8822b_1ant_lte_break_table_type { + BT_8822B_1ANT_LBTT_WL_BREAK_LTE = 0x0, + BT_8822B_1ANT_LBTT_BT_BREAK_LTE = 0x1, + BT_8822B_1ANT_LBTT_LTE_BREAK_WL = 0x2, + BT_8822B_1ANT_LBTT_LTE_BREAK_BT = 0x3, + BT_8822B_1ANT_LBTT_MAX +}; + +enum bt_info_src_8822b_1ant { + BT_INFO_SRC_8822B_1ANT_WIFI_FW = 0x0, + BT_INFO_SRC_8822B_1ANT_BT_RSP = 0x1, + BT_INFO_SRC_8822B_1ANT_BT_ACTIVE_SEND = 0x2, + BT_INFO_SRC_8822B_1ANT_MAX +}; + +enum bt_8822b_1ant_bt_status { + BT_8822B_1ANT_BT_STATUS_NON_CONNECTED_IDLE = 0x0, + BT_8822B_1ANT_BT_STATUS_CONNECTED_IDLE = 0x1, + BT_8822B_1ANT_BT_STATUS_INQ_PAGE = 0x2, + BT_8822B_1ANT_BT_STATUS_ACL_BUSY = 0x3, + BT_8822B_1ANT_BT_STATUS_SCO_BUSY = 0x4, + BT_8822B_1ANT_BT_STATUS_ACL_SCO_BUSY = 0x5, + BT_8822B_1ANT_BT_STATUS_MAX +}; + +enum bt_8822b_1ant_wifi_status { + BT_8822B_1ANT_WIFI_STATUS_NON_CONNECTED_IDLE = 0x0, + BT_8822B_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN = 0x1, + BT_8822B_1ANT_WIFI_STATUS_CONNECTED_SCAN = 0x2, + BT_8822B_1ANT_WIFI_STATUS_CONNECTED_SPECIFIC_PKT = 0x3, + BT_8822B_1ANT_WIFI_STATUS_CONNECTED_IDLE = 0x4, + BT_8822B_1ANT_WIFI_STATUS_CONNECTED_BUSY = 0x5, + BT_8822B_1ANT_WIFI_STATUS_MAX +}; + +enum bt_8822b_1ant_coex_algo { + BT_8822B_1ANT_COEX_ALGO_UNDEFINED = 0x0, + BT_8822B_1ANT_COEX_ALGO_SCO = 0x1, + BT_8822B_1ANT_COEX_ALGO_HID = 0x2, + BT_8822B_1ANT_COEX_ALGO_A2DP = 0x3, + BT_8822B_1ANT_COEX_ALGO_A2DP_PANHS = 0x4, + BT_8822B_1ANT_COEX_ALGO_PANEDR = 0x5, + BT_8822B_1ANT_COEX_ALGO_PANHS = 0x6, + BT_8822B_1ANT_COEX_ALGO_PANEDR_A2DP = 0x7, + BT_8822B_1ANT_COEX_ALGO_PANEDR_HID = 0x8, + BT_8822B_1ANT_COEX_ALGO_HID_A2DP_PANEDR = 0x9, + BT_8822B_1ANT_COEX_ALGO_HID_A2DP = 0xa, + BT_8822B_1ANT_COEX_ALGO_MAX = 0xb, +}; + +enum bt_8822b_1ant_ext_ant_switch_type { + BT_8822B_1ANT_EXT_ANT_SWITCH_USE_SPDT = 0x0, + BT_8822B_1ANT_EXT_ANT_SWITCH_USE_SP3T = 0x1, + BT_8822B_1ANT_EXT_ANT_SWITCH_MAX +}; + +enum bt_8822b_1ant_ext_ant_switch_ctrl_type { + BT_8822B_1ANT_EXT_ANT_SWITCH_CTRL_BY_BBSW = 0x0, + BT_8822B_1ANT_EXT_ANT_SWITCH_CTRL_BY_PTA = 0x1, + BT_8822B_1ANT_EXT_ANT_SWITCH_CTRL_BY_ANTDIV = 0x2, + BT_8822B_1ANT_EXT_ANT_SWITCH_CTRL_BY_MAC = 0x3, + BT_8822B_1ANT_EXT_ANT_SWITCH_CTRL_BY_BT = 0x4, + BT_8822B_1ANT_EXT_ANT_SWITCH_CTRL_MAX +}; + +enum bt_8822b_1ant_ext_ant_switch_pos_type { + BT_8822B_1ANT_EXT_ANT_SWITCH_TO_BT = 0x0, + BT_8822B_1ANT_EXT_ANT_SWITCH_TO_WLG = 0x1, + BT_8822B_1ANT_EXT_ANT_SWITCH_TO_WLA = 0x2, + BT_8822B_1ANT_EXT_ANT_SWITCH_TO_NOCARE = 0x3, + BT_8822B_1ANT_EXT_ANT_SWITCH_TO_MAX +}; + +enum bt_8822b_1ant_phase { + BT_8822B_1ANT_PHASE_COEX_INIT = 0x0, + BT_8822B_1ANT_PHASE_WLANONLY_INIT = 0x1, + BT_8822B_1ANT_PHASE_WLAN_OFF = 0x2, + BT_8822B_1ANT_PHASE_2G_RUNTIME = 0x3, + BT_8822B_1ANT_PHASE_5G_RUNTIME = 0x4, + BT_8822B_1ANT_PHASE_BTMPMODE = 0x5, + BT_8822B_1ANT_PHASE_MAX +}; + +/*ADD SCOREBOARD TO FIX BT LPS 32K ISSUE WHILE WL BUSY*/ +enum bt_8822b_1ant_scoreboard { + BT_8822B_1ANT_SCOREBOARD_ACTIVE = BIT(0), + BT_8822B_1ANT_SCOREBOARD_ONOFF = BIT(1), + BT_8822B_1ANT_SCOREBOARD_SCAN = BIT(2), + BT_8822B_1ANT_SCOREBOARD_UNDERTEST = BIT(3), + BT_8822B_1ANT_SCOREBOARD_WLBUSY = BIT(6) +}; + +struct coex_dm_8822b_1ant { + /* hw setting */ + u32 pre_ant_pos_type; + u32 cur_ant_pos_type; + /* fw mechanism */ + bool cur_ignore_wlan_act; + bool pre_ignore_wlan_act; + u8 pre_ps_tdma; + u8 cur_ps_tdma; + u8 ps_tdma_para[5]; + u8 ps_tdma_du_adj_type; + bool auto_tdma_adjust; + bool pre_ps_tdma_on; + bool cur_ps_tdma_on; + bool pre_bt_auto_report; + bool cur_bt_auto_report; + u8 pre_lps; + u8 cur_lps; + u8 pre_rpwm; + u8 cur_rpwm; + + /* sw mechanism */ + bool pre_low_penalty_ra; + bool cur_low_penalty_ra; + u32 pre_val0x6c0; + u32 cur_val0x6c0; + u32 pre_val0x6c4; + u32 cur_val0x6c4; + u32 pre_val0x6c8; + u32 cur_val0x6c8; + u8 pre_val0x6cc; + u8 cur_val0x6cc; + bool limited_dig; + + u32 backup_arfr_cnt1; /* Auto Rate Fallback Retry cnt */ + u32 backup_arfr_cnt2; /* Auto Rate Fallback Retry cnt */ + u16 backup_retry_limit; + u8 backup_ampdu_max_time; + + /* algorithm related */ + u8 pre_algorithm; + u8 cur_algorithm; + u8 bt_status; + u8 wifi_chnl_info[3]; + + u32 pre_ra_mask; + u32 cur_ra_mask; + u8 pre_arfr_type; + u8 cur_arfr_type; + u8 pre_retry_limit_type; + u8 cur_retry_limit_type; + u8 pre_ampdu_time_type; + u8 cur_ampdu_time_type; + u32 arp_cnt; + + u32 pre_ext_ant_switch_status; + u32 cur_ext_ant_switch_status; + + u8 error_condition; +}; + +struct coex_sta_8822b_1ant { + bool bt_disabled; + bool bt_link_exist; + bool sco_exist; + bool a2dp_exist; + bool hid_exist; + bool pan_exist; + u8 num_of_profile; + + bool under_lps; + bool under_ips; + u32 specific_pkt_period_cnt; + u32 high_priority_tx; + u32 high_priority_rx; + u32 low_priority_tx; + u32 low_priority_rx; + bool is_hi_pri_rx_overhead; + s8 bt_rssi; + u8 pre_bt_rssi_state; + u8 pre_wifi_rssi_state[4]; + u8 bt_info_c2h[BT_INFO_SRC_8822B_1ANT_MAX][10]; + u32 bt_info_c2h_cnt[BT_INFO_SRC_8822B_1ANT_MAX]; + bool bt_whck_test; + bool c2h_bt_inquiry_page; + bool c2h_bt_remote_name_req; + bool c2h_bt_page; /* Add for win8.1 page out issue */ + bool wifi_is_high_pri_task; /* Add for win8.1 page out issue */ + + u8 bt_info_ext; + u8 bt_info_ext2; + u32 pop_event_cnt; + u8 scan_ap_num; + u8 bt_retry_cnt; + + u32 crc_ok_cck; + u32 crc_ok_11g; + u32 crc_ok_11n; + u32 crc_ok_11n_vht; + + u32 crc_err_cck; + u32 crc_err_11g; + u32 crc_err_11n; + u32 crc_err_11n_vht; + + bool cck_lock; + bool pre_ccklock; + bool cck_ever_lock; + u8 coex_table_type; + + bool force_lps_ctrl; + + bool concurrent_rx_mode_on; + + u16 score_board; + u8 isolation_btween_wb; /* 0~ 50 */ + + u8 a2dp_bit_pool; + u8 cut_version; + bool acl_busy; + bool bt_create_connection; + + u32 bt_coex_supported_feature; + u32 bt_coex_supported_version; + + u8 bt_ble_scan_type; + u32 bt_ble_scan_para[3]; + + bool run_time_state; + bool freeze_coexrun_by_btinfo; + + bool is_A2DP_3M; + bool voice_over_HOGP; + u8 bt_info; + bool is_autoslot; + u8 forbidden_slot; + u8 hid_busy_num; + u8 hid_pair_cnt; + + u32 cnt_remote_name_req; + u32 cnt_setup_link; + u32 cnt_reinit; + u32 cnt_ign_wlan_act; + u32 cnt_page; + u32 cnt_role_switch; + + u16 bt_reg_vendor_ac; + u16 bt_reg_vendor_ae; + + bool is_setup_link; + u8 wl_noisy_level; + u32 gnt_error_cnt; + u8 bt_afh_map[10]; + u8 bt_relink_downcount; + bool is_tdma_btautoslot; + bool is_tdma_btautoslot_hang; + + u8 switch_band_notify_to; + bool is_rf_state_off; + + bool is_hid_low_pri_tx_overhead; + bool is_bt_multi_link; + bool is_bt_a2dp_sink; + bool rf4ce_enabled; + + bool is_set_ps_state_fail; + u8 cnt_set_ps_state_fail; +}; + +struct rfe_type_8822b_1ant { + u8 rfe_module_type; + bool ext_ant_switch_exist; + u8 ext_ant_switch_type; + /* iF 0: ANTSW(rfe_sel9)=0, ANTSWB(rfe_sel8)=1 => Ant to BT/5G */ + u8 ext_ant_switch_ctrl_polarity; +}; + +#define BT_8822B_1ANT_ANTDET_PSD_POINTS 256 /* MAX:1024 */ +#define BT_8822B_1ANT_ANTDET_PSD_AVGNUM 1 /* MAX:3 */ +#define BT_8822B_1ANT_ANTDET_BUF_LEN 16 + +struct psdscan_sta_8822b_1ant { + u32 ant_det_bt_le_channel; /* BT LE Channel ex:2412 */ + u32 ant_det_bt_tx_time; + u32 ant_det_pre_psdscan_peak_val; + bool ant_det_is_ant_det_available; + u32 ant_det_psd_scan_peak_val; + bool ant_det_is_btreply_available; + u32 ant_det_psd_scan_peak_freq; + + u8 ant_det_result; + u8 ant_det_peak_val[BT_8822B_1ANT_ANTDET_BUF_LEN]; + u8 ant_det_peak_freq[BT_8822B_1ANT_ANTDET_BUF_LEN]; + u32 ant_det_try_count; + u32 ant_det_fail_count; + u32 ant_det_inteval_count; + u32 ant_det_thres_offset; + + u32 real_cent_freq; + s32 real_offset; + u32 real_span; + + u32 psd_band_width; /* unit: Hz */ + u32 psd_point; /* 128/256/512/1024 */ + u32 psd_report[1024]; /* unit:dB (20logx), 0~255 */ + u32 psd_report_max_hold[1024]; /* unit:dB (20logx), 0~255 */ + u32 psd_start_point; + u32 psd_stop_point; + u32 psd_max_value_point; + u32 psd_max_value; + u32 psd_start_base; + u32 psd_avg_num; /* 1/8/16/32 */ + u32 psd_gen_count; + bool is_psd_running; + bool is_psd_show_max_only; + bool is_ant_det_running; +}; + +/* ******************************************* + * The following is interface which will notify coex module. + * ********************************************/ +void ex_btc8822b1ant_power_on_setting(struct btc_coexist *btcoexist); +void ex_btc8822b1ant_pre_load_firmware(struct btc_coexist *btcoexist); +void ex_btc8822b1ant_init_hw_config(struct btc_coexist *btcoexist, + bool wifi_only); +void ex_btc8822b1ant_init_coex_dm(struct btc_coexist *btcoexist); +void ex_btc8822b1ant_ips_notify(struct btc_coexist *btcoexist, u8 type); +void ex_btc8822b1ant_lps_notify(struct btc_coexist *btcoexist, u8 type); +void ex_btc8822b1ant_scan_notify(struct btc_coexist *btcoexist, u8 type); +void ex_btc8822b1ant_scan_notify_without_bt(struct btc_coexist *btcoexist, + u8 type); +void ex_btc8822b1ant_switchband_notify(struct btc_coexist *btcoexist, u8 type); +void ex_btc8822b1ant_switchband_notify_without_bt(struct btc_coexist *btcoexist, + u8 type); +void ex_btc8822b1ant_connect_notify(struct btc_coexist *btcoexist, u8 type); +void ex_btc8822b1ant_media_status_notify(struct btc_coexist *btcoexist, + u8 type); +void ex_btc8822b1ant_specific_packet_notify(struct btc_coexist *btcoexist, + u8 type); +void ex_btc8822b1ant_bt_info_notify(struct btc_coexist *btcoexist, u8 *tmp_buf, + u8 length); +void ex_btc8822b1ant_rf_status_notify(struct btc_coexist *btcoexist, u8 type); +void ex_btc8822b1ant_halt_notify(struct btc_coexist *btcoexist); +void ex_btc8822b1ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state); +void ex_halbtc8822b1ant_score_board_status_notify(struct btc_coexist *btcoexist, + u8 *tmp_buf, u8 length); +void ex_btc8822b1ant_coex_dm_reset(struct btc_coexist *btcoexist); +void ex_btc8822b1ant_periodical(struct btc_coexist *btcoexist); +void ex_btc8822b1ant_display_coex_info(struct btc_coexist *btcoexist, + struct seq_file *m); +void ex_btc8822b1ant_antenna_detection(struct btc_coexist *btcoexist, + u32 cent_freq, u32 offset, u32 span, + u32 seconds); +void ex_btc8822b1ant_antenna_isolation(struct btc_coexist *btcoexist, + u32 cent_freq, u32 offset, u32 span, + u32 seconds); + +void ex_btc8822b1ant_psd_scan(struct btc_coexist *btcoexist, u32 cent_freq, + u32 offset, u32 span, u32 seconds); +void ex_btc8822b1ant_display_ant_detection(struct btc_coexist *btcoexist); + +void ex_btc8822b1ant_dbg_control(struct btc_coexist *btcoexist, u8 op_code, + u8 op_len, u8 *pdata); diff --git a/drivers/staging/rtlwifi/btcoexist/halbtc8822b2ant.c b/drivers/staging/rtlwifi/btcoexist/halbtc8822b2ant.c new file mode 100644 index 000000000000..ffff5b062672 --- /dev/null +++ b/drivers/staging/rtlwifi/btcoexist/halbtc8822b2ant.c @@ -0,0 +1,5225 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +/* ************************************************************ + * Description: + * + * This file is for RTL8822B Co-exist mechanism + * + * History + * 2012/11/15 Cosa first check in. + * + * *************************************************************/ + +/* ************************************************************ + * include files + * *************************************************************/ +#include "halbt_precomp.h" + +/* ************************************************************ + * Global variables, these are static variables + * *************************************************************/ +static struct coex_dm_8822b_2ant glcoex_dm_8822b_2ant; +static struct coex_dm_8822b_2ant *coex_dm = &glcoex_dm_8822b_2ant; +static struct coex_sta_8822b_2ant glcoex_sta_8822b_2ant; +static struct coex_sta_8822b_2ant *coex_sta = &glcoex_sta_8822b_2ant; +static struct psdscan_sta_8822b_2ant gl_psd_scan_8822b_2ant; +static struct psdscan_sta_8822b_2ant *psd_scan = &gl_psd_scan_8822b_2ant; +static struct rfe_type_8822b_2ant gl_rfe_type_8822b_2ant; +static struct rfe_type_8822b_2ant *rfe_type = &gl_rfe_type_8822b_2ant; + +static const char *const glbt_info_src_8822b_2ant[] = { + "BT Info[wifi fw]", "BT Info[bt rsp]", "BT Info[bt auto report]", +}; + +static u32 glcoex_ver_date_8822b_2ant = 20170327; +static u32 glcoex_ver_8822b_2ant = 0x44; +static u32 glcoex_ver_btdesired_8822b_2ant = 0x42; + +/* ************************************************************ + * local function proto type if needed + * ************************************************************ + * ************************************************************ + * local function start with halbtc8822b2ant_ + * *************************************************************/ +static u8 halbtc8822b2ant_bt_rssi_state(struct btc_coexist *btcoexist, + u8 *ppre_bt_rssi_state, u8 level_num, + u8 rssi_thresh, u8 rssi_thresh1) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + s32 bt_rssi = 0; + u8 bt_rssi_state = *ppre_bt_rssi_state; + + bt_rssi = coex_sta->bt_rssi; + + if (level_num == 2) { + if ((*ppre_bt_rssi_state == BTC_RSSI_STATE_LOW) || + (*ppre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) { + if (bt_rssi >= + (rssi_thresh + BTC_RSSI_COEX_THRESH_TOL_8822B_2ANT)) + bt_rssi_state = BTC_RSSI_STATE_HIGH; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else { + if (bt_rssi < rssi_thresh) + bt_rssi_state = BTC_RSSI_STATE_LOW; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } else if (level_num == 3) { + if (rssi_thresh > rssi_thresh1) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BT Rssi thresh error!!\n"); + return *ppre_bt_rssi_state; + } + + if ((*ppre_bt_rssi_state == BTC_RSSI_STATE_LOW) || + (*ppre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) { + if (bt_rssi >= + (rssi_thresh + BTC_RSSI_COEX_THRESH_TOL_8822B_2ANT)) + bt_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else if ((*ppre_bt_rssi_state == BTC_RSSI_STATE_MEDIUM) || + (*ppre_bt_rssi_state == + BTC_RSSI_STATE_STAY_MEDIUM)) { + if (bt_rssi >= (rssi_thresh1 + + BTC_RSSI_COEX_THRESH_TOL_8822B_2ANT)) + bt_rssi_state = BTC_RSSI_STATE_HIGH; + else if (bt_rssi < rssi_thresh) + bt_rssi_state = BTC_RSSI_STATE_LOW; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM; + } else { + if (bt_rssi < rssi_thresh1) + bt_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } + + *ppre_bt_rssi_state = bt_rssi_state; + + return bt_rssi_state; +} + +static u8 halbtc8822b2ant_wifi_rssi_state(struct btc_coexist *btcoexist, + u8 *pprewifi_rssi_state, u8 level_num, + u8 rssi_thresh, u8 rssi_thresh1) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + s32 wifi_rssi = 0; + u8 wifi_rssi_state = *pprewifi_rssi_state; + + btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); + + if (level_num == 2) { + if ((*pprewifi_rssi_state == BTC_RSSI_STATE_LOW) || + (*pprewifi_rssi_state == BTC_RSSI_STATE_STAY_LOW)) { + if (wifi_rssi >= + (rssi_thresh + BTC_RSSI_COEX_THRESH_TOL_8822B_2ANT)) + wifi_rssi_state = BTC_RSSI_STATE_HIGH; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else { + if (wifi_rssi < rssi_thresh) + wifi_rssi_state = BTC_RSSI_STATE_LOW; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } else if (level_num == 3) { + if (rssi_thresh > rssi_thresh1) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], wifi RSSI thresh error!!\n"); + return *pprewifi_rssi_state; + } + + if ((*pprewifi_rssi_state == BTC_RSSI_STATE_LOW) || + (*pprewifi_rssi_state == BTC_RSSI_STATE_STAY_LOW)) { + if (wifi_rssi >= + (rssi_thresh + BTC_RSSI_COEX_THRESH_TOL_8822B_2ANT)) + wifi_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else if ((*pprewifi_rssi_state == BTC_RSSI_STATE_MEDIUM) || + (*pprewifi_rssi_state == + BTC_RSSI_STATE_STAY_MEDIUM)) { + if (wifi_rssi >= (rssi_thresh1 + + BTC_RSSI_COEX_THRESH_TOL_8822B_2ANT)) + wifi_rssi_state = BTC_RSSI_STATE_HIGH; + else if (wifi_rssi < rssi_thresh) + wifi_rssi_state = BTC_RSSI_STATE_LOW; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM; + } else { + if (wifi_rssi < rssi_thresh1) + wifi_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } + + *pprewifi_rssi_state = wifi_rssi_state; + + return wifi_rssi_state; +} + +static void halbtc8822b2ant_coex_switch_threshold(struct btc_coexist *btcoexist, + u8 isolation_measuared) +{ + s8 interference_wl_tx = 0, interference_bt_tx = 0; + + interference_wl_tx = + BT_8822B_2ANT_WIFI_MAX_TX_POWER - isolation_measuared; + interference_bt_tx = + BT_8822B_2ANT_BT_MAX_TX_POWER - isolation_measuared; + + coex_sta->wifi_coex_thres = BT_8822B_2ANT_WIFI_RSSI_COEXSWITCH_THRES1; + coex_sta->wifi_coex_thres2 = BT_8822B_2ANT_WIFI_RSSI_COEXSWITCH_THRES2; + + coex_sta->bt_coex_thres = BT_8822B_2ANT_BT_RSSI_COEXSWITCH_THRES1; + coex_sta->bt_coex_thres2 = BT_8822B_2ANT_BT_RSSI_COEXSWITCH_THRES2; +} + +static void halbtc8822b2ant_query_bt_info(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + u8 h2c_parameter[1] = {0}; + + if (coex_sta->bt_disabled) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], No query BT info because BT is disabled!\n"); + return; + } + + h2c_parameter[0] |= BIT(0); /* trigger */ + + btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter); +} + +static void halbtc8822b2ant_monitor_bt_ctr(struct btc_coexist *btcoexist) +{ + u32 reg_hp_txrx, reg_lp_txrx, u32tmp; + u32 reg_hp_tx = 0, reg_hp_rx = 0, reg_lp_tx = 0, reg_lp_rx = 0; + static u8 num_of_bt_counter_chk, cnt_slave, cnt_autoslot_hang; + + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + reg_hp_txrx = 0x770; + reg_lp_txrx = 0x774; + + u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_hp_txrx); + reg_hp_tx = u32tmp & MASKLWORD; + reg_hp_rx = (u32tmp & MASKHWORD) >> 16; + + u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_lp_txrx); + reg_lp_tx = u32tmp & MASKLWORD; + reg_lp_rx = (u32tmp & MASKHWORD) >> 16; + + coex_sta->high_priority_tx = reg_hp_tx; + coex_sta->high_priority_rx = reg_hp_rx; + coex_sta->low_priority_tx = reg_lp_tx; + coex_sta->low_priority_rx = reg_lp_rx; + + /* reset counter */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc); + + if ((coex_sta->low_priority_tx > 1050) && + (!coex_sta->c2h_bt_inquiry_page)) + coex_sta->pop_event_cnt++; + + if ((coex_sta->low_priority_rx >= 950) && + (coex_sta->low_priority_rx >= coex_sta->low_priority_tx) && + (!coex_sta->under_ips) && (!coex_sta->c2h_bt_inquiry_page) && + (coex_sta->bt_link_exist)) { + if (cnt_slave >= 2) { + bt_link_info->slave_role = true; + cnt_slave = 2; + } else { + cnt_slave++; + } + } else { + if (cnt_slave == 0) { + bt_link_info->slave_role = false; + cnt_slave = 0; + } else { + cnt_slave--; + } + } + + if (coex_sta->is_tdma_btautoslot) { + if ((coex_sta->low_priority_tx >= 1300) && + (coex_sta->low_priority_rx <= 150)) { + if (cnt_autoslot_hang >= 2) { + coex_sta->is_tdma_btautoslot_hang = true; + cnt_autoslot_hang = 2; + } else { + cnt_autoslot_hang++; + } + } else { + if (cnt_autoslot_hang == 0) { + coex_sta->is_tdma_btautoslot_hang = false; + cnt_autoslot_hang = 0; + } else { + cnt_autoslot_hang--; + } + } + } + + if (coex_sta->sco_exist) { + if ((coex_sta->high_priority_tx >= 400) && + (coex_sta->high_priority_rx >= 400)) + coex_sta->is_esco_mode = false; + else + coex_sta->is_esco_mode = true; + } + + if (bt_link_info->hid_only) { + if (coex_sta->low_priority_rx > 50) + coex_sta->is_hid_low_pri_tx_overhead = true; + else + coex_sta->is_hid_low_pri_tx_overhead = false; + } + + if ((coex_sta->high_priority_tx == 0) && + (coex_sta->high_priority_rx == 0) && + (coex_sta->low_priority_tx == 0) && + (coex_sta->low_priority_rx == 0)) { + num_of_bt_counter_chk++; + if (num_of_bt_counter_chk >= 3) { + halbtc8822b2ant_query_bt_info(btcoexist); + num_of_bt_counter_chk = 0; + } + } +} + +static void halbtc8822b2ant_monitor_wifi_ctr(struct btc_coexist *btcoexist) +{ + s32 wifi_rssi = 0; + bool wifi_busy = false, wifi_under_b_mode = false, wifi_scan = false; + bool bt_idle = false; + static u8 cck_lock_counter, wl_noisy_count0, wl_noisy_count1 = 3, + wl_noisy_count2; + u32 total_cnt, cck_cnt; + u32 cnt_crcok = 0, cnt_crcerr = 0; + static u8 cnt; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_B_MODE, + &wifi_under_b_mode); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &wifi_scan); + + coex_sta->crc_ok_cck = btcoexist->btc_phydm_query_phy_counter( + btcoexist, "PHYDM_INFO_CRC32_OK_CCK"); + coex_sta->crc_ok_11g = btcoexist->btc_phydm_query_phy_counter( + btcoexist, "PHYDM_INFO_CRC32_OK_LEGACY"); + coex_sta->crc_ok_11n = btcoexist->btc_phydm_query_phy_counter( + btcoexist, "PHYDM_INFO_CRC32_OK_HT"); + coex_sta->crc_ok_11n_vht = btcoexist->btc_phydm_query_phy_counter( + btcoexist, "PHYDM_INFO_CRC32_OK_VHT"); + + coex_sta->crc_err_cck = btcoexist->btc_phydm_query_phy_counter( + btcoexist, "PHYDM_INFO_CRC32_ERROR_CCK"); + coex_sta->crc_err_11g = btcoexist->btc_phydm_query_phy_counter( + btcoexist, "PHYDM_INFO_CRC32_ERROR_LEGACY"); + coex_sta->crc_err_11n = btcoexist->btc_phydm_query_phy_counter( + btcoexist, "PHYDM_INFO_CRC32_ERROR_HT"); + coex_sta->crc_err_11n_vht = btcoexist->btc_phydm_query_phy_counter( + btcoexist, "PHYDM_INFO_CRC32_ERROR_VHT"); + + cnt_crcok = coex_sta->crc_ok_cck + coex_sta->crc_ok_11g + + coex_sta->crc_ok_11n + coex_sta->crc_ok_11n_vht; + + cnt_crcerr = coex_sta->crc_err_cck + coex_sta->crc_err_11g + + coex_sta->crc_err_11n + coex_sta->crc_err_11n_vht; + + if ((wifi_busy) && (cnt_crcerr != 0)) { + coex_sta->now_crc_ratio = cnt_crcok / cnt_crcerr; + + if (cnt == 0) + coex_sta->acc_crc_ratio = coex_sta->now_crc_ratio; + else + coex_sta->acc_crc_ratio = + (coex_sta->acc_crc_ratio * 7 + + coex_sta->now_crc_ratio * 3) / + 10; + + if (cnt >= 10) + cnt = 0; + else + cnt++; + } + + cck_cnt = coex_sta->crc_ok_cck + coex_sta->crc_err_cck; + + if ((coex_dm->bt_status == + BT_8822B_2ANT_BT_STATUS_NON_CONNECTED_IDLE) || + (coex_dm->bt_status == BT_8822B_2ANT_BT_STATUS_CONNECTED_IDLE) || + (coex_sta->bt_disabled)) + bt_idle = true; + + if (cck_cnt > 250) { + if (wl_noisy_count2 < 3) + wl_noisy_count2++; + + if (wl_noisy_count2 == 3) { + wl_noisy_count0 = 0; + wl_noisy_count1 = 0; + } + + } else if (cck_cnt < 50) { + if (wl_noisy_count0 < 3) + wl_noisy_count0++; + + if (wl_noisy_count0 == 3) { + wl_noisy_count1 = 0; + wl_noisy_count2 = 0; + } + + } else { + if (wl_noisy_count1 < 3) + wl_noisy_count1++; + + if (wl_noisy_count1 == 3) { + wl_noisy_count0 = 0; + wl_noisy_count2 = 0; + } + } + + if (wl_noisy_count2 == 3) + coex_sta->wl_noisy_level = 2; + else if (wl_noisy_count1 == 3) + coex_sta->wl_noisy_level = 1; + else + coex_sta->wl_noisy_level = 0; + + if ((wifi_busy) && (wifi_rssi >= 30) && (!wifi_under_b_mode)) { + total_cnt = cnt_crcok; + + if ((coex_dm->bt_status == BT_8822B_1ANT_BT_STATUS_ACL_BUSY) || + (coex_dm->bt_status == + BT_8822B_1ANT_BT_STATUS_ACL_SCO_BUSY) || + (coex_dm->bt_status == BT_8822B_1ANT_BT_STATUS_SCO_BUSY)) { + if (coex_sta->crc_ok_cck > + (total_cnt - coex_sta->crc_ok_cck)) { + if (cck_lock_counter < 3) + cck_lock_counter++; + } else { + if (cck_lock_counter > 0) + cck_lock_counter--; + } + + } else { + if (cck_lock_counter > 0) + cck_lock_counter--; + } + } else { + if (cck_lock_counter > 0) + cck_lock_counter--; + } + + if (!coex_sta->pre_ccklock) { + if (cck_lock_counter >= 3) + coex_sta->cck_lock = true; + else + coex_sta->cck_lock = false; + } else { + if (cck_lock_counter == 0) + coex_sta->cck_lock = false; + else + coex_sta->cck_lock = true; + } + + if (coex_sta->cck_lock) + coex_sta->cck_ever_lock = true; + + coex_sta->pre_ccklock = coex_sta->cck_lock; +} + +static bool +halbtc8822b2ant_is_wifibt_status_changed(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + static bool pre_wifi_busy, pre_under_4way, pre_bt_hs_on, pre_bt_off, + pre_bt_slave, pre_hid_low_pri_tx_overhead, pre_wifi_under_lps, + pre_bt_setup_link; + static u8 pre_hid_busy_num, pre_wl_noisy_level; + bool wifi_busy = false, under_4way = false, bt_hs_on = false; + bool wifi_connected = false; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, + &under_4way); + + if (coex_sta->bt_disabled != pre_bt_off) { + pre_bt_off = coex_sta->bt_disabled; + + if (coex_sta->bt_disabled) + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BT is disabled !!\n"); + else + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BT is enabled !!\n"); + + coex_sta->bt_coex_supported_feature = 0; + coex_sta->bt_coex_supported_version = 0; + coex_sta->bt_ble_scan_type = 0; + coex_sta->bt_ble_scan_para[0] = 0; + coex_sta->bt_ble_scan_para[1] = 0; + coex_sta->bt_ble_scan_para[2] = 0; + coex_sta->bt_reg_vendor_ac = 0xffff; + coex_sta->bt_reg_vendor_ae = 0xffff; + return true; + } + + if (wifi_connected) { + if (wifi_busy != pre_wifi_busy) { + pre_wifi_busy = wifi_busy; + return true; + } + if (under_4way != pre_under_4way) { + pre_under_4way = under_4way; + return true; + } + if (bt_hs_on != pre_bt_hs_on) { + pre_bt_hs_on = bt_hs_on; + return true; + } + if (coex_sta->wl_noisy_level != pre_wl_noisy_level) { + pre_wl_noisy_level = coex_sta->wl_noisy_level; + return true; + } + if (coex_sta->under_lps != pre_wifi_under_lps) { + pre_wifi_under_lps = coex_sta->under_lps; + if (coex_sta->under_lps) + return true; + } + } + + if (!coex_sta->bt_disabled) { + if (coex_sta->hid_busy_num != pre_hid_busy_num) { + pre_hid_busy_num = coex_sta->hid_busy_num; + return true; + } + + if (bt_link_info->slave_role != pre_bt_slave) { + pre_bt_slave = bt_link_info->slave_role; + return true; + } + + if (pre_hid_low_pri_tx_overhead != + coex_sta->is_hid_low_pri_tx_overhead) { + pre_hid_low_pri_tx_overhead = + coex_sta->is_hid_low_pri_tx_overhead; + return true; + } + + if (pre_bt_setup_link != coex_sta->is_setup_link) { + pre_bt_setup_link = coex_sta->is_setup_link; + return true; + } + } + + return false; +} + +static void halbtc8822b2ant_update_bt_link_info(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + bool bt_hs_on = false; + bool bt_busy = false; + + coex_sta->num_of_profile = 0; + + /* set link exist status */ + if (!(coex_sta->bt_info & BT_INFO_8822B_1ANT_B_CONNECTION)) { + coex_sta->bt_link_exist = false; + coex_sta->pan_exist = false; + coex_sta->a2dp_exist = false; + coex_sta->hid_exist = false; + coex_sta->sco_exist = false; + } else { /* connection exists */ + coex_sta->bt_link_exist = true; + if (coex_sta->bt_info & BT_INFO_8822B_1ANT_B_FTP) { + coex_sta->pan_exist = true; + coex_sta->num_of_profile++; + } else { + coex_sta->pan_exist = false; + } + + if (coex_sta->bt_info & BT_INFO_8822B_1ANT_B_A2DP) { + coex_sta->a2dp_exist = true; + coex_sta->num_of_profile++; + } else { + coex_sta->a2dp_exist = false; + } + + if (coex_sta->bt_info & BT_INFO_8822B_1ANT_B_HID) { + coex_sta->hid_exist = true; + coex_sta->num_of_profile++; + } else { + coex_sta->hid_exist = false; + } + + if (coex_sta->bt_info & BT_INFO_8822B_1ANT_B_SCO_ESCO) { + coex_sta->sco_exist = true; + coex_sta->num_of_profile++; + } else { + coex_sta->sco_exist = false; + } + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + + bt_link_info->bt_link_exist = coex_sta->bt_link_exist; + bt_link_info->sco_exist = coex_sta->sco_exist; + bt_link_info->a2dp_exist = coex_sta->a2dp_exist; + bt_link_info->pan_exist = coex_sta->pan_exist; + bt_link_info->hid_exist = coex_sta->hid_exist; + bt_link_info->acl_busy = coex_sta->acl_busy; + + /* work around for HS mode. */ + if (bt_hs_on) { + bt_link_info->pan_exist = true; + bt_link_info->bt_link_exist = true; + } + + /* check if Sco only */ + if (bt_link_info->sco_exist && !bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && !bt_link_info->hid_exist) + bt_link_info->sco_only = true; + else + bt_link_info->sco_only = false; + + /* check if A2dp only */ + if (!bt_link_info->sco_exist && bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && !bt_link_info->hid_exist) + bt_link_info->a2dp_only = true; + else + bt_link_info->a2dp_only = false; + + /* check if Pan only */ + if (!bt_link_info->sco_exist && !bt_link_info->a2dp_exist && + bt_link_info->pan_exist && !bt_link_info->hid_exist) + bt_link_info->pan_only = true; + else + bt_link_info->pan_only = false; + + /* check if Hid only */ + if (!bt_link_info->sco_exist && !bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && bt_link_info->hid_exist) + bt_link_info->hid_only = true; + else + bt_link_info->hid_only = false; + + if (coex_sta->bt_info & BT_INFO_8822B_2ANT_B_INQ_PAGE) { + coex_dm->bt_status = BT_8822B_2ANT_BT_STATUS_INQ_PAGE; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BtInfoNotify(), BT Inq/page!!!\n"); + } else if (!(coex_sta->bt_info & BT_INFO_8822B_2ANT_B_CONNECTION)) { + coex_dm->bt_status = BT_8822B_2ANT_BT_STATUS_NON_CONNECTED_IDLE; + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BtInfoNotify(), BT Non-Connected idle!!!\n"); + } else if (coex_sta->bt_info == BT_INFO_8822B_2ANT_B_CONNECTION) { + /* connection exists but no busy */ + coex_dm->bt_status = BT_8822B_2ANT_BT_STATUS_CONNECTED_IDLE; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BtInfoNotify(), BT Connected-idle!!!\n"); + } else if (((coex_sta->bt_info & BT_INFO_8822B_2ANT_B_SCO_ESCO) || + (coex_sta->bt_info & BT_INFO_8822B_2ANT_B_SCO_BUSY)) && + (coex_sta->bt_info & BT_INFO_8822B_2ANT_B_ACL_BUSY)) { + coex_dm->bt_status = BT_8822B_2ANT_BT_STATUS_ACL_SCO_BUSY; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BtInfoNotify(), BT ACL SCO busy!!!\n"); + } else if ((coex_sta->bt_info & BT_INFO_8822B_2ANT_B_SCO_ESCO) || + (coex_sta->bt_info & BT_INFO_8822B_2ANT_B_SCO_BUSY)) { + coex_dm->bt_status = BT_8822B_2ANT_BT_STATUS_SCO_BUSY; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BtInfoNotify(), BT SCO busy!!!\n"); + } else if (coex_sta->bt_info & BT_INFO_8822B_2ANT_B_ACL_BUSY) { + coex_dm->bt_status = BT_8822B_2ANT_BT_STATUS_ACL_BUSY; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BtInfoNotify(), BT ACL busy!!!\n"); + } else { + coex_dm->bt_status = BT_8822B_2ANT_BT_STATUS_MAX; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BtInfoNotify(), BT Non-Defined state!!!\n"); + } + + if ((coex_dm->bt_status == BT_8822B_2ANT_BT_STATUS_ACL_BUSY) || + (coex_dm->bt_status == BT_8822B_2ANT_BT_STATUS_SCO_BUSY) || + (coex_dm->bt_status == BT_8822B_2ANT_BT_STATUS_ACL_SCO_BUSY)) + bt_busy = true; + else + bt_busy = false; + + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy); +} + +static void halbtc8822b2ant_update_wifi_ch_info(struct btc_coexist *btcoexist, + u8 type) +{ + u8 h2c_parameter[3] = {0}; + u32 wifi_bw; + u8 wifi_central_chnl; + u32 RTL97F_8822B = 0; + + if (RTL97F_8822B) + return; + + /* only 2.4G we need to inform bt the chnl mask */ + btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL, + &wifi_central_chnl); + if ((type == BTC_MEDIA_CONNECT) && (wifi_central_chnl <= 14)) { + /* enable BT AFH skip WL channel for 8822b + * because BT Rx LO interference + */ + h2c_parameter[0] = 0x1; + h2c_parameter[1] = wifi_central_chnl; + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (wifi_bw == BTC_WIFI_BW_HT40) + h2c_parameter[2] = 0x30; + else + h2c_parameter[2] = 0x20; + } + + coex_dm->wifi_chnl_info[0] = h2c_parameter[0]; + coex_dm->wifi_chnl_info[1] = h2c_parameter[1]; + coex_dm->wifi_chnl_info[2] = h2c_parameter[2]; + + btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, h2c_parameter); +} + +static void +halbtc8822b2ant_set_fw_dac_swing_level(struct btc_coexist *btcoexist, + u8 dac_swing_lvl) +{ + u8 h2c_parameter[1] = {0}; + u32 RTL97F_8822B = 0; + + if (RTL97F_8822B) + return; + + /* There are several type of dacswing */ + /* 0x18/ 0x10/ 0xc/ 0x8/ 0x4/ 0x6 */ + h2c_parameter[0] = dac_swing_lvl; + + btcoexist->btc_fill_h2c(btcoexist, 0x64, 1, h2c_parameter); +} + +static void halbtc8822b2ant_fw_dac_swing_lvl(struct btc_coexist *btcoexist, + bool force_exec, + u8 fw_dac_swing_lvl) +{ + u32 RTL97F_8822B = 0; + + if (RTL97F_8822B) + return; + + coex_dm->cur_fw_dac_swing_lvl = fw_dac_swing_lvl; + + if (!force_exec) { + if (coex_dm->pre_fw_dac_swing_lvl == + coex_dm->cur_fw_dac_swing_lvl) + return; + } + + halbtc8822b2ant_set_fw_dac_swing_level(btcoexist, + coex_dm->cur_fw_dac_swing_lvl); + + coex_dm->pre_fw_dac_swing_lvl = coex_dm->cur_fw_dac_swing_lvl; +} + +static void halbtc8822b2ant_set_fw_dec_bt_pwr(struct btc_coexist *btcoexist, + u8 dec_bt_pwr_lvl) +{ + u32 RTL97F_8822B = 0; + u8 h2c_parameter[1] = {0}; + + if (RTL97F_8822B) + return; + + h2c_parameter[0] = dec_bt_pwr_lvl; + + btcoexist->btc_fill_h2c(btcoexist, 0x62, 1, h2c_parameter); +} + +static void halbtc8822b2ant_dec_bt_pwr(struct btc_coexist *btcoexist, + bool force_exec, u8 dec_bt_pwr_lvl) +{ + coex_dm->cur_bt_dec_pwr_lvl = dec_bt_pwr_lvl; + + if (!force_exec) { + if (coex_dm->pre_bt_dec_pwr_lvl == coex_dm->cur_bt_dec_pwr_lvl) + return; + } + halbtc8822b2ant_set_fw_dec_bt_pwr(btcoexist, + coex_dm->cur_bt_dec_pwr_lvl); + + coex_dm->pre_bt_dec_pwr_lvl = coex_dm->cur_bt_dec_pwr_lvl; +} + +static void halbtc8822b2ant_low_penalty_ra(struct btc_coexist *btcoexist, + bool force_exec, bool low_penalty_ra) +{ + coex_dm->cur_low_penalty_ra = low_penalty_ra; + + if (!force_exec) { + if (coex_dm->pre_low_penalty_ra == coex_dm->cur_low_penalty_ra) + return; + } + + if (low_penalty_ra) + btcoexist->btc_phydm_modify_ra_pcr_threshold(btcoexist, 0, 50); + else + btcoexist->btc_phydm_modify_ra_pcr_threshold(btcoexist, 0, 0); + + coex_dm->pre_low_penalty_ra = coex_dm->cur_low_penalty_ra; +} + +static void halbtc8822b2ant_write_score_board(struct btc_coexist *btcoexist, + u16 bitpos, bool state) +{ + static u16 originalval = 0x8002; + + if (state) + originalval = originalval | bitpos; + else + originalval = originalval & (~bitpos); + + btcoexist->btc_write_2byte(btcoexist, 0xaa, originalval); +} + +static void halbtc8822b2ant_read_score_board(struct btc_coexist *btcoexist, + u16 *score_board_val) +{ + *score_board_val = + (btcoexist->btc_read_2byte(btcoexist, 0xaa)) & 0x7fff; +} + +static void halbtc8822b2ant_post_state_to_bt(struct btc_coexist *btcoexist, + u16 type, bool state) +{ + halbtc8822b2ant_write_score_board(btcoexist, (u16)type, state); +} + +static void +halbtc8822b2ant_monitor_bt_enable_disable(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + static u32 bt_disable_cnt; + bool bt_active = true, bt_disabled = false, wifi_under_5g = false; + u16 u16tmp; + + /* This function check if bt is disabled */ + + /* Read BT on/off status from scoreboard[1], + * enable this only if BT patch support this feature + */ + halbtc8822b2ant_read_score_board(btcoexist, &u16tmp); + + bt_active = u16tmp & BIT(1); + + if (bt_active) { + bt_disable_cnt = 0; + bt_disabled = false; + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE, + &bt_disabled); + } else { + bt_disable_cnt++; + if (bt_disable_cnt >= 10) { + bt_disabled = true; + bt_disable_cnt = 10; + } + + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE, + &bt_disabled); + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + + if ((wifi_under_5g) || (bt_disabled)) + halbtc8822b2ant_low_penalty_ra(btcoexist, NORMAL_EXEC, false); + else + halbtc8822b2ant_low_penalty_ra(btcoexist, NORMAL_EXEC, true); + + if (coex_sta->bt_disabled != bt_disabled) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BT is from %s to %s!!\n", + (coex_sta->bt_disabled ? "disabled" : "enabled"), + (bt_disabled ? "disabled" : "enabled")); + coex_sta->bt_disabled = bt_disabled; + } +} + +static void halbtc8822b2ant_enable_gnt_to_gpio(struct btc_coexist *btcoexist, + bool isenable) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + static u8 bit_val[5] = {0, 0, 0, 0, 0}; + + if (!btcoexist->dbg_mode_2ant) + return; + + if (isenable) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], enable_gnt_to_gpio!!\n"); + + /* enable GNT_WL, GNT_BT to GPIO for debug */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x73, 0x8, 0x1); + + /* store original value */ + bit_val[0] = + (btcoexist->btc_read_1byte(btcoexist, 0x66) & BIT(4)) >> + 4; /*0x66[4] */ + bit_val[1] = (btcoexist->btc_read_1byte(btcoexist, 0x67) & + BIT(0)); /*0x66[8] */ + bit_val[2] = + (btcoexist->btc_read_1byte(btcoexist, 0x42) & BIT(3)) >> + 3; /*0x40[19] */ + bit_val[3] = + (btcoexist->btc_read_1byte(btcoexist, 0x65) & BIT(7)) >> + 7; /*0x64[15] */ + bit_val[4] = + (btcoexist->btc_read_1byte(btcoexist, 0x72) & BIT(2)) >> + 2; /*0x70[18] */ + + /* switch GPIO Mux */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x66, BIT(4), + 0x0); /*0x66[4] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, BIT(0), + 0x0); /*0x66[8] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x42, BIT(3), + 0x0); /*0x40[19] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x65, BIT(7), + 0x0); /*0x64[15] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x72, BIT(2), + 0x0); /*0x70[18] = 0 */ + + } else { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], disable_gnt_to_gpio!!\n"); + + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x73, 0x8, 0x0); + + /* Restore original value */ + /* switch GPIO Mux */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x66, BIT(4), + bit_val[0]); /*0x66[4] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, BIT(0), + bit_val[1]); /*0x66[8] = 0 */ + btcoexist->btc_write_1byte_bitmask( + btcoexist, 0x42, BIT(3), bit_val[2]); /*0x40[19] = 0 */ + btcoexist->btc_write_1byte_bitmask( + btcoexist, 0x65, BIT(7), bit_val[3]); /*0x64[15] = 0 */ + btcoexist->btc_write_1byte_bitmask( + btcoexist, 0x72, BIT(2), bit_val[4]); /*0x70[18] = 0 */ + } +} + +static u32 +halbtc8822b2ant_ltecoex_indirect_read_reg(struct btc_coexist *btcoexist, + u16 reg_addr) +{ + u32 delay_count = 0; + + while (1) { + if ((btcoexist->btc_read_1byte(btcoexist, 0x1703) & BIT(5)) == + 0) { + mdelay(50); + delay_count++; + if (delay_count >= 10) { + delay_count = 0; + break; + } + } else { + break; + } + } + + /* wait for ready bit before access 0x1700 */ + btcoexist->btc_write_4byte(btcoexist, 0x1700, 0x800F0000 | reg_addr); + + return btcoexist->btc_read_4byte(btcoexist, 0x1708); /* get read data */ +} + +static void +halbtc8822b2ant_ltecoex_indirect_write_reg(struct btc_coexist *btcoexist, + u16 reg_addr, u32 bit_mask, + u32 reg_value) +{ + u32 val, i = 0, bitpos = 0, delay_count = 0; + + if (bit_mask == 0x0) + return; + if (bit_mask == 0xffffffff) { + /* wait for ready bit before access 0x1700/0x1704 */ + while (1) { + if ((btcoexist->btc_read_1byte(btcoexist, 0x1703) & + BIT(5)) == 0) { + mdelay(50); + delay_count++; + if (delay_count >= 10) { + delay_count = 0; + break; + } + } else { + break; + } + } + + btcoexist->btc_write_4byte(btcoexist, 0x1704, + reg_value); /* put write data */ + + btcoexist->btc_write_4byte(btcoexist, 0x1700, + 0xc00F0000 | reg_addr); + } else { + for (i = 0; i <= 31; i++) { + if (((bit_mask >> i) & 0x1) == 0x1) { + bitpos = i; + break; + } + } + + /* read back register value before write */ + val = halbtc8822b2ant_ltecoex_indirect_read_reg(btcoexist, + reg_addr); + val = (val & (~bit_mask)) | (reg_value << bitpos); + + /* wait for ready bit before access 0x1700/0x1704 */ + while (1) { + if ((btcoexist->btc_read_1byte(btcoexist, 0x1703) & + BIT(5)) == 0) { + mdelay(50); + delay_count++; + if (delay_count >= 10) { + delay_count = 0; + break; + } + } else { + break; + } + } + + btcoexist->btc_write_4byte(btcoexist, 0x1704, + val); /* put write data */ + + btcoexist->btc_write_4byte(btcoexist, 0x1700, + 0xc00F0000 | reg_addr); + } +} + +static void halbtc8822b2ant_ltecoex_enable(struct btc_coexist *btcoexist, + bool enable) +{ + u8 val; + + val = (enable) ? 1 : 0; + halbtc8822b2ant_ltecoex_indirect_write_reg(btcoexist, 0x38, 0x80, + val); /* 0x38[7] */ +} + +static void +halbtc8822b2ant_ltecoex_pathcontrol_owner(struct btc_coexist *btcoexist, + bool wifi_control) +{ + u8 val; + + val = (wifi_control) ? 1 : 0; + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x73, 0x4, + val); /* 0x70[26] */ +} + +static void halbtc8822b2ant_ltecoex_set_gnt_bt(struct btc_coexist *btcoexist, + u8 control_block, + bool sw_control, u8 state) +{ + u32 val = 0, bit_mask; + + state = state & 0x1; + val = (sw_control) ? ((state << 1) | 0x1) : 0; + + switch (control_block) { + case BT_8822B_2ANT_GNT_BLOCK_RFC_BB: + default: + bit_mask = 0xc000; + halbtc8822b2ant_ltecoex_indirect_write_reg( + btcoexist, 0x38, bit_mask, val); /* 0x38[15:14] */ + bit_mask = 0x0c00; + halbtc8822b2ant_ltecoex_indirect_write_reg( + btcoexist, 0x38, bit_mask, val); /* 0x38[11:10] */ + break; + case BT_8822B_2ANT_GNT_BLOCK_RFC: + bit_mask = 0xc000; + halbtc8822b2ant_ltecoex_indirect_write_reg( + btcoexist, 0x38, bit_mask, val); /* 0x38[15:14] */ + break; + case BT_8822B_2ANT_GNT_BLOCK_BB: + bit_mask = 0x0c00; + halbtc8822b2ant_ltecoex_indirect_write_reg( + btcoexist, 0x38, bit_mask, val); /* 0x38[11:10] */ + break; + } +} + +static void halbtc8822b2ant_ltecoex_set_gnt_wl(struct btc_coexist *btcoexist, + u8 control_block, + bool sw_control, u8 state) +{ + u32 val = 0, bit_mask; + + state = state & 0x1; + val = (sw_control) ? ((state << 1) | 0x1) : 0; + + switch (control_block) { + case BT_8822B_2ANT_GNT_BLOCK_RFC_BB: + default: + bit_mask = 0x3000; + halbtc8822b2ant_ltecoex_indirect_write_reg( + btcoexist, 0x38, bit_mask, val); /* 0x38[13:12] */ + bit_mask = 0x0300; + halbtc8822b2ant_ltecoex_indirect_write_reg( + btcoexist, 0x38, bit_mask, val); /* 0x38[9:8] */ + break; + case BT_8822B_2ANT_GNT_BLOCK_RFC: + bit_mask = 0x3000; + halbtc8822b2ant_ltecoex_indirect_write_reg( + btcoexist, 0x38, bit_mask, val); /* 0x38[13:12] */ + break; + case BT_8822B_2ANT_GNT_BLOCK_BB: + bit_mask = 0x0300; + halbtc8822b2ant_ltecoex_indirect_write_reg( + btcoexist, 0x38, bit_mask, val); /* 0x38[9:8] */ + break; + } +} + +static void +halbtc8822b2ant_ltecoex_set_coex_table(struct btc_coexist *btcoexist, + u8 table_type, u16 table_content) +{ + u16 reg_addr = 0x0000; + + switch (table_type) { + case BT_8822B_2ANT_CTT_WL_VS_LTE: + reg_addr = 0xa0; + break; + case BT_8822B_2ANT_CTT_BT_VS_LTE: + reg_addr = 0xa4; + break; + } + + if (reg_addr != 0x0000) + halbtc8822b2ant_ltecoex_indirect_write_reg( + btcoexist, reg_addr, 0xffff, + table_content); /* 0xa0[15:0] or 0xa4[15:0] */ +} + +static void halbtc8822b2ant_set_wltoggle_coex_table( + struct btc_coexist *btcoexist, bool force_exec, u8 interval, + u8 val0x6c4_b0, u8 val0x6c4_b1, u8 val0x6c4_b2, u8 val0x6c4_b3) +{ + static u8 pre_h2c_parameter[6] = {0}; + u8 cur_h2c_parameter[6] = {0}; + u8 i, match_cnt = 0; + + cur_h2c_parameter[0] = 0x7; /* op_code, 0x7= wlan toggle slot*/ + + cur_h2c_parameter[1] = interval; + cur_h2c_parameter[2] = val0x6c4_b0; + cur_h2c_parameter[3] = val0x6c4_b1; + cur_h2c_parameter[4] = val0x6c4_b2; + cur_h2c_parameter[5] = val0x6c4_b3; + + if (!force_exec) { + for (i = 1; i <= 5; i++) { + if (cur_h2c_parameter[i] != pre_h2c_parameter[i]) + break; + + match_cnt++; + } + + if (match_cnt == 5) + return; + } + + for (i = 1; i <= 5; i++) + pre_h2c_parameter[i] = cur_h2c_parameter[i]; + + btcoexist->btc_fill_h2c(btcoexist, 0x69, 6, cur_h2c_parameter); +} + +static void halbtc8822b2ant_set_coex_table(struct btc_coexist *btcoexist, + u32 val0x6c0, u32 val0x6c4, + u32 val0x6c8, u8 val0x6cc) +{ + btcoexist->btc_write_4byte(btcoexist, 0x6c0, val0x6c0); + + btcoexist->btc_write_4byte(btcoexist, 0x6c4, val0x6c4); + + btcoexist->btc_write_4byte(btcoexist, 0x6c8, val0x6c8); + + btcoexist->btc_write_1byte(btcoexist, 0x6cc, val0x6cc); +} + +static void halbtc8822b2ant_coex_table(struct btc_coexist *btcoexist, + bool force_exec, u32 val0x6c0, + u32 val0x6c4, u32 val0x6c8, u8 val0x6cc) +{ + coex_dm->cur_val0x6c0 = val0x6c0; + coex_dm->cur_val0x6c4 = val0x6c4; + coex_dm->cur_val0x6c8 = val0x6c8; + coex_dm->cur_val0x6cc = val0x6cc; + + if (!force_exec) { + if ((coex_dm->pre_val0x6c0 == coex_dm->cur_val0x6c0) && + (coex_dm->pre_val0x6c4 == coex_dm->cur_val0x6c4) && + (coex_dm->pre_val0x6c8 == coex_dm->cur_val0x6c8) && + (coex_dm->pre_val0x6cc == coex_dm->cur_val0x6cc)) + return; + } + halbtc8822b2ant_set_coex_table(btcoexist, val0x6c0, val0x6c4, val0x6c8, + val0x6cc); + + coex_dm->pre_val0x6c0 = coex_dm->cur_val0x6c0; + coex_dm->pre_val0x6c4 = coex_dm->cur_val0x6c4; + coex_dm->pre_val0x6c8 = coex_dm->cur_val0x6c8; + coex_dm->pre_val0x6cc = coex_dm->cur_val0x6cc; +} + +static void halbtc8822b2ant_coex_table_with_type(struct btc_coexist *btcoexist, + bool force_exec, u8 type) +{ + u32 break_table; + u8 select_table; + + coex_sta->coex_table_type = type; + + if (coex_sta->concurrent_rx_mode_on) { + break_table = 0xf0ffffff; /* set WL hi-pri can break BT */ + /* set Tx response = Hi-Pri (ex: Transmitting ACK,BA,CTS) */ + select_table = 0xb; + } else { + break_table = 0xffffff; + select_table = 0x3; + } + + switch (type) { + case 0: + halbtc8822b2ant_coex_table(btcoexist, force_exec, 0xffffffff, + 0xffffffff, break_table, + select_table); + break; + case 1: + halbtc8822b2ant_coex_table(btcoexist, force_exec, 0x55555555, + 0x5a5a5a5a, break_table, + select_table); + break; + case 2: + halbtc8822b2ant_coex_table(btcoexist, force_exec, 0x5a5a5a5a, + 0x5a5a5a5a, break_table, + select_table); + break; + case 3: + halbtc8822b2ant_coex_table(btcoexist, force_exec, 0x55555555, + 0x5a5a5a5a, break_table, + select_table); + break; + case 4: + halbtc8822b2ant_coex_table(btcoexist, force_exec, 0x55555555, + 0x5a5a5a5a, break_table, + select_table); + break; + case 5: + halbtc8822b2ant_coex_table(btcoexist, force_exec, 0x55555555, + 0x55555555, break_table, + select_table); + break; + case 6: + halbtc8822b2ant_coex_table(btcoexist, force_exec, 0xa5555555, + 0xfafafafa, break_table, + select_table); + break; + case 7: + halbtc8822b2ant_coex_table(btcoexist, force_exec, 0xa5555555, + 0xaa5a5a5a, break_table, + select_table); + break; + case 8: + halbtc8822b2ant_coex_table(btcoexist, force_exec, 0xa5555555, + 0xfafafafa, break_table, + select_table); + break; + case 9: + halbtc8822b2ant_coex_table(btcoexist, force_exec, 0x5a5a5a5a, + 0xaaaa5aaa, break_table, + select_table); + break; + case 10: + halbtc8822b2ant_coex_table(btcoexist, force_exec, 0x55555555, + 0x5a5a555a, break_table, + select_table); + break; + default: + break; + } +} + +static void +halbtc8822b2ant_set_fw_ignore_wlan_act(struct btc_coexist *btcoexist, + bool enable) +{ + u8 h2c_parameter[1] = {0}; + u32 RTL97F_8822B = 0; + + if (RTL97F_8822B) + return; + + if (enable) + h2c_parameter[0] |= BIT(0); /* function enable */ + + btcoexist->btc_fill_h2c(btcoexist, 0x63, 1, h2c_parameter); +} + +static void halbtc8822b2ant_ignore_wlan_act(struct btc_coexist *btcoexist, + bool force_exec, bool enable) +{ + coex_dm->cur_ignore_wlan_act = enable; + + if (!force_exec) { + if (coex_dm->pre_ignore_wlan_act == + coex_dm->cur_ignore_wlan_act) + return; + } + halbtc8822b2ant_set_fw_ignore_wlan_act(btcoexist, enable); + + coex_dm->pre_ignore_wlan_act = coex_dm->cur_ignore_wlan_act; +} + +static void halbtc8822b2ant_set_lps_rpwm(struct btc_coexist *btcoexist, + u8 lps_val, u8 rpwm_val) +{ + u8 lps = lps_val; + u8 rpwm = rpwm_val; + + btcoexist->btc_set(btcoexist, BTC_SET_U1_LPS_VAL, &lps); + btcoexist->btc_set(btcoexist, BTC_SET_U1_RPWM_VAL, &rpwm); +} + +static void halbtc8822b2ant_lps_rpwm(struct btc_coexist *btcoexist, + bool force_exec, u8 lps_val, u8 rpwm_val) +{ + coex_dm->cur_lps = lps_val; + coex_dm->cur_rpwm = rpwm_val; + + if (!force_exec) { + if ((coex_dm->pre_lps == coex_dm->cur_lps) && + (coex_dm->pre_rpwm == coex_dm->cur_rpwm)) + return; + } + halbtc8822b2ant_set_lps_rpwm(btcoexist, lps_val, rpwm_val); + + coex_dm->pre_lps = coex_dm->cur_lps; + coex_dm->pre_rpwm = coex_dm->cur_rpwm; +} + +static void halbtc8822b2ant_ps_tdma_check_for_power_save_state( + struct btc_coexist *btcoexist, bool new_ps_state) +{ + u8 lps_mode = 0x0; + u8 h2c_parameter[5] = {0, 0, 0, 0x40, 0}; + u32 RTL97F_8822B = 0; + + if (RTL97F_8822B) + return; + + btcoexist->btc_get(btcoexist, BTC_GET_U1_LPS_MODE, &lps_mode); + + if (lps_mode) { /* already under LPS state */ + if (new_ps_state) { + /* keep state under LPS, do nothing. */ + } else { + /* will leave LPS state, turn off psTdma first */ + btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, + h2c_parameter); + } + } else { /* NO PS state */ + if (new_ps_state) { + /* will enter LPS state, turn off psTdma first */ + btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, + h2c_parameter); + } else { + /* keep state under NO PS state, do nothing. */ + } + } +} + +static bool halbtc8822b2ant_power_save_state(struct btc_coexist *btcoexist, + u8 ps_type, u8 lps_val, + u8 rpwm_val) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + bool low_pwr_disable = false, result = true; + + switch (ps_type) { + case BTC_PS_WIFI_NATIVE: + coex_sta->force_lps_ctrl = false; + /* recover to original 32k low power setting */ + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], %s == BTC_PS_WIFI_NATIVE\n", __func__); + + low_pwr_disable = false; + btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_NORMAL_LPS, NULL); + break; + case BTC_PS_LPS_ON: + coex_sta->force_lps_ctrl = true; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], %s == BTC_PS_LPS_ON\n", __func__); + + halbtc8822b2ant_ps_tdma_check_for_power_save_state(btcoexist, + true); + halbtc8822b2ant_lps_rpwm(btcoexist, NORMAL_EXEC, lps_val, + rpwm_val); + /* when coex force to enter LPS, do not enter 32k low power. */ + low_pwr_disable = true; + btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + /* power save must executed before psTdma. */ + btcoexist->btc_set(btcoexist, BTC_SET_ACT_ENTER_LPS, NULL); + break; + case BTC_PS_LPS_OFF: + coex_sta->force_lps_ctrl = true; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], %s == BTC_PS_LPS_OFF\n", __func__); + + halbtc8822b2ant_ps_tdma_check_for_power_save_state(btcoexist, + false); + result = btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS, + NULL); + break; + default: + break; + } + + return result; +} + +static void halbtc8822b2ant_set_fw_pstdma(struct btc_coexist *btcoexist, + u8 byte1, u8 byte2, u8 byte3, + u8 byte4, u8 byte5) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + u8 h2c_parameter[5] = {0}; + u8 real_byte1 = byte1, real_byte5 = byte5; + bool ap_enable = false, result = false; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + if (byte5 & BIT(2)) + coex_sta->is_tdma_btautoslot = true; + else + coex_sta->is_tdma_btautoslot = false; + + /* release bt-auto slot for auto-slot hang is detected!! */ + if (coex_sta->is_tdma_btautoslot) + if ((coex_sta->is_tdma_btautoslot_hang) || + (bt_link_info->slave_role)) + byte5 = byte5 & 0xfb; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, + &ap_enable); + + if ((ap_enable) && (byte1 & BIT(4) && !(byte1 & BIT(5)))) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], %s == FW for AP mode\n", __func__); + + real_byte1 &= ~BIT(4); + real_byte1 |= BIT(5); + + real_byte5 |= BIT(5); + real_byte5 &= ~BIT(6); + + halbtc8822b2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + } else if (byte1 & BIT(4) && !(byte1 & BIT(5))) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], %s == Force LPS (byte1 = 0x%x)\n", + __func__, byte1); + + if (!halbtc8822b2ant_power_save_state(btcoexist, BTC_PS_LPS_OFF, + 0x50, 0x4)) + result = true; + } else { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], %s == Native LPS (byte1 = 0x%x)\n", + __func__, byte1); + + halbtc8822b2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + } + + coex_sta->is_set_ps_state_fail = result; + + if (!coex_sta->is_set_ps_state_fail) { + h2c_parameter[0] = real_byte1; + h2c_parameter[1] = byte2; + h2c_parameter[2] = byte3; + h2c_parameter[3] = byte4; + h2c_parameter[4] = real_byte5; + + coex_dm->ps_tdma_para[0] = real_byte1; + coex_dm->ps_tdma_para[1] = byte2; + coex_dm->ps_tdma_para[2] = byte3; + coex_dm->ps_tdma_para[3] = byte4; + coex_dm->ps_tdma_para[4] = real_byte5; + + btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, h2c_parameter); + } else { + coex_sta->cnt_set_ps_state_fail++; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], %s == Force Leave LPS Fail (cnt = %d)\n", + __func__, coex_sta->cnt_set_ps_state_fail); + } +} + +static void halbtc8822b2ant_ps_tdma(struct btc_coexist *btcoexist, + bool force_exec, bool turn_on, u8 type) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + static u8 ps_tdma_byte4_modify, pre_ps_tdma_byte4_modify; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + coex_dm->cur_ps_tdma_on = turn_on; + coex_dm->cur_ps_tdma = type; + + /* 0x778 = 0x1 at wifi slot (no blocking BT Low-Pri pkts) */ + if (bt_link_info->slave_role) + ps_tdma_byte4_modify = 0x1; + else + ps_tdma_byte4_modify = 0x0; + + if (pre_ps_tdma_byte4_modify != ps_tdma_byte4_modify) { + force_exec = true; + pre_ps_tdma_byte4_modify = ps_tdma_byte4_modify; + } + + if (!force_exec) { + if ((coex_dm->pre_ps_tdma_on == coex_dm->cur_ps_tdma_on) && + (coex_dm->pre_ps_tdma == coex_dm->cur_ps_tdma)) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Skip TDMA because no change TDMA(%s, %d)\n", + (coex_dm->cur_ps_tdma_on ? "on" : "off"), + coex_dm->cur_ps_tdma); + return; + } + } + + if (coex_dm->cur_ps_tdma_on) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** TDMA(on, %d) **********\n", + coex_dm->cur_ps_tdma); + + btcoexist->btc_write_1byte_bitmask( + btcoexist, 0x550, 0x8, 0x1); /* enable TBTT nterrupt */ + } else { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** TDMA(off, %d) **********\n", + coex_dm->cur_ps_tdma); + } + + if (turn_on) { + switch (type) { + case 1: + halbtc8822b2ant_set_fw_pstdma( + btcoexist, 0x61, 0x10, 0x03, 0x91, + 0x54 | ps_tdma_byte4_modify); + break; + case 2: + default: + halbtc8822b2ant_set_fw_pstdma( + btcoexist, 0x61, 0x35, 0x03, 0x11, + 0x11 | ps_tdma_byte4_modify); + break; + case 3: + halbtc8822b2ant_set_fw_pstdma( + btcoexist, 0x61, 0x3a, 0x3, 0x91, + 0x10 | ps_tdma_byte4_modify); + break; + case 4: + halbtc8822b2ant_set_fw_pstdma( + btcoexist, 0x61, 0x21, 0x3, 0x91, + 0x10 | ps_tdma_byte4_modify); + break; + case 5: + halbtc8822b2ant_set_fw_pstdma( + btcoexist, 0x61, 0x25, 0x3, 0x91, + 0x10 | ps_tdma_byte4_modify); + break; + case 6: + halbtc8822b2ant_set_fw_pstdma( + btcoexist, 0x61, 0x10, 0x3, 0x91, + 0x10 | ps_tdma_byte4_modify); + break; + case 7: + halbtc8822b2ant_set_fw_pstdma( + btcoexist, 0x61, 0x20, 0x3, 0x91, + 0x10 | ps_tdma_byte4_modify); + break; + case 8: + halbtc8822b2ant_set_fw_pstdma(btcoexist, 0x61, 0x15, + 0x03, 0x11, 0x11); + break; + case 10: + halbtc8822b2ant_set_fw_pstdma(btcoexist, 0x61, 0x30, + 0x03, 0x11, 0x10); + break; + case 11: + halbtc8822b2ant_set_fw_pstdma( + btcoexist, 0x61, 0x35, 0x03, 0x11, + 0x10 | ps_tdma_byte4_modify); + break; + case 12: + halbtc8822b2ant_set_fw_pstdma(btcoexist, 0x61, 0x35, + 0x03, 0x11, 0x11); + break; + case 13: + halbtc8822b2ant_set_fw_pstdma( + btcoexist, 0x61, 0x1c, 0x03, 0x11, + 0x10 | ps_tdma_byte4_modify); + break; + case 14: + halbtc8822b2ant_set_fw_pstdma(btcoexist, 0x61, 0x20, + 0x03, 0x11, 0x11); + break; + case 15: + halbtc8822b2ant_set_fw_pstdma(btcoexist, 0x61, 0x10, + 0x03, 0x11, 0x14); + break; + case 16: + halbtc8822b2ant_set_fw_pstdma(btcoexist, 0x61, 0x10, + 0x03, 0x11, 0x15); + break; + case 21: + halbtc8822b2ant_set_fw_pstdma(btcoexist, 0x61, 0x30, + 0x03, 0x11, 0x10); + break; + case 22: + halbtc8822b2ant_set_fw_pstdma(btcoexist, 0x61, 0x25, + 0x03, 0x11, 0x10); + break; + case 23: + halbtc8822b2ant_set_fw_pstdma(btcoexist, 0x61, 0x10, + 0x03, 0x11, 0x10); + break; + case 51: + halbtc8822b2ant_set_fw_pstdma( + btcoexist, 0x61, 0x10, 0x03, 0x91, + 0x10 | ps_tdma_byte4_modify); + break; + case 101: + halbtc8822b2ant_set_fw_pstdma( + btcoexist, 0x61, 0x25, 0x03, 0x11, + 0x11 | ps_tdma_byte4_modify); + break; + case 102: + halbtc8822b2ant_set_fw_pstdma( + btcoexist, 0x61, 0x35, 0x03, 0x11, + 0x11 | ps_tdma_byte4_modify); + break; + case 103: + halbtc8822b2ant_set_fw_pstdma( + btcoexist, 0x51, 0x3a, 0x3, 0x10, + 0x50 | ps_tdma_byte4_modify); + break; + case 104: + halbtc8822b2ant_set_fw_pstdma( + btcoexist, 0x51, 0x21, 0x3, 0x10, + 0x50 | ps_tdma_byte4_modify); + break; + case 105: + halbtc8822b2ant_set_fw_pstdma( + btcoexist, 0x51, 0x30, 0x3, 0x10, + 0x50 | ps_tdma_byte4_modify); + break; + case 106: + halbtc8822b2ant_set_fw_pstdma( + btcoexist, 0x51, 0x10, 0x3, 0x10, + 0x50 | ps_tdma_byte4_modify); + break; + case 107: + halbtc8822b2ant_set_fw_pstdma( + btcoexist, 0x51, 0x10, 0x7, 0x10, + 0x54 | ps_tdma_byte4_modify); + break; + case 108: + halbtc8822b2ant_set_fw_pstdma( + btcoexist, 0x51, 0x30, 0x3, 0x10, + 0x50 | ps_tdma_byte4_modify); + break; + case 109: + halbtc8822b2ant_set_fw_pstdma( + btcoexist, 0x51, 0x10, 0x03, 0x10, + 0x54 | ps_tdma_byte4_modify); + break; + case 110: + halbtc8822b2ant_set_fw_pstdma( + btcoexist, 0x55, 0x30, 0x03, 0x10, + 0x50 | ps_tdma_byte4_modify); + break; + case 111: + halbtc8822b2ant_set_fw_pstdma( + btcoexist, 0x61, 0x25, 0x03, 0x11, + 0x11 | ps_tdma_byte4_modify); + break; + case 151: + halbtc8822b2ant_set_fw_pstdma( + btcoexist, 0x51, 0x10, 0x03, 0x10, + 0x50 | ps_tdma_byte4_modify); + break; + } + } else { + /* disable PS tdma */ + switch (type) { + case 0: + halbtc8822b2ant_set_fw_pstdma(btcoexist, 0x0, 0x0, 0x0, + 0x40, 0x0); + break; + case 1: + halbtc8822b2ant_set_fw_pstdma(btcoexist, 0x0, 0x0, 0x0, + 0x48, 0x0); + break; + default: + halbtc8822b2ant_set_fw_pstdma(btcoexist, 0x0, 0x0, 0x0, + 0x40, 0x0); + break; + } + } + + if (!coex_sta->is_set_ps_state_fail) { + /* update pre state */ + coex_dm->pre_ps_tdma_on = coex_dm->cur_ps_tdma_on; + coex_dm->pre_ps_tdma = coex_dm->cur_ps_tdma; + } +} + +/*anttenna control by bb mac bt antdiv pta to write 0x4c 0xcb4,0xcbd*/ +static void halbtc8822b2ant_set_ext_ant_switch(struct btc_coexist *btcoexist, + bool force_exec, u8 ctrl_type, + u8 pos_type) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + bool switch_polatiry_inverse = false; + u8 regval_0xcbc = 0, regval_0x64; + u32 u32tmp1 = 0, u32tmp2 = 0, u32tmp3 = 0; + + if (!rfe_type->ext_ant_switch_exist) + return; + + coex_dm->cur_ext_ant_switch_status = (ctrl_type << 8) + pos_type; + + if (!force_exec) { + if (coex_dm->pre_ext_ant_switch_status == + coex_dm->cur_ext_ant_switch_status) + return; + } + coex_dm->pre_ext_ant_switch_status = coex_dm->cur_ext_ant_switch_status; + + /* Ext switch buffer mux */ + btcoexist->btc_write_1byte(btcoexist, 0x974, 0xff); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x1991, 0x3, 0x0); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcbe, 0x8, 0x0); + + switch (ctrl_type) { + default: + case BT_8822B_2ANT_EXT_ANT_SWITCH_CTRL_BY_BBSW: + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4e, 0x80, + 0x0); /* 0x4c[23] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4f, 0x01, + 0x1); /* 0x4c[24] = 1 */ + /* BB SW, DPDT use RFE_ctrl8 and RFE_ctrl9 as conctrol pin */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb4, 0xff, + 0x77); + + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcbd, 0x03, 01); + + break; + case BT_8822B_2ANT_EXT_ANT_SWITCH_CTRL_BY_PTA: + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4e, 0x80, + 0x0); /* 0x4c[23] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4f, 0x01, + 0x1); /* 0x4c[24] = 1 */ + /* PTA, DPDT use RFE_ctrl8 and RFE_ctrl9 as conctrol pin */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb4, 0xff, + 0x66); + + /* 0xcb4[29:28] = 2b'10 for no switch_polatiry_inverse, + * DPDT_SEL_N =1, DPDT_SEL_P =0 @ GNT_BT=1 + */ + regval_0xcbc = (!switch_polatiry_inverse ? 0x2 : 0x1); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcbc, 0x03, + regval_0xcbc); + + break; + case BT_8822B_2ANT_EXT_ANT_SWITCH_CTRL_BY_ANTDIV: + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4e, 0x80, + 0x0); /* 0x4c[23] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4f, 0x01, + 0x1); /* 0x4c[24] = 1 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb4, 0xff, + 0x88); + break; + case BT_8822B_2ANT_EXT_ANT_SWITCH_CTRL_BY_MAC: + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4e, 0x80, + 0x1); /* 0x4c[23] = 1 */ + + /* 0x64[0] = 1b'0 for no switch_polatiry_inverse, + * DPDT_SEL_N =1, DPDT_SEL_P =0 + */ + regval_0x64 = (!switch_polatiry_inverse ? 0x0 : 0x1); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x64, 0x1, + regval_0x64); + break; + case BT_8822B_2ANT_EXT_ANT_SWITCH_CTRL_BY_BT: + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4e, 0x80, + 0x0); /* 0x4c[23] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4f, 0x01, + 0x0); /* 0x4c[24] = 0 */ + + /* no setup required, because antenna switch control value by + * BT vendor 0x1c[1:0] + */ + break; + } + + /* PAPE, LNA_ON control by BT while WLAN off for current leakage issue*/ + if (ctrl_type == BT_8822B_2ANT_EXT_ANT_SWITCH_CTRL_BY_BT) { + btcoexist->btc_write_1byte_bitmask( + btcoexist, 0x67, 0x20, 0x0); /* PAPE 0x64[29] = 0 */ + btcoexist->btc_write_1byte_bitmask( + btcoexist, 0x67, 0x10, 0x0); /* LNA_ON 0x64[28] = 0 */ + } else { + btcoexist->btc_write_1byte_bitmask( + btcoexist, 0x67, 0x20, 0x1); /* PAPE 0x64[29] = 1 */ + btcoexist->btc_write_1byte_bitmask( + btcoexist, 0x67, 0x10, 0x1); /* LNA_ON 0x64[28] = 1 */ + } + + if (btcoexist->dbg_mode_2ant) { + u32tmp1 = btcoexist->btc_read_4byte(btcoexist, 0xcb4); + u32tmp2 = btcoexist->btc_read_4byte(btcoexist, 0x4c); + u32tmp3 = btcoexist->btc_read_4byte(btcoexist, 0x64) & 0xff; + + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], (After Ext Ant switch setup) 0xcb4 = 0x%08x, 0x4c = 0x%08x, 0x64= 0x%02x\n", + u32tmp1, u32tmp2, u32tmp3); + } +} + +/* rf4 type by efuse, and for ant at main aux inverse use, + * because is 2x2, and control types are the same, does not need + */ +static void halbtc8822b2ant_set_rfe_type(struct btc_coexist *btcoexist) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + + rfe_type->ext_band_switch_exist = false; + rfe_type->ext_band_switch_type = + BT_8822B_2ANT_EXT_BAND_SWITCH_USE_SPDT; /* SPDT; */ + rfe_type->ext_band_switch_ctrl_polarity = 0; + /* Ext switch buffer mux */ + btcoexist->btc_write_1byte(btcoexist, 0x974, 0xff); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x1991, 0x3, 0x0); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcbe, 0x8, 0x0); + + if (rfe_type->ext_band_switch_exist) { + /* band switch use RFE_ctrl1 (pin name: PAPE_A) and + * RFE_ctrl3 (pin name: LNAON_A) + */ + + /* set RFE_ctrl1 as software control */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb0, 0xf0, 0x7); + + /* set RFE_ctrl3 as software control */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb1, 0xf0, 0x7); + } + + /* the following setup should be got from Efuse in the future */ + rfe_type->rfe_module_type = board_info->rfe_type; + + rfe_type->ext_ant_switch_ctrl_polarity = 0; + + switch (rfe_type->rfe_module_type) { + case 0: + default: + rfe_type->ext_ant_switch_exist = true; + rfe_type->ext_ant_switch_type = + BT_8822B_2ANT_EXT_ANT_SWITCH_USE_SPDT; + break; + case 1: + rfe_type->ext_ant_switch_exist = true; + rfe_type->ext_ant_switch_type = + BT_8822B_2ANT_EXT_ANT_SWITCH_USE_SPDT; + break; + case 2: + rfe_type->ext_ant_switch_exist = true; + rfe_type->ext_ant_switch_type = + BT_8822B_2ANT_EXT_ANT_SWITCH_USE_SPDT; + break; + case 3: + rfe_type->ext_ant_switch_exist = true; + rfe_type->ext_ant_switch_type = + BT_8822B_2ANT_EXT_ANT_SWITCH_USE_SPDT; + break; + case 4: + rfe_type->ext_ant_switch_exist = true; + rfe_type->ext_ant_switch_type = + BT_8822B_2ANT_EXT_ANT_SWITCH_USE_SPDT; + break; + case 5: + rfe_type->ext_ant_switch_exist = true; + rfe_type->ext_ant_switch_type = + BT_8822B_2ANT_EXT_ANT_SWITCH_USE_SPDT; + break; + case 6: + rfe_type->ext_ant_switch_exist = true; + rfe_type->ext_ant_switch_type = + BT_8822B_2ANT_EXT_ANT_SWITCH_USE_SPDT; + break; + case 7: + rfe_type->ext_ant_switch_exist = true; + rfe_type->ext_ant_switch_type = + BT_8822B_2ANT_EXT_ANT_SWITCH_USE_SPDT; + break; + } +} + +/* set gnt_wl gnt_bt control by sw high low, or hwpta while in + * power on, ini, wlan off, wlan only, wl2g non-currrent, wl2g current, wl5g + */ +static void halbtc8822b2ant_set_ant_path(struct btc_coexist *btcoexist, + u8 ant_pos_type, bool force_exec, + u8 phase) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + u8 u8tmp = 0; + u32 u32tmp1 = 0; + u32 u32tmp2 = 0, u32tmp3 = 0; + + u32tmp1 = halbtc8822b2ant_ltecoex_indirect_read_reg(btcoexist, 0x38); + + /* To avoid indirect access fail */ + if (((u32tmp1 & 0xf000) >> 12) != ((u32tmp1 & 0x0f00) >> 8)) { + force_exec = true; + coex_sta->gnt_error_cnt++; + } + + /* Ext switch buffer mux */ + btcoexist->btc_write_1byte(btcoexist, 0x974, 0xff); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x1991, 0x3, 0x0); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcbe, 0x8, 0x0); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4e, 0x80, + 0x0); /* 0x4c[23] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4f, 0x01, + 0x1); /* 0x4c[24] = 1 */ + + coex_dm->cur_ant_pos_type = (ant_pos_type << 8) + phase; + + if (!force_exec) { + if (coex_dm->cur_ant_pos_type == coex_dm->pre_ant_pos_type) + return; + } + + coex_dm->pre_ant_pos_type = coex_dm->cur_ant_pos_type; + + if (btcoexist->dbg_mode_2ant) { + u32tmp1 = halbtc8822b2ant_ltecoex_indirect_read_reg(btcoexist, + 0x38); + u32tmp2 = halbtc8822b2ant_ltecoex_indirect_read_reg(btcoexist, + 0x54); + u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x73); + + u32tmp3 = btcoexist->btc_read_4byte(btcoexist, 0xcb4); + + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], (Before Ant Setup) 0xcb4 = 0x%x, 0x73 = 0x%x, 0x38= 0x%x, 0x54= 0x%x\n", + u32tmp3, u8tmp, u32tmp1, u32tmp2); + } + + switch (phase) { + case BT_8822B_2ANT_PHASE_COEX_POWERON: + + /* set Path control owner to WL at initial step */ + halbtc8822b2ant_ltecoex_pathcontrol_owner( + btcoexist, BT_8822B_2ANT_PCO_BTSIDE); + + /* set GNT_BT to SW high */ + halbtc8822b2ant_ltecoex_set_gnt_bt( + btcoexist, BT_8822B_2ANT_GNT_BLOCK_RFC_BB, + BT_8822B_2ANT_GNT_TYPE_CTRL_BY_SW, + BT_8822B_2ANT_SIG_STA_SET_TO_HIGH); + /* Set GNT_WL to SW high */ + halbtc8822b2ant_ltecoex_set_gnt_wl( + btcoexist, BT_8822B_2ANT_GNT_BLOCK_RFC_BB, + BT_8822B_2ANT_GNT_TYPE_CTRL_BY_SW, + BT_8822B_2ANT_SIG_STA_SET_TO_HIGH); + + coex_sta->run_time_state = false; + + break; + case BT_8822B_2ANT_PHASE_COEX_INIT: + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4e, 0x80, + 0x0); /* 0x4c[23] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4f, 0x01, + 0x1); /* 0x4c[24] = 1 */ + /* Disable LTE Coex Function in WiFi side + * (this should be on if LTE coex is required) + */ + halbtc8822b2ant_ltecoex_enable(btcoexist, 0x0); + + /* GNT_WL_LTE always = 1 + * (this should be config if LTE coex is required) + */ + halbtc8822b2ant_ltecoex_set_coex_table( + btcoexist, BT_8822B_2ANT_CTT_WL_VS_LTE, 0xffff); + + /* GNT_BT_LTE always = 1 + * (this should be config if LTE coex is required) + */ + halbtc8822b2ant_ltecoex_set_coex_table( + btcoexist, BT_8822B_2ANT_CTT_BT_VS_LTE, 0xffff); + + /* set Path control owner to WL at initial step */ + halbtc8822b2ant_ltecoex_pathcontrol_owner( + btcoexist, BT_8822B_2ANT_PCO_WLSIDE); + + /* set GNT_BT to SW high */ + halbtc8822b2ant_ltecoex_set_gnt_bt( + btcoexist, BT_8822B_2ANT_GNT_BLOCK_RFC_BB, + BT_8822B_2ANT_GNT_TYPE_CTRL_BY_SW, + BT_8822B_2ANT_SIG_STA_SET_TO_HIGH); + /* Set GNT_WL to SW high */ + halbtc8822b2ant_ltecoex_set_gnt_wl( + btcoexist, BT_8822B_2ANT_GNT_BLOCK_RFC_BB, + BT_8822B_2ANT_GNT_TYPE_CTRL_BY_SW, + BT_8822B_2ANT_SIG_STA_SET_TO_HIGH); + + coex_sta->run_time_state = false; + + break; + case BT_8822B_2ANT_PHASE_WLANONLY_INIT: + /* Disable LTE Coex Function in WiFi side + * (this should be on if LTE coex is required) + */ + halbtc8822b2ant_ltecoex_enable(btcoexist, 0x0); + + /* GNT_WL_LTE always = 1 + * (this should be config if LTE coex is required) + */ + halbtc8822b2ant_ltecoex_set_coex_table( + btcoexist, BT_8822B_2ANT_CTT_WL_VS_LTE, 0xffff); + + /* GNT_BT_LTE always = 1 + * (this should be config if LTE coex is required) + */ + halbtc8822b2ant_ltecoex_set_coex_table( + btcoexist, BT_8822B_2ANT_CTT_BT_VS_LTE, 0xffff); + + /* set Path control owner to WL at initial step */ + halbtc8822b2ant_ltecoex_pathcontrol_owner( + btcoexist, BT_8822B_2ANT_PCO_WLSIDE); + + /* set GNT_BT to SW Low */ + halbtc8822b2ant_ltecoex_set_gnt_bt( + btcoexist, BT_8822B_2ANT_GNT_BLOCK_RFC_BB, + BT_8822B_2ANT_GNT_TYPE_CTRL_BY_SW, + BT_8822B_2ANT_SIG_STA_SET_TO_LOW); + /* Set GNT_WL to SW high */ + halbtc8822b2ant_ltecoex_set_gnt_wl( + btcoexist, BT_8822B_2ANT_GNT_BLOCK_RFC_BB, + BT_8822B_2ANT_GNT_TYPE_CTRL_BY_SW, + BT_8822B_2ANT_SIG_STA_SET_TO_HIGH); + + coex_sta->run_time_state = false; + + break; + case BT_8822B_2ANT_PHASE_WLAN_OFF: + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4e, 0x80, + 0x0); /* 0x4c[23] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4f, 0x01, + 0x0); /* 0x4c[24] = 0 */ + /* Disable LTE Coex Function in WiFi side */ + halbtc8822b2ant_ltecoex_enable(btcoexist, 0x0); + + /* set Path control owner to BT */ + halbtc8822b2ant_ltecoex_pathcontrol_owner( + btcoexist, BT_8822B_2ANT_PCO_BTSIDE); + + /* Set Ext Ant Switch to BT control at wifi off step */ + halbtc8822b2ant_set_ext_ant_switch( + btcoexist, FORCE_EXEC, + BT_8822B_2ANT_EXT_ANT_SWITCH_CTRL_BY_BT, + BT_8822B_2ANT_EXT_ANT_SWITCH_MAIN_TO_NOCARE); + coex_sta->run_time_state = false; + break; + case BT_8822B_2ANT_PHASE_2G_RUNTIME: + case BT_8822B_2ANT_PHASE_2G_RUNTIME_CONCURRENT: + + /* set Path control owner to WL at runtime step */ + halbtc8822b2ant_ltecoex_pathcontrol_owner( + btcoexist, BT_8822B_2ANT_PCO_WLSIDE); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb4, 0xff, + 0x66); + if (phase == BT_8822B_2ANT_PHASE_2G_RUNTIME_CONCURRENT) { + /* set GNT_BT to PTA */ + halbtc8822b2ant_ltecoex_set_gnt_bt( + btcoexist, BT_8822B_2ANT_GNT_BLOCK_RFC_BB, + BT_8822B_2ANT_GNT_TYPE_CTRL_BY_PTA, + BT_8822B_2ANT_SIG_STA_SET_BY_HW); + + /* Set GNT_WL to SW High */ + halbtc8822b2ant_ltecoex_set_gnt_wl( + btcoexist, BT_8822B_2ANT_GNT_BLOCK_RFC_BB, + BT_8822B_2ANT_GNT_TYPE_CTRL_BY_SW, + BT_8822B_2ANT_SIG_STA_SET_TO_HIGH); + } else { + /* set GNT_BT to PTA */ + halbtc8822b2ant_ltecoex_set_gnt_bt( + btcoexist, BT_8822B_2ANT_GNT_BLOCK_RFC_BB, + BT_8822B_2ANT_GNT_TYPE_CTRL_BY_PTA, + BT_8822B_2ANT_SIG_STA_SET_BY_HW); + + /* Set GNT_WL to PTA */ + halbtc8822b2ant_ltecoex_set_gnt_wl( + btcoexist, BT_8822B_2ANT_GNT_BLOCK_RFC_BB, + BT_8822B_2ANT_GNT_TYPE_CTRL_BY_PTA, + BT_8822B_2ANT_SIG_STA_SET_BY_HW); + } + + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ************* under2g 0xcbd setting =2 *************\n"); + + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcbd, 0x03, 02); + break; + + case BT_8822B_2ANT_PHASE_5G_RUNTIME: + + /* set Path control owner to WL at runtime step */ + halbtc8822b2ant_ltecoex_pathcontrol_owner( + btcoexist, BT_8822B_2ANT_PCO_WLSIDE); + + /* set GNT_BT to SW Hi */ + halbtc8822b2ant_ltecoex_set_gnt_bt( + btcoexist, BT_8822B_2ANT_GNT_BLOCK_RFC_BB, + BT_8822B_2ANT_GNT_TYPE_CTRL_BY_SW, + BT_8822B_2ANT_SIG_STA_SET_TO_HIGH); + /* Set GNT_WL to SW Hi */ + halbtc8822b2ant_ltecoex_set_gnt_wl( + btcoexist, BT_8822B_2ANT_GNT_BLOCK_RFC_BB, + BT_8822B_2ANT_GNT_TYPE_CTRL_BY_SW, + BT_8822B_2ANT_SIG_STA_SET_TO_HIGH); + coex_sta->run_time_state = true; + + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ************* under5g 0xcbd setting =1 *************\n"); + + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcbd, 0x03, 01); + + break; + case BT_8822B_2ANT_PHASE_BTMPMODE: + /* Disable LTE Coex Function in WiFi side */ + halbtc8822b2ant_ltecoex_enable(btcoexist, 0x0); + + /* set Path control owner to WL */ + halbtc8822b2ant_ltecoex_pathcontrol_owner( + btcoexist, BT_8822B_2ANT_PCO_WLSIDE); + + /* set GNT_BT to SW Hi */ + halbtc8822b2ant_ltecoex_set_gnt_bt( + btcoexist, BT_8822B_2ANT_GNT_BLOCK_RFC_BB, + BT_8822B_2ANT_GNT_TYPE_CTRL_BY_SW, + BT_8822B_2ANT_SIG_STA_SET_TO_HIGH); + + /* Set GNT_WL to SW Lo */ + halbtc8822b2ant_ltecoex_set_gnt_wl( + btcoexist, BT_8822B_2ANT_GNT_BLOCK_RFC_BB, + BT_8822B_2ANT_GNT_TYPE_CTRL_BY_SW, + BT_8822B_2ANT_SIG_STA_SET_TO_LOW); + + coex_sta->run_time_state = false; + break; + } + + if (btcoexist->dbg_mode_2ant) { + u32tmp1 = halbtc8822b2ant_ltecoex_indirect_read_reg(btcoexist, + 0x38); + u32tmp2 = halbtc8822b2ant_ltecoex_indirect_read_reg(btcoexist, + 0x54); + u32tmp3 = btcoexist->btc_read_4byte(btcoexist, 0xcb4); + u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x73); + + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], (After Ant-Setup phase---%d) 0xcb4 = 0x%x, 0x73 = 0x%x, 0x38= 0x%x, 0x54= 0x%x\n", + phase, u32tmp3, u8tmp, u32tmp1, u32tmp2); + } +} + +static u8 halbtc8822b2ant_action_algorithm(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + bool bt_hs_on = false; + u8 algorithm = BT_8822B_2ANT_COEX_ALGO_UNDEFINED; + u8 num_of_diff_profile = 0; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + + if (!bt_link_info->bt_link_exist) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], No BT link exists!!!\n"); + return algorithm; + } + + if (bt_link_info->sco_exist) + num_of_diff_profile++; + if (bt_link_info->hid_exist) + num_of_diff_profile++; + if (bt_link_info->pan_exist) + num_of_diff_profile++; + if (bt_link_info->a2dp_exist) + num_of_diff_profile++; + + if (num_of_diff_profile == 0) { + if (bt_link_info->acl_busy) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], No-Profile busy\n"); + algorithm = BT_8822B_2ANT_COEX_ALGO_NOPROFILEBUSY; + } + } else if ((bt_link_info->a2dp_exist) && (coex_sta->is_bt_a2dp_sink)) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], A2DP Sink\n"); + algorithm = BT_8822B_2ANT_COEX_ALGO_A2DPSINK; + } else if (num_of_diff_profile == 1) { + if (bt_link_info->sco_exist) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], SCO only\n"); + algorithm = BT_8822B_2ANT_COEX_ALGO_SCO; + } else { + if (bt_link_info->hid_exist) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], HID only\n"); + algorithm = BT_8822B_2ANT_COEX_ALGO_HID; + } else if (bt_link_info->a2dp_exist) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], A2DP only\n"); + algorithm = BT_8822B_2ANT_COEX_ALGO_A2DP; + } else if (bt_link_info->pan_exist) { + if (bt_hs_on) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, + DBG_LOUD, + "[BTCoex], PAN(HS) only\n"); + algorithm = + BT_8822B_2ANT_COEX_ALGO_PANHS; + } else { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, + DBG_LOUD, + "[BTCoex], PAN(EDR) only\n"); + algorithm = + BT_8822B_2ANT_COEX_ALGO_PANEDR; + } + } + } + } else if (num_of_diff_profile == 2) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], SCO + HID\n"); + algorithm = BT_8822B_2ANT_COEX_ALGO_SCO; + } else if (bt_link_info->a2dp_exist) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], SCO + A2DP ==> A2DP\n"); + algorithm = BT_8822B_2ANT_COEX_ALGO_A2DP; + } else if (bt_link_info->pan_exist) { + if (bt_hs_on) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, + DBG_LOUD, + "[BTCoex], SCO + PAN(HS)\n"); + algorithm = BT_8822B_2ANT_COEX_ALGO_SCO; + } else { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, + DBG_LOUD, + "[BTCoex], SCO + PAN(EDR)\n"); + algorithm = + BT_8822B_2ANT_COEX_ALGO_PANEDR; + } + } + } else { + if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { + { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, + DBG_LOUD, + "[BTCoex], HID + A2DP\n"); + algorithm = + BT_8822B_2ANT_COEX_ALGO_HID_A2DP; + } + } else if (bt_link_info->hid_exist && + bt_link_info->pan_exist) { + if (bt_hs_on) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, + DBG_LOUD, + "[BTCoex], HID + PAN(HS)\n"); + algorithm = BT_8822B_2ANT_COEX_ALGO_HID; + } else { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, + DBG_LOUD, + "[BTCoex], HID + PAN(EDR)\n"); + algorithm = + BT_8822B_2ANT_COEX_ALGO_PANEDR_HID; + } + } else if (bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, + DBG_LOUD, + "[BTCoex], A2DP + PAN(HS)\n"); + algorithm = + BT_8822B_2ANT_COEX_ALGO_A2DP_PANHS; + } else { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, + DBG_LOUD, + "[BTCoex], A2DP + PAN(EDR)\n"); + algorithm = + BT_8822B_2ANT_COEX_ALGO_PANEDR_A2DP; + } + } + } + } else if (num_of_diff_profile == 3) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], SCO + HID + A2DP ==> HID + A2DP\n"); + algorithm = BT_8822B_2ANT_COEX_ALGO_HID_A2DP; + } else if (bt_link_info->hid_exist && + bt_link_info->pan_exist) { + if (bt_hs_on) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, + DBG_LOUD, + "[BTCoex], SCO + HID + PAN(HS)\n"); + algorithm = + BT_8822B_2ANT_COEX_ALGO_PANEDR_HID; + } else { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, + DBG_LOUD, + "[BTCoex], SCO + HID + PAN(EDR)\n"); + algorithm = + BT_8822B_2ANT_COEX_ALGO_PANEDR_HID; + } + } else if (bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, + DBG_LOUD, + "[BTCoex], SCO + A2DP + PAN(HS)\n"); + algorithm = + BT_8822B_2ANT_COEX_ALGO_A2DP_PANHS; + } else { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, + DBG_LOUD, + "[BTCoex], SCO + A2DP + PAN(EDR) ==> HID\n"); + algorithm = + BT_8822B_2ANT_COEX_ALGO_PANEDR_A2DP; + } + } + } else { + if (bt_link_info->hid_exist && + bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, + DBG_LOUD, + "[BTCoex], HID + A2DP + PAN(HS)\n"); + algorithm = + BT_8822B_2ANT_COEX_ALGO_HID_A2DP_PANEDR; + } else { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, + DBG_LOUD, + "[BTCoex], HID + A2DP + PAN(EDR)\n"); + algorithm = + BT_8822B_2ANT_COEX_ALGO_HID_A2DP_PANEDR; + } + } + } + } else if (num_of_diff_profile >= 3) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist && + bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, + DBG_LOUD, + "[BTCoex], Error!!! SCO + HID + A2DP + PAN(HS)\n"); + algorithm = + BT_8822B_2ANT_COEX_ALGO_HID_A2DP_PANEDR; + } else { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, + DBG_LOUD, + "[BTCoex], SCO + HID + A2DP + PAN(EDR)==>PAN(EDR)+HID\n"); + algorithm = + BT_8822B_2ANT_COEX_ALGO_HID_A2DP_PANEDR; + } + } + } + } + + return algorithm; +} + +static void halbtc8822b2ant_action_coex_all_off(struct btc_coexist *btcoexist) +{ + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 5); + + /* fw all off */ + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); +} + +static void halbtc8822b2ant_action_wifi_under5g(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + + /* fw all off */ + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ************* under5g *************\n"); + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + + halbtc8822b2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, FORCE_EXEC, + BT_8822B_2ANT_PHASE_5G_RUNTIME); +} + +static void +halbtc8822b2ant_action_wifi_native_lps(struct btc_coexist *btcoexist) +{ + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 5); + + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); +} + +static void halbtc8822b2ant_action_bt_inquiry(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + bool wifi_connected = false; + bool wifi_scan = false, wifi_link = false, wifi_roam = false; + bool wifi_busy = false; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &wifi_scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &wifi_link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &wifi_roam); + + if ((coex_sta->bt_create_connection) && + ((wifi_link) || (wifi_roam) || (wifi_scan) || (wifi_busy) || + (coex_sta->wifi_is_high_pri_task))) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Wifi link/roam/Scan/busy/hi-pri-task + BT Inq/Page!!\n"); + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 8); + + if ((bt_link_info->a2dp_exist) && (!bt_link_info->pan_exist)) + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 15); + else + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 11); + } else if ((!wifi_connected) && (!wifi_scan)) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Wifi no-link + no-scan + BT Inq/Page!!\n"); + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 5); + + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } else if (bt_link_info->pan_exist) { + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 22); + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 8); + + } else if (bt_link_info->a2dp_exist) { + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 8); + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 10); + } else { + if ((wifi_link) || (wifi_roam) || (wifi_scan) || (wifi_busy) || + (coex_sta->wifi_is_high_pri_task)) + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 21); + else + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 23); + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 8); + } + + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, FORCE_EXEC, 0xd8); +} + +static void +halbtc8822b2ant_action_wifi_link_process(struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, FORCE_EXEC, 0xd4); + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 8); + + if (bt_link_info->pan_exist) { + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 22); + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 8); + + } else if (bt_link_info->a2dp_exist) { + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 16); + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 8); + } else { + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 21); + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 8); + } +} + +static void +halbtc8822b2ant_action_wifi_nonconnected(struct btc_coexist *btcoexist) +{ + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + /* fw all off */ + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); +} + +static void halbtc8822b2ant_action_bt_relink(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], run bt multi link function\n"); + + if (coex_sta->is_bt_multi_link) + return; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], run bt re-link function\n"); + + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 5); +} + +static void halbtc8822b2ant_action_bt_idle(struct btc_coexist *btcoexist) +{ + bool wifi_busy = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + if (!wifi_busy) { + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 8); + + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 14); + } else { /* if wl busy */ + + if (BT_8822B_2ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) { + halbtc8822b2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 0); + + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 0); + } else { + halbtc8822b2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 8); + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 12); + } + } + + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, FORCE_EXEC, 0xd8); +} + +/* SCO only or SCO+PAN(HS) */ +static void halbtc8822b2ant_action_sco(struct btc_coexist *btcoexist) +{ + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state, bt_rssi_state; + + static u8 prewifi_rssi_state2 = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state2 = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state2, bt_rssi_state2; + bool wifi_busy = false; + u32 wifi_bw = 1; + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + wifi_rssi_state = halbtc8822b2ant_wifi_rssi_state( + btcoexist, &prewifi_rssi_state, 2, coex_sta->wifi_coex_thres, + 0); + + wifi_rssi_state2 = halbtc8822b2ant_wifi_rssi_state( + btcoexist, &prewifi_rssi_state2, 2, coex_sta->wifi_coex_thres2, + 0); + + bt_rssi_state = halbtc8822b2ant_bt_rssi_state( + btcoexist, &pre_bt_rssi_state, 2, coex_sta->bt_coex_thres, 0); + + bt_rssi_state2 = halbtc8822b2ant_bt_rssi_state( + btcoexist, &pre_bt_rssi_state2, 2, coex_sta->bt_coex_thres2, 0); + + if (BTC_RSSI_HIGH(wifi_rssi_state) && BTC_RSSI_HIGH(bt_rssi_state)) { + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 5); + + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } else { + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = false; + + if (coex_sta->is_esco_mode) + halbtc8822b2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + else /* 2-Ant free run if SCO mode */ + halbtc8822b2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 0); + + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 8); + } +} + +static void halbtc8822b2ant_action_hid(struct btc_coexist *btcoexist) +{ + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state, bt_rssi_state; + + static u8 prewifi_rssi_state2 = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state2 = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state2, bt_rssi_state2; + bool wifi_busy = false; + u32 wifi_bw = 1; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + wifi_rssi_state = halbtc8822b2ant_wifi_rssi_state( + btcoexist, &prewifi_rssi_state, 2, coex_sta->wifi_coex_thres, + 0); + + wifi_rssi_state2 = halbtc8822b2ant_wifi_rssi_state( + btcoexist, &prewifi_rssi_state2, 2, coex_sta->wifi_coex_thres2, + 0); + + bt_rssi_state = halbtc8822b2ant_bt_rssi_state( + btcoexist, &pre_bt_rssi_state, 2, coex_sta->bt_coex_thres, 0); + + bt_rssi_state2 = halbtc8822b2ant_bt_rssi_state( + btcoexist, &pre_bt_rssi_state2, 2, coex_sta->bt_coex_thres2, 0); + + if (BTC_RSSI_HIGH(wifi_rssi_state) && BTC_RSSI_HIGH(bt_rssi_state)) { + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } else { + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = false; + + if (coex_sta->is_hid_low_pri_tx_overhead) { + halbtc8822b2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 108); + } else if (wifi_bw == 0) { /* if 11bg mode */ + + halbtc8822b2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 8); + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 111); + } else { + halbtc8822b2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 8); + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 111); + } + } +} + +static void halbtc8822b2ant_action_a2dpsink(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state, bt_rssi_state; + + static u8 prewifi_rssi_state2 = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state2 = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state2, bt_rssi_state2; + bool wifi_busy = false, wifi_turbo = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, + &coex_sta->scan_ap_num); + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "############# [BTCoex], scan_ap_num = %d, wl_noisy = %d\n", + coex_sta->scan_ap_num, coex_sta->wl_noisy_level); + + if ((wifi_busy) && (coex_sta->wl_noisy_level == 0)) + wifi_turbo = true; + + wifi_rssi_state = halbtc8822b2ant_wifi_rssi_state( + btcoexist, &prewifi_rssi_state, 2, coex_sta->wifi_coex_thres, + 0); + + wifi_rssi_state2 = halbtc8822b2ant_wifi_rssi_state( + btcoexist, &prewifi_rssi_state2, 2, coex_sta->wifi_coex_thres2, + 0); + + bt_rssi_state = halbtc8822b2ant_bt_rssi_state( + btcoexist, &pre_bt_rssi_state, 2, coex_sta->bt_coex_thres, 0); + + bt_rssi_state2 = halbtc8822b2ant_bt_rssi_state( + btcoexist, &pre_bt_rssi_state2, 2, coex_sta->bt_coex_thres2, 0); + + if (BTC_RSSI_HIGH(wifi_rssi_state) && BTC_RSSI_HIGH(bt_rssi_state)) { + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } else if (BTC_RSSI_HIGH(wifi_rssi_state2) && + BTC_RSSI_HIGH(bt_rssi_state2)) { + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xc8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + + if (wifi_busy) + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 1); + else + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 16); + } else { + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = true; + + if ((coex_sta->bt_relink_downcount != 0) && (wifi_busy)) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "############# [BTCoex], BT Re-Link + A2DP + WL busy\n"); + + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 0); + halbtc8822b2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 5); + + } else { + halbtc8822b2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 8); + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 105); + } + } +} + +/* A2DP only / PAN(EDR) only/ A2DP+PAN(HS) */ +static void halbtc8822b2ant_action_a2dp(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state, bt_rssi_state; + + static u8 prewifi_rssi_state2 = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state2 = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state2, bt_rssi_state2; + bool wifi_busy = false, wifi_turbo = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, + &coex_sta->scan_ap_num); + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "############# [BTCoex], scan_ap_num = %d, wl_noisy = %d\n", + coex_sta->scan_ap_num, coex_sta->wl_noisy_level); + + if ((wifi_busy) && (coex_sta->wl_noisy_level == 0)) + wifi_turbo = true; + + wifi_rssi_state = halbtc8822b2ant_wifi_rssi_state( + btcoexist, &prewifi_rssi_state, 2, coex_sta->wifi_coex_thres, + 0); + + wifi_rssi_state2 = halbtc8822b2ant_wifi_rssi_state( + btcoexist, &prewifi_rssi_state2, 2, coex_sta->wifi_coex_thres2, + 0); + + bt_rssi_state = halbtc8822b2ant_bt_rssi_state( + btcoexist, &pre_bt_rssi_state, 2, coex_sta->bt_coex_thres, 0); + + bt_rssi_state2 = halbtc8822b2ant_bt_rssi_state( + btcoexist, &pre_bt_rssi_state2, 2, coex_sta->bt_coex_thres2, 0); + + if (BTC_RSSI_HIGH(wifi_rssi_state) && BTC_RSSI_HIGH(bt_rssi_state)) { + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } else if (BTC_RSSI_HIGH(wifi_rssi_state2) && + BTC_RSSI_HIGH(bt_rssi_state2)) { + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xc8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + + if (wifi_busy) + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 1); + else + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 16); + } else { + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = true; + + if ((coex_sta->bt_relink_downcount != 0) && (wifi_busy)) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "############# [BTCoex], BT Re-Link + A2DP + WL busy\n"); + + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 0); + halbtc8822b2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 5); + + } else { + if (wifi_turbo) + halbtc8822b2ant_coex_table_with_type( + btcoexist, NORMAL_EXEC, 10); + else + halbtc8822b2ant_coex_table_with_type( + btcoexist, NORMAL_EXEC, 10); + + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 109); + } + } +} + +static void halbtc8822b2ant_action_pan_edr(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state, bt_rssi_state; + + static u8 prewifi_rssi_state2 = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state2 = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state2, bt_rssi_state2; + bool wifi_busy = false, wifi_turbo = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, + &coex_sta->scan_ap_num); + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "############# [BTCoex], scan_ap_num = %d, wl_noisy = %d\n", + coex_sta->scan_ap_num, coex_sta->wl_noisy_level); + + if ((wifi_busy) && (coex_sta->wl_noisy_level == 0)) + wifi_turbo = true; + + wifi_rssi_state = halbtc8822b2ant_wifi_rssi_state( + btcoexist, &prewifi_rssi_state, 2, coex_sta->wifi_coex_thres, + 0); + + wifi_rssi_state2 = halbtc8822b2ant_wifi_rssi_state( + btcoexist, &prewifi_rssi_state2, 2, coex_sta->wifi_coex_thres2, + 0); + + bt_rssi_state = halbtc8822b2ant_bt_rssi_state( + btcoexist, &pre_bt_rssi_state, 2, coex_sta->bt_coex_thres, 0); + + bt_rssi_state2 = halbtc8822b2ant_bt_rssi_state( + btcoexist, &pre_bt_rssi_state2, 2, coex_sta->bt_coex_thres2, 0); + + if (BTC_RSSI_HIGH(wifi_rssi_state) && BTC_RSSI_HIGH(bt_rssi_state)) { + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } else if (BTC_RSSI_HIGH(wifi_rssi_state2) && + BTC_RSSI_HIGH(bt_rssi_state2)) { + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xc8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + + if (wifi_busy) + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 3); + else + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 4); + } else { + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = true; + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 8); + + if (wifi_busy) + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 103); + else + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 104); + } +} + +static void halbtc8822b2ant_action_hid_a2dp(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state, bt_rssi_state; + + static u8 prewifi_rssi_state2 = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state2 = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state2, bt_rssi_state2; + bool wifi_busy = false; + u32 wifi_bw = 1; + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + wifi_rssi_state = halbtc8822b2ant_wifi_rssi_state( + btcoexist, &prewifi_rssi_state, 2, coex_sta->wifi_coex_thres, + 0); + + wifi_rssi_state2 = halbtc8822b2ant_wifi_rssi_state( + btcoexist, &prewifi_rssi_state2, 2, coex_sta->wifi_coex_thres2, + 0); + + bt_rssi_state = halbtc8822b2ant_bt_rssi_state( + btcoexist, &pre_bt_rssi_state, 2, coex_sta->bt_coex_thres, 0); + + bt_rssi_state2 = halbtc8822b2ant_bt_rssi_state( + btcoexist, &pre_bt_rssi_state2, 2, coex_sta->bt_coex_thres2, 0); + + if (BTC_RSSI_HIGH(wifi_rssi_state) && BTC_RSSI_HIGH(bt_rssi_state)) { + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } else if (BTC_RSSI_HIGH(wifi_rssi_state2) && + BTC_RSSI_HIGH(bt_rssi_state2)) { + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xc8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + + if (wifi_busy) + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 1); + else + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 16); + } else { + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = true; + + if ((coex_sta->bt_relink_downcount != 0) && (wifi_busy)) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "############# [BTCoex], BT Re-Link + A2DP + WL busy\n"); + + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 0); + halbtc8822b2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 5); + } else { + halbtc8822b2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 8); + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 109); + } + } +} + +static void halbtc8822b2ant_action_a2dp_pan_hs(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state, bt_rssi_state; + + static u8 prewifi_rssi_state2 = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state2 = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state2, bt_rssi_state2; + bool wifi_busy = false, wifi_turbo = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, + &coex_sta->scan_ap_num); + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "############# [BTCoex], scan_ap_num = %d, wl_noisy = %d\n", + coex_sta->scan_ap_num, coex_sta->wl_noisy_level); + + if ((wifi_busy) && (coex_sta->wl_noisy_level == 0)) + wifi_turbo = true; + + wifi_rssi_state = halbtc8822b2ant_wifi_rssi_state( + btcoexist, &prewifi_rssi_state, 2, coex_sta->wifi_coex_thres, + 0); + + wifi_rssi_state2 = halbtc8822b2ant_wifi_rssi_state( + btcoexist, &prewifi_rssi_state2, 2, coex_sta->wifi_coex_thres2, + 0); + + bt_rssi_state = halbtc8822b2ant_bt_rssi_state( + btcoexist, &pre_bt_rssi_state, 2, coex_sta->bt_coex_thres, 0); + + bt_rssi_state2 = halbtc8822b2ant_bt_rssi_state( + btcoexist, &pre_bt_rssi_state2, 2, coex_sta->bt_coex_thres2, 0); + + if (BTC_RSSI_HIGH(wifi_rssi_state) && BTC_RSSI_HIGH(bt_rssi_state)) { + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + /*halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0);*/ + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } else if (BTC_RSSI_HIGH(wifi_rssi_state2) && + BTC_RSSI_HIGH(bt_rssi_state2)) { + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xc8); + /*halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2);*/ + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + + if (wifi_busy) { + if ((coex_sta->a2dp_bit_pool > 40) && + (coex_sta->a2dp_bit_pool < 255)) + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 7); + else + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 5); + } else { + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 6); + } + } else { + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + /*halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0);*/ + + coex_dm->is_switch_to_1dot5_ant = true; + + if (wifi_turbo) + halbtc8822b2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 6); + else + halbtc8822b2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 7); + + if (wifi_busy) { + if ((coex_sta->a2dp_bit_pool > 40) && + (coex_sta->a2dp_bit_pool < 255)) + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 107); + else + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 105); + } else { + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 106); + } + } +} + +/* PAN(EDR)+A2DP */ +static void halbtc8822b2ant_action_pan_edr_a2dp(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state, bt_rssi_state; + + static u8 prewifi_rssi_state2 = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state2 = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state2, bt_rssi_state2; + bool wifi_busy = false, wifi_turbo = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, + &coex_sta->scan_ap_num); + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "############# [BTCoex], scan_ap_num = %d, wl_noisy = %d\n", + coex_sta->scan_ap_num, coex_sta->wl_noisy_level); + + if ((wifi_busy) && (coex_sta->wl_noisy_level == 0)) + wifi_turbo = true; + + wifi_rssi_state = halbtc8822b2ant_wifi_rssi_state( + btcoexist, &prewifi_rssi_state, 2, coex_sta->wifi_coex_thres, + 0); + + wifi_rssi_state2 = halbtc8822b2ant_wifi_rssi_state( + btcoexist, &prewifi_rssi_state2, 2, coex_sta->wifi_coex_thres2, + 0); + + bt_rssi_state = halbtc8822b2ant_bt_rssi_state( + btcoexist, &pre_bt_rssi_state, 2, coex_sta->bt_coex_thres, 0); + + bt_rssi_state2 = halbtc8822b2ant_bt_rssi_state( + btcoexist, &pre_bt_rssi_state2, 2, coex_sta->bt_coex_thres2, 0); + + if (BTC_RSSI_HIGH(wifi_rssi_state) && BTC_RSSI_HIGH(bt_rssi_state)) { + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } else if (BTC_RSSI_HIGH(wifi_rssi_state2) && + BTC_RSSI_HIGH(bt_rssi_state2)) { + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xc8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + + if (wifi_busy) { + if (((coex_sta->a2dp_bit_pool > 40) && + (coex_sta->a2dp_bit_pool < 255)) || + (!coex_sta->is_A2DP_3M)) + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 7); + else + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 5); + } else { + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 6); + } + } else { + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = true; + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 8); + if (wifi_busy) + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 107); + else + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 106); + } +} + +static void halbtc8822b2ant_action_pan_edr_hid(struct btc_coexist *btcoexist) +{ + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state, bt_rssi_state; + + static u8 prewifi_rssi_state2 = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state2 = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state2, bt_rssi_state2; + bool wifi_busy = false; + u32 wifi_bw = 1; + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + wifi_rssi_state = halbtc8822b2ant_wifi_rssi_state( + btcoexist, &prewifi_rssi_state, 2, coex_sta->wifi_coex_thres, + 0); + + wifi_rssi_state2 = halbtc8822b2ant_wifi_rssi_state( + btcoexist, &prewifi_rssi_state2, 2, coex_sta->wifi_coex_thres2, + 0); + + bt_rssi_state = halbtc8822b2ant_bt_rssi_state( + btcoexist, &pre_bt_rssi_state, 2, coex_sta->bt_coex_thres, 0); + + bt_rssi_state2 = halbtc8822b2ant_bt_rssi_state( + btcoexist, &pre_bt_rssi_state2, 2, coex_sta->bt_coex_thres2, 0); + + if (BTC_RSSI_HIGH(wifi_rssi_state) && BTC_RSSI_HIGH(bt_rssi_state)) { + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } else if (BTC_RSSI_HIGH(wifi_rssi_state2) && + BTC_RSSI_HIGH(bt_rssi_state2)) { + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xc8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + + if (wifi_busy) + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 3); + else + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 4); + } else { + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = true; + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 8); + + if (wifi_busy) + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 103); + else + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 104); + } +} + +/* HID+A2DP+PAN(EDR) */ +static void +halbtc8822b2ant_action_hid_a2dp_pan_edr(struct btc_coexist *btcoexist) +{ + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state, bt_rssi_state; + + static u8 prewifi_rssi_state2 = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state2 = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state2, bt_rssi_state2; + bool wifi_busy = false; + u32 wifi_bw = 1; + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + wifi_rssi_state = halbtc8822b2ant_wifi_rssi_state( + btcoexist, &prewifi_rssi_state, 2, coex_sta->wifi_coex_thres, + 0); + + wifi_rssi_state2 = halbtc8822b2ant_wifi_rssi_state( + btcoexist, &prewifi_rssi_state2, 2, coex_sta->wifi_coex_thres2, + 0); + + bt_rssi_state = halbtc8822b2ant_bt_rssi_state( + btcoexist, &pre_bt_rssi_state, 2, coex_sta->bt_coex_thres, 0); + + bt_rssi_state2 = halbtc8822b2ant_bt_rssi_state( + btcoexist, &pre_bt_rssi_state2, 2, coex_sta->bt_coex_thres2, 0); + + if (BTC_RSSI_HIGH(wifi_rssi_state) && BTC_RSSI_HIGH(bt_rssi_state)) { + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } else if (BTC_RSSI_HIGH(wifi_rssi_state2) && + BTC_RSSI_HIGH(bt_rssi_state2)) { + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xc8); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + + if (wifi_busy) { + if (((coex_sta->a2dp_bit_pool > 40) && + (coex_sta->a2dp_bit_pool < 255)) || + (!coex_sta->is_A2DP_3M)) + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 7); + else + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 5); + } else { + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 6); + } + } else { + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + + coex_dm->is_switch_to_1dot5_ant = true; + + if (coex_sta->hid_busy_num >= 2) { + halbtc8822b2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 8); + + if (wifi_bw == 0) { + halbtc8822b2ant_set_wltoggle_coex_table( + btcoexist, NORMAL_EXEC, 0x1, 0xaa, 0x5a, + 0xaa, 0xaa); + } else { + halbtc8822b2ant_set_wltoggle_coex_table( + btcoexist, NORMAL_EXEC, 0x2, 0xaa, 0x5a, + 0xaa, 0xaa); + } + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 110); + } else { + halbtc8822b2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + + if (wifi_busy) { + if ((coex_sta->a2dp_bit_pool > 40) && + (coex_sta->a2dp_bit_pool < 255)) + halbtc8822b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 107); + else + halbtc8822b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 105); + } else { + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 106); + } + } + } +} + +static void halbtc8822b2ant_action_bt_whck_test(struct btc_coexist *btcoexist) +{ + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); +} + +static void halbtc8822b2ant_action_bt_hs(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state, bt_rssi_state; + + static u8 prewifi_rssi_state2 = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state2 = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state2, bt_rssi_state2; + bool wifi_busy = false, wifi_turbo = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, + &coex_sta->scan_ap_num); + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "############# [BTCoex], scan_ap_num = %d, wl_noisy = %d\n", + coex_sta->scan_ap_num, coex_sta->wl_noisy_level); + + if ((wifi_busy) && (coex_sta->wl_noisy_level == 0)) + wifi_turbo = true; + + wifi_rssi_state = halbtc8822b2ant_wifi_rssi_state( + btcoexist, &prewifi_rssi_state, 2, coex_sta->wifi_coex_thres, + 0); + + wifi_rssi_state2 = halbtc8822b2ant_wifi_rssi_state( + btcoexist, &prewifi_rssi_state2, 2, coex_sta->wifi_coex_thres2, + 0); + + bt_rssi_state = halbtc8822b2ant_bt_rssi_state( + btcoexist, &pre_bt_rssi_state, 2, coex_sta->bt_coex_thres, 0); + + bt_rssi_state2 = halbtc8822b2ant_bt_rssi_state( + btcoexist, &pre_bt_rssi_state2, 2, coex_sta->bt_coex_thres2, 0); + + if (BTC_RSSI_HIGH(wifi_rssi_state) && BTC_RSSI_HIGH(bt_rssi_state)) { + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } else if (BTC_RSSI_HIGH(wifi_rssi_state2) && + BTC_RSSI_HIGH(bt_rssi_state2)) { + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xc8); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + + } else { + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + + coex_dm->is_switch_to_1dot5_ant = true; + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } +} + +static void +halbtc8822b2ant_action_wifi_multi_port(struct btc_coexist *btcoexist) +{ + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + + /* hw all off */ + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); +} + +static void halbtc8822b2ant_action_wifi_connected(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + + switch (coex_dm->cur_algorithm) { + case BT_8822B_2ANT_COEX_ALGO_SCO: + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Action 2-Ant, algorithm = SCO.\n"); + halbtc8822b2ant_action_sco(btcoexist); + break; + case BT_8822B_2ANT_COEX_ALGO_HID: + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Action 2-Ant, algorithm = HID.\n"); + halbtc8822b2ant_action_hid(btcoexist); + break; + case BT_8822B_2ANT_COEX_ALGO_A2DP: + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Action 2-Ant, algorithm = A2DP.\n"); + halbtc8822b2ant_action_a2dp(btcoexist); + break; + case BT_8822B_2ANT_COEX_ALGO_A2DPSINK: + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Action 2-Ant, algorithm = A2DP Sink.\n"); + halbtc8822b2ant_action_a2dpsink(btcoexist); + break; + case BT_8822B_2ANT_COEX_ALGO_A2DP_PANHS: + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Action 2-Ant, algorithm = A2DP+PAN(HS).\n"); + halbtc8822b2ant_action_a2dp_pan_hs(btcoexist); + break; + case BT_8822B_2ANT_COEX_ALGO_PANEDR: + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Action 2-Ant, algorithm = PAN(EDR).\n"); + halbtc8822b2ant_action_pan_edr(btcoexist); + break; + case BT_8822B_2ANT_COEX_ALGO_PANEDR_A2DP: + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Action 2-Ant, algorithm = PAN+A2DP.\n"); + halbtc8822b2ant_action_pan_edr_a2dp(btcoexist); + break; + case BT_8822B_2ANT_COEX_ALGO_PANEDR_HID: + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Action 2-Ant, algorithm = PAN(EDR)+HID.\n"); + halbtc8822b2ant_action_pan_edr_hid(btcoexist); + break; + case BT_8822B_2ANT_COEX_ALGO_HID_A2DP_PANEDR: + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Action 2-Ant, algorithm = HID+A2DP+PAN.\n"); + halbtc8822b2ant_action_hid_a2dp_pan_edr(btcoexist); + break; + case BT_8822B_2ANT_COEX_ALGO_HID_A2DP: + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Action 2-Ant, algorithm = HID+A2DP.\n"); + halbtc8822b2ant_action_hid_a2dp(btcoexist); + break; + case BT_8822B_2ANT_COEX_ALGO_NOPROFILEBUSY: + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Action 2-Ant, algorithm = No-Profile busy.\n"); + halbtc8822b2ant_action_bt_idle(btcoexist); + break; + default: + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Action 2-Ant, algorithm = coexist All Off!!\n"); + halbtc8822b2ant_action_coex_all_off(btcoexist); + break; + } + + coex_dm->pre_algorithm = coex_dm->cur_algorithm; +} + +static void halbtc8822b2ant_run_coexist_mechanism(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + u8 algorithm = 0; + u32 num_of_wifi_link = 0; + u32 wifi_link_status = 0; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + bool miracast_plus_bt = false; + bool scan = false, link = false, roam = false, under_4way = false, + wifi_connected = false, wifi_under_5g = false, bt_hs_on = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, + &under_4way); + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], RunCoexistMechanism()===>\n"); + + if (btcoexist->manual_control) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], RunCoexistMechanism(), return for Manual CTRL <===\n"); + return; + } + + if (btcoexist->stop_coex_dm) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], RunCoexistMechanism(), return for Stop Coex DM <===\n"); + return; + } + + if (coex_sta->under_ips) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], wifi is under IPS !!!\n"); + return; + } + + if ((coex_sta->under_lps) && + (coex_dm->bt_status != BT_8822B_2ANT_BT_STATUS_ACL_BUSY)) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], RunCoexistMechanism(), wifi is under LPS !!!\n"); + halbtc8822b2ant_action_wifi_native_lps(btcoexist); + return; + } + + if (!coex_sta->run_time_state) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], return for run_time_state = false !!!\n"); + return; + } + + if (coex_sta->freeze_coexrun_by_btinfo) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BtInfoNotify(), return for freeze_coexrun_by_btinfo\n"); + return; + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + + if ((wifi_under_5g) && + (coex_sta->switch_band_notify_to != BTC_SWITCH_TO_24G) && + (coex_sta->switch_band_notify_to != BTC_SWITCH_TO_24G_NOFORSCAN)) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], WiFi is under 5G!!!\n"); + + halbtc8822b2ant_action_wifi_under5g(btcoexist); + return; + } + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], WiFi is under 2G!!!\n"); + + halbtc8822b2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, NORMAL_EXEC, + BT_8822B_2ANT_PHASE_2G_RUNTIME); + + if (coex_sta->bt_whck_test) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BT is under WHCK TEST!!!\n"); + halbtc8822b2ant_action_bt_whck_test(btcoexist); + return; + } + + if (coex_sta->bt_disabled) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BT is disabled!!!\n"); + halbtc8822b2ant_action_coex_all_off(btcoexist); + return; + } + + if (coex_sta->c2h_bt_inquiry_page) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BT is under inquiry/page scan !!\n"); + halbtc8822b2ant_action_bt_inquiry(btcoexist); + return; + } + + if (coex_sta->is_setup_link) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BT is re-link !!!\n"); + halbtc8822b2ant_action_bt_relink(btcoexist); + return; + } + + /* for P2P */ + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, + &wifi_link_status); + num_of_wifi_link = wifi_link_status >> 16; + + if ((num_of_wifi_link >= 2) || + (wifi_link_status & WIFI_P2P_GO_CONNECTED)) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "############# [BTCoex], Multi-Port num_of_wifi_link = %d, wifi_link_status = 0x%x\n", + num_of_wifi_link, wifi_link_status); + + if (bt_link_info->bt_link_exist) + miracast_plus_bt = true; + else + miracast_plus_bt = false; + + btcoexist->btc_set(btcoexist, BTC_SET_BL_MIRACAST_PLUS_BT, + &miracast_plus_bt); + + if (scan || link || roam || under_4way) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], scan = %d, link = %d, roam = %d 4way = %d!!!\n", + scan, link, roam, under_4way); + + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], wifi is under linkscan process + Multi-Port !!\n"); + + halbtc8822b2ant_action_wifi_link_process(btcoexist); + } else { + halbtc8822b2ant_action_wifi_multi_port(btcoexist); + } + + return; + } + + miracast_plus_bt = false; + btcoexist->btc_set(btcoexist, BTC_SET_BL_MIRACAST_PLUS_BT, + &miracast_plus_bt); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + + if (bt_hs_on) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "############# [BTCoex], BT Is hs\n"); + halbtc8822b2ant_action_bt_hs(btcoexist); + return; + } + + if ((BT_8822B_2ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) || + (coex_dm->bt_status == BT_8822B_2ANT_BT_STATUS_CONNECTED_IDLE)) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Action 2-Ant, bt idle!!.\n"); + + halbtc8822b2ant_action_bt_idle(btcoexist); + return; + } + + algorithm = halbtc8822b2ant_action_algorithm(btcoexist); + coex_dm->cur_algorithm = algorithm; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Algorithm = %d\n", coex_dm->cur_algorithm); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + if (scan || link || roam || under_4way) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], WiFi is under Link Process !!\n"); + halbtc8822b2ant_action_wifi_link_process(btcoexist); + } else if (wifi_connected) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Action 2-Ant, wifi connected!!.\n"); + halbtc8822b2ant_action_wifi_connected(btcoexist); + + } else { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Action 2-Ant, wifi not-connected!!.\n"); + halbtc8822b2ant_action_wifi_nonconnected(btcoexist); + } +} + +static void halbtc8822b2ant_init_coex_dm(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Coex Mechanism Init!!\n"); + + halbtc8822b2ant_low_penalty_ra(btcoexist, NORMAL_EXEC, false); + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 5); + + /* fw all off */ + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + + coex_sta->pop_event_cnt = 0; + coex_sta->cnt_remote_name_req = 0; + coex_sta->cnt_reinit = 0; + coex_sta->cnt_setup_link = 0; + coex_sta->cnt_ign_wlan_act = 0; + coex_sta->cnt_page = 0; + coex_sta->cnt_role_switch = 0; + coex_sta->switch_band_notify_to = BTC_NOT_SWITCH; + + halbtc8822b2ant_query_bt_info(btcoexist); +} + +static void halbtc8822b2ant_init_hw_config(struct btc_coexist *btcoexist, + bool wifi_only) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + u32 u32tmp1 = 0, u32tmp2 = 0, u32tmp3 = 0; + u32 RTL97F_8822B = 0; + u8 i = 0; + + u32tmp3 = btcoexist->btc_read_4byte(btcoexist, 0xcb4); + u32tmp1 = halbtc8822b2ant_ltecoex_indirect_read_reg(btcoexist, 0x38); + u32tmp2 = halbtc8822b2ant_ltecoex_indirect_read_reg(btcoexist, 0x54); + + if (RTL97F_8822B) { + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x66, 0x04, 0x0); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x41, 0x02, 0x0); + + /* set GNT_BT to SW high */ + halbtc8822b2ant_ltecoex_set_gnt_bt( + btcoexist, BT_8822B_2ANT_GNT_BLOCK_RFC_BB, + BT_8822B_2ANT_GNT_TYPE_CTRL_BY_SW, + BT_8822B_2ANT_SIG_STA_SET_TO_HIGH); + /* Set GNT_WL to SW high */ + halbtc8822b2ant_ltecoex_set_gnt_wl( + btcoexist, BT_8822B_2ANT_GNT_BLOCK_RFC_BB, + BT_8822B_2ANT_GNT_TYPE_CTRL_BY_SW, + BT_8822B_2ANT_SIG_STA_SET_TO_HIGH); + return; + } + + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], (Before Init HW config) 0xcb4 = 0x%x, 0x38= 0x%x, 0x54= 0x%x\n", + u32tmp3, u32tmp1, u32tmp2); + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], 2Ant Init HW Config!!\n"); + + coex_sta->bt_coex_supported_feature = 0; + coex_sta->bt_coex_supported_version = 0; + coex_sta->bt_ble_scan_type = 0; + coex_sta->bt_ble_scan_para[0] = 0; + coex_sta->bt_ble_scan_para[1] = 0; + coex_sta->bt_ble_scan_para[2] = 0; + coex_sta->bt_reg_vendor_ac = 0xffff; + coex_sta->bt_reg_vendor_ae = 0xffff; + coex_sta->isolation_btween_wb = BT_8822B_2ANT_DEFAULT_ISOLATION; + coex_sta->gnt_error_cnt = 0; + coex_sta->bt_relink_downcount = 0; + coex_sta->is_set_ps_state_fail = false; + coex_sta->cnt_set_ps_state_fail = 0; + + for (i = 0; i <= 9; i++) + coex_sta->bt_afh_map[i] = 0; + + /* 0xf0[15:12] --> Chip Cut information */ + coex_sta->cut_version = + (btcoexist->btc_read_1byte(btcoexist, 0xf1) & 0xf0) >> 4; + + coex_sta->dis_ver_info_cnt = 0; + + halbtc8822b2ant_coex_switch_threshold(btcoexist, + coex_sta->isolation_btween_wb); + + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x550, 0x8, + 0x1); /* enable TBTT nterrupt */ + + /* BT report packet sample rate */ + btcoexist->btc_write_1byte(btcoexist, 0x790, 0x5); + + /* Init 0x778 = 0x1 for 2-Ant */ + btcoexist->btc_write_1byte(btcoexist, 0x778, 0x1); + + /* Enable PTA (3-wire function form BT side) */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x40, 0x20, 0x1); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x41, 0x02, 0x1); + + /* Enable PTA (tx/rx signal form WiFi side) */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4c6, 0x10, 0x1); + + halbtc8822b2ant_enable_gnt_to_gpio(btcoexist, true); + + /*GNT_BT=1 while select both */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x763, 0x10, 0x1); + + /* check if WL firmware download ok */ + halbtc8822b2ant_post_state_to_bt(btcoexist, + BT_8822B_2ANT_SCOREBOARD_ONOFF, true); + + /* Enable counter statistics */ + btcoexist->btc_write_1byte( + btcoexist, 0x76e, + 0x4); /* 0x76e[3] =1, WLAN_Act control by PTA */ + + halbtc8822b2ant_coex_table_with_type(btcoexist, FORCE_EXEC, 5); + + halbtc8822b2ant_ps_tdma(btcoexist, FORCE_EXEC, false, 0); + + psd_scan->ant_det_is_ant_det_available = true; + + if (coex_sta->is_rf_state_off) { + halbtc8822b2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8822B_2ANT_PHASE_WLAN_OFF); + + btcoexist->stop_coex_dm = true; + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** %s (RF Off)**********\n", + __func__); + } else if (wifi_only) { + coex_sta->concurrent_rx_mode_on = false; + /* Path config */ + /* Set Antenna Path */ + halbtc8822b2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8822B_2ANT_PHASE_WLANONLY_INIT); + + btcoexist->stop_coex_dm = true; + } else { + /* Set BT polluted packet on for Tx rate adaptive not including + * Tx retry break by PTA, 0x45c[19] =1 + */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x45e, 0x8, 0x1); + + coex_sta->concurrent_rx_mode_on = true; + + /* RF 0x1[1] = 0->Set GNT_WL_RF_Rx always = 1 for + * con-current Rx, mask Tx only + */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0x2, 0x0); + + /* Set Antenna Path */ + halbtc8822b2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8822B_2ANT_PHASE_COEX_INIT); + + btcoexist->stop_coex_dm = false; + } +} + +/* ************************************************************ + * work around function start with wa_halbtc8822b2ant_ + * ************************************************************ + * ************************************************************ + * extern function start with ex_halbtc8822b2ant_ + * *************************************************************/ +void ex_btc8822b2ant_power_on_setting(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct btc_board_info *board_info = &btcoexist->board_info; + u8 u8tmp = 0x0; + u16 u16tmp = 0x0; + + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "xxxxxxxxxxxxxxxx Execute 8822b 2-Ant PowerOn Setting xxxxxxxxxxxxxxxx!!\n"); + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "Ant Det Finish = %s, Ant Det Number = %d\n", + (board_info->btdm_ant_det_finish ? "Yes" : "No"), + board_info->btdm_ant_num_by_ant_det); + + btcoexist->dbg_mode_2ant = false; + btcoexist->stop_coex_dm = true; + psd_scan->ant_det_is_ant_det_available = false; + + /* enable BB, REG_SYS_FUNC_EN such that we can write BB Reg correctly */ + u16tmp = btcoexist->btc_read_2byte(btcoexist, 0x2); + btcoexist->btc_write_2byte(btcoexist, 0x2, u16tmp | BIT(0) | BIT(1)); + + /* Local setting bit define */ + /* BIT0: "0" for no antenna inverse; "1" for antenna inverse */ + /* BIT1: "0" for internal switch; "1" for external switch */ + /* BIT2: "0" for one antenna; "1" for two antenna */ + /* NOTE: here default all internal switch and 1-antenna ==> + * BIT1=0 and BIT2=0 + */ + + /* Check efuse 0xc3[6] for Single Antenna Path */ + + /* Setup RF front end type */ + halbtc8822b2ant_set_rfe_type(btcoexist); + + /* Set Antenna Path to BT side */ + halbtc8822b2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, FORCE_EXEC, + BT_8822B_2ANT_PHASE_COEX_POWERON); + + /* Save"single antenna position" info in Local register setting for + * FW reading, because FW may not ready at power on + */ + if (btcoexist->chip_interface == BTC_INTF_PCI) + btcoexist->btc_write_local_reg_1byte(btcoexist, 0x3e0, u8tmp); + else if (btcoexist->chip_interface == BTC_INTF_USB) + btcoexist->btc_write_local_reg_1byte(btcoexist, 0xfe08, u8tmp); + else if (btcoexist->chip_interface == BTC_INTF_SDIO) + btcoexist->btc_write_local_reg_1byte(btcoexist, 0x60, u8tmp); + + /* enable GNT_WL/GNT_BT debug signal to GPIO14/15 */ + halbtc8822b2ant_enable_gnt_to_gpio(btcoexist, true); + + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** LTE coex Reg 0x38 (Power-On) = 0x%x**********\n", + halbtc8822b2ant_ltecoex_indirect_read_reg(btcoexist, 0x38)); + + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** MAC Reg 0x70/ BB Reg 0xcb4 (Power-On) = 0x%x / 0x%x\n", + btcoexist->btc_read_4byte(btcoexist, 0x70), + btcoexist->btc_read_4byte(btcoexist, 0xcb4)); +} + +void ex_btc8822b2ant_pre_load_firmware(struct btc_coexist *btcoexist) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + u8 u8tmp = 0x4; /* Set BIT2 by default since it's 2ant case */ + + /* */ + /* S0 or S1 setting and Local register setting + * (By the setting fw can get ant number, S0/S1, ... info) + */ + /* Local setting bit define */ + /* BIT0: "0" for no antenna inverse; "1" for antenna inverse */ + /* BIT1: "0" for internal switch; "1" for external switch */ + /* BIT2: "0" for one antenna; "1" for two antenna */ + /* NOTE: here default all internal switch and 1-antenna ==> + * BIT1=0 and BIT2=0 + */ + if (btcoexist->chip_interface == BTC_INTF_USB) { + /* fixed at S0 for USB interface */ + u8tmp |= 0x1; /* antenna inverse */ + btcoexist->btc_write_local_reg_1byte(btcoexist, 0xfe08, u8tmp); + } else { + /* for PCIE and SDIO interface, we check efuse 0xc3[6] */ + if (board_info->single_ant_path == 0) { + } else if (board_info->single_ant_path == 1) { + /* set to S0 */ + u8tmp |= 0x1; /* antenna inverse */ + } + + if (btcoexist->chip_interface == BTC_INTF_PCI) + btcoexist->btc_write_local_reg_1byte(btcoexist, 0x3e0, + u8tmp); + else if (btcoexist->chip_interface == BTC_INTF_SDIO) + btcoexist->btc_write_local_reg_1byte(btcoexist, 0x60, + u8tmp); + } +} + +void ex_btc8822b2ant_init_hw_config(struct btc_coexist *btcoexist, + bool wifi_only) +{ + halbtc8822b2ant_init_hw_config(btcoexist, wifi_only); + btcoexist->auto_report_2ant = true; +} + +void ex_btc8822b2ant_init_coex_dm(struct btc_coexist *btcoexist) +{ + halbtc8822b2ant_init_coex_dm(btcoexist); +} + +void ex_btc8822b2ant_display_coex_info(struct btc_coexist *btcoexist, + struct seq_file *m) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + u8 u8tmp[4], i, ps_tdma_case = 0; + u32 u32tmp[4]; + u16 u16tmp[4]; + u32 fa_ofdm, fa_cck, cca_ofdm, cca_cck, ratio_ofdm; + u32 fw_ver = 0, bt_patch_ver = 0, bt_coex_ver = 0; + static u8 pop_report_in_10s; + u32 phyver = 0; + bool lte_coex_on = false; + static u8 cnt; + + seq_puts(m, "\r\n ============[BT Coexist info]============"); + + if (btcoexist->manual_control) { + seq_puts(m, + "\r\n ============[Under Manual Control]============"); + seq_puts(m, "\r\n =========================================="); + } + + if (!coex_sta->bt_disabled) { + if (coex_sta->bt_coex_supported_feature == 0) + btcoexist->btc_get( + btcoexist, BTC_GET_U4_SUPPORTED_FEATURE, + &coex_sta->bt_coex_supported_feature); + + if ((coex_sta->bt_coex_supported_version == 0) || + (coex_sta->bt_coex_supported_version == 0xffff)) + btcoexist->btc_get( + btcoexist, BTC_GET_U4_SUPPORTED_VERSION, + &coex_sta->bt_coex_supported_version); + + if (coex_sta->bt_reg_vendor_ac == 0xffff) + coex_sta->bt_reg_vendor_ac = (u16)( + btcoexist->btc_get_bt_reg(btcoexist, 3, 0xac) & + 0xffff); + + if (coex_sta->bt_reg_vendor_ae == 0xffff) + coex_sta->bt_reg_vendor_ae = (u16)( + btcoexist->btc_get_bt_reg(btcoexist, 3, 0xae) & + 0xffff); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER, + &bt_patch_ver); + btcoexist->bt_info.bt_get_fw_ver = bt_patch_ver; + + if (coex_sta->num_of_profile > 0) { + cnt++; + + if (cnt >= 3) { + btcoexist->btc_get_bt_afh_map_from_bt( + btcoexist, 0, &coex_sta->bt_afh_map[0]); + cnt = 0; + } + } + } + + if (psd_scan->ant_det_try_count == 0) { + seq_printf( + m, "\r\n %-35s = %d/ %d/ %s / %d", + "Ant PG Num/ Mech/ Pos/ RFE", board_info->pg_ant_num, + board_info->btdm_ant_num, + (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT ? + "Main" : + "Aux"), + rfe_type->rfe_module_type); + } else { + seq_printf( + m, "\r\n %-35s = %d/ %d/ %s/ %d (%d/%d/%d)", + "Ant PG Num/ Mech(Ant_Det)/ Pos/ RFE", + board_info->pg_ant_num, + board_info->btdm_ant_num_by_ant_det, + (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT ? + "Main" : + "Aux"), + rfe_type->rfe_module_type, psd_scan->ant_det_try_count, + psd_scan->ant_det_fail_count, psd_scan->ant_det_result); + + if (board_info->btdm_ant_det_finish) { + if (psd_scan->ant_det_result != 12) + seq_printf(m, "\r\n %-35s = %s", + "Ant Det PSD Value", + psd_scan->ant_det_peak_val); + else + seq_printf(m, "\r\n %-35s = %d", + "Ant Det PSD Value", + psd_scan->ant_det_psd_scan_peak_val / + 100); + } + } + + bt_patch_ver = btcoexist->bt_info.bt_get_fw_ver; + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver); + phyver = btcoexist->btc_get_bt_phydm_version(btcoexist); + + bt_coex_ver = (coex_sta->bt_coex_supported_version & 0xff); + + seq_printf( + m, "\r\n %-35s = %d_%02x/ 0x%02x/ 0x%02x (%s)", + "CoexVer WL/ BT_Desired/ BT_Report", + glcoex_ver_date_8822b_2ant, glcoex_ver_8822b_2ant, + glcoex_ver_btdesired_8822b_2ant, bt_coex_ver, + (bt_coex_ver == 0xff ? + "Unknown" : + (coex_sta->bt_disabled ? "BT-disable" : + (bt_coex_ver >= glcoex_ver_btdesired_8822b_2ant ? + "Match" : + "Mis-Match")))); + + seq_printf(m, "\r\n %-35s = 0x%x/ 0x%x/ v%d/ %c", "W_FW/ B_FW/ Phy/ Kt", + fw_ver, bt_patch_ver, phyver, coex_sta->cut_version + 65); + + seq_printf(m, "\r\n %-35s = %02x %02x %02x ", "AFH Map to BT", + coex_dm->wifi_chnl_info[0], coex_dm->wifi_chnl_info[1], + coex_dm->wifi_chnl_info[2]); + + seq_printf(m, "\r\n %-35s = %d / %d / %d ", + "Isolation/WL_Thres/BT_Thres", coex_sta->isolation_btween_wb, + coex_sta->wifi_coex_thres, coex_sta->bt_coex_thres); + + /* wifi status */ + seq_printf(m, "\r\n %-35s", "============[Wifi Status]============"); + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_WIFI_STATUS, m); + + seq_printf(m, "\r\n %-35s", "============[BT Status]============"); + + pop_report_in_10s++; + seq_printf( + m, "\r\n %-35s = [%s/ %d dBm/ %d/ %d] ", + "BT [status/ rssi/ retryCnt/ popCnt]", + ((coex_sta->bt_disabled) ? + ("disabled") : + ((coex_sta->c2h_bt_inquiry_page) ? ("inquiry/page") : + ((BT_8822B_2ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) ? + "non-connected idle" : + ((coex_dm->bt_status == + BT_8822B_2ANT_BT_STATUS_CONNECTED_IDLE) ? + "connected-idle" : + "busy")))), + coex_sta->bt_rssi - 100, coex_sta->bt_retry_cnt, + coex_sta->pop_event_cnt); + + if (pop_report_in_10s >= 5) { + coex_sta->pop_event_cnt = 0; + pop_report_in_10s = 0; + } + + if (coex_sta->num_of_profile != 0) + seq_printf( + m, "\r\n %-35s = %s%s%s%s%s", "Profiles", + ((bt_link_info->a2dp_exist) ? + ((coex_sta->is_bt_a2dp_sink) ? "A2DP sink," : + "A2DP,") : + ""), + ((bt_link_info->sco_exist) ? "HFP," : ""), + ((bt_link_info->hid_exist) ? + ((coex_sta->hid_busy_num >= 2) ? + "HID(4/18)," : + "HID(2/18),") : + ""), + ((bt_link_info->pan_exist) ? "PAN," : ""), + ((coex_sta->voice_over_HOGP) ? "Voice" : "")); + else + seq_printf(m, "\r\n %-35s = None", "Profiles"); + + if (bt_link_info->a2dp_exist) { + seq_printf(m, "\r\n %-35s = %s/ %d/ %s", + "A2DP Rate/Bitpool/Auto_Slot", + ((coex_sta->is_A2DP_3M) ? "3M" : "No_3M"), + coex_sta->a2dp_bit_pool, + ((coex_sta->is_autoslot) ? "On" : "Off")); + } + + if (bt_link_info->hid_exist) { + seq_printf(m, "\r\n %-35s = %d/ %d", "HID PairNum/Forbid_Slot", + coex_sta->hid_pair_cnt, coex_sta->forbidden_slot); + } + + seq_printf(m, "\r\n %-35s = %s/ %d/ %s/ 0x%x", + "Role/RoleSwCnt/IgnWlact/Feature", + ((bt_link_info->slave_role) ? "Slave" : "Master"), + coex_sta->cnt_role_switch, + ((coex_dm->cur_ignore_wlan_act) ? "Yes" : "No"), + coex_sta->bt_coex_supported_feature); + + if ((coex_sta->bt_ble_scan_type & 0x7) != 0x0) { + seq_printf(m, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", + "BLEScan Type/TV/Init/Ble", + coex_sta->bt_ble_scan_type, + (coex_sta->bt_ble_scan_type & 0x1 ? + coex_sta->bt_ble_scan_para[0] : + 0x0), + (coex_sta->bt_ble_scan_type & 0x2 ? + coex_sta->bt_ble_scan_para[1] : + 0x0), + (coex_sta->bt_ble_scan_type & 0x4 ? + coex_sta->bt_ble_scan_para[2] : + 0x0)); + } + + seq_printf(m, "\r\n %-35s = %d/ %d/ %d/ %d/ %d", + "ReInit/ReLink/IgnWlact/Page/NameReq", coex_sta->cnt_reinit, + coex_sta->cnt_setup_link, coex_sta->cnt_ign_wlan_act, + coex_sta->cnt_page, coex_sta->cnt_remote_name_req); + + halbtc8822b2ant_read_score_board(btcoexist, &u16tmp[0]); + + if ((coex_sta->bt_reg_vendor_ae == 0xffff) || + (coex_sta->bt_reg_vendor_ac == 0xffff)) + seq_printf(m, "\r\n %-35s = x/ x/ %04x", + "0xae[4]/0xac[1:0]/Scoreboard", u16tmp[0]); + else + seq_printf(m, "\r\n %-35s = 0x%x/ 0x%x/ %04x", + "0xae[4]/0xac[1:0]/Scoreboard", + (int)((coex_sta->bt_reg_vendor_ae & BIT(4)) >> 4), + coex_sta->bt_reg_vendor_ac & 0x3, u16tmp[0]); + + if (coex_sta->num_of_profile > 0) { + seq_printf( + m, + "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", + "AFH MAP", coex_sta->bt_afh_map[0], + coex_sta->bt_afh_map[1], coex_sta->bt_afh_map[2], + coex_sta->bt_afh_map[3], coex_sta->bt_afh_map[4], + coex_sta->bt_afh_map[5], coex_sta->bt_afh_map[6], + coex_sta->bt_afh_map[7], coex_sta->bt_afh_map[8], + coex_sta->bt_afh_map[9]); + } + + for (i = 0; i < BT_INFO_SRC_8822B_2ANT_MAX; i++) { + if (coex_sta->bt_info_c2h_cnt[i]) { + seq_printf( + m, + "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x(%d)", + glbt_info_src_8822b_2ant[i], + coex_sta->bt_info_c2h[i][0], + coex_sta->bt_info_c2h[i][1], + coex_sta->bt_info_c2h[i][2], + coex_sta->bt_info_c2h[i][3], + coex_sta->bt_info_c2h[i][4], + coex_sta->bt_info_c2h[i][5], + coex_sta->bt_info_c2h[i][6], + coex_sta->bt_info_c2h_cnt[i]); + } + } + + /* Sw mechanism */ + if (btcoexist->manual_control) + seq_printf( + m, "\r\n %-35s", + "============[mechanism] (before Manual)============"); + else + seq_printf(m, "\r\n %-35s", + "============[Mechanism]============"); + + ps_tdma_case = coex_dm->cur_ps_tdma; + + seq_printf(m, "\r\n %-35s = %02x %02x %02x %02x %02x (case-%d, %s, %s)", + "TDMA", coex_dm->ps_tdma_para[0], coex_dm->ps_tdma_para[1], + coex_dm->ps_tdma_para[2], coex_dm->ps_tdma_para[3], + coex_dm->ps_tdma_para[4], ps_tdma_case, + (coex_dm->cur_ps_tdma_on ? "TDMA On" : "TDMA Off"), + (coex_dm->is_switch_to_1dot5_ant ? "1.5Ant" : "2Ant")); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6c0); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x6c4); + u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x6c8); + seq_printf(m, "\r\n %-35s = %d/ 0x%x/ 0x%x/ 0x%x", + "Table/0x6c0/0x6c4/0x6c8", coex_sta->coex_table_type, + u32tmp[0], u32tmp[1], u32tmp[2]); + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778); + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6cc); + seq_printf(m, "\r\n %-35s = 0x%x/ 0x%x", "0x778/0x6cc", u8tmp[0], + u32tmp[0]); + + seq_printf(m, "\r\n %-35s = %s/ %s/ %s/ %d", + "AntDiv/BtCtrlLPS/LPRA/PsFail", + ((board_info->ant_div_cfg) ? "On" : "Off"), + ((coex_sta->force_lps_ctrl) ? "On" : "Off"), + ((coex_dm->cur_low_penalty_ra) ? "On" : "Off"), + coex_sta->cnt_set_ps_state_fail); + + seq_printf(m, "\r\n %-35s = 0x%x/ 0x%x", "WL_DACSwing/ BT_Dec_Pwr", + coex_dm->cur_fw_dac_swing_lvl, coex_dm->cur_bt_dec_pwr_lvl); + + u32tmp[0] = halbtc8822b2ant_ltecoex_indirect_read_reg(btcoexist, 0x38); + lte_coex_on = ((u32tmp[0] & BIT(7)) >> 7) ? true : false; + + if (lte_coex_on) { + u32tmp[0] = halbtc8822b2ant_ltecoex_indirect_read_reg(btcoexist, + 0xa0); + u32tmp[1] = halbtc8822b2ant_ltecoex_indirect_read_reg(btcoexist, + 0xa4); + seq_printf(m, "\r\n %-35s = 0x%x/ 0x%x", + "LTE Coex Table W_L/B_L", u32tmp[0] & 0xffff, + u32tmp[1] & 0xffff); + + u32tmp[0] = halbtc8822b2ant_ltecoex_indirect_read_reg(btcoexist, + 0xa8); + u32tmp[1] = halbtc8822b2ant_ltecoex_indirect_read_reg(btcoexist, + 0xac); + u32tmp[2] = halbtc8822b2ant_ltecoex_indirect_read_reg(btcoexist, + 0xb0); + u32tmp[3] = halbtc8822b2ant_ltecoex_indirect_read_reg(btcoexist, + 0xb4); + seq_printf(m, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", + "LTE Break Table W_L/B_L/L_W/L_B", + u32tmp[0] & 0xffff, u32tmp[1] & 0xffff, + u32tmp[2] & 0xffff, u32tmp[3] & 0xffff); + } + + /* Hw setting */ + seq_printf(m, "\r\n %-35s", "============[Hw setting]============"); + + u32tmp[0] = halbtc8822b2ant_ltecoex_indirect_read_reg(btcoexist, 0x38); + u32tmp[1] = halbtc8822b2ant_ltecoex_indirect_read_reg(btcoexist, 0x54); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x73); + + seq_printf(m, "\r\n %-35s = %s/ %s", "LTE Coex/Path Owner", + ((lte_coex_on) ? "On" : "Off"), + ((u8tmp[0] & BIT(2)) ? "WL" : "BT")); + + if (lte_coex_on) { + seq_printf(m, "\r\n %-35s = %d/ %d/ %d/ %d", + "LTE 3Wire/OPMode/UART/UARTMode", + (int)((u32tmp[0] & BIT(6)) >> 6), + (int)((u32tmp[0] & (BIT(5) | BIT(4))) >> 4), + (int)((u32tmp[0] & BIT(3)) >> 3), + (int)(u32tmp[0] & (BIT(2) | BIT(1) | BIT(0)))); + + seq_printf(m, "\r\n %-35s = %d/ %d", "LTE_Busy/UART_Busy", + (int)((u32tmp[1] & BIT(1)) >> 1), + (int)(u32tmp[1] & BIT(0))); + } + seq_printf(m, "\r\n %-35s = %s (BB:%s)/ %s (BB:%s)/ %s %d", + "GNT_WL_Ctrl/GNT_BT_Ctrl/Dbg", + ((u32tmp[0] & BIT(12)) ? "SW" : "HW"), + ((u32tmp[0] & BIT(8)) ? "SW" : "HW"), + ((u32tmp[0] & BIT(14)) ? "SW" : "HW"), + ((u32tmp[0] & BIT(10)) ? "SW" : "HW"), + ((u8tmp[0] & BIT(3)) ? "On" : "Off"), + coex_sta->gnt_error_cnt); + + seq_printf(m, "\r\n %-35s = %d/ %d", "GNT_WL/GNT_BT", + (int)((u32tmp[1] & BIT(2)) >> 2), + (int)((u32tmp[1] & BIT(3)) >> 3)); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xcbc); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0xcb4); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0xcba); + + seq_printf(m, "\r\n %-35s = 0x%04x/ 0x%04x/ 0x%02x %s", + "0xcbc/0xcb4/0xcb8[23:16]", u32tmp[0], u32tmp[1], u8tmp[0], + ((u8tmp[0] & 0x1) == 0x1 ? "(BTG)" : "(WL_A+G)")); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x4c); + u8tmp[2] = btcoexist->btc_read_1byte(btcoexist, 0x64); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x4c6); + u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x40); + + seq_printf(m, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", + "4c[24:23]/64[0]/4c6[4]/40[5]", + (int)(u32tmp[0] & (BIT(24) | BIT(23))) >> 23, u8tmp[2] & 0x1, + (int)((u8tmp[0] & BIT(4)) >> 4), + (int)((u8tmp[1] & BIT(5)) >> 5)); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522); + u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x953); + u8tmp[2] = btcoexist->btc_read_1byte(btcoexist, 0xc50); + + seq_printf(m, "\r\n %-35s = 0x%x/ 0x%x/ %s/ 0x%x", + "0x550/0x522/4-RxAGC/0xc50", u32tmp[0], u8tmp[0], + (u8tmp[1] & 0x2) ? "On" : "Off", u8tmp[2]); + + fa_ofdm = btcoexist->btc_phydm_query_phy_counter(btcoexist, + "PHYDM_INFO_FA_OFDM"); + fa_cck = btcoexist->btc_phydm_query_phy_counter(btcoexist, + "PHYDM_INFO_FA_CCK"); + cca_ofdm = btcoexist->btc_phydm_query_phy_counter( + btcoexist, "PHYDM_INFO_CCA_OFDM"); + cca_cck = btcoexist->btc_phydm_query_phy_counter(btcoexist, + "PHYDM_INFO_CCA_CCK"); + + ratio_ofdm = (fa_ofdm == 0) ? 1000 : (cca_ofdm / fa_ofdm); + + seq_printf(m, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x (%d)", + "CCK-CCA/CCK-FA/OFDM-CCA/OFDM-FA", cca_cck, fa_cck, cca_ofdm, + fa_ofdm, ratio_ofdm); + + seq_printf(m, "\r\n %-35s = %d/ %d/ %d/ %d", "CRC_OK CCK/11g/11n/11ac", + coex_sta->crc_ok_cck, coex_sta->crc_ok_11g, + coex_sta->crc_ok_11n, coex_sta->crc_ok_11n_vht); + + seq_printf(m, "\r\n %-35s = %d/ %d/ %d/ %d (%d, %d)", + "CRC_Err CCK/11g/11n/11ac", coex_sta->crc_err_cck, + coex_sta->crc_err_11g, coex_sta->crc_err_11n, + coex_sta->crc_err_11n_vht, coex_sta->now_crc_ratio, + coex_sta->acc_crc_ratio); + + seq_printf(m, "\r\n %-35s = %s/ %s/ %s/ %d", + "WlHiPri/ Locking/ Locked/ Noisy", + (coex_sta->wifi_is_high_pri_task ? "Yes" : "No"), + (coex_sta->cck_lock ? "Yes" : "No"), + (coex_sta->cck_ever_lock ? "Yes" : "No"), + coex_sta->wl_noisy_level); + + seq_printf(m, "\r\n %-35s = %d/ %d", "0x770(Hi-pri rx/tx)", + coex_sta->high_priority_rx, coex_sta->high_priority_tx); + + seq_printf(m, "\r\n %-35s = %d/ %d %s", "0x774(Lo-pri rx/tx)", + coex_sta->low_priority_rx, coex_sta->low_priority_tx, + (bt_link_info->slave_role ? + "(Slave!!)" : + (coex_sta->is_tdma_btautoslot_hang ? + "(auto-slot hang!!)" : + ""))); + + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_COEX_STATISTICS, m); +} + +void ex_btc8822b2ant_ips_notify(struct btc_coexist *btcoexist, u8 type) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + + if (btcoexist->manual_control || btcoexist->stop_coex_dm) + return; + + if (type == BTC_IPS_ENTER) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], IPS ENTER notify\n"); + coex_sta->under_ips = true; + coex_sta->under_lps = false; + + halbtc8822b2ant_post_state_to_bt( + btcoexist, BT_8822B_2ANT_SCOREBOARD_ACTIVE, false); + + halbtc8822b2ant_post_state_to_bt( + btcoexist, BT_8822B_2ANT_SCOREBOARD_ONOFF, false); + + halbtc8822b2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8822B_2ANT_PHASE_WLAN_OFF); + + halbtc8822b2ant_action_coex_all_off(btcoexist); + } else if (type == BTC_IPS_LEAVE) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], IPS LEAVE notify\n"); + coex_sta->under_ips = false; + + halbtc8822b2ant_post_state_to_bt( + btcoexist, BT_8822B_2ANT_SCOREBOARD_ACTIVE, true); + halbtc8822b2ant_post_state_to_bt( + btcoexist, BT_8822B_2ANT_SCOREBOARD_ONOFF, true); + halbtc8822b2ant_init_hw_config(btcoexist, false); + halbtc8822b2ant_init_coex_dm(btcoexist); + halbtc8822b2ant_query_bt_info(btcoexist); + } +} + +void ex_btc8822b2ant_lps_notify(struct btc_coexist *btcoexist, u8 type) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + static bool pre_force_lps_on; + + if (btcoexist->manual_control || btcoexist->stop_coex_dm) + return; + + if (type == BTC_LPS_ENABLE) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], LPS ENABLE notify\n"); + coex_sta->under_lps = true; + coex_sta->under_ips = false; + + if (coex_sta->force_lps_ctrl) { /* LPS No-32K */ + /* Write WL "Active" in Score-board for PS-TDMA */ + pre_force_lps_on = true; + halbtc8822b2ant_post_state_to_bt( + btcoexist, BT_8822B_2ANT_SCOREBOARD_ACTIVE, + true); + + } else { + /* LPS-32K, need check if this h2c 0x71 can work?? + * (2015/08/28) + */ + /* Write WL "Non-Active" in Score-board for Native-PS */ + pre_force_lps_on = false; + halbtc8822b2ant_post_state_to_bt( + btcoexist, BT_8822B_2ANT_SCOREBOARD_ACTIVE, + false); + } + + } else if (type == BTC_LPS_DISABLE) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], LPS DISABLE notify\n"); + coex_sta->under_lps = false; + + halbtc8822b2ant_post_state_to_bt( + btcoexist, BT_8822B_2ANT_SCOREBOARD_ACTIVE, true); + + if ((!pre_force_lps_on) && (!coex_sta->force_lps_ctrl)) + halbtc8822b2ant_query_bt_info(btcoexist); + } +} + +void ex_btc8822b2ant_scan_notify(struct btc_coexist *btcoexist, u8 type) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + bool wifi_connected = false; + bool wifi_under_5g = false; + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], SCAN notify()\n"); + + halbtc8822b2ant_post_state_to_bt(btcoexist, + BT_8822B_2ANT_SCOREBOARD_ACTIVE, true); + + if (btcoexist->manual_control || btcoexist->stop_coex_dm) + return; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + /* this can't be removed for RF off_on event, or BT would dis-connect */ + halbtc8822b2ant_query_bt_info(btcoexist); + + if (type == BTC_SCAN_START) { + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, + &wifi_under_5g); + + if (wifi_under_5g) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** SCAN START notify (5g)\n"); + + halbtc8822b2ant_action_wifi_under5g(btcoexist); + return; + } + + coex_sta->wifi_is_high_pri_task = true; + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** SCAN START notify (2g)\n"); + + halbtc8822b2ant_run_coexist_mechanism(btcoexist); + + return; + } + + if (type == BTC_SCAN_START_2G) { + if (!wifi_connected) + coex_sta->wifi_is_high_pri_task = true; + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], SCAN START notify (2G)\n"); + + halbtc8822b2ant_post_state_to_bt( + btcoexist, BT_8822B_2ANT_SCOREBOARD_SCAN, true); + halbtc8822b2ant_post_state_to_bt( + btcoexist, BT_8822B_2ANT_SCOREBOARD_ACTIVE, true); + + halbtc8822b2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8822B_2ANT_PHASE_2G_RUNTIME); + + halbtc8822b2ant_run_coexist_mechanism(btcoexist); + + } else if (type == BTC_SCAN_FINISH) { + coex_sta->wifi_is_high_pri_task = false; + + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, + &coex_sta->scan_ap_num); + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], SCAN FINISH notify (Scan-AP = %d)\n", + coex_sta->scan_ap_num); + + halbtc8822b2ant_post_state_to_bt( + btcoexist, BT_8822B_2ANT_SCOREBOARD_SCAN, false); + + halbtc8822b2ant_run_coexist_mechanism(btcoexist); + } +} + +void ex_btc8822b2ant_switchband_notify(struct btc_coexist *btcoexist, u8 type) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + + if (btcoexist->manual_control || btcoexist->stop_coex_dm) + return; + coex_sta->switch_band_notify_to = type; + + if (type == BTC_SWITCH_TO_5G) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], switchband_notify --- switch to 5G\n"); + + halbtc8822b2ant_action_wifi_under5g(btcoexist); + + } else if (type == BTC_SWITCH_TO_24G_NOFORSCAN) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ********** switchband_notify BTC_SWITCH_TO_2G (no for scan)\n"); + + halbtc8822b2ant_run_coexist_mechanism(btcoexist); + + } else { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], switchband_notify --- switch to 2G\n"); + + ex_btc8822b2ant_scan_notify(btcoexist, BTC_SCAN_START_2G); + } + coex_sta->switch_band_notify_to = BTC_NOT_SWITCH; +} + +void ex_btc8822b2ant_connect_notify(struct btc_coexist *btcoexist, u8 type) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + + halbtc8822b2ant_post_state_to_bt(btcoexist, + BT_8822B_2ANT_SCOREBOARD_ACTIVE, true); + if (btcoexist->manual_control || btcoexist->stop_coex_dm) + return; + + if ((type == BTC_ASSOCIATE_5G_START) || + (type == BTC_ASSOCIATE_5G_FINISH)) { + if (type == BTC_ASSOCIATE_5G_START) + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], connect_notify --- 5G start\n"); + else + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], connect_notify --- 5G finish\n"); + + halbtc8822b2ant_action_wifi_under5g(btcoexist); + return; + } + + if (type == BTC_ASSOCIATE_START) { + coex_sta->wifi_is_high_pri_task = true; + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], CONNECT START notify (2G)\n"); + + halbtc8822b2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8822B_2ANT_PHASE_2G_RUNTIME); + + halbtc8822b2ant_action_wifi_link_process(btcoexist); + + /* To keep TDMA case during connect process, + * to avoid changed by Btinfo and runcoexmechanism + */ + coex_sta->freeze_coexrun_by_btinfo = true; + + coex_dm->arp_cnt = 0; + + } else if (type == BTC_ASSOCIATE_FINISH) { + coex_sta->wifi_is_high_pri_task = false; + coex_sta->freeze_coexrun_by_btinfo = false; + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], CONNECT FINISH notify (2G)\n"); + + halbtc8822b2ant_run_coexist_mechanism(btcoexist); + } +} + +void ex_btc8822b2ant_media_status_notify(struct btc_coexist *btcoexist, u8 type) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + bool wifi_under_b_mode = false, wifi_under_5g = false; + + if (btcoexist->manual_control || btcoexist->stop_coex_dm) + return; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + + if (type == BTC_MEDIA_CONNECT) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], MEDIA connect notify\n"); + + halbtc8822b2ant_post_state_to_bt( + btcoexist, BT_8822B_2ANT_SCOREBOARD_ACTIVE, true); + + if (wifi_under_5g) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], WiFi is under 5G!!!\n"); + + halbtc8822b2ant_action_wifi_under5g(btcoexist); + return; + } + + halbtc8822b2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8822B_2ANT_PHASE_2G_RUNTIME); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_B_MODE, + &wifi_under_b_mode); + + /* Set CCK Tx/Rx high Pri except 11b mode */ + if (wifi_under_b_mode) { + btcoexist->btc_write_1byte(btcoexist, 0x6cd, + 0x00); /* CCK Tx */ + btcoexist->btc_write_1byte(btcoexist, 0x6cf, + 0x00); /* CCK Rx */ + } else { + btcoexist->btc_write_1byte(btcoexist, 0x6cd, + 0x00); /* CCK Tx */ + btcoexist->btc_write_1byte(btcoexist, 0x6cf, + 0x10); /* CCK Rx */ + } + + } else { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], MEDIA disconnect notify\n"); + + btcoexist->btc_write_1byte(btcoexist, 0x6cd, 0x0); /* CCK Tx */ + btcoexist->btc_write_1byte(btcoexist, 0x6cf, 0x0); /* CCK Rx */ + + halbtc8822b2ant_post_state_to_bt( + btcoexist, BT_8822B_2ANT_SCOREBOARD_ACTIVE, false); + } + + halbtc8822b2ant_update_wifi_ch_info(btcoexist, type); +} + +void ex_btc8822b2ant_specific_packet_notify(struct btc_coexist *btcoexist, + u8 type) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + bool under_4way = false, wifi_under_5g = false; + + if (btcoexist->manual_control || btcoexist->stop_coex_dm) + return; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + + if (wifi_under_5g) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], WiFi is under 5G!!!\n"); + + halbtc8822b2ant_action_wifi_under5g(btcoexist); + return; + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, + &under_4way); + + if (under_4way) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], specific Packet ---- under_4way!!\n"); + + coex_sta->wifi_is_high_pri_task = true; + coex_sta->specific_pkt_period_cnt = 2; + + } else if (type == BTC_PACKET_ARP) { + coex_dm->arp_cnt++; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], specific Packet ARP notify -cnt = %d\n", + coex_dm->arp_cnt); + + } else { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], specific Packet DHCP or EAPOL notify [Type = %d]\n", + type); + + coex_sta->wifi_is_high_pri_task = true; + coex_sta->specific_pkt_period_cnt = 2; + } + + if (coex_sta->wifi_is_high_pri_task) + halbtc8822b2ant_run_coexist_mechanism(btcoexist); +} + +void ex_btc8822b2ant_bt_info_notify(struct btc_coexist *btcoexist, u8 *tmp_buf, + u8 length) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + u8 i, rsp_source = 0; + bool wifi_connected = false; + bool wifi_scan = false, wifi_link = false, wifi_roam = false, + wifi_busy = false; + static bool is_scoreboard_scan; + + rsp_source = tmp_buf[0] & 0xf; + if (rsp_source >= BT_INFO_SRC_8822B_2ANT_MAX) + rsp_source = BT_INFO_SRC_8822B_2ANT_WIFI_FW; + coex_sta->bt_info_c2h_cnt[rsp_source]++; + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Bt_info[%d], len=%d, data=[", rsp_source, length); + + for (i = 0; i < length; i++) { + coex_sta->bt_info_c2h[rsp_source][i] = tmp_buf[i]; + + if (i == length - 1) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "0x%02x]\n", tmp_buf[i]); + } else { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "0x%02x, ", + tmp_buf[i]); + } + } + + coex_sta->bt_info = coex_sta->bt_info_c2h[rsp_source][1]; + coex_sta->bt_info_ext = coex_sta->bt_info_c2h[rsp_source][4]; + coex_sta->bt_info_ext2 = coex_sta->bt_info_c2h[rsp_source][5]; + + if (rsp_source != BT_INFO_SRC_8822B_2ANT_WIFI_FW) { + /* if 0xff, it means BT is under WHCK test */ + coex_sta->bt_whck_test = + ((coex_sta->bt_info == 0xff) ? true : false); + + coex_sta->bt_create_connection = + ((coex_sta->bt_info_c2h[rsp_source][2] & 0x80) ? true : + false); + + /* unit: %, value-100 to translate to unit: dBm */ + coex_sta->bt_rssi = + coex_sta->bt_info_c2h[rsp_source][3] * 2 + 10; + + coex_sta->c2h_bt_remote_name_req = + ((coex_sta->bt_info_c2h[rsp_source][2] & 0x20) ? true : + false); + + coex_sta->is_A2DP_3M = + ((coex_sta->bt_info_c2h[rsp_source][2] & 0x10) ? true : + false); + + coex_sta->acl_busy = + ((coex_sta->bt_info_c2h[rsp_source][1] & 0x9) ? true : + false); + + coex_sta->voice_over_HOGP = + ((coex_sta->bt_info_ext & 0x10) ? true : false); + + coex_sta->c2h_bt_inquiry_page = + ((coex_sta->bt_info & BT_INFO_8822B_2ANT_B_INQ_PAGE) ? + true : + false); + + coex_sta->a2dp_bit_pool = + (((coex_sta->bt_info_c2h[rsp_source][1] & 0x49) == + 0x49) ? + (coex_sta->bt_info_c2h[rsp_source][6] & 0x7f) : + 0); + + coex_sta->is_bt_a2dp_sink = + (coex_sta->bt_info_c2h[rsp_source][6] & 0x80) ? true : + false; + + coex_sta->bt_retry_cnt = + coex_sta->bt_info_c2h[rsp_source][2] & 0xf; + + coex_sta->is_autoslot = coex_sta->bt_info_ext2 & 0x8; + + coex_sta->forbidden_slot = coex_sta->bt_info_ext2 & 0x7; + + coex_sta->hid_busy_num = (coex_sta->bt_info_ext2 & 0x30) >> 4; + + coex_sta->hid_pair_cnt = (coex_sta->bt_info_ext2 & 0xc0) >> 6; + + if (coex_sta->bt_retry_cnt >= 1) + coex_sta->pop_event_cnt++; + + if (coex_sta->c2h_bt_remote_name_req) + coex_sta->cnt_remote_name_req++; + + if (coex_sta->bt_info_ext & BIT(1)) + coex_sta->cnt_reinit++; + + if (coex_sta->bt_info_ext & BIT(2)) { + coex_sta->cnt_setup_link++; + coex_sta->is_setup_link = true; + coex_sta->bt_relink_downcount = 2; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Re-Link start in BT info!!\n"); + } else { + coex_sta->is_setup_link = false; + coex_sta->bt_relink_downcount = 0; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Re-Link stop in BT info!!\n"); + } + + if (coex_sta->bt_info_ext & BIT(3)) + coex_sta->cnt_ign_wlan_act++; + + if (coex_sta->bt_info_ext & BIT(6)) + coex_sta->cnt_role_switch++; + + if (coex_sta->bt_info_ext & BIT(7)) + coex_sta->is_bt_multi_link = true; + else + coex_sta->is_bt_multi_link = false; + + if (coex_sta->bt_create_connection) { + coex_sta->cnt_page++; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, + &wifi_busy); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, + &wifi_scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, + &wifi_link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, + &wifi_roam); + + if ((wifi_link) || (wifi_roam) || (wifi_scan) || + (coex_sta->wifi_is_high_pri_task) || (wifi_busy)) { + is_scoreboard_scan = true; + halbtc8822b2ant_post_state_to_bt( + btcoexist, + BT_8822B_2ANT_SCOREBOARD_SCAN, true); + + } else { + halbtc8822b2ant_post_state_to_bt( + btcoexist, + BT_8822B_2ANT_SCOREBOARD_SCAN, false); + } + } else { + if (is_scoreboard_scan) { + halbtc8822b2ant_post_state_to_bt( + btcoexist, + BT_8822B_2ANT_SCOREBOARD_SCAN, false); + is_scoreboard_scan = false; + } + } + + /* Here we need to resend some wifi info to BT */ + /* because bt is reset and loss of the info. */ + + if ((!btcoexist->manual_control) && + (!btcoexist->stop_coex_dm)) { + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + /* Re-Init */ + if ((coex_sta->bt_info_ext & BIT(1))) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BT ext info bit1 check, send wifi BW&Chnl to BT!!\n"); + if (wifi_connected) + halbtc8822b2ant_update_wifi_ch_info( + btcoexist, BTC_MEDIA_CONNECT); + else + halbtc8822b2ant_update_wifi_ch_info( + btcoexist, + BTC_MEDIA_DISCONNECT); + } + + /* If Ignore_WLanAct && not SetUp_Link */ + if ((coex_sta->bt_info_ext & BIT(3)) && + (!(coex_sta->bt_info_ext & BIT(2))) && + (!(coex_sta->bt_info_ext & BIT(6)))) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BT ext info bit3 check, set BT NOT to ignore Wlan active!!\n"); + halbtc8822b2ant_ignore_wlan_act( + btcoexist, FORCE_EXEC, false); + } else { + if (coex_sta->bt_info_ext & BIT(2)) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, + DBG_LOUD, + "[BTCoex], BT ignore Wlan active because Re-link!!\n"); + } else if (coex_sta->bt_info_ext & BIT(6)) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, + DBG_LOUD, + "[BTCoex], BT ignore Wlan active because Role-Switch!!\n"); + } + } + } + } + + if ((coex_sta->bt_info_ext & BIT(5))) { + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BT ext info bit4 check, query BLE Scan type!!\n"); + coex_sta->bt_ble_scan_type = + btcoexist->btc_get_ble_scan_type_from_bt(btcoexist); + + if ((coex_sta->bt_ble_scan_type & 0x1) == 0x1) + coex_sta->bt_ble_scan_para[0] = + btcoexist->btc_get_ble_scan_para_from_bt( + btcoexist, 0x1); + if ((coex_sta->bt_ble_scan_type & 0x2) == 0x2) + coex_sta->bt_ble_scan_para[1] = + btcoexist->btc_get_ble_scan_para_from_bt( + btcoexist, 0x2); + if ((coex_sta->bt_ble_scan_type & 0x4) == 0x4) + coex_sta->bt_ble_scan_para[2] = + btcoexist->btc_get_ble_scan_para_from_bt( + btcoexist, 0x4); + } + + halbtc8822b2ant_update_bt_link_info(btcoexist); + + halbtc8822b2ant_run_coexist_mechanism(btcoexist); +} + +void ex_btc8822b2ant_rf_status_notify(struct btc_coexist *btcoexist, u8 type) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], RF Status notify\n"); + + if (type == BTC_RF_ON) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], RF is turned ON!!\n"); + + btcoexist->stop_coex_dm = false; + coex_sta->is_rf_state_off = false; + } else if (type == BTC_RF_OFF) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], RF is turned OFF!!\n"); + + halbtc8822b2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8822B_2ANT_PHASE_WLAN_OFF); + + halbtc8822b2ant_action_coex_all_off(btcoexist); + + halbtc8822b2ant_post_state_to_bt( + btcoexist, BT_8822B_2ANT_SCOREBOARD_ACTIVE | + BT_8822B_2ANT_SCOREBOARD_ONOFF | + BT_8822B_2ANT_SCOREBOARD_SCAN | + BT_8822B_2ANT_SCOREBOARD_UNDERTEST, + false); + + btcoexist->stop_coex_dm = true; + coex_sta->is_rf_state_off = true; + } +} + +void ex_btc8822b2ant_halt_notify(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], Halt notify\n"); + + halbtc8822b2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, FORCE_EXEC, + BT_8822B_2ANT_PHASE_WLAN_OFF); + + ex_btc8822b2ant_media_status_notify(btcoexist, BTC_MEDIA_DISCONNECT); + + halbtc8822b2ant_post_state_to_bt( + btcoexist, BT_8822B_2ANT_SCOREBOARD_ACTIVE, false); + halbtc8822b2ant_post_state_to_bt(btcoexist, + BT_8822B_2ANT_SCOREBOARD_ONOFF, false); +} + +void ex_btc8822b2ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + bool wifi_under_5g = false; + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], Pnp notify\n"); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + + if ((pnp_state == BTC_WIFI_PNP_SLEEP) || + (pnp_state == BTC_WIFI_PNP_SLEEP_KEEP_ANT)) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Pnp notify to SLEEP\n"); + + /* Sinda 20150819, workaround for driver skip leave IPS/LPS to + * speed up sleep time. + * Driver do not leave IPS/LPS when driver is going to sleep, + * so BTCoexistence think wifi is still under IPS/LPS. + * BT should clear UnderIPS/UnderLPS state to avoid mismatch + * state after wakeup. + */ + coex_sta->under_ips = false; + coex_sta->under_lps = false; + + halbtc8822b2ant_post_state_to_bt( + btcoexist, BT_8822B_2ANT_SCOREBOARD_ACTIVE, false); + halbtc8822b2ant_post_state_to_bt( + btcoexist, BT_8822B_2ANT_SCOREBOARD_ONOFF, false); + + if (pnp_state == BTC_WIFI_PNP_SLEEP_KEEP_ANT) { + if (wifi_under_5g) + halbtc8822b2ant_set_ant_path( + btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8822B_2ANT_PHASE_5G_RUNTIME); + else + halbtc8822b2ant_set_ant_path( + btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8822B_2ANT_PHASE_2G_RUNTIME); + } else { + halbtc8822b2ant_set_ant_path( + btcoexist, BTC_ANT_PATH_AUTO, FORCE_EXEC, + BT_8822B_2ANT_PHASE_WLAN_OFF); + } + } else if (pnp_state == BTC_WIFI_PNP_WAKE_UP) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Pnp notify to WAKE UP\n"); + + halbtc8822b2ant_post_state_to_bt( + btcoexist, BT_8822B_2ANT_SCOREBOARD_ACTIVE, true); + halbtc8822b2ant_post_state_to_bt( + btcoexist, BT_8822B_2ANT_SCOREBOARD_ONOFF, true); + } +} + +void ex_btc8822b2ant_periodical(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + bool wifi_busy = false; + u16 bt_scoreboard_val = 0; + bool bt_relink_finish = false; + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ************* Periodical *************\n"); + + if (!btcoexist->auto_report_2ant) + halbtc8822b2ant_query_bt_info(btcoexist); + + halbtc8822b2ant_monitor_bt_ctr(btcoexist); + halbtc8822b2ant_monitor_wifi_ctr(btcoexist); + halbtc8822b2ant_monitor_bt_enable_disable(btcoexist); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + halbtc8822b2ant_read_score_board(btcoexist, &bt_scoreboard_val); + + if (wifi_busy) { + halbtc8822b2ant_post_state_to_bt( + btcoexist, BT_8822B_2ANT_SCOREBOARD_UNDERTEST, true); + /*for bt lps32 clock offset*/ + if (bt_scoreboard_val & BIT(6)) + halbtc8822b2ant_query_bt_info(btcoexist); + } else { + halbtc8822b2ant_post_state_to_bt( + btcoexist, BT_8822B_2ANT_SCOREBOARD_UNDERTEST, false); + } + + if (coex_sta->bt_relink_downcount != 0) { + coex_sta->bt_relink_downcount--; + + if (coex_sta->bt_relink_downcount == 0) { + coex_sta->is_setup_link = false; + bt_relink_finish = true; + } + } + + /* for 4-way, DHCP, EAPOL packet */ + if (coex_sta->specific_pkt_period_cnt > 0) { + coex_sta->specific_pkt_period_cnt--; + + if ((coex_sta->specific_pkt_period_cnt == 0) && + (coex_sta->wifi_is_high_pri_task)) + coex_sta->wifi_is_high_pri_task = false; + + RT_TRACE( + rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ***************** Hi-Pri Task = %s*****************\n", + (coex_sta->wifi_is_high_pri_task ? "Yes" : "No")); + } + + if (halbtc8822b2ant_is_wifibt_status_changed(btcoexist) || + (bt_relink_finish) || (coex_sta->is_set_ps_state_fail)) + halbtc8822b2ant_run_coexist_mechanism(btcoexist); +} + +void ex_btc8822b2ant_antenna_detection(struct btc_coexist *btcoexist, + u32 cent_freq, u32 offset, u32 span, + u32 seconds) +{ +} + +void ex_btc8822b2ant_display_ant_detection(struct btc_coexist *btcoexist) {} diff --git a/drivers/staging/rtlwifi/btcoexist/halbtc8822b2ant.h b/drivers/staging/rtlwifi/btcoexist/halbtc8822b2ant.h new file mode 100644 index 000000000000..212e0c8404fa --- /dev/null +++ b/drivers/staging/rtlwifi/btcoexist/halbtc8822b2ant.h @@ -0,0 +1,498 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +/* ******************************************* + * The following is for 8822B 2Ant BT Co-exist definition + * ********************************************/ +#define BT_INFO_8822B_2ANT_B_FTP BIT(7) +#define BT_INFO_8822B_2ANT_B_A2DP BIT(6) +#define BT_INFO_8822B_2ANT_B_HID BIT(5) +#define BT_INFO_8822B_2ANT_B_SCO_BUSY BIT(4) +#define BT_INFO_8822B_2ANT_B_ACL_BUSY BIT(3) +#define BT_INFO_8822B_2ANT_B_INQ_PAGE BIT(2) +#define BT_INFO_8822B_2ANT_B_SCO_ESCO BIT(1) +#define BT_INFO_8822B_2ANT_B_CONNECTION BIT(0) + +#define BTC_RSSI_COEX_THRESH_TOL_8822B_2ANT 2 + +/* unit: % WiFi RSSI Threshold for 2-Ant free-run/2-Ant TDMA translation. + * (default = 42) + */ +#define BT_8822B_2ANT_WIFI_RSSI_COEXSWITCH_THRES1 80 +/* unit: % BT RSSI Threshold for 2-Ant free-run/2-Ant TDMA translation. + * (default = 46) + */ +#define BT_8822B_2ANT_BT_RSSI_COEXSWITCH_THRES1 80 +/* unit: % WiFi RSSI Threshold for 1-Ant TDMA/1-Ant PS-TDMA translation. + * (default = 42) + */ +#define BT_8822B_2ANT_WIFI_RSSI_COEXSWITCH_THRES2 80 +/* unit: % BT RSSI Threshold for 1-Ant TDMA/1-Ant PS-TDMA translation. + * (default = 46) + */ +#define BT_8822B_2ANT_BT_RSSI_COEXSWITCH_THRES2 80 +#define BT_8822B_2ANT_DEFAULT_ISOLATION 15 /* unit: dB */ +#define BT_8822B_2ANT_WIFI_MAX_TX_POWER 15 /* unit: dBm */ +#define BT_8822B_2ANT_BT_MAX_TX_POWER 3 /* unit: dBm */ +#define BT_8822B_2ANT_WIFI_SIR_THRES1 -15 /* unit: dB */ +#define BT_8822B_2ANT_WIFI_SIR_THRES2 -30 /* unit: dB */ +#define BT_8822B_2ANT_BT_SIR_THRES1 -15 /* unit: dB */ +#define BT_8822B_2ANT_BT_SIR_THRES2 -30 /* unit: dB */ + +/* for Antenna detection */ +#define BT_8822B_2ANT_ANTDET_PSDTHRES_BACKGROUND 50 +#define BT_8822B_2ANT_ANTDET_PSDTHRES_2ANT_BADISOLATION 70 +#define BT_8822B_2ANT_ANTDET_PSDTHRES_2ANT_GOODISOLATION 52 +#define BT_8822B_2ANT_ANTDET_PSDTHRES_1ANT 40 +#define BT_8822B_2ANT_ANTDET_RETRY_INTERVAL \ + 10 /* retry timer if ant det is fail, unit: second */ +#define BT_8822B_2ANT_ANTDET_SWEEPPOINT_DELAY 60000 +#define BT_8822B_2ANT_ANTDET_ENABLE 0 +#define BT_8822B_2ANT_ANTDET_BTTXTIME 100 +#define BT_8822B_2ANT_ANTDET_BTTXCHANNEL 39 +#define BT_8822B_2ANT_ANTDET_PSD_SWWEEPCOUNT 50 + +#define BT_8822B_2ANT_LTECOEX_INDIRECTREG_ACCESS_TIMEOUT 30000 + +enum bt_8822b_2ant_signal_state { + BT_8822B_2ANT_SIG_STA_SET_TO_LOW = 0x0, + BT_8822B_2ANT_SIG_STA_SET_BY_HW = 0x0, + BT_8822B_2ANT_SIG_STA_SET_TO_HIGH = 0x1, + BT_8822B_2ANT_SIG_STA_MAX +}; + +enum bt_8822b_2ant_path_ctrl_owner { + BT_8822B_2ANT_PCO_BTSIDE = 0x0, + BT_8822B_2ANT_PCO_WLSIDE = 0x1, + BT_8822B_2ANT_PCO_MAX +}; + +enum bt_8822b_2ant_gnt_ctrl_type { + BT_8822B_2ANT_GNT_TYPE_CTRL_BY_PTA = 0x0, + BT_8822B_2ANT_GNT_TYPE_CTRL_BY_SW = 0x1, + BT_8822B_2ANT_GNT_TYPE_MAX +}; + +enum bt_8822b_2ant_gnt_ctrl_block { + BT_8822B_2ANT_GNT_BLOCK_RFC_BB = 0x0, + BT_8822B_2ANT_GNT_BLOCK_RFC = 0x1, + BT_8822B_2ANT_GNT_BLOCK_BB = 0x2, + BT_8822B_2ANT_GNT_BLOCK_MAX +}; + +enum bt_8822b_2ant_lte_coex_table_type { + BT_8822B_2ANT_CTT_WL_VS_LTE = 0x0, + BT_8822B_2ANT_CTT_BT_VS_LTE = 0x1, + BT_8822B_2ANT_CTT_MAX +}; + +enum bt_8822b_2ant_lte_break_table_type { + BT_8822B_2ANT_LBTT_WL_BREAK_LTE = 0x0, + BT_8822B_2ANT_LBTT_BT_BREAK_LTE = 0x1, + BT_8822B_2ANT_LBTT_LTE_BREAK_WL = 0x2, + BT_8822B_2ANT_LBTT_LTE_BREAK_BT = 0x3, + BT_8822B_2ANT_LBTT_MAX +}; + +enum bt_info_src_8822b_2ant { + BT_INFO_SRC_8822B_2ANT_WIFI_FW = 0x0, + BT_INFO_SRC_8822B_2ANT_BT_RSP = 0x1, + BT_INFO_SRC_8822B_2ANT_BT_ACTIVE_SEND = 0x2, + BT_INFO_SRC_8822B_2ANT_MAX +}; + +enum bt_8822b_2ant_bt_status { + BT_8822B_2ANT_BT_STATUS_NON_CONNECTED_IDLE = 0x0, + BT_8822B_2ANT_BT_STATUS_CONNECTED_IDLE = 0x1, + BT_8822B_2ANT_BT_STATUS_INQ_PAGE = 0x2, + BT_8822B_2ANT_BT_STATUS_ACL_BUSY = 0x3, + BT_8822B_2ANT_BT_STATUS_SCO_BUSY = 0x4, + BT_8822B_2ANT_BT_STATUS_ACL_SCO_BUSY = 0x5, + BT_8822B_2ANT_BT_STATUS_MAX +}; + +enum bt_8822b_2ant_coex_algo { + BT_8822B_2ANT_COEX_ALGO_UNDEFINED = 0x0, + BT_8822B_2ANT_COEX_ALGO_SCO = 0x1, + BT_8822B_2ANT_COEX_ALGO_HID = 0x2, + BT_8822B_2ANT_COEX_ALGO_A2DP = 0x3, + BT_8822B_2ANT_COEX_ALGO_A2DP_PANHS = 0x4, + BT_8822B_2ANT_COEX_ALGO_PANEDR = 0x5, + BT_8822B_2ANT_COEX_ALGO_PANHS = 0x6, + BT_8822B_2ANT_COEX_ALGO_PANEDR_A2DP = 0x7, + BT_8822B_2ANT_COEX_ALGO_PANEDR_HID = 0x8, + BT_8822B_2ANT_COEX_ALGO_HID_A2DP_PANEDR = 0x9, + BT_8822B_2ANT_COEX_ALGO_HID_A2DP = 0xa, + BT_8822B_2ANT_COEX_ALGO_NOPROFILEBUSY = 0xb, + BT_8822B_2ANT_COEX_ALGO_A2DPSINK = 0xc, + BT_8822B_2ANT_COEX_ALGO_MAX +}; + +enum bt_8822b_2ant_ext_ant_switch_type { + BT_8822B_2ANT_EXT_ANT_SWITCH_USE_DPDT = 0x0, + BT_8822B_2ANT_EXT_ANT_SWITCH_USE_SPDT = 0x1, + BT_8822B_2ANT_EXT_ANT_SWITCH_NONE = 0x2, + BT_8822B_2ANT_EXT_ANT_SWITCH_MAX +}; + +enum bt_8822b_2ant_ext_ant_switch_ctrl_type { + BT_8822B_2ANT_EXT_ANT_SWITCH_CTRL_BY_BBSW = 0x0, + BT_8822B_2ANT_EXT_ANT_SWITCH_CTRL_BY_PTA = 0x1, + BT_8822B_2ANT_EXT_ANT_SWITCH_CTRL_BY_ANTDIV = 0x2, + BT_8822B_2ANT_EXT_ANT_SWITCH_CTRL_BY_MAC = 0x3, + BT_8822B_2ANT_EXT_ANT_SWITCH_CTRL_BY_BT = 0x4, + BT_8822B_2ANT_EXT_ANT_SWITCH_CTRL_MAX +}; + +enum bt_8822b_2ant_ext_ant_switch_pos_type { + BT_8822B_2ANT_EXT_ANT_SWITCH_MAIN_TO_BT = 0x0, + BT_8822B_2ANT_EXT_ANT_SWITCH_MAIN_TO_WLG = 0x1, + BT_8822B_2ANT_EXT_ANT_SWITCH_MAIN_TO_WLA = 0x2, + BT_8822B_2ANT_EXT_ANT_SWITCH_MAIN_TO_NOCARE = 0x3, + BT_8822B_2ANT_EXT_ANT_SWITCH_MAIN_TO_MAX +}; + +enum bt_8822b_2ant_ext_band_switch_pos_type { + BT_8822B_2ANT_EXT_BAND_SWITCH_TO_WLG = 0x0, + BT_8822B_2ANT_EXT_BAND_SWITCH_TO_WLA = 0x1, + BT_8822B_2ANT_EXT_BAND_SWITCH_TO_MAX +}; + +enum bt_8822b_2ant_int_block { + BT_8822B_2ANT_INT_BLOCK_SWITCH_TO_WLG_OF_BTG = 0x0, + BT_8822B_2ANT_INT_BLOCK_SWITCH_TO_WLG_OF_WLAG = 0x1, + BT_8822B_2ANT_INT_BLOCK_SWITCH_TO_WLA_OF_WLAG = 0x2, + BT_8822B_2ANT_INT_BLOCK_SWITCH_TO_MAX +}; + +enum bt_8822b_2ant_phase { + BT_8822B_2ANT_PHASE_COEX_INIT = 0x0, + BT_8822B_2ANT_PHASE_WLANONLY_INIT = 0x1, + BT_8822B_2ANT_PHASE_WLAN_OFF = 0x2, + BT_8822B_2ANT_PHASE_2G_RUNTIME = 0x3, + BT_8822B_2ANT_PHASE_5G_RUNTIME = 0x4, + BT_8822B_2ANT_PHASE_BTMPMODE = 0x5, + BT_8822B_2ANT_PHASE_ANTENNA_DET = 0x6, + BT_8822B_2ANT_PHASE_COEX_POWERON = 0x7, + BT_8822B_2ANT_PHASE_2G_RUNTIME_CONCURRENT = 0x8, + BT_8822B_2ANT_PHASE_MAX +}; + +/*ADD SCOREBOARD TO FIX BT LPS 32K ISSUE WHILE WL BUSY*/ + +enum bt_8822b_2ant_scoreboard { + BT_8822B_2ANT_SCOREBOARD_ACTIVE = BIT(0), + BT_8822B_2ANT_SCOREBOARD_ONOFF = BIT(1), + BT_8822B_2ANT_SCOREBOARD_SCAN = BIT(2), + BT_8822B_2ANT_SCOREBOARD_UNDERTEST = BIT(3), + BT_8822B_2ANT_SCOREBOARD_WLBUSY = BIT(6) +}; + +struct coex_dm_8822b_2ant { + /* hw setting */ + u32 pre_ant_pos_type; + u32 cur_ant_pos_type; + /* fw mechanism */ + u8 pre_bt_dec_pwr_lvl; + u8 cur_bt_dec_pwr_lvl; + u8 pre_fw_dac_swing_lvl; + u8 cur_fw_dac_swing_lvl; + bool cur_ignore_wlan_act; + bool pre_ignore_wlan_act; + u8 pre_ps_tdma; + u8 cur_ps_tdma; + u8 ps_tdma_para[5]; + u8 ps_tdma_du_adj_type; + bool reset_tdma_adjust; + bool pre_ps_tdma_on; + bool cur_ps_tdma_on; + bool pre_bt_auto_report; + bool cur_bt_auto_report; + + /* sw mechanism */ + bool pre_rf_rx_lpf_shrink; + bool cur_rf_rx_lpf_shrink; + u32 bt_rf_0x1e_backup; + bool pre_low_penalty_ra; + bool cur_low_penalty_ra; + bool pre_dac_swing_on; + u32 pre_dac_swing_lvl; + bool cur_dac_swing_on; + u32 cur_dac_swing_lvl; + bool pre_adc_back_off; + bool cur_adc_back_off; + bool pre_agc_table_en; + bool cur_agc_table_en; + u32 pre_val0x6c0; + u32 cur_val0x6c0; + u32 pre_val0x6c4; + u32 cur_val0x6c4; + u32 pre_val0x6c8; + u32 cur_val0x6c8; + u8 pre_val0x6cc; + u8 cur_val0x6cc; + bool limited_dig; + + /* algorithm related */ + u8 pre_algorithm; + u8 cur_algorithm; + u8 bt_status; + u8 wifi_chnl_info[3]; + + bool need_recover0x948; + u32 backup0x948; + + u8 pre_lps; + u8 cur_lps; + u8 pre_rpwm; + u8 cur_rpwm; + + bool is_switch_to_1dot5_ant; + u8 switch_thres_offset; + u32 arp_cnt; + + u32 pre_ext_ant_switch_status; + u32 cur_ext_ant_switch_status; + + u8 pre_ext_band_switch_status; + u8 cur_ext_band_switch_status; + + u8 pre_int_block_status; + u8 cur_int_block_status; +}; + +struct coex_sta_8822b_2ant { + bool bt_disabled; + bool bt_link_exist; + bool sco_exist; + bool a2dp_exist; + bool hid_exist; + bool pan_exist; + + bool under_lps; + bool under_ips; + u32 high_priority_tx; + u32 high_priority_rx; + u32 low_priority_tx; + u32 low_priority_rx; + bool is_hi_pri_rx_overhead; + u8 bt_rssi; + u8 pre_bt_rssi_state; + u8 pre_wifi_rssi_state[4]; + u8 bt_info_c2h[BT_INFO_SRC_8822B_2ANT_MAX][10]; + u32 bt_info_c2h_cnt[BT_INFO_SRC_8822B_2ANT_MAX]; + bool bt_whck_test; + bool c2h_bt_inquiry_page; + bool c2h_bt_remote_name_req; + + u8 bt_info_ext; + u8 bt_info_ext2; + u32 pop_event_cnt; + u8 scan_ap_num; + u8 bt_retry_cnt; + + u32 crc_ok_cck; + u32 crc_ok_11g; + u32 crc_ok_11n; + u32 crc_ok_11n_vht; + + u32 crc_err_cck; + u32 crc_err_11g; + u32 crc_err_11n; + u32 crc_err_11n_vht; + + u32 acc_crc_ratio; + u32 now_crc_ratio; + + bool cck_lock; + bool pre_ccklock; + bool cck_ever_lock; + + u8 coex_table_type; + bool force_lps_ctrl; + + u8 dis_ver_info_cnt; + + u8 a2dp_bit_pool; + u8 cut_version; + + bool concurrent_rx_mode_on; + + u16 score_board; + u8 isolation_btween_wb; /* 0~ 50 */ + u8 wifi_coex_thres; + u8 bt_coex_thres; + u8 wifi_coex_thres2; + u8 bt_coex_thres2; + + u8 num_of_profile; + bool acl_busy; + bool bt_create_connection; + bool wifi_is_high_pri_task; + u32 specific_pkt_period_cnt; + u32 bt_coex_supported_feature; + u32 bt_coex_supported_version; + + u8 bt_ble_scan_type; + u32 bt_ble_scan_para[3]; + + bool run_time_state; + bool freeze_coexrun_by_btinfo; + + bool is_A2DP_3M; + bool voice_over_HOGP; + u8 bt_info; + bool is_autoslot; + u8 forbidden_slot; + u8 hid_busy_num; + u8 hid_pair_cnt; + + u32 cnt_remote_name_req; + u32 cnt_setup_link; + u32 cnt_reinit; + u32 cnt_ign_wlan_act; + u32 cnt_page; + u32 cnt_role_switch; + + u16 bt_reg_vendor_ac; + u16 bt_reg_vendor_ae; + + bool is_setup_link; + u8 wl_noisy_level; + u32 gnt_error_cnt; + + u8 bt_afh_map[10]; + u8 bt_relink_downcount; + bool is_tdma_btautoslot; + bool is_tdma_btautoslot_hang; + + bool is_esco_mode; + u8 switch_band_notify_to; + bool is_rf_state_off; + + bool is_hid_low_pri_tx_overhead; + bool is_bt_multi_link; + bool is_bt_a2dp_sink; + + bool is_set_ps_state_fail; + u8 cnt_set_ps_state_fail; +}; + +#define BT_8822B_2ANT_EXT_BAND_SWITCH_USE_DPDT 0 +#define BT_8822B_2ANT_EXT_BAND_SWITCH_USE_SPDT 1 + +struct rfe_type_8822b_2ant { + u8 rfe_module_type; + bool ext_ant_switch_exist; + u8 ext_ant_switch_type; /* 0:DPDT, 1:SPDT */ + /* iF 0: DPDT_P=0, DPDT_N=1 => BTG to Main, WL_A+G to Aux */ + u8 ext_ant_switch_ctrl_polarity; + + bool ext_band_switch_exist; + u8 ext_band_switch_type; /* 0:DPDT, 1:SPDT */ + u8 ext_band_switch_ctrl_polarity; + + /* If true: WLG at BTG, If false: WLG at WLAG */ + bool wlg_locate_at_btg; + + bool ext_ant_switch_diversity; /* If diversity on */ +}; + +#define BT_8822B_2ANT_ANTDET_PSD_POINTS 256 /* MAX:1024 */ +#define BT_8822B_2ANT_ANTDET_PSD_AVGNUM 1 /* MAX:3 */ +#define BT_8822B_2ANT_ANTDET_BUF_LEN 16 + +struct psdscan_sta_8822b_2ant { + u32 ant_det_bt_le_channel; /* BT LE Channel ex:2412 */ + u32 ant_det_bt_tx_time; + u32 ant_det_pre_psdscan_peak_val; + bool ant_det_is_ant_det_available; + u32 ant_det_psd_scan_peak_val; + bool ant_det_is_btreply_available; + u32 ant_det_psd_scan_peak_freq; + + u8 ant_det_result; + u8 ant_det_peak_val[BT_8822B_2ANT_ANTDET_BUF_LEN]; + u8 ant_det_peak_freq[BT_8822B_2ANT_ANTDET_BUF_LEN]; + u32 ant_det_try_count; + u32 ant_det_fail_count; + u32 ant_det_inteval_count; + u32 ant_det_thres_offset; + + u32 real_cent_freq; + s32 real_offset; + u32 real_span; + + u32 psd_band_width; /* unit: Hz */ + u32 psd_point; /* 128/256/512/1024 */ + u32 psd_report[1024]; /* unit:dB (20logx), 0~255 */ + u32 psd_report_max_hold[1024]; /* unit:dB (20logx), 0~255 */ + u32 psd_start_point; + u32 psd_stop_point; + u32 psd_max_value_point; + u32 psd_max_value; + u32 psd_max_value2; + /* filter loop_max_value that below BT_8822B_1ANT_ANTDET_PSDTHRES_1ANT, + * and average the rest + */ + u32 psd_avg_value; + /*max value in each loop */ + u32 psd_loop_max_value[BT_8822B_2ANT_ANTDET_PSD_SWWEEPCOUNT]; + u32 psd_start_base; + u32 psd_avg_num; /* 1/8/16/32 */ + u32 psd_gen_count; + bool is_ant_det_running; + bool is_psd_show_max_only; +}; + +/* ******************************************* + * The following is interface which will notify coex module. + * ********************************************/ +void ex_btc8822b2ant_power_on_setting(struct btc_coexist *btcoexist); +void ex_btc8822b2ant_pre_load_firmware(struct btc_coexist *btcoexist); +void ex_btc8822b2ant_init_hw_config(struct btc_coexist *btcoexist, + bool wifi_only); +void ex_btc8822b2ant_init_coex_dm(struct btc_coexist *btcoexist); +void ex_btc8822b2ant_ips_notify(struct btc_coexist *btcoexist, u8 type); +void ex_btc8822b2ant_lps_notify(struct btc_coexist *btcoexist, u8 type); +void ex_btc8822b2ant_scan_notify(struct btc_coexist *btcoexist, u8 type); +void ex_btc8822b2ant_switchband_notify(struct btc_coexist *btcoexist, u8 type); +void ex_btc8822b2ant_connect_notify(struct btc_coexist *btcoexist, u8 type); +void ex_btc8822b2ant_media_status_notify(struct btc_coexist *btcoexist, + u8 type); +void ex_btc8822b2ant_specific_packet_notify(struct btc_coexist *btcoexist, + u8 type); +void ex_btc8822b2ant_bt_info_notify(struct btc_coexist *btcoexist, u8 *tmp_buf, + u8 length); +void ex_btc8822b2ant_rf_status_notify(struct btc_coexist *btcoexist, u8 type); +void ex_btc8822b2ant_halt_notify(struct btc_coexist *btcoexist); +void ex_btc8822b2ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state); +void ex_btc8822b2ant_periodical(struct btc_coexist *btcoexist); +void ex_btc8822b2ant_display_coex_info(struct btc_coexist *btcoexist, + struct seq_file *m); +void ex_btc8822b2ant_antenna_detection(struct btc_coexist *btcoexist, + u32 cent_freq, u32 offset, u32 span, + u32 seconds); +void ex_btc8822b2ant_display_ant_detection(struct btc_coexist *btcoexist); diff --git a/drivers/staging/rtlwifi/btcoexist/halbtc8822bwifionly.c b/drivers/staging/rtlwifi/btcoexist/halbtc8822bwifionly.c new file mode 100644 index 000000000000..43d628a71611 --- /dev/null +++ b/drivers/staging/rtlwifi/btcoexist/halbtc8822bwifionly.c @@ -0,0 +1,65 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#include "halbt_precomp.h" + +void ex_hal8822b_wifi_only_hw_config(struct wifi_only_cfg *wifionlycfg) +{ + /*BB control*/ + halwifionly_phy_set_bb_reg(wifionlycfg, 0x4c, 0x01800000, 0x2); + /*SW control*/ + halwifionly_phy_set_bb_reg(wifionlycfg, 0xcb4, 0xff, 0x77); + /*antenna mux switch */ + halwifionly_phy_set_bb_reg(wifionlycfg, 0x974, 0x300, 0x3); + + halwifionly_phy_set_bb_reg(wifionlycfg, 0x1990, 0x300, 0x0); + + halwifionly_phy_set_bb_reg(wifionlycfg, 0xcbc, 0x80000, 0x0); + /*switch to WL side controller and gnt_wl gnt_bt debug signal */ + halwifionly_phy_set_bb_reg(wifionlycfg, 0x70, 0xff000000, 0x0e); + /*gnt_wl=1 , gnt_bt=0*/ + halwifionly_phy_set_bb_reg(wifionlycfg, 0x1704, 0xffffffff, 0x7700); + halwifionly_phy_set_bb_reg(wifionlycfg, 0x1700, 0xffffffff, 0xc00f0038); +} + +void ex_hal8822b_wifi_only_scannotify(struct wifi_only_cfg *wifionlycfg, + u8 is_5g) +{ + hal8822b_wifi_only_switch_antenna(wifionlycfg, is_5g); +} + +void ex_hal8822b_wifi_only_switchbandnotify(struct wifi_only_cfg *wifionlycfg, + u8 is_5g) +{ + hal8822b_wifi_only_switch_antenna(wifionlycfg, is_5g); +} + +void hal8822b_wifi_only_switch_antenna(struct wifi_only_cfg *wifionlycfg, + u8 is_5g) +{ + if (is_5g) + halwifionly_phy_set_bb_reg(wifionlycfg, 0xcbc, 0x300, 0x1); + else + halwifionly_phy_set_bb_reg(wifionlycfg, 0xcbc, 0x300, 0x2); +} diff --git a/drivers/staging/rtlwifi/btcoexist/halbtc8822bwifionly.h b/drivers/staging/rtlwifi/btcoexist/halbtc8822bwifionly.h new file mode 100644 index 000000000000..464774e6e7b4 --- /dev/null +++ b/drivers/staging/rtlwifi/btcoexist/halbtc8822bwifionly.h @@ -0,0 +1,35 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef __INC_HAL8822BWIFIONLYHWCFG_H +#define __INC_HAL8822BWIFIONLYHWCFG_H + +void ex_hal8822b_wifi_only_hw_config(struct wifi_only_cfg *wifionlycfg); +void ex_hal8822b_wifi_only_scannotify(struct wifi_only_cfg *wifionlycfg, + u8 is_5g); +void ex_hal8822b_wifi_only_switchbandnotify(struct wifi_only_cfg *wifionlycfg, + u8 is_5g); +void hal8822b_wifi_only_switch_antenna(struct wifi_only_cfg *wifionlycfg, + u8 is_5g); +#endif diff --git a/drivers/staging/rtlwifi/btcoexist/halbtcoutsrc.c b/drivers/staging/rtlwifi/btcoexist/halbtcoutsrc.c new file mode 100644 index 000000000000..52620b72cfa9 --- /dev/null +++ b/drivers/staging/rtlwifi/btcoexist/halbtcoutsrc.c @@ -0,0 +1,1881 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2013 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ + +#include "halbt_precomp.h" + +/*************************************************** + * Debug related function + ***************************************************/ + +static const char *const gl_btc_wifi_bw_string[] = { + "11bg", + "HT20", + "HT40", + "HT80", + "HT160" +}; + +static const char *const gl_btc_wifi_freq_string[] = { + "2.4G", + "5G" +}; + +static bool halbtc_is_bt_coexist_available(struct btc_coexist *btcoexist) +{ + if (!btcoexist->binded || NULL == btcoexist->adapter) + return false; + + return true; +} + +static bool halbtc_is_wifi_busy(struct rtl_priv *rtlpriv) +{ + if (rtlpriv->link_info.busytraffic) + return true; + else + return false; +} + +static void halbtc_dbg_init(void) +{ +} + +/*************************************************** + * helper function + ***************************************************/ +static bool is_any_client_connect_to_ap(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct rtl_mac *mac = rtl_mac(rtlpriv); + struct rtl_sta_info *drv_priv; + u8 cnt = 0; + + if (mac->opmode == NL80211_IFTYPE_ADHOC || + mac->opmode == NL80211_IFTYPE_MESH_POINT || + mac->opmode == NL80211_IFTYPE_AP) { + if (in_interrupt() > 0) { + list_for_each_entry(drv_priv, &rtlpriv->entry_list, + list) { + cnt++; + } + } else { + spin_lock_bh(&rtlpriv->locks.entry_list_lock); + list_for_each_entry(drv_priv, &rtlpriv->entry_list, + list) { + cnt++; + } + spin_unlock_bh(&rtlpriv->locks.entry_list_lock); + } + } + if (cnt > 0) + return true; + else + return false; +} + +static bool halbtc_legacy(struct rtl_priv *adapter) +{ + struct rtl_priv *rtlpriv = adapter; + struct rtl_mac *mac = rtl_mac(rtlpriv); + + bool is_legacy = false; + + if ((mac->mode == WIRELESS_MODE_B) || (mac->mode == WIRELESS_MODE_G)) + is_legacy = true; + + return is_legacy; +} + +bool halbtc_is_wifi_uplink(struct rtl_priv *adapter) +{ + struct rtl_priv *rtlpriv = adapter; + + if (rtlpriv->link_info.tx_busy_traffic) + return true; + else + return false; +} + +static u32 halbtc_get_wifi_bw(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = + (struct rtl_priv *)btcoexist->adapter; + struct rtl_phy *rtlphy = &rtlpriv->phy; + u32 wifi_bw = BTC_WIFI_BW_HT20; + + if (halbtc_legacy(rtlpriv)) { + wifi_bw = BTC_WIFI_BW_LEGACY; + } else { + switch (rtlphy->current_chan_bw) { + case HT_CHANNEL_WIDTH_20: + wifi_bw = BTC_WIFI_BW_HT20; + break; + case HT_CHANNEL_WIDTH_20_40: + wifi_bw = BTC_WIFI_BW_HT40; + break; + case HT_CHANNEL_WIDTH_80: + wifi_bw = BTC_WIFI_BW_HT80; + break; + } + } + + return wifi_bw; +} + +static u8 halbtc_get_wifi_central_chnl(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct rtl_phy *rtlphy = &rtlpriv->phy; + u8 chnl = 1; + + if (rtlphy->current_channel != 0) + chnl = rtlphy->current_channel; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "%s:%d\n", __func__, chnl); + return chnl; +} + +static u8 rtl_get_hwpg_single_ant_path(struct rtl_priv *rtlpriv) +{ + return rtlpriv->btcoexist.btc_info.single_ant_path; +} + +static u8 rtl_get_hwpg_bt_type(struct rtl_priv *rtlpriv) +{ + return rtlpriv->btcoexist.btc_info.bt_type; +} + +static u8 rtl_get_hwpg_ant_num(struct rtl_priv *rtlpriv) +{ + u8 num; + + if (rtlpriv->btcoexist.btc_info.ant_num == ANT_X2) + num = 2; + else + num = 1; + + return num; +} + +static u8 rtl_get_hwpg_package_type(struct rtl_priv *rtlpriv) +{ + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + + return rtlhal->package_type; +} + +static +u8 rtl_get_hwpg_rfe_type(struct rtl_priv *rtlpriv) +{ + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + + return rtlhal->rfe_type; +} + +/* ************************************ + * Hal helper function + * ************************************ + */ +static +bool halbtc_is_hw_mailbox_exist(struct btc_coexist *btcoexist) +{ + if (IS_HARDWARE_TYPE_8812(btcoexist->adapter)) + return false; + else + return true; +} + +static +bool halbtc_send_bt_mp_operation(struct btc_coexist *btcoexist, u8 op_code, + u8 *cmd, u32 len, unsigned long wait_ms) +{ + struct rtl_priv *rtlpriv; + const u8 oper_ver = 0; + u8 req_num; + + if (!halbtc_is_hw_mailbox_exist(btcoexist)) + return false; + + if (wait_ms) /* before h2c to avoid race condition */ + reinit_completion(&btcoexist->bt_mp_comp); + + rtlpriv = btcoexist->adapter; + + /* + * fill req_num by op_code, and rtl_btc_btmpinfo_notify() use it + * to know message type + */ + switch (op_code) { + case BT_OP_GET_BT_VERSION: + req_num = BT_SEQ_GET_BT_VERSION; + break; + case BT_OP_GET_AFH_MAP_L: + req_num = BT_SEQ_GET_AFH_MAP_L; + break; + case BT_OP_GET_AFH_MAP_M: + req_num = BT_SEQ_GET_AFH_MAP_M; + break; + case BT_OP_GET_AFH_MAP_H: + req_num = BT_SEQ_GET_AFH_MAP_H; + break; + case BT_OP_GET_BT_COEX_SUPPORTED_FEATURE: + req_num = BT_SEQ_GET_BT_COEX_SUPPORTED_FEATURE; + break; + case BT_OP_GET_BT_COEX_SUPPORTED_VERSION: + req_num = BT_SEQ_GET_BT_COEX_SUPPORTED_VERSION; + break; + case BT_OP_GET_BT_ANT_DET_VAL: + req_num = BT_SEQ_GET_BT_ANT_DET_VAL; + break; + case BT_OP_GET_BT_BLE_SCAN_PARA: + req_num = BT_SEQ_GET_BT_BLE_SCAN_PARA; + break; + case BT_OP_GET_BT_BLE_SCAN_TYPE: + req_num = BT_SEQ_GET_BT_BLE_SCAN_TYPE; + break; + case BT_OP_WRITE_REG_ADDR: + case BT_OP_WRITE_REG_VALUE: + case BT_OP_READ_REG: + default: + req_num = BT_SEQ_DONT_CARE; + break; + } + + cmd[0] |= (oper_ver & 0x0f); /* Set OperVer */ + cmd[0] |= ((req_num << 4) & 0xf0); /* Set ReqNum */ + cmd[1] = op_code; + rtlpriv->cfg->ops->fill_h2c_cmd(rtlpriv->mac80211.hw, 0x67, len, cmd); + + /* wait? */ + if (!wait_ms) + return true; + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "btmpinfo wait req_num=%d wait=%ld\n", req_num, wait_ms); + + if (in_interrupt()) + return false; + + if (wait_for_completion_timeout(&btcoexist->bt_mp_comp, + msecs_to_jiffies(wait_ms)) == 0) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, + "btmpinfo wait (req_num=%d) timeout\n", req_num); + + return false; /* timeout */ + } + + return true; +} + +static void halbtc_leave_lps(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv; + struct rtl_ps_ctl *ppsc; + bool ap_enable = false; + + rtlpriv = btcoexist->adapter; + ppsc = rtl_psc(rtlpriv); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, + &ap_enable); + + if (ap_enable) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, + "%s()<--dont leave lps under AP mode\n", __func__); + return; + } + + btcoexist->bt_info.bt_ctrl_lps = true; + btcoexist->bt_info.bt_lps_on = false; + rtl_lps_leave(rtlpriv->mac80211.hw); +} + +static void halbtc_enter_lps(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv; + struct rtl_ps_ctl *ppsc; + bool ap_enable = false; + + rtlpriv = btcoexist->adapter; + ppsc = rtl_psc(rtlpriv); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, + &ap_enable); + + if (ap_enable) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, + "%s()<--dont enter lps under AP mode\n", __func__); + return; + } + + btcoexist->bt_info.bt_ctrl_lps = true; + btcoexist->bt_info.bt_lps_on = true; + rtl_lps_enter(rtlpriv->mac80211.hw); +} + +static void halbtc_normal_lps(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv; + + rtlpriv = btcoexist->adapter; + + if (btcoexist->bt_info.bt_ctrl_lps) { + btcoexist->bt_info.bt_lps_on = false; + rtl_lps_leave(rtlpriv->mac80211.hw); + btcoexist->bt_info.bt_ctrl_lps = false; + } +} + +static void halbtc_leave_low_power(struct btc_coexist *btcoexist) +{ +} + +static void halbtc_normal_low_power(struct btc_coexist *btcoexist) +{ +} + +static void halbtc_disable_low_power(struct btc_coexist *btcoexist, + bool low_pwr_disable) +{ + /* TODO: original/leave 32k low power */ + btcoexist->bt_info.bt_disable_low_pwr = low_pwr_disable; +} + +static void halbtc_aggregation_check(struct btc_coexist *btcoexist) +{ + bool need_to_act = false; + static unsigned long pre_time; + unsigned long cur_time = 0; + struct rtl_priv *rtlpriv = btcoexist->adapter; + + /* To void continuous deleteBA=>addBA=>deleteBA=>addBA + * This function is not allowed to continuous called + * It can only be called after 8 seconds + */ + + cur_time = jiffies; + if (jiffies_to_msecs(cur_time - pre_time) <= 8000) { + /* over 8 seconds you can execute this function again. */ + return; + } + pre_time = cur_time; + + if (btcoexist->bt_info.reject_agg_pkt) { + need_to_act = true; + btcoexist->bt_info.pre_reject_agg_pkt = + btcoexist->bt_info.reject_agg_pkt; + } else { + if (btcoexist->bt_info.pre_reject_agg_pkt) { + need_to_act = true; + btcoexist->bt_info.pre_reject_agg_pkt = + btcoexist->bt_info.reject_agg_pkt; + } + + if (btcoexist->bt_info.pre_bt_ctrl_agg_buf_size != + btcoexist->bt_info.bt_ctrl_agg_buf_size) { + need_to_act = true; + btcoexist->bt_info.pre_bt_ctrl_agg_buf_size = + btcoexist->bt_info.bt_ctrl_agg_buf_size; + } + + if (btcoexist->bt_info.bt_ctrl_agg_buf_size) { + if (btcoexist->bt_info.pre_agg_buf_size != + btcoexist->bt_info.agg_buf_size) { + need_to_act = true; + } + btcoexist->bt_info.pre_agg_buf_size = + btcoexist->bt_info.agg_buf_size; + } + + if (need_to_act) + rtl_rx_ampdu_apply(rtlpriv); + } +} + +static u32 halbtc_get_bt_patch_version(struct btc_coexist *btcoexist) +{ + u8 cmd_buffer[4] = {0}; + + if (btcoexist->bt_info.bt_real_fw_ver) + goto label_done; + + /* cmd_buffer[0] and [1] is filled by halbtc_send_bt_mp_operation() */ + halbtc_send_bt_mp_operation(btcoexist, BT_OP_GET_BT_VERSION, + cmd_buffer, 4, 200); + +label_done: + return btcoexist->bt_info.bt_real_fw_ver; +} + +static u32 halbtc_get_bt_coex_supported_feature(void *btc_context) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)btc_context; + u8 cmd_buffer[4] = {0}; + + if (btcoexist->bt_info.bt_supported_feature) + goto label_done; + + /* cmd_buffer[0] and [1] is filled by halbtc_send_bt_mp_operation() */ + halbtc_send_bt_mp_operation(btcoexist, + BT_OP_GET_BT_COEX_SUPPORTED_FEATURE, + cmd_buffer, 4, 200); + +label_done: + return btcoexist->bt_info.bt_supported_feature; +} + +static u32 halbtc_get_bt_coex_supported_version(void *btc_context) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)btc_context; + u8 cmd_buffer[4] = {0}; + + if (btcoexist->bt_info.bt_supported_version) + goto label_done; + + /* cmd_buffer[0] and [1] is filled by halbtc_send_bt_mp_operation() */ + halbtc_send_bt_mp_operation(btcoexist, + BT_OP_GET_BT_COEX_SUPPORTED_VERSION, + cmd_buffer, 4, 200); + +label_done: + return btcoexist->bt_info.bt_supported_version; +} + +static u32 halbtc_get_wifi_link_status(struct btc_coexist *btcoexist) +{ + /* return value: + * [31:16] => connected port number + * [15:0] => port connected bit define + */ + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct rtl_mac *mac = rtl_mac(rtlpriv); + u32 ret_val = 0; + u32 port_connected_status = 0, num_of_connected_port = 0; + + if (mac->opmode == NL80211_IFTYPE_STATION && + mac->link_state >= MAC80211_LINKED) { + port_connected_status |= WIFI_STA_CONNECTED; + num_of_connected_port++; + } + /* AP & ADHOC & MESH */ + if (is_any_client_connect_to_ap(btcoexist)) { + port_connected_status |= WIFI_AP_CONNECTED; + num_of_connected_port++; + } + /* TODO: P2P Connected Status */ + + ret_val = (num_of_connected_port << 16) | port_connected_status; + + return ret_val; +} + +static s32 halbtc_get_wifi_rssi(struct rtl_priv *rtlpriv) +{ + int undec_sm_pwdb = 0; + + if (rtlpriv->mac80211.link_state >= MAC80211_LINKED) + undec_sm_pwdb = rtlpriv->dm.undec_sm_pwdb; + else /* associated entry pwdb */ + undec_sm_pwdb = rtlpriv->dm.undec_sm_pwdb; + return undec_sm_pwdb; +} + +static bool halbtc_get(void *void_btcoexist, u8 get_type, void *out_buf) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)void_btcoexist; + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct rtl_phy *rtlphy = &rtlpriv->phy; + struct rtl_mac *mac = rtl_mac(rtlpriv); + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + bool *bool_tmp = (bool *)out_buf; + int *s32_tmp = (int *)out_buf; + u32 *u32_tmp = (u32 *)out_buf; + u8 *u8_tmp = (u8 *)out_buf; + bool tmp = false; + bool ret = true; + + if (!halbtc_is_bt_coexist_available(btcoexist)) + return false; + + switch (get_type) { + case BTC_GET_BL_HS_OPERATION: + *bool_tmp = false; + ret = false; + break; + case BTC_GET_BL_HS_CONNECTING: + *bool_tmp = false; + ret = false; + break; + case BTC_GET_BL_WIFI_CONNECTED: + if (rtlpriv->mac80211.opmode == NL80211_IFTYPE_STATION && + rtlpriv->mac80211.link_state >= MAC80211_LINKED) + tmp = true; + if (is_any_client_connect_to_ap(btcoexist)) + tmp = true; + *bool_tmp = tmp; + break; + case BTC_GET_BL_WIFI_BUSY: + if (halbtc_is_wifi_busy(rtlpriv)) + *bool_tmp = true; + else + *bool_tmp = false; + break; + case BTC_GET_BL_WIFI_SCAN: + if (mac->act_scanning) + *bool_tmp = true; + else + *bool_tmp = false; + break; + case BTC_GET_BL_WIFI_LINK: + if (mac->link_state == MAC80211_LINKING) + *bool_tmp = true; + else + *bool_tmp = false; + break; + case BTC_GET_BL_WIFI_ROAM: + if (mac->link_state == MAC80211_LINKING) + *bool_tmp = true; + else + *bool_tmp = false; + break; + case BTC_GET_BL_WIFI_4_WAY_PROGRESS: + *bool_tmp = rtlpriv->btcoexist.btc_info.in_4way; + break; + case BTC_GET_BL_WIFI_UNDER_5G: + if (rtlhal->current_bandtype == BAND_ON_5G) + *bool_tmp = true; + else + *bool_tmp = false; + break; + case BTC_GET_BL_WIFI_AP_MODE_ENABLE: + if (mac->opmode == NL80211_IFTYPE_AP) + *bool_tmp = true; + else + *bool_tmp = false; + break; + case BTC_GET_BL_WIFI_ENABLE_ENCRYPTION: + if (rtlpriv->sec.pairwise_enc_algorithm == NO_ENCRYPTION) + *bool_tmp = false; + else + *bool_tmp = true; + break; + case BTC_GET_BL_WIFI_UNDER_B_MODE: + if (rtlpriv->mac80211.mode == WIRELESS_MODE_B) + *bool_tmp = true; + else + *bool_tmp = false; + break; + case BTC_GET_BL_EXT_SWITCH: + *bool_tmp = false; + break; + case BTC_GET_BL_WIFI_IS_IN_MP_MODE: + *bool_tmp = false; + break; + case BTC_GET_BL_IS_ASUS_8723B: + *bool_tmp = false; + break; + case BTC_GET_BL_RF4CE_CONNECTED: + *bool_tmp = false; + break; + case BTC_GET_S4_WIFI_RSSI: + *s32_tmp = halbtc_get_wifi_rssi(rtlpriv); + break; + case BTC_GET_S4_HS_RSSI: + *s32_tmp = 0; + ret = false; + break; + case BTC_GET_U4_WIFI_BW: + *u32_tmp = halbtc_get_wifi_bw(btcoexist); + break; + case BTC_GET_U4_WIFI_TRAFFIC_DIRECTION: + if (halbtc_is_wifi_uplink(rtlpriv)) + *u32_tmp = BTC_WIFI_TRAFFIC_TX; + else + *u32_tmp = BTC_WIFI_TRAFFIC_RX; + break; + case BTC_GET_U4_WIFI_FW_VER: + *u32_tmp = (rtlhal->fw_version << 16) | rtlhal->fw_subversion; + break; + case BTC_GET_U4_WIFI_LINK_STATUS: + *u32_tmp = halbtc_get_wifi_link_status(btcoexist); + break; + case BTC_GET_U4_BT_PATCH_VER: + *u32_tmp = halbtc_get_bt_patch_version(btcoexist); + break; + case BTC_GET_U4_VENDOR: + *u32_tmp = BTC_VENDOR_OTHER; + break; + case BTC_GET_U4_SUPPORTED_VERSION: + *u32_tmp = halbtc_get_bt_coex_supported_version(btcoexist); + break; + case BTC_GET_U4_SUPPORTED_FEATURE: + *u32_tmp = halbtc_get_bt_coex_supported_feature(btcoexist); + break; + case BTC_GET_U4_WIFI_IQK_TOTAL: + *u32_tmp = btcoexist->btc_phydm_query_phy_counter(btcoexist, + "IQK_TOTAL"); + break; + case BTC_GET_U4_WIFI_IQK_OK: + *u32_tmp = btcoexist->btc_phydm_query_phy_counter(btcoexist, + "IQK_OK"); + break; + case BTC_GET_U4_WIFI_IQK_FAIL: + *u32_tmp = btcoexist->btc_phydm_query_phy_counter(btcoexist, + "IQK_FAIL"); + break; + case BTC_GET_U1_WIFI_DOT11_CHNL: + *u8_tmp = rtlphy->current_channel; + break; + case BTC_GET_U1_WIFI_CENTRAL_CHNL: + *u8_tmp = halbtc_get_wifi_central_chnl(btcoexist); + break; + case BTC_GET_U1_WIFI_HS_CHNL: + *u8_tmp = 0; + ret = false; + break; + case BTC_GET_U1_AP_NUM: + *u8_tmp = rtlpriv->btcoexist.btc_info.ap_num; + break; + case BTC_GET_U1_ANT_TYPE: + *u8_tmp = (u8)BTC_ANT_TYPE_0; + break; + case BTC_GET_U1_IOT_PEER: + *u8_tmp = 0; + break; + + /************* 1Ant **************/ + case BTC_GET_U1_LPS_MODE: + *u8_tmp = btcoexist->pwr_mode_val[0]; + break; + + default: + ret = false; + break; + } + + return ret; +} + +static bool halbtc_set(void *void_btcoexist, u8 set_type, void *in_buf) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)void_btcoexist; + bool *bool_tmp = (bool *)in_buf; + u8 *u8_tmp = (u8 *)in_buf; + u32 *u32_tmp = (u32 *)in_buf; + bool ret = true; + + if (!halbtc_is_bt_coexist_available(btcoexist)) + return false; + + switch (set_type) { + /* set some bool type variables. */ + case BTC_SET_BL_BT_DISABLE: + btcoexist->bt_info.bt_disabled = *bool_tmp; + break; + case BTC_SET_BL_BT_TRAFFIC_BUSY: + btcoexist->bt_info.bt_busy = *bool_tmp; + break; + case BTC_SET_BL_BT_LIMITED_DIG: + btcoexist->bt_info.limited_dig = *bool_tmp; + break; + case BTC_SET_BL_FORCE_TO_ROAM: + btcoexist->bt_info.force_to_roam = *bool_tmp; + break; + case BTC_SET_BL_TO_REJ_AP_AGG_PKT: + btcoexist->bt_info.reject_agg_pkt = *bool_tmp; + break; + case BTC_SET_BL_BT_CTRL_AGG_SIZE: + btcoexist->bt_info.bt_ctrl_agg_buf_size = *bool_tmp; + break; + case BTC_SET_BL_INC_SCAN_DEV_NUM: + btcoexist->bt_info.increase_scan_dev_num = *bool_tmp; + break; + case BTC_SET_BL_BT_TX_RX_MASK: + btcoexist->bt_info.bt_tx_rx_mask = *bool_tmp; + break; + case BTC_SET_BL_MIRACAST_PLUS_BT: + btcoexist->bt_info.miracast_plus_bt = *bool_tmp; + break; + /* set some u1Byte type variables. */ + case BTC_SET_U1_RSSI_ADJ_VAL_FOR_AGC_TABLE_ON: + btcoexist->bt_info.rssi_adjust_for_agc_table_on = *u8_tmp; + break; + case BTC_SET_U1_AGG_BUF_SIZE: + btcoexist->bt_info.agg_buf_size = *u8_tmp; + break; + + /* the following are some action which will be triggered */ + case BTC_SET_ACT_GET_BT_RSSI: + ret = false; + break; + case BTC_SET_ACT_AGGREGATE_CTRL: + halbtc_aggregation_check(btcoexist); + break; + + /* 1Ant */ + case BTC_SET_U1_RSSI_ADJ_VAL_FOR_1ANT_COEX_TYPE: + btcoexist->bt_info.rssi_adjust_for_1ant_coex_type = *u8_tmp; + break; + case BTC_SET_UI_SCAN_SIG_COMPENSATION: + break; + case BTC_SET_U1_LPS_VAL: + btcoexist->bt_info.lps_val = *u8_tmp; + break; + case BTC_SET_U1_RPWM_VAL: + btcoexist->bt_info.rpwm_val = *u8_tmp; + break; + /* the following are some action which will be triggered */ + case BTC_SET_ACT_LEAVE_LPS: + halbtc_leave_lps(btcoexist); + break; + case BTC_SET_ACT_ENTER_LPS: + halbtc_enter_lps(btcoexist); + break; + case BTC_SET_ACT_NORMAL_LPS: + halbtc_normal_lps(btcoexist); + break; + case BTC_SET_ACT_DISABLE_LOW_POWER: + halbtc_disable_low_power(btcoexist, *bool_tmp); + break; + case BTC_SET_ACT_UPDATE_RAMASK: + btcoexist->bt_info.ra_mask = *u32_tmp; + break; + case BTC_SET_ACT_SEND_MIMO_PS: + break; + case BTC_SET_ACT_CTRL_BT_INFO: /*wait for 8812/8821*/ + break; + case BTC_SET_ACT_CTRL_BT_COEX: + break; + case BTC_SET_ACT_CTRL_8723B_ANT: + break; + default: + break; + } + + return ret; +} + +static void halbtc_display_coex_statistics(struct btc_coexist *btcoexist, + struct seq_file *m) +{ +} + +static void halbtc_display_bt_link_info(struct btc_coexist *btcoexist, + struct seq_file *m) +{ +} + +static void halbtc_display_wifi_status(struct btc_coexist *btcoexist, + struct seq_file *m) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + s32 wifi_rssi = 0, bt_hs_rssi = 0; + bool scan = false, link = false, roam = false, wifi_busy = false; + bool wifi_under_b_mode = false, wifi_under_5g = false; + u32 wifi_bw = BTC_WIFI_BW_HT20; + u32 wifi_traffic_dir = BTC_WIFI_TRAFFIC_TX; + u32 wifi_freq = BTC_FREQ_2_4G; + u32 wifi_link_status = 0x0; + bool bt_hs_on = false, under_ips = false, under_lps = false; + bool low_power = false, dc_mode = false; + u8 wifi_chnl = 0, wifi_hs_chnl = 0, fw_ps_state; + u8 ap_num = 0; + + wifi_link_status = halbtc_get_wifi_link_status(btcoexist); + seq_printf(m, "\n %-35s = %d/ %d/ %d/ %d/ %d", + "STA/vWifi/HS/p2pGo/p2pGc", + ((wifi_link_status & WIFI_STA_CONNECTED) ? 1 : 0), + ((wifi_link_status & WIFI_AP_CONNECTED) ? 1 : 0), + ((wifi_link_status & WIFI_HS_CONNECTED) ? 1 : 0), + ((wifi_link_status & WIFI_P2P_GO_CONNECTED) ? 1 : 0), + ((wifi_link_status & WIFI_P2P_GC_CONNECTED) ? 1 : 0)); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_DOT11_CHNL, &wifi_chnl); + btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_HS_CHNL, &wifi_hs_chnl); + seq_printf(m, "\n %-35s = %d / %d(%d)", + "Dot11 channel / HsChnl(High Speed)", + wifi_chnl, wifi_hs_chnl, bt_hs_on); + + btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); + btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi); + seq_printf(m, "\n %-35s = %d/ %d", + "Wifi rssi/ HS rssi", + wifi_rssi - 100, bt_hs_rssi - 100); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + seq_printf(m, "\n %-35s = %d/ %d/ %d ", + "Wifi link/ roam/ scan", + link, roam, scan); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, + &wifi_traffic_dir); + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, &ap_num); + wifi_freq = (wifi_under_5g ? BTC_FREQ_5G : BTC_FREQ_2_4G); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_B_MODE, + &wifi_under_b_mode); + + seq_printf(m, "\n %-35s = %s / %s/ %s/ AP=%d ", + "Wifi freq/ bw/ traffic", + gl_btc_wifi_freq_string[wifi_freq], + ((wifi_under_b_mode) ? "11b" : + gl_btc_wifi_bw_string[wifi_bw]), + ((!wifi_busy) ? "idle" : ((BTC_WIFI_TRAFFIC_TX == + wifi_traffic_dir) ? "uplink" : + "downlink")), + ap_num); + + /* power status */ + dc_mode = true; /*TODO*/ + under_ips = rtlpriv->psc.inactive_pwrstate == ERFOFF ? 1 : 0; + under_lps = rtlpriv->psc.dot11_psmode == EACTIVE ? 0 : 1; + fw_ps_state = 0; + low_power = 0; /*TODO*/ + seq_printf(m, "\n %-35s = %s%s%s%s", + "Power Status", + (dc_mode ? "DC mode" : "AC mode"), + (under_ips ? ", IPS ON" : ""), + (under_lps ? ", LPS ON" : ""), + (low_power ? ", 32k" : "")); + + seq_printf(m, + "\n %-35s = %02x %02x %02x %02x %02x %02x (0x%x/0x%x)", + "Power mode cmd(lps/rpwm)", + btcoexist->pwr_mode_val[0], btcoexist->pwr_mode_val[1], + btcoexist->pwr_mode_val[2], btcoexist->pwr_mode_val[3], + btcoexist->pwr_mode_val[4], btcoexist->pwr_mode_val[5], + btcoexist->bt_info.lps_val, + btcoexist->bt_info.rpwm_val); +} + +/************************************************************ + * IO related function + ************************************************************/ +static u8 halbtc_read_1byte(void *bt_context, u32 reg_addr) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; + struct rtl_priv *rtlpriv = btcoexist->adapter; + + return rtl_read_byte(rtlpriv, reg_addr); +} + +static u16 halbtc_read_2byte(void *bt_context, u32 reg_addr) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; + struct rtl_priv *rtlpriv = btcoexist->adapter; + + return rtl_read_word(rtlpriv, reg_addr); +} + +static u32 halbtc_read_4byte(void *bt_context, u32 reg_addr) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; + struct rtl_priv *rtlpriv = btcoexist->adapter; + + return rtl_read_dword(rtlpriv, reg_addr); +} + +static void halbtc_write_1byte(void *bt_context, u32 reg_addr, u32 data) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; + struct rtl_priv *rtlpriv = btcoexist->adapter; + + rtl_write_byte(rtlpriv, reg_addr, data); +} + +static void halbtc_bitmask_write_1byte(void *bt_context, u32 reg_addr, + u32 bit_mask, u8 data) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; + struct rtl_priv *rtlpriv = btcoexist->adapter; + u8 original_value, bit_shift = 0; + u8 i; + + if (bit_mask != MASKDWORD) {/*if not "double word" write*/ + original_value = rtl_read_byte(rtlpriv, reg_addr); + for (i = 0; i <= 7; i++) { + if ((bit_mask >> i) & 0x1) + break; + } + bit_shift = i; + data = (original_value & (~bit_mask)) | + ((data << bit_shift) & bit_mask); + } + rtl_write_byte(rtlpriv, reg_addr, data); +} + +static void halbtc_write_2byte(void *bt_context, u32 reg_addr, u16 data) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; + struct rtl_priv *rtlpriv = btcoexist->adapter; + + rtl_write_word(rtlpriv, reg_addr, data); +} + +static void halbtc_write_4byte(void *bt_context, u32 reg_addr, u32 data) +{ + struct btc_coexist *btcoexist = + (struct btc_coexist *)bt_context; + struct rtl_priv *rtlpriv = btcoexist->adapter; + + rtl_write_dword(rtlpriv, reg_addr, data); +} + +static void halbtc_write_local_reg_1byte(void *btc_context, u32 reg_addr, + u8 data) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)btc_context; + struct rtl_priv *rtlpriv = btcoexist->adapter; + + if (btcoexist->chip_interface == BTC_INTF_SDIO) + ; + else if (btcoexist->chip_interface == BTC_INTF_PCI) + rtl_write_byte(rtlpriv, reg_addr, data); + else if (btcoexist->chip_interface == BTC_INTF_USB) + rtl_write_byte(rtlpriv, reg_addr, data); +} + +static void halbtc_set_bbreg(void *bt_context, u32 reg_addr, u32 bit_mask, + u32 data) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; + struct rtl_priv *rtlpriv = btcoexist->adapter; + + rtl_set_bbreg(rtlpriv->mac80211.hw, reg_addr, bit_mask, data); +} + +static u32 halbtc_get_bbreg(void *bt_context, u32 reg_addr, u32 bit_mask) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; + struct rtl_priv *rtlpriv = btcoexist->adapter; + + return rtl_get_bbreg(rtlpriv->mac80211.hw, reg_addr, bit_mask); +} + +static void halbtc_set_rfreg(void *bt_context, u8 rf_path, u32 reg_addr, + u32 bit_mask, u32 data) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; + struct rtl_priv *rtlpriv = btcoexist->adapter; + + rtl_set_rfreg(rtlpriv->mac80211.hw, rf_path, reg_addr, bit_mask, data); +} + +static u32 halbtc_get_rfreg(void *bt_context, u8 rf_path, u32 reg_addr, + u32 bit_mask) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; + struct rtl_priv *rtlpriv = btcoexist->adapter; + + return rtl_get_rfreg(rtlpriv->mac80211.hw, rf_path, reg_addr, bit_mask); +} + +static void halbtc_fill_h2c_cmd(void *bt_context, u8 element_id, + u32 cmd_len, u8 *cmd_buf) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; + struct rtl_priv *rtlpriv = btcoexist->adapter; + + rtlpriv->cfg->ops->fill_h2c_cmd(rtlpriv->mac80211.hw, element_id, + cmd_len, cmd_buf); +} + +static void halbtc_send_wifi_port_id_cmd(void *bt_context) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; + struct rtl_priv *rtlpriv = btcoexist->adapter; + u8 cmd_buf[1] = {0}; /* port id [2:0] = 0 */ + + rtlpriv->cfg->ops->fill_h2c_cmd(rtlpriv->mac80211.hw, 0x71, 1, + cmd_buf); +} + +static void halbtc_set_default_port_id_cmd(void *bt_context) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct ieee80211_hw *hw = rtlpriv->mac80211.hw; + + if (!rtlpriv->cfg->ops->set_default_port_id_cmd) + return; + + rtlpriv->cfg->ops->set_default_port_id_cmd(hw); +} + +static +void halbtc_set_bt_reg(void *btc_context, u8 reg_type, u32 offset, u32 set_val) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)btc_context; + u8 cmd_buffer1[4] = {0}; + u8 cmd_buffer2[4] = {0}; + + /* cmd_buffer[0] and [1] is filled by halbtc_send_bt_mp_operation() */ + *((__le16 *)&cmd_buffer1[2]) = cpu_to_le16((u16)set_val); + if (!halbtc_send_bt_mp_operation(btcoexist, BT_OP_WRITE_REG_VALUE, + cmd_buffer1, 4, 200)) + return; + + /* cmd_buffer[0] and [1] is filled by halbtc_send_bt_mp_operation() */ + cmd_buffer2[2] = reg_type; + *((u8 *)&cmd_buffer2[3]) = (u8)offset; + halbtc_send_bt_mp_operation(btcoexist, BT_OP_WRITE_REG_ADDR, + cmd_buffer2, 4, 200); +} + +static void halbtc_display_dbg_msg(void *bt_context, u8 disp_type, + struct seq_file *m) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; + + switch (disp_type) { + case BTC_DBG_DISP_COEX_STATISTICS: + halbtc_display_coex_statistics(btcoexist, m); + break; + case BTC_DBG_DISP_BT_LINK_INFO: + halbtc_display_bt_link_info(btcoexist, m); + break; + case BTC_DBG_DISP_WIFI_STATUS: + halbtc_display_wifi_status(btcoexist, m); + break; + default: + break; + } +} + +static u32 halbtc_get_bt_reg(void *btc_context, u8 reg_type, u32 offset) +{ + return 0; +} + +static +u32 halbtc_get_phydm_version(void *btc_context) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)btc_context; + struct rtl_priv *rtlpriv = btcoexist->adapter; + + if (rtlpriv->phydm.ops) + return rtlpriv->phydm.ops->phydm_get_version(rtlpriv); + + return 0; +} + +static +void halbtc_phydm_modify_ra_pcr_threshold(void *btc_context, + u8 ra_offset_direction, + u8 ra_threshold_offset) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)btc_context; + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct rtl_phydm_ops *phydm_ops = rtlpriv->phydm.ops; + + if (phydm_ops) + phydm_ops->phydm_modify_ra_pcr_threshold(rtlpriv, + ra_offset_direction, + ra_threshold_offset); +} + +static +u32 halbtc_phydm_query_phy_counter(void *btc_context, const char *info_type) +{ + /* info_type may be strings below: + * PHYDM_INFO_FA_OFDM, PHYDM_INFO_FA_CCK, PHYDM_INFO_CCA_OFDM, + * PHYDM_INFO_CCA_CCK + * IQK_TOTAL, IQK_OK, IQK_FAIL + */ + + struct btc_coexist *btcoexist = (struct btc_coexist *)btc_context; + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct rtl_phydm_ops *phydm_ops = rtlpriv->phydm.ops; + + if (phydm_ops) + return phydm_ops->phydm_query_counter(rtlpriv, info_type); + + return 0; +} + +static u8 halbtc_get_ant_det_val_from_bt(void *btc_context) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)btc_context; + u8 cmd_buffer[4] = {0}; + + /* cmd_buffer[0] and [1] is filled by halbtc_send_bt_mp_operation() */ + halbtc_send_bt_mp_operation(btcoexist, BT_OP_GET_BT_ANT_DET_VAL, + cmd_buffer, 4, 200); + + /* need wait completion to return correct value */ + + return btcoexist->bt_info.bt_ant_det_val; +} + +static u8 halbtc_get_ble_scan_type_from_bt(void *btc_context) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)btc_context; + u8 cmd_buffer[4] = {0}; + + /* cmd_buffer[0] and [1] is filled by halbtc_send_bt_mp_operation() */ + halbtc_send_bt_mp_operation(btcoexist, BT_OP_GET_BT_BLE_SCAN_TYPE, + cmd_buffer, 4, 200); + + /* need wait completion to return correct value */ + + return btcoexist->bt_info.bt_ble_scan_type; +} + +static u32 halbtc_get_ble_scan_para_from_bt(void *btc_context, u8 scan_type) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)btc_context; + u8 cmd_buffer[4] = {0}; + + /* cmd_buffer[0] and [1] is filled by halbtc_send_bt_mp_operation() */ + halbtc_send_bt_mp_operation(btcoexist, BT_OP_GET_BT_BLE_SCAN_PARA, + cmd_buffer, 4, 200); + + /* need wait completion to return correct value */ + + return btcoexist->bt_info.bt_ble_scan_para; +} + +static bool halbtc_get_bt_afh_map_from_bt(void *btc_context, u8 map_type, + u8 *afh_map) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)btc_context; + u8 cmd_buffer[2] = {0}; + bool ret; + u32 *afh_map_l = (u32 *)afh_map; + u32 *afh_map_m = (u32 *)(afh_map + 4); + u16 *afh_map_h = (u16 *)(afh_map + 8); + + /* cmd_buffer[0] and [1] is filled by halbtc_send_bt_mp_operation() */ + ret = halbtc_send_bt_mp_operation(btcoexist, BT_OP_GET_AFH_MAP_L, + cmd_buffer, 2, 200); + if (!ret) + goto exit; + + *afh_map_l = btcoexist->bt_info.afh_map_l; + + /* cmd_buffer[0] and [1] is filled by halbtc_send_bt_mp_operation() */ + ret = halbtc_send_bt_mp_operation(btcoexist, BT_OP_GET_AFH_MAP_M, + cmd_buffer, 2, 200); + if (!ret) + goto exit; + + *afh_map_m = btcoexist->bt_info.afh_map_m; + + /* cmd_buffer[0] and [1] is filled by halbtc_send_bt_mp_operation() */ + ret = halbtc_send_bt_mp_operation(btcoexist, BT_OP_GET_AFH_MAP_H, + cmd_buffer, 2, 200); + if (!ret) + goto exit; + + *afh_map_h = btcoexist->bt_info.afh_map_h; + +exit: + return ret; +} + +/***************************************************************** + * Extern functions called by other module + *****************************************************************/ +bool exhalbtc_initlize_variables(struct rtl_priv *rtlpriv) +{ + struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv); + + if (!btcoexist) + return false; + + halbtc_dbg_init(); + + btcoexist->btc_read_1byte = halbtc_read_1byte; + btcoexist->btc_write_1byte = halbtc_write_1byte; + btcoexist->btc_write_1byte_bitmask = halbtc_bitmask_write_1byte; + btcoexist->btc_read_2byte = halbtc_read_2byte; + btcoexist->btc_write_2byte = halbtc_write_2byte; + btcoexist->btc_read_4byte = halbtc_read_4byte; + btcoexist->btc_write_4byte = halbtc_write_4byte; + btcoexist->btc_write_local_reg_1byte = halbtc_write_local_reg_1byte; + + btcoexist->btc_set_bb_reg = halbtc_set_bbreg; + btcoexist->btc_get_bb_reg = halbtc_get_bbreg; + + btcoexist->btc_set_rf_reg = halbtc_set_rfreg; + btcoexist->btc_get_rf_reg = halbtc_get_rfreg; + + btcoexist->btc_fill_h2c = halbtc_fill_h2c_cmd; + btcoexist->btc_disp_dbg_msg = halbtc_display_dbg_msg; + + btcoexist->btc_get = halbtc_get; + btcoexist->btc_set = halbtc_set; + btcoexist->btc_set_bt_reg = halbtc_set_bt_reg; + btcoexist->btc_get_bt_reg = halbtc_get_bt_reg; + + btcoexist->bt_info.bt_ctrl_buf_size = false; + btcoexist->bt_info.agg_buf_size = 5; + + btcoexist->bt_info.increase_scan_dev_num = false; + + btcoexist->btc_get_bt_coex_supported_feature = + halbtc_get_bt_coex_supported_feature; + btcoexist->btc_get_bt_coex_supported_version = + halbtc_get_bt_coex_supported_version; + btcoexist->btc_get_bt_phydm_version = halbtc_get_phydm_version; + btcoexist->btc_phydm_modify_ra_pcr_threshold = + halbtc_phydm_modify_ra_pcr_threshold; + btcoexist->btc_phydm_query_phy_counter = halbtc_phydm_query_phy_counter; + btcoexist->btc_get_ant_det_val_from_bt = halbtc_get_ant_det_val_from_bt; + btcoexist->btc_get_ble_scan_type_from_bt = + halbtc_get_ble_scan_type_from_bt; + btcoexist->btc_get_ble_scan_para_from_bt = + halbtc_get_ble_scan_para_from_bt; + btcoexist->btc_get_bt_afh_map_from_bt = + halbtc_get_bt_afh_map_from_bt; + + init_completion(&btcoexist->bt_mp_comp); + + return true; +} + +bool exhalbtc_initlize_variables_wifi_only(struct rtl_priv *rtlpriv) +{ + struct wifi_only_cfg *wifionly_cfg = rtl_btc_wifi_only(rtlpriv); + struct wifi_only_haldata *wifionly_haldata; + + if (!wifionly_cfg) + return false; + + wifionly_cfg->adapter = rtlpriv; + + switch (rtlpriv->rtlhal.interface) { + case INTF_PCI: + wifionly_cfg->chip_interface = BTC_INTF_PCI; + break; + case INTF_USB: + wifionly_cfg->chip_interface = BTC_INTF_USB; + break; + default: + wifionly_cfg->chip_interface = BTC_INTF_UNKNOWN; + break; + } + + wifionly_haldata = &wifionly_cfg->haldata_info; + + wifionly_haldata->customer_id = CUSTOMER_NORMAL; + wifionly_haldata->efuse_pg_antnum = rtl_get_hwpg_ant_num(rtlpriv); + wifionly_haldata->efuse_pg_antpath = + rtl_get_hwpg_single_ant_path(rtlpriv); + wifionly_haldata->rfe_type = rtl_get_hwpg_rfe_type(rtlpriv); + wifionly_haldata->ant_div_cfg = 0; + + return true; +} + +bool exhalbtc_bind_bt_coex_withadapter(void *adapter) +{ + struct rtl_priv *rtlpriv = adapter; + struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv); + u8 ant_num = 2, chip_type, single_ant_path = 0; + + if (!btcoexist) + return false; + + if (btcoexist->binded) + return false; + + switch (rtlpriv->rtlhal.interface) { + case INTF_PCI: + btcoexist->chip_interface = BTC_INTF_PCI; + break; + case INTF_USB: + btcoexist->chip_interface = BTC_INTF_USB; + break; + default: + btcoexist->chip_interface = BTC_INTF_UNKNOWN; + break; + } + + btcoexist->binded = true; + btcoexist->statistics.cnt_bind++; + + btcoexist->adapter = adapter; + + btcoexist->stack_info.profile_notified = false; + + btcoexist->bt_info.bt_ctrl_agg_buf_size = false; + btcoexist->bt_info.agg_buf_size = 5; + + btcoexist->bt_info.increase_scan_dev_num = false; + btcoexist->bt_info.miracast_plus_bt = false; + + chip_type = rtl_get_hwpg_bt_type(rtlpriv); + exhalbtc_set_chip_type(btcoexist, chip_type); + ant_num = rtl_get_hwpg_ant_num(rtlpriv); + exhalbtc_set_ant_num(rtlpriv, BT_COEX_ANT_TYPE_PG, ant_num); + + /* set default antenna position to main port */ + btcoexist->board_info.btdm_ant_pos = BTC_ANTENNA_AT_MAIN_PORT; + + single_ant_path = rtl_get_hwpg_single_ant_path(rtlpriv); + exhalbtc_set_single_ant_path(btcoexist, single_ant_path); + + if (rtl_get_hwpg_package_type(rtlpriv) == 0) + btcoexist->board_info.tfbga_package = false; + else if (rtl_get_hwpg_package_type(rtlpriv) == 1) + btcoexist->board_info.tfbga_package = false; + else + btcoexist->board_info.tfbga_package = true; + + if (btcoexist->board_info.tfbga_package) + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Package Type = TFBGA\n"); + else + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Package Type = Non-TFBGA\n"); + + btcoexist->board_info.rfe_type = rtl_get_hwpg_rfe_type(rtlpriv); + btcoexist->board_info.ant_div_cfg = 0; + + return true; +} + +void exhalbtc_power_on_setting(struct btc_coexist *btcoexist) +{ + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + + btcoexist->statistics.cnt_power_on++; + + if (IS_HARDWARE_TYPE_8822B(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8822b1ant_power_on_setting(btcoexist); + else if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8822b2ant_power_on_setting(btcoexist); + } +} + +void exhalbtc_pre_load_firmware(struct btc_coexist *btcoexist) +{ + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + + btcoexist->statistics.cnt_pre_load_firmware++; + + if (IS_HARDWARE_TYPE_8822B(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8822b1ant_pre_load_firmware(btcoexist); + else if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8822b2ant_pre_load_firmware(btcoexist); + } +} + +void exhalbtc_init_hw_config(struct btc_coexist *btcoexist, bool wifi_only) +{ + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + + btcoexist->statistics.cnt_init_hw_config++; + + if (IS_HARDWARE_TYPE_8822B(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8822b1ant_init_hw_config(btcoexist, wifi_only); + else if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8822b2ant_init_hw_config(btcoexist, wifi_only); + + halbtc_set_default_port_id_cmd(btcoexist); + halbtc_send_wifi_port_id_cmd(btcoexist); + } +} + +void exhalbtc_init_hw_config_wifi_only(struct wifi_only_cfg *wifionly_cfg) +{ + if (IS_HARDWARE_TYPE_8822B(wifionly_cfg->adapter)) + ex_hal8822b_wifi_only_hw_config(wifionly_cfg); +} + +void exhalbtc_init_coex_dm(struct btc_coexist *btcoexist) +{ + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + + btcoexist->statistics.cnt_init_coex_dm++; + + if (IS_HARDWARE_TYPE_8822B(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8822b1ant_init_coex_dm(btcoexist); + else if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8822b2ant_init_coex_dm(btcoexist); + } + + btcoexist->initilized = true; +} + +void exhalbtc_ips_notify(struct btc_coexist *btcoexist, u8 type) +{ + u8 ips_type; + + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + btcoexist->statistics.cnt_ips_notify++; + if (btcoexist->manual_control) + return; + + if (type == ERFOFF) + ips_type = BTC_IPS_ENTER; + else + ips_type = BTC_IPS_LEAVE; + + halbtc_leave_low_power(btcoexist); + + if (IS_HARDWARE_TYPE_8822B(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8822b1ant_ips_notify(btcoexist, ips_type); + else if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8822b2ant_ips_notify(btcoexist, ips_type); + } + + halbtc_normal_low_power(btcoexist); +} + +void exhalbtc_lps_notify(struct btc_coexist *btcoexist, u8 type) +{ + u8 lps_type; + + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + btcoexist->statistics.cnt_lps_notify++; + if (btcoexist->manual_control) + return; + + if (type == EACTIVE) + lps_type = BTC_LPS_DISABLE; + else + lps_type = BTC_LPS_ENABLE; + + if (IS_HARDWARE_TYPE_8822B(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8822b1ant_lps_notify(btcoexist, lps_type); + else if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8822b2ant_lps_notify(btcoexist, lps_type); + } +} + +void exhalbtc_scan_notify(struct btc_coexist *btcoexist, u8 type) +{ + u8 scan_type; + + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + btcoexist->statistics.cnt_scan_notify++; + if (btcoexist->manual_control) + return; + + if (type) + scan_type = BTC_SCAN_START; + else + scan_type = BTC_SCAN_FINISH; + + halbtc_leave_low_power(btcoexist); + + if (IS_HARDWARE_TYPE_8822B(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8822b1ant_scan_notify(btcoexist, scan_type); + else if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8822b2ant_scan_notify(btcoexist, scan_type); + } + + halbtc_normal_low_power(btcoexist); +} + +void exhalbtc_scan_notify_wifi_only(struct wifi_only_cfg *wifionly_cfg, + u8 is_5g) +{ + if (IS_HARDWARE_TYPE_8822B(wifionly_cfg->adapter)) + ex_hal8822b_wifi_only_scannotify(wifionly_cfg, is_5g); +} + +void exhalbtc_connect_notify(struct btc_coexist *btcoexist, u8 action) +{ + u8 asso_type; + + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + btcoexist->statistics.cnt_connect_notify++; + if (btcoexist->manual_control) + return; + + if (action) + asso_type = BTC_ASSOCIATE_START; + else + asso_type = BTC_ASSOCIATE_FINISH; + + halbtc_leave_low_power(btcoexist); + + if (IS_HARDWARE_TYPE_8822B(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8822b1ant_connect_notify(btcoexist, asso_type); + else if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8822b2ant_connect_notify(btcoexist, asso_type); + } + + halbtc_normal_low_power(btcoexist); +} + +void exhalbtc_mediastatus_notify(struct btc_coexist *btcoexist, + enum rt_media_status media_status) +{ + u8 status; + + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + btcoexist->statistics.cnt_media_status_notify++; + if (btcoexist->manual_control) + return; + + if (media_status == RT_MEDIA_CONNECT) + status = BTC_MEDIA_CONNECT; + else + status = BTC_MEDIA_DISCONNECT; + + halbtc_leave_low_power(btcoexist); + + if (IS_HARDWARE_TYPE_8822B(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8822b1ant_media_status_notify(btcoexist, status); + else if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8822b2ant_media_status_notify(btcoexist, status); + } + + halbtc_normal_low_power(btcoexist); +} + +void exhalbtc_special_packet_notify(struct btc_coexist *btcoexist, u8 pkt_type) +{ + u8 packet_type; + + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + btcoexist->statistics.cnt_special_packet_notify++; + if (btcoexist->manual_control) + return; + + if (pkt_type == PACKET_DHCP) { + packet_type = BTC_PACKET_DHCP; + } else if (pkt_type == PACKET_EAPOL) { + packet_type = BTC_PACKET_EAPOL; + } else if (pkt_type == PACKET_ARP) { + packet_type = BTC_PACKET_ARP; + } else { + packet_type = BTC_PACKET_UNKNOWN; + return; + } + + halbtc_leave_low_power(btcoexist); + + if (IS_HARDWARE_TYPE_8822B(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8822b1ant_specific_packet_notify(btcoexist, + packet_type); + else if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8822b2ant_specific_packet_notify(btcoexist, + packet_type); + } + + halbtc_normal_low_power(btcoexist); +} + +void exhalbtc_bt_info_notify(struct btc_coexist *btcoexist, + u8 *tmp_buf, u8 length) +{ + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + btcoexist->statistics.cnt_bt_info_notify++; + + halbtc_leave_low_power(btcoexist); + + if (IS_HARDWARE_TYPE_8822B(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8822b1ant_bt_info_notify(btcoexist, tmp_buf, + length); + else if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8822b2ant_bt_info_notify(btcoexist, tmp_buf, + length); + } + + halbtc_normal_low_power(btcoexist); +} + +void exhalbtc_rf_status_notify(struct btc_coexist *btcoexist, u8 type) +{ + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + + if (IS_HARDWARE_TYPE_8822B(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8822b1ant_rf_status_notify(btcoexist, type); + else if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8822b2ant_rf_status_notify(btcoexist, type); + } +} + +void exhalbtc_stack_operation_notify(struct btc_coexist *btcoexist, u8 type) +{ + u8 stack_op_type; + + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + btcoexist->statistics.cnt_stack_operation_notify++; + if (btcoexist->manual_control) + return; + + if ((type == HCI_BT_OP_INQUIRY_START) || + (type == HCI_BT_OP_PAGING_START) || + (type == HCI_BT_OP_PAIRING_START)) { + stack_op_type = BTC_STACK_OP_INQ_PAGE_PAIR_START; + } else if ((type == HCI_BT_OP_INQUIRY_FINISH) || + (type == HCI_BT_OP_PAGING_SUCCESS) || + (type == HCI_BT_OP_PAGING_UNSUCCESS) || + (type == HCI_BT_OP_PAIRING_FINISH)) { + stack_op_type = BTC_STACK_OP_INQ_PAGE_PAIR_FINISH; + } else { + stack_op_type = BTC_STACK_OP_NONE; + } +} + +void exhalbtc_halt_notify(struct btc_coexist *btcoexist) +{ + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + + if (IS_HARDWARE_TYPE_8822B(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8822b1ant_halt_notify(btcoexist); + else if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8822b2ant_halt_notify(btcoexist); + } + + btcoexist->binded = false; +} + +void exhalbtc_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state) +{ + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + + /* currently only 1ant we have to do the notification, + * once pnp is notified to sleep state, we have to leave LPS that + * we can sleep normally. + */ + + if (IS_HARDWARE_TYPE_8822B(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8822b1ant_pnp_notify(btcoexist, pnp_state); + else if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8822b2ant_pnp_notify(btcoexist, pnp_state); + } +} + +void exhalbtc_coex_dm_switch(struct btc_coexist *btcoexist) +{ + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + btcoexist->statistics.cnt_coex_dm_switch++; + + halbtc_leave_low_power(btcoexist); + + halbtc_normal_low_power(btcoexist); +} + +void exhalbtc_periodical(struct btc_coexist *btcoexist) +{ + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + btcoexist->statistics.cnt_periodical++; + + halbtc_leave_low_power(btcoexist); + + if (IS_HARDWARE_TYPE_8822B(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8822b1ant_periodical(btcoexist); + else if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8822b2ant_periodical(btcoexist); + } + + halbtc_normal_low_power(btcoexist); +} + +void exhalbtc_dbg_control(struct btc_coexist *btcoexist, + u8 code, u8 len, u8 *data) +{ + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + btcoexist->statistics.cnt_dbg_ctrl++; + + halbtc_leave_low_power(btcoexist); + + halbtc_normal_low_power(btcoexist); +} + +void exhalbtc_antenna_detection(struct btc_coexist *btcoexist, u32 cent_freq, + u32 offset, u32 span, u32 seconds) +{ + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; +} + +void exhalbtc_stack_update_profile_info(void) +{ +} + +void exhalbtc_update_min_bt_rssi(struct btc_coexist *btcoexist, s8 bt_rssi) +{ + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + + btcoexist->stack_info.min_bt_rssi = bt_rssi; +} + +void exhalbtc_set_hci_version(struct btc_coexist *btcoexist, u16 hci_version) +{ + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + + btcoexist->stack_info.hci_version = hci_version; +} + +void exhalbtc_set_bt_patch_version(struct btc_coexist *btcoexist, + u16 bt_hci_version, u16 bt_patch_version) +{ + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + + btcoexist->bt_info.bt_real_fw_ver = bt_patch_version; + btcoexist->bt_info.bt_hci_ver = bt_hci_version; +} + +void exhalbtc_set_chip_type(struct btc_coexist *btcoexist, u8 chip_type) +{ + switch (chip_type) { + default: + case BT_2WIRE: + case BT_ISSC_3WIRE: + case BT_ACCEL: + case BT_RTL8756: + btcoexist->board_info.bt_chip_type = BTC_CHIP_UNDEF; + break; + case BT_CSR_BC4: + btcoexist->board_info.bt_chip_type = BTC_CHIP_CSR_BC4; + break; + case BT_CSR_BC8: + btcoexist->board_info.bt_chip_type = BTC_CHIP_CSR_BC8; + break; + case BT_RTL8723A: + btcoexist->board_info.bt_chip_type = BTC_CHIP_RTL8723A; + break; + case BT_RTL8821A: + btcoexist->board_info.bt_chip_type = BTC_CHIP_RTL8821; + break; + case BT_RTL8723B: + btcoexist->board_info.bt_chip_type = BTC_CHIP_RTL8723B; + break; + } +} + +void exhalbtc_set_ant_num(struct rtl_priv *rtlpriv, u8 type, u8 ant_num) +{ + struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv); + + if (!btcoexist) + return; + + if (type == BT_COEX_ANT_TYPE_PG) { + btcoexist->board_info.pg_ant_num = ant_num; + btcoexist->board_info.btdm_ant_num = ant_num; + } else if (type == BT_COEX_ANT_TYPE_ANTDIV) { + btcoexist->board_info.btdm_ant_num = ant_num; + } else if (type == BT_COEX_ANT_TYPE_DETECTED) { + btcoexist->board_info.btdm_ant_num = ant_num; + if (rtlpriv->cfg->mod_params->ant_sel == 1) + btcoexist->board_info.btdm_ant_pos = + BTC_ANTENNA_AT_AUX_PORT; + else + btcoexist->board_info.btdm_ant_pos = + BTC_ANTENNA_AT_MAIN_PORT; + } +} + +/* Currently used by 8723b only, S0 or S1 */ +void exhalbtc_set_single_ant_path(struct btc_coexist *btcoexist, + u8 single_ant_path) +{ + btcoexist->board_info.single_ant_path = single_ant_path; +} + +void exhalbtc_display_bt_coex_info(struct btc_coexist *btcoexist, + struct seq_file *m) +{ + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + + halbtc_leave_low_power(btcoexist); + + if (IS_HARDWARE_TYPE_8822B(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8822b1ant_display_coex_info(btcoexist, m); + else if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8822b2ant_display_coex_info(btcoexist, m); + } + + halbtc_normal_low_power(btcoexist); +} + +void exhalbtc_switch_band_notify(struct btc_coexist *btcoexist, u8 type) +{ + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + + if (btcoexist->manual_control) + return; + + halbtc_leave_low_power(btcoexist); + + if (IS_HARDWARE_TYPE_8822B(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8822b1ant_switchband_notify(btcoexist, type); + else if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8822b2ant_switchband_notify(btcoexist, type); + } + + halbtc_normal_low_power(btcoexist); +} + +void exhalbtc_switch_band_notify_wifi_only(struct wifi_only_cfg *wifionly_cfg, + u8 is_5g) +{ + if (IS_HARDWARE_TYPE_8822B(wifionly_cfg->adapter)) + ex_hal8822b_wifi_only_switchbandnotify(wifionly_cfg, is_5g); +} diff --git a/drivers/staging/rtlwifi/btcoexist/halbtcoutsrc.h b/drivers/staging/rtlwifi/btcoexist/halbtcoutsrc.h new file mode 100644 index 000000000000..8913983b8ad8 --- /dev/null +++ b/drivers/staging/rtlwifi/btcoexist/halbtcoutsrc.h @@ -0,0 +1,802 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef __HALBTC_OUT_SRC_H__ +#define __HALBTC_OUT_SRC_H__ + +#include "../wifi.h" + +#define BTC_COEX_OFFLOAD 0 + +#define NORMAL_EXEC false +#define FORCE_EXEC true + +#define BTC_RF_OFF 0x0 +#define BTC_RF_ON 0x1 + +#define BTC_RF_A RF90_PATH_A +#define BTC_RF_B RF90_PATH_B +#define BTC_RF_C RF90_PATH_C +#define BTC_RF_D RF90_PATH_D + +#define BTC_SMSP SINGLEMAC_SINGLEPHY +#define BTC_DMDP DUALMAC_DUALPHY +#define BTC_DMSP DUALMAC_SINGLEPHY +#define BTC_MP_UNKNOWN 0xff + +#define IN +#define OUT + +#define BT_TMP_BUF_SIZE 100 + +#define BT_COEX_ANT_TYPE_PG 0 +#define BT_COEX_ANT_TYPE_ANTDIV 1 +#define BT_COEX_ANT_TYPE_DETECTED 2 + +#define BTC_MIMO_PS_STATIC 0 +#define BTC_MIMO_PS_DYNAMIC 1 + +#define BTC_RATE_DISABLE 0 +#define BTC_RATE_ENABLE 1 + +/* single Antenna definition */ +#define BTC_ANT_PATH_WIFI 0 +#define BTC_ANT_PATH_BT 1 +#define BTC_ANT_PATH_PTA 2 +#define BTC_ANT_PATH_WIFI5G 3 +#define BTC_ANT_PATH_AUTO 4 +/* dual Antenna definition */ +#define BTC_ANT_WIFI_AT_MAIN 0 +#define BTC_ANT_WIFI_AT_AUX 1 +#define BTC_ANT_WIFI_AT_DIVERSITY 2 +/* coupler Antenna definition */ +#define BTC_ANT_WIFI_AT_CPL_MAIN 0 +#define BTC_ANT_WIFI_AT_CPL_AUX 1 + +enum btc_bt_reg_type { + BTC_BT_REG_RF = 0, + BTC_BT_REG_MODEM = 1, + BTC_BT_REG_BLUEWIZE = 2, + BTC_BT_REG_VENDOR = 3, + BTC_BT_REG_LE = 4, + BTC_BT_REG_MAX +}; + +enum btc_chip_interface { + BTC_INTF_UNKNOWN = 0, + BTC_INTF_PCI = 1, + BTC_INTF_USB = 2, + BTC_INTF_SDIO = 3, + BTC_INTF_GSPI = 4, + BTC_INTF_MAX +}; + +enum btc_chip_type { + BTC_CHIP_UNDEF = 0, + BTC_CHIP_CSR_BC4 = 1, + BTC_CHIP_CSR_BC8 = 2, + BTC_CHIP_RTL8723A = 3, + BTC_CHIP_RTL8821 = 4, + BTC_CHIP_RTL8723B = 5, + BTC_CHIP_MAX +}; + +enum btc_msg_type { + BTC_MSG_INTERFACE = 0x0, + BTC_MSG_ALGORITHM = 0x1, + BTC_MSG_MAX +}; + +/* following is for BTC_MSG_INTERFACE */ +#define INTF_INIT BIT0 +#define INTF_NOTIFY BIT2 + +/* following is for BTC_ALGORITHM */ +#define ALGO_BT_RSSI_STATE BIT0 +#define ALGO_WIFI_RSSI_STATE BIT1 +#define ALGO_BT_MONITOR BIT2 +#define ALGO_TRACE BIT3 +#define ALGO_TRACE_FW BIT4 +#define ALGO_TRACE_FW_DETAIL BIT5 +#define ALGO_TRACE_FW_EXEC BIT6 +#define ALGO_TRACE_SW BIT7 +#define ALGO_TRACE_SW_DETAIL BIT8 +#define ALGO_TRACE_SW_EXEC BIT9 + +/* following is for wifi link status */ +#define WIFI_STA_CONNECTED BIT0 +#define WIFI_AP_CONNECTED BIT1 +#define WIFI_HS_CONNECTED BIT2 +#define WIFI_P2P_GO_CONNECTED BIT3 +#define WIFI_P2P_GC_CONNECTED BIT4 + +#define BTC_RSSI_HIGH(_rssi_) \ + ((_rssi_ == BTC_RSSI_STATE_HIGH || \ + _rssi_ == BTC_RSSI_STATE_STAY_HIGH) ? true : false) +#define BTC_RSSI_MEDIUM(_rssi_) \ + ((_rssi_ == BTC_RSSI_STATE_MEDIUM || \ + _rssi_ == BTC_RSSI_STATE_STAY_MEDIUM) ? true : false) +#define BTC_RSSI_LOW(_rssi_) \ + ((_rssi_ == BTC_RSSI_STATE_LOW || \ + _rssi_ == BTC_RSSI_STATE_STAY_LOW) ? true : false) + +enum btc_power_save_type { + BTC_PS_WIFI_NATIVE = 0, + BTC_PS_LPS_ON = 1, + BTC_PS_LPS_OFF = 2, + BTC_PS_LPS_MAX +}; + +struct btc_board_info { + /* The following is some board information */ + u8 bt_chip_type; + u8 pg_ant_num; /* pg ant number */ + u8 btdm_ant_num; /* ant number for btdm */ + u8 btdm_ant_num_by_ant_det; + u8 btdm_ant_pos; + u8 single_ant_path; /* current used for 8723b only, 1=>s0, 0=>s1 */ + bool tfbga_package; + bool btdm_ant_det_finish; + + u8 rfe_type; + u8 ant_div_cfg; +}; + +enum btc_dbg_opcode { + BTC_DBG_SET_COEX_NORMAL = 0x0, + BTC_DBG_SET_COEX_WIFI_ONLY = 0x1, + BTC_DBG_SET_COEX_BT_ONLY = 0x2, + BTC_DBG_MAX +}; + +enum btc_rssi_state { + BTC_RSSI_STATE_HIGH = 0x0, + BTC_RSSI_STATE_MEDIUM = 0x1, + BTC_RSSI_STATE_LOW = 0x2, + BTC_RSSI_STATE_STAY_HIGH = 0x3, + BTC_RSSI_STATE_STAY_MEDIUM = 0x4, + BTC_RSSI_STATE_STAY_LOW = 0x5, + BTC_RSSI_MAX +}; + +enum btc_wifi_role { + BTC_ROLE_STATION = 0x0, + BTC_ROLE_AP = 0x1, + BTC_ROLE_IBSS = 0x2, + BTC_ROLE_HS_MODE = 0x3, + BTC_ROLE_MAX +}; + +enum btc_wireless_freq { + BTC_FREQ_2_4G = 0x0, + BTC_FREQ_5G = 0x1, + BTC_FREQ_MAX +}; + +enum btc_wifi_bw_mode { + BTC_WIFI_BW_LEGACY = 0x0, + BTC_WIFI_BW_HT20 = 0x1, + BTC_WIFI_BW_HT40 = 0x2, + BTC_WIFI_BW_HT80 = 0x3, + BTC_WIFI_BW_MAX +}; + +enum btc_wifi_traffic_dir { + BTC_WIFI_TRAFFIC_TX = 0x0, + BTC_WIFI_TRAFFIC_RX = 0x1, + BTC_WIFI_TRAFFIC_MAX +}; + +enum btc_wifi_pnp { + BTC_WIFI_PNP_WAKE_UP = 0x0, + BTC_WIFI_PNP_SLEEP = 0x1, + BTC_WIFI_PNP_SLEEP_KEEP_ANT = 0x2, + BTC_WIFI_PNP_MAX +}; + +enum btc_iot_peer { + BTC_IOT_PEER_UNKNOWN = 0, + BTC_IOT_PEER_REALTEK = 1, + BTC_IOT_PEER_REALTEK_92SE = 2, + BTC_IOT_PEER_BROADCOM = 3, + BTC_IOT_PEER_RALINK = 4, + BTC_IOT_PEER_ATHEROS = 5, + BTC_IOT_PEER_CISCO = 6, + BTC_IOT_PEER_MERU = 7, + BTC_IOT_PEER_MARVELL = 8, + BTC_IOT_PEER_REALTEK_SOFTAP = 9, + BTC_IOT_PEER_SELF_SOFTAP = 10, /* Self is SoftAP */ + BTC_IOT_PEER_AIRGO = 11, + BTC_IOT_PEER_REALTEK_JAGUAR_BCUTAP = 12, + BTC_IOT_PEER_REALTEK_JAGUAR_CCUTAP = 13, + BTC_IOT_PEER_MAX, +}; + +/* for 8723b-d cut large current issue */ +enum bt_wifi_coex_state { + BTC_WIFI_STAT_INIT, + BTC_WIFI_STAT_IQK, + BTC_WIFI_STAT_NORMAL_OFF, + BTC_WIFI_STAT_MP_OFF, + BTC_WIFI_STAT_NORMAL, + BTC_WIFI_STAT_ANT_DIV, + BTC_WIFI_STAT_MAX +}; + +enum bt_ant_type { + BTC_ANT_TYPE_0, + BTC_ANT_TYPE_1, + BTC_ANT_TYPE_2, + BTC_ANT_TYPE_3, + BTC_ANT_TYPE_4, + BTC_ANT_TYPE_MAX +}; + +enum btc_get_type { + /* type bool */ + BTC_GET_BL_HS_OPERATION, + BTC_GET_BL_HS_CONNECTING, + BTC_GET_BL_WIFI_CONNECTED, + BTC_GET_BL_WIFI_BUSY, + BTC_GET_BL_WIFI_SCAN, + BTC_GET_BL_WIFI_LINK, + BTC_GET_BL_WIFI_DHCP, + BTC_GET_BL_WIFI_SOFTAP_IDLE, + BTC_GET_BL_WIFI_SOFTAP_LINKING, + BTC_GET_BL_WIFI_IN_EARLY_SUSPEND, + BTC_GET_BL_WIFI_ROAM, + BTC_GET_BL_WIFI_4_WAY_PROGRESS, + BTC_GET_BL_WIFI_UNDER_5G, + BTC_GET_BL_WIFI_AP_MODE_ENABLE, + BTC_GET_BL_WIFI_ENABLE_ENCRYPTION, + BTC_GET_BL_WIFI_UNDER_B_MODE, + BTC_GET_BL_EXT_SWITCH, + BTC_GET_BL_WIFI_IS_IN_MP_MODE, + BTC_GET_BL_IS_ASUS_8723B, + BTC_GET_BL_FW_READY, + BTC_GET_BL_RF4CE_CONNECTED, + + /* type s4Byte */ + BTC_GET_S4_WIFI_RSSI, + BTC_GET_S4_HS_RSSI, + + /* type u32 */ + BTC_GET_U4_WIFI_BW, + BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, + BTC_GET_U4_WIFI_FW_VER, + BTC_GET_U4_WIFI_LINK_STATUS, + BTC_GET_U4_BT_PATCH_VER, + BTC_GET_U4_VENDOR, + BTC_GET_U4_SUPPORTED_VERSION, + BTC_GET_U4_SUPPORTED_FEATURE, + BTC_GET_U4_WIFI_IQK_TOTAL, + BTC_GET_U4_WIFI_IQK_OK, + BTC_GET_U4_WIFI_IQK_FAIL, + + /* type u1Byte */ + BTC_GET_U1_WIFI_DOT11_CHNL, + BTC_GET_U1_WIFI_CENTRAL_CHNL, + BTC_GET_U1_WIFI_HS_CHNL, + BTC_GET_U1_MAC_PHY_MODE, + BTC_GET_U1_AP_NUM, + BTC_GET_U1_ANT_TYPE, + BTC_GET_U1_IOT_PEER, + + /* for 1Ant */ + BTC_GET_U1_LPS_MODE, + BTC_GET_BL_BT_SCO_BUSY, + + /* for test mode */ + BTC_GET_DRIVER_TEST_CFG, + BTC_GET_MAX +}; + +enum btc_vendor { + BTC_VENDOR_LENOVO, + BTC_VENDOR_ASUS, + BTC_VENDOR_OTHER +}; + +enum btc_set_type { + /* type bool */ + BTC_SET_BL_BT_DISABLE, + BTC_SET_BL_BT_ENABLE_DISABLE_CHANGE, + BTC_SET_BL_BT_TRAFFIC_BUSY, + BTC_SET_BL_BT_LIMITED_DIG, + BTC_SET_BL_FORCE_TO_ROAM, + BTC_SET_BL_TO_REJ_AP_AGG_PKT, + BTC_SET_BL_BT_CTRL_AGG_SIZE, + BTC_SET_BL_INC_SCAN_DEV_NUM, + BTC_SET_BL_BT_TX_RX_MASK, + BTC_SET_BL_MIRACAST_PLUS_BT, + + /* type u1Byte */ + BTC_SET_U1_RSSI_ADJ_VAL_FOR_AGC_TABLE_ON, + BTC_SET_UI_SCAN_SIG_COMPENSATION, + BTC_SET_U1_AGG_BUF_SIZE, + + /* type trigger some action */ + BTC_SET_ACT_GET_BT_RSSI, + BTC_SET_ACT_AGGREGATE_CTRL, + BTC_SET_ACT_ANTPOSREGRISTRY_CTRL, + + /********* for 1Ant **********/ + /* type bool */ + BTC_SET_BL_BT_SCO_BUSY, + /* type u1Byte */ + BTC_SET_U1_RSSI_ADJ_VAL_FOR_1ANT_COEX_TYPE, + BTC_SET_U1_LPS_VAL, + BTC_SET_U1_RPWM_VAL, + BTC_SET_U1_1ANT_LPS, + BTC_SET_U1_1ANT_RPWM, + /* type trigger some action */ + BTC_SET_ACT_LEAVE_LPS, + BTC_SET_ACT_ENTER_LPS, + BTC_SET_ACT_NORMAL_LPS, + BTC_SET_ACT_INC_FORCE_EXEC_PWR_CMD_CNT, + BTC_SET_ACT_DISABLE_LOW_POWER, + BTC_SET_ACT_UPDATE_RAMASK, + BTC_SET_ACT_SEND_MIMO_PS, + /* BT Coex related */ + BTC_SET_ACT_CTRL_BT_INFO, + BTC_SET_ACT_CTRL_BT_COEX, + BTC_SET_ACT_CTRL_8723B_ANT, + /***************************/ + BTC_SET_MAX +}; + +enum btc_dbg_disp_type { + BTC_DBG_DISP_COEX_STATISTICS = 0x0, + BTC_DBG_DISP_BT_LINK_INFO = 0x1, + BTC_DBG_DISP_BT_FW_VER = 0x2, + BTC_DBG_DISP_FW_PWR_MODE_CMD = 0x3, + BTC_DBG_DISP_WIFI_STATUS = 0x04, + BTC_DBG_DISP_MAX +}; + +enum btc_notify_type_ips { + BTC_IPS_LEAVE = 0x0, + BTC_IPS_ENTER = 0x1, + BTC_IPS_MAX +}; + +enum btc_notify_type_lps { + BTC_LPS_DISABLE = 0x0, + BTC_LPS_ENABLE = 0x1, + BTC_LPS_MAX +}; + +enum btc_notify_type_scan { + BTC_SCAN_FINISH = 0x0, + BTC_SCAN_START = 0x1, + BTC_SCAN_START_2G = 0x2, + BTC_SCAN_MAX +}; + +enum btc_notify_type_switchband { + BTC_NOT_SWITCH = 0x0, + BTC_SWITCH_TO_24G = 0x1, + BTC_SWITCH_TO_5G = 0x2, + BTC_SWITCH_TO_24G_NOFORSCAN = 0x3, + BTC_SWITCH_MAX +}; + +enum btc_notify_type_associate { + BTC_ASSOCIATE_FINISH = 0x0, + BTC_ASSOCIATE_START = 0x1, + BTC_ASSOCIATE_5G_FINISH = 0x2, + BTC_ASSOCIATE_5G_START = 0x3, + BTC_ASSOCIATE_MAX +}; + +enum btc_notify_type_media_status { + BTC_MEDIA_DISCONNECT = 0x0, + BTC_MEDIA_CONNECT = 0x1, + BTC_MEDIA_MAX +}; + +enum btc_notify_type_special_packet { + BTC_PACKET_UNKNOWN = 0x0, + BTC_PACKET_DHCP = 0x1, + BTC_PACKET_ARP = 0x2, + BTC_PACKET_EAPOL = 0x3, + BTC_PACKET_MAX +}; + +enum hci_ext_bt_operation { + HCI_BT_OP_NONE = 0x0, + HCI_BT_OP_INQUIRY_START = 0x1, + HCI_BT_OP_INQUIRY_FINISH = 0x2, + HCI_BT_OP_PAGING_START = 0x3, + HCI_BT_OP_PAGING_SUCCESS = 0x4, + HCI_BT_OP_PAGING_UNSUCCESS = 0x5, + HCI_BT_OP_PAIRING_START = 0x6, + HCI_BT_OP_PAIRING_FINISH = 0x7, + HCI_BT_OP_BT_DEV_ENABLE = 0x8, + HCI_BT_OP_BT_DEV_DISABLE = 0x9, + HCI_BT_OP_MAX +}; + +enum btc_notify_type_stack_operation { + BTC_STACK_OP_NONE = 0x0, + BTC_STACK_OP_INQ_PAGE_PAIR_START = 0x1, + BTC_STACK_OP_INQ_PAGE_PAIR_FINISH = 0x2, + BTC_STACK_OP_MAX +}; + +typedef u8 (*bfp_btc_r1)(void *btc_context, u32 reg_addr); + +typedef u16 (*bfp_btc_r2)(void *btc_context, u32 reg_addr); + +typedef u32 (*bfp_btc_r4)(void *btc_context, u32 reg_addr); + +typedef void (*bfp_btc_w1)(void *btc_context, u32 reg_addr, u32 data); + +typedef void (*bfp_btc_w1_bit_mak)(void *btc_context, u32 reg_addr, + u32 bit_mask, u8 data1b); + +typedef void (*bfp_btc_w2)(void *btc_context, u32 reg_addr, u16 data); + +typedef void (*bfp_btc_w4)(void *btc_context, u32 reg_addr, u32 data); + +typedef void (*bfp_btc_local_reg_w1)(void *btc_context, u32 reg_addr, u8 data); +typedef void (*bfp_btc_wr_1byte_bit_mask)(void *btc_context, u32 reg_addr, + u8 bit_mask, u8 data); + +typedef void (*bfp_btc_set_bb_reg)(void *btc_context, u32 reg_addr, + u32 bit_mask, u32 data); + +typedef u32 (*bfp_btc_get_bb_reg)(void *btc_context, u32 reg_addr, + u32 bit_mask); + +typedef void (*bfp_btc_set_rf_reg)(void *btc_context, u8 rf_path, u32 reg_addr, + u32 bit_mask, u32 data); + +typedef u32 (*bfp_btc_get_rf_reg)(void *btc_context, u8 rf_path, + u32 reg_addr, u32 bit_mask); + +typedef void (*bfp_btc_fill_h2c)(void *btc_context, u8 element_id, + u32 cmd_len, u8 *cmd_buffer); + +typedef bool (*bfp_btc_get)(void *btcoexist, u8 get_type, void *out_buf); + +typedef bool (*bfp_btc_set)(void *btcoexist, u8 set_type, void *in_buf); + +typedef u32 (*bfp_btc_get_bt_coex_supported_feature)(void *btcoexist); + +typedef u32 (*bfp_btc_get_bt_coex_supported_version)(void *btcoexist); + +typedef u32 (*bfp_btc_get_bt_phydm_version)(void *btcoexist); + +typedef void (*bfp_btc_phydm_modify_ra_pcr_threshold)(void *btcoexist, + u8 ra_offset_direction, + u8 ra_threshold_offset); + +typedef u32 (*bfp_btc_phydm_query_phy_counter)(void *btcoexist, + const char *info_type); + +typedef u8 (*bfp_btc_get_ant_det_val_from_bt)(void *btcoexist); + +typedef u8 (*bfp_btc_get_ble_scan_type_from_bt)(void *btcoexist); + +typedef u32 (*bfp_btc_get_ble_scan_para_from_bt)(void *btcoexist, u8 scan_type); + +typedef bool (*bfp_btc_get_bt_afh_map_from_bt)(void *btcoexist, u8 map_type, + u8 *afh_map); + +typedef void (*bfp_btc_set_bt_reg)(void *btc_context, u8 reg_type, u32 offset, + u32 value); +typedef u32 (*bfp_btc_get_bt_reg)(void *btc_context, u8 reg_type, u32 offset); + +typedef void (*bfp_btc_disp_dbg_msg)(void *btcoexist, u8 disp_type, + struct seq_file *m); + +struct btc_bt_info { + bool bt_disabled; + u8 rssi_adjust_for_agc_table_on; + u8 rssi_adjust_for_1ant_coex_type; + bool pre_bt_ctrl_agg_buf_size; + bool bt_busy; + u8 pre_agg_buf_size; + u8 agg_buf_size; + bool limited_dig; + bool pre_reject_agg_pkt; + bool reject_agg_pkt; + bool bt_ctrl_buf_size; + bool increase_scan_dev_num; + bool miracast_plus_bt; + bool bt_ctrl_agg_buf_size; + bool bt_tx_rx_mask; + u16 bt_hci_ver; + u16 bt_real_fw_ver; + u8 bt_fw_ver; + u32 bt_get_fw_ver; + + bool bt_disable_low_pwr; + + /* the following is for 1Ant solution */ + bool bt_ctrl_lps; + bool bt_pwr_save_mode; + bool bt_lps_on; + bool force_to_roam; + u8 force_exec_pwr_cmd_cnt; + u8 lps_val; + u8 rpwm_val; + u32 ra_mask; + + u32 afh_map_l; + u32 afh_map_m; + u16 afh_map_h; + u32 bt_supported_feature; + u32 bt_supported_version; + u8 bt_ant_det_val; + u8 bt_ble_scan_type; + u32 bt_ble_scan_para; +}; + +struct btc_stack_info { + bool profile_notified; + u16 hci_version; /* stack hci version */ + u8 num_of_link; + bool bt_link_exist; + bool sco_exist; + bool acl_exist; + bool a2dp_exist; + bool hid_exist; + u8 num_of_hid; + bool pan_exist; + bool unknown_acl_exist; + s8 min_bt_rssi; +}; + +struct btc_statistics { + u32 cnt_bind; + u32 cnt_init_hw_config; + u32 cnt_init_coex_dm; + u32 cnt_ips_notify; + u32 cnt_lps_notify; + u32 cnt_scan_notify; + u32 cnt_connect_notify; + u32 cnt_media_status_notify; + u32 cnt_special_packet_notify; + u32 cnt_bt_info_notify; + u32 cnt_periodical; + u32 cnt_coex_dm_switch; + u32 cnt_stack_operation_notify; + u32 cnt_dbg_ctrl; + u32 cnt_pre_load_firmware; + u32 cnt_power_on; +}; + +struct btc_bt_link_info { + bool bt_link_exist; + bool bt_hi_pri_link_exist; + bool sco_exist; + bool sco_only; + bool a2dp_exist; + bool a2dp_only; + bool hid_exist; + bool hid_only; + bool pan_exist; + bool pan_only; + bool slave_role; + bool acl_busy; +}; + +enum btc_antenna_pos { + BTC_ANTENNA_AT_MAIN_PORT = 0x1, + BTC_ANTENNA_AT_AUX_PORT = 0x2, +}; + +enum btc_mp_h2c_op_code { + BT_OP_GET_BT_VERSION = 0, + BT_OP_WRITE_REG_ADDR = 12, + BT_OP_WRITE_REG_VALUE = 13, + BT_OP_READ_REG = 17, + BT_OP_GET_AFH_MAP_L = 30, + BT_OP_GET_AFH_MAP_M = 31, + BT_OP_GET_AFH_MAP_H = 32, + BT_OP_GET_BT_COEX_SUPPORTED_FEATURE = 42, + BT_OP_GET_BT_COEX_SUPPORTED_VERSION = 43, + BT_OP_GET_BT_ANT_DET_VAL = 44, + BT_OP_GET_BT_BLE_SCAN_PARA = 45, + BT_OP_GET_BT_BLE_SCAN_TYPE = 46, + BT_OP_MAX +}; + +enum btc_mp_h2c_req_num { + /* 4 bits only */ + BT_SEQ_DONT_CARE = 0, + BT_SEQ_GET_BT_VERSION = 0xE, + BT_SEQ_GET_AFH_MAP_L = 0x5, + BT_SEQ_GET_AFH_MAP_M = 0x6, + BT_SEQ_GET_AFH_MAP_H = 0x9, + BT_SEQ_GET_BT_COEX_SUPPORTED_FEATURE = 0x7, + BT_SEQ_GET_BT_COEX_SUPPORTED_VERSION = 0x8, + BT_SEQ_GET_BT_ANT_DET_VAL = 0x2, + BT_SEQ_GET_BT_BLE_SCAN_PARA = 0x3, + BT_SEQ_GET_BT_BLE_SCAN_TYPE = 0x4, +}; + +struct btc_coexist { + /* make sure only one adapter can bind the data context */ + bool binded; + /* default adapter */ + void *adapter; + struct btc_board_info board_info; + /* some bt info referenced by non-bt module */ + struct btc_bt_info bt_info; + struct btc_stack_info stack_info; + enum btc_chip_interface chip_interface; + struct btc_bt_link_info bt_link_info; + + /* boolean variables to replace BT_AUTO_REPORT_ONLY_XXXXY_ZANT + * configuration parameters + */ + bool auto_report_1ant; + bool auto_report_2ant; + bool dbg_mode_1ant; + bool dbg_mode_2ant; + bool initilized; + bool stop_coex_dm; + bool manual_control; + struct btc_statistics statistics; + u8 pwr_mode_val[10]; + + struct completion bt_mp_comp; + + /* function pointers - io related */ + bfp_btc_r1 btc_read_1byte; + bfp_btc_w1 btc_write_1byte; + bfp_btc_w1_bit_mak btc_write_1byte_bitmask; + bfp_btc_r2 btc_read_2byte; + bfp_btc_w2 btc_write_2byte; + bfp_btc_r4 btc_read_4byte; + bfp_btc_w4 btc_write_4byte; + bfp_btc_local_reg_w1 btc_write_local_reg_1byte; + + bfp_btc_set_bb_reg btc_set_bb_reg; + bfp_btc_get_bb_reg btc_get_bb_reg; + + bfp_btc_set_rf_reg btc_set_rf_reg; + bfp_btc_get_rf_reg btc_get_rf_reg; + + bfp_btc_fill_h2c btc_fill_h2c; + + bfp_btc_disp_dbg_msg btc_disp_dbg_msg; + + bfp_btc_get btc_get; + bfp_btc_set btc_set; + + bfp_btc_set_bt_reg btc_set_bt_reg; + bfp_btc_get_bt_reg btc_get_bt_reg; + + bfp_btc_get_bt_coex_supported_feature btc_get_bt_coex_supported_feature; + bfp_btc_get_bt_coex_supported_version btc_get_bt_coex_supported_version; + bfp_btc_get_bt_phydm_version btc_get_bt_phydm_version; + bfp_btc_phydm_modify_ra_pcr_threshold btc_phydm_modify_ra_pcr_threshold; + bfp_btc_phydm_query_phy_counter btc_phydm_query_phy_counter; + bfp_btc_get_ant_det_val_from_bt btc_get_ant_det_val_from_bt; + bfp_btc_get_ble_scan_type_from_bt btc_get_ble_scan_type_from_bt; + bfp_btc_get_ble_scan_para_from_bt btc_get_ble_scan_para_from_bt; + bfp_btc_get_bt_afh_map_from_bt btc_get_bt_afh_map_from_bt; + +}; + +bool halbtc_is_wifi_uplink(struct rtl_priv *adapter); + +#define rtl_btc_coexist(rtlpriv) \ + ((struct btc_coexist *)((rtlpriv)->btcoexist.btc_context)) +#define rtl_btc_wifi_only(rtlpriv) \ + ((struct wifi_only_cfg *)((rtlpriv)->btcoexist.wifi_only_context)) + +struct wifi_only_cfg; + +bool exhalbtc_initlize_variables(struct rtl_priv *rtlpriv); +bool exhalbtc_initlize_variables_wifi_only(struct rtl_priv *rtlpriv); +bool exhalbtc_bind_bt_coex_withadapter(void *adapter); +void exhalbtc_power_on_setting(struct btc_coexist *btcoexist); +void exhalbtc_pre_load_firmware(struct btc_coexist *btcoexist); +void exhalbtc_init_hw_config(struct btc_coexist *btcoexist, bool wifi_only); +void exhalbtc_init_hw_config_wifi_only(struct wifi_only_cfg *wifionly_cfg); +void exhalbtc_init_coex_dm(struct btc_coexist *btcoexist); +void exhalbtc_ips_notify(struct btc_coexist *btcoexist, u8 type); +void exhalbtc_lps_notify(struct btc_coexist *btcoexist, u8 type); +void exhalbtc_scan_notify(struct btc_coexist *btcoexist, u8 type); +void exhalbtc_scan_notify_wifi_only(struct wifi_only_cfg *wifionly_cfg, + u8 is_5g); +void exhalbtc_connect_notify(struct btc_coexist *btcoexist, u8 action); +void exhalbtc_mediastatus_notify(struct btc_coexist *btcoexist, + enum rt_media_status media_status); +void exhalbtc_special_packet_notify(struct btc_coexist *btcoexist, u8 pkt_type); +void exhalbtc_bt_info_notify(struct btc_coexist *btcoexist, u8 *tmp_buf, + u8 length); +void exhalbtc_rf_status_notify(struct btc_coexist *btcoexist, u8 type); +void exhalbtc_stack_operation_notify(struct btc_coexist *btcoexist, u8 type); +void exhalbtc_halt_notify(struct btc_coexist *btcoexist); +void exhalbtc_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state); +void exhalbtc_coex_dm_switch(struct btc_coexist *btcoexist); +void exhalbtc_periodical(struct btc_coexist *btcoexist); +void exhalbtc_dbg_control(struct btc_coexist *btcoexist, u8 code, u8 len, + u8 *data); +void exhalbtc_antenna_detection(struct btc_coexist *btcoexist, u32 cent_freq, + u32 offset, u32 span, u32 seconds); +void exhalbtc_stack_update_profile_info(void); +void exhalbtc_set_hci_version(struct btc_coexist *btcoexist, u16 hci_version); +void exhalbtc_set_bt_patch_version(struct btc_coexist *btcoexist, + u16 bt_hci_version, u16 bt_patch_version); +void exhalbtc_update_min_bt_rssi(struct btc_coexist *btcoexist, s8 bt_rssi); +void exhalbtc_set_bt_exist(struct btc_coexist *btcoexist, bool bt_exist); +void exhalbtc_set_chip_type(struct btc_coexist *btcoexist, u8 chip_type); +void exhalbtc_set_ant_num(struct rtl_priv *rtlpriv, u8 type, u8 ant_num); +void exhalbtc_display_bt_coex_info(struct btc_coexist *btcoexist, + struct seq_file *m); +void exhalbtc_switch_band_notify(struct btc_coexist *btcoexist, u8 type); +void exhalbtc_switch_band_notify_wifi_only(struct wifi_only_cfg *wifionly_cfg, + u8 is_5g); +void exhalbtc_signal_compensation(struct btc_coexist *btcoexist, + u8 *rssi_wifi, u8 *rssi_bt); +void exhalbtc_lps_leave(struct btc_coexist *btcoexist); +void exhalbtc_low_wifi_traffic_notify(struct btc_coexist *btcoexist); +void exhalbtc_set_single_ant_path(struct btc_coexist *btcoexist, + u8 single_ant_path); + +/* The following are used by wifi_only case */ +enum wifionly_chip_interface { + WIFIONLY_INTF_UNKNOWN = 0, + WIFIONLY_INTF_PCI = 1, + WIFIONLY_INTF_USB = 2, + WIFIONLY_INTF_SDIO = 3, + WIFIONLY_INTF_MAX +}; + +enum wifionly_customer_id { + CUSTOMER_NORMAL = 0, + CUSTOMER_HP_1 = 1, +}; + +struct wifi_only_haldata { + u16 customer_id; + u8 efuse_pg_antnum; + u8 efuse_pg_antpath; + u8 rfe_type; + u8 ant_div_cfg; +}; + +struct wifi_only_cfg { + void *adapter; + struct wifi_only_haldata haldata_info; + enum wifionly_chip_interface chip_interface; +}; + +static inline +void halwifionly_phy_set_bb_reg(struct wifi_only_cfg *wifi_conly_cfg, + u32 regaddr, u32 bitmask, u32 data) +{ + struct rtl_priv *rtlpriv = (struct rtl_priv *)wifi_conly_cfg->adapter; + + rtl_set_bbreg(rtlpriv->hw, regaddr, bitmask, data); +} + +#endif diff --git a/drivers/staging/rtlwifi/btcoexist/rtl_btc.c b/drivers/staging/rtlwifi/btcoexist/rtl_btc.c new file mode 100644 index 000000000000..18a4f5b43b5a --- /dev/null +++ b/drivers/staging/rtlwifi/btcoexist/rtl_btc.c @@ -0,0 +1,528 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2013 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#include "../wifi.h" +#include <linux/vmalloc.h> +#include <linux/module.h> + +#include "rtl_btc.h" +#include "halbt_precomp.h" + +static struct rtl_btc_ops rtl_btc_operation = { + .btc_init_variables = rtl_btc_init_variables, + .btc_init_variables_wifi_only = rtl_btc_init_variables_wifi_only, + .btc_deinit_variables = rtl_btc_deinit_variables, + .btc_init_hal_vars = rtl_btc_init_hal_vars, + .btc_power_on_setting = rtl_btc_power_on_setting, + .btc_init_hw_config = rtl_btc_init_hw_config, + .btc_init_hw_config_wifi_only = rtl_btc_init_hw_config_wifi_only, + .btc_ips_notify = rtl_btc_ips_notify, + .btc_lps_notify = rtl_btc_lps_notify, + .btc_scan_notify = rtl_btc_scan_notify, + .btc_scan_notify_wifi_only = rtl_btc_scan_notify_wifi_only, + .btc_connect_notify = rtl_btc_connect_notify, + .btc_mediastatus_notify = rtl_btc_mediastatus_notify, + .btc_periodical = rtl_btc_periodical, + .btc_halt_notify = rtl_btc_halt_notify, + .btc_btinfo_notify = rtl_btc_btinfo_notify, + .btc_btmpinfo_notify = rtl_btc_btmpinfo_notify, + .btc_is_limited_dig = rtl_btc_is_limited_dig, + .btc_is_disable_edca_turbo = rtl_btc_is_disable_edca_turbo, + .btc_is_bt_disabled = rtl_btc_is_bt_disabled, + .btc_special_packet_notify = rtl_btc_special_packet_notify, + .btc_switch_band_notify = rtl_btc_switch_band_notify, + .btc_switch_band_notify_wifi_only = rtl_btc_switch_band_notify_wifionly, + .btc_record_pwr_mode = rtl_btc_record_pwr_mode, + .btc_get_lps_val = rtl_btc_get_lps_val, + .btc_get_rpwm_val = rtl_btc_get_rpwm_val, + .btc_is_bt_ctrl_lps = rtl_btc_is_bt_ctrl_lps, + .btc_is_bt_lps_on = rtl_btc_is_bt_lps_on, + .btc_get_ampdu_cfg = rtl_btc_get_ampdu_cfg, + .btc_display_bt_coex_info = rtl_btc_display_bt_coex_info, +}; + +void rtl_btc_display_bt_coex_info(struct rtl_priv *rtlpriv, struct seq_file *m) +{ + struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv); + + if (!btcoexist) { + seq_puts(m, "btc_coexist context is NULL!\n"); + return; + } + + exhalbtc_display_bt_coex_info(btcoexist, m); +} + +void rtl_btc_record_pwr_mode(struct rtl_priv *rtlpriv, u8 *buf, u8 len) +{ + struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv); + u8 safe_len; + + if (!btcoexist) + return; + + safe_len = sizeof(btcoexist->pwr_mode_val); + + if (safe_len > len) + safe_len = len; + + memcpy(btcoexist->pwr_mode_val, buf, safe_len); +} + +u8 rtl_btc_get_lps_val(struct rtl_priv *rtlpriv) +{ + struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv); + + if (!btcoexist) + return 0; + + return btcoexist->bt_info.lps_val; +} + +u8 rtl_btc_get_rpwm_val(struct rtl_priv *rtlpriv) +{ + struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv); + + if (!btcoexist) + return 0; + + return btcoexist->bt_info.rpwm_val; +} + +bool rtl_btc_is_bt_ctrl_lps(struct rtl_priv *rtlpriv) +{ + struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv); + + if (!btcoexist) + return false; + + return btcoexist->bt_info.bt_ctrl_lps; +} + +bool rtl_btc_is_bt_lps_on(struct rtl_priv *rtlpriv) +{ + struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv); + + if (!btcoexist) + return false; + + return btcoexist->bt_info.bt_lps_on; +} + +void rtl_btc_get_ampdu_cfg(struct rtl_priv *rtlpriv, u8 *reject_agg, + u8 *ctrl_agg_size, u8 *agg_size) +{ + struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv); + + if (!btcoexist) { + *reject_agg = false; + *ctrl_agg_size = false; + return; + } + + if (reject_agg) + *reject_agg = btcoexist->bt_info.reject_agg_pkt; + if (ctrl_agg_size) + *ctrl_agg_size = btcoexist->bt_info.bt_ctrl_agg_buf_size; + if (agg_size) + *agg_size = btcoexist->bt_info.agg_buf_size; +} + +static void rtl_btc_alloc_variable(struct rtl_priv *rtlpriv, bool wifi_only) +{ + if (wifi_only) + rtlpriv->btcoexist.wifi_only_context = + kzalloc(sizeof(struct wifi_only_cfg), GFP_KERNEL); + else + rtlpriv->btcoexist.btc_context = + kzalloc(sizeof(struct btc_coexist), GFP_KERNEL); +} + +static void rtl_btc_free_variable(struct rtl_priv *rtlpriv) +{ + kfree(rtlpriv->btcoexist.btc_context); + rtlpriv->btcoexist.btc_context = NULL; + + kfree(rtlpriv->btcoexist.wifi_only_context); + rtlpriv->btcoexist.wifi_only_context = NULL; +} + +void rtl_btc_init_variables(struct rtl_priv *rtlpriv) +{ + rtl_btc_alloc_variable(rtlpriv, false); + + exhalbtc_initlize_variables(rtlpriv); + exhalbtc_bind_bt_coex_withadapter(rtlpriv); +} + +void rtl_btc_init_variables_wifi_only(struct rtl_priv *rtlpriv) +{ + rtl_btc_alloc_variable(rtlpriv, true); + + exhalbtc_initlize_variables_wifi_only(rtlpriv); +} + +void rtl_btc_deinit_variables(struct rtl_priv *rtlpriv) +{ + rtl_btc_free_variable(rtlpriv); +} + +void rtl_btc_init_hal_vars(struct rtl_priv *rtlpriv) +{ + /* move ant_num, bt_type and single_ant_path to + * exhalbtc_bind_bt_coex_withadapter() + */ +} + +void rtl_btc_power_on_setting(struct rtl_priv *rtlpriv) +{ + struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv); + + if (!btcoexist) + return; + + exhalbtc_power_on_setting(btcoexist); +} + +void rtl_btc_init_hw_config(struct rtl_priv *rtlpriv) +{ + struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv); + + u8 bt_exist; + + bt_exist = rtl_get_hwpg_bt_exist(rtlpriv); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "%s, bt_exist is %d\n", __func__, bt_exist); + + if (!btcoexist) + return; + + exhalbtc_init_hw_config(btcoexist, !bt_exist); + exhalbtc_init_coex_dm(btcoexist); +} + +void rtl_btc_init_hw_config_wifi_only(struct rtl_priv *rtlpriv) +{ + struct wifi_only_cfg *wifionly_cfg = rtl_btc_wifi_only(rtlpriv); + + if (!wifionly_cfg) + return; + + exhalbtc_init_hw_config_wifi_only(wifionly_cfg); +} + +void rtl_btc_ips_notify(struct rtl_priv *rtlpriv, u8 type) +{ + struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv); + + if (!btcoexist) + return; + + exhalbtc_ips_notify(btcoexist, type); + + if (type == ERFON) { + /* + * In some situation, it doesn't scan after leaving IPS, and + * this will cause btcoex in wrong state. + */ + exhalbtc_scan_notify(btcoexist, 1); + exhalbtc_scan_notify(btcoexist, 0); + } +} + +void rtl_btc_lps_notify(struct rtl_priv *rtlpriv, u8 type) +{ + struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv); + + if (!btcoexist) + return; + + exhalbtc_lps_notify(btcoexist, type); +} + +void rtl_btc_scan_notify(struct rtl_priv *rtlpriv, u8 scantype) +{ + struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv); + + if (!btcoexist) + return; + + exhalbtc_scan_notify(btcoexist, scantype); +} + +void rtl_btc_scan_notify_wifi_only(struct rtl_priv *rtlpriv, u8 scantype) +{ + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + struct wifi_only_cfg *wifionly_cfg = rtl_btc_wifi_only(rtlpriv); + u8 is_5g = (rtlhal->current_bandtype == BAND_ON_5G); + + if (!wifionly_cfg) + return; + + exhalbtc_scan_notify_wifi_only(wifionly_cfg, is_5g); +} + +void rtl_btc_connect_notify(struct rtl_priv *rtlpriv, u8 action) +{ + struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv); + + if (!btcoexist) + return; + + exhalbtc_connect_notify(btcoexist, action); +} + +void rtl_btc_mediastatus_notify(struct rtl_priv *rtlpriv, + enum rt_media_status mstatus) +{ + struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv); + + if (!btcoexist) + return; + + exhalbtc_mediastatus_notify(btcoexist, mstatus); +} + +void rtl_btc_periodical(struct rtl_priv *rtlpriv) +{ + struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv); + + if (!btcoexist) + return; + + /*rtl_bt_dm_monitor();*/ + exhalbtc_periodical(btcoexist); +} + +void rtl_btc_halt_notify(struct rtl_priv *rtlpriv) +{ + struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv); + + if (!btcoexist) + return; + + exhalbtc_halt_notify(btcoexist); +} + +void rtl_btc_btinfo_notify(struct rtl_priv *rtlpriv, u8 *tmp_buf, u8 length) +{ + struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv); + + if (!btcoexist) + return; + + exhalbtc_bt_info_notify(btcoexist, tmp_buf, length); +} + +void rtl_btc_btmpinfo_notify(struct rtl_priv *rtlpriv, u8 *tmp_buf, u8 length) +{ + struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv); + u8 extid, seq, len; + u16 bt_real_fw_ver; + u8 bt_fw_ver; + u8 *data; + + if (!btcoexist) + return; + + if ((length < 4) || (!tmp_buf)) + return; + + extid = tmp_buf[0]; + /* not response from BT FW then exit*/ + if (extid != 1) /* C2H_TRIG_BY_BT_FW = 1 */ + return; + + len = tmp_buf[1] >> 4; + seq = tmp_buf[2] >> 4; + data = &tmp_buf[3]; + + /* BT Firmware version response */ + switch (seq) { + case BT_SEQ_GET_BT_VERSION: + bt_real_fw_ver = tmp_buf[3] | (tmp_buf[4] << 8); + bt_fw_ver = tmp_buf[5]; + + btcoexist->bt_info.bt_real_fw_ver = bt_real_fw_ver; + btcoexist->bt_info.bt_fw_ver = bt_fw_ver; + break; + case BT_SEQ_GET_AFH_MAP_L: + btcoexist->bt_info.afh_map_l = le32_to_cpu(*(__le32 *)data); + break; + case BT_SEQ_GET_AFH_MAP_M: + btcoexist->bt_info.afh_map_m = le32_to_cpu(*(__le32 *)data); + break; + case BT_SEQ_GET_AFH_MAP_H: + btcoexist->bt_info.afh_map_h = le16_to_cpu(*(__le16 *)data); + break; + case BT_SEQ_GET_BT_COEX_SUPPORTED_FEATURE: + btcoexist->bt_info.bt_supported_feature = tmp_buf[3] | + (tmp_buf[4] << 8); + break; + case BT_SEQ_GET_BT_COEX_SUPPORTED_VERSION: + btcoexist->bt_info.bt_supported_version = tmp_buf[3] | + (tmp_buf[4] << 8); + break; + case BT_SEQ_GET_BT_ANT_DET_VAL: + btcoexist->bt_info.bt_ant_det_val = tmp_buf[3]; + break; + case BT_SEQ_GET_BT_BLE_SCAN_PARA: + btcoexist->bt_info.bt_ble_scan_para = tmp_buf[3] | + (tmp_buf[4] << 8) | + (tmp_buf[5] << 16) | + (tmp_buf[6] << 24); + break; + case BT_SEQ_GET_BT_BLE_SCAN_TYPE: + btcoexist->bt_info.bt_ble_scan_type = tmp_buf[3]; + break; + } + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "btmpinfo complete req_num=%d\n", seq); + + complete(&btcoexist->bt_mp_comp); +} + +bool rtl_btc_is_limited_dig(struct rtl_priv *rtlpriv) +{ + struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv); + + if (!btcoexist) + return false; + + return btcoexist->bt_info.limited_dig; +} + +bool rtl_btc_is_disable_edca_turbo(struct rtl_priv *rtlpriv) +{ + bool bt_change_edca = false; + u32 cur_edca_val; + u32 edca_bt_hs_uplink = 0x5ea42b, edca_bt_hs_downlink = 0x5ea42b; + u32 edca_hs; + u32 edca_addr = 0x504; + + cur_edca_val = rtl_read_dword(rtlpriv, edca_addr); + if (halbtc_is_wifi_uplink(rtlpriv)) { + if (cur_edca_val != edca_bt_hs_uplink) { + edca_hs = edca_bt_hs_uplink; + bt_change_edca = true; + } + } else { + if (cur_edca_val != edca_bt_hs_downlink) { + edca_hs = edca_bt_hs_downlink; + bt_change_edca = true; + } + } + + if (bt_change_edca) + rtl_write_dword(rtlpriv, edca_addr, edca_hs); + + return true; +} + +bool rtl_btc_is_bt_disabled(struct rtl_priv *rtlpriv) +{ + struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv); + + if (!btcoexist) + return true; + + /* It seems 'bt_disabled' is never be initialized or set. */ + if (btcoexist->bt_info.bt_disabled) + return true; + else + return false; +} + +void rtl_btc_special_packet_notify(struct rtl_priv *rtlpriv, u8 pkt_type) +{ + struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv); + + if (!btcoexist) + return; + + return exhalbtc_special_packet_notify(btcoexist, pkt_type); +} + +void rtl_btc_switch_band_notify(struct rtl_priv *rtlpriv, u8 band_type, + bool scanning) +{ + struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv); + u8 type = BTC_NOT_SWITCH; + + if (!btcoexist) + return; + + switch (band_type) { + case BAND_ON_2_4G: + if (scanning) + type = BTC_SWITCH_TO_24G; + else + type = BTC_SWITCH_TO_24G_NOFORSCAN; + break; + + case BAND_ON_5G: + type = BTC_SWITCH_TO_5G; + break; + } + + if (type != BTC_NOT_SWITCH) + exhalbtc_switch_band_notify(btcoexist, type); +} + +void rtl_btc_switch_band_notify_wifionly(struct rtl_priv *rtlpriv, u8 band_type, + bool scanning) +{ + struct wifi_only_cfg *wifionly_cfg = rtl_btc_wifi_only(rtlpriv); + u8 is_5g = (band_type == BAND_ON_5G); + + if (!wifionly_cfg) + return; + + exhalbtc_switch_band_notify_wifi_only(wifionly_cfg, is_5g); +} + +struct rtl_btc_ops *rtl_btc_get_ops_pointer(void) +{ + return &rtl_btc_operation; +} + +enum rt_media_status mgnt_link_status_query(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + enum rt_media_status m_status = RT_MEDIA_DISCONNECT; + + u8 bibss = (mac->opmode == NL80211_IFTYPE_ADHOC) ? 1 : 0; + + if (bibss || rtlpriv->mac80211.link_state >= MAC80211_LINKED) + m_status = RT_MEDIA_CONNECT; + + return m_status; +} + +u8 rtl_get_hwpg_bt_exist(struct rtl_priv *rtlpriv) +{ + return rtlpriv->btcoexist.btc_info.btcoexist; +} diff --git a/drivers/staging/rtlwifi/btcoexist/rtl_btc.h b/drivers/staging/rtlwifi/btcoexist/rtl_btc.h new file mode 100644 index 000000000000..8c996055de71 --- /dev/null +++ b/drivers/staging/rtlwifi/btcoexist/rtl_btc.h @@ -0,0 +1,75 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL_BTC_H__ +#define __RTL_BTC_H__ + +#include "halbt_precomp.h" + +void rtl_btc_init_variables(struct rtl_priv *rtlpriv); +void rtl_btc_init_variables_wifi_only(struct rtl_priv *rtlpriv); +void rtl_btc_deinit_variables(struct rtl_priv *rtlpriv); +void rtl_btc_init_hal_vars(struct rtl_priv *rtlpriv); +void rtl_btc_power_on_setting(struct rtl_priv *rtlpriv); +void rtl_btc_init_hw_config(struct rtl_priv *rtlpriv); +void rtl_btc_init_hw_config_wifi_only(struct rtl_priv *rtlpriv); +void rtl_btc_ips_notify(struct rtl_priv *rtlpriv, u8 type); +void rtl_btc_lps_notify(struct rtl_priv *rtlpriv, u8 type); +void rtl_btc_scan_notify(struct rtl_priv *rtlpriv, u8 scantype); +void rtl_btc_scan_notify_wifi_only(struct rtl_priv *rtlpriv, u8 scantype); +void rtl_btc_connect_notify(struct rtl_priv *rtlpriv, u8 action); +void rtl_btc_mediastatus_notify(struct rtl_priv *rtlpriv, + enum rt_media_status mstatus); +void rtl_btc_periodical(struct rtl_priv *rtlpriv); +void rtl_btc_halt_notify(struct rtl_priv *rtlpriv); +void rtl_btc_btinfo_notify(struct rtl_priv *rtlpriv, u8 *tmpbuf, u8 length); +void rtl_btc_btmpinfo_notify(struct rtl_priv *rtlpriv, u8 *tmp_buf, u8 length); +bool rtl_btc_is_limited_dig(struct rtl_priv *rtlpriv); +bool rtl_btc_is_disable_edca_turbo(struct rtl_priv *rtlpriv); +bool rtl_btc_is_bt_disabled(struct rtl_priv *rtlpriv); +void rtl_btc_special_packet_notify(struct rtl_priv *rtlpriv, u8 pkt_type); +void rtl_btc_switch_band_notify(struct rtl_priv *rtlpriv, u8 band_type, + bool scanning); +void rtl_btc_switch_band_notify_wifionly(struct rtl_priv *rtlpriv, u8 band_type, + bool scanning); +void rtl_btc_display_bt_coex_info(struct rtl_priv *rtlpriv, struct seq_file *m); +void rtl_btc_record_pwr_mode(struct rtl_priv *rtlpriv, u8 *buf, u8 len); +u8 rtl_btc_get_lps_val(struct rtl_priv *rtlpriv); +u8 rtl_btc_get_rpwm_val(struct rtl_priv *rtlpriv); +bool rtl_btc_is_bt_ctrl_lps(struct rtl_priv *rtlpriv); +bool rtl_btc_is_bt_lps_on(struct rtl_priv *rtlpriv); +void rtl_btc_get_ampdu_cfg(struct rtl_priv *rtlpriv, u8 *reject_agg, + u8 *ctrl_agg_size, u8 *agg_size); + +struct rtl_btc_ops *rtl_btc_get_ops_pointer(void); + +u8 rtl_get_hwpg_bt_exist(struct rtl_priv *rtlpriv); +u8 rtl_get_hwpg_bt_type(struct rtl_priv *rtlpriv); +u8 rtl_get_hwpg_ant_num(struct rtl_priv *rtlpriv); +u8 rtl_get_hwpg_single_ant_path(struct rtl_priv *rtlpriv); +u8 rtl_get_hwpg_package_type(struct rtl_priv *rtlpriv); + +enum rt_media_status mgnt_link_status_query(struct ieee80211_hw *hw); + +#endif diff --git a/drivers/staging/rtlwifi/cam.c b/drivers/staging/rtlwifi/cam.c new file mode 100644 index 000000000000..9c8c907cb48e --- /dev/null +++ b/drivers/staging/rtlwifi/cam.c @@ -0,0 +1,326 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#include "wifi.h" +#include "cam.h" +#include <linux/export.h> + +void rtl_cam_reset_sec_info(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtlpriv->sec.use_defaultkey = false; + rtlpriv->sec.pairwise_enc_algorithm = NO_ENCRYPTION; + rtlpriv->sec.group_enc_algorithm = NO_ENCRYPTION; + memset(rtlpriv->sec.key_buf, 0, KEY_BUF_SIZE * MAX_KEY_LEN); + memset(rtlpriv->sec.key_len, 0, KEY_BUF_SIZE); + rtlpriv->sec.pairwise_key = NULL; +} + +static void rtl_cam_program_entry(struct ieee80211_hw *hw, u32 entry_no, + u8 *mac_addr, u8 *key_cont_128, u16 us_config) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + u32 target_command; + u32 target_content = 0; + int entry_i; + + RT_PRINT_DATA(rtlpriv, COMP_SEC, DBG_DMESG, "Key content :", + key_cont_128, 16); + + /* 0-1 config + mac, 2-5 fill 128key,6-7 are reserved */ + for (entry_i = CAM_CONTENT_COUNT - 1; entry_i >= 0; entry_i--) { + target_command = entry_i + CAM_CONTENT_COUNT * entry_no; + target_command = target_command | BIT(31) | BIT(16); + + if (entry_i == 0) { + target_content = (u32)(*(mac_addr + 0)) << 16 | + (u32)(*(mac_addr + 1)) << 24 | + (u32)us_config; + + rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI], + target_content); + rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], + target_command); + + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, + "WRITE %x: %x\n", + rtlpriv->cfg->maps[WCAMI], target_content); + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, + "The Key ID is %d\n", entry_no); + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, + "WRITE %x: %x\n", + rtlpriv->cfg->maps[RWCAM], target_command); + + } else if (entry_i == 1) { + target_content = (u32)(*(mac_addr + 5)) << 24 | + (u32)(*(mac_addr + 4)) << 16 | + (u32)(*(mac_addr + 3)) << 8 | + (u32)(*(mac_addr + 2)); + + rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI], + target_content); + rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], + target_command); + + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, + "WRITE A4: %x\n", target_content); + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, + "WRITE A0: %x\n", target_command); + } else { + target_content = + (u32)(*(key_cont_128 + (entry_i * 4 - 8) + 3)) << + 24 | (u32)(*(key_cont_128 + (entry_i * 4 - 8) + 2)) + << 16 | + (u32)(*(key_cont_128 + (entry_i * 4 - 8) + 1)) << 8 + | (u32)(*(key_cont_128 + (entry_i * 4 - 8) + 0)); + + rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI], + target_content); + rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], + target_command); + + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, + "WRITE A4: %x\n", target_content); + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, + "WRITE A0: %x\n", target_command); + } + } + + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, + "after set key, usconfig:%x\n", us_config); +} + +u8 rtl_cam_add_one_entry(struct ieee80211_hw *hw, u8 *mac_addr, + u32 ul_key_id, u32 ul_entry_idx, u32 ul_enc_alg, + u32 ul_default_key, u8 *key_content) +{ + u32 us_config; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + "EntryNo:%x, ulKeyId=%x, ulEncAlg=%x, ulUseDK=%x MacAddr %pM\n", + ul_entry_idx, ul_key_id, ul_enc_alg, + ul_default_key, mac_addr); + + if (ul_key_id == TOTAL_CAM_ENTRY) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "ulKeyId exceed!\n"); + return 0; + } + + if (ul_default_key == 1) + us_config = CFG_VALID | ((u16)(ul_enc_alg) << 2); + else + us_config = CFG_VALID | ((ul_enc_alg) << 2) | ul_key_id; + + rtl_cam_program_entry(hw, ul_entry_idx, mac_addr, + (u8 *)key_content, us_config); + + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "end\n"); + + return 1; +} + +int rtl_cam_delete_one_entry(struct ieee80211_hw *hw, + u8 *mac_addr, u32 ul_key_id) +{ + u32 ul_command; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "key_idx:%d\n", ul_key_id); + + ul_command = ul_key_id * CAM_CONTENT_COUNT; + ul_command = ul_command | BIT(31) | BIT(16); + + rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI], 0); + rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], ul_command); + + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + "%s(): WRITE A4: %x\n", __func__, 0); + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + "%s(): WRITE A0: %x\n", __func__, ul_command); + + return 0; +} + +void rtl_cam_reset_all_entry(struct ieee80211_hw *hw) +{ + u32 ul_command; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + ul_command = BIT(31) | BIT(30); + rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], ul_command); +} + +void rtl_cam_mark_invalid(struct ieee80211_hw *hw, u8 uc_index) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + u32 ul_command; + u32 ul_content; + u32 ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_AES]; + + switch (rtlpriv->sec.pairwise_enc_algorithm) { + case WEP40_ENCRYPTION: + ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_WEP40]; + break; + case WEP104_ENCRYPTION: + ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_WEP104]; + break; + case TKIP_ENCRYPTION: + ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_TKIP]; + break; + case AESCCMP_ENCRYPTION: + ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_AES]; + break; + default: + ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_AES]; + } + + ul_content = (uc_index & 3) | ((u16)(ul_enc_algo) << 2); + + ul_content |= BIT(15); + ul_command = CAM_CONTENT_COUNT * uc_index; + ul_command = ul_command | BIT(31) | BIT(16); + + rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI], ul_content); + rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], ul_command); + + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + "%s(): WRITE A4: %x\n", __func__, ul_content); + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + "%s(): WRITE A0: %x\n", __func__, ul_command); +} + +void rtl_cam_empty_entry(struct ieee80211_hw *hw, u8 uc_index) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + u32 ul_command; + u32 ul_content; + u32 ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_AES]; + u8 entry_i; + + switch (rtlpriv->sec.pairwise_enc_algorithm) { + case WEP40_ENCRYPTION: + ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_WEP40]; + break; + case WEP104_ENCRYPTION: + ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_WEP104]; + break; + case TKIP_ENCRYPTION: + ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_TKIP]; + break; + case AESCCMP_ENCRYPTION: + ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_AES]; + break; + default: + ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_AES]; + } + + for (entry_i = 0; entry_i < CAM_CONTENT_COUNT; entry_i++) { + if (entry_i == 0) { + ul_content = + (uc_index & 0x03) | ((u16)(ul_encalgo) << 2); + ul_content |= BIT(15); + } else { + ul_content = 0; + } + + ul_command = CAM_CONTENT_COUNT * uc_index + entry_i; + ul_command = ul_command | BIT(31) | BIT(16); + + rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI], ul_content); + rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], ul_command); + + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, + "%s(): WRITE A4: %x\n", __func__, ul_content); + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, + "%s(): WRITE A0: %x\n", __func__, ul_command); + } +} + +u8 rtl_cam_get_free_entry(struct ieee80211_hw *hw, u8 *sta_addr) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 bitmap = (rtlpriv->sec.hwsec_cam_bitmap) >> 4; + u8 entry_idx = 0; + u8 i, *addr; + + if (!sta_addr) { + pr_err("sta_addr is NULL.\n"); + return TOTAL_CAM_ENTRY; + } + /* Does STA already exist? */ + for (i = 4; i < TOTAL_CAM_ENTRY; i++) { + addr = rtlpriv->sec.hwsec_cam_sta_addr[i]; + if (ether_addr_equal_unaligned(addr, sta_addr)) + return i; + } + /* Get a free CAM entry. */ + for (entry_idx = 4; entry_idx < TOTAL_CAM_ENTRY; entry_idx++) { + if ((bitmap & BIT(0)) == 0) { + pr_err("-----hwsec_cam_bitmap: 0x%x entry_idx=%d\n", + rtlpriv->sec.hwsec_cam_bitmap, entry_idx); + rtlpriv->sec.hwsec_cam_bitmap |= BIT(0) << entry_idx; + memcpy(rtlpriv->sec.hwsec_cam_sta_addr[entry_idx], + sta_addr, ETH_ALEN); + return entry_idx; + } + bitmap = bitmap >> 1; + } + return TOTAL_CAM_ENTRY; +} + +void rtl_cam_del_entry(struct ieee80211_hw *hw, u8 *sta_addr) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 bitmap; + u8 i, *addr; + + if (!sta_addr) { + pr_err("sta_addr is NULL.\n"); + return; + } + + if (is_zero_ether_addr(sta_addr)) { + pr_err("sta_addr is %pM\n", sta_addr); + return; + } + /* Does STA already exist? */ + for (i = 4; i < TOTAL_CAM_ENTRY; i++) { + addr = rtlpriv->sec.hwsec_cam_sta_addr[i]; + bitmap = (rtlpriv->sec.hwsec_cam_bitmap) >> i; + if (((bitmap & BIT(0)) == BIT(0)) && + (ether_addr_equal_unaligned(addr, sta_addr))) { + /* Remove from HW Security CAM */ + eth_zero_addr(rtlpriv->sec.hwsec_cam_sta_addr[i]); + rtlpriv->sec.hwsec_cam_bitmap &= ~(BIT(0) << i); + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + "&&&&&&&&&del entry %d\n", i); + } + } +} diff --git a/drivers/staging/rtlwifi/cam.h b/drivers/staging/rtlwifi/cam.h new file mode 100644 index 000000000000..b25729e15b75 --- /dev/null +++ b/drivers/staging/rtlwifi/cam.h @@ -0,0 +1,50 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL_CAM_H_ +#define __RTL_CAM_H_ + +#define CAM_CONTENT_COUNT 8 + +#define CFG_VALID BIT(15) + +#define PAIRWISE_KEYIDX 0 +#define CAM_PAIRWISE_KEY_POSITION 4 + +#define CAM_CONFIG_NO_USEDK 0 + +void rtl_cam_reset_all_entry(struct ieee80211_hw *hw); +u8 rtl_cam_add_one_entry(struct ieee80211_hw *hw, u8 *mac_addr, + u32 ul_key_id, u32 ul_entry_idx, u32 ul_enc_alg, + u32 ul_default_key, u8 *key_content); +int rtl_cam_delete_one_entry(struct ieee80211_hw *hw, u8 *mac_addr, + u32 ul_key_id); +void rtl_cam_mark_invalid(struct ieee80211_hw *hw, u8 uc_index); +void rtl_cam_empty_entry(struct ieee80211_hw *hw, u8 uc_index); +void rtl_cam_reset_sec_info(struct ieee80211_hw *hw); +u8 rtl_cam_get_free_entry(struct ieee80211_hw *hw, u8 *sta_addr); +void rtl_cam_del_entry(struct ieee80211_hw *hw, u8 *sta_addr); + +#endif diff --git a/drivers/staging/rtlwifi/core.c b/drivers/staging/rtlwifi/core.c new file mode 100644 index 000000000000..d33847d0550d --- /dev/null +++ b/drivers/staging/rtlwifi/core.c @@ -0,0 +1,2046 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include "wifi.h" +#include "core.h" +#include "cam.h" +#include "base.h" +#include "ps.h" +#include "pwrseqcmd.h" + +#include "btcoexist/rtl_btc.h" +#include <linux/firmware.h> +#include <linux/export.h> +#include <net/cfg80211.h> + +u8 channel5g[CHANNEL_MAX_NUMBER_5G] = { + 36, 38, 40, 42, 44, 46, 48, /* Band 1 */ + 52, 54, 56, 58, 60, 62, 64, /* Band 2 */ + 100, 102, 104, 106, 108, 110, 112, /* Band 3 */ + 116, 118, 120, 122, 124, 126, 128, /* Band 3 */ + 132, 134, 136, 138, 140, 142, 144, /* Band 3 */ + 149, 151, 153, 155, 157, 159, 161, /* Band 4 */ + 165, 167, 169, 171, 173, 175, 177 /* Band 4 */ +}; + +u8 channel5g_80m[CHANNEL_MAX_NUMBER_5G_80M] = { + 42, 58, 106, 122, 138, 155, 171 +}; + +void rtl_addr_delay(u32 addr) +{ + if (addr == 0xfe) + mdelay(50); + else if (addr == 0xfd) + msleep(5); + else if (addr == 0xfc) + msleep(1); + else if (addr == 0xfb) + usleep_range(50, 100); + else if (addr == 0xfa) + usleep_range(5, 10); + else if (addr == 0xf9) + usleep_range(1, 2); +} + +void rtl_rfreg_delay(struct ieee80211_hw *hw, enum radio_path rfpath, u32 addr, + u32 mask, u32 data) +{ + if (addr >= 0xf9 && addr <= 0xfe) { + rtl_addr_delay(addr); + } else { + rtl_set_rfreg(hw, rfpath, addr, mask, data); + udelay(1); + } +} + +void rtl_bb_delay(struct ieee80211_hw *hw, u32 addr, u32 data) +{ + if (addr >= 0xf9 && addr <= 0xfe) { + rtl_addr_delay(addr); + } else { + rtl_set_bbreg(hw, addr, MASKDWORD, data); + udelay(1); + } +} + +static void rtl_fw_do_work(const struct firmware *firmware, void *context, + bool is_wow) +{ + struct ieee80211_hw *hw = context; + struct rtl_priv *rtlpriv = rtl_priv(hw); + int err; + + RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD, + "Firmware callback routine entered!\n"); + complete(&rtlpriv->firmware_loading_complete); + if (!firmware) { + if (rtlpriv->cfg->alt_fw_name) { + err = request_firmware(&firmware, + rtlpriv->cfg->alt_fw_name, + rtlpriv->io.dev); + pr_info("Loading alternative firmware %s\n", + rtlpriv->cfg->alt_fw_name); + if (!err) + goto found_alt; + } + pr_err("Selected firmware is not available\n"); + rtlpriv->max_fw_size = 0; + return; + } +found_alt: + if (firmware->size > rtlpriv->max_fw_size) { + pr_err("Firmware is too big!\n"); + release_firmware(firmware); + return; + } + if (!is_wow) { + memcpy(rtlpriv->rtlhal.pfirmware, firmware->data, + firmware->size); + rtlpriv->rtlhal.fwsize = firmware->size; + } else { + memcpy(rtlpriv->rtlhal.wowlan_firmware, firmware->data, + firmware->size); + rtlpriv->rtlhal.wowlan_fwsize = firmware->size; + } + rtlpriv->rtlhal.fwsize = firmware->size; + release_firmware(firmware); +} + +void rtl_fw_cb(const struct firmware *firmware, void *context) +{ + rtl_fw_do_work(firmware, context, false); +} + +void rtl_wowlan_fw_cb(const struct firmware *firmware, void *context) +{ + rtl_fw_do_work(firmware, context, true); +} + +/*mutex for start & stop is must here. */ +static int rtl_op_start(struct ieee80211_hw *hw) +{ + int err = 0; + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + + if (!is_hal_stop(rtlhal)) + return 0; + if (!test_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status)) + return 0; + mutex_lock(&rtlpriv->locks.conf_mutex); + err = rtlpriv->intf_ops->adapter_start(hw); + if (!err) + rtl_watch_dog_timer_callback((unsigned long)hw); + mutex_unlock(&rtlpriv->locks.conf_mutex); + return err; +} + +static void rtl_op_stop(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + bool support_remote_wakeup = false; + + if (is_hal_stop(rtlhal)) + return; + + rtlpriv->cfg->ops->get_hw_reg(hw, HAL_DEF_WOWLAN, + (u8 *)(&support_remote_wakeup)); + /* here is must, because adhoc do stop and start, + * but stop with RFOFF may cause something wrong, + * like adhoc TP + */ + if (unlikely(ppsc->rfpwr_state == ERFOFF)) + rtl_ips_nic_on(hw); + + mutex_lock(&rtlpriv->locks.conf_mutex); + /* if wowlan supported, DON'T clear connected info */ + if (!(support_remote_wakeup && + rtlhal->enter_pnp_sleep)) { + mac->link_state = MAC80211_NOLINK; + eth_zero_addr(mac->bssid); + mac->vendor = PEER_UNKNOWN; + + /* reset sec info */ + rtl_cam_reset_sec_info(hw); + + rtl_deinit_deferred_work(hw); + } + rtlpriv->intf_ops->adapter_stop(hw); + + mutex_unlock(&rtlpriv->locks.conf_mutex); +} + +static void rtl_op_tx(struct ieee80211_hw *hw, + struct ieee80211_tx_control *control, + struct sk_buff *skb) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_tcb_desc tcb_desc; + + memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc)); + + if (unlikely(is_hal_stop(rtlhal) || ppsc->rfpwr_state != ERFON)) + goto err_free; + + if (!test_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status)) + goto err_free; + + if (!rtlpriv->intf_ops->waitq_insert(hw, control->sta, skb)) + rtlpriv->intf_ops->adapter_tx(hw, control->sta, skb, &tcb_desc); + return; + +err_free: + dev_kfree_skb_any(skb); +} + +static int rtl_op_add_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + int err = 0; + u8 retry_limit = 0x30; + + if (mac->vif) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "vif has been set!! mac->vif = 0x%p\n", mac->vif); + return -EOPNOTSUPP; + } + + vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; + + rtl_ips_nic_on(hw); + + mutex_lock(&rtlpriv->locks.conf_mutex); + switch (ieee80211_vif_type_p2p(vif)) { + case NL80211_IFTYPE_P2P_CLIENT: + mac->p2p = P2P_ROLE_CLIENT; + /*fall through*/ + case NL80211_IFTYPE_STATION: + if (mac->beacon_enabled == 1) { + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, + "NL80211_IFTYPE_STATION\n"); + mac->beacon_enabled = 0; + rtlpriv->cfg->ops->update_interrupt_mask(hw, 0, + rtlpriv->cfg->maps[RTL_IBSS_INT_MASKS]); + } + break; + case NL80211_IFTYPE_ADHOC: + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, + "NL80211_IFTYPE_ADHOC\n"); + + mac->link_state = MAC80211_LINKED; + rtlpriv->cfg->ops->set_bcn_reg(hw); + if (rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G) + mac->basic_rates = 0xfff; + else + mac->basic_rates = 0xff0; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE, + (u8 *)(&mac->basic_rates)); + + retry_limit = 0x07; + break; + case NL80211_IFTYPE_P2P_GO: + mac->p2p = P2P_ROLE_GO; + /*fall through*/ + case NL80211_IFTYPE_AP: + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, + "NL80211_IFTYPE_AP\n"); + + mac->link_state = MAC80211_LINKED; + rtlpriv->cfg->ops->set_bcn_reg(hw); + if (rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G) + mac->basic_rates = 0xfff; + else + mac->basic_rates = 0xff0; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE, + (u8 *)(&mac->basic_rates)); + + retry_limit = 0x07; + break; + case NL80211_IFTYPE_MESH_POINT: + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, + "NL80211_IFTYPE_MESH_POINT\n"); + + mac->link_state = MAC80211_LINKED; + rtlpriv->cfg->ops->set_bcn_reg(hw); + if (rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G) + mac->basic_rates = 0xfff; + else + mac->basic_rates = 0xff0; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE, + (u8 *)(&mac->basic_rates)); + + retry_limit = 0x07; + break; + default: + pr_err("operation mode %d is not supported!\n", + vif->type); + err = -EOPNOTSUPP; + goto out; + } + + if (mac->p2p) { + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, + "p2p role %x\n", vif->type); + mac->basic_rates = 0xff0;/*disable cck rate for p2p*/ + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE, + (u8 *)(&mac->basic_rates)); + } + mac->vif = vif; + mac->opmode = vif->type; + rtlpriv->cfg->ops->set_network_type(hw, vif->type); + memcpy(mac->mac_addr, vif->addr, ETH_ALEN); + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ETHER_ADDR, mac->mac_addr); + + mac->retry_long = retry_limit; + mac->retry_short = retry_limit; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RETRY_LIMIT, + (u8 *)(&retry_limit)); +out: + mutex_unlock(&rtlpriv->locks.conf_mutex); + return err; +} + +static void rtl_op_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + + mutex_lock(&rtlpriv->locks.conf_mutex); + + /* Free beacon resources */ + if ((vif->type == NL80211_IFTYPE_AP) || + (vif->type == NL80211_IFTYPE_ADHOC) || + (vif->type == NL80211_IFTYPE_MESH_POINT)) { + if (mac->beacon_enabled == 1) { + mac->beacon_enabled = 0; + rtlpriv->cfg->ops->update_interrupt_mask(hw, 0, + rtlpriv->cfg->maps[RTL_IBSS_INT_MASKS]); + } + } + + /* + *Note: We assume NL80211_IFTYPE_UNSPECIFIED as + *NO LINK for our hardware. + */ + mac->p2p = 0; + mac->vif = NULL; + mac->link_state = MAC80211_NOLINK; + eth_zero_addr(mac->bssid); + mac->vendor = PEER_UNKNOWN; + mac->opmode = NL80211_IFTYPE_UNSPECIFIED; + rtlpriv->cfg->ops->set_network_type(hw, mac->opmode); + + mutex_unlock(&rtlpriv->locks.conf_mutex); +} + +static int rtl_op_change_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + enum nl80211_iftype new_type, bool p2p) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + int ret; + + rtl_op_remove_interface(hw, vif); + + vif->type = new_type; + vif->p2p = p2p; + ret = rtl_op_add_interface(hw, vif); + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, + "p2p %x\n", p2p); + return ret; +} + +#ifdef CONFIG_PM +static u16 crc16_ccitt(u8 data, u16 crc) +{ + u8 shift_in, data_bit, crc_bit11, crc_bit4, crc_bit15; + u8 i; + u16 result; + + for (i = 0; i < 8; i++) { + crc_bit15 = ((crc & BIT(15)) ? 1 : 0); + data_bit = (data & (BIT(0) << i) ? 1 : 0); + shift_in = crc_bit15 ^ data_bit; + + result = crc << 1; + if (shift_in == 0) + result &= (~BIT(0)); + else + result |= BIT(0); + + crc_bit11 = ((crc & BIT(11)) ? 1 : 0) ^ shift_in; + if (crc_bit11 == 0) + result &= (~BIT(12)); + else + result |= BIT(12); + + crc_bit4 = ((crc & BIT(4)) ? 1 : 0) ^ shift_in; + if (crc_bit4 == 0) + result &= (~BIT(5)); + else + result |= BIT(5); + + crc = result; + } + + return crc; +} + +static u16 _calculate_wol_pattern_crc(u8 *pattern, u16 len) +{ + u16 crc = 0xffff; + u32 i; + + for (i = 0; i < len; i++) + crc = crc16_ccitt(pattern[i], crc); + + crc = ~crc; + + return crc; +} + +static void _rtl_add_wowlan_patterns(struct ieee80211_hw *hw, + struct cfg80211_wowlan *wow) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = &rtlpriv->mac80211; + struct cfg80211_pkt_pattern *patterns = wow->patterns; + struct rtl_wow_pattern rtl_pattern; + const u8 *pattern_os, *mask_os; + u8 mask[MAX_WOL_BIT_MASK_SIZE] = {0}; + u8 content[MAX_WOL_PATTERN_SIZE] = {0}; + u8 broadcast_addr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + u8 multicast_addr1[2] = {0x33, 0x33}; + u8 multicast_addr2[3] = {0x01, 0x00, 0x5e}; + u8 i, mask_len; + u16 j, len; + + for (i = 0; i < wow->n_patterns; i++) { + memset(&rtl_pattern, 0, sizeof(struct rtl_wow_pattern)); + memset(mask, 0, MAX_WOL_BIT_MASK_SIZE); + if (patterns[i].pattern_len > MAX_WOL_PATTERN_SIZE) { + RT_TRACE(rtlpriv, COMP_POWER, DBG_WARNING, + "Pattern[%d] is too long\n", i); + continue; + } + pattern_os = patterns[i].pattern; + mask_len = DIV_ROUND_UP(patterns[i].pattern_len, 8); + mask_os = patterns[i].mask; + RT_PRINT_DATA(rtlpriv, COMP_POWER, DBG_TRACE, + "pattern content\n", pattern_os, + patterns[i].pattern_len); + RT_PRINT_DATA(rtlpriv, COMP_POWER, DBG_TRACE, + "mask content\n", mask_os, mask_len); + /* 1. unicast? multicast? or broadcast? */ + if (memcmp(pattern_os, broadcast_addr, 6) == 0) + rtl_pattern.type = BROADCAST_PATTERN; + else if (memcmp(pattern_os, multicast_addr1, 2) == 0 || + memcmp(pattern_os, multicast_addr2, 3) == 0) + rtl_pattern.type = MULTICAST_PATTERN; + else if (memcmp(pattern_os, mac->mac_addr, 6) == 0) + rtl_pattern.type = UNICAST_PATTERN; + else + rtl_pattern.type = UNKNOWN_TYPE; + + /* 2. translate mask_from_os to mask_for_hw */ + +/****************************************************************************** + * pattern from OS uses 'ethenet frame', like this: + + | 6 | 6 | 2 | 20 | Variable | 4 | + |--------+--------+------+-----------+------------+-----| + | 802.3 Mac Header | IP Header | TCP Packet | FCS | + | DA | SA | Type | + + * BUT, packet catched by our HW is in '802.11 frame', begin from LLC, + + | 24 or 30 | 6 | 2 | 20 | Variable | 4 | + |-------------------+--------+------+-----------+------------+-----| + | 802.11 MAC Header | LLC | IP Header | TCP Packet | FCS | + | Others | Tpye | + + * Therefore, we need translate mask_from_OS to mask_to_hw. + * We should left-shift mask by 6 bits, then set the new bit[0~5] = 0, + * because new mask[0~5] means 'SA', but our HW packet begins from LLC, + * bit[0~5] corresponds to first 6 Bytes in LLC, they just don't match. + ******************************************************************************/ + + /* Shift 6 bits */ + for (j = 0; j < mask_len - 1; j++) { + mask[j] = mask_os[j] >> 6; + mask[j] |= (mask_os[j + 1] & 0x3F) << 2; + } + mask[j] = (mask_os[j] >> 6) & 0x3F; + /* Set bit 0-5 to zero */ + mask[0] &= 0xC0; + + RT_PRINT_DATA(rtlpriv, COMP_POWER, DBG_TRACE, + "mask to hw\n", mask, mask_len); + for (j = 0; j < (MAX_WOL_BIT_MASK_SIZE + 1) / 4; j++) { + rtl_pattern.mask[j] = mask[j * 4]; + rtl_pattern.mask[j] |= (mask[j * 4 + 1] << 8); + rtl_pattern.mask[j] |= (mask[j * 4 + 2] << 16); + rtl_pattern.mask[j] |= (mask[j * 4 + 3] << 24); + } + + /* To get the wake up pattern from the mask. + * We do not count first 12 bits which means + * DA[6] and SA[6] in the pattern to match HW design. + */ + len = 0; + for (j = 12; j < patterns[i].pattern_len; j++) { + if ((mask_os[j / 8] >> (j % 8)) & 0x01) { + content[len] = pattern_os[j]; + len++; + } + } + + RT_PRINT_DATA(rtlpriv, COMP_POWER, DBG_TRACE, + "pattern to hw\n", content, len); + /* 3. calculate crc */ + rtl_pattern.crc = _calculate_wol_pattern_crc(content, len); + RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE, + "CRC_Remainder = 0x%x\n", rtl_pattern.crc); + + /* 4. write crc & mask_for_hw to hw */ + rtlpriv->cfg->ops->add_wowlan_pattern(hw, &rtl_pattern, i); + } + rtl_write_byte(rtlpriv, 0x698, wow->n_patterns); +} + +static int rtl_op_suspend(struct ieee80211_hw *hw, + struct cfg80211_wowlan *wow) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct timeval ts; + + RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, "\n"); + if (WARN_ON(!wow)) + return -EINVAL; + + /* to resolve s4 can not wake up*/ + do_gettimeofday(&ts); + rtlhal->last_suspend_sec = ts.tv_sec; + + if ((ppsc->wo_wlan_mode & WAKE_ON_PATTERN_MATCH) && wow->n_patterns) + _rtl_add_wowlan_patterns(hw, wow); + + rtlhal->driver_is_goingto_unload = true; + rtlhal->enter_pnp_sleep = true; + + rtl_lps_leave(hw); + rtl_op_stop(hw); + device_set_wakeup_enable(wiphy_dev(hw->wiphy), true); + return 0; +} + +static int rtl_op_resume(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct timeval ts; + + RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, "\n"); + rtlhal->driver_is_goingto_unload = false; + rtlhal->enter_pnp_sleep = false; + rtlhal->wake_from_pnp_sleep = true; + + /* to resovle s4 can not wake up*/ + do_gettimeofday(&ts); + if (ts.tv_sec - rtlhal->last_suspend_sec < 5) + return -1; + + rtl_op_start(hw); + device_set_wakeup_enable(wiphy_dev(hw->wiphy), false); + ieee80211_resume_disconnect(mac->vif); + rtlhal->wake_from_pnp_sleep = false; + return 0; +} +#endif + +static int rtl_op_config(struct ieee80211_hw *hw, u32 changed) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &rtlpriv->phy; + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct ieee80211_conf *conf = &hw->conf; + + if (mac->skip_scan) + return 1; + + mutex_lock(&rtlpriv->locks.conf_mutex); + if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) { /* BIT(2)*/ + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, + "IEEE80211_CONF_CHANGE_LISTEN_INTERVAL\n"); + } + + /*For IPS */ + if (changed & IEEE80211_CONF_CHANGE_IDLE) { + if (hw->conf.flags & IEEE80211_CONF_IDLE) + rtl_ips_nic_off(hw); + else + rtl_ips_nic_on(hw); + } else { + /* + *although rfoff may not cause by ips, but we will + *check the reason in set_rf_power_state function + */ + if (unlikely(ppsc->rfpwr_state == ERFOFF)) + rtl_ips_nic_on(hw); + } + + /*For LPS */ + if ((changed & IEEE80211_CONF_CHANGE_PS) && + rtlpriv->psc.swctrl_lps && !rtlpriv->psc.fwctrl_lps) { + cancel_delayed_work(&rtlpriv->works.ps_work); + cancel_delayed_work(&rtlpriv->works.ps_rfon_wq); + if (conf->flags & IEEE80211_CONF_PS) { + rtlpriv->psc.sw_ps_enabled = true; + /* sleep here is must, or we may recv the beacon and + * cause mac80211 into wrong ps state, this will cause + * power save nullfunc send fail, and further cause + * pkt loss, So sleep must quickly but not immediately + * because that will cause nullfunc send by mac80211 + * fail, and cause pkt loss, we have tested that 5mA + * works very well + */ + if (!rtlpriv->psc.multi_buffered) + queue_delayed_work(rtlpriv->works.rtl_wq, + &rtlpriv->works.ps_work, + MSECS(5)); + } else { + rtl_swlps_rf_awake(hw); + rtlpriv->psc.sw_ps_enabled = false; + } + } + + if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) { + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, + "IEEE80211_CONF_CHANGE_RETRY_LIMITS %x\n", + hw->conf.long_frame_max_tx_count); + /* brought up everything changes (changed == ~0) indicates first + * open, so use our default value instead of that of wiphy. + */ + if (changed != ~0) { + mac->retry_long = hw->conf.long_frame_max_tx_count; + mac->retry_short = hw->conf.long_frame_max_tx_count; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RETRY_LIMIT, + (u8 *)(&hw->conf.long_frame_max_tx_count)); + } + } + + if (changed & IEEE80211_CONF_CHANGE_CHANNEL && + !rtlpriv->proximity.proxim_on) { + struct ieee80211_channel *channel = hw->conf.chandef.chan; + enum nl80211_chan_width width = hw->conf.chandef.width; + enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; + u8 wide_chan = (u8)channel->hw_value; + + /* channel_type is for 20&40M */ + if (width < NL80211_CHAN_WIDTH_80) + channel_type = + cfg80211_get_chandef_type(&hw->conf.chandef); + if (mac->act_scanning) + mac->n_channels++; + + if (rtlpriv->dm.supp_phymode_switch && + mac->link_state < MAC80211_LINKED && + !mac->act_scanning) { + if (rtlpriv->cfg->ops->chk_switch_dmdp) + rtlpriv->cfg->ops->chk_switch_dmdp(hw); + } + + /* + *because we should back channel to + *current_network.chan in in scanning, + *So if set_chan == current_network.chan + *we should set it. + *because mac80211 tell us wrong bw40 + *info for cisco1253 bw20, so we modify + *it here based on UPPER & LOWER + */ + + if (width >= NL80211_CHAN_WIDTH_80) { + if (width == NL80211_CHAN_WIDTH_80) { + u32 center = hw->conf.chandef.center_freq1; + u32 primary = + (u32)hw->conf.chandef.chan->center_freq; + + rtlphy->current_chan_bw = + HT_CHANNEL_WIDTH_80; + mac->bw_80 = true; + mac->bw_40 = true; + if (center > primary) { + mac->cur_80_prime_sc = + PRIME_CHNL_OFFSET_LOWER; + if (center - primary == 10) { + mac->cur_40_prime_sc = + PRIME_CHNL_OFFSET_UPPER; + + wide_chan += 2; + } else if (center - primary == 30) { + mac->cur_40_prime_sc = + PRIME_CHNL_OFFSET_LOWER; + + wide_chan += 6; + } + } else { + mac->cur_80_prime_sc = + PRIME_CHNL_OFFSET_UPPER; + if (primary - center == 10) { + mac->cur_40_prime_sc = + PRIME_CHNL_OFFSET_LOWER; + + wide_chan -= 2; + } else if (primary - center == 30) { + mac->cur_40_prime_sc = + PRIME_CHNL_OFFSET_UPPER; + + wide_chan -= 6; + } + } + } + } else { + switch (channel_type) { + case NL80211_CHAN_HT20: + case NL80211_CHAN_NO_HT: + /* SC */ + mac->cur_40_prime_sc = + PRIME_CHNL_OFFSET_DONT_CARE; + rtlphy->current_chan_bw = + HT_CHANNEL_WIDTH_20; + mac->bw_40 = false; + mac->bw_80 = false; + break; + case NL80211_CHAN_HT40MINUS: + /* SC */ + mac->cur_40_prime_sc = + PRIME_CHNL_OFFSET_UPPER; + rtlphy->current_chan_bw = + HT_CHANNEL_WIDTH_20_40; + mac->bw_40 = true; + mac->bw_80 = false; + + /*wide channel */ + wide_chan -= 2; + + break; + case NL80211_CHAN_HT40PLUS: + /* SC */ + mac->cur_40_prime_sc = + PRIME_CHNL_OFFSET_LOWER; + rtlphy->current_chan_bw = + HT_CHANNEL_WIDTH_20_40; + mac->bw_40 = true; + mac->bw_80 = false; + + /*wide channel */ + wide_chan += 2; + + break; + default: + mac->bw_40 = false; + mac->bw_80 = false; + pr_err("switch case %#x not processed\n", + channel_type); + break; + } + } + + if (wide_chan <= 0) + wide_chan = 1; + + /* In scanning, when before we offchannel we may send a ps=1 + * null to AP, and then we may send a ps = 0 null to AP quickly, + * but first null may have caused AP to put lots of packet to + * hw tx buffer. These packets must be tx'd before we go off + * channel so we must delay more time to let AP flush these + * packets before going offchannel, or dis-association or + * delete BA will be caused by AP + */ + if (rtlpriv->mac80211.offchan_delay) { + rtlpriv->mac80211.offchan_delay = false; + mdelay(50); + } + + rtlphy->current_channel = wide_chan; + + rtlpriv->cfg->ops->switch_channel(hw); + rtlpriv->cfg->ops->set_channel_access(hw); + rtlpriv->cfg->ops->set_bw_mode(hw, channel_type); + } + + mutex_unlock(&rtlpriv->locks.conf_mutex); + + return 0; +} + +static void rtl_op_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *new_flags, u64 multicast) +{ + bool update_rcr = false; + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + + *new_flags &= RTL_SUPPORTED_FILTERS; + if (changed_flags == 0) + return; + + /*TODO: we disable broadcase now, so enable here */ + if (changed_flags & FIF_ALLMULTI) { + if (*new_flags & FIF_ALLMULTI) { + mac->rx_conf |= rtlpriv->cfg->maps[MAC_RCR_AM] | + rtlpriv->cfg->maps[MAC_RCR_AB]; + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, + "Enable receive multicast frame\n"); + } else { + mac->rx_conf &= ~(rtlpriv->cfg->maps[MAC_RCR_AM] | + rtlpriv->cfg->maps[MAC_RCR_AB]); + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, + "Disable receive multicast frame\n"); + } + update_rcr = true; + } + + if (changed_flags & FIF_FCSFAIL) { + if (*new_flags & FIF_FCSFAIL) { + mac->rx_conf |= rtlpriv->cfg->maps[MAC_RCR_ACRC32]; + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, + "Enable receive FCS error frame\n"); + } else { + mac->rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_ACRC32]; + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, + "Disable receive FCS error frame\n"); + } + if (!update_rcr) + update_rcr = true; + } + + /* if ssid not set to hw don't check bssid + * here just used for linked scanning, & linked + * and nolink check bssid is set in set network_type + */ + if ((changed_flags & FIF_BCN_PRBRESP_PROMISC) && + (mac->link_state >= MAC80211_LINKED)) { + if (mac->opmode != NL80211_IFTYPE_AP && + mac->opmode != NL80211_IFTYPE_MESH_POINT) { + if (*new_flags & FIF_BCN_PRBRESP_PROMISC) + rtlpriv->cfg->ops->set_chk_bssid(hw, false); + else + rtlpriv->cfg->ops->set_chk_bssid(hw, true); + if (update_rcr) + update_rcr = false; + } + } + + if (changed_flags & FIF_CONTROL) { + if (*new_flags & FIF_CONTROL) { + mac->rx_conf |= rtlpriv->cfg->maps[MAC_RCR_ACF]; + + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, + "Enable receive control frame.\n"); + } else { + mac->rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_ACF]; + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, + "Disable receive control frame.\n"); + } + if (!update_rcr) + update_rcr = true; + } + + if (changed_flags & FIF_OTHER_BSS) { + if (*new_flags & FIF_OTHER_BSS) { + mac->rx_conf |= rtlpriv->cfg->maps[MAC_RCR_AAP]; + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, + "Enable receive other BSS's frame.\n"); + } else { + mac->rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_AAP]; + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, + "Disable receive other BSS's frame.\n"); + } + if (!update_rcr) + update_rcr = true; + } + + if (update_rcr) + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, + (u8 *)(&mac->rx_conf)); +} + +static int rtl_op_sta_add(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &rtlpriv->phy; + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_sta_info *sta_entry; + + if (sta) { + sta_entry = (struct rtl_sta_info *)sta->drv_priv; + spin_lock_bh(&rtlpriv->locks.entry_list_lock); + list_add_tail(&sta_entry->list, &rtlpriv->entry_list); + spin_unlock_bh(&rtlpriv->locks.entry_list_lock); + if (rtlhal->current_bandtype == BAND_ON_2_4G) { + sta_entry->wireless_mode = WIRELESS_MODE_G; + if (sta->supp_rates[0] <= 0xf) + sta_entry->wireless_mode = WIRELESS_MODE_B; + if (sta->ht_cap.ht_supported) + sta_entry->wireless_mode = WIRELESS_MODE_N_24G; + + if (vif->type == NL80211_IFTYPE_ADHOC) + sta_entry->wireless_mode = WIRELESS_MODE_G; + } else if (rtlhal->current_bandtype == BAND_ON_5G) { + sta_entry->wireless_mode = WIRELESS_MODE_A; + if (sta->ht_cap.ht_supported) + sta_entry->wireless_mode = WIRELESS_MODE_N_5G; + if (sta->vht_cap.vht_supported) + sta_entry->wireless_mode = WIRELESS_MODE_AC_5G; + + if (vif->type == NL80211_IFTYPE_ADHOC) + sta_entry->wireless_mode = WIRELESS_MODE_A; + } + /*disable cck rate for p2p*/ + if (mac->p2p) + sta->supp_rates[0] &= 0xfffffff0; + + if (sta->ht_cap.ht_supported) { + if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) + rtlphy->max_ht_chan_bw = HT_CHANNEL_WIDTH_20_40; + else + rtlphy->max_ht_chan_bw = HT_CHANNEL_WIDTH_20; + } + + if (sta->vht_cap.vht_supported) + rtlphy->max_vht_chan_bw = HT_CHANNEL_WIDTH_80; + + memcpy(sta_entry->mac_addr, sta->addr, ETH_ALEN); + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG, + "Add sta addr is %pM\n", sta->addr); + rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0, true); + + if (rtlpriv->phydm.ops) + rtlpriv->phydm.ops->phydm_add_sta(rtlpriv, sta); + } + + return 0; +} + +static int rtl_op_sta_remove(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_sta_info *sta_entry; + + if (sta) { + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG, + "Remove sta addr is %pM\n", sta->addr); + + if (rtlpriv->phydm.ops) + rtlpriv->phydm.ops->phydm_del_sta(rtlpriv, sta); + + sta_entry = (struct rtl_sta_info *)sta->drv_priv; + sta_entry->wireless_mode = 0; + sta_entry->ratr_index = 0; + spin_lock_bh(&rtlpriv->locks.entry_list_lock); + list_del(&sta_entry->list); + spin_unlock_bh(&rtlpriv->locks.entry_list_lock); + } + return 0; +} + +static int _rtl_get_hal_qnum(u16 queue) +{ + int qnum; + + switch (queue) { + case 0: + qnum = AC3_VO; + break; + case 1: + qnum = AC2_VI; + break; + case 2: + qnum = AC0_BE; + break; + case 3: + qnum = AC1_BK; + break; + default: + qnum = AC0_BE; + break; + } + return qnum; +} + +static void rtl_op_sta_statistics(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct station_info *sinfo) +{ + /* nothing filled by driver, so mac80211 will update all info */ + sinfo->filled = 0; +} + +static int rtl_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value) +{ + return -EOPNOTSUPP; +} + +/* + *for mac80211 VO = 0, VI = 1, BE = 2, BK = 3 + *for rtl819x BE = 0, BK = 1, VI = 2, VO = 3 + */ +static int rtl_op_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, + const struct ieee80211_tx_queue_params *param) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + int aci; + + if (queue >= AC_MAX) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "queue number %d is incorrect!\n", queue); + return -EINVAL; + } + + aci = _rtl_get_hal_qnum(queue); + mac->ac[aci].aifs = param->aifs; + mac->ac[aci].cw_min = cpu_to_le16(param->cw_min); + mac->ac[aci].cw_max = cpu_to_le16(param->cw_max); + mac->ac[aci].tx_op = cpu_to_le16(param->txop); + memcpy(&mac->edca_param[aci], param, sizeof(*param)); + rtlpriv->cfg->ops->set_qos(hw, aci); + return 0; +} + +static void send_beacon_frame(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct sk_buff *skb = ieee80211_beacon_get(hw, vif); + struct rtl_tcb_desc tcb_desc; + + if (skb) { + memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc)); + rtlpriv->intf_ops->adapter_tx(hw, NULL, skb, &tcb_desc); + } +} + +static void rtl_op_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, + u32 changed) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &rtlpriv->phy; + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + + mutex_lock(&rtlpriv->locks.conf_mutex); + if ((vif->type == NL80211_IFTYPE_ADHOC) || + (vif->type == NL80211_IFTYPE_AP) || + (vif->type == NL80211_IFTYPE_MESH_POINT)) { + if ((changed & BSS_CHANGED_BEACON) || + (changed & BSS_CHANGED_BEACON_ENABLED && + bss_conf->enable_beacon)) { + if (mac->beacon_enabled == 0) { + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG, + "BSS_CHANGED_BEACON_ENABLED\n"); + + /*start hw beacon interrupt. */ + /*rtlpriv->cfg->ops->set_bcn_reg(hw); */ + mac->beacon_enabled = 1; + rtlpriv->cfg->ops->update_interrupt_mask(hw, + rtlpriv->cfg->maps + [RTL_IBSS_INT_MASKS], 0); + + if (rtlpriv->cfg->ops->linked_set_reg) + rtlpriv->cfg->ops->linked_set_reg(hw); + send_beacon_frame(hw, vif); + } + } + if ((changed & BSS_CHANGED_BEACON_ENABLED && + !bss_conf->enable_beacon)) { + if (mac->beacon_enabled == 1) { + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG, + "ADHOC DISABLE BEACON\n"); + + mac->beacon_enabled = 0; + rtlpriv->cfg->ops->update_interrupt_mask(hw, 0, + rtlpriv->cfg->maps + [RTL_IBSS_INT_MASKS]); + } + } + if (changed & BSS_CHANGED_BEACON_INT) { + RT_TRACE(rtlpriv, COMP_BEACON, DBG_TRACE, + "BSS_CHANGED_BEACON_INT\n"); + mac->beacon_interval = bss_conf->beacon_int; + rtlpriv->cfg->ops->set_bcn_intv(hw); + } + } + + /*TODO: reference to enum ieee80211_bss_change */ + if (changed & BSS_CHANGED_ASSOC) { + u8 mstatus; + + if (bss_conf->assoc) { + struct ieee80211_sta *sta = NULL; + u8 keep_alive = 10; + + mstatus = RT_MEDIA_CONNECT; + /* we should reset all sec info & cam + * before set cam after linked, we should not + * reset in disassoc, that will cause tkip->wep + * fail because some flag will be wrong + * reset sec info + */ + rtl_cam_reset_sec_info(hw); + /* reset cam to fix wep fail issue + * when change from wpa to wep + */ + rtl_cam_reset_all_entry(hw); + + mac->link_state = MAC80211_LINKED; + mac->cnt_after_linked = 0; + mac->assoc_id = bss_conf->aid; + memcpy(mac->bssid, bss_conf->bssid, ETH_ALEN); + + if (rtlpriv->cfg->ops->linked_set_reg) + rtlpriv->cfg->ops->linked_set_reg(hw); + + rcu_read_lock(); + sta = ieee80211_find_sta(vif, (u8 *)bss_conf->bssid); + if (!sta) { + rcu_read_unlock(); + goto out; + } + RT_TRACE(rtlpriv, COMP_EASY_CONCURRENT, DBG_LOUD, + "send PS STATIC frame\n"); + if (rtlpriv->dm.supp_phymode_switch) { + if (sta->ht_cap.ht_supported) + rtl_send_smps_action(hw, sta, + IEEE80211_SMPS_STATIC); + } + + if (rtlhal->current_bandtype == BAND_ON_5G) { + mac->mode = WIRELESS_MODE_A; + } else { + if (sta->supp_rates[0] <= 0xf) + mac->mode = WIRELESS_MODE_B; + else + mac->mode = WIRELESS_MODE_G; + } + + if (sta->ht_cap.ht_supported) { + if (rtlhal->current_bandtype == BAND_ON_2_4G) + mac->mode = WIRELESS_MODE_N_24G; + else + mac->mode = WIRELESS_MODE_N_5G; + } + + if (sta->vht_cap.vht_supported) { + if (rtlhal->current_bandtype == BAND_ON_5G) + mac->mode = WIRELESS_MODE_AC_5G; + else + mac->mode = WIRELESS_MODE_AC_24G; + } + + if (vif->type == NL80211_IFTYPE_STATION) + rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0, + true); + rcu_read_unlock(); + + /* to avoid AP Disassociation caused by inactivity */ + rtlpriv->cfg->ops->set_hw_reg(hw, + HW_VAR_KEEP_ALIVE, + (u8 *)(&keep_alive)); + + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG, + "BSS_CHANGED_ASSOC\n"); + } else { + struct cfg80211_bss *bss = NULL; + + mstatus = RT_MEDIA_DISCONNECT; + + if (mac->link_state == MAC80211_LINKED) + rtl_lps_leave(hw); + if (ppsc->p2p_ps_info.p2p_ps_mode > P2P_PS_NONE) + rtl_p2p_ps_cmd(hw, P2P_PS_DISABLE); + mac->link_state = MAC80211_NOLINK; + + bss = cfg80211_get_bss(hw->wiphy, NULL, + (u8 *)mac->bssid, NULL, 0, + IEEE80211_BSS_TYPE_ESS, + IEEE80211_PRIVACY_OFF); + + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG, + "bssid = %x-%x-%x-%x-%x-%x\n", + mac->bssid[0], mac->bssid[1], + mac->bssid[2], mac->bssid[3], + mac->bssid[4], mac->bssid[5]); + + if (bss) { + cfg80211_unlink_bss(hw->wiphy, bss); + cfg80211_put_bss(hw->wiphy, bss); + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG, + "cfg80211_unlink !!\n"); + } + + eth_zero_addr(mac->bssid); + mac->vendor = PEER_UNKNOWN; + mac->mode = 0; + + if (rtlpriv->dm.supp_phymode_switch) { + if (rtlpriv->cfg->ops->chk_switch_dmdp) + rtlpriv->cfg->ops->chk_switch_dmdp(hw); + } + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG, + "BSS_CHANGED_UN_ASSOC\n"); + } + rtlpriv->cfg->ops->set_network_type(hw, vif->type); + /* For FW LPS: + * To tell firmware we have connected or disconnected + */ + rtlpriv->cfg->ops->set_hw_reg(hw, + HW_VAR_H2C_FW_JOINBSSRPT, + (u8 *)(&mstatus)); + ppsc->report_linked = (mstatus == RT_MEDIA_CONNECT) ? + true : false; + + if (rtlpriv->cfg->ops->get_btc_status()) + rtlpriv->btcoexist.btc_ops->btc_mediastatus_notify( + rtlpriv, mstatus); + } + + if (changed & BSS_CHANGED_ERP_CTS_PROT) { + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE, + "BSS_CHANGED_ERP_CTS_PROT\n"); + mac->use_cts_protect = bss_conf->use_cts_prot; + } + + if (changed & BSS_CHANGED_ERP_PREAMBLE) { + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, + "BSS_CHANGED_ERP_PREAMBLE use short preamble:%x\n", + bss_conf->use_short_preamble); + + mac->short_preamble = bss_conf->use_short_preamble; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ACK_PREAMBLE, + (u8 *)(&mac->short_preamble)); + } + + if (changed & BSS_CHANGED_ERP_SLOT) { + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE, + "BSS_CHANGED_ERP_SLOT\n"); + + if (bss_conf->use_short_slot) + mac->slot_time = RTL_SLOT_TIME_9; + else + mac->slot_time = RTL_SLOT_TIME_20; + + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SLOT_TIME, + (u8 *)(&mac->slot_time)); + } + + if (changed & BSS_CHANGED_HT) { + struct ieee80211_sta *sta = NULL; + + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE, + "BSS_CHANGED_HT\n"); + + rcu_read_lock(); + sta = ieee80211_find_sta(vif, (u8 *)bss_conf->bssid); + if (sta) { + if (sta->ht_cap.ampdu_density > + mac->current_ampdu_density) + mac->current_ampdu_density = + sta->ht_cap.ampdu_density; + if (sta->ht_cap.ampdu_factor < + mac->current_ampdu_factor) + mac->current_ampdu_factor = + sta->ht_cap.ampdu_factor; + + if (sta->ht_cap.ht_supported) { + if (sta->ht_cap.cap & + IEEE80211_HT_CAP_SUP_WIDTH_20_40) + rtlphy->max_ht_chan_bw = + HT_CHANNEL_WIDTH_20_40; + else + rtlphy->max_ht_chan_bw = + HT_CHANNEL_WIDTH_20; + } + } + rcu_read_unlock(); + + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SHORTGI_DENSITY, + (u8 *)(&mac->max_mss_density)); + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AMPDU_FACTOR, + &mac->current_ampdu_factor); + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AMPDU_MIN_SPACE, + &mac->current_ampdu_density); + } + + if (changed & BSS_CHANGED_BANDWIDTH) { + struct ieee80211_sta *sta = NULL; + + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE, + "BSS_CHANGED_BANDWIDTH\n"); + + rcu_read_lock(); + sta = ieee80211_find_sta(vif, (u8 *)bss_conf->bssid); + + if (sta) { + if (sta->ht_cap.ht_supported) { + if (sta->ht_cap.cap & + IEEE80211_HT_CAP_SUP_WIDTH_20_40) + rtlphy->max_ht_chan_bw = + HT_CHANNEL_WIDTH_20_40; + else + rtlphy->max_ht_chan_bw = + HT_CHANNEL_WIDTH_20; + } + + if (sta->vht_cap.vht_supported) + rtlphy->max_vht_chan_bw = HT_CHANNEL_WIDTH_80; + } + rcu_read_unlock(); + } + + if (changed & BSS_CHANGED_BSSID) { + u32 basic_rates; + struct ieee80211_sta *sta = NULL; + + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BSSID, + (u8 *)bss_conf->bssid); + + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG, + "bssid: %pM\n", bss_conf->bssid); + + mac->vendor = PEER_UNKNOWN; + memcpy(mac->bssid, bss_conf->bssid, ETH_ALEN); + + rcu_read_lock(); + sta = ieee80211_find_sta(vif, (u8 *)bss_conf->bssid); + if (!sta) { + rcu_read_unlock(); + goto out; + } + + if (rtlhal->current_bandtype == BAND_ON_5G) { + mac->mode = WIRELESS_MODE_A; + } else { + if (sta->supp_rates[0] <= 0xf) + mac->mode = WIRELESS_MODE_B; + else + mac->mode = WIRELESS_MODE_G; + } + + if (sta->ht_cap.ht_supported) { + if (rtlhal->current_bandtype == BAND_ON_2_4G) + mac->mode = WIRELESS_MODE_N_24G; + else + mac->mode = WIRELESS_MODE_N_5G; + } + + if (sta->vht_cap.vht_supported) { + if (rtlhal->current_bandtype == BAND_ON_5G) + mac->mode = WIRELESS_MODE_AC_5G; + else + mac->mode = WIRELESS_MODE_AC_24G; + } + + /* just station need it, because ibss & ap mode will + * set in sta_add, and will be NULL here + */ + if (vif->type == NL80211_IFTYPE_STATION) { + struct rtl_sta_info *sta_entry; + + sta_entry = (struct rtl_sta_info *)sta->drv_priv; + sta_entry->wireless_mode = mac->mode; + } + + if (sta->ht_cap.ht_supported) { + mac->ht_enable = true; + + /* for cisco 1252 bw20 it's wrong + * if (ht_cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) { + * mac->bw_40 = true; + * } + */ + } + + if (sta->vht_cap.vht_supported) + mac->vht_enable = true; + + if (changed & BSS_CHANGED_BASIC_RATES) { + /* for 5G must << RATE_6M_INDEX = 4, + * because 5G have no cck rate + */ + if (rtlhal->current_bandtype == BAND_ON_5G) + basic_rates = sta->supp_rates[1] << 4; + else + basic_rates = sta->supp_rates[0]; + + mac->basic_rates = basic_rates; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE, + (u8 *)(&basic_rates)); + } + rcu_read_unlock(); + } +out: + mutex_unlock(&rtlpriv->locks.conf_mutex); +} + +static u64 rtl_op_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u64 tsf; + + rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_CORRECT_TSF, (u8 *)(&tsf)); + return tsf; +} + +static void rtl_op_set_tsf(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u64 tsf) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + u8 bibss = (mac->opmode == NL80211_IFTYPE_ADHOC) ? 1 : 0; + + mac->tsf = tsf; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_CORRECT_TSF, (u8 *)(&bibss)); +} + +static void rtl_op_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 tmp = 0; + + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_DUAL_TSF_RST, (u8 *)(&tmp)); +} + +static void rtl_op_sta_notify(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + enum sta_notify_cmd cmd, + struct ieee80211_sta *sta) +{ + switch (cmd) { + case STA_NOTIFY_SLEEP: + break; + case STA_NOTIFY_AWAKE: + break; + default: + break; + } +} + +static int rtl_op_ampdu_action(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_ampdu_params *params) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct ieee80211_sta *sta = params->sta; + enum ieee80211_ampdu_mlme_action action = params->action; + u16 tid = params->tid; + u16 *ssn = ¶ms->ssn; + + switch (action) { + case IEEE80211_AMPDU_TX_START: + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE, + "IEEE80211_AMPDU_TX_START: TID:%d\n", tid); + return rtl_tx_agg_start(hw, vif, sta, tid, ssn); + case IEEE80211_AMPDU_TX_STOP_CONT: + case IEEE80211_AMPDU_TX_STOP_FLUSH: + case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE, + "IEEE80211_AMPDU_TX_STOP: TID:%d\n", tid); + return rtl_tx_agg_stop(hw, vif, sta, tid); + case IEEE80211_AMPDU_TX_OPERATIONAL: + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE, + "IEEE80211_AMPDU_TX_OPERATIONAL:TID:%d\n", tid); + rtl_tx_agg_oper(hw, sta, tid); + break; + case IEEE80211_AMPDU_RX_START: + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE, + "IEEE80211_AMPDU_RX_START:TID:%d\n", tid); + return rtl_rx_agg_start(hw, sta, tid); + case IEEE80211_AMPDU_RX_STOP: + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE, + "IEEE80211_AMPDU_RX_STOP:TID:%d\n", tid); + return rtl_rx_agg_stop(hw, sta, tid); + default: + pr_err("IEEE80211_AMPDU_ERR!!!!:\n"); + return -EOPNOTSUPP; + } + return 0; +} + +static void rtl_op_sw_scan_start(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + const u8 *mac_addr) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, "\n"); + mac->act_scanning = true; + if (rtlpriv->link_info.higher_busytraffic) { + mac->skip_scan = true; + return; + } + + if (rtlpriv->phydm.ops) + rtlpriv->phydm.ops->phydm_pause_dig(rtlpriv, 1); + + if (rtlpriv->cfg->ops->get_btc_status()) + rtlpriv->btcoexist.btc_ops->btc_scan_notify(rtlpriv, 1); + else if (rtlpriv->btcoexist.btc_ops) + rtlpriv->btcoexist.btc_ops->btc_scan_notify_wifi_only(rtlpriv, + 1); + + if (rtlpriv->dm.supp_phymode_switch) { + if (rtlpriv->cfg->ops->chk_switch_dmdp) + rtlpriv->cfg->ops->chk_switch_dmdp(hw); + } + + if (mac->link_state == MAC80211_LINKED) { + rtl_lps_leave(hw); + mac->link_state = MAC80211_LINKED_SCANNING; + } else { + rtl_ips_nic_on(hw); + } + + /* Dul mac */ + rtlpriv->rtlhal.load_imrandiqk_setting_for2g = false; + + rtlpriv->cfg->ops->led_control(hw, LED_CTL_SITE_SURVEY); + rtlpriv->cfg->ops->scan_operation_backup(hw, SCAN_OPT_BACKUP_BAND0); +} + +static void rtl_op_sw_scan_complete(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, "\n"); + mac->act_scanning = false; + mac->skip_scan = false; + + rtlpriv->btcoexist.btc_info.ap_num = rtlpriv->scan_list.num; + + if (rtlpriv->link_info.higher_busytraffic) + return; + + /* p2p will use 1/6/11 to scan */ + if (mac->n_channels == 3) + mac->p2p_in_use = true; + else + mac->p2p_in_use = false; + mac->n_channels = 0; + /* Dul mac */ + rtlpriv->rtlhal.load_imrandiqk_setting_for2g = false; + + if (mac->link_state == MAC80211_LINKED_SCANNING) { + mac->link_state = MAC80211_LINKED; + if (mac->opmode == NL80211_IFTYPE_STATION) { + /* fix fwlps issue */ + rtlpriv->cfg->ops->set_network_type(hw, mac->opmode); + } + } + + rtlpriv->cfg->ops->scan_operation_backup(hw, SCAN_OPT_RESTORE); + if (rtlpriv->cfg->ops->get_btc_status()) + rtlpriv->btcoexist.btc_ops->btc_scan_notify(rtlpriv, 0); + else if (rtlpriv->btcoexist.btc_ops) + rtlpriv->btcoexist.btc_ops->btc_scan_notify_wifi_only(rtlpriv, + 0); + + if (rtlpriv->phydm.ops) + rtlpriv->phydm.ops->phydm_pause_dig(rtlpriv, 0); +} + +static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + struct ieee80211_vif *vif, struct ieee80211_sta *sta, + struct ieee80211_key_conf *key) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 key_type = NO_ENCRYPTION; + u8 key_idx; + bool group_key = false; + bool wep_only = false; + int err = 0; + u8 mac_addr[ETH_ALEN]; + u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + + rtlpriv->btcoexist.btc_info.in_4way = false; + + if (rtlpriv->cfg->mod_params->sw_crypto || rtlpriv->sec.use_sw_sec) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "not open hw encryption\n"); + return -ENOSPC; /*User disabled HW-crypto */ + } + /* To support IBSS, use sw-crypto for GTK */ + if (((vif->type == NL80211_IFTYPE_ADHOC) || + (vif->type == NL80211_IFTYPE_MESH_POINT)) && + !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) + return -ENOSPC; + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + "%s hardware based encryption for keyidx: %d, mac: %pM\n", + cmd == SET_KEY ? "Using" : "Disabling", key->keyidx, + sta ? sta->addr : bcast_addr); + rtlpriv->sec.being_setkey = true; + rtl_ips_nic_on(hw); + mutex_lock(&rtlpriv->locks.conf_mutex); + /* <1> get encryption alg */ + + switch (key->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + key_type = WEP40_ENCRYPTION; + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "alg:WEP40\n"); + break; + case WLAN_CIPHER_SUITE_WEP104: + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "alg:WEP104\n"); + key_type = WEP104_ENCRYPTION; + break; + case WLAN_CIPHER_SUITE_TKIP: + key_type = TKIP_ENCRYPTION; + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "alg:TKIP\n"); + break; + case WLAN_CIPHER_SUITE_CCMP: + key_type = AESCCMP_ENCRYPTION; + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "alg:CCMP\n"); + break; + case WLAN_CIPHER_SUITE_AES_CMAC: + /* HW don't support CMAC encryption, + * use software CMAC encryption + */ + key_type = AESCMAC_ENCRYPTION; + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "alg:CMAC\n"); + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + "HW don't support CMAC encryption, use software CMAC encryption\n"); + err = -EOPNOTSUPP; + goto out_unlock; + default: + pr_err("alg_err:%x!!!!:\n", key->cipher); + goto out_unlock; + } + if (key_type == WEP40_ENCRYPTION || + key_type == WEP104_ENCRYPTION || + vif->type == NL80211_IFTYPE_ADHOC) + rtlpriv->sec.use_defaultkey = true; + + /* <2> get key_idx */ + key_idx = (u8)(key->keyidx); + if (key_idx > 3) + goto out_unlock; + /* <3> if pairwise key enable_hw_sec */ + group_key = !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE); + + /* wep always be group key, but there are two conditions: + * 1) wep only: is just for wep enc, in this condition + * rtlpriv->sec.pairwise_enc_algorithm == NO_ENCRYPTION + * will be true & enable_hw_sec will be set when wep + * ke setting. + * 2) wep(group) + AES(pairwise): some AP like cisco + * may use it, in this condition enable_hw_sec will not + * be set when wep key setting. + * we must reset sec_info after lingked before set key, + * or some flag will be wrong + */ + if (vif->type == NL80211_IFTYPE_AP || + vif->type == NL80211_IFTYPE_MESH_POINT) { + if (!group_key || key_type == WEP40_ENCRYPTION || + key_type == WEP104_ENCRYPTION) { + if (group_key) + wep_only = true; + rtlpriv->cfg->ops->enable_hw_sec(hw); + } + } else { + if ((!group_key) || (vif->type == NL80211_IFTYPE_ADHOC) || + rtlpriv->sec.pairwise_enc_algorithm == NO_ENCRYPTION) { + if (rtlpriv->sec.pairwise_enc_algorithm == + NO_ENCRYPTION && + (key_type == WEP40_ENCRYPTION || + key_type == WEP104_ENCRYPTION)) + wep_only = true; + rtlpriv->sec.pairwise_enc_algorithm = key_type; + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + "set enable_hw_sec, key_type:%x(OPEN:0 WEP40:1 TKIP:2 AES:4 WEP104:5)\n", + key_type); + rtlpriv->cfg->ops->enable_hw_sec(hw); + } + } + /* <4> set key based on cmd */ + switch (cmd) { + case SET_KEY: + if (wep_only) { + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + "set WEP(group/pairwise) key\n"); + /* Pairwise key with an assigned MAC address. */ + rtlpriv->sec.pairwise_enc_algorithm = key_type; + rtlpriv->sec.group_enc_algorithm = key_type; + /*set local buf about wep key. */ + memcpy(rtlpriv->sec.key_buf[key_idx], + key->key, key->keylen); + rtlpriv->sec.key_len[key_idx] = key->keylen; + eth_zero_addr(mac_addr); + } else if (group_key) { /* group key */ + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + "set group key\n"); + /* group key */ + rtlpriv->sec.group_enc_algorithm = key_type; + /*set local buf about group key. */ + memcpy(rtlpriv->sec.key_buf[key_idx], + key->key, key->keylen); + rtlpriv->sec.key_len[key_idx] = key->keylen; + memcpy(mac_addr, bcast_addr, ETH_ALEN); + } else { /* pairwise key */ + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + "set pairwise key\n"); + if (!sta) { + WARN_ONCE(true, + "rtlwifi: pairwise key without mac_addr\n"); + + err = -EOPNOTSUPP; + goto out_unlock; + } + /* Pairwise key with an assigned MAC address. */ + rtlpriv->sec.pairwise_enc_algorithm = key_type; + /*set local buf about pairwise key. */ + memcpy(rtlpriv->sec.key_buf[PAIRWISE_KEYIDX], + key->key, key->keylen); + rtlpriv->sec.key_len[PAIRWISE_KEYIDX] = key->keylen; + rtlpriv->sec.pairwise_key = + rtlpriv->sec.key_buf[PAIRWISE_KEYIDX]; + memcpy(mac_addr, sta->addr, ETH_ALEN); + } + rtlpriv->cfg->ops->set_key(hw, key_idx, mac_addr, + group_key, key_type, wep_only, + false); + /* <5> tell mac80211 do something: */ + /*must use sw generate IV, or can not work !!!!. */ + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + key->hw_key_idx = key_idx; + if (key_type == TKIP_ENCRYPTION) + key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; + /*use software CCMP encryption for management frames (MFP) */ + if (key_type == AESCCMP_ENCRYPTION) + key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX; + break; + case DISABLE_KEY: + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + "disable key delete one entry\n"); + /*set local buf about wep key. */ + if (vif->type == NL80211_IFTYPE_AP || + vif->type == NL80211_IFTYPE_MESH_POINT) { + if (sta) + rtl_cam_del_entry(hw, sta->addr); + } + memset(rtlpriv->sec.key_buf[key_idx], 0, key->keylen); + rtlpriv->sec.key_len[key_idx] = 0; + eth_zero_addr(mac_addr); + /* + *mac80211 will delete entries one by one, + *so don't use rtl_cam_reset_all_entry + *or clear all entries here. + */ + rtl_wait_tx_report_acked(hw, 500); /* wait 500ms for TX ack */ + + rtl_cam_delete_one_entry(hw, mac_addr, key_idx); + break; + default: + pr_err("cmd_err:%x!!!!:\n", cmd); + } +out_unlock: + mutex_unlock(&rtlpriv->locks.conf_mutex); + rtlpriv->sec.being_setkey = false; + return err; +} + +static void rtl_op_rfkill_poll(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + bool radio_state; + bool blocked; + u8 valid = 0; + + if (!test_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status)) + return; + + mutex_lock(&rtlpriv->locks.conf_mutex); + + /*if Radio On return true here */ + radio_state = rtlpriv->cfg->ops->radio_onoff_checking(hw, &valid); + + if (valid) { + if (unlikely(radio_state != rtlpriv->rfkill.rfkill_state)) { + rtlpriv->rfkill.rfkill_state = radio_state; + + RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, + "wireless radio switch turned %s\n", + radio_state ? "on" : "off"); + + blocked = (rtlpriv->rfkill.rfkill_state == 1) ? 0 : 1; + wiphy_rfkill_set_hw_state(hw->wiphy, blocked); + } + } + + mutex_unlock(&rtlpriv->locks.conf_mutex); +} + +/* this function is called by mac80211 to flush tx buffer + * before switch channel or power save, or tx buffer packet + * maybe send after offchannel or rf sleep, this may cause + * dis-association by AP + */ +static void rtl_op_flush(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + u32 queues, + bool drop) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (rtlpriv->intf_ops->flush) + rtlpriv->intf_ops->flush(hw, queues, drop); +} + +/* Description: + * This routine deals with the Power Configuration CMD + * parsing for RTL8723/RTL8188E Series IC. + * Assumption: + * We should follow specific format that was released from HW SD. + */ +bool rtl_hal_pwrseqcmdparsing(struct rtl_priv *rtlpriv, u8 cut_version, + u8 faversion, u8 interface_type, + struct wlan_pwr_cfg pwrcfgcmd[]) +{ + struct wlan_pwr_cfg cfg_cmd = {0}; + bool polling_bit = false; + u32 ary_idx = 0; + u8 value = 0; + u32 offset = 0; + u32 polling_count = 0; + u32 max_polling_cnt = 5000; + + do { + cfg_cmd = pwrcfgcmd[ary_idx]; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "%s(): offset(%#x),cut_msk(%#x), famsk(%#x), interface_msk(%#x), base(%#x), cmd(%#x), msk(%#x), value(%#x)\n", + __func__, GET_PWR_CFG_OFFSET(cfg_cmd), + GET_PWR_CFG_CUT_MASK(cfg_cmd), + GET_PWR_CFG_FAB_MASK(cfg_cmd), + GET_PWR_CFG_INTF_MASK(cfg_cmd), + GET_PWR_CFG_BASE(cfg_cmd), GET_PWR_CFG_CMD(cfg_cmd), + GET_PWR_CFG_MASK(cfg_cmd), GET_PWR_CFG_VALUE(cfg_cmd)); + + if ((GET_PWR_CFG_FAB_MASK(cfg_cmd) & faversion) && + (GET_PWR_CFG_CUT_MASK(cfg_cmd) & cut_version) && + (GET_PWR_CFG_INTF_MASK(cfg_cmd) & interface_type)) { + switch (GET_PWR_CFG_CMD(cfg_cmd)) { + case PWR_CMD_READ: + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "%s(): PWR_CMD_READ\n", __func__); + break; + case PWR_CMD_WRITE: + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "%s(): PWR_CMD_WRITE\n", __func__); + offset = GET_PWR_CFG_OFFSET(cfg_cmd); + + /*Read the value from system register*/ + value = rtl_read_byte(rtlpriv, offset); + value &= (~(GET_PWR_CFG_MASK(cfg_cmd))); + value |= (GET_PWR_CFG_VALUE(cfg_cmd) & + GET_PWR_CFG_MASK(cfg_cmd)); + + /*Write the value back to system register*/ + rtl_write_byte(rtlpriv, offset, value); + break; + case PWR_CMD_POLLING: + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "%s(): PWR_CMD_POLLING\n", __func__); + polling_bit = false; + offset = GET_PWR_CFG_OFFSET(cfg_cmd); + + do { + value = rtl_read_byte(rtlpriv, offset); + + value &= GET_PWR_CFG_MASK(cfg_cmd); + if (value == + (GET_PWR_CFG_VALUE(cfg_cmd) & + GET_PWR_CFG_MASK(cfg_cmd))) + polling_bit = true; + else + udelay(10); + + if (polling_count++ > max_polling_cnt) + return false; + } while (!polling_bit); + break; + case PWR_CMD_DELAY: + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "%s(): PWR_CMD_DELAY\n", __func__); + if (GET_PWR_CFG_VALUE(cfg_cmd) == + PWRSEQ_DELAY_US) + udelay(GET_PWR_CFG_OFFSET(cfg_cmd)); + else + mdelay(GET_PWR_CFG_OFFSET(cfg_cmd)); + break; + case PWR_CMD_END: + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "%s(): PWR_CMD_END\n", __func__); + return true; + default: + WARN_ONCE(true, + "rtlwifi: %s(): Unknown CMD!!\n", __func__); + break; + } + } + ary_idx++; + } while (1); + + return true; +} + +bool rtl_cmd_send_packet(struct ieee80211_hw *hw, struct sk_buff *skb) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl8192_tx_ring *ring; + struct rtl_tx_desc *pdesc; + unsigned long flags; + struct sk_buff *pskb = NULL; + + ring = &rtlpci->tx_ring[BEACON_QUEUE]; + + spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags); + pskb = __skb_dequeue(&ring->queue); + if (pskb) + dev_kfree_skb_irq(pskb); + + /*this is wrong, fill_tx_cmddesc needs update*/ + pdesc = &ring->desc[0]; + + rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *)pdesc, 1, 1, skb); + + __skb_queue_tail(&ring->queue, skb); + + spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); + + rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE); + + return true; +} + +const struct ieee80211_ops rtl_ops = { + .start = rtl_op_start, + .stop = rtl_op_stop, + .tx = rtl_op_tx, + .add_interface = rtl_op_add_interface, + .remove_interface = rtl_op_remove_interface, + .change_interface = rtl_op_change_interface, +#ifdef CONFIG_PM + .suspend = rtl_op_suspend, + .resume = rtl_op_resume, +#endif + .config = rtl_op_config, + .configure_filter = rtl_op_configure_filter, + .set_key = rtl_op_set_key, + .sta_statistics = rtl_op_sta_statistics, + .set_frag_threshold = rtl_op_set_frag_threshold, + .conf_tx = rtl_op_conf_tx, + .bss_info_changed = rtl_op_bss_info_changed, + .get_tsf = rtl_op_get_tsf, + .set_tsf = rtl_op_set_tsf, + .reset_tsf = rtl_op_reset_tsf, + .sta_notify = rtl_op_sta_notify, + .ampdu_action = rtl_op_ampdu_action, + .sw_scan_start = rtl_op_sw_scan_start, + .sw_scan_complete = rtl_op_sw_scan_complete, + .rfkill_poll = rtl_op_rfkill_poll, + .sta_add = rtl_op_sta_add, + .sta_remove = rtl_op_sta_remove, + .flush = rtl_op_flush, +}; + +bool rtl_btc_status_false(void) +{ + return false; +} + +void rtl_dm_diginit(struct ieee80211_hw *hw, u32 cur_igvalue) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct dig_t *dm_digtable = &rtlpriv->dm_digtable; + + dm_digtable->dig_enable_flag = true; + dm_digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX; + dm_digtable->cur_igvalue = cur_igvalue; + dm_digtable->pre_igvalue = 0; + dm_digtable->cur_sta_cstate = DIG_STA_DISCONNECT; + dm_digtable->presta_cstate = DIG_STA_DISCONNECT; + dm_digtable->curmultista_cstate = DIG_MULTISTA_DISCONNECT; + dm_digtable->rssi_lowthresh = DM_DIG_THRESH_LOW; + dm_digtable->rssi_highthresh = DM_DIG_THRESH_HIGH; + dm_digtable->fa_lowthresh = DM_FALSEALARM_THRESH_LOW; + dm_digtable->fa_highthresh = DM_FALSEALARM_THRESH_HIGH; + dm_digtable->rx_gain_max = DM_DIG_MAX; + dm_digtable->rx_gain_min = DM_DIG_MIN; + dm_digtable->back_val = DM_DIG_BACKOFF_DEFAULT; + dm_digtable->back_range_max = DM_DIG_BACKOFF_MAX; + dm_digtable->back_range_min = DM_DIG_BACKOFF_MIN; + dm_digtable->pre_cck_cca_thres = 0xff; + dm_digtable->cur_cck_cca_thres = 0x83; + dm_digtable->forbidden_igi = DM_DIG_MIN; + dm_digtable->large_fa_hit = 0; + dm_digtable->recover_cnt = 0; + dm_digtable->dig_min_0 = 0x25; + dm_digtable->dig_min_1 = 0x25; + dm_digtable->media_connect_0 = false; + dm_digtable->media_connect_1 = false; + rtlpriv->dm.dm_initialgain_enable = true; + dm_digtable->bt30_cur_igi = 0x32; + dm_digtable->pre_cck_pd_state = CCK_PD_STAGE_MAX; + dm_digtable->cur_cck_pd_state = CCK_PD_STAGE_LOWRSSI; +} diff --git a/drivers/staging/rtlwifi/core.h b/drivers/staging/rtlwifi/core.h new file mode 100644 index 000000000000..782ac2fc4b28 --- /dev/null +++ b/drivers/staging/rtlwifi/core.h @@ -0,0 +1,86 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL_CORE_H__ +#define __RTL_CORE_H__ + +#define RTL_SUPPORTED_FILTERS \ + (FIF_ALLMULTI | FIF_CONTROL | \ + FIF_OTHER_BSS | \ + FIF_FCSFAIL | \ + FIF_BCN_PRBRESP_PROMISC) + +#define DM_DIG_THRESH_HIGH 40 +#define DM_DIG_THRESH_LOW 35 +#define DM_FALSEALARM_THRESH_LOW 400 +#define DM_FALSEALARM_THRESH_HIGH 1000 + +#define DM_DIG_MAX 0x3e +#define DM_DIG_MIN 0x1e +#define DM_DIG_MAX_AP 0x32 +#define DM_DIG_BACKOFF_MAX 12 +#define DM_DIG_BACKOFF_MIN -4 +#define DM_DIG_BACKOFF_DEFAULT 10 + +enum cck_packet_detection_threshold { + CCK_PD_STAGE_LOWRSSI = 0, + CCK_PD_STAGE_HIGHRSSI = 1, + CCK_FA_STAGE_LOW = 2, + CCK_FA_STAGE_HIGH = 3, + CCK_PD_STAGE_MAX = 4, +}; + +enum dm_dig_ext_port_alg_e { + DIG_EXT_PORT_STAGE_0 = 0, + DIG_EXT_PORT_STAGE_1 = 1, + DIG_EXT_PORT_STAGE_2 = 2, + DIG_EXT_PORT_STAGE_3 = 3, + DIG_EXT_PORT_STAGE_MAX = 4, +}; + +enum dm_dig_connect_e { + DIG_STA_DISCONNECT, + DIG_STA_CONNECT, + DIG_STA_BEFORE_CONNECT, + DIG_MULTISTA_DISCONNECT, + DIG_MULTISTA_CONNECT, + DIG_AP_DISCONNECT, + DIG_AP_CONNECT, + DIG_AP_ADD_STATION, + DIG_CONNECT_MAX +}; + +extern const struct ieee80211_ops rtl_ops; +void rtl_fw_cb(const struct firmware *firmware, void *context); +void rtl_wowlan_fw_cb(const struct firmware *firmware, void *context); +void rtl_addr_delay(u32 addr); +void rtl_rfreg_delay(struct ieee80211_hw *hw, enum radio_path rfpath, u32 addr, + u32 mask, u32 data); +void rtl_bb_delay(struct ieee80211_hw *hw, u32 addr, u32 data); +bool rtl_cmd_send_packet(struct ieee80211_hw *hw, struct sk_buff *skb); +bool rtl_btc_status_false(void); +void rtl_dm_diginit(struct ieee80211_hw *hw, u32 cur_igval); + +#endif diff --git a/drivers/staging/rtlwifi/debug.c b/drivers/staging/rtlwifi/debug.c new file mode 100644 index 000000000000..7446d71c41d1 --- /dev/null +++ b/drivers/staging/rtlwifi/debug.c @@ -0,0 +1,636 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + *****************************************************************************/ + +#include "wifi.h" +#include "cam.h" + +#include <linux/moduleparam.h> +#include <linux/vmalloc.h> + +#ifdef CONFIG_RTLWIFI_DEBUG_ST +void _rtl_dbg_trace(struct rtl_priv *rtlpriv, u64 comp, int level, + const char *fmt, ...) +{ + if (unlikely((comp & rtlpriv->cfg->mod_params->debug_mask) && + (level <= rtlpriv->cfg->mod_params->debug_level))) { + struct va_format vaf; + va_list args; + + va_start(args, fmt); + + vaf.fmt = fmt; + vaf.va = &args; + + pr_info(":<%lx> %pV", in_interrupt(), &vaf); + + va_end(args); + } +} + +void _rtl_dbg_print(struct rtl_priv *rtlpriv, u64 comp, int level, + const char *fmt, ...) +{ + if (unlikely((comp & rtlpriv->cfg->mod_params->debug_mask) && + (level <= rtlpriv->cfg->mod_params->debug_level))) { + struct va_format vaf; + va_list args; + + va_start(args, fmt); + + vaf.fmt = fmt; + vaf.va = &args; + + pr_info("%pV", &vaf); + + va_end(args); + } +} + +void _rtl_dbg_print_data(struct rtl_priv *rtlpriv, u64 comp, int level, + const char *titlestring, + const void *hexdata, int hexdatalen) +{ + if (unlikely(((comp) & rtlpriv->cfg->mod_params->debug_mask) && + ((level) <= rtlpriv->cfg->mod_params->debug_level))) { + pr_info("In process \"%s\" (pid %i): %s\n", + current->comm, current->pid, titlestring); + print_hex_dump_bytes("", DUMP_PREFIX_NONE, + hexdata, hexdatalen); + } +} + +struct rtl_debugfs_priv { + struct rtl_priv *rtlpriv; + int (*cb_read)(struct seq_file *m, void *v); + ssize_t (*cb_write)(struct file *filp, const char __user *buffer, + size_t count, loff_t *loff); + u32 cb_data; +}; + +static struct dentry *debugfs_topdir; + +static int rtl_debug_get_common(struct seq_file *m, void *v) +{ + struct rtl_debugfs_priv *debugfs_priv = m->private; + + return debugfs_priv->cb_read(m, v); +} + +static int dl_debug_open_common(struct inode *inode, struct file *file) +{ + return single_open(file, rtl_debug_get_common, inode->i_private); +} + +static const struct file_operations file_ops_common = { + .open = dl_debug_open_common, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static int rtl_debug_get_mac_page(struct seq_file *m, void *v) +{ + struct rtl_debugfs_priv *debugfs_priv = m->private; + struct rtl_priv *rtlpriv = debugfs_priv->rtlpriv; + u32 page = debugfs_priv->cb_data; + int i, n; + int max = 0xff; + + for (n = 0; n <= max; ) { + seq_printf(m, "\n%8.8x ", n + page); + for (i = 0; i < 4 && n <= max; i++, n += 4) + seq_printf(m, "%8.8x ", + rtl_read_dword(rtlpriv, (page | n))); + } + seq_puts(m, "\n"); + return 0; +} + +#define RTL_DEBUG_IMPL_MAC_SERIES(page, addr) \ +struct rtl_debugfs_priv rtl_debug_priv_mac_ ##page = { \ + .cb_read = rtl_debug_get_mac_page, \ + .cb_data = addr, \ +} + +RTL_DEBUG_IMPL_MAC_SERIES(0, 0x0000); +RTL_DEBUG_IMPL_MAC_SERIES(1, 0x0100); +RTL_DEBUG_IMPL_MAC_SERIES(2, 0x0200); +RTL_DEBUG_IMPL_MAC_SERIES(3, 0x0300); +RTL_DEBUG_IMPL_MAC_SERIES(4, 0x0400); +RTL_DEBUG_IMPL_MAC_SERIES(5, 0x0500); +RTL_DEBUG_IMPL_MAC_SERIES(6, 0x0600); +RTL_DEBUG_IMPL_MAC_SERIES(7, 0x0700); +RTL_DEBUG_IMPL_MAC_SERIES(10, 0x1000); +RTL_DEBUG_IMPL_MAC_SERIES(11, 0x1100); +RTL_DEBUG_IMPL_MAC_SERIES(12, 0x1200); +RTL_DEBUG_IMPL_MAC_SERIES(13, 0x1300); +RTL_DEBUG_IMPL_MAC_SERIES(14, 0x1400); +RTL_DEBUG_IMPL_MAC_SERIES(15, 0x1500); +RTL_DEBUG_IMPL_MAC_SERIES(16, 0x1600); +RTL_DEBUG_IMPL_MAC_SERIES(17, 0x1700); + +static int rtl_debug_get_bb_page(struct seq_file *m, void *v) +{ + struct rtl_debugfs_priv *debugfs_priv = m->private; + struct rtl_priv *rtlpriv = debugfs_priv->rtlpriv; + struct ieee80211_hw *hw = rtlpriv->hw; + u32 page = debugfs_priv->cb_data; + int i, n; + int max = 0xff; + + for (n = 0; n <= max; ) { + seq_printf(m, "\n%8.8x ", n + page); + for (i = 0; i < 4 && n <= max; i++, n += 4) + seq_printf(m, "%8.8x ", + rtl_get_bbreg(hw, (page | n), 0xffffffff)); + } + seq_puts(m, "\n"); + return 0; +} + +#define RTL_DEBUG_IMPL_BB_SERIES(page, addr) \ +struct rtl_debugfs_priv rtl_debug_priv_bb_ ##page = { \ + .cb_read = rtl_debug_get_bb_page, \ + .cb_data = addr, \ +} + +RTL_DEBUG_IMPL_BB_SERIES(8, 0x0800); +RTL_DEBUG_IMPL_BB_SERIES(9, 0x0900); +RTL_DEBUG_IMPL_BB_SERIES(a, 0x0a00); +RTL_DEBUG_IMPL_BB_SERIES(b, 0x0b00); +RTL_DEBUG_IMPL_BB_SERIES(c, 0x0c00); +RTL_DEBUG_IMPL_BB_SERIES(d, 0x0d00); +RTL_DEBUG_IMPL_BB_SERIES(e, 0x0e00); +RTL_DEBUG_IMPL_BB_SERIES(f, 0x0f00); +RTL_DEBUG_IMPL_BB_SERIES(18, 0x1800); +RTL_DEBUG_IMPL_BB_SERIES(19, 0x1900); +RTL_DEBUG_IMPL_BB_SERIES(1a, 0x1a00); +RTL_DEBUG_IMPL_BB_SERIES(1b, 0x1b00); +RTL_DEBUG_IMPL_BB_SERIES(1c, 0x1c00); +RTL_DEBUG_IMPL_BB_SERIES(1d, 0x1d00); +RTL_DEBUG_IMPL_BB_SERIES(1e, 0x1e00); +RTL_DEBUG_IMPL_BB_SERIES(1f, 0x1f00); + +static int rtl_debug_get_reg_rf(struct seq_file *m, void *v) +{ + struct rtl_debugfs_priv *debugfs_priv = m->private; + struct rtl_priv *rtlpriv = debugfs_priv->rtlpriv; + struct ieee80211_hw *hw = rtlpriv->hw; + enum radio_path rfpath = debugfs_priv->cb_data; + int i, n; + int max = 0x40; + + if (IS_HARDWARE_TYPE_8822B(rtlpriv)) + max = 0xff; + + seq_printf(m, "\nPATH(%d)", rfpath); + + for (n = 0; n <= max; ) { + seq_printf(m, "\n%8.8x ", n); + for (i = 0; i < 4 && n <= max; n += 1, i++) + seq_printf(m, "%8.8x ", + rtl_get_rfreg(hw, rfpath, n, 0xffffffff)); + } + seq_puts(m, "\n"); + return 0; +} + +#define RTL_DEBUG_IMPL_RF_SERIES(page, addr) \ +struct rtl_debugfs_priv rtl_debug_priv_rf_ ##page = { \ + .cb_read = rtl_debug_get_reg_rf, \ + .cb_data = addr, \ +} + +RTL_DEBUG_IMPL_RF_SERIES(a, RF90_PATH_A); +RTL_DEBUG_IMPL_RF_SERIES(b, RF90_PATH_B); + +static int rtl_debug_get_cam_register(struct seq_file *m, void *v) +{ + struct rtl_debugfs_priv *debugfs_priv = m->private; + struct rtl_priv *rtlpriv = debugfs_priv->rtlpriv; + int start = debugfs_priv->cb_data; + u32 target_cmd = 0; + u32 target_val = 0; + u8 entry_i = 0; + u32 ulstatus; + int i = 100, j = 0; + int end = (start + 11 > TOTAL_CAM_ENTRY ? TOTAL_CAM_ENTRY : start + 11); + + /* This dump the current register page */ + seq_printf(m, + "\n#################### SECURITY CAM (%d-%d) ##################\n", + start, end - 1); + + for (j = start; j < end; j++) { + seq_printf(m, "\nD: %2x > ", j); + for (entry_i = 0; entry_i < CAM_CONTENT_COUNT; entry_i++) { + /* polling bit, and No Write enable, and address */ + target_cmd = entry_i + CAM_CONTENT_COUNT * j; + target_cmd = target_cmd | BIT(31); + + /* Check polling bit is clear */ + while ((i--) >= 0) { + ulstatus = rtl_read_dword( + rtlpriv, + rtlpriv->cfg->maps[RWCAM]); + if (ulstatus & BIT(31)) + continue; + else + break; + } + + rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], + target_cmd); + target_val = rtl_read_dword(rtlpriv, + rtlpriv->cfg->maps[RCAMO]); + seq_printf(m, "%8.8x ", target_val); + } + } + seq_puts(m, "\n"); + return 0; +} + +#define RTL_DEBUG_IMPL_CAM_SERIES(page, addr) \ +struct rtl_debugfs_priv rtl_debug_priv_cam_ ##page = { \ + .cb_read = rtl_debug_get_cam_register, \ + .cb_data = addr, \ +} + +RTL_DEBUG_IMPL_CAM_SERIES(1, 0); +RTL_DEBUG_IMPL_CAM_SERIES(2, 11); +RTL_DEBUG_IMPL_CAM_SERIES(3, 22); + +static int rtl_debug_get_btcoex(struct seq_file *m, void *v) +{ + struct rtl_debugfs_priv *debugfs_priv = m->private; + struct rtl_priv *rtlpriv = debugfs_priv->rtlpriv; + + if (rtlpriv->cfg->ops->get_btc_status()) + rtlpriv->btcoexist.btc_ops->btc_display_bt_coex_info(rtlpriv, + m); + + seq_puts(m, "\n"); + + return 0; +} + +static struct rtl_debugfs_priv rtl_debug_priv_btcoex = { + .cb_read = rtl_debug_get_btcoex, + .cb_data = 0, +}; + +static ssize_t rtl_debugfs_set_write_reg(struct file *filp, + const char __user *buffer, + size_t count, loff_t *loff) +{ + struct rtl_debugfs_priv *debugfs_priv = filp->private_data; + struct rtl_priv *rtlpriv = debugfs_priv->rtlpriv; + char tmp[32 + 1]; + int tmp_len; + u32 addr, val, len; + int num; + + if (count < 3) + return -EFAULT; + + tmp_len = (count > sizeof(tmp) - 1 ? sizeof(tmp) - 1 : count); + + if (!buffer || copy_from_user(tmp, buffer, tmp_len)) + return count; + + tmp[tmp_len] = '\0'; + + /* write BB/MAC register */ + num = sscanf(tmp, "%x %x %x", &addr, &val, &len); + + if (num != 3) + return count; + + switch (len) { + case 1: + rtl_write_byte(rtlpriv, addr, (u8)val); + break; + case 2: + rtl_write_word(rtlpriv, addr, (u16)val); + break; + case 4: + rtl_write_dword(rtlpriv, addr, val); + break; + default: + /*printk("error write length=%d", len);*/ + break; + } + + return count; +} + +static struct rtl_debugfs_priv rtl_debug_priv_write_reg = { + .cb_write = rtl_debugfs_set_write_reg, +}; + +static ssize_t rtl_debugfs_set_write_h2c(struct file *filp, + const char __user *buffer, + size_t count, loff_t *loff) +{ + struct rtl_debugfs_priv *debugfs_priv = filp->private_data; + struct rtl_priv *rtlpriv = debugfs_priv->rtlpriv; + struct ieee80211_hw *hw = rtlpriv->hw; + char tmp[32 + 1]; + int tmp_len; + u8 h2c_len, h2c_data_packed[8]; + int h2c_data[8]; /* idx 0: cmd */ + int i; + + if (count < 3) + return -EFAULT; + + tmp_len = (count > sizeof(tmp) - 1 ? sizeof(tmp) - 1 : count); + + if (!buffer || copy_from_user(tmp, buffer, tmp_len)) + return count; + + tmp[tmp_len] = '\0'; + + h2c_len = sscanf(tmp, "%X %X %X %X %X %X %X %X", + &h2c_data[0], &h2c_data[1], + &h2c_data[2], &h2c_data[3], + &h2c_data[4], &h2c_data[5], + &h2c_data[6], &h2c_data[7]); + + if (h2c_len <= 0) + return count; + + for (i = 0; i < h2c_len; i++) + h2c_data_packed[i] = (u8)h2c_data[i]; + + rtlpriv->cfg->ops->fill_h2c_cmd(hw, h2c_data_packed[0], + h2c_len - 1, + &h2c_data_packed[1]); + + return count; +} + +static struct rtl_debugfs_priv rtl_debug_priv_write_h2c = { + .cb_write = rtl_debugfs_set_write_h2c, +}; + +static ssize_t rtl_debugfs_set_write_rfreg(struct file *filp, + const char __user *buffer, + size_t count, loff_t *loff) +{ + struct rtl_debugfs_priv *debugfs_priv = filp->private_data; + struct rtl_priv *rtlpriv = debugfs_priv->rtlpriv; + struct ieee80211_hw *hw = rtlpriv->hw; + char tmp[32 + 1]; + int tmp_len; + int num; + int path; + u32 addr, bitmask, data; + + if (count < 3) + return -EFAULT; + + tmp_len = (count > sizeof(tmp) - 1 ? sizeof(tmp) - 1 : count); + + if (!buffer || copy_from_user(tmp, buffer, tmp_len)) + return count; + + tmp[tmp_len] = '\0'; + + num = sscanf(tmp, "%X %X %X %X", + &path, &addr, &bitmask, &data); + + if (num != 4) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_DMESG, + "Format is <path> <addr> <mask> <data>\n"); + return count; + } + + rtl_set_rfreg(hw, path, addr, bitmask, data); + + return count; +} + +static struct rtl_debugfs_priv rtl_debug_priv_write_rfreg = { + .cb_write = rtl_debugfs_set_write_rfreg, +}; + +static int rtl_debugfs_close(struct inode *inode, struct file *filp) +{ + return 0; +} + +static ssize_t rtl_debugfs_common_write(struct file *filp, + const char __user *buffer, + size_t count, loff_t *loff) +{ + struct rtl_debugfs_priv *debugfs_priv = filp->private_data; + + return debugfs_priv->cb_write(filp, buffer, count, loff); +} + +static const struct file_operations file_ops_common_write = { + .owner = THIS_MODULE, + .write = rtl_debugfs_common_write, + .open = simple_open, + .release = rtl_debugfs_close, +}; + +static ssize_t rtl_debugfs_phydm_cmd(struct file *filp, + const char __user *buffer, + size_t count, loff_t *loff) +{ + struct rtl_debugfs_priv *debugfs_priv = filp->private_data; + struct rtl_priv *rtlpriv = debugfs_priv->rtlpriv; + + char tmp[64]; + + if (!rtlpriv->dbg.msg_buf) + return -ENOMEM; + + if (!rtlpriv->phydm.ops) + return -EFAULT; + + if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { + tmp[count] = '\0'; + + rtlpriv->phydm.ops->phydm_debug_cmd(rtlpriv, tmp, count, + rtlpriv->dbg.msg_buf, + 80 * 25); + } + + return count; +} + +static int rtl_debug_get_phydm_cmd(struct seq_file *m, void *v) +{ + struct rtl_debugfs_priv *debugfs_priv = m->private; + struct rtl_priv *rtlpriv = debugfs_priv->rtlpriv; + + if (rtlpriv->dbg.msg_buf) + seq_puts(m, rtlpriv->dbg.msg_buf); + + return 0; +} + +static int rtl_debugfs_open_rw(struct inode *inode, struct file *filp) +{ + if (filp->f_mode & FMODE_READ) + single_open(filp, rtl_debug_get_common, inode->i_private); + else + filp->private_data = inode->i_private; + + return 0; +} + +static int rtl_debugfs_close_rw(struct inode *inode, struct file *filp) +{ + if (filp->f_mode == FMODE_READ) + seq_release(inode, filp); + + return 0; +} + +static struct rtl_debugfs_priv rtl_debug_priv_phydm_cmd = { + .cb_read = rtl_debug_get_phydm_cmd, + .cb_write = rtl_debugfs_phydm_cmd, + .cb_data = 0, +}; + +static const struct file_operations file_ops_common_rw = { + .owner = THIS_MODULE, + .open = rtl_debugfs_open_rw, + .release = rtl_debugfs_close_rw, + .read = seq_read, + .llseek = seq_lseek, + .write = rtl_debugfs_common_write, +}; + +#define RTL_DEBUGFS_ADD_CORE(name, mode, fopname) \ + do { \ + rtl_debug_priv_ ##name.rtlpriv = rtlpriv; \ + if (!debugfs_create_file(#name, mode, \ + parent, &rtl_debug_priv_ ##name, \ + &file_ops_ ##fopname)) \ + pr_err("Unable to initialize debugfs:%s/%s\n", \ + rtlpriv->dbg.debugfs_name, \ + #name); \ + } while (0) + +#define RTL_DEBUGFS_ADD(name) \ + RTL_DEBUGFS_ADD_CORE(name, S_IFREG | 0444, common) +#define RTL_DEBUGFS_ADD_W(name) \ + RTL_DEBUGFS_ADD_CORE(name, S_IFREG | 0222, common_write) +#define RTL_DEBUGFS_ADD_RW(name) \ + RTL_DEBUGFS_ADD_CORE(name, S_IFREG | 0666, common_rw) + +void rtl_debug_add_one(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct dentry *parent; + + rtlpriv->dbg.msg_buf = vzalloc(80 * 25); + + snprintf(rtlpriv->dbg.debugfs_name, 18, "%pMF", rtlefuse->dev_addr); + + rtlpriv->dbg.debugfs_dir = + debugfs_create_dir(rtlpriv->dbg.debugfs_name, debugfs_topdir); + if (!rtlpriv->dbg.debugfs_dir) { + pr_err("Unable to init debugfs:/%s/%s\n", rtlpriv->cfg->name, + rtlpriv->dbg.debugfs_name); + return; + } + + parent = rtlpriv->dbg.debugfs_dir; + + RTL_DEBUGFS_ADD(mac_0); + RTL_DEBUGFS_ADD(mac_1); + RTL_DEBUGFS_ADD(mac_2); + RTL_DEBUGFS_ADD(mac_3); + RTL_DEBUGFS_ADD(mac_4); + RTL_DEBUGFS_ADD(mac_5); + RTL_DEBUGFS_ADD(mac_6); + RTL_DEBUGFS_ADD(mac_7); + RTL_DEBUGFS_ADD(bb_8); + RTL_DEBUGFS_ADD(bb_9); + RTL_DEBUGFS_ADD(bb_a); + RTL_DEBUGFS_ADD(bb_b); + RTL_DEBUGFS_ADD(bb_c); + RTL_DEBUGFS_ADD(bb_d); + RTL_DEBUGFS_ADD(bb_e); + RTL_DEBUGFS_ADD(bb_f); + RTL_DEBUGFS_ADD(mac_10); + RTL_DEBUGFS_ADD(mac_11); + RTL_DEBUGFS_ADD(mac_12); + RTL_DEBUGFS_ADD(mac_13); + RTL_DEBUGFS_ADD(mac_14); + RTL_DEBUGFS_ADD(mac_15); + RTL_DEBUGFS_ADD(mac_16); + RTL_DEBUGFS_ADD(mac_17); + RTL_DEBUGFS_ADD(bb_18); + RTL_DEBUGFS_ADD(bb_19); + RTL_DEBUGFS_ADD(bb_1a); + RTL_DEBUGFS_ADD(bb_1b); + RTL_DEBUGFS_ADD(bb_1c); + RTL_DEBUGFS_ADD(bb_1d); + RTL_DEBUGFS_ADD(bb_1e); + RTL_DEBUGFS_ADD(bb_1f); + RTL_DEBUGFS_ADD(rf_a); + RTL_DEBUGFS_ADD(rf_b); + + RTL_DEBUGFS_ADD(cam_1); + RTL_DEBUGFS_ADD(cam_2); + RTL_DEBUGFS_ADD(cam_3); + + RTL_DEBUGFS_ADD(btcoex); + + RTL_DEBUGFS_ADD_W(write_reg); + RTL_DEBUGFS_ADD_W(write_h2c); + RTL_DEBUGFS_ADD_W(write_rfreg); + + RTL_DEBUGFS_ADD_RW(phydm_cmd); +} + +void rtl_debug_remove_one(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + debugfs_remove_recursive(rtlpriv->dbg.debugfs_dir); + rtlpriv->dbg.debugfs_dir = NULL; + + vfree(rtlpriv->dbg.msg_buf); +} + +void rtl_debugfs_add_topdir(void) +{ + debugfs_topdir = debugfs_create_dir("rtlwifi", NULL); +} + +void rtl_debugfs_remove_topdir(void) +{ + debugfs_remove_recursive(debugfs_topdir); +} + +#endif diff --git a/drivers/staging/rtlwifi/debug.h b/drivers/staging/rtlwifi/debug.h new file mode 100644 index 000000000000..ac942477f629 --- /dev/null +++ b/drivers/staging/rtlwifi/debug.h @@ -0,0 +1,234 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + *****************************************************************************/ + +#ifndef __RTL_DEBUG_H__ +#define __RTL_DEBUG_H__ + +/*-------------------------------------------------------------- + * Debug level + *------------------------------------------------------------ + * + *Fatal bug. + *For example, Tx/Rx/IO locked up, + *memory access violation, + *resource allocation failed, + *unexpected HW behavior, HW BUG + *and so on. + */ +/*#define DBG_EMERG 0 */ + +/*Abnormal, rare, or unexpected cases. + *For example, Packet/IO Ctl canceled, + *device surprisingly removed and so on. + */ +#define DBG_WARNING 2 + +/*Normal case driver developer should + *open, we can see link status like + *assoc/AddBA/DHCP/adapter start and + *so on basic and useful infromations. + */ +#define DBG_DMESG 3 + +/*Normal case with useful information + *about current SW or HW state. + *For example, Tx/Rx descriptor to fill, + *Tx/Rx descriptor completed status, + *SW protocol state change, dynamic + *mechanism state change and so on. + */ +#define DBG_LOUD 4 + +/*Normal case with detail execution + *flow or information. + */ +#define DBG_TRACE 5 + +/*-------------------------------------------------------------- + * Define the rt_trace components + *-------------------------------------------------------------- + */ +#define COMP_ERR BIT(0) +#define COMP_FW BIT(1) +#define COMP_INIT BIT(2) /*For init/deinit */ +#define COMP_RECV BIT(3) /*For Rx. */ +#define COMP_SEND BIT(4) /*For Tx. */ +#define COMP_MLME BIT(5) /*For MLME. */ +#define COMP_SCAN BIT(6) /*For Scan. */ +#define COMP_INTR BIT(7) /*For interrupt Related. */ +#define COMP_LED BIT(8) /*For LED. */ +#define COMP_SEC BIT(9) /*For sec. */ +#define COMP_BEACON BIT(10) /*For beacon. */ +#define COMP_RATE BIT(11) /*For rate. */ +#define COMP_RXDESC BIT(12) /*For rx desc. */ +#define COMP_DIG BIT(13) /*For DIG */ +#define COMP_TXAGC BIT(14) /*For Tx power */ +#define COMP_HIPWR BIT(15) /*For High Power Mechanism */ +#define COMP_POWER BIT(16) /*For lps/ips/aspm. */ +#define COMP_POWER_TRACKING BIT(17) /*For TX POWER TRACKING */ +#define COMP_BB_POWERSAVING BIT(18) +#define COMP_SWAS BIT(19) /*For SW Antenna Switch */ +#define COMP_RF BIT(20) /*For RF. */ +#define COMP_TURBO BIT(21) /*For EDCA TURBO. */ +#define COMP_RATR BIT(22) +#define COMP_CMD BIT(23) +#define COMP_EFUSE BIT(24) +#define COMP_QOS BIT(25) +#define COMP_MAC80211 BIT(26) +#define COMP_REGD BIT(27) +#define COMP_CHAN BIT(28) +#define COMP_USB BIT(29) +#define COMP_EASY_CONCURRENT COMP_USB /* reuse of this bit is OK */ +#define COMP_BT_COEXIST BIT(30) +#define COMP_IQK BIT(31) +#define COMP_TX_REPORT BIT_ULL(32) +#define COMP_HALMAC BIT_ULL(34) +#define COMP_PHYDM BIT_ULL(35) + +/*-------------------------------------------------------------- + * Define the rt_print components + *-------------------------------------------------------------- + */ +/* Define EEPROM and EFUSE check module bit*/ +#define EEPROM_W BIT(0) +#define EFUSE_PG BIT(1) +#define EFUSE_READ_ALL BIT(2) + +/* Define init check for module bit*/ +#define INIT_EEPROM BIT(0) +#define INIT_TXPOWER BIT(1) +#define INIT_IQK BIT(2) +#define INIT_RF BIT(3) + +/* Define PHY-BB/RF/MAC check module bit */ +#define PHY_BBR BIT(0) +#define PHY_BBW BIT(1) +#define PHY_RFR BIT(2) +#define PHY_RFW BIT(3) +#define PHY_MACR BIT(4) +#define PHY_MACW BIT(5) +#define PHY_ALLR BIT(6) +#define PHY_ALLW BIT(7) +#define PHY_TXPWR BIT(8) +#define PHY_PWRDIFF BIT(9) + +/* Define Dynamic Mechanism check module bit --> FDM */ +#define WA_IOT BIT(0) +#define DM_PWDB BIT(1) +#define DM_MONITOR BIT(2) +#define DM_DIG BIT(3) +#define DM_EDCA_TURBO BIT(4) + +#define DM_PWDB BIT(1) + +enum dbgp_flag_e { + FQOS = 0, + FTX = 1, + FRX = 2, + FSEC = 3, + FMGNT = 4, + FMLME = 5, + FRESOURCE = 6, + FBEACON = 7, + FISR = 8, + FPHY = 9, + FMP = 10, + FEEPROM = 11, + FPWR = 12, + FDM = 13, + FDBGCTRL = 14, + FC2H = 15, + FBT = 16, + FINIT = 17, + FIOCTL = 18, + DBGP_TYPE_MAX +}; + +#ifdef CONFIG_RTLWIFI_DEBUG_ST + +struct rtl_priv; + +__printf(4, 5) +void _rtl_dbg_trace(struct rtl_priv *rtlpriv, u64 comp, int level, + const char *fmt, ...); + +__printf(4, 5) +void _rtl_dbg_print(struct rtl_priv *rtlpriv, u64 comp, int level, + const char *fmt, ...); + +void _rtl_dbg_print_data(struct rtl_priv *rtlpriv, u64 comp, int level, + const char *titlestring, + const void *hexdata, int hexdatalen); + +#define RT_TRACE(rtlpriv, comp, level, fmt, ...) \ + _rtl_dbg_trace(rtlpriv, comp, level, \ + fmt, ##__VA_ARGS__) + +#define RTPRINT(rtlpriv, dbgtype, dbgflag, fmt, ...) \ + _rtl_dbg_print(rtlpriv, dbgtype, dbgflag, fmt, ##__VA_ARGS__) + +#define RT_PRINT_DATA(rtlpriv, _comp, _level, _titlestring, _hexdata, \ + _hexdatalen) \ + _rtl_dbg_print_data(rtlpriv, _comp, _level, \ + _titlestring, _hexdata, _hexdatalen) + +#else + +struct rtl_priv; + +__printf(4, 5) +static inline void RT_TRACE(struct rtl_priv *rtlpriv, + u64 comp, int level, + const char *fmt, ...) +{ +} + +__printf(4, 5) +static inline void RTPRINT(struct rtl_priv *rtlpriv, + int dbgtype, int dbgflag, + const char *fmt, ...) +{ +} + +static inline void RT_PRINT_DATA(struct rtl_priv *rtlpriv, + u64 comp, int level, + const char *titlestring, + const void *hexdata, size_t hexdatalen) +{ +} + +#endif + +#ifdef CONFIG_RTLWIFI_DEBUG_ST +void rtl_debug_add_one(struct ieee80211_hw *hw); +void rtl_debug_remove_one(struct ieee80211_hw *hw); +void rtl_debugfs_add_topdir(void); +void rtl_debugfs_remove_topdir(void); +#else +#define rtl_debug_add_one(hw) +#define rtl_debug_remove_one(hw) +#define rtl_debugfs_add_topdir() +#define rtl_debugfs_remove_topdir() +#endif +#endif diff --git a/drivers/staging/rtlwifi/efuse.c b/drivers/staging/rtlwifi/efuse.c new file mode 100644 index 000000000000..6d5e657017c6 --- /dev/null +++ b/drivers/staging/rtlwifi/efuse.c @@ -0,0 +1,1342 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#include "wifi.h" +#include "efuse.h" +#include "pci.h" +#include <linux/export.h> + +static const u8 MAX_PGPKT_SIZE = 9; +static const u8 PGPKT_DATA_SIZE = 8; +static const int EFUSE_MAX_SIZE = 512; + +#define START_ADDRESS 0x1000 +#define REG_MCUFWDL 0x0080 + +static const struct efuse_map RTL8712_SDIO_EFUSE_TABLE[] = { + {0, 0, 0, 2}, + {0, 1, 0, 2}, + {0, 2, 0, 2}, + {1, 0, 0, 1}, + {1, 0, 1, 1}, + {1, 1, 0, 1}, + {1, 1, 1, 3}, + {1, 3, 0, 17}, + {3, 3, 1, 48}, + {10, 0, 0, 6}, + {10, 3, 0, 1}, + {10, 3, 1, 1}, + {11, 0, 0, 28} +}; + +static void efuse_shadow_read_1byte(struct ieee80211_hw *hw, u16 offset, + u8 *value); +static void efuse_shadow_read_2byte(struct ieee80211_hw *hw, u16 offset, + u16 *value); +static void efuse_shadow_read_4byte(struct ieee80211_hw *hw, u16 offset, + u32 *value); +static void efuse_shadow_write_1byte(struct ieee80211_hw *hw, u16 offset, + u8 value); +static void efuse_shadow_write_2byte(struct ieee80211_hw *hw, u16 offset, + u16 value); +static void efuse_shadow_write_4byte(struct ieee80211_hw *hw, u16 offset, + u32 value); +static int efuse_one_byte_write(struct ieee80211_hw *hw, u16 addr, + u8 data); +static void efuse_read_all_map(struct ieee80211_hw *hw, u8 *efuse); +static int efuse_pg_packet_read(struct ieee80211_hw *hw, u8 offset, + u8 *data); +static int efuse_pg_packet_write(struct ieee80211_hw *hw, u8 offset, + u8 word_en, u8 *data); +static void efuse_word_enable_data_read(u8 word_en, u8 *sourdata, + u8 *targetdata); +static u8 enable_efuse_data_write(struct ieee80211_hw *hw, + u16 efuse_addr, u8 word_en, u8 *data); +static u16 efuse_get_current_size(struct ieee80211_hw *hw); +static u8 efuse_calculate_word_cnts(u8 word_en); + +void efuse_initialize(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 bytetemp; + u8 temp; + + bytetemp = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[SYS_FUNC_EN] + 1); + temp = bytetemp | 0x20; + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[SYS_FUNC_EN] + 1, temp); + + bytetemp = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[SYS_ISO_CTRL] + 1); + temp = bytetemp & 0xFE; + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[SYS_ISO_CTRL] + 1, temp); + + bytetemp = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_TEST] + 3); + temp = bytetemp | 0x80; + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_TEST] + 3, temp); + + rtl_write_byte(rtlpriv, 0x2F8, 0x3); + + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 3, 0x72); +} + +u8 efuse_read_1byte(struct ieee80211_hw *hw, u16 address) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 data; + u8 bytetemp; + u8 temp; + u32 k = 0; + const u32 efuse_len = + rtlpriv->cfg->maps[EFUSE_REAL_CONTENT_SIZE]; + + if (address < efuse_len) { + temp = address & 0xFF; + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 1, + temp); + bytetemp = rtl_read_byte(rtlpriv, + rtlpriv->cfg->maps[EFUSE_CTRL] + 2); + temp = ((address >> 8) & 0x03) | (bytetemp & 0xFC); + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 2, + temp); + + bytetemp = rtl_read_byte(rtlpriv, + rtlpriv->cfg->maps[EFUSE_CTRL] + 3); + temp = bytetemp & 0x7F; + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 3, + temp); + + bytetemp = rtl_read_byte(rtlpriv, + rtlpriv->cfg->maps[EFUSE_CTRL] + 3); + while (!(bytetemp & 0x80)) { + bytetemp = + rtl_read_byte(rtlpriv, + rtlpriv->cfg->maps[EFUSE_CTRL] + 3); + k++; + if (k == 1000) { + k = 0; + break; + } + } + data = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL]); + return data; + } + return 0xFF; +} + +void efuse_write_1byte(struct ieee80211_hw *hw, u16 address, u8 value) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 bytetemp; + u8 temp; + u32 k = 0; + const u32 efuse_len = + rtlpriv->cfg->maps[EFUSE_REAL_CONTENT_SIZE]; + + RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD, "Addr=%x Data =%x\n", + address, value); + + if (address < efuse_len) { + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL], value); + + temp = address & 0xFF; + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 1, + temp); + bytetemp = rtl_read_byte(rtlpriv, + rtlpriv->cfg->maps[EFUSE_CTRL] + 2); + + temp = ((address >> 8) & 0x03) | (bytetemp & 0xFC); + rtl_write_byte(rtlpriv, + rtlpriv->cfg->maps[EFUSE_CTRL] + 2, temp); + + bytetemp = rtl_read_byte(rtlpriv, + rtlpriv->cfg->maps[EFUSE_CTRL] + 3); + temp = bytetemp | 0x80; + rtl_write_byte(rtlpriv, + rtlpriv->cfg->maps[EFUSE_CTRL] + 3, temp); + + bytetemp = rtl_read_byte(rtlpriv, + rtlpriv->cfg->maps[EFUSE_CTRL] + 3); + + while (bytetemp & 0x80) { + bytetemp = + rtl_read_byte(rtlpriv, + rtlpriv->cfg->maps[EFUSE_CTRL] + 3); + k++; + if (k == 100) { + k = 0; + break; + } + } + } +} + +void read_efuse_byte(struct ieee80211_hw *hw, u16 _offset, u8 *pbuf) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 value32; + u8 readbyte; + u16 retry; + + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 1, + (_offset & 0xff)); + readbyte = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 2); + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 2, + ((_offset >> 8) & 0x03) | (readbyte & 0xfc)); + + readbyte = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 3); + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 3, + (readbyte & 0x7f)); + + retry = 0; + value32 = rtl_read_dword(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL]); + while (!(((value32 >> 24) & 0xff) & 0x80) && (retry < 10000)) { + value32 = rtl_read_dword(rtlpriv, + rtlpriv->cfg->maps[EFUSE_CTRL]); + retry++; + } + + udelay(50); + value32 = rtl_read_dword(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL]); + + *pbuf = (u8)(value32 & 0xff); +} + +void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u8 *efuse_tbl; + u8 rtemp8[1]; + u16 efuse_addr = 0; + u8 offset, wren; + u8 u1temp = 0; + u16 i; + u16 j; + const u16 efuse_max_section = + rtlpriv->cfg->maps[EFUSE_MAX_SECTION_MAP]; + const u32 efuse_len = + rtlpriv->cfg->maps[EFUSE_REAL_CONTENT_SIZE]; + u16 **efuse_word; + u16 efuse_utilized = 0; + u8 efuse_usage; + + if ((_offset + _size_byte) > rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]) { + RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD, + "%s(): Invalid offset(%#x) with read bytes(%#x)!!\n", + __func__, _offset, _size_byte); + return; + } + + /* allocate memory for efuse_tbl and efuse_word */ + efuse_tbl = kzalloc(rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE] * + sizeof(u8), GFP_ATOMIC); + if (!efuse_tbl) + return; + efuse_word = kzalloc(EFUSE_MAX_WORD_UNIT * sizeof(u16 *), GFP_ATOMIC); + if (!efuse_word) + goto out; + for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) { + efuse_word[i] = kzalloc(efuse_max_section * sizeof(u16), + GFP_ATOMIC); + if (!efuse_word[i]) + goto done; + } + + for (i = 0; i < efuse_max_section; i++) + for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++) + efuse_word[j][i] = 0xFFFF; + + read_efuse_byte(hw, efuse_addr, rtemp8); + if (*rtemp8 != 0xFF) { + efuse_utilized++; + RTPRINT(rtlpriv, FEEPROM, EFUSE_READ_ALL, + "Addr=%d\n", efuse_addr); + efuse_addr++; + } + + while ((*rtemp8 != 0xFF) && (efuse_addr < efuse_len)) { + /* Check PG header for section num. */ + if ((*rtemp8 & 0x1F) == 0x0F) {/* extended header */ + u1temp = ((*rtemp8 & 0xE0) >> 5); + read_efuse_byte(hw, efuse_addr, rtemp8); + + if ((*rtemp8 & 0x0F) == 0x0F) { + efuse_addr++; + read_efuse_byte(hw, efuse_addr, rtemp8); + + if (*rtemp8 != 0xFF && + (efuse_addr < efuse_len)) { + efuse_addr++; + } + continue; + } else { + offset = ((*rtemp8 & 0xF0) >> 1) | u1temp; + wren = (*rtemp8 & 0x0F); + efuse_addr++; + } + } else { + offset = ((*rtemp8 >> 4) & 0x0f); + wren = (*rtemp8 & 0x0f); + } + + if (offset < efuse_max_section) { + RTPRINT(rtlpriv, FEEPROM, EFUSE_READ_ALL, + "offset-%d Worden=%x\n", offset, wren); + + for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) { + if (!(wren & 0x01)) { + RTPRINT(rtlpriv, FEEPROM, + EFUSE_READ_ALL, + "Addr=%d\n", efuse_addr); + + read_efuse_byte(hw, efuse_addr, rtemp8); + efuse_addr++; + efuse_utilized++; + efuse_word[i][offset] = + (*rtemp8 & 0xff); + + if (efuse_addr >= efuse_len) + break; + + RTPRINT(rtlpriv, FEEPROM, + EFUSE_READ_ALL, + "Addr=%d\n", efuse_addr); + + read_efuse_byte(hw, efuse_addr, rtemp8); + efuse_addr++; + efuse_utilized++; + efuse_word[i][offset] |= + (((u16)*rtemp8 << 8) & 0xff00); + + if (efuse_addr >= efuse_len) + break; + } + + wren >>= 1; + } + } + + RTPRINT(rtlpriv, FEEPROM, EFUSE_READ_ALL, + "Addr=%d\n", efuse_addr); + read_efuse_byte(hw, efuse_addr, rtemp8); + if (*rtemp8 != 0xFF && (efuse_addr < efuse_len)) { + efuse_utilized++; + efuse_addr++; + } + } + + for (i = 0; i < efuse_max_section; i++) { + for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++) { + efuse_tbl[(i * 8) + (j * 2)] = + (efuse_word[j][i] & 0xff); + efuse_tbl[(i * 8) + ((j * 2) + 1)] = + ((efuse_word[j][i] >> 8) & 0xff); + } + } + + for (i = 0; i < _size_byte; i++) + pbuf[i] = efuse_tbl[_offset + i]; + + rtlefuse->efuse_usedbytes = efuse_utilized; + efuse_usage = (u8)((efuse_utilized * 100) / efuse_len); + rtlefuse->efuse_usedpercentage = efuse_usage; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_EFUSE_BYTES, + (u8 *)&efuse_utilized); + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_EFUSE_USAGE, + &efuse_usage); +done: + for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) + kfree(efuse_word[i]); + kfree(efuse_word); +out: + kfree(efuse_tbl); +} + +bool efuse_shadow_update_chk(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u8 section_idx, i, base; + u16 words_need = 0, hdr_num = 0, totalbytes, efuse_used; + bool wordchanged, result = true; + + for (section_idx = 0; section_idx < 16; section_idx++) { + base = section_idx * 8; + wordchanged = false; + + for (i = 0; i < 8; i = i + 2) { + if ((rtlefuse->efuse_map[EFUSE_INIT_MAP][base + i] != + rtlefuse->efuse_map[EFUSE_MODIFY_MAP][base + i]) || + (rtlefuse->efuse_map[EFUSE_INIT_MAP][base + i + 1] != + rtlefuse->efuse_map[EFUSE_MODIFY_MAP][base + i + + 1])) { + words_need++; + wordchanged = true; + } + } + + if (wordchanged) + hdr_num++; + } + + totalbytes = hdr_num + words_need * 2; + efuse_used = rtlefuse->efuse_usedbytes; + + if ((totalbytes + efuse_used) >= + (EFUSE_MAX_SIZE - rtlpriv->cfg->maps[EFUSE_OOB_PROTECT_BYTES_LEN])) + result = false; + + RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD, + "%s(): totalbytes(%#x), hdr_num(%#x), words_need(%#x), efuse_used(%d)\n", + __func__, totalbytes, hdr_num, words_need, efuse_used); + + return result; +} + +void efuse_shadow_read(struct ieee80211_hw *hw, u8 type, + u16 offset, u32 *value) +{ + if (type == 1) + efuse_shadow_read_1byte(hw, offset, (u8 *)value); + else if (type == 2) + efuse_shadow_read_2byte(hw, offset, (u16 *)value); + else if (type == 4) + efuse_shadow_read_4byte(hw, offset, value); +} + +void efuse_shadow_write(struct ieee80211_hw *hw, u8 type, u16 offset, + u32 value) +{ + if (type == 1) + efuse_shadow_write_1byte(hw, offset, (u8)value); + else if (type == 2) + efuse_shadow_write_2byte(hw, offset, (u16)value); + else if (type == 4) + efuse_shadow_write_4byte(hw, offset, value); +} + +bool efuse_shadow_update(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u16 i, offset, base; + u8 word_en = 0x0F; + u8 first_pg = false; + + RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD, "\n"); + + if (!efuse_shadow_update_chk(hw)) { + efuse_read_all_map(hw, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0]); + memcpy(&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][0], + &rtlefuse->efuse_map[EFUSE_INIT_MAP][0], + rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]); + + RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD, + "efuse out of capacity!!\n"); + return false; + } + efuse_power_switch(hw, true, true); + + for (offset = 0; offset < 16; offset++) { + word_en = 0x0F; + base = offset * 8; + + for (i = 0; i < 8; i++) { + if (first_pg) { + word_en &= ~(BIT(i / 2)); + + rtlefuse->efuse_map[EFUSE_INIT_MAP][base + i] = + rtlefuse->efuse_map[EFUSE_MODIFY_MAP][base + i]; + } else { + if (rtlefuse->efuse_map[EFUSE_INIT_MAP][base + i] != + rtlefuse->efuse_map[EFUSE_MODIFY_MAP][base + i]) { + word_en &= ~(BIT(i / 2)); + + rtlefuse->efuse_map[EFUSE_INIT_MAP][base + i] = + rtlefuse->efuse_map[EFUSE_MODIFY_MAP][base + i]; + } + } + } + if (word_en != 0x0F) { + u8 tmpdata[8]; + + memcpy(tmpdata, + &rtlefuse->efuse_map[EFUSE_MODIFY_MAP][base], + 8); + RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_LOUD, + "U-efuse\n", tmpdata, 8); + + if (!efuse_pg_packet_write(hw, (u8)offset, word_en, + tmpdata)) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "PG section(%#x) fail!!\n", offset); + break; + } + } + } + + efuse_power_switch(hw, true, false); + efuse_read_all_map(hw, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0]); + + memcpy(&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][0], + &rtlefuse->efuse_map[EFUSE_INIT_MAP][0], + rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]); + + RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD, "\n"); + return true; +} + +void rtl_efuse_shadow_map_update(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + + if (rtlefuse->autoload_failflag) + memset((&rtlefuse->efuse_map[EFUSE_INIT_MAP][0]), + 0xFF, rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]); + else + efuse_read_all_map(hw, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0]); + + memcpy(&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][0], + &rtlefuse->efuse_map[EFUSE_INIT_MAP][0], + rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]); +} + +void efuse_force_write_vendor_id(struct ieee80211_hw *hw) +{ + u8 tmpdata[8] = { 0xFF, 0xFF, 0xEC, 0x10, 0xFF, 0xFF, 0xFF, 0xFF }; + + efuse_power_switch(hw, true, true); + + efuse_pg_packet_write(hw, 1, 0xD, tmpdata); + + efuse_power_switch(hw, true, false); +} + +void efuse_re_pg_section(struct ieee80211_hw *hw, u8 section_idx) +{ +} + +static void efuse_shadow_read_1byte(struct ieee80211_hw *hw, + u16 offset, u8 *value) +{ + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + *value = rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset]; +} + +static void efuse_shadow_read_2byte(struct ieee80211_hw *hw, + u16 offset, u16 *value) +{ + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + + *value = rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset]; + *value |= rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 1] << 8; +} + +static void efuse_shadow_read_4byte(struct ieee80211_hw *hw, + u16 offset, u32 *value) +{ + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + + *value = rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset]; + *value |= rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 1] << 8; + *value |= rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 2] << 16; + *value |= rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 3] << 24; +} + +static void efuse_shadow_write_1byte(struct ieee80211_hw *hw, + u16 offset, u8 value) +{ + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + + rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset] = value; +} + +static void efuse_shadow_write_2byte(struct ieee80211_hw *hw, + u16 offset, u16 value) +{ + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + + rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset] = value & 0x00FF; + rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 1] = value >> 8; +} + +static void efuse_shadow_write_4byte(struct ieee80211_hw *hw, + u16 offset, u32 value) +{ + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + + rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset] = + (u8)(value & 0x000000FF); + rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 1] = + (u8)((value >> 8) & 0x0000FF); + rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 2] = + (u8)((value >> 16) & 0x00FF); + rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 3] = + (u8)((value >> 24) & 0xFF); +} + +int efuse_one_byte_read(struct ieee80211_hw *hw, u16 addr, u8 *data) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 tmpidx = 0; + int result; + + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 1, + (u8)(addr & 0xff)); + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 2, + ((u8)((addr >> 8) & 0x03)) | + (rtl_read_byte(rtlpriv, + rtlpriv->cfg->maps[EFUSE_CTRL] + 2) & + 0xFC)); + + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 3, 0x72); + + while (!(0x80 & rtl_read_byte(rtlpriv, + rtlpriv->cfg->maps[EFUSE_CTRL] + 3)) && + (tmpidx < 100)) { + tmpidx++; + } + + if (tmpidx < 100) { + *data = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL]); + result = true; + } else { + *data = 0xff; + result = false; + } + return result; +} + +static int efuse_one_byte_write(struct ieee80211_hw *hw, u16 addr, u8 data) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 tmpidx = 0; + + RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD, + "Addr = %x Data=%x\n", addr, data); + + rtl_write_byte(rtlpriv, + rtlpriv->cfg->maps[EFUSE_CTRL] + 1, (u8)(addr & 0xff)); + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 2, + (rtl_read_byte(rtlpriv, + rtlpriv->cfg->maps[EFUSE_CTRL] + + 2) & 0xFC) | (u8)((addr >> 8) & 0x03)); + + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL], data); + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 3, 0xF2); + + while ((0x80 & + rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 3)) && + (tmpidx < 100)) { + tmpidx++; + } + + if (tmpidx < 100) + return true; + return false; +} + +static void efuse_read_all_map(struct ieee80211_hw *hw, u8 *efuse) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + efuse_power_switch(hw, false, true); + read_efuse(hw, 0, rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE], efuse); + efuse_power_switch(hw, false, false); +} + +static void efuse_read_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr, + u8 efuse_data, u8 offset, u8 *tmpdata, + u8 *readstate) +{ + bool dataempty = true; + u8 hoffset; + u8 tmpidx; + u8 hworden; + u8 word_cnts; + + hoffset = (efuse_data >> 4) & 0x0F; + hworden = efuse_data & 0x0F; + word_cnts = efuse_calculate_word_cnts(hworden); + + if (hoffset == offset) { + for (tmpidx = 0; tmpidx < word_cnts * 2; tmpidx++) { + if (efuse_one_byte_read(hw, *efuse_addr + 1 + tmpidx, + &efuse_data)) { + tmpdata[tmpidx] = efuse_data; + if (efuse_data != 0xff) + dataempty = false; + } + } + + if (!dataempty) { + *readstate = PG_STATE_DATA; + } else { + *efuse_addr = *efuse_addr + (word_cnts * 2) + 1; + *readstate = PG_STATE_HEADER; + } + + } else { + *efuse_addr = *efuse_addr + (word_cnts * 2) + 1; + *readstate = PG_STATE_HEADER; + } +} + +static int efuse_pg_packet_read(struct ieee80211_hw *hw, u8 offset, u8 *data) +{ + u8 readstate = PG_STATE_HEADER; + + bool continual = true; + + u8 efuse_data, word_cnts = 0; + u16 efuse_addr = 0; + u8 tmpdata[8]; + + if (!data) + return false; + if (offset > 15) + return false; + + memset(data, 0xff, PGPKT_DATA_SIZE * sizeof(u8)); + memset(tmpdata, 0xff, PGPKT_DATA_SIZE * sizeof(u8)); + + while (continual && (efuse_addr < EFUSE_MAX_SIZE)) { + if (readstate & PG_STATE_HEADER) { + if (efuse_one_byte_read(hw, efuse_addr, &efuse_data) && + (efuse_data != 0xFF)) + efuse_read_data_case1(hw, &efuse_addr, + efuse_data, offset, + tmpdata, &readstate); + else + continual = false; + } else if (readstate & PG_STATE_DATA) { + efuse_word_enable_data_read(0, tmpdata, data); + efuse_addr = efuse_addr + (word_cnts * 2) + 1; + readstate = PG_STATE_HEADER; + } + } + + if ((data[0] == 0xff) && (data[1] == 0xff) && + (data[2] == 0xff) && (data[3] == 0xff) && + (data[4] == 0xff) && (data[5] == 0xff) && + (data[6] == 0xff) && (data[7] == 0xff)) + return false; + return true; +} + +static void efuse_write_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr, + u8 efuse_data, u8 offset, + int *continual, u8 *write_state, + struct pgpkt_struct *target_pkt, + int *repeat_times, int *result, u8 word_en) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct pgpkt_struct tmp_pkt; + int dataempty = true; + u8 originaldata[8 * sizeof(u8)]; + u8 badworden = 0x0F; + u8 match_word_en, tmp_word_en; + u8 tmpindex; + u8 tmp_header = efuse_data; + u8 tmp_word_cnts; + + tmp_pkt.offset = (tmp_header >> 4) & 0x0F; + tmp_pkt.word_en = tmp_header & 0x0F; + tmp_word_cnts = efuse_calculate_word_cnts(tmp_pkt.word_en); + + if (tmp_pkt.offset != target_pkt->offset) { + *efuse_addr = *efuse_addr + (tmp_word_cnts * 2) + 1; + *write_state = PG_STATE_HEADER; + } else { + for (tmpindex = 0; tmpindex < (tmp_word_cnts * 2); tmpindex++) { + if (efuse_one_byte_read(hw, + (*efuse_addr + 1 + tmpindex), + &efuse_data) && + (efuse_data != 0xFF)) + dataempty = false; + } + + if (!dataempty) { + *efuse_addr = *efuse_addr + (tmp_word_cnts * 2) + 1; + *write_state = PG_STATE_HEADER; + } else { + match_word_en = 0x0F; + if (!((target_pkt->word_en & BIT(0)) | + (tmp_pkt.word_en & BIT(0)))) + match_word_en &= (~BIT(0)); + + if (!((target_pkt->word_en & BIT(1)) | + (tmp_pkt.word_en & BIT(1)))) + match_word_en &= (~BIT(1)); + + if (!((target_pkt->word_en & BIT(2)) | + (tmp_pkt.word_en & BIT(2)))) + match_word_en &= (~BIT(2)); + + if (!((target_pkt->word_en & BIT(3)) | + (tmp_pkt.word_en & BIT(3)))) + match_word_en &= (~BIT(3)); + + if ((match_word_en & 0x0F) != 0x0F) { + badworden = + enable_efuse_data_write(hw, + *efuse_addr + 1, + tmp_pkt.word_en, + target_pkt->data); + + if (0x0F != (badworden & 0x0F)) { + u8 reorg_offset = offset; + u8 reorg_worden = badworden; + + efuse_pg_packet_write(hw, reorg_offset, + reorg_worden, + originaldata); + } + + tmp_word_en = 0x0F; + if ((target_pkt->word_en & BIT(0)) ^ + (match_word_en & BIT(0))) + tmp_word_en &= (~BIT(0)); + + if ((target_pkt->word_en & BIT(1)) ^ + (match_word_en & BIT(1))) + tmp_word_en &= (~BIT(1)); + + if ((target_pkt->word_en & BIT(2)) ^ + (match_word_en & BIT(2))) + tmp_word_en &= (~BIT(2)); + + if ((target_pkt->word_en & BIT(3)) ^ + (match_word_en & BIT(3))) + tmp_word_en &= (~BIT(3)); + + if ((tmp_word_en & 0x0F) != 0x0F) { + *efuse_addr = + efuse_get_current_size(hw); + target_pkt->offset = offset; + target_pkt->word_en = tmp_word_en; + } else { + *continual = false; + } + *write_state = PG_STATE_HEADER; + *repeat_times += 1; + if (*repeat_times > EFUSE_REPEAT_THRESHOLD_) { + *continual = false; + *result = false; + } + } else { + *efuse_addr += (2 * tmp_word_cnts) + 1; + target_pkt->offset = offset; + target_pkt->word_en = word_en; + *write_state = PG_STATE_HEADER; + } + } + } + RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, "efuse PG_STATE_HEADER-1\n"); +} + +static void efuse_write_data_case2(struct ieee80211_hw *hw, u16 *efuse_addr, + int *continual, u8 *write_state, + struct pgpkt_struct target_pkt, + int *repeat_times, int *result) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct pgpkt_struct tmp_pkt; + u8 pg_header; + u8 tmp_header; + u8 originaldata[8 * sizeof(u8)]; + u8 tmp_word_cnts; + u8 badworden = 0x0F; + + pg_header = ((target_pkt.offset << 4) & 0xf0) | target_pkt.word_en; + efuse_one_byte_write(hw, *efuse_addr, pg_header); + efuse_one_byte_read(hw, *efuse_addr, &tmp_header); + + if (tmp_header == pg_header) { + *write_state = PG_STATE_DATA; + } else if (tmp_header == 0xFF) { + *write_state = PG_STATE_HEADER; + *repeat_times += 1; + if (*repeat_times > EFUSE_REPEAT_THRESHOLD_) { + *continual = false; + *result = false; + } + } else { + tmp_pkt.offset = (tmp_header >> 4) & 0x0F; + tmp_pkt.word_en = tmp_header & 0x0F; + + tmp_word_cnts = efuse_calculate_word_cnts(tmp_pkt.word_en); + + memset(originaldata, 0xff, 8 * sizeof(u8)); + + if (efuse_pg_packet_read(hw, tmp_pkt.offset, originaldata)) { + badworden = enable_efuse_data_write(hw, + *efuse_addr + 1, + tmp_pkt.word_en, + originaldata); + + if (0x0F != (badworden & 0x0F)) { + u8 reorg_offset = tmp_pkt.offset; + u8 reorg_worden = badworden; + + efuse_pg_packet_write(hw, reorg_offset, + reorg_worden, + originaldata); + *efuse_addr = efuse_get_current_size(hw); + } else { + *efuse_addr = *efuse_addr + + (tmp_word_cnts * 2) + 1; + } + } else { + *efuse_addr = *efuse_addr + (tmp_word_cnts * 2) + 1; + } + + *write_state = PG_STATE_HEADER; + *repeat_times += 1; + if (*repeat_times > EFUSE_REPEAT_THRESHOLD_) { + *continual = false; + *result = false; + } + + RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, + "efuse PG_STATE_HEADER-2\n"); + } +} + +static int efuse_pg_packet_write(struct ieee80211_hw *hw, + u8 offset, u8 word_en, u8 *data) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct pgpkt_struct target_pkt; + u8 write_state = PG_STATE_HEADER; + int continual = true, dataempty = true, result = true; + u16 efuse_addr = 0; + u8 efuse_data; + u8 target_word_cnts = 0; + u8 badworden = 0x0F; + static int repeat_times; + + if (efuse_get_current_size(hw) >= (EFUSE_MAX_SIZE - + rtlpriv->cfg->maps[EFUSE_OOB_PROTECT_BYTES_LEN])) { + RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, + "%s error\n", __func__); + return false; + } + + target_pkt.offset = offset; + target_pkt.word_en = word_en; + + memset(target_pkt.data, 0xFF, 8 * sizeof(u8)); + + efuse_word_enable_data_read(word_en, data, target_pkt.data); + target_word_cnts = efuse_calculate_word_cnts(target_pkt.word_en); + + RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, "efuse Power ON\n"); + + while (continual && (efuse_addr < (EFUSE_MAX_SIZE - + rtlpriv->cfg->maps[EFUSE_OOB_PROTECT_BYTES_LEN]))) { + if (write_state == PG_STATE_HEADER) { + dataempty = true; + badworden = 0x0F; + RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, + "efuse PG_STATE_HEADER\n"); + + if (efuse_one_byte_read(hw, efuse_addr, &efuse_data) && + (efuse_data != 0xFF)) + efuse_write_data_case1(hw, &efuse_addr, + efuse_data, offset, + &continual, + &write_state, + &target_pkt, + &repeat_times, &result, + word_en); + else + efuse_write_data_case2(hw, &efuse_addr, + &continual, + &write_state, + target_pkt, + &repeat_times, + &result); + + } else if (write_state == PG_STATE_DATA) { + RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, + "efuse PG_STATE_DATA\n"); + badworden = 0x0f; + badworden = + enable_efuse_data_write(hw, efuse_addr + 1, + target_pkt.word_en, + target_pkt.data); + + if ((badworden & 0x0F) == 0x0F) { + continual = false; + } else { + efuse_addr = + efuse_addr + (2 * target_word_cnts) + 1; + + target_pkt.offset = offset; + target_pkt.word_en = badworden; + target_word_cnts = + efuse_calculate_word_cnts(target_pkt.word_en); + write_state = PG_STATE_HEADER; + repeat_times++; + if (repeat_times > EFUSE_REPEAT_THRESHOLD_) { + continual = false; + result = false; + } + RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, + "efuse PG_STATE_HEADER-3\n"); + } + } + } + + if (efuse_addr >= (EFUSE_MAX_SIZE - + rtlpriv->cfg->maps[EFUSE_OOB_PROTECT_BYTES_LEN])) { + RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD, + "efuse_addr(%#x) Out of size!!\n", efuse_addr); + } + + return true; +} + +static void efuse_word_enable_data_read(u8 word_en, u8 *sourdata, + u8 *targetdata) +{ + if (!(word_en & BIT(0))) { + targetdata[0] = sourdata[0]; + targetdata[1] = sourdata[1]; + } + + if (!(word_en & BIT(1))) { + targetdata[2] = sourdata[2]; + targetdata[3] = sourdata[3]; + } + + if (!(word_en & BIT(2))) { + targetdata[4] = sourdata[4]; + targetdata[5] = sourdata[5]; + } + + if (!(word_en & BIT(3))) { + targetdata[6] = sourdata[6]; + targetdata[7] = sourdata[7]; + } +} + +static u8 enable_efuse_data_write(struct ieee80211_hw *hw, + u16 efuse_addr, u8 word_en, u8 *data) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u16 tmpaddr; + u16 start_addr = efuse_addr; + u8 badworden = 0x0F; + u8 tmpdata[8]; + + memset(tmpdata, 0xff, PGPKT_DATA_SIZE); + RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD, + "word_en = %x efuse_addr=%x\n", word_en, efuse_addr); + + if (!(word_en & BIT(0))) { + tmpaddr = start_addr; + efuse_one_byte_write(hw, start_addr++, data[0]); + efuse_one_byte_write(hw, start_addr++, data[1]); + + efuse_one_byte_read(hw, tmpaddr, &tmpdata[0]); + efuse_one_byte_read(hw, tmpaddr + 1, &tmpdata[1]); + if ((data[0] != tmpdata[0]) || (data[1] != tmpdata[1])) + badworden &= (~BIT(0)); + } + + if (!(word_en & BIT(1))) { + tmpaddr = start_addr; + efuse_one_byte_write(hw, start_addr++, data[2]); + efuse_one_byte_write(hw, start_addr++, data[3]); + + efuse_one_byte_read(hw, tmpaddr, &tmpdata[2]); + efuse_one_byte_read(hw, tmpaddr + 1, &tmpdata[3]); + if ((data[2] != tmpdata[2]) || (data[3] != tmpdata[3])) + badworden &= (~BIT(1)); + } + + if (!(word_en & BIT(2))) { + tmpaddr = start_addr; + efuse_one_byte_write(hw, start_addr++, data[4]); + efuse_one_byte_write(hw, start_addr++, data[5]); + + efuse_one_byte_read(hw, tmpaddr, &tmpdata[4]); + efuse_one_byte_read(hw, tmpaddr + 1, &tmpdata[5]); + if ((data[4] != tmpdata[4]) || (data[5] != tmpdata[5])) + badworden &= (~BIT(2)); + } + + if (!(word_en & BIT(3))) { + tmpaddr = start_addr; + efuse_one_byte_write(hw, start_addr++, data[6]); + efuse_one_byte_write(hw, start_addr++, data[7]); + + efuse_one_byte_read(hw, tmpaddr, &tmpdata[6]); + efuse_one_byte_read(hw, tmpaddr + 1, &tmpdata[7]); + if ((data[6] != tmpdata[6]) || (data[7] != tmpdata[7])) + badworden &= (~BIT(3)); + } + + return badworden; +} + +void efuse_power_switch(struct ieee80211_hw *hw, u8 write, u8 pwrstate) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u8 tempval; + u16 tmpv16; + + if (pwrstate && (rtlhal->hw_type != HARDWARE_TYPE_RTL8192SE)) { + if (rtlhal->hw_type != HARDWARE_TYPE_RTL8192CE && + rtlhal->hw_type != HARDWARE_TYPE_RTL8192DE) { + rtl_write_byte(rtlpriv, + rtlpriv->cfg->maps[EFUSE_ACCESS], 0x69); + } else { + tmpv16 = + rtl_read_word(rtlpriv, + rtlpriv->cfg->maps[SYS_ISO_CTRL]); + if (!(tmpv16 & rtlpriv->cfg->maps[EFUSE_PWC_EV12V])) { + tmpv16 |= rtlpriv->cfg->maps[EFUSE_PWC_EV12V]; + rtl_write_word(rtlpriv, + rtlpriv->cfg->maps[SYS_ISO_CTRL], + tmpv16); + } + } + tmpv16 = rtl_read_word(rtlpriv, + rtlpriv->cfg->maps[SYS_FUNC_EN]); + if (!(tmpv16 & rtlpriv->cfg->maps[EFUSE_FEN_ELDR])) { + tmpv16 |= rtlpriv->cfg->maps[EFUSE_FEN_ELDR]; + rtl_write_word(rtlpriv, + rtlpriv->cfg->maps[SYS_FUNC_EN], tmpv16); + } + + tmpv16 = rtl_read_word(rtlpriv, rtlpriv->cfg->maps[SYS_CLK]); + if ((!(tmpv16 & rtlpriv->cfg->maps[EFUSE_LOADER_CLK_EN])) || + (!(tmpv16 & rtlpriv->cfg->maps[EFUSE_ANA8M]))) { + tmpv16 |= (rtlpriv->cfg->maps[EFUSE_LOADER_CLK_EN] | + rtlpriv->cfg->maps[EFUSE_ANA8M]); + rtl_write_word(rtlpriv, + rtlpriv->cfg->maps[SYS_CLK], tmpv16); + } + } + + if (pwrstate) { + if (write) { + tempval = rtl_read_byte(rtlpriv, + rtlpriv->cfg->maps[EFUSE_TEST] + + 3); + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) { + tempval &= ~(BIT(3) | BIT(4) | BIT(5) | BIT(6)); + tempval |= (VOLTAGE_V25 << 3); + } else if (rtlhal->hw_type != HARDWARE_TYPE_RTL8192SE) { + tempval &= 0x0F; + tempval |= (VOLTAGE_V25 << 4); + } + + rtl_write_byte(rtlpriv, + rtlpriv->cfg->maps[EFUSE_TEST] + 3, + (tempval | 0x80)); + } + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) { + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CLK], + 0x03); + } + } else { + if (rtlhal->hw_type != HARDWARE_TYPE_RTL8192CE && + rtlhal->hw_type != HARDWARE_TYPE_RTL8192DE) + rtl_write_byte(rtlpriv, + rtlpriv->cfg->maps[EFUSE_ACCESS], 0); + + if (write) { + tempval = rtl_read_byte(rtlpriv, + rtlpriv->cfg->maps[EFUSE_TEST] + + 3); + rtl_write_byte(rtlpriv, + rtlpriv->cfg->maps[EFUSE_TEST] + 3, + (tempval & 0x7F)); + } + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) { + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CLK], + 0x02); + } + } +} + +static u16 efuse_get_current_size(struct ieee80211_hw *hw) +{ + int continual = true; + u16 efuse_addr = 0; + u8 hoffset, hworden; + u8 efuse_data, word_cnts; + + while (continual && efuse_one_byte_read(hw, efuse_addr, &efuse_data) && + (efuse_addr < EFUSE_MAX_SIZE)) { + if (efuse_data != 0xFF) { + hoffset = (efuse_data >> 4) & 0x0F; + hworden = efuse_data & 0x0F; + word_cnts = efuse_calculate_word_cnts(hworden); + efuse_addr = efuse_addr + (word_cnts * 2) + 1; + } else { + continual = false; + } + } + + return efuse_addr; +} + +static u8 efuse_calculate_word_cnts(u8 word_en) +{ + u8 word_cnts = 0; + + if (!(word_en & BIT(0))) + word_cnts++; + if (!(word_en & BIT(1))) + word_cnts++; + if (!(word_en & BIT(2))) + word_cnts++; + if (!(word_en & BIT(3))) + word_cnts++; + return word_cnts; +} + +int rtl_get_hwinfo(struct ieee80211_hw *hw, struct rtl_priv *rtlpriv, + int max_size, u8 *hwinfo, int *params) +{ + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + struct device *dev = &rtlpcipriv->dev.pdev->dev; + u16 eeprom_id; + u16 i, usvalue; + + switch (rtlefuse->epromtype) { + case EEPROM_BOOT_EFUSE: + rtl_efuse_shadow_map_update(hw); + break; + + case EEPROM_93C46: + pr_err("RTL8XXX did not boot from eeprom, check it !!\n"); + return 1; + + default: + dev_warn(dev, "no efuse data\n"); + return 1; + } + + memcpy(hwinfo, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0], max_size); + + RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, "MAP", + hwinfo, max_size); + + eeprom_id = *((u16 *)&hwinfo[0]); + if (eeprom_id != params[0]) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "EEPROM ID(%#x) is invalid!!\n", eeprom_id); + rtlefuse->autoload_failflag = true; + } else { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Autoload OK\n"); + rtlefuse->autoload_failflag = false; + } + + if (rtlefuse->autoload_failflag) + return 1; + + rtlefuse->eeprom_vid = *(u16 *)&hwinfo[params[1]]; + rtlefuse->eeprom_did = *(u16 *)&hwinfo[params[2]]; + rtlefuse->eeprom_svid = *(u16 *)&hwinfo[params[3]]; + rtlefuse->eeprom_smid = *(u16 *)&hwinfo[params[4]]; + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "EEPROMId = 0x%4x\n", eeprom_id); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "EEPROM VID = 0x%4x\n", rtlefuse->eeprom_vid); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "EEPROM DID = 0x%4x\n", rtlefuse->eeprom_did); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "EEPROM SVID = 0x%4x\n", rtlefuse->eeprom_svid); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "EEPROM SMID = 0x%4x\n", rtlefuse->eeprom_smid); + + for (i = 0; i < 6; i += 2) { + usvalue = *(u16 *)&hwinfo[params[5] + i]; + *((u16 *)(&rtlefuse->dev_addr[i])) = usvalue; + } + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "%pM\n", rtlefuse->dev_addr); + + rtlefuse->eeprom_channelplan = *&hwinfo[params[6]]; + rtlefuse->eeprom_version = *(u16 *)&hwinfo[params[7]]; + rtlefuse->txpwr_fromeprom = true; + rtlefuse->eeprom_oemid = *&hwinfo[params[8]]; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "EEPROM Customer ID: 0x%2x\n", rtlefuse->eeprom_oemid); + + /* set channel plan to world wide 13 */ + rtlefuse->channel_plan = params[9]; + + return 0; +} + +void rtl_fw_block_write(struct ieee80211_hw *hw, const u8 *buffer, u32 size) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 *pu4byteptr = (u8 *)buffer; + u32 i; + + for (i = 0; i < size; i++) + rtl_write_byte(rtlpriv, (START_ADDRESS + i), *(pu4byteptr + i)); +} + +void rtl_fw_page_write(struct ieee80211_hw *hw, u32 page, const u8 *buffer, + u32 size) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 value8; + u8 u8page = (u8)(page & 0x07); + + value8 = (rtl_read_byte(rtlpriv, REG_MCUFWDL + 2) & 0xF8) | u8page; + + rtl_write_byte(rtlpriv, (REG_MCUFWDL + 2), value8); + rtl_fw_block_write(hw, buffer, size); +} + +void rtl_fill_dummy(u8 *pfwbuf, u32 *pfwlen) +{ + u32 fwlen = *pfwlen; + u8 remain = (u8)(fwlen % 4); + + remain = (remain == 0) ? 0 : (4 - remain); + + while (remain > 0) { + pfwbuf[fwlen] = 0; + fwlen++; + remain--; + } + + *pfwlen = fwlen; +} diff --git a/drivers/staging/rtlwifi/efuse.h b/drivers/staging/rtlwifi/efuse.h new file mode 100644 index 000000000000..0a23305b0b7a --- /dev/null +++ b/drivers/staging/rtlwifi/efuse.h @@ -0,0 +1,120 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL_EFUSE_H_ +#define __RTL_EFUSE_H_ + +#define EFUSE_IC_ID_OFFSET 506 + +#define EFUSE_MAX_WORD_UNIT 4 + +#define EFUSE_INIT_MAP 0 +#define EFUSE_MODIFY_MAP 1 + +#define PG_STATE_HEADER 0x01 +#define PG_STATE_WORD_0 0x02 +#define PG_STATE_WORD_1 0x04 +#define PG_STATE_WORD_2 0x08 +#define PG_STATE_WORD_3 0x10 +#define PG_STATE_DATA 0x20 + +#define EFUSE_REPEAT_THRESHOLD_ 3 +#define EFUSE_ERROE_HANDLE 1 + +struct efuse_map { + u8 offset; + u8 word_start; + u8 byte_start; + u8 byte_cnts; +}; + +struct pgpkt_struct { + u8 offset; + u8 word_en; + u8 data[8]; +}; + +enum efuse_data_item { + EFUSE_CHIP_ID = 0, + EFUSE_LDO_SETTING, + EFUSE_CLK_SETTING, + EFUSE_SDIO_SETTING, + EFUSE_CCCR, + EFUSE_SDIO_MODE, + EFUSE_OCR, + EFUSE_F0CIS, + EFUSE_F1CIS, + EFUSE_MAC_ADDR, + EFUSE_EEPROM_VER, + EFUSE_CHAN_PLAN, + EFUSE_TXPW_TAB +}; + +enum { + VOLTAGE_V25 = 0x03, + LDOE25_SHIFT = 28, +}; + +struct efuse_priv { + u8 id[2]; + u8 ldo_setting[2]; + u8 clk_setting[2]; + u8 cccr; + u8 sdio_mode; + u8 ocr[3]; + u8 cis0[17]; + u8 cis1[48]; + u8 mac_addr[6]; + u8 eeprom_verno; + u8 channel_plan; + u8 tx_power_b[14]; + u8 tx_power_g[14]; +}; + +void read_efuse_byte(struct ieee80211_hw *hw, u16 _offset, u8 *pbuf); +void efuse_initialize(struct ieee80211_hw *hw); +u8 efuse_read_1byte(struct ieee80211_hw *hw, u16 address); +int efuse_one_byte_read(struct ieee80211_hw *hw, u16 addr, u8 *data); +void efuse_write_1byte(struct ieee80211_hw *hw, u16 address, u8 value); +void read_efuse(struct ieee80211_hw *hw, u16 _offset, + u16 _size_byte, u8 *pbuf); +void efuse_shadow_read(struct ieee80211_hw *hw, u8 type, + u16 offset, u32 *value); +void efuse_shadow_write(struct ieee80211_hw *hw, u8 type, + u16 offset, u32 value); +bool efuse_shadow_update(struct ieee80211_hw *hw); +bool efuse_shadow_update_chk(struct ieee80211_hw *hw); +void rtl_efuse_shadow_map_update(struct ieee80211_hw *hw); +void efuse_force_write_vendor_id(struct ieee80211_hw *hw); +void efuse_re_pg_section(struct ieee80211_hw *hw, u8 section_idx); +void efuse_power_switch(struct ieee80211_hw *hw, u8 write, u8 pwrstate); +int rtl_get_hwinfo(struct ieee80211_hw *hw, struct rtl_priv *rtlpriv, + int max_size, u8 *hwinfo, int *params); +void rtl_fill_dummy(u8 *pfwbuf, u32 *pfwlen); +void rtl_fw_page_write(struct ieee80211_hw *hw, u32 page, const u8 *buffer, + u32 size); +void rtl_fw_block_write(struct ieee80211_hw *hw, const u8 *buffer, u32 size); + +#endif diff --git a/drivers/staging/rtlwifi/halmac/halmac_2_platform.h b/drivers/staging/rtlwifi/halmac/halmac_2_platform.h new file mode 100644 index 000000000000..26e60cb873eb --- /dev/null +++ b/drivers/staging/rtlwifi/halmac/halmac_2_platform.h @@ -0,0 +1,52 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef _HALMAC_2_PLATFORM_H_ +#define _HALMAC_2_PLATFORM_H_ + +#include "../wifi.h" +#include <asm/byteorder.h> + +#define HALMAC_PLATFORM_LITTLE_ENDIAN 1 +#define HALMAC_PLATFORM_BIG_ENDIAN 0 + +/* Note : Named HALMAC_PLATFORM_LITTLE_ENDIAN / HALMAC_PLATFORM_BIG_ENDIAN + * is not mandatory. But Little endian must be '1'. Big endian must be '0' + */ +#if defined(__LITTLE_ENDIAN) +#define HALMAC_SYSTEM_ENDIAN HALMAC_PLATFORM_LITTLE_ENDIAN +#elif defined(__BIG_ENDIAN) +#define HALMAC_SYSTEM_ENDIAN HALMAC_PLATFORM_BIG_ENDIAN +#else +#error +#endif + +/* define the Platform SDIO Bus CLK */ +#define PLATFORM_SD_CLK 50000000 /*50MHz*/ + +/* define the Rx FIFO expanding mode packet size unit for 8821C and 8822B */ +/* Should be 8 Byte alignment */ +#define HALMAC_RX_FIFO_EXPANDING_MODE_PKT_SIZE 16 /*Bytes*/ + +#endif /* _HALMAC_2_PLATFORM_H_ */ diff --git a/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_8822b/halmac_8822b_cfg.h b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_8822b/halmac_8822b_cfg.h new file mode 100644 index 000000000000..04e44aed9b45 --- /dev/null +++ b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_8822b/halmac_8822b_cfg.h @@ -0,0 +1,132 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef _HALMAC_8822B_CFG_H_ +#define _HALMAC_8822B_CFG_H_ + +#include "halmac_8822b_pwr_seq.h" +#include "halmac_api_8822b.h" +#include "halmac_api_8822b_usb.h" +#include "halmac_api_8822b_sdio.h" +#include "halmac_api_8822b_pcie.h" +#include "../../halmac_bit2.h" +#include "../../halmac_reg2.h" +#include "../../halmac_api.h" + +#define HALMAC_TX_FIFO_SIZE_8822B 262144 /* 256k */ +#define HALMAC_TX_FIFO_SIZE_LA_8822B 131072 /* 128k */ +#define HALMAC_RX_FIFO_SIZE_8822B 24576 /* 24k */ +#define HALMAC_TX_PAGE_SIZE_8822B 128 /* PageSize 128Byte */ +#define HALMAC_TX_ALIGN_SIZE_8822B 8 +#define HALMAC_TX_PAGE_SIZE_2_POWER_8822B 7 /* 128 = 2^7 */ +#define HALMAC_SECURITY_CAM_ENTRY_NUM_8822B 64 /* CAM Entry size */ +#define HALMAC_TX_AGG_ALIGNMENT_SIZE_8822B 8 +#define HALMAC_TX_DESC_SIZE_8822B 48 +#define HALMAC_RX_DESC_SIZE_8822B 24 +#define HALMAC_RX_DESC_DUMMY_SIZE_MAX_8822B 120 +#define HALMAC_C2H_PKT_BUF_8822B 256 +#define HALMAC_RX_FIFO_EXPANDING_MODE_PKT_SIZE_MAX_8822B 80 /* align 8 Byte*/ +#define HALMAC_RX_FIFO_EXPANDING_UNIT_8822B \ + (HALMAC_RX_DESC_SIZE_8822B + HALMAC_RX_DESC_DUMMY_SIZE_MAX_8822B + \ + HALMAC_RX_FIFO_EXPANDING_MODE_PKT_SIZE) /* align 8 Byte*/ +#define HALMAC_RX_FIFO_EXPANDING_UNIT_MAX_8822B \ + (HALMAC_RX_DESC_SIZE_8822B + HALMAC_RX_DESC_DUMMY_SIZE_MAX_8822B + \ + HALMAC_RX_FIFO_EXPANDING_MODE_PKT_SIZE_MAX_8822B) /* align 8 Byte*/ + +#define HALMAC_TX_FIFO_SIZE_EX_1_BLK_8822B 196608 /* 192k */ +#define HALMAC_RX_FIFO_SIZE_EX_1_BLK_8822B \ + ((((HALMAC_RX_FIFO_EXPANDING_UNIT_8822B << 8) - 1) >> 10) \ + << 10) /* < 56k*/ +#define HALMAC_RX_FIFO_SIZE_EX_1_BLK_MAX_8822B \ + ((((HALMAC_RX_FIFO_EXPANDING_UNIT_MAX_8822B << 8) - 1) >> 10) \ + << 10) /* 55k*/ +#define HALMAC_TX_FIFO_SIZE_EX_2_BLK_8822B 131072 /* 128k */ +#define HALMAC_RX_FIFO_SIZE_EX_2_BLK_8822B 155648 /* 152k */ +#define HALMAC_TX_FIFO_SIZE_EX_3_BLK_8822B 65536 /* 64k */ +#define HALMAC_RX_FIFO_SIZE_EX_3_BLK_8822B 221184 /* 216k */ + +/* TXFIFO LAYOUT + * HIGH_QUEUE + * NORMAL_QUEUE + * LOW_QUEUE + * EXTRA_QUEUE + * PUBLIC_QUEUE -- decided after all other queue are defined + * GAP_QUEUE -- Used to separate AC queue and Rsvd page + * + * RSVD_DRIVER -- Driver used rsvd page area + * RSVD_H2C_EXTRAINFO -- Extra Information for h2c + * RSVD_H2C_QUEUE -- h2c queue in rsvd page + * RSVD_CPU_INSTRUCTION -- extend fw code + * RSVD_FW_TXBUFF -- fw used this area to send packet + * + * Symbol: HALMAC_MODE_QUEUE_UNIT_CHIP, ex: HALMAC_LB_2BULKOUT_FWCMD_PGNUM_8822B + */ +#define HALMAC_EXTRA_INFO_BUFF_SIZE_FULL_FIFO_8822B \ + 16384 /*16K, only used in init case*/ + +#define HALMAC_RSVD_DRV_PGNUM_8822B 16 /*2048*/ +#define HALMAC_RSVD_H2C_EXTRAINFO_PGNUM_8822B 32 /*4096*/ +#define HALMAC_RSVD_H2C_QUEUE_PGNUM_8822B 8 /*1024*/ +#define HALMAC_RSVD_CPU_INSTRUCTION_PGNUM_8822B 0 /*0*/ +#define HALMAC_RSVD_FW_TXBUFF_PGNUM_8822B 4 /*512*/ + +#define HALMAC_EFUSE_SIZE_8822B 1024 /* 0x400 */ +#define HALMAC_BT_EFUSE_SIZE_8822B 128 /* 0x80 */ +#define HALMAC_EEPROM_SIZE_8822B 0x300 +#define HALMAC_CR_TRX_ENABLE_8822B \ + (BIT_HCI_TXDMA_EN | BIT_HCI_RXDMA_EN | BIT_TXDMA_EN | BIT_RXDMA_EN | \ + BIT_PROTOCOL_EN | BIT_SCHEDULE_EN | BIT_MACTXEN | BIT_MACRXEN) + +#define HALMAC_BLK_DESC_NUM_8822B 0x3 /* Only for USB */ + +/* AMPDU max time (unit : 32us) */ +#define HALMAC_AMPDU_MAX_TIME_8822B 0x70 + +/* Protect mode control */ +#define HALMAC_PROT_RTS_LEN_TH_8822B 0xFF +#define HALMAC_PROT_RTS_TX_TIME_TH_8822B 0x08 +#define HALMAC_PROT_MAX_AGG_PKT_LIMIT_8822B 0x20 +#define HALMAC_PROT_RTS_MAX_AGG_PKT_LIMIT_8822B 0x20 + +/* Fast EDCA setting */ +#define HALMAC_FAST_EDCA_VO_TH_8822B 0x06 +#define HALMAC_FAST_EDCA_VI_TH_8822B 0x06 +#define HALMAC_FAST_EDCA_BE_TH_8822B 0x06 +#define HALMAC_FAST_EDCA_BK_TH_8822B 0x06 + +/* BAR setting */ +#define HALMAC_BAR_RETRY_LIMIT_8822B 0x01 +#define HALMAC_RA_TRY_RATE_AGG_LIMIT_8822B 0x08 + +enum halmac_normal_rxagg_th_to_8822b { + HALMAC_NORMAL_RXAGG_THRESHOLD_8822B = 0xFF, + HALMAC_NORMAL_RXAGG_TIMEOUT_8822B = 0x01, +}; + +enum halmac_loopback_rxagg_th_to_8822b { + HALMAC_LOOPBACK_RXAGG_THRESHOLD_8822B = 0xFF, + HALMAC_LOOPBACK_RXAGG_TIMEOUT_8822B = 0x01, +}; + +#endif diff --git a/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_8822b/halmac_8822b_phy.c b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_8822b/halmac_8822b_phy.c new file mode 100644 index 000000000000..b2a5aed75dca --- /dev/null +++ b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_8822b/halmac_8822b_phy.c @@ -0,0 +1,106 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#include "../halmac_88xx_cfg.h" +#include "halmac_8822b_cfg.h" + +/** + * ============ip sel item list============ + * HALMAC_IP_SEL_INTF_PHY + * USB2 : usb2 phy, 1byte value + * USB3 : usb3 phy, 2byte value + * PCIE1 : pcie gen1 mdio, 2byte value + * PCIE2 : pcie gen2 mdio, 2byte value + * HALMAC_IP_SEL_MAC + * USB2, USB3, PCIE1, PCIE2 : mac ip, 1byte value + * HALMAC_IP_SEL_PCIE_DBI + * USB2 USB3 : none + * PCIE1, PCIE2 : pcie dbi, 1byte value + */ + +struct halmac_intf_phy_para_ HALMAC_RTL8822B_USB2_PHY[] = { + /* {offset, value, ip sel, cut mask, platform mask} */ + {0xFFFF, 0x00, HALMAC_IP_SEL_INTF_PHY, HALMAC_INTF_PHY_CUT_ALL, + HALMAC_INTF_PHY_PLATFORM_ALL}, +}; + +struct halmac_intf_phy_para_ HALMAC_RTL8822B_USB3_PHY[] = { + /* {offset, value, ip sel, cut mask, platform mask} */ + {0x0001, 0xA841, HALMAC_IP_SEL_INTF_PHY, HALMAC_INTF_PHY_CUT_D, + HALMAC_INTF_PHY_PLATFORM_ALL}, + {0xFFFF, 0x0000, HALMAC_IP_SEL_INTF_PHY, HALMAC_INTF_PHY_CUT_ALL, + HALMAC_INTF_PHY_PLATFORM_ALL}, +}; + +struct halmac_intf_phy_para_ HALMAC_RTL8822B_PCIE_PHY_GEN1[] = { + /* {offset, value, ip sel, cut mask, platform mask} */ + {0x0001, 0xA841, HALMAC_IP_SEL_INTF_PHY, HALMAC_INTF_PHY_CUT_C, + HALMAC_INTF_PHY_PLATFORM_ALL}, + {0x0002, 0x60C6, HALMAC_IP_SEL_INTF_PHY, HALMAC_INTF_PHY_CUT_C, + HALMAC_INTF_PHY_PLATFORM_ALL}, + {0x0008, 0x3596, HALMAC_IP_SEL_INTF_PHY, HALMAC_INTF_PHY_CUT_C, + HALMAC_INTF_PHY_PLATFORM_ALL}, + {0x0009, 0x321C, HALMAC_IP_SEL_INTF_PHY, HALMAC_INTF_PHY_CUT_C, + HALMAC_INTF_PHY_PLATFORM_ALL}, + {0x000A, 0x9623, HALMAC_IP_SEL_INTF_PHY, HALMAC_INTF_PHY_CUT_C, + HALMAC_INTF_PHY_PLATFORM_ALL}, + {0x0020, 0x94FF, HALMAC_IP_SEL_INTF_PHY, HALMAC_INTF_PHY_CUT_C, + HALMAC_INTF_PHY_PLATFORM_ALL}, + {0x0021, 0xFFCF, HALMAC_IP_SEL_INTF_PHY, HALMAC_INTF_PHY_CUT_C, + HALMAC_INTF_PHY_PLATFORM_ALL}, + {0x0026, 0xC006, HALMAC_IP_SEL_INTF_PHY, HALMAC_INTF_PHY_CUT_C, + HALMAC_INTF_PHY_PLATFORM_ALL}, + {0x0029, 0xFF0E, HALMAC_IP_SEL_INTF_PHY, HALMAC_INTF_PHY_CUT_C, + HALMAC_INTF_PHY_PLATFORM_ALL}, + {0x002A, 0x1840, HALMAC_IP_SEL_INTF_PHY, HALMAC_INTF_PHY_CUT_C, + HALMAC_INTF_PHY_PLATFORM_ALL}, + {0xFFFF, 0x0000, HALMAC_IP_SEL_INTF_PHY, HALMAC_INTF_PHY_CUT_ALL, + HALMAC_INTF_PHY_PLATFORM_ALL}, +}; + +struct halmac_intf_phy_para_ HALMAC_RTL8822B_PCIE_PHY_GEN2[] = { + /* {offset, value, ip sel, cut mask, platform mask} */ + {0x0001, 0xA841, HALMAC_IP_SEL_INTF_PHY, HALMAC_INTF_PHY_CUT_C, + HALMAC_INTF_PHY_PLATFORM_ALL}, + {0x0002, 0x60C6, HALMAC_IP_SEL_INTF_PHY, HALMAC_INTF_PHY_CUT_C, + HALMAC_INTF_PHY_PLATFORM_ALL}, + {0x0008, 0x3597, HALMAC_IP_SEL_INTF_PHY, HALMAC_INTF_PHY_CUT_C, + HALMAC_INTF_PHY_PLATFORM_ALL}, + {0x0009, 0x321C, HALMAC_IP_SEL_INTF_PHY, HALMAC_INTF_PHY_CUT_C, + HALMAC_INTF_PHY_PLATFORM_ALL}, + {0x000A, 0x9623, HALMAC_IP_SEL_INTF_PHY, HALMAC_INTF_PHY_CUT_C, + HALMAC_INTF_PHY_PLATFORM_ALL}, + {0x0020, 0x94FF, HALMAC_IP_SEL_INTF_PHY, HALMAC_INTF_PHY_CUT_C, + HALMAC_INTF_PHY_PLATFORM_ALL}, + {0x0021, 0xFFCF, HALMAC_IP_SEL_INTF_PHY, HALMAC_INTF_PHY_CUT_C, + HALMAC_INTF_PHY_PLATFORM_ALL}, + {0x0026, 0xC006, HALMAC_IP_SEL_INTF_PHY, HALMAC_INTF_PHY_CUT_C, + HALMAC_INTF_PHY_PLATFORM_ALL}, + {0x0029, 0xFF0E, HALMAC_IP_SEL_INTF_PHY, HALMAC_INTF_PHY_CUT_C, + HALMAC_INTF_PHY_PLATFORM_ALL}, + {0x002A, 0x3040, HALMAC_IP_SEL_INTF_PHY, HALMAC_INTF_PHY_CUT_C, + HALMAC_INTF_PHY_PLATFORM_ALL}, + {0xFFFF, 0x0000, HALMAC_IP_SEL_INTF_PHY, HALMAC_INTF_PHY_CUT_ALL, + HALMAC_INTF_PHY_PLATFORM_ALL}, +}; diff --git a/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_8822b/halmac_8822b_pwr_seq.c b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_8822b/halmac_8822b_pwr_seq.c new file mode 100644 index 000000000000..0edd1f5a04a8 --- /dev/null +++ b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_8822b/halmac_8822b_pwr_seq.c @@ -0,0 +1,563 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#include "../halmac_88xx_cfg.h" +#include "halmac_8822b_cfg.h" + +static struct halmac_wl_pwr_cfg_ HALMAC_RTL8822B_TRANS_CARDEMU_TO_ACT[] = { + /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value } */ + {0x0012, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + BIT(1), 0}, /*SWR OCP = SWR OCP = 010 1382.40*/ + {0x0012, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + BIT(0), BIT(0)}, /*SWR OCP = 010 1382.40 */ + {0x0020, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_USB_MSK | HALMAC_PWR_INTF_SDIO_MSK, + HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, BIT(0), + BIT(0)}, /*0x20[0] = 1b'1 enable LDOA12 MACRO block for all interface*/ + {0x0001, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_USB_MSK | HALMAC_PWR_INTF_SDIO_MSK, + HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_DELAY, 1, + HALMAC_PWRSEQ_DELAY_MS}, /*Delay 1ms*/ + {0x0000, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_USB_MSK | HALMAC_PWR_INTF_SDIO_MSK, + HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, BIT(5), + 0}, /*0x00[5] = 1b'0 release analog Ips to digital ,1:isolation*/ + {0x0005, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + (BIT(4) | BIT(3) | BIT(2)), + 0}, /* disable SW LPS 0x04[10]=0 and WLSUS_EN 0x04[12:11]=0*/ + {0x0075, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_PCI_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + BIT(0), BIT(0)}, /* Disable USB suspend */ + {0x0006, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, + HALMAC_PWR_CMD_POLLING, BIT(1), + BIT(1)}, /* wait till 0x04[17] = 1 power ready*/ + {0x0075, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_PCI_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + BIT(0), 0}, /* Enable USB suspend */ + {0xFF1A, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_USB_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + 0xFF, 0}, /*0xFF1A = 0 to release resume signals*/ + {0x0006, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + BIT(0), BIT(0)}, /* release WLON reset 0x04[16]=1*/ + {0x0005, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + BIT(7), 0}, /* disable HWPDN 0x04[15]=0*/ + {0x0005, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + (BIT(4) | BIT(3)), 0}, /* disable WL suspend*/ + {0x0005, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + BIT(0), BIT(0)}, /* polling until return 0*/ + {0x0005, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, + HALMAC_PWR_CMD_POLLING, BIT(0), 0}, + {0x0020, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + BIT(3), BIT(3)}, /*Enable XTAL_CLK*/ + {0x10A8, HALMAC_PWR_CUT_C_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + 0xFF, 0}, /*NFC pad enabled*/ + {0x10A9, HALMAC_PWR_CUT_C_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + 0xFF, 0xef}, /*NFC pad enabled*/ + {0x10AA, HALMAC_PWR_CUT_C_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + 0xFF, 0x0c}, /*NFC pad enabled*/ + {0x0068, HALMAC_PWR_CUT_C_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_SDIO_MSK, HALMAC_PWR_BASEADDR_MAC, + HALMAC_PWR_CMD_WRITE, BIT(4), BIT(4)}, /*SDIO pad power down disabled*/ + {0x0029, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + 0xFF, 0xF9}, /*PLL seting*/ + {0x0024, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + BIT(2), 0}, /*Improve TX EVM of CH13 and some 5G channles */ + {0x0074, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_PCI_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + BIT(5), BIT(5)}, /*PCIE WAKE# enabled*/ + {0xFFFF, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, 0, HALMAC_PWR_CMD_END, 0, 0}, +}; + +static struct halmac_wl_pwr_cfg_ HALMAC_RTL8822B_TRANS_ACT_TO_CARDEMU[] = { + /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value } */ + {0x0003, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_SDIO_MSK, HALMAC_PWR_BASEADDR_MAC, + HALMAC_PWR_CMD_WRITE, BIT(2), 0}, /*0x02[10] = 0 Disable MCU Core*/ + {0x0093, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + BIT(3), 0}, /*LPS option 0x93[3]=0 , SWR PFM*/ + {0x001F, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + 0xFF, 0}, /*0x1F[7:0] = 0 turn off RF*/ + {0x00EF, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + 0xFF, 0}, /*0xEF[7:0] = 0 turn off RF*/ + {0xFF1A, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_USB_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + 0xFF, 0x30}, /*0xFF1A = 0x30 to block resume signals*/ + {0x0049, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + BIT(1), 0}, /*Enable rising edge triggering interrupt*/ + {0x0006, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + BIT(0), BIT(0)}, /* release WLON reset 0x04[16]=1*/ + {0x0002, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + BIT(1), 0}, /* Whole BB is reset */ + {0x0005, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + BIT(1), BIT(1)}, /*0x04[9] = 1 turn off MAC by HW state machine*/ + {0x0005, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, + HALMAC_PWR_CMD_POLLING, BIT(1), + 0}, /*wait till 0x04[9] = 0 polling until return 0 to disable*/ + {0x0020, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + BIT(3), 0}, /* XTAL_CLK gated*/ + {0x0000, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_USB_MSK | HALMAC_PWR_INTF_SDIO_MSK, + HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, BIT(5), + BIT(5)}, /*0x00[5] = 1b'1 analog Ips to digital ,1:isolation*/ + {0xFFFF, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, 0, HALMAC_PWR_CMD_END, 0, 0}, +}; + +static struct halmac_wl_pwr_cfg_ HALMAC_RTL8822B_TRANS_CARDEMU_TO_SUS[] = { + /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value } */ + {0x0005, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_PCI_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + BIT(4) | BIT(3), + (BIT(4) | BIT(3))}, /*0x04[12:11] = 2b'11 enable WL suspend for PCIe*/ + {0x0005, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_USB_MSK | HALMAC_PWR_INTF_SDIO_MSK, + HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, BIT(3) | BIT(4), + BIT(3)}, /*0x04[12:11] = 2b'01 enable WL suspend*/ + {0x0007, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_SDIO_MSK, HALMAC_PWR_BASEADDR_MAC, + HALMAC_PWR_CMD_WRITE, 0xFF, + 0x20}, /*0x07[7:0] = 0x20 SDIO SOP option to disable BG/MB/ACK/SWR*/ + {0x0005, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_PCI_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + BIT(3) | BIT(4), + BIT(3) | BIT(4)}, /*0x04[12:11] = 2b'11 enable WL suspend for PCIe*/ + {0x0086, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_SDIO_MSK, HALMAC_PWR_BASEADDR_SDIO, + HALMAC_PWR_CMD_WRITE, BIT(0), + BIT(0)}, /*Set SDIO suspend local register*/ + {0x0086, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_SDIO_MSK, HALMAC_PWR_BASEADDR_SDIO, + HALMAC_PWR_CMD_POLLING, BIT(1), 0}, /*wait power state to suspend*/ + {0xFFFF, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, 0, HALMAC_PWR_CMD_END, 0, 0}, +}; + +static struct halmac_wl_pwr_cfg_ HALMAC_RTL8822B_TRANS_SUS_TO_CARDEMU[] = { + /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value } */ + {0x0005, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + BIT(3) | BIT(7), 0}, /*clear suspend enable and power down enable*/ + {0x0086, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_SDIO_MSK, HALMAC_PWR_BASEADDR_SDIO, + HALMAC_PWR_CMD_WRITE, BIT(0), 0}, /*Set SDIO suspend local register*/ + {0x0086, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_SDIO_MSK, HALMAC_PWR_BASEADDR_SDIO, + HALMAC_PWR_CMD_POLLING, BIT(1), + BIT(1)}, /*wait power state to suspend*/ + {0x0005, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + BIT(3) | BIT(4), 0}, /*0x04[12:11] = 2b'01enable WL suspend*/ + {0xFFFF, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, 0, HALMAC_PWR_CMD_END, 0, 0}, +}; + +static struct halmac_wl_pwr_cfg_ HALMAC_RTL8822B_TRANS_CARDEMU_TO_CARDDIS[] = { + /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value } */ + {0x0005, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_SDIO_MSK, HALMAC_PWR_BASEADDR_MAC, + HALMAC_PWR_CMD_WRITE, BIT(7), + BIT(7)}, /*suspend enable and power down enable*/ + {0x0007, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_USB_MSK | HALMAC_PWR_INTF_SDIO_MSK, + HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, 0xFF, + 0x20}, /*0x07=0x20 , SOP option to disable BG/MB*/ + {0x0067, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + BIT(5), 0}, /*0x67[5]=0 , BIT_PAPE_WLBT_SEL*/ + {0x0005, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_USB_MSK | HALMAC_PWR_INTF_SDIO_MSK, + HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, BIT(3) | BIT(4), + BIT(3)}, /*0x04[12:11] = 2b'01 enable WL suspend*/ + {0x0005, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_PCI_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + BIT(2), BIT(2)}, /*0x04[10] = 1, enable SW LPS*/ + {0x004A, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_USB_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + BIT(0), 0}, /*0x48[16] = 0 to disable GPIO9 as EXT WAKEUP*/ + {0x0067, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_SDIO_MSK, HALMAC_PWR_BASEADDR_MAC, + HALMAC_PWR_CMD_WRITE, BIT(5), + 0}, /* 0: BT PAPE control ; 1: WL BB LNAON control*/ + {0x0067, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_SDIO_MSK, HALMAC_PWR_BASEADDR_MAC, + HALMAC_PWR_CMD_WRITE, BIT(4), + 0}, /* 0: BT GPIO[11:10] control ; 1: WL BB LNAON control*/ + {0x004F, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_SDIO_MSK, HALMAC_PWR_BASEADDR_MAC, + HALMAC_PWR_CMD_WRITE, BIT(0), 0}, /* 0: BT Control*/ + {0x0067, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_SDIO_MSK, HALMAC_PWR_BASEADDR_MAC, + HALMAC_PWR_CMD_WRITE, BIT(1), + 0}, /* turn off BT_3DD_SYNC_B and BT_GPIO[18] */ + {0x0046, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_SDIO_MSK, HALMAC_PWR_BASEADDR_MAC, + HALMAC_PWR_CMD_WRITE, BIT(6), BIT(6)}, /* GPIO[6] : Output mode*/ + {0x0067, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_SDIO_MSK, HALMAC_PWR_BASEADDR_MAC, + HALMAC_PWR_CMD_WRITE, BIT(2), 0}, /* turn off BT_GPIO[16] */ + {0x0046, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_SDIO_MSK, HALMAC_PWR_BASEADDR_MAC, + HALMAC_PWR_CMD_WRITE, BIT(7), BIT(7)}, /* GPIO[7] : Output mode*/ + {0x0062, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_SDIO_MSK, HALMAC_PWR_BASEADDR_MAC, + HALMAC_PWR_CMD_WRITE, BIT(4), BIT(4)}, /* GPIO[12] : Output mode */ + {0x0086, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_SDIO_MSK, HALMAC_PWR_BASEADDR_SDIO, + HALMAC_PWR_CMD_WRITE, BIT(0), + BIT(0)}, /*Set SDIO suspend local register*/ + {0x0086, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_SDIO_MSK, HALMAC_PWR_BASEADDR_SDIO, + HALMAC_PWR_CMD_POLLING, BIT(1), 0}, /*wait power state to suspend*/ + {0x0090, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_USB_MSK | HALMAC_PWR_INTF_PCI_MSK, + HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, BIT(1), + 0}, /*0x90[1]=0 , disable 32k clock*/ + {0x0044, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_SDIO_MSK, HALMAC_PWR_BASEADDR_SDIO, + HALMAC_PWR_CMD_WRITE, 0xFF, + 0}, /*0x90[1]=0 , disable 32k clock by indirect access*/ + {0x0040, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_SDIO_MSK, HALMAC_PWR_BASEADDR_SDIO, + HALMAC_PWR_CMD_WRITE, 0xFF, + 0x90}, /*0x90[1]=0 , disable 32k clock by indirect access*/ + {0x0041, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_SDIO_MSK, HALMAC_PWR_BASEADDR_SDIO, + HALMAC_PWR_CMD_WRITE, 0xFF, + 0x00}, /*0x90[1]=0 , disable 32k clock by indirect access*/ + {0x0042, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_SDIO_MSK, HALMAC_PWR_BASEADDR_SDIO, + HALMAC_PWR_CMD_WRITE, 0xFF, + 0x04}, /*0x90[1]=0 , disable 32k clock by indirect access*/ + {0x0081, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + BIT(7), 0}, /*0x80[15]clean fw init ready bit*/ + {0xFFFF, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, 0, HALMAC_PWR_CMD_END, 0, 0}, +}; + +static struct halmac_wl_pwr_cfg_ HALMAC_RTL8822B_TRANS_CARDDIS_TO_CARDEMU[] = { + /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value } */ + {0x0086, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_SDIO_MSK, HALMAC_PWR_BASEADDR_SDIO, + HALMAC_PWR_CMD_WRITE, BIT(0), 0}, /*Set SDIO suspend local register*/ + {0x0086, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_SDIO_MSK, HALMAC_PWR_BASEADDR_SDIO, + HALMAC_PWR_CMD_POLLING, BIT(1), + BIT(1)}, /*wait power state to suspend*/ + {0x004A, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_USB_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + BIT(0), 0}, /*0x48[16] = 0 to disable GPIO9 as EXT WAKEUP*/ + {0x0005, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + BIT(3) | BIT(4) | BIT(7), + 0}, /*clear suspend enable and power down enable*/ + {0x0301, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_PCI_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + 0xFF, 0}, + {0xFFFF, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, 0, HALMAC_PWR_CMD_END, 0, 0}, +}; + +static struct halmac_wl_pwr_cfg_ HALMAC_RTL8822B_TRANS_ACT_TO_LPS[] = { + /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value } */ + {0x0101, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + BIT(2), BIT(2)}, /*Enable 32k calibration and thermal meter*/ + {0x0199, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + BIT(3), BIT(3)}, /*Register write data of 32K calibration*/ + {0x019B, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + BIT(7), BIT(7)}, /*Enable 32k calibration reg write*/ + {0x1138, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + BIT(0) | BIT(1), BIT(0) | BIT(1)}, /*set RPWM IMR*/ + {0x0194, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + BIT(0), BIT(0)}, /* enable 32K CLK*/ + {0x0093, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + 0xFF, 0x42}, /* LPS Option MAC OFF enable*/ + {0x0092, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + 0xFF, 0x20}, /* LPS Option Enable memory to deep sleep mode*/ + {0x0090, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + BIT(1), BIT(1)}, /* enable reg use 32K CLK*/ + {0x0301, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_PCI_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + 0xFF, 0xFF}, /*PCIe DMA stop*/ + {0x0522, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + 0xFF, 0xFF}, /*Tx Pause*/ + {0x05F8, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, + HALMAC_PWR_CMD_POLLING, 0xFF, + 0}, /*Should be zero if no packet is transmitting*/ + {0x05F9, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, + HALMAC_PWR_CMD_POLLING, 0xFF, + 0}, /*Should be zero if no packet is transmitting*/ + {0x05FA, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, + HALMAC_PWR_CMD_POLLING, 0xFF, + 0}, /*Should be zero if no packet is transmitting*/ + {0x05FB, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, + HALMAC_PWR_CMD_POLLING, 0xFF, + 0}, /*Should be zero if no packet is transmitting*/ + {0x0002, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + BIT(0), 0}, /*CCK and OFDM are disabled,and clock are gated*/ + {0x0002, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_DELAY, + 0, HALMAC_PWRSEQ_DELAY_US}, /*Delay 1us*/ + {0x0002, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + BIT(1), 0}, /*Whole BB is reset*/ + {0x0100, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + 0xFF, 0x3F}, /*Reset MAC TRX*/ + {0x0101, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + BIT(1), 0}, /*check if removed later*/ + {0x0553, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + BIT(5), BIT(5)}, /*Respond TxOK to scheduler*/ + {0x0008, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + BIT(4), BIT(4)}, /* switch TSF clock to 32K*/ + {0x0109, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, + HALMAC_PWR_CMD_POLLING, BIT(7), + BIT(7)}, /*Polling 0x109[7]=0 TSF in 40M*/ + {0x0090, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + BIT(0), BIT(0)}, /* enable WL_LPS_EN*/ + {0xFFFF, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, 0, HALMAC_PWR_CMD_END, 0, 0}, +}; + +static struct halmac_wl_pwr_cfg_ HALMAC_RTL8822B_TRANS_ACT_TO_DEEP_LPS[] = { + /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value } */ + {0x0101, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + BIT(2), BIT(2)}, /*Enable 32k calibration and thermal meter*/ + {0x0199, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + BIT(3), BIT(3)}, /*Register write data of 32K calibration*/ + {0x019B, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + BIT(7), BIT(7)}, /*Enable 32k calibration reg write*/ + {0x1138, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + BIT(0) | BIT(1), BIT(0) | BIT(1)}, /*set RPWM IMR*/ + {0x0194, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + BIT(0), BIT(0)}, /* enable 32K CLK*/ + {0x0093, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + 0xFF, 0x40}, /* LPS Option MAC OFF enable*/ + {0x0092, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + 0xFF, 0x20}, /* LPS Option Enable memory to deep sleep mode*/ + {0x0090, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + BIT(1), BIT(1)}, /* enable reg use 32K CLK*/ + {0x0301, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_PCI_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + 0xFF, 0xFF}, /*PCIe DMA stop*/ + {0x0522, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + 0xFF, 0xFF}, /*Tx Pause*/ + {0x05F8, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, + HALMAC_PWR_CMD_POLLING, 0xFF, + 0}, /*Should be zero if no packet is transmitting*/ + {0x05F9, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, + HALMAC_PWR_CMD_POLLING, 0xFF, + 0}, /*Should be zero if no packet is transmitting*/ + {0x05FA, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, + HALMAC_PWR_CMD_POLLING, 0xFF, + 0}, /*Should be zero if no packet is transmitting*/ + {0x05FB, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, + HALMAC_PWR_CMD_POLLING, 0xFF, + 0}, /*Should be zero if no packet is transmitting*/ + {0x0002, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + BIT(0), 0}, /*CCK and OFDM are disabled,and clock are gated*/ + {0x0002, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_DELAY, + 0, HALMAC_PWRSEQ_DELAY_US}, /*Delay 1us*/ + {0x0002, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + BIT(1), 0}, /*Whole BB is reset*/ + {0x0100, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + 0xFF, 0x3F}, /*Reset MAC TRX*/ + {0x0101, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + BIT(1), 0}, /*check if removed later*/ + {0x0553, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + BIT(5), BIT(5)}, /*Respond TxOK to scheduler*/ + {0x0008, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + BIT(4), BIT(4)}, /* switch TSF clock to 32K*/ + {0x0109, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, + HALMAC_PWR_CMD_POLLING, BIT(7), + BIT(7)}, /*Polling 0x109[7]=1 TSF in 32K*/ + {0x0090, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + BIT(0), BIT(0)}, /* enable WL_LPS_EN*/ + {0xFFFF, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, 0, HALMAC_PWR_CMD_END, 0, 0}, +}; + +static struct halmac_wl_pwr_cfg_ HALMAC_RTL8822B_TRANS_LPS_TO_ACT[] = { + /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value } */ + {0x0080, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_SDIO_MSK, HALMAC_PWR_BASEADDR_SDIO, + HALMAC_PWR_CMD_WRITE, BIT(7), BIT(7)}, /*SDIO RPWM*/ + {0x0002, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_DELAY, + 0, HALMAC_PWRSEQ_DELAY_MS}, /*Delay*/ + {0x0080, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_SDIO_MSK, HALMAC_PWR_BASEADDR_SDIO, + HALMAC_PWR_CMD_WRITE, BIT(7), 0}, /*SDIO RPWM*/ + {0xFE58, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_USB_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + 0xFF, 0x84}, /*USB RPWM*/ + {0x0361, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_PCI_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + 0xFF, 0x84}, /*PCIe RPWM*/ + {0x0002, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_DELAY, + 0, HALMAC_PWRSEQ_DELAY_MS}, /*Delay*/ + {0x0008, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + BIT(4), 0}, /* switch TSF to 40M*/ + {0x0109, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, + HALMAC_PWR_CMD_POLLING, BIT(7), 0}, /*Polling 0x109[7]=0 TSF in 40M*/ + {0x0101, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + BIT(1), BIT(1)}, + {0x0100, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + 0xFF, 0xFF}, /*nable WMAC TRX*/ + {0x0002, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + BIT(1) | BIT(0), BIT(1) | BIT(0)}, /*nable BB macro*/ + {0x0522, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + 0xFF, 0}, + {0x113C, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + 0xFF, 0x03}, /*clear RPWM INT*/ + {0x0124, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + 0xFF, 0xFF}, /*clear FW INT*/ + {0x0125, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + 0xFF, 0xFF}, /*clear FW INT*/ + {0x0126, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + 0xFF, 0xFF}, /*clear FW INT*/ + {0x0127, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + 0xFF, 0xFF}, /*clear FW INT*/ + {0x0090, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + BIT(1), 0}, /* disable reg use 32K CLK*/ + {0x0101, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, HALMAC_PWR_BASEADDR_MAC, HALMAC_PWR_CMD_WRITE, + BIT(2), 0}, /*disable 32k calibration and thermal meter*/ + {0xFFFF, HALMAC_PWR_CUT_ALL_MSK, HALMAC_PWR_FAB_ALL_MSK, + HALMAC_PWR_INTF_ALL_MSK, 0, HALMAC_PWR_CMD_END, 0, 0}, +}; + +/* Card Enable Array */ +struct halmac_wl_pwr_cfg_ *halmac_8822b_card_enable_flow[] = { + HALMAC_RTL8822B_TRANS_CARDDIS_TO_CARDEMU, + HALMAC_RTL8822B_TRANS_CARDEMU_TO_ACT, NULL}; + +/* Card Disable Array */ +struct halmac_wl_pwr_cfg_ *halmac_8822b_card_disable_flow[] = { + HALMAC_RTL8822B_TRANS_ACT_TO_CARDEMU, + HALMAC_RTL8822B_TRANS_CARDEMU_TO_CARDDIS, NULL}; + +/* Suspend Array */ +struct halmac_wl_pwr_cfg_ *halmac_8822b_suspend_flow[] = { + HALMAC_RTL8822B_TRANS_ACT_TO_CARDEMU, + HALMAC_RTL8822B_TRANS_CARDEMU_TO_SUS, NULL}; + +/* Resume Array */ +struct halmac_wl_pwr_cfg_ *halmac_8822b_resume_flow[] = { + HALMAC_RTL8822B_TRANS_SUS_TO_CARDEMU, + HALMAC_RTL8822B_TRANS_CARDEMU_TO_ACT, NULL}; + +/* HWPDN Array - HW behavior */ +struct halmac_wl_pwr_cfg_ *halmac_8822b_hwpdn_flow[] = {NULL}; + +/* Enter LPS - FW behavior */ +struct halmac_wl_pwr_cfg_ *halmac_8822b_enter_lps_flow[] = { + HALMAC_RTL8822B_TRANS_ACT_TO_LPS, NULL}; + +/* Enter Deep LPS - FW behavior */ +struct halmac_wl_pwr_cfg_ *halmac_8822b_enter_deep_lps_flow[] = { + HALMAC_RTL8822B_TRANS_ACT_TO_DEEP_LPS, NULL}; + +/* Leave LPS -FW behavior */ +struct halmac_wl_pwr_cfg_ *halmac_8822b_leave_lps_flow[] = { + HALMAC_RTL8822B_TRANS_LPS_TO_ACT, NULL}; diff --git a/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_8822b/halmac_8822b_pwr_seq.h b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_8822b/halmac_8822b_pwr_seq.h new file mode 100644 index 000000000000..79a6072ef2ef --- /dev/null +++ b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_8822b/halmac_8822b_pwr_seq.h @@ -0,0 +1,40 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef HALMAC_POWER_SEQUENCE_8822B +#define HALMAC_POWER_SEQUENCE_8822B + +#include "../../halmac_pwr_seq_cmd.h" + +#define HALMAC_8822B_PWR_SEQ_VER "V17" +extern struct halmac_wl_pwr_cfg_ *halmac_8822b_card_disable_flow[]; +extern struct halmac_wl_pwr_cfg_ *halmac_8822b_card_enable_flow[]; +extern struct halmac_wl_pwr_cfg_ *halmac_8822b_suspend_flow[]; +extern struct halmac_wl_pwr_cfg_ *halmac_8822b_resume_flow[]; +extern struct halmac_wl_pwr_cfg_ *halmac_8822b_hwpdn_flow[]; +extern struct halmac_wl_pwr_cfg_ *halmac_8822b_enter_lps_flow[]; +extern struct halmac_wl_pwr_cfg_ *halmac_8822b_enter_deep_lps_flow[]; +extern struct halmac_wl_pwr_cfg_ *halmac_8822b_leave_lps_flow[]; + +#endif diff --git a/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_8822b/halmac_api_8822b.c b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_8822b/halmac_api_8822b.c new file mode 100644 index 000000000000..6b729fe4c096 --- /dev/null +++ b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_8822b/halmac_api_8822b.c @@ -0,0 +1,343 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#include "halmac_8822b_cfg.h" +#include "halmac_func_8822b.h" +#include "../halmac_func_88xx.h" + +/** + * halmac_mount_api_8822b() - attach functions to function pointer + * @halmac_adapter + * + * SD1 internal use + * + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + */ +enum halmac_ret_status +halmac_mount_api_8822b(struct halmac_adapter *halmac_adapter) +{ + struct halmac_api *halmac_api = + (struct halmac_api *)halmac_adapter->halmac_api; + + halmac_adapter->chip_id = HALMAC_CHIP_ID_8822B; + halmac_adapter->hw_config_info.efuse_size = HALMAC_EFUSE_SIZE_8822B; + halmac_adapter->hw_config_info.eeprom_size = HALMAC_EEPROM_SIZE_8822B; + halmac_adapter->hw_config_info.bt_efuse_size = + HALMAC_BT_EFUSE_SIZE_8822B; + halmac_adapter->hw_config_info.cam_entry_num = + HALMAC_SECURITY_CAM_ENTRY_NUM_8822B; + halmac_adapter->hw_config_info.txdesc_size = HALMAC_TX_DESC_SIZE_8822B; + halmac_adapter->hw_config_info.rxdesc_size = HALMAC_RX_DESC_SIZE_8822B; + halmac_adapter->hw_config_info.tx_fifo_size = HALMAC_TX_FIFO_SIZE_8822B; + halmac_adapter->hw_config_info.rx_fifo_size = HALMAC_RX_FIFO_SIZE_8822B; + halmac_adapter->hw_config_info.page_size = HALMAC_TX_PAGE_SIZE_8822B; + halmac_adapter->hw_config_info.tx_align_size = + HALMAC_TX_ALIGN_SIZE_8822B; + halmac_adapter->hw_config_info.page_size_2_power = + HALMAC_TX_PAGE_SIZE_2_POWER_8822B; + + halmac_adapter->txff_allocation.rsvd_drv_pg_num = + HALMAC_RSVD_DRV_PGNUM_8822B; + + halmac_api->halmac_init_trx_cfg = halmac_init_trx_cfg_8822b; + halmac_api->halmac_init_protocol_cfg = halmac_init_protocol_cfg_8822b; + halmac_api->halmac_init_h2c = halmac_init_h2c_8822b; + + if (halmac_adapter->halmac_interface == HALMAC_INTERFACE_SDIO) { + halmac_api->halmac_tx_allowed_sdio = + halmac_tx_allowed_sdio_88xx; + halmac_api->halmac_cfg_tx_agg_align = + halmac_cfg_tx_agg_align_sdio_not_support_88xx; + halmac_api->halmac_mac_power_switch = + halmac_mac_power_switch_8822b_sdio; + halmac_api->halmac_phy_cfg = halmac_phy_cfg_8822b_sdio; + halmac_api->halmac_interface_integration_tuning = + halmac_interface_integration_tuning_8822b_sdio; + } else if (halmac_adapter->halmac_interface == HALMAC_INTERFACE_USB) { + halmac_api->halmac_mac_power_switch = + halmac_mac_power_switch_8822b_usb; + halmac_api->halmac_cfg_tx_agg_align = + halmac_cfg_tx_agg_align_usb_not_support_88xx; + halmac_api->halmac_phy_cfg = halmac_phy_cfg_8822b_usb; + halmac_api->halmac_interface_integration_tuning = + halmac_interface_integration_tuning_8822b_usb; + } else if (halmac_adapter->halmac_interface == HALMAC_INTERFACE_PCIE) { + halmac_api->halmac_mac_power_switch = + halmac_mac_power_switch_8822b_pcie; + halmac_api->halmac_cfg_tx_agg_align = + halmac_cfg_tx_agg_align_pcie_not_support_88xx; + halmac_api->halmac_pcie_switch = halmac_pcie_switch_8822b; + halmac_api->halmac_phy_cfg = halmac_phy_cfg_8822b_pcie; + halmac_api->halmac_interface_integration_tuning = + halmac_interface_integration_tuning_8822b_pcie; + } else { + halmac_api->halmac_pcie_switch = halmac_pcie_switch_8822b_nc; + } + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_init_trx_cfg_8822b() - config trx dma register + * @halmac_adapter : the adapter of halmac + * @halmac_trx_mode : trx mode selection + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_init_trx_cfg_8822b(struct halmac_adapter *halmac_adapter, + enum halmac_trx_mode halmac_trx_mode) +{ + u8 value8; + u32 value32; + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_INIT_TRX_CFG); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + halmac_adapter->trx_mode = halmac_trx_mode; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "halmac_init_trx_cfg ==========>halmac_trx_mode = %d\n", + halmac_trx_mode); + + status = halmac_txdma_queue_mapping_8822b(halmac_adapter, + halmac_trx_mode); + + if (status != HALMAC_RET_SUCCESS) { + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "halmac_txdma_queue_mapping fail!\n"); + return status; + } + + value8 = 0; + HALMAC_REG_WRITE_8(halmac_adapter, REG_CR, value8); + value8 = HALMAC_CR_TRX_ENABLE_8822B; + HALMAC_REG_WRITE_8(halmac_adapter, REG_CR, value8); + HALMAC_REG_WRITE_32(halmac_adapter, REG_H2CQ_CSR, BIT(31)); + + status = halmac_priority_queue_config_8822b(halmac_adapter, + halmac_trx_mode); + if (halmac_adapter->txff_allocation.rx_fifo_expanding_mode != + HALMAC_RX_FIFO_EXPANDING_MODE_DISABLE) + HALMAC_REG_WRITE_8(halmac_adapter, REG_RX_DRVINFO_SZ, 0xF); + + if (status != HALMAC_RET_SUCCESS) { + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "halmac_txdma_queue_mapping fail!\n"); + return status; + } + + /* Config H2C packet buffer */ + value32 = HALMAC_REG_READ_32(halmac_adapter, REG_H2C_HEAD); + value32 = (value32 & 0xFFFC0000) | + (halmac_adapter->txff_allocation.rsvd_h2c_queue_pg_bndy + << HALMAC_TX_PAGE_SIZE_2_POWER_8822B); + HALMAC_REG_WRITE_32(halmac_adapter, REG_H2C_HEAD, value32); + + value32 = HALMAC_REG_READ_32(halmac_adapter, REG_H2C_READ_ADDR); + value32 = (value32 & 0xFFFC0000) | + (halmac_adapter->txff_allocation.rsvd_h2c_queue_pg_bndy + << HALMAC_TX_PAGE_SIZE_2_POWER_8822B); + HALMAC_REG_WRITE_32(halmac_adapter, REG_H2C_READ_ADDR, value32); + + value32 = HALMAC_REG_READ_32(halmac_adapter, REG_H2C_TAIL); + value32 = (value32 & 0xFFFC0000) | + ((halmac_adapter->txff_allocation.rsvd_h2c_queue_pg_bndy + << HALMAC_TX_PAGE_SIZE_2_POWER_8822B) + + (HALMAC_RSVD_H2C_QUEUE_PGNUM_8822B + << HALMAC_TX_PAGE_SIZE_2_POWER_8822B)); + HALMAC_REG_WRITE_32(halmac_adapter, REG_H2C_TAIL, value32); + + value8 = HALMAC_REG_READ_8(halmac_adapter, REG_H2C_INFO); + value8 = (u8)((value8 & 0xFC) | 0x01); + HALMAC_REG_WRITE_8(halmac_adapter, REG_H2C_INFO, value8); + + value8 = HALMAC_REG_READ_8(halmac_adapter, REG_H2C_INFO); + value8 = (u8)((value8 & 0xFB) | 0x04); + HALMAC_REG_WRITE_8(halmac_adapter, REG_H2C_INFO, value8); + + value8 = HALMAC_REG_READ_8(halmac_adapter, REG_TXDMA_OFFSET_CHK + 1); + value8 = (u8)((value8 & 0x7f) | 0x80); + HALMAC_REG_WRITE_8(halmac_adapter, REG_TXDMA_OFFSET_CHK + 1, value8); + + halmac_adapter->h2c_buff_size = HALMAC_RSVD_H2C_QUEUE_PGNUM_8822B + << HALMAC_TX_PAGE_SIZE_2_POWER_8822B; + halmac_get_h2c_buff_free_space_88xx(halmac_adapter); + + if (halmac_adapter->h2c_buff_size != + halmac_adapter->h2c_buf_free_space) { + pr_err("get h2c free space error!\n"); + return HALMAC_RET_GET_H2C_SPACE_ERR; + } + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "halmac_init_trx_cfg <==========\n"); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_init_protocol_cfg_8822b() - config protocol register + * @halmac_adapter : the adapter of halmac + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_init_protocol_cfg_8822b(struct halmac_adapter *halmac_adapter) +{ + u32 value32; + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_INIT_PROTOCOL_CFG); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "[TRACE]%s ==========>\n", __func__); + + HALMAC_REG_WRITE_8(halmac_adapter, REG_AMPDU_MAX_TIME_V1, + HALMAC_AMPDU_MAX_TIME_8822B); + HALMAC_REG_WRITE_8(halmac_adapter, REG_TX_HANG_CTRL, BIT_EN_EOF_V1); + + value32 = HALMAC_PROT_RTS_LEN_TH_8822B | + (HALMAC_PROT_RTS_TX_TIME_TH_8822B << 8) | + (HALMAC_PROT_MAX_AGG_PKT_LIMIT_8822B << 16) | + (HALMAC_PROT_RTS_MAX_AGG_PKT_LIMIT_8822B << 24); + HALMAC_REG_WRITE_32(halmac_adapter, REG_PROT_MODE_CTRL, value32); + + HALMAC_REG_WRITE_16(halmac_adapter, REG_BAR_MODE_CTRL + 2, + HALMAC_BAR_RETRY_LIMIT_8822B | + HALMAC_RA_TRY_RATE_AGG_LIMIT_8822B << 8); + + HALMAC_REG_WRITE_8(halmac_adapter, REG_FAST_EDCA_VOVI_SETTING, + HALMAC_FAST_EDCA_VO_TH_8822B); + HALMAC_REG_WRITE_8(halmac_adapter, REG_FAST_EDCA_VOVI_SETTING + 2, + HALMAC_FAST_EDCA_VI_TH_8822B); + HALMAC_REG_WRITE_8(halmac_adapter, REG_FAST_EDCA_BEBK_SETTING, + HALMAC_FAST_EDCA_BE_TH_8822B); + HALMAC_REG_WRITE_8(halmac_adapter, REG_FAST_EDCA_BEBK_SETTING + 2, + HALMAC_FAST_EDCA_BK_TH_8822B); + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "[TRACE]%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_init_h2c_8822b() - config h2c packet buffer + * @halmac_adapter : the adapter of halmac + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_init_h2c_8822b(struct halmac_adapter *halmac_adapter) +{ + u8 value8; + u32 value32; + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + value8 = 0; + HALMAC_REG_WRITE_8(halmac_adapter, REG_CR, value8); + value8 = HALMAC_CR_TRX_ENABLE_8822B; + HALMAC_REG_WRITE_8(halmac_adapter, REG_CR, value8); + + value32 = HALMAC_REG_READ_32(halmac_adapter, REG_H2C_HEAD); + value32 = (value32 & 0xFFFC0000) | + (halmac_adapter->txff_allocation.rsvd_h2c_queue_pg_bndy + << HALMAC_TX_PAGE_SIZE_2_POWER_8822B); + HALMAC_REG_WRITE_32(halmac_adapter, REG_H2C_HEAD, value32); + + value32 = HALMAC_REG_READ_32(halmac_adapter, REG_H2C_READ_ADDR); + value32 = (value32 & 0xFFFC0000) | + (halmac_adapter->txff_allocation.rsvd_h2c_queue_pg_bndy + << HALMAC_TX_PAGE_SIZE_2_POWER_8822B); + HALMAC_REG_WRITE_32(halmac_adapter, REG_H2C_READ_ADDR, value32); + + value32 = HALMAC_REG_READ_32(halmac_adapter, REG_H2C_TAIL); + value32 = (value32 & 0xFFFC0000) | + ((halmac_adapter->txff_allocation.rsvd_h2c_queue_pg_bndy + << HALMAC_TX_PAGE_SIZE_2_POWER_8822B) + + (HALMAC_RSVD_H2C_QUEUE_PGNUM_8822B + << HALMAC_TX_PAGE_SIZE_2_POWER_8822B)); + HALMAC_REG_WRITE_32(halmac_adapter, REG_H2C_TAIL, value32); + value8 = HALMAC_REG_READ_8(halmac_adapter, REG_H2C_INFO); + value8 = (u8)((value8 & 0xFC) | 0x01); + HALMAC_REG_WRITE_8(halmac_adapter, REG_H2C_INFO, value8); + + value8 = HALMAC_REG_READ_8(halmac_adapter, REG_H2C_INFO); + value8 = (u8)((value8 & 0xFB) | 0x04); + HALMAC_REG_WRITE_8(halmac_adapter, REG_H2C_INFO, value8); + + value8 = HALMAC_REG_READ_8(halmac_adapter, REG_TXDMA_OFFSET_CHK + 1); + value8 = (u8)((value8 & 0x7f) | 0x80); + HALMAC_REG_WRITE_8(halmac_adapter, REG_TXDMA_OFFSET_CHK + 1, value8); + + halmac_adapter->h2c_buff_size = HALMAC_RSVD_H2C_QUEUE_PGNUM_8822B + << HALMAC_TX_PAGE_SIZE_2_POWER_8822B; + halmac_get_h2c_buff_free_space_88xx(halmac_adapter); + + if (halmac_adapter->h2c_buff_size != + halmac_adapter->h2c_buf_free_space) { + pr_err("get h2c free space error!\n"); + return HALMAC_RET_GET_H2C_SPACE_ERR; + } + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "h2c free space : %d\n", + halmac_adapter->h2c_buf_free_space); + + return HALMAC_RET_SUCCESS; +} diff --git a/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_8822b/halmac_api_8822b.h b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_8822b/halmac_api_8822b.h new file mode 100644 index 000000000000..cf21e3d25607 --- /dev/null +++ b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_8822b/halmac_api_8822b.h @@ -0,0 +1,44 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef _HALMAC_API_8822B_H_ +#define _HALMAC_API_8822B_H_ + +#include "../../halmac_2_platform.h" +#include "../../halmac_type.h" + +enum halmac_ret_status +halmac_mount_api_8822b(struct halmac_adapter *halmac_adapter); + +enum halmac_ret_status +halmac_init_trx_cfg_8822b(struct halmac_adapter *halmac_adapter, + enum halmac_trx_mode halmac_trx_mode); + +enum halmac_ret_status +halmac_init_protocol_cfg_8822b(struct halmac_adapter *halmac_adapter); + +enum halmac_ret_status +halmac_init_h2c_8822b(struct halmac_adapter *halmac_adapter); + +#endif /* _HALMAC_API_8822B_H_ */ diff --git a/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_8822b/halmac_api_8822b_pcie.c b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_8822b/halmac_api_8822b_pcie.c new file mode 100644 index 000000000000..e25e2b0ebb4c --- /dev/null +++ b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_8822b/halmac_api_8822b_pcie.c @@ -0,0 +1,323 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#include "../halmac_88xx_cfg.h" +#include "../halmac_api_88xx_pcie.h" +#include "halmac_8822b_cfg.h" + +/** + * halmac_mac_power_switch_8822b_pcie() - switch mac power + * @halmac_adapter : the adapter of halmac + * @halmac_power : power state + * Author : KaiYuan Chang + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_mac_power_switch_8822b_pcie(struct halmac_adapter *halmac_adapter, + enum halmac_mac_power halmac_power) +{ + u8 interface_mask; + u8 value8; + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_MAC_POWER_SWITCH); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_RT_TRACE( + driver_adapter, HALMAC_MSG_PWR, DBG_DMESG, + "halmac_mac_power_switch_88xx_pcie halmac_power = %x ==========>\n", + halmac_power); + interface_mask = HALMAC_PWR_INTF_PCI_MSK; + + value8 = HALMAC_REG_READ_8(halmac_adapter, REG_CR); + if (value8 == 0xEA) + halmac_adapter->halmac_state.mac_power = HALMAC_MAC_POWER_OFF; + else + halmac_adapter->halmac_state.mac_power = HALMAC_MAC_POWER_ON; + + /* Check if power switch is needed */ + if (halmac_power == HALMAC_MAC_POWER_ON && + halmac_adapter->halmac_state.mac_power == HALMAC_MAC_POWER_ON) { + HALMAC_RT_TRACE( + driver_adapter, HALMAC_MSG_PWR, DBG_WARNING, + "halmac_mac_power_switch power state unchange!\n"); + return HALMAC_RET_PWR_UNCHANGE; + } + + if (halmac_power == HALMAC_MAC_POWER_OFF) { + if (halmac_pwr_seq_parser_88xx( + halmac_adapter, HALMAC_PWR_CUT_ALL_MSK, + HALMAC_PWR_FAB_TSMC_MSK, interface_mask, + halmac_8822b_card_disable_flow) != + HALMAC_RET_SUCCESS) { + pr_err("Handle power off cmd error\n"); + return HALMAC_RET_POWER_OFF_FAIL; + } + + halmac_adapter->halmac_state.mac_power = HALMAC_MAC_POWER_OFF; + halmac_adapter->halmac_state.ps_state = + HALMAC_PS_STATE_UNDEFINE; + halmac_adapter->halmac_state.dlfw_state = HALMAC_DLFW_NONE; + halmac_init_adapter_dynamic_para_88xx(halmac_adapter); + } else { + if (halmac_pwr_seq_parser_88xx( + halmac_adapter, HALMAC_PWR_CUT_ALL_MSK, + HALMAC_PWR_FAB_TSMC_MSK, interface_mask, + halmac_8822b_card_enable_flow) != + HALMAC_RET_SUCCESS) { + pr_err("Handle power on cmd error\n"); + return HALMAC_RET_POWER_ON_FAIL; + } + + halmac_adapter->halmac_state.mac_power = HALMAC_MAC_POWER_ON; + halmac_adapter->halmac_state.ps_state = HALMAC_PS_STATE_ACT; + } + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_PWR, DBG_DMESG, + "halmac_mac_power_switch_88xx_pcie <==========\n"); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_pcie_switch_8822b() - pcie gen1/gen2 switch + * @halmac_adapter : the adapter of halmac + * @pcie_cfg : gen1/gen2 selection + * Author : KaiYuan Chang + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_pcie_switch_8822b(struct halmac_adapter *halmac_adapter, + enum halmac_pcie_cfg pcie_cfg) +{ + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + u8 current_link_speed = 0; + u32 count = 0; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_PCIE_SWITCH); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_PWR, DBG_DMESG, + "%s ==========>\n", __func__); + + /* Link Control 2 Register[3:0] Target Link Speed + * Defined encodings are: + * 0001b Target Link 2.5 GT/s + * 0010b Target Link 5.0 GT/s + * 0100b Target Link 8.0 GT/s + */ + + if (pcie_cfg == HALMAC_PCIE_GEN1) { + /* cfg 0xA0[3:0]=4'b0001 */ + halmac_dbi_write8_88xx( + halmac_adapter, LINK_CTRL2_REG_OFFSET, + (halmac_dbi_read8_88xx(halmac_adapter, + LINK_CTRL2_REG_OFFSET) & + 0xF0) | BIT(0)); + + /* cfg 0x80C[17]=1 //PCIe DesignWave */ + halmac_dbi_write32_88xx( + halmac_adapter, GEN2_CTRL_OFFSET, + halmac_dbi_read32_88xx(halmac_adapter, + GEN2_CTRL_OFFSET) | + BIT(17)); + + /* check link speed if GEN1 */ + /* cfg 0x82[3:0]=4'b0001 */ + current_link_speed = + halmac_dbi_read8_88xx(halmac_adapter, + LINK_STATUS_REG_OFFSET) & + 0x0F; + count = 2000; + + while (current_link_speed != GEN1_SPEED && count != 0) { + usleep_range(50, 60); + current_link_speed = + halmac_dbi_read8_88xx(halmac_adapter, + LINK_STATUS_REG_OFFSET) & + 0x0F; + count--; + } + + if (current_link_speed != GEN1_SPEED) { + pr_err("Speed change to GEN1 fail !\n"); + return HALMAC_RET_FAIL; + } + + } else if (pcie_cfg == HALMAC_PCIE_GEN2) { + /* cfg 0xA0[3:0]=4'b0010 */ + halmac_dbi_write8_88xx( + halmac_adapter, LINK_CTRL2_REG_OFFSET, + (halmac_dbi_read8_88xx(halmac_adapter, + LINK_CTRL2_REG_OFFSET) & + 0xF0) | BIT(1)); + + /* cfg 0x80C[17]=1 //PCIe DesignWave */ + halmac_dbi_write32_88xx( + halmac_adapter, GEN2_CTRL_OFFSET, + halmac_dbi_read32_88xx(halmac_adapter, + GEN2_CTRL_OFFSET) | + BIT(17)); + + /* check link speed if GEN2 */ + /* cfg 0x82[3:0]=4'b0010 */ + current_link_speed = + halmac_dbi_read8_88xx(halmac_adapter, + LINK_STATUS_REG_OFFSET) & + 0x0F; + count = 2000; + + while (current_link_speed != GEN2_SPEED && count != 0) { + usleep_range(50, 60); + current_link_speed = + halmac_dbi_read8_88xx(halmac_adapter, + LINK_STATUS_REG_OFFSET) & + 0x0F; + count--; + } + + if (current_link_speed != GEN2_SPEED) { + pr_err("Speed change to GEN1 fail !\n"); + return HALMAC_RET_FAIL; + } + + } else { + pr_err("Error Speed !\n"); + return HALMAC_RET_FAIL; + } + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_PWR, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status +halmac_pcie_switch_8822b_nc(struct halmac_adapter *halmac_adapter, + enum halmac_pcie_cfg pcie_cfg) +{ + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_PCIE_SWITCH); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_PWR, DBG_DMESG, + "%s ==========>\n", __func__); + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_PWR, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_phy_cfg_8822b_pcie() - phy config + * @halmac_adapter : the adapter of halmac + * Author : KaiYuan Chang + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_phy_cfg_8822b_pcie(struct halmac_adapter *halmac_adapter, + enum halmac_intf_phy_platform platform) +{ + void *driver_adapter = NULL; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + struct halmac_api *halmac_api; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_PHY_CFG); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_PWR, DBG_DMESG, + "halmac_phy_cfg ==========>\n"); + + status = halmac_parse_intf_phy_88xx(halmac_adapter, + HALMAC_RTL8822B_PCIE_PHY_GEN1, + platform, HAL_INTF_PHY_PCIE_GEN1); + + if (status != HALMAC_RET_SUCCESS) + return status; + + status = halmac_parse_intf_phy_88xx(halmac_adapter, + HALMAC_RTL8822B_PCIE_PHY_GEN2, + platform, HAL_INTF_PHY_PCIE_GEN2); + + if (status != HALMAC_RET_SUCCESS) + return status; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_PWR, DBG_DMESG, + "halmac_phy_cfg <==========\n"); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_interface_integration_tuning_8822b_pcie() - pcie interface fine tuning + * @halmac_adapter : the adapter of halmac + * Author : Rick Liu + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status halmac_interface_integration_tuning_8822b_pcie( + struct halmac_adapter *halmac_adapter) +{ + return HALMAC_RET_SUCCESS; +} diff --git a/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_8822b/halmac_api_8822b_pcie.h b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_8822b/halmac_api_8822b_pcie.h new file mode 100644 index 000000000000..c68ea0039703 --- /dev/null +++ b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_8822b/halmac_api_8822b_pcie.h @@ -0,0 +1,53 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef _HALMAC_API_8822B_PCIE_H_ +#define _HALMAC_API_8822B_PCIE_H_ + +#include "../../halmac_2_platform.h" +#include "../../halmac_type.h" + +extern struct halmac_intf_phy_para_ HALMAC_RTL8822B_PCIE_PHY_GEN1[]; +extern struct halmac_intf_phy_para_ HALMAC_RTL8822B_PCIE_PHY_GEN2[]; + +enum halmac_ret_status +halmac_mac_power_switch_8822b_pcie(struct halmac_adapter *halmac_adapter, + enum halmac_mac_power halmac_power); + +enum halmac_ret_status +halmac_pcie_switch_8822b(struct halmac_adapter *halmac_adapter, + enum halmac_pcie_cfg pcie_cfg); + +enum halmac_ret_status +halmac_pcie_switch_8822b_nc(struct halmac_adapter *halmac_adapter, + enum halmac_pcie_cfg pcie_cfg); + +enum halmac_ret_status +halmac_phy_cfg_8822b_pcie(struct halmac_adapter *halmac_adapter, + enum halmac_intf_phy_platform platform); + +enum halmac_ret_status halmac_interface_integration_tuning_8822b_pcie( + struct halmac_adapter *halmac_adapter); + +#endif /* _HALMAC_API_8822B_PCIE_H_ */ diff --git a/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_8822b/halmac_api_8822b_sdio.c b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_8822b/halmac_api_8822b_sdio.c new file mode 100644 index 000000000000..4d708d841bad --- /dev/null +++ b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_8822b/halmac_api_8822b_sdio.c @@ -0,0 +1,184 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#include "halmac_8822b_cfg.h" + +/** + * halmac_mac_power_switch_8822b_sdio() - switch mac power + * @halmac_adapter : the adapter of halmac + * @halmac_power : power state + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_mac_power_switch_8822b_sdio(struct halmac_adapter *halmac_adapter, + enum halmac_mac_power halmac_power) +{ + u8 interface_mask; + u8 value8; + u8 rpwm; + u32 imr_backup; + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_RT_TRACE( + driver_adapter, HALMAC_MSG_PWR, DBG_DMESG, + "[TRACE]halmac_mac_power_switch_88xx_sdio==========>\n"); + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_PWR, DBG_DMESG, + "[TRACE]halmac_power = %x ==========>\n", halmac_power); + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_PWR, DBG_DMESG, + "[TRACE]8822B pwr seq ver = %s\n", + HALMAC_8822B_PWR_SEQ_VER); + + interface_mask = HALMAC_PWR_INTF_SDIO_MSK; + + halmac_adapter->rpwm_record = + HALMAC_REG_READ_8(halmac_adapter, REG_SDIO_HRPWM1); + + /* Check FW still exist or not */ + if (HALMAC_REG_READ_16(halmac_adapter, REG_MCUFW_CTRL) == 0xC078) { + /* Leave 32K */ + rpwm = (u8)((halmac_adapter->rpwm_record ^ BIT(7)) & 0x80); + HALMAC_REG_WRITE_8(halmac_adapter, REG_SDIO_HRPWM1, rpwm); + } + + value8 = HALMAC_REG_READ_8(halmac_adapter, REG_CR); + if (value8 == 0xEA) + halmac_adapter->halmac_state.mac_power = HALMAC_MAC_POWER_OFF; + else + halmac_adapter->halmac_state.mac_power = HALMAC_MAC_POWER_ON; + + /*Check if power switch is needed*/ + if (halmac_power == HALMAC_MAC_POWER_ON && + halmac_adapter->halmac_state.mac_power == HALMAC_MAC_POWER_ON) { + HALMAC_RT_TRACE( + driver_adapter, HALMAC_MSG_PWR, DBG_WARNING, + "[WARN]halmac_mac_power_switch power state unchange!\n"); + return HALMAC_RET_PWR_UNCHANGE; + } + + imr_backup = HALMAC_REG_READ_32(halmac_adapter, REG_SDIO_HIMR); + HALMAC_REG_WRITE_32(halmac_adapter, REG_SDIO_HIMR, 0); + + if (halmac_power == HALMAC_MAC_POWER_OFF) { + if (halmac_pwr_seq_parser_88xx( + halmac_adapter, HALMAC_PWR_CUT_ALL_MSK, + HALMAC_PWR_FAB_TSMC_MSK, interface_mask, + halmac_8822b_card_disable_flow) != + HALMAC_RET_SUCCESS) { + pr_err("[ERR]Handle power off cmd error\n"); + HALMAC_REG_WRITE_32(halmac_adapter, REG_SDIO_HIMR, + imr_backup); + return HALMAC_RET_POWER_OFF_FAIL; + } + + halmac_adapter->halmac_state.mac_power = HALMAC_MAC_POWER_OFF; + halmac_adapter->halmac_state.ps_state = + HALMAC_PS_STATE_UNDEFINE; + halmac_adapter->halmac_state.dlfw_state = HALMAC_DLFW_NONE; + halmac_init_adapter_dynamic_para_88xx(halmac_adapter); + } else { + if (halmac_pwr_seq_parser_88xx( + halmac_adapter, HALMAC_PWR_CUT_ALL_MSK, + HALMAC_PWR_FAB_TSMC_MSK, interface_mask, + halmac_8822b_card_enable_flow) != + HALMAC_RET_SUCCESS) { + pr_err("[ERR]Handle power on cmd error\n"); + HALMAC_REG_WRITE_32(halmac_adapter, REG_SDIO_HIMR, + imr_backup); + return HALMAC_RET_POWER_ON_FAIL; + } + + halmac_adapter->halmac_state.mac_power = HALMAC_MAC_POWER_ON; + halmac_adapter->halmac_state.ps_state = HALMAC_PS_STATE_ACT; + } + + HALMAC_REG_WRITE_32(halmac_adapter, REG_SDIO_HIMR, imr_backup); + + HALMAC_RT_TRACE( + driver_adapter, HALMAC_MSG_PWR, DBG_DMESG, + "[TRACE]halmac_mac_power_switch_88xx_sdio <==========\n"); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_phy_cfg_8822b_sdio() - phy config + * @halmac_adapter : the adapter of halmac + * Author : KaiYuan Chang + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_phy_cfg_8822b_sdio(struct halmac_adapter *halmac_adapter, + enum halmac_intf_phy_platform platform) +{ + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_PHY_CFG); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_PWR, DBG_DMESG, + "halmac_phy_cfg ==========>\n"); + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_PWR, DBG_DMESG, + "sdio no phy\n"); + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_PWR, DBG_DMESG, + "halmac_phy_cfg <==========\n"); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_interface_integration_tuning_8822b_sdio() - sdio interface fine tuning + * @halmac_adapter : the adapter of halmac + * Author : Ivan + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status halmac_interface_integration_tuning_8822b_sdio( + struct halmac_adapter *halmac_adapter) +{ + return HALMAC_RET_SUCCESS; +} diff --git a/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_8822b/halmac_api_8822b_sdio.h b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_8822b/halmac_api_8822b_sdio.h new file mode 100644 index 000000000000..07ffb3baf7c0 --- /dev/null +++ b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_8822b/halmac_api_8822b_sdio.h @@ -0,0 +1,42 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef _HALMAC_API_8822B_SDIO_H_ +#define _HALMAC_API_8822B_SDIO_H_ + +#include "../../halmac_2_platform.h" +#include "../../halmac_type.h" + +enum halmac_ret_status +halmac_mac_power_switch_8822b_sdio(struct halmac_adapter *halmac_adapter, + enum halmac_mac_power halmac_power); + +enum halmac_ret_status +halmac_phy_cfg_8822b_sdio(struct halmac_adapter *halmac_adapter, + enum halmac_intf_phy_platform platform); + +enum halmac_ret_status halmac_interface_integration_tuning_8822b_sdio( + struct halmac_adapter *halmac_adapter); + +#endif /* _HALMAC_API_8822B_SDIO_H_ */ diff --git a/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_8822b/halmac_api_8822b_usb.c b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_8822b/halmac_api_8822b_usb.c new file mode 100644 index 000000000000..5f27eb172430 --- /dev/null +++ b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_8822b/halmac_api_8822b_usb.c @@ -0,0 +1,185 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#include "../halmac_88xx_cfg.h" +#include "halmac_8822b_cfg.h" + +/** + * halmac_mac_power_switch_8822b_usb() - switch mac power + * @halmac_adapter : the adapter of halmac + * @halmac_power : power state + * Author : KaiYuan Chang + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_mac_power_switch_8822b_usb(struct halmac_adapter *halmac_adapter, + enum halmac_mac_power halmac_power) +{ + u8 interface_mask; + u8 value8; + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_MAC_POWER_SWITCH); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_RT_TRACE( + driver_adapter, HALMAC_MSG_PWR, DBG_DMESG, + "halmac_mac_power_switch_88xx_usb halmac_power = %x ==========>\n", + halmac_power); + + interface_mask = HALMAC_PWR_INTF_USB_MSK; + + value8 = HALMAC_REG_READ_8(halmac_adapter, REG_CR); + if (value8 == 0xEA) { + halmac_adapter->halmac_state.mac_power = HALMAC_MAC_POWER_OFF; + } else { + if (BIT(0) == + (HALMAC_REG_READ_8(halmac_adapter, REG_SYS_STATUS1 + 1) & + BIT(0))) + halmac_adapter->halmac_state.mac_power = + HALMAC_MAC_POWER_OFF; + else + halmac_adapter->halmac_state.mac_power = + HALMAC_MAC_POWER_ON; + } + + /*Check if power switch is needed*/ + if (halmac_power == HALMAC_MAC_POWER_ON && + halmac_adapter->halmac_state.mac_power == HALMAC_MAC_POWER_ON) { + HALMAC_RT_TRACE( + driver_adapter, HALMAC_MSG_PWR, DBG_WARNING, + "halmac_mac_power_switch power state unchange!\n"); + return HALMAC_RET_PWR_UNCHANGE; + } + if (halmac_power == HALMAC_MAC_POWER_OFF) { + if (halmac_pwr_seq_parser_88xx( + halmac_adapter, HALMAC_PWR_CUT_ALL_MSK, + HALMAC_PWR_FAB_TSMC_MSK, interface_mask, + halmac_8822b_card_disable_flow) != + HALMAC_RET_SUCCESS) { + pr_err("Handle power off cmd error\n"); + return HALMAC_RET_POWER_OFF_FAIL; + } + + halmac_adapter->halmac_state.mac_power = HALMAC_MAC_POWER_OFF; + halmac_adapter->halmac_state.ps_state = + HALMAC_PS_STATE_UNDEFINE; + halmac_adapter->halmac_state.dlfw_state = HALMAC_DLFW_NONE; + halmac_init_adapter_dynamic_para_88xx(halmac_adapter); + } else { + if (halmac_pwr_seq_parser_88xx( + halmac_adapter, HALMAC_PWR_CUT_ALL_MSK, + HALMAC_PWR_FAB_TSMC_MSK, interface_mask, + halmac_8822b_card_enable_flow) != + HALMAC_RET_SUCCESS) { + pr_err("Handle power on cmd error\n"); + return HALMAC_RET_POWER_ON_FAIL; + } + + HALMAC_REG_WRITE_8( + halmac_adapter, REG_SYS_STATUS1 + 1, + HALMAC_REG_READ_8(halmac_adapter, REG_SYS_STATUS1 + 1) & + ~(BIT(0))); + + halmac_adapter->halmac_state.mac_power = HALMAC_MAC_POWER_ON; + halmac_adapter->halmac_state.ps_state = HALMAC_PS_STATE_ACT; + } + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_PWR, DBG_DMESG, + "halmac_mac_power_switch_88xx_usb <==========\n"); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_phy_cfg_8822b_usb() - phy config + * @halmac_adapter : the adapter of halmac + * Author : KaiYuan Chang + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_phy_cfg_8822b_usb(struct halmac_adapter *halmac_adapter, + enum halmac_intf_phy_platform platform) +{ + void *driver_adapter = NULL; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + struct halmac_api *halmac_api; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_PHY_CFG); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_PWR, DBG_DMESG, + "halmac_phy_cfg ==========>\n"); + + status = halmac_parse_intf_phy_88xx(halmac_adapter, + HALMAC_RTL8822B_USB2_PHY, platform, + HAL_INTF_PHY_USB2); + + if (status != HALMAC_RET_SUCCESS) + return status; + + status = halmac_parse_intf_phy_88xx(halmac_adapter, + HALMAC_RTL8822B_USB3_PHY, platform, + HAL_INTF_PHY_USB3); + + if (status != HALMAC_RET_SUCCESS) + return status; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_PWR, DBG_DMESG, + "halmac_phy_cfg <==========\n"); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_interface_integration_tuning_8822b_usb() - usb interface fine tuning + * @halmac_adapter : the adapter of halmac + * Author : Ivan + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status halmac_interface_integration_tuning_8822b_usb( + struct halmac_adapter *halmac_adapter) +{ + return HALMAC_RET_SUCCESS; +} diff --git a/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_8822b/halmac_api_8822b_usb.h b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_8822b/halmac_api_8822b_usb.h new file mode 100644 index 000000000000..3a99fd5675e0 --- /dev/null +++ b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_8822b/halmac_api_8822b_usb.h @@ -0,0 +1,45 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef _HALMAC_API_8822B_USB_H_ +#define _HALMAC_API_8822B_USB_H_ + +extern struct halmac_intf_phy_para_ HALMAC_RTL8822B_USB2_PHY[]; +extern struct halmac_intf_phy_para_ HALMAC_RTL8822B_USB3_PHY[]; + +#include "../../halmac_2_platform.h" +#include "../../halmac_type.h" + +enum halmac_ret_status +halmac_mac_power_switch_8822b_usb(struct halmac_adapter *halmac_adapter, + enum halmac_mac_power halmac_power); + +enum halmac_ret_status +halmac_phy_cfg_8822b_usb(struct halmac_adapter *halmac_adapter, + enum halmac_intf_phy_platform platform); + +enum halmac_ret_status halmac_interface_integration_tuning_8822b_usb( + struct halmac_adapter *halmac_adapter); + +#endif /* _HALMAC_API_8822B_USB_H_ */ diff --git a/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_8822b/halmac_func_8822b.c b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_8822b/halmac_func_8822b.c new file mode 100644 index 000000000000..5f1dff8d9e3b --- /dev/null +++ b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_8822b/halmac_func_8822b.c @@ -0,0 +1,414 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#include "halmac_8822b_cfg.h" +#include "halmac_func_8822b.h" + +/*SDIO RQPN Mapping*/ +static struct halmac_rqpn_ HALMAC_RQPN_SDIO_8822B[] = { + /* { mode, vo_map, vi_map, be_map, bk_map, mg_map, hi_map } */ + {HALMAC_TRX_MODE_NORMAL, HALMAC_MAP2_NQ, HALMAC_MAP2_NQ, HALMAC_MAP2_LQ, + HALMAC_MAP2_LQ, HALMAC_MAP2_EXQ, HALMAC_MAP2_HQ}, + {HALMAC_TRX_MODE_TRXSHARE, HALMAC_MAP2_NQ, HALMAC_MAP2_NQ, + HALMAC_MAP2_LQ, HALMAC_MAP2_LQ, HALMAC_MAP2_EXQ, HALMAC_MAP2_HQ}, + {HALMAC_TRX_MODE_WMM, HALMAC_MAP2_HQ, HALMAC_MAP2_NQ, HALMAC_MAP2_LQ, + HALMAC_MAP2_NQ, HALMAC_MAP2_EXQ, HALMAC_MAP2_HQ}, + {HALMAC_TRX_MODE_P2P, HALMAC_MAP2_NQ, HALMAC_MAP2_NQ, HALMAC_MAP2_LQ, + HALMAC_MAP2_LQ, HALMAC_MAP2_EXQ, HALMAC_MAP2_HQ}, + {HALMAC_TRX_MODE_LOOPBACK, HALMAC_MAP2_NQ, HALMAC_MAP2_NQ, + HALMAC_MAP2_LQ, HALMAC_MAP2_LQ, HALMAC_MAP2_EXQ, HALMAC_MAP2_HQ}, + {HALMAC_TRX_MODE_DELAY_LOOPBACK, HALMAC_MAP2_NQ, HALMAC_MAP2_NQ, + HALMAC_MAP2_LQ, HALMAC_MAP2_LQ, HALMAC_MAP2_EXQ, HALMAC_MAP2_HQ}, +}; + +/*PCIE RQPN Mapping*/ +static struct halmac_rqpn_ HALMAC_RQPN_PCIE_8822B[] = { + /* { mode, vo_map, vi_map, be_map, bk_map, mg_map, hi_map } */ + {HALMAC_TRX_MODE_NORMAL, HALMAC_MAP2_NQ, HALMAC_MAP2_NQ, HALMAC_MAP2_LQ, + HALMAC_MAP2_LQ, HALMAC_MAP2_EXQ, HALMAC_MAP2_HQ}, + {HALMAC_TRX_MODE_TRXSHARE, HALMAC_MAP2_NQ, HALMAC_MAP2_NQ, + HALMAC_MAP2_LQ, HALMAC_MAP2_LQ, HALMAC_MAP2_EXQ, HALMAC_MAP2_HQ}, + {HALMAC_TRX_MODE_WMM, HALMAC_MAP2_HQ, HALMAC_MAP2_NQ, HALMAC_MAP2_LQ, + HALMAC_MAP2_NQ, HALMAC_MAP2_EXQ, HALMAC_MAP2_HQ}, + {HALMAC_TRX_MODE_P2P, HALMAC_MAP2_NQ, HALMAC_MAP2_NQ, HALMAC_MAP2_LQ, + HALMAC_MAP2_LQ, HALMAC_MAP2_EXQ, HALMAC_MAP2_HQ}, + {HALMAC_TRX_MODE_LOOPBACK, HALMAC_MAP2_NQ, HALMAC_MAP2_NQ, + HALMAC_MAP2_LQ, HALMAC_MAP2_LQ, HALMAC_MAP2_EXQ, HALMAC_MAP2_HQ}, + {HALMAC_TRX_MODE_DELAY_LOOPBACK, HALMAC_MAP2_NQ, HALMAC_MAP2_NQ, + HALMAC_MAP2_LQ, HALMAC_MAP2_LQ, HALMAC_MAP2_EXQ, HALMAC_MAP2_HQ}, +}; + +/*USB 2 Bulkout RQPN Mapping*/ +static struct halmac_rqpn_ HALMAC_RQPN_2BULKOUT_8822B[] = { + /* { mode, vo_map, vi_map, be_map, bk_map, mg_map, hi_map } */ + {HALMAC_TRX_MODE_NORMAL, HALMAC_MAP2_NQ, HALMAC_MAP2_NQ, HALMAC_MAP2_NQ, + HALMAC_MAP2_HQ, HALMAC_MAP2_HQ, HALMAC_MAP2_HQ}, + {HALMAC_TRX_MODE_TRXSHARE, HALMAC_MAP2_NQ, HALMAC_MAP2_NQ, + HALMAC_MAP2_NQ, HALMAC_MAP2_HQ, HALMAC_MAP2_HQ, HALMAC_MAP2_HQ}, + {HALMAC_TRX_MODE_WMM, HALMAC_MAP2_NQ, HALMAC_MAP2_NQ, HALMAC_MAP2_NQ, + HALMAC_MAP2_HQ, HALMAC_MAP2_HQ, HALMAC_MAP2_HQ}, + {HALMAC_TRX_MODE_P2P, HALMAC_MAP2_HQ, HALMAC_MAP2_HQ, HALMAC_MAP2_HQ, + HALMAC_MAP2_NQ, HALMAC_MAP2_HQ, HALMAC_MAP2_HQ}, + {HALMAC_TRX_MODE_LOOPBACK, HALMAC_MAP2_HQ, HALMAC_MAP2_HQ, + HALMAC_MAP2_HQ, HALMAC_MAP2_NQ, HALMAC_MAP2_HQ, HALMAC_MAP2_HQ}, + {HALMAC_TRX_MODE_DELAY_LOOPBACK, HALMAC_MAP2_HQ, HALMAC_MAP2_HQ, + HALMAC_MAP2_HQ, HALMAC_MAP2_NQ, HALMAC_MAP2_HQ, HALMAC_MAP2_HQ}, +}; + +/*USB 3 Bulkout RQPN Mapping*/ +static struct halmac_rqpn_ HALMAC_RQPN_3BULKOUT_8822B[] = { + /* { mode, vo_map, vi_map, be_map, bk_map, mg_map, hi_map } */ + {HALMAC_TRX_MODE_NORMAL, HALMAC_MAP2_NQ, HALMAC_MAP2_NQ, HALMAC_MAP2_LQ, + HALMAC_MAP2_LQ, HALMAC_MAP2_HQ, HALMAC_MAP2_HQ}, + {HALMAC_TRX_MODE_TRXSHARE, HALMAC_MAP2_NQ, HALMAC_MAP2_NQ, + HALMAC_MAP2_LQ, HALMAC_MAP2_LQ, HALMAC_MAP2_HQ, HALMAC_MAP2_HQ}, + {HALMAC_TRX_MODE_WMM, HALMAC_MAP2_HQ, HALMAC_MAP2_NQ, HALMAC_MAP2_LQ, + HALMAC_MAP2_NQ, HALMAC_MAP2_HQ, HALMAC_MAP2_HQ}, + {HALMAC_TRX_MODE_P2P, HALMAC_MAP2_HQ, HALMAC_MAP2_HQ, HALMAC_MAP2_LQ, + HALMAC_MAP2_NQ, HALMAC_MAP2_HQ, HALMAC_MAP2_HQ}, + {HALMAC_TRX_MODE_LOOPBACK, HALMAC_MAP2_HQ, HALMAC_MAP2_HQ, + HALMAC_MAP2_LQ, HALMAC_MAP2_NQ, HALMAC_MAP2_HQ, HALMAC_MAP2_HQ}, + {HALMAC_TRX_MODE_DELAY_LOOPBACK, HALMAC_MAP2_HQ, HALMAC_MAP2_HQ, + HALMAC_MAP2_LQ, HALMAC_MAP2_NQ, HALMAC_MAP2_HQ, HALMAC_MAP2_HQ}, +}; + +/*USB 4 Bulkout RQPN Mapping*/ +static struct halmac_rqpn_ HALMAC_RQPN_4BULKOUT_8822B[] = { + /* { mode, vo_map, vi_map, be_map, bk_map, mg_map, hi_map } */ + {HALMAC_TRX_MODE_NORMAL, HALMAC_MAP2_NQ, HALMAC_MAP2_NQ, HALMAC_MAP2_LQ, + HALMAC_MAP2_LQ, HALMAC_MAP2_EXQ, HALMAC_MAP2_HQ}, + {HALMAC_TRX_MODE_TRXSHARE, HALMAC_MAP2_NQ, HALMAC_MAP2_NQ, + HALMAC_MAP2_LQ, HALMAC_MAP2_LQ, HALMAC_MAP2_EXQ, HALMAC_MAP2_HQ}, + {HALMAC_TRX_MODE_WMM, HALMAC_MAP2_HQ, HALMAC_MAP2_NQ, HALMAC_MAP2_LQ, + HALMAC_MAP2_NQ, HALMAC_MAP2_EXQ, HALMAC_MAP2_HQ}, + {HALMAC_TRX_MODE_P2P, HALMAC_MAP2_NQ, HALMAC_MAP2_NQ, HALMAC_MAP2_LQ, + HALMAC_MAP2_LQ, HALMAC_MAP2_EXQ, HALMAC_MAP2_HQ}, + {HALMAC_TRX_MODE_LOOPBACK, HALMAC_MAP2_NQ, HALMAC_MAP2_NQ, + HALMAC_MAP2_LQ, HALMAC_MAP2_LQ, HALMAC_MAP2_EXQ, HALMAC_MAP2_HQ}, + {HALMAC_TRX_MODE_DELAY_LOOPBACK, HALMAC_MAP2_NQ, HALMAC_MAP2_NQ, + HALMAC_MAP2_LQ, HALMAC_MAP2_LQ, HALMAC_MAP2_EXQ, HALMAC_MAP2_HQ}, +}; + +/*SDIO Page Number*/ +static struct halmac_pg_num_ HALMAC_PG_NUM_SDIO_8822B[] = { + /* { mode, hq_num, nq_num, lq_num, exq_num, gap_num} */ + {HALMAC_TRX_MODE_NORMAL, 64, 64, 64, 64, 1}, + {HALMAC_TRX_MODE_TRXSHARE, 32, 32, 32, 32, 1}, + {HALMAC_TRX_MODE_WMM, 64, 64, 64, 64, 1}, + {HALMAC_TRX_MODE_P2P, 64, 64, 64, 64, 1}, + {HALMAC_TRX_MODE_LOOPBACK, 64, 64, 64, 64, 640}, + {HALMAC_TRX_MODE_DELAY_LOOPBACK, 64, 64, 64, 64, 640}, +}; + +/*PCIE Page Number*/ +static struct halmac_pg_num_ HALMAC_PG_NUM_PCIE_8822B[] = { + /* { mode, hq_num, nq_num, lq_num, exq_num, gap_num} */ + {HALMAC_TRX_MODE_NORMAL, 64, 64, 64, 64, 1}, + {HALMAC_TRX_MODE_TRXSHARE, 64, 64, 64, 64, 1}, + {HALMAC_TRX_MODE_WMM, 64, 64, 64, 64, 1}, + {HALMAC_TRX_MODE_P2P, 64, 64, 64, 64, 1}, + {HALMAC_TRX_MODE_LOOPBACK, 64, 64, 64, 64, 640}, + {HALMAC_TRX_MODE_DELAY_LOOPBACK, 64, 64, 64, 64, 640}, +}; + +/*USB 2 Bulkout Page Number*/ +static struct halmac_pg_num_ HALMAC_PG_NUM_2BULKOUT_8822B[] = { + /* { mode, hq_num, nq_num, lq_num, exq_num, gap_num} */ + {HALMAC_TRX_MODE_NORMAL, 64, 64, 0, 0, 1}, + {HALMAC_TRX_MODE_TRXSHARE, 64, 64, 0, 0, 1}, + {HALMAC_TRX_MODE_WMM, 64, 64, 0, 0, 1}, + {HALMAC_TRX_MODE_P2P, 64, 64, 0, 0, 1}, + {HALMAC_TRX_MODE_LOOPBACK, 64, 64, 0, 0, 1024}, + {HALMAC_TRX_MODE_DELAY_LOOPBACK, 64, 64, 0, 0, 1024}, +}; + +/*USB 3 Bulkout Page Number*/ +static struct halmac_pg_num_ HALMAC_PG_NUM_3BULKOUT_8822B[] = { + /* { mode, hq_num, nq_num, lq_num, exq_num, gap_num} */ + {HALMAC_TRX_MODE_NORMAL, 64, 64, 64, 0, 1}, + {HALMAC_TRX_MODE_TRXSHARE, 64, 64, 64, 0, 1}, + {HALMAC_TRX_MODE_WMM, 64, 64, 64, 0, 1}, + {HALMAC_TRX_MODE_P2P, 64, 64, 64, 0, 1}, + {HALMAC_TRX_MODE_LOOPBACK, 64, 64, 64, 0, 1024}, + {HALMAC_TRX_MODE_DELAY_LOOPBACK, 64, 64, 64, 0, 1024}, +}; + +/*USB 4 Bulkout Page Number*/ +static struct halmac_pg_num_ HALMAC_PG_NUM_4BULKOUT_8822B[] = { + /* { mode, hq_num, nq_num, lq_num, exq_num, gap_num} */ + {HALMAC_TRX_MODE_NORMAL, 64, 64, 64, 64, 1}, + {HALMAC_TRX_MODE_TRXSHARE, 64, 64, 64, 64, 1}, + {HALMAC_TRX_MODE_WMM, 64, 64, 64, 64, 1}, + {HALMAC_TRX_MODE_P2P, 64, 64, 64, 64, 1}, + {HALMAC_TRX_MODE_LOOPBACK, 64, 64, 64, 64, 640}, + {HALMAC_TRX_MODE_DELAY_LOOPBACK, 64, 64, 64, 64, 640}, +}; + +enum halmac_ret_status +halmac_txdma_queue_mapping_8822b(struct halmac_adapter *halmac_adapter, + enum halmac_trx_mode halmac_trx_mode) +{ + u16 value16; + void *driver_adapter = NULL; + struct halmac_rqpn_ *curr_rqpn_sel = NULL; + enum halmac_ret_status status; + struct halmac_api *halmac_api; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + if (halmac_adapter->halmac_interface == HALMAC_INTERFACE_SDIO) { + curr_rqpn_sel = HALMAC_RQPN_SDIO_8822B; + } else if (halmac_adapter->halmac_interface == HALMAC_INTERFACE_PCIE) { + curr_rqpn_sel = HALMAC_RQPN_PCIE_8822B; + } else if (halmac_adapter->halmac_interface == HALMAC_INTERFACE_USB) { + if (halmac_adapter->halmac_bulkout_num == 2) { + curr_rqpn_sel = HALMAC_RQPN_2BULKOUT_8822B; + } else if (halmac_adapter->halmac_bulkout_num == 3) { + curr_rqpn_sel = HALMAC_RQPN_3BULKOUT_8822B; + } else if (halmac_adapter->halmac_bulkout_num == 4) { + curr_rqpn_sel = HALMAC_RQPN_4BULKOUT_8822B; + } else { + pr_err("[ERR]interface not support\n"); + return HALMAC_RET_NOT_SUPPORT; + } + } else { + return HALMAC_RET_NOT_SUPPORT; + } + + status = halmac_rqpn_parser_88xx(halmac_adapter, halmac_trx_mode, + curr_rqpn_sel); + if (status != HALMAC_RET_SUCCESS) + return status; + + value16 = 0; + value16 |= BIT_TXDMA_HIQ_MAP( + halmac_adapter->halmac_ptcl_queue[HALMAC_PTCL_QUEUE_HI]); + value16 |= BIT_TXDMA_MGQ_MAP( + halmac_adapter->halmac_ptcl_queue[HALMAC_PTCL_QUEUE_MG]); + value16 |= BIT_TXDMA_BKQ_MAP( + halmac_adapter->halmac_ptcl_queue[HALMAC_PTCL_QUEUE_BK]); + value16 |= BIT_TXDMA_BEQ_MAP( + halmac_adapter->halmac_ptcl_queue[HALMAC_PTCL_QUEUE_BE]); + value16 |= BIT_TXDMA_VIQ_MAP( + halmac_adapter->halmac_ptcl_queue[HALMAC_PTCL_QUEUE_VI]); + value16 |= BIT_TXDMA_VOQ_MAP( + halmac_adapter->halmac_ptcl_queue[HALMAC_PTCL_QUEUE_VO]); + HALMAC_REG_WRITE_16(halmac_adapter, REG_TXDMA_PQ_MAP, value16); + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status +halmac_priority_queue_config_8822b(struct halmac_adapter *halmac_adapter, + enum halmac_trx_mode halmac_trx_mode) +{ + u8 transfer_mode = 0; + u8 value8; + u32 counter; + enum halmac_ret_status status; + struct halmac_pg_num_ *curr_pg_num = NULL; + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + if (halmac_adapter->txff_allocation.la_mode == HALMAC_LA_MODE_DISABLE) { + if (halmac_adapter->txff_allocation.rx_fifo_expanding_mode == + HALMAC_RX_FIFO_EXPANDING_MODE_DISABLE) { + halmac_adapter->txff_allocation.tx_fifo_pg_num = + HALMAC_TX_FIFO_SIZE_8822B >> + HALMAC_TX_PAGE_SIZE_2_POWER_8822B; + } else if (halmac_adapter->txff_allocation + .rx_fifo_expanding_mode == + HALMAC_RX_FIFO_EXPANDING_MODE_1_BLOCK) { + halmac_adapter->txff_allocation.tx_fifo_pg_num = + HALMAC_TX_FIFO_SIZE_EX_1_BLK_8822B >> + HALMAC_TX_PAGE_SIZE_2_POWER_8822B; + halmac_adapter->hw_config_info.tx_fifo_size = + HALMAC_TX_FIFO_SIZE_EX_1_BLK_8822B; + if (HALMAC_RX_FIFO_SIZE_EX_1_BLK_8822B <= + HALMAC_RX_FIFO_SIZE_EX_1_BLK_MAX_8822B) + halmac_adapter->hw_config_info.rx_fifo_size = + HALMAC_RX_FIFO_SIZE_EX_1_BLK_8822B; + else + halmac_adapter->hw_config_info.rx_fifo_size = + HALMAC_RX_FIFO_SIZE_EX_1_BLK_MAX_8822B; + } else { + halmac_adapter->txff_allocation.tx_fifo_pg_num = + HALMAC_TX_FIFO_SIZE_8822B >> + HALMAC_TX_PAGE_SIZE_2_POWER_8822B; + pr_err("[ERR]rx_fifo_expanding_mode = %d not support\n", + halmac_adapter->txff_allocation + .rx_fifo_expanding_mode); + } + } else { + halmac_adapter->txff_allocation.tx_fifo_pg_num = + HALMAC_TX_FIFO_SIZE_LA_8822B >> + HALMAC_TX_PAGE_SIZE_2_POWER_8822B; + } + halmac_adapter->txff_allocation.rsvd_pg_num = + (halmac_adapter->txff_allocation.rsvd_drv_pg_num + + HALMAC_RSVD_H2C_EXTRAINFO_PGNUM_8822B + + HALMAC_RSVD_H2C_QUEUE_PGNUM_8822B + + HALMAC_RSVD_CPU_INSTRUCTION_PGNUM_8822B + + HALMAC_RSVD_FW_TXBUFF_PGNUM_8822B); + if (halmac_adapter->txff_allocation.rsvd_pg_num > + halmac_adapter->txff_allocation.tx_fifo_pg_num) + return HALMAC_RET_CFG_TXFIFO_PAGE_FAIL; + + halmac_adapter->txff_allocation.ac_q_pg_num = + halmac_adapter->txff_allocation.tx_fifo_pg_num - + halmac_adapter->txff_allocation.rsvd_pg_num; + halmac_adapter->txff_allocation.rsvd_pg_bndy = + halmac_adapter->txff_allocation.tx_fifo_pg_num - + halmac_adapter->txff_allocation.rsvd_pg_num; + halmac_adapter->txff_allocation.rsvd_fw_txbuff_pg_bndy = + halmac_adapter->txff_allocation.tx_fifo_pg_num - + HALMAC_RSVD_FW_TXBUFF_PGNUM_8822B; + halmac_adapter->txff_allocation.rsvd_cpu_instr_pg_bndy = + halmac_adapter->txff_allocation.rsvd_fw_txbuff_pg_bndy - + HALMAC_RSVD_CPU_INSTRUCTION_PGNUM_8822B; + halmac_adapter->txff_allocation.rsvd_h2c_queue_pg_bndy = + halmac_adapter->txff_allocation.rsvd_cpu_instr_pg_bndy - + HALMAC_RSVD_H2C_QUEUE_PGNUM_8822B; + halmac_adapter->txff_allocation.rsvd_h2c_extra_info_pg_bndy = + halmac_adapter->txff_allocation.rsvd_h2c_queue_pg_bndy - + HALMAC_RSVD_H2C_EXTRAINFO_PGNUM_8822B; + halmac_adapter->txff_allocation.rsvd_drv_pg_bndy = + halmac_adapter->txff_allocation.rsvd_h2c_extra_info_pg_bndy - + halmac_adapter->txff_allocation.rsvd_drv_pg_num; + + if (halmac_adapter->halmac_interface == HALMAC_INTERFACE_SDIO) { + curr_pg_num = HALMAC_PG_NUM_SDIO_8822B; + } else if (halmac_adapter->halmac_interface == HALMAC_INTERFACE_PCIE) { + curr_pg_num = HALMAC_PG_NUM_PCIE_8822B; + } else if (halmac_adapter->halmac_interface == HALMAC_INTERFACE_USB) { + if (halmac_adapter->halmac_bulkout_num == 2) { + curr_pg_num = HALMAC_PG_NUM_2BULKOUT_8822B; + } else if (halmac_adapter->halmac_bulkout_num == 3) { + curr_pg_num = HALMAC_PG_NUM_3BULKOUT_8822B; + } else if (halmac_adapter->halmac_bulkout_num == 4) { + curr_pg_num = HALMAC_PG_NUM_4BULKOUT_8822B; + } else { + pr_err("[ERR]interface not support\n"); + return HALMAC_RET_NOT_SUPPORT; + } + } else { + return HALMAC_RET_NOT_SUPPORT; + } + + status = halmac_pg_num_parser_88xx(halmac_adapter, halmac_trx_mode, + curr_pg_num); + if (status != HALMAC_RET_SUCCESS) + return status; + + HALMAC_REG_WRITE_16(halmac_adapter, REG_FIFOPAGE_INFO_1, + halmac_adapter->txff_allocation.high_queue_pg_num); + HALMAC_REG_WRITE_16(halmac_adapter, REG_FIFOPAGE_INFO_2, + halmac_adapter->txff_allocation.low_queue_pg_num); + HALMAC_REG_WRITE_16( + halmac_adapter, REG_FIFOPAGE_INFO_3, + halmac_adapter->txff_allocation.normal_queue_pg_num); + HALMAC_REG_WRITE_16(halmac_adapter, REG_FIFOPAGE_INFO_4, + halmac_adapter->txff_allocation.extra_queue_pg_num); + HALMAC_REG_WRITE_16(halmac_adapter, REG_FIFOPAGE_INFO_5, + halmac_adapter->txff_allocation.pub_queue_pg_num); + + halmac_adapter->sdio_free_space.high_queue_number = + halmac_adapter->txff_allocation.high_queue_pg_num; + halmac_adapter->sdio_free_space.normal_queue_number = + halmac_adapter->txff_allocation.normal_queue_pg_num; + halmac_adapter->sdio_free_space.low_queue_number = + halmac_adapter->txff_allocation.low_queue_pg_num; + halmac_adapter->sdio_free_space.public_queue_number = + halmac_adapter->txff_allocation.pub_queue_pg_num; + halmac_adapter->sdio_free_space.extra_queue_number = + halmac_adapter->txff_allocation.extra_queue_pg_num; + + HALMAC_REG_WRITE_32( + halmac_adapter, REG_RQPN_CTRL_2, + HALMAC_REG_READ_32(halmac_adapter, REG_RQPN_CTRL_2) | BIT(31)); + + HALMAC_REG_WRITE_16(halmac_adapter, REG_FIFOPAGE_CTRL_2, + (u16)(halmac_adapter->txff_allocation.rsvd_pg_bndy & + BIT_MASK_BCN_HEAD_1_V1)); + HALMAC_REG_WRITE_16(halmac_adapter, REG_BCNQ_BDNY_V1, + (u16)(halmac_adapter->txff_allocation.rsvd_pg_bndy & + BIT_MASK_BCNQ_PGBNDY_V1)); + HALMAC_REG_WRITE_16(halmac_adapter, REG_FIFOPAGE_CTRL_2 + 2, + (u16)(halmac_adapter->txff_allocation.rsvd_pg_bndy & + BIT_MASK_BCN_HEAD_1_V1)); + HALMAC_REG_WRITE_16(halmac_adapter, REG_BCNQ1_BDNY_V1, + (u16)(halmac_adapter->txff_allocation.rsvd_pg_bndy & + BIT_MASK_BCNQ_PGBNDY_V1)); + + HALMAC_REG_WRITE_32(halmac_adapter, REG_RXFF_BNDY, + halmac_adapter->hw_config_info.rx_fifo_size - + HALMAC_C2H_PKT_BUF_8822B - 1); + + if (halmac_adapter->halmac_interface == HALMAC_INTERFACE_USB) { + value8 = (u8)( + HALMAC_REG_READ_8(halmac_adapter, REG_AUTO_LLT_V1) & + ~(BIT_MASK_BLK_DESC_NUM << BIT_SHIFT_BLK_DESC_NUM)); + value8 = (u8)(value8 | (HALMAC_BLK_DESC_NUM_8822B + << BIT_SHIFT_BLK_DESC_NUM)); + HALMAC_REG_WRITE_8(halmac_adapter, REG_AUTO_LLT_V1, value8); + + HALMAC_REG_WRITE_8(halmac_adapter, REG_AUTO_LLT_V1 + 3, + HALMAC_BLK_DESC_NUM_8822B); + HALMAC_REG_WRITE_8(halmac_adapter, REG_TXDMA_OFFSET_CHK + 1, + HALMAC_REG_READ_8(halmac_adapter, + REG_TXDMA_OFFSET_CHK + 1) | + BIT(1)); + } + + HALMAC_REG_WRITE_8( + halmac_adapter, REG_AUTO_LLT_V1, + (u8)(HALMAC_REG_READ_8(halmac_adapter, REG_AUTO_LLT_V1) | + BIT_AUTO_INIT_LLT_V1)); + counter = 1000; + while (HALMAC_REG_READ_8(halmac_adapter, REG_AUTO_LLT_V1) & + BIT_AUTO_INIT_LLT_V1) { + counter--; + if (counter == 0) + return HALMAC_RET_INIT_LLT_FAIL; + } + + if (halmac_trx_mode == HALMAC_TRX_MODE_DELAY_LOOPBACK) { + transfer_mode = HALMAC_TRNSFER_LOOPBACK_DELAY; + HALMAC_REG_WRITE_16( + halmac_adapter, REG_WMAC_LBK_BUF_HD_V1, + (u16)halmac_adapter->txff_allocation.rsvd_pg_bndy); + } else if (halmac_trx_mode == HALMAC_TRX_MODE_LOOPBACK) { + transfer_mode = HALMAC_TRNSFER_LOOPBACK_DIRECT; + } else { + transfer_mode = HALMAC_TRNSFER_NORMAL; + } + + HALMAC_REG_WRITE_8(halmac_adapter, REG_CR + 3, (u8)transfer_mode); + + return HALMAC_RET_SUCCESS; +} diff --git a/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_8822b/halmac_func_8822b.h b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_8822b/halmac_func_8822b.h new file mode 100644 index 000000000000..5ac2b15477c0 --- /dev/null +++ b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_8822b/halmac_func_8822b.h @@ -0,0 +1,38 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef _HALMAC_FUNC_8822B_H_ +#define _HALMAC_FUNC_8822B_H_ + +#include "../../halmac_type.h" + +enum halmac_ret_status +halmac_txdma_queue_mapping_8822b(struct halmac_adapter *halmac_adapter, + enum halmac_trx_mode halmac_trx_mode); + +enum halmac_ret_status +halmac_priority_queue_config_8822b(struct halmac_adapter *halmac_adapter, + enum halmac_trx_mode halmac_trx_mode); + +#endif /* _HALMAC_FUNC_8822B_H_ */ diff --git a/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_88xx_cfg.h b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_88xx_cfg.h new file mode 100644 index 000000000000..ea1206744902 --- /dev/null +++ b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_88xx_cfg.h @@ -0,0 +1,171 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef _HALMAC_88XX_CFG_H_ +#define _HALMAC_88XX_CFG_H_ + +#include "../halmac_2_platform.h" +#include "../halmac_type.h" +#include "../halmac_api.h" +#include "../halmac_bit2.h" +#include "../halmac_reg2.h" +#include "../halmac_pwr_seq_cmd.h" +#include "halmac_func_88xx.h" +#include "halmac_api_88xx.h" +#include "halmac_api_88xx_usb.h" +#include "halmac_api_88xx_pcie.h" +#include "halmac_api_88xx_sdio.h" + +#define HALMAC_SVN_VER_88XX "13359M" + +#define HALMAC_MAJOR_VER_88XX 0x0001 /* major version, ver_1 for async_api */ +/* For halmac_api num change or prototype change, increment prototype version. + * Otherwise, increase minor version + */ +#define HALMAC_PROTOTYPE_VER_88XX 0x0003 /* prototype version */ +#define HALMAC_MINOR_VER_88XX 0x0005 /* minor version */ +#define HALMAC_PATCH_VER_88XX 0x0000 /* patch version */ + +#define HALMAC_C2H_DATA_OFFSET_88XX 10 +#define HALMAC_RX_AGG_ALIGNMENT_SIZE_88XX 8 +#define HALMAC_TX_AGG_ALIGNMENT_SIZE_88XX 8 +#define HALMAC_TX_AGG_BUFF_SIZE_88XX 32768 + +#define HALMAC_EXTRA_INFO_BUFF_SIZE_88XX 4096 /*4K*/ +#define HALMAC_EXTRA_INFO_BUFF_SIZE_FULL_FIFO_88XX 16384 /*16K*/ +#define HALMAC_FW_OFFLOAD_CMD_SIZE_88XX \ + 12 /*Fw config parameter cmd size, each 12 byte*/ + +#define HALMAC_H2C_CMD_ORIGINAL_SIZE_88XX 8 +#define HALMAC_H2C_CMD_SIZE_UNIT_88XX 32 /* Only support 32 byte packet now */ + +#define HALMAC_NLO_INFO_SIZE_88XX 1024 + +/* Download FW */ +#define HALMAC_FW_SIZE_MAX_88XX 0x40000 +#define HALMAC_FWHDR_SIZE_88XX 64 +#define HALMAC_FW_CHKSUM_DUMMY_SIZE_88XX 8 +#define HALMAC_FW_MAX_DL_SIZE_88XX 0x2000 /* need power of 2 */ +/* Max dlfw size can not over 31K, because SDIO HW restriction */ +#define HALMAC_FW_CFG_MAX_DL_SIZE_MAX_88XX 0x7C00 + +#define DLFW_RESTORE_REG_NUM_88XX 9 +#define ID_INFORM_DLEMEM_RDY 0x80 + +/* FW header information */ +#define HALMAC_FWHDR_OFFSET_VERSION_88XX 4 +#define HALMAC_FWHDR_OFFSET_SUBVERSION_88XX 6 +#define HALMAC_FWHDR_OFFSET_SUBINDEX_88XX 7 +#define HALMAC_FWHDR_OFFSET_MEM_USAGE_88XX 24 +#define HALMAC_FWHDR_OFFSET_H2C_FORMAT_VER_88XX 28 +#define HALMAC_FWHDR_OFFSET_DMEM_ADDR_88XX 32 +#define HALMAC_FWHDR_OFFSET_DMEM_SIZE_88XX 36 +#define HALMAC_FWHDR_OFFSET_IRAM_SIZE_88XX 48 +#define HALMAC_FWHDR_OFFSET_ERAM_SIZE_88XX 52 +#define HALMAC_FWHDR_OFFSET_EMEM_ADDR_88XX 56 +#define HALMAC_FWHDR_OFFSET_IRAM_ADDR_88XX 60 + +/* HW memory address */ +#define HALMAC_OCPBASE_TXBUF_88XX 0x18780000 +#define HALMAC_OCPBASE_DMEM_88XX 0x00200000 +#define HALMAC_OCPBASE_IMEM_88XX 0x00000000 + +/* define the SDIO Bus CLK threshold, for avoiding CMD53 fails that + * result from SDIO CLK sync to ana_clk fail + */ +#define HALMAC_SD_CLK_THRESHOLD_88XX 150000000 /* 150MHz */ + +/* MAC clock */ +#define HALMAC_MAC_CLOCK_88XX 80 /* 80M */ + +/* H2C/C2H*/ +#define HALMAC_H2C_CMD_SIZE_88XX 32 +#define HALMAC_H2C_CMD_HDR_SIZE_88XX 8 + +#define HALMAC_PROTECTED_EFUSE_SIZE_88XX 0x60 + +/* Function enable */ +#define HALMAC_FUNCTION_ENABLE_88XX 0xDC + +/* FIFO size & packet size */ +/* #define HALMAC_WOWLAN_PATTERN_SIZE 256 */ + +/* CFEND rate */ +#define HALMAC_BASIC_CFEND_RATE_88XX 0x5 +#define HALMAC_STBC_CFEND_RATE_88XX 0xF + +/* Response rate */ +#define HALMAC_RESPONSE_RATE_BITMAP_ALL_88XX 0xFFFFF +#define HALMAC_RESPONSE_RATE_88XX HALMAC_RESPONSE_RATE_BITMAP_ALL_88XX + +/* Spec SIFS */ +#define HALMAC_SIFS_CCK_PTCL_88XX 16 +#define HALMAC_SIFS_OFDM_PTCL_88XX 16 + +/* Retry limit */ +#define HALMAC_LONG_RETRY_LIMIT_88XX 8 +#define HALMAC_SHORT_RETRY_LIMIT_88XX 7 + +/* Slot, SIFS, PIFS time */ +#define HALMAC_SLOT_TIME_88XX 0x05 +#define HALMAC_PIFS_TIME_88XX 0x19 +#define HALMAC_SIFS_CCK_CTX_88XX 0xA +#define HALMAC_SIFS_OFDM_CTX_88XX 0xA +#define HALMAC_SIFS_CCK_TRX_88XX 0x10 +#define HALMAC_SIFS_OFDM_TRX_88XX 0x10 + +/* TXOP limit */ +#define HALMAC_VO_TXOP_LIMIT_88XX 0x186 +#define HALMAC_VI_TXOP_LIMIT_88XX 0x3BC + +/* NAV */ +#define HALMAC_RDG_NAV_88XX 0x05 +#define HALMAC_TXOP_NAV_88XX 0x1B + +/* TSF */ +#define HALMAC_CCK_RX_TSF_88XX 0x30 +#define HALMAC_OFDM_RX_TSF_88XX 0x30 + +/* Send beacon related */ +#define HALMAC_TBTT_PROHIBIT_88XX 0x04 +#define HALMAC_TBTT_HOLD_TIME_88XX 0x064 +#define HALMAC_DRIVER_EARLY_INT_88XX 0x04 +#define HALMAC_BEACON_DMA_TIM_88XX 0x02 + +/* RX filter */ +#define HALMAC_RX_FILTER0_RECIVE_ALL_88XX 0xFFFFFFF +#define HALMAC_RX_FILTER0_88XX HALMAC_RX_FILTER0_RECIVE_ALL_88XX +#define HALMAC_RX_FILTER_RECIVE_ALL_88XX 0xFFFF +#define HALMAC_RX_FILTER_88XX HALMAC_RX_FILTER_RECIVE_ALL_88XX + +/* RCR */ +#define HALMAC_RCR_CONFIG_88XX 0xE400631E + +/* Security config */ +#define HALMAC_SECURITY_CONFIG_88XX 0x01CC + +/* CCK rate ACK timeout */ +#define HALMAC_ACK_TO_CCK_88XX 0x40 + +#endif diff --git a/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_api_88xx.c b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_api_88xx.c new file mode 100644 index 000000000000..5f84526cb5b5 --- /dev/null +++ b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_api_88xx.c @@ -0,0 +1,5979 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#include "halmac_88xx_cfg.h" + +/** + * halmac_init_adapter_para_88xx() - int halmac adapter + * @halmac_adapter + * + * SD1 internal use + * + * Author : KaiYuan Chang/Ivan Lin + * Return : void + */ +void halmac_init_adapter_para_88xx(struct halmac_adapter *halmac_adapter) +{ + halmac_adapter->api_record.array_wptr = 0; + halmac_adapter->hal_adapter_backup = halmac_adapter; + halmac_adapter->hal_efuse_map = (u8 *)NULL; + halmac_adapter->hal_efuse_map_valid = false; + halmac_adapter->efuse_end = 0; + halmac_adapter->hal_mac_addr[0].address_l_h.address_low = 0; + halmac_adapter->hal_mac_addr[0].address_l_h.address_high = 0; + halmac_adapter->hal_mac_addr[1].address_l_h.address_low = 0; + halmac_adapter->hal_mac_addr[1].address_l_h.address_high = 0; + halmac_adapter->hal_bss_addr[0].address_l_h.address_low = 0; + halmac_adapter->hal_bss_addr[0].address_l_h.address_high = 0; + halmac_adapter->hal_bss_addr[1].address_l_h.address_low = 0; + halmac_adapter->hal_bss_addr[1].address_l_h.address_high = 0; + + halmac_adapter->low_clk = false; + halmac_adapter->max_download_size = HALMAC_FW_MAX_DL_SIZE_88XX; + + /* Init LPS Option */ + halmac_adapter->fwlps_option.mode = 0x01; /*0:Active 1:LPS 2:WMMPS*/ + halmac_adapter->fwlps_option.awake_interval = 1; + halmac_adapter->fwlps_option.enter_32K = 1; + halmac_adapter->fwlps_option.clk_request = 0; + halmac_adapter->fwlps_option.rlbm = 0; + halmac_adapter->fwlps_option.smart_ps = 0; + halmac_adapter->fwlps_option.awake_interval = 1; + halmac_adapter->fwlps_option.all_queue_uapsd = 0; + halmac_adapter->fwlps_option.pwr_state = 0; + halmac_adapter->fwlps_option.low_pwr_rx_beacon = 0; + halmac_adapter->fwlps_option.ant_auto_switch = 0; + halmac_adapter->fwlps_option.ps_allow_bt_high_priority = 0; + halmac_adapter->fwlps_option.protect_bcn = 0; + halmac_adapter->fwlps_option.silence_period = 0; + halmac_adapter->fwlps_option.fast_bt_connect = 0; + halmac_adapter->fwlps_option.two_antenna_en = 0; + halmac_adapter->fwlps_option.adopt_user_setting = 1; + halmac_adapter->fwlps_option.drv_bcn_early_shift = 0; + + halmac_adapter->config_para_info.cfg_para_buf = NULL; + halmac_adapter->config_para_info.para_buf_w = NULL; + halmac_adapter->config_para_info.para_num = 0; + halmac_adapter->config_para_info.full_fifo_mode = false; + halmac_adapter->config_para_info.para_buf_size = 0; + halmac_adapter->config_para_info.avai_para_buf_size = 0; + halmac_adapter->config_para_info.offset_accumulation = 0; + halmac_adapter->config_para_info.value_accumulation = 0; + halmac_adapter->config_para_info.datapack_segment = 0; + + halmac_adapter->ch_sw_info.ch_info_buf = NULL; + halmac_adapter->ch_sw_info.ch_info_buf_w = NULL; + halmac_adapter->ch_sw_info.extra_info_en = 0; + halmac_adapter->ch_sw_info.buf_size = 0; + halmac_adapter->ch_sw_info.avai_buf_size = 0; + halmac_adapter->ch_sw_info.total_size = 0; + halmac_adapter->ch_sw_info.ch_num = 0; + + halmac_adapter->drv_info_size = 0; + + memset(halmac_adapter->api_record.api_array, HALMAC_API_STUFF, + sizeof(halmac_adapter->api_record.api_array)); + + halmac_adapter->txff_allocation.tx_fifo_pg_num = 0; + halmac_adapter->txff_allocation.ac_q_pg_num = 0; + halmac_adapter->txff_allocation.rsvd_pg_bndy = 0; + halmac_adapter->txff_allocation.rsvd_drv_pg_bndy = 0; + halmac_adapter->txff_allocation.rsvd_h2c_extra_info_pg_bndy = 0; + halmac_adapter->txff_allocation.rsvd_h2c_queue_pg_bndy = 0; + halmac_adapter->txff_allocation.rsvd_cpu_instr_pg_bndy = 0; + halmac_adapter->txff_allocation.rsvd_fw_txbuff_pg_bndy = 0; + halmac_adapter->txff_allocation.pub_queue_pg_num = 0; + halmac_adapter->txff_allocation.high_queue_pg_num = 0; + halmac_adapter->txff_allocation.low_queue_pg_num = 0; + halmac_adapter->txff_allocation.normal_queue_pg_num = 0; + halmac_adapter->txff_allocation.extra_queue_pg_num = 0; + + halmac_adapter->txff_allocation.la_mode = HALMAC_LA_MODE_DISABLE; + halmac_adapter->txff_allocation.rx_fifo_expanding_mode = + HALMAC_RX_FIFO_EXPANDING_MODE_DISABLE; + + halmac_init_adapter_dynamic_para_88xx(halmac_adapter); + halmac_init_state_machine_88xx(halmac_adapter); +} + +/** + * halmac_init_adapter_dynamic_para_88xx() - int halmac adapter + * @halmac_adapter + * + * SD1 internal use + * + * Author : KaiYuan Chang/Ivan Lin + * Return : void + */ +void halmac_init_adapter_dynamic_para_88xx( + struct halmac_adapter *halmac_adapter) +{ + halmac_adapter->h2c_packet_seq = 0; + halmac_adapter->h2c_buf_free_space = 0; + halmac_adapter->gen_info_valid = false; +} + +/** + * halmac_init_state_machine_88xx() - init halmac software state machine + * @halmac_adapter + * + * SD1 internal use. + * + * Author : KaiYuan Chang/Ivan Lin + * Return : void + */ +void halmac_init_state_machine_88xx(struct halmac_adapter *halmac_adapter) +{ + struct halmac_state *state = &halmac_adapter->halmac_state; + + halmac_init_offload_feature_state_machine_88xx(halmac_adapter); + + state->api_state = HALMAC_API_STATE_INIT; + + state->dlfw_state = HALMAC_DLFW_NONE; + state->mac_power = HALMAC_MAC_POWER_OFF; + state->ps_state = HALMAC_PS_STATE_UNDEFINE; +} + +/** + * halmac_mount_api_88xx() - attach functions to function pointer + * @halmac_adapter + * + * SD1 internal use + * + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + */ +enum halmac_ret_status +halmac_mount_api_88xx(struct halmac_adapter *halmac_adapter) +{ + void *driver_adapter = halmac_adapter->driver_adapter; + struct halmac_api *halmac_api = (struct halmac_api *)NULL; + + halmac_adapter->halmac_api = + kzalloc(sizeof(struct halmac_api), GFP_KERNEL); + if (!halmac_adapter->halmac_api) + return HALMAC_RET_MALLOC_FAIL; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + HALMAC_SVN_VER_88XX "\n"); + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "HALMAC_MAJOR_VER_88XX = %x\n", HALMAC_MAJOR_VER_88XX); + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "HALMAC_PROTOTYPE_88XX = %x\n", + HALMAC_PROTOTYPE_VER_88XX); + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "HALMAC_MINOR_VER_88XX = %x\n", HALMAC_MINOR_VER_88XX); + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "HALMAC_PATCH_VER_88XX = %x\n", HALMAC_PATCH_VER_88XX); + + /* Mount function pointer */ + halmac_api->halmac_download_firmware = halmac_download_firmware_88xx; + halmac_api->halmac_free_download_firmware = + halmac_free_download_firmware_88xx; + halmac_api->halmac_get_fw_version = halmac_get_fw_version_88xx; + halmac_api->halmac_cfg_mac_addr = halmac_cfg_mac_addr_88xx; + halmac_api->halmac_cfg_bssid = halmac_cfg_bssid_88xx; + halmac_api->halmac_cfg_multicast_addr = halmac_cfg_multicast_addr_88xx; + halmac_api->halmac_pre_init_system_cfg = + halmac_pre_init_system_cfg_88xx; + halmac_api->halmac_init_system_cfg = halmac_init_system_cfg_88xx; + halmac_api->halmac_init_edca_cfg = halmac_init_edca_cfg_88xx; + halmac_api->halmac_cfg_operation_mode = halmac_cfg_operation_mode_88xx; + halmac_api->halmac_cfg_ch_bw = halmac_cfg_ch_bw_88xx; + halmac_api->halmac_cfg_bw = halmac_cfg_bw_88xx; + halmac_api->halmac_init_wmac_cfg = halmac_init_wmac_cfg_88xx; + halmac_api->halmac_init_mac_cfg = halmac_init_mac_cfg_88xx; + halmac_api->halmac_init_sdio_cfg = halmac_init_sdio_cfg_88xx; + halmac_api->halmac_init_usb_cfg = halmac_init_usb_cfg_88xx; + halmac_api->halmac_init_pcie_cfg = halmac_init_pcie_cfg_88xx; + halmac_api->halmac_deinit_sdio_cfg = halmac_deinit_sdio_cfg_88xx; + halmac_api->halmac_deinit_usb_cfg = halmac_deinit_usb_cfg_88xx; + halmac_api->halmac_deinit_pcie_cfg = halmac_deinit_pcie_cfg_88xx; + halmac_api->halmac_dump_efuse_map = halmac_dump_efuse_map_88xx; + halmac_api->halmac_dump_efuse_map_bt = halmac_dump_efuse_map_bt_88xx; + halmac_api->halmac_write_efuse_bt = halmac_write_efuse_bt_88xx; + halmac_api->halmac_dump_logical_efuse_map = + halmac_dump_logical_efuse_map_88xx; + halmac_api->halmac_pg_efuse_by_map = halmac_pg_efuse_by_map_88xx; + halmac_api->halmac_get_efuse_size = halmac_get_efuse_size_88xx; + halmac_api->halmac_get_efuse_available_size = + halmac_get_efuse_available_size_88xx; + halmac_api->halmac_get_c2h_info = halmac_get_c2h_info_88xx; + + halmac_api->halmac_get_logical_efuse_size = + halmac_get_logical_efuse_size_88xx; + + halmac_api->halmac_write_logical_efuse = + halmac_write_logical_efuse_88xx; + halmac_api->halmac_read_logical_efuse = halmac_read_logical_efuse_88xx; + + halmac_api->halmac_cfg_fwlps_option = halmac_cfg_fwlps_option_88xx; + halmac_api->halmac_cfg_fwips_option = halmac_cfg_fwips_option_88xx; + halmac_api->halmac_enter_wowlan = halmac_enter_wowlan_88xx; + halmac_api->halmac_leave_wowlan = halmac_leave_wowlan_88xx; + halmac_api->halmac_enter_ps = halmac_enter_ps_88xx; + halmac_api->halmac_leave_ps = halmac_leave_ps_88xx; + halmac_api->halmac_h2c_lb = halmac_h2c_lb_88xx; + halmac_api->halmac_debug = halmac_debug_88xx; + halmac_api->halmac_cfg_parameter = halmac_cfg_parameter_88xx; + halmac_api->halmac_update_datapack = halmac_update_datapack_88xx; + halmac_api->halmac_run_datapack = halmac_run_datapack_88xx; + halmac_api->halmac_cfg_drv_info = halmac_cfg_drv_info_88xx; + halmac_api->halmac_send_bt_coex = halmac_send_bt_coex_88xx; + halmac_api->halmac_verify_platform_api = + halmac_verify_platform_api_88xx; + halmac_api->halmac_update_packet = halmac_update_packet_88xx; + halmac_api->halmac_bcn_ie_filter = halmac_bcn_ie_filter_88xx; + halmac_api->halmac_cfg_txbf = halmac_cfg_txbf_88xx; + halmac_api->halmac_cfg_mumimo = halmac_cfg_mumimo_88xx; + halmac_api->halmac_cfg_sounding = halmac_cfg_sounding_88xx; + halmac_api->halmac_del_sounding = halmac_del_sounding_88xx; + halmac_api->halmac_su_bfer_entry_init = halmac_su_bfer_entry_init_88xx; + halmac_api->halmac_su_bfee_entry_init = halmac_su_bfee_entry_init_88xx; + halmac_api->halmac_mu_bfer_entry_init = halmac_mu_bfer_entry_init_88xx; + halmac_api->halmac_mu_bfee_entry_init = halmac_mu_bfee_entry_init_88xx; + halmac_api->halmac_su_bfer_entry_del = halmac_su_bfer_entry_del_88xx; + halmac_api->halmac_su_bfee_entry_del = halmac_su_bfee_entry_del_88xx; + halmac_api->halmac_mu_bfer_entry_del = halmac_mu_bfer_entry_del_88xx; + halmac_api->halmac_mu_bfee_entry_del = halmac_mu_bfee_entry_del_88xx; + + halmac_api->halmac_add_ch_info = halmac_add_ch_info_88xx; + halmac_api->halmac_add_extra_ch_info = halmac_add_extra_ch_info_88xx; + halmac_api->halmac_ctrl_ch_switch = halmac_ctrl_ch_switch_88xx; + halmac_api->halmac_p2pps = halmac_p2pps_88xx; + halmac_api->halmac_clear_ch_info = halmac_clear_ch_info_88xx; + halmac_api->halmac_send_general_info = halmac_send_general_info_88xx; + + halmac_api->halmac_start_iqk = halmac_start_iqk_88xx; + halmac_api->halmac_ctrl_pwr_tracking = halmac_ctrl_pwr_tracking_88xx; + halmac_api->halmac_psd = halmac_psd_88xx; + halmac_api->halmac_cfg_la_mode = halmac_cfg_la_mode_88xx; + halmac_api->halmac_cfg_rx_fifo_expanding_mode = + halmac_cfg_rx_fifo_expanding_mode_88xx; + + halmac_api->halmac_config_security = halmac_config_security_88xx; + halmac_api->halmac_get_used_cam_entry_num = + halmac_get_used_cam_entry_num_88xx; + halmac_api->halmac_read_cam_entry = halmac_read_cam_entry_88xx; + halmac_api->halmac_write_cam = halmac_write_cam_88xx; + halmac_api->halmac_clear_cam_entry = halmac_clear_cam_entry_88xx; + + halmac_api->halmac_get_hw_value = halmac_get_hw_value_88xx; + halmac_api->halmac_set_hw_value = halmac_set_hw_value_88xx; + + halmac_api->halmac_cfg_drv_rsvd_pg_num = + halmac_cfg_drv_rsvd_pg_num_88xx; + halmac_api->halmac_get_chip_version = halmac_get_chip_version_88xx; + + halmac_api->halmac_query_status = halmac_query_status_88xx; + halmac_api->halmac_reset_feature = halmac_reset_feature_88xx; + halmac_api->halmac_check_fw_status = halmac_check_fw_status_88xx; + halmac_api->halmac_dump_fw_dmem = halmac_dump_fw_dmem_88xx; + halmac_api->halmac_cfg_max_dl_size = halmac_cfg_max_dl_size_88xx; + + halmac_api->halmac_dump_fifo = halmac_dump_fifo_88xx; + halmac_api->halmac_get_fifo_size = halmac_get_fifo_size_88xx; + + halmac_api->halmac_chk_txdesc = halmac_chk_txdesc_88xx; + halmac_api->halmac_dl_drv_rsvd_page = halmac_dl_drv_rsvd_page_88xx; + halmac_api->halmac_cfg_csi_rate = halmac_cfg_csi_rate_88xx; + + halmac_api->halmac_sdio_cmd53_4byte = halmac_sdio_cmd53_4byte_88xx; + halmac_api->halmac_txfifo_is_empty = halmac_txfifo_is_empty_88xx; + + if (halmac_adapter->halmac_interface == HALMAC_INTERFACE_SDIO) { + halmac_api->halmac_cfg_rx_aggregation = + halmac_cfg_rx_aggregation_88xx_sdio; + halmac_api->halmac_init_interface_cfg = + halmac_init_sdio_cfg_88xx; + halmac_api->halmac_deinit_interface_cfg = + halmac_deinit_sdio_cfg_88xx; + halmac_api->halmac_reg_read_8 = halmac_reg_read_8_sdio_88xx; + halmac_api->halmac_reg_write_8 = halmac_reg_write_8_sdio_88xx; + halmac_api->halmac_reg_read_16 = halmac_reg_read_16_sdio_88xx; + halmac_api->halmac_reg_write_16 = halmac_reg_write_16_sdio_88xx; + halmac_api->halmac_reg_read_32 = halmac_reg_read_32_sdio_88xx; + halmac_api->halmac_reg_write_32 = halmac_reg_write_32_sdio_88xx; + halmac_api->halmac_reg_read_indirect_32 = + halmac_reg_read_indirect_32_sdio_88xx; + halmac_api->halmac_reg_sdio_cmd53_read_n = + halmac_reg_read_nbyte_sdio_88xx; + } else if (halmac_adapter->halmac_interface == HALMAC_INTERFACE_USB) { + halmac_api->halmac_cfg_rx_aggregation = + halmac_cfg_rx_aggregation_88xx_usb; + halmac_api->halmac_init_interface_cfg = + halmac_init_usb_cfg_88xx; + halmac_api->halmac_deinit_interface_cfg = + halmac_deinit_usb_cfg_88xx; + halmac_api->halmac_reg_read_8 = halmac_reg_read_8_usb_88xx; + halmac_api->halmac_reg_write_8 = halmac_reg_write_8_usb_88xx; + halmac_api->halmac_reg_read_16 = halmac_reg_read_16_usb_88xx; + halmac_api->halmac_reg_write_16 = halmac_reg_write_16_usb_88xx; + halmac_api->halmac_reg_read_32 = halmac_reg_read_32_usb_88xx; + halmac_api->halmac_reg_write_32 = halmac_reg_write_32_usb_88xx; + } else if (halmac_adapter->halmac_interface == HALMAC_INTERFACE_PCIE) { + halmac_api->halmac_cfg_rx_aggregation = + halmac_cfg_rx_aggregation_88xx_pcie; + halmac_api->halmac_init_interface_cfg = + halmac_init_pcie_cfg_88xx; + halmac_api->halmac_deinit_interface_cfg = + halmac_deinit_pcie_cfg_88xx; + halmac_api->halmac_reg_read_8 = halmac_reg_read_8_pcie_88xx; + halmac_api->halmac_reg_write_8 = halmac_reg_write_8_pcie_88xx; + halmac_api->halmac_reg_read_16 = halmac_reg_read_16_pcie_88xx; + halmac_api->halmac_reg_write_16 = halmac_reg_write_16_pcie_88xx; + halmac_api->halmac_reg_read_32 = halmac_reg_read_32_pcie_88xx; + halmac_api->halmac_reg_write_32 = halmac_reg_write_32_pcie_88xx; + } else { + pr_err("Set halmac io function Error!!\n"); + } + + halmac_api->halmac_set_bulkout_num = halmac_set_bulkout_num_88xx; + halmac_api->halmac_get_sdio_tx_addr = halmac_get_sdio_tx_addr_88xx; + halmac_api->halmac_get_usb_bulkout_id = halmac_get_usb_bulkout_id_88xx; + halmac_api->halmac_timer_2s = halmac_timer_2s_88xx; + halmac_api->halmac_fill_txdesc_checksum = + halmac_fill_txdesc_check_sum_88xx; + + if (halmac_adapter->chip_id == HALMAC_CHIP_ID_8822B) { + /*mount 8822b function and data*/ + halmac_mount_api_8822b(halmac_adapter); + + } else if (halmac_adapter->chip_id == HALMAC_CHIP_ID_8821C) { + } else if (halmac_adapter->chip_id == HALMAC_CHIP_ID_8814B) { + } else if (halmac_adapter->chip_id == HALMAC_CHIP_ID_8197F) { + } else { + pr_err("Chip ID undefine!!\n"); + return HALMAC_RET_CHIP_NOT_SUPPORT; + } + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_download_firmware_88xx() - download Firmware + * @halmac_adapter : the adapter of halmac + * @hamacl_fw : firmware bin + * @halmac_fw_size : firmware size + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_download_firmware_88xx(struct halmac_adapter *halmac_adapter, + u8 *hamacl_fw, u32 halmac_fw_size) +{ + u8 value8; + u8 *file_ptr; + u32 dest; + u16 value16; + u32 restore_index = 0; + u32 halmac_h2c_ver = 0, fw_h2c_ver = 0; + u32 iram_pkt_size, dmem_pkt_size, eram_pkt_size = 0; + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + struct halmac_restore_info restore_info[DLFW_RESTORE_REG_NUM_88XX]; + u32 temp; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_DOWNLOAD_FIRMWARE); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s ==========>\n", __func__); + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s start!!\n", __func__); + + if (halmac_fw_size > HALMAC_FW_SIZE_MAX_88XX || + halmac_fw_size < HALMAC_FWHDR_SIZE_88XX) { + pr_err("FW size error!\n"); + return HALMAC_RET_FW_SIZE_ERR; + } + + fw_h2c_ver = le32_to_cpu( + *((__le32 *) + (hamacl_fw + HALMAC_FWHDR_OFFSET_H2C_FORMAT_VER_88XX))); + halmac_h2c_ver = H2C_FORMAT_VERSION; + HALMAC_RT_TRACE( + driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "halmac h2c/c2h format = %x, fw h2c/c2h format = %x!!\n", + halmac_h2c_ver, fw_h2c_ver); + if (fw_h2c_ver != halmac_h2c_ver) + HALMAC_RT_TRACE( + driver_adapter, HALMAC_MSG_INIT, DBG_WARNING, + "[WARN]H2C/C2H version between HALMAC and FW is compatible!!\n"); + + halmac_adapter->halmac_state.dlfw_state = HALMAC_DLFW_NONE; + + value8 = HALMAC_REG_READ_8(halmac_adapter, REG_SYS_FUNC_EN + 1); + value8 = (u8)(value8 & ~(BIT(2))); + HALMAC_REG_WRITE_8(halmac_adapter, REG_SYS_FUNC_EN + 1, + value8); /* Disable CPU reset */ + + value8 = HALMAC_REG_READ_8(halmac_adapter, REG_RSV_CTRL + 1); + value8 = (u8)(value8 & ~(BIT(0))); + HALMAC_REG_WRITE_8(halmac_adapter, REG_RSV_CTRL + 1, value8); + + restore_info[restore_index].length = 1; + restore_info[restore_index].mac_register = REG_TXDMA_PQ_MAP + 1; + restore_info[restore_index].value = + HALMAC_REG_READ_8(halmac_adapter, REG_TXDMA_PQ_MAP + 1); + restore_index++; + value8 = HALMAC_DMA_MAPPING_HIGH << 6; + HALMAC_REG_WRITE_8(halmac_adapter, REG_TXDMA_PQ_MAP + 1, + value8); /* set HIQ to hi priority */ + + /* DLFW only use HIQ, map HIQ to hi priority */ + halmac_adapter->halmac_ptcl_queue[HALMAC_PTCL_QUEUE_HI] = + HALMAC_DMA_MAPPING_HIGH; + restore_info[restore_index].length = 1; + restore_info[restore_index].mac_register = REG_CR; + restore_info[restore_index].value = + HALMAC_REG_READ_8(halmac_adapter, REG_CR); + restore_index++; + restore_info[restore_index].length = 4; + restore_info[restore_index].mac_register = REG_H2CQ_CSR; + restore_info[restore_index].value = BIT(31); + restore_index++; + value8 = BIT_HCI_TXDMA_EN | BIT_TXDMA_EN; + HALMAC_REG_WRITE_8(halmac_adapter, REG_CR, value8); + HALMAC_REG_WRITE_32(halmac_adapter, REG_H2CQ_CSR, BIT(31)); + + /* Config hi priority queue and public priority queue page number + * (only for DLFW) + */ + restore_info[restore_index].length = 2; + restore_info[restore_index].mac_register = REG_FIFOPAGE_INFO_1; + restore_info[restore_index].value = + HALMAC_REG_READ_16(halmac_adapter, REG_FIFOPAGE_INFO_1); + restore_index++; + restore_info[restore_index].length = 4; + restore_info[restore_index].mac_register = REG_RQPN_CTRL_2; + restore_info[restore_index].value = + HALMAC_REG_READ_32(halmac_adapter, REG_RQPN_CTRL_2) | BIT(31); + restore_index++; + HALMAC_REG_WRITE_16(halmac_adapter, REG_FIFOPAGE_INFO_1, 0x200); + HALMAC_REG_WRITE_32(halmac_adapter, REG_RQPN_CTRL_2, + restore_info[restore_index - 1].value); + + if (halmac_adapter->halmac_interface == HALMAC_INTERFACE_SDIO) { + HALMAC_REG_READ_32(halmac_adapter, REG_SDIO_FREE_TXPG); + HALMAC_REG_WRITE_32(halmac_adapter, REG_SDIO_TX_CTRL, + 0x00000000); + } + + halmac_adapter->fw_version.version = le16_to_cpu( + *((__le16 *)(hamacl_fw + HALMAC_FWHDR_OFFSET_VERSION_88XX))); + halmac_adapter->fw_version.sub_version = + *(hamacl_fw + HALMAC_FWHDR_OFFSET_SUBVERSION_88XX); + halmac_adapter->fw_version.sub_index = + *(hamacl_fw + HALMAC_FWHDR_OFFSET_SUBINDEX_88XX); + halmac_adapter->fw_version.h2c_version = (u16)fw_h2c_ver; + + dmem_pkt_size = le32_to_cpu(*((__le32 *)(hamacl_fw + + HALMAC_FWHDR_OFFSET_DMEM_SIZE_88XX))); + iram_pkt_size = le32_to_cpu(*((__le32 *)(hamacl_fw + + HALMAC_FWHDR_OFFSET_IRAM_SIZE_88XX))); + if (((*(hamacl_fw + HALMAC_FWHDR_OFFSET_MEM_USAGE_88XX)) & BIT(4)) != 0) + eram_pkt_size = + le32_to_cpu(*((__le32 *)(hamacl_fw + + HALMAC_FWHDR_OFFSET_ERAM_SIZE_88XX))); + + dmem_pkt_size += HALMAC_FW_CHKSUM_DUMMY_SIZE_88XX; + iram_pkt_size += HALMAC_FW_CHKSUM_DUMMY_SIZE_88XX; + if (eram_pkt_size != 0) + eram_pkt_size += HALMAC_FW_CHKSUM_DUMMY_SIZE_88XX; + + if (halmac_fw_size != (HALMAC_FWHDR_SIZE_88XX + dmem_pkt_size + + iram_pkt_size + eram_pkt_size)) { + pr_err("FW size mismatch the real fw size!\n"); + goto DLFW_FAIL; + } + + value8 = HALMAC_REG_READ_8(halmac_adapter, REG_CR + 1); + restore_info[restore_index].length = 1; + restore_info[restore_index].mac_register = REG_CR + 1; + restore_info[restore_index].value = value8; + restore_index++; + value8 = (u8)(value8 | BIT(0)); + HALMAC_REG_WRITE_8(halmac_adapter, REG_CR + 1, + value8); /* Enable SW TX beacon */ + + value8 = HALMAC_REG_READ_8(halmac_adapter, REG_BCN_CTRL); + restore_info[restore_index].length = 1; + restore_info[restore_index].mac_register = REG_BCN_CTRL; + restore_info[restore_index].value = value8; + restore_index++; + value8 = (u8)((value8 & (~BIT(3))) | BIT(4)); + HALMAC_REG_WRITE_8(halmac_adapter, REG_BCN_CTRL, + value8); /* Disable beacon related functions */ + + value8 = HALMAC_REG_READ_8(halmac_adapter, REG_FWHW_TXQ_CTRL + 2); + restore_info[restore_index].length = 1; + restore_info[restore_index].mac_register = REG_FWHW_TXQ_CTRL + 2; + restore_info[restore_index].value = value8; + restore_index++; + value8 = (u8)(value8 & ~(BIT(6))); + HALMAC_REG_WRITE_8(halmac_adapter, REG_FWHW_TXQ_CTRL + 2, + value8); /* Disable ptcl tx bcnq */ + + restore_info[restore_index].length = 2; + restore_info[restore_index].mac_register = REG_FIFOPAGE_CTRL_2; + restore_info[restore_index].value = + HALMAC_REG_READ_16(halmac_adapter, REG_FIFOPAGE_CTRL_2) | + BIT(15); + restore_index++; + value16 = 0x8000; + HALMAC_REG_WRITE_16(halmac_adapter, REG_FIFOPAGE_CTRL_2, + value16); /* Set beacon header to 0 */ + + value16 = (u16)(HALMAC_REG_READ_16(halmac_adapter, REG_MCUFW_CTRL) & + 0x3800); + value16 |= BIT(0); + HALMAC_REG_WRITE_16(halmac_adapter, REG_MCUFW_CTRL, + value16); /* MCU/FW setting */ + + value8 = HALMAC_REG_READ_8(halmac_adapter, REG_CPU_DMEM_CON + 2); + value8 &= ~(BIT(0)); + HALMAC_REG_WRITE_8(halmac_adapter, REG_CPU_DMEM_CON + 2, value8); + value8 |= BIT(0); + HALMAC_REG_WRITE_8(halmac_adapter, REG_CPU_DMEM_CON + 2, value8); + + /* Download to DMEM */ + file_ptr = hamacl_fw + HALMAC_FWHDR_SIZE_88XX; + temp = le32_to_cpu(*((__le32 *)(hamacl_fw + + HALMAC_FWHDR_OFFSET_DMEM_ADDR_88XX))) & + ~(BIT(31)); + if (halmac_dlfw_to_mem_88xx(halmac_adapter, file_ptr, temp, + dmem_pkt_size) != HALMAC_RET_SUCCESS) + goto DLFW_END; + + /* Download to IMEM */ + file_ptr = hamacl_fw + HALMAC_FWHDR_SIZE_88XX + dmem_pkt_size; + temp = le32_to_cpu(*((__le32 *)(hamacl_fw + + HALMAC_FWHDR_OFFSET_IRAM_ADDR_88XX))) & + ~(BIT(31)); + if (halmac_dlfw_to_mem_88xx(halmac_adapter, file_ptr, temp, + iram_pkt_size) != HALMAC_RET_SUCCESS) + goto DLFW_END; + + /* Download to EMEM */ + if (eram_pkt_size != 0) { + file_ptr = hamacl_fw + HALMAC_FWHDR_SIZE_88XX + dmem_pkt_size + + iram_pkt_size; + dest = le32_to_cpu((*((__le32 *)(hamacl_fw + + HALMAC_FWHDR_OFFSET_EMEM_ADDR_88XX)))) & + ~(BIT(31)); + if (halmac_dlfw_to_mem_88xx(halmac_adapter, file_ptr, dest, + eram_pkt_size) != + HALMAC_RET_SUCCESS) + goto DLFW_END; + } + + halmac_init_offload_feature_state_machine_88xx(halmac_adapter); +DLFW_END: + + halmac_restore_mac_register_88xx(halmac_adapter, restore_info, + DLFW_RESTORE_REG_NUM_88XX); + + if (halmac_dlfw_end_flow_88xx(halmac_adapter) != HALMAC_RET_SUCCESS) + goto DLFW_FAIL; + + halmac_adapter->halmac_state.dlfw_state = HALMAC_DLFW_DONE; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; + +DLFW_FAIL: + + /* Disable FWDL_EN */ + HALMAC_REG_WRITE_8( + halmac_adapter, REG_MCUFW_CTRL, + (u8)(HALMAC_REG_READ_8(halmac_adapter, REG_MCUFW_CTRL) & + ~(BIT(0)))); + + return HALMAC_RET_DLFW_FAIL; +} + +/** + * halmac_free_download_firmware_88xx() - download specific memory firmware + * @halmac_adapter + * @dlfw_mem : memory selection + * @hamacl_fw : firmware bin + * @halmac_fw_size : firmware size + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + */ +enum halmac_ret_status +halmac_free_download_firmware_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_dlfw_mem dlfw_mem, u8 *hamacl_fw, + u32 halmac_fw_size) +{ + u8 tx_pause_backup; + u8 *file_ptr; + u32 dest; + u16 bcn_head_backup; + u32 iram_pkt_size, dmem_pkt_size, eram_pkt_size = 0; + void *driver_adapter = NULL; + enum halmac_ret_status status = HALMAC_RET_DLFW_FAIL; + struct halmac_api *halmac_api; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + if (halmac_fw_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_NO_DLFW; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "[TRACE]%s ==========>\n", __func__); + + if (halmac_fw_size > HALMAC_FW_SIZE_MAX_88XX || + halmac_fw_size < HALMAC_FWHDR_SIZE_88XX) { + pr_err("[ERR]FW size error!\n"); + return HALMAC_RET_FW_SIZE_ERR; + } + + dmem_pkt_size = + le32_to_cpu(*(__le32 *)(hamacl_fw + + HALMAC_FWHDR_OFFSET_DMEM_SIZE_88XX)); + iram_pkt_size = + le32_to_cpu(*(__le32 *)(hamacl_fw + + HALMAC_FWHDR_OFFSET_IRAM_SIZE_88XX)); + if (((*(hamacl_fw + HALMAC_FWHDR_OFFSET_MEM_USAGE_88XX)) & BIT(4)) != 0) + eram_pkt_size = + le32_to_cpu(*(__le32 *)(hamacl_fw + + HALMAC_FWHDR_OFFSET_ERAM_SIZE_88XX)); + + dmem_pkt_size += HALMAC_FW_CHKSUM_DUMMY_SIZE_88XX; + iram_pkt_size += HALMAC_FW_CHKSUM_DUMMY_SIZE_88XX; + if (eram_pkt_size != 0) + eram_pkt_size += HALMAC_FW_CHKSUM_DUMMY_SIZE_88XX; + + if (halmac_fw_size != (HALMAC_FWHDR_SIZE_88XX + dmem_pkt_size + + iram_pkt_size + eram_pkt_size)) { + pr_err("[ERR]FW size mismatch the real fw size!\n"); + return HALMAC_RET_DLFW_FAIL; + } + + tx_pause_backup = HALMAC_REG_READ_8(halmac_adapter, REG_TXPAUSE); + HALMAC_REG_WRITE_8(halmac_adapter, REG_TXPAUSE, + tx_pause_backup | BIT(7)); + + bcn_head_backup = + HALMAC_REG_READ_16(halmac_adapter, REG_FIFOPAGE_CTRL_2) | + BIT(15); + HALMAC_REG_WRITE_16(halmac_adapter, REG_FIFOPAGE_CTRL_2, 0x8000); + + if (eram_pkt_size != 0) { + file_ptr = hamacl_fw + HALMAC_FWHDR_SIZE_88XX + dmem_pkt_size + + iram_pkt_size; + dest = le32_to_cpu(*((__le32 *)(hamacl_fw + + HALMAC_FWHDR_OFFSET_EMEM_ADDR_88XX))) & + ~(BIT(31)); + status = halmac_dlfw_to_mem_88xx(halmac_adapter, file_ptr, dest, + eram_pkt_size); + if (status != HALMAC_RET_SUCCESS) + goto DL_FREE_FW_END; + } + + status = halmac_free_dl_fw_end_flow_88xx(halmac_adapter); + +DL_FREE_FW_END: + HALMAC_REG_WRITE_8(halmac_adapter, REG_TXPAUSE, tx_pause_backup); + HALMAC_REG_WRITE_16(halmac_adapter, REG_FIFOPAGE_CTRL_2, + bcn_head_backup); + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "[TRACE]%s <==========\n", __func__); + + return status; +} + +/** + * halmac_get_fw_version_88xx() - get FW version + * @halmac_adapter : the adapter of halmac + * @fw_version : fw version info + * Author : Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_get_fw_version_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_fw_version *fw_version) +{ + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_adapter->halmac_state.dlfw_state == 0) + return HALMAC_RET_DLFW_FAIL; + + fw_version->version = halmac_adapter->fw_version.version; + fw_version->sub_version = halmac_adapter->fw_version.sub_version; + fw_version->sub_index = halmac_adapter->fw_version.sub_index; + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_cfg_mac_addr_88xx() - config mac address + * @halmac_adapter : the adapter of halmac + * @halmac_port :0 for port0, 1 for port1, 2 for port2, 3 for port3, 4 for port4 + * @hal_address : mac address + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_cfg_mac_addr_88xx(struct halmac_adapter *halmac_adapter, u8 halmac_port, + union halmac_wlan_addr *hal_address) +{ + u16 mac_address_H; + u32 mac_address_L; + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "[TRACE]%s ==========>\n", __func__); + + if (halmac_port >= HALMAC_PORTIDMAX) { + pr_err("[ERR]port index > 5\n"); + return HALMAC_RET_PORT_NOT_SUPPORT; + } + + mac_address_L = le32_to_cpu(hal_address->address_l_h.le_address_low); + mac_address_H = le16_to_cpu(hal_address->address_l_h.le_address_high); + + halmac_adapter->hal_mac_addr[halmac_port].address_l_h.address_low = + mac_address_L; + halmac_adapter->hal_mac_addr[halmac_port].address_l_h.address_high = + mac_address_H; + + switch (halmac_port) { + case HALMAC_PORTID0: + HALMAC_REG_WRITE_32(halmac_adapter, REG_MACID, mac_address_L); + HALMAC_REG_WRITE_16(halmac_adapter, REG_MACID + 4, + mac_address_H); + break; + + case HALMAC_PORTID1: + HALMAC_REG_WRITE_32(halmac_adapter, REG_MACID1, mac_address_L); + HALMAC_REG_WRITE_16(halmac_adapter, REG_MACID1 + 4, + mac_address_H); + break; + + case HALMAC_PORTID2: + HALMAC_REG_WRITE_32(halmac_adapter, REG_MACID2, mac_address_L); + HALMAC_REG_WRITE_16(halmac_adapter, REG_MACID2 + 4, + mac_address_H); + break; + + case HALMAC_PORTID3: + HALMAC_REG_WRITE_32(halmac_adapter, REG_MACID3, mac_address_L); + HALMAC_REG_WRITE_16(halmac_adapter, REG_MACID3 + 4, + mac_address_H); + break; + + case HALMAC_PORTID4: + HALMAC_REG_WRITE_32(halmac_adapter, REG_MACID4, mac_address_L); + HALMAC_REG_WRITE_16(halmac_adapter, REG_MACID4 + 4, + mac_address_H); + break; + + default: + + break; + } + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "[TRACE]%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_cfg_bssid_88xx() - config BSSID + * @halmac_adapter : the adapter of halmac + * @halmac_port :0 for port0, 1 for port1, 2 for port2, 3 for port3, 4 for port4 + * @hal_address : bssid + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_cfg_bssid_88xx(struct halmac_adapter *halmac_adapter, u8 halmac_port, + union halmac_wlan_addr *hal_address) +{ + u16 bssid_address_H; + u32 bssid_address_L; + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "[TRACE]%s ==========>\n", __func__); + + if (halmac_port >= HALMAC_PORTIDMAX) { + pr_err("[ERR]port index > 5\n"); + return HALMAC_RET_PORT_NOT_SUPPORT; + } + + bssid_address_L = le32_to_cpu(hal_address->address_l_h.le_address_low); + bssid_address_H = le16_to_cpu(hal_address->address_l_h.le_address_high); + + halmac_adapter->hal_bss_addr[halmac_port].address_l_h.address_low = + bssid_address_L; + halmac_adapter->hal_bss_addr[halmac_port].address_l_h.address_high = + bssid_address_H; + + switch (halmac_port) { + case HALMAC_PORTID0: + HALMAC_REG_WRITE_32(halmac_adapter, REG_BSSID, bssid_address_L); + HALMAC_REG_WRITE_16(halmac_adapter, REG_BSSID + 4, + bssid_address_H); + break; + + case HALMAC_PORTID1: + HALMAC_REG_WRITE_32(halmac_adapter, REG_BSSID1, + bssid_address_L); + HALMAC_REG_WRITE_16(halmac_adapter, REG_BSSID1 + 4, + bssid_address_H); + break; + + case HALMAC_PORTID2: + HALMAC_REG_WRITE_32(halmac_adapter, REG_BSSID2, + bssid_address_L); + HALMAC_REG_WRITE_16(halmac_adapter, REG_BSSID2 + 4, + bssid_address_H); + break; + + case HALMAC_PORTID3: + HALMAC_REG_WRITE_32(halmac_adapter, REG_BSSID3, + bssid_address_L); + HALMAC_REG_WRITE_16(halmac_adapter, REG_BSSID3 + 4, + bssid_address_H); + break; + + case HALMAC_PORTID4: + HALMAC_REG_WRITE_32(halmac_adapter, REG_BSSID4, + bssid_address_L); + HALMAC_REG_WRITE_16(halmac_adapter, REG_BSSID4 + 4, + bssid_address_H); + break; + + default: + + break; + } + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "[TRACE]%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_cfg_multicast_addr_88xx() - config multicast address + * @halmac_adapter : the adapter of halmac + * @hal_address : multicast address + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_cfg_multicast_addr_88xx(struct halmac_adapter *halmac_adapter, + union halmac_wlan_addr *hal_address) +{ + u16 address_H; + u32 address_L; + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, + HALMAC_API_CFG_MULTICAST_ADDR); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s ==========>\n", __func__); + + address_L = le32_to_cpu(hal_address->address_l_h.le_address_low); + address_H = le16_to_cpu(hal_address->address_l_h.le_address_high); + + HALMAC_REG_WRITE_32(halmac_adapter, REG_MAR, address_L); + HALMAC_REG_WRITE_16(halmac_adapter, REG_MAR + 4, address_H); + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_pre_init_system_cfg_88xx() - pre-init system config + * @halmac_adapter : the adapter of halmac + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_pre_init_system_cfg_88xx(struct halmac_adapter *halmac_adapter) +{ + u32 value32, counter; + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + bool enable_bb; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, + HALMAC_API_PRE_INIT_SYSTEM_CFG); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "halmac_pre_init_system_cfg ==========>\n"); + + if (halmac_adapter->halmac_interface == HALMAC_INTERFACE_SDIO) { + HALMAC_REG_WRITE_8( + halmac_adapter, REG_SDIO_HSUS_CTRL, + HALMAC_REG_READ_8(halmac_adapter, REG_SDIO_HSUS_CTRL) & + ~(BIT(0))); + counter = 10000; + while (!(HALMAC_REG_READ_8(halmac_adapter, REG_SDIO_HSUS_CTRL) & + 0x02)) { + counter--; + if (counter == 0) + return HALMAC_RET_SDIO_LEAVE_SUSPEND_FAIL; + } + } else if (halmac_adapter->halmac_interface == HALMAC_INTERFACE_USB) { + if (HALMAC_REG_READ_8(halmac_adapter, REG_SYS_CFG2 + 3) == + 0x20) /* usb3.0 */ + HALMAC_REG_WRITE_8( + halmac_adapter, 0xFE5B, + HALMAC_REG_READ_8(halmac_adapter, 0xFE5B) | + BIT(4)); + } + + /* Config PIN Mux */ + value32 = HALMAC_REG_READ_32(halmac_adapter, REG_PAD_CTRL1); + value32 = value32 & (~(BIT(28) | BIT(29))); + value32 = value32 | BIT(28) | BIT(29); + HALMAC_REG_WRITE_32(halmac_adapter, REG_PAD_CTRL1, value32); + + value32 = HALMAC_REG_READ_32(halmac_adapter, REG_LED_CFG); + value32 = value32 & (~(BIT(25) | BIT(26))); + HALMAC_REG_WRITE_32(halmac_adapter, REG_LED_CFG, value32); + + value32 = HALMAC_REG_READ_32(halmac_adapter, REG_GPIO_MUXCFG); + value32 = value32 & (~(BIT(2))); + value32 = value32 | BIT(2); + HALMAC_REG_WRITE_32(halmac_adapter, REG_GPIO_MUXCFG, value32); + + enable_bb = false; + halmac_set_hw_value_88xx(halmac_adapter, HALMAC_HW_EN_BB_RF, + &enable_bb); + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "halmac_pre_init_system_cfg <==========\n"); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_init_system_cfg_88xx() - init system config + * @halmac_adapter : the adapter of halmac + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_init_system_cfg_88xx(struct halmac_adapter *halmac_adapter) +{ + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_INIT_SYSTEM_CFG); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "halmac_init_system_cfg ==========>\n"); + + HALMAC_REG_WRITE_8(halmac_adapter, REG_SYS_FUNC_EN + 1, + HALMAC_FUNCTION_ENABLE_88XX); + HALMAC_REG_WRITE_32( + halmac_adapter, REG_SYS_SDIO_CTRL, + (u32)(HALMAC_REG_READ_32(halmac_adapter, REG_SYS_SDIO_CTRL) | + BIT_LTE_MUX_CTRL_PATH)); + HALMAC_REG_WRITE_32( + halmac_adapter, REG_CPU_DMEM_CON, + (u32)(HALMAC_REG_READ_32(halmac_adapter, REG_CPU_DMEM_CON) | + BIT_WL_PLATFORM_RST)); + + /* halmac_api->halmac_init_h2c(halmac_adapter); */ + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "halmac_init_system_cfg <==========\n"); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_init_edca_cfg_88xx() - init EDCA config + * @halmac_adapter : the adapter of halmac + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_init_edca_cfg_88xx(struct halmac_adapter *halmac_adapter) +{ + u8 value8; + u32 value32; + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_INIT_EDCA_CFG); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s ==========>\n", __func__); + + /* Clear TX pause */ + HALMAC_REG_WRITE_16(halmac_adapter, REG_TXPAUSE, 0x0000); + + HALMAC_REG_WRITE_8(halmac_adapter, REG_SLOT, HALMAC_SLOT_TIME_88XX); + HALMAC_REG_WRITE_8(halmac_adapter, REG_PIFS, HALMAC_PIFS_TIME_88XX); + value32 = HALMAC_SIFS_CCK_CTX_88XX | + (HALMAC_SIFS_OFDM_CTX_88XX << BIT_SHIFT_SIFS_OFDM_CTX) | + (HALMAC_SIFS_CCK_TRX_88XX << BIT_SHIFT_SIFS_CCK_TRX) | + (HALMAC_SIFS_OFDM_TRX_88XX << BIT_SHIFT_SIFS_OFDM_TRX); + HALMAC_REG_WRITE_32(halmac_adapter, REG_SIFS, value32); + + HALMAC_REG_WRITE_32( + halmac_adapter, REG_EDCA_VO_PARAM, + HALMAC_REG_READ_32(halmac_adapter, REG_EDCA_VO_PARAM) & 0xFFFF); + HALMAC_REG_WRITE_16(halmac_adapter, REG_EDCA_VO_PARAM + 2, + HALMAC_VO_TXOP_LIMIT_88XX); + HALMAC_REG_WRITE_16(halmac_adapter, REG_EDCA_VI_PARAM + 2, + HALMAC_VI_TXOP_LIMIT_88XX); + + HALMAC_REG_WRITE_32(halmac_adapter, REG_RD_NAV_NXT, + HALMAC_RDG_NAV_88XX | (HALMAC_TXOP_NAV_88XX << 16)); + HALMAC_REG_WRITE_16(halmac_adapter, REG_RXTSF_OFFSET_CCK, + HALMAC_CCK_RX_TSF_88XX | + (HALMAC_OFDM_RX_TSF_88XX) << 8); + + value8 = HALMAC_REG_READ_8(halmac_adapter, REG_RD_CTRL + 1); + value8 |= + (BIT_VOQ_RD_INIT_EN | BIT_VIQ_RD_INIT_EN | BIT_BEQ_RD_INIT_EN); + HALMAC_REG_WRITE_8(halmac_adapter, REG_RD_CTRL + 1, value8); + + /* Set beacon cotnrol - enable TSF and other related functions */ + HALMAC_REG_WRITE_8( + halmac_adapter, REG_BCN_CTRL, + (u8)(HALMAC_REG_READ_8(halmac_adapter, REG_BCN_CTRL) | + BIT_EN_BCN_FUNCTION)); + + /* Set send beacon related registers */ + HALMAC_REG_WRITE_32(halmac_adapter, REG_TBTT_PROHIBIT, + HALMAC_TBTT_PROHIBIT_88XX | + (HALMAC_TBTT_HOLD_TIME_88XX + << BIT_SHIFT_TBTT_HOLD_TIME_AP)); + HALMAC_REG_WRITE_8(halmac_adapter, REG_DRVERLYINT, + HALMAC_DRIVER_EARLY_INT_88XX); + HALMAC_REG_WRITE_8(halmac_adapter, REG_BCNDMATIM, + HALMAC_BEACON_DMA_TIM_88XX); + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_init_wmac_cfg_88xx() - init wmac config + * @halmac_adapter : the adapter of halmac + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_init_wmac_cfg_88xx(struct halmac_adapter *halmac_adapter) +{ + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_INIT_WMAC_CFG); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s ==========>\n", __func__); + + HALMAC_REG_WRITE_32(halmac_adapter, REG_RXFLTMAP0, + HALMAC_RX_FILTER0_88XX); + HALMAC_REG_WRITE_16(halmac_adapter, REG_RXFLTMAP, + HALMAC_RX_FILTER_88XX); + + HALMAC_REG_WRITE_32(halmac_adapter, REG_RCR, HALMAC_RCR_CONFIG_88XX); + + HALMAC_REG_WRITE_8( + halmac_adapter, REG_TCR + 1, + (u8)(HALMAC_REG_READ_8(halmac_adapter, REG_TCR + 1) | 0x30)); + HALMAC_REG_WRITE_8(halmac_adapter, REG_TCR + 2, 0x30); + HALMAC_REG_WRITE_8(halmac_adapter, REG_TCR + 1, 0x00); + + HALMAC_REG_WRITE_32(halmac_adapter, REG_WMAC_OPTION_FUNCTION + 8, + 0x30810041); + HALMAC_REG_WRITE_32(halmac_adapter, REG_WMAC_OPTION_FUNCTION + 4, + 0x50802080); + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_init_mac_cfg_88xx() - config page1~page7 register + * @halmac_adapter : the adapter of halmac + * @mode : trx mode + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_init_mac_cfg_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_trx_mode mode) +{ + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_INIT_MAC_CFG); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s ==========>mode = %d\n", __func__, + mode); + + status = halmac_api->halmac_init_trx_cfg(halmac_adapter, mode); + if (status != HALMAC_RET_SUCCESS) { + pr_err("halmac_init_trx_cfg error = %x\n", status); + return status; + } + status = halmac_api->halmac_init_protocol_cfg(halmac_adapter); + if (status != HALMAC_RET_SUCCESS) { + pr_err("halmac_init_protocol_cfg_88xx error = %x\n", status); + return status; + } + + status = halmac_init_edca_cfg_88xx(halmac_adapter); + if (status != HALMAC_RET_SUCCESS) { + pr_err("halmac_init_edca_cfg_88xx error = %x\n", status); + return status; + } + + status = halmac_init_wmac_cfg_88xx(halmac_adapter); + if (status != HALMAC_RET_SUCCESS) { + pr_err("halmac_init_wmac_cfg_88xx error = %x\n", status); + return status; + } + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s <==========\n", __func__); + + return status; +} + +/** + * halmac_cfg_operation_mode_88xx() - config operation mode + * @halmac_adapter : the adapter of halmac + * @wireless_mode : 802.11 standard(b/g/n/ac) + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_cfg_operation_mode_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_wireless_mode wireless_mode) +{ + void *driver_adapter = NULL; + enum halmac_wireless_mode wireless_mode_local = + HALMAC_WIRELESS_MODE_UNDEFINE; + + wireless_mode_local = wireless_mode; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, + HALMAC_API_CFG_OPERATION_MODE); + + driver_adapter = halmac_adapter->driver_adapter; + + HALMAC_RT_TRACE( + driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s ==========>wireless_mode = %d\n", __func__, + wireless_mode); + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_cfg_ch_bw_88xx() - config channel & bandwidth + * @halmac_adapter : the adapter of halmac + * @channel : WLAN channel, support 2.4G & 5G + * @pri_ch_idx : primary channel index, idx1, idx2, idx3, idx4 + * @bw : band width, 20, 40, 80, 160, 5 ,10 + * Author : KaiYuan Chang + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_cfg_ch_bw_88xx(struct halmac_adapter *halmac_adapter, u8 channel, + enum halmac_pri_ch_idx pri_ch_idx, enum halmac_bw bw) +{ + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_CFG_CH_BW); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s ==========>ch = %d, idx=%d, bw=%d\n", __func__, + channel, pri_ch_idx, bw); + + halmac_cfg_pri_ch_idx_88xx(halmac_adapter, pri_ch_idx); + + halmac_cfg_bw_88xx(halmac_adapter, bw); + + halmac_cfg_ch_88xx(halmac_adapter, channel); + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status halmac_cfg_ch_88xx(struct halmac_adapter *halmac_adapter, + u8 channel) +{ + u8 value8; + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_CFG_CH_BW); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s ==========>ch = %d\n", __func__, channel); + + value8 = HALMAC_REG_READ_8(halmac_adapter, REG_CCK_CHECK); + value8 = value8 & (~(BIT(7))); + + if (channel > 35) + value8 = value8 | BIT(7); + + HALMAC_REG_WRITE_8(halmac_adapter, REG_CCK_CHECK, value8); + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status +halmac_cfg_pri_ch_idx_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_pri_ch_idx pri_ch_idx) +{ + u8 txsc_40 = 0, txsc_20 = 0; + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_CFG_CH_BW); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s ==========> idx=%d\n", __func__, + pri_ch_idx); + + txsc_20 = pri_ch_idx; + if (txsc_20 == HALMAC_CH_IDX_1 || txsc_20 == HALMAC_CH_IDX_3) + txsc_40 = 9; + else + txsc_40 = 10; + + HALMAC_REG_WRITE_8(halmac_adapter, REG_DATA_SC, + BIT_TXSC_20M(txsc_20) | BIT_TXSC_40M(txsc_40)); + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_cfg_bw_88xx() - config bandwidth + * @halmac_adapter : the adapter of halmac + * @bw : band width, 20, 40, 80, 160, 5 ,10 + * Author : KaiYuan Chang + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status halmac_cfg_bw_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_bw bw) +{ + u32 value32; + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_CFG_BW); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s ==========>bw=%d\n", __func__, bw); + + /* RF mode */ + value32 = HALMAC_REG_READ_32(halmac_adapter, REG_WMAC_TRXPTCL_CTL); + value32 = value32 & (~(BIT(7) | BIT(8))); + + switch (bw) { + case HALMAC_BW_80: + value32 = value32 | BIT(7); + break; + case HALMAC_BW_40: + value32 = value32 | BIT(8); + break; + case HALMAC_BW_20: + case HALMAC_BW_10: + case HALMAC_BW_5: + break; + default: + pr_err("%s switch case not support\n", __func__); + break; + } + HALMAC_REG_WRITE_32(halmac_adapter, REG_WMAC_TRXPTCL_CTL, value32); + + /* MAC CLK */ + value32 = HALMAC_REG_READ_32(halmac_adapter, REG_AFE_CTRL1); + value32 = (value32 & (~(BIT(20) | BIT(21)))) | + (HALMAC_MAC_CLOCK_HW_DEF_80M << BIT_SHIFT_MAC_CLK_SEL); + HALMAC_REG_WRITE_32(halmac_adapter, REG_AFE_CTRL1, value32); + + HALMAC_REG_WRITE_8(halmac_adapter, REG_USTIME_TSF, + HALMAC_MAC_CLOCK_88XX); + HALMAC_REG_WRITE_8(halmac_adapter, REG_USTIME_EDCA, + HALMAC_MAC_CLOCK_88XX); + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_dump_efuse_map_88xx() - dump "physical" efuse map + * @halmac_adapter : the adapter of halmac + * @cfg : dump efuse method + * Author : Ivan Lin/KaiYuan Chang + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_dump_efuse_map_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_efuse_read_cfg cfg) +{ + void *driver_adapter = NULL; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + enum halmac_cmd_process_status *process_status = + &halmac_adapter->halmac_state.efuse_state_set.process_status; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_DUMP_EFUSE_MAP); + + driver_adapter = halmac_adapter->driver_adapter; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s ==========>cfg=%d\n", __func__, cfg); + + if (*process_status == HALMAC_CMD_PROCESS_SENDING) { + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "Wait event(dump efuse)...\n"); + return HALMAC_RET_BUSY_STATE; + } + + if (halmac_query_efuse_curr_state_88xx(halmac_adapter) != + HALMAC_EFUSE_CMD_CONSTRUCT_IDLE) { + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "Not idle state(dump efuse)...\n"); + return HALMAC_RET_ERROR_STATE; + } + + if (halmac_adapter->halmac_state.mac_power == HALMAC_MAC_POWER_OFF) + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_EFUSE, DBG_WARNING, + "[WARN]Dump efuse in suspend mode\n"); + + *process_status = HALMAC_CMD_PROCESS_IDLE; + halmac_adapter->event_trigger.physical_efuse_map = 1; + + status = halmac_func_switch_efuse_bank_88xx(halmac_adapter, + HALMAC_EFUSE_BANK_WIFI); + if (status != HALMAC_RET_SUCCESS) { + pr_err("halmac_func_switch_efuse_bank error = %x\n", status); + return status; + } + + status = halmac_dump_efuse_88xx(halmac_adapter, cfg); + + if (status != HALMAC_RET_SUCCESS) { + pr_err("halmac_read_efuse error = %x\n", status); + return status; + } + + if (halmac_adapter->hal_efuse_map_valid) { + *process_status = HALMAC_CMD_PROCESS_DONE; + + PLATFORM_EVENT_INDICATION( + driver_adapter, HALMAC_FEATURE_DUMP_PHYSICAL_EFUSE, + *process_status, halmac_adapter->hal_efuse_map, + halmac_adapter->hw_config_info.efuse_size); + halmac_adapter->event_trigger.physical_efuse_map = 0; + } + + if (halmac_transition_efuse_state_88xx( + halmac_adapter, HALMAC_EFUSE_CMD_CONSTRUCT_IDLE) != + HALMAC_RET_SUCCESS) + return HALMAC_RET_ERROR_STATE; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_EFUSE, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_dump_efuse_map_bt_88xx() - dump "BT physical" efuse map + * @halmac_adapter : the adapter of halmac + * @halmac_efuse_bank : bt efuse bank + * @bt_efuse_map_size : bt efuse map size. get from halmac_get_efuse_size API + * @bt_efuse_map : bt efuse map + * Author : Soar / Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_dump_efuse_map_bt_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_efuse_bank halmac_efuse_bank, + u32 bt_efuse_map_size, u8 *bt_efuse_map) +{ + void *driver_adapter = NULL; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + enum halmac_cmd_process_status *process_status = + &halmac_adapter->halmac_state.efuse_state_set.process_status; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_DUMP_EFUSE_MAP_BT); + + driver_adapter = halmac_adapter->driver_adapter; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s ==========>\n", __func__); + + if (halmac_adapter->hw_config_info.bt_efuse_size != bt_efuse_map_size) + return HALMAC_RET_EFUSE_SIZE_INCORRECT; + + if ((halmac_efuse_bank >= HALMAC_EFUSE_BANK_MAX) || + halmac_efuse_bank == HALMAC_EFUSE_BANK_WIFI) { + pr_err("Undefined BT bank\n"); + return HALMAC_RET_EFUSE_BANK_INCORRECT; + } + + if (*process_status == HALMAC_CMD_PROCESS_SENDING) { + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "Wait event(dump efuse)...\n"); + return HALMAC_RET_BUSY_STATE; + } + + if (halmac_query_efuse_curr_state_88xx(halmac_adapter) != + HALMAC_EFUSE_CMD_CONSTRUCT_IDLE) { + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "Not idle state(dump efuse)...\n"); + return HALMAC_RET_ERROR_STATE; + } + + status = halmac_func_switch_efuse_bank_88xx(halmac_adapter, + halmac_efuse_bank); + if (status != HALMAC_RET_SUCCESS) { + pr_err("halmac_func_switch_efuse_bank error = %x\n", status); + return status; + } + + status = halmac_read_hw_efuse_88xx(halmac_adapter, 0, bt_efuse_map_size, + bt_efuse_map); + + if (status != HALMAC_RET_SUCCESS) { + pr_err("halmac_read_hw_efuse_88xx error = %x\n", status); + return status; + } + + if (halmac_transition_efuse_state_88xx( + halmac_adapter, HALMAC_EFUSE_CMD_CONSTRUCT_IDLE) != + HALMAC_RET_SUCCESS) + return HALMAC_RET_ERROR_STATE; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_EFUSE, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_write_efuse_bt_88xx() - write "BT physical" efuse offset + * @halmac_adapter : the adapter of halmac + * @halmac_offset : offset + * @halmac_value : Write value + * @bt_efuse_map : bt efuse map + * Author : Soar + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_write_efuse_bt_88xx(struct halmac_adapter *halmac_adapter, + u32 halmac_offset, u8 halmac_value, + enum halmac_efuse_bank halmac_efuse_bank) +{ + void *driver_adapter = NULL; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + + enum halmac_cmd_process_status *process_status = + &halmac_adapter->halmac_state.efuse_state_set.process_status; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_WRITE_EFUSE_BT); + + driver_adapter = halmac_adapter->driver_adapter; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_EFUSE, DBG_DMESG, + "%s ==========>\n", __func__); + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_EFUSE, DBG_DMESG, + "offset : %X value : %X Bank : %X\n", halmac_offset, + halmac_value, halmac_efuse_bank); + + if (*process_status == HALMAC_CMD_PROCESS_SENDING) { + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "Wait/Rcvd event(dump efuse)...\n"); + return HALMAC_RET_BUSY_STATE; + } + + if (halmac_query_efuse_curr_state_88xx(halmac_adapter) != + HALMAC_EFUSE_CMD_CONSTRUCT_IDLE) { + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "Not idle state(dump efuse)...\n"); + return HALMAC_RET_ERROR_STATE; + } + + if (halmac_offset >= halmac_adapter->hw_config_info.efuse_size) { + pr_err("Offset is too large\n"); + return HALMAC_RET_EFUSE_SIZE_INCORRECT; + } + + if (halmac_efuse_bank > HALMAC_EFUSE_BANK_MAX || + halmac_efuse_bank == HALMAC_EFUSE_BANK_WIFI) { + pr_err("Undefined BT bank\n"); + return HALMAC_RET_EFUSE_BANK_INCORRECT; + } + + status = halmac_func_switch_efuse_bank_88xx(halmac_adapter, + halmac_efuse_bank); + if (status != HALMAC_RET_SUCCESS) { + pr_err("halmac_func_switch_efuse_bank error = %x\n", status); + return status; + } + + status = halmac_func_write_efuse_88xx(halmac_adapter, halmac_offset, + halmac_value); + if (status != HALMAC_RET_SUCCESS) { + pr_err("halmac_func_write_efuse error = %x\n", status); + return status; + } + + if (halmac_transition_efuse_state_88xx( + halmac_adapter, HALMAC_EFUSE_CMD_CONSTRUCT_IDLE) != + HALMAC_RET_SUCCESS) + return HALMAC_RET_ERROR_STATE; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_EFUSE, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_get_efuse_available_size_88xx() - get efuse available size + * @halmac_adapter : the adapter of halmac + * @halmac_size : physical efuse available size + * Author : Soar + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_get_efuse_available_size_88xx(struct halmac_adapter *halmac_adapter, + u32 *halmac_size) +{ + enum halmac_ret_status status; + void *driver_adapter = NULL; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + driver_adapter = halmac_adapter->driver_adapter; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_EFUSE, DBG_DMESG, + "%s ==========>\n", __func__); + + status = halmac_dump_logical_efuse_map_88xx(halmac_adapter, + HALMAC_EFUSE_R_DRV); + + if (status != HALMAC_RET_SUCCESS) + return status; + + *halmac_size = halmac_adapter->hw_config_info.efuse_size - + HALMAC_PROTECTED_EFUSE_SIZE_88XX - + halmac_adapter->efuse_end; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_EFUSE, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_get_efuse_size_88xx() - get "physical" efuse size + * @halmac_adapter : the adapter of halmac + * @halmac_size : physical efuse size + * Author : Ivan Lin/KaiYuan Chang + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_get_efuse_size_88xx(struct halmac_adapter *halmac_adapter, + u32 *halmac_size) +{ + void *driver_adapter = NULL; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_GET_EFUSE_SIZE); + + driver_adapter = halmac_adapter->driver_adapter; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_EFUSE, DBG_DMESG, + "%s ==========>\n", __func__); + + *halmac_size = halmac_adapter->hw_config_info.efuse_size; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_EFUSE, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_get_logical_efuse_size_88xx() - get "logical" efuse size + * @halmac_adapter : the adapter of halmac + * @halmac_size : logical efuse size + * Author : Ivan Lin/KaiYuan Chang + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_get_logical_efuse_size_88xx(struct halmac_adapter *halmac_adapter, + u32 *halmac_size) +{ + void *driver_adapter = NULL; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, + HALMAC_API_GET_LOGICAL_EFUSE_SIZE); + + driver_adapter = halmac_adapter->driver_adapter; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_EFUSE, DBG_DMESG, + "%s ==========>\n", __func__); + + *halmac_size = halmac_adapter->hw_config_info.eeprom_size; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_EFUSE, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_dump_logical_efuse_map_88xx() - dump "logical" efuse map + * @halmac_adapter : the adapter of halmac + * @cfg : dump efuse method + * Author : Soar + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_dump_logical_efuse_map_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_efuse_read_cfg cfg) +{ + u8 *eeprom_map = NULL; + u32 eeprom_size = halmac_adapter->hw_config_info.eeprom_size; + void *driver_adapter = NULL; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + enum halmac_cmd_process_status *process_status = + &halmac_adapter->halmac_state.efuse_state_set.process_status; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, + HALMAC_API_DUMP_LOGICAL_EFUSE_MAP); + + driver_adapter = halmac_adapter->driver_adapter; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_EFUSE, DBG_DMESG, + "%s ==========>cfg = %d\n", __func__, cfg); + + if (*process_status == HALMAC_CMD_PROCESS_SENDING) { + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "Wait/Rcvd event(dump efuse)...\n"); + return HALMAC_RET_BUSY_STATE; + } + + if (halmac_query_efuse_curr_state_88xx(halmac_adapter) != + HALMAC_EFUSE_CMD_CONSTRUCT_IDLE) { + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "Not idle state(dump efuse)...\n"); + return HALMAC_RET_ERROR_STATE; + } + + if (halmac_adapter->halmac_state.mac_power == HALMAC_MAC_POWER_OFF) + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_EFUSE, DBG_WARNING, + "[WARN]Dump logical efuse in suspend mode\n"); + + *process_status = HALMAC_CMD_PROCESS_IDLE; + halmac_adapter->event_trigger.logical_efuse_map = 1; + + status = halmac_func_switch_efuse_bank_88xx(halmac_adapter, + HALMAC_EFUSE_BANK_WIFI); + if (status != HALMAC_RET_SUCCESS) { + pr_err("halmac_func_switch_efuse_bank error = %x\n", status); + return status; + } + + status = halmac_dump_efuse_88xx(halmac_adapter, cfg); + + if (status != HALMAC_RET_SUCCESS) { + pr_err("halmac_eeprom_parser_88xx error = %x\n", status); + return status; + } + + if (halmac_adapter->hal_efuse_map_valid) { + *process_status = HALMAC_CMD_PROCESS_DONE; + + eeprom_map = kzalloc(eeprom_size, GFP_KERNEL); + if (!eeprom_map) { + /* out of memory */ + return HALMAC_RET_MALLOC_FAIL; + } + memset(eeprom_map, 0xFF, eeprom_size); + + if (halmac_eeprom_parser_88xx(halmac_adapter, + halmac_adapter->hal_efuse_map, + eeprom_map) != HALMAC_RET_SUCCESS) { + kfree(eeprom_map); + return HALMAC_RET_EEPROM_PARSING_FAIL; + } + + PLATFORM_EVENT_INDICATION( + driver_adapter, HALMAC_FEATURE_DUMP_LOGICAL_EFUSE, + *process_status, eeprom_map, eeprom_size); + halmac_adapter->event_trigger.logical_efuse_map = 0; + + kfree(eeprom_map); + } + + if (halmac_transition_efuse_state_88xx( + halmac_adapter, HALMAC_EFUSE_CMD_CONSTRUCT_IDLE) != + HALMAC_RET_SUCCESS) + return HALMAC_RET_ERROR_STATE; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_EFUSE, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_read_logical_efuse_88xx() - read logical efuse map 1 byte + * @halmac_adapter : the adapter of halmac + * @halmac_offset : offset + * @value : 1 byte efuse value + * Author : Soar + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_read_logical_efuse_88xx(struct halmac_adapter *halmac_adapter, + u32 halmac_offset, u8 *value) +{ + u8 *eeprom_map = NULL; + u32 eeprom_size = halmac_adapter->hw_config_info.eeprom_size; + void *driver_adapter = NULL; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + + enum halmac_cmd_process_status *process_status = + &halmac_adapter->halmac_state.efuse_state_set.process_status; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, + HALMAC_API_READ_LOGICAL_EFUSE); + + driver_adapter = halmac_adapter->driver_adapter; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_EFUSE, DBG_DMESG, + "%s ==========>\n", __func__); + + if (halmac_offset >= eeprom_size) { + pr_err("Offset is too large\n"); + return HALMAC_RET_EFUSE_SIZE_INCORRECT; + } + + if (*process_status == HALMAC_CMD_PROCESS_SENDING) { + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "Wait/Rcvd event(dump efuse)...\n"); + return HALMAC_RET_BUSY_STATE; + } + if (halmac_query_efuse_curr_state_88xx(halmac_adapter) != + HALMAC_EFUSE_CMD_CONSTRUCT_IDLE) { + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "Not idle state(dump efuse)...\n"); + return HALMAC_RET_ERROR_STATE; + } + + status = halmac_func_switch_efuse_bank_88xx(halmac_adapter, + HALMAC_EFUSE_BANK_WIFI); + if (status != HALMAC_RET_SUCCESS) { + pr_err("halmac_func_switch_efuse_bank error = %x\n", status); + return status; + } + + eeprom_map = kzalloc(eeprom_size, GFP_KERNEL); + if (!eeprom_map) { + /* out of memory */ + return HALMAC_RET_MALLOC_FAIL; + } + memset(eeprom_map, 0xFF, eeprom_size); + + status = halmac_read_logical_efuse_map_88xx(halmac_adapter, eeprom_map); + if (status != HALMAC_RET_SUCCESS) { + pr_err("halmac_read_logical_efuse_map error = %x\n", status); + kfree(eeprom_map); + return status; + } + + *value = *(eeprom_map + halmac_offset); + + if (halmac_transition_efuse_state_88xx( + halmac_adapter, HALMAC_EFUSE_CMD_CONSTRUCT_IDLE) != + HALMAC_RET_SUCCESS) { + kfree(eeprom_map); + return HALMAC_RET_ERROR_STATE; + } + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_EFUSE, DBG_DMESG, + "%s <==========\n", __func__); + + kfree(eeprom_map); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_write_logical_efuse_88xx() - write "logical" efuse offset + * @halmac_adapter : the adapter of halmac + * @halmac_offset : offset + * @halmac_value : value + * Author : Soar + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_write_logical_efuse_88xx(struct halmac_adapter *halmac_adapter, + u32 halmac_offset, u8 halmac_value) +{ + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + + enum halmac_cmd_process_status *process_status = + &halmac_adapter->halmac_state.efuse_state_set.process_status; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, + HALMAC_API_WRITE_LOGICAL_EFUSE); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_EFUSE, DBG_DMESG, + "%s ==========>\n", __func__); + + if (halmac_offset >= halmac_adapter->hw_config_info.eeprom_size) { + pr_err("Offset is too large\n"); + return HALMAC_RET_EFUSE_SIZE_INCORRECT; + } + + if (*process_status == HALMAC_CMD_PROCESS_SENDING) { + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "Wait/Rcvd event(dump efuse)...\n"); + return HALMAC_RET_BUSY_STATE; + } + + if (halmac_query_efuse_curr_state_88xx(halmac_adapter) != + HALMAC_EFUSE_CMD_CONSTRUCT_IDLE) { + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "Not idle state(dump efuse)...\n"); + return HALMAC_RET_ERROR_STATE; + } + + status = halmac_func_switch_efuse_bank_88xx(halmac_adapter, + HALMAC_EFUSE_BANK_WIFI); + if (status != HALMAC_RET_SUCCESS) { + pr_err("halmac_func_switch_efuse_bank error = %x\n", status); + return status; + } + + status = halmac_func_write_logical_efuse_88xx( + halmac_adapter, halmac_offset, halmac_value); + if (status != HALMAC_RET_SUCCESS) { + pr_err("halmac_write_logical_efuse error = %x\n", status); + return status; + } + + if (halmac_transition_efuse_state_88xx( + halmac_adapter, HALMAC_EFUSE_CMD_CONSTRUCT_IDLE) != + HALMAC_RET_SUCCESS) + return HALMAC_RET_ERROR_STATE; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_EFUSE, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_pg_efuse_by_map_88xx() - pg logical efuse by map + * @halmac_adapter : the adapter of halmac + * @pg_efuse_info : efuse map information + * @cfg : dump efuse method + * Author : Soar + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_pg_efuse_by_map_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_pg_efuse_info *pg_efuse_info, + enum halmac_efuse_read_cfg cfg) +{ + void *driver_adapter = NULL; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + + enum halmac_cmd_process_status *process_status = + &halmac_adapter->halmac_state.efuse_state_set.process_status; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_PG_EFUSE_BY_MAP); + + driver_adapter = halmac_adapter->driver_adapter; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_EFUSE, DBG_DMESG, + "%s ==========>\n", __func__); + + if (pg_efuse_info->efuse_map_size != + halmac_adapter->hw_config_info.eeprom_size) { + pr_err("efuse_map_size is incorrect, should be %d bytes\n", + halmac_adapter->hw_config_info.eeprom_size); + return HALMAC_RET_EFUSE_SIZE_INCORRECT; + } + + if ((pg_efuse_info->efuse_map_size & 0xF) > 0) { + pr_err("efuse_map_size should be multiple of 16\n"); + return HALMAC_RET_EFUSE_SIZE_INCORRECT; + } + + if (pg_efuse_info->efuse_mask_size != + pg_efuse_info->efuse_map_size >> 4) { + pr_err("efuse_mask_size is incorrect, should be %d bytes\n", + pg_efuse_info->efuse_map_size >> 4); + return HALMAC_RET_EFUSE_SIZE_INCORRECT; + } + + if (!pg_efuse_info->efuse_map) { + pr_err("efuse_map is NULL\n"); + return HALMAC_RET_NULL_POINTER; + } + + if (!pg_efuse_info->efuse_mask) { + pr_err("efuse_mask is NULL\n"); + return HALMAC_RET_NULL_POINTER; + } + + if (*process_status == HALMAC_CMD_PROCESS_SENDING) { + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "Wait/Rcvd event(dump efuse)...\n"); + return HALMAC_RET_BUSY_STATE; + } + + if (halmac_query_efuse_curr_state_88xx(halmac_adapter) != + HALMAC_EFUSE_CMD_CONSTRUCT_IDLE) { + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "Not idle state(dump efuse)...\n"); + return HALMAC_RET_ERROR_STATE; + } + + status = halmac_func_switch_efuse_bank_88xx(halmac_adapter, + HALMAC_EFUSE_BANK_WIFI); + if (status != HALMAC_RET_SUCCESS) { + pr_err("halmac_func_switch_efuse_bank error = %x\n", status); + return status; + } + + status = halmac_func_pg_efuse_by_map_88xx(halmac_adapter, pg_efuse_info, + cfg); + + if (status != HALMAC_RET_SUCCESS) { + pr_err("halmac_pg_efuse_by_map error = %x\n", status); + return status; + } + + if (halmac_transition_efuse_state_88xx( + halmac_adapter, HALMAC_EFUSE_CMD_CONSTRUCT_IDLE) != + HALMAC_RET_SUCCESS) + return HALMAC_RET_ERROR_STATE; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_EFUSE, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_get_c2h_info_88xx() - process halmac C2H packet + * @halmac_adapter : the adapter of halmac + * @halmac_buf : RX Packet pointer + * @halmac_size : RX Packet size + * Author : KaiYuan Chang/Ivan Lin + * + * Used to process c2h packet info from RX path. After receiving the packet, + * user need to call this api and pass the packet pointer. + * + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_get_c2h_info_88xx(struct halmac_adapter *halmac_adapter, u8 *halmac_buf, + u32 halmac_size) +{ + void *driver_adapter = NULL; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_GET_C2H_INFO); + + driver_adapter = halmac_adapter->driver_adapter; + + /* Check if it is C2H packet */ + if (GET_RX_DESC_C2H(halmac_buf)) { + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "C2H packet, start parsing!\n"); + + status = halmac_parse_c2h_packet_88xx(halmac_adapter, + halmac_buf, halmac_size); + + if (status != HALMAC_RET_SUCCESS) { + pr_err("halmac_parse_c2h_packet_88xx error = %x\n", + status); + return status; + } + } + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status +halmac_cfg_fwlps_option_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_fwlps_option *lps_option) +{ + void *driver_adapter = NULL; + struct halmac_fwlps_option *hal_fwlps_option; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_CFG_FWLPS_OPTION); + + driver_adapter = halmac_adapter->driver_adapter; + hal_fwlps_option = &halmac_adapter->fwlps_option; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_PWR, DBG_DMESG, + "%s ==========>\n", __func__); + + hal_fwlps_option->mode = lps_option->mode; + hal_fwlps_option->clk_request = lps_option->clk_request; + hal_fwlps_option->rlbm = lps_option->rlbm; + hal_fwlps_option->smart_ps = lps_option->smart_ps; + hal_fwlps_option->awake_interval = lps_option->awake_interval; + hal_fwlps_option->all_queue_uapsd = lps_option->all_queue_uapsd; + hal_fwlps_option->pwr_state = lps_option->pwr_state; + hal_fwlps_option->low_pwr_rx_beacon = lps_option->low_pwr_rx_beacon; + hal_fwlps_option->ant_auto_switch = lps_option->ant_auto_switch; + hal_fwlps_option->ps_allow_bt_high_priority = + lps_option->ps_allow_bt_high_priority; + hal_fwlps_option->protect_bcn = lps_option->protect_bcn; + hal_fwlps_option->silence_period = lps_option->silence_period; + hal_fwlps_option->fast_bt_connect = lps_option->fast_bt_connect; + hal_fwlps_option->two_antenna_en = lps_option->two_antenna_en; + hal_fwlps_option->adopt_user_setting = lps_option->adopt_user_setting; + hal_fwlps_option->drv_bcn_early_shift = lps_option->drv_bcn_early_shift; + hal_fwlps_option->enter_32K = lps_option->enter_32K; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_PWR, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status +halmac_cfg_fwips_option_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_fwips_option *ips_option) +{ + void *driver_adapter = NULL; + struct halmac_fwips_option *ips_option_local; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_CFG_FWIPS_OPTION); + + driver_adapter = halmac_adapter->driver_adapter; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_PWR, DBG_DMESG, + "%s ==========>\n", __func__); + + ips_option_local = ips_option; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_PWR, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status +halmac_enter_wowlan_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_wowlan_option *wowlan_option) +{ + void *driver_adapter = NULL; + struct halmac_wowlan_option *wowlan_option_local; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_ENTER_WOWLAN); + + driver_adapter = halmac_adapter->driver_adapter; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_PWR, DBG_DMESG, + "%s ==========>\n", __func__); + + wowlan_option_local = wowlan_option; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_PWR, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status +halmac_leave_wowlan_88xx(struct halmac_adapter *halmac_adapter) +{ + void *driver_adapter = NULL; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_LEAVE_WOWLAN); + + driver_adapter = halmac_adapter->driver_adapter; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_PWR, DBG_DMESG, + "%s ==========>\n", __func__); + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_PWR, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status +halmac_enter_ps_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_ps_state ps_state) +{ + u8 rpwm; + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + if (halmac_fw_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_NO_DLFW; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_ENTER_PS); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_PWR, DBG_DMESG, + "%s ==========>\n", __func__); + + if (ps_state == halmac_adapter->halmac_state.ps_state) { + pr_err("power state is already in PS State!!\n"); + return HALMAC_RET_SUCCESS; + } + + if (ps_state == HALMAC_PS_STATE_LPS) { + status = halmac_send_h2c_set_pwr_mode_88xx( + halmac_adapter, &halmac_adapter->fwlps_option); + if (status != HALMAC_RET_SUCCESS) { + pr_err("halmac_send_h2c_set_pwr_mode_88xx error = %x!!\n", + status); + return status; + } + } else if (ps_state == HALMAC_PS_STATE_IPS) { + } + + halmac_adapter->halmac_state.ps_state = ps_state; + + /* Enter 32K */ + if (halmac_adapter->halmac_interface == HALMAC_INTERFACE_SDIO) { + if (halmac_adapter->fwlps_option.enter_32K) { + rpwm = (u8)(((halmac_adapter->rpwm_record ^ (BIT(7))) | + (BIT(0))) & + 0x81); + HALMAC_REG_WRITE_8(halmac_adapter, REG_SDIO_HRPWM1, + rpwm); + halmac_adapter->low_clk = true; + } + } else if (halmac_adapter->halmac_interface == HALMAC_INTERFACE_USB) { + if (halmac_adapter->fwlps_option.enter_32K) { + rpwm = (u8)(((halmac_adapter->rpwm_record ^ (BIT(7))) | + (BIT(0))) & + 0x81); + HALMAC_REG_WRITE_8(halmac_adapter, 0xFE58, rpwm); + halmac_adapter->low_clk = true; + } + } + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_PWR, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status +halmac_leave_ps_88xx(struct halmac_adapter *halmac_adapter) +{ + u8 rpwm, cpwm; + u32 counter; + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + struct halmac_fwlps_option fw_lps_option; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + if (halmac_fw_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_NO_DLFW; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_LEAVE_PS); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_PWR, DBG_DMESG, + "%s ==========>\n", __func__); + + if (halmac_adapter->halmac_state.ps_state == HALMAC_PS_STATE_ACT) { + pr_err("power state is already in active!!\n"); + return HALMAC_RET_SUCCESS; + } + + if (halmac_adapter->low_clk) { + cpwm = HALMAC_REG_READ_8(halmac_adapter, REG_SDIO_HRPWM1); + rpwm = (u8)( + ((halmac_adapter->rpwm_record ^ (BIT(7))) | (BIT(6))) & + 0xC0); + HALMAC_REG_WRITE_8(halmac_adapter, REG_SDIO_HRPWM1, rpwm); + + cpwm = (u8)((cpwm ^ BIT(7)) & BIT(7)); + counter = 100; + while (cpwm != + (HALMAC_REG_READ_8(halmac_adapter, REG_SDIO_HRPWM1) & + BIT(7))) { + usleep_range(50, 60); + counter--; + if (counter == 0) + return HALMAC_RET_CHANGE_PS_FAIL; + } + halmac_adapter->low_clk = false; + } + + memcpy(&fw_lps_option, &halmac_adapter->fwlps_option, + sizeof(struct halmac_fwlps_option)); + fw_lps_option.mode = 0; + + status = halmac_send_h2c_set_pwr_mode_88xx(halmac_adapter, + &fw_lps_option); + if (status != HALMAC_RET_SUCCESS) { + pr_err("halmac_send_h2c_set_pwr_mode_88xx error!!=%x\n", + status); + return status; + } + + halmac_adapter->halmac_state.ps_state = HALMAC_PS_STATE_ACT; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_PWR, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * (debug API)halmac_h2c_lb_88xx() - send h2c loopback packet + * @halmac_adapter : the adapter of halmac + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status halmac_h2c_lb_88xx(struct halmac_adapter *halmac_adapter) +{ + void *driver_adapter = NULL; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_H2C_LB); + + driver_adapter = halmac_adapter->driver_adapter; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "%s ==========>\n", __func__); + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_debug_88xx() - dump information for debugging + * @halmac_adapter : the adapter of halmac + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status halmac_debug_88xx(struct halmac_adapter *halmac_adapter) +{ + u8 temp8 = 0; + u32 i = 0, temp32 = 0; + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_DEBUG); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s ==========>\n", __func__); + + if (halmac_adapter->halmac_interface == HALMAC_INTERFACE_SDIO) { + /* Dump CCCR, it needs new platform api */ + + /*Dump SDIO Local Register, use CMD52*/ + for (i = 0x10250000; i < 0x102500ff; i++) { + temp8 = PLATFORM_SDIO_CMD52_READ(halmac_adapter, i); + HALMAC_RT_TRACE( + driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "halmac_debug: sdio[%x]=%x\n", i, temp8); + } + + /*Dump MAC Register*/ + for (i = 0x0000; i < 0x17ff; i++) { + temp8 = PLATFORM_SDIO_CMD52_READ(halmac_adapter, i); + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, + DBG_DMESG, "halmac_debug: mac[%x]=%x\n", + i, temp8); + } + + /*Check RX Fifo status*/ + i = REG_RXFF_PTR_V1; + temp8 = PLATFORM_SDIO_CMD52_READ(halmac_adapter, i); + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "halmac_debug: mac[%x]=%x\n", i, temp8); + i = REG_RXFF_WTR_V1; + temp8 = PLATFORM_SDIO_CMD52_READ(halmac_adapter, i); + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "halmac_debug: mac[%x]=%x\n", i, temp8); + i = REG_RXFF_PTR_V1; + temp8 = PLATFORM_SDIO_CMD52_READ(halmac_adapter, i); + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "halmac_debug: mac[%x]=%x\n", i, temp8); + i = REG_RXFF_WTR_V1; + temp8 = PLATFORM_SDIO_CMD52_READ(halmac_adapter, i); + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "halmac_debug: mac[%x]=%x\n", i, temp8); + } else { + /*Dump MAC Register*/ + for (i = 0x0000; i < 0x17fc; i += 4) { + temp32 = HALMAC_REG_READ_32(halmac_adapter, i); + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, + DBG_DMESG, "halmac_debug: mac[%x]=%x\n", + i, temp32); + } + + /*Check RX Fifo status*/ + i = REG_RXFF_PTR_V1; + temp32 = HALMAC_REG_READ_32(halmac_adapter, i); + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "halmac_debug: mac[%x]=%x\n", i, temp32); + i = REG_RXFF_WTR_V1; + temp32 = HALMAC_REG_READ_32(halmac_adapter, i); + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "halmac_debug: mac[%x]=%x\n", i, temp32); + i = REG_RXFF_PTR_V1; + temp32 = HALMAC_REG_READ_32(halmac_adapter, i); + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "halmac_debug: mac[%x]=%x\n", i, temp32); + i = REG_RXFF_WTR_V1; + temp32 = HALMAC_REG_READ_32(halmac_adapter, i); + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "halmac_debug: mac[%x]=%x\n", i, temp32); + } + + /* TODO: Add check register code, including MAC CLK, CPU CLK */ + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_cfg_parameter_88xx() - config parameter by FW + * @halmac_adapter : the adapter of halmac + * @para_info : cmd id, content + * @full_fifo : parameter information + * + * If msk_en = true, the format of array is {reg_info, mask, value}. + * If msk_en =_FAUSE, the format of array is {reg_info, value} + * The format of reg_info is + * reg_info[31]=rf_reg, 0: MAC_BB reg, 1: RF reg + * reg_info[27:24]=rf_path, 0: path_A, 1: path_B + * if rf_reg=0(MAC_BB reg), rf_path is meaningless. + * ref_info[15:0]=offset + * + * Example: msk_en = false + * {0x8100000a, 0x00001122} + * =>Set RF register, path_B, offset 0xA to 0x00001122 + * {0x00000824, 0x11224433} + * =>Set MAC_BB register, offset 0x800 to 0x11224433 + * + * Note : full fifo mode only for init flow + * + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_cfg_parameter_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_phy_parameter_info *para_info, + u8 full_fifo) +{ + void *driver_adapter = NULL; + enum halmac_ret_status ret_status = HALMAC_RET_SUCCESS; + enum halmac_cmd_process_status *process_status = + &halmac_adapter->halmac_state.cfg_para_state_set.process_status; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + if (halmac_fw_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_NO_DLFW; + + if (halmac_adapter->fw_version.h2c_version < 4) + return HALMAC_RET_FW_NO_SUPPORT; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_CFG_PARAMETER); + + driver_adapter = halmac_adapter->driver_adapter; + + if (halmac_adapter->halmac_state.dlfw_state == HALMAC_DLFW_NONE) { + pr_err("%s Fail due to DLFW NONE!!\n", __func__); + return HALMAC_RET_DLFW_FAIL; + } + + if (*process_status == HALMAC_CMD_PROCESS_SENDING) { + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "Wait event(cfg para)...\n"); + return HALMAC_RET_BUSY_STATE; + } + + if (halmac_query_cfg_para_curr_state_88xx(halmac_adapter) != + HALMAC_CFG_PARA_CMD_CONSTRUCT_IDLE && + halmac_query_cfg_para_curr_state_88xx(halmac_adapter) != + HALMAC_CFG_PARA_CMD_CONSTRUCT_CONSTRUCTING) { + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "Not idle state(cfg para)...\n"); + return HALMAC_RET_BUSY_STATE; + } + + *process_status = HALMAC_CMD_PROCESS_IDLE; + + ret_status = halmac_send_h2c_phy_parameter_88xx(halmac_adapter, + para_info, full_fifo); + + if (ret_status != HALMAC_RET_SUCCESS) { + pr_err("halmac_send_h2c_phy_parameter_88xx Fail!! = %x\n", + ret_status); + return ret_status; + } + + return ret_status; +} + +/** + * halmac_update_packet_88xx() - send specific packet to FW + * @halmac_adapter : the adapter of halmac + * @pkt_id : packet id, to know the purpose of this packet + * @pkt : packet + * @pkt_size : packet size + * + * Note : TX_DESC is not included in the pkt + * + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_update_packet_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_packet_id pkt_id, u8 *pkt, u32 pkt_size) +{ + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + enum halmac_cmd_process_status *process_status = + &halmac_adapter->halmac_state.update_packet_set.process_status; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + if (halmac_fw_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_NO_DLFW; + + if (halmac_adapter->fw_version.h2c_version < 4) + return HALMAC_RET_FW_NO_SUPPORT; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_UPDATE_PACKET); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "%s ==========>\n", __func__); + + if (*process_status == HALMAC_CMD_PROCESS_SENDING) { + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "Wait event(update_packet)...\n"); + return HALMAC_RET_BUSY_STATE; + } + + *process_status = HALMAC_CMD_PROCESS_SENDING; + + status = halmac_send_h2c_update_packet_88xx(halmac_adapter, pkt_id, pkt, + pkt_size); + + if (status != HALMAC_RET_SUCCESS) { + pr_err("halmac_send_h2c_update_packet_88xx packet = %x, fail = %x!!\n", + pkt_id, status); + return status; + } + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status +halmac_bcn_ie_filter_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_bcn_ie_info *bcn_ie_info) +{ + void *driver_adapter = NULL; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + if (halmac_fw_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_NO_DLFW; + + if (halmac_adapter->fw_version.h2c_version < 4) + return HALMAC_RET_FW_NO_SUPPORT; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_BCN_IE_FILTER); + + driver_adapter = halmac_adapter->driver_adapter; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "%s ==========>\n", __func__); + + status = halmac_send_h2c_update_bcn_parse_info_88xx(halmac_adapter, + bcn_ie_info); + + if (status != HALMAC_RET_SUCCESS) { + pr_err("halmac_send_h2c_update_bcn_parse_info_88xx fail = %x\n", + status); + return status; + } + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status +halmac_update_datapack_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_data_type halmac_data_type, + struct halmac_phy_parameter_info *para_info) +{ + void *driver_adapter = NULL; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + if (halmac_fw_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_NO_DLFW; + + if (halmac_adapter->fw_version.h2c_version < 4) + return HALMAC_RET_FW_NO_SUPPORT; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "[TRACE]%s ==========>\n", __func__); + + driver_adapter = halmac_adapter->driver_adapter; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "[TRACE]%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status +halmac_run_datapack_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_data_type halmac_data_type) +{ + void *driver_adapter = NULL; + enum halmac_ret_status ret_status = HALMAC_RET_SUCCESS; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + if (halmac_fw_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_NO_DLFW; + + if (halmac_adapter->fw_version.h2c_version < 4) + return HALMAC_RET_FW_NO_SUPPORT; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_RUN_DATAPACK); + + driver_adapter = halmac_adapter->driver_adapter; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "%s ==========>\n", __func__); + + ret_status = halmac_send_h2c_run_datapack_88xx(halmac_adapter, + halmac_data_type); + + if (ret_status != HALMAC_RET_SUCCESS) { + pr_err("halmac_send_h2c_run_datapack_88xx Fail, datatype = %x, status = %x!!\n", + halmac_data_type, ret_status); + return ret_status; + } + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "halmac_update_datapack_88xx <==========\n"); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_cfg_drv_info_88xx() - config driver info + * @halmac_adapter : the adapter of halmac + * @halmac_drv_info : driver information selection + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_cfg_drv_info_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_drv_info halmac_drv_info) +{ + u8 drv_info_size = 0; + u8 phy_status_en = 0; + u8 sniffer_en = 0; + u8 plcp_hdr_en = 0; + u32 value32; + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_CFG_DRV_INFO); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "%s ==========>\n", __func__); + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "halmac_cfg_drv_info = %d\n", halmac_drv_info); + + switch (halmac_drv_info) { + case HALMAC_DRV_INFO_NONE: + drv_info_size = 0; + phy_status_en = 0; + sniffer_en = 0; + plcp_hdr_en = 0; + break; + case HALMAC_DRV_INFO_PHY_STATUS: + drv_info_size = 4; + phy_status_en = 1; + sniffer_en = 0; + plcp_hdr_en = 0; + break; + case HALMAC_DRV_INFO_PHY_SNIFFER: + drv_info_size = 5; /* phy status 4byte, sniffer info 1byte */ + phy_status_en = 1; + sniffer_en = 1; + plcp_hdr_en = 0; + break; + case HALMAC_DRV_INFO_PHY_PLCP: + drv_info_size = 6; /* phy status 4byte, plcp header 2byte */ + phy_status_en = 1; + sniffer_en = 0; + plcp_hdr_en = 1; + break; + default: + status = HALMAC_RET_SW_CASE_NOT_SUPPORT; + pr_err("%s error = %x\n", __func__, status); + return status; + } + + if (halmac_adapter->txff_allocation.rx_fifo_expanding_mode != + HALMAC_RX_FIFO_EXPANDING_MODE_DISABLE) + drv_info_size = 0xF; + + HALMAC_REG_WRITE_8(halmac_adapter, REG_RX_DRVINFO_SZ, drv_info_size); + + halmac_adapter->drv_info_size = drv_info_size; + + value32 = HALMAC_REG_READ_32(halmac_adapter, REG_RCR); + value32 = (value32 & (~BIT_APP_PHYSTS)); + if (phy_status_en == 1) + value32 = value32 | BIT_APP_PHYSTS; + HALMAC_REG_WRITE_32(halmac_adapter, REG_RCR, value32); + + value32 = HALMAC_REG_READ_32(halmac_adapter, + REG_WMAC_OPTION_FUNCTION + 4); + value32 = (value32 & (~(BIT(8) | BIT(9)))); + if (sniffer_en == 1) + value32 = value32 | BIT(9); + if (plcp_hdr_en == 1) + value32 = value32 | BIT(8); + HALMAC_REG_WRITE_32(halmac_adapter, REG_WMAC_OPTION_FUNCTION + 4, + value32); + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status +halmac_send_bt_coex_88xx(struct halmac_adapter *halmac_adapter, u8 *bt_buf, + u32 bt_size, u8 ack) +{ + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + enum halmac_ret_status ret_status = HALMAC_RET_SUCCESS; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + if (halmac_fw_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_NO_DLFW; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_SEND_BT_COEX); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "%s ==========>\n", __func__); + + ret_status = halmac_send_bt_coex_cmd_88xx(halmac_adapter, bt_buf, + bt_size, ack); + + if (ret_status != HALMAC_RET_SUCCESS) { + pr_err("halmac_send_bt_coex_cmd_88xx Fail = %x!!\n", + ret_status); + return ret_status; + } + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * (debug API)halmac_verify_platform_api_88xx() - verify platform api + * @halmac_adapter : the adapter of halmac + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_verify_platform_api_88xx(struct halmac_adapter *halmac_adapter) +{ + void *driver_adapter = NULL; + enum halmac_ret_status ret_status = HALMAC_RET_SUCCESS; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, + HALMAC_API_VERIFY_PLATFORM_API); + + driver_adapter = halmac_adapter->driver_adapter; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "%s ==========>\n", __func__); + + ret_status = halmac_verify_io_88xx(halmac_adapter); + + if (ret_status != HALMAC_RET_SUCCESS) + return ret_status; + + if (halmac_adapter->txff_allocation.la_mode != HALMAC_LA_MODE_FULL) + ret_status = halmac_verify_send_rsvd_page_88xx(halmac_adapter); + + if (ret_status != HALMAC_RET_SUCCESS) + return ret_status; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "%s <==========\n", __func__); + + return ret_status; +} + +enum halmac_ret_status +halmac_send_original_h2c_88xx(struct halmac_adapter *halmac_adapter, + u8 *original_h2c, u16 *seq, u8 ack) +{ + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + if (halmac_fw_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_NO_DLFW; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_SEND_ORIGINAL_H2C); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "%s ==========>\n", __func__); + + status = halmac_func_send_original_h2c_88xx(halmac_adapter, + original_h2c, seq, ack); + + if (status != HALMAC_RET_SUCCESS) { + pr_err("halmac_send_original_h2c FAIL = %x!!\n", status); + return status; + } + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status +halmac_timer_2s_88xx(struct halmac_adapter *halmac_adapter) +{ + void *driver_adapter = NULL; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + driver_adapter = halmac_adapter->driver_adapter; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s ==========>\n", __func__); + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_fill_txdesc_check_sum_88xx() - fill in tx desc check sum + * @halmac_adapter : the adapter of halmac + * @cur_desc : tx desc packet + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_fill_txdesc_check_sum_88xx(struct halmac_adapter *halmac_adapter, + u8 *cur_desc) +{ + u16 chk_result = 0; + u16 *data = (u16 *)NULL; + u32 i; + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, + HALMAC_API_FILL_TXDESC_CHECKSUM); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + if (!cur_desc) { + pr_err("%s NULL PTR", __func__); + return HALMAC_RET_NULL_POINTER; + } + + SET_TX_DESC_TXDESC_CHECKSUM(cur_desc, 0x0000); + + data = (u16 *)(cur_desc); + + /* HW clculates only 32byte */ + for (i = 0; i < 8; i++) + chk_result ^= (*(data + 2 * i) ^ *(data + (2 * i + 1))); + + SET_TX_DESC_TXDESC_CHECKSUM(cur_desc, chk_result); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_dump_fifo_88xx() - dump fifo data + * @halmac_adapter : the adapter of halmac + * @halmac_fifo_sel : FIFO selection + * @halmac_start_addr : start address of selected FIFO + * @halmac_fifo_dump_size : dump size of selected FIFO + * @fifo_map : FIFO data + * + * Note : before dump fifo, user need to call halmac_get_fifo_size to + * get fifo size. Then input this size to halmac_dump_fifo. + * + * Author : Ivan Lin/KaiYuan Chang + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_dump_fifo_88xx(struct halmac_adapter *halmac_adapter, + enum hal_fifo_sel halmac_fifo_sel, u32 halmac_start_addr, + u32 halmac_fifo_dump_size, u8 *fifo_map) +{ + void *driver_adapter = NULL; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_DUMP_FIFO); + + driver_adapter = halmac_adapter->driver_adapter; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s ==========>\n", __func__); + + if (halmac_fifo_sel == HAL_FIFO_SEL_TX && + (halmac_start_addr + halmac_fifo_dump_size) > + halmac_adapter->hw_config_info.tx_fifo_size) { + pr_err("TX fifo dump size is too large\n"); + return HALMAC_RET_DUMP_FIFOSIZE_INCORRECT; + } + + if (halmac_fifo_sel == HAL_FIFO_SEL_RX && + (halmac_start_addr + halmac_fifo_dump_size) > + halmac_adapter->hw_config_info.rx_fifo_size) { + pr_err("RX fifo dump size is too large\n"); + return HALMAC_RET_DUMP_FIFOSIZE_INCORRECT; + } + + if ((halmac_fifo_dump_size & (4 - 1)) != 0) { + pr_err("halmac_fifo_dump_size shall 4byte align\n"); + return HALMAC_RET_DUMP_FIFOSIZE_INCORRECT; + } + + if (!fifo_map) { + pr_err("fifo_map address is NULL\n"); + return HALMAC_RET_NULL_POINTER; + } + + status = halmac_buffer_read_88xx(halmac_adapter, halmac_start_addr, + halmac_fifo_dump_size, halmac_fifo_sel, + fifo_map); + + if (status != HALMAC_RET_SUCCESS) { + pr_err("halmac_buffer_read_88xx error = %x\n", status); + return status; + } + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_get_fifo_size_88xx() - get fifo size + * @halmac_adapter : the adapter of halmac + * @halmac_fifo_sel : FIFO selection + * Author : Ivan Lin/KaiYuan Chang + * Return : u32 + * More details of status code can be found in prototype document + */ +u32 halmac_get_fifo_size_88xx(struct halmac_adapter *halmac_adapter, + enum hal_fifo_sel halmac_fifo_sel) +{ + u32 fifo_size = 0; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_GET_FIFO_SIZE); + + if (halmac_fifo_sel == HAL_FIFO_SEL_TX) + fifo_size = halmac_adapter->hw_config_info.tx_fifo_size; + else if (halmac_fifo_sel == HAL_FIFO_SEL_RX) + fifo_size = halmac_adapter->hw_config_info.rx_fifo_size; + else if (halmac_fifo_sel == HAL_FIFO_SEL_RSVD_PAGE) + fifo_size = + ((halmac_adapter->hw_config_info.tx_fifo_size >> 7) - + halmac_adapter->txff_allocation.rsvd_pg_bndy) + << 7; + else if (halmac_fifo_sel == HAL_FIFO_SEL_REPORT) + fifo_size = 65536; + else if (halmac_fifo_sel == HAL_FIFO_SEL_LLT) + fifo_size = 65536; + + return fifo_size; +} + +/** + * halmac_cfg_txbf_88xx() - enable/disable specific user's txbf + * @halmac_adapter : the adapter of halmac + * @userid : su bfee userid = 0 or 1 to apply TXBF + * @bw : the sounding bandwidth + * @txbf_en : 0: disable TXBF, 1: enable TXBF + * Author : chunchu + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_cfg_txbf_88xx(struct halmac_adapter *halmac_adapter, u8 userid, + enum halmac_bw bw, u8 txbf_en) +{ + u16 temp42C = 0; + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_CFG_TXBF); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + if (txbf_en) { + switch (bw) { + case HALMAC_BW_80: + temp42C |= BIT_R_TXBF0_80M; + case HALMAC_BW_40: + temp42C |= BIT_R_TXBF0_40M; + case HALMAC_BW_20: + temp42C |= BIT_R_TXBF0_20M; + break; + default: + pr_err("%s invalid TXBF BW setting 0x%x of userid %d\n", + __func__, bw, userid); + return HALMAC_RET_INVALID_SOUNDING_SETTING; + } + } + + switch (userid) { + case 0: + temp42C |= + HALMAC_REG_READ_16(halmac_adapter, REG_TXBF_CTRL) & + ~(BIT_R_TXBF0_20M | BIT_R_TXBF0_40M | BIT_R_TXBF0_80M); + HALMAC_REG_WRITE_16(halmac_adapter, REG_TXBF_CTRL, temp42C); + break; + case 1: + temp42C |= + HALMAC_REG_READ_16(halmac_adapter, REG_TXBF_CTRL + 2) & + ~(BIT_R_TXBF0_20M | BIT_R_TXBF0_40M | BIT_R_TXBF0_80M); + HALMAC_REG_WRITE_16(halmac_adapter, REG_TXBF_CTRL + 2, temp42C); + break; + default: + pr_err("%s invalid userid %d\n", __func__, userid); + return HALMAC_RET_INVALID_SOUNDING_SETTING; + } + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_SND, DBG_DMESG, + "%s, txbf_en = %x <==========\n", __func__, + txbf_en); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_cfg_mumimo_88xx() -config mumimo + * @halmac_adapter : the adapter of halmac + * @cfgmu : parameters to configure MU PPDU Tx/Rx + * Author : chunchu + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_cfg_mumimo_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_cfg_mumimo_para *cfgmu) +{ + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + u8 i, idx, id0, id1, gid, mu_tab_sel; + u8 mu_tab_valid = 0; + u32 gid_valid[6] = {0}; + u8 temp14C0 = 0; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_CFG_MUMIMO); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + if (cfgmu->role == HAL_BFEE) { + /*config MU BFEE*/ + temp14C0 = HALMAC_REG_READ_8(halmac_adapter, REG_MU_TX_CTL) & + ~BIT_MASK_R_MU_TABLE_VALID; + /*enable MU table 0 and 1, disable MU TX*/ + HALMAC_REG_WRITE_8(halmac_adapter, REG_MU_TX_CTL, + (temp14C0 | BIT(0) | BIT(1)) & ~(BIT(7))); + + /*config GID valid table and user position table*/ + mu_tab_sel = + HALMAC_REG_READ_8(halmac_adapter, REG_MU_TX_CTL + 1) & + ~(BIT(0) | BIT(1) | BIT(2)); + for (i = 0; i < 2; i++) { + HALMAC_REG_WRITE_8(halmac_adapter, REG_MU_TX_CTL + 1, + mu_tab_sel | i); + HALMAC_REG_WRITE_32(halmac_adapter, REG_MU_STA_GID_VLD, + cfgmu->given_gid_tab[i]); + HALMAC_REG_WRITE_32(halmac_adapter, + REG_MU_STA_USER_POS_INFO, + cfgmu->given_user_pos[i * 2]); + HALMAC_REG_WRITE_32(halmac_adapter, + REG_MU_STA_USER_POS_INFO + 4, + cfgmu->given_user_pos[i * 2 + 1]); + } + } else { + /*config MU BFER*/ + if (!cfgmu->mu_tx_en) { + HALMAC_REG_WRITE_8(halmac_adapter, REG_MU_TX_CTL, + HALMAC_REG_READ_8(halmac_adapter, + REG_MU_TX_CTL) & + ~(BIT(7))); + HALMAC_RT_TRACE( + driver_adapter, HALMAC_MSG_SND, DBG_DMESG, + "%s disable mu tx <==========\n", __func__); + return HALMAC_RET_SUCCESS; + } + + /*Transform BB grouping bitmap[14:0] to MAC GID_valid table*/ + for (idx = 0; idx < 15; idx++) { + if (idx < 5) { + /*group_bitmap bit0~4, MU_STA0 with MUSTA1~5*/ + id0 = 0; + id1 = (u8)(idx + 1); + } else if (idx < 9) { + /*group_bitmap bit5~8, MU_STA1 with MUSTA2~5*/ + id0 = 1; + id1 = (u8)(idx - 3); + } else if (idx < 12) { + /*group_bitmap bit9~11, MU_STA2 with MUSTA3~5*/ + id0 = 2; + id1 = (u8)(idx - 6); + } else if (idx < 14) { + /*group_bitmap bit12~13, MU_STA3 with MUSTA4~5*/ + id0 = 3; + id1 = (u8)(idx - 8); + } else { + /*group_bitmap bit14, MU_STA4 with MUSTA5*/ + id0 = 4; + id1 = (u8)(idx - 9); + } + if (cfgmu->grouping_bitmap & BIT(idx)) { + /*Pair 1*/ + gid = (idx << 1) + 1; + gid_valid[id0] |= (BIT(gid)); + gid_valid[id1] |= (BIT(gid)); + /*Pair 2*/ + gid += 1; + gid_valid[id0] |= (BIT(gid)); + gid_valid[id1] |= (BIT(gid)); + } else { + /*Pair 1*/ + gid = (idx << 1) + 1; + gid_valid[id0] &= ~(BIT(gid)); + gid_valid[id1] &= ~(BIT(gid)); + /*Pair 2*/ + gid += 1; + gid_valid[id0] &= ~(BIT(gid)); + gid_valid[id1] &= ~(BIT(gid)); + } + } + + /*set MU STA GID valid TABLE*/ + mu_tab_sel = + HALMAC_REG_READ_8(halmac_adapter, REG_MU_TX_CTL + 1) & + ~(BIT(0) | BIT(1) | BIT(2)); + for (idx = 0; idx < 6; idx++) { + HALMAC_REG_WRITE_8(halmac_adapter, REG_MU_TX_CTL + 1, + idx | mu_tab_sel); + HALMAC_REG_WRITE_32(halmac_adapter, REG_MU_STA_GID_VLD, + gid_valid[idx]); + } + + /*To validate the sounding successful MU STA and enable MU TX*/ + for (i = 0; i < 6; i++) { + if (cfgmu->sounding_sts[i]) + mu_tab_valid |= BIT(i); + } + HALMAC_REG_WRITE_8(halmac_adapter, REG_MU_TX_CTL, + mu_tab_valid | BIT(7)); + } + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_SND, DBG_DMESG, + "%s <==========\n", __func__); + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_cfg_sounding_88xx() - configure general sounding + * @halmac_adapter : the adapter of halmac + * @role : driver's role, BFer or BFee + * @datarate : set ndpa tx rate if driver is BFer, or set csi response rate + * if driver is BFee + * Author : chunchu + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_cfg_sounding_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_snd_role role, + enum halmac_data_rate datarate) +{ + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_CFG_SOUNDING); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + switch (role) { + case HAL_BFER: + HALMAC_REG_WRITE_32( + halmac_adapter, REG_TXBF_CTRL, + HALMAC_REG_READ_32(halmac_adapter, REG_TXBF_CTRL) | + BIT_R_ENABLE_NDPA | BIT_USE_NDPA_PARAMETER | + BIT_R_EN_NDPA_INT | BIT_DIS_NDP_BFEN); + HALMAC_REG_WRITE_8(halmac_adapter, REG_NDPA_RATE, datarate); + HALMAC_REG_WRITE_8( + halmac_adapter, REG_NDPA_OPT_CTRL, + HALMAC_REG_READ_8(halmac_adapter, REG_NDPA_OPT_CTRL) & + (~(BIT(0) | BIT(1)))); + /*service file length 2 bytes; fix non-STA1 csi start offset */ + HALMAC_REG_WRITE_8(halmac_adapter, REG_SND_PTCL_CTRL + 1, + 0x2 | BIT(7)); + HALMAC_REG_WRITE_8(halmac_adapter, REG_SND_PTCL_CTRL + 2, 0x2); + break; + case HAL_BFEE: + HALMAC_REG_WRITE_8(halmac_adapter, REG_SND_PTCL_CTRL, 0xDB); + HALMAC_REG_WRITE_8(halmac_adapter, REG_SND_PTCL_CTRL + 3, 0x50); + /*use ndpa rx rate to decide csi rate*/ + HALMAC_REG_WRITE_8(halmac_adapter, REG_BBPSF_CTRL + 3, + HALMAC_OFDM54 | BIT(6)); + HALMAC_REG_WRITE_16( + halmac_adapter, REG_RRSR, + HALMAC_REG_READ_16(halmac_adapter, REG_RRSR) | + BIT(datarate)); + /*RXFF do not accept BF Rpt Poll, avoid CSI crc error*/ + HALMAC_REG_WRITE_8( + halmac_adapter, REG_RXFLTMAP1, + HALMAC_REG_READ_8(halmac_adapter, REG_RXFLTMAP1) & + (~(BIT(4)))); + /*FWFF do not accept BF Rpt Poll, avoid CSI crc error*/ + HALMAC_REG_WRITE_8( + halmac_adapter, REG_RXFLTMAP4, + HALMAC_REG_READ_8(halmac_adapter, REG_RXFLTMAP4) & + (~(BIT(4)))); + break; + default: + pr_err("%s invalid role\n", __func__); + return HALMAC_RET_INVALID_SOUNDING_SETTING; + } + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_SND, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_del_sounding_88xx() - reset general sounding + * @halmac_adapter : the adapter of halmac + * @role : driver's role, BFer or BFee + * Author : chunchu + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_del_sounding_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_snd_role role) +{ + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_DEL_SOUNDING); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + switch (role) { + case HAL_BFER: + HALMAC_REG_WRITE_8(halmac_adapter, REG_TXBF_CTRL + 3, 0); + break; + case HAL_BFEE: + HALMAC_REG_WRITE_8(halmac_adapter, REG_SND_PTCL_CTRL, 0); + break; + default: + pr_err("%s invalid role\n", __func__); + return HALMAC_RET_INVALID_SOUNDING_SETTING; + } + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_SND, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_su_bfee_entry_init_88xx() - config SU beamformee's registers + * @halmac_adapter : the adapter of halmac + * @userid : SU bfee userid = 0 or 1 to be added + * @paid : partial AID of this bfee + * Author : chunchu + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_su_bfee_entry_init_88xx(struct halmac_adapter *halmac_adapter, u8 userid, + u16 paid) +{ + u16 temp42C = 0; + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, + HALMAC_API_SU_BFEE_ENTRY_INIT); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + switch (userid) { + case 0: + temp42C = HALMAC_REG_READ_16(halmac_adapter, REG_TXBF_CTRL) & + ~(BIT_MASK_R_TXBF0_AID | BIT_R_TXBF0_20M | + BIT_R_TXBF0_40M | BIT_R_TXBF0_80M); + HALMAC_REG_WRITE_16(halmac_adapter, REG_TXBF_CTRL, + temp42C | paid); + HALMAC_REG_WRITE_16(halmac_adapter, REG_ASSOCIATED_BFMEE_SEL, + paid); + break; + case 1: + temp42C = + HALMAC_REG_READ_16(halmac_adapter, REG_TXBF_CTRL + 2) & + ~(BIT_MASK_R_TXBF1_AID | BIT_R_TXBF0_20M | + BIT_R_TXBF0_40M | BIT_R_TXBF0_80M); + HALMAC_REG_WRITE_16(halmac_adapter, REG_TXBF_CTRL + 2, + temp42C | paid); + HALMAC_REG_WRITE_16(halmac_adapter, + REG_ASSOCIATED_BFMEE_SEL + 2, + paid | BIT(9)); + break; + default: + pr_err("%s invalid userid %d\n", __func__, + userid); + return HALMAC_RET_INVALID_SOUNDING_SETTING; + } + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_SND, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_su_bfee_entry_init_88xx() - config SU beamformer's registers + * @halmac_adapter : the adapter of halmac + * @su_bfer_init : parameters to configure SU BFER entry + * Author : chunchu + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_su_bfer_entry_init_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_su_bfer_init_para *su_bfer_init) +{ + u16 mac_address_H; + u32 mac_address_L; + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, + HALMAC_API_SU_BFER_ENTRY_INIT); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + /* mac_address_L = bfer_address.address_l_h.address_low; */ + /* mac_address_H = bfer_address.address_l_h.address_high; */ + + mac_address_L = le32_to_cpu( + su_bfer_init->bfer_address.address_l_h.le_address_low); + mac_address_H = le16_to_cpu( + su_bfer_init->bfer_address.address_l_h.le_address_high); + + switch (su_bfer_init->userid) { + case 0: + HALMAC_REG_WRITE_32(halmac_adapter, REG_ASSOCIATED_BFMER0_INFO, + mac_address_L); + HALMAC_REG_WRITE_16(halmac_adapter, + REG_ASSOCIATED_BFMER0_INFO + 4, + mac_address_H); + HALMAC_REG_WRITE_16(halmac_adapter, + REG_ASSOCIATED_BFMER0_INFO + 6, + su_bfer_init->paid); + HALMAC_REG_WRITE_16(halmac_adapter, REG_TX_CSI_RPT_PARAM_BW20, + su_bfer_init->csi_para); + break; + case 1: + HALMAC_REG_WRITE_32(halmac_adapter, REG_ASSOCIATED_BFMER1_INFO, + mac_address_L); + HALMAC_REG_WRITE_16(halmac_adapter, + REG_ASSOCIATED_BFMER1_INFO + 4, + mac_address_H); + HALMAC_REG_WRITE_16(halmac_adapter, + REG_ASSOCIATED_BFMER1_INFO + 6, + su_bfer_init->paid); + HALMAC_REG_WRITE_16(halmac_adapter, + REG_TX_CSI_RPT_PARAM_BW20 + 2, + su_bfer_init->csi_para); + break; + default: + pr_err("%s invalid userid %d\n", __func__, + su_bfer_init->userid); + return HALMAC_RET_INVALID_SOUNDING_SETTING; + } + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_SND, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_mu_bfee_entry_init_88xx() - config MU beamformee's registers + * @halmac_adapter : the adapter of halmac + * @mu_bfee_init : parameters to configure MU BFEE entry + * Author : chunchu + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_mu_bfee_entry_init_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_mu_bfee_init_para *mu_bfee_init) +{ + u16 temp168X = 0, temp14C0; + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, + HALMAC_API_MU_BFEE_ENTRY_INIT); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + temp168X |= mu_bfee_init->paid | BIT(9); + HALMAC_REG_WRITE_16(halmac_adapter, (0x1680 + mu_bfee_init->userid * 2), + temp168X); + + temp14C0 = HALMAC_REG_READ_16(halmac_adapter, REG_MU_TX_CTL) & + ~(BIT(8) | BIT(9) | BIT(10)); + HALMAC_REG_WRITE_16(halmac_adapter, REG_MU_TX_CTL, + temp14C0 | ((mu_bfee_init->userid - 2) << 8)); + HALMAC_REG_WRITE_32(halmac_adapter, REG_MU_STA_GID_VLD, 0); + HALMAC_REG_WRITE_32(halmac_adapter, REG_MU_STA_USER_POS_INFO, + mu_bfee_init->user_position_l); + HALMAC_REG_WRITE_32(halmac_adapter, REG_MU_STA_USER_POS_INFO + 4, + mu_bfee_init->user_position_h); + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_SND, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_mu_bfer_entry_init_88xx() - config MU beamformer's registers + * @halmac_adapter : the adapter of halmac + * @mu_bfer_init : parameters to configure MU BFER entry + * Author : chunchu + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_mu_bfer_entry_init_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_mu_bfer_init_para *mu_bfer_init) +{ + u16 temp1680 = 0; + u16 mac_address_H; + u32 mac_address_L; + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, + HALMAC_API_MU_BFER_ENTRY_INIT); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + mac_address_L = + le32_to_cpu(mu_bfer_init->bfer_address.address_l_h.le_address_low); + mac_address_H = + le16_to_cpu(mu_bfer_init->bfer_address.address_l_h.le_address_high); + + HALMAC_REG_WRITE_32(halmac_adapter, REG_ASSOCIATED_BFMER0_INFO, + mac_address_L); + HALMAC_REG_WRITE_16(halmac_adapter, REG_ASSOCIATED_BFMER0_INFO + 4, + mac_address_H); + HALMAC_REG_WRITE_16(halmac_adapter, REG_ASSOCIATED_BFMER0_INFO + 6, + mu_bfer_init->paid); + HALMAC_REG_WRITE_16(halmac_adapter, REG_TX_CSI_RPT_PARAM_BW20, + mu_bfer_init->csi_para); + + temp1680 = HALMAC_REG_READ_16(halmac_adapter, 0x1680) & 0xC000; + temp1680 |= mu_bfer_init->my_aid | (mu_bfer_init->csi_length_sel << 12); + HALMAC_REG_WRITE_16(halmac_adapter, 0x1680, temp1680); + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_SND, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_su_bfee_entry_del_88xx() - reset SU beamformee's registers + * @halmac_adapter : the adapter of halmac + * @userid : the SU BFee userid to be deleted + * Author : chunchu + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_su_bfee_entry_del_88xx(struct halmac_adapter *halmac_adapter, u8 userid) +{ + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_SU_BFEE_ENTRY_DEL); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + switch (userid) { + case 0: + HALMAC_REG_WRITE_16( + halmac_adapter, REG_TXBF_CTRL, + HALMAC_REG_READ_16(halmac_adapter, REG_TXBF_CTRL) & + ~(BIT_MASK_R_TXBF0_AID | BIT_R_TXBF0_20M | + BIT_R_TXBF0_40M | BIT_R_TXBF0_80M)); + HALMAC_REG_WRITE_16(halmac_adapter, REG_ASSOCIATED_BFMEE_SEL, + 0); + break; + case 1: + HALMAC_REG_WRITE_16( + halmac_adapter, REG_TXBF_CTRL + 2, + HALMAC_REG_READ_16(halmac_adapter, REG_TXBF_CTRL + 2) & + ~(BIT_MASK_R_TXBF1_AID | BIT_R_TXBF0_20M | + BIT_R_TXBF0_40M | BIT_R_TXBF0_80M)); + HALMAC_REG_WRITE_16(halmac_adapter, + REG_ASSOCIATED_BFMEE_SEL + 2, 0); + break; + default: + pr_err("%s invalid userid %d\n", __func__, + userid); + return HALMAC_RET_INVALID_SOUNDING_SETTING; + } + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_SND, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_su_bfee_entry_del_88xx() - reset SU beamformer's registers + * @halmac_adapter : the adapter of halmac + * @userid : the SU BFer userid to be deleted + * Author : chunchu + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_su_bfer_entry_del_88xx(struct halmac_adapter *halmac_adapter, u8 userid) +{ + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_SU_BFER_ENTRY_DEL); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + switch (userid) { + case 0: + HALMAC_REG_WRITE_32(halmac_adapter, REG_ASSOCIATED_BFMER0_INFO, + 0); + HALMAC_REG_WRITE_32(halmac_adapter, + REG_ASSOCIATED_BFMER0_INFO + 4, 0); + break; + case 1: + HALMAC_REG_WRITE_32(halmac_adapter, REG_ASSOCIATED_BFMER1_INFO, + 0); + HALMAC_REG_WRITE_32(halmac_adapter, + REG_ASSOCIATED_BFMER1_INFO + 4, 0); + break; + default: + pr_err("%s invalid userid %d\n", __func__, + userid); + return HALMAC_RET_INVALID_SOUNDING_SETTING; + } + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_SND, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_mu_bfee_entry_del_88xx() - reset MU beamformee's registers + * @halmac_adapter : the adapter of halmac + * @userid : the MU STA userid to be deleted + * Author : chunchu + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_mu_bfee_entry_del_88xx(struct halmac_adapter *halmac_adapter, u8 userid) +{ + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_MU_BFEE_ENTRY_DEL); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_REG_WRITE_16(halmac_adapter, 0x1680 + userid * 2, 0); + HALMAC_REG_WRITE_8(halmac_adapter, REG_MU_TX_CTL, + HALMAC_REG_READ_8(halmac_adapter, REG_MU_TX_CTL) & + ~(BIT(userid - 2))); + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_SND, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_mu_bfer_entry_del_88xx() -reset MU beamformer's registers + * @halmac_adapter : the adapter of halmac + * Author : chunchu + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_mu_bfer_entry_del_88xx(struct halmac_adapter *halmac_adapter) +{ + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_MU_BFER_ENTRY_DEL); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_REG_WRITE_32(halmac_adapter, REG_ASSOCIATED_BFMER0_INFO, 0); + HALMAC_REG_WRITE_32(halmac_adapter, REG_ASSOCIATED_BFMER0_INFO + 4, 0); + HALMAC_REG_WRITE_16(halmac_adapter, 0x1680, 0); + HALMAC_REG_WRITE_8(halmac_adapter, REG_MU_TX_CTL, 0); + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_SND, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_add_ch_info_88xx() -add channel information + * @halmac_adapter : the adapter of halmac + * @ch_info : channel information + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_add_ch_info_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_ch_info *ch_info) +{ + void *driver_adapter = NULL; + struct halmac_cs_info *ch_sw_info; + enum halmac_scan_cmd_construct_state state_scan; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + driver_adapter = halmac_adapter->driver_adapter; + ch_sw_info = &halmac_adapter->ch_sw_info; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "[TRACE]%s ==========>\n", __func__); + + if (halmac_adapter->halmac_state.dlfw_state != HALMAC_GEN_INFO_SENT) { + pr_err("[ERR]%s: gen_info is not send to FW!!!!\n", __func__); + return HALMAC_RET_GEN_INFO_NOT_SENT; + } + + state_scan = halmac_query_scan_curr_state_88xx(halmac_adapter); + if (state_scan != HALMAC_SCAN_CMD_CONSTRUCT_BUFFER_CLEARED && + state_scan != HALMAC_SCAN_CMD_CONSTRUCT_CONSTRUCTING) { + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_WARNING, + "[WARN]Scan machine fail(add ch info)...\n"); + return HALMAC_RET_ERROR_STATE; + } + + if (!ch_sw_info->ch_info_buf) { + ch_sw_info->ch_info_buf = + kzalloc(HALMAC_EXTRA_INFO_BUFF_SIZE_88XX, GFP_KERNEL); + if (!ch_sw_info->ch_info_buf) + return HALMAC_RET_NULL_POINTER; + ch_sw_info->ch_info_buf_w = ch_sw_info->ch_info_buf; + ch_sw_info->buf_size = HALMAC_EXTRA_INFO_BUFF_SIZE_88XX; + ch_sw_info->avai_buf_size = HALMAC_EXTRA_INFO_BUFF_SIZE_88XX; + ch_sw_info->total_size = 0; + ch_sw_info->extra_info_en = 0; + ch_sw_info->ch_num = 0; + } + + if (ch_sw_info->extra_info_en == 1) { + pr_err("[ERR]%s: construct sequence wrong!!\n", __func__); + return HALMAC_RET_CH_SW_SEQ_WRONG; + } + + if (ch_sw_info->avai_buf_size < 4) { + pr_err("[ERR]%s: no available buffer!!\n", __func__); + return HALMAC_RET_CH_SW_NO_BUF; + } + + if (halmac_transition_scan_state_88xx( + halmac_adapter, HALMAC_SCAN_CMD_CONSTRUCT_CONSTRUCTING) != + HALMAC_RET_SUCCESS) + return HALMAC_RET_ERROR_STATE; + + CHANNEL_INFO_SET_CHANNEL(ch_sw_info->ch_info_buf_w, ch_info->channel); + CHANNEL_INFO_SET_PRI_CH_IDX(ch_sw_info->ch_info_buf_w, + ch_info->pri_ch_idx); + CHANNEL_INFO_SET_BANDWIDTH(ch_sw_info->ch_info_buf_w, ch_info->bw); + CHANNEL_INFO_SET_TIMEOUT(ch_sw_info->ch_info_buf_w, ch_info->timeout); + CHANNEL_INFO_SET_ACTION_ID(ch_sw_info->ch_info_buf_w, + ch_info->action_id); + CHANNEL_INFO_SET_CH_EXTRA_INFO(ch_sw_info->ch_info_buf_w, + ch_info->extra_info); + + ch_sw_info->avai_buf_size = ch_sw_info->avai_buf_size - 4; + ch_sw_info->total_size = ch_sw_info->total_size + 4; + ch_sw_info->ch_num++; + ch_sw_info->extra_info_en = ch_info->extra_info; + ch_sw_info->ch_info_buf_w = ch_sw_info->ch_info_buf_w + 4; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "[TRACE]%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_add_extra_ch_info_88xx() -add extra channel information + * @halmac_adapter : the adapter of halmac + * @ch_extra_info : extra channel information + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_add_extra_ch_info_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_ch_extra_info *ch_extra_info) +{ + void *driver_adapter = NULL; + struct halmac_cs_info *ch_sw_info; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_ADD_EXTRA_CH_INFO); + + driver_adapter = halmac_adapter->driver_adapter; + ch_sw_info = &halmac_adapter->ch_sw_info; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "%s ==========>\n", __func__); + + if (!ch_sw_info->ch_info_buf) { + pr_err("%s: NULL==ch_sw_info->ch_info_buf!!\n", __func__); + return HALMAC_RET_CH_SW_SEQ_WRONG; + } + + if (ch_sw_info->extra_info_en == 0) { + pr_err("%s: construct sequence wrong!!\n", __func__); + return HALMAC_RET_CH_SW_SEQ_WRONG; + } + + if (ch_sw_info->avai_buf_size < + (u32)(ch_extra_info->extra_info_size + 2)) { + /* +2: ch_extra_info_id, ch_extra_info, ch_extra_info_size + * are totally 2Byte + */ + pr_err("%s: no available buffer!!\n", __func__); + return HALMAC_RET_CH_SW_NO_BUF; + } + + if (halmac_query_scan_curr_state_88xx(halmac_adapter) != + HALMAC_SCAN_CMD_CONSTRUCT_CONSTRUCTING) { + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "Scan machine fail(add extra ch info)...\n"); + return HALMAC_RET_ERROR_STATE; + } + + if (halmac_transition_scan_state_88xx( + halmac_adapter, HALMAC_SCAN_CMD_CONSTRUCT_CONSTRUCTING) != + HALMAC_RET_SUCCESS) + return HALMAC_RET_ERROR_STATE; + + CH_EXTRA_INFO_SET_CH_EXTRA_INFO_ID(ch_sw_info->ch_info_buf_w, + ch_extra_info->extra_action_id); + CH_EXTRA_INFO_SET_CH_EXTRA_INFO(ch_sw_info->ch_info_buf_w, + ch_extra_info->extra_info); + CH_EXTRA_INFO_SET_CH_EXTRA_INFO_SIZE(ch_sw_info->ch_info_buf_w, + ch_extra_info->extra_info_size); + memcpy(ch_sw_info->ch_info_buf_w + 2, ch_extra_info->extra_info_data, + ch_extra_info->extra_info_size); + + ch_sw_info->avai_buf_size = ch_sw_info->avai_buf_size - + (2 + ch_extra_info->extra_info_size); + ch_sw_info->total_size = + ch_sw_info->total_size + (2 + ch_extra_info->extra_info_size); + ch_sw_info->extra_info_en = ch_extra_info->extra_info; + ch_sw_info->ch_info_buf_w = ch_sw_info->ch_info_buf_w + + (2 + ch_extra_info->extra_info_size); + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_ctrl_ch_switch_88xx() -send channel switch cmd + * @halmac_adapter : the adapter of halmac + * @cs_option : channel switch config + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_ctrl_ch_switch_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_ch_switch_option *cs_option) +{ + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + enum halmac_scan_cmd_construct_state state_scan; + enum halmac_cmd_process_status *process_status = + &halmac_adapter->halmac_state.scan_state_set.process_status; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + if (halmac_fw_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_NO_DLFW; + + if (halmac_adapter->fw_version.h2c_version < 4) + return HALMAC_RET_FW_NO_SUPPORT; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_CTRL_CH_SWITCH); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "%s cs_option->switch_en = %d==========>\n", __func__, + cs_option->switch_en); + + if (!cs_option->switch_en) + *process_status = HALMAC_CMD_PROCESS_IDLE; + + if (*process_status == HALMAC_CMD_PROCESS_SENDING || + *process_status == HALMAC_CMD_PROCESS_RCVD) { + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "Wait event(ctrl ch switch)...\n"); + return HALMAC_RET_BUSY_STATE; + } + + state_scan = halmac_query_scan_curr_state_88xx(halmac_adapter); + if (cs_option->switch_en) { + if (state_scan != HALMAC_SCAN_CMD_CONSTRUCT_CONSTRUCTING) { + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, + DBG_DMESG, + "%s(on) invalid in state %x\n", + __func__, state_scan); + return HALMAC_RET_ERROR_STATE; + } + } else { + if (state_scan != HALMAC_SCAN_CMD_CONSTRUCT_BUFFER_CLEARED) { + HALMAC_RT_TRACE( + driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "%s(off) invalid in state %x\n", __func__, + state_scan); + return HALMAC_RET_ERROR_STATE; + } + } + + status = halmac_func_ctrl_ch_switch_88xx(halmac_adapter, cs_option); + + if (status != HALMAC_RET_SUCCESS) { + pr_err("halmac_ctrl_ch_switch FAIL = %x!!\n", status); + return status; + } + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_clear_ch_info_88xx() -clear channel information + * @halmac_adapter : the adapter of halmac + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_clear_ch_info_88xx(struct halmac_adapter *halmac_adapter) +{ + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_CLEAR_CH_INFO); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "%s ==========>\n", __func__); + + if (halmac_query_scan_curr_state_88xx(halmac_adapter) == + HALMAC_SCAN_CMD_CONSTRUCT_H2C_SENT) { + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "Scan machine fail(clear ch info)...\n"); + return HALMAC_RET_ERROR_STATE; + } + + if (halmac_transition_scan_state_88xx( + halmac_adapter, HALMAC_SCAN_CMD_CONSTRUCT_BUFFER_CLEARED) != + HALMAC_RET_SUCCESS) + return HALMAC_RET_ERROR_STATE; + + kfree(halmac_adapter->ch_sw_info.ch_info_buf); + halmac_adapter->ch_sw_info.ch_info_buf = NULL; + halmac_adapter->ch_sw_info.ch_info_buf_w = NULL; + halmac_adapter->ch_sw_info.extra_info_en = 0; + halmac_adapter->ch_sw_info.buf_size = 0; + halmac_adapter->ch_sw_info.avai_buf_size = 0; + halmac_adapter->ch_sw_info.total_size = 0; + halmac_adapter->ch_sw_info.ch_num = 0; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status halmac_p2pps_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_p2pps *p2p_ps) +{ + void *driver_adapter = NULL; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + if (halmac_fw_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_NO_DLFW; + + if (halmac_adapter->fw_version.h2c_version < 6) + return HALMAC_RET_FW_NO_SUPPORT; + + driver_adapter = halmac_adapter->driver_adapter; + + status = halmac_func_p2pps_88xx(halmac_adapter, p2p_ps); + + if (status != HALMAC_RET_SUCCESS) { + pr_err("[ERR]halmac_p2pps FAIL = %x!!\n", status); + return status; + } + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status +halmac_func_p2pps_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_p2pps *p2p_ps) +{ + u8 h2c_buff[HALMAC_H2C_CMD_SIZE_88XX] = {0}; + u16 h2c_seq_mum = 0; + void *driver_adapter = halmac_adapter->driver_adapter; + struct halmac_api *halmac_api; + struct halmac_h2c_header_info h2c_header_info; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "[TRACE]halmac_p2pps !!\n"); + + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + P2PPS_SET_OFFLOAD_EN(h2c_buff, p2p_ps->offload_en); + P2PPS_SET_ROLE(h2c_buff, p2p_ps->role); + P2PPS_SET_CTWINDOW_EN(h2c_buff, p2p_ps->ctwindow_en); + P2PPS_SET_NOA_EN(h2c_buff, p2p_ps->noa_en); + P2PPS_SET_NOA_SEL(h2c_buff, p2p_ps->noa_sel); + P2PPS_SET_ALLSTASLEEP(h2c_buff, p2p_ps->all_sta_sleep); + P2PPS_SET_DISCOVERY(h2c_buff, p2p_ps->discovery); + P2PPS_SET_P2P_PORT_ID(h2c_buff, p2p_ps->p2p_port_id); + P2PPS_SET_P2P_GROUP(h2c_buff, p2p_ps->p2p_group); + P2PPS_SET_P2P_MACID(h2c_buff, p2p_ps->p2p_macid); + + P2PPS_SET_CTWINDOW_LENGTH(h2c_buff, p2p_ps->ctwindow_length); + + P2PPS_SET_NOA_DURATION_PARA(h2c_buff, p2p_ps->noa_duration_para); + P2PPS_SET_NOA_INTERVAL_PARA(h2c_buff, p2p_ps->noa_interval_para); + P2PPS_SET_NOA_START_TIME_PARA(h2c_buff, p2p_ps->noa_start_time_para); + P2PPS_SET_NOA_COUNT_PARA(h2c_buff, p2p_ps->noa_count_para); + + h2c_header_info.sub_cmd_id = SUB_CMD_ID_P2PPS; + h2c_header_info.content_size = 24; + h2c_header_info.ack = false; + halmac_set_fw_offload_h2c_header_88xx(halmac_adapter, h2c_buff, + &h2c_header_info, &h2c_seq_mum); + + status = halmac_send_h2c_pkt_88xx(halmac_adapter, h2c_buff, + HALMAC_H2C_CMD_SIZE_88XX, false); + + if (status != HALMAC_RET_SUCCESS) + pr_err("[ERR]halmac_send_h2c_p2pps_88xx Fail = %x!!\n", status); + + return status; +} + +/** + * halmac_send_general_info_88xx() -send general information to FW + * @halmac_adapter : the adapter of halmac + * @general_info : general information + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_send_general_info_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_general_info *general_info) +{ + void *driver_adapter = NULL; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + if (halmac_fw_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_NO_DLFW; + + if (halmac_adapter->fw_version.h2c_version < 4) + return HALMAC_RET_FW_NO_SUPPORT; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_SEND_GENERAL_INFO); + + driver_adapter = halmac_adapter->driver_adapter; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "%s ==========>\n", __func__); + + if (halmac_adapter->halmac_state.dlfw_state == HALMAC_DLFW_NONE) { + pr_err("%s Fail due to DLFW NONE!!\n", __func__); + return HALMAC_RET_DLFW_FAIL; + } + + status = halmac_func_send_general_info_88xx(halmac_adapter, + general_info); + + if (status != HALMAC_RET_SUCCESS) { + pr_err("halmac_send_general_info error = %x\n", status); + return status; + } + + if (halmac_adapter->halmac_state.dlfw_state == HALMAC_DLFW_DONE) + halmac_adapter->halmac_state.dlfw_state = HALMAC_GEN_INFO_SENT; + + halmac_adapter->gen_info_valid = true; + memcpy(&halmac_adapter->general_info, general_info, + sizeof(struct halmac_general_info)); + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_start_iqk_88xx() -trigger FW IQK + * @halmac_adapter : the adapter of halmac + * @iqk_para : IQK parameter + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_start_iqk_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_iqk_para_ *iqk_para) +{ + u8 h2c_buff[HALMAC_H2C_CMD_SIZE_88XX] = {0}; + u16 h2c_seq_num = 0; + void *driver_adapter = NULL; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + struct halmac_h2c_header_info h2c_header_info; + enum halmac_cmd_process_status *process_status = + &halmac_adapter->halmac_state.iqk_set.process_status; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + if (halmac_fw_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_NO_DLFW; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_START_IQK); + + driver_adapter = halmac_adapter->driver_adapter; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "%s ==========>\n", __func__); + + if (*process_status == HALMAC_CMD_PROCESS_SENDING) { + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "Wait event(iqk)...\n"); + return HALMAC_RET_BUSY_STATE; + } + + *process_status = HALMAC_CMD_PROCESS_SENDING; + + IQK_SET_CLEAR(h2c_buff, iqk_para->clear); + IQK_SET_SEGMENT_IQK(h2c_buff, iqk_para->segment_iqk); + + h2c_header_info.sub_cmd_id = SUB_CMD_ID_IQK; + h2c_header_info.content_size = 1; + h2c_header_info.ack = true; + halmac_set_fw_offload_h2c_header_88xx(halmac_adapter, h2c_buff, + &h2c_header_info, &h2c_seq_num); + + halmac_adapter->halmac_state.iqk_set.seq_num = h2c_seq_num; + + status = halmac_send_h2c_pkt_88xx(halmac_adapter, h2c_buff, + HALMAC_H2C_CMD_SIZE_88XX, true); + + if (status != HALMAC_RET_SUCCESS) { + pr_err("halmac_send_h2c_pkt_88xx Fail = %x!!\n", status); + return status; + } + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_ctrl_pwr_tracking_88xx() -trigger FW power tracking + * @halmac_adapter : the adapter of halmac + * @pwr_tracking_opt : power tracking option + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status halmac_ctrl_pwr_tracking_88xx( + struct halmac_adapter *halmac_adapter, + struct halmac_pwr_tracking_option *pwr_tracking_opt) +{ + u8 h2c_buff[HALMAC_H2C_CMD_SIZE_88XX] = {0}; + u16 h2c_seq_mum = 0; + void *driver_adapter = NULL; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + struct halmac_h2c_header_info h2c_header_info; + enum halmac_cmd_process_status *process_status = + &halmac_adapter->halmac_state.power_tracking_set.process_status; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + if (halmac_fw_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_NO_DLFW; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_CTRL_PWR_TRACKING); + + driver_adapter = halmac_adapter->driver_adapter; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "halmac_start_iqk_88xx ==========>\n"); + + if (*process_status == HALMAC_CMD_PROCESS_SENDING) { + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "Wait event(pwr tracking)...\n"); + return HALMAC_RET_BUSY_STATE; + } + + *process_status = HALMAC_CMD_PROCESS_SENDING; + + POWER_TRACKING_SET_TYPE(h2c_buff, pwr_tracking_opt->type); + POWER_TRACKING_SET_BBSWING_INDEX(h2c_buff, + pwr_tracking_opt->bbswing_index); + POWER_TRACKING_SET_ENABLE_A( + h2c_buff, + pwr_tracking_opt->pwr_tracking_para[HALMAC_RF_PATH_A].enable); + POWER_TRACKING_SET_TX_PWR_INDEX_A( + h2c_buff, pwr_tracking_opt->pwr_tracking_para[HALMAC_RF_PATH_A] + .tx_pwr_index); + POWER_TRACKING_SET_PWR_TRACKING_OFFSET_VALUE_A( + h2c_buff, pwr_tracking_opt->pwr_tracking_para[HALMAC_RF_PATH_A] + .pwr_tracking_offset_value); + POWER_TRACKING_SET_TSSI_VALUE_A( + h2c_buff, pwr_tracking_opt->pwr_tracking_para[HALMAC_RF_PATH_A] + .tssi_value); + POWER_TRACKING_SET_ENABLE_B( + h2c_buff, + pwr_tracking_opt->pwr_tracking_para[HALMAC_RF_PATH_B].enable); + POWER_TRACKING_SET_TX_PWR_INDEX_B( + h2c_buff, pwr_tracking_opt->pwr_tracking_para[HALMAC_RF_PATH_B] + .tx_pwr_index); + POWER_TRACKING_SET_PWR_TRACKING_OFFSET_VALUE_B( + h2c_buff, pwr_tracking_opt->pwr_tracking_para[HALMAC_RF_PATH_B] + .pwr_tracking_offset_value); + POWER_TRACKING_SET_TSSI_VALUE_B( + h2c_buff, pwr_tracking_opt->pwr_tracking_para[HALMAC_RF_PATH_B] + .tssi_value); + POWER_TRACKING_SET_ENABLE_C( + h2c_buff, + pwr_tracking_opt->pwr_tracking_para[HALMAC_RF_PATH_C].enable); + POWER_TRACKING_SET_TX_PWR_INDEX_C( + h2c_buff, pwr_tracking_opt->pwr_tracking_para[HALMAC_RF_PATH_C] + .tx_pwr_index); + POWER_TRACKING_SET_PWR_TRACKING_OFFSET_VALUE_C( + h2c_buff, pwr_tracking_opt->pwr_tracking_para[HALMAC_RF_PATH_C] + .pwr_tracking_offset_value); + POWER_TRACKING_SET_TSSI_VALUE_C( + h2c_buff, pwr_tracking_opt->pwr_tracking_para[HALMAC_RF_PATH_C] + .tssi_value); + POWER_TRACKING_SET_ENABLE_D( + h2c_buff, + pwr_tracking_opt->pwr_tracking_para[HALMAC_RF_PATH_D].enable); + POWER_TRACKING_SET_TX_PWR_INDEX_D( + h2c_buff, pwr_tracking_opt->pwr_tracking_para[HALMAC_RF_PATH_D] + .tx_pwr_index); + POWER_TRACKING_SET_PWR_TRACKING_OFFSET_VALUE_D( + h2c_buff, pwr_tracking_opt->pwr_tracking_para[HALMAC_RF_PATH_D] + .pwr_tracking_offset_value); + POWER_TRACKING_SET_TSSI_VALUE_D( + h2c_buff, pwr_tracking_opt->pwr_tracking_para[HALMAC_RF_PATH_D] + .tssi_value); + + h2c_header_info.sub_cmd_id = SUB_CMD_ID_POWER_TRACKING; + h2c_header_info.content_size = 20; + h2c_header_info.ack = true; + halmac_set_fw_offload_h2c_header_88xx(halmac_adapter, h2c_buff, + &h2c_header_info, &h2c_seq_mum); + + halmac_adapter->halmac_state.power_tracking_set.seq_num = h2c_seq_mum; + + status = halmac_send_h2c_pkt_88xx(halmac_adapter, h2c_buff, + HALMAC_H2C_CMD_SIZE_88XX, true); + + if (status != HALMAC_RET_SUCCESS) { + pr_err("halmac_send_h2c_pkt_88xx Fail = %x!!\n", status); + return status; + } + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "halmac_start_iqk_88xx <==========\n"); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_query_status_88xx() -query the offload feature status + * @halmac_adapter : the adapter of halmac + * @feature_id : feature_id + * @process_status : feature_status + * @data : data buffer + * @size : data size + * + * Note : + * If user wants to know the data size, use can allocate zero + * size buffer first. If this size less than the data size, halmac + * will return HALMAC_RET_BUFFER_TOO_SMALL. User need to + * re-allocate data buffer with correct data size. + * + * Author : Ivan Lin/KaiYuan Chang + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_query_status_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_feature_id feature_id, + enum halmac_cmd_process_status *process_status, + u8 *data, u32 *size) +{ + void *driver_adapter = NULL; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_QUERY_STATE); + + driver_adapter = halmac_adapter->driver_adapter; + + if (!process_status) { + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "null pointer!!\n"); + return HALMAC_RET_NULL_POINTER; + } + + switch (feature_id) { + case HALMAC_FEATURE_CFG_PARA: + status = halmac_query_cfg_para_status_88xx( + halmac_adapter, process_status, data, size); + break; + case HALMAC_FEATURE_DUMP_PHYSICAL_EFUSE: + status = halmac_query_dump_physical_efuse_status_88xx( + halmac_adapter, process_status, data, size); + break; + case HALMAC_FEATURE_DUMP_LOGICAL_EFUSE: + status = halmac_query_dump_logical_efuse_status_88xx( + halmac_adapter, process_status, data, size); + break; + case HALMAC_FEATURE_CHANNEL_SWITCH: + status = halmac_query_channel_switch_status_88xx( + halmac_adapter, process_status, data, size); + break; + case HALMAC_FEATURE_UPDATE_PACKET: + status = halmac_query_update_packet_status_88xx( + halmac_adapter, process_status, data, size); + break; + case HALMAC_FEATURE_IQK: + status = halmac_query_iqk_status_88xx( + halmac_adapter, process_status, data, size); + break; + case HALMAC_FEATURE_POWER_TRACKING: + status = halmac_query_power_tracking_status_88xx( + halmac_adapter, process_status, data, size); + break; + case HALMAC_FEATURE_PSD: + status = halmac_query_psd_status_88xx( + halmac_adapter, process_status, data, size); + break; + default: + pr_err("%s invalid feature id %d\n", __func__, + feature_id); + return HALMAC_RET_INVALID_FEATURE_ID; + } + + return status; +} + +/** + * halmac_reset_feature_88xx() -reset async api cmd status + * @halmac_adapter : the adapter of halmac + * @feature_id : feature_id + * Author : Ivan Lin/KaiYuan Chang + * Return : enum halmac_ret_status. + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_reset_feature_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_feature_id feature_id) +{ + void *driver_adapter = NULL; + struct halmac_state *state = &halmac_adapter->halmac_state; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_RESET_FEATURE); + + driver_adapter = halmac_adapter->driver_adapter; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "%s ==========>\n", __func__); + + switch (feature_id) { + case HALMAC_FEATURE_CFG_PARA: + state->cfg_para_state_set.process_status = + HALMAC_CMD_PROCESS_IDLE; + state->cfg_para_state_set.cfg_para_cmd_construct_state = + HALMAC_CFG_PARA_CMD_CONSTRUCT_IDLE; + break; + case HALMAC_FEATURE_DUMP_PHYSICAL_EFUSE: + case HALMAC_FEATURE_DUMP_LOGICAL_EFUSE: + state->efuse_state_set.process_status = HALMAC_CMD_PROCESS_IDLE; + state->efuse_state_set.efuse_cmd_construct_state = + HALMAC_EFUSE_CMD_CONSTRUCT_IDLE; + break; + case HALMAC_FEATURE_CHANNEL_SWITCH: + state->scan_state_set.process_status = HALMAC_CMD_PROCESS_IDLE; + state->scan_state_set.scan_cmd_construct_state = + HALMAC_SCAN_CMD_CONSTRUCT_IDLE; + break; + case HALMAC_FEATURE_UPDATE_PACKET: + state->update_packet_set.process_status = + HALMAC_CMD_PROCESS_IDLE; + break; + case HALMAC_FEATURE_ALL: + state->cfg_para_state_set.process_status = + HALMAC_CMD_PROCESS_IDLE; + state->cfg_para_state_set.cfg_para_cmd_construct_state = + HALMAC_CFG_PARA_CMD_CONSTRUCT_IDLE; + state->efuse_state_set.process_status = HALMAC_CMD_PROCESS_IDLE; + state->efuse_state_set.efuse_cmd_construct_state = + HALMAC_EFUSE_CMD_CONSTRUCT_IDLE; + state->scan_state_set.process_status = HALMAC_CMD_PROCESS_IDLE; + state->scan_state_set.scan_cmd_construct_state = + HALMAC_SCAN_CMD_CONSTRUCT_IDLE; + state->update_packet_set.process_status = + HALMAC_CMD_PROCESS_IDLE; + break; + default: + pr_err("%s invalid feature id %d\n", __func__, + feature_id); + return HALMAC_RET_INVALID_FEATURE_ID; + } + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_check_fw_status_88xx() -check fw status + * @halmac_adapter : the adapter of halmac + * @fw_status : fw status + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_check_fw_status_88xx(struct halmac_adapter *halmac_adapter, + bool *fw_status) +{ + u32 value32 = 0, value32_backup = 0, i = 0; + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_CHECK_FW_STATUS); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "%s ==========>\n", __func__); + + value32 = PLATFORM_REG_READ_32(driver_adapter, REG_FW_DBG6); + + if (value32 != 0) { + pr_err("halmac_check_fw_status REG_FW_DBG6 !=0\n"); + *fw_status = false; + return status; + } + + value32_backup = PLATFORM_REG_READ_32(driver_adapter, REG_FW_DBG7); + + for (i = 0; i <= 10; i++) { + value32 = PLATFORM_REG_READ_32(driver_adapter, REG_FW_DBG7); + if (value32_backup != value32) + break; + + if (i == 10) { + pr_err("halmac_check_fw_status Polling FW PC fail\n"); + *fw_status = false; + return status; + } + } + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "%s <==========\n", __func__); + + return status; +} + +enum halmac_ret_status +halmac_dump_fw_dmem_88xx(struct halmac_adapter *halmac_adapter, u8 *dmem, + u32 *size) +{ + void *driver_adapter = NULL; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_DUMP_FW_DMEM); + + driver_adapter = halmac_adapter->driver_adapter; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "%s ==========>\n", __func__); + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "%s <==========\n", __func__); + + return status; +} + +/** + * halmac_cfg_max_dl_size_88xx() - config max download FW size + * @halmac_adapter : the adapter of halmac + * @size : max download fw size + * + * Halmac uses this setting to set max packet size for + * download FW. + * If user has not called this API, halmac use default + * setting for download FW + * Note1 : size need multiple of 2 + * Note2 : max size is 31K + * + * Author : Ivan Lin/KaiYuan Chang + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_cfg_max_dl_size_88xx(struct halmac_adapter *halmac_adapter, u32 size) +{ + void *driver_adapter = NULL; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_CFG_MAX_DL_SIZE); + + driver_adapter = halmac_adapter->driver_adapter; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_FW, DBG_DMESG, + "%s ==========>\n", __func__); + + if (size > HALMAC_FW_CFG_MAX_DL_SIZE_MAX_88XX) { + pr_err("size > HALMAC_FW_CFG_MAX_DL_SIZE_MAX!\n"); + return HALMAC_RET_CFG_DLFW_SIZE_FAIL; + } + + if ((size & (2 - 1)) != 0) { + pr_err("size is not power of 2!\n"); + return HALMAC_RET_CFG_DLFW_SIZE_FAIL; + } + + halmac_adapter->max_download_size = size; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_FW, DBG_DMESG, + "Cfg max size is : %X\n", size); + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_FW, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_psd_88xx() - trigger fw psd + * @halmac_adapter : the adapter of halmac + * @start_psd : start PSD + * @end_psd : end PSD + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status halmac_psd_88xx(struct halmac_adapter *halmac_adapter, + u16 start_psd, u16 end_psd) +{ + u8 h2c_buff[HALMAC_H2C_CMD_SIZE_88XX] = {0}; + u16 h2c_seq_mum = 0; + void *driver_adapter = NULL; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + struct halmac_h2c_header_info h2c_header_info; + enum halmac_cmd_process_status *process_status = + &halmac_adapter->halmac_state.psd_set.process_status; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + if (halmac_fw_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_NO_DLFW; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_PSD); + + driver_adapter = halmac_adapter->driver_adapter; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "%s ==========>\n", __func__); + + if (*process_status == HALMAC_CMD_PROCESS_SENDING) { + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "Wait event(psd)...\n"); + return HALMAC_RET_BUSY_STATE; + } + + kfree(halmac_adapter->halmac_state.psd_set.data); + halmac_adapter->halmac_state.psd_set.data = (u8 *)NULL; + + halmac_adapter->halmac_state.psd_set.data_size = 0; + halmac_adapter->halmac_state.psd_set.segment_size = 0; + + *process_status = HALMAC_CMD_PROCESS_SENDING; + + PSD_SET_START_PSD(h2c_buff, start_psd); + PSD_SET_END_PSD(h2c_buff, end_psd); + + h2c_header_info.sub_cmd_id = SUB_CMD_ID_PSD; + h2c_header_info.content_size = 4; + h2c_header_info.ack = true; + halmac_set_fw_offload_h2c_header_88xx(halmac_adapter, h2c_buff, + &h2c_header_info, &h2c_seq_mum); + + status = halmac_send_h2c_pkt_88xx(halmac_adapter, h2c_buff, + HALMAC_H2C_CMD_SIZE_88XX, true); + + if (status != HALMAC_RET_SUCCESS) { + pr_err("halmac_send_h2c_pkt_88xx Fail = %x!!\n", status); + return status; + } + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_cfg_la_mode_88xx() - config la mode + * @halmac_adapter : the adapter of halmac + * @la_mode : + * disable : no TXFF space reserved for LA debug + * partial : partial TXFF space is reserved for LA debug + * full : all TXFF space is reserved for LA debug + * Author : KaiYuan Chang + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_cfg_la_mode_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_la_mode la_mode) +{ + void *driver_adapter = NULL; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_CFG_LA_MODE); + + driver_adapter = halmac_adapter->driver_adapter; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "%s ==========>la_mode = %d\n", __func__, + la_mode); + + halmac_adapter->txff_allocation.la_mode = la_mode; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_cfg_rx_fifo_expanding_mode_88xx() - rx fifo expanding + * @halmac_adapter : the adapter of halmac + * @la_mode : + * disable : normal mode + * 1 block : Rx FIFO + 1 FIFO block; Tx fifo - 1 FIFO block + * 2 block : Rx FIFO + 2 FIFO block; Tx fifo - 2 FIFO block + * 3 block : Rx FIFO + 3 FIFO block; Tx fifo - 3 FIFO block + * Author : Soar + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status halmac_cfg_rx_fifo_expanding_mode_88xx( + struct halmac_adapter *halmac_adapter, + enum halmac_rx_fifo_expanding_mode rx_fifo_expanding_mode) +{ + void *driver_adapter = NULL; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, + HALMAC_API_CFG_RX_FIFO_EXPANDING_MODE); + + driver_adapter = halmac_adapter->driver_adapter; + + HALMAC_RT_TRACE( + driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "%s ==========>rx_fifo_expanding_mode = %d\n", __func__, + rx_fifo_expanding_mode); + + halmac_adapter->txff_allocation.rx_fifo_expanding_mode = + rx_fifo_expanding_mode; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status +halmac_config_security_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_security_setting *sec_setting) +{ + struct halmac_api *halmac_api; + void *driver_adapter = NULL; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + driver_adapter = halmac_adapter->driver_adapter; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_COMMON, DBG_DMESG, + "%s ==========>\n", __func__); + + HALMAC_REG_WRITE_16(halmac_adapter, REG_CR, + (u16)(HALMAC_REG_READ_16(halmac_adapter, REG_CR) | + BIT_MAC_SEC_EN)); + + if (sec_setting->tx_encryption == 1) + HALMAC_REG_WRITE_8( + halmac_adapter, REG_SECCFG, + HALMAC_REG_READ_8(halmac_adapter, REG_SECCFG) | BIT(2)); + else + HALMAC_REG_WRITE_8( + halmac_adapter, REG_SECCFG, + HALMAC_REG_READ_8(halmac_adapter, REG_SECCFG) & + ~(BIT(2))); + + if (sec_setting->rx_decryption == 1) + HALMAC_REG_WRITE_8( + halmac_adapter, REG_SECCFG, + HALMAC_REG_READ_8(halmac_adapter, REG_SECCFG) | BIT(3)); + else + HALMAC_REG_WRITE_8( + halmac_adapter, REG_SECCFG, + HALMAC_REG_READ_8(halmac_adapter, REG_SECCFG) & + ~(BIT(3))); + + if (sec_setting->bip_enable == 1) { + if (halmac_adapter->chip_id == HALMAC_CHIP_ID_8822B) + return HALMAC_RET_BIP_NO_SUPPORT; + } + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_COMMON, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +u8 halmac_get_used_cam_entry_num_88xx(struct halmac_adapter *halmac_adapter, + enum hal_security_type sec_type) +{ + u8 entry_num; + void *driver_adapter = NULL; + + driver_adapter = halmac_adapter->driver_adapter; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_COMMON, DBG_DMESG, + "%s ==========>\n", __func__); + + switch (sec_type) { + case HAL_SECURITY_TYPE_WEP40: + case HAL_SECURITY_TYPE_WEP104: + case HAL_SECURITY_TYPE_TKIP: + case HAL_SECURITY_TYPE_AES128: + case HAL_SECURITY_TYPE_GCMP128: + case HAL_SECURITY_TYPE_GCMSMS4: + case HAL_SECURITY_TYPE_BIP: + entry_num = 1; + break; + case HAL_SECURITY_TYPE_WAPI: + case HAL_SECURITY_TYPE_AES256: + case HAL_SECURITY_TYPE_GCMP256: + entry_num = 2; + break; + default: + entry_num = 0; + break; + } + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_COMMON, DBG_DMESG, + "%s <==========\n", __func__); + + return entry_num; +} + +enum halmac_ret_status +halmac_write_cam_88xx(struct halmac_adapter *halmac_adapter, u32 entry_index, + struct halmac_cam_entry_info *cam_entry_info) +{ + u32 i; + u32 command = 0x80010000; + struct halmac_api *halmac_api; + void *driver_adapter = NULL; + struct halmac_cam_entry_format *cam_entry_format = NULL; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_COMMON, DBG_DMESG, + "[TRACE]%s ==========>\n", __func__); + + if (entry_index >= halmac_adapter->hw_config_info.cam_entry_num) + return HALMAC_RET_ENTRY_INDEX_ERROR; + + if (cam_entry_info->key_id > 3) + return HALMAC_RET_FAIL; + + cam_entry_format = kzalloc(sizeof(*cam_entry_format), GFP_KERNEL); + if (!cam_entry_format) + return HALMAC_RET_NULL_POINTER; + + cam_entry_format->key_id = cam_entry_info->key_id; + cam_entry_format->valid = cam_entry_info->valid; + memcpy(cam_entry_format->mac_address, cam_entry_info->mac_address, 6); + memcpy(cam_entry_format->key, cam_entry_info->key, 16); + + switch (cam_entry_info->security_type) { + case HAL_SECURITY_TYPE_NONE: + cam_entry_format->type = 0; + break; + case HAL_SECURITY_TYPE_WEP40: + cam_entry_format->type = 1; + break; + case HAL_SECURITY_TYPE_WEP104: + cam_entry_format->type = 5; + break; + case HAL_SECURITY_TYPE_TKIP: + cam_entry_format->type = 2; + break; + case HAL_SECURITY_TYPE_AES128: + cam_entry_format->type = 4; + break; + case HAL_SECURITY_TYPE_WAPI: + cam_entry_format->type = 6; + break; + case HAL_SECURITY_TYPE_AES256: + cam_entry_format->type = 4; + cam_entry_format->ext_sectype = 1; + break; + case HAL_SECURITY_TYPE_GCMP128: + cam_entry_format->type = 7; + break; + case HAL_SECURITY_TYPE_GCMP256: + case HAL_SECURITY_TYPE_GCMSMS4: + cam_entry_format->type = 7; + cam_entry_format->ext_sectype = 1; + break; + case HAL_SECURITY_TYPE_BIP: + cam_entry_format->type = cam_entry_info->unicast == 1 ? 4 : 0; + cam_entry_format->mgnt = 1; + cam_entry_format->grp = cam_entry_info->unicast == 1 ? 0 : 1; + break; + default: + kfree(cam_entry_format); + return HALMAC_RET_FAIL; + } + + for (i = 0; i < 8; i++) { + HALMAC_REG_WRITE_32(halmac_adapter, REG_CAMWRITE, + *((u32 *)cam_entry_format + i)); + HALMAC_REG_WRITE_32(halmac_adapter, REG_CAMCMD, + command | ((entry_index << 3) + i)); + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_COMMON, DBG_DMESG, + "[TRACE]1 - CAM entry format : %X\n", + *((u32 *)cam_entry_format + i)); + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_COMMON, DBG_DMESG, + "[TRACE]1 - REG_CAMCMD : %X\n", + command | ((entry_index << 3) + i)); + } + + if (cam_entry_info->security_type == HAL_SECURITY_TYPE_WAPI || + cam_entry_info->security_type == HAL_SECURITY_TYPE_AES256 || + cam_entry_info->security_type == HAL_SECURITY_TYPE_GCMP256 || + cam_entry_info->security_type == HAL_SECURITY_TYPE_GCMSMS4) { + cam_entry_format->mic = 1; + memcpy(cam_entry_format->key, cam_entry_info->key_ext, 16); + + for (i = 0; i < 8; i++) { + HALMAC_REG_WRITE_32(halmac_adapter, REG_CAMWRITE, + *((u32 *)cam_entry_format + i)); + HALMAC_REG_WRITE_32( + halmac_adapter, REG_CAMCMD, + command | (((entry_index + 1) << 3) + i)); + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_COMMON, + DBG_DMESG, + "[TRACE]2 - CAM entry format : %X\n", + *((u32 *)cam_entry_format + i)); + HALMAC_RT_TRACE( + driver_adapter, HALMAC_MSG_COMMON, DBG_DMESG, + "[TRACE]2 - REG_CAMCMD : %X\n", + command | (((entry_index + 1) << 3) + i)); + } + } + + kfree(cam_entry_format); + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_COMMON, DBG_DMESG, + "[TRACE]%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status +halmac_read_cam_entry_88xx(struct halmac_adapter *halmac_adapter, + u32 entry_index, + struct halmac_cam_entry_format *content) +{ + u32 i; + u32 command = 0x80000000; + struct halmac_api *halmac_api; + void *driver_adapter = NULL; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_COMMON, DBG_DMESG, + "%s ==========>\n", __func__); + + if (entry_index >= halmac_adapter->hw_config_info.cam_entry_num) + return HALMAC_RET_ENTRY_INDEX_ERROR; + + for (i = 0; i < 8; i++) { + HALMAC_REG_WRITE_32(halmac_adapter, REG_CAMCMD, + command | ((entry_index << 3) + i)); + *((u32 *)content + i) = + HALMAC_REG_READ_32(halmac_adapter, REG_CAMREAD); + } + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_COMMON, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status +halmac_clear_cam_entry_88xx(struct halmac_adapter *halmac_adapter, + u32 entry_index) +{ + u32 i; + u32 command = 0x80010000; + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + struct halmac_cam_entry_format *cam_entry_format; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "[TRACE]halmac_clear_security_cam_88xx ==========>\n"); + + if (entry_index >= halmac_adapter->hw_config_info.cam_entry_num) + return HALMAC_RET_ENTRY_INDEX_ERROR; + + cam_entry_format = kzalloc(sizeof(*cam_entry_format), GFP_KERNEL); + if (!cam_entry_format) + return HALMAC_RET_NULL_POINTER; + + for (i = 0; i < 8; i++) { + HALMAC_REG_WRITE_32(halmac_adapter, REG_CAMWRITE, + *((u32 *)cam_entry_format + i)); + HALMAC_REG_WRITE_32(halmac_adapter, REG_CAMCMD, + command | ((entry_index << 3) + i)); + } + + kfree(cam_entry_format); + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "[TRACE]halmac_clear_security_cam_88xx <==========\n"); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_get_hw_value_88xx() -get hw config value + * @halmac_adapter : the adapter of halmac + * @hw_id : hw id for driver to query + * @pvalue : hw value, reference table to get data type + * Author : KaiYuan Chang / Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_get_hw_value_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_hw_id hw_id, void *pvalue) +{ + void *driver_adapter = NULL; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_GET_HW_VALUE); + + driver_adapter = halmac_adapter->driver_adapter; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "%s ==========>\n", __func__); + + if (!pvalue) { + pr_err("%s (!pvalue)==========>\n", __func__); + return HALMAC_RET_NULL_POINTER; + } + + switch (hw_id) { + case HALMAC_HW_RQPN_MAPPING: + ((struct halmac_rqpn_map *)pvalue)->dma_map_vo = + halmac_adapter->halmac_ptcl_queue[HALMAC_PTCL_QUEUE_VO]; + ((struct halmac_rqpn_map *)pvalue)->dma_map_vi = + halmac_adapter->halmac_ptcl_queue[HALMAC_PTCL_QUEUE_VI]; + ((struct halmac_rqpn_map *)pvalue)->dma_map_be = + halmac_adapter->halmac_ptcl_queue[HALMAC_PTCL_QUEUE_BE]; + ((struct halmac_rqpn_map *)pvalue)->dma_map_bk = + halmac_adapter->halmac_ptcl_queue[HALMAC_PTCL_QUEUE_BK]; + ((struct halmac_rqpn_map *)pvalue)->dma_map_mg = + halmac_adapter->halmac_ptcl_queue[HALMAC_PTCL_QUEUE_MG]; + ((struct halmac_rqpn_map *)pvalue)->dma_map_hi = + halmac_adapter->halmac_ptcl_queue[HALMAC_PTCL_QUEUE_HI]; + break; + case HALMAC_HW_EFUSE_SIZE: + *(u32 *)pvalue = halmac_adapter->hw_config_info.efuse_size; + break; + case HALMAC_HW_EEPROM_SIZE: + *(u32 *)pvalue = halmac_adapter->hw_config_info.eeprom_size; + break; + case HALMAC_HW_BT_BANK_EFUSE_SIZE: + *(u32 *)pvalue = halmac_adapter->hw_config_info.bt_efuse_size; + break; + case HALMAC_HW_BT_BANK1_EFUSE_SIZE: + case HALMAC_HW_BT_BANK2_EFUSE_SIZE: + *(u32 *)pvalue = 0; + break; + case HALMAC_HW_TXFIFO_SIZE: + *(u32 *)pvalue = halmac_adapter->hw_config_info.tx_fifo_size; + break; + case HALMAC_HW_RSVD_PG_BNDY: + *(u16 *)pvalue = + halmac_adapter->txff_allocation.rsvd_drv_pg_bndy; + break; + case HALMAC_HW_CAM_ENTRY_NUM: + *(u8 *)pvalue = halmac_adapter->hw_config_info.cam_entry_num; + break; + case HALMAC_HW_WLAN_EFUSE_AVAILABLE_SIZE: /*Remove later*/ + status = halmac_dump_logical_efuse_map_88xx(halmac_adapter, + HALMAC_EFUSE_R_DRV); + if (status != HALMAC_RET_SUCCESS) + return status; + *(u32 *)pvalue = halmac_adapter->hw_config_info.efuse_size - + HALMAC_PROTECTED_EFUSE_SIZE_88XX - + halmac_adapter->efuse_end; + break; + case HALMAC_HW_IC_VERSION: + *(u8 *)pvalue = halmac_adapter->chip_version; + break; + case HALMAC_HW_PAGE_SIZE: + *(u32 *)pvalue = halmac_adapter->hw_config_info.page_size; + break; + case HALMAC_HW_TX_AGG_ALIGN_SIZE: + *(u16 *)pvalue = halmac_adapter->hw_config_info.tx_align_size; + break; + case HALMAC_HW_RX_AGG_ALIGN_SIZE: + *(u8 *)pvalue = 8; + break; + case HALMAC_HW_DRV_INFO_SIZE: + *(u8 *)pvalue = halmac_adapter->drv_info_size; + break; + case HALMAC_HW_TXFF_ALLOCATION: + memcpy(pvalue, &halmac_adapter->txff_allocation, + sizeof(struct halmac_txff_allocation)); + break; + case HALMAC_HW_TX_DESC_SIZE: + *(u32 *)pvalue = halmac_adapter->hw_config_info.txdesc_size; + break; + case HALMAC_HW_RX_DESC_SIZE: + *(u32 *)pvalue = halmac_adapter->hw_config_info.rxdesc_size; + break; + default: + return HALMAC_RET_PARA_NOT_SUPPORT; + } + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_set_hw_value_88xx() -set hw config value + * @halmac_adapter : the adapter of halmac + * @hw_id : hw id for driver to config + * @pvalue : hw value, reference table to get data type + * Author : KaiYuan Chang / Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_set_hw_value_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_hw_id hw_id, void *pvalue) +{ + void *driver_adapter = NULL; + enum halmac_ret_status status; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_GET_HW_VALUE); + + driver_adapter = halmac_adapter->driver_adapter; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "%s ==========>\n", __func__); + + if (!pvalue) { + pr_err("%s (!pvalue)==========>\n", __func__); + return HALMAC_RET_NULL_POINTER; + } + + switch (hw_id) { + case HALMAC_HW_USB_MODE: + status = halmac_set_usb_mode_88xx( + halmac_adapter, *(enum halmac_usb_mode *)pvalue); + if (status != HALMAC_RET_SUCCESS) + return status; + break; + case HALMAC_HW_SEQ_EN: + break; + case HALMAC_HW_BANDWIDTH: + halmac_cfg_bw_88xx(halmac_adapter, *(enum halmac_bw *)pvalue); + break; + case HALMAC_HW_CHANNEL: + halmac_cfg_ch_88xx(halmac_adapter, *(u8 *)pvalue); + break; + case HALMAC_HW_PRI_CHANNEL_IDX: + halmac_cfg_pri_ch_idx_88xx(halmac_adapter, + *(enum halmac_pri_ch_idx *)pvalue); + break; + case HALMAC_HW_EN_BB_RF: + halmac_enable_bb_rf_88xx(halmac_adapter, *(u8 *)pvalue); + break; + case HALMAC_HW_SDIO_TX_PAGE_THRESHOLD: + halmac_config_sdio_tx_page_threshold_88xx( + halmac_adapter, + (struct halmac_tx_page_threshold_info *)pvalue); + break; + case HALMAC_HW_AMPDU_CONFIG: + halmac_config_ampdu_88xx(halmac_adapter, + (struct halmac_ampdu_config *)pvalue); + break; + default: + return HALMAC_RET_PARA_NOT_SUPPORT; + } + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_cfg_drv_rsvd_pg_num_88xx() -config reserved page number for driver + * @halmac_adapter : the adapter of halmac + * @pg_num : page number + * Author : KaiYuan Chang + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_cfg_drv_rsvd_pg_num_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_drv_rsvd_pg_num pg_num) +{ + void *driver_adapter = NULL; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, + HALMAC_API_CFG_DRV_RSVD_PG_NUM); + + driver_adapter = halmac_adapter->driver_adapter; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "%s ==========>pg_num = %d\n", __func__, + pg_num); + + switch (pg_num) { + case HALMAC_RSVD_PG_NUM16: + halmac_adapter->txff_allocation.rsvd_drv_pg_num = 16; + break; + case HALMAC_RSVD_PG_NUM24: + halmac_adapter->txff_allocation.rsvd_drv_pg_num = 24; + break; + case HALMAC_RSVD_PG_NUM32: + halmac_adapter->txff_allocation.rsvd_drv_pg_num = 32; + break; + } + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status +halmac_get_chip_version_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_ver *version) +{ + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "%s ==========>\n", __func__); + version->major_ver = (u8)HALMAC_MAJOR_VER_88XX; + version->prototype_ver = (u8)HALMAC_PROTOTYPE_VER_88XX; + version->minor_ver = (u8)HALMAC_MINOR_VER_88XX; + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_chk_txdesc_88xx() -check if the tx packet format is incorrect + * @halmac_adapter : the adapter of halmac + * @halmac_buf : tx Packet buffer, tx desc is included + * @halmac_size : tx packet size + * Author : KaiYuan Chang + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_chk_txdesc_88xx(struct halmac_adapter *halmac_adapter, u8 *halmac_buf, + u32 halmac_size) +{ + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s ==========>\n", __func__); + + if (GET_TX_DESC_BMC(halmac_buf)) + if (GET_TX_DESC_AGG_EN(halmac_buf)) + pr_err("TxDesc: Agg should not be set when BMC\n"); + + if (halmac_size < (GET_TX_DESC_TXPKTSIZE(halmac_buf) + + GET_TX_DESC_OFFSET(halmac_buf))) + pr_err("TxDesc: PktSize too small\n"); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_dl_drv_rsvd_page_88xx() - download packet to rsvd page + * @halmac_adapter : the adapter of halmac + * @pg_offset : page offset of driver's rsvd page + * @halmac_buf : data to be downloaded, tx_desc is not included + * @halmac_size : data size to be downloaded + * Author : KaiYuan Chang + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_dl_drv_rsvd_page_88xx(struct halmac_adapter *halmac_adapter, + u8 pg_offset, u8 *halmac_buf, u32 halmac_size) +{ + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + enum halmac_ret_status ret_status; + u16 drv_pg_bndy = 0; + u32 dl_pg_num = 0; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_DL_DRV_RSVD_PG); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s ==========>\n", __func__); + + /*check boundary and size valid*/ + dl_pg_num = halmac_size / halmac_adapter->hw_config_info.page_size + + ((halmac_size & + (halmac_adapter->hw_config_info.page_size - 1)) ? + 1 : + 0); + if (pg_offset + dl_pg_num > + halmac_adapter->txff_allocation.rsvd_drv_pg_num) { + pr_err("[ERROR] driver download offset or size error ==========>\n"); + return HALMAC_RET_DRV_DL_ERR; + } + + /*update to target download boundary*/ + drv_pg_bndy = + halmac_adapter->txff_allocation.rsvd_drv_pg_bndy + pg_offset; + HALMAC_REG_WRITE_16(halmac_adapter, REG_FIFOPAGE_CTRL_2, + (u16)(drv_pg_bndy & BIT_MASK_BCN_HEAD_1_V1)); + + ret_status = halmac_download_rsvd_page_88xx(halmac_adapter, halmac_buf, + halmac_size); + + /*restore to original bundary*/ + if (ret_status != HALMAC_RET_SUCCESS) { + pr_err("halmac_download_rsvd_page_88xx Fail = %x!!\n", + ret_status); + HALMAC_REG_WRITE_16( + halmac_adapter, REG_FIFOPAGE_CTRL_2, + (u16)(halmac_adapter->txff_allocation.rsvd_pg_bndy & + BIT_MASK_BCN_HEAD_1_V1)); + return ret_status; + } + + HALMAC_REG_WRITE_16(halmac_adapter, REG_FIFOPAGE_CTRL_2, + (u16)(halmac_adapter->txff_allocation.rsvd_pg_bndy & + BIT_MASK_BCN_HEAD_1_V1)); + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s < ==========\n", __func__); + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_cfg_csi_rate_88xx() - config CSI frame Tx rate + * @halmac_adapter : the adapter of halmac + * @rssi : rssi in decimal value + * @current_rate : current CSI frame rate + * @fixrate_en : enable to fix CSI frame in VHT rate, otherwise legacy OFDM rate + * @new_rate : API returns the final CSI frame rate + * Author : chunchu + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_cfg_csi_rate_88xx(struct halmac_adapter *halmac_adapter, u8 rssi, + u8 current_rate, u8 fixrate_en, u8 *new_rate) +{ + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + u32 temp_csi_setting; + u16 current_rrsr; + enum halmac_ret_status ret_status; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_CFG_CSI_RATE); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_SND, DBG_DMESG, + "<%s ==========>\n", __func__); + + temp_csi_setting = HALMAC_REG_READ_32(halmac_adapter, REG_BBPSF_CTRL) & + ~(BIT_MASK_WMAC_CSI_RATE << BIT_SHIFT_WMAC_CSI_RATE); + + current_rrsr = HALMAC_REG_READ_16(halmac_adapter, REG_RRSR); + + if (rssi >= 40) { + if (current_rate != HALMAC_OFDM54) { + HALMAC_REG_WRITE_16(halmac_adapter, REG_RRSR, + current_rrsr | BIT(HALMAC_OFDM54)); + HALMAC_REG_WRITE_32( + halmac_adapter, REG_BBPSF_CTRL, + temp_csi_setting | + BIT_WMAC_CSI_RATE(HALMAC_OFDM54)); + } + *new_rate = HALMAC_OFDM54; + ret_status = HALMAC_RET_SUCCESS; + } else { + if (current_rate != HALMAC_OFDM24) { + HALMAC_REG_WRITE_16(halmac_adapter, REG_RRSR, + current_rrsr & + ~(BIT(HALMAC_OFDM54))); + HALMAC_REG_WRITE_32( + halmac_adapter, REG_BBPSF_CTRL, + temp_csi_setting | + BIT_WMAC_CSI_RATE(HALMAC_OFDM24)); + } + *new_rate = HALMAC_OFDM24; + ret_status = HALMAC_RET_SUCCESS; + } + + return ret_status; +} + +/** + * halmac_sdio_cmd53_4byte_88xx() - cmd53 only for 4byte len register IO + * @halmac_adapter : the adapter of halmac + * @enable : 1->CMD53 only use in 4byte reg, 0 : No limitation + * Author : Ivan Lin/KaiYuan Chang + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_sdio_cmd53_4byte_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_sdio_cmd53_4byte_mode cmd53_4byte_mode) +{ + halmac_adapter->sdio_cmd53_4byte = cmd53_4byte_mode; + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_txfifo_is_empty_88xx() -check if txfifo is empty + * @halmac_adapter : the adapter of halmac + * Author : Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_txfifo_is_empty_88xx(struct halmac_adapter *halmac_adapter, u32 chk_num) +{ + u32 counter; + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_COMMON, DBG_DMESG, + "%s ==========>\n", __func__); + + counter = (chk_num <= 10) ? 10 : chk_num; + do { + if (HALMAC_REG_READ_8(halmac_adapter, REG_TXPKT_EMPTY) != 0xFF) + return HALMAC_RET_TXFIFO_NO_EMPTY; + + if ((HALMAC_REG_READ_8(halmac_adapter, REG_TXPKT_EMPTY + 1) & + 0x07) != 0x07) + return HALMAC_RET_TXFIFO_NO_EMPTY; + counter--; + + } while (counter != 0); + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_COMMON, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} diff --git a/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_api_88xx.h b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_api_88xx.h new file mode 100644 index 000000000000..5debd1ff3abd --- /dev/null +++ b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_api_88xx.h @@ -0,0 +1,396 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef _HALMAC_API_88XX_H_ +#define _HALMAC_API_88XX_H_ + +#include "../halmac_2_platform.h" +#include "../halmac_type.h" + +void halmac_init_state_machine_88xx(struct halmac_adapter *halmac_adapter); + +void halmac_init_adapter_para_88xx(struct halmac_adapter *halmac_adapter); + +void halmac_init_adapter_dynamic_para_88xx( + struct halmac_adapter *halmac_adapter); + +enum halmac_ret_status +halmac_mount_api_88xx(struct halmac_adapter *halmac_adapter); + +enum halmac_ret_status +halmac_download_firmware_88xx(struct halmac_adapter *halmac_adapter, + u8 *hamacl_fw, u32 halmac_fw_size); + +enum halmac_ret_status +halmac_free_download_firmware_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_dlfw_mem dlfw_mem, u8 *hamacl_fw, + u32 halmac_fw_size); + +enum halmac_ret_status +halmac_get_fw_version_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_fw_version *fw_version); + +enum halmac_ret_status +halmac_cfg_mac_addr_88xx(struct halmac_adapter *halmac_adapter, u8 halmac_port, + union halmac_wlan_addr *hal_address); + +enum halmac_ret_status +halmac_cfg_bssid_88xx(struct halmac_adapter *halmac_adapter, u8 halmac_port, + union halmac_wlan_addr *hal_address); + +enum halmac_ret_status +halmac_cfg_multicast_addr_88xx(struct halmac_adapter *halmac_adapter, + union halmac_wlan_addr *hal_address); + +enum halmac_ret_status +halmac_pre_init_system_cfg_88xx(struct halmac_adapter *halmac_adapter); + +enum halmac_ret_status +halmac_init_system_cfg_88xx(struct halmac_adapter *halmac_adapter); + +enum halmac_ret_status +halmac_cfg_rx_aggregation_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_rxagg_cfg halmac_rxagg_cfg); + +enum halmac_ret_status +halmac_init_edca_cfg_88xx(struct halmac_adapter *halmac_adapter); + +enum halmac_ret_status +halmac_cfg_operation_mode_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_wireless_mode wireless_mode); + +enum halmac_ret_status +halmac_cfg_ch_bw_88xx(struct halmac_adapter *halmac_adapter, u8 channel, + enum halmac_pri_ch_idx pri_ch_idx, enum halmac_bw bw); + +enum halmac_ret_status halmac_cfg_ch_88xx(struct halmac_adapter *halmac_adapter, + u8 channel); + +enum halmac_ret_status +halmac_cfg_pri_ch_idx_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_pri_ch_idx pri_ch_idx); + +enum halmac_ret_status halmac_cfg_bw_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_bw bw); + +enum halmac_ret_status +halmac_init_wmac_cfg_88xx(struct halmac_adapter *halmac_adapter); + +enum halmac_ret_status +halmac_init_mac_cfg_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_trx_mode mode); + +enum halmac_ret_status +halmac_dump_efuse_map_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_efuse_read_cfg cfg); + +enum halmac_ret_status +halmac_dump_efuse_map_bt_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_efuse_bank halmac_efuse_bank, + u32 bt_efuse_map_size, u8 *bt_efuse_map); + +enum halmac_ret_status +halmac_write_efuse_bt_88xx(struct halmac_adapter *halmac_adapter, + u32 halmac_offset, u8 halmac_value, + enum halmac_efuse_bank halmac_efuse_bank); + +enum halmac_ret_status +halmac_pg_efuse_by_map_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_pg_efuse_info *pg_efuse_info, + enum halmac_efuse_read_cfg cfg); + +enum halmac_ret_status +halmac_get_efuse_size_88xx(struct halmac_adapter *halmac_adapter, + u32 *halmac_size); + +enum halmac_ret_status +halmac_get_efuse_available_size_88xx(struct halmac_adapter *halmac_adapter, + u32 *halmac_size); + +enum halmac_ret_status +halmac_get_c2h_info_88xx(struct halmac_adapter *halmac_adapter, u8 *halmac_buf, + u32 halmac_size); + +enum halmac_ret_status +halmac_get_logical_efuse_size_88xx(struct halmac_adapter *halmac_adapter, + u32 *halmac_size); + +enum halmac_ret_status +halmac_dump_logical_efuse_map_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_efuse_read_cfg cfg); + +enum halmac_ret_status +halmac_write_logical_efuse_88xx(struct halmac_adapter *halmac_adapter, + u32 halmac_offset, u8 halmac_value); + +enum halmac_ret_status +halmac_read_logical_efuse_88xx(struct halmac_adapter *halmac_adapter, + u32 halmac_offset, u8 *value); + +enum halmac_ret_status +halmac_cfg_fwlps_option_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_fwlps_option *lps_option); + +enum halmac_ret_status +halmac_cfg_fwips_option_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_fwips_option *ips_option); + +enum halmac_ret_status +halmac_enter_wowlan_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_wowlan_option *wowlan_option); + +enum halmac_ret_status +halmac_leave_wowlan_88xx(struct halmac_adapter *halmac_adapter); + +enum halmac_ret_status +halmac_enter_ps_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_ps_state ps_state); + +enum halmac_ret_status +halmac_leave_ps_88xx(struct halmac_adapter *halmac_adapter); + +enum halmac_ret_status +halmac_h2c_lb_88xx(struct halmac_adapter *halmac_adapter); + +enum halmac_ret_status halmac_debug_88xx(struct halmac_adapter *halmac_adapter); + +enum halmac_ret_status +halmac_cfg_parameter_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_phy_parameter_info *para_info, + u8 full_fifo); + +enum halmac_ret_status +halmac_update_packet_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_packet_id pkt_id, u8 *pkt, u32 pkt_size); + +enum halmac_ret_status +halmac_bcn_ie_filter_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_bcn_ie_info *bcn_ie_info); + +enum halmac_ret_status +halmac_send_original_h2c_88xx(struct halmac_adapter *halmac_adapter, + u8 *original_h2c, u16 *seq, u8 ack); + +enum halmac_ret_status +halmac_update_datapack_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_data_type halmac_data_type, + struct halmac_phy_parameter_info *para_info); + +enum halmac_ret_status +halmac_run_datapack_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_data_type halmac_data_type); + +enum halmac_ret_status +halmac_cfg_drv_info_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_drv_info halmac_drv_info); + +enum halmac_ret_status +halmac_send_bt_coex_88xx(struct halmac_adapter *halmac_adapter, u8 *bt_buf, + u32 bt_size, u8 ack); + +enum halmac_ret_status +halmac_verify_platform_api_88xx(struct halmac_adapter *halmac_adapter); + +enum halmac_ret_status +halmac_timer_2s_88xx(struct halmac_adapter *halmac_adapter); + +enum halmac_ret_status +halmac_fill_txdesc_check_sum_88xx(struct halmac_adapter *halmac_adapter, + u8 *cur_desc); + +enum halmac_ret_status +halmac_dump_fifo_88xx(struct halmac_adapter *halmac_adapter, + enum hal_fifo_sel halmac_fifo_sel, u32 halmac_start_addr, + u32 halmac_fifo_dump_size, u8 *fifo_map); + +u32 halmac_get_fifo_size_88xx(struct halmac_adapter *halmac_adapter, + enum hal_fifo_sel halmac_fifo_sel); + +enum halmac_ret_status +halmac_cfg_txbf_88xx(struct halmac_adapter *halmac_adapter, u8 userid, + enum halmac_bw bw, u8 txbf_en); + +enum halmac_ret_status +halmac_cfg_mumimo_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_cfg_mumimo_para *cfgmu); + +enum halmac_ret_status +halmac_cfg_sounding_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_snd_role role, + enum halmac_data_rate datarate); + +enum halmac_ret_status +halmac_del_sounding_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_snd_role role); + +enum halmac_ret_status +halmac_su_bfee_entry_init_88xx(struct halmac_adapter *halmac_adapter, u8 userid, + u16 paid); + +enum halmac_ret_status +halmac_su_bfer_entry_init_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_su_bfer_init_para *su_bfer_init); + +enum halmac_ret_status +halmac_mu_bfee_entry_init_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_mu_bfee_init_para *mu_bfee_init); + +enum halmac_ret_status +halmac_mu_bfer_entry_init_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_mu_bfer_init_para *mu_bfer_init); + +enum halmac_ret_status +halmac_su_bfee_entry_del_88xx(struct halmac_adapter *halmac_adapter, u8 userid); + +enum halmac_ret_status +halmac_su_bfer_entry_del_88xx(struct halmac_adapter *halmac_adapter, u8 userid); + +enum halmac_ret_status +halmac_mu_bfee_entry_del_88xx(struct halmac_adapter *halmac_adapter, u8 userid); + +enum halmac_ret_status +halmac_mu_bfer_entry_del_88xx(struct halmac_adapter *halmac_adapter); + +enum halmac_ret_status +halmac_add_ch_info_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_ch_info *ch_info); + +enum halmac_ret_status +halmac_add_extra_ch_info_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_ch_extra_info *ch_extra_info); + +enum halmac_ret_status +halmac_ctrl_ch_switch_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_ch_switch_option *cs_option); + +enum halmac_ret_status halmac_p2pps_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_p2pps *p2p_ps); + +enum halmac_ret_status +halmac_func_p2pps_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_p2pps *p2p_ps); + +enum halmac_ret_status +halmac_clear_ch_info_88xx(struct halmac_adapter *halmac_adapter); + +enum halmac_ret_status +halmac_send_general_info_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_general_info *general_info); + +enum halmac_ret_status +halmac_start_iqk_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_iqk_para_ *iqk_para); + +enum halmac_ret_status halmac_ctrl_pwr_tracking_88xx( + struct halmac_adapter *halmac_adapter, + struct halmac_pwr_tracking_option *pwr_tracking_opt); + +enum halmac_ret_status +halmac_query_status_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_feature_id feature_id, + enum halmac_cmd_process_status *process_status, + u8 *data, u32 *size); + +enum halmac_ret_status +halmac_reset_feature_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_feature_id feature_id); + +enum halmac_ret_status +halmac_check_fw_status_88xx(struct halmac_adapter *halmac_adapter, + bool *fw_status); + +enum halmac_ret_status +halmac_dump_fw_dmem_88xx(struct halmac_adapter *halmac_adapter, u8 *dmem, + u32 *size); + +enum halmac_ret_status +halmac_cfg_max_dl_size_88xx(struct halmac_adapter *halmac_adapter, u32 size); + +enum halmac_ret_status halmac_psd_88xx(struct halmac_adapter *halmac_adapter, + u16 start_psd, u16 end_psd); + +enum halmac_ret_status +halmac_cfg_la_mode_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_la_mode la_mode); + +enum halmac_ret_status halmac_cfg_rx_fifo_expanding_mode_88xx( + struct halmac_adapter *halmac_adapter, + enum halmac_rx_fifo_expanding_mode rx_fifo_expanding_mode); + +enum halmac_ret_status +halmac_config_security_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_security_setting *sec_setting); + +u8 halmac_get_used_cam_entry_num_88xx(struct halmac_adapter *halmac_adapter, + enum hal_security_type sec_type); + +enum halmac_ret_status +halmac_write_cam_88xx(struct halmac_adapter *halmac_adapter, u32 entry_index, + struct halmac_cam_entry_info *cam_entry_info); + +enum halmac_ret_status +halmac_read_cam_entry_88xx(struct halmac_adapter *halmac_adapter, + u32 entry_index, + struct halmac_cam_entry_format *content); + +enum halmac_ret_status +halmac_clear_cam_entry_88xx(struct halmac_adapter *halmac_adapter, + u32 entry_index); + +enum halmac_ret_status +halmac_get_hw_value_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_hw_id hw_id, void *pvalue); + +enum halmac_ret_status +halmac_set_hw_value_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_hw_id hw_id, void *pvalue); + +enum halmac_ret_status +halmac_cfg_drv_rsvd_pg_num_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_drv_rsvd_pg_num pg_num); + +enum halmac_ret_status +halmac_get_chip_version_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_ver *version); + +enum halmac_ret_status +halmac_chk_txdesc_88xx(struct halmac_adapter *halmac_adapter, u8 *halmac_buf, + u32 halmac_size); + +enum halmac_ret_status +halmac_dl_drv_rsvd_page_88xx(struct halmac_adapter *halmac_adapter, + u8 pg_offset, u8 *halmac_buf, u32 halmac_size); + +enum halmac_ret_status +halmac_cfg_csi_rate_88xx(struct halmac_adapter *halmac_adapter, u8 rssi, + u8 current_rate, u8 fixrate_en, u8 *new_rate); + +enum halmac_ret_status halmac_sdio_cmd53_4byte_88xx( + struct halmac_adapter *halmac_adapter, + enum halmac_sdio_cmd53_4byte_mode cmd53_4byte_mode); + +enum halmac_ret_status +halmac_txfifo_is_empty_88xx(struct halmac_adapter *halmac_adapter, u32 chk_num); + +#endif /* _HALMAC_API_H_ */ diff --git a/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_api_88xx_pcie.c b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_api_88xx_pcie.c new file mode 100644 index 000000000000..fa97cac34742 --- /dev/null +++ b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_api_88xx_pcie.c @@ -0,0 +1,329 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#include "halmac_88xx_cfg.h" + +/** + * halmac_init_pcie_cfg_88xx() - init PCIe + * @halmac_adapter : the adapter of halmac + * Author : KaiYuan Chang + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_init_pcie_cfg_88xx(struct halmac_adapter *halmac_adapter) +{ + void *driver_adapter = NULL; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_INIT_PCIE_CFG); + + driver_adapter = halmac_adapter->driver_adapter; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s ==========>\n", __func__); + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_deinit_pcie_cfg_88xx() - deinit PCIE + * @halmac_adapter : the adapter of halmac + * Author : KaiYuan Chang + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_deinit_pcie_cfg_88xx(struct halmac_adapter *halmac_adapter) +{ + void *driver_adapter = NULL; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_DEINIT_PCIE_CFG); + + driver_adapter = halmac_adapter->driver_adapter; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s ==========>\n", __func__); + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_cfg_rx_aggregation_88xx_pcie() - config rx aggregation + * @halmac_adapter : the adapter of halmac + * @halmac_rx_agg_mode + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_cfg_rx_aggregation_88xx_pcie(struct halmac_adapter *halmac_adapter, + struct halmac_rxagg_cfg *phalmac_rxagg_cfg) +{ + void *driver_adapter = NULL; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, + HALMAC_API_CFG_RX_AGGREGATION); + + driver_adapter = halmac_adapter->driver_adapter; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s ==========>\n", __func__); + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_reg_read_8_pcie_88xx() - read 1byte register + * @halmac_adapter : the adapter of halmac + * @halmac_offset : register offset + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +u8 halmac_reg_read_8_pcie_88xx(struct halmac_adapter *halmac_adapter, + u32 halmac_offset) +{ + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + return PLATFORM_REG_READ_8(driver_adapter, halmac_offset); +} + +/** + * halmac_reg_write_8_pcie_88xx() - write 1byte register + * @halmac_adapter : the adapter of halmac + * @halmac_offset : register offset + * @halmac_data : register value + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_reg_write_8_pcie_88xx(struct halmac_adapter *halmac_adapter, + u32 halmac_offset, u8 halmac_data) +{ + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + PLATFORM_REG_WRITE_8(driver_adapter, halmac_offset, halmac_data); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_reg_read_16_pcie_88xx() - read 2byte register + * @halmac_adapter : the adapter of halmac + * @halmac_offset : register offset + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +u16 halmac_reg_read_16_pcie_88xx(struct halmac_adapter *halmac_adapter, + u32 halmac_offset) +{ + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + return PLATFORM_REG_READ_16(driver_adapter, halmac_offset); +} + +/** + * halmac_reg_write_16_pcie_88xx() - write 2byte register + * @halmac_adapter : the adapter of halmac + * @halmac_offset : register offset + * @halmac_data : register value + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_reg_write_16_pcie_88xx(struct halmac_adapter *halmac_adapter, + u32 halmac_offset, u16 halmac_data) +{ + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + PLATFORM_REG_WRITE_16(driver_adapter, halmac_offset, halmac_data); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_reg_read_32_pcie_88xx() - read 4byte register + * @halmac_adapter : the adapter of halmac + * @halmac_offset : register offset + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +u32 halmac_reg_read_32_pcie_88xx(struct halmac_adapter *halmac_adapter, + u32 halmac_offset) +{ + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + return PLATFORM_REG_READ_32(driver_adapter, halmac_offset); +} + +/** + * halmac_reg_write_32_pcie_88xx() - write 4byte register + * @halmac_adapter : the adapter of halmac + * @halmac_offset : register offset + * @halmac_data : register value + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_reg_write_32_pcie_88xx(struct halmac_adapter *halmac_adapter, + u32 halmac_offset, u32 halmac_data) +{ + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + PLATFORM_REG_WRITE_32(driver_adapter, halmac_offset, halmac_data); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_cfg_tx_agg_align_pcie_88xx() -config sdio bus tx agg alignment + * @halmac_adapter : the adapter of halmac + * @enable : function enable(1)/disable(0) + * @align_size : sdio bus tx agg alignment size (2^n, n = 3~11) + * Author : Soar Tu + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status halmac_cfg_tx_agg_align_pcie_not_support_88xx( + struct halmac_adapter *halmac_adapter, u8 enable, u16 align_size) +{ + struct halmac_api *halmac_api; + void *driver_adapter = NULL; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_CFG_TX_AGG_ALIGN); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_RT_TRACE( + driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s ==========>\n", __func__); + + HALMAC_RT_TRACE( + driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s not support\n", __func__); + HALMAC_RT_TRACE( + driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} diff --git a/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_api_88xx_pcie.h b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_api_88xx_pcie.h new file mode 100644 index 000000000000..34969fc5c03e --- /dev/null +++ b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_api_88xx_pcie.h @@ -0,0 +1,71 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef _HALMAC_API_88XX_PCIE_H_ +#define _HALMAC_API_88XX_PCIE_H_ + +#include "../halmac_2_platform.h" +#include "../halmac_type.h" + +#define LINK_CTRL2_REG_OFFSET 0xA0 +#define GEN2_CTRL_OFFSET 0x80C +#define LINK_STATUS_REG_OFFSET 0x82 +#define GEN1_SPEED 0x01 +#define GEN2_SPEED 0x02 + +enum halmac_ret_status +halmac_init_pcie_cfg_88xx(struct halmac_adapter *halmac_adapter); + +enum halmac_ret_status +halmac_deinit_pcie_cfg_88xx(struct halmac_adapter *halmac_adapter); + +enum halmac_ret_status +halmac_cfg_rx_aggregation_88xx_pcie(struct halmac_adapter *halmac_adapter, + struct halmac_rxagg_cfg *phalmac_rxagg_cfg); + +u8 halmac_reg_read_8_pcie_88xx(struct halmac_adapter *halmac_adapter, + u32 halmac_offset); + +enum halmac_ret_status +halmac_reg_write_8_pcie_88xx(struct halmac_adapter *halmac_adapter, + u32 halmac_offset, u8 halmac_data); + +u16 halmac_reg_read_16_pcie_88xx(struct halmac_adapter *halmac_adapter, + u32 halmac_offset); + +enum halmac_ret_status +halmac_reg_write_16_pcie_88xx(struct halmac_adapter *halmac_adapter, + u32 halmac_offset, u16 halmac_data); + +u32 halmac_reg_read_32_pcie_88xx(struct halmac_adapter *halmac_adapter, + u32 halmac_offset); + +enum halmac_ret_status +halmac_reg_write_32_pcie_88xx(struct halmac_adapter *halmac_adapter, + u32 halmac_offset, u32 halmac_data); + +enum halmac_ret_status halmac_cfg_tx_agg_align_pcie_not_support_88xx( + struct halmac_adapter *halmac_adapter, u8 enable, u16 align_size); + +#endif /* _HALMAC_API_88XX_PCIE_H_ */ diff --git a/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_api_88xx_sdio.c b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_api_88xx_sdio.c new file mode 100644 index 000000000000..69b26a5a3cf3 --- /dev/null +++ b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_api_88xx_sdio.c @@ -0,0 +1,974 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#include "halmac_88xx_cfg.h" + +/** + * halmac_init_sdio_cfg_88xx() - init SDIO + * @halmac_adapter : the adapter of halmac + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_init_sdio_cfg_88xx(struct halmac_adapter *halmac_adapter) +{ + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_INIT_SDIO_CFG); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s ==========>\n", __func__); + + HALMAC_REG_READ_32(halmac_adapter, REG_SDIO_FREE_TXPG); + HALMAC_REG_WRITE_32(halmac_adapter, REG_SDIO_TX_CTRL, 0x00000000); + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_deinit_sdio_cfg_88xx() - deinit SDIO + * @halmac_adapter : the adapter of halmac + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_deinit_sdio_cfg_88xx(struct halmac_adapter *halmac_adapter) +{ + void *driver_adapter = NULL; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_DEINIT_SDIO_CFG); + + driver_adapter = halmac_adapter->driver_adapter; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s ==========>\n", __func__); + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_cfg_rx_aggregation_88xx_sdio() - config rx aggregation + * @halmac_adapter : the adapter of halmac + * @halmac_rx_agg_mode + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_cfg_rx_aggregation_88xx_sdio(struct halmac_adapter *halmac_adapter, + struct halmac_rxagg_cfg *phalmac_rxagg_cfg) +{ + u8 value8; + u8 size = 0, timeout = 0, agg_enable = 0; + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, + HALMAC_API_CFG_RX_AGGREGATION); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s ==========>\n", __func__); + + agg_enable = HALMAC_REG_READ_8(halmac_adapter, REG_TXDMA_PQ_MAP); + + switch (phalmac_rxagg_cfg->mode) { + case HALMAC_RX_AGG_MODE_NONE: + agg_enable &= ~(BIT_RXDMA_AGG_EN); + break; + case HALMAC_RX_AGG_MODE_DMA: + case HALMAC_RX_AGG_MODE_USB: + agg_enable |= BIT_RXDMA_AGG_EN; + break; + default: + pr_err("halmac_cfg_rx_aggregation_88xx_usb switch case not support\n"); + agg_enable &= ~BIT_RXDMA_AGG_EN; + break; + } + + if (!phalmac_rxagg_cfg->threshold.drv_define) { + size = 0xFF; + timeout = 0x01; + } else { + size = phalmac_rxagg_cfg->threshold.size; + timeout = phalmac_rxagg_cfg->threshold.timeout; + } + + HALMAC_REG_WRITE_8(halmac_adapter, REG_TXDMA_PQ_MAP, agg_enable); + HALMAC_REG_WRITE_16(halmac_adapter, REG_RXDMA_AGG_PG_TH, + (u16)(size | (timeout << BIT_SHIFT_DMA_AGG_TO))); + + value8 = HALMAC_REG_READ_8(halmac_adapter, REG_RXDMA_MODE); + if ((agg_enable & BIT_RXDMA_AGG_EN) != 0) + HALMAC_REG_WRITE_8(halmac_adapter, REG_RXDMA_MODE, + value8 | BIT_DMA_MODE); + else + HALMAC_REG_WRITE_8(halmac_adapter, REG_RXDMA_MODE, + value8 & ~(BIT_DMA_MODE)); + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_reg_read_8_sdio_88xx() - read 1byte register + * @halmac_adapter : the adapter of halmac + * @halmac_offset : register offset + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +u8 halmac_reg_read_8_sdio_88xx(struct halmac_adapter *halmac_adapter, + u32 halmac_offset) +{ + u8 value8; + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + if ((halmac_offset & 0xFFFF0000) == 0) + halmac_offset |= WLAN_IOREG_OFFSET; + + status = halmac_convert_to_sdio_bus_offset_88xx(halmac_adapter, + &halmac_offset); + + if (status != HALMAC_RET_SUCCESS) { + pr_err("%s error = %x\n", __func__, status); + return status; + } + + value8 = PLATFORM_SDIO_CMD52_READ(driver_adapter, halmac_offset); + + return value8; +} + +/** + * halmac_reg_write_8_sdio_88xx() - write 1byte register + * @halmac_adapter : the adapter of halmac + * @halmac_offset : register offset + * @halmac_data : register value + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_reg_write_8_sdio_88xx(struct halmac_adapter *halmac_adapter, + u32 halmac_offset, u8 halmac_data) +{ + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + if ((halmac_offset & 0xFFFF0000) == 0) + halmac_offset |= WLAN_IOREG_OFFSET; + + status = halmac_convert_to_sdio_bus_offset_88xx(halmac_adapter, + &halmac_offset); + + if (status != HALMAC_RET_SUCCESS) { + pr_err("%s error = %x\n", __func__, status); + return status; + } + + PLATFORM_SDIO_CMD52_WRITE(driver_adapter, halmac_offset, halmac_data); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_reg_read_16_sdio_88xx() - read 2byte register + * @halmac_adapter : the adapter of halmac + * @halmac_offset : register offset + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +u16 halmac_reg_read_16_sdio_88xx(struct halmac_adapter *halmac_adapter, + u32 halmac_offset) +{ + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + + union { + u16 word; + u8 byte[2]; + __le16 le_word; + } value16 = {0x0000}; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + if ((halmac_offset & 0xFFFF0000) == 0) + halmac_offset |= WLAN_IOREG_OFFSET; + + status = halmac_convert_to_sdio_bus_offset_88xx(halmac_adapter, + &halmac_offset); + + if (status != HALMAC_RET_SUCCESS) { + pr_err("%s error = %x\n", __func__, status); + return status; + } + + if (halmac_adapter->halmac_state.mac_power == HALMAC_MAC_POWER_OFF || + (halmac_offset & (2 - 1)) != 0 || + halmac_adapter->sdio_cmd53_4byte == + HALMAC_SDIO_CMD53_4BYTE_MODE_RW || + halmac_adapter->sdio_cmd53_4byte == + HALMAC_SDIO_CMD53_4BYTE_MODE_R) { + value16.byte[0] = + PLATFORM_SDIO_CMD52_READ(driver_adapter, halmac_offset); + value16.byte[1] = PLATFORM_SDIO_CMD52_READ(driver_adapter, + halmac_offset + 1); + value16.word = le16_to_cpu(value16.le_word); + } else { +#if (PLATFORM_SD_CLK > HALMAC_SD_CLK_THRESHOLD_88XX) + if ((halmac_offset & 0xffffef00) == 0x00000000) { + value16.byte[0] = PLATFORM_SDIO_CMD52_READ( + driver_adapter, halmac_offset); + value16.byte[1] = PLATFORM_SDIO_CMD52_READ( + driver_adapter, halmac_offset + 1); + value16.word = le16_to_cpu(value16.word); + } else { + value16.word = PLATFORM_SDIO_CMD53_READ_16( + driver_adapter, halmac_offset); + } +#else + value16.word = PLATFORM_SDIO_CMD53_READ_16(driver_adapter, + halmac_offset); +#endif + } + + return value16.word; +} + +/** + * halmac_reg_write_16_sdio_88xx() - write 2byte register + * @halmac_adapter : the adapter of halmac + * @halmac_offset : register offset + * @halmac_data : register value + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_reg_write_16_sdio_88xx(struct halmac_adapter *halmac_adapter, + u32 halmac_offset, u16 halmac_data) +{ + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + if ((halmac_offset & 0xFFFF0000) == 0) + halmac_offset |= WLAN_IOREG_OFFSET; + + status = halmac_convert_to_sdio_bus_offset_88xx(halmac_adapter, + &halmac_offset); + + if (status != HALMAC_RET_SUCCESS) { + pr_err("%s error = %x\n", __func__, status); + return status; + } + + if (halmac_adapter->halmac_state.mac_power == HALMAC_MAC_POWER_OFF || + (halmac_offset & (2 - 1)) != 0 || + halmac_adapter->sdio_cmd53_4byte == + HALMAC_SDIO_CMD53_4BYTE_MODE_RW || + halmac_adapter->sdio_cmd53_4byte == + HALMAC_SDIO_CMD53_4BYTE_MODE_W) { + PLATFORM_SDIO_CMD52_WRITE(driver_adapter, halmac_offset, + (u8)(halmac_data & 0xFF)); + PLATFORM_SDIO_CMD52_WRITE(driver_adapter, halmac_offset + 1, + (u8)((halmac_data & 0xFF00) >> 8)); + } else { + PLATFORM_SDIO_CMD53_WRITE_16(driver_adapter, halmac_offset, + halmac_data); + } + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_reg_read_32_sdio_88xx() - read 4byte register + * @halmac_adapter : the adapter of halmac + * @halmac_offset : register offset + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +u32 halmac_reg_read_32_sdio_88xx(struct halmac_adapter *halmac_adapter, + u32 halmac_offset) +{ + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + u32 halmac_offset_old = 0; + + union { + u32 dword; + u8 byte[4]; + __le32 le_dword; + } value32 = {0x00000000}; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + halmac_offset_old = halmac_offset; + + if ((halmac_offset & 0xFFFF0000) == 0) + halmac_offset |= WLAN_IOREG_OFFSET; + + status = halmac_convert_to_sdio_bus_offset_88xx(halmac_adapter, + &halmac_offset); + if (status != HALMAC_RET_SUCCESS) { + pr_err("%s error = %x\n", __func__, status); + return status; + } + + if (halmac_adapter->halmac_state.mac_power == HALMAC_MAC_POWER_OFF || + (halmac_offset & (4 - 1)) != 0) { + value32.byte[0] = + PLATFORM_SDIO_CMD52_READ(driver_adapter, halmac_offset); + value32.byte[1] = PLATFORM_SDIO_CMD52_READ(driver_adapter, + halmac_offset + 1); + value32.byte[2] = PLATFORM_SDIO_CMD52_READ(driver_adapter, + halmac_offset + 2); + value32.byte[3] = PLATFORM_SDIO_CMD52_READ(driver_adapter, + halmac_offset + 3); + value32.dword = le32_to_cpu(value32.le_dword); + } else { +#if (PLATFORM_SD_CLK > HALMAC_SD_CLK_THRESHOLD_88XX) + if ((halmac_offset_old & 0xffffef00) == 0x00000000) { + value32.byte[0] = PLATFORM_SDIO_CMD52_READ( + driver_adapter, halmac_offset); + value32.byte[1] = PLATFORM_SDIO_CMD52_READ( + driver_adapter, halmac_offset + 1); + value32.byte[2] = PLATFORM_SDIO_CMD52_READ( + driver_adapter, halmac_offset + 2); + value32.byte[3] = PLATFORM_SDIO_CMD52_READ( + driver_adapter, halmac_offset + 3); + value32.dword = le32_to_cpu(value32.dword); + } else { + value32.dword = PLATFORM_SDIO_CMD53_READ_32( + driver_adapter, halmac_offset); + } +#else + value32.dword = PLATFORM_SDIO_CMD53_READ_32(driver_adapter, + halmac_offset); +#endif + } + + return value32.dword; +} + +/** + * halmac_reg_write_32_sdio_88xx() - write 4byte register + * @halmac_adapter : the adapter of halmac + * @halmac_offset : register offset + * @halmac_data : register value + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_reg_write_32_sdio_88xx(struct halmac_adapter *halmac_adapter, + u32 halmac_offset, u32 halmac_data) +{ + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + if ((halmac_offset & 0xFFFF0000) == 0) + halmac_offset |= WLAN_IOREG_OFFSET; + + status = halmac_convert_to_sdio_bus_offset_88xx(halmac_adapter, + &halmac_offset); + + if (status != HALMAC_RET_SUCCESS) { + pr_err("%s error = %x\n", __func__, status); + return status; + } + + if (halmac_adapter->halmac_state.mac_power == HALMAC_MAC_POWER_OFF || + (halmac_offset & (4 - 1)) != 0) { + PLATFORM_SDIO_CMD52_WRITE(driver_adapter, halmac_offset, + (u8)(halmac_data & 0xFF)); + PLATFORM_SDIO_CMD52_WRITE(driver_adapter, halmac_offset + 1, + (u8)((halmac_data & 0xFF00) >> 8)); + PLATFORM_SDIO_CMD52_WRITE(driver_adapter, halmac_offset + 2, + (u8)((halmac_data & 0xFF0000) >> 16)); + PLATFORM_SDIO_CMD52_WRITE( + driver_adapter, halmac_offset + 3, + (u8)((halmac_data & 0xFF000000) >> 24)); + } else { + PLATFORM_SDIO_CMD53_WRITE_32(driver_adapter, halmac_offset, + halmac_data); + } + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_reg_read_nbyte_sdio_88xx() - read n byte register + * @halmac_adapter : the adapter of halmac + * @halmac_offset : register offset + * @halmac_size : register value size + * @halmac_data : register value + * Author : Soar + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +u8 halmac_reg_read_nbyte_sdio_88xx(struct halmac_adapter *halmac_adapter, + u32 halmac_offset, u32 halmac_size, + u8 *halmac_data) +{ + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + if ((halmac_offset & 0xFFFF0000) == 0) { + pr_err("halmac_offset error = 0x%x\n", halmac_offset); + return HALMAC_RET_FAIL; + } + + status = halmac_convert_to_sdio_bus_offset_88xx(halmac_adapter, + &halmac_offset); + if (status != HALMAC_RET_SUCCESS) { + pr_err("%s error = %x\n", __func__, status); + return status; + } + + if (halmac_adapter->halmac_state.mac_power == HALMAC_MAC_POWER_OFF) { + pr_err("halmac_state error = 0x%x\n", + halmac_adapter->halmac_state.mac_power); + return HALMAC_RET_FAIL; + } + + PLATFORM_SDIO_CMD53_READ_N(driver_adapter, halmac_offset, halmac_size, + halmac_data); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_get_sdio_tx_addr_sdio_88xx() - get CMD53 addr for the TX packet + * @halmac_adapter : the adapter of halmac + * @halmac_buf : tx packet, include txdesc + * @halmac_size : tx packet size + * @pcmd53_addr : cmd53 addr value + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_get_sdio_tx_addr_88xx(struct halmac_adapter *halmac_adapter, + u8 *halmac_buf, u32 halmac_size, u32 *pcmd53_addr) +{ + u32 four_byte_len; + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + enum halmac_queue_select queue_sel; + enum halmac_dma_mapping dma_mapping; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_GET_SDIO_TX_ADDR); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s ==========>\n", __func__); + + if (!halmac_buf) { + pr_err("halmac_buf is NULL!!\n"); + return HALMAC_RET_DATA_BUF_NULL; + } + + if (halmac_size == 0) { + pr_err("halmac_size is 0!!\n"); + return HALMAC_RET_DATA_SIZE_INCORRECT; + } + + queue_sel = (enum halmac_queue_select)GET_TX_DESC_QSEL(halmac_buf); + + switch (queue_sel) { + case HALMAC_QUEUE_SELECT_VO: + case HALMAC_QUEUE_SELECT_VO_V2: + dma_mapping = + halmac_adapter->halmac_ptcl_queue[HALMAC_PTCL_QUEUE_VO]; + break; + case HALMAC_QUEUE_SELECT_VI: + case HALMAC_QUEUE_SELECT_VI_V2: + dma_mapping = + halmac_adapter->halmac_ptcl_queue[HALMAC_PTCL_QUEUE_VI]; + break; + case HALMAC_QUEUE_SELECT_BE: + case HALMAC_QUEUE_SELECT_BE_V2: + dma_mapping = + halmac_adapter->halmac_ptcl_queue[HALMAC_PTCL_QUEUE_BE]; + break; + case HALMAC_QUEUE_SELECT_BK: + case HALMAC_QUEUE_SELECT_BK_V2: + dma_mapping = + halmac_adapter->halmac_ptcl_queue[HALMAC_PTCL_QUEUE_BK]; + break; + case HALMAC_QUEUE_SELECT_MGNT: + dma_mapping = + halmac_adapter->halmac_ptcl_queue[HALMAC_PTCL_QUEUE_MG]; + break; + case HALMAC_QUEUE_SELECT_HIGH: + case HALMAC_QUEUE_SELECT_BCN: + case HALMAC_QUEUE_SELECT_CMD: + dma_mapping = + halmac_adapter->halmac_ptcl_queue[HALMAC_PTCL_QUEUE_HI]; + break; + default: + pr_err("Qsel is out of range\n"); + return HALMAC_RET_QSEL_INCORRECT; + } + + four_byte_len = (halmac_size >> 2) + ((halmac_size & (4 - 1)) ? 1 : 0); + + switch (dma_mapping) { + case HALMAC_DMA_MAPPING_HIGH: + *pcmd53_addr = HALMAC_SDIO_CMD_ADDR_TXFF_HIGH; + break; + case HALMAC_DMA_MAPPING_NORMAL: + *pcmd53_addr = HALMAC_SDIO_CMD_ADDR_TXFF_NORMAL; + break; + case HALMAC_DMA_MAPPING_LOW: + *pcmd53_addr = HALMAC_SDIO_CMD_ADDR_TXFF_LOW; + break; + case HALMAC_DMA_MAPPING_EXTRA: + *pcmd53_addr = HALMAC_SDIO_CMD_ADDR_TXFF_EXTRA; + break; + default: + pr_err("DmaMapping is out of range\n"); + return HALMAC_RET_DMA_MAP_INCORRECT; + } + + *pcmd53_addr = (*pcmd53_addr << 13) | + (four_byte_len & HALMAC_SDIO_4BYTE_LEN_MASK); + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_cfg_tx_agg_align_sdio_88xx() -config sdio bus tx agg alignment + * @halmac_adapter : the adapter of halmac + * @enable : function enable(1)/disable(0) + * @align_size : sdio bus tx agg alignment size (2^n, n = 3~11) + * Author : Soar Tu + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_cfg_tx_agg_align_sdio_88xx(struct halmac_adapter *halmac_adapter, + u8 enable, u16 align_size) +{ + struct halmac_api *halmac_api; + void *driver_adapter = NULL; + u8 i, align_size_ok = 0; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_CFG_TX_AGG_ALIGN); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s ==========>\n", __func__); + + if ((align_size & 0xF000) != 0) { + pr_err("Align size is out of range\n"); + return HALMAC_RET_FAIL; + } + + for (i = 3; i <= 11; i++) { + if (align_size == 1 << i) { + align_size_ok = 1; + break; + } + } + if (align_size_ok == 0) { + pr_err("Align size is not 2^3 ~ 2^11\n"); + return HALMAC_RET_FAIL; + } + + /*Keep sdio tx agg alignment size for driver query*/ + halmac_adapter->hw_config_info.tx_align_size = align_size; + + if (enable) + HALMAC_REG_WRITE_16(halmac_adapter, REG_RQPN_CTRL_2, + 0x8000 | align_size); + else + HALMAC_REG_WRITE_16(halmac_adapter, REG_RQPN_CTRL_2, + align_size); + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status halmac_cfg_tx_agg_align_sdio_not_support_88xx( + struct halmac_adapter *halmac_adapter, u8 enable, u16 align_size) +{ + struct halmac_api *halmac_api; + void *driver_adapter = NULL; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_CFG_TX_AGG_ALIGN); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_RT_TRACE( + driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s ==========>\n", __func__); + + HALMAC_RT_TRACE( + driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s not support\n", __func__); + HALMAC_RT_TRACE( + driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_tx_allowed_sdio_88xx() - check tx status + * @halmac_adapter : the adapter of halmac + * @halmac_buf : tx packet, include txdesc + * @halmac_size : tx packet size, include txdesc + * Author : Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_tx_allowed_sdio_88xx(struct halmac_adapter *halmac_adapter, + u8 *halmac_buf, u32 halmac_size) +{ + u8 *curr_packet; + u16 *curr_free_space; + u32 i, counter; + u32 tx_agg_num, packet_size = 0; + u32 tx_required_page_num, total_required_page_num = 0; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + void *driver_adapter = NULL; + enum halmac_dma_mapping dma_mapping; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_TX_ALLOWED_SDIO); + + driver_adapter = halmac_adapter->driver_adapter; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s ==========>\n", __func__); + + tx_agg_num = GET_TX_DESC_DMA_TXAGG_NUM(halmac_buf); + curr_packet = halmac_buf; + + tx_agg_num = tx_agg_num == 0 ? 1 : tx_agg_num; + + switch ((enum halmac_queue_select)GET_TX_DESC_QSEL(curr_packet)) { + case HALMAC_QUEUE_SELECT_VO: + case HALMAC_QUEUE_SELECT_VO_V2: + dma_mapping = + halmac_adapter->halmac_ptcl_queue[HALMAC_PTCL_QUEUE_VO]; + break; + case HALMAC_QUEUE_SELECT_VI: + case HALMAC_QUEUE_SELECT_VI_V2: + dma_mapping = + halmac_adapter->halmac_ptcl_queue[HALMAC_PTCL_QUEUE_VI]; + break; + case HALMAC_QUEUE_SELECT_BE: + case HALMAC_QUEUE_SELECT_BE_V2: + dma_mapping = + halmac_adapter->halmac_ptcl_queue[HALMAC_PTCL_QUEUE_BE]; + break; + case HALMAC_QUEUE_SELECT_BK: + case HALMAC_QUEUE_SELECT_BK_V2: + dma_mapping = + halmac_adapter->halmac_ptcl_queue[HALMAC_PTCL_QUEUE_BK]; + break; + case HALMAC_QUEUE_SELECT_MGNT: + dma_mapping = + halmac_adapter->halmac_ptcl_queue[HALMAC_PTCL_QUEUE_MG]; + break; + case HALMAC_QUEUE_SELECT_HIGH: + dma_mapping = + halmac_adapter->halmac_ptcl_queue[HALMAC_PTCL_QUEUE_HI]; + break; + case HALMAC_QUEUE_SELECT_BCN: + case HALMAC_QUEUE_SELECT_CMD: + return HALMAC_RET_SUCCESS; + default: + pr_err("Qsel is out of range\n"); + return HALMAC_RET_QSEL_INCORRECT; + } + + switch (dma_mapping) { + case HALMAC_DMA_MAPPING_HIGH: + curr_free_space = + &halmac_adapter->sdio_free_space.high_queue_number; + break; + case HALMAC_DMA_MAPPING_NORMAL: + curr_free_space = + &halmac_adapter->sdio_free_space.normal_queue_number; + break; + case HALMAC_DMA_MAPPING_LOW: + curr_free_space = + &halmac_adapter->sdio_free_space.low_queue_number; + break; + case HALMAC_DMA_MAPPING_EXTRA: + curr_free_space = + &halmac_adapter->sdio_free_space.extra_queue_number; + break; + default: + pr_err("DmaMapping is out of range\n"); + return HALMAC_RET_DMA_MAP_INCORRECT; + } + + for (i = 0; i < tx_agg_num; i++) { + packet_size = GET_TX_DESC_TXPKTSIZE(curr_packet) + + GET_TX_DESC_OFFSET(curr_packet) + + (GET_TX_DESC_PKT_OFFSET(curr_packet) << 3); + tx_required_page_num = + (packet_size >> + halmac_adapter->hw_config_info.page_size_2_power) + + ((packet_size & + (halmac_adapter->hw_config_info.page_size - 1)) ? + 1 : + 0); + total_required_page_num += tx_required_page_num; + + packet_size = HALMAC_ALIGN(packet_size, 8); + + curr_packet += packet_size; + } + + counter = 10; + do { + if ((u32)(*curr_free_space + + halmac_adapter->sdio_free_space.public_queue_number) > + total_required_page_num) { + if (*curr_free_space >= total_required_page_num) { + *curr_free_space -= + (u16)total_required_page_num; + } else { + halmac_adapter->sdio_free_space + .public_queue_number -= + (u16)(total_required_page_num - + *curr_free_space); + *curr_free_space = 0; + } + + status = halmac_check_oqt_88xx(halmac_adapter, + tx_agg_num, halmac_buf); + + if (status != HALMAC_RET_SUCCESS) + return status; + + break; + } + + halmac_update_sdio_free_page_88xx(halmac_adapter); + + counter--; + if (counter == 0) + return HALMAC_RET_FREE_SPACE_NOT_ENOUGH; + } while (1); + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_reg_read_indirect_32_sdio_88xx() - read MAC reg by SDIO reg + * @halmac_adapter : the adapter of halmac + * @halmac_offset : register offset + * Author : Soar + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +u32 halmac_reg_read_indirect_32_sdio_88xx(struct halmac_adapter *halmac_adapter, + u32 halmac_offset) +{ + u8 rtemp; + u32 counter = 1000; + void *driver_adapter = NULL; + + union { + u32 dword; + u8 byte[4]; + } value32 = {0x00000000}; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + driver_adapter = halmac_adapter->driver_adapter; + + PLATFORM_SDIO_CMD53_WRITE_32( + driver_adapter, + (HALMAC_SDIO_CMD_ADDR_SDIO_REG << 13) | + (REG_SDIO_INDIRECT_REG_CFG & HALMAC_SDIO_LOCAL_MSK), + halmac_offset | BIT(19) | BIT(17)); + + do { + rtemp = PLATFORM_SDIO_CMD52_READ( + driver_adapter, + (HALMAC_SDIO_CMD_ADDR_SDIO_REG << 13) | + ((REG_SDIO_INDIRECT_REG_CFG + 2) & + HALMAC_SDIO_LOCAL_MSK)); + counter--; + } while ((rtemp & BIT(4)) != 0 && counter > 0); + + value32.dword = PLATFORM_SDIO_CMD53_READ_32( + driver_adapter, + (HALMAC_SDIO_CMD_ADDR_SDIO_REG << 13) | + (REG_SDIO_INDIRECT_REG_DATA & HALMAC_SDIO_LOCAL_MSK)); + + return value32.dword; +} diff --git a/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_api_88xx_sdio.h b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_api_88xx_sdio.h new file mode 100644 index 000000000000..ee441eee24d6 --- /dev/null +++ b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_api_88xx_sdio.h @@ -0,0 +1,84 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef _HALMAC_API_88XX_SDIO_H_ +#define _HALMAC_API_88XX_SDIO_H_ + +#include "../halmac_2_platform.h" +#include "../halmac_type.h" + +enum halmac_ret_status +halmac_init_sdio_cfg_88xx(struct halmac_adapter *halmac_adapter); + +enum halmac_ret_status +halmac_deinit_sdio_cfg_88xx(struct halmac_adapter *halmac_adapter); + +enum halmac_ret_status +halmac_cfg_rx_aggregation_88xx_sdio(struct halmac_adapter *halmac_adapter, + struct halmac_rxagg_cfg *phalmac_rxagg_cfg); + +u8 halmac_reg_read_8_sdio_88xx(struct halmac_adapter *halmac_adapter, + u32 halmac_offset); + +enum halmac_ret_status +halmac_reg_write_8_sdio_88xx(struct halmac_adapter *halmac_adapter, + u32 halmac_offset, u8 halmac_data); + +u16 halmac_reg_read_16_sdio_88xx(struct halmac_adapter *halmac_adapter, + u32 halmac_offset); + +enum halmac_ret_status +halmac_reg_write_16_sdio_88xx(struct halmac_adapter *halmac_adapter, + u32 halmac_offset, u16 halmac_data); + +u32 halmac_reg_read_32_sdio_88xx(struct halmac_adapter *halmac_adapter, + u32 halmac_offset); + +enum halmac_ret_status +halmac_reg_write_32_sdio_88xx(struct halmac_adapter *halmac_adapter, + u32 halmac_offset, u32 halmac_data); + +enum halmac_ret_status +halmac_get_sdio_tx_addr_88xx(struct halmac_adapter *halmac_adapter, + u8 *halmac_buf, u32 halmac_size, u32 *pcmd53_addr); + +enum halmac_ret_status +halmac_cfg_tx_agg_align_sdio_88xx(struct halmac_adapter *halmac_adapter, + u8 enable, u16 align_size); + +enum halmac_ret_status halmac_cfg_tx_agg_align_sdio_not_support_88xx( + struct halmac_adapter *halmac_adapter, u8 enable, u16 align_size); + +enum halmac_ret_status +halmac_tx_allowed_sdio_88xx(struct halmac_adapter *halmac_adapter, + u8 *halmac_buf, u32 halmac_size); + +u32 halmac_reg_read_indirect_32_sdio_88xx(struct halmac_adapter *halmac_adapter, + u32 halmac_offset); + +u8 halmac_reg_read_nbyte_sdio_88xx(struct halmac_adapter *halmac_adapter, + u32 halmac_offset, u32 halmac_size, + u8 *halmac_data); + +#endif /* _HALMAC_API_88XX_SDIO_H_ */ diff --git a/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_api_88xx_usb.c b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_api_88xx_usb.c new file mode 100644 index 000000000000..17d7c3cc62ec --- /dev/null +++ b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_api_88xx_usb.c @@ -0,0 +1,554 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#include "halmac_88xx_cfg.h" + +/** + * halmac_init_usb_cfg_88xx() - init USB + * @halmac_adapter : the adapter of halmac + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_init_usb_cfg_88xx(struct halmac_adapter *halmac_adapter) +{ + void *driver_adapter = NULL; + u8 value8 = 0; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_INIT_USB_CFG); + + driver_adapter = halmac_adapter->driver_adapter; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s ==========>\n", __func__); + + value8 |= (BIT_DMA_MODE | + (0x3 << BIT_SHIFT_BURST_CNT)); /* burst number = 4 */ + + if (PLATFORM_REG_READ_8(driver_adapter, REG_SYS_CFG2 + 3) == + 0x20) { /* usb3.0 */ + value8 |= (HALMAC_USB_BURST_SIZE_3_0 << BIT_SHIFT_BURST_SIZE); + } else { + if ((PLATFORM_REG_READ_8(driver_adapter, REG_USB_USBSTAT) & + 0x3) == 0x1) /* usb2.0 */ + value8 |= HALMAC_USB_BURST_SIZE_2_0_HSPEED + << BIT_SHIFT_BURST_SIZE; + else /* usb1.1 */ + value8 |= HALMAC_USB_BURST_SIZE_2_0_FSPEED + << BIT_SHIFT_BURST_SIZE; + } + + PLATFORM_REG_WRITE_8(driver_adapter, REG_RXDMA_MODE, value8); + PLATFORM_REG_WRITE_16( + driver_adapter, REG_TXDMA_OFFSET_CHK, + PLATFORM_REG_READ_16(driver_adapter, REG_TXDMA_OFFSET_CHK) | + BIT_DROP_DATA_EN); + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_deinit_usb_cfg_88xx() - deinit USB + * @halmac_adapter : the adapter of halmac + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_deinit_usb_cfg_88xx(struct halmac_adapter *halmac_adapter) +{ + void *driver_adapter = NULL; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_DEINIT_USB_CFG); + + driver_adapter = halmac_adapter->driver_adapter; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s ==========>\n", __func__); + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_cfg_rx_aggregation_88xx_usb() - config rx aggregation + * @halmac_adapter : the adapter of halmac + * @halmac_rx_agg_mode + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_cfg_rx_aggregation_88xx_usb(struct halmac_adapter *halmac_adapter, + struct halmac_rxagg_cfg *phalmac_rxagg_cfg) +{ + u8 dma_usb_agg; + u8 size = 0, timeout = 0, agg_enable = 0; + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, + HALMAC_API_CFG_RX_AGGREGATION); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s ==========>\n", __func__); + + dma_usb_agg = + HALMAC_REG_READ_8(halmac_adapter, REG_RXDMA_AGG_PG_TH + 3); + agg_enable = HALMAC_REG_READ_8(halmac_adapter, REG_TXDMA_PQ_MAP); + + switch (phalmac_rxagg_cfg->mode) { + case HALMAC_RX_AGG_MODE_NONE: + agg_enable &= ~BIT_RXDMA_AGG_EN; + break; + case HALMAC_RX_AGG_MODE_DMA: + agg_enable |= BIT_RXDMA_AGG_EN; + dma_usb_agg |= BIT(7); + break; + + case HALMAC_RX_AGG_MODE_USB: + agg_enable |= BIT_RXDMA_AGG_EN; + dma_usb_agg &= ~BIT(7); + break; + default: + pr_err("%s switch case not support\n", __func__); + agg_enable &= ~BIT_RXDMA_AGG_EN; + break; + } + + if (!phalmac_rxagg_cfg->threshold.drv_define) { + if (PLATFORM_REG_READ_8(driver_adapter, REG_SYS_CFG2 + 3) == + 0x20) { + /* usb3.0 */ + size = 0x5; + timeout = 0xA; + } else { + /* usb2.0 */ + size = 0x5; + timeout = 0x20; + } + } else { + size = phalmac_rxagg_cfg->threshold.size; + timeout = phalmac_rxagg_cfg->threshold.timeout; + } + + HALMAC_REG_WRITE_8(halmac_adapter, REG_TXDMA_PQ_MAP, agg_enable); + HALMAC_REG_WRITE_8(halmac_adapter, REG_RXDMA_AGG_PG_TH + 3, + dma_usb_agg); + HALMAC_REG_WRITE_16(halmac_adapter, REG_RXDMA_AGG_PG_TH, + (u16)(size | (timeout << BIT_SHIFT_DMA_AGG_TO))); + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_reg_read_8_usb_88xx() - read 1byte register + * @halmac_adapter : the adapter of halmac + * @halmac_offset : register offset + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +u8 halmac_reg_read_8_usb_88xx(struct halmac_adapter *halmac_adapter, + u32 halmac_offset) +{ + u8 value8; + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + value8 = PLATFORM_REG_READ_8(driver_adapter, halmac_offset); + + return value8; +} + +/** + * halmac_reg_write_8_usb_88xx() - write 1byte register + * @halmac_adapter : the adapter of halmac + * @halmac_offset : register offset + * @halmac_data : register value + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_reg_write_8_usb_88xx(struct halmac_adapter *halmac_adapter, + u32 halmac_offset, u8 halmac_data) +{ + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + PLATFORM_REG_WRITE_8(driver_adapter, halmac_offset, halmac_data); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_reg_read_16_usb_88xx() - read 2byte register + * @halmac_adapter : the adapter of halmac + * @halmac_offset : register offset + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +u16 halmac_reg_read_16_usb_88xx(struct halmac_adapter *halmac_adapter, + u32 halmac_offset) +{ + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + union { + u16 word; + u8 byte[2]; + } value16 = {0x0000}; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + value16.word = PLATFORM_REG_READ_16(driver_adapter, halmac_offset); + + return value16.word; +} + +/** + * halmac_reg_write_16_usb_88xx() - write 2byte register + * @halmac_adapter : the adapter of halmac + * @halmac_offset : register offset + * @halmac_data : register value + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_reg_write_16_usb_88xx(struct halmac_adapter *halmac_adapter, + u32 halmac_offset, u16 halmac_data) +{ + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + PLATFORM_REG_WRITE_16(driver_adapter, halmac_offset, halmac_data); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_reg_read_32_usb_88xx() - read 4byte register + * @halmac_adapter : the adapter of halmac + * @halmac_offset : register offset + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +u32 halmac_reg_read_32_usb_88xx(struct halmac_adapter *halmac_adapter, + u32 halmac_offset) +{ + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + union { + u32 dword; + u8 byte[4]; + } value32 = {0x00000000}; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + value32.dword = PLATFORM_REG_READ_32(driver_adapter, halmac_offset); + + return value32.dword; +} + +/** + * halmac_reg_write_32_usb_88xx() - write 4byte register + * @halmac_adapter : the adapter of halmac + * @halmac_offset : register offset + * @halmac_data : register value + * Author : KaiYuan Chang/Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_reg_write_32_usb_88xx(struct halmac_adapter *halmac_adapter, + u32 halmac_offset, u32 halmac_data) +{ + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + PLATFORM_REG_WRITE_32(driver_adapter, halmac_offset, halmac_data); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_set_bulkout_num_usb_88xx() - inform bulk-out num + * @halmac_adapter : the adapter of halmac + * @bulkout_num : usb bulk-out number + * Author : KaiYuan Chang + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_set_bulkout_num_88xx(struct halmac_adapter *halmac_adapter, + u8 bulkout_num) +{ + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_SET_BULKOUT_NUM); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + halmac_adapter->halmac_bulkout_num = bulkout_num; + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_get_usb_bulkout_id_usb_88xx() - get bulk out id for the TX packet + * @halmac_adapter : the adapter of halmac + * @halmac_buf : tx packet, include txdesc + * @halmac_size : tx packet size + * @bulkout_id : usb bulk-out id + * Author : KaiYuan Chang + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_get_usb_bulkout_id_88xx(struct halmac_adapter *halmac_adapter, + u8 *halmac_buf, u32 halmac_size, u8 *bulkout_id) +{ + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + enum halmac_queue_select queue_sel; + enum halmac_dma_mapping dma_mapping; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, + HALMAC_API_GET_USB_BULKOUT_ID); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s ==========>\n", __func__); + + if (!halmac_buf) { + pr_err("halmac_buf is NULL!!\n"); + return HALMAC_RET_DATA_BUF_NULL; + } + + if (halmac_size == 0) { + pr_err("halmac_size is 0!!\n"); + return HALMAC_RET_DATA_SIZE_INCORRECT; + } + + queue_sel = (enum halmac_queue_select)GET_TX_DESC_QSEL(halmac_buf); + + switch (queue_sel) { + case HALMAC_QUEUE_SELECT_VO: + case HALMAC_QUEUE_SELECT_VO_V2: + dma_mapping = + halmac_adapter->halmac_ptcl_queue[HALMAC_PTCL_QUEUE_VO]; + break; + case HALMAC_QUEUE_SELECT_VI: + case HALMAC_QUEUE_SELECT_VI_V2: + dma_mapping = + halmac_adapter->halmac_ptcl_queue[HALMAC_PTCL_QUEUE_VI]; + break; + case HALMAC_QUEUE_SELECT_BE: + case HALMAC_QUEUE_SELECT_BE_V2: + dma_mapping = + halmac_adapter->halmac_ptcl_queue[HALMAC_PTCL_QUEUE_BE]; + break; + case HALMAC_QUEUE_SELECT_BK: + case HALMAC_QUEUE_SELECT_BK_V2: + dma_mapping = + halmac_adapter->halmac_ptcl_queue[HALMAC_PTCL_QUEUE_BK]; + break; + case HALMAC_QUEUE_SELECT_MGNT: + dma_mapping = + halmac_adapter->halmac_ptcl_queue[HALMAC_PTCL_QUEUE_MG]; + break; + case HALMAC_QUEUE_SELECT_HIGH: + case HALMAC_QUEUE_SELECT_BCN: + case HALMAC_QUEUE_SELECT_CMD: + dma_mapping = HALMAC_DMA_MAPPING_HIGH; + break; + default: + pr_err("Qsel is out of range\n"); + return HALMAC_RET_QSEL_INCORRECT; + } + + switch (dma_mapping) { + case HALMAC_DMA_MAPPING_HIGH: + *bulkout_id = 0; + break; + case HALMAC_DMA_MAPPING_NORMAL: + *bulkout_id = 1; + break; + case HALMAC_DMA_MAPPING_LOW: + *bulkout_id = 2; + break; + case HALMAC_DMA_MAPPING_EXTRA: + *bulkout_id = 3; + break; + default: + pr_err("DmaMapping is out of range\n"); + return HALMAC_RET_DMA_MAP_INCORRECT; + } + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_cfg_tx_agg_align_usb_88xx() -config sdio bus tx agg alignment + * @halmac_adapter : the adapter of halmac + * @enable : function enable(1)/disable(0) + * @align_size : sdio bus tx agg alignment size (2^n, n = 3~11) + * Author : Soar Tu + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status halmac_cfg_tx_agg_align_usb_not_support_88xx( + struct halmac_adapter *halmac_adapter, u8 enable, u16 align_size) +{ + struct halmac_api *halmac_api; + void *driver_adapter = NULL; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + if (halmac_api_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_API_INVALID; + + halmac_api_record_id_88xx(halmac_adapter, HALMAC_API_CFG_TX_AGG_ALIGN); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_RT_TRACE( + driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s ==========>\n", __func__); + + HALMAC_RT_TRACE( + driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s not support\n", __func__); + HALMAC_RT_TRACE( + driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} diff --git a/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_api_88xx_usb.h b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_api_88xx_usb.h new file mode 100644 index 000000000000..a3d2a6abd91b --- /dev/null +++ b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_api_88xx_usb.h @@ -0,0 +1,73 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef _HALMAC_API_88XX_USB_H_ +#define _HALMAC_API_88XX_USB_H_ + +#include "../halmac_2_platform.h" +#include "../halmac_type.h" + +enum halmac_ret_status +halmac_init_usb_cfg_88xx(struct halmac_adapter *halmac_adapter); + +enum halmac_ret_status +halmac_deinit_usb_cfg_88xx(struct halmac_adapter *halmac_adapter); + +enum halmac_ret_status +halmac_cfg_rx_aggregation_88xx_usb(struct halmac_adapter *halmac_adapter, + struct halmac_rxagg_cfg *phalmac_rxagg_cfg); + +u8 halmac_reg_read_8_usb_88xx(struct halmac_adapter *halmac_adapter, + u32 halmac_offset); + +enum halmac_ret_status +halmac_reg_write_8_usb_88xx(struct halmac_adapter *halmac_adapter, + u32 halmac_offset, u8 halmac_data); + +u16 halmac_reg_read_16_usb_88xx(struct halmac_adapter *halmac_adapter, + u32 halmac_offset); + +enum halmac_ret_status +halmac_reg_write_16_usb_88xx(struct halmac_adapter *halmac_adapter, + u32 halmac_offset, u16 halmac_data); + +u32 halmac_reg_read_32_usb_88xx(struct halmac_adapter *halmac_adapter, + u32 halmac_offset); + +enum halmac_ret_status +halmac_reg_write_32_usb_88xx(struct halmac_adapter *halmac_adapter, + u32 halmac_offset, u32 halmac_data); + +enum halmac_ret_status +halmac_set_bulkout_num_88xx(struct halmac_adapter *halmac_adapter, + u8 bulkout_num); + +enum halmac_ret_status +halmac_get_usb_bulkout_id_88xx(struct halmac_adapter *halmac_adapter, + u8 *halmac_buf, u32 halmac_size, u8 *bulkout_id); + +enum halmac_ret_status halmac_cfg_tx_agg_align_usb_not_support_88xx( + struct halmac_adapter *halmac_adapter, u8 enable, u16 align_size); + +#endif /* _HALMAC_API_88XX_USB_H_ */ diff --git a/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_func_88xx.c b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_func_88xx.c new file mode 100644 index 000000000000..f33024e4d853 --- /dev/null +++ b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_func_88xx.c @@ -0,0 +1,4494 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#include "halmac_88xx_cfg.h" + +static enum halmac_ret_status +halmac_dump_efuse_fw_88xx(struct halmac_adapter *halmac_adapter); + +static enum halmac_ret_status +halmac_dump_efuse_drv_88xx(struct halmac_adapter *halmac_adapter); + +static enum halmac_ret_status +halmac_update_eeprom_mask_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_pg_efuse_info *pg_efuse_info, + u8 *eeprom_mask_updated); + +static enum halmac_ret_status +halmac_check_efuse_enough_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_pg_efuse_info *pg_efuse_info, + u8 *eeprom_mask_updated); + +static enum halmac_ret_status +halmac_program_efuse_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_pg_efuse_info *pg_efuse_info, + u8 *eeprom_mask_updated); + +static enum halmac_ret_status +halmac_pwr_sub_seq_parer_88xx(struct halmac_adapter *halmac_adapter, u8 cut, + u8 fab, u8 intf, + struct halmac_wl_pwr_cfg_ *pwr_sub_seq_cfg); + +static enum halmac_ret_status +halmac_parse_c2h_debug_88xx(struct halmac_adapter *halmac_adapter, u8 *c2h_buf, + u32 c2h_size); + +static enum halmac_ret_status +halmac_parse_scan_status_rpt_88xx(struct halmac_adapter *halmac_adapter, + u8 *c2h_buf, u32 c2h_size); + +static enum halmac_ret_status +halmac_parse_psd_data_88xx(struct halmac_adapter *halmac_adapter, u8 *c2h_buf, + u32 c2h_size); + +static enum halmac_ret_status +halmac_parse_efuse_data_88xx(struct halmac_adapter *halmac_adapter, u8 *c2h_buf, + u32 c2h_size); + +static enum halmac_ret_status +halmac_parse_h2c_ack_88xx(struct halmac_adapter *halmac_adapter, u8 *c2h_buf, + u32 c2h_size); + +static enum halmac_ret_status +halmac_enqueue_para_buff_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_phy_parameter_info *para_info, + u8 *curr_buff_wptr, bool *end_cmd); + +static enum halmac_ret_status +halmac_parse_h2c_ack_phy_efuse_88xx(struct halmac_adapter *halmac_adapter, + u8 *c2h_buf, u32 c2h_size); + +static enum halmac_ret_status +halmac_parse_h2c_ack_cfg_para_88xx(struct halmac_adapter *halmac_adapter, + u8 *c2h_buf, u32 c2h_size); + +static enum halmac_ret_status +halmac_gen_cfg_para_h2c_88xx(struct halmac_adapter *halmac_adapter, + u8 *h2c_buff); + +static enum halmac_ret_status +halmac_parse_h2c_ack_update_packet_88xx(struct halmac_adapter *halmac_adapter, + u8 *c2h_buf, u32 c2h_size); + +static enum halmac_ret_status +halmac_parse_h2c_ack_update_datapack_88xx(struct halmac_adapter *halmac_adapter, + u8 *c2h_buf, u32 c2h_size); + +static enum halmac_ret_status +halmac_parse_h2c_ack_run_datapack_88xx(struct halmac_adapter *halmac_adapter, + u8 *c2h_buf, u32 c2h_size); + +static enum halmac_ret_status +halmac_parse_h2c_ack_channel_switch_88xx(struct halmac_adapter *halmac_adapter, + u8 *c2h_buf, u32 c2h_size); + +static enum halmac_ret_status +halmac_parse_h2c_ack_iqk_88xx(struct halmac_adapter *halmac_adapter, + u8 *c2h_buf, u32 c2h_size); + +static enum halmac_ret_status +halmac_parse_h2c_ack_power_tracking_88xx(struct halmac_adapter *halmac_adapter, + u8 *c2h_buf, u32 c2h_size); + +void halmac_init_offload_feature_state_machine_88xx( + struct halmac_adapter *halmac_adapter) +{ + struct halmac_state *state = &halmac_adapter->halmac_state; + + state->efuse_state_set.efuse_cmd_construct_state = + HALMAC_EFUSE_CMD_CONSTRUCT_IDLE; + state->efuse_state_set.process_status = HALMAC_CMD_PROCESS_IDLE; + state->efuse_state_set.seq_num = halmac_adapter->h2c_packet_seq; + + state->cfg_para_state_set.cfg_para_cmd_construct_state = + HALMAC_CFG_PARA_CMD_CONSTRUCT_IDLE; + state->cfg_para_state_set.process_status = HALMAC_CMD_PROCESS_IDLE; + state->cfg_para_state_set.seq_num = halmac_adapter->h2c_packet_seq; + + state->scan_state_set.scan_cmd_construct_state = + HALMAC_SCAN_CMD_CONSTRUCT_IDLE; + state->scan_state_set.process_status = HALMAC_CMD_PROCESS_IDLE; + state->scan_state_set.seq_num = halmac_adapter->h2c_packet_seq; + + state->update_packet_set.process_status = HALMAC_CMD_PROCESS_IDLE; + state->update_packet_set.seq_num = halmac_adapter->h2c_packet_seq; + + state->iqk_set.process_status = HALMAC_CMD_PROCESS_IDLE; + state->iqk_set.seq_num = halmac_adapter->h2c_packet_seq; + + state->power_tracking_set.process_status = HALMAC_CMD_PROCESS_IDLE; + state->power_tracking_set.seq_num = halmac_adapter->h2c_packet_seq; + + state->psd_set.process_status = HALMAC_CMD_PROCESS_IDLE; + state->psd_set.seq_num = halmac_adapter->h2c_packet_seq; + state->psd_set.data_size = 0; + state->psd_set.segment_size = 0; + state->psd_set.data = NULL; +} + +enum halmac_ret_status +halmac_dump_efuse_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_efuse_read_cfg cfg) +{ + u32 chk_h2c_init; + void *driver_adapter = NULL; + struct halmac_api *halmac_api = + (struct halmac_api *)halmac_adapter->halmac_api; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + enum halmac_cmd_process_status *process_status = + &halmac_adapter->halmac_state.efuse_state_set.process_status; + + driver_adapter = halmac_adapter->driver_adapter; + + *process_status = HALMAC_CMD_PROCESS_SENDING; + + if (halmac_transition_efuse_state_88xx( + halmac_adapter, HALMAC_EFUSE_CMD_CONSTRUCT_H2C_SENT) != + HALMAC_RET_SUCCESS) + return HALMAC_RET_ERROR_STATE; + + if (cfg == HALMAC_EFUSE_R_AUTO) { + chk_h2c_init = HALMAC_REG_READ_32(halmac_adapter, + REG_H2C_PKT_READADDR); + if (halmac_adapter->halmac_state.dlfw_state == + HALMAC_DLFW_NONE || + chk_h2c_init == 0) + status = halmac_dump_efuse_drv_88xx(halmac_adapter); + else + status = halmac_dump_efuse_fw_88xx(halmac_adapter); + } else if (cfg == HALMAC_EFUSE_R_FW) { + status = halmac_dump_efuse_fw_88xx(halmac_adapter); + } else { + status = halmac_dump_efuse_drv_88xx(halmac_adapter); + } + + if (status != HALMAC_RET_SUCCESS) { + pr_err("halmac_read_efuse error = %x\n", status); + return status; + } + + return status; +} + +enum halmac_ret_status +halmac_func_read_efuse_88xx(struct halmac_adapter *halmac_adapter, u32 offset, + u32 size, u8 *efuse_map) +{ + void *driver_adapter = NULL; + + driver_adapter = halmac_adapter->driver_adapter; + + if (!efuse_map) { + pr_err("Malloc for dump efuse map error\n"); + return HALMAC_RET_NULL_POINTER; + } + + if (halmac_adapter->hal_efuse_map_valid) + memcpy(efuse_map, halmac_adapter->hal_efuse_map + offset, size); + else if (halmac_read_hw_efuse_88xx(halmac_adapter, offset, size, + efuse_map) != HALMAC_RET_SUCCESS) + return HALMAC_RET_EFUSE_R_FAIL; + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status +halmac_read_hw_efuse_88xx(struct halmac_adapter *halmac_adapter, u32 offset, + u32 size, u8 *efuse_map) +{ + u8 value8; + u32 value32; + u32 address; + u32 tmp32, counter; + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + /* Read efuse no need 2.5V LDO */ + value8 = HALMAC_REG_READ_8(halmac_adapter, REG_LDO_EFUSE_CTRL + 3); + if (value8 & BIT(7)) + HALMAC_REG_WRITE_8(halmac_adapter, REG_LDO_EFUSE_CTRL + 3, + (u8)(value8 & ~(BIT(7)))); + + value32 = HALMAC_REG_READ_32(halmac_adapter, REG_EFUSE_CTRL); + + for (address = offset; address < offset + size; address++) { + value32 = value32 & + ~((BIT_MASK_EF_DATA) | + (BIT_MASK_EF_ADDR << BIT_SHIFT_EF_ADDR)); + value32 = value32 | + ((address & BIT_MASK_EF_ADDR) << BIT_SHIFT_EF_ADDR); + HALMAC_REG_WRITE_32(halmac_adapter, REG_EFUSE_CTRL, + value32 & (~BIT_EF_FLAG)); + + counter = 1000000; + do { + udelay(1); + tmp32 = HALMAC_REG_READ_32(halmac_adapter, + REG_EFUSE_CTRL); + counter--; + if (counter == 0) { + pr_err("HALMAC_RET_EFUSE_R_FAIL\n"); + return HALMAC_RET_EFUSE_R_FAIL; + } + } while ((tmp32 & BIT_EF_FLAG) == 0); + + *(efuse_map + address - offset) = + (u8)(tmp32 & BIT_MASK_EF_DATA); + } + + return HALMAC_RET_SUCCESS; +} + +static enum halmac_ret_status +halmac_dump_efuse_drv_88xx(struct halmac_adapter *halmac_adapter) +{ + u8 *efuse_map = NULL; + u32 efuse_size; + void *driver_adapter = NULL; + + driver_adapter = halmac_adapter->driver_adapter; + + efuse_size = halmac_adapter->hw_config_info.efuse_size; + + if (!halmac_adapter->hal_efuse_map) { + halmac_adapter->hal_efuse_map = kzalloc(efuse_size, GFP_KERNEL); + if (!halmac_adapter->hal_efuse_map) { + pr_err("[ERR]halmac allocate efuse map Fail!!\n"); + return HALMAC_RET_MALLOC_FAIL; + } + } + + efuse_map = kzalloc(efuse_size, GFP_KERNEL); + if (!efuse_map) { + /* out of memory */ + return HALMAC_RET_MALLOC_FAIL; + } + + if (halmac_read_hw_efuse_88xx(halmac_adapter, 0, efuse_size, + efuse_map) != HALMAC_RET_SUCCESS) { + kfree(efuse_map); + return HALMAC_RET_EFUSE_R_FAIL; + } + + spin_lock(&halmac_adapter->efuse_lock); + memcpy(halmac_adapter->hal_efuse_map, efuse_map, efuse_size); + halmac_adapter->hal_efuse_map_valid = true; + spin_unlock(&halmac_adapter->efuse_lock); + + kfree(efuse_map); + + return HALMAC_RET_SUCCESS; +} + +static enum halmac_ret_status +halmac_dump_efuse_fw_88xx(struct halmac_adapter *halmac_adapter) +{ + u8 h2c_buff[HALMAC_H2C_CMD_SIZE_88XX] = {0}; + u16 h2c_seq_mum = 0; + void *driver_adapter = NULL; + struct halmac_h2c_header_info h2c_header_info; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + + driver_adapter = halmac_adapter->driver_adapter; + + h2c_header_info.sub_cmd_id = SUB_CMD_ID_DUMP_PHYSICAL_EFUSE; + h2c_header_info.content_size = 0; + h2c_header_info.ack = true; + halmac_set_fw_offload_h2c_header_88xx(halmac_adapter, h2c_buff, + &h2c_header_info, &h2c_seq_mum); + halmac_adapter->halmac_state.efuse_state_set.seq_num = h2c_seq_mum; + + if (!halmac_adapter->hal_efuse_map) { + halmac_adapter->hal_efuse_map = kzalloc( + halmac_adapter->hw_config_info.efuse_size, GFP_KERNEL); + if (!halmac_adapter->hal_efuse_map) { + /* out of memory */ + return HALMAC_RET_MALLOC_FAIL; + } + } + + if (!halmac_adapter->hal_efuse_map_valid) { + status = halmac_send_h2c_pkt_88xx(halmac_adapter, h2c_buff, + HALMAC_H2C_CMD_SIZE_88XX, + true); + if (status != HALMAC_RET_SUCCESS) { + pr_err("halmac_read_efuse_fw Fail = %x!!\n", status); + return status; + } + } + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status +halmac_func_write_efuse_88xx(struct halmac_adapter *halmac_adapter, u32 offset, + u8 value) +{ + const u8 wite_protect_code = 0x69; + u32 value32, tmp32, counter; + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + spin_lock(&halmac_adapter->efuse_lock); + halmac_adapter->hal_efuse_map_valid = false; + spin_unlock(&halmac_adapter->efuse_lock); + + HALMAC_REG_WRITE_8(halmac_adapter, REG_PMC_DBG_CTRL2 + 3, + wite_protect_code); + + /* Enable 2.5V LDO */ + HALMAC_REG_WRITE_8( + halmac_adapter, REG_LDO_EFUSE_CTRL + 3, + (u8)(HALMAC_REG_READ_8(halmac_adapter, REG_LDO_EFUSE_CTRL + 3) | + BIT(7))); + + value32 = HALMAC_REG_READ_32(halmac_adapter, REG_EFUSE_CTRL); + value32 = + value32 & + ~((BIT_MASK_EF_DATA) | (BIT_MASK_EF_ADDR << BIT_SHIFT_EF_ADDR)); + value32 = value32 | ((offset & BIT_MASK_EF_ADDR) << BIT_SHIFT_EF_ADDR) | + (value & BIT_MASK_EF_DATA); + HALMAC_REG_WRITE_32(halmac_adapter, REG_EFUSE_CTRL, + value32 | BIT_EF_FLAG); + + counter = 1000000; + do { + udelay(1); + tmp32 = HALMAC_REG_READ_32(halmac_adapter, REG_EFUSE_CTRL); + counter--; + if (counter == 0) { + pr_err("halmac_write_efuse Fail !!\n"); + return HALMAC_RET_EFUSE_W_FAIL; + } + } while ((tmp32 & BIT_EF_FLAG) == BIT_EF_FLAG); + + HALMAC_REG_WRITE_8(halmac_adapter, REG_PMC_DBG_CTRL2 + 3, 0x00); + + /* Disable 2.5V LDO */ + HALMAC_REG_WRITE_8( + halmac_adapter, REG_LDO_EFUSE_CTRL + 3, + (u8)(HALMAC_REG_READ_8(halmac_adapter, REG_LDO_EFUSE_CTRL + 3) & + ~(BIT(7)))); + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status +halmac_func_switch_efuse_bank_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_efuse_bank efuse_bank) +{ + u8 reg_value; + struct halmac_api *halmac_api; + + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + if (halmac_transition_efuse_state_88xx( + halmac_adapter, HALMAC_EFUSE_CMD_CONSTRUCT_BUSY) != + HALMAC_RET_SUCCESS) + return HALMAC_RET_ERROR_STATE; + + reg_value = HALMAC_REG_READ_8(halmac_adapter, REG_LDO_EFUSE_CTRL + 1); + + if (efuse_bank == (reg_value & (BIT(0) | BIT(1)))) + return HALMAC_RET_SUCCESS; + + reg_value &= ~(BIT(0) | BIT(1)); + reg_value |= efuse_bank; + HALMAC_REG_WRITE_8(halmac_adapter, REG_LDO_EFUSE_CTRL + 1, reg_value); + + if ((HALMAC_REG_READ_8(halmac_adapter, REG_LDO_EFUSE_CTRL + 1) & + (BIT(0) | BIT(1))) != efuse_bank) + return HALMAC_RET_SWITCH_EFUSE_BANK_FAIL; + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status +halmac_eeprom_parser_88xx(struct halmac_adapter *halmac_adapter, + u8 *physical_efuse_map, u8 *logical_efuse_map) +{ + u8 j; + u8 value8; + u8 block_index; + u8 valid_word_enable, word_enable; + u8 efuse_read_header, efuse_read_header2 = 0; + u32 eeprom_index; + u32 efuse_index = 0; + u32 eeprom_size = halmac_adapter->hw_config_info.eeprom_size; + void *driver_adapter = NULL; + + driver_adapter = halmac_adapter->driver_adapter; + + memset(logical_efuse_map, 0xFF, eeprom_size); + + do { + value8 = *(physical_efuse_map + efuse_index); + efuse_read_header = value8; + + if ((efuse_read_header & 0x1f) == 0x0f) { + efuse_index++; + value8 = *(physical_efuse_map + efuse_index); + efuse_read_header2 = value8; + block_index = ((efuse_read_header2 & 0xF0) >> 1) | + ((efuse_read_header >> 5) & 0x07); + word_enable = efuse_read_header2 & 0x0F; + } else { + block_index = (efuse_read_header & 0xF0) >> 4; + word_enable = efuse_read_header & 0x0F; + } + + if (efuse_read_header == 0xff) + break; + + efuse_index++; + + if (efuse_index >= halmac_adapter->hw_config_info.efuse_size - + HALMAC_PROTECTED_EFUSE_SIZE_88XX - 1) + return HALMAC_RET_EEPROM_PARSING_FAIL; + + for (j = 0; j < 4; j++) { + valid_word_enable = + (u8)((~(word_enable >> j)) & BIT(0)); + if (valid_word_enable != 1) + continue; + + eeprom_index = (block_index << 3) + (j << 1); + + if ((eeprom_index + 1) > eeprom_size) { + pr_err("Error: EEPROM addr exceeds eeprom_size:0x%X, at eFuse 0x%X\n", + eeprom_size, efuse_index - 1); + if ((efuse_read_header & 0x1f) == 0x0f) + pr_err("Error: EEPROM header: 0x%X, 0x%X,\n", + efuse_read_header, + efuse_read_header2); + else + pr_err("Error: EEPROM header: 0x%X,\n", + efuse_read_header); + + return HALMAC_RET_EEPROM_PARSING_FAIL; + } + + value8 = *(physical_efuse_map + efuse_index); + *(logical_efuse_map + eeprom_index) = value8; + + eeprom_index++; + efuse_index++; + + if (efuse_index > + halmac_adapter->hw_config_info.efuse_size - + HALMAC_PROTECTED_EFUSE_SIZE_88XX - 1) + return HALMAC_RET_EEPROM_PARSING_FAIL; + + value8 = *(physical_efuse_map + efuse_index); + *(logical_efuse_map + eeprom_index) = value8; + + efuse_index++; + + if (efuse_index > + halmac_adapter->hw_config_info.efuse_size - + HALMAC_PROTECTED_EFUSE_SIZE_88XX) + return HALMAC_RET_EEPROM_PARSING_FAIL; + } + } while (1); + + halmac_adapter->efuse_end = efuse_index; + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status +halmac_read_logical_efuse_map_88xx(struct halmac_adapter *halmac_adapter, + u8 *map) +{ + u8 *efuse_map = NULL; + u32 efuse_size; + void *driver_adapter = NULL; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + + driver_adapter = halmac_adapter->driver_adapter; + efuse_size = halmac_adapter->hw_config_info.efuse_size; + + if (!halmac_adapter->hal_efuse_map_valid) { + efuse_map = kzalloc(efuse_size, GFP_KERNEL); + if (!efuse_map) { + pr_err("[ERR]halmac allocate local efuse map Fail!!\n"); + return HALMAC_RET_MALLOC_FAIL; + } + + status = halmac_func_read_efuse_88xx(halmac_adapter, 0, + efuse_size, efuse_map); + if (status != HALMAC_RET_SUCCESS) { + pr_err("[ERR]halmac_read_efuse error = %x\n", status); + kfree(efuse_map); + return status; + } + + if (!halmac_adapter->hal_efuse_map) { + halmac_adapter->hal_efuse_map = + kzalloc(efuse_size, GFP_KERNEL); + if (!halmac_adapter->hal_efuse_map) { + pr_err("[ERR]halmac allocate efuse map Fail!!\n"); + kfree(efuse_map); + return HALMAC_RET_MALLOC_FAIL; + } + } + + spin_lock(&halmac_adapter->efuse_lock); + memcpy(halmac_adapter->hal_efuse_map, efuse_map, efuse_size); + halmac_adapter->hal_efuse_map_valid = true; + spin_unlock(&halmac_adapter->efuse_lock); + + kfree(efuse_map); + } + + if (halmac_eeprom_parser_88xx(halmac_adapter, + halmac_adapter->hal_efuse_map, + map) != HALMAC_RET_SUCCESS) + return HALMAC_RET_EEPROM_PARSING_FAIL; + + return status; +} + +enum halmac_ret_status +halmac_func_write_logical_efuse_88xx(struct halmac_adapter *halmac_adapter, + u32 offset, u8 value) +{ + u8 pg_efuse_byte1, pg_efuse_byte2; + u8 pg_block, pg_block_index; + u8 pg_efuse_header, pg_efuse_header2; + u8 *eeprom_map = NULL; + u32 eeprom_size = halmac_adapter->hw_config_info.eeprom_size; + u32 efuse_end, pg_efuse_num; + void *driver_adapter = NULL; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + + driver_adapter = halmac_adapter->driver_adapter; + + eeprom_map = kzalloc(eeprom_size, GFP_KERNEL); + if (!eeprom_map) { + /* out of memory */ + return HALMAC_RET_MALLOC_FAIL; + } + memset(eeprom_map, 0xFF, eeprom_size); + + status = halmac_read_logical_efuse_map_88xx(halmac_adapter, eeprom_map); + if (status != HALMAC_RET_SUCCESS) { + pr_err("[ERR]halmac_read_logical_efuse_map_88xx error = %x\n", + status); + kfree(eeprom_map); + return status; + } + + if (*(eeprom_map + offset) != value) { + efuse_end = halmac_adapter->efuse_end; + pg_block = (u8)(offset >> 3); + pg_block_index = (u8)((offset & (8 - 1)) >> 1); + + if (offset > 0x7f) { + pg_efuse_header = + (((pg_block & 0x07) << 5) & 0xE0) | 0x0F; + pg_efuse_header2 = + (u8)(((pg_block & 0x78) << 1) + + ((0x1 << pg_block_index) ^ 0x0F)); + } else { + pg_efuse_header = + (u8)((pg_block << 4) + + ((0x01 << pg_block_index) ^ 0x0F)); + } + + if ((offset & 1) == 0) { + pg_efuse_byte1 = value; + pg_efuse_byte2 = *(eeprom_map + offset + 1); + } else { + pg_efuse_byte1 = *(eeprom_map + offset - 1); + pg_efuse_byte2 = value; + } + + if (offset > 0x7f) { + pg_efuse_num = 4; + if (halmac_adapter->hw_config_info.efuse_size <= + (pg_efuse_num + HALMAC_PROTECTED_EFUSE_SIZE_88XX + + halmac_adapter->efuse_end)) { + kfree(eeprom_map); + return HALMAC_RET_EFUSE_NOT_ENOUGH; + } + halmac_func_write_efuse_88xx(halmac_adapter, efuse_end, + pg_efuse_header); + halmac_func_write_efuse_88xx(halmac_adapter, + efuse_end + 1, + pg_efuse_header2); + halmac_func_write_efuse_88xx( + halmac_adapter, efuse_end + 2, pg_efuse_byte1); + status = halmac_func_write_efuse_88xx( + halmac_adapter, efuse_end + 3, pg_efuse_byte2); + } else { + pg_efuse_num = 3; + if (halmac_adapter->hw_config_info.efuse_size <= + (pg_efuse_num + HALMAC_PROTECTED_EFUSE_SIZE_88XX + + halmac_adapter->efuse_end)) { + kfree(eeprom_map); + return HALMAC_RET_EFUSE_NOT_ENOUGH; + } + halmac_func_write_efuse_88xx(halmac_adapter, efuse_end, + pg_efuse_header); + halmac_func_write_efuse_88xx( + halmac_adapter, efuse_end + 1, pg_efuse_byte1); + status = halmac_func_write_efuse_88xx( + halmac_adapter, efuse_end + 2, pg_efuse_byte2); + } + + if (status != HALMAC_RET_SUCCESS) { + pr_err("[ERR]halmac_write_logical_efuse error = %x\n", + status); + kfree(eeprom_map); + return status; + } + } + + kfree(eeprom_map); + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status +halmac_func_pg_efuse_by_map_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_pg_efuse_info *pg_efuse_info, + enum halmac_efuse_read_cfg cfg) +{ + u8 *eeprom_mask_updated = NULL; + u32 eeprom_mask_size = halmac_adapter->hw_config_info.eeprom_size >> 4; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + + eeprom_mask_updated = kzalloc(eeprom_mask_size, GFP_KERNEL); + if (!eeprom_mask_updated) { + /* out of memory */ + return HALMAC_RET_MALLOC_FAIL; + } + + status = halmac_update_eeprom_mask_88xx(halmac_adapter, pg_efuse_info, + eeprom_mask_updated); + + if (status != HALMAC_RET_SUCCESS) { + pr_err("[ERR]halmac_update_eeprom_mask_88xx error = %x\n", + status); + kfree(eeprom_mask_updated); + return status; + } + + status = halmac_check_efuse_enough_88xx(halmac_adapter, pg_efuse_info, + eeprom_mask_updated); + + if (status != HALMAC_RET_SUCCESS) { + pr_err("[ERR]halmac_check_efuse_enough_88xx error = %x\n", + status); + kfree(eeprom_mask_updated); + return status; + } + + status = halmac_program_efuse_88xx(halmac_adapter, pg_efuse_info, + eeprom_mask_updated); + + if (status != HALMAC_RET_SUCCESS) { + pr_err("[ERR]halmac_program_efuse_88xx error = %x\n", status); + kfree(eeprom_mask_updated); + return status; + } + + kfree(eeprom_mask_updated); + + return HALMAC_RET_SUCCESS; +} + +static enum halmac_ret_status +halmac_update_eeprom_mask_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_pg_efuse_info *pg_efuse_info, + u8 *eeprom_mask_updated) +{ + u8 *eeprom_map = NULL; + u32 eeprom_size = halmac_adapter->hw_config_info.eeprom_size; + u8 *eeprom_map_pg, *eeprom_mask; + u16 i, j; + u16 map_byte_offset, mask_byte_offset; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + + void *driver_adapter = NULL; + + driver_adapter = halmac_adapter->driver_adapter; + + eeprom_map = kzalloc(eeprom_size, GFP_KERNEL); + if (!eeprom_map) { + /* out of memory */ + return HALMAC_RET_MALLOC_FAIL; + } + memset(eeprom_map, 0xFF, eeprom_size); + + memset(eeprom_mask_updated, 0x00, pg_efuse_info->efuse_mask_size); + + status = halmac_read_logical_efuse_map_88xx(halmac_adapter, eeprom_map); + + if (status != HALMAC_RET_SUCCESS) { + kfree(eeprom_map); + return status; + } + + eeprom_map_pg = pg_efuse_info->efuse_map; + eeprom_mask = pg_efuse_info->efuse_mask; + + for (i = 0; i < pg_efuse_info->efuse_mask_size; i++) + *(eeprom_mask_updated + i) = *(eeprom_mask + i); + + for (i = 0; i < pg_efuse_info->efuse_map_size; i = i + 16) { + for (j = 0; j < 16; j = j + 2) { + map_byte_offset = i + j; + mask_byte_offset = i >> 4; + if (*(eeprom_map_pg + map_byte_offset) == + *(eeprom_map + map_byte_offset)) { + if (*(eeprom_map_pg + map_byte_offset + 1) == + *(eeprom_map + map_byte_offset + 1)) { + switch (j) { + case 0: + *(eeprom_mask_updated + + mask_byte_offset) = + *(eeprom_mask_updated + + mask_byte_offset) & + (BIT(4) ^ 0xFF); + break; + case 2: + *(eeprom_mask_updated + + mask_byte_offset) = + *(eeprom_mask_updated + + mask_byte_offset) & + (BIT(5) ^ 0xFF); + break; + case 4: + *(eeprom_mask_updated + + mask_byte_offset) = + *(eeprom_mask_updated + + mask_byte_offset) & + (BIT(6) ^ 0xFF); + break; + case 6: + *(eeprom_mask_updated + + mask_byte_offset) = + *(eeprom_mask_updated + + mask_byte_offset) & + (BIT(7) ^ 0xFF); + break; + case 8: + *(eeprom_mask_updated + + mask_byte_offset) = + *(eeprom_mask_updated + + mask_byte_offset) & + (BIT(0) ^ 0xFF); + break; + case 10: + *(eeprom_mask_updated + + mask_byte_offset) = + *(eeprom_mask_updated + + mask_byte_offset) & + (BIT(1) ^ 0xFF); + break; + case 12: + *(eeprom_mask_updated + + mask_byte_offset) = + *(eeprom_mask_updated + + mask_byte_offset) & + (BIT(2) ^ 0xFF); + break; + case 14: + *(eeprom_mask_updated + + mask_byte_offset) = + *(eeprom_mask_updated + + mask_byte_offset) & + (BIT(3) ^ 0xFF); + break; + default: + break; + } + } + } + } + } + + kfree(eeprom_map); + + return status; +} + +static enum halmac_ret_status +halmac_check_efuse_enough_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_pg_efuse_info *pg_efuse_info, + u8 *eeprom_mask_updated) +{ + u8 pre_word_enb, word_enb; + u8 pg_efuse_header, pg_efuse_header2; + u8 pg_block; + u16 i, j; + u32 efuse_end; + u32 tmp_eeprom_offset, pg_efuse_num = 0; + + efuse_end = halmac_adapter->efuse_end; + + for (i = 0; i < pg_efuse_info->efuse_map_size; i = i + 8) { + tmp_eeprom_offset = i; + + if ((tmp_eeprom_offset & 7) > 0) { + pre_word_enb = + (*(eeprom_mask_updated + (i >> 4)) & 0x0F); + word_enb = pre_word_enb ^ 0x0F; + } else { + pre_word_enb = (*(eeprom_mask_updated + (i >> 4)) >> 4); + word_enb = pre_word_enb ^ 0x0F; + } + + pg_block = (u8)(tmp_eeprom_offset >> 3); + + if (pre_word_enb > 0) { + if (tmp_eeprom_offset > 0x7f) { + pg_efuse_header = + (((pg_block & 0x07) << 5) & 0xE0) | + 0x0F; + pg_efuse_header2 = (u8)( + ((pg_block & 0x78) << 1) + word_enb); + } else { + pg_efuse_header = + (u8)((pg_block << 4) + word_enb); + } + + if (tmp_eeprom_offset > 0x7f) { + pg_efuse_num++; + pg_efuse_num++; + efuse_end = efuse_end + 2; + for (j = 0; j < 4; j++) { + if (((pre_word_enb >> j) & 0x1) > 0) { + pg_efuse_num++; + pg_efuse_num++; + efuse_end = efuse_end + 2; + } + } + } else { + pg_efuse_num++; + efuse_end = efuse_end + 1; + for (j = 0; j < 4; j++) { + if (((pre_word_enb >> j) & 0x1) > 0) { + pg_efuse_num++; + pg_efuse_num++; + efuse_end = efuse_end + 2; + } + } + } + } + } + + if (halmac_adapter->hw_config_info.efuse_size <= + (pg_efuse_num + HALMAC_PROTECTED_EFUSE_SIZE_88XX + + halmac_adapter->efuse_end)) + return HALMAC_RET_EFUSE_NOT_ENOUGH; + + return HALMAC_RET_SUCCESS; +} + +static enum halmac_ret_status +halmac_program_efuse_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_pg_efuse_info *pg_efuse_info, + u8 *eeprom_mask_updated) +{ + u8 pre_word_enb, word_enb; + u8 pg_efuse_header, pg_efuse_header2; + u8 pg_block; + u16 i, j; + u32 efuse_end; + u32 tmp_eeprom_offset; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + + efuse_end = halmac_adapter->efuse_end; + + for (i = 0; i < pg_efuse_info->efuse_map_size; i = i + 8) { + tmp_eeprom_offset = i; + + if (((tmp_eeprom_offset >> 3) & 1) > 0) { + pre_word_enb = + (*(eeprom_mask_updated + (i >> 4)) & 0x0F); + word_enb = pre_word_enb ^ 0x0F; + } else { + pre_word_enb = (*(eeprom_mask_updated + (i >> 4)) >> 4); + word_enb = pre_word_enb ^ 0x0F; + } + + pg_block = (u8)(tmp_eeprom_offset >> 3); + + if (pre_word_enb <= 0) + continue; + + if (tmp_eeprom_offset > 0x7f) { + pg_efuse_header = + (((pg_block & 0x07) << 5) & 0xE0) | 0x0F; + pg_efuse_header2 = + (u8)(((pg_block & 0x78) << 1) + word_enb); + } else { + pg_efuse_header = (u8)((pg_block << 4) + word_enb); + } + + if (tmp_eeprom_offset > 0x7f) { + halmac_func_write_efuse_88xx(halmac_adapter, efuse_end, + pg_efuse_header); + status = halmac_func_write_efuse_88xx(halmac_adapter, + efuse_end + 1, + pg_efuse_header2); + efuse_end = efuse_end + 2; + for (j = 0; j < 4; j++) { + if (((pre_word_enb >> j) & 0x1) > 0) { + halmac_func_write_efuse_88xx( + halmac_adapter, efuse_end, + *(pg_efuse_info->efuse_map + + tmp_eeprom_offset + + (j << 1))); + status = halmac_func_write_efuse_88xx( + halmac_adapter, efuse_end + 1, + *(pg_efuse_info->efuse_map + + tmp_eeprom_offset + (j << 1) + + 1)); + efuse_end = efuse_end + 2; + } + } + } else { + status = halmac_func_write_efuse_88xx( + halmac_adapter, efuse_end, pg_efuse_header); + efuse_end = efuse_end + 1; + for (j = 0; j < 4; j++) { + if (((pre_word_enb >> j) & 0x1) > 0) { + halmac_func_write_efuse_88xx( + halmac_adapter, efuse_end, + *(pg_efuse_info->efuse_map + + tmp_eeprom_offset + + (j << 1))); + status = halmac_func_write_efuse_88xx( + halmac_adapter, efuse_end + 1, + *(pg_efuse_info->efuse_map + + tmp_eeprom_offset + (j << 1) + + 1)); + efuse_end = efuse_end + 2; + } + } + } + } + + return status; +} + +enum halmac_ret_status +halmac_dlfw_to_mem_88xx(struct halmac_adapter *halmac_adapter, u8 *ram_code, + u32 dest, u32 code_size) +{ + u8 *code_ptr; + u8 first_part; + u32 mem_offset; + u32 pkt_size_tmp, send_pkt_size; + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + code_ptr = ram_code; + mem_offset = 0; + first_part = 1; + pkt_size_tmp = code_size; + + HALMAC_REG_WRITE_32( + halmac_adapter, REG_DDMA_CH0CTRL, + HALMAC_REG_READ_32(halmac_adapter, REG_DDMA_CH0CTRL) | + BIT_DDMACH0_RESET_CHKSUM_STS); + + while (pkt_size_tmp != 0) { + if (pkt_size_tmp >= halmac_adapter->max_download_size) + send_pkt_size = halmac_adapter->max_download_size; + else + send_pkt_size = pkt_size_tmp; + + if (halmac_send_fwpkt_88xx( + halmac_adapter, code_ptr + mem_offset, + send_pkt_size) != HALMAC_RET_SUCCESS) { + pr_err("halmac_send_fwpkt_88xx fail!!"); + return HALMAC_RET_DLFW_FAIL; + } + + if (halmac_iddma_dlfw_88xx( + halmac_adapter, + HALMAC_OCPBASE_TXBUF_88XX + + halmac_adapter->hw_config_info.txdesc_size, + dest + mem_offset, send_pkt_size, + first_part) != HALMAC_RET_SUCCESS) { + pr_err("halmac_iddma_dlfw_88xx fail!!"); + return HALMAC_RET_DLFW_FAIL; + } + + first_part = 0; + mem_offset += send_pkt_size; + pkt_size_tmp -= send_pkt_size; + } + + if (halmac_check_fw_chksum_88xx(halmac_adapter, dest) != + HALMAC_RET_SUCCESS) { + pr_err("halmac_check_fw_chksum_88xx fail!!"); + return HALMAC_RET_DLFW_FAIL; + } + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status +halmac_send_fwpkt_88xx(struct halmac_adapter *halmac_adapter, u8 *ram_code, + u32 code_size) +{ + if (halmac_download_rsvd_page_88xx(halmac_adapter, ram_code, + code_size) != HALMAC_RET_SUCCESS) { + pr_err("PLATFORM_SEND_RSVD_PAGE 0 error!!\n"); + return HALMAC_RET_DL_RSVD_PAGE_FAIL; + } + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status +halmac_iddma_dlfw_88xx(struct halmac_adapter *halmac_adapter, u32 source, + u32 dest, u32 length, u8 first) +{ + u32 counter; + u32 ch0_control = (u32)(BIT_DDMACH0_CHKSUM_EN | BIT_DDMACH0_OWN); + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + counter = HALMC_DDMA_POLLING_COUNT; + while (HALMAC_REG_READ_32(halmac_adapter, REG_DDMA_CH0CTRL) & + BIT_DDMACH0_OWN) { + counter--; + if (counter == 0) { + pr_err("%s error-1!!\n", __func__); + return HALMAC_RET_DDMA_FAIL; + } + } + + ch0_control |= (length & BIT_MASK_DDMACH0_DLEN); + if (first == 0) + ch0_control |= BIT_DDMACH0_CHKSUM_CONT; + + HALMAC_REG_WRITE_32(halmac_adapter, REG_DDMA_CH0SA, source); + HALMAC_REG_WRITE_32(halmac_adapter, REG_DDMA_CH0DA, dest); + HALMAC_REG_WRITE_32(halmac_adapter, REG_DDMA_CH0CTRL, ch0_control); + + counter = HALMC_DDMA_POLLING_COUNT; + while (HALMAC_REG_READ_32(halmac_adapter, REG_DDMA_CH0CTRL) & + BIT_DDMACH0_OWN) { + counter--; + if (counter == 0) { + pr_err("%s error-2!!\n", __func__); + return HALMAC_RET_DDMA_FAIL; + } + } + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status +halmac_check_fw_chksum_88xx(struct halmac_adapter *halmac_adapter, + u32 memory_address) +{ + u8 mcu_fw_ctrl; + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + enum halmac_ret_status status; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + mcu_fw_ctrl = HALMAC_REG_READ_8(halmac_adapter, REG_MCUFW_CTRL); + + if (HALMAC_REG_READ_32(halmac_adapter, REG_DDMA_CH0CTRL) & + BIT_DDMACH0_CHKSUM_STS) { + if (memory_address < HALMAC_OCPBASE_DMEM_88XX) { + mcu_fw_ctrl |= BIT_IMEM_DW_OK; + HALMAC_REG_WRITE_8( + halmac_adapter, REG_MCUFW_CTRL, + (u8)(mcu_fw_ctrl & ~(BIT_IMEM_CHKSUM_OK))); + } else { + mcu_fw_ctrl |= BIT_DMEM_DW_OK; + HALMAC_REG_WRITE_8( + halmac_adapter, REG_MCUFW_CTRL, + (u8)(mcu_fw_ctrl & ~(BIT_DMEM_CHKSUM_OK))); + } + + pr_err("%s error!!\n", __func__); + + status = HALMAC_RET_FW_CHECKSUM_FAIL; + } else { + if (memory_address < HALMAC_OCPBASE_DMEM_88XX) { + mcu_fw_ctrl |= BIT_IMEM_DW_OK; + HALMAC_REG_WRITE_8( + halmac_adapter, REG_MCUFW_CTRL, + (u8)(mcu_fw_ctrl | BIT_IMEM_CHKSUM_OK)); + } else { + mcu_fw_ctrl |= BIT_DMEM_DW_OK; + HALMAC_REG_WRITE_8( + halmac_adapter, REG_MCUFW_CTRL, + (u8)(mcu_fw_ctrl | BIT_DMEM_CHKSUM_OK)); + } + + status = HALMAC_RET_SUCCESS; + } + + return status; +} + +enum halmac_ret_status +halmac_dlfw_end_flow_88xx(struct halmac_adapter *halmac_adapter) +{ + u8 value8; + u32 counter; + void *driver_adapter = halmac_adapter->driver_adapter; + struct halmac_api *halmac_api = + (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_REG_WRITE_32(halmac_adapter, REG_TXDMA_STATUS, BIT(2)); + + /* Check IMEM & DMEM checksum is OK or not */ + if ((HALMAC_REG_READ_8(halmac_adapter, REG_MCUFW_CTRL) & 0x50) == 0x50) + HALMAC_REG_WRITE_16(halmac_adapter, REG_MCUFW_CTRL, + (u16)(HALMAC_REG_READ_16(halmac_adapter, + REG_MCUFW_CTRL) | + BIT_FW_DW_RDY)); + else + return HALMAC_RET_DLFW_FAIL; + + HALMAC_REG_WRITE_8( + halmac_adapter, REG_MCUFW_CTRL, + (u8)(HALMAC_REG_READ_8(halmac_adapter, REG_MCUFW_CTRL) & + ~(BIT(0)))); + + value8 = HALMAC_REG_READ_8(halmac_adapter, REG_RSV_CTRL + 1); + value8 = (u8)(value8 | BIT(0)); + HALMAC_REG_WRITE_8(halmac_adapter, REG_RSV_CTRL + 1, value8); + + value8 = HALMAC_REG_READ_8(halmac_adapter, REG_SYS_FUNC_EN + 1); + value8 = (u8)(value8 | BIT(2)); + HALMAC_REG_WRITE_8(halmac_adapter, REG_SYS_FUNC_EN + 1, + value8); /* Release MCU reset */ + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "Download Finish, Reset CPU\n"); + + counter = 10000; + while (HALMAC_REG_READ_16(halmac_adapter, REG_MCUFW_CTRL) != 0xC078) { + if (counter == 0) { + pr_err("Check 0x80 = 0xC078 fail\n"); + if ((HALMAC_REG_READ_32(halmac_adapter, REG_FW_DBG7) & + 0xFFFFFF00) == 0xFAAAAA00) + pr_err("Key fail\n"); + return HALMAC_RET_DLFW_FAIL; + } + counter--; + usleep_range(50, 60); + } + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "Check 0x80 = 0xC078 counter = %d\n", counter); + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status +halmac_free_dl_fw_end_flow_88xx(struct halmac_adapter *halmac_adapter) +{ + u32 counter; + struct halmac_api *halmac_api = + (struct halmac_api *)halmac_adapter->halmac_api; + + counter = 100; + while (HALMAC_REG_READ_8(halmac_adapter, REG_HMETFR + 3) != 0) { + counter--; + if (counter == 0) { + pr_err("[ERR]0x1CF != 0\n"); + return HALMAC_RET_DLFW_FAIL; + } + usleep_range(50, 60); + } + + HALMAC_REG_WRITE_8(halmac_adapter, REG_HMETFR + 3, + ID_INFORM_DLEMEM_RDY); + + counter = 10000; + while (HALMAC_REG_READ_8(halmac_adapter, REG_C2HEVT_3 + 3) != + ID_INFORM_DLEMEM_RDY) { + counter--; + if (counter == 0) { + pr_err("[ERR]0x1AF != 0x80\n"); + return HALMAC_RET_DLFW_FAIL; + } + usleep_range(50, 60); + } + + HALMAC_REG_WRITE_8(halmac_adapter, REG_C2HEVT_3 + 3, 0); + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status +halmac_pwr_seq_parser_88xx(struct halmac_adapter *halmac_adapter, u8 cut, + u8 fab, u8 intf, + struct halmac_wl_pwr_cfg_ **pp_pwr_seq_cfg) +{ + u32 seq_idx = 0; + void *driver_adapter = NULL; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + struct halmac_wl_pwr_cfg_ *seq_cmd; + + driver_adapter = halmac_adapter->driver_adapter; + + do { + seq_cmd = pp_pwr_seq_cfg[seq_idx]; + + if (!seq_cmd) + break; + + status = halmac_pwr_sub_seq_parer_88xx(halmac_adapter, cut, fab, + intf, seq_cmd); + if (status != HALMAC_RET_SUCCESS) { + pr_err("[Err]pwr sub seq parser fail, status = 0x%X!\n", + status); + return status; + } + + seq_idx++; + } while (1); + + return status; +} + +static enum halmac_ret_status +halmac_pwr_sub_seq_parer_do_cmd_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_wl_pwr_cfg_ *sub_seq_cmd, + bool *reti) +{ + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + u8 value, flag; + u8 polling_bit; + u32 polling_count; + static u32 poll_to_static; + u32 offset; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + *reti = true; + + switch (sub_seq_cmd->cmd) { + case HALMAC_PWR_CMD_WRITE: + if (sub_seq_cmd->base == HALMAC_PWR_BASEADDR_SDIO) + offset = sub_seq_cmd->offset | SDIO_LOCAL_OFFSET; + else + offset = sub_seq_cmd->offset; + + value = HALMAC_REG_READ_8(halmac_adapter, offset); + value = (u8)(value & (u8)(~(sub_seq_cmd->msk))); + value = (u8)(value | + (u8)(sub_seq_cmd->value & sub_seq_cmd->msk)); + + HALMAC_REG_WRITE_8(halmac_adapter, offset, value); + break; + case HALMAC_PWR_CMD_POLLING: + polling_bit = 0; + polling_count = HALMAC_POLLING_READY_TIMEOUT_COUNT; + flag = 0; + + if (sub_seq_cmd->base == HALMAC_PWR_BASEADDR_SDIO) + offset = sub_seq_cmd->offset | SDIO_LOCAL_OFFSET; + else + offset = sub_seq_cmd->offset; + + do { + polling_count--; + value = HALMAC_REG_READ_8(halmac_adapter, offset); + value = (u8)(value & sub_seq_cmd->msk); + + if (value == (sub_seq_cmd->value & sub_seq_cmd->msk)) { + polling_bit = 1; + continue; + } + + if (polling_count != 0) { + usleep_range(50, 60); + continue; + } + + if (halmac_adapter->halmac_interface == + HALMAC_INTERFACE_PCIE && + flag == 0) { + /* For PCIE + USB package poll power bit + * timeout issue + */ + poll_to_static++; + HALMAC_RT_TRACE( + driver_adapter, HALMAC_MSG_PWR, + DBG_WARNING, + "[WARN]PCIE polling timeout : %d!!\n", + poll_to_static); + HALMAC_REG_WRITE_8( + halmac_adapter, REG_SYS_PW_CTRL, + HALMAC_REG_READ_8(halmac_adapter, + REG_SYS_PW_CTRL) | + BIT(3)); + HALMAC_REG_WRITE_8( + halmac_adapter, REG_SYS_PW_CTRL, + HALMAC_REG_READ_8(halmac_adapter, + REG_SYS_PW_CTRL) & + ~BIT(3)); + polling_bit = 0; + polling_count = + HALMAC_POLLING_READY_TIMEOUT_COUNT; + flag = 1; + } else { + pr_err("[ERR]Pwr cmd polling timeout!!\n"); + pr_err("[ERR]Pwr cmd offset : %X!!\n", + sub_seq_cmd->offset); + pr_err("[ERR]Pwr cmd value : %X!!\n", + sub_seq_cmd->value); + pr_err("[ERR]Pwr cmd msk : %X!!\n", + sub_seq_cmd->msk); + pr_err("[ERR]Read offset = %X value = %X!!\n", + offset, value); + return HALMAC_RET_PWRSEQ_POLLING_FAIL; + } + } while (!polling_bit); + break; + case HALMAC_PWR_CMD_DELAY: + if (sub_seq_cmd->value == HALMAC_PWRSEQ_DELAY_US) + udelay(sub_seq_cmd->offset); + else + usleep_range(1000 * sub_seq_cmd->offset, + 1000 * sub_seq_cmd->offset + 100); + + break; + case HALMAC_PWR_CMD_READ: + break; + case HALMAC_PWR_CMD_END: + return HALMAC_RET_SUCCESS; + default: + return HALMAC_RET_PWRSEQ_CMD_INCORRECT; + } + + *reti = false; + + return HALMAC_RET_SUCCESS; +} + +static enum halmac_ret_status +halmac_pwr_sub_seq_parer_88xx(struct halmac_adapter *halmac_adapter, u8 cut, + u8 fab, u8 intf, + struct halmac_wl_pwr_cfg_ *pwr_sub_seq_cfg) +{ + struct halmac_wl_pwr_cfg_ *sub_seq_cmd; + bool reti; + enum halmac_ret_status status; + + for (sub_seq_cmd = pwr_sub_seq_cfg;; sub_seq_cmd++) { + if ((sub_seq_cmd->interface_msk & intf) && + (sub_seq_cmd->fab_msk & fab) && + (sub_seq_cmd->cut_msk & cut)) { + status = halmac_pwr_sub_seq_parer_do_cmd_88xx( + halmac_adapter, sub_seq_cmd, &reti); + + if (reti) + return status; + } + } + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status +halmac_get_h2c_buff_free_space_88xx(struct halmac_adapter *halmac_adapter) +{ + u32 hw_wptr, fw_rptr; + struct halmac_api *halmac_api = + (struct halmac_api *)halmac_adapter->halmac_api; + + hw_wptr = HALMAC_REG_READ_32(halmac_adapter, REG_H2C_PKT_WRITEADDR) & + BIT_MASK_H2C_WR_ADDR; + fw_rptr = HALMAC_REG_READ_32(halmac_adapter, REG_H2C_PKT_READADDR) & + BIT_MASK_H2C_READ_ADDR; + + if (hw_wptr >= fw_rptr) + halmac_adapter->h2c_buf_free_space = + halmac_adapter->h2c_buff_size - (hw_wptr - fw_rptr); + else + halmac_adapter->h2c_buf_free_space = fw_rptr - hw_wptr; + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status +halmac_send_h2c_pkt_88xx(struct halmac_adapter *halmac_adapter, u8 *hal_h2c_cmd, + u32 size, bool ack) +{ + u32 counter = 100; + void *driver_adapter = halmac_adapter->driver_adapter; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + + while (halmac_adapter->h2c_buf_free_space <= + HALMAC_H2C_CMD_SIZE_UNIT_88XX) { + halmac_get_h2c_buff_free_space_88xx(halmac_adapter); + counter--; + if (counter == 0) { + pr_err("h2c free space is not enough!!\n"); + return HALMAC_RET_H2C_SPACE_FULL; + } + } + + /* Send TxDesc + H2C_CMD */ + if (!PLATFORM_SEND_H2C_PKT(driver_adapter, hal_h2c_cmd, size)) { + pr_err("Send H2C_CMD pkt error!!\n"); + return HALMAC_RET_SEND_H2C_FAIL; + } + + halmac_adapter->h2c_buf_free_space -= HALMAC_H2C_CMD_SIZE_UNIT_88XX; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "H2C free space : %d\n", + halmac_adapter->h2c_buf_free_space); + + return status; +} + +enum halmac_ret_status +halmac_download_rsvd_page_88xx(struct halmac_adapter *halmac_adapter, + u8 *hal_buf, u32 size) +{ + u8 restore[3]; + u8 value8; + u32 counter; + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + if (size == 0) { + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "Rsvd page packet size is zero!!\n"); + return HALMAC_RET_ZERO_LEN_RSVD_PACKET; + } + + value8 = HALMAC_REG_READ_8(halmac_adapter, REG_FIFOPAGE_CTRL_2 + 1); + value8 = (u8)(value8 | BIT(7)); + HALMAC_REG_WRITE_8(halmac_adapter, REG_FIFOPAGE_CTRL_2 + 1, value8); + + value8 = HALMAC_REG_READ_8(halmac_adapter, REG_CR + 1); + restore[0] = value8; + value8 = (u8)(value8 | BIT(0)); + HALMAC_REG_WRITE_8(halmac_adapter, REG_CR + 1, value8); + + value8 = HALMAC_REG_READ_8(halmac_adapter, REG_BCN_CTRL); + restore[1] = value8; + value8 = (u8)((value8 & ~(BIT(3))) | BIT(4)); + HALMAC_REG_WRITE_8(halmac_adapter, REG_BCN_CTRL, value8); + + value8 = HALMAC_REG_READ_8(halmac_adapter, REG_FWHW_TXQ_CTRL + 2); + restore[2] = value8; + value8 = (u8)(value8 & ~(BIT(6))); + HALMAC_REG_WRITE_8(halmac_adapter, REG_FWHW_TXQ_CTRL + 2, value8); + + if (!PLATFORM_SEND_RSVD_PAGE(driver_adapter, hal_buf, size)) { + pr_err("PLATFORM_SEND_RSVD_PAGE 1 error!!\n"); + status = HALMAC_RET_DL_RSVD_PAGE_FAIL; + } + + /* Check Bcn_Valid_Bit */ + counter = 1000; + while (!(HALMAC_REG_READ_8(halmac_adapter, REG_FIFOPAGE_CTRL_2 + 1) & + BIT(7))) { + udelay(10); + counter--; + if (counter == 0) { + pr_err("Polling Bcn_Valid_Fail error!!\n"); + status = HALMAC_RET_POLLING_BCN_VALID_FAIL; + break; + } + } + + value8 = HALMAC_REG_READ_8(halmac_adapter, REG_FIFOPAGE_CTRL_2 + 1); + HALMAC_REG_WRITE_8(halmac_adapter, REG_FIFOPAGE_CTRL_2 + 1, + (value8 | BIT(7))); + + HALMAC_REG_WRITE_8(halmac_adapter, REG_FWHW_TXQ_CTRL + 2, restore[2]); + HALMAC_REG_WRITE_8(halmac_adapter, REG_BCN_CTRL, restore[1]); + HALMAC_REG_WRITE_8(halmac_adapter, REG_CR + 1, restore[0]); + + return status; +} + +enum halmac_ret_status +halmac_set_h2c_header_88xx(struct halmac_adapter *halmac_adapter, + u8 *hal_h2c_hdr, u16 *seq, bool ack) +{ + void *driver_adapter = halmac_adapter->driver_adapter; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "%s!!\n", __func__); + + H2C_CMD_HEADER_SET_CATEGORY(hal_h2c_hdr, 0x00); + H2C_CMD_HEADER_SET_TOTAL_LEN(hal_h2c_hdr, 16); + + spin_lock(&halmac_adapter->h2c_seq_lock); + H2C_CMD_HEADER_SET_SEQ_NUM(hal_h2c_hdr, halmac_adapter->h2c_packet_seq); + *seq = halmac_adapter->h2c_packet_seq; + halmac_adapter->h2c_packet_seq++; + spin_unlock(&halmac_adapter->h2c_seq_lock); + + if (ack) + H2C_CMD_HEADER_SET_ACK(hal_h2c_hdr, 1); + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status halmac_set_fw_offload_h2c_header_88xx( + struct halmac_adapter *halmac_adapter, u8 *hal_h2c_hdr, + struct halmac_h2c_header_info *h2c_header_info, u16 *seq_num) +{ + void *driver_adapter = halmac_adapter->driver_adapter; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "%s!!\n", __func__); + + FW_OFFLOAD_H2C_SET_TOTAL_LEN(hal_h2c_hdr, + 8 + h2c_header_info->content_size); + FW_OFFLOAD_H2C_SET_SUB_CMD_ID(hal_h2c_hdr, h2c_header_info->sub_cmd_id); + + FW_OFFLOAD_H2C_SET_CATEGORY(hal_h2c_hdr, 0x01); + FW_OFFLOAD_H2C_SET_CMD_ID(hal_h2c_hdr, 0xFF); + + spin_lock(&halmac_adapter->h2c_seq_lock); + FW_OFFLOAD_H2C_SET_SEQ_NUM(hal_h2c_hdr, halmac_adapter->h2c_packet_seq); + *seq_num = halmac_adapter->h2c_packet_seq; + halmac_adapter->h2c_packet_seq++; + spin_unlock(&halmac_adapter->h2c_seq_lock); + + if (h2c_header_info->ack) + FW_OFFLOAD_H2C_SET_ACK(hal_h2c_hdr, 1); + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status +halmac_send_h2c_set_pwr_mode_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_fwlps_option *hal_fw_lps_opt) +{ + u8 h2c_buff[HALMAC_H2C_CMD_SIZE_88XX]; + u8 *h2c_header, *h2c_cmd; + u16 seq = 0; + void *driver_adapter = NULL; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "%s!!\n", __func__); + + driver_adapter = halmac_adapter->driver_adapter; + h2c_header = h2c_buff; + h2c_cmd = h2c_header + HALMAC_H2C_CMD_HDR_SIZE_88XX; + + memset(h2c_buff, 0x00, HALMAC_H2C_CMD_SIZE_88XX); + + SET_PWR_MODE_SET_CMD_ID(h2c_cmd, CMD_ID_SET_PWR_MODE); + SET_PWR_MODE_SET_CLASS(h2c_cmd, CLASS_SET_PWR_MODE); + SET_PWR_MODE_SET_MODE(h2c_cmd, hal_fw_lps_opt->mode); + SET_PWR_MODE_SET_CLK_REQUEST(h2c_cmd, hal_fw_lps_opt->clk_request); + SET_PWR_MODE_SET_RLBM(h2c_cmd, hal_fw_lps_opt->rlbm); + SET_PWR_MODE_SET_SMART_PS(h2c_cmd, hal_fw_lps_opt->smart_ps); + SET_PWR_MODE_SET_AWAKE_INTERVAL(h2c_cmd, + hal_fw_lps_opt->awake_interval); + SET_PWR_MODE_SET_B_ALL_QUEUE_UAPSD(h2c_cmd, + hal_fw_lps_opt->all_queue_uapsd); + SET_PWR_MODE_SET_PWR_STATE(h2c_cmd, hal_fw_lps_opt->pwr_state); + SET_PWR_MODE_SET_ANT_AUTO_SWITCH(h2c_cmd, + hal_fw_lps_opt->ant_auto_switch); + SET_PWR_MODE_SET_PS_ALLOW_BT_HIGH_PRIORITY( + h2c_cmd, hal_fw_lps_opt->ps_allow_bt_high_priority); + SET_PWR_MODE_SET_PROTECT_BCN(h2c_cmd, hal_fw_lps_opt->protect_bcn); + SET_PWR_MODE_SET_SILENCE_PERIOD(h2c_cmd, + hal_fw_lps_opt->silence_period); + SET_PWR_MODE_SET_FAST_BT_CONNECT(h2c_cmd, + hal_fw_lps_opt->fast_bt_connect); + SET_PWR_MODE_SET_TWO_ANTENNA_EN(h2c_cmd, + hal_fw_lps_opt->two_antenna_en); + SET_PWR_MODE_SET_ADOPT_USER_SETTING(h2c_cmd, + hal_fw_lps_opt->adopt_user_setting); + SET_PWR_MODE_SET_DRV_BCN_EARLY_SHIFT( + h2c_cmd, hal_fw_lps_opt->drv_bcn_early_shift); + + halmac_set_h2c_header_88xx(halmac_adapter, h2c_header, &seq, true); + + status = halmac_send_h2c_pkt_88xx(halmac_adapter, h2c_buff, + HALMAC_H2C_CMD_SIZE_88XX, true); + + if (status != HALMAC_RET_SUCCESS) { + pr_err("%s Fail = %x!!\n", __func__, status); + return status; + } + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status +halmac_func_send_original_h2c_88xx(struct halmac_adapter *halmac_adapter, + u8 *original_h2c, u16 *seq, u8 ack) +{ + u8 H2c_buff[HALMAC_H2C_CMD_SIZE_88XX] = {0}; + u8 *h2c_header, *h2c_cmd; + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "halmac_send_original_h2c ==========>\n"); + + h2c_header = H2c_buff; + h2c_cmd = h2c_header + HALMAC_H2C_CMD_HDR_SIZE_88XX; + memcpy(h2c_cmd, original_h2c, 8); /* Original H2C 8 byte */ + + halmac_set_h2c_header_88xx(halmac_adapter, h2c_header, seq, ack); + + status = halmac_send_h2c_pkt_88xx(halmac_adapter, H2c_buff, + HALMAC_H2C_CMD_SIZE_88XX, ack); + + if (status != HALMAC_RET_SUCCESS) { + pr_err("halmac_send_original_h2c Fail = %x!!\n", status); + return status; + } + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "halmac_send_original_h2c <==========\n"); + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status +halmac_media_status_rpt_88xx(struct halmac_adapter *halmac_adapter, u8 op_mode, + u8 mac_id_ind, u8 mac_id, u8 mac_id_end) +{ + u8 H2c_buff[HALMAC_H2C_CMD_SIZE_88XX] = {0}; + u8 *h2c_header, *h2c_cmd; + u16 seq = 0; + void *driver_adapter = NULL; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "halmac_send_h2c_set_pwr_mode_88xx!!\n"); + + driver_adapter = halmac_adapter->driver_adapter; + h2c_header = H2c_buff; + h2c_cmd = h2c_header + HALMAC_H2C_CMD_HDR_SIZE_88XX; + + memset(H2c_buff, 0x00, HALMAC_H2C_CMD_SIZE_88XX); + + MEDIA_STATUS_RPT_SET_CMD_ID(h2c_cmd, CMD_ID_MEDIA_STATUS_RPT); + MEDIA_STATUS_RPT_SET_CLASS(h2c_cmd, CLASS_MEDIA_STATUS_RPT); + MEDIA_STATUS_RPT_SET_OP_MODE(h2c_cmd, op_mode); + MEDIA_STATUS_RPT_SET_MACID_IN(h2c_cmd, mac_id_ind); + MEDIA_STATUS_RPT_SET_MACID(h2c_cmd, mac_id); + MEDIA_STATUS_RPT_SET_MACID_END(h2c_cmd, mac_id_end); + + halmac_set_h2c_header_88xx(halmac_adapter, h2c_header, &seq, true); + + status = halmac_send_h2c_pkt_88xx(halmac_adapter, H2c_buff, + HALMAC_H2C_CMD_SIZE_88XX, true); + + if (status != HALMAC_RET_SUCCESS) { + pr_err("%s Fail = %x!!\n", __func__, status); + return status; + } + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status +halmac_send_h2c_update_packet_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_packet_id pkt_id, u8 *pkt, + u32 pkt_size) +{ + u8 h2c_buff[HALMAC_H2C_CMD_SIZE_88XX] = {0}; + u16 h2c_seq_mum = 0; + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + struct halmac_h2c_header_info h2c_header_info; + enum halmac_ret_status ret_status = HALMAC_RET_SUCCESS; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_REG_WRITE_16(halmac_adapter, REG_FIFOPAGE_CTRL_2, + (u16)(halmac_adapter->txff_allocation + .rsvd_h2c_extra_info_pg_bndy & + BIT_MASK_BCN_HEAD_1_V1)); + + ret_status = + halmac_download_rsvd_page_88xx(halmac_adapter, pkt, pkt_size); + + if (ret_status != HALMAC_RET_SUCCESS) { + pr_err("halmac_download_rsvd_page_88xx Fail = %x!!\n", + ret_status); + HALMAC_REG_WRITE_16( + halmac_adapter, REG_FIFOPAGE_CTRL_2, + (u16)(halmac_adapter->txff_allocation.rsvd_pg_bndy & + BIT_MASK_BCN_HEAD_1_V1)); + return ret_status; + } + + HALMAC_REG_WRITE_16(halmac_adapter, REG_FIFOPAGE_CTRL_2, + (u16)(halmac_adapter->txff_allocation.rsvd_pg_bndy & + BIT_MASK_BCN_HEAD_1_V1)); + + UPDATE_PACKET_SET_SIZE( + h2c_buff, + pkt_size + halmac_adapter->hw_config_info.txdesc_size); + UPDATE_PACKET_SET_PACKET_ID(h2c_buff, pkt_id); + UPDATE_PACKET_SET_PACKET_LOC( + h2c_buff, + halmac_adapter->txff_allocation.rsvd_h2c_extra_info_pg_bndy - + halmac_adapter->txff_allocation.rsvd_pg_bndy); + + h2c_header_info.sub_cmd_id = SUB_CMD_ID_UPDATE_PACKET; + h2c_header_info.content_size = 8; + h2c_header_info.ack = true; + halmac_set_fw_offload_h2c_header_88xx(halmac_adapter, h2c_buff, + &h2c_header_info, &h2c_seq_mum); + halmac_adapter->halmac_state.update_packet_set.seq_num = h2c_seq_mum; + + ret_status = halmac_send_h2c_pkt_88xx(halmac_adapter, h2c_buff, + HALMAC_H2C_CMD_SIZE_88XX, true); + + if (ret_status != HALMAC_RET_SUCCESS) { + pr_err("%s Fail = %x!!\n", __func__, ret_status); + return ret_status; + } + + return ret_status; +} + +enum halmac_ret_status +halmac_send_h2c_phy_parameter_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_phy_parameter_info *para_info, + bool full_fifo) +{ + bool drv_trigger_send = false; + u8 h2c_buff[HALMAC_H2C_CMD_SIZE_88XX] = {0}; + u16 h2c_seq_mum = 0; + u32 info_size = 0; + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + struct halmac_h2c_header_info h2c_header_info; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + struct halmac_config_para_info *config_para_info; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + config_para_info = &halmac_adapter->config_para_info; + + if (!config_para_info->cfg_para_buf) { + if (full_fifo) + config_para_info->para_buf_size = + HALMAC_EXTRA_INFO_BUFF_SIZE_FULL_FIFO_88XX; + else + config_para_info->para_buf_size = + HALMAC_EXTRA_INFO_BUFF_SIZE_88XX; + + config_para_info->cfg_para_buf = + kzalloc(config_para_info->para_buf_size, GFP_KERNEL); + + if (config_para_info->cfg_para_buf) { + memset(config_para_info->cfg_para_buf, 0x00, + config_para_info->para_buf_size); + config_para_info->full_fifo_mode = full_fifo; + config_para_info->para_buf_w = + config_para_info->cfg_para_buf; + config_para_info->para_num = 0; + config_para_info->avai_para_buf_size = + config_para_info->para_buf_size; + config_para_info->value_accumulation = 0; + config_para_info->offset_accumulation = 0; + } else { + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, + DBG_DMESG, + "Allocate cfg_para_buf fail!!\n"); + return HALMAC_RET_MALLOC_FAIL; + } + } + + if (halmac_transition_cfg_para_state_88xx( + halmac_adapter, + HALMAC_CFG_PARA_CMD_CONSTRUCT_CONSTRUCTING) != + HALMAC_RET_SUCCESS) + return HALMAC_RET_ERROR_STATE; + + halmac_enqueue_para_buff_88xx(halmac_adapter, para_info, + config_para_info->para_buf_w, + &drv_trigger_send); + + if (para_info->cmd_id != HALMAC_PARAMETER_CMD_END) { + config_para_info->para_num++; + config_para_info->para_buf_w += HALMAC_FW_OFFLOAD_CMD_SIZE_88XX; + config_para_info->avai_para_buf_size = + config_para_info->avai_para_buf_size - + HALMAC_FW_OFFLOAD_CMD_SIZE_88XX; + } + + if ((config_para_info->avai_para_buf_size - + halmac_adapter->hw_config_info.txdesc_size) > + HALMAC_FW_OFFLOAD_CMD_SIZE_88XX && + !drv_trigger_send) + return HALMAC_RET_SUCCESS; + + if (config_para_info->para_num == 0) { + kfree(config_para_info->cfg_para_buf); + config_para_info->cfg_para_buf = NULL; + config_para_info->para_buf_w = NULL; + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_WARNING, + "no cfg parameter element!!\n"); + + if (halmac_transition_cfg_para_state_88xx( + halmac_adapter, + HALMAC_CFG_PARA_CMD_CONSTRUCT_IDLE) != + HALMAC_RET_SUCCESS) + return HALMAC_RET_ERROR_STATE; + + return HALMAC_RET_SUCCESS; + } + + if (halmac_transition_cfg_para_state_88xx( + halmac_adapter, HALMAC_CFG_PARA_CMD_CONSTRUCT_H2C_SENT) != + HALMAC_RET_SUCCESS) + return HALMAC_RET_ERROR_STATE; + + halmac_adapter->halmac_state.cfg_para_state_set.process_status = + HALMAC_CMD_PROCESS_SENDING; + + if (config_para_info->full_fifo_mode) + HALMAC_REG_WRITE_16(halmac_adapter, REG_FIFOPAGE_CTRL_2, 0); + else + HALMAC_REG_WRITE_16(halmac_adapter, REG_FIFOPAGE_CTRL_2, + (u16)(halmac_adapter->txff_allocation + .rsvd_h2c_extra_info_pg_bndy & + BIT_MASK_BCN_HEAD_1_V1)); + + info_size = + config_para_info->para_num * HALMAC_FW_OFFLOAD_CMD_SIZE_88XX; + + status = halmac_download_rsvd_page_88xx( + halmac_adapter, (u8 *)config_para_info->cfg_para_buf, + info_size); + + if (status != HALMAC_RET_SUCCESS) { + pr_err("halmac_download_rsvd_page_88xx Fail!!\n"); + } else { + halmac_gen_cfg_para_h2c_88xx(halmac_adapter, h2c_buff); + + h2c_header_info.sub_cmd_id = SUB_CMD_ID_CFG_PARAMETER; + h2c_header_info.content_size = 4; + h2c_header_info.ack = true; + halmac_set_fw_offload_h2c_header_88xx(halmac_adapter, h2c_buff, + &h2c_header_info, + &h2c_seq_mum); + + halmac_adapter->halmac_state.cfg_para_state_set.seq_num = + h2c_seq_mum; + + status = halmac_send_h2c_pkt_88xx(halmac_adapter, h2c_buff, + HALMAC_H2C_CMD_SIZE_88XX, + true); + + if (status != HALMAC_RET_SUCCESS) + pr_err("halmac_send_h2c_pkt_88xx Fail!!\n"); + + HALMAC_RT_TRACE( + driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "config parameter time = %d\n", + HALMAC_REG_READ_32(halmac_adapter, REG_FW_DBG6)); + } + + kfree(config_para_info->cfg_para_buf); + config_para_info->cfg_para_buf = NULL; + config_para_info->para_buf_w = NULL; + + /* Restore bcn head */ + HALMAC_REG_WRITE_16(halmac_adapter, REG_FIFOPAGE_CTRL_2, + (u16)(halmac_adapter->txff_allocation.rsvd_pg_bndy & + BIT_MASK_BCN_HEAD_1_V1)); + + if (halmac_transition_cfg_para_state_88xx( + halmac_adapter, HALMAC_CFG_PARA_CMD_CONSTRUCT_IDLE) != + HALMAC_RET_SUCCESS) + return HALMAC_RET_ERROR_STATE; + + if (!drv_trigger_send) { + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "Buffer full trigger sending H2C!!\n"); + return HALMAC_RET_PARA_SENDING; + } + + return status; +} + +static enum halmac_ret_status +halmac_enqueue_para_buff_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_phy_parameter_info *para_info, + u8 *curr_buff_wptr, bool *end_cmd) +{ + struct halmac_config_para_info *config_para_info = + &halmac_adapter->config_para_info; + + *end_cmd = false; + + PHY_PARAMETER_INFO_SET_LENGTH(curr_buff_wptr, + HALMAC_FW_OFFLOAD_CMD_SIZE_88XX); + PHY_PARAMETER_INFO_SET_IO_CMD(curr_buff_wptr, para_info->cmd_id); + + switch (para_info->cmd_id) { + case HALMAC_PARAMETER_CMD_BB_W8: + case HALMAC_PARAMETER_CMD_BB_W16: + case HALMAC_PARAMETER_CMD_BB_W32: + case HALMAC_PARAMETER_CMD_MAC_W8: + case HALMAC_PARAMETER_CMD_MAC_W16: + case HALMAC_PARAMETER_CMD_MAC_W32: + PHY_PARAMETER_INFO_SET_IO_ADDR( + curr_buff_wptr, para_info->content.MAC_REG_W.offset); + PHY_PARAMETER_INFO_SET_DATA(curr_buff_wptr, + para_info->content.MAC_REG_W.value); + PHY_PARAMETER_INFO_SET_MASK(curr_buff_wptr, + para_info->content.MAC_REG_W.msk); + PHY_PARAMETER_INFO_SET_MSK_EN( + curr_buff_wptr, para_info->content.MAC_REG_W.msk_en); + config_para_info->value_accumulation += + para_info->content.MAC_REG_W.value; + config_para_info->offset_accumulation += + para_info->content.MAC_REG_W.offset; + break; + case HALMAC_PARAMETER_CMD_RF_W: + /*In rf register, the address is only 1 byte*/ + PHY_PARAMETER_INFO_SET_RF_ADDR( + curr_buff_wptr, para_info->content.RF_REG_W.offset); + PHY_PARAMETER_INFO_SET_RF_PATH( + curr_buff_wptr, para_info->content.RF_REG_W.rf_path); + PHY_PARAMETER_INFO_SET_DATA(curr_buff_wptr, + para_info->content.RF_REG_W.value); + PHY_PARAMETER_INFO_SET_MASK(curr_buff_wptr, + para_info->content.RF_REG_W.msk); + PHY_PARAMETER_INFO_SET_MSK_EN( + curr_buff_wptr, para_info->content.RF_REG_W.msk_en); + config_para_info->value_accumulation += + para_info->content.RF_REG_W.value; + config_para_info->offset_accumulation += + (para_info->content.RF_REG_W.offset + + (para_info->content.RF_REG_W.rf_path << 8)); + break; + case HALMAC_PARAMETER_CMD_DELAY_US: + case HALMAC_PARAMETER_CMD_DELAY_MS: + PHY_PARAMETER_INFO_SET_DELAY_VALUE( + curr_buff_wptr, + para_info->content.DELAY_TIME.delay_time); + break; + case HALMAC_PARAMETER_CMD_END: + *end_cmd = true; + break; + default: + pr_err(" halmac_send_h2c_phy_parameter_88xx illegal cmd_id!!\n"); + break; + } + + return HALMAC_RET_SUCCESS; +} + +static enum halmac_ret_status +halmac_gen_cfg_para_h2c_88xx(struct halmac_adapter *halmac_adapter, + u8 *h2c_buff) +{ + struct halmac_config_para_info *config_para_info = + &halmac_adapter->config_para_info; + + CFG_PARAMETER_SET_NUM(h2c_buff, config_para_info->para_num); + + if (config_para_info->full_fifo_mode) { + CFG_PARAMETER_SET_INIT_CASE(h2c_buff, 0x1); + CFG_PARAMETER_SET_PHY_PARAMETER_LOC(h2c_buff, 0); + } else { + CFG_PARAMETER_SET_INIT_CASE(h2c_buff, 0x0); + CFG_PARAMETER_SET_PHY_PARAMETER_LOC( + h2c_buff, + halmac_adapter->txff_allocation + .rsvd_h2c_extra_info_pg_bndy - + halmac_adapter->txff_allocation.rsvd_pg_bndy); + } + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status +halmac_send_h2c_run_datapack_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_data_type halmac_data_type) +{ + u8 h2c_buff[HALMAC_H2C_CMD_SIZE_88XX] = {0}; + u16 h2c_seq_mum = 0; + void *driver_adapter = NULL; + struct halmac_h2c_header_info h2c_header_info; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + + driver_adapter = halmac_adapter->driver_adapter; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "%s!!\n", __func__); + + RUN_DATAPACK_SET_DATAPACK_ID(h2c_buff, halmac_data_type); + + h2c_header_info.sub_cmd_id = SUB_CMD_ID_RUN_DATAPACK; + h2c_header_info.content_size = 4; + h2c_header_info.ack = true; + halmac_set_fw_offload_h2c_header_88xx(halmac_adapter, h2c_buff, + &h2c_header_info, &h2c_seq_mum); + + status = halmac_send_h2c_pkt_88xx(halmac_adapter, h2c_buff, + HALMAC_H2C_CMD_SIZE_88XX, true); + + if (status != HALMAC_RET_SUCCESS) { + pr_err("halmac_send_h2c_pkt_88xx Fail = %x!!\n", status); + return status; + } + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status +halmac_send_bt_coex_cmd_88xx(struct halmac_adapter *halmac_adapter, u8 *bt_buf, + u32 bt_size, u8 ack) +{ + u8 h2c_buff[HALMAC_H2C_CMD_SIZE_88XX] = {0}; + u16 h2c_seq_mum = 0; + void *driver_adapter = NULL; + struct halmac_h2c_header_info h2c_header_info; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + + driver_adapter = halmac_adapter->driver_adapter; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "%s!!\n", __func__); + + memcpy(h2c_buff + 8, bt_buf, bt_size); + + h2c_header_info.sub_cmd_id = SUB_CMD_ID_BT_COEX; + h2c_header_info.content_size = (u16)bt_size; + h2c_header_info.ack = ack; + halmac_set_fw_offload_h2c_header_88xx(halmac_adapter, h2c_buff, + &h2c_header_info, &h2c_seq_mum); + + status = halmac_send_h2c_pkt_88xx(halmac_adapter, h2c_buff, + HALMAC_H2C_CMD_SIZE_88XX, ack); + + if (status != HALMAC_RET_SUCCESS) { + pr_err("halmac_send_h2c_pkt_88xx Fail = %x!!\n", status); + return status; + } + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status +halmac_func_ctrl_ch_switch_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_ch_switch_option *cs_option) +{ + u8 h2c_buff[HALMAC_H2C_CMD_SIZE_88XX] = {0}; + u16 h2c_seq_mum = 0; + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + struct halmac_h2c_header_info h2c_header_info; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + enum halmac_cmd_process_status *process_status = + &halmac_adapter->halmac_state.scan_state_set.process_status; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "halmac_ctrl_ch_switch!!\n"); + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + if (halmac_transition_scan_state_88xx( + halmac_adapter, HALMAC_SCAN_CMD_CONSTRUCT_H2C_SENT) != + HALMAC_RET_SUCCESS) + return HALMAC_RET_ERROR_STATE; + + *process_status = HALMAC_CMD_PROCESS_SENDING; + + if (cs_option->switch_en != 0) { + HALMAC_REG_WRITE_16(halmac_adapter, REG_FIFOPAGE_CTRL_2, + (u16)(halmac_adapter->txff_allocation + .rsvd_h2c_extra_info_pg_bndy & + BIT_MASK_BCN_HEAD_1_V1)); + + status = halmac_download_rsvd_page_88xx( + halmac_adapter, halmac_adapter->ch_sw_info.ch_info_buf, + halmac_adapter->ch_sw_info.total_size); + + if (status != HALMAC_RET_SUCCESS) { + pr_err("halmac_download_rsvd_page_88xx Fail = %x!!\n", + status); + HALMAC_REG_WRITE_16( + halmac_adapter, REG_FIFOPAGE_CTRL_2, + (u16)(halmac_adapter->txff_allocation + .rsvd_pg_bndy & + BIT_MASK_BCN_HEAD_1_V1)); + return status; + } + + HALMAC_REG_WRITE_16( + halmac_adapter, REG_FIFOPAGE_CTRL_2, + (u16)(halmac_adapter->txff_allocation.rsvd_pg_bndy & + BIT_MASK_BCN_HEAD_1_V1)); + } + + CHANNEL_SWITCH_SET_SWITCH_START(h2c_buff, cs_option->switch_en); + CHANNEL_SWITCH_SET_CHANNEL_NUM(h2c_buff, + halmac_adapter->ch_sw_info.ch_num); + CHANNEL_SWITCH_SET_CHANNEL_INFO_LOC( + h2c_buff, + halmac_adapter->txff_allocation.rsvd_h2c_extra_info_pg_bndy - + halmac_adapter->txff_allocation.rsvd_pg_bndy); + CHANNEL_SWITCH_SET_DEST_CH_EN(h2c_buff, cs_option->dest_ch_en); + CHANNEL_SWITCH_SET_DEST_CH(h2c_buff, cs_option->dest_ch); + CHANNEL_SWITCH_SET_PRI_CH_IDX(h2c_buff, cs_option->dest_pri_ch_idx); + CHANNEL_SWITCH_SET_ABSOLUTE_TIME(h2c_buff, cs_option->absolute_time_en); + CHANNEL_SWITCH_SET_TSF_LOW(h2c_buff, cs_option->tsf_low); + CHANNEL_SWITCH_SET_PERIODIC_OPTION(h2c_buff, + cs_option->periodic_option); + CHANNEL_SWITCH_SET_NORMAL_CYCLE(h2c_buff, cs_option->normal_cycle); + CHANNEL_SWITCH_SET_NORMAL_PERIOD(h2c_buff, cs_option->normal_period); + CHANNEL_SWITCH_SET_SLOW_PERIOD(h2c_buff, cs_option->phase_2_period); + CHANNEL_SWITCH_SET_CHANNEL_INFO_SIZE( + h2c_buff, halmac_adapter->ch_sw_info.total_size); + + h2c_header_info.sub_cmd_id = SUB_CMD_ID_CHANNEL_SWITCH; + h2c_header_info.content_size = 20; + h2c_header_info.ack = true; + halmac_set_fw_offload_h2c_header_88xx(halmac_adapter, h2c_buff, + &h2c_header_info, &h2c_seq_mum); + halmac_adapter->halmac_state.scan_state_set.seq_num = h2c_seq_mum; + + status = halmac_send_h2c_pkt_88xx(halmac_adapter, h2c_buff, + HALMAC_H2C_CMD_SIZE_88XX, true); + + if (status != HALMAC_RET_SUCCESS) + pr_err("halmac_send_h2c_pkt_88xx Fail = %x!!\n", status); + + kfree(halmac_adapter->ch_sw_info.ch_info_buf); + halmac_adapter->ch_sw_info.ch_info_buf = NULL; + halmac_adapter->ch_sw_info.ch_info_buf_w = NULL; + halmac_adapter->ch_sw_info.extra_info_en = 0; + halmac_adapter->ch_sw_info.buf_size = 0; + halmac_adapter->ch_sw_info.avai_buf_size = 0; + halmac_adapter->ch_sw_info.total_size = 0; + halmac_adapter->ch_sw_info.ch_num = 0; + + if (halmac_transition_scan_state_88xx(halmac_adapter, + HALMAC_SCAN_CMD_CONSTRUCT_IDLE) != + HALMAC_RET_SUCCESS) + return HALMAC_RET_ERROR_STATE; + + return status; +} + +enum halmac_ret_status +halmac_func_send_general_info_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_general_info *general_info) +{ + u8 h2c_buff[HALMAC_H2C_CMD_SIZE_88XX] = {0}; + u16 h2c_seq_mum = 0; + void *driver_adapter = NULL; + struct halmac_h2c_header_info h2c_header_info; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + + driver_adapter = halmac_adapter->driver_adapter; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "halmac_send_general_info!!\n"); + + GENERAL_INFO_SET_REF_TYPE(h2c_buff, general_info->rfe_type); + GENERAL_INFO_SET_RF_TYPE(h2c_buff, general_info->rf_type); + GENERAL_INFO_SET_FW_TX_BOUNDARY( + h2c_buff, + halmac_adapter->txff_allocation.rsvd_fw_txbuff_pg_bndy - + halmac_adapter->txff_allocation.rsvd_pg_bndy); + + h2c_header_info.sub_cmd_id = SUB_CMD_ID_GENERAL_INFO; + h2c_header_info.content_size = 4; + h2c_header_info.ack = false; + halmac_set_fw_offload_h2c_header_88xx(halmac_adapter, h2c_buff, + &h2c_header_info, &h2c_seq_mum); + + status = halmac_send_h2c_pkt_88xx(halmac_adapter, h2c_buff, + HALMAC_H2C_CMD_SIZE_88XX, true); + + if (status != HALMAC_RET_SUCCESS) + pr_err("halmac_send_h2c_pkt_88xx Fail = %x!!\n", status); + + return status; +} + +enum halmac_ret_status halmac_send_h2c_update_bcn_parse_info_88xx( + struct halmac_adapter *halmac_adapter, + struct halmac_bcn_ie_info *bcn_ie_info) +{ + u8 h2c_buff[HALMAC_H2C_CMD_SIZE_88XX] = {0}; + u16 h2c_seq_mum = 0; + void *driver_adapter = NULL; + struct halmac_h2c_header_info h2c_header_info; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "%s!!\n", __func__); + + driver_adapter = halmac_adapter->driver_adapter; + + UPDATE_BEACON_PARSING_INFO_SET_FUNC_EN(h2c_buff, bcn_ie_info->func_en); + UPDATE_BEACON_PARSING_INFO_SET_SIZE_TH(h2c_buff, bcn_ie_info->size_th); + UPDATE_BEACON_PARSING_INFO_SET_TIMEOUT(h2c_buff, bcn_ie_info->timeout); + + UPDATE_BEACON_PARSING_INFO_SET_IE_ID_BMP_0( + h2c_buff, (u32)(bcn_ie_info->ie_bmp[0])); + UPDATE_BEACON_PARSING_INFO_SET_IE_ID_BMP_1( + h2c_buff, (u32)(bcn_ie_info->ie_bmp[1])); + UPDATE_BEACON_PARSING_INFO_SET_IE_ID_BMP_2( + h2c_buff, (u32)(bcn_ie_info->ie_bmp[2])); + UPDATE_BEACON_PARSING_INFO_SET_IE_ID_BMP_3( + h2c_buff, (u32)(bcn_ie_info->ie_bmp[3])); + UPDATE_BEACON_PARSING_INFO_SET_IE_ID_BMP_4( + h2c_buff, (u32)(bcn_ie_info->ie_bmp[4])); + + h2c_header_info.sub_cmd_id = SUB_CMD_ID_UPDATE_BEACON_PARSING_INFO; + h2c_header_info.content_size = 24; + h2c_header_info.ack = true; + halmac_set_fw_offload_h2c_header_88xx(halmac_adapter, h2c_buff, + &h2c_header_info, &h2c_seq_mum); + + status = halmac_send_h2c_pkt_88xx(halmac_adapter, h2c_buff, + HALMAC_H2C_CMD_SIZE_88XX, true); + + if (status != HALMAC_RET_SUCCESS) { + pr_err("halmac_send_h2c_pkt_88xx Fail =%x !!\n", status); + return status; + } + + return status; +} + +enum halmac_ret_status +halmac_send_h2c_ps_tuning_para_88xx(struct halmac_adapter *halmac_adapter) +{ + u8 h2c_buff[HALMAC_H2C_CMD_SIZE_88XX] = {0}; + u8 *h2c_header, *h2c_cmd; + u16 seq = 0; + void *driver_adapter = NULL; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + + driver_adapter = halmac_adapter->driver_adapter; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "%s!!\n", __func__); + + h2c_header = h2c_buff; + h2c_cmd = h2c_header + HALMAC_H2C_CMD_HDR_SIZE_88XX; + + halmac_set_h2c_header_88xx(halmac_adapter, h2c_header, &seq, false); + + status = halmac_send_h2c_pkt_88xx(halmac_adapter, h2c_buff, + HALMAC_H2C_CMD_SIZE_88XX, false); + + if (status != HALMAC_RET_SUCCESS) { + pr_err("halmac_send_h2c_pkt_88xx Fail = %x!!\n", status); + return status; + } + + return status; +} + +enum halmac_ret_status +halmac_parse_c2h_packet_88xx(struct halmac_adapter *halmac_adapter, + u8 *halmac_buf, u32 halmac_size) +{ + u8 c2h_cmd, c2h_sub_cmd_id; + u8 *c2h_buf = halmac_buf + halmac_adapter->hw_config_info.rxdesc_size; + u32 c2h_size = halmac_size - halmac_adapter->hw_config_info.rxdesc_size; + void *driver_adapter = halmac_adapter->driver_adapter; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + + c2h_cmd = (u8)C2H_HDR_GET_CMD_ID(c2h_buf); + + /* FW offload C2H cmd is 0xFF */ + if (c2h_cmd != 0xFF) { + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "C2H_PKT not for FwOffloadC2HFormat!!\n"); + return HALMAC_RET_C2H_NOT_HANDLED; + } + + /* Get C2H sub cmd ID */ + c2h_sub_cmd_id = (u8)C2H_HDR_GET_C2H_SUB_CMD_ID(c2h_buf); + + switch (c2h_sub_cmd_id) { + case C2H_SUB_CMD_ID_C2H_DBG: + status = halmac_parse_c2h_debug_88xx(halmac_adapter, c2h_buf, + c2h_size); + break; + case C2H_SUB_CMD_ID_H2C_ACK_HDR: + status = halmac_parse_h2c_ack_88xx(halmac_adapter, c2h_buf, + c2h_size); + break; + case C2H_SUB_CMD_ID_BT_COEX_INFO: + status = HALMAC_RET_C2H_NOT_HANDLED; + break; + case C2H_SUB_CMD_ID_SCAN_STATUS_RPT: + status = halmac_parse_scan_status_rpt_88xx(halmac_adapter, + c2h_buf, c2h_size); + break; + case C2H_SUB_CMD_ID_PSD_DATA: + status = halmac_parse_psd_data_88xx(halmac_adapter, c2h_buf, + c2h_size); + break; + + case C2H_SUB_CMD_ID_EFUSE_DATA: + status = halmac_parse_efuse_data_88xx(halmac_adapter, c2h_buf, + c2h_size); + break; + default: + pr_err("c2h_sub_cmd_id switch case out of boundary!!\n"); + pr_err("[ERR]c2h pkt : %.8X %.8X!!\n", *(u32 *)c2h_buf, + *(u32 *)(c2h_buf + 4)); + status = HALMAC_RET_C2H_NOT_HANDLED; + break; + } + + return status; +} + +static enum halmac_ret_status +halmac_parse_c2h_debug_88xx(struct halmac_adapter *halmac_adapter, u8 *c2h_buf, + u32 c2h_size) +{ + void *driver_adapter = NULL; + u8 *c2h_buf_local = (u8 *)NULL; + u32 c2h_size_local = 0; + u8 dbg_content_length = 0; + u8 dbg_seq_num = 0; + + driver_adapter = halmac_adapter->driver_adapter; + c2h_buf_local = c2h_buf; + c2h_size_local = c2h_size; + + dbg_content_length = (u8)C2H_HDR_GET_LEN((u8 *)c2h_buf_local); + + if (dbg_content_length > C2H_DBG_CONTENT_MAX_LENGTH) + return HALMAC_RET_SUCCESS; + + *(c2h_buf_local + C2H_DBG_HEADER_LENGTH + dbg_content_length - 2) = + '\n'; + dbg_seq_num = (u8)(*(c2h_buf_local + C2H_DBG_HEADER_LENGTH)); + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "[RTKFW, SEQ=%d]: %s", dbg_seq_num, + (char *)(c2h_buf_local + C2H_DBG_HEADER_LENGTH + 1)); + + return HALMAC_RET_SUCCESS; +} + +static enum halmac_ret_status +halmac_parse_scan_status_rpt_88xx(struct halmac_adapter *halmac_adapter, + u8 *c2h_buf, u32 c2h_size) +{ + u8 h2c_return_code; + void *driver_adapter = halmac_adapter->driver_adapter; + enum halmac_cmd_process_status process_status; + + h2c_return_code = (u8)SCAN_STATUS_RPT_GET_H2C_RETURN_CODE(c2h_buf); + process_status = (enum halmac_h2c_return_code)h2c_return_code == + HALMAC_H2C_RETURN_SUCCESS ? + HALMAC_CMD_PROCESS_DONE : + HALMAC_CMD_PROCESS_ERROR; + + PLATFORM_EVENT_INDICATION(driver_adapter, HALMAC_FEATURE_CHANNEL_SWITCH, + process_status, NULL, 0); + + halmac_adapter->halmac_state.scan_state_set.process_status = + process_status; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "[TRACE]scan status : %X\n", process_status); + + return HALMAC_RET_SUCCESS; +} + +static enum halmac_ret_status +halmac_parse_psd_data_88xx(struct halmac_adapter *halmac_adapter, u8 *c2h_buf, + u32 c2h_size) +{ + u8 segment_id = 0, segment_size = 0, h2c_seq = 0; + u16 total_size; + void *driver_adapter = halmac_adapter->driver_adapter; + enum halmac_cmd_process_status process_status; + struct halmac_psd_state_set *psd_set = + &halmac_adapter->halmac_state.psd_set; + + h2c_seq = (u8)PSD_DATA_GET_H2C_SEQ(c2h_buf); + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "[TRACE]Seq num : h2c -> %d c2h -> %d\n", + psd_set->seq_num, h2c_seq); + if (h2c_seq != psd_set->seq_num) { + pr_err("[ERR]Seq num mismatch : h2c -> %d c2h -> %d\n", + psd_set->seq_num, h2c_seq); + return HALMAC_RET_SUCCESS; + } + + if (psd_set->process_status != HALMAC_CMD_PROCESS_SENDING) { + pr_err("[ERR]Not in HALMAC_CMD_PROCESS_SENDING\n"); + return HALMAC_RET_SUCCESS; + } + + total_size = (u16)PSD_DATA_GET_TOTAL_SIZE(c2h_buf); + segment_id = (u8)PSD_DATA_GET_SEGMENT_ID(c2h_buf); + segment_size = (u8)PSD_DATA_GET_SEGMENT_SIZE(c2h_buf); + psd_set->data_size = total_size; + + if (!psd_set->data) + psd_set->data = kzalloc(psd_set->data_size, GFP_KERNEL); + + if (segment_id == 0) + psd_set->segment_size = segment_size; + + memcpy(psd_set->data + segment_id * psd_set->segment_size, + c2h_buf + HALMAC_C2H_DATA_OFFSET_88XX, segment_size); + + if (!PSD_DATA_GET_END_SEGMENT(c2h_buf)) + return HALMAC_RET_SUCCESS; + + process_status = HALMAC_CMD_PROCESS_DONE; + psd_set->process_status = process_status; + + PLATFORM_EVENT_INDICATION(driver_adapter, HALMAC_FEATURE_PSD, + process_status, psd_set->data, + psd_set->data_size); + + return HALMAC_RET_SUCCESS; +} + +static enum halmac_ret_status +halmac_parse_efuse_data_88xx(struct halmac_adapter *halmac_adapter, u8 *c2h_buf, + u32 c2h_size) +{ + u8 segment_id = 0, segment_size = 0, h2c_seq = 0; + u8 *eeprom_map = NULL; + u32 eeprom_size = halmac_adapter->hw_config_info.eeprom_size; + u8 h2c_return_code = 0; + void *driver_adapter = halmac_adapter->driver_adapter; + enum halmac_cmd_process_status process_status; + + h2c_seq = (u8)EFUSE_DATA_GET_H2C_SEQ(c2h_buf); + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "[TRACE]Seq num : h2c -> %d c2h -> %d\n", + halmac_adapter->halmac_state.efuse_state_set.seq_num, + h2c_seq); + if (h2c_seq != halmac_adapter->halmac_state.efuse_state_set.seq_num) { + pr_err("[ERR]Seq num mismatch : h2c -> %d c2h -> %d\n", + halmac_adapter->halmac_state.efuse_state_set.seq_num, + h2c_seq); + return HALMAC_RET_SUCCESS; + } + + if (halmac_adapter->halmac_state.efuse_state_set.process_status != + HALMAC_CMD_PROCESS_SENDING) { + pr_err("[ERR]Not in HALMAC_CMD_PROCESS_SENDING\n"); + return HALMAC_RET_SUCCESS; + } + + segment_id = (u8)EFUSE_DATA_GET_SEGMENT_ID(c2h_buf); + segment_size = (u8)EFUSE_DATA_GET_SEGMENT_SIZE(c2h_buf); + if (segment_id == 0) + halmac_adapter->efuse_segment_size = segment_size; + + eeprom_map = kzalloc(eeprom_size, GFP_KERNEL); + if (!eeprom_map) { + /* out of memory */ + return HALMAC_RET_MALLOC_FAIL; + } + memset(eeprom_map, 0xFF, eeprom_size); + + spin_lock(&halmac_adapter->efuse_lock); + memcpy(halmac_adapter->hal_efuse_map + + segment_id * halmac_adapter->efuse_segment_size, + c2h_buf + HALMAC_C2H_DATA_OFFSET_88XX, segment_size); + spin_unlock(&halmac_adapter->efuse_lock); + + if (!EFUSE_DATA_GET_END_SEGMENT(c2h_buf)) { + kfree(eeprom_map); + return HALMAC_RET_SUCCESS; + } + + h2c_return_code = + halmac_adapter->halmac_state.efuse_state_set.fw_return_code; + + if ((enum halmac_h2c_return_code)h2c_return_code == + HALMAC_H2C_RETURN_SUCCESS) { + process_status = HALMAC_CMD_PROCESS_DONE; + halmac_adapter->halmac_state.efuse_state_set.process_status = + process_status; + + spin_lock(&halmac_adapter->efuse_lock); + halmac_adapter->hal_efuse_map_valid = true; + spin_unlock(&halmac_adapter->efuse_lock); + + if (halmac_adapter->event_trigger.physical_efuse_map == 1) { + PLATFORM_EVENT_INDICATION( + driver_adapter, + HALMAC_FEATURE_DUMP_PHYSICAL_EFUSE, + process_status, halmac_adapter->hal_efuse_map, + halmac_adapter->hw_config_info.efuse_size); + halmac_adapter->event_trigger.physical_efuse_map = 0; + } + + if (halmac_adapter->event_trigger.logical_efuse_map == 1) { + if (halmac_eeprom_parser_88xx( + halmac_adapter, + halmac_adapter->hal_efuse_map, + eeprom_map) != HALMAC_RET_SUCCESS) { + kfree(eeprom_map); + return HALMAC_RET_EEPROM_PARSING_FAIL; + } + PLATFORM_EVENT_INDICATION( + driver_adapter, + HALMAC_FEATURE_DUMP_LOGICAL_EFUSE, + process_status, eeprom_map, eeprom_size); + halmac_adapter->event_trigger.logical_efuse_map = 0; + } + } else { + process_status = HALMAC_CMD_PROCESS_ERROR; + halmac_adapter->halmac_state.efuse_state_set.process_status = + process_status; + + if (halmac_adapter->event_trigger.physical_efuse_map == 1) { + PLATFORM_EVENT_INDICATION( + driver_adapter, + HALMAC_FEATURE_DUMP_PHYSICAL_EFUSE, + process_status, + &halmac_adapter->halmac_state.efuse_state_set + .fw_return_code, + 1); + halmac_adapter->event_trigger.physical_efuse_map = 0; + } + + if (halmac_adapter->event_trigger.logical_efuse_map == 1) { + if (halmac_eeprom_parser_88xx( + halmac_adapter, + halmac_adapter->hal_efuse_map, + eeprom_map) != HALMAC_RET_SUCCESS) { + kfree(eeprom_map); + return HALMAC_RET_EEPROM_PARSING_FAIL; + } + PLATFORM_EVENT_INDICATION( + driver_adapter, + HALMAC_FEATURE_DUMP_LOGICAL_EFUSE, + process_status, + &halmac_adapter->halmac_state.efuse_state_set + .fw_return_code, + 1); + halmac_adapter->event_trigger.logical_efuse_map = 0; + } + } + + kfree(eeprom_map); + + return HALMAC_RET_SUCCESS; +} + +static enum halmac_ret_status +halmac_parse_h2c_ack_88xx(struct halmac_adapter *halmac_adapter, u8 *c2h_buf, + u32 c2h_size) +{ + u8 h2c_cmd_id, h2c_sub_cmd_id; + u8 h2c_return_code; + void *driver_adapter = halmac_adapter->driver_adapter; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "Ack for C2H!!\n"); + + h2c_return_code = (u8)H2C_ACK_HDR_GET_H2C_RETURN_CODE(c2h_buf); + if ((enum halmac_h2c_return_code)h2c_return_code != + HALMAC_H2C_RETURN_SUCCESS) + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "C2H_PKT Status Error!! Status = %d\n", + h2c_return_code); + + h2c_cmd_id = (u8)H2C_ACK_HDR_GET_H2C_CMD_ID(c2h_buf); + + if (h2c_cmd_id != 0xFF) { + pr_err("original h2c ack is not handled!!\n"); + status = HALMAC_RET_C2H_NOT_HANDLED; + } else { + h2c_sub_cmd_id = (u8)H2C_ACK_HDR_GET_H2C_SUB_CMD_ID(c2h_buf); + + switch (h2c_sub_cmd_id) { + case H2C_SUB_CMD_ID_DUMP_PHYSICAL_EFUSE_ACK: + status = halmac_parse_h2c_ack_phy_efuse_88xx( + halmac_adapter, c2h_buf, c2h_size); + break; + case H2C_SUB_CMD_ID_CFG_PARAMETER_ACK: + status = halmac_parse_h2c_ack_cfg_para_88xx( + halmac_adapter, c2h_buf, c2h_size); + break; + case H2C_SUB_CMD_ID_UPDATE_PACKET_ACK: + status = halmac_parse_h2c_ack_update_packet_88xx( + halmac_adapter, c2h_buf, c2h_size); + break; + case H2C_SUB_CMD_ID_UPDATE_DATAPACK_ACK: + status = halmac_parse_h2c_ack_update_datapack_88xx( + halmac_adapter, c2h_buf, c2h_size); + break; + case H2C_SUB_CMD_ID_RUN_DATAPACK_ACK: + status = halmac_parse_h2c_ack_run_datapack_88xx( + halmac_adapter, c2h_buf, c2h_size); + break; + case H2C_SUB_CMD_ID_CHANNEL_SWITCH_ACK: + status = halmac_parse_h2c_ack_channel_switch_88xx( + halmac_adapter, c2h_buf, c2h_size); + break; + case H2C_SUB_CMD_ID_IQK_ACK: + status = halmac_parse_h2c_ack_iqk_88xx( + halmac_adapter, c2h_buf, c2h_size); + break; + case H2C_SUB_CMD_ID_POWER_TRACKING_ACK: + status = halmac_parse_h2c_ack_power_tracking_88xx( + halmac_adapter, c2h_buf, c2h_size); + break; + case H2C_SUB_CMD_ID_PSD_ACK: + break; + default: + pr_err("h2c_sub_cmd_id switch case out of boundary!!\n"); + status = HALMAC_RET_C2H_NOT_HANDLED; + break; + } + } + + return status; +} + +static enum halmac_ret_status +halmac_parse_h2c_ack_phy_efuse_88xx(struct halmac_adapter *halmac_adapter, + u8 *c2h_buf, u32 c2h_size) +{ + u8 h2c_seq = 0; + u8 h2c_return_code; + void *driver_adapter = halmac_adapter->driver_adapter; + + h2c_seq = (u8)H2C_ACK_HDR_GET_H2C_SEQ(c2h_buf); + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "[TRACE]Seq num : h2c -> %d c2h -> %d\n", + halmac_adapter->halmac_state.efuse_state_set.seq_num, + h2c_seq); + if (h2c_seq != halmac_adapter->halmac_state.efuse_state_set.seq_num) { + pr_err("[ERR]Seq num mismatch : h2c -> %d c2h -> %d\n", + halmac_adapter->halmac_state.efuse_state_set.seq_num, + h2c_seq); + return HALMAC_RET_SUCCESS; + } + + if (halmac_adapter->halmac_state.efuse_state_set.process_status != + HALMAC_CMD_PROCESS_SENDING) { + pr_err("[ERR]Not in HALMAC_CMD_PROCESS_SENDING\n"); + return HALMAC_RET_SUCCESS; + } + + h2c_return_code = (u8)H2C_ACK_HDR_GET_H2C_RETURN_CODE(c2h_buf); + halmac_adapter->halmac_state.efuse_state_set.fw_return_code = + h2c_return_code; + + return HALMAC_RET_SUCCESS; +} + +static enum halmac_ret_status +halmac_parse_h2c_ack_cfg_para_88xx(struct halmac_adapter *halmac_adapter, + u8 *c2h_buf, u32 c2h_size) +{ + u8 h2c_seq = 0; + u8 h2c_return_code; + u32 offset_accu = 0, value_accu = 0; + void *driver_adapter = halmac_adapter->driver_adapter; + enum halmac_cmd_process_status process_status = + HALMAC_CMD_PROCESS_UNDEFINE; + + h2c_seq = (u8)H2C_ACK_HDR_GET_H2C_SEQ(c2h_buf); + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "Seq num : h2c -> %d c2h -> %d\n", + halmac_adapter->halmac_state.cfg_para_state_set.seq_num, + h2c_seq); + if (h2c_seq != + halmac_adapter->halmac_state.cfg_para_state_set.seq_num) { + pr_err("Seq num mismatch : h2c -> %d c2h -> %d\n", + halmac_adapter->halmac_state.cfg_para_state_set.seq_num, + h2c_seq); + return HALMAC_RET_SUCCESS; + } + + if (halmac_adapter->halmac_state.cfg_para_state_set.process_status != + HALMAC_CMD_PROCESS_SENDING) { + pr_err("Not in HALMAC_CMD_PROCESS_SENDING\n"); + return HALMAC_RET_SUCCESS; + } + + h2c_return_code = (u8)H2C_ACK_HDR_GET_H2C_RETURN_CODE(c2h_buf); + halmac_adapter->halmac_state.cfg_para_state_set.fw_return_code = + h2c_return_code; + offset_accu = CFG_PARAMETER_ACK_GET_OFFSET_ACCUMULATION(c2h_buf); + value_accu = CFG_PARAMETER_ACK_GET_VALUE_ACCUMULATION(c2h_buf); + + if ((offset_accu != + halmac_adapter->config_para_info.offset_accumulation) || + (value_accu != + halmac_adapter->config_para_info.value_accumulation)) { + pr_err("[C2H]offset_accu : %x, value_accu : %x!!\n", + offset_accu, value_accu); + pr_err("[Adapter]offset_accu : %x, value_accu : %x!!\n", + halmac_adapter->config_para_info.offset_accumulation, + halmac_adapter->config_para_info.value_accumulation); + process_status = HALMAC_CMD_PROCESS_ERROR; + } + + if ((enum halmac_h2c_return_code)h2c_return_code == + HALMAC_H2C_RETURN_SUCCESS && + process_status != HALMAC_CMD_PROCESS_ERROR) { + process_status = HALMAC_CMD_PROCESS_DONE; + halmac_adapter->halmac_state.cfg_para_state_set.process_status = + process_status; + PLATFORM_EVENT_INDICATION(driver_adapter, + HALMAC_FEATURE_CFG_PARA, + process_status, NULL, 0); + } else { + process_status = HALMAC_CMD_PROCESS_ERROR; + halmac_adapter->halmac_state.cfg_para_state_set.process_status = + process_status; + PLATFORM_EVENT_INDICATION( + driver_adapter, HALMAC_FEATURE_CFG_PARA, process_status, + &halmac_adapter->halmac_state.cfg_para_state_set + .fw_return_code, + 1); + } + + return HALMAC_RET_SUCCESS; +} + +static enum halmac_ret_status +halmac_parse_h2c_ack_update_packet_88xx(struct halmac_adapter *halmac_adapter, + u8 *c2h_buf, u32 c2h_size) +{ + u8 h2c_seq = 0; + u8 h2c_return_code; + void *driver_adapter = halmac_adapter->driver_adapter; + enum halmac_cmd_process_status process_status; + + h2c_seq = (u8)H2C_ACK_HDR_GET_H2C_SEQ(c2h_buf); + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "[TRACE]Seq num : h2c -> %d c2h -> %d\n", + halmac_adapter->halmac_state.update_packet_set.seq_num, + h2c_seq); + if (h2c_seq != halmac_adapter->halmac_state.update_packet_set.seq_num) { + pr_err("[ERR]Seq num mismatch : h2c -> %d c2h -> %d\n", + halmac_adapter->halmac_state.update_packet_set.seq_num, + h2c_seq); + return HALMAC_RET_SUCCESS; + } + + if (halmac_adapter->halmac_state.update_packet_set.process_status != + HALMAC_CMD_PROCESS_SENDING) { + pr_err("[ERR]Not in HALMAC_CMD_PROCESS_SENDING\n"); + return HALMAC_RET_SUCCESS; + } + + h2c_return_code = (u8)H2C_ACK_HDR_GET_H2C_RETURN_CODE(c2h_buf); + halmac_adapter->halmac_state.update_packet_set.fw_return_code = + h2c_return_code; + + if ((enum halmac_h2c_return_code)h2c_return_code == + HALMAC_H2C_RETURN_SUCCESS) { + process_status = HALMAC_CMD_PROCESS_DONE; + halmac_adapter->halmac_state.update_packet_set.process_status = + process_status; + PLATFORM_EVENT_INDICATION(driver_adapter, + HALMAC_FEATURE_UPDATE_PACKET, + process_status, NULL, 0); + } else { + process_status = HALMAC_CMD_PROCESS_ERROR; + halmac_adapter->halmac_state.update_packet_set.process_status = + process_status; + PLATFORM_EVENT_INDICATION( + driver_adapter, HALMAC_FEATURE_UPDATE_PACKET, + process_status, + &halmac_adapter->halmac_state.update_packet_set + .fw_return_code, + 1); + } + + return HALMAC_RET_SUCCESS; +} + +static enum halmac_ret_status +halmac_parse_h2c_ack_update_datapack_88xx(struct halmac_adapter *halmac_adapter, + u8 *c2h_buf, u32 c2h_size) +{ + void *driver_adapter = halmac_adapter->driver_adapter; + enum halmac_cmd_process_status process_status = + HALMAC_CMD_PROCESS_UNDEFINE; + + PLATFORM_EVENT_INDICATION(driver_adapter, + HALMAC_FEATURE_UPDATE_DATAPACK, + process_status, NULL, 0); + + return HALMAC_RET_SUCCESS; +} + +static enum halmac_ret_status +halmac_parse_h2c_ack_run_datapack_88xx(struct halmac_adapter *halmac_adapter, + u8 *c2h_buf, u32 c2h_size) +{ + void *driver_adapter = halmac_adapter->driver_adapter; + enum halmac_cmd_process_status process_status = + HALMAC_CMD_PROCESS_UNDEFINE; + + PLATFORM_EVENT_INDICATION(driver_adapter, HALMAC_FEATURE_RUN_DATAPACK, + process_status, NULL, 0); + + return HALMAC_RET_SUCCESS; +} + +static enum halmac_ret_status +halmac_parse_h2c_ack_channel_switch_88xx(struct halmac_adapter *halmac_adapter, + u8 *c2h_buf, u32 c2h_size) +{ + u8 h2c_seq = 0; + u8 h2c_return_code; + void *driver_adapter = halmac_adapter->driver_adapter; + enum halmac_cmd_process_status process_status; + + h2c_seq = (u8)H2C_ACK_HDR_GET_H2C_SEQ(c2h_buf); + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "[TRACE]Seq num : h2c -> %d c2h -> %d\n", + halmac_adapter->halmac_state.scan_state_set.seq_num, + h2c_seq); + if (h2c_seq != halmac_adapter->halmac_state.scan_state_set.seq_num) { + pr_err("[ERR]Seq num misactch : h2c -> %d c2h -> %d\n", + halmac_adapter->halmac_state.scan_state_set.seq_num, + h2c_seq); + return HALMAC_RET_SUCCESS; + } + + if (halmac_adapter->halmac_state.scan_state_set.process_status != + HALMAC_CMD_PROCESS_SENDING) { + pr_err("[ERR]Not in HALMAC_CMD_PROCESS_SENDING\n"); + return HALMAC_RET_SUCCESS; + } + + h2c_return_code = (u8)H2C_ACK_HDR_GET_H2C_RETURN_CODE(c2h_buf); + halmac_adapter->halmac_state.scan_state_set.fw_return_code = + h2c_return_code; + + if ((enum halmac_h2c_return_code)h2c_return_code == + HALMAC_H2C_RETURN_SUCCESS) { + process_status = HALMAC_CMD_PROCESS_RCVD; + halmac_adapter->halmac_state.scan_state_set.process_status = + process_status; + PLATFORM_EVENT_INDICATION(driver_adapter, + HALMAC_FEATURE_CHANNEL_SWITCH, + process_status, NULL, 0); + } else { + process_status = HALMAC_CMD_PROCESS_ERROR; + halmac_adapter->halmac_state.scan_state_set.process_status = + process_status; + PLATFORM_EVENT_INDICATION( + driver_adapter, HALMAC_FEATURE_CHANNEL_SWITCH, + process_status, &halmac_adapter->halmac_state + .scan_state_set.fw_return_code, + 1); + } + + return HALMAC_RET_SUCCESS; +} + +static enum halmac_ret_status +halmac_parse_h2c_ack_iqk_88xx(struct halmac_adapter *halmac_adapter, + u8 *c2h_buf, u32 c2h_size) +{ + u8 h2c_seq = 0; + u8 h2c_return_code; + void *driver_adapter = halmac_adapter->driver_adapter; + enum halmac_cmd_process_status process_status; + + h2c_seq = (u8)H2C_ACK_HDR_GET_H2C_SEQ(c2h_buf); + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "[TRACE]Seq num : h2c -> %d c2h -> %d\n", + halmac_adapter->halmac_state.iqk_set.seq_num, h2c_seq); + if (h2c_seq != halmac_adapter->halmac_state.iqk_set.seq_num) { + pr_err("[ERR]Seq num misactch : h2c -> %d c2h -> %d\n", + halmac_adapter->halmac_state.iqk_set.seq_num, h2c_seq); + return HALMAC_RET_SUCCESS; + } + + if (halmac_adapter->halmac_state.iqk_set.process_status != + HALMAC_CMD_PROCESS_SENDING) { + pr_err("[ERR]Not in HALMAC_CMD_PROCESS_SENDING\n"); + return HALMAC_RET_SUCCESS; + } + + h2c_return_code = (u8)H2C_ACK_HDR_GET_H2C_RETURN_CODE(c2h_buf); + halmac_adapter->halmac_state.iqk_set.fw_return_code = h2c_return_code; + + if ((enum halmac_h2c_return_code)h2c_return_code == + HALMAC_H2C_RETURN_SUCCESS) { + process_status = HALMAC_CMD_PROCESS_DONE; + halmac_adapter->halmac_state.iqk_set.process_status = + process_status; + PLATFORM_EVENT_INDICATION(driver_adapter, HALMAC_FEATURE_IQK, + process_status, NULL, 0); + } else { + process_status = HALMAC_CMD_PROCESS_ERROR; + halmac_adapter->halmac_state.iqk_set.process_status = + process_status; + PLATFORM_EVENT_INDICATION( + driver_adapter, HALMAC_FEATURE_IQK, process_status, + &halmac_adapter->halmac_state.iqk_set.fw_return_code, + 1); + } + + return HALMAC_RET_SUCCESS; +} + +static enum halmac_ret_status +halmac_parse_h2c_ack_power_tracking_88xx(struct halmac_adapter *halmac_adapter, + u8 *c2h_buf, u32 c2h_size) +{ + u8 h2c_seq = 0; + u8 h2c_return_code; + void *driver_adapter = halmac_adapter->driver_adapter; + enum halmac_cmd_process_status process_status; + + h2c_seq = (u8)H2C_ACK_HDR_GET_H2C_SEQ(c2h_buf); + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_H2C, DBG_DMESG, + "[TRACE]Seq num : h2c -> %d c2h -> %d\n", + halmac_adapter->halmac_state.power_tracking_set.seq_num, + h2c_seq); + if (h2c_seq != + halmac_adapter->halmac_state.power_tracking_set.seq_num) { + pr_err("[ERR]Seq num mismatch : h2c -> %d c2h -> %d\n", + halmac_adapter->halmac_state.power_tracking_set.seq_num, + h2c_seq); + return HALMAC_RET_SUCCESS; + } + + if (halmac_adapter->halmac_state.power_tracking_set.process_status != + HALMAC_CMD_PROCESS_SENDING) { + pr_err("[ERR]Not in HALMAC_CMD_PROCESS_SENDING\n"); + return HALMAC_RET_SUCCESS; + } + + h2c_return_code = (u8)H2C_ACK_HDR_GET_H2C_RETURN_CODE(c2h_buf); + halmac_adapter->halmac_state.power_tracking_set.fw_return_code = + h2c_return_code; + + if ((enum halmac_h2c_return_code)h2c_return_code == + HALMAC_H2C_RETURN_SUCCESS) { + process_status = HALMAC_CMD_PROCESS_DONE; + halmac_adapter->halmac_state.power_tracking_set.process_status = + process_status; + PLATFORM_EVENT_INDICATION(driver_adapter, + HALMAC_FEATURE_POWER_TRACKING, + process_status, NULL, 0); + } else { + process_status = HALMAC_CMD_PROCESS_ERROR; + halmac_adapter->halmac_state.power_tracking_set.process_status = + process_status; + PLATFORM_EVENT_INDICATION( + driver_adapter, HALMAC_FEATURE_POWER_TRACKING, + process_status, + &halmac_adapter->halmac_state.power_tracking_set + .fw_return_code, + 1); + } + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status +halmac_convert_to_sdio_bus_offset_88xx(struct halmac_adapter *halmac_adapter, + u32 *halmac_offset) +{ + void *driver_adapter = NULL; + + driver_adapter = halmac_adapter->driver_adapter; + + switch ((*halmac_offset) & 0xFFFF0000) { + case WLAN_IOREG_OFFSET: + *halmac_offset = (HALMAC_SDIO_CMD_ADDR_MAC_REG << 13) | + (*halmac_offset & HALMAC_WLAN_MAC_REG_MSK); + break; + case SDIO_LOCAL_OFFSET: + *halmac_offset = (HALMAC_SDIO_CMD_ADDR_SDIO_REG << 13) | + (*halmac_offset & HALMAC_SDIO_LOCAL_MSK); + break; + default: + *halmac_offset = 0xFFFFFFFF; + pr_err("Unknown base address!!\n"); + return HALMAC_RET_CONVERT_SDIO_OFFSET_FAIL; + } + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status +halmac_update_sdio_free_page_88xx(struct halmac_adapter *halmac_adapter) +{ + u32 free_page = 0, free_page2 = 0, free_page3 = 0; + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + struct halmac_sdio_free_space *sdio_free_space; + u8 data[12] = {0}; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s ==========>\n", __func__); + + sdio_free_space = &halmac_adapter->sdio_free_space; + /*need to use HALMAC_REG_READ_N, 20160316, Soar*/ + HALMAC_REG_SDIO_CMD53_READ_N(halmac_adapter, REG_SDIO_FREE_TXPG, 12, + data); + free_page = + data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); + free_page2 = + data[4] | (data[5] << 8) | (data[6] << 16) | (data[7] << 24); + free_page3 = + data[8] | (data[9] << 8) | (data[10] << 16) | (data[11] << 24); + + sdio_free_space->high_queue_number = + (u16)BIT_GET_HIQ_FREEPG_V1(free_page); + sdio_free_space->normal_queue_number = + (u16)BIT_GET_MID_FREEPG_V1(free_page); + sdio_free_space->low_queue_number = + (u16)BIT_GET_LOW_FREEPG_V1(free_page2); + sdio_free_space->public_queue_number = + (u16)BIT_GET_PUB_FREEPG_V1(free_page2); + sdio_free_space->extra_queue_number = + (u16)BIT_GET_EXQ_FREEPG_V1(free_page3); + sdio_free_space->ac_oqt_number = (u8)((free_page3 >> 16) & 0xFF); + sdio_free_space->non_ac_oqt_number = (u8)((free_page3 >> 24) & 0xFF); + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status +halmac_update_oqt_free_space_88xx(struct halmac_adapter *halmac_adapter) +{ + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + struct halmac_sdio_free_space *sdio_free_space; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s ==========>\n", __func__); + + sdio_free_space = &halmac_adapter->sdio_free_space; + + sdio_free_space->ac_oqt_number = HALMAC_REG_READ_8( + halmac_adapter, REG_SDIO_OQT_FREE_TXPG_V1 + 2); + sdio_free_space->ac_empty = + HALMAC_REG_READ_8(halmac_adapter, REG_TXPKT_EMPTY); + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s <==========\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +enum halmac_efuse_cmd_construct_state +halmac_query_efuse_curr_state_88xx(struct halmac_adapter *halmac_adapter) +{ + return halmac_adapter->halmac_state.efuse_state_set + .efuse_cmd_construct_state; +} + +enum halmac_ret_status halmac_transition_efuse_state_88xx( + struct halmac_adapter *halmac_adapter, + enum halmac_efuse_cmd_construct_state dest_state) +{ + struct halmac_efuse_state_set *efuse_state = + &halmac_adapter->halmac_state.efuse_state_set; + + if (efuse_state->efuse_cmd_construct_state != + HALMAC_EFUSE_CMD_CONSTRUCT_IDLE && + efuse_state->efuse_cmd_construct_state != + HALMAC_EFUSE_CMD_CONSTRUCT_BUSY && + efuse_state->efuse_cmd_construct_state != + HALMAC_EFUSE_CMD_CONSTRUCT_H2C_SENT) + return HALMAC_RET_ERROR_STATE; + + if (efuse_state->efuse_cmd_construct_state == dest_state) + return HALMAC_RET_ERROR_STATE; + + if (dest_state == HALMAC_EFUSE_CMD_CONSTRUCT_BUSY) { + if (efuse_state->efuse_cmd_construct_state == + HALMAC_EFUSE_CMD_CONSTRUCT_H2C_SENT) + return HALMAC_RET_ERROR_STATE; + } else if (dest_state == HALMAC_EFUSE_CMD_CONSTRUCT_H2C_SENT) { + if (efuse_state->efuse_cmd_construct_state == + HALMAC_EFUSE_CMD_CONSTRUCT_IDLE) + return HALMAC_RET_ERROR_STATE; + } + + efuse_state->efuse_cmd_construct_state = dest_state; + + return HALMAC_RET_SUCCESS; +} + +enum halmac_cfg_para_cmd_construct_state +halmac_query_cfg_para_curr_state_88xx(struct halmac_adapter *halmac_adapter) +{ + return halmac_adapter->halmac_state.cfg_para_state_set + .cfg_para_cmd_construct_state; +} + +enum halmac_ret_status halmac_transition_cfg_para_state_88xx( + struct halmac_adapter *halmac_adapter, + enum halmac_cfg_para_cmd_construct_state dest_state) +{ + struct halmac_cfg_para_state_set *cfg_para = + &halmac_adapter->halmac_state.cfg_para_state_set; + + if (cfg_para->cfg_para_cmd_construct_state != + HALMAC_CFG_PARA_CMD_CONSTRUCT_IDLE && + cfg_para->cfg_para_cmd_construct_state != + HALMAC_CFG_PARA_CMD_CONSTRUCT_CONSTRUCTING && + cfg_para->cfg_para_cmd_construct_state != + HALMAC_CFG_PARA_CMD_CONSTRUCT_H2C_SENT) + return HALMAC_RET_ERROR_STATE; + + if (dest_state == HALMAC_CFG_PARA_CMD_CONSTRUCT_IDLE) { + if (cfg_para->cfg_para_cmd_construct_state == + HALMAC_CFG_PARA_CMD_CONSTRUCT_CONSTRUCTING) + return HALMAC_RET_ERROR_STATE; + } else if (dest_state == HALMAC_CFG_PARA_CMD_CONSTRUCT_CONSTRUCTING) { + if (cfg_para->cfg_para_cmd_construct_state == + HALMAC_CFG_PARA_CMD_CONSTRUCT_H2C_SENT) + return HALMAC_RET_ERROR_STATE; + } else if (dest_state == HALMAC_CFG_PARA_CMD_CONSTRUCT_H2C_SENT) { + if (cfg_para->cfg_para_cmd_construct_state == + HALMAC_CFG_PARA_CMD_CONSTRUCT_IDLE || + cfg_para->cfg_para_cmd_construct_state == + HALMAC_CFG_PARA_CMD_CONSTRUCT_H2C_SENT) + return HALMAC_RET_ERROR_STATE; + } + + cfg_para->cfg_para_cmd_construct_state = dest_state; + + return HALMAC_RET_SUCCESS; +} + +enum halmac_scan_cmd_construct_state +halmac_query_scan_curr_state_88xx(struct halmac_adapter *halmac_adapter) +{ + return halmac_adapter->halmac_state.scan_state_set + .scan_cmd_construct_state; +} + +enum halmac_ret_status halmac_transition_scan_state_88xx( + struct halmac_adapter *halmac_adapter, + enum halmac_scan_cmd_construct_state dest_state) +{ + struct halmac_scan_state_set *scan = + &halmac_adapter->halmac_state.scan_state_set; + + if (scan->scan_cmd_construct_state > HALMAC_SCAN_CMD_CONSTRUCT_H2C_SENT) + return HALMAC_RET_ERROR_STATE; + + if (dest_state == HALMAC_SCAN_CMD_CONSTRUCT_IDLE) { + if (scan->scan_cmd_construct_state == + HALMAC_SCAN_CMD_CONSTRUCT_BUFFER_CLEARED || + scan->scan_cmd_construct_state == + HALMAC_SCAN_CMD_CONSTRUCT_CONSTRUCTING) + return HALMAC_RET_ERROR_STATE; + } else if (dest_state == HALMAC_SCAN_CMD_CONSTRUCT_BUFFER_CLEARED) { + if (scan->scan_cmd_construct_state == + HALMAC_SCAN_CMD_CONSTRUCT_H2C_SENT) + return HALMAC_RET_ERROR_STATE; + } else if (dest_state == HALMAC_SCAN_CMD_CONSTRUCT_CONSTRUCTING) { + if (scan->scan_cmd_construct_state == + HALMAC_SCAN_CMD_CONSTRUCT_IDLE || + scan->scan_cmd_construct_state == + HALMAC_SCAN_CMD_CONSTRUCT_H2C_SENT) + return HALMAC_RET_ERROR_STATE; + } else if (dest_state == HALMAC_SCAN_CMD_CONSTRUCT_H2C_SENT) { + if (scan->scan_cmd_construct_state != + HALMAC_SCAN_CMD_CONSTRUCT_CONSTRUCTING && + scan->scan_cmd_construct_state != + HALMAC_SCAN_CMD_CONSTRUCT_BUFFER_CLEARED) + return HALMAC_RET_ERROR_STATE; + } + + scan->scan_cmd_construct_state = dest_state; + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status halmac_query_cfg_para_status_88xx( + struct halmac_adapter *halmac_adapter, + enum halmac_cmd_process_status *process_status, u8 *data, u32 *size) +{ + struct halmac_cfg_para_state_set *cfg_para_state_set = + &halmac_adapter->halmac_state.cfg_para_state_set; + + *process_status = cfg_para_state_set->process_status; + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status halmac_query_dump_physical_efuse_status_88xx( + struct halmac_adapter *halmac_adapter, + enum halmac_cmd_process_status *process_status, u8 *data, u32 *size) +{ + void *driver_adapter = NULL; + struct halmac_efuse_state_set *efuse_state_set = + &halmac_adapter->halmac_state.efuse_state_set; + + driver_adapter = halmac_adapter->driver_adapter; + + *process_status = efuse_state_set->process_status; + + if (!data) + return HALMAC_RET_NULL_POINTER; + + if (!size) + return HALMAC_RET_NULL_POINTER; + + if (*process_status == HALMAC_CMD_PROCESS_DONE) { + if (*size < halmac_adapter->hw_config_info.efuse_size) { + *size = halmac_adapter->hw_config_info.efuse_size; + return HALMAC_RET_BUFFER_TOO_SMALL; + } + + *size = halmac_adapter->hw_config_info.efuse_size; + memcpy(data, halmac_adapter->hal_efuse_map, *size); + } + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status halmac_query_dump_logical_efuse_status_88xx( + struct halmac_adapter *halmac_adapter, + enum halmac_cmd_process_status *process_status, u8 *data, u32 *size) +{ + u8 *eeprom_map = NULL; + u32 eeprom_size = halmac_adapter->hw_config_info.eeprom_size; + void *driver_adapter = NULL; + struct halmac_efuse_state_set *efuse_state_set = + &halmac_adapter->halmac_state.efuse_state_set; + + driver_adapter = halmac_adapter->driver_adapter; + + *process_status = efuse_state_set->process_status; + + if (!data) + return HALMAC_RET_NULL_POINTER; + + if (!size) + return HALMAC_RET_NULL_POINTER; + + if (*process_status == HALMAC_CMD_PROCESS_DONE) { + if (*size < eeprom_size) { + *size = eeprom_size; + return HALMAC_RET_BUFFER_TOO_SMALL; + } + + *size = eeprom_size; + + eeprom_map = kzalloc(eeprom_size, GFP_KERNEL); + if (!eeprom_map) { + /* out of memory */ + return HALMAC_RET_MALLOC_FAIL; + } + memset(eeprom_map, 0xFF, eeprom_size); + + if (halmac_eeprom_parser_88xx( + halmac_adapter, halmac_adapter->hal_efuse_map, + eeprom_map) != HALMAC_RET_SUCCESS) { + kfree(eeprom_map); + return HALMAC_RET_EEPROM_PARSING_FAIL; + } + + memcpy(data, eeprom_map, *size); + + kfree(eeprom_map); + } + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status halmac_query_channel_switch_status_88xx( + struct halmac_adapter *halmac_adapter, + enum halmac_cmd_process_status *process_status, u8 *data, u32 *size) +{ + struct halmac_scan_state_set *scan_state_set = + &halmac_adapter->halmac_state.scan_state_set; + + *process_status = scan_state_set->process_status; + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status halmac_query_update_packet_status_88xx( + struct halmac_adapter *halmac_adapter, + enum halmac_cmd_process_status *process_status, u8 *data, u32 *size) +{ + struct halmac_update_packet_state_set *update_packet_set = + &halmac_adapter->halmac_state.update_packet_set; + + *process_status = update_packet_set->process_status; + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status +halmac_query_iqk_status_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_cmd_process_status *process_status, + u8 *data, u32 *size) +{ + struct halmac_iqk_state_set *iqk_set = + &halmac_adapter->halmac_state.iqk_set; + + *process_status = iqk_set->process_status; + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status halmac_query_power_tracking_status_88xx( + struct halmac_adapter *halmac_adapter, + enum halmac_cmd_process_status *process_status, u8 *data, u32 *size) +{ + struct halmac_power_tracking_state_set *power_tracking_state_set = + &halmac_adapter->halmac_state.power_tracking_set; + ; + + *process_status = power_tracking_state_set->process_status; + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status +halmac_query_psd_status_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_cmd_process_status *process_status, + u8 *data, u32 *size) +{ + void *driver_adapter = NULL; + struct halmac_psd_state_set *psd_set = + &halmac_adapter->halmac_state.psd_set; + + driver_adapter = halmac_adapter->driver_adapter; + + *process_status = psd_set->process_status; + + if (!data) + return HALMAC_RET_NULL_POINTER; + + if (!size) + return HALMAC_RET_NULL_POINTER; + + if (*process_status == HALMAC_CMD_PROCESS_DONE) { + if (*size < psd_set->data_size) { + *size = psd_set->data_size; + return HALMAC_RET_BUFFER_TOO_SMALL; + } + + *size = psd_set->data_size; + memcpy(data, psd_set->data, *size); + } + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status +halmac_verify_io_88xx(struct halmac_adapter *halmac_adapter) +{ + u8 value8, wvalue8; + u32 value32, value32_2, wvalue32; + u32 halmac_offset; + void *driver_adapter = NULL; + enum halmac_ret_status ret_status = HALMAC_RET_SUCCESS; + + driver_adapter = halmac_adapter->driver_adapter; + + if (halmac_adapter->halmac_interface == HALMAC_INTERFACE_SDIO) { + halmac_offset = REG_PAGE5_DUMMY; + if ((halmac_offset & 0xFFFF0000) == 0) + halmac_offset |= WLAN_IOREG_OFFSET; + + ret_status = halmac_convert_to_sdio_bus_offset_88xx( + halmac_adapter, &halmac_offset); + + /* Verify CMD52 R/W */ + wvalue8 = 0xab; + PLATFORM_SDIO_CMD52_WRITE(driver_adapter, halmac_offset, + wvalue8); + + value8 = + PLATFORM_SDIO_CMD52_READ(driver_adapter, halmac_offset); + + if (value8 != wvalue8) { + pr_err("cmd52 r/w fail write = %X read = %X\n", wvalue8, + value8); + ret_status = HALMAC_RET_PLATFORM_API_INCORRECT; + } else { + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, + DBG_DMESG, "cmd52 r/w ok\n"); + } + + /* Verify CMD53 R/W */ + PLATFORM_SDIO_CMD52_WRITE(driver_adapter, halmac_offset, 0xaa); + PLATFORM_SDIO_CMD52_WRITE(driver_adapter, halmac_offset + 1, + 0xbb); + PLATFORM_SDIO_CMD52_WRITE(driver_adapter, halmac_offset + 2, + 0xcc); + PLATFORM_SDIO_CMD52_WRITE(driver_adapter, halmac_offset + 3, + 0xdd); + + value32 = PLATFORM_SDIO_CMD53_READ_32(driver_adapter, + halmac_offset); + + if (value32 != 0xddccbbaa) { + pr_err("cmd53 r fail : read = %X\n", value32); + ret_status = HALMAC_RET_PLATFORM_API_INCORRECT; + } else { + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, + DBG_DMESG, "cmd53 r ok\n"); + } + + wvalue32 = 0x11223344; + PLATFORM_SDIO_CMD53_WRITE_32(driver_adapter, halmac_offset, + wvalue32); + + value32 = PLATFORM_SDIO_CMD53_READ_32(driver_adapter, + halmac_offset); + + if (value32 != wvalue32) { + pr_err("cmd53 w fail\n"); + ret_status = HALMAC_RET_PLATFORM_API_INCORRECT; + } else { + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, + DBG_DMESG, "cmd53 w ok\n"); + } + + value32 = PLATFORM_SDIO_CMD53_READ_32( + driver_adapter, + halmac_offset + 2); /* value32 should be 0x33441122 */ + + wvalue32 = 0x11225566; + PLATFORM_SDIO_CMD53_WRITE_32(driver_adapter, halmac_offset, + wvalue32); + + value32_2 = PLATFORM_SDIO_CMD53_READ_32( + driver_adapter, + halmac_offset + 2); /* value32 should be 0x55661122 */ + if (value32_2 == value32) { + pr_err("cmd52 is used for HAL_SDIO_CMD53_READ_32\n"); + ret_status = HALMAC_RET_PLATFORM_API_INCORRECT; + } else { + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, + DBG_DMESG, "cmd53 is correctly used\n"); + } + } else { + wvalue32 = 0x77665511; + PLATFORM_REG_WRITE_32(driver_adapter, REG_PAGE5_DUMMY, + wvalue32); + + value32 = PLATFORM_REG_READ_32(driver_adapter, REG_PAGE5_DUMMY); + if (value32 != wvalue32) { + pr_err("reg rw\n"); + ret_status = HALMAC_RET_PLATFORM_API_INCORRECT; + } else { + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, + DBG_DMESG, "reg rw ok\n"); + } + } + + return ret_status; +} + +enum halmac_ret_status +halmac_verify_send_rsvd_page_88xx(struct halmac_adapter *halmac_adapter) +{ + u8 *rsvd_buf = NULL; + u8 *rsvd_page = NULL; + u32 i; + u32 h2c_pkt_verify_size = 64, h2c_pkt_verify_payload = 0xab; + void *driver_adapter = NULL; + enum halmac_ret_status ret_status = HALMAC_RET_SUCCESS; + + driver_adapter = halmac_adapter->driver_adapter; + + rsvd_buf = kzalloc(h2c_pkt_verify_size, GFP_KERNEL); + + if (!rsvd_buf) { + /*pr_err("[ERR]rsvd buffer malloc fail!!\n");*/ + return HALMAC_RET_MALLOC_FAIL; + } + + memset(rsvd_buf, (u8)h2c_pkt_verify_payload, h2c_pkt_verify_size); + + ret_status = halmac_download_rsvd_page_88xx(halmac_adapter, rsvd_buf, + h2c_pkt_verify_size); + + if (ret_status != HALMAC_RET_SUCCESS) { + kfree(rsvd_buf); + return ret_status; + } + + rsvd_page = kzalloc(h2c_pkt_verify_size + + halmac_adapter->hw_config_info.txdesc_size, + GFP_KERNEL); + + if (!rsvd_page) { + pr_err("[ERR]rsvd page malloc fail!!\n"); + kfree(rsvd_buf); + return HALMAC_RET_MALLOC_FAIL; + } + + ret_status = halmac_dump_fifo_88xx( + halmac_adapter, HAL_FIFO_SEL_RSVD_PAGE, 0, + h2c_pkt_verify_size + + halmac_adapter->hw_config_info.txdesc_size, + rsvd_page); + + if (ret_status != HALMAC_RET_SUCCESS) { + kfree(rsvd_buf); + kfree(rsvd_page); + return ret_status; + } + + for (i = 0; i < h2c_pkt_verify_size; i++) { + if (*(rsvd_buf + i) != + *(rsvd_page + + (i + halmac_adapter->hw_config_info.txdesc_size))) { + pr_err("[ERR]Compare RSVD page Fail\n"); + ret_status = HALMAC_RET_PLATFORM_API_INCORRECT; + } + } + + kfree(rsvd_buf); + kfree(rsvd_page); + + return ret_status; +} + +void halmac_power_save_cb_88xx(void *cb_data) +{ + void *driver_adapter = NULL; + struct halmac_adapter *halmac_adapter = (struct halmac_adapter *)NULL; + + halmac_adapter = (struct halmac_adapter *)cb_data; + driver_adapter = halmac_adapter->driver_adapter; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_PWR, DBG_DMESG, + "%s\n", __func__); +} + +enum halmac_ret_status +halmac_buffer_read_88xx(struct halmac_adapter *halmac_adapter, u32 offset, + u32 size, enum hal_fifo_sel halmac_fifo_sel, + u8 *fifo_map) +{ + u32 start_page, value_read; + u32 i, counter = 0, residue; + struct halmac_api *halmac_api; + + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + if (halmac_fifo_sel == HAL_FIFO_SEL_RSVD_PAGE) + offset = offset + + (halmac_adapter->txff_allocation.rsvd_pg_bndy << 7); + + start_page = offset >> 12; + residue = offset & (4096 - 1); + + if (halmac_fifo_sel == HAL_FIFO_SEL_TX || + halmac_fifo_sel == HAL_FIFO_SEL_RSVD_PAGE) + start_page += 0x780; + else if (halmac_fifo_sel == HAL_FIFO_SEL_RX) + start_page += 0x700; + else if (halmac_fifo_sel == HAL_FIFO_SEL_REPORT) + start_page += 0x660; + else if (halmac_fifo_sel == HAL_FIFO_SEL_LLT) + start_page += 0x650; + else + return HALMAC_RET_NOT_SUPPORT; + + value_read = HALMAC_REG_READ_16(halmac_adapter, REG_PKTBUF_DBG_CTRL); + + do { + HALMAC_REG_WRITE_16(halmac_adapter, REG_PKTBUF_DBG_CTRL, + (u16)(start_page | (value_read & 0xF000))); + + for (i = 0x8000 + residue; i <= 0x8FFF; i += 4) { + *(u32 *)(fifo_map + counter) = + HALMAC_REG_READ_32(halmac_adapter, i); + *(u32 *)(fifo_map + counter) = + le32_to_cpu(*(__le32 *)(fifo_map + counter)); + counter += 4; + if (size == counter) + goto HALMAC_BUF_READ_OK; + } + + residue = 0; + start_page++; + } while (1); + +HALMAC_BUF_READ_OK: + HALMAC_REG_WRITE_16(halmac_adapter, REG_PKTBUF_DBG_CTRL, + (u16)value_read); + + return HALMAC_RET_SUCCESS; +} + +void halmac_restore_mac_register_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_restore_info *restore_info, + u32 restore_num) +{ + u8 value_length; + u32 i; + u32 mac_register; + u32 mac_value; + struct halmac_api *halmac_api; + struct halmac_restore_info *curr_restore_info = restore_info; + + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + for (i = 0; i < restore_num; i++) { + mac_register = curr_restore_info->mac_register; + mac_value = curr_restore_info->value; + value_length = curr_restore_info->length; + + if (value_length == 1) + HALMAC_REG_WRITE_8(halmac_adapter, mac_register, + (u8)mac_value); + else if (value_length == 2) + HALMAC_REG_WRITE_16(halmac_adapter, mac_register, + (u16)mac_value); + else if (value_length == 4) + HALMAC_REG_WRITE_32(halmac_adapter, mac_register, + mac_value); + + curr_restore_info++; + } +} + +void halmac_api_record_id_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_api_id api_id) +{ +} + +enum halmac_ret_status +halmac_set_usb_mode_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_usb_mode usb_mode) +{ + u32 usb_temp; + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + enum halmac_usb_mode current_usb_mode; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + current_usb_mode = + HALMAC_REG_READ_8(halmac_adapter, REG_SYS_CFG2 + 3) == 0x20 ? + HALMAC_USB_MODE_U3 : + HALMAC_USB_MODE_U2; + + /*check if HW supports usb2_usb3 swtich*/ + usb_temp = HALMAC_REG_READ_32(halmac_adapter, REG_PAD_CTRL2); + if (!BIT_GET_USB23_SW_MODE_V1(usb_temp) && + !(usb_temp & BIT_USB3_USB2_TRANSITION)) { + pr_err("HALMAC_HW_USB_MODE usb mode HW unsupport\n"); + return HALMAC_RET_USB2_3_SWITCH_UNSUPPORT; + } + + if (usb_mode == current_usb_mode) { + pr_err("HALMAC_HW_USB_MODE usb mode unchange\n"); + return HALMAC_RET_USB_MODE_UNCHANGE; + } + + usb_temp &= ~(BIT_USB23_SW_MODE_V1(0x3)); + + if (usb_mode == HALMAC_USB_MODE_U2) { + /* usb3 to usb2 */ + HALMAC_REG_WRITE_32( + halmac_adapter, REG_PAD_CTRL2, + usb_temp | BIT_USB23_SW_MODE_V1(HALMAC_USB_MODE_U2) | + BIT_RSM_EN_V1); + } else { + /* usb2 to usb3 */ + HALMAC_REG_WRITE_32( + halmac_adapter, REG_PAD_CTRL2, + usb_temp | BIT_USB23_SW_MODE_V1(HALMAC_USB_MODE_U3) | + BIT_RSM_EN_V1); + } + + HALMAC_REG_WRITE_8(halmac_adapter, REG_PAD_CTRL2 + 1, + 4); /* set counter down timer 4x64 ms */ + HALMAC_REG_WRITE_16( + halmac_adapter, REG_SYS_PW_CTRL, + HALMAC_REG_READ_16(halmac_adapter, REG_SYS_PW_CTRL) | + BIT_APFM_OFFMAC); + usleep_range(1000, 1100); + HALMAC_REG_WRITE_32(halmac_adapter, REG_PAD_CTRL2, + HALMAC_REG_READ_32(halmac_adapter, REG_PAD_CTRL2) | + BIT_NO_PDN_CHIPOFF_V1); + + return HALMAC_RET_SUCCESS; +} + +void halmac_enable_bb_rf_88xx(struct halmac_adapter *halmac_adapter, u8 enable) +{ + u8 value8; + u32 value32; + struct halmac_api *halmac_api; + + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + if (enable == 1) { + value8 = HALMAC_REG_READ_8(halmac_adapter, REG_SYS_FUNC_EN); + value8 = value8 | BIT(0) | BIT(1); + HALMAC_REG_WRITE_8(halmac_adapter, REG_SYS_FUNC_EN, value8); + + value8 = HALMAC_REG_READ_8(halmac_adapter, REG_RF_CTRL); + value8 = value8 | BIT(0) | BIT(1) | BIT(2); + HALMAC_REG_WRITE_8(halmac_adapter, REG_RF_CTRL, value8); + + value32 = HALMAC_REG_READ_32(halmac_adapter, REG_WLRF1); + value32 = value32 | BIT(24) | BIT(25) | BIT(26); + HALMAC_REG_WRITE_32(halmac_adapter, REG_WLRF1, value32); + } else { + value8 = HALMAC_REG_READ_8(halmac_adapter, REG_SYS_FUNC_EN); + value8 = value8 & (~(BIT(0) | BIT(1))); + HALMAC_REG_WRITE_8(halmac_adapter, REG_SYS_FUNC_EN, value8); + + value8 = HALMAC_REG_READ_8(halmac_adapter, REG_RF_CTRL); + value8 = value8 & (~(BIT(0) | BIT(1) | BIT(2))); + HALMAC_REG_WRITE_8(halmac_adapter, REG_RF_CTRL, value8); + + value32 = HALMAC_REG_READ_32(halmac_adapter, REG_WLRF1); + value32 = value32 & (~(BIT(24) | BIT(25) | BIT(26))); + HALMAC_REG_WRITE_32(halmac_adapter, REG_WLRF1, value32); + } +} + +void halmac_config_sdio_tx_page_threshold_88xx( + struct halmac_adapter *halmac_adapter, + struct halmac_tx_page_threshold_info *threshold_info) +{ + struct halmac_api *halmac_api; + + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + switch (threshold_info->dma_queue_sel) { + case HALMAC_MAP2_HQ: + HALMAC_REG_WRITE_32(halmac_adapter, REG_TQPNT1, + threshold_info->threshold); + break; + case HALMAC_MAP2_NQ: + HALMAC_REG_WRITE_32(halmac_adapter, REG_TQPNT2, + threshold_info->threshold); + break; + case HALMAC_MAP2_LQ: + HALMAC_REG_WRITE_32(halmac_adapter, REG_TQPNT3, + threshold_info->threshold); + break; + case HALMAC_MAP2_EXQ: + HALMAC_REG_WRITE_32(halmac_adapter, REG_TQPNT4, + threshold_info->threshold); + break; + default: + break; + } +} + +void halmac_config_ampdu_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_ampdu_config *ampdu_config) +{ + struct halmac_api *halmac_api; + + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_REG_WRITE_8(halmac_adapter, REG_PROT_MODE_CTRL + 2, + ampdu_config->max_agg_num); + HALMAC_REG_WRITE_8(halmac_adapter, REG_PROT_MODE_CTRL + 3, + ampdu_config->max_agg_num); +}; + +enum halmac_ret_status +halmac_check_oqt_88xx(struct halmac_adapter *halmac_adapter, u32 tx_agg_num, + u8 *halmac_buf) +{ + u32 counter = 10; + + /*S0, S1 are not allowed to use, 0x4E4[0] should be 0. Soar 20160323*/ + /*no need to check non_ac_oqt_number. HI and MGQ blocked will cause + *protocal issue before H_OQT being full + */ + switch ((enum halmac_queue_select)GET_TX_DESC_QSEL(halmac_buf)) { + case HALMAC_QUEUE_SELECT_VO: + case HALMAC_QUEUE_SELECT_VO_V2: + case HALMAC_QUEUE_SELECT_VI: + case HALMAC_QUEUE_SELECT_VI_V2: + case HALMAC_QUEUE_SELECT_BE: + case HALMAC_QUEUE_SELECT_BE_V2: + case HALMAC_QUEUE_SELECT_BK: + case HALMAC_QUEUE_SELECT_BK_V2: + counter = 10; + do { + if (halmac_adapter->sdio_free_space.ac_empty > 0) { + halmac_adapter->sdio_free_space.ac_empty -= 1; + break; + } + + if (halmac_adapter->sdio_free_space.ac_oqt_number >= + tx_agg_num) { + halmac_adapter->sdio_free_space.ac_oqt_number -= + (u8)tx_agg_num; + break; + } + + halmac_update_oqt_free_space_88xx(halmac_adapter); + + counter--; + if (counter == 0) + return HALMAC_RET_OQT_NOT_ENOUGH; + } while (1); + break; + default: + break; + } + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status +halmac_rqpn_parser_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_trx_mode halmac_trx_mode, + struct halmac_rqpn_ *rqpn_table) +{ + u8 search_flag; + u32 i; + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + search_flag = 0; + for (i = 0; i < HALMAC_TRX_MODE_MAX; i++) { + if (halmac_trx_mode == rqpn_table[i].mode) { + halmac_adapter + ->halmac_ptcl_queue[HALMAC_PTCL_QUEUE_VO] = + rqpn_table[i].dma_map_vo; + halmac_adapter + ->halmac_ptcl_queue[HALMAC_PTCL_QUEUE_VI] = + rqpn_table[i].dma_map_vi; + halmac_adapter + ->halmac_ptcl_queue[HALMAC_PTCL_QUEUE_BE] = + rqpn_table[i].dma_map_be; + halmac_adapter + ->halmac_ptcl_queue[HALMAC_PTCL_QUEUE_BK] = + rqpn_table[i].dma_map_bk; + halmac_adapter + ->halmac_ptcl_queue[HALMAC_PTCL_QUEUE_MG] = + rqpn_table[i].dma_map_mg; + halmac_adapter + ->halmac_ptcl_queue[HALMAC_PTCL_QUEUE_HI] = + rqpn_table[i].dma_map_hi; + search_flag = 1; + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, + DBG_DMESG, "%s done\n", __func__); + break; + } + } + + if (search_flag == 0) { + pr_err("HALMAC_RET_TRX_MODE_NOT_SUPPORT 1 switch case not support\n"); + return HALMAC_RET_TRX_MODE_NOT_SUPPORT; + } + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status +halmac_pg_num_parser_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_trx_mode halmac_trx_mode, + struct halmac_pg_num_ *pg_num_table) +{ + u8 search_flag; + u16 HPQ_num = 0, lpq_nnum = 0, NPQ_num = 0, GAPQ_num = 0; + u16 EXPQ_num = 0, PUBQ_num = 0; + u32 i = 0; + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + search_flag = 0; + for (i = 0; i < HALMAC_TRX_MODE_MAX; i++) { + if (halmac_trx_mode == pg_num_table[i].mode) { + HPQ_num = pg_num_table[i].hq_num; + lpq_nnum = pg_num_table[i].lq_num; + NPQ_num = pg_num_table[i].nq_num; + EXPQ_num = pg_num_table[i].exq_num; + GAPQ_num = pg_num_table[i].gap_num; + PUBQ_num = halmac_adapter->txff_allocation.ac_q_pg_num - + HPQ_num - lpq_nnum - NPQ_num - EXPQ_num - + GAPQ_num; + search_flag = 1; + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, + DBG_DMESG, "%s done\n", __func__); + break; + } + } + + if (search_flag == 0) { + pr_err("HALMAC_RET_TRX_MODE_NOT_SUPPORT 1 switch case not support\n"); + return HALMAC_RET_TRX_MODE_NOT_SUPPORT; + } + + if (halmac_adapter->txff_allocation.ac_q_pg_num < + HPQ_num + lpq_nnum + NPQ_num + EXPQ_num + GAPQ_num) + return HALMAC_RET_CFG_TXFIFO_PAGE_FAIL; + + halmac_adapter->txff_allocation.high_queue_pg_num = HPQ_num; + halmac_adapter->txff_allocation.low_queue_pg_num = lpq_nnum; + halmac_adapter->txff_allocation.normal_queue_pg_num = NPQ_num; + halmac_adapter->txff_allocation.extra_queue_pg_num = EXPQ_num; + halmac_adapter->txff_allocation.pub_queue_pg_num = PUBQ_num; + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status +halmac_parse_intf_phy_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_intf_phy_para_ *intf_phy_para, + enum halmac_intf_phy_platform platform, + enum hal_intf_phy intf_phy) +{ + u16 value; + u16 curr_cut; + u16 offset; + u16 ip_sel; + struct halmac_intf_phy_para_ *curr_phy_para; + struct halmac_api *halmac_api; + void *driver_adapter = NULL; + u8 result = HALMAC_RET_SUCCESS; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + switch (halmac_adapter->chip_version) { + case HALMAC_CHIP_VER_A_CUT: + curr_cut = (u16)HALMAC_INTF_PHY_CUT_A; + break; + case HALMAC_CHIP_VER_B_CUT: + curr_cut = (u16)HALMAC_INTF_PHY_CUT_B; + break; + case HALMAC_CHIP_VER_C_CUT: + curr_cut = (u16)HALMAC_INTF_PHY_CUT_C; + break; + case HALMAC_CHIP_VER_D_CUT: + curr_cut = (u16)HALMAC_INTF_PHY_CUT_D; + break; + case HALMAC_CHIP_VER_E_CUT: + curr_cut = (u16)HALMAC_INTF_PHY_CUT_E; + break; + case HALMAC_CHIP_VER_F_CUT: + curr_cut = (u16)HALMAC_INTF_PHY_CUT_F; + break; + case HALMAC_CHIP_VER_TEST: + curr_cut = (u16)HALMAC_INTF_PHY_CUT_TESTCHIP; + break; + default: + return HALMAC_RET_FAIL; + } + + for (curr_phy_para = intf_phy_para;; curr_phy_para++) { + if (!(curr_phy_para->cut & curr_cut) || + !(curr_phy_para->plaform & (u16)platform)) + continue; + + offset = curr_phy_para->offset; + value = curr_phy_para->value; + ip_sel = curr_phy_para->ip_sel; + + if (offset == 0xFFFF) + break; + + if (ip_sel == HALMAC_IP_SEL_MAC) { + HALMAC_REG_WRITE_8(halmac_adapter, (u32)offset, + (u8)value); + } else if (intf_phy == HAL_INTF_PHY_USB2) { + result = halmac_usbphy_write_88xx(halmac_adapter, + (u8)offset, value, + HAL_INTF_PHY_USB2); + + if (result != HALMAC_RET_SUCCESS) + pr_err("[ERR]Write USB2PHY fail!\n"); + + } else if (intf_phy == HAL_INTF_PHY_USB3) { + result = halmac_usbphy_write_88xx(halmac_adapter, + (u8)offset, value, + HAL_INTF_PHY_USB3); + + if (result != HALMAC_RET_SUCCESS) + pr_err("[ERR]Write USB3PHY fail!\n"); + + } else if (intf_phy == HAL_INTF_PHY_PCIE_GEN1) { + if (ip_sel == HALMAC_IP_SEL_INTF_PHY) + result = halmac_mdio_write_88xx( + halmac_adapter, (u8)offset, value, + HAL_INTF_PHY_PCIE_GEN1); + else + result = halmac_dbi_write8_88xx( + halmac_adapter, offset, (u8)value); + + if (result != HALMAC_RET_SUCCESS) + pr_err("[ERR]MDIO write GEN1 fail!\n"); + + } else if (intf_phy == HAL_INTF_PHY_PCIE_GEN2) { + if (ip_sel == HALMAC_IP_SEL_INTF_PHY) + result = halmac_mdio_write_88xx( + halmac_adapter, (u8)offset, value, + HAL_INTF_PHY_PCIE_GEN2); + else + result = halmac_dbi_write8_88xx( + halmac_adapter, offset, (u8)value); + + if (result != HALMAC_RET_SUCCESS) + pr_err("[ERR]MDIO write GEN2 fail!\n"); + } else { + pr_err("[ERR]Parse intf phy cfg error!\n"); + } + } + + return HALMAC_RET_SUCCESS; +} + +enum halmac_ret_status +halmac_dbi_write32_88xx(struct halmac_adapter *halmac_adapter, u16 addr, + u32 data) +{ + u8 tmp_u1b = 0; + u32 count = 0; + u16 write_addr = 0; + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_REG_WRITE_32(halmac_adapter, REG_DBI_WDATA_V1, data); + + write_addr = ((addr & 0x0ffc) | (0x000F << 12)); + HALMAC_REG_WRITE_16(halmac_adapter, REG_DBI_FLAG_V1, write_addr); + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_DBI, DBG_DMESG, + "WriteAddr = %x\n", write_addr); + + HALMAC_REG_WRITE_8(halmac_adapter, REG_DBI_FLAG_V1 + 2, 0x01); + tmp_u1b = HALMAC_REG_READ_8(halmac_adapter, REG_DBI_FLAG_V1 + 2); + + count = 20; + while (tmp_u1b && count != 0) { + udelay(10); + tmp_u1b = + HALMAC_REG_READ_8(halmac_adapter, REG_DBI_FLAG_V1 + 2); + count--; + } + + if (tmp_u1b) { + pr_err("DBI write fail!\n"); + return HALMAC_RET_FAIL; + } else { + return HALMAC_RET_SUCCESS; + } +} + +u32 halmac_dbi_read32_88xx(struct halmac_adapter *halmac_adapter, u16 addr) +{ + u16 read_addr = addr & 0x0ffc; + u8 tmp_u1b = 0; + u32 count = 0; + u32 ret = 0; + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_REG_WRITE_16(halmac_adapter, REG_DBI_FLAG_V1, read_addr); + + HALMAC_REG_WRITE_8(halmac_adapter, REG_DBI_FLAG_V1 + 2, 0x2); + tmp_u1b = HALMAC_REG_READ_8(halmac_adapter, REG_DBI_FLAG_V1 + 2); + + count = 20; + while (tmp_u1b && count != 0) { + udelay(10); + tmp_u1b = + HALMAC_REG_READ_8(halmac_adapter, REG_DBI_FLAG_V1 + 2); + count--; + } + + if (tmp_u1b) { + ret = 0xFFFF; + pr_err("DBI read fail!\n"); + } else { + ret = HALMAC_REG_READ_32(halmac_adapter, REG_DBI_RDATA_V1); + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_DBI, DBG_DMESG, + "Read Value = %x\n", ret); + } + + return ret; +} + +enum halmac_ret_status +halmac_dbi_write8_88xx(struct halmac_adapter *halmac_adapter, u16 addr, u8 data) +{ + u8 tmp_u1b = 0; + u32 count = 0; + u16 write_addr = 0; + u16 remainder = addr & (4 - 1); + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_REG_WRITE_8(halmac_adapter, REG_DBI_WDATA_V1 + remainder, data); + + write_addr = ((addr & 0x0ffc) | (BIT(0) << (remainder + 12))); + + HALMAC_REG_WRITE_16(halmac_adapter, REG_DBI_FLAG_V1, write_addr); + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_DBI, DBG_DMESG, + "WriteAddr = %x\n", write_addr); + + HALMAC_REG_WRITE_8(halmac_adapter, REG_DBI_FLAG_V1 + 2, 0x01); + + tmp_u1b = HALMAC_REG_READ_8(halmac_adapter, REG_DBI_FLAG_V1 + 2); + + count = 20; + while (tmp_u1b && count != 0) { + udelay(10); + tmp_u1b = + HALMAC_REG_READ_8(halmac_adapter, REG_DBI_FLAG_V1 + 2); + count--; + } + + if (tmp_u1b) { + pr_err("DBI write fail!\n"); + return HALMAC_RET_FAIL; + } else { + return HALMAC_RET_SUCCESS; + } +} + +u8 halmac_dbi_read8_88xx(struct halmac_adapter *halmac_adapter, u16 addr) +{ + u16 read_addr = addr & 0x0ffc; + u8 tmp_u1b = 0; + u32 count = 0; + u8 ret = 0; + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_REG_WRITE_16(halmac_adapter, REG_DBI_FLAG_V1, read_addr); + HALMAC_REG_WRITE_8(halmac_adapter, REG_DBI_FLAG_V1 + 2, 0x2); + + tmp_u1b = HALMAC_REG_READ_8(halmac_adapter, REG_DBI_FLAG_V1 + 2); + + count = 20; + while (tmp_u1b && count != 0) { + udelay(10); + tmp_u1b = + HALMAC_REG_READ_8(halmac_adapter, REG_DBI_FLAG_V1 + 2); + count--; + } + + if (tmp_u1b) { + ret = 0xFF; + pr_err("DBI read fail!\n"); + } else { + ret = HALMAC_REG_READ_8(halmac_adapter, + REG_DBI_RDATA_V1 + (addr & (4 - 1))); + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_DBI, DBG_DMESG, + "Read Value = %x\n", ret); + } + + return ret; +} + +enum halmac_ret_status +halmac_mdio_write_88xx(struct halmac_adapter *halmac_adapter, u8 addr, u16 data, + u8 speed) +{ + u8 tmp_u1b = 0; + u32 count = 0; + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + u8 real_addr = 0; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_REG_WRITE_16(halmac_adapter, REG_MDIO_V1, data); + + /* address : 5bit */ + real_addr = (addr & 0x1F); + HALMAC_REG_WRITE_8(halmac_adapter, REG_PCIE_MIX_CFG, real_addr); + + if (speed == HAL_INTF_PHY_PCIE_GEN1) { + /* GEN1 page 0 */ + if (addr < 0x20) { + /* select MDIO PHY Addr : reg 0x3F8[28:24]=5'b00 */ + HALMAC_REG_WRITE_8(halmac_adapter, REG_PCIE_MIX_CFG + 3, + 0x00); + + /* GEN1 page 1 */ + } else { + /* select MDIO PHY Addr : reg 0x3F8[28:24]=5'b01 */ + HALMAC_REG_WRITE_8(halmac_adapter, REG_PCIE_MIX_CFG + 3, + 0x01); + } + + } else if (speed == HAL_INTF_PHY_PCIE_GEN2) { + /* GEN2 page 0 */ + if (addr < 0x20) { + /* select MDIO PHY Addr : reg 0x3F8[28:24]=5'b10 */ + HALMAC_REG_WRITE_8(halmac_adapter, REG_PCIE_MIX_CFG + 3, + 0x02); + + /* GEN2 page 1 */ + } else { + /* select MDIO PHY Addr : reg 0x3F8[28:24]=5'b11 */ + HALMAC_REG_WRITE_8(halmac_adapter, REG_PCIE_MIX_CFG + 3, + 0x03); + } + } else { + pr_err("Error Speed !\n"); + } + + HALMAC_REG_WRITE_8(halmac_adapter, REG_PCIE_MIX_CFG, + HALMAC_REG_READ_8(halmac_adapter, REG_PCIE_MIX_CFG) | + BIT_MDIO_WFLAG_V1); + + tmp_u1b = HALMAC_REG_READ_8(halmac_adapter, REG_PCIE_MIX_CFG) & + BIT_MDIO_WFLAG_V1; + count = 20; + + while (tmp_u1b && count != 0) { + udelay(10); + tmp_u1b = HALMAC_REG_READ_8(halmac_adapter, REG_PCIE_MIX_CFG) & + BIT_MDIO_WFLAG_V1; + count--; + } + + if (tmp_u1b) { + pr_err("MDIO write fail!\n"); + return HALMAC_RET_FAIL; + } else { + return HALMAC_RET_SUCCESS; + } +} + +u16 halmac_mdio_read_88xx(struct halmac_adapter *halmac_adapter, u8 addr, + u8 speed + + ) +{ + u16 ret = 0; + u8 tmp_u1b = 0; + u32 count = 0; + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + u8 real_addr = 0; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + /* address : 5bit */ + real_addr = (addr & 0x1F); + HALMAC_REG_WRITE_8(halmac_adapter, REG_PCIE_MIX_CFG, real_addr); + + if (speed == HAL_INTF_PHY_PCIE_GEN1) { + /* GEN1 page 0 */ + if (addr < 0x20) { + /* select MDIO PHY Addr : reg 0x3F8[28:24]=5'b00 */ + HALMAC_REG_WRITE_8(halmac_adapter, REG_PCIE_MIX_CFG + 3, + 0x00); + + /* GEN1 page 1 */ + } else { + /* select MDIO PHY Addr : reg 0x3F8[28:24]=5'b01 */ + HALMAC_REG_WRITE_8(halmac_adapter, REG_PCIE_MIX_CFG + 3, + 0x01); + } + + } else if (speed == HAL_INTF_PHY_PCIE_GEN2) { + /* GEN2 page 0 */ + if (addr < 0x20) { + /* select MDIO PHY Addr : reg 0x3F8[28:24]=5'b10 */ + HALMAC_REG_WRITE_8(halmac_adapter, REG_PCIE_MIX_CFG + 3, + 0x02); + + /* GEN2 page 1 */ + } else { + /* select MDIO PHY Addr : reg 0x3F8[28:24]=5'b11 */ + HALMAC_REG_WRITE_8(halmac_adapter, REG_PCIE_MIX_CFG + 3, + 0x03); + } + } else { + pr_err("Error Speed !\n"); + } + + HALMAC_REG_WRITE_8(halmac_adapter, REG_PCIE_MIX_CFG, + HALMAC_REG_READ_8(halmac_adapter, REG_PCIE_MIX_CFG) | + BIT_MDIO_RFLAG_V1); + + tmp_u1b = HALMAC_REG_READ_8(halmac_adapter, REG_PCIE_MIX_CFG) & + BIT_MDIO_RFLAG_V1; + count = 20; + + while (tmp_u1b && count != 0) { + udelay(10); + tmp_u1b = HALMAC_REG_READ_8(halmac_adapter, REG_PCIE_MIX_CFG) & + BIT_MDIO_RFLAG_V1; + count--; + } + + if (tmp_u1b) { + ret = 0xFFFF; + pr_err("MDIO read fail!\n"); + + } else { + ret = HALMAC_REG_READ_16(halmac_adapter, REG_MDIO_V1 + 2); + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_MDIO, DBG_DMESG, + "Read Value = %x\n", ret); + } + + return ret; +} + +enum halmac_ret_status +halmac_usbphy_write_88xx(struct halmac_adapter *halmac_adapter, u8 addr, + u16 data, u8 speed) +{ + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + if (speed == HAL_INTF_PHY_USB3) { + HALMAC_REG_WRITE_8(halmac_adapter, 0xff0d, (u8)data); + HALMAC_REG_WRITE_8(halmac_adapter, 0xff0e, (u8)(data >> 8)); + HALMAC_REG_WRITE_8(halmac_adapter, 0xff0c, addr | BIT(7)); + } else if (speed == HAL_INTF_PHY_USB2) { + HALMAC_REG_WRITE_8(halmac_adapter, 0xfe41, (u8)data); + HALMAC_REG_WRITE_8(halmac_adapter, 0xfe40, addr); + HALMAC_REG_WRITE_8(halmac_adapter, 0xfe42, 0x81); + } else { + pr_err("[ERR]Error USB Speed !\n"); + return HALMAC_RET_NOT_SUPPORT; + } + + return HALMAC_RET_SUCCESS; +} + +u16 halmac_usbphy_read_88xx(struct halmac_adapter *halmac_adapter, u8 addr, + u8 speed) +{ + void *driver_adapter = NULL; + struct halmac_api *halmac_api; + u16 value = 0; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + if (speed == HAL_INTF_PHY_USB3) { + HALMAC_REG_WRITE_8(halmac_adapter, 0xff0c, addr | BIT(6)); + value = (u16)(HALMAC_REG_READ_32(halmac_adapter, 0xff0c) >> 8); + } else if (speed == HAL_INTF_PHY_USB2) { + if ((addr >= 0xE0) /*&& (addr <= 0xFF)*/) + addr -= 0x20; + if ((addr >= 0xC0) && (addr <= 0xDF)) { + HALMAC_REG_WRITE_8(halmac_adapter, 0xfe40, addr); + HALMAC_REG_WRITE_8(halmac_adapter, 0xfe42, 0x81); + value = HALMAC_REG_READ_8(halmac_adapter, 0xfe43); + } else { + pr_err("[ERR]Error USB2PHY offset!\n"); + return HALMAC_RET_NOT_SUPPORT; + } + } else { + pr_err("[ERR]Error USB Speed !\n"); + return HALMAC_RET_NOT_SUPPORT; + } + + return value; +} diff --git a/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_func_88xx.h b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_func_88xx.h new file mode 100644 index 000000000000..1b59301d1158 --- /dev/null +++ b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_func_88xx.h @@ -0,0 +1,321 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef _HALMAC_FUNC_88XX_H_ +#define _HALMAC_FUNC_88XX_H_ + +#include "../halmac_type.h" + +void halmac_init_offload_feature_state_machine_88xx( + struct halmac_adapter *halmac_adapter); + +enum halmac_ret_status +halmac_send_h2c_pkt_88xx(struct halmac_adapter *halmac_adapter, u8 *hal_buff, + u32 size, bool ack); + +enum halmac_ret_status +halmac_download_rsvd_page_88xx(struct halmac_adapter *halmac_adapter, + u8 *hal_buf, u32 size); + +enum halmac_ret_status +halmac_set_h2c_header_88xx(struct halmac_adapter *halmac_adapter, + u8 *hal_h2c_hdr, u16 *seq, bool ack); + +enum halmac_ret_status halmac_set_fw_offload_h2c_header_88xx( + struct halmac_adapter *halmac_adapter, u8 *hal_h2c_hdr, + struct halmac_h2c_header_info *h2c_header_info, u16 *seq_num); + +enum halmac_ret_status +halmac_dump_efuse_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_efuse_read_cfg cfg); + +enum halmac_ret_status +halmac_func_read_efuse_88xx(struct halmac_adapter *halmac_adapter, u32 offset, + u32 size, u8 *efuse_map); + +enum halmac_ret_status +halmac_func_write_efuse_88xx(struct halmac_adapter *halmac_adapter, u32 offset, + u8 value); + +enum halmac_ret_status +halmac_func_switch_efuse_bank_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_efuse_bank efuse_bank); + +enum halmac_ret_status +halmac_read_logical_efuse_map_88xx(struct halmac_adapter *halmac_adapter, + u8 *map); + +enum halmac_ret_status +halmac_func_write_logical_efuse_88xx(struct halmac_adapter *halmac_adapter, + u32 offset, u8 value); + +enum halmac_ret_status +halmac_func_pg_efuse_by_map_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_pg_efuse_info *pg_efuse_info, + enum halmac_efuse_read_cfg cfg); + +enum halmac_ret_status +halmac_eeprom_parser_88xx(struct halmac_adapter *halmac_adapter, + u8 *physical_efuse_map, u8 *logical_efuse_map); + +enum halmac_ret_status +halmac_read_hw_efuse_88xx(struct halmac_adapter *halmac_adapter, u32 offset, + u32 size, u8 *efuse_map); + +enum halmac_ret_status +halmac_dlfw_to_mem_88xx(struct halmac_adapter *halmac_adapter, u8 *ram_code, + u32 dest, u32 code_size); + +enum halmac_ret_status +halmac_send_fwpkt_88xx(struct halmac_adapter *halmac_adapter, u8 *ram_code, + u32 code_size); + +enum halmac_ret_status +halmac_iddma_dlfw_88xx(struct halmac_adapter *halmac_adapter, u32 source, + u32 dest, u32 length, u8 first); + +enum halmac_ret_status +halmac_check_fw_chksum_88xx(struct halmac_adapter *halmac_adapter, + u32 memory_address); + +enum halmac_ret_status +halmac_dlfw_end_flow_88xx(struct halmac_adapter *halmac_adapter); + +enum halmac_ret_status +halmac_free_dl_fw_end_flow_88xx(struct halmac_adapter *halmac_adapter); + +enum halmac_ret_status +halmac_pwr_seq_parser_88xx(struct halmac_adapter *halmac_adapter, u8 cut, + u8 fab, u8 intf, + struct halmac_wl_pwr_cfg_ **pp_pwr_seq_cfg + + ); + +enum halmac_ret_status +halmac_get_h2c_buff_free_space_88xx(struct halmac_adapter *halmac_adapter); + +enum halmac_ret_status +halmac_send_h2c_set_pwr_mode_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_fwlps_option *hal_fw_lps_opt); + +enum halmac_ret_status +halmac_func_send_original_h2c_88xx(struct halmac_adapter *halmac_adapter, + u8 *original_h2c, u16 *seq, u8 ack); + +enum halmac_ret_status +halmac_media_status_rpt_88xx(struct halmac_adapter *halmac_adapter, u8 op_mode, + u8 mac_id_ind, u8 mac_id, u8 mac_id_end); + +enum halmac_ret_status halmac_send_h2c_update_datapack_88xx( + struct halmac_adapter *halmac_adapter, + enum halmac_data_type halmac_data_type, + struct halmac_phy_parameter_info *para_info); + +enum halmac_ret_status +halmac_send_h2c_run_datapack_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_data_type halmac_data_type); + +enum halmac_ret_status +halmac_send_bt_coex_cmd_88xx(struct halmac_adapter *halmac_adapter, u8 *bt_buf, + u32 bt_size, u8 ack); + +enum halmac_ret_status +halmac_func_ctrl_ch_switch_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_ch_switch_option *cs_option); + +enum halmac_ret_status +halmac_func_send_general_info_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_general_info *general_info); + +enum halmac_ret_status +halmac_send_h2c_ps_tuning_para_88xx(struct halmac_adapter *halmac_adapter); + +enum halmac_ret_status +halmac_parse_c2h_packet_88xx(struct halmac_adapter *halmac_adapter, + u8 *halmac_buf, u32 halmac_size); + +enum halmac_ret_status +halmac_send_h2c_update_packet_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_packet_id pkt_id, u8 *pkt, + u32 pkt_size); + +enum halmac_ret_status +halmac_send_h2c_phy_parameter_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_phy_parameter_info *para_info, + bool full_fifo); + +enum halmac_ret_status +halmac_dump_physical_efuse_fw_88xx(struct halmac_adapter *halmac_adapter, + u32 offset, u32 size, u8 *efuse_map); + +enum halmac_ret_status halmac_send_h2c_update_bcn_parse_info_88xx( + struct halmac_adapter *halmac_adapter, + struct halmac_bcn_ie_info *bcn_ie_info); + +enum halmac_ret_status +halmac_convert_to_sdio_bus_offset_88xx(struct halmac_adapter *halmac_adapter, + u32 *halmac_offset); + +enum halmac_ret_status +halmac_update_sdio_free_page_88xx(struct halmac_adapter *halmac_adapter); + +enum halmac_ret_status +halmac_update_oqt_free_space_88xx(struct halmac_adapter *halmac_adapter); + +enum halmac_efuse_cmd_construct_state +halmac_query_efuse_curr_state_88xx(struct halmac_adapter *halmac_adapter); + +enum halmac_ret_status halmac_transition_efuse_state_88xx( + struct halmac_adapter *halmac_adapter, + enum halmac_efuse_cmd_construct_state dest_state); + +enum halmac_cfg_para_cmd_construct_state +halmac_query_cfg_para_curr_state_88xx(struct halmac_adapter *halmac_adapter); + +enum halmac_ret_status halmac_transition_cfg_para_state_88xx( + struct halmac_adapter *halmac_adapter, + enum halmac_cfg_para_cmd_construct_state dest_state); + +enum halmac_scan_cmd_construct_state +halmac_query_scan_curr_state_88xx(struct halmac_adapter *halmac_adapter); + +enum halmac_ret_status halmac_transition_scan_state_88xx( + struct halmac_adapter *halmac_adapter, + enum halmac_scan_cmd_construct_state dest_state); + +enum halmac_ret_status halmac_query_cfg_para_status_88xx( + struct halmac_adapter *halmac_adapter, + enum halmac_cmd_process_status *process_status, u8 *data, u32 *size); + +enum halmac_ret_status halmac_query_dump_physical_efuse_status_88xx( + struct halmac_adapter *halmac_adapter, + enum halmac_cmd_process_status *process_status, u8 *data, u32 *size); + +enum halmac_ret_status halmac_query_dump_logical_efuse_status_88xx( + struct halmac_adapter *halmac_adapter, + enum halmac_cmd_process_status *process_status, u8 *data, u32 *size); + +enum halmac_ret_status halmac_query_channel_switch_status_88xx( + struct halmac_adapter *halmac_adapter, + enum halmac_cmd_process_status *process_status, u8 *data, u32 *size); + +enum halmac_ret_status halmac_query_update_packet_status_88xx( + struct halmac_adapter *halmac_adapter, + enum halmac_cmd_process_status *process_status, u8 *data, u32 *size); + +enum halmac_ret_status +halmac_query_iqk_status_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_cmd_process_status *process_status, + u8 *data, u32 *size); + +enum halmac_ret_status halmac_query_power_tracking_status_88xx( + struct halmac_adapter *halmac_adapter, + enum halmac_cmd_process_status *process_status, u8 *data, u32 *size); + +enum halmac_ret_status +halmac_query_psd_status_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_cmd_process_status *process_status, + u8 *data, u32 *size); + +enum halmac_ret_status +halmac_verify_io_88xx(struct halmac_adapter *halmac_adapter); + +enum halmac_ret_status +halmac_verify_send_rsvd_page_88xx(struct halmac_adapter *halmac_adapter); + +void halmac_power_save_cb_88xx(void *cb_data); + +enum halmac_ret_status +halmac_buffer_read_88xx(struct halmac_adapter *halmac_adapter, u32 offset, + u32 size, enum hal_fifo_sel halmac_fifo_sel, + u8 *fifo_map); + +void halmac_restore_mac_register_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_restore_info *restore_info, + u32 restore_num); + +void halmac_api_record_id_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_api_id api_id); + +enum halmac_ret_status +halmac_set_usb_mode_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_usb_mode usb_mode); + +void halmac_enable_bb_rf_88xx(struct halmac_adapter *halmac_adapter, u8 enable); + +void halmac_config_sdio_tx_page_threshold_88xx( + struct halmac_adapter *halmac_adapter, + struct halmac_tx_page_threshold_info *threshold_info); + +enum halmac_ret_status +halmac_rqpn_parser_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_trx_mode halmac_trx_mode, + struct halmac_rqpn_ *pwr_seq_cfg); + +enum halmac_ret_status +halmac_check_oqt_88xx(struct halmac_adapter *halmac_adapter, u32 tx_agg_num, + u8 *halmac_buf); + +enum halmac_ret_status +halmac_pg_num_parser_88xx(struct halmac_adapter *halmac_adapter, + enum halmac_trx_mode halmac_trx_mode, + struct halmac_pg_num_ *pg_num_table); + +enum halmac_ret_status +halmac_parse_intf_phy_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_intf_phy_para_ *intf_phy_para, + enum halmac_intf_phy_platform platform, + enum hal_intf_phy intf_phy); + +enum halmac_ret_status +halmac_dbi_write32_88xx(struct halmac_adapter *halmac_adapter, u16 addr, + u32 data); + +u32 halmac_dbi_read32_88xx(struct halmac_adapter *halmac_adapter, u16 addr); + +enum halmac_ret_status +halmac_dbi_write8_88xx(struct halmac_adapter *halmac_adapter, u16 addr, + u8 data); + +u8 halmac_dbi_read8_88xx(struct halmac_adapter *halmac_adapter, u16 addr); + +u16 halmac_mdio_read_88xx(struct halmac_adapter *halmac_adapter, u8 addr, + u8 speed + + ); + +enum halmac_ret_status +halmac_mdio_write_88xx(struct halmac_adapter *halmac_adapter, u8 addr, u16 data, + u8 speed); + +void halmac_config_ampdu_88xx(struct halmac_adapter *halmac_adapter, + struct halmac_ampdu_config *ampdu_config); + +enum halmac_ret_status +halmac_usbphy_write_88xx(struct halmac_adapter *halmac_adapter, u8 addr, + u16 data, u8 speed); + +u16 halmac_usbphy_read_88xx(struct halmac_adapter *halmac_adapter, u8 addr, + u8 speed); +#endif /* _HALMAC_FUNC_88XX_H_ */ diff --git a/drivers/staging/rtlwifi/halmac/halmac_api.c b/drivers/staging/rtlwifi/halmac/halmac_api.c new file mode 100644 index 000000000000..0886a4611da0 --- /dev/null +++ b/drivers/staging/rtlwifi/halmac/halmac_api.c @@ -0,0 +1,426 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#include "halmac_2_platform.h" +#include "halmac_type.h" +#include "halmac_88xx/halmac_api_88xx.h" +#include "halmac_88xx/halmac_88xx_cfg.h" + +#include "halmac_88xx/halmac_8822b/halmac_8822b_cfg.h" + +static enum halmac_ret_status +halmac_check_platform_api(void *driver_adapter, + enum halmac_interface halmac_interface, + struct halmac_platform_api *halmac_platform_api) +{ + void *adapter_local = NULL; + + adapter_local = driver_adapter; + + if (!halmac_platform_api) + return HALMAC_RET_PLATFORM_API_NULL; + + if (halmac_interface == HALMAC_INTERFACE_SDIO) { + if (!halmac_platform_api->SDIO_CMD52_READ) { + pr_err("(!halmac_platform_api->SDIO_CMD52_READ)\n"); + return HALMAC_RET_PLATFORM_API_NULL; + } + if (!halmac_platform_api->SDIO_CMD53_READ_8) { + pr_err("(!halmac_platform_api->SDIO_CMD53_READ_8)\n"); + return HALMAC_RET_PLATFORM_API_NULL; + } + if (!halmac_platform_api->SDIO_CMD53_READ_16) { + pr_err("(!halmac_platform_api->SDIO_CMD53_READ_16)\n"); + return HALMAC_RET_PLATFORM_API_NULL; + } + if (!halmac_platform_api->SDIO_CMD53_READ_32) { + pr_err("(!halmac_platform_api->SDIO_CMD53_READ_32)\n"); + return HALMAC_RET_PLATFORM_API_NULL; + } + if (!halmac_platform_api->SDIO_CMD53_READ_N) { + pr_err("(!halmac_platform_api->SDIO_CMD53_READ_N)\n"); + return HALMAC_RET_PLATFORM_API_NULL; + } + if (!halmac_platform_api->SDIO_CMD52_WRITE) { + pr_err("(!halmac_platform_api->SDIO_CMD52_WRITE)\n"); + return HALMAC_RET_PLATFORM_API_NULL; + } + if (!halmac_platform_api->SDIO_CMD53_WRITE_8) { + pr_err("(!halmac_platform_api->SDIO_CMD53_WRITE_8)\n"); + return HALMAC_RET_PLATFORM_API_NULL; + } + if (!halmac_platform_api->SDIO_CMD53_WRITE_16) { + pr_err("(!halmac_platform_api->SDIO_CMD53_WRITE_16)\n"); + return HALMAC_RET_PLATFORM_API_NULL; + } + if (!halmac_platform_api->SDIO_CMD53_WRITE_32) { + pr_err("(!halmac_platform_api->SDIO_CMD53_WRITE_32)\n"); + return HALMAC_RET_PLATFORM_API_NULL; + } + } + + if (halmac_interface == HALMAC_INTERFACE_USB || + halmac_interface == HALMAC_INTERFACE_PCIE) { + if (!halmac_platform_api->REG_READ_8) { + pr_err("(!halmac_platform_api->REG_READ_8)\n"); + return HALMAC_RET_PLATFORM_API_NULL; + } + if (!halmac_platform_api->REG_READ_16) { + pr_err("(!halmac_platform_api->REG_READ_16)\n"); + return HALMAC_RET_PLATFORM_API_NULL; + } + if (!halmac_platform_api->REG_READ_32) { + pr_err("(!halmac_platform_api->REG_READ_32)\n"); + return HALMAC_RET_PLATFORM_API_NULL; + } + if (!halmac_platform_api->REG_WRITE_8) { + pr_err("(!halmac_platform_api->REG_WRITE_8)\n"); + return HALMAC_RET_PLATFORM_API_NULL; + } + if (!halmac_platform_api->REG_WRITE_16) { + pr_err("(!halmac_platform_api->REG_WRITE_16)\n"); + return HALMAC_RET_PLATFORM_API_NULL; + } + if (!halmac_platform_api->REG_WRITE_32) { + pr_err("(!halmac_platform_api->REG_WRITE_32)\n"); + return HALMAC_RET_PLATFORM_API_NULL; + } + } + + if (!halmac_platform_api->EVENT_INDICATION) { + pr_err("(!halmac_platform_api->EVENT_INDICATION)\n"); + return HALMAC_RET_PLATFORM_API_NULL; + } + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s ==========>\n", __func__); + + return HALMAC_RET_SUCCESS; +} + +static enum halmac_ret_status +halmac_convert_to_sdio_bus_offset(u32 *halmac_offset) +{ + switch ((*halmac_offset) & 0xFFFF0000) { + case WLAN_IOREG_OFFSET: + *halmac_offset = (HALMAC_SDIO_CMD_ADDR_MAC_REG << 13) | + (*halmac_offset & HALMAC_WLAN_MAC_REG_MSK); + break; + case SDIO_LOCAL_OFFSET: + *halmac_offset = (HALMAC_SDIO_CMD_ADDR_SDIO_REG << 13) | + (*halmac_offset & HALMAC_SDIO_LOCAL_MSK); + break; + default: + *halmac_offset = 0xFFFFFFFF; + return HALMAC_RET_CONVERT_SDIO_OFFSET_FAIL; + } + + return HALMAC_RET_SUCCESS; +} + +static u8 +platform_reg_read_8_sdio(void *driver_adapter, + struct halmac_platform_api *halmac_platform_api, + u32 offset) +{ + u8 value8; + u32 halmac_offset = offset; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + + if ((halmac_offset & 0xFFFF0000) == 0) + halmac_offset |= WLAN_IOREG_OFFSET; + + status = halmac_convert_to_sdio_bus_offset(&halmac_offset); + if (status != HALMAC_RET_SUCCESS) { + pr_err("%s error = %x\n", __func__, status); + return status; + } + + value8 = halmac_platform_api->SDIO_CMD52_READ(driver_adapter, + halmac_offset); + + return value8; +} + +static enum halmac_ret_status +platform_reg_write_8_sdio(void *driver_adapter, + struct halmac_platform_api *halmac_platform_api, + u32 offset, u8 data) +{ + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + u32 halmac_offset = offset; + + if ((halmac_offset & 0xFFFF0000) == 0) + halmac_offset |= WLAN_IOREG_OFFSET; + + status = halmac_convert_to_sdio_bus_offset(&halmac_offset); + + if (status != HALMAC_RET_SUCCESS) { + pr_err("halmac_reg_write_8_sdio_88xx error = %x\n", status); + return status; + } + halmac_platform_api->SDIO_CMD52_WRITE(driver_adapter, halmac_offset, + data); + + return HALMAC_RET_SUCCESS; +} + +static enum halmac_ret_status +halmac_get_chip_info(void *driver_adapter, + struct halmac_platform_api *halmac_platform_api, + enum halmac_interface halmac_interface, + struct halmac_adapter *halmac_adapter) +{ + struct halmac_api *halmac_api = (struct halmac_api *)NULL; + u8 chip_id, chip_version; + u32 polling_count; + + halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + /* Get Chip_id and Chip_version */ + if (halmac_adapter->halmac_interface == HALMAC_INTERFACE_SDIO) { + platform_reg_write_8_sdio( + driver_adapter, halmac_platform_api, REG_SDIO_HSUS_CTRL, + platform_reg_read_8_sdio(driver_adapter, + halmac_platform_api, + REG_SDIO_HSUS_CTRL) & + ~(BIT(0))); + + polling_count = 10000; + while (!(platform_reg_read_8_sdio(driver_adapter, + halmac_platform_api, + REG_SDIO_HSUS_CTRL) & + 0x02)) { + polling_count--; + if (polling_count == 0) + return HALMAC_RET_SDIO_LEAVE_SUSPEND_FAIL; + } + + chip_id = platform_reg_read_8_sdio( + driver_adapter, halmac_platform_api, REG_SYS_CFG2); + chip_version = platform_reg_read_8_sdio(driver_adapter, + halmac_platform_api, + REG_SYS_CFG1 + 1) >> + 4; + } else { + chip_id = halmac_platform_api->REG_READ_8(driver_adapter, + REG_SYS_CFG2); + chip_version = halmac_platform_api->REG_READ_8( + driver_adapter, REG_SYS_CFG1 + 1) >> + 4; + } + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "[TRACE]Chip id : 0x%X\n", chip_id); + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "[TRACE]Chip version : 0x%X\n", chip_version); + + halmac_adapter->chip_version = (enum halmac_chip_ver)chip_version; + + if (chip_id == HALMAC_CHIP_ID_HW_DEF_8822B) + halmac_adapter->chip_id = HALMAC_CHIP_ID_8822B; + else if (chip_id == HALMAC_CHIP_ID_HW_DEF_8821C) + halmac_adapter->chip_id = HALMAC_CHIP_ID_8821C; + else if (chip_id == HALMAC_CHIP_ID_HW_DEF_8814B) + halmac_adapter->chip_id = HALMAC_CHIP_ID_8814B; + else if (chip_id == HALMAC_CHIP_ID_HW_DEF_8197F) + halmac_adapter->chip_id = HALMAC_CHIP_ID_8197F; + else + halmac_adapter->chip_id = HALMAC_CHIP_ID_UNDEFINE; + + if (halmac_adapter->chip_id == HALMAC_CHIP_ID_UNDEFINE) + return HALMAC_RET_CHIP_NOT_SUPPORT; + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_init_adapter() - init halmac_adapter + * @driver_adapter : the adapter of caller + * @halmac_platform_api : the platform APIs which is used in halmac APIs + * @halmac_interface : bus interface + * @pp_halmac_adapter : the adapter of halmac + * @pp_halmac_api : the function pointer of APIs, caller shall call APIs by + * function pointer + * Author : KaiYuan Chang / Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_init_adapter(void *driver_adapter, + struct halmac_platform_api *halmac_platform_api, + enum halmac_interface halmac_interface, + struct halmac_adapter **pp_halmac_adapter, + struct halmac_api **pp_halmac_api) +{ + struct halmac_adapter *halmac_adapter = (struct halmac_adapter *)NULL; + enum halmac_ret_status status = HALMAC_RET_SUCCESS; + + union { + u32 i; + u8 x[4]; + } ENDIAN_CHECK = {0x01000000}; + + status = halmac_check_platform_api(driver_adapter, halmac_interface, + halmac_platform_api); + if (status != HALMAC_RET_SUCCESS) + return status; + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + HALMAC_SVN_VER "\n"); + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "HALMAC_MAJOR_VER = %x\n", HALMAC_MAJOR_VER); + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "HALMAC_PROTOTYPE_VER = %x\n", HALMAC_PROTOTYPE_VER); + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "HALMAC_MINOR_VER = %x\n", HALMAC_MINOR_VER); + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "HALMAC_PATCH_VER = %x\n", HALMAC_PATCH_VER); + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "halmac_init_adapter_88xx ==========>\n"); + + /* Check endian setting - Little endian : 1, Big endian : 0*/ + if (ENDIAN_CHECK.x[0] == HALMAC_SYSTEM_ENDIAN) { + pr_err("Endian setting Err!!\n"); + return HALMAC_RET_ENDIAN_ERR; + } + + halmac_adapter = kzalloc(sizeof(*halmac_adapter), GFP_KERNEL); + if (!halmac_adapter) { + /* out of memory */ + return HALMAC_RET_MALLOC_FAIL; + } + + /* return halmac adapter address to caller */ + *pp_halmac_adapter = halmac_adapter; + + /* Record caller info */ + halmac_adapter->halmac_platform_api = halmac_platform_api; + halmac_adapter->driver_adapter = driver_adapter; + halmac_interface = halmac_interface == HALMAC_INTERFACE_AXI ? + HALMAC_INTERFACE_PCIE : + halmac_interface; + halmac_adapter->halmac_interface = halmac_interface; + + spin_lock_init(&halmac_adapter->efuse_lock); + spin_lock_init(&halmac_adapter->h2c_seq_lock); + + /*Get Chip*/ + if (halmac_get_chip_info(driver_adapter, halmac_platform_api, + halmac_interface, + halmac_adapter) != HALMAC_RET_SUCCESS) { + pr_err("HALMAC_RET_CHIP_NOT_SUPPORT\n"); + return HALMAC_RET_CHIP_NOT_SUPPORT; + } + + /* Assign function pointer to halmac API */ + halmac_init_adapter_para_88xx(halmac_adapter); + status = halmac_mount_api_88xx(halmac_adapter); + + /* Return halmac API function pointer */ + *pp_halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "halmac_init_adapter_88xx <==========\n"); + + return status; +} + +/** + * halmac_halt_api() - stop halmac_api action + * @halmac_adapter : the adapter of halmac + * Author : Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status halmac_halt_api(struct halmac_adapter *halmac_adapter) +{ + void *driver_adapter = NULL; + struct halmac_platform_api *halmac_platform_api = + (struct halmac_platform_api *)NULL; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + driver_adapter = halmac_adapter->driver_adapter; + halmac_platform_api = halmac_adapter->halmac_platform_api; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s ==========>\n", __func__); + halmac_adapter->halmac_state.api_state = HALMAC_API_STATE_HALT; + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "%s ==========>\n", __func__); + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_deinit_adapter() - deinit halmac adapter + * @halmac_adapter : the adapter of halmac + * Author : KaiYuan Chang / Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status +halmac_deinit_adapter(struct halmac_adapter *halmac_adapter) +{ + void *driver_adapter = NULL; + + if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) + return HALMAC_RET_ADAPTER_INVALID; + + driver_adapter = halmac_adapter->driver_adapter; + + HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, + "[TRACE]halmac_deinit_adapter_88xx ==========>\n"); + + kfree(halmac_adapter->hal_efuse_map); + halmac_adapter->hal_efuse_map = (u8 *)NULL; + + kfree(halmac_adapter->halmac_state.psd_set.data); + halmac_adapter->halmac_state.psd_set.data = (u8 *)NULL; + + kfree(halmac_adapter->halmac_api); + halmac_adapter->halmac_api = NULL; + + halmac_adapter->hal_adapter_backup = NULL; + kfree(halmac_adapter); + + return HALMAC_RET_SUCCESS; +} + +/** + * halmac_get_version() - get HALMAC version + * @version : return version of major, prototype and minor information + * Author : KaiYuan Chang / Ivan Lin + * Return : enum halmac_ret_status + * More details of status code can be found in prototype document + */ +enum halmac_ret_status halmac_get_version(struct halmac_ver *version) +{ + version->major_ver = (u8)HALMAC_MAJOR_VER; + version->prototype_ver = (u8)HALMAC_PROTOTYPE_VER; + version->minor_ver = (u8)HALMAC_MINOR_VER; + + return HALMAC_RET_SUCCESS; +} diff --git a/drivers/staging/rtlwifi/halmac/halmac_api.h b/drivers/staging/rtlwifi/halmac/halmac_api.h new file mode 100644 index 000000000000..917a64601053 --- /dev/null +++ b/drivers/staging/rtlwifi/halmac/halmac_api.h @@ -0,0 +1,82 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef _HALMAC_API_H_ +#define _HALMAC_API_H_ + +#define HALMAC_SVN_VER "13348M" + +#define HALMAC_MAJOR_VER 0x0001 /* major version, ver_1 for async_api */ +/* For halmac_api num change or prototype change, increment prototype version. + * Otherwise, increase minor version + */ +#define HALMAC_PROTOTYPE_VER 0x0003 /* prototype version */ +#define HALMAC_MINOR_VER 0x0005 /* minor version */ +#define HALMAC_PATCH_VER 0x0000 /* patch version */ + +#include "halmac_2_platform.h" +#include "halmac_type.h" + +#include "halmac_usb_reg.h" +#include "halmac_sdio_reg.h" +#include "halmac_pcie_reg.h" + +#include "halmac_bit2.h" +#include "halmac_reg2.h" + +#include "halmac_tx_desc_nic.h" +#include "halmac_rx_desc_nic.h" +#include "halmac_tx_bd_nic.h" +#include "halmac_rx_bd_nic.h" +#include "halmac_fw_offload_c2h_nic.h" +#include "halmac_fw_offload_h2c_nic.h" +#include "halmac_h2c_extra_info_nic.h" +#include "halmac_original_c2h_nic.h" +#include "halmac_original_h2c_nic.h" + +#include "halmac_tx_desc_chip.h" +#include "halmac_rx_desc_chip.h" +#include "halmac_tx_bd_chip.h" +#include "halmac_rx_bd_chip.h" +#include "halmac_88xx/halmac_88xx_cfg.h" + +#include "halmac_88xx/halmac_8822b/halmac_8822b_cfg.h" +#include "halmac_reg_8822b.h" +#include "halmac_bit_8822b.h" + +enum halmac_ret_status +halmac_init_adapter(void *driver_adapter, + struct halmac_platform_api *halmac_platform_api, + enum halmac_interface halmac_interface, + struct halmac_adapter **pp_halmac_adapter, + struct halmac_api **pp_halmac_api); + +enum halmac_ret_status +halmac_deinit_adapter(struct halmac_adapter *halmac_adapter); + +enum halmac_ret_status halmac_halt_api(struct halmac_adapter *halmac_adapter); + +enum halmac_ret_status halmac_get_version(struct halmac_ver *version); + +#endif diff --git a/drivers/staging/rtlwifi/halmac/halmac_bit2.h b/drivers/staging/rtlwifi/halmac/halmac_bit2.h new file mode 100644 index 000000000000..1c7fe5d7df64 --- /dev/null +++ b/drivers/staging/rtlwifi/halmac/halmac_bit2.h @@ -0,0 +1,13407 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef __RTL_WLAN_BITDEF_H__ +#define __RTL_WLAN_BITDEF_H__ + +/*-------------------------Modification Log----------------------------------- + * Base on MAC_Register.doc SVN391 + *-------------------------Modification Log----------------------------------- + */ + +/*--------------------------Include File--------------------------------------*/ +/*--------------------------Include File--------------------------------------*/ + +/* 3 ============Programming guide Start===================== */ +/* + * 1. For all bit define, it should be prefixed by "BIT_" + * 2. For all bit mask, it should be prefixed by "BIT_MASK_" + * 3. For all bit shift, it should be prefixed by "BIT_SHIFT_" + * 4. For other case, prefix is not needed + * + * Example: + * #define BIT_SHIFT_MAX_TXDMA 16 + * #define BIT_MASK_MAX_TXDMA 0x7 + * #define BIT_MAX_TXDMA(x) \ + * (((x) & BIT_MASK_MAX_TXDMA) << BIT_SHIFT_MAX_TXDMA) + * #define BIT_GET_MAX_TXDMA(x) \ + * (((x) >> BIT_SHIFT_MAX_TXDMA) & BIT_MASK_MAX_TXDMA) + * + */ +/* 3 ============Programming guide End===================== */ + +#define CPU_OPT_WIDTH 0x1F + +#define BIT_SHIFT_WATCH_DOG_RECORD_V1 10 +#define BIT_MASK_WATCH_DOG_RECORD_V1 0x3fff +#define BIT_WATCH_DOG_RECORD_V1(x) \ + (((x) & BIT_MASK_WATCH_DOG_RECORD_V1) << BIT_SHIFT_WATCH_DOG_RECORD_V1) +#define BIT_GET_WATCH_DOG_RECORD_V1(x) \ + (((x) >> BIT_SHIFT_WATCH_DOG_RECORD_V1) & BIT_MASK_WATCH_DOG_RECORD_V1) + +#define BIT_R_IO_TIMEOUT_FLAG_V1 BIT(9) + +#define BIT_ISO_MD2PP BIT(0) + +#define BIT_SHIFT_R_WMAC_IPV6_MYIPAD 0 +#define BIT_MASK_R_WMAC_IPV6_MYIPAD 0xffffffffffffffffffffffffffffffffL +#define BIT_R_WMAC_IPV6_MYIPAD(x) \ + (((x) & BIT_MASK_R_WMAC_IPV6_MYIPAD) << BIT_SHIFT_R_WMAC_IPV6_MYIPAD) +#define BIT_GET_R_WMAC_IPV6_MYIPAD(x) \ + (((x) >> BIT_SHIFT_R_WMAC_IPV6_MYIPAD) & BIT_MASK_R_WMAC_IPV6_MYIPAD) + +/* 2 REG_SDIO_TX_CTRL (Offset 0x10250000) */ + +#define BIT_SHIFT_SDIO_INT_TIMEOUT 16 +#define BIT_MASK_SDIO_INT_TIMEOUT 0xffff +#define BIT_SDIO_INT_TIMEOUT(x) \ + (((x) & BIT_MASK_SDIO_INT_TIMEOUT) << BIT_SHIFT_SDIO_INT_TIMEOUT) +#define BIT_GET_SDIO_INT_TIMEOUT(x) \ + (((x) >> BIT_SHIFT_SDIO_INT_TIMEOUT) & BIT_MASK_SDIO_INT_TIMEOUT) + +/* 2 REG_SYS_ISO_CTRL (Offset 0x0000) */ + +#define BIT_PWC_EV12V BIT(15) + +/* 2 REG_SDIO_TX_CTRL (Offset 0x10250000) */ + +#define BIT_IO_ERR_STATUS BIT(15) + +/* 2 REG_SYS_ISO_CTRL (Offset 0x0000) */ + +#define BIT_PWC_EV25V BIT(14) + +/* 2 REG_SYS_ISO_CTRL (Offset 0x0000) */ + +#define BIT_PA33V_EN BIT(13) +#define BIT_PA12V_EN BIT(12) + +/* 2 REG_SYS_ISO_CTRL (Offset 0x0000) */ + +#define BIT_UA33V_EN BIT(11) +#define BIT_UA12V_EN BIT(10) + +/* 2 REG_SYS_ISO_CTRL (Offset 0x0000) */ + +#define BIT_ISO_RFDIO BIT(9) + +/* 2 REG_SDIO_TX_CTRL (Offset 0x10250000) */ + +#define BIT_REPLY_ERRCRC_IN_DATA BIT(9) + +/* 2 REG_SYS_ISO_CTRL (Offset 0x0000) */ + +#define BIT_ISO_EB2CORE BIT(8) + +/* 2 REG_SDIO_TX_CTRL (Offset 0x10250000) */ + +#define BIT_EN_CMD53_OVERLAP BIT(8) + +/* 2 REG_SYS_ISO_CTRL (Offset 0x0000) */ + +#define BIT_ISO_DIOE BIT(7) + +/* 2 REG_SDIO_TX_CTRL (Offset 0x10250000) */ + +#define BIT_REPLY_ERR_IN_R5 BIT(7) + +/* 2 REG_SYS_ISO_CTRL (Offset 0x0000) */ + +#define BIT_ISO_WLPON2PP BIT(6) + +/* 2 REG_SDIO_TX_CTRL (Offset 0x10250000) */ + +#define BIT_R18A_EN BIT(6) + +/* 2 REG_SYS_ISO_CTRL (Offset 0x0000) */ + +#define BIT_ISO_IP2MAC_WA2PP BIT(5) + +/* 2 REG_SDIO_TX_CTRL (Offset 0x10250000) */ + +#define BIT_INIT_CMD_EN BIT(5) + +/* 2 REG_SYS_ISO_CTRL (Offset 0x0000) */ + +#define BIT_ISO_PD2CORE BIT(4) + +/* 2 REG_SYS_ISO_CTRL (Offset 0x0000) */ + +#define BIT_ISO_PA2PCIE BIT(3) + +/* 2 REG_SYS_ISO_CTRL (Offset 0x0000) */ + +#define BIT_ISO_UD2CORE BIT(2) + +/* 2 REG_SDIO_TX_CTRL (Offset 0x10250000) */ + +#define BIT_EN_RXDMA_MASK_INT BIT(2) + +/* 2 REG_SYS_ISO_CTRL (Offset 0x0000) */ + +#define BIT_ISO_UA2USB BIT(1) + +/* 2 REG_SDIO_TX_CTRL (Offset 0x10250000) */ + +#define BIT_EN_MASK_TIMER BIT(1) + +/* 2 REG_SYS_ISO_CTRL (Offset 0x0000) */ + +#define BIT_ISO_WD2PP BIT(0) + +/* 2 REG_SDIO_TX_CTRL (Offset 0x10250000) */ + +#define BIT_CMD_ERR_STOP_INT_EN BIT(0) + +/* 2 REG_SYS_FUNC_EN (Offset 0x0002) */ + +#define BIT_FEN_MREGEN BIT(15) +#define BIT_FEN_HWPDN BIT(14) + +/* 2 REG_SYS_FUNC_EN (Offset 0x0002) */ + +#define BIT_EN_25_1 BIT(13) + +/* 2 REG_SYS_FUNC_EN (Offset 0x0002) */ + +#define BIT_FEN_ELDR BIT(12) +#define BIT_FEN_DCORE BIT(11) +#define BIT_FEN_CPUEN BIT(10) +#define BIT_FEN_DIOE BIT(9) +#define BIT_FEN_PCIED BIT(8) +#define BIT_FEN_PPLL BIT(7) +#define BIT_FEN_PCIEA BIT(6) +#define BIT_FEN_DIO_PCIE BIT(5) +#define BIT_FEN_USBD BIT(4) +#define BIT_FEN_UPLL BIT(3) +#define BIT_FEN_USBA BIT(2) + +/* 2 REG_SYS_FUNC_EN (Offset 0x0002) */ + +#define BIT_FEN_BB_GLB_RSTN BIT(1) +#define BIT_FEN_BBRSTB BIT(0) + +/* 2 REG_SYS_PW_CTRL (Offset 0x0004) */ + +#define BIT_SOP_EABM BIT(31) + +/* 2 REG_SYS_PW_CTRL (Offset 0x0004) */ + +#define BIT_SOP_ACKF BIT(30) +#define BIT_SOP_ERCK BIT(29) + +/* 2 REG_SYS_PW_CTRL (Offset 0x0004) */ + +#define BIT_SOP_ESWR BIT(28) + +/* 2 REG_SYS_PW_CTRL (Offset 0x0004) */ + +#define BIT_SOP_PWMM BIT(27) + +/* 2 REG_SYS_PW_CTRL (Offset 0x0004) */ + +#define BIT_SOP_EECK BIT(26) + +/* 2 REG_SYS_PW_CTRL (Offset 0x0004) */ + +#define BIT_SOP_EXTL BIT(24) + +/* 2 REG_SYS_PW_CTRL (Offset 0x0004) */ + +#define BIT_SYM_OP_RING_12M BIT(22) + +/* 2 REG_SYS_PW_CTRL (Offset 0x0004) */ + +#define BIT_ROP_SWPR BIT(21) + +/* 2 REG_SYS_PW_CTRL (Offset 0x0004) */ + +#define BIT_DIS_HW_LPLDM BIT(20) + +/* 2 REG_SYS_PW_CTRL (Offset 0x0004) */ + +#define BIT_OPT_SWRST_WLMCU BIT(19) +#define BIT_RDY_SYSPWR BIT(17) + +/* 2 REG_SYS_PW_CTRL (Offset 0x0004) */ + +#define BIT_EN_WLON BIT(16) + +/* 2 REG_SYS_PW_CTRL (Offset 0x0004) */ + +#define BIT_APDM_HPDN BIT(15) + +/* 2 REG_SYS_PW_CTRL (Offset 0x0004) */ + +#define BIT_AFSM_PCIE_SUS_EN BIT(12) + +/* 2 REG_SYS_PW_CTRL (Offset 0x0004) */ + +#define BIT_AFSM_WLSUS_EN BIT(11) + +/* 2 REG_SYS_PW_CTRL (Offset 0x0004) */ + +#define BIT_APFM_SWLPS BIT(10) + +/* 2 REG_SYS_PW_CTRL (Offset 0x0004) */ + +#define BIT_APFM_OFFMAC BIT(9) +#define BIT_APFN_ONMAC BIT(8) + +/* 2 REG_SYS_PW_CTRL (Offset 0x0004) */ + +#define BIT_CHIP_PDN_EN BIT(7) + +/* 2 REG_SYS_PW_CTRL (Offset 0x0004) */ + +#define BIT_RDY_MACDIS BIT(6) + +/* 2 REG_SYS_PW_CTRL (Offset 0x0004) */ + +#define BIT_RING_CLK_12M_EN BIT(4) + +/* 2 REG_SYS_PW_CTRL (Offset 0x0004) */ + +#define BIT_PFM_WOWL BIT(3) + +/* 2 REG_SYS_PW_CTRL (Offset 0x0004) */ + +#define BIT_PFM_LDKP BIT(2) + +/* 2 REG_SYS_PW_CTRL (Offset 0x0004) */ + +#define BIT_WL_HCI_ALD BIT(1) + +/* 2 REG_SYS_PW_CTRL (Offset 0x0004) */ + +#define BIT_PFM_LDALL BIT(0) + +/* 2 REG_SYS_CLK_CTRL (Offset 0x0008) */ + +#define BIT_LDO_DUMMY BIT(15) + +/* 2 REG_SYS_CLK_CTRL (Offset 0x0008) */ + +#define BIT_CPU_CLK_EN BIT(14) + +/* 2 REG_SYS_CLK_CTRL (Offset 0x0008) */ + +#define BIT_SYMREG_CLK_EN BIT(13) + +/* 2 REG_SYS_CLK_CTRL (Offset 0x0008) */ + +#define BIT_HCI_CLK_EN BIT(12) + +/* 2 REG_SYS_CLK_CTRL (Offset 0x0008) */ + +#define BIT_MAC_CLK_EN BIT(11) +#define BIT_SEC_CLK_EN BIT(10) + +/* 2 REG_SYS_CLK_CTRL (Offset 0x0008) */ + +#define BIT_PHY_SSC_RSTB BIT(9) +#define BIT_EXT_32K_EN BIT(8) + +/* 2 REG_SYS_CLK_CTRL (Offset 0x0008) */ + +#define BIT_WL_CLK_TEST BIT(7) +#define BIT_OP_SPS_PWM_EN BIT(6) + +/* 2 REG_SYS_CLK_CTRL (Offset 0x0008) */ + +#define BIT_LOADER_CLK_EN BIT(5) +#define BIT_MACSLP BIT(4) +#define BIT_WAKEPAD_EN BIT(3) +#define BIT_ROMD16V_EN BIT(2) + +/* 2 REG_SYS_CLK_CTRL (Offset 0x0008) */ + +#define BIT_CKANA12M_EN BIT(1) + +/* 2 REG_SYS_CLK_CTRL (Offset 0x0008) */ + +#define BIT_CNTD16V_EN BIT(0) + +/* 2 REG_SYS_EEPROM_CTRL (Offset 0x000A) */ + +#define BIT_SHIFT_VPDIDX 8 +#define BIT_MASK_VPDIDX 0xff +#define BIT_VPDIDX(x) (((x) & BIT_MASK_VPDIDX) << BIT_SHIFT_VPDIDX) +#define BIT_GET_VPDIDX(x) (((x) >> BIT_SHIFT_VPDIDX) & BIT_MASK_VPDIDX) + +#define BIT_SHIFT_EEM1_0 6 +#define BIT_MASK_EEM1_0 0x3 +#define BIT_EEM1_0(x) (((x) & BIT_MASK_EEM1_0) << BIT_SHIFT_EEM1_0) +#define BIT_GET_EEM1_0(x) (((x) >> BIT_SHIFT_EEM1_0) & BIT_MASK_EEM1_0) + +#define BIT_AUTOLOAD_SUS BIT(5) + +/* 2 REG_SYS_EEPROM_CTRL (Offset 0x000A) */ + +#define BIT_EERPOMSEL BIT(4) + +/* 2 REG_SYS_EEPROM_CTRL (Offset 0x000A) */ + +#define BIT_EECS_V1 BIT(3) +#define BIT_EESK_V1 BIT(2) +#define BIT_EEDI_V1 BIT(1) +#define BIT_EEDO_V1 BIT(0) + +/* 2 REG_EE_VPD (Offset 0x000C) */ + +#define BIT_SHIFT_VPD_DATA 0 +#define BIT_MASK_VPD_DATA 0xffffffffL +#define BIT_VPD_DATA(x) (((x) & BIT_MASK_VPD_DATA) << BIT_SHIFT_VPD_DATA) +#define BIT_GET_VPD_DATA(x) (((x) >> BIT_SHIFT_VPD_DATA) & BIT_MASK_VPD_DATA) + +/* 2 REG_SYS_SWR_CTRL1 (Offset 0x0010) */ + +#define BIT_C2_L_BIT0 BIT(31) + +/* 2 REG_SYS_SWR_CTRL1 (Offset 0x0010) */ + +#define BIT_SHIFT_C1_L 29 +#define BIT_MASK_C1_L 0x3 +#define BIT_C1_L(x) (((x) & BIT_MASK_C1_L) << BIT_SHIFT_C1_L) +#define BIT_GET_C1_L(x) (((x) >> BIT_SHIFT_C1_L) & BIT_MASK_C1_L) + +/* 2 REG_SYS_SWR_CTRL1 (Offset 0x0010) */ + +#define BIT_SHIFT_REG_FREQ_L 25 +#define BIT_MASK_REG_FREQ_L 0x7 +#define BIT_REG_FREQ_L(x) (((x) & BIT_MASK_REG_FREQ_L) << BIT_SHIFT_REG_FREQ_L) +#define BIT_GET_REG_FREQ_L(x) \ + (((x) >> BIT_SHIFT_REG_FREQ_L) & BIT_MASK_REG_FREQ_L) + +#define BIT_REG_EN_DUTY BIT(24) + +/* 2 REG_SYS_SWR_CTRL1 (Offset 0x0010) */ + +#define BIT_SHIFT_REG_MODE 22 +#define BIT_MASK_REG_MODE 0x3 +#define BIT_REG_MODE(x) (((x) & BIT_MASK_REG_MODE) << BIT_SHIFT_REG_MODE) +#define BIT_GET_REG_MODE(x) (((x) >> BIT_SHIFT_REG_MODE) & BIT_MASK_REG_MODE) + +/* 2 REG_SYS_SWR_CTRL1 (Offset 0x0010) */ + +#define BIT_REG_EN_SP BIT(21) +#define BIT_REG_AUTO_L BIT(20) + +/* 2 REG_SYS_SWR_CTRL1 (Offset 0x0010) */ + +#define BIT_SW18_SELD_BIT0 BIT(19) + +/* 2 REG_SYS_SWR_CTRL1 (Offset 0x0010) */ + +#define BIT_SW18_POWOCP BIT(18) + +/* 2 REG_SYS_SWR_CTRL1 (Offset 0x0010) */ + +#define BIT_SHIFT_OCP_L1 15 +#define BIT_MASK_OCP_L1 0x7 +#define BIT_OCP_L1(x) (((x) & BIT_MASK_OCP_L1) << BIT_SHIFT_OCP_L1) +#define BIT_GET_OCP_L1(x) (((x) >> BIT_SHIFT_OCP_L1) & BIT_MASK_OCP_L1) + +/* 2 REG_SYS_SWR_CTRL1 (Offset 0x0010) */ + +#define BIT_SHIFT_CF_L 13 +#define BIT_MASK_CF_L 0x3 +#define BIT_CF_L(x) (((x) & BIT_MASK_CF_L) << BIT_SHIFT_CF_L) +#define BIT_GET_CF_L(x) (((x) >> BIT_SHIFT_CF_L) & BIT_MASK_CF_L) + +/* 2 REG_SYS_SWR_CTRL1 (Offset 0x0010) */ + +#define BIT_SW18_FPWM BIT(11) + +/* 2 REG_SYS_SWR_CTRL1 (Offset 0x0010) */ + +#define BIT_SW18_SWEN BIT(9) +#define BIT_SW18_LDEN BIT(8) +#define BIT_MAC_ID_EN BIT(7) + +/* 2 REG_SYS_SWR_CTRL1 (Offset 0x0010) */ + +#define BIT_AFE_BGEN BIT(0) + +/* 2 REG_SYS_SWR_CTRL2 (Offset 0x0014) */ + +#define BIT_POW_ZCD_L BIT(31) + +/* 2 REG_SDIO_HIMR (Offset 0x10250014) */ + +#define BIT_SDIO_CRCERR_MSK BIT(31) + +/* 2 REG_SYS_SWR_CTRL2 (Offset 0x0014) */ + +#define BIT_AUTOZCD_L BIT(30) +#define BIT_SDIO_HSISR3_IND_MSK BIT(30) +#define BIT_SDIO_HSISR2_IND_MSK BIT(29) + +/* 2 REG_SYS_SWR_CTRL2 (Offset 0x0014) */ + +#define BIT_SHIFT_REG_DELAY 28 +#define BIT_MASK_REG_DELAY 0x3 +#define BIT_REG_DELAY(x) (((x) & BIT_MASK_REG_DELAY) << BIT_SHIFT_REG_DELAY) +#define BIT_GET_REG_DELAY(x) (((x) >> BIT_SHIFT_REG_DELAY) & BIT_MASK_REG_DELAY) + +/* 2 REG_SDIO_HIMR (Offset 0x10250014) */ + +#define BIT_SDIO_HEISR_IND_MSK BIT(28) + +/* 2 REG_SDIO_HIMR (Offset 0x10250014) */ + +#define BIT_SDIO_CTWEND_MSK BIT(27) +#define BIT_SDIO_ATIMEND_E_MSK BIT(26) + +/* 2 REG_SDIO_HIMR (Offset 0x10250014) */ + +#define BIT_SDIIO_ATIMEND_MSK BIT(25) + +/* 2 REG_SDIO_HIMR (Offset 0x10250014) */ + +#define BIT_SDIO_OCPINT_MSK BIT(24) + +/* 2 REG_SYS_SWR_CTRL2 (Offset 0x0014) */ + +#define BIT_SHIFT_V15ADJ_L1_V1 24 +#define BIT_MASK_V15ADJ_L1_V1 0x7 +#define BIT_V15ADJ_L1_V1(x) \ + (((x) & BIT_MASK_V15ADJ_L1_V1) << BIT_SHIFT_V15ADJ_L1_V1) +#define BIT_GET_V15ADJ_L1_V1(x) \ + (((x) >> BIT_SHIFT_V15ADJ_L1_V1) & BIT_MASK_V15ADJ_L1_V1) + +/* 2 REG_SDIO_HIMR (Offset 0x10250014) */ + +#define BIT_SDIO_PSTIMEOUT_MSK BIT(23) + +/* 2 REG_SDIO_HIMR (Offset 0x10250014) */ + +#define BIT_SDIO_GTINT4_MSK BIT(22) + +/* 2 REG_SDIO_HIMR (Offset 0x10250014) */ + +#define BIT_SDIO_GTINT3_MSK BIT(21) + +/* 2 REG_SDIO_HIMR (Offset 0x10250014) */ + +#define BIT_SDIO_HSISR_IND_MSK BIT(20) + +/* 2 REG_SYS_SWR_CTRL2 (Offset 0x0014) */ + +#define BIT_SHIFT_VOL_L1_V1 20 +#define BIT_MASK_VOL_L1_V1 0xf +#define BIT_VOL_L1_V1(x) (((x) & BIT_MASK_VOL_L1_V1) << BIT_SHIFT_VOL_L1_V1) +#define BIT_GET_VOL_L1_V1(x) (((x) >> BIT_SHIFT_VOL_L1_V1) & BIT_MASK_VOL_L1_V1) + +/* 2 REG_SDIO_HIMR (Offset 0x10250014) */ + +#define BIT_SDIO_CPWM2_MSK BIT(19) + +/* 2 REG_SDIO_HIMR (Offset 0x10250014) */ + +#define BIT_SDIO_CPWM1_MSK BIT(18) + +/* 2 REG_SDIO_HIMR (Offset 0x10250014) */ + +#define BIT_SDIO_C2HCMD_INT_MSK BIT(17) + +/* 2 REG_SYS_SWR_CTRL2 (Offset 0x0014) */ + +#define BIT_SHIFT_IN_L1_V1 17 +#define BIT_MASK_IN_L1_V1 0x7 +#define BIT_IN_L1_V1(x) (((x) & BIT_MASK_IN_L1_V1) << BIT_SHIFT_IN_L1_V1) +#define BIT_GET_IN_L1_V1(x) (((x) >> BIT_SHIFT_IN_L1_V1) & BIT_MASK_IN_L1_V1) + +/* 2 REG_SDIO_HIMR (Offset 0x10250014) */ + +#define BIT_SDIO_BCNERLY_INT_MSK BIT(16) + +/* 2 REG_SYS_SWR_CTRL2 (Offset 0x0014) */ + +#define BIT_SHIFT_TBOX_L1 15 +#define BIT_MASK_TBOX_L1 0x3 +#define BIT_TBOX_L1(x) (((x) & BIT_MASK_TBOX_L1) << BIT_SHIFT_TBOX_L1) +#define BIT_GET_TBOX_L1(x) (((x) >> BIT_SHIFT_TBOX_L1) & BIT_MASK_TBOX_L1) + +/* 2 REG_SYS_SWR_CTRL2 (Offset 0x0014) */ + +#define BIT_SW18_SEL BIT(13) + +/* 2 REG_SYS_SWR_CTRL2 (Offset 0x0014) */ + +#define BIT_SW18_SD BIT(10) + +/* 2 REG_SDIO_HIMR (Offset 0x10250014) */ + +#define BIT_SDIO_TXBCNERR_MSK BIT(7) + +/* 2 REG_SYS_SWR_CTRL2 (Offset 0x0014) */ + +#define BIT_SHIFT_R3_L 7 +#define BIT_MASK_R3_L 0x3 +#define BIT_R3_L(x) (((x) & BIT_MASK_R3_L) << BIT_SHIFT_R3_L) +#define BIT_GET_R3_L(x) (((x) >> BIT_SHIFT_R3_L) & BIT_MASK_R3_L) + +/* 2 REG_SDIO_HIMR (Offset 0x10250014) */ + +#define BIT_SDIO_TXBCNOK_MSK BIT(6) + +/* 2 REG_SYS_SWR_CTRL2 (Offset 0x0014) */ + +#define BIT_SHIFT_SW18_R2 5 +#define BIT_MASK_SW18_R2 0x3 +#define BIT_SW18_R2(x) (((x) & BIT_MASK_SW18_R2) << BIT_SHIFT_SW18_R2) +#define BIT_GET_SW18_R2(x) (((x) >> BIT_SHIFT_SW18_R2) & BIT_MASK_SW18_R2) + +/* 2 REG_SDIO_HIMR (Offset 0x10250014) */ + +#define BIT_SDIO_RXFOVW_MSK BIT(5) +#define BIT_SDIO_TXFOVW_MSK BIT(4) + +/* 2 REG_SYS_SWR_CTRL2 (Offset 0x0014) */ + +#define BIT_SHIFT_SW18_R1 3 +#define BIT_MASK_SW18_R1 0x3 +#define BIT_SW18_R1(x) (((x) & BIT_MASK_SW18_R1) << BIT_SHIFT_SW18_R1) +#define BIT_GET_SW18_R1(x) (((x) >> BIT_SHIFT_SW18_R1) & BIT_MASK_SW18_R1) + +/* 2 REG_SDIO_HIMR (Offset 0x10250014) */ + +#define BIT_SDIO_RXERR_MSK BIT(3) +#define BIT_SDIO_TXERR_MSK BIT(2) + +/* 2 REG_SDIO_HIMR (Offset 0x10250014) */ + +#define BIT_SDIO_AVAL_MSK BIT(1) + +/* 2 REG_SYS_SWR_CTRL2 (Offset 0x0014) */ + +#define BIT_SHIFT_C3_L_C3 1 +#define BIT_MASK_C3_L_C3 0x3 +#define BIT_C3_L_C3(x) (((x) & BIT_MASK_C3_L_C3) << BIT_SHIFT_C3_L_C3) +#define BIT_GET_C3_L_C3(x) (((x) >> BIT_SHIFT_C3_L_C3) & BIT_MASK_C3_L_C3) + +/* 2 REG_SDIO_HIMR (Offset 0x10250014) */ + +#define BIT_RX_REQUEST_MSK BIT(0) + +/* 2 REG_SYS_SWR_CTRL2 (Offset 0x0014) */ + +#define BIT_C2_L_BIT1 BIT(0) + +/* 2 REG_SYS_SWR_CTRL3 (Offset 0x0018) */ + +#define BIT_SPS18_OCP_DIS BIT(31) + +/* 2 REG_SDIO_HISR (Offset 0x10250018) */ + +#define BIT_SDIO_CRCERR BIT(31) + +/* 2 REG_SDIO_HISR (Offset 0x10250018) */ + +#define BIT_SDIO_HSISR3_IND BIT(30) +#define BIT_SDIO_HSISR2_IND BIT(29) +#define BIT_SDIO_HEISR_IND BIT(28) + +/* 2 REG_SDIO_HISR (Offset 0x10250018) */ + +#define BIT_SDIO_CTWEND BIT(27) +#define BIT_SDIO_ATIMEND_E BIT(26) +#define BIT_SDIO_ATIMEND BIT(25) +#define BIT_SDIO_OCPINT BIT(24) +#define BIT_SDIO_PSTIMEOUT BIT(23) +#define BIT_SDIO_GTINT4 BIT(22) +#define BIT_SDIO_GTINT3 BIT(21) +#define BIT_SDIO_HSISR_IND BIT(20) +#define BIT_SDIO_CPWM2 BIT(19) +#define BIT_SDIO_CPWM1 BIT(18) +#define BIT_SDIO_C2HCMD_INT BIT(17) + +/* 2 REG_SYS_SWR_CTRL3 (Offset 0x0018) */ + +#define BIT_SHIFT_SPS18_OCP_TH 16 +#define BIT_MASK_SPS18_OCP_TH 0x7fff +#define BIT_SPS18_OCP_TH(x) \ + (((x) & BIT_MASK_SPS18_OCP_TH) << BIT_SHIFT_SPS18_OCP_TH) +#define BIT_GET_SPS18_OCP_TH(x) \ + (((x) >> BIT_SHIFT_SPS18_OCP_TH) & BIT_MASK_SPS18_OCP_TH) + +/* 2 REG_SDIO_HISR (Offset 0x10250018) */ + +#define BIT_SDIO_BCNERLY_INT BIT(16) +#define BIT_SDIO_TXBCNERR BIT(7) +#define BIT_SDIO_TXBCNOK BIT(6) +#define BIT_SDIO_RXFOVW BIT(5) +#define BIT_SDIO_TXFOVW BIT(4) +#define BIT_SDIO_RXERR BIT(3) +#define BIT_SDIO_TXERR BIT(2) +#define BIT_SDIO_AVAL BIT(1) + +/* 2 REG_SYS_SWR_CTRL3 (Offset 0x0018) */ + +#define BIT_SHIFT_OCP_WINDOW 0 +#define BIT_MASK_OCP_WINDOW 0xffff +#define BIT_OCP_WINDOW(x) (((x) & BIT_MASK_OCP_WINDOW) << BIT_SHIFT_OCP_WINDOW) +#define BIT_GET_OCP_WINDOW(x) \ + (((x) >> BIT_SHIFT_OCP_WINDOW) & BIT_MASK_OCP_WINDOW) + +/* 2 REG_SDIO_HISR (Offset 0x10250018) */ + +#define BIT_RX_REQUEST BIT(0) + +/* 2 REG_RSV_CTRL (Offset 0x001C) */ + +#define BIT_HREG_DBG BIT(23) + +/* 2 REG_RSV_CTRL (Offset 0x001C) */ + +#define BIT_WLMCUIOIF BIT(8) + +/* 2 REG_RSV_CTRL (Offset 0x001C) */ + +#define BIT_LOCK_ALL_EN BIT(7) + +/* 2 REG_RSV_CTRL (Offset 0x001C) */ + +#define BIT_R_DIS_PRST BIT(6) + +/* 2 REG_RSV_CTRL (Offset 0x001C) */ + +#define BIT_WLOCK_1C_B6 BIT(5) + +/* 2 REG_RSV_CTRL (Offset 0x001C) */ + +#define BIT_WLOCK_40 BIT(4) +#define BIT_WLOCK_08 BIT(3) +#define BIT_WLOCK_04 BIT(2) +#define BIT_WLOCK_00 BIT(1) +#define BIT_WLOCK_ALL BIT(0) + +/* 2 REG_SDIO_RX_REQ_LEN (Offset 0x1025001C) */ + +#define BIT_SHIFT_RX_REQ_LEN_V1 0 +#define BIT_MASK_RX_REQ_LEN_V1 0x3ffff +#define BIT_RX_REQ_LEN_V1(x) \ + (((x) & BIT_MASK_RX_REQ_LEN_V1) << BIT_SHIFT_RX_REQ_LEN_V1) +#define BIT_GET_RX_REQ_LEN_V1(x) \ + (((x) >> BIT_SHIFT_RX_REQ_LEN_V1) & BIT_MASK_RX_REQ_LEN_V1) + +/* 2 REG_RF_CTRL (Offset 0x001F) */ + +#define BIT_RF_SDMRSTB BIT(2) + +/* 2 REG_RF_CTRL (Offset 0x001F) */ + +#define BIT_RF_RSTB BIT(1) + +/* 2 REG_RF_CTRL (Offset 0x001F) */ + +#define BIT_RF_EN BIT(0) + +/* 2 REG_SDIO_FREE_TXPG_SEQ_V1 (Offset 0x1025001F) */ + +#define BIT_SHIFT_FREE_TXPG_SEQ 0 +#define BIT_MASK_FREE_TXPG_SEQ 0xff +#define BIT_FREE_TXPG_SEQ(x) \ + (((x) & BIT_MASK_FREE_TXPG_SEQ) << BIT_SHIFT_FREE_TXPG_SEQ) +#define BIT_GET_FREE_TXPG_SEQ(x) \ + (((x) >> BIT_SHIFT_FREE_TXPG_SEQ) & BIT_MASK_FREE_TXPG_SEQ) + +/* 2 REG_AFE_LDO_CTRL (Offset 0x0020) */ + +#define BIT_SHIFT_LPLDH12_RSV 29 +#define BIT_MASK_LPLDH12_RSV 0x7 +#define BIT_LPLDH12_RSV(x) \ + (((x) & BIT_MASK_LPLDH12_RSV) << BIT_SHIFT_LPLDH12_RSV) +#define BIT_GET_LPLDH12_RSV(x) \ + (((x) >> BIT_SHIFT_LPLDH12_RSV) & BIT_MASK_LPLDH12_RSV) + +/* 2 REG_AFE_LDO_CTRL (Offset 0x0020) */ + +#define BIT_LPLDH12_SLP BIT(28) + +#define BIT_SHIFT_LPLDH12_VADJ 24 +#define BIT_MASK_LPLDH12_VADJ 0xf +#define BIT_LPLDH12_VADJ(x) \ + (((x) & BIT_MASK_LPLDH12_VADJ) << BIT_SHIFT_LPLDH12_VADJ) +#define BIT_GET_LPLDH12_VADJ(x) \ + (((x) >> BIT_SHIFT_LPLDH12_VADJ) & BIT_MASK_LPLDH12_VADJ) + +/* 2 REG_AFE_LDO_CTRL (Offset 0x0020) */ + +#define BIT_LDH12_EN BIT(16) + +/* 2 REG_SDIO_FREE_TXPG (Offset 0x10250020) */ + +#define BIT_SHIFT_MID_FREEPG_V1 16 +#define BIT_MASK_MID_FREEPG_V1 0xfff +#define BIT_MID_FREEPG_V1(x) \ + (((x) & BIT_MASK_MID_FREEPG_V1) << BIT_SHIFT_MID_FREEPG_V1) +#define BIT_GET_MID_FREEPG_V1(x) \ + (((x) >> BIT_SHIFT_MID_FREEPG_V1) & BIT_MASK_MID_FREEPG_V1) + +/* 2 REG_AFE_LDO_CTRL (Offset 0x0020) */ + +#define BIT_WLBBOFF_BIG_PWC_EN BIT(14) +#define BIT_WLBBOFF_SMALL_PWC_EN BIT(13) +#define BIT_WLMACOFF_BIG_PWC_EN BIT(12) +#define BIT_WLPON_PWC_EN BIT(11) + +/* 2 REG_AFE_LDO_CTRL (Offset 0x0020) */ + +#define BIT_POW_REGU_P1 BIT(10) + +/* 2 REG_AFE_LDO_CTRL (Offset 0x0020) */ + +#define BIT_LDOV12W_EN BIT(8) + +/* 2 REG_AFE_LDO_CTRL (Offset 0x0020) */ + +#define BIT_EX_XTAL_DRV_DIGI BIT(7) +#define BIT_EX_XTAL_DRV_USB BIT(6) +#define BIT_EX_XTAL_DRV_AFE BIT(5) + +/* 2 REG_AFE_LDO_CTRL (Offset 0x0020) */ + +#define BIT_EX_XTAL_DRV_RF2 BIT(4) + +/* 2 REG_AFE_LDO_CTRL (Offset 0x0020) */ + +#define BIT_EX_XTAL_DRV_RF1 BIT(3) +#define BIT_POW_REGU_P0 BIT(2) + +/* 2 REG_AFE_LDO_CTRL (Offset 0x0020) */ + +#define BIT_POW_PLL_LDO BIT(0) + +/* 2 REG_SDIO_FREE_TXPG (Offset 0x10250020) */ + +#define BIT_SHIFT_HIQ_FREEPG_V1 0 +#define BIT_MASK_HIQ_FREEPG_V1 0xfff +#define BIT_HIQ_FREEPG_V1(x) \ + (((x) & BIT_MASK_HIQ_FREEPG_V1) << BIT_SHIFT_HIQ_FREEPG_V1) +#define BIT_GET_HIQ_FREEPG_V1(x) \ + (((x) >> BIT_SHIFT_HIQ_FREEPG_V1) & BIT_MASK_HIQ_FREEPG_V1) + +/* 2 REG_AFE_CTRL1 (Offset 0x0024) */ + +#define BIT_AGPIO_GPE BIT(31) + +/* 2 REG_AFE_CTRL1 (Offset 0x0024) */ + +#define BIT_SHIFT_XTAL_CAP_XI 25 +#define BIT_MASK_XTAL_CAP_XI 0x3f +#define BIT_XTAL_CAP_XI(x) \ + (((x) & BIT_MASK_XTAL_CAP_XI) << BIT_SHIFT_XTAL_CAP_XI) +#define BIT_GET_XTAL_CAP_XI(x) \ + (((x) >> BIT_SHIFT_XTAL_CAP_XI) & BIT_MASK_XTAL_CAP_XI) + +/* 2 REG_AFE_CTRL1 (Offset 0x0024) */ + +#define BIT_SHIFT_XTAL_DRV_DIGI 23 +#define BIT_MASK_XTAL_DRV_DIGI 0x3 +#define BIT_XTAL_DRV_DIGI(x) \ + (((x) & BIT_MASK_XTAL_DRV_DIGI) << BIT_SHIFT_XTAL_DRV_DIGI) +#define BIT_GET_XTAL_DRV_DIGI(x) \ + (((x) >> BIT_SHIFT_XTAL_DRV_DIGI) & BIT_MASK_XTAL_DRV_DIGI) + +#define BIT_XTAL_DRV_USB_BIT1 BIT(22) + +/* 2 REG_AFE_CTRL1 (Offset 0x0024) */ + +#define BIT_SHIFT_MAC_CLK_SEL 20 +#define BIT_MASK_MAC_CLK_SEL 0x3 +#define BIT_MAC_CLK_SEL(x) \ + (((x) & BIT_MASK_MAC_CLK_SEL) << BIT_SHIFT_MAC_CLK_SEL) +#define BIT_GET_MAC_CLK_SEL(x) \ + (((x) >> BIT_SHIFT_MAC_CLK_SEL) & BIT_MASK_MAC_CLK_SEL) + +/* 2 REG_AFE_CTRL1 (Offset 0x0024) */ + +#define BIT_XTAL_DRV_USB_BIT0 BIT(19) + +/* 2 REG_AFE_CTRL1 (Offset 0x0024) */ + +#define BIT_SHIFT_XTAL_DRV_AFE 17 +#define BIT_MASK_XTAL_DRV_AFE 0x3 +#define BIT_XTAL_DRV_AFE(x) \ + (((x) & BIT_MASK_XTAL_DRV_AFE) << BIT_SHIFT_XTAL_DRV_AFE) +#define BIT_GET_XTAL_DRV_AFE(x) \ + (((x) >> BIT_SHIFT_XTAL_DRV_AFE) & BIT_MASK_XTAL_DRV_AFE) + +/* 2 REG_SDIO_FREE_TXPG2 (Offset 0x10250024) */ + +#define BIT_SHIFT_PUB_FREEPG_V1 16 +#define BIT_MASK_PUB_FREEPG_V1 0xfff +#define BIT_PUB_FREEPG_V1(x) \ + (((x) & BIT_MASK_PUB_FREEPG_V1) << BIT_SHIFT_PUB_FREEPG_V1) +#define BIT_GET_PUB_FREEPG_V1(x) \ + (((x) >> BIT_SHIFT_PUB_FREEPG_V1) & BIT_MASK_PUB_FREEPG_V1) + +/* 2 REG_AFE_CTRL1 (Offset 0x0024) */ + +#define BIT_SHIFT_XTAL_DRV_RF2 15 +#define BIT_MASK_XTAL_DRV_RF2 0x3 +#define BIT_XTAL_DRV_RF2(x) \ + (((x) & BIT_MASK_XTAL_DRV_RF2) << BIT_SHIFT_XTAL_DRV_RF2) +#define BIT_GET_XTAL_DRV_RF2(x) \ + (((x) >> BIT_SHIFT_XTAL_DRV_RF2) & BIT_MASK_XTAL_DRV_RF2) + +/* 2 REG_AFE_CTRL1 (Offset 0x0024) */ + +#define BIT_SHIFT_XTAL_DRV_RF1 13 +#define BIT_MASK_XTAL_DRV_RF1 0x3 +#define BIT_XTAL_DRV_RF1(x) \ + (((x) & BIT_MASK_XTAL_DRV_RF1) << BIT_SHIFT_XTAL_DRV_RF1) +#define BIT_GET_XTAL_DRV_RF1(x) \ + (((x) >> BIT_SHIFT_XTAL_DRV_RF1) & BIT_MASK_XTAL_DRV_RF1) + +/* 2 REG_AFE_CTRL1 (Offset 0x0024) */ + +#define BIT_XTAL_DELAY_DIGI BIT(12) + +/* 2 REG_AFE_CTRL1 (Offset 0x0024) */ + +#define BIT_XTAL_DELAY_USB BIT(11) +#define BIT_XTAL_DELAY_AFE BIT(10) + +/* 2 REG_AFE_CTRL1 (Offset 0x0024) */ + +#define BIT_SHIFT_XTAL_LDO_VREF 7 +#define BIT_MASK_XTAL_LDO_VREF 0x7 +#define BIT_XTAL_LDO_VREF(x) \ + (((x) & BIT_MASK_XTAL_LDO_VREF) << BIT_SHIFT_XTAL_LDO_VREF) +#define BIT_GET_XTAL_LDO_VREF(x) \ + (((x) >> BIT_SHIFT_XTAL_LDO_VREF) & BIT_MASK_XTAL_LDO_VREF) + +/* 2 REG_AFE_CTRL1 (Offset 0x0024) */ + +#define BIT_XTAL_XQSEL_RF BIT(6) +#define BIT_XTAL_XQSEL BIT(5) + +/* 2 REG_AFE_CTRL1 (Offset 0x0024) */ + +#define BIT_SHIFT_XTAL_GMN_V2 3 +#define BIT_MASK_XTAL_GMN_V2 0x3 +#define BIT_XTAL_GMN_V2(x) \ + (((x) & BIT_MASK_XTAL_GMN_V2) << BIT_SHIFT_XTAL_GMN_V2) +#define BIT_GET_XTAL_GMN_V2(x) \ + (((x) >> BIT_SHIFT_XTAL_GMN_V2) & BIT_MASK_XTAL_GMN_V2) + +/* 2 REG_AFE_CTRL1 (Offset 0x0024) */ + +#define BIT_SHIFT_XTAL_GMP_V2 1 +#define BIT_MASK_XTAL_GMP_V2 0x3 +#define BIT_XTAL_GMP_V2(x) \ + (((x) & BIT_MASK_XTAL_GMP_V2) << BIT_SHIFT_XTAL_GMP_V2) +#define BIT_GET_XTAL_GMP_V2(x) \ + (((x) >> BIT_SHIFT_XTAL_GMP_V2) & BIT_MASK_XTAL_GMP_V2) + +/* 2 REG_AFE_CTRL1 (Offset 0x0024) */ + +#define BIT_XTAL_EN BIT(0) + +/* 2 REG_SDIO_FREE_TXPG2 (Offset 0x10250024) */ + +#define BIT_SHIFT_LOW_FREEPG_V1 0 +#define BIT_MASK_LOW_FREEPG_V1 0xfff +#define BIT_LOW_FREEPG_V1(x) \ + (((x) & BIT_MASK_LOW_FREEPG_V1) << BIT_SHIFT_LOW_FREEPG_V1) +#define BIT_GET_LOW_FREEPG_V1(x) \ + (((x) >> BIT_SHIFT_LOW_FREEPG_V1) & BIT_MASK_LOW_FREEPG_V1) + +/* 2 REG_AFE_CTRL2 (Offset 0x0028) */ + +#define BIT_SHIFT_REG_C3_V4 30 +#define BIT_MASK_REG_C3_V4 0x3 +#define BIT_REG_C3_V4(x) (((x) & BIT_MASK_REG_C3_V4) << BIT_SHIFT_REG_C3_V4) +#define BIT_GET_REG_C3_V4(x) (((x) >> BIT_SHIFT_REG_C3_V4) & BIT_MASK_REG_C3_V4) + +#define BIT_REG_CP_BIT1 BIT(29) + +/* 2 REG_AFE_CTRL2 (Offset 0x0028) */ + +#define BIT_SHIFT_REG_RS_V4 26 +#define BIT_MASK_REG_RS_V4 0x7 +#define BIT_REG_RS_V4(x) (((x) & BIT_MASK_REG_RS_V4) << BIT_SHIFT_REG_RS_V4) +#define BIT_GET_REG_RS_V4(x) (((x) >> BIT_SHIFT_REG_RS_V4) & BIT_MASK_REG_RS_V4) + +/* 2 REG_SDIO_OQT_FREE_TXPG_V1 (Offset 0x10250028) */ + +#define BIT_SHIFT_NOAC_OQT_FREEPG_V1 24 +#define BIT_MASK_NOAC_OQT_FREEPG_V1 0xff +#define BIT_NOAC_OQT_FREEPG_V1(x) \ + (((x) & BIT_MASK_NOAC_OQT_FREEPG_V1) << BIT_SHIFT_NOAC_OQT_FREEPG_V1) +#define BIT_GET_NOAC_OQT_FREEPG_V1(x) \ + (((x) >> BIT_SHIFT_NOAC_OQT_FREEPG_V1) & BIT_MASK_NOAC_OQT_FREEPG_V1) + +/* 2 REG_AFE_CTRL2 (Offset 0x0028) */ + +#define BIT_SHIFT_REG__CS 24 +#define BIT_MASK_REG__CS 0x3 +#define BIT_REG__CS(x) (((x) & BIT_MASK_REG__CS) << BIT_SHIFT_REG__CS) +#define BIT_GET_REG__CS(x) (((x) >> BIT_SHIFT_REG__CS) & BIT_MASK_REG__CS) + +/* 2 REG_AFE_CTRL2 (Offset 0x0028) */ + +#define BIT_SHIFT_REG_CP_OFFSET 21 +#define BIT_MASK_REG_CP_OFFSET 0x7 +#define BIT_REG_CP_OFFSET(x) \ + (((x) & BIT_MASK_REG_CP_OFFSET) << BIT_SHIFT_REG_CP_OFFSET) +#define BIT_GET_REG_CP_OFFSET(x) \ + (((x) >> BIT_SHIFT_REG_CP_OFFSET) & BIT_MASK_REG_CP_OFFSET) + +/* 2 REG_AFE_CTRL2 (Offset 0x0028) */ + +#define BIT_SHIFT_CP_BIAS 18 +#define BIT_MASK_CP_BIAS 0x7 +#define BIT_CP_BIAS(x) (((x) & BIT_MASK_CP_BIAS) << BIT_SHIFT_CP_BIAS) +#define BIT_GET_CP_BIAS(x) (((x) >> BIT_SHIFT_CP_BIAS) & BIT_MASK_CP_BIAS) + +/* 2 REG_AFE_CTRL2 (Offset 0x0028) */ + +#define BIT_REG_IDOUBLE_V2 BIT(17) + +/* 2 REG_AFE_CTRL2 (Offset 0x0028) */ + +#define BIT_EN_SYN BIT(16) + +#define BIT_SHIFT_AC_OQT_FREEPG_V1 16 +#define BIT_MASK_AC_OQT_FREEPG_V1 0xff +#define BIT_AC_OQT_FREEPG_V1(x) \ + (((x) & BIT_MASK_AC_OQT_FREEPG_V1) << BIT_SHIFT_AC_OQT_FREEPG_V1) +#define BIT_GET_AC_OQT_FREEPG_V1(x) \ + (((x) >> BIT_SHIFT_AC_OQT_FREEPG_V1) & BIT_MASK_AC_OQT_FREEPG_V1) + +/* 2 REG_AFE_CTRL2 (Offset 0x0028) */ + +#define BIT_SHIFT_MCCO 14 +#define BIT_MASK_MCCO 0x3 +#define BIT_MCCO(x) (((x) & BIT_MASK_MCCO) << BIT_SHIFT_MCCO) +#define BIT_GET_MCCO(x) (((x) >> BIT_SHIFT_MCCO) & BIT_MASK_MCCO) + +/* 2 REG_AFE_CTRL2 (Offset 0x0028) */ + +#define BIT_SHIFT_REG_LDO_SEL 12 +#define BIT_MASK_REG_LDO_SEL 0x3 +#define BIT_REG_LDO_SEL(x) \ + (((x) & BIT_MASK_REG_LDO_SEL) << BIT_SHIFT_REG_LDO_SEL) +#define BIT_GET_REG_LDO_SEL(x) \ + (((x) >> BIT_SHIFT_REG_LDO_SEL) & BIT_MASK_REG_LDO_SEL) + +#define BIT_REG_KVCO_V2 BIT(10) + +/* 2 REG_AFE_CTRL2 (Offset 0x0028) */ + +#define BIT_AGPIO_GPO BIT(9) + +/* 2 REG_AFE_CTRL2 (Offset 0x0028) */ + +#define BIT_SHIFT_AGPIO_DRV 7 +#define BIT_MASK_AGPIO_DRV 0x3 +#define BIT_AGPIO_DRV(x) (((x) & BIT_MASK_AGPIO_DRV) << BIT_SHIFT_AGPIO_DRV) +#define BIT_GET_AGPIO_DRV(x) (((x) >> BIT_SHIFT_AGPIO_DRV) & BIT_MASK_AGPIO_DRV) + +/* 2 REG_AFE_CTRL2 (Offset 0x0028) */ + +#define BIT_SHIFT_XTAL_CAP_XO 1 +#define BIT_MASK_XTAL_CAP_XO 0x3f +#define BIT_XTAL_CAP_XO(x) \ + (((x) & BIT_MASK_XTAL_CAP_XO) << BIT_SHIFT_XTAL_CAP_XO) +#define BIT_GET_XTAL_CAP_XO(x) \ + (((x) >> BIT_SHIFT_XTAL_CAP_XO) & BIT_MASK_XTAL_CAP_XO) + +/* 2 REG_AFE_CTRL2 (Offset 0x0028) */ + +#define BIT_POW_PLL BIT(0) + +/* 2 REG_SDIO_OQT_FREE_TXPG_V1 (Offset 0x10250028) */ + +#define BIT_SHIFT_EXQ_FREEPG_V1 0 +#define BIT_MASK_EXQ_FREEPG_V1 0xfff +#define BIT_EXQ_FREEPG_V1(x) \ + (((x) & BIT_MASK_EXQ_FREEPG_V1) << BIT_SHIFT_EXQ_FREEPG_V1) +#define BIT_GET_EXQ_FREEPG_V1(x) \ + (((x) >> BIT_SHIFT_EXQ_FREEPG_V1) & BIT_MASK_EXQ_FREEPG_V1) + +/* 2 REG_AFE_CTRL3 (Offset 0x002C) */ + +#define BIT_SHIFT_PS 7 +#define BIT_MASK_PS 0x7 +#define BIT_PS(x) (((x) & BIT_MASK_PS) << BIT_SHIFT_PS) +#define BIT_GET_PS(x) (((x) >> BIT_SHIFT_PS) & BIT_MASK_PS) + +/* 2 REG_AFE_CTRL3 (Offset 0x002C) */ + +#define BIT_PSEN BIT(6) +#define BIT_DOGENB BIT(5) + +/* 2 REG_AFE_CTRL3 (Offset 0x002C) */ + +#define BIT_REG_MBIAS BIT(4) + +/* 2 REG_AFE_CTRL3 (Offset 0x002C) */ + +#define BIT_SHIFT_REG_R3_V4 1 +#define BIT_MASK_REG_R3_V4 0x7 +#define BIT_REG_R3_V4(x) (((x) & BIT_MASK_REG_R3_V4) << BIT_SHIFT_REG_R3_V4) +#define BIT_GET_REG_R3_V4(x) (((x) >> BIT_SHIFT_REG_R3_V4) & BIT_MASK_REG_R3_V4) + +/* 2 REG_AFE_CTRL3 (Offset 0x002C) */ + +#define BIT_REG_CP_BIT0 BIT(0) + +/* 2 REG_EFUSE_CTRL (Offset 0x0030) */ + +#define BIT_EF_FLAG BIT(31) + +#define BIT_SHIFT_EF_PGPD 28 +#define BIT_MASK_EF_PGPD 0x7 +#define BIT_EF_PGPD(x) (((x) & BIT_MASK_EF_PGPD) << BIT_SHIFT_EF_PGPD) +#define BIT_GET_EF_PGPD(x) (((x) >> BIT_SHIFT_EF_PGPD) & BIT_MASK_EF_PGPD) + +#define BIT_SHIFT_EF_RDT 24 +#define BIT_MASK_EF_RDT 0xf +#define BIT_EF_RDT(x) (((x) & BIT_MASK_EF_RDT) << BIT_SHIFT_EF_RDT) +#define BIT_GET_EF_RDT(x) (((x) >> BIT_SHIFT_EF_RDT) & BIT_MASK_EF_RDT) + +#define BIT_SHIFT_EF_PGTS 20 +#define BIT_MASK_EF_PGTS 0xf +#define BIT_EF_PGTS(x) (((x) & BIT_MASK_EF_PGTS) << BIT_SHIFT_EF_PGTS) +#define BIT_GET_EF_PGTS(x) (((x) >> BIT_SHIFT_EF_PGTS) & BIT_MASK_EF_PGTS) + +/* 2 REG_EFUSE_CTRL (Offset 0x0030) */ + +#define BIT_EF_PDWN BIT(19) + +/* 2 REG_EFUSE_CTRL (Offset 0x0030) */ + +#define BIT_EF_ALDEN BIT(18) + +/* 2 REG_SDIO_HTSFR_INFO (Offset 0x10250030) */ + +#define BIT_SHIFT_HTSFR1 16 +#define BIT_MASK_HTSFR1 0xffff +#define BIT_HTSFR1(x) (((x) & BIT_MASK_HTSFR1) << BIT_SHIFT_HTSFR1) +#define BIT_GET_HTSFR1(x) (((x) >> BIT_SHIFT_HTSFR1) & BIT_MASK_HTSFR1) + +/* 2 REG_EFUSE_CTRL (Offset 0x0030) */ + +#define BIT_SHIFT_EF_ADDR 8 +#define BIT_MASK_EF_ADDR 0x3ff +#define BIT_EF_ADDR(x) (((x) & BIT_MASK_EF_ADDR) << BIT_SHIFT_EF_ADDR) +#define BIT_GET_EF_ADDR(x) (((x) >> BIT_SHIFT_EF_ADDR) & BIT_MASK_EF_ADDR) + +#define BIT_SHIFT_EF_DATA 0 +#define BIT_MASK_EF_DATA 0xff +#define BIT_EF_DATA(x) (((x) & BIT_MASK_EF_DATA) << BIT_SHIFT_EF_DATA) +#define BIT_GET_EF_DATA(x) (((x) >> BIT_SHIFT_EF_DATA) & BIT_MASK_EF_DATA) + +/* 2 REG_SDIO_HTSFR_INFO (Offset 0x10250030) */ + +#define BIT_SHIFT_HTSFR0 0 +#define BIT_MASK_HTSFR0 0xffff +#define BIT_HTSFR0(x) (((x) & BIT_MASK_HTSFR0) << BIT_SHIFT_HTSFR0) +#define BIT_GET_HTSFR0(x) (((x) >> BIT_SHIFT_HTSFR0) & BIT_MASK_HTSFR0) + +/* 2 REG_LDO_EFUSE_CTRL (Offset 0x0034) */ + +#define BIT_LDOE25_EN BIT(31) + +/* 2 REG_LDO_EFUSE_CTRL (Offset 0x0034) */ + +#define BIT_SHIFT_LDOE25_V12ADJ_L 27 +#define BIT_MASK_LDOE25_V12ADJ_L 0xf +#define BIT_LDOE25_V12ADJ_L(x) \ + (((x) & BIT_MASK_LDOE25_V12ADJ_L) << BIT_SHIFT_LDOE25_V12ADJ_L) +#define BIT_GET_LDOE25_V12ADJ_L(x) \ + (((x) >> BIT_SHIFT_LDOE25_V12ADJ_L) & BIT_MASK_LDOE25_V12ADJ_L) + +/* 2 REG_LDO_EFUSE_CTRL (Offset 0x0034) */ + +#define BIT_EF_CRES_SEL BIT(26) + +/* 2 REG_LDO_EFUSE_CTRL (Offset 0x0034) */ + +#define BIT_SHIFT_EF_SCAN_START_V1 16 +#define BIT_MASK_EF_SCAN_START_V1 0x3ff +#define BIT_EF_SCAN_START_V1(x) \ + (((x) & BIT_MASK_EF_SCAN_START_V1) << BIT_SHIFT_EF_SCAN_START_V1) +#define BIT_GET_EF_SCAN_START_V1(x) \ + (((x) >> BIT_SHIFT_EF_SCAN_START_V1) & BIT_MASK_EF_SCAN_START_V1) + +/* 2 REG_LDO_EFUSE_CTRL (Offset 0x0034) */ + +#define BIT_SHIFT_EF_SCAN_END 12 +#define BIT_MASK_EF_SCAN_END 0xf +#define BIT_EF_SCAN_END(x) \ + (((x) & BIT_MASK_EF_SCAN_END) << BIT_SHIFT_EF_SCAN_END) +#define BIT_GET_EF_SCAN_END(x) \ + (((x) >> BIT_SHIFT_EF_SCAN_END) & BIT_MASK_EF_SCAN_END) + +/* 2 REG_LDO_EFUSE_CTRL (Offset 0x0034) */ + +#define BIT_EF_PD_DIS BIT(11) + +/* 2 REG_LDO_EFUSE_CTRL (Offset 0x0034) */ + +#define BIT_SHIFT_EF_CELL_SEL 8 +#define BIT_MASK_EF_CELL_SEL 0x3 +#define BIT_EF_CELL_SEL(x) \ + (((x) & BIT_MASK_EF_CELL_SEL) << BIT_SHIFT_EF_CELL_SEL) +#define BIT_GET_EF_CELL_SEL(x) \ + (((x) >> BIT_SHIFT_EF_CELL_SEL) & BIT_MASK_EF_CELL_SEL) + +/* 2 REG_LDO_EFUSE_CTRL (Offset 0x0034) */ + +#define BIT_EF_TRPT BIT(7) + +#define BIT_SHIFT_EF_TTHD 0 +#define BIT_MASK_EF_TTHD 0x7f +#define BIT_EF_TTHD(x) (((x) & BIT_MASK_EF_TTHD) << BIT_SHIFT_EF_TTHD) +#define BIT_GET_EF_TTHD(x) (((x) >> BIT_SHIFT_EF_TTHD) & BIT_MASK_EF_TTHD) + +/* 2 REG_PWR_OPTION_CTRL (Offset 0x0038) */ + +#define BIT_SHIFT_DBG_SEL_V1 16 +#define BIT_MASK_DBG_SEL_V1 0xff +#define BIT_DBG_SEL_V1(x) (((x) & BIT_MASK_DBG_SEL_V1) << BIT_SHIFT_DBG_SEL_V1) +#define BIT_GET_DBG_SEL_V1(x) \ + (((x) >> BIT_SHIFT_DBG_SEL_V1) & BIT_MASK_DBG_SEL_V1) + +/* 2 REG_PWR_OPTION_CTRL (Offset 0x0038) */ + +#define BIT_SHIFT_DBG_SEL_BYTE 14 +#define BIT_MASK_DBG_SEL_BYTE 0x3 +#define BIT_DBG_SEL_BYTE(x) \ + (((x) & BIT_MASK_DBG_SEL_BYTE) << BIT_SHIFT_DBG_SEL_BYTE) +#define BIT_GET_DBG_SEL_BYTE(x) \ + (((x) >> BIT_SHIFT_DBG_SEL_BYTE) & BIT_MASK_DBG_SEL_BYTE) + +/* 2 REG_PWR_OPTION_CTRL (Offset 0x0038) */ + +#define BIT_SHIFT_STD_L1_V1 12 +#define BIT_MASK_STD_L1_V1 0x3 +#define BIT_STD_L1_V1(x) (((x) & BIT_MASK_STD_L1_V1) << BIT_SHIFT_STD_L1_V1) +#define BIT_GET_STD_L1_V1(x) (((x) >> BIT_SHIFT_STD_L1_V1) & BIT_MASK_STD_L1_V1) + +/* 2 REG_PWR_OPTION_CTRL (Offset 0x0038) */ + +#define BIT_SYSON_DBG_PAD_E2 BIT(11) + +/* 2 REG_PWR_OPTION_CTRL (Offset 0x0038) */ + +#define BIT_SYSON_LED_PAD_E2 BIT(10) + +/* 2 REG_PWR_OPTION_CTRL (Offset 0x0038) */ + +#define BIT_SYSON_GPEE_PAD_E2 BIT(9) + +/* 2 REG_PWR_OPTION_CTRL (Offset 0x0038) */ + +#define BIT_SYSON_PCI_PAD_E2 BIT(8) + +#define BIT_SHIFT_MATCH_CNT 8 +#define BIT_MASK_MATCH_CNT 0xff +#define BIT_MATCH_CNT(x) (((x) & BIT_MASK_MATCH_CNT) << BIT_SHIFT_MATCH_CNT) +#define BIT_GET_MATCH_CNT(x) (((x) >> BIT_SHIFT_MATCH_CNT) & BIT_MASK_MATCH_CNT) + +/* 2 REG_PWR_OPTION_CTRL (Offset 0x0038) */ + +#define BIT_AUTO_SW_LDO_VOL_EN BIT(7) + +/* 2 REG_PWR_OPTION_CTRL (Offset 0x0038) */ + +#define BIT_SHIFT_SYSON_SPS0WWV_WT 4 +#define BIT_MASK_SYSON_SPS0WWV_WT 0x3 +#define BIT_SYSON_SPS0WWV_WT(x) \ + (((x) & BIT_MASK_SYSON_SPS0WWV_WT) << BIT_SHIFT_SYSON_SPS0WWV_WT) +#define BIT_GET_SYSON_SPS0WWV_WT(x) \ + (((x) >> BIT_SHIFT_SYSON_SPS0WWV_WT) & BIT_MASK_SYSON_SPS0WWV_WT) + +/* 2 REG_PWR_OPTION_CTRL (Offset 0x0038) */ + +#define BIT_SHIFT_SYSON_SPS0LDO_WT 2 +#define BIT_MASK_SYSON_SPS0LDO_WT 0x3 +#define BIT_SYSON_SPS0LDO_WT(x) \ + (((x) & BIT_MASK_SYSON_SPS0LDO_WT) << BIT_SHIFT_SYSON_SPS0LDO_WT) +#define BIT_GET_SYSON_SPS0LDO_WT(x) \ + (((x) >> BIT_SHIFT_SYSON_SPS0LDO_WT) & BIT_MASK_SYSON_SPS0LDO_WT) + +/* 2 REG_PWR_OPTION_CTRL (Offset 0x0038) */ + +#define BIT_SHIFT_SYSON_RCLK_SCALE 0 +#define BIT_MASK_SYSON_RCLK_SCALE 0x3 +#define BIT_SYSON_RCLK_SCALE(x) \ + (((x) & BIT_MASK_SYSON_RCLK_SCALE) << BIT_SHIFT_SYSON_RCLK_SCALE) +#define BIT_GET_SYSON_RCLK_SCALE(x) \ + (((x) >> BIT_SHIFT_SYSON_RCLK_SCALE) & BIT_MASK_SYSON_RCLK_SCALE) + +/* 2 REG_SDIO_HCPWM1_V2 (Offset 0x10250038) */ + +#define BIT_SYS_CLK BIT(0) + +/* 2 REG_CAL_TIMER (Offset 0x003C) */ + +#define BIT_SHIFT_CAL_SCAL 0 +#define BIT_MASK_CAL_SCAL 0xff +#define BIT_CAL_SCAL(x) (((x) & BIT_MASK_CAL_SCAL) << BIT_SHIFT_CAL_SCAL) +#define BIT_GET_CAL_SCAL(x) (((x) >> BIT_SHIFT_CAL_SCAL) & BIT_MASK_CAL_SCAL) + +/* 2 REG_ACLK_MON (Offset 0x003E) */ + +#define BIT_SHIFT_RCLK_MON 5 +#define BIT_MASK_RCLK_MON 0x7ff +#define BIT_RCLK_MON(x) (((x) & BIT_MASK_RCLK_MON) << BIT_SHIFT_RCLK_MON) +#define BIT_GET_RCLK_MON(x) (((x) >> BIT_SHIFT_RCLK_MON) & BIT_MASK_RCLK_MON) + +#define BIT_CAL_EN BIT(4) + +#define BIT_SHIFT_DPSTU 2 +#define BIT_MASK_DPSTU 0x3 +#define BIT_DPSTU(x) (((x) & BIT_MASK_DPSTU) << BIT_SHIFT_DPSTU) +#define BIT_GET_DPSTU(x) (((x) >> BIT_SHIFT_DPSTU) & BIT_MASK_DPSTU) + +#define BIT_SUS_16X BIT(1) + +/* 2 REG_SDIO_INDIRECT_REG_CFG (Offset 0x10250040) */ + +#define BIT_INDIRECT_REG_RDY BIT(20) + +/* 2 REG_GPIO_MUXCFG (Offset 0x0040) */ + +#define BIT_FSPI_EN BIT(19) + +/* 2 REG_SDIO_INDIRECT_REG_CFG (Offset 0x10250040) */ + +#define BIT_INDIRECT_REG_R BIT(19) + +/* 2 REG_GPIO_MUXCFG (Offset 0x0040) */ + +#define BIT_WL_RTS_EXT_32K_SEL BIT(18) + +/* 2 REG_SDIO_INDIRECT_REG_CFG (Offset 0x10250040) */ + +#define BIT_INDIRECT_REG_W BIT(18) + +/* 2 REG_GPIO_MUXCFG (Offset 0x0040) */ + +#define BIT_WLGP_SPI_EN BIT(16) + +/* 2 REG_SDIO_INDIRECT_REG_CFG (Offset 0x10250040) */ + +#define BIT_SHIFT_INDIRECT_REG_SIZE 16 +#define BIT_MASK_INDIRECT_REG_SIZE 0x3 +#define BIT_INDIRECT_REG_SIZE(x) \ + (((x) & BIT_MASK_INDIRECT_REG_SIZE) << BIT_SHIFT_INDIRECT_REG_SIZE) +#define BIT_GET_INDIRECT_REG_SIZE(x) \ + (((x) >> BIT_SHIFT_INDIRECT_REG_SIZE) & BIT_MASK_INDIRECT_REG_SIZE) + +/* 2 REG_GPIO_MUXCFG (Offset 0x0040) */ + +#define BIT_SIC_LBK BIT(15) +#define BIT_ENHTP BIT(14) + +/* 2 REG_GPIO_MUXCFG (Offset 0x0040) */ + +#define BIT_ENSIC BIT(12) +#define BIT_SIC_SWRST BIT(11) + +/* 2 REG_GPIO_MUXCFG (Offset 0x0040) */ + +#define BIT_PO_WIFI_PTA_PINS BIT(10) + +/* 2 REG_GPIO_MUXCFG (Offset 0x0040) */ + +#define BIT_PO_BT_PTA_PINS BIT(9) + +/* 2 REG_GPIO_MUXCFG (Offset 0x0040) */ + +#define BIT_ENUART BIT(8) + +#define BIT_SHIFT_BTMODE 6 +#define BIT_MASK_BTMODE 0x3 +#define BIT_BTMODE(x) (((x) & BIT_MASK_BTMODE) << BIT_SHIFT_BTMODE) +#define BIT_GET_BTMODE(x) (((x) >> BIT_SHIFT_BTMODE) & BIT_MASK_BTMODE) + +#define BIT_ENBT BIT(5) +#define BIT_EROM_EN BIT(4) + +/* 2 REG_GPIO_MUXCFG (Offset 0x0040) */ + +#define BIT_WLRFE_6_7_EN BIT(3) + +/* 2 REG_GPIO_MUXCFG (Offset 0x0040) */ + +#define BIT_WLRFE_4_5_EN BIT(2) + +/* 2 REG_GPIO_MUXCFG (Offset 0x0040) */ + +#define BIT_SHIFT_GPIOSEL 0 +#define BIT_MASK_GPIOSEL 0x3 +#define BIT_GPIOSEL(x) (((x) & BIT_MASK_GPIOSEL) << BIT_SHIFT_GPIOSEL) +#define BIT_GET_GPIOSEL(x) (((x) >> BIT_SHIFT_GPIOSEL) & BIT_MASK_GPIOSEL) + +/* 2 REG_SDIO_INDIRECT_REG_CFG (Offset 0x10250040) */ + +#define BIT_SHIFT_INDIRECT_REG_ADDR 0 +#define BIT_MASK_INDIRECT_REG_ADDR 0xffff +#define BIT_INDIRECT_REG_ADDR(x) \ + (((x) & BIT_MASK_INDIRECT_REG_ADDR) << BIT_SHIFT_INDIRECT_REG_ADDR) +#define BIT_GET_INDIRECT_REG_ADDR(x) \ + (((x) >> BIT_SHIFT_INDIRECT_REG_ADDR) & BIT_MASK_INDIRECT_REG_ADDR) + +/* 2 REG_GPIO_PIN_CTRL (Offset 0x0044) */ + +#define BIT_SHIFT_GPIO_MOD_7_TO_0 24 +#define BIT_MASK_GPIO_MOD_7_TO_0 0xff +#define BIT_GPIO_MOD_7_TO_0(x) \ + (((x) & BIT_MASK_GPIO_MOD_7_TO_0) << BIT_SHIFT_GPIO_MOD_7_TO_0) +#define BIT_GET_GPIO_MOD_7_TO_0(x) \ + (((x) >> BIT_SHIFT_GPIO_MOD_7_TO_0) & BIT_MASK_GPIO_MOD_7_TO_0) + +#define BIT_SHIFT_GPIO_IO_SEL_7_TO_0 16 +#define BIT_MASK_GPIO_IO_SEL_7_TO_0 0xff +#define BIT_GPIO_IO_SEL_7_TO_0(x) \ + (((x) & BIT_MASK_GPIO_IO_SEL_7_TO_0) << BIT_SHIFT_GPIO_IO_SEL_7_TO_0) +#define BIT_GET_GPIO_IO_SEL_7_TO_0(x) \ + (((x) >> BIT_SHIFT_GPIO_IO_SEL_7_TO_0) & BIT_MASK_GPIO_IO_SEL_7_TO_0) + +#define BIT_SHIFT_GPIO_OUT_7_TO_0 8 +#define BIT_MASK_GPIO_OUT_7_TO_0 0xff +#define BIT_GPIO_OUT_7_TO_0(x) \ + (((x) & BIT_MASK_GPIO_OUT_7_TO_0) << BIT_SHIFT_GPIO_OUT_7_TO_0) +#define BIT_GET_GPIO_OUT_7_TO_0(x) \ + (((x) >> BIT_SHIFT_GPIO_OUT_7_TO_0) & BIT_MASK_GPIO_OUT_7_TO_0) + +#define BIT_SHIFT_GPIO_IN_7_TO_0 0 +#define BIT_MASK_GPIO_IN_7_TO_0 0xff +#define BIT_GPIO_IN_7_TO_0(x) \ + (((x) & BIT_MASK_GPIO_IN_7_TO_0) << BIT_SHIFT_GPIO_IN_7_TO_0) +#define BIT_GET_GPIO_IN_7_TO_0(x) \ + (((x) >> BIT_SHIFT_GPIO_IN_7_TO_0) & BIT_MASK_GPIO_IN_7_TO_0) + +/* 2 REG_SDIO_INDIRECT_REG_DATA (Offset 0x10250044) */ + +#define BIT_SHIFT_INDIRECT_REG_DATA 0 +#define BIT_MASK_INDIRECT_REG_DATA 0xffffffffL +#define BIT_INDIRECT_REG_DATA(x) \ + (((x) & BIT_MASK_INDIRECT_REG_DATA) << BIT_SHIFT_INDIRECT_REG_DATA) +#define BIT_GET_INDIRECT_REG_DATA(x) \ + (((x) >> BIT_SHIFT_INDIRECT_REG_DATA) & BIT_MASK_INDIRECT_REG_DATA) + +/* 2 REG_GPIO_INTM (Offset 0x0048) */ + +#define BIT_SHIFT_MUXDBG_SEL 30 +#define BIT_MASK_MUXDBG_SEL 0x3 +#define BIT_MUXDBG_SEL(x) (((x) & BIT_MASK_MUXDBG_SEL) << BIT_SHIFT_MUXDBG_SEL) +#define BIT_GET_MUXDBG_SEL(x) \ + (((x) >> BIT_SHIFT_MUXDBG_SEL) & BIT_MASK_MUXDBG_SEL) + +/* 2 REG_GPIO_INTM (Offset 0x0048) */ + +#define BIT_EXTWOL_SEL BIT(17) + +/* 2 REG_GPIO_INTM (Offset 0x0048) */ + +#define BIT_EXTWOL_EN BIT(16) + +/* 2 REG_GPIO_INTM (Offset 0x0048) */ + +#define BIT_GPIOF_INT_MD BIT(15) +#define BIT_GPIOE_INT_MD BIT(14) +#define BIT_GPIOD_INT_MD BIT(13) +#define BIT_GPIOC_INT_MD BIT(12) +#define BIT_GPIOB_INT_MD BIT(11) +#define BIT_GPIOA_INT_MD BIT(10) +#define BIT_GPIO9_INT_MD BIT(9) +#define BIT_GPIO8_INT_MD BIT(8) +#define BIT_GPIO7_INT_MD BIT(7) +#define BIT_GPIO6_INT_MD BIT(6) +#define BIT_GPIO5_INT_MD BIT(5) +#define BIT_GPIO4_INT_MD BIT(4) +#define BIT_GPIO3_INT_MD BIT(3) +#define BIT_GPIO2_INT_MD BIT(2) +#define BIT_GPIO1_INT_MD BIT(1) +#define BIT_GPIO0_INT_MD BIT(0) + +/* 2 REG_LED_CFG (Offset 0x004C) */ + +#define BIT_GPIO3_WL_CTRL_EN BIT(27) + +/* 2 REG_LED_CFG (Offset 0x004C) */ + +#define BIT_LNAON_SEL_EN BIT(26) + +/* 2 REG_LED_CFG (Offset 0x004C) */ + +#define BIT_PAPE_SEL_EN BIT(25) + +/* 2 REG_LED_CFG (Offset 0x004C) */ + +#define BIT_DPDT_WLBT_SEL BIT(24) + +/* 2 REG_LED_CFG (Offset 0x004C) */ + +#define BIT_DPDT_SEL_EN BIT(23) + +/* 2 REG_LED_CFG (Offset 0x004C) */ + +#define BIT_GPIO13_14_WL_CTRL_EN BIT(22) + +/* 2 REG_LED_CFG (Offset 0x004C) */ + +#define BIT_LED2DIS BIT(21) + +/* 2 REG_LED_CFG (Offset 0x004C) */ + +#define BIT_LED2PL BIT(20) +#define BIT_LED2SV BIT(19) + +#define BIT_SHIFT_LED2CM 16 +#define BIT_MASK_LED2CM 0x7 +#define BIT_LED2CM(x) (((x) & BIT_MASK_LED2CM) << BIT_SHIFT_LED2CM) +#define BIT_GET_LED2CM(x) (((x) >> BIT_SHIFT_LED2CM) & BIT_MASK_LED2CM) + +#define BIT_LED1DIS BIT(15) +#define BIT_LED1PL BIT(12) +#define BIT_LED1SV BIT(11) + +#define BIT_SHIFT_LED1CM 8 +#define BIT_MASK_LED1CM 0x7 +#define BIT_LED1CM(x) (((x) & BIT_MASK_LED1CM) << BIT_SHIFT_LED1CM) +#define BIT_GET_LED1CM(x) (((x) >> BIT_SHIFT_LED1CM) & BIT_MASK_LED1CM) + +#define BIT_LED0DIS BIT(7) + +/* 2 REG_LED_CFG (Offset 0x004C) */ + +#define BIT_SHIFT_AFE_LDO_SWR_CHECK 5 +#define BIT_MASK_AFE_LDO_SWR_CHECK 0x3 +#define BIT_AFE_LDO_SWR_CHECK(x) \ + (((x) & BIT_MASK_AFE_LDO_SWR_CHECK) << BIT_SHIFT_AFE_LDO_SWR_CHECK) +#define BIT_GET_AFE_LDO_SWR_CHECK(x) \ + (((x) >> BIT_SHIFT_AFE_LDO_SWR_CHECK) & BIT_MASK_AFE_LDO_SWR_CHECK) + +/* 2 REG_LED_CFG (Offset 0x004C) */ + +#define BIT_LED0PL BIT(4) +#define BIT_LED0SV BIT(3) + +#define BIT_SHIFT_LED0CM 0 +#define BIT_MASK_LED0CM 0x7 +#define BIT_LED0CM(x) (((x) & BIT_MASK_LED0CM) << BIT_SHIFT_LED0CM) +#define BIT_GET_LED0CM(x) (((x) >> BIT_SHIFT_LED0CM) & BIT_MASK_LED0CM) + +/* 2 REG_FSIMR (Offset 0x0050) */ + +#define BIT_FS_PDNINT_EN BIT(31) + +/* 2 REG_FSIMR (Offset 0x0050) */ + +#define BIT_NFC_INT_PAD_EN BIT(30) + +/* 2 REG_FSIMR (Offset 0x0050) */ + +#define BIT_FS_SPS_OCP_INT_EN BIT(29) + +/* 2 REG_FSIMR (Offset 0x0050) */ + +#define BIT_FS_PWMERR_INT_EN BIT(28) + +/* 2 REG_FSIMR (Offset 0x0050) */ + +#define BIT_FS_GPIOF_INT_EN BIT(27) +#define BIT_FS_GPIOE_INT_EN BIT(26) +#define BIT_FS_GPIOD_INT_EN BIT(25) +#define BIT_FS_GPIOC_INT_EN BIT(24) + +/* 2 REG_FSIMR (Offset 0x0050) */ + +#define BIT_FS_GPIOB_INT_EN BIT(23) + +/* 2 REG_FSIMR (Offset 0x0050) */ + +#define BIT_FS_GPIOA_INT_EN BIT(22) + +/* 2 REG_FSIMR (Offset 0x0050) */ + +#define BIT_FS_GPIO9_INT_EN BIT(21) + +/* 2 REG_FSIMR (Offset 0x0050) */ + +#define BIT_FS_GPIO8_INT_EN BIT(20) + +/* 2 REG_FSIMR (Offset 0x0050) */ + +#define BIT_FS_GPIO7_INT_EN BIT(19) + +/* 2 REG_FSIMR (Offset 0x0050) */ + +#define BIT_FS_GPIO6_INT_EN BIT(18) + +/* 2 REG_FSIMR (Offset 0x0050) */ + +#define BIT_FS_GPIO5_INT_EN BIT(17) + +/* 2 REG_FSIMR (Offset 0x0050) */ + +#define BIT_FS_GPIO4_INT_EN BIT(16) + +/* 2 REG_FSIMR (Offset 0x0050) */ + +#define BIT_FS_GPIO3_INT_EN BIT(15) + +/* 2 REG_FSIMR (Offset 0x0050) */ + +#define BIT_FS_GPIO2_INT_EN BIT(14) + +/* 2 REG_FSIMR (Offset 0x0050) */ + +#define BIT_FS_GPIO1_INT_EN BIT(13) + +/* 2 REG_FSIMR (Offset 0x0050) */ + +#define BIT_FS_GPIO0_INT_EN BIT(12) + +/* 2 REG_FSIMR (Offset 0x0050) */ + +#define BIT_FS_HCI_SUS_EN BIT(11) + +/* 2 REG_FSIMR (Offset 0x0050) */ + +#define BIT_FS_HCI_RES_EN BIT(10) + +/* 2 REG_FSIMR (Offset 0x0050) */ + +#define BIT_FS_HCI_RESET_EN BIT(9) + +/* 2 REG_FSIMR (Offset 0x0050) */ + +#define BIT_FS_BTON_STS_UPDATE_MSK_EN BIT(7) + +/* 2 REG_FSIMR (Offset 0x0050) */ + +#define BIT_ACT2RECOVERY_INT_EN_V1 BIT(6) + +/* 2 REG_FSIMR (Offset 0x0050) */ + +#define BIT_GEN1GEN2_SWITCH BIT(5) + +/* 2 REG_FSIMR (Offset 0x0050) */ + +#define BIT_HCI_TXDMA_REQ_HIMR BIT(4) + +/* 2 REG_FSIMR (Offset 0x0050) */ + +#define BIT_FS_32K_LEAVE_SETTING_MAK BIT(3) + +/* 2 REG_FSIMR (Offset 0x0050) */ + +#define BIT_FS_32K_ENTER_SETTING_MAK BIT(2) + +/* 2 REG_FSIMR (Offset 0x0050) */ + +#define BIT_FS_USB_LPMRSM_MSK BIT(1) + +/* 2 REG_FSIMR (Offset 0x0050) */ + +#define BIT_FS_USB_LPMINT_MSK BIT(0) + +/* 2 REG_FSISR (Offset 0x0054) */ + +#define BIT_FS_PDNINT BIT(31) + +/* 2 REG_FSISR (Offset 0x0054) */ + +#define BIT_FS_SPS_OCP_INT BIT(29) + +/* 2 REG_FSISR (Offset 0x0054) */ + +#define BIT_FS_PWMERR_INT BIT(28) + +/* 2 REG_FSISR (Offset 0x0054) */ + +#define BIT_FS_GPIOF_INT BIT(27) +#define BIT_FS_GPIOE_INT BIT(26) +#define BIT_FS_GPIOD_INT BIT(25) +#define BIT_FS_GPIOC_INT BIT(24) + +/* 2 REG_FSISR (Offset 0x0054) */ + +#define BIT_FS_GPIOB_INT BIT(23) + +/* 2 REG_FSISR (Offset 0x0054) */ + +#define BIT_FS_GPIOA_INT BIT(22) + +/* 2 REG_FSISR (Offset 0x0054) */ + +#define BIT_FS_GPIO9_INT BIT(21) + +/* 2 REG_FSISR (Offset 0x0054) */ + +#define BIT_FS_GPIO8_INT BIT(20) + +/* 2 REG_FSISR (Offset 0x0054) */ + +#define BIT_FS_GPIO7_INT BIT(19) + +/* 2 REG_FSISR (Offset 0x0054) */ + +#define BIT_FS_GPIO6_INT BIT(18) + +/* 2 REG_FSISR (Offset 0x0054) */ + +#define BIT_FS_GPIO5_INT BIT(17) + +/* 2 REG_FSISR (Offset 0x0054) */ + +#define BIT_FS_GPIO4_INT BIT(16) + +/* 2 REG_FSISR (Offset 0x0054) */ + +#define BIT_FS_GPIO3_INT BIT(15) + +/* 2 REG_FSISR (Offset 0x0054) */ + +#define BIT_FS_GPIO2_INT BIT(14) + +/* 2 REG_FSISR (Offset 0x0054) */ + +#define BIT_FS_GPIO1_INT BIT(13) + +/* 2 REG_FSISR (Offset 0x0054) */ + +#define BIT_FS_GPIO0_INT BIT(12) + +/* 2 REG_FSISR (Offset 0x0054) */ + +#define BIT_FS_HCI_SUS_INT BIT(11) + +/* 2 REG_FSISR (Offset 0x0054) */ + +#define BIT_FS_HCI_RES_INT BIT(10) + +/* 2 REG_FSISR (Offset 0x0054) */ + +#define BIT_FS_HCI_RESET_INT BIT(9) + +/* 2 REG_FSISR (Offset 0x0054) */ + +#define BIT_ACT2RECOVERY BIT(6) + +/* 2 REG_FSISR (Offset 0x0054) */ + +#define BIT_HCI_TXDMA_REQ_HISR BIT(4) + +/* 2 REG_FSISR (Offset 0x0054) */ + +#define BIT_FS_32K_LEAVE_SETTING_INT BIT(3) + +/* 2 REG_FSISR (Offset 0x0054) */ + +#define BIT_FS_32K_ENTER_SETTING_INT BIT(2) + +/* 2 REG_FSISR (Offset 0x0054) */ + +#define BIT_FS_USB_LPMRSM_INT BIT(1) + +/* 2 REG_FSISR (Offset 0x0054) */ + +#define BIT_FS_USB_LPMINT_INT BIT(0) + +/* 2 REG_HSIMR (Offset 0x0058) */ + +#define BIT_GPIOF_INT_EN BIT(31) +#define BIT_GPIOE_INT_EN BIT(30) +#define BIT_GPIOD_INT_EN BIT(29) +#define BIT_GPIOC_INT_EN BIT(28) +#define BIT_GPIOB_INT_EN BIT(27) +#define BIT_GPIOA_INT_EN BIT(26) +#define BIT_GPIO9_INT_EN BIT(25) +#define BIT_GPIO8_INT_EN BIT(24) +#define BIT_GPIO7_INT_EN BIT(23) +#define BIT_GPIO6_INT_EN BIT(22) +#define BIT_GPIO5_INT_EN BIT(21) +#define BIT_GPIO4_INT_EN BIT(20) +#define BIT_GPIO3_INT_EN BIT(19) + +/* 2 REG_HSIMR (Offset 0x0058) */ + +#define BIT_GPIO1_INT_EN BIT(17) +#define BIT_GPIO0_INT_EN BIT(16) + +/* 2 REG_HSIMR (Offset 0x0058) */ + +#define BIT_GPIO2_INT_EN_V1 BIT(16) + +/* 2 REG_HSIMR (Offset 0x0058) */ + +#define BIT_PDNINT_EN BIT(7) + +/* 2 REG_HSIMR (Offset 0x0058) */ + +#define BIT_RON_INT_EN BIT(6) + +/* 2 REG_HSIMR (Offset 0x0058) */ + +#define BIT_SPS_OCP_INT_EN BIT(5) + +/* 2 REG_HSIMR (Offset 0x0058) */ + +#define BIT_GPIO15_0_INT_EN BIT(0) + +/* 2 REG_HSISR (Offset 0x005C) */ + +#define BIT_GPIOF_INT BIT(31) +#define BIT_GPIOE_INT BIT(30) +#define BIT_GPIOD_INT BIT(29) +#define BIT_GPIOC_INT BIT(28) +#define BIT_GPIOB_INT BIT(27) +#define BIT_GPIOA_INT BIT(26) +#define BIT_GPIO9_INT BIT(25) +#define BIT_GPIO8_INT BIT(24) +#define BIT_GPIO7_INT BIT(23) + +/* 2 REG_HSISR (Offset 0x005C) */ + +#define BIT_GPIO6_INT BIT(22) +#define BIT_GPIO5_INT BIT(21) +#define BIT_GPIO4_INT BIT(20) +#define BIT_GPIO3_INT BIT(19) + +/* 2 REG_HSISR (Offset 0x005C) */ + +#define BIT_GPIO1_INT BIT(17) +#define BIT_GPIO0_INT BIT(16) + +/* 2 REG_HSISR (Offset 0x005C) */ + +#define BIT_GPIO2_INT_V1 BIT(16) + +/* 2 REG_HSISR (Offset 0x005C) */ + +#define BIT_PDNINT BIT(7) + +/* 2 REG_HSISR (Offset 0x005C) */ + +#define BIT_RON_INT BIT(6) + +/* 2 REG_HSISR (Offset 0x005C) */ + +#define BIT_SPS_OCP_INT BIT(5) + +/* 2 REG_HSISR (Offset 0x005C) */ + +#define BIT_GPIO15_0_INT BIT(0) +#define BIT_MCUFWDL_EN BIT(0) + +/* 2 REG_GPIO_EXT_CTRL (Offset 0x0060) */ + +#define BIT_SHIFT_GPIO_MOD_15_TO_8 24 +#define BIT_MASK_GPIO_MOD_15_TO_8 0xff +#define BIT_GPIO_MOD_15_TO_8(x) \ + (((x) & BIT_MASK_GPIO_MOD_15_TO_8) << BIT_SHIFT_GPIO_MOD_15_TO_8) +#define BIT_GET_GPIO_MOD_15_TO_8(x) \ + (((x) >> BIT_SHIFT_GPIO_MOD_15_TO_8) & BIT_MASK_GPIO_MOD_15_TO_8) + +#define BIT_SHIFT_GPIO_IO_SEL_15_TO_8 16 +#define BIT_MASK_GPIO_IO_SEL_15_TO_8 0xff +#define BIT_GPIO_IO_SEL_15_TO_8(x) \ + (((x) & BIT_MASK_GPIO_IO_SEL_15_TO_8) << BIT_SHIFT_GPIO_IO_SEL_15_TO_8) +#define BIT_GET_GPIO_IO_SEL_15_TO_8(x) \ + (((x) >> BIT_SHIFT_GPIO_IO_SEL_15_TO_8) & BIT_MASK_GPIO_IO_SEL_15_TO_8) + +#define BIT_SHIFT_GPIO_OUT_15_TO_8 8 +#define BIT_MASK_GPIO_OUT_15_TO_8 0xff +#define BIT_GPIO_OUT_15_TO_8(x) \ + (((x) & BIT_MASK_GPIO_OUT_15_TO_8) << BIT_SHIFT_GPIO_OUT_15_TO_8) +#define BIT_GET_GPIO_OUT_15_TO_8(x) \ + (((x) >> BIT_SHIFT_GPIO_OUT_15_TO_8) & BIT_MASK_GPIO_OUT_15_TO_8) + +#define BIT_SHIFT_GPIO_IN_15_TO_8 0 +#define BIT_MASK_GPIO_IN_15_TO_8 0xff +#define BIT_GPIO_IN_15_TO_8(x) \ + (((x) & BIT_MASK_GPIO_IN_15_TO_8) << BIT_SHIFT_GPIO_IN_15_TO_8) +#define BIT_GET_GPIO_IN_15_TO_8(x) \ + (((x) >> BIT_SHIFT_GPIO_IN_15_TO_8) & BIT_MASK_GPIO_IN_15_TO_8) + +/* 2 REG_SDIO_H2C (Offset 0x10250060) */ + +#define BIT_SHIFT_SDIO_H2C_MSG 0 +#define BIT_MASK_SDIO_H2C_MSG 0xffffffffL +#define BIT_SDIO_H2C_MSG(x) \ + (((x) & BIT_MASK_SDIO_H2C_MSG) << BIT_SHIFT_SDIO_H2C_MSG) +#define BIT_GET_SDIO_H2C_MSG(x) \ + (((x) >> BIT_SHIFT_SDIO_H2C_MSG) & BIT_MASK_SDIO_H2C_MSG) + +/* 2 REG_PAD_CTRL1 (Offset 0x0064) */ + +#define BIT_PAPE_WLBT_SEL BIT(29) +#define BIT_LNAON_WLBT_SEL BIT(28) + +/* 2 REG_PAD_CTRL1 (Offset 0x0064) */ + +#define BIT_BTGP_GPG3_FEN BIT(26) +#define BIT_BTGP_GPG2_FEN BIT(25) + +/* 2 REG_PAD_CTRL1 (Offset 0x0064) */ + +#define BIT_BTGP_JTAG_EN BIT(24) + +/* 2 REG_PAD_CTRL1 (Offset 0x0064) */ + +#define BIT_XTAL_CLK_EXTARNAL_EN BIT(23) + +/* 2 REG_PAD_CTRL1 (Offset 0x0064) */ + +#define BIT_BTGP_UART0_EN BIT(22) + +/* 2 REG_PAD_CTRL1 (Offset 0x0064) */ + +#define BIT_BTGP_UART1_EN BIT(21) + +/* 2 REG_PAD_CTRL1 (Offset 0x0064) */ + +#define BIT_BTGP_SPI_EN BIT(20) + +/* 2 REG_PAD_CTRL1 (Offset 0x0064) */ + +#define BIT_BTGP_GPIO_E2 BIT(19) + +/* 2 REG_PAD_CTRL1 (Offset 0x0064) */ + +#define BIT_BTGP_GPIO_EN BIT(18) + +/* 2 REG_PAD_CTRL1 (Offset 0x0064) */ + +#define BIT_SHIFT_BTGP_GPIO_SL 16 +#define BIT_MASK_BTGP_GPIO_SL 0x3 +#define BIT_BTGP_GPIO_SL(x) \ + (((x) & BIT_MASK_BTGP_GPIO_SL) << BIT_SHIFT_BTGP_GPIO_SL) +#define BIT_GET_BTGP_GPIO_SL(x) \ + (((x) >> BIT_SHIFT_BTGP_GPIO_SL) & BIT_MASK_BTGP_GPIO_SL) + +/* 2 REG_PAD_CTRL1 (Offset 0x0064) */ + +#define BIT_PAD_SDIO_SR BIT(14) + +/* 2 REG_PAD_CTRL1 (Offset 0x0064) */ + +#define BIT_GPIO14_OUTPUT_PL BIT(13) + +/* 2 REG_PAD_CTRL1 (Offset 0x0064) */ + +#define BIT_HOST_WAKE_PAD_PULL_EN BIT(12) + +/* 2 REG_PAD_CTRL1 (Offset 0x0064) */ + +#define BIT_HOST_WAKE_PAD_SL BIT(11) + +/* 2 REG_PAD_CTRL1 (Offset 0x0064) */ + +#define BIT_PAD_LNAON_SR BIT(10) + +/* 2 REG_PAD_CTRL1 (Offset 0x0064) */ + +#define BIT_PAD_LNAON_E2 BIT(9) + +/* 2 REG_PAD_CTRL1 (Offset 0x0064) */ + +#define BIT_SW_LNAON_G_SEL_DATA BIT(8) + +/* 2 REG_PAD_CTRL1 (Offset 0x0064) */ + +#define BIT_SW_LNAON_A_SEL_DATA BIT(7) + +/* 2 REG_PAD_CTRL1 (Offset 0x0064) */ + +#define BIT_PAD_PAPE_SR BIT(6) + +/* 2 REG_PAD_CTRL1 (Offset 0x0064) */ + +#define BIT_PAD_PAPE_E2 BIT(5) + +/* 2 REG_PAD_CTRL1 (Offset 0x0064) */ + +#define BIT_SW_PAPE_G_SEL_DATA BIT(4) + +/* 2 REG_PAD_CTRL1 (Offset 0x0064) */ + +#define BIT_SW_PAPE_A_SEL_DATA BIT(3) + +/* 2 REG_PAD_CTRL1 (Offset 0x0064) */ + +#define BIT_PAD_DPDT_SR BIT(2) + +/* 2 REG_PAD_CTRL1 (Offset 0x0064) */ + +#define BIT_PAD_DPDT_PAD_E2 BIT(1) + +/* 2 REG_PAD_CTRL1 (Offset 0x0064) */ + +#define BIT_SW_DPDT_SEL_DATA BIT(0) + +/* 2 REG_SDIO_C2H (Offset 0x10250064) */ + +#define BIT_SHIFT_SDIO_C2H_MSG 0 +#define BIT_MASK_SDIO_C2H_MSG 0xffffffffL +#define BIT_SDIO_C2H_MSG(x) \ + (((x) & BIT_MASK_SDIO_C2H_MSG) << BIT_SHIFT_SDIO_C2H_MSG) +#define BIT_GET_SDIO_C2H_MSG(x) \ + (((x) >> BIT_SHIFT_SDIO_C2H_MSG) & BIT_MASK_SDIO_C2H_MSG) + +/* 2 REG_WL_BT_PWR_CTRL (Offset 0x0068) */ + +#define BIT_ISO_BD2PP BIT(31) +#define BIT_LDOV12B_EN BIT(30) +#define BIT_CKEN_BTGPS BIT(29) +#define BIT_FEN_BTGPS BIT(28) + +/* 2 REG_WL_BT_PWR_CTRL (Offset 0x0068) */ + +#define BIT_MULRW BIT(27) + +/* 2 REG_WL_BT_PWR_CTRL (Offset 0x0068) */ + +#define BIT_BTCPU_BOOTSEL BIT(27) +#define BIT_SPI_SPEEDUP BIT(26) + +/* 2 REG_WL_BT_PWR_CTRL (Offset 0x0068) */ + +#define BIT_DEVWAKE_PAD_TYPE_SEL BIT(24) +#define BIT_CLKREQ_PAD_TYPE_SEL BIT(23) + +/* 2 REG_WL_BT_PWR_CTRL (Offset 0x0068) */ + +#define BIT_EN_CPL_TIMEOUT_PS BIT(22) + +/* 2 REG_WL_BT_PWR_CTRL (Offset 0x0068) */ + +#define BIT_ISO_BTPON2PP BIT(22) + +/* 2 REG_WL_BT_PWR_CTRL (Offset 0x0068) */ + +#define BIT_REG_TXDMA_FAIL_PS BIT(21) + +/* 2 REG_WL_BT_PWR_CTRL (Offset 0x0068) */ + +#define BIT_EN_HWENTR_L1 BIT(19) + +/* 2 REG_WL_BT_PWR_CTRL (Offset 0x0068) */ + +#define BIT_BT_HWROF_EN BIT(19) + +/* 2 REG_WL_BT_PWR_CTRL (Offset 0x0068) */ + +#define BIT_EN_ADV_CLKGATE BIT(18) + +/* 2 REG_WL_BT_PWR_CTRL (Offset 0x0068) */ + +#define BIT_BT_FUNC_EN BIT(18) + +/* 2 REG_WL_BT_PWR_CTRL (Offset 0x0068) */ + +#define BIT_BT_HWPDN_SL BIT(17) + +/* 2 REG_WL_BT_PWR_CTRL (Offset 0x0068) */ + +#define BIT_BT_DISN_EN BIT(16) + +/* 2 REG_WL_BT_PWR_CTRL (Offset 0x0068) */ + +#define BIT_BT_PDN_PULL_EN BIT(15) + +/* 2 REG_WL_BT_PWR_CTRL (Offset 0x0068) */ + +#define BIT_WL_PDN_PULL_EN BIT(14) +#define BIT_EXTERNAL_REQUEST_PL BIT(13) + +/* 2 REG_WL_BT_PWR_CTRL (Offset 0x0068) */ + +#define BIT_GPIO0_2_3_PULL_LOW_EN BIT(12) + +/* 2 REG_WL_BT_PWR_CTRL (Offset 0x0068) */ + +#define BIT_ISO_BA2PP BIT(11) +#define BIT_BT_AFE_LDO_EN BIT(10) + +/* 2 REG_WL_BT_PWR_CTRL (Offset 0x0068) */ + +#define BIT_BT_AFE_PLL_EN BIT(9) + +/* 2 REG_WL_BT_PWR_CTRL (Offset 0x0068) */ + +#define BIT_BT_DIG_CLK_EN BIT(8) + +/* 2 REG_WL_BT_PWR_CTRL (Offset 0x0068) */ + +#define BIT_WL_DRV_EXIST_IDX BIT(5) + +/* 2 REG_WL_BT_PWR_CTRL (Offset 0x0068) */ + +#define BIT_DOP_EHPAD BIT(4) + +/* 2 REG_WL_BT_PWR_CTRL (Offset 0x0068) */ + +#define BIT_WL_HWROF_EN BIT(3) + +/* 2 REG_WL_BT_PWR_CTRL (Offset 0x0068) */ + +#define BIT_WL_FUNC_EN BIT(2) + +/* 2 REG_WL_BT_PWR_CTRL (Offset 0x0068) */ + +#define BIT_WL_HWPDN_SL BIT(1) +#define BIT_WL_HWPDN_EN BIT(0) + +/* 2 REG_SDM_DEBUG (Offset 0x006C) */ + +#define BIT_SHIFT_WLCLK_PHASE 0 +#define BIT_MASK_WLCLK_PHASE 0x1f +#define BIT_WLCLK_PHASE(x) \ + (((x) & BIT_MASK_WLCLK_PHASE) << BIT_SHIFT_WLCLK_PHASE) +#define BIT_GET_WLCLK_PHASE(x) \ + (((x) >> BIT_SHIFT_WLCLK_PHASE) & BIT_MASK_WLCLK_PHASE) + +/* 2 REG_SYS_SDIO_CTRL (Offset 0x0070) */ + +#define BIT_DBG_GNT_WL_BT BIT(27) + +/* 2 REG_SYS_SDIO_CTRL (Offset 0x0070) */ + +#define BIT_LTE_MUX_CTRL_PATH BIT(26) + +/* 2 REG_SYS_SDIO_CTRL (Offset 0x0070) */ + +#define BIT_LTE_COEX_UART BIT(25) + +/* 2 REG_SYS_SDIO_CTRL (Offset 0x0070) */ + +#define BIT_3W_LTE_WL_GPIO BIT(24) + +/* 2 REG_SYS_SDIO_CTRL (Offset 0x0070) */ + +#define BIT_SDIO_INT_POLARITY BIT(19) +#define BIT_SDIO_INT BIT(18) + +/* 2 REG_SYS_SDIO_CTRL (Offset 0x0070) */ + +#define BIT_SDIO_OFF_EN BIT(17) + +/* 2 REG_SYS_SDIO_CTRL (Offset 0x0070) */ + +#define BIT_SDIO_ON_EN BIT(16) + +/* 2 REG_SYS_SDIO_CTRL (Offset 0x0070) */ + +#define BIT_PCIE_WAIT_TIMEOUT_EVENT BIT(10) +#define BIT_PCIE_WAIT_TIME BIT(9) + +/* 2 REG_SYS_SDIO_CTRL (Offset 0x0070) */ + +#define BIT_MPCIE_REFCLK_XTAL_SEL BIT(8) + +/* 2 REG_HCI_OPT_CTRL (Offset 0x0074) */ + +#define BIT_SHIFT_TSFT_SEL 29 +#define BIT_MASK_TSFT_SEL 0x7 +#define BIT_TSFT_SEL(x) (((x) & BIT_MASK_TSFT_SEL) << BIT_SHIFT_TSFT_SEL) +#define BIT_GET_TSFT_SEL(x) (((x) >> BIT_SHIFT_TSFT_SEL) & BIT_MASK_TSFT_SEL) + +/* 2 REG_HCI_OPT_CTRL (Offset 0x0074) */ + +#define BIT_SHIFT_RPWM 24 +#define BIT_MASK_RPWM 0xff +#define BIT_RPWM(x) (((x) & BIT_MASK_RPWM) << BIT_SHIFT_RPWM) +#define BIT_GET_RPWM(x) (((x) >> BIT_SHIFT_RPWM) & BIT_MASK_RPWM) + +#define BIT_ROM_DLEN BIT(19) + +#define BIT_SHIFT_ROM_PGE 16 +#define BIT_MASK_ROM_PGE 0x7 +#define BIT_ROM_PGE(x) (((x) & BIT_MASK_ROM_PGE) << BIT_SHIFT_ROM_PGE) +#define BIT_GET_ROM_PGE(x) (((x) >> BIT_SHIFT_ROM_PGE) & BIT_MASK_ROM_PGE) + +/* 2 REG_HCI_OPT_CTRL (Offset 0x0074) */ + +#define BIT_USB_HOST_PWR_OFF_EN BIT(12) + +/* 2 REG_HCI_OPT_CTRL (Offset 0x0074) */ + +#define BIT_SYM_LPS_BLOCK_EN BIT(11) + +/* 2 REG_HCI_OPT_CTRL (Offset 0x0074) */ + +#define BIT_USB_LPM_ACT_EN BIT(10) + +/* 2 REG_HCI_OPT_CTRL (Offset 0x0074) */ + +#define BIT_USB_LPM_NY BIT(9) + +/* 2 REG_HCI_OPT_CTRL (Offset 0x0074) */ + +#define BIT_USB_SUS_DIS BIT(8) + +/* 2 REG_HCI_OPT_CTRL (Offset 0x0074) */ + +#define BIT_SHIFT_SDIO_PAD_E 5 +#define BIT_MASK_SDIO_PAD_E 0x7 +#define BIT_SDIO_PAD_E(x) (((x) & BIT_MASK_SDIO_PAD_E) << BIT_SHIFT_SDIO_PAD_E) +#define BIT_GET_SDIO_PAD_E(x) \ + (((x) >> BIT_SHIFT_SDIO_PAD_E) & BIT_MASK_SDIO_PAD_E) + +/* 2 REG_HCI_OPT_CTRL (Offset 0x0074) */ + +#define BIT_USB_LPPLL_EN BIT(4) + +/* 2 REG_HCI_OPT_CTRL (Offset 0x0074) */ + +#define BIT_ROP_SW15 BIT(2) + +/* 2 REG_HCI_OPT_CTRL (Offset 0x0074) */ + +#define BIT_PCI_CKRDY_OPT BIT(1) + +/* 2 REG_HCI_OPT_CTRL (Offset 0x0074) */ + +#define BIT_PCI_VAUX_EN BIT(0) + +/* 2 REG_LDO_SWR_CTRL (Offset 0x007C) */ + +#define BIT_ZCD_HW_AUTO_EN BIT(27) +#define BIT_ZCD_REGSEL BIT(26) + +/* 2 REG_LDO_SWR_CTRL (Offset 0x007C) */ + +#define BIT_SHIFT_AUTO_ZCD_IN_CODE 21 +#define BIT_MASK_AUTO_ZCD_IN_CODE 0x1f +#define BIT_AUTO_ZCD_IN_CODE(x) \ + (((x) & BIT_MASK_AUTO_ZCD_IN_CODE) << BIT_SHIFT_AUTO_ZCD_IN_CODE) +#define BIT_GET_AUTO_ZCD_IN_CODE(x) \ + (((x) >> BIT_SHIFT_AUTO_ZCD_IN_CODE) & BIT_MASK_AUTO_ZCD_IN_CODE) + +/* 2 REG_LDO_SWR_CTRL (Offset 0x007C) */ + +#define BIT_SHIFT_ZCD_CODE_IN_L 16 +#define BIT_MASK_ZCD_CODE_IN_L 0x1f +#define BIT_ZCD_CODE_IN_L(x) \ + (((x) & BIT_MASK_ZCD_CODE_IN_L) << BIT_SHIFT_ZCD_CODE_IN_L) +#define BIT_GET_ZCD_CODE_IN_L(x) \ + (((x) >> BIT_SHIFT_ZCD_CODE_IN_L) & BIT_MASK_ZCD_CODE_IN_L) + +/* 2 REG_LDO_SWR_CTRL (Offset 0x007C) */ + +#define BIT_SHIFT_LDO_HV5_DUMMY 14 +#define BIT_MASK_LDO_HV5_DUMMY 0x3 +#define BIT_LDO_HV5_DUMMY(x) \ + (((x) & BIT_MASK_LDO_HV5_DUMMY) << BIT_SHIFT_LDO_HV5_DUMMY) +#define BIT_GET_LDO_HV5_DUMMY(x) \ + (((x) >> BIT_SHIFT_LDO_HV5_DUMMY) & BIT_MASK_LDO_HV5_DUMMY) + +/* 2 REG_LDO_SWR_CTRL (Offset 0x007C) */ + +#define BIT_SHIFT_REG_VTUNE33_BIT0_TO_BIT1 12 +#define BIT_MASK_REG_VTUNE33_BIT0_TO_BIT1 0x3 +#define BIT_REG_VTUNE33_BIT0_TO_BIT1(x) \ + (((x) & BIT_MASK_REG_VTUNE33_BIT0_TO_BIT1) \ + << BIT_SHIFT_REG_VTUNE33_BIT0_TO_BIT1) +#define BIT_GET_REG_VTUNE33_BIT0_TO_BIT1(x) \ + (((x) >> BIT_SHIFT_REG_VTUNE33_BIT0_TO_BIT1) & \ + BIT_MASK_REG_VTUNE33_BIT0_TO_BIT1) + +/* 2 REG_LDO_SWR_CTRL (Offset 0x007C) */ + +#define BIT_SHIFT_REG_STANDBY33_BIT0_TO_BIT1 10 +#define BIT_MASK_REG_STANDBY33_BIT0_TO_BIT1 0x3 +#define BIT_REG_STANDBY33_BIT0_TO_BIT1(x) \ + (((x) & BIT_MASK_REG_STANDBY33_BIT0_TO_BIT1) \ + << BIT_SHIFT_REG_STANDBY33_BIT0_TO_BIT1) +#define BIT_GET_REG_STANDBY33_BIT0_TO_BIT1(x) \ + (((x) >> BIT_SHIFT_REG_STANDBY33_BIT0_TO_BIT1) & \ + BIT_MASK_REG_STANDBY33_BIT0_TO_BIT1) + +/* 2 REG_LDO_SWR_CTRL (Offset 0x007C) */ + +#define BIT_SHIFT_REG_LOAD33_BIT0_TO_BIT1 8 +#define BIT_MASK_REG_LOAD33_BIT0_TO_BIT1 0x3 +#define BIT_REG_LOAD33_BIT0_TO_BIT1(x) \ + (((x) & BIT_MASK_REG_LOAD33_BIT0_TO_BIT1) \ + << BIT_SHIFT_REG_LOAD33_BIT0_TO_BIT1) +#define BIT_GET_REG_LOAD33_BIT0_TO_BIT1(x) \ + (((x) >> BIT_SHIFT_REG_LOAD33_BIT0_TO_BIT1) & \ + BIT_MASK_REG_LOAD33_BIT0_TO_BIT1) + +/* 2 REG_LDO_SWR_CTRL (Offset 0x007C) */ + +#define BIT_REG_BYPASS_L BIT(7) + +/* 2 REG_LDO_SWR_CTRL (Offset 0x007C) */ + +#define BIT_REG_LDOF_L BIT(6) + +/* 2 REG_LDO_SWR_CTRL (Offset 0x007C) */ + +#define BIT_REG_TYPE_L_V1 BIT(5) + +/* 2 REG_LDO_SWR_CTRL (Offset 0x007C) */ + +#define BIT_ARENB_L BIT(3) + +/* 2 REG_LDO_SWR_CTRL (Offset 0x007C) */ + +#define BIT_SHIFT_CFC_L 1 +#define BIT_MASK_CFC_L 0x3 +#define BIT_CFC_L(x) (((x) & BIT_MASK_CFC_L) << BIT_SHIFT_CFC_L) +#define BIT_GET_CFC_L(x) (((x) >> BIT_SHIFT_CFC_L) & BIT_MASK_CFC_L) + +/* 2 REG_LDO_SWR_CTRL (Offset 0x007C) */ + +#define BIT_REG_OCPS_L_V1 BIT(0) + +/* 2 REG_MCUFW_CTRL (Offset 0x0080) */ + +#define BIT_ANA_PORT_EN BIT(22) +#define BIT_MAC_PORT_EN BIT(21) +#define BIT_BOOT_FSPI_EN BIT(20) +#define BIT_FW_INIT_RDY BIT(15) +#define BIT_FW_DW_RDY BIT(14) + +/* 2 REG_MCUFW_CTRL (Offset 0x0080) */ + +#define BIT_SHIFT_CPU_CLK_SEL 12 +#define BIT_MASK_CPU_CLK_SEL 0x3 +#define BIT_CPU_CLK_SEL(x) \ + (((x) & BIT_MASK_CPU_CLK_SEL) << BIT_SHIFT_CPU_CLK_SEL) +#define BIT_GET_CPU_CLK_SEL(x) \ + (((x) >> BIT_SHIFT_CPU_CLK_SEL) & BIT_MASK_CPU_CLK_SEL) + +/* 2 REG_MCUFW_CTRL (Offset 0x0080) */ + +#define BIT_CCLK_CHG_MASK BIT(11) + +/* 2 REG_MCUFW_CTRL (Offset 0x0080) */ + +#define BIT_EMEM__TXBUF_CHKSUM_OK BIT(10) + +/* 2 REG_MCUFW_CTRL (Offset 0x0080) */ + +#define BIT_EMEM_TXBUF_DW_RDY BIT(9) + +/* 2 REG_MCUFW_CTRL (Offset 0x0080) */ + +#define BIT_EMEM_CHKSUM_OK BIT(8) +#define BIT_EMEM_DW_OK BIT(7) +#define BIT_TOGGLING BIT(7) +#define BIT_DMEM_CHKSUM_OK BIT(6) +#define BIT_ACK BIT(6) + +/* 2 REG_MCUFW_CTRL (Offset 0x0080) */ + +#define BIT_DMEM_DW_OK BIT(5) + +/* 2 REG_MCUFW_CTRL (Offset 0x0080) */ + +#define BIT_IMEM_CHKSUM_OK BIT(4) + +/* 2 REG_MCUFW_CTRL (Offset 0x0080) */ + +#define BIT_IMEM_DW_OK BIT(3) + +/* 2 REG_MCUFW_CTRL (Offset 0x0080) */ + +#define BIT_IMEM_BOOT_LOAD_CHKSUM_OK BIT(2) + +/* 2 REG_MCUFW_CTRL (Offset 0x0080) */ + +#define BIT_IMEM_BOOT_LOAD_DW_OK BIT(1) + +/* 2 REG_SDIO_HRPWM1 (Offset 0x10250080) */ + +#define BIT_32K_PERMISSION BIT(0) + +/* 2 REG_MCU_TST_CFG (Offset 0x0084) */ + +#define BIT_SHIFT_LBKTST 0 +#define BIT_MASK_LBKTST 0xffff +#define BIT_LBKTST(x) (((x) & BIT_MASK_LBKTST) << BIT_SHIFT_LBKTST) +#define BIT_GET_LBKTST(x) (((x) >> BIT_SHIFT_LBKTST) & BIT_MASK_LBKTST) + +/* 2 REG_SDIO_BUS_CTRL (Offset 0x10250085) */ + +#define BIT_PAD_CLK_XHGE_EN BIT(3) +#define BIT_INTER_CLK_EN BIT(2) +#define BIT_EN_RPT_TXCRC BIT(1) +#define BIT_DIS_RXDMA_STS BIT(0) + +/* 2 REG_SDIO_HSUS_CTRL (Offset 0x10250086) */ + +#define BIT_INTR_CTRL BIT(4) +#define BIT_SDIO_VOLTAGE BIT(3) +#define BIT_BYPASS_INIT BIT(2) + +/* 2 REG_SDIO_HSUS_CTRL (Offset 0x10250086) */ + +#define BIT_HCI_RESUME_RDY BIT(1) +#define BIT_HCI_SUS_REQ BIT(0) + +/* 2 REG_HMEBOX_E0_E1 (Offset 0x0088) */ + +#define BIT_SHIFT_HOST_MSG_E1 16 +#define BIT_MASK_HOST_MSG_E1 0xffff +#define BIT_HOST_MSG_E1(x) \ + (((x) & BIT_MASK_HOST_MSG_E1) << BIT_SHIFT_HOST_MSG_E1) +#define BIT_GET_HOST_MSG_E1(x) \ + (((x) >> BIT_SHIFT_HOST_MSG_E1) & BIT_MASK_HOST_MSG_E1) + +#define BIT_SHIFT_HOST_MSG_E0 0 +#define BIT_MASK_HOST_MSG_E0 0xffff +#define BIT_HOST_MSG_E0(x) \ + (((x) & BIT_MASK_HOST_MSG_E0) << BIT_SHIFT_HOST_MSG_E0) +#define BIT_GET_HOST_MSG_E0(x) \ + (((x) >> BIT_SHIFT_HOST_MSG_E0) & BIT_MASK_HOST_MSG_E0) + +/* 2 REG_SDIO_RESPONSE_TIMER (Offset 0x10250088) */ + +#define BIT_SHIFT_CMDIN_2RESP_TIMER 0 +#define BIT_MASK_CMDIN_2RESP_TIMER 0xffff +#define BIT_CMDIN_2RESP_TIMER(x) \ + (((x) & BIT_MASK_CMDIN_2RESP_TIMER) << BIT_SHIFT_CMDIN_2RESP_TIMER) +#define BIT_GET_CMDIN_2RESP_TIMER(x) \ + (((x) >> BIT_SHIFT_CMDIN_2RESP_TIMER) & BIT_MASK_CMDIN_2RESP_TIMER) + +/* 2 REG_SDIO_CMD_CRC (Offset 0x1025008A) */ + +#define BIT_SHIFT_SDIO_CMD_CRC_V1 0 +#define BIT_MASK_SDIO_CMD_CRC_V1 0xff +#define BIT_SDIO_CMD_CRC_V1(x) \ + (((x) & BIT_MASK_SDIO_CMD_CRC_V1) << BIT_SHIFT_SDIO_CMD_CRC_V1) +#define BIT_GET_SDIO_CMD_CRC_V1(x) \ + (((x) >> BIT_SHIFT_SDIO_CMD_CRC_V1) & BIT_MASK_SDIO_CMD_CRC_V1) + +/* 2 REG_HMEBOX_E2_E3 (Offset 0x008C) */ + +#define BIT_SHIFT_HOST_MSG_E3 16 +#define BIT_MASK_HOST_MSG_E3 0xffff +#define BIT_HOST_MSG_E3(x) \ + (((x) & BIT_MASK_HOST_MSG_E3) << BIT_SHIFT_HOST_MSG_E3) +#define BIT_GET_HOST_MSG_E3(x) \ + (((x) >> BIT_SHIFT_HOST_MSG_E3) & BIT_MASK_HOST_MSG_E3) + +#define BIT_SHIFT_HOST_MSG_E2 0 +#define BIT_MASK_HOST_MSG_E2 0xffff +#define BIT_HOST_MSG_E2(x) \ + (((x) & BIT_MASK_HOST_MSG_E2) << BIT_SHIFT_HOST_MSG_E2) +#define BIT_GET_HOST_MSG_E2(x) \ + (((x) >> BIT_SHIFT_HOST_MSG_E2) & BIT_MASK_HOST_MSG_E2) + +/* 2 REG_WLLPS_CTRL (Offset 0x0090) */ + +#define BIT_WLLPSOP_EABM BIT(31) + +/* 2 REG_WLLPS_CTRL (Offset 0x0090) */ + +#define BIT_WLLPSOP_ACKF BIT(30) + +/* 2 REG_WLLPS_CTRL (Offset 0x0090) */ + +#define BIT_WLLPSOP_DLDM BIT(29) + +/* 2 REG_WLLPS_CTRL (Offset 0x0090) */ + +#define BIT_WLLPSOP_ESWR BIT(28) + +/* 2 REG_WLLPS_CTRL (Offset 0x0090) */ + +#define BIT_WLLPSOP_PWMM BIT(27) +#define BIT_WLLPSOP_EECK BIT(26) + +/* 2 REG_WLLPS_CTRL (Offset 0x0090) */ + +#define BIT_WLLPSOP_WLMACOFF BIT(25) + +/* 2 REG_WLLPS_CTRL (Offset 0x0090) */ + +#define BIT_WLLPSOP_EXTAL BIT(24) + +/* 2 REG_WLLPS_CTRL (Offset 0x0090) */ + +#define BIT_WL_SYNPON_VOLTSPDN BIT(23) + +/* 2 REG_WLLPS_CTRL (Offset 0x0090) */ + +#define BIT_WLLPSOP_WLBBOFF BIT(22) + +/* 2 REG_WLLPS_CTRL (Offset 0x0090) */ + +#define BIT_WLLPSOP_WLMEM_DS BIT(21) + +/* 2 REG_WLLPS_CTRL (Offset 0x0090) */ + +#define BIT_SHIFT_LPLDH12_VADJ_STEP_DN 12 +#define BIT_MASK_LPLDH12_VADJ_STEP_DN 0xf +#define BIT_LPLDH12_VADJ_STEP_DN(x) \ + (((x) & BIT_MASK_LPLDH12_VADJ_STEP_DN) \ + << BIT_SHIFT_LPLDH12_VADJ_STEP_DN) +#define BIT_GET_LPLDH12_VADJ_STEP_DN(x) \ + (((x) >> BIT_SHIFT_LPLDH12_VADJ_STEP_DN) & \ + BIT_MASK_LPLDH12_VADJ_STEP_DN) + +/* 2 REG_WLLPS_CTRL (Offset 0x0090) */ + +#define BIT_SHIFT_V15ADJ_L1_STEP_DN 8 +#define BIT_MASK_V15ADJ_L1_STEP_DN 0x7 +#define BIT_V15ADJ_L1_STEP_DN(x) \ + (((x) & BIT_MASK_V15ADJ_L1_STEP_DN) << BIT_SHIFT_V15ADJ_L1_STEP_DN) +#define BIT_GET_V15ADJ_L1_STEP_DN(x) \ + (((x) >> BIT_SHIFT_V15ADJ_L1_STEP_DN) & BIT_MASK_V15ADJ_L1_STEP_DN) + +#define BIT_REGU_32K_CLK_EN BIT(1) +#define BIT_DRV_WLAN_INT_CLR BIT(1) + +/* 2 REG_WLLPS_CTRL (Offset 0x0090) */ + +#define BIT_WL_LPS_EN BIT(0) + +/* 2 REG_SDIO_HSISR (Offset 0x10250090) */ + +#define BIT_DRV_WLAN_INT BIT(0) + +/* 2 REG_SDIO_HSIMR (Offset 0x10250091) */ + +#define BIT_HISR_MASK BIT(0) + +/* 2 REG_AFE_CTRL5 (Offset 0x0094) */ + +#define BIT_BB_DBG_SEL_AFE_SDM_BIT0 BIT(31) + +/* 2 REG_AFE_CTRL5 (Offset 0x0094) */ + +#define BIT_ORDER_SDM BIT(30) +#define BIT_RFE_SEL_SDM BIT(29) + +#define BIT_SHIFT_REF_SEL 25 +#define BIT_MASK_REF_SEL 0xf +#define BIT_REF_SEL(x) (((x) & BIT_MASK_REF_SEL) << BIT_SHIFT_REF_SEL) +#define BIT_GET_REF_SEL(x) (((x) >> BIT_SHIFT_REF_SEL) & BIT_MASK_REF_SEL) + +/* 2 REG_AFE_CTRL5 (Offset 0x0094) */ + +#define BIT_SHIFT_F0F_SDM 12 +#define BIT_MASK_F0F_SDM 0x1fff +#define BIT_F0F_SDM(x) (((x) & BIT_MASK_F0F_SDM) << BIT_SHIFT_F0F_SDM) +#define BIT_GET_F0F_SDM(x) (((x) >> BIT_SHIFT_F0F_SDM) & BIT_MASK_F0F_SDM) + +/* 2 REG_AFE_CTRL5 (Offset 0x0094) */ + +#define BIT_SHIFT_F0N_SDM 9 +#define BIT_MASK_F0N_SDM 0x7 +#define BIT_F0N_SDM(x) (((x) & BIT_MASK_F0N_SDM) << BIT_SHIFT_F0N_SDM) +#define BIT_GET_F0N_SDM(x) (((x) >> BIT_SHIFT_F0N_SDM) & BIT_MASK_F0N_SDM) + +/* 2 REG_AFE_CTRL5 (Offset 0x0094) */ + +#define BIT_SHIFT_DIVN_SDM 3 +#define BIT_MASK_DIVN_SDM 0x3f +#define BIT_DIVN_SDM(x) (((x) & BIT_MASK_DIVN_SDM) << BIT_SHIFT_DIVN_SDM) +#define BIT_GET_DIVN_SDM(x) (((x) >> BIT_SHIFT_DIVN_SDM) & BIT_MASK_DIVN_SDM) + +/* 2 REG_GPIO_DEBOUNCE_CTRL (Offset 0x0098) */ + +#define BIT_WLGP_DBC1EN BIT(15) + +#define BIT_SHIFT_WLGP_DBC1 8 +#define BIT_MASK_WLGP_DBC1 0xf +#define BIT_WLGP_DBC1(x) (((x) & BIT_MASK_WLGP_DBC1) << BIT_SHIFT_WLGP_DBC1) +#define BIT_GET_WLGP_DBC1(x) (((x) >> BIT_SHIFT_WLGP_DBC1) & BIT_MASK_WLGP_DBC1) + +#define BIT_WLGP_DBC0EN BIT(7) + +#define BIT_SHIFT_WLGP_DBC0 0 +#define BIT_MASK_WLGP_DBC0 0xf +#define BIT_WLGP_DBC0(x) (((x) & BIT_MASK_WLGP_DBC0) << BIT_SHIFT_WLGP_DBC0) +#define BIT_GET_WLGP_DBC0(x) (((x) >> BIT_SHIFT_WLGP_DBC0) & BIT_MASK_WLGP_DBC0) + +/* 2 REG_RPWM2 (Offset 0x009C) */ + +#define BIT_SHIFT_RPWM2 16 +#define BIT_MASK_RPWM2 0xffff +#define BIT_RPWM2(x) (((x) & BIT_MASK_RPWM2) << BIT_SHIFT_RPWM2) +#define BIT_GET_RPWM2(x) (((x) >> BIT_SHIFT_RPWM2) & BIT_MASK_RPWM2) + +/* 2 REG_SYSON_FSM_MON (Offset 0x00A0) */ + +#define BIT_SHIFT_FSM_MON_SEL 24 +#define BIT_MASK_FSM_MON_SEL 0x7 +#define BIT_FSM_MON_SEL(x) \ + (((x) & BIT_MASK_FSM_MON_SEL) << BIT_SHIFT_FSM_MON_SEL) +#define BIT_GET_FSM_MON_SEL(x) \ + (((x) >> BIT_SHIFT_FSM_MON_SEL) & BIT_MASK_FSM_MON_SEL) + +#define BIT_DOP_ELDO BIT(23) +#define BIT_FSM_MON_UPD BIT(15) + +#define BIT_SHIFT_FSM_PAR 0 +#define BIT_MASK_FSM_PAR 0x7fff +#define BIT_FSM_PAR(x) (((x) & BIT_MASK_FSM_PAR) << BIT_SHIFT_FSM_PAR) +#define BIT_GET_FSM_PAR(x) (((x) >> BIT_SHIFT_FSM_PAR) & BIT_MASK_FSM_PAR) + +/* 2 REG_AFE_CTRL6 (Offset 0x00A4) */ + +#define BIT_SHIFT_BB_DBG_SEL_AFE_SDM_BIT3_1 0 +#define BIT_MASK_BB_DBG_SEL_AFE_SDM_BIT3_1 0x7 +#define BIT_BB_DBG_SEL_AFE_SDM_BIT3_1(x) \ + (((x) & BIT_MASK_BB_DBG_SEL_AFE_SDM_BIT3_1) \ + << BIT_SHIFT_BB_DBG_SEL_AFE_SDM_BIT3_1) +#define BIT_GET_BB_DBG_SEL_AFE_SDM_BIT3_1(x) \ + (((x) >> BIT_SHIFT_BB_DBG_SEL_AFE_SDM_BIT3_1) & \ + BIT_MASK_BB_DBG_SEL_AFE_SDM_BIT3_1) + +/* 2 REG_PMC_DBG_CTRL1 (Offset 0x00A8) */ + +#define BIT_BT_INT_EN BIT(31) + +#define BIT_SHIFT_RD_WR_WIFI_BT_INFO 16 +#define BIT_MASK_RD_WR_WIFI_BT_INFO 0x7fff +#define BIT_RD_WR_WIFI_BT_INFO(x) \ + (((x) & BIT_MASK_RD_WR_WIFI_BT_INFO) << BIT_SHIFT_RD_WR_WIFI_BT_INFO) +#define BIT_GET_RD_WR_WIFI_BT_INFO(x) \ + (((x) >> BIT_SHIFT_RD_WR_WIFI_BT_INFO) & BIT_MASK_RD_WR_WIFI_BT_INFO) + +/* 2 REG_PMC_DBG_CTRL1 (Offset 0x00A8) */ + +#define BIT_PMC_WR_OVF BIT(8) + +#define BIT_SHIFT_WLPMC_ERRINT 0 +#define BIT_MASK_WLPMC_ERRINT 0xff +#define BIT_WLPMC_ERRINT(x) \ + (((x) & BIT_MASK_WLPMC_ERRINT) << BIT_SHIFT_WLPMC_ERRINT) +#define BIT_GET_WLPMC_ERRINT(x) \ + (((x) >> BIT_SHIFT_WLPMC_ERRINT) & BIT_MASK_WLPMC_ERRINT) + +/* 2 REG_AFE_CTRL7 (Offset 0x00AC) */ + +#define BIT_SHIFT_SEL_V 30 +#define BIT_MASK_SEL_V 0x3 +#define BIT_SEL_V(x) (((x) & BIT_MASK_SEL_V) << BIT_SHIFT_SEL_V) +#define BIT_GET_SEL_V(x) (((x) >> BIT_SHIFT_SEL_V) & BIT_MASK_SEL_V) + +/* 2 REG_AFE_CTRL7 (Offset 0x00AC) */ + +#define BIT_TXFIFO_TH_INT BIT(30) + +/* 2 REG_AFE_CTRL7 (Offset 0x00AC) */ + +#define BIT_SEL_LDO_PC BIT(29) + +/* 2 REG_AFE_CTRL7 (Offset 0x00AC) */ + +#define BIT_SHIFT_CK_MON_SEL 26 +#define BIT_MASK_CK_MON_SEL 0x7 +#define BIT_CK_MON_SEL(x) (((x) & BIT_MASK_CK_MON_SEL) << BIT_SHIFT_CK_MON_SEL) +#define BIT_GET_CK_MON_SEL(x) \ + (((x) >> BIT_SHIFT_CK_MON_SEL) & BIT_MASK_CK_MON_SEL) + +/* 2 REG_AFE_CTRL7 (Offset 0x00AC) */ + +#define BIT_CK_MON_EN BIT(25) +#define BIT_FREF_EDGE BIT(24) +#define BIT_CK320M_EN BIT(23) +#define BIT_CK_5M_EN BIT(22) +#define BIT_TESTEN BIT(21) + +/* 2 REG_HIMR0 (Offset 0x00B0) */ + +#define BIT_TIMEOUT_INTERRUPT2_MASK BIT(31) +#define BIT_TIMEOUT_INTERRUTP1_MASK BIT(30) +#define BIT_PSTIMEOUT_MSK BIT(29) +#define BIT_GTINT4_MSK BIT(28) +#define BIT_GTINT3_MSK BIT(27) +#define BIT_TXBCN0ERR_MSK BIT(26) +#define BIT_TXBCN0OK_MSK BIT(25) +#define BIT_TSF_BIT32_TOGGLE_MSK BIT(24) +#define BIT_BCNDMAINT0_MSK BIT(20) +#define BIT_BCNDERR0_MSK BIT(16) +#define BIT_HSISR_IND_ON_INT_MSK BIT(15) + +/* 2 REG_HIMR0 (Offset 0x00B0) */ + +#define BIT_BCNDMAINT_E_MSK BIT(14) + +/* 2 REG_HIMR0 (Offset 0x00B0) */ + +#define BIT_CTWEND_MSK BIT(12) +#define BIT_HISR1_IND_MSK BIT(11) + +/* 2 REG_HIMR0 (Offset 0x00B0) */ + +#define BIT_C2HCMD_MSK BIT(10) +#define BIT_CPWM2_MSK BIT(9) +#define BIT_CPWM_MSK BIT(8) +#define BIT_HIGHDOK_MSK BIT(7) +#define BIT_MGTDOK_MSK BIT(6) +#define BIT_BKDOK_MSK BIT(5) +#define BIT_BEDOK_MSK BIT(4) +#define BIT_VIDOK_MSK BIT(3) +#define BIT_VODOK_MSK BIT(2) +#define BIT_RDU_MSK BIT(1) +#define BIT_RXOK_MSK BIT(0) + +/* 2 REG_HISR0 (Offset 0x00B4) */ + +#define BIT_TIMEOUT_INTERRUPT2 BIT(31) + +/* 2 REG_HISR0 (Offset 0x00B4) */ + +#define BIT_TIMEOUT_INTERRUTP1 BIT(30) + +/* 2 REG_HISR0 (Offset 0x00B4) */ + +#define BIT_PSTIMEOUT BIT(29) +#define BIT_GTINT4 BIT(28) +#define BIT_GTINT3 BIT(27) +#define BIT_TXBCN0ERR BIT(26) +#define BIT_TXBCN0OK BIT(25) +#define BIT_TSF_BIT32_TOGGLE BIT(24) +#define BIT_BCNDMAINT0 BIT(20) +#define BIT_BCNDERR0 BIT(16) +#define BIT_HSISR_IND_ON_INT BIT(15) + +/* 2 REG_HISR0 (Offset 0x00B4) */ + +#define BIT_BCNDMAINT_E BIT(14) + +/* 2 REG_HISR0 (Offset 0x00B4) */ + +#define BIT_CTWEND BIT(12) + +/* 2 REG_HISR0 (Offset 0x00B4) */ + +#define BIT_HISR1_IND_INT BIT(11) +#define BIT_C2HCMD BIT(10) +#define BIT_CPWM2 BIT(9) +#define BIT_CPWM BIT(8) +#define BIT_HIGHDOK BIT(7) +#define BIT_MGTDOK BIT(6) +#define BIT_BKDOK BIT(5) +#define BIT_BEDOK BIT(4) +#define BIT_VIDOK BIT(3) +#define BIT_VODOK BIT(2) +#define BIT_RDU BIT(1) +#define BIT_RXOK BIT(0) + +/* 2 REG_HIMR1 (Offset 0x00B8) */ + +#define BIT_BTON_STS_UPDATE_MASK BIT(29) + +/* 2 REG_HIMR1 (Offset 0x00B8) */ + +#define BIT_MCU_ERR_MASK BIT(28) + +/* 2 REG_HIMR1 (Offset 0x00B8) */ + +#define BIT_BCNDMAINT7__MSK BIT(27) + +/* 2 REG_HIMR1 (Offset 0x00B8) */ + +#define BIT_BCNDMAINT6__MSK BIT(26) + +/* 2 REG_HIMR1 (Offset 0x00B8) */ + +#define BIT_BCNDMAINT5__MSK BIT(25) + +/* 2 REG_HIMR1 (Offset 0x00B8) */ + +#define BIT_BCNDMAINT4__MSK BIT(24) + +/* 2 REG_HIMR1 (Offset 0x00B8) */ + +#define BIT_BCNDMAINT3_MSK BIT(23) +#define BIT_BCNDMAINT2_MSK BIT(22) +#define BIT_BCNDMAINT1_MSK BIT(21) +#define BIT_BCNDERR7_MSK BIT(20) +#define BIT_BCNDERR6_MSK BIT(19) +#define BIT_BCNDERR5_MSK BIT(18) +#define BIT_BCNDERR4_MSK BIT(17) +#define BIT_BCNDERR3_MSK BIT(16) +#define BIT_BCNDERR2_MSK BIT(15) +#define BIT_BCNDERR1_MSK BIT(14) + +/* 2 REG_HIMR1 (Offset 0x00B8) */ + +#define BIT_ATIMEND_E_MSK BIT(13) + +/* 2 REG_HIMR1 (Offset 0x00B8) */ + +#define BIT_ATIMEND__MSK BIT(12) + +/* 2 REG_HIMR1 (Offset 0x00B8) */ + +#define BIT_TXERR_MSK BIT(11) +#define BIT_RXERR_MSK BIT(10) +#define BIT_TXFOVW_MSK BIT(9) +#define BIT_FOVW_MSK BIT(8) + +/* 2 REG_HIMR1 (Offset 0x00B8) */ + +#define BIT_CPU_MGQ_TXDONE_MSK BIT(5) +#define BIT_PS_TIMER_C_MSK BIT(4) +#define BIT_PS_TIMER_B_MSK BIT(3) +#define BIT_PS_TIMER_A_MSK BIT(2) +#define BIT_CPUMGQ_TX_TIMER_MSK BIT(1) + +/* 2 REG_HISR1 (Offset 0x00BC) */ + +#define BIT_BTON_STS_UPDATE_INT BIT(29) + +/* 2 REG_HISR1 (Offset 0x00BC) */ + +#define BIT_MCU_ERR BIT(28) + +/* 2 REG_HISR1 (Offset 0x00BC) */ + +#define BIT_BCNDMAINT7 BIT(27) +#define BIT_BCNDMAINT6 BIT(26) +#define BIT_BCNDMAINT5 BIT(25) +#define BIT_BCNDMAINT4 BIT(24) +#define BIT_BCNDMAINT3 BIT(23) +#define BIT_BCNDMAINT2 BIT(22) +#define BIT_BCNDMAINT1 BIT(21) +#define BIT_BCNDERR7 BIT(20) +#define BIT_BCNDERR6 BIT(19) +#define BIT_BCNDERR5 BIT(18) +#define BIT_BCNDERR4 BIT(17) +#define BIT_BCNDERR3 BIT(16) +#define BIT_BCNDERR2 BIT(15) +#define BIT_BCNDERR1 BIT(14) + +/* 2 REG_HISR1 (Offset 0x00BC) */ + +#define BIT_ATIMEND_E BIT(13) + +/* 2 REG_HISR1 (Offset 0x00BC) */ + +#define BIT_ATIMEND BIT(12) +#define BIT_TXERR_INT BIT(11) +#define BIT_RXERR_INT BIT(10) +#define BIT_TXFOVW BIT(9) +#define BIT_FOVW BIT(8) + +/* 2 REG_HISR1 (Offset 0x00BC) */ + +#define BIT_CPU_MGQ_TXDONE BIT(5) +#define BIT_PS_TIMER_C BIT(4) +#define BIT_PS_TIMER_B BIT(3) +#define BIT_PS_TIMER_A BIT(2) +#define BIT_CPUMGQ_TX_TIMER BIT(1) + +/* 2 REG_SDIO_ERR_RPT (Offset 0x102500C0) */ + +#define BIT_HR_FF_OVF BIT(6) +#define BIT_HR_FF_UDN BIT(5) +#define BIT_TXDMA_BUSY_ERR BIT(4) +#define BIT_TXDMA_VLD_ERR BIT(3) +#define BIT_QSEL_UNKNOWN_ERR BIT(2) +#define BIT_QSEL_MIS_ERR BIT(1) + +/* 2 REG_DBG_PORT_SEL (Offset 0x00C0) */ + +#define BIT_SHIFT_DEBUG_ST 0 +#define BIT_MASK_DEBUG_ST 0xffffffffL +#define BIT_DEBUG_ST(x) (((x) & BIT_MASK_DEBUG_ST) << BIT_SHIFT_DEBUG_ST) +#define BIT_GET_DEBUG_ST(x) (((x) >> BIT_SHIFT_DEBUG_ST) & BIT_MASK_DEBUG_ST) + +/* 2 REG_SDIO_ERR_RPT (Offset 0x102500C0) */ + +#define BIT_SDIO_OVERRD_ERR BIT(0) + +/* 2 REG_SDIO_CMD_ERRCNT (Offset 0x102500C1) */ + +#define BIT_SHIFT_CMD_CRC_ERR_CNT 0 +#define BIT_MASK_CMD_CRC_ERR_CNT 0xff +#define BIT_CMD_CRC_ERR_CNT(x) \ + (((x) & BIT_MASK_CMD_CRC_ERR_CNT) << BIT_SHIFT_CMD_CRC_ERR_CNT) +#define BIT_GET_CMD_CRC_ERR_CNT(x) \ + (((x) >> BIT_SHIFT_CMD_CRC_ERR_CNT) & BIT_MASK_CMD_CRC_ERR_CNT) + +/* 2 REG_SDIO_DATA_ERRCNT (Offset 0x102500C2) */ + +#define BIT_SHIFT_DATA_CRC_ERR_CNT 0 +#define BIT_MASK_DATA_CRC_ERR_CNT 0xff +#define BIT_DATA_CRC_ERR_CNT(x) \ + (((x) & BIT_MASK_DATA_CRC_ERR_CNT) << BIT_SHIFT_DATA_CRC_ERR_CNT) +#define BIT_GET_DATA_CRC_ERR_CNT(x) \ + (((x) >> BIT_SHIFT_DATA_CRC_ERR_CNT) & BIT_MASK_DATA_CRC_ERR_CNT) + +/* 2 REG_PAD_CTRL2 (Offset 0x00C4) */ + +#define BIT_USB3_USB2_TRANSITION BIT(20) + +/* 2 REG_PAD_CTRL2 (Offset 0x00C4) */ + +#define BIT_SHIFT_USB23_SW_MODE_V1 18 +#define BIT_MASK_USB23_SW_MODE_V1 0x3 +#define BIT_USB23_SW_MODE_V1(x) \ + (((x) & BIT_MASK_USB23_SW_MODE_V1) << BIT_SHIFT_USB23_SW_MODE_V1) +#define BIT_GET_USB23_SW_MODE_V1(x) \ + (((x) >> BIT_SHIFT_USB23_SW_MODE_V1) & BIT_MASK_USB23_SW_MODE_V1) + +/* 2 REG_PAD_CTRL2 (Offset 0x00C4) */ + +#define BIT_NO_PDN_CHIPOFF_V1 BIT(17) + +/* 2 REG_PAD_CTRL2 (Offset 0x00C4) */ + +#define BIT_RSM_EN_V1 BIT(16) + +/* 2 REG_PAD_CTRL2 (Offset 0x00C4) */ + +#define BIT_LD_B12V_EN BIT(7) + +/* 2 REG_PAD_CTRL2 (Offset 0x00C4) */ + +#define BIT_EECS_IOSEL_V1 BIT(6) + +/* 2 REG_PAD_CTRL2 (Offset 0x00C4) */ + +#define BIT_EECS_DATA_O_V1 BIT(5) + +/* 2 REG_PAD_CTRL2 (Offset 0x00C4) */ + +#define BIT_EECS_DATA_I_V1 BIT(4) + +/* 2 REG_PAD_CTRL2 (Offset 0x00C4) */ + +#define BIT_EESK_IOSEL_V1 BIT(2) + +/* 2 REG_PAD_CTRL2 (Offset 0x00C4) */ + +#define BIT_EESK_DATA_O_V1 BIT(1) + +/* 2 REG_PAD_CTRL2 (Offset 0x00C4) */ + +#define BIT_EESK_DATA_I_V1 BIT(0) + +/* 2 REG_SDIO_CMD_ERR_CONTENT (Offset 0x102500C4) */ + +#define BIT_SHIFT_SDIO_CMD_ERR_CONTENT 0 +#define BIT_MASK_SDIO_CMD_ERR_CONTENT 0xffffffffffL +#define BIT_SDIO_CMD_ERR_CONTENT(x) \ + (((x) & BIT_MASK_SDIO_CMD_ERR_CONTENT) \ + << BIT_SHIFT_SDIO_CMD_ERR_CONTENT) +#define BIT_GET_SDIO_CMD_ERR_CONTENT(x) \ + (((x) >> BIT_SHIFT_SDIO_CMD_ERR_CONTENT) & \ + BIT_MASK_SDIO_CMD_ERR_CONTENT) + +/* 2 REG_SDIO_CRC_ERR_IDX (Offset 0x102500C9) */ + +#define BIT_D3_CRC_ERR BIT(4) +#define BIT_D2_CRC_ERR BIT(3) +#define BIT_D1_CRC_ERR BIT(2) +#define BIT_D0_CRC_ERR BIT(1) +#define BIT_CMD_CRC_ERR BIT(0) + +/* 2 REG_SDIO_DATA_CRC (Offset 0x102500CA) */ + +#define BIT_SHIFT_SDIO_DATA_CRC 0 +#define BIT_MASK_SDIO_DATA_CRC 0xff +#define BIT_SDIO_DATA_CRC(x) \ + (((x) & BIT_MASK_SDIO_DATA_CRC) << BIT_SHIFT_SDIO_DATA_CRC) +#define BIT_GET_SDIO_DATA_CRC(x) \ + (((x) >> BIT_SHIFT_SDIO_DATA_CRC) & BIT_MASK_SDIO_DATA_CRC) + +/* 2 REG_SDIO_DATA_REPLY_TIME (Offset 0x102500CB) */ + +#define BIT_SHIFT_SDIO_DATA_REPLY_TIME 0 +#define BIT_MASK_SDIO_DATA_REPLY_TIME 0x7 +#define BIT_SDIO_DATA_REPLY_TIME(x) \ + (((x) & BIT_MASK_SDIO_DATA_REPLY_TIME) \ + << BIT_SHIFT_SDIO_DATA_REPLY_TIME) +#define BIT_GET_SDIO_DATA_REPLY_TIME(x) \ + (((x) >> BIT_SHIFT_SDIO_DATA_REPLY_TIME) & \ + BIT_MASK_SDIO_DATA_REPLY_TIME) + +/* 2 REG_PMC_DBG_CTRL2 (Offset 0x00CC) */ + +#define BIT_SHIFT_EFUSE_BURN_GNT 24 +#define BIT_MASK_EFUSE_BURN_GNT 0xff +#define BIT_EFUSE_BURN_GNT(x) \ + (((x) & BIT_MASK_EFUSE_BURN_GNT) << BIT_SHIFT_EFUSE_BURN_GNT) +#define BIT_GET_EFUSE_BURN_GNT(x) \ + (((x) >> BIT_SHIFT_EFUSE_BURN_GNT) & BIT_MASK_EFUSE_BURN_GNT) + +/* 2 REG_PMC_DBG_CTRL2 (Offset 0x00CC) */ + +#define BIT_STOP_WL_PMC BIT(9) +#define BIT_STOP_SYM_PMC BIT(8) + +/* 2 REG_PMC_DBG_CTRL2 (Offset 0x00CC) */ + +#define BIT_REG_RST_WLPMC BIT(5) +#define BIT_REG_RST_PD12N BIT(4) +#define BIT_SYSON_DIS_WLREG_WRMSK BIT(3) +#define BIT_SYSON_DIS_PMCREG_WRMSK BIT(2) + +#define BIT_SHIFT_SYSON_REG_ARB 0 +#define BIT_MASK_SYSON_REG_ARB 0x3 +#define BIT_SYSON_REG_ARB(x) \ + (((x) & BIT_MASK_SYSON_REG_ARB) << BIT_SHIFT_SYSON_REG_ARB) +#define BIT_GET_SYSON_REG_ARB(x) \ + (((x) >> BIT_SHIFT_SYSON_REG_ARB) & BIT_MASK_SYSON_REG_ARB) + +/* 2 REG_BIST_CTRL (Offset 0x00D0) */ + +#define BIT_BIST_USB_DIS BIT(27) + +/* 2 REG_BIST_CTRL (Offset 0x00D0) */ + +#define BIT_BIST_PCI_DIS BIT(26) + +/* 2 REG_BIST_CTRL (Offset 0x00D0) */ + +#define BIT_BIST_BT_DIS BIT(25) + +/* 2 REG_BIST_CTRL (Offset 0x00D0) */ + +#define BIT_BIST_WL_DIS BIT(24) + +/* 2 REG_BIST_CTRL (Offset 0x00D0) */ + +#define BIT_SHIFT_BIST_RPT_SEL 16 +#define BIT_MASK_BIST_RPT_SEL 0xf +#define BIT_BIST_RPT_SEL(x) \ + (((x) & BIT_MASK_BIST_RPT_SEL) << BIT_SHIFT_BIST_RPT_SEL) +#define BIT_GET_BIST_RPT_SEL(x) \ + (((x) >> BIT_SHIFT_BIST_RPT_SEL) & BIT_MASK_BIST_RPT_SEL) + +/* 2 REG_BIST_CTRL (Offset 0x00D0) */ + +#define BIT_BIST_RESUME_PS BIT(4) + +/* 2 REG_BIST_CTRL (Offset 0x00D0) */ + +#define BIT_BIST_RESUME BIT(3) +#define BIT_BIST_NORMAL BIT(2) + +/* 2 REG_BIST_CTRL (Offset 0x00D0) */ + +#define BIT_BIST_RSTN BIT(1) +#define BIT_BIST_CLK_EN BIT(0) + +/* 2 REG_BIST_RPT (Offset 0x00D4) */ + +#define BIT_SHIFT_MBIST_REPORT 0 +#define BIT_MASK_MBIST_REPORT 0xffffffffL +#define BIT_MBIST_REPORT(x) \ + (((x) & BIT_MASK_MBIST_REPORT) << BIT_SHIFT_MBIST_REPORT) +#define BIT_GET_MBIST_REPORT(x) \ + (((x) >> BIT_SHIFT_MBIST_REPORT) & BIT_MASK_MBIST_REPORT) + +/* 2 REG_MEM_CTRL (Offset 0x00D8) */ + +#define BIT_UMEM_RME BIT(31) + +/* 2 REG_MEM_CTRL (Offset 0x00D8) */ + +#define BIT_SHIFT_BT_SPRAM 28 +#define BIT_MASK_BT_SPRAM 0x3 +#define BIT_BT_SPRAM(x) (((x) & BIT_MASK_BT_SPRAM) << BIT_SHIFT_BT_SPRAM) +#define BIT_GET_BT_SPRAM(x) (((x) >> BIT_SHIFT_BT_SPRAM) & BIT_MASK_BT_SPRAM) + +/* 2 REG_MEM_CTRL (Offset 0x00D8) */ + +#define BIT_SHIFT_BT_ROM 24 +#define BIT_MASK_BT_ROM 0xf +#define BIT_BT_ROM(x) (((x) & BIT_MASK_BT_ROM) << BIT_SHIFT_BT_ROM) +#define BIT_GET_BT_ROM(x) (((x) >> BIT_SHIFT_BT_ROM) & BIT_MASK_BT_ROM) + +#define BIT_SHIFT_PCI_DPRAM 10 +#define BIT_MASK_PCI_DPRAM 0x3 +#define BIT_PCI_DPRAM(x) (((x) & BIT_MASK_PCI_DPRAM) << BIT_SHIFT_PCI_DPRAM) +#define BIT_GET_PCI_DPRAM(x) (((x) >> BIT_SHIFT_PCI_DPRAM) & BIT_MASK_PCI_DPRAM) + +/* 2 REG_MEM_CTRL (Offset 0x00D8) */ + +#define BIT_SHIFT_PCI_SPRAM 8 +#define BIT_MASK_PCI_SPRAM 0x3 +#define BIT_PCI_SPRAM(x) (((x) & BIT_MASK_PCI_SPRAM) << BIT_SHIFT_PCI_SPRAM) +#define BIT_GET_PCI_SPRAM(x) (((x) >> BIT_SHIFT_PCI_SPRAM) & BIT_MASK_PCI_SPRAM) + +#define BIT_SHIFT_USB_SPRAM 6 +#define BIT_MASK_USB_SPRAM 0x3 +#define BIT_USB_SPRAM(x) (((x) & BIT_MASK_USB_SPRAM) << BIT_SHIFT_USB_SPRAM) +#define BIT_GET_USB_SPRAM(x) (((x) >> BIT_SHIFT_USB_SPRAM) & BIT_MASK_USB_SPRAM) + +/* 2 REG_MEM_CTRL (Offset 0x00D8) */ + +#define BIT_SHIFT_USB_SPRF 4 +#define BIT_MASK_USB_SPRF 0x3 +#define BIT_USB_SPRF(x) (((x) & BIT_MASK_USB_SPRF) << BIT_SHIFT_USB_SPRF) +#define BIT_GET_USB_SPRF(x) (((x) >> BIT_SHIFT_USB_SPRF) & BIT_MASK_USB_SPRF) + +/* 2 REG_MEM_CTRL (Offset 0x00D8) */ + +#define BIT_SHIFT_MCU_ROM 0 +#define BIT_MASK_MCU_ROM 0xf +#define BIT_MCU_ROM(x) (((x) & BIT_MASK_MCU_ROM) << BIT_SHIFT_MCU_ROM) +#define BIT_GET_MCU_ROM(x) (((x) >> BIT_SHIFT_MCU_ROM) & BIT_MASK_MCU_ROM) + +/* 2 REG_AFE_CTRL8 (Offset 0x00DC) */ + +#define BIT_SYN_AGPIO BIT(20) + +/* 2 REG_AFE_CTRL8 (Offset 0x00DC) */ + +#define BIT_XTAL_LP BIT(4) +#define BIT_XTAL_GM_SEP BIT(3) + +/* 2 REG_AFE_CTRL8 (Offset 0x00DC) */ + +#define BIT_SHIFT_XTAL_SEL_TOK 0 +#define BIT_MASK_XTAL_SEL_TOK 0x7 +#define BIT_XTAL_SEL_TOK(x) \ + (((x) & BIT_MASK_XTAL_SEL_TOK) << BIT_SHIFT_XTAL_SEL_TOK) +#define BIT_GET_XTAL_SEL_TOK(x) \ + (((x) >> BIT_SHIFT_XTAL_SEL_TOK) & BIT_MASK_XTAL_SEL_TOK) + +/* 2 REG_USB_SIE_INTF (Offset 0x00E0) */ + +#define BIT_RD_SEL BIT(31) + +/* 2 REG_USB_SIE_INTF (Offset 0x00E0) */ + +#define BIT_USB_SIE_INTF_WE_V1 BIT(30) +#define BIT_USB_SIE_INTF_BYIOREG_V1 BIT(29) +#define BIT_USB_SIE_SELECT BIT(28) + +/* 2 REG_USB_SIE_INTF (Offset 0x00E0) */ + +#define BIT_SHIFT_USB_SIE_INTF_ADDR_V1 16 +#define BIT_MASK_USB_SIE_INTF_ADDR_V1 0x1ff +#define BIT_USB_SIE_INTF_ADDR_V1(x) \ + (((x) & BIT_MASK_USB_SIE_INTF_ADDR_V1) \ + << BIT_SHIFT_USB_SIE_INTF_ADDR_V1) +#define BIT_GET_USB_SIE_INTF_ADDR_V1(x) \ + (((x) >> BIT_SHIFT_USB_SIE_INTF_ADDR_V1) & \ + BIT_MASK_USB_SIE_INTF_ADDR_V1) + +/* 2 REG_USB_SIE_INTF (Offset 0x00E0) */ + +#define BIT_SHIFT_USB_SIE_INTF_RD 8 +#define BIT_MASK_USB_SIE_INTF_RD 0xff +#define BIT_USB_SIE_INTF_RD(x) \ + (((x) & BIT_MASK_USB_SIE_INTF_RD) << BIT_SHIFT_USB_SIE_INTF_RD) +#define BIT_GET_USB_SIE_INTF_RD(x) \ + (((x) >> BIT_SHIFT_USB_SIE_INTF_RD) & BIT_MASK_USB_SIE_INTF_RD) + +#define BIT_SHIFT_USB_SIE_INTF_WD 0 +#define BIT_MASK_USB_SIE_INTF_WD 0xff +#define BIT_USB_SIE_INTF_WD(x) \ + (((x) & BIT_MASK_USB_SIE_INTF_WD) << BIT_SHIFT_USB_SIE_INTF_WD) +#define BIT_GET_USB_SIE_INTF_WD(x) \ + (((x) >> BIT_SHIFT_USB_SIE_INTF_WD) & BIT_MASK_USB_SIE_INTF_WD) + +/* 2 REG_PCIE_MIO_INTF (Offset 0x00E4) */ + +#define BIT_PCIE_MIO_BYIOREG BIT(13) +#define BIT_PCIE_MIO_RE BIT(12) + +#define BIT_SHIFT_PCIE_MIO_WE 8 +#define BIT_MASK_PCIE_MIO_WE 0xf +#define BIT_PCIE_MIO_WE(x) \ + (((x) & BIT_MASK_PCIE_MIO_WE) << BIT_SHIFT_PCIE_MIO_WE) +#define BIT_GET_PCIE_MIO_WE(x) \ + (((x) >> BIT_SHIFT_PCIE_MIO_WE) & BIT_MASK_PCIE_MIO_WE) + +#define BIT_SHIFT_PCIE_MIO_ADDR 0 +#define BIT_MASK_PCIE_MIO_ADDR 0xff +#define BIT_PCIE_MIO_ADDR(x) \ + (((x) & BIT_MASK_PCIE_MIO_ADDR) << BIT_SHIFT_PCIE_MIO_ADDR) +#define BIT_GET_PCIE_MIO_ADDR(x) \ + (((x) >> BIT_SHIFT_PCIE_MIO_ADDR) & BIT_MASK_PCIE_MIO_ADDR) + +/* 2 REG_PCIE_MIO_INTD (Offset 0x00E8) */ + +#define BIT_SHIFT_PCIE_MIO_DATA 0 +#define BIT_MASK_PCIE_MIO_DATA 0xffffffffL +#define BIT_PCIE_MIO_DATA(x) \ + (((x) & BIT_MASK_PCIE_MIO_DATA) << BIT_SHIFT_PCIE_MIO_DATA) +#define BIT_GET_PCIE_MIO_DATA(x) \ + (((x) >> BIT_SHIFT_PCIE_MIO_DATA) & BIT_MASK_PCIE_MIO_DATA) + +/* 2 REG_WLRF1 (Offset 0x00EC) */ + +#define BIT_SHIFT_WLRF1_CTRL 24 +#define BIT_MASK_WLRF1_CTRL 0xff +#define BIT_WLRF1_CTRL(x) (((x) & BIT_MASK_WLRF1_CTRL) << BIT_SHIFT_WLRF1_CTRL) +#define BIT_GET_WLRF1_CTRL(x) \ + (((x) >> BIT_SHIFT_WLRF1_CTRL) & BIT_MASK_WLRF1_CTRL) + +/* 2 REG_SYS_CFG1 (Offset 0x00F0) */ + +#define BIT_SHIFT_TRP_ICFG 28 +#define BIT_MASK_TRP_ICFG 0xf +#define BIT_TRP_ICFG(x) (((x) & BIT_MASK_TRP_ICFG) << BIT_SHIFT_TRP_ICFG) +#define BIT_GET_TRP_ICFG(x) (((x) >> BIT_SHIFT_TRP_ICFG) & BIT_MASK_TRP_ICFG) + +/* 2 REG_SYS_CFG1 (Offset 0x00F0) */ + +#define BIT_RF_TYPE_ID BIT(27) +#define BIT_BD_HCI_SEL BIT(26) + +/* 2 REG_SYS_CFG1 (Offset 0x00F0) */ + +#define BIT_BD_PKG_SEL BIT(25) + +/* 2 REG_SYS_CFG1 (Offset 0x00F0) */ + +#define BIT_SPSLDO_SEL BIT(24) + +/* 2 REG_SYS_CFG1 (Offset 0x00F0) */ + +#define BIT_RTL_ID BIT(23) +#define BIT_PAD_HWPD_IDN BIT(22) + +/* 2 REG_SYS_CFG1 (Offset 0x00F0) */ + +#define BIT_TESTMODE BIT(20) + +/* 2 REG_SYS_CFG1 (Offset 0x00F0) */ + +#define BIT_SHIFT_VENDOR_ID 16 +#define BIT_MASK_VENDOR_ID 0xf +#define BIT_VENDOR_ID(x) (((x) & BIT_MASK_VENDOR_ID) << BIT_SHIFT_VENDOR_ID) +#define BIT_GET_VENDOR_ID(x) (((x) >> BIT_SHIFT_VENDOR_ID) & BIT_MASK_VENDOR_ID) + +/* 2 REG_SYS_CFG1 (Offset 0x00F0) */ + +#define BIT_SHIFT_CHIP_VER 12 +#define BIT_MASK_CHIP_VER 0xf +#define BIT_CHIP_VER(x) (((x) & BIT_MASK_CHIP_VER) << BIT_SHIFT_CHIP_VER) +#define BIT_GET_CHIP_VER(x) (((x) >> BIT_SHIFT_CHIP_VER) & BIT_MASK_CHIP_VER) + +/* 2 REG_SYS_CFG1 (Offset 0x00F0) */ + +#define BIT_BD_MAC3 BIT(11) + +/* 2 REG_SYS_CFG1 (Offset 0x00F0) */ + +#define BIT_BD_MAC1 BIT(10) +#define BIT_BD_MAC2 BIT(9) +#define BIT_SIC_IDLE BIT(8) +#define BIT_SW_OFFLOAD_EN BIT(7) + +/* 2 REG_SYS_CFG1 (Offset 0x00F0) */ + +#define BIT_OCP_SHUTDN BIT(6) + +/* 2 REG_SYS_CFG1 (Offset 0x00F0) */ + +#define BIT_V15_VLD BIT(5) + +/* 2 REG_SYS_CFG1 (Offset 0x00F0) */ + +#define BIT_PCIRSTB BIT(4) + +/* 2 REG_SYS_CFG1 (Offset 0x00F0) */ + +#define BIT_PCLK_VLD BIT(3) + +/* 2 REG_SYS_CFG1 (Offset 0x00F0) */ + +#define BIT_UCLK_VLD BIT(2) + +/* 2 REG_SYS_CFG1 (Offset 0x00F0) */ + +#define BIT_ACLK_VLD BIT(1) + +/* 2 REG_SYS_CFG1 (Offset 0x00F0) */ + +#define BIT_XCLK_VLD BIT(0) + +/* 2 REG_SYS_STATUS1 (Offset 0x00F4) */ + +#define BIT_SHIFT_RF_RL_ID 28 +#define BIT_MASK_RF_RL_ID 0xf +#define BIT_RF_RL_ID(x) (((x) & BIT_MASK_RF_RL_ID) << BIT_SHIFT_RF_RL_ID) +#define BIT_GET_RF_RL_ID(x) (((x) >> BIT_SHIFT_RF_RL_ID) & BIT_MASK_RF_RL_ID) + +/* 2 REG_SYS_STATUS1 (Offset 0x00F4) */ + +#define BIT_HPHY_ICFG BIT(19) + +/* 2 REG_SYS_STATUS1 (Offset 0x00F4) */ + +#define BIT_SHIFT_SEL_0XC0 16 +#define BIT_MASK_SEL_0XC0 0x3 +#define BIT_SEL_0XC0(x) (((x) & BIT_MASK_SEL_0XC0) << BIT_SHIFT_SEL_0XC0) +#define BIT_GET_SEL_0XC0(x) (((x) >> BIT_SHIFT_SEL_0XC0) & BIT_MASK_SEL_0XC0) + +/* 2 REG_SYS_STATUS1 (Offset 0x00F4) */ + +#define BIT_SHIFT_HCI_SEL_V3 12 +#define BIT_MASK_HCI_SEL_V3 0x7 +#define BIT_HCI_SEL_V3(x) (((x) & BIT_MASK_HCI_SEL_V3) << BIT_SHIFT_HCI_SEL_V3) +#define BIT_GET_HCI_SEL_V3(x) \ + (((x) >> BIT_SHIFT_HCI_SEL_V3) & BIT_MASK_HCI_SEL_V3) + +/* 2 REG_SYS_STATUS1 (Offset 0x00F4) */ + +#define BIT_USB_OPERATION_MODE BIT(10) +#define BIT_BT_PDN BIT(9) +#define BIT_AUTO_WLPON BIT(8) + +/* 2 REG_SYS_STATUS1 (Offset 0x00F4) */ + +#define BIT_WL_MODE BIT(7) + +/* 2 REG_SYS_STATUS1 (Offset 0x00F4) */ + +#define BIT_PKG_SEL_HCI BIT(6) + +/* 2 REG_SYS_STATUS1 (Offset 0x00F4) */ + +#define BIT_SHIFT_PAD_HCI_SEL_V1 3 +#define BIT_MASK_PAD_HCI_SEL_V1 0x7 +#define BIT_PAD_HCI_SEL_V1(x) \ + (((x) & BIT_MASK_PAD_HCI_SEL_V1) << BIT_SHIFT_PAD_HCI_SEL_V1) +#define BIT_GET_PAD_HCI_SEL_V1(x) \ + (((x) >> BIT_SHIFT_PAD_HCI_SEL_V1) & BIT_MASK_PAD_HCI_SEL_V1) + +/* 2 REG_SYS_STATUS1 (Offset 0x00F4) */ + +#define BIT_SHIFT_EFS_HCI_SEL_V1 0 +#define BIT_MASK_EFS_HCI_SEL_V1 0x7 +#define BIT_EFS_HCI_SEL_V1(x) \ + (((x) & BIT_MASK_EFS_HCI_SEL_V1) << BIT_SHIFT_EFS_HCI_SEL_V1) +#define BIT_GET_EFS_HCI_SEL_V1(x) \ + (((x) >> BIT_SHIFT_EFS_HCI_SEL_V1) & BIT_MASK_EFS_HCI_SEL_V1) + +/* 2 REG_SYS_STATUS2 (Offset 0x00F8) */ + +#define BIT_SIO_ALDN BIT(19) +#define BIT_USB_ALDN BIT(18) +#define BIT_PCI_ALDN BIT(17) +#define BIT_SYS_ALDN BIT(16) + +#define BIT_SHIFT_EPVID1 8 +#define BIT_MASK_EPVID1 0xff +#define BIT_EPVID1(x) (((x) & BIT_MASK_EPVID1) << BIT_SHIFT_EPVID1) +#define BIT_GET_EPVID1(x) (((x) >> BIT_SHIFT_EPVID1) & BIT_MASK_EPVID1) + +#define BIT_SHIFT_EPVID0 0 +#define BIT_MASK_EPVID0 0xff +#define BIT_EPVID0(x) (((x) & BIT_MASK_EPVID0) << BIT_SHIFT_EPVID0) +#define BIT_GET_EPVID0(x) (((x) >> BIT_SHIFT_EPVID0) & BIT_MASK_EPVID0) + +/* 2 REG_SYS_CFG2 (Offset 0x00FC) */ + +#define BIT_HCI_SEL_EMBEDDED BIT(8) + +/* 2 REG_SYS_CFG2 (Offset 0x00FC) */ + +#define BIT_SHIFT_HW_ID 0 +#define BIT_MASK_HW_ID 0xff +#define BIT_HW_ID(x) (((x) & BIT_MASK_HW_ID) << BIT_SHIFT_HW_ID) +#define BIT_GET_HW_ID(x) (((x) >> BIT_SHIFT_HW_ID) & BIT_MASK_HW_ID) + +/* 2 REG_CR (Offset 0x0100) */ + +#define BIT_SHIFT_LBMODE 24 +#define BIT_MASK_LBMODE 0x1f +#define BIT_LBMODE(x) (((x) & BIT_MASK_LBMODE) << BIT_SHIFT_LBMODE) +#define BIT_GET_LBMODE(x) (((x) >> BIT_SHIFT_LBMODE) & BIT_MASK_LBMODE) + +#define BIT_SHIFT_NETYPE1 18 +#define BIT_MASK_NETYPE1 0x3 +#define BIT_NETYPE1(x) (((x) & BIT_MASK_NETYPE1) << BIT_SHIFT_NETYPE1) +#define BIT_GET_NETYPE1(x) (((x) >> BIT_SHIFT_NETYPE1) & BIT_MASK_NETYPE1) + +#define BIT_SHIFT_NETYPE0 16 +#define BIT_MASK_NETYPE0 0x3 +#define BIT_NETYPE0(x) (((x) & BIT_MASK_NETYPE0) << BIT_SHIFT_NETYPE0) +#define BIT_GET_NETYPE0(x) (((x) >> BIT_SHIFT_NETYPE0) & BIT_MASK_NETYPE0) + +/* 2 REG_CR (Offset 0x0100) */ + +#define BIT_I2C_MAILBOX_EN BIT(12) +#define BIT_SHCUT_EN BIT(11) + +/* 2 REG_CR (Offset 0x0100) */ + +#define BIT_32K_CAL_TMR_EN BIT(10) +#define BIT_MAC_SEC_EN BIT(9) +#define BIT_ENSWBCN BIT(8) +#define BIT_MACRXEN BIT(7) +#define BIT_MACTXEN BIT(6) +#define BIT_SCHEDULE_EN BIT(5) +#define BIT_PROTOCOL_EN BIT(4) +#define BIT_RXDMA_EN BIT(3) +#define BIT_TXDMA_EN BIT(2) +#define BIT_HCI_RXDMA_EN BIT(1) +#define BIT_HCI_TXDMA_EN BIT(0) + +/* 2 REG_PKT_BUFF_ACCESS_CTRL (Offset 0x0106) */ + +#define BIT_SHIFT_PKT_BUFF_ACCESS_CTRL 0 +#define BIT_MASK_PKT_BUFF_ACCESS_CTRL 0xff +#define BIT_PKT_BUFF_ACCESS_CTRL(x) \ + (((x) & BIT_MASK_PKT_BUFF_ACCESS_CTRL) \ + << BIT_SHIFT_PKT_BUFF_ACCESS_CTRL) +#define BIT_GET_PKT_BUFF_ACCESS_CTRL(x) \ + (((x) >> BIT_SHIFT_PKT_BUFF_ACCESS_CTRL) & \ + BIT_MASK_PKT_BUFF_ACCESS_CTRL) + +/* 2 REG_TSF_CLK_STATE (Offset 0x0108) */ + +#define BIT_TSF_CLK_STABLE BIT(15) + +#define BIT_SHIFT_I2C_M_BUS_GNT_FW 4 +#define BIT_MASK_I2C_M_BUS_GNT_FW 0x7 +#define BIT_I2C_M_BUS_GNT_FW(x) \ + (((x) & BIT_MASK_I2C_M_BUS_GNT_FW) << BIT_SHIFT_I2C_M_BUS_GNT_FW) +#define BIT_GET_I2C_M_BUS_GNT_FW(x) \ + (((x) >> BIT_SHIFT_I2C_M_BUS_GNT_FW) & BIT_MASK_I2C_M_BUS_GNT_FW) + +#define BIT_I2C_M_GNT_FW BIT(3) + +#define BIT_SHIFT_I2C_M_SPEED 1 +#define BIT_MASK_I2C_M_SPEED 0x3 +#define BIT_I2C_M_SPEED(x) \ + (((x) & BIT_MASK_I2C_M_SPEED) << BIT_SHIFT_I2C_M_SPEED) +#define BIT_GET_I2C_M_SPEED(x) \ + (((x) >> BIT_SHIFT_I2C_M_SPEED) & BIT_MASK_I2C_M_SPEED) + +#define BIT_I2C_M_UNLOCK BIT(0) + +/* 2 REG_TXDMA_PQ_MAP (Offset 0x010C) */ + +#define BIT_SHIFT_TXDMA_HIQ_MAP 14 +#define BIT_MASK_TXDMA_HIQ_MAP 0x3 +#define BIT_TXDMA_HIQ_MAP(x) \ + (((x) & BIT_MASK_TXDMA_HIQ_MAP) << BIT_SHIFT_TXDMA_HIQ_MAP) +#define BIT_GET_TXDMA_HIQ_MAP(x) \ + (((x) >> BIT_SHIFT_TXDMA_HIQ_MAP) & BIT_MASK_TXDMA_HIQ_MAP) + +#define BIT_SHIFT_TXDMA_MGQ_MAP 12 +#define BIT_MASK_TXDMA_MGQ_MAP 0x3 +#define BIT_TXDMA_MGQ_MAP(x) \ + (((x) & BIT_MASK_TXDMA_MGQ_MAP) << BIT_SHIFT_TXDMA_MGQ_MAP) +#define BIT_GET_TXDMA_MGQ_MAP(x) \ + (((x) >> BIT_SHIFT_TXDMA_MGQ_MAP) & BIT_MASK_TXDMA_MGQ_MAP) + +#define BIT_SHIFT_TXDMA_BKQ_MAP 10 +#define BIT_MASK_TXDMA_BKQ_MAP 0x3 +#define BIT_TXDMA_BKQ_MAP(x) \ + (((x) & BIT_MASK_TXDMA_BKQ_MAP) << BIT_SHIFT_TXDMA_BKQ_MAP) +#define BIT_GET_TXDMA_BKQ_MAP(x) \ + (((x) >> BIT_SHIFT_TXDMA_BKQ_MAP) & BIT_MASK_TXDMA_BKQ_MAP) + +#define BIT_SHIFT_TXDMA_BEQ_MAP 8 +#define BIT_MASK_TXDMA_BEQ_MAP 0x3 +#define BIT_TXDMA_BEQ_MAP(x) \ + (((x) & BIT_MASK_TXDMA_BEQ_MAP) << BIT_SHIFT_TXDMA_BEQ_MAP) +#define BIT_GET_TXDMA_BEQ_MAP(x) \ + (((x) >> BIT_SHIFT_TXDMA_BEQ_MAP) & BIT_MASK_TXDMA_BEQ_MAP) + +#define BIT_SHIFT_TXDMA_VIQ_MAP 6 +#define BIT_MASK_TXDMA_VIQ_MAP 0x3 +#define BIT_TXDMA_VIQ_MAP(x) \ + (((x) & BIT_MASK_TXDMA_VIQ_MAP) << BIT_SHIFT_TXDMA_VIQ_MAP) +#define BIT_GET_TXDMA_VIQ_MAP(x) \ + (((x) >> BIT_SHIFT_TXDMA_VIQ_MAP) & BIT_MASK_TXDMA_VIQ_MAP) + +#define BIT_SHIFT_TXDMA_VOQ_MAP 4 +#define BIT_MASK_TXDMA_VOQ_MAP 0x3 +#define BIT_TXDMA_VOQ_MAP(x) \ + (((x) & BIT_MASK_TXDMA_VOQ_MAP) << BIT_SHIFT_TXDMA_VOQ_MAP) +#define BIT_GET_TXDMA_VOQ_MAP(x) \ + (((x) >> BIT_SHIFT_TXDMA_VOQ_MAP) & BIT_MASK_TXDMA_VOQ_MAP) + +#define BIT_RXDMA_AGG_EN BIT(2) +#define BIT_RXSHFT_EN BIT(1) +#define BIT_RXDMA_ARBBW_EN BIT(0) + +/* 2 REG_TRXFF_BNDY (Offset 0x0114) */ + +#define BIT_SHIFT_RXFFOVFL_RSV_V2 8 +#define BIT_MASK_RXFFOVFL_RSV_V2 0xf +#define BIT_RXFFOVFL_RSV_V2(x) \ + (((x) & BIT_MASK_RXFFOVFL_RSV_V2) << BIT_SHIFT_RXFFOVFL_RSV_V2) +#define BIT_GET_RXFFOVFL_RSV_V2(x) \ + (((x) >> BIT_SHIFT_RXFFOVFL_RSV_V2) & BIT_MASK_RXFFOVFL_RSV_V2) + +/* 2 REG_TRXFF_BNDY (Offset 0x0114) */ + +#define BIT_SHIFT_TXPKTBUF_PGBNDY 0 +#define BIT_MASK_TXPKTBUF_PGBNDY 0xff +#define BIT_TXPKTBUF_PGBNDY(x) \ + (((x) & BIT_MASK_TXPKTBUF_PGBNDY) << BIT_SHIFT_TXPKTBUF_PGBNDY) +#define BIT_GET_TXPKTBUF_PGBNDY(x) \ + (((x) >> BIT_SHIFT_TXPKTBUF_PGBNDY) & BIT_MASK_TXPKTBUF_PGBNDY) + +/* 2 REG_TRXFF_BNDY (Offset 0x0114) */ + +#define BIT_SHIFT_RXFF0_BNDY_V2 0 +#define BIT_MASK_RXFF0_BNDY_V2 0x3ffff +#define BIT_RXFF0_BNDY_V2(x) \ + (((x) & BIT_MASK_RXFF0_BNDY_V2) << BIT_SHIFT_RXFF0_BNDY_V2) +#define BIT_GET_RXFF0_BNDY_V2(x) \ + (((x) >> BIT_SHIFT_RXFF0_BNDY_V2) & BIT_MASK_RXFF0_BNDY_V2) + +#define BIT_SHIFT_RXFF0_RDPTR_V2 0 +#define BIT_MASK_RXFF0_RDPTR_V2 0x3ffff +#define BIT_RXFF0_RDPTR_V2(x) \ + (((x) & BIT_MASK_RXFF0_RDPTR_V2) << BIT_SHIFT_RXFF0_RDPTR_V2) +#define BIT_GET_RXFF0_RDPTR_V2(x) \ + (((x) >> BIT_SHIFT_RXFF0_RDPTR_V2) & BIT_MASK_RXFF0_RDPTR_V2) + +#define BIT_SHIFT_RXFF0_WTPTR_V2 0 +#define BIT_MASK_RXFF0_WTPTR_V2 0x3ffff +#define BIT_RXFF0_WTPTR_V2(x) \ + (((x) & BIT_MASK_RXFF0_WTPTR_V2) << BIT_SHIFT_RXFF0_WTPTR_V2) +#define BIT_GET_RXFF0_WTPTR_V2(x) \ + (((x) >> BIT_SHIFT_RXFF0_WTPTR_V2) & BIT_MASK_RXFF0_WTPTR_V2) + +/* 2 REG_PTA_I2C_MBOX (Offset 0x0118) */ + +#define BIT_SHIFT_I2C_M_STATUS 8 +#define BIT_MASK_I2C_M_STATUS 0xf +#define BIT_I2C_M_STATUS(x) \ + (((x) & BIT_MASK_I2C_M_STATUS) << BIT_SHIFT_I2C_M_STATUS) +#define BIT_GET_I2C_M_STATUS(x) \ + (((x) >> BIT_SHIFT_I2C_M_STATUS) & BIT_MASK_I2C_M_STATUS) + +/* 2 REG_FE1IMR (Offset 0x0120) */ + +#define BIT_FS_RXDMA2_DONE_INT_EN BIT(28) +#define BIT_FS_RXDONE3_INT_EN BIT(27) +#define BIT_FS_RXDONE2_INT_EN BIT(26) +#define BIT_FS_RX_BCN_P4_INT_EN BIT(25) +#define BIT_FS_RX_BCN_P3_INT_EN BIT(24) +#define BIT_FS_RX_BCN_P2_INT_EN BIT(23) +#define BIT_FS_RX_BCN_P1_INT_EN BIT(22) +#define BIT_FS_RX_BCN_P0_INT_EN BIT(21) +#define BIT_FS_RX_UMD0_INT_EN BIT(20) +#define BIT_FS_RX_UMD1_INT_EN BIT(19) +#define BIT_FS_RX_BMD0_INT_EN BIT(18) +#define BIT_FS_RX_BMD1_INT_EN BIT(17) +#define BIT_FS_RXDONE_INT_EN BIT(16) +#define BIT_FS_WWLAN_INT_EN BIT(15) +#define BIT_FS_SOUND_DONE_INT_EN BIT(14) +#define BIT_FS_LP_STBY_INT_EN BIT(13) +#define BIT_FS_TRL_MTR_INT_EN BIT(12) +#define BIT_FS_BF1_PRETO_INT_EN BIT(11) +#define BIT_FS_BF0_PRETO_INT_EN BIT(10) +#define BIT_FS_PTCL_RELEASE_MACID_INT_EN BIT(9) + +/* 2 REG_FE1IMR (Offset 0x0120) */ + +#define BIT_FS_LTE_COEX_EN BIT(6) + +/* 2 REG_FE1IMR (Offset 0x0120) */ + +#define BIT_FS_WLACTOFF_INT_EN BIT(5) +#define BIT_FS_WLACTON_INT_EN BIT(4) +#define BIT_FS_BTCMD_INT_EN BIT(3) + +/* 2 REG_FE1IMR (Offset 0x0120) */ + +#define BIT_FS_REG_MAILBOX_TO_I2C_INT_EN BIT(2) + +/* 2 REG_FE1IMR (Offset 0x0120) */ + +#define BIT_FS_TRPC_TO_INT_EN_V1 BIT(1) + +/* 2 REG_FE1IMR (Offset 0x0120) */ + +#define BIT_FS_RPC_O_T_INT_EN_V1 BIT(0) + +/* 2 REG_FE1ISR (Offset 0x0124) */ + +#define BIT_FS_RXDMA2_DONE_INT BIT(28) +#define BIT_FS_RXDONE3_INT BIT(27) +#define BIT_FS_RXDONE2_INT BIT(26) +#define BIT_FS_RX_BCN_P4_INT BIT(25) +#define BIT_FS_RX_BCN_P3_INT BIT(24) +#define BIT_FS_RX_BCN_P2_INT BIT(23) +#define BIT_FS_RX_BCN_P1_INT BIT(22) +#define BIT_FS_RX_BCN_P0_INT BIT(21) +#define BIT_FS_RX_UMD0_INT BIT(20) +#define BIT_FS_RX_UMD1_INT BIT(19) +#define BIT_FS_RX_BMD0_INT BIT(18) +#define BIT_FS_RX_BMD1_INT BIT(17) +#define BIT_FS_RXDONE_INT BIT(16) +#define BIT_FS_WWLAN_INT BIT(15) +#define BIT_FS_SOUND_DONE_INT BIT(14) +#define BIT_FS_LP_STBY_INT BIT(13) +#define BIT_FS_TRL_MTR_INT BIT(12) +#define BIT_FS_BF1_PRETO_INT BIT(11) +#define BIT_FS_BF0_PRETO_INT BIT(10) +#define BIT_FS_PTCL_RELEASE_MACID_INT BIT(9) + +/* 2 REG_FE1ISR (Offset 0x0124) */ + +#define BIT_FS_LTE_COEX_INT BIT(6) + +/* 2 REG_FE1ISR (Offset 0x0124) */ + +#define BIT_FS_WLACTOFF_INT BIT(5) +#define BIT_FS_WLACTON_INT BIT(4) +#define BIT_FS_BCN_RX_INT_INT BIT(3) + +/* 2 REG_FE1ISR (Offset 0x0124) */ + +#define BIT_FS_MAILBOX_TO_I2C_INT BIT(2) + +/* 2 REG_FE1ISR (Offset 0x0124) */ + +#define BIT_FS_TRPC_TO_INT BIT(1) + +/* 2 REG_FE1ISR (Offset 0x0124) */ + +#define BIT_FS_RPC_O_T_INT BIT(0) + +/* 2 REG_CPWM (Offset 0x012C) */ + +#define BIT_CPWM_TOGGLING BIT(31) + +#define BIT_SHIFT_CPWM_MOD 24 +#define BIT_MASK_CPWM_MOD 0x7f +#define BIT_CPWM_MOD(x) (((x) & BIT_MASK_CPWM_MOD) << BIT_SHIFT_CPWM_MOD) +#define BIT_GET_CPWM_MOD(x) (((x) >> BIT_SHIFT_CPWM_MOD) & BIT_MASK_CPWM_MOD) + +/* 2 REG_FWIMR (Offset 0x0130) */ + +#define BIT_FS_TXBCNOK_MB7_INT_EN BIT(31) + +/* 2 REG_FWIMR (Offset 0x0130) */ + +#define BIT_FS_TXBCNOK_MB6_INT_EN BIT(30) + +/* 2 REG_FWIMR (Offset 0x0130) */ + +#define BIT_FS_TXBCNOK_MB5_INT_EN BIT(29) + +/* 2 REG_FWIMR (Offset 0x0130) */ + +#define BIT_FS_TXBCNOK_MB4_INT_EN BIT(28) + +/* 2 REG_FWIMR (Offset 0x0130) */ + +#define BIT_FS_TXBCNOK_MB3_INT_EN BIT(27) + +/* 2 REG_FWIMR (Offset 0x0130) */ + +#define BIT_FS_TXBCNOK_MB2_INT_EN BIT(26) + +/* 2 REG_FWIMR (Offset 0x0130) */ + +#define BIT_FS_TXBCNOK_MB1_INT_EN BIT(25) + +/* 2 REG_FWIMR (Offset 0x0130) */ + +#define BIT_FS_TXBCNOK_MB0_INT_EN BIT(24) + +/* 2 REG_FWIMR (Offset 0x0130) */ + +#define BIT_FS_TXBCNERR_MB7_INT_EN BIT(23) + +/* 2 REG_FWIMR (Offset 0x0130) */ + +#define BIT_FS_TXBCNERR_MB6_INT_EN BIT(22) + +/* 2 REG_FWIMR (Offset 0x0130) */ + +#define BIT_FS_TXBCNERR_MB5_INT_EN BIT(21) + +/* 2 REG_FWIMR (Offset 0x0130) */ + +#define BIT_FS_TXBCNERR_MB4_INT_EN BIT(20) + +/* 2 REG_FWIMR (Offset 0x0130) */ + +#define BIT_FS_TXBCNERR_MB3_INT_EN BIT(19) + +/* 2 REG_FWIMR (Offset 0x0130) */ + +#define BIT_FS_TXBCNERR_MB2_INT_EN BIT(18) + +/* 2 REG_FWIMR (Offset 0x0130) */ + +#define BIT_FS_TXBCNERR_MB1_INT_EN BIT(17) + +/* 2 REG_FWIMR (Offset 0x0130) */ + +#define BIT_FS_TXBCNERR_MB0_INT_EN BIT(16) + +/* 2 REG_FWIMR (Offset 0x0130) */ + +#define BIT_CPU_MGQ_TXDONE_INT_EN BIT(15) + +/* 2 REG_FWIMR (Offset 0x0130) */ + +#define BIT_SIFS_OVERSPEC_INT_EN BIT(14) + +/* 2 REG_FWIMR (Offset 0x0130) */ + +#define BIT_FS_MGNTQ_RPTR_RELEASE_INT_EN BIT(13) + +/* 2 REG_FWIMR (Offset 0x0130) */ + +#define BIT_FS_MGNTQFF_TO_INT_EN BIT(12) + +/* 2 REG_FWIMR (Offset 0x0130) */ + +#define BIT_FS_DDMA1_LP_INT_EN BIT(11) + +/* 2 REG_FWIMR (Offset 0x0130) */ + +#define BIT_FS_DDMA1_HP_INT_EN BIT(10) + +/* 2 REG_FWIMR (Offset 0x0130) */ + +#define BIT_FS_DDMA0_LP_INT_EN BIT(9) + +/* 2 REG_FWIMR (Offset 0x0130) */ + +#define BIT_FS_DDMA0_HP_INT_EN BIT(8) + +/* 2 REG_FWIMR (Offset 0x0130) */ + +#define BIT_FS_TRXRPT_INT_EN BIT(7) + +/* 2 REG_FWIMR (Offset 0x0130) */ + +#define BIT_FS_C2H_W_READY_INT_EN BIT(6) + +/* 2 REG_FWIMR (Offset 0x0130) */ + +#define BIT_FS_HRCV_INT_EN BIT(5) + +/* 2 REG_FWIMR (Offset 0x0130) */ + +#define BIT_FS_H2CCMD_INT_EN BIT(4) + +/* 2 REG_FWIMR (Offset 0x0130) */ + +#define BIT_FS_TXPKTIN_INT_EN BIT(3) + +/* 2 REG_FWIMR (Offset 0x0130) */ + +#define BIT_FS_ERRORHDL_INT_EN BIT(2) + +/* 2 REG_FWIMR (Offset 0x0130) */ + +#define BIT_FS_TXCCX_INT_EN BIT(1) + +/* 2 REG_FWIMR (Offset 0x0130) */ + +#define BIT_FS_TXCLOSE_INT_EN BIT(0) + +/* 2 REG_FWISR (Offset 0x0134) */ + +#define BIT_FS_TXBCNOK_MB7_INT BIT(31) + +/* 2 REG_FWISR (Offset 0x0134) */ + +#define BIT_FS_TXBCNOK_MB6_INT BIT(30) + +/* 2 REG_FWISR (Offset 0x0134) */ + +#define BIT_FS_TXBCNOK_MB5_INT BIT(29) + +/* 2 REG_FWISR (Offset 0x0134) */ + +#define BIT_FS_TXBCNOK_MB4_INT BIT(28) + +/* 2 REG_FWISR (Offset 0x0134) */ + +#define BIT_FS_TXBCNOK_MB3_INT BIT(27) + +/* 2 REG_FWISR (Offset 0x0134) */ + +#define BIT_FS_TXBCNOK_MB2_INT BIT(26) + +/* 2 REG_FWISR (Offset 0x0134) */ + +#define BIT_FS_TXBCNOK_MB1_INT BIT(25) + +/* 2 REG_FWISR (Offset 0x0134) */ + +#define BIT_FS_TXBCNOK_MB0_INT BIT(24) + +/* 2 REG_FWISR (Offset 0x0134) */ + +#define BIT_FS_TXBCNERR_MB7_INT BIT(23) + +/* 2 REG_FWISR (Offset 0x0134) */ + +#define BIT_FS_TXBCNERR_MB6_INT BIT(22) + +/* 2 REG_FWISR (Offset 0x0134) */ + +#define BIT_FS_TXBCNERR_MB5_INT BIT(21) + +/* 2 REG_FWISR (Offset 0x0134) */ + +#define BIT_FS_TXBCNERR_MB4_INT BIT(20) + +/* 2 REG_FWISR (Offset 0x0134) */ + +#define BIT_FS_TXBCNERR_MB3_INT BIT(19) + +/* 2 REG_FWISR (Offset 0x0134) */ + +#define BIT_FS_TXBCNERR_MB2_INT BIT(18) + +/* 2 REG_FWISR (Offset 0x0134) */ + +#define BIT_FS_TXBCNERR_MB1_INT BIT(17) + +/* 2 REG_FWISR (Offset 0x0134) */ + +#define BIT_FS_TXBCNERR_MB0_INT BIT(16) + +/* 2 REG_FWISR (Offset 0x0134) */ + +#define BIT_CPU_MGQ_TXDONE_INT BIT(15) + +/* 2 REG_FWISR (Offset 0x0134) */ + +#define BIT_SIFS_OVERSPEC_INT BIT(14) + +/* 2 REG_FWISR (Offset 0x0134) */ + +#define BIT_FS_MGNTQ_RPTR_RELEASE_INT BIT(13) + +/* 2 REG_FWISR (Offset 0x0134) */ + +#define BIT_FS_MGNTQFF_TO_INT BIT(12) + +/* 2 REG_FWISR (Offset 0x0134) */ + +#define BIT_FS_DDMA1_LP_INT BIT(11) + +/* 2 REG_FWISR (Offset 0x0134) */ + +#define BIT_FS_DDMA1_HP_INT BIT(10) + +/* 2 REG_FWISR (Offset 0x0134) */ + +#define BIT_FS_DDMA0_LP_INT BIT(9) + +/* 2 REG_FWISR (Offset 0x0134) */ + +#define BIT_FS_DDMA0_HP_INT BIT(8) + +/* 2 REG_FWISR (Offset 0x0134) */ + +#define BIT_FS_TRXRPT_INT BIT(7) + +/* 2 REG_FWISR (Offset 0x0134) */ + +#define BIT_FS_C2H_W_READY_INT BIT(6) + +/* 2 REG_FWISR (Offset 0x0134) */ + +#define BIT_FS_HRCV_INT BIT(5) + +/* 2 REG_FWISR (Offset 0x0134) */ + +#define BIT_FS_H2CCMD_INT BIT(4) + +/* 2 REG_FWISR (Offset 0x0134) */ + +#define BIT_FS_TXPKTIN_INT BIT(3) + +/* 2 REG_FWISR (Offset 0x0134) */ + +#define BIT_FS_ERRORHDL_INT BIT(2) + +/* 2 REG_FWISR (Offset 0x0134) */ + +#define BIT_FS_TXCCX_INT BIT(1) + +/* 2 REG_FWISR (Offset 0x0134) */ + +#define BIT_FS_TXCLOSE_INT BIT(0) + +/* 2 REG_FTIMR (Offset 0x0138) */ + +#define BIT_PS_TIMER_C_EARLY_INT_EN BIT(23) + +/* 2 REG_FTIMR (Offset 0x0138) */ + +#define BIT_PS_TIMER_B_EARLY_INT_EN BIT(22) + +/* 2 REG_FTIMR (Offset 0x0138) */ + +#define BIT_PS_TIMER_A_EARLY_INT_EN BIT(21) + +/* 2 REG_FTIMR (Offset 0x0138) */ + +#define BIT_CPUMGQ_TX_TIMER_EARLY_INT_EN BIT(20) + +/* 2 REG_FTIMR (Offset 0x0138) */ + +#define BIT_PS_TIMER_C_INT_EN BIT(19) + +/* 2 REG_FTIMR (Offset 0x0138) */ + +#define BIT_PS_TIMER_B_INT_EN BIT(18) + +/* 2 REG_FTIMR (Offset 0x0138) */ + +#define BIT_PS_TIMER_A_INT_EN BIT(17) + +/* 2 REG_FTIMR (Offset 0x0138) */ + +#define BIT_CPUMGQ_TX_TIMER_INT_EN BIT(16) + +/* 2 REG_FTIMR (Offset 0x0138) */ + +#define BIT_FS_PS_TIMEOUT2_EN BIT(15) + +/* 2 REG_FTIMR (Offset 0x0138) */ + +#define BIT_FS_PS_TIMEOUT1_EN BIT(14) + +/* 2 REG_FTIMR (Offset 0x0138) */ + +#define BIT_FS_PS_TIMEOUT0_EN BIT(13) + +/* 2 REG_FTIMR (Offset 0x0138) */ + +#define BIT_FS_GTINT8_EN BIT(8) + +/* 2 REG_FTIMR (Offset 0x0138) */ + +#define BIT_FS_GTINT7_EN BIT(7) + +/* 2 REG_FTIMR (Offset 0x0138) */ + +#define BIT_FS_GTINT6_EN BIT(6) + +/* 2 REG_FTIMR (Offset 0x0138) */ + +#define BIT_FS_GTINT5_EN BIT(5) + +/* 2 REG_FTIMR (Offset 0x0138) */ + +#define BIT_FS_GTINT4_EN BIT(4) + +/* 2 REG_FTIMR (Offset 0x0138) */ + +#define BIT_FS_GTINT3_EN BIT(3) + +/* 2 REG_FTIMR (Offset 0x0138) */ + +#define BIT_FS_GTINT2_EN BIT(2) + +/* 2 REG_FTIMR (Offset 0x0138) */ + +#define BIT_FS_GTINT1_EN BIT(1) + +/* 2 REG_FTIMR (Offset 0x0138) */ + +#define BIT_FS_GTINT0_EN BIT(0) + +/* 2 REG_FTISR (Offset 0x013C) */ + +#define BIT_PS_TIMER_C_EARLY__INT BIT(23) + +/* 2 REG_FTISR (Offset 0x013C) */ + +#define BIT_PS_TIMER_B_EARLY__INT BIT(22) + +/* 2 REG_FTISR (Offset 0x013C) */ + +#define BIT_PS_TIMER_A_EARLY__INT BIT(21) + +/* 2 REG_FTISR (Offset 0x013C) */ + +#define BIT_CPUMGQ_TX_TIMER_EARLY_INT BIT(20) + +/* 2 REG_FTISR (Offset 0x013C) */ + +#define BIT_PS_TIMER_C_INT BIT(19) + +/* 2 REG_FTISR (Offset 0x013C) */ + +#define BIT_PS_TIMER_B_INT BIT(18) + +/* 2 REG_FTISR (Offset 0x013C) */ + +#define BIT_PS_TIMER_A_INT BIT(17) + +/* 2 REG_FTISR (Offset 0x013C) */ + +#define BIT_CPUMGQ_TX_TIMER_INT BIT(16) + +/* 2 REG_FTISR (Offset 0x013C) */ + +#define BIT_FS_PS_TIMEOUT2_INT BIT(15) + +/* 2 REG_FTISR (Offset 0x013C) */ + +#define BIT_FS_PS_TIMEOUT1_INT BIT(14) + +/* 2 REG_FTISR (Offset 0x013C) */ + +#define BIT_FS_PS_TIMEOUT0_INT BIT(13) + +/* 2 REG_FTISR (Offset 0x013C) */ + +#define BIT_FS_GTINT8_INT BIT(8) + +/* 2 REG_FTISR (Offset 0x013C) */ + +#define BIT_FS_GTINT7_INT BIT(7) + +/* 2 REG_FTISR (Offset 0x013C) */ + +#define BIT_FS_GTINT6_INT BIT(6) + +/* 2 REG_FTISR (Offset 0x013C) */ + +#define BIT_FS_GTINT5_INT BIT(5) + +/* 2 REG_FTISR (Offset 0x013C) */ + +#define BIT_FS_GTINT4_INT BIT(4) + +/* 2 REG_FTISR (Offset 0x013C) */ + +#define BIT_FS_GTINT3_INT BIT(3) + +/* 2 REG_FTISR (Offset 0x013C) */ + +#define BIT_FS_GTINT2_INT BIT(2) + +/* 2 REG_FTISR (Offset 0x013C) */ + +#define BIT_FS_GTINT1_INT BIT(1) + +/* 2 REG_FTISR (Offset 0x013C) */ + +#define BIT_FS_GTINT0_INT BIT(0) + +/* 2 REG_PKTBUF_DBG_CTRL (Offset 0x0140) */ + +#define BIT_SHIFT_PKTBUF_WRITE_EN 24 +#define BIT_MASK_PKTBUF_WRITE_EN 0xff +#define BIT_PKTBUF_WRITE_EN(x) \ + (((x) & BIT_MASK_PKTBUF_WRITE_EN) << BIT_SHIFT_PKTBUF_WRITE_EN) +#define BIT_GET_PKTBUF_WRITE_EN(x) \ + (((x) >> BIT_SHIFT_PKTBUF_WRITE_EN) & BIT_MASK_PKTBUF_WRITE_EN) + +/* 2 REG_PKTBUF_DBG_CTRL (Offset 0x0140) */ + +#define BIT_TXRPTBUF_DBG BIT(23) + +/* 2 REG_PKTBUF_DBG_CTRL (Offset 0x0140) */ + +#define BIT_TXPKTBUF_DBG_V2 BIT(20) + +/* 2 REG_PKTBUF_DBG_CTRL (Offset 0x0140) */ + +#define BIT_RXPKTBUF_DBG BIT(16) + +/* 2 REG_PKTBUF_DBG_CTRL (Offset 0x0140) */ + +#define BIT_SHIFT_PKTBUF_DBG_ADDR 0 +#define BIT_MASK_PKTBUF_DBG_ADDR 0x1fff +#define BIT_PKTBUF_DBG_ADDR(x) \ + (((x) & BIT_MASK_PKTBUF_DBG_ADDR) << BIT_SHIFT_PKTBUF_DBG_ADDR) +#define BIT_GET_PKTBUF_DBG_ADDR(x) \ + (((x) >> BIT_SHIFT_PKTBUF_DBG_ADDR) & BIT_MASK_PKTBUF_DBG_ADDR) + +/* 2 REG_PKTBUF_DBG_DATA_L (Offset 0x0144) */ + +#define BIT_SHIFT_PKTBUF_DBG_DATA_L 0 +#define BIT_MASK_PKTBUF_DBG_DATA_L 0xffffffffL +#define BIT_PKTBUF_DBG_DATA_L(x) \ + (((x) & BIT_MASK_PKTBUF_DBG_DATA_L) << BIT_SHIFT_PKTBUF_DBG_DATA_L) +#define BIT_GET_PKTBUF_DBG_DATA_L(x) \ + (((x) >> BIT_SHIFT_PKTBUF_DBG_DATA_L) & BIT_MASK_PKTBUF_DBG_DATA_L) + +/* 2 REG_PKTBUF_DBG_DATA_H (Offset 0x0148) */ + +#define BIT_SHIFT_PKTBUF_DBG_DATA_H 0 +#define BIT_MASK_PKTBUF_DBG_DATA_H 0xffffffffL +#define BIT_PKTBUF_DBG_DATA_H(x) \ + (((x) & BIT_MASK_PKTBUF_DBG_DATA_H) << BIT_SHIFT_PKTBUF_DBG_DATA_H) +#define BIT_GET_PKTBUF_DBG_DATA_H(x) \ + (((x) >> BIT_SHIFT_PKTBUF_DBG_DATA_H) & BIT_MASK_PKTBUF_DBG_DATA_H) + +/* 2 REG_CPWM2 (Offset 0x014C) */ + +#define BIT_SHIFT_L0S_TO_RCVY_NUM 16 +#define BIT_MASK_L0S_TO_RCVY_NUM 0xff +#define BIT_L0S_TO_RCVY_NUM(x) \ + (((x) & BIT_MASK_L0S_TO_RCVY_NUM) << BIT_SHIFT_L0S_TO_RCVY_NUM) +#define BIT_GET_L0S_TO_RCVY_NUM(x) \ + (((x) >> BIT_SHIFT_L0S_TO_RCVY_NUM) & BIT_MASK_L0S_TO_RCVY_NUM) + +#define BIT_CPWM2_TOGGLING BIT(15) + +#define BIT_SHIFT_CPWM2_MOD 0 +#define BIT_MASK_CPWM2_MOD 0x7fff +#define BIT_CPWM2_MOD(x) (((x) & BIT_MASK_CPWM2_MOD) << BIT_SHIFT_CPWM2_MOD) +#define BIT_GET_CPWM2_MOD(x) (((x) >> BIT_SHIFT_CPWM2_MOD) & BIT_MASK_CPWM2_MOD) + +/* 2 REG_TC0_CTRL (Offset 0x0150) */ + +#define BIT_TC0INT_EN BIT(26) +#define BIT_TC0MODE BIT(25) +#define BIT_TC0EN BIT(24) + +#define BIT_SHIFT_TC0DATA 0 +#define BIT_MASK_TC0DATA 0xffffff +#define BIT_TC0DATA(x) (((x) & BIT_MASK_TC0DATA) << BIT_SHIFT_TC0DATA) +#define BIT_GET_TC0DATA(x) (((x) >> BIT_SHIFT_TC0DATA) & BIT_MASK_TC0DATA) + +/* 2 REG_TC1_CTRL (Offset 0x0154) */ + +#define BIT_TC1INT_EN BIT(26) +#define BIT_TC1MODE BIT(25) +#define BIT_TC1EN BIT(24) + +#define BIT_SHIFT_TC1DATA 0 +#define BIT_MASK_TC1DATA 0xffffff +#define BIT_TC1DATA(x) (((x) & BIT_MASK_TC1DATA) << BIT_SHIFT_TC1DATA) +#define BIT_GET_TC1DATA(x) (((x) >> BIT_SHIFT_TC1DATA) & BIT_MASK_TC1DATA) + +/* 2 REG_TC2_CTRL (Offset 0x0158) */ + +#define BIT_TC2INT_EN BIT(26) +#define BIT_TC2MODE BIT(25) +#define BIT_TC2EN BIT(24) + +#define BIT_SHIFT_TC2DATA 0 +#define BIT_MASK_TC2DATA 0xffffff +#define BIT_TC2DATA(x) (((x) & BIT_MASK_TC2DATA) << BIT_SHIFT_TC2DATA) +#define BIT_GET_TC2DATA(x) (((x) >> BIT_SHIFT_TC2DATA) & BIT_MASK_TC2DATA) + +/* 2 REG_TC3_CTRL (Offset 0x015C) */ + +#define BIT_TC3INT_EN BIT(26) +#define BIT_TC3MODE BIT(25) +#define BIT_TC3EN BIT(24) + +#define BIT_SHIFT_TC3DATA 0 +#define BIT_MASK_TC3DATA 0xffffff +#define BIT_TC3DATA(x) (((x) & BIT_MASK_TC3DATA) << BIT_SHIFT_TC3DATA) +#define BIT_GET_TC3DATA(x) (((x) >> BIT_SHIFT_TC3DATA) & BIT_MASK_TC3DATA) + +/* 2 REG_TC4_CTRL (Offset 0x0160) */ + +#define BIT_TC4INT_EN BIT(26) +#define BIT_TC4MODE BIT(25) +#define BIT_TC4EN BIT(24) + +#define BIT_SHIFT_TC4DATA 0 +#define BIT_MASK_TC4DATA 0xffffff +#define BIT_TC4DATA(x) (((x) & BIT_MASK_TC4DATA) << BIT_SHIFT_TC4DATA) +#define BIT_GET_TC4DATA(x) (((x) >> BIT_SHIFT_TC4DATA) & BIT_MASK_TC4DATA) + +/* 2 REG_TCUNIT_BASE (Offset 0x0164) */ + +#define BIT_SHIFT_TCUNIT_BASE 0 +#define BIT_MASK_TCUNIT_BASE 0x3fff +#define BIT_TCUNIT_BASE(x) \ + (((x) & BIT_MASK_TCUNIT_BASE) << BIT_SHIFT_TCUNIT_BASE) +#define BIT_GET_TCUNIT_BASE(x) \ + (((x) >> BIT_SHIFT_TCUNIT_BASE) & BIT_MASK_TCUNIT_BASE) + +/* 2 REG_TC5_CTRL (Offset 0x0168) */ + +#define BIT_TC5INT_EN BIT(26) + +/* 2 REG_TC5_CTRL (Offset 0x0168) */ + +#define BIT_TC5MODE BIT(25) +#define BIT_TC5EN BIT(24) + +#define BIT_SHIFT_TC5DATA 0 +#define BIT_MASK_TC5DATA 0xffffff +#define BIT_TC5DATA(x) (((x) & BIT_MASK_TC5DATA) << BIT_SHIFT_TC5DATA) +#define BIT_GET_TC5DATA(x) (((x) >> BIT_SHIFT_TC5DATA) & BIT_MASK_TC5DATA) + +/* 2 REG_TC6_CTRL (Offset 0x016C) */ + +#define BIT_TC6INT_EN BIT(26) + +/* 2 REG_TC6_CTRL (Offset 0x016C) */ + +#define BIT_TC6MODE BIT(25) +#define BIT_TC6EN BIT(24) + +#define BIT_SHIFT_TC6DATA 0 +#define BIT_MASK_TC6DATA 0xffffff +#define BIT_TC6DATA(x) (((x) & BIT_MASK_TC6DATA) << BIT_SHIFT_TC6DATA) +#define BIT_GET_TC6DATA(x) (((x) >> BIT_SHIFT_TC6DATA) & BIT_MASK_TC6DATA) + +/* 2 REG_MBIST_FAIL (Offset 0x0170) */ + +#define BIT_SHIFT_8051_MBIST_FAIL 26 +#define BIT_MASK_8051_MBIST_FAIL 0x7 +#define BIT_8051_MBIST_FAIL(x) \ + (((x) & BIT_MASK_8051_MBIST_FAIL) << BIT_SHIFT_8051_MBIST_FAIL) +#define BIT_GET_8051_MBIST_FAIL(x) \ + (((x) >> BIT_SHIFT_8051_MBIST_FAIL) & BIT_MASK_8051_MBIST_FAIL) + +#define BIT_SHIFT_USB_MBIST_FAIL 24 +#define BIT_MASK_USB_MBIST_FAIL 0x3 +#define BIT_USB_MBIST_FAIL(x) \ + (((x) & BIT_MASK_USB_MBIST_FAIL) << BIT_SHIFT_USB_MBIST_FAIL) +#define BIT_GET_USB_MBIST_FAIL(x) \ + (((x) >> BIT_SHIFT_USB_MBIST_FAIL) & BIT_MASK_USB_MBIST_FAIL) + +#define BIT_SHIFT_PCIE_MBIST_FAIL 16 +#define BIT_MASK_PCIE_MBIST_FAIL 0x3f +#define BIT_PCIE_MBIST_FAIL(x) \ + (((x) & BIT_MASK_PCIE_MBIST_FAIL) << BIT_SHIFT_PCIE_MBIST_FAIL) +#define BIT_GET_PCIE_MBIST_FAIL(x) \ + (((x) >> BIT_SHIFT_PCIE_MBIST_FAIL) & BIT_MASK_PCIE_MBIST_FAIL) + +/* 2 REG_MBIST_FAIL (Offset 0x0170) */ + +#define BIT_SHIFT_MAC_MBIST_FAIL 0 +#define BIT_MASK_MAC_MBIST_FAIL 0xfff +#define BIT_MAC_MBIST_FAIL(x) \ + (((x) & BIT_MASK_MAC_MBIST_FAIL) << BIT_SHIFT_MAC_MBIST_FAIL) +#define BIT_GET_MAC_MBIST_FAIL(x) \ + (((x) >> BIT_SHIFT_MAC_MBIST_FAIL) & BIT_MASK_MAC_MBIST_FAIL) + +/* 2 REG_MBIST_START_PAUSE (Offset 0x0174) */ + +#define BIT_SHIFT_8051_MBIST_START_PAUSE 26 +#define BIT_MASK_8051_MBIST_START_PAUSE 0x7 +#define BIT_8051_MBIST_START_PAUSE(x) \ + (((x) & BIT_MASK_8051_MBIST_START_PAUSE) \ + << BIT_SHIFT_8051_MBIST_START_PAUSE) +#define BIT_GET_8051_MBIST_START_PAUSE(x) \ + (((x) >> BIT_SHIFT_8051_MBIST_START_PAUSE) & \ + BIT_MASK_8051_MBIST_START_PAUSE) + +#define BIT_SHIFT_USB_MBIST_START_PAUSE 24 +#define BIT_MASK_USB_MBIST_START_PAUSE 0x3 +#define BIT_USB_MBIST_START_PAUSE(x) \ + (((x) & BIT_MASK_USB_MBIST_START_PAUSE) \ + << BIT_SHIFT_USB_MBIST_START_PAUSE) +#define BIT_GET_USB_MBIST_START_PAUSE(x) \ + (((x) >> BIT_SHIFT_USB_MBIST_START_PAUSE) & \ + BIT_MASK_USB_MBIST_START_PAUSE) + +#define BIT_SHIFT_PCIE_MBIST_START_PAUSE 16 +#define BIT_MASK_PCIE_MBIST_START_PAUSE 0x3f +#define BIT_PCIE_MBIST_START_PAUSE(x) \ + (((x) & BIT_MASK_PCIE_MBIST_START_PAUSE) \ + << BIT_SHIFT_PCIE_MBIST_START_PAUSE) +#define BIT_GET_PCIE_MBIST_START_PAUSE(x) \ + (((x) >> BIT_SHIFT_PCIE_MBIST_START_PAUSE) & \ + BIT_MASK_PCIE_MBIST_START_PAUSE) + +/* 2 REG_MBIST_START_PAUSE (Offset 0x0174) */ + +#define BIT_SHIFT_MAC_MBIST_START_PAUSE 0 +#define BIT_MASK_MAC_MBIST_START_PAUSE 0xfff +#define BIT_MAC_MBIST_START_PAUSE(x) \ + (((x) & BIT_MASK_MAC_MBIST_START_PAUSE) \ + << BIT_SHIFT_MAC_MBIST_START_PAUSE) +#define BIT_GET_MAC_MBIST_START_PAUSE(x) \ + (((x) >> BIT_SHIFT_MAC_MBIST_START_PAUSE) & \ + BIT_MASK_MAC_MBIST_START_PAUSE) + +/* 2 REG_MBIST_DONE (Offset 0x0178) */ + +#define BIT_SHIFT_8051_MBIST_DONE 26 +#define BIT_MASK_8051_MBIST_DONE 0x7 +#define BIT_8051_MBIST_DONE(x) \ + (((x) & BIT_MASK_8051_MBIST_DONE) << BIT_SHIFT_8051_MBIST_DONE) +#define BIT_GET_8051_MBIST_DONE(x) \ + (((x) >> BIT_SHIFT_8051_MBIST_DONE) & BIT_MASK_8051_MBIST_DONE) + +#define BIT_SHIFT_USB_MBIST_DONE 24 +#define BIT_MASK_USB_MBIST_DONE 0x3 +#define BIT_USB_MBIST_DONE(x) \ + (((x) & BIT_MASK_USB_MBIST_DONE) << BIT_SHIFT_USB_MBIST_DONE) +#define BIT_GET_USB_MBIST_DONE(x) \ + (((x) >> BIT_SHIFT_USB_MBIST_DONE) & BIT_MASK_USB_MBIST_DONE) + +#define BIT_SHIFT_PCIE_MBIST_DONE 16 +#define BIT_MASK_PCIE_MBIST_DONE 0x3f +#define BIT_PCIE_MBIST_DONE(x) \ + (((x) & BIT_MASK_PCIE_MBIST_DONE) << BIT_SHIFT_PCIE_MBIST_DONE) +#define BIT_GET_PCIE_MBIST_DONE(x) \ + (((x) >> BIT_SHIFT_PCIE_MBIST_DONE) & BIT_MASK_PCIE_MBIST_DONE) + +/* 2 REG_MBIST_DONE (Offset 0x0178) */ + +#define BIT_SHIFT_MAC_MBIST_DONE 0 +#define BIT_MASK_MAC_MBIST_DONE 0xfff +#define BIT_MAC_MBIST_DONE(x) \ + (((x) & BIT_MASK_MAC_MBIST_DONE) << BIT_SHIFT_MAC_MBIST_DONE) +#define BIT_GET_MAC_MBIST_DONE(x) \ + (((x) >> BIT_SHIFT_MAC_MBIST_DONE) & BIT_MASK_MAC_MBIST_DONE) + +/* 2 REG_MBIST_FAIL_NRML (Offset 0x017C) */ + +#define BIT_SHIFT_MBIST_FAIL_NRML 0 +#define BIT_MASK_MBIST_FAIL_NRML 0xffffffffL +#define BIT_MBIST_FAIL_NRML(x) \ + (((x) & BIT_MASK_MBIST_FAIL_NRML) << BIT_SHIFT_MBIST_FAIL_NRML) +#define BIT_GET_MBIST_FAIL_NRML(x) \ + (((x) >> BIT_SHIFT_MBIST_FAIL_NRML) & BIT_MASK_MBIST_FAIL_NRML) + +/* 2 REG_AES_DECRPT_DATA (Offset 0x0180) */ + +#define BIT_SHIFT_IPS_CFG_ADDR 0 +#define BIT_MASK_IPS_CFG_ADDR 0xff +#define BIT_IPS_CFG_ADDR(x) \ + (((x) & BIT_MASK_IPS_CFG_ADDR) << BIT_SHIFT_IPS_CFG_ADDR) +#define BIT_GET_IPS_CFG_ADDR(x) \ + (((x) >> BIT_SHIFT_IPS_CFG_ADDR) & BIT_MASK_IPS_CFG_ADDR) + +/* 2 REG_AES_DECRPT_CFG (Offset 0x0184) */ + +#define BIT_SHIFT_IPS_CFG_DATA 0 +#define BIT_MASK_IPS_CFG_DATA 0xffffffffL +#define BIT_IPS_CFG_DATA(x) \ + (((x) & BIT_MASK_IPS_CFG_DATA) << BIT_SHIFT_IPS_CFG_DATA) +#define BIT_GET_IPS_CFG_DATA(x) \ + (((x) >> BIT_SHIFT_IPS_CFG_DATA) & BIT_MASK_IPS_CFG_DATA) + +/* 2 REG_TMETER (Offset 0x0190) */ + +#define BIT_TEMP_VALID BIT(31) + +#define BIT_SHIFT_TEMP_VALUE 24 +#define BIT_MASK_TEMP_VALUE 0x3f +#define BIT_TEMP_VALUE(x) (((x) & BIT_MASK_TEMP_VALUE) << BIT_SHIFT_TEMP_VALUE) +#define BIT_GET_TEMP_VALUE(x) \ + (((x) >> BIT_SHIFT_TEMP_VALUE) & BIT_MASK_TEMP_VALUE) + +#define BIT_SHIFT_REG_TMETER_TIMER 8 +#define BIT_MASK_REG_TMETER_TIMER 0xfff +#define BIT_REG_TMETER_TIMER(x) \ + (((x) & BIT_MASK_REG_TMETER_TIMER) << BIT_SHIFT_REG_TMETER_TIMER) +#define BIT_GET_REG_TMETER_TIMER(x) \ + (((x) >> BIT_SHIFT_REG_TMETER_TIMER) & BIT_MASK_REG_TMETER_TIMER) + +#define BIT_SHIFT_REG_TEMP_DELTA 2 +#define BIT_MASK_REG_TEMP_DELTA 0x3f +#define BIT_REG_TEMP_DELTA(x) \ + (((x) & BIT_MASK_REG_TEMP_DELTA) << BIT_SHIFT_REG_TEMP_DELTA) +#define BIT_GET_REG_TEMP_DELTA(x) \ + (((x) >> BIT_SHIFT_REG_TEMP_DELTA) & BIT_MASK_REG_TEMP_DELTA) + +#define BIT_REG_TMETER_EN BIT(0) + +/* 2 REG_OSC_32K_CTRL (Offset 0x0194) */ + +#define BIT_SHIFT_OSC_32K_CLKGEN_0 16 +#define BIT_MASK_OSC_32K_CLKGEN_0 0xffff +#define BIT_OSC_32K_CLKGEN_0(x) \ + (((x) & BIT_MASK_OSC_32K_CLKGEN_0) << BIT_SHIFT_OSC_32K_CLKGEN_0) +#define BIT_GET_OSC_32K_CLKGEN_0(x) \ + (((x) >> BIT_SHIFT_OSC_32K_CLKGEN_0) & BIT_MASK_OSC_32K_CLKGEN_0) + +/* 2 REG_OSC_32K_CTRL (Offset 0x0194) */ + +#define BIT_SHIFT_OSC_32K_RES_COMP 4 +#define BIT_MASK_OSC_32K_RES_COMP 0x3 +#define BIT_OSC_32K_RES_COMP(x) \ + (((x) & BIT_MASK_OSC_32K_RES_COMP) << BIT_SHIFT_OSC_32K_RES_COMP) +#define BIT_GET_OSC_32K_RES_COMP(x) \ + (((x) >> BIT_SHIFT_OSC_32K_RES_COMP) & BIT_MASK_OSC_32K_RES_COMP) + +#define BIT_OSC_32K_OUT_SEL BIT(3) + +/* 2 REG_OSC_32K_CTRL (Offset 0x0194) */ + +#define BIT_ISO_WL_2_OSC_32K BIT(1) + +/* 2 REG_OSC_32K_CTRL (Offset 0x0194) */ + +#define BIT_POW_CKGEN BIT(0) + +/* 2 REG_32K_CAL_REG1 (Offset 0x0198) */ + +#define BIT_CAL_32K_REG_WR BIT(31) +#define BIT_CAL_32K_DBG_SEL BIT(22) + +#define BIT_SHIFT_CAL_32K_REG_ADDR 16 +#define BIT_MASK_CAL_32K_REG_ADDR 0x3f +#define BIT_CAL_32K_REG_ADDR(x) \ + (((x) & BIT_MASK_CAL_32K_REG_ADDR) << BIT_SHIFT_CAL_32K_REG_ADDR) +#define BIT_GET_CAL_32K_REG_ADDR(x) \ + (((x) >> BIT_SHIFT_CAL_32K_REG_ADDR) & BIT_MASK_CAL_32K_REG_ADDR) + +/* 2 REG_32K_CAL_REG1 (Offset 0x0198) */ + +#define BIT_SHIFT_CAL_32K_REG_DATA 0 +#define BIT_MASK_CAL_32K_REG_DATA 0xffff +#define BIT_CAL_32K_REG_DATA(x) \ + (((x) & BIT_MASK_CAL_32K_REG_DATA) << BIT_SHIFT_CAL_32K_REG_DATA) +#define BIT_GET_CAL_32K_REG_DATA(x) \ + (((x) >> BIT_SHIFT_CAL_32K_REG_DATA) & BIT_MASK_CAL_32K_REG_DATA) + +/* 2 REG_C2HEVT (Offset 0x01A0) */ + +#define BIT_SHIFT_C2HEVT_MSG 0 +#define BIT_MASK_C2HEVT_MSG 0xffffffffffffffffffffffffffffffffL +#define BIT_C2HEVT_MSG(x) (((x) & BIT_MASK_C2HEVT_MSG) << BIT_SHIFT_C2HEVT_MSG) +#define BIT_GET_C2HEVT_MSG(x) \ + (((x) >> BIT_SHIFT_C2HEVT_MSG) & BIT_MASK_C2HEVT_MSG) + +/* 2 REG_SW_DEFINED_PAGE1 (Offset 0x01B8) */ + +#define BIT_SHIFT_SW_DEFINED_PAGE1 0 +#define BIT_MASK_SW_DEFINED_PAGE1 0xffffffffffffffffL +#define BIT_SW_DEFINED_PAGE1(x) \ + (((x) & BIT_MASK_SW_DEFINED_PAGE1) << BIT_SHIFT_SW_DEFINED_PAGE1) +#define BIT_GET_SW_DEFINED_PAGE1(x) \ + (((x) >> BIT_SHIFT_SW_DEFINED_PAGE1) & BIT_MASK_SW_DEFINED_PAGE1) + +/* 2 REG_MCUTST_I (Offset 0x01C0) */ + +#define BIT_SHIFT_MCUDMSG_I 0 +#define BIT_MASK_MCUDMSG_I 0xffffffffL +#define BIT_MCUDMSG_I(x) (((x) & BIT_MASK_MCUDMSG_I) << BIT_SHIFT_MCUDMSG_I) +#define BIT_GET_MCUDMSG_I(x) (((x) >> BIT_SHIFT_MCUDMSG_I) & BIT_MASK_MCUDMSG_I) + +/* 2 REG_MCUTST_II (Offset 0x01C4) */ + +#define BIT_SHIFT_MCUDMSG_II 0 +#define BIT_MASK_MCUDMSG_II 0xffffffffL +#define BIT_MCUDMSG_II(x) (((x) & BIT_MASK_MCUDMSG_II) << BIT_SHIFT_MCUDMSG_II) +#define BIT_GET_MCUDMSG_II(x) \ + (((x) >> BIT_SHIFT_MCUDMSG_II) & BIT_MASK_MCUDMSG_II) + +/* 2 REG_FMETHR (Offset 0x01C8) */ + +#define BIT_FMSG_INT BIT(31) + +#define BIT_SHIFT_FW_MSG 0 +#define BIT_MASK_FW_MSG 0xffffffffL +#define BIT_FW_MSG(x) (((x) & BIT_MASK_FW_MSG) << BIT_SHIFT_FW_MSG) +#define BIT_GET_FW_MSG(x) (((x) >> BIT_SHIFT_FW_MSG) & BIT_MASK_FW_MSG) + +/* 2 REG_HMETFR (Offset 0x01CC) */ + +#define BIT_SHIFT_HRCV_MSG 24 +#define BIT_MASK_HRCV_MSG 0xff +#define BIT_HRCV_MSG(x) (((x) & BIT_MASK_HRCV_MSG) << BIT_SHIFT_HRCV_MSG) +#define BIT_GET_HRCV_MSG(x) (((x) >> BIT_SHIFT_HRCV_MSG) & BIT_MASK_HRCV_MSG) + +#define BIT_INT_BOX3 BIT(3) +#define BIT_INT_BOX2 BIT(2) +#define BIT_INT_BOX1 BIT(1) +#define BIT_INT_BOX0 BIT(0) + +/* 2 REG_HMEBOX0 (Offset 0x01D0) */ + +#define BIT_SHIFT_HOST_MSG_0 0 +#define BIT_MASK_HOST_MSG_0 0xffffffffL +#define BIT_HOST_MSG_0(x) (((x) & BIT_MASK_HOST_MSG_0) << BIT_SHIFT_HOST_MSG_0) +#define BIT_GET_HOST_MSG_0(x) \ + (((x) >> BIT_SHIFT_HOST_MSG_0) & BIT_MASK_HOST_MSG_0) + +/* 2 REG_HMEBOX1 (Offset 0x01D4) */ + +#define BIT_SHIFT_HOST_MSG_1 0 +#define BIT_MASK_HOST_MSG_1 0xffffffffL +#define BIT_HOST_MSG_1(x) (((x) & BIT_MASK_HOST_MSG_1) << BIT_SHIFT_HOST_MSG_1) +#define BIT_GET_HOST_MSG_1(x) \ + (((x) >> BIT_SHIFT_HOST_MSG_1) & BIT_MASK_HOST_MSG_1) + +/* 2 REG_HMEBOX2 (Offset 0x01D8) */ + +#define BIT_SHIFT_HOST_MSG_2 0 +#define BIT_MASK_HOST_MSG_2 0xffffffffL +#define BIT_HOST_MSG_2(x) (((x) & BIT_MASK_HOST_MSG_2) << BIT_SHIFT_HOST_MSG_2) +#define BIT_GET_HOST_MSG_2(x) \ + (((x) >> BIT_SHIFT_HOST_MSG_2) & BIT_MASK_HOST_MSG_2) + +/* 2 REG_HMEBOX3 (Offset 0x01DC) */ + +#define BIT_SHIFT_HOST_MSG_3 0 +#define BIT_MASK_HOST_MSG_3 0xffffffffL +#define BIT_HOST_MSG_3(x) (((x) & BIT_MASK_HOST_MSG_3) << BIT_SHIFT_HOST_MSG_3) +#define BIT_GET_HOST_MSG_3(x) \ + (((x) >> BIT_SHIFT_HOST_MSG_3) & BIT_MASK_HOST_MSG_3) + +/* 2 REG_LLT_INIT (Offset 0x01E0) */ + +#define BIT_SHIFT_LLTE_RWM 30 +#define BIT_MASK_LLTE_RWM 0x3 +#define BIT_LLTE_RWM(x) (((x) & BIT_MASK_LLTE_RWM) << BIT_SHIFT_LLTE_RWM) +#define BIT_GET_LLTE_RWM(x) (((x) >> BIT_SHIFT_LLTE_RWM) & BIT_MASK_LLTE_RWM) + +/* 2 REG_LLT_INIT (Offset 0x01E0) */ + +#define BIT_SHIFT_LLTINI_PDATA_V1 16 +#define BIT_MASK_LLTINI_PDATA_V1 0xfff +#define BIT_LLTINI_PDATA_V1(x) \ + (((x) & BIT_MASK_LLTINI_PDATA_V1) << BIT_SHIFT_LLTINI_PDATA_V1) +#define BIT_GET_LLTINI_PDATA_V1(x) \ + (((x) >> BIT_SHIFT_LLTINI_PDATA_V1) & BIT_MASK_LLTINI_PDATA_V1) + +/* 2 REG_LLT_INIT (Offset 0x01E0) */ + +#define BIT_SHIFT_LLTINI_HDATA_V1 0 +#define BIT_MASK_LLTINI_HDATA_V1 0xfff +#define BIT_LLTINI_HDATA_V1(x) \ + (((x) & BIT_MASK_LLTINI_HDATA_V1) << BIT_SHIFT_LLTINI_HDATA_V1) +#define BIT_GET_LLTINI_HDATA_V1(x) \ + (((x) >> BIT_SHIFT_LLTINI_HDATA_V1) & BIT_MASK_LLTINI_HDATA_V1) + +/* 2 REG_LLT_INIT_ADDR (Offset 0x01E4) */ + +#define BIT_SHIFT_LLTINI_ADDR_V1 0 +#define BIT_MASK_LLTINI_ADDR_V1 0xfff +#define BIT_LLTINI_ADDR_V1(x) \ + (((x) & BIT_MASK_LLTINI_ADDR_V1) << BIT_SHIFT_LLTINI_ADDR_V1) +#define BIT_GET_LLTINI_ADDR_V1(x) \ + (((x) >> BIT_SHIFT_LLTINI_ADDR_V1) & BIT_MASK_LLTINI_ADDR_V1) + +/* 2 REG_BB_ACCESS_CTRL (Offset 0x01E8) */ + +#define BIT_SHIFT_BB_WRITE_READ 30 +#define BIT_MASK_BB_WRITE_READ 0x3 +#define BIT_BB_WRITE_READ(x) \ + (((x) & BIT_MASK_BB_WRITE_READ) << BIT_SHIFT_BB_WRITE_READ) +#define BIT_GET_BB_WRITE_READ(x) \ + (((x) >> BIT_SHIFT_BB_WRITE_READ) & BIT_MASK_BB_WRITE_READ) + +/* 2 REG_BB_ACCESS_CTRL (Offset 0x01E8) */ + +#define BIT_SHIFT_BB_WRITE_EN 12 +#define BIT_MASK_BB_WRITE_EN 0xf +#define BIT_BB_WRITE_EN(x) \ + (((x) & BIT_MASK_BB_WRITE_EN) << BIT_SHIFT_BB_WRITE_EN) +#define BIT_GET_BB_WRITE_EN(x) \ + (((x) >> BIT_SHIFT_BB_WRITE_EN) & BIT_MASK_BB_WRITE_EN) + +#define BIT_SHIFT_BB_ADDR 2 +#define BIT_MASK_BB_ADDR 0x1ff +#define BIT_BB_ADDR(x) (((x) & BIT_MASK_BB_ADDR) << BIT_SHIFT_BB_ADDR) +#define BIT_GET_BB_ADDR(x) (((x) >> BIT_SHIFT_BB_ADDR) & BIT_MASK_BB_ADDR) + +/* 2 REG_BB_ACCESS_CTRL (Offset 0x01E8) */ + +#define BIT_BB_ERRACC BIT(0) + +/* 2 REG_BB_ACCESS_DATA (Offset 0x01EC) */ + +#define BIT_SHIFT_BB_DATA 0 +#define BIT_MASK_BB_DATA 0xffffffffL +#define BIT_BB_DATA(x) (((x) & BIT_MASK_BB_DATA) << BIT_SHIFT_BB_DATA) +#define BIT_GET_BB_DATA(x) (((x) >> BIT_SHIFT_BB_DATA) & BIT_MASK_BB_DATA) + +/* 2 REG_HMEBOX_E0 (Offset 0x01F0) */ + +#define BIT_SHIFT_HMEBOX_E0 0 +#define BIT_MASK_HMEBOX_E0 0xffffffffL +#define BIT_HMEBOX_E0(x) (((x) & BIT_MASK_HMEBOX_E0) << BIT_SHIFT_HMEBOX_E0) +#define BIT_GET_HMEBOX_E0(x) (((x) >> BIT_SHIFT_HMEBOX_E0) & BIT_MASK_HMEBOX_E0) + +/* 2 REG_HMEBOX_E1 (Offset 0x01F4) */ + +#define BIT_SHIFT_HMEBOX_E1 0 +#define BIT_MASK_HMEBOX_E1 0xffffffffL +#define BIT_HMEBOX_E1(x) (((x) & BIT_MASK_HMEBOX_E1) << BIT_SHIFT_HMEBOX_E1) +#define BIT_GET_HMEBOX_E1(x) (((x) >> BIT_SHIFT_HMEBOX_E1) & BIT_MASK_HMEBOX_E1) + +/* 2 REG_HMEBOX_E2 (Offset 0x01F8) */ + +#define BIT_SHIFT_HMEBOX_E2 0 +#define BIT_MASK_HMEBOX_E2 0xffffffffL +#define BIT_HMEBOX_E2(x) (((x) & BIT_MASK_HMEBOX_E2) << BIT_SHIFT_HMEBOX_E2) +#define BIT_GET_HMEBOX_E2(x) (((x) >> BIT_SHIFT_HMEBOX_E2) & BIT_MASK_HMEBOX_E2) + +/* 2 REG_HMEBOX_E3 (Offset 0x01FC) */ + +#define BIT_LD_RQPN BIT(31) + +#define BIT_SHIFT_HMEBOX_E3 0 +#define BIT_MASK_HMEBOX_E3 0xffffffffL +#define BIT_HMEBOX_E3(x) (((x) & BIT_MASK_HMEBOX_E3) << BIT_SHIFT_HMEBOX_E3) +#define BIT_GET_HMEBOX_E3(x) (((x) >> BIT_SHIFT_HMEBOX_E3) & BIT_MASK_HMEBOX_E3) + +/* 2 REG_FIFOPAGE_CTRL_1 (Offset 0x0200) */ + +#define BIT_SHIFT_TX_OQT_HE_FREE_SPACE_V1 16 +#define BIT_MASK_TX_OQT_HE_FREE_SPACE_V1 0xff +#define BIT_TX_OQT_HE_FREE_SPACE_V1(x) \ + (((x) & BIT_MASK_TX_OQT_HE_FREE_SPACE_V1) \ + << BIT_SHIFT_TX_OQT_HE_FREE_SPACE_V1) +#define BIT_GET_TX_OQT_HE_FREE_SPACE_V1(x) \ + (((x) >> BIT_SHIFT_TX_OQT_HE_FREE_SPACE_V1) & \ + BIT_MASK_TX_OQT_HE_FREE_SPACE_V1) + +/* 2 REG_FIFOPAGE_CTRL_1 (Offset 0x0200) */ + +#define BIT_SHIFT_TX_OQT_NL_FREE_SPACE_V1 0 +#define BIT_MASK_TX_OQT_NL_FREE_SPACE_V1 0xff +#define BIT_TX_OQT_NL_FREE_SPACE_V1(x) \ + (((x) & BIT_MASK_TX_OQT_NL_FREE_SPACE_V1) \ + << BIT_SHIFT_TX_OQT_NL_FREE_SPACE_V1) +#define BIT_GET_TX_OQT_NL_FREE_SPACE_V1(x) \ + (((x) >> BIT_SHIFT_TX_OQT_NL_FREE_SPACE_V1) & \ + BIT_MASK_TX_OQT_NL_FREE_SPACE_V1) + +/* 2 REG_FIFOPAGE_CTRL_2 (Offset 0x0204) */ + +#define BIT_BCN_VALID_1_V1 BIT(31) + +/* 2 REG_FIFOPAGE_CTRL_2 (Offset 0x0204) */ + +#define BIT_SHIFT_BCN_HEAD_1_V1 16 +#define BIT_MASK_BCN_HEAD_1_V1 0xfff +#define BIT_BCN_HEAD_1_V1(x) \ + (((x) & BIT_MASK_BCN_HEAD_1_V1) << BIT_SHIFT_BCN_HEAD_1_V1) +#define BIT_GET_BCN_HEAD_1_V1(x) \ + (((x) >> BIT_SHIFT_BCN_HEAD_1_V1) & BIT_MASK_BCN_HEAD_1_V1) + +#define BIT_BCN_VALID_V1 BIT(15) + +/* 2 REG_FIFOPAGE_CTRL_2 (Offset 0x0204) */ + +#define BIT_SHIFT_BCN_HEAD_V1 0 +#define BIT_MASK_BCN_HEAD_V1 0xfff +#define BIT_BCN_HEAD_V1(x) \ + (((x) & BIT_MASK_BCN_HEAD_V1) << BIT_SHIFT_BCN_HEAD_V1) +#define BIT_GET_BCN_HEAD_V1(x) \ + (((x) >> BIT_SHIFT_BCN_HEAD_V1) & BIT_MASK_BCN_HEAD_V1) + +/* 2 REG_AUTO_LLT_V1 (Offset 0x0208) */ + +#define BIT_SHIFT_MAX_TX_PKT_FOR_USB_AND_SDIO_V1 24 +#define BIT_MASK_MAX_TX_PKT_FOR_USB_AND_SDIO_V1 0xff +#define BIT_MAX_TX_PKT_FOR_USB_AND_SDIO_V1(x) \ + (((x) & BIT_MASK_MAX_TX_PKT_FOR_USB_AND_SDIO_V1) \ + << BIT_SHIFT_MAX_TX_PKT_FOR_USB_AND_SDIO_V1) +#define BIT_GET_MAX_TX_PKT_FOR_USB_AND_SDIO_V1(x) \ + (((x) >> BIT_SHIFT_MAX_TX_PKT_FOR_USB_AND_SDIO_V1) & \ + BIT_MASK_MAX_TX_PKT_FOR_USB_AND_SDIO_V1) + +/* 2 REG_AUTO_LLT_V1 (Offset 0x0208) */ + +#define BIT_SHIFT_LLT_FREE_PAGE_V1 8 +#define BIT_MASK_LLT_FREE_PAGE_V1 0xffff +#define BIT_LLT_FREE_PAGE_V1(x) \ + (((x) & BIT_MASK_LLT_FREE_PAGE_V1) << BIT_SHIFT_LLT_FREE_PAGE_V1) +#define BIT_GET_LLT_FREE_PAGE_V1(x) \ + (((x) >> BIT_SHIFT_LLT_FREE_PAGE_V1) & BIT_MASK_LLT_FREE_PAGE_V1) + +/* 2 REG_DWBCN0_CTRL (Offset 0x0208) */ + +#define BIT_SHIFT_BLK_DESC_NUM 4 +#define BIT_MASK_BLK_DESC_NUM 0xf +#define BIT_BLK_DESC_NUM(x) \ + (((x) & BIT_MASK_BLK_DESC_NUM) << BIT_SHIFT_BLK_DESC_NUM) +#define BIT_GET_BLK_DESC_NUM(x) \ + (((x) >> BIT_SHIFT_BLK_DESC_NUM) & BIT_MASK_BLK_DESC_NUM) + +/* 2 REG_AUTO_LLT_V1 (Offset 0x0208) */ + +#define BIT_R_BCN_HEAD_SEL BIT(3) +#define BIT_R_EN_BCN_SW_HEAD_SEL BIT(2) +#define BIT_LLT_DBG_SEL BIT(1) +#define BIT_AUTO_INIT_LLT_V1 BIT(0) + +/* 2 REG_TXDMA_OFFSET_CHK (Offset 0x020C) */ + +#define BIT_EM_CHKSUM_FIN BIT(31) +#define BIT_EMN_PCIE_DMA_MOD BIT(30) + +/* 2 REG_TXDMA_OFFSET_CHK (Offset 0x020C) */ + +#define BIT_EN_TXQUE_CLR BIT(29) +#define BIT_EN_PCIE_FIFO_MODE BIT(28) + +/* 2 REG_TXDMA_OFFSET_CHK (Offset 0x020C) */ + +#define BIT_SHIFT_PG_UNDER_TH_V1 16 +#define BIT_MASK_PG_UNDER_TH_V1 0xfff +#define BIT_PG_UNDER_TH_V1(x) \ + (((x) & BIT_MASK_PG_UNDER_TH_V1) << BIT_SHIFT_PG_UNDER_TH_V1) +#define BIT_GET_PG_UNDER_TH_V1(x) \ + (((x) >> BIT_SHIFT_PG_UNDER_TH_V1) & BIT_MASK_PG_UNDER_TH_V1) + +/* 2 REG_TXDMA_OFFSET_CHK (Offset 0x020C) */ + +#define BIT_RESTORE_H2C_ADDRESS BIT(15) + +/* 2 REG_TXDMA_OFFSET_CHK (Offset 0x020C) */ + +#define BIT_SDIO_TXDESC_CHKSUM_EN BIT(13) +#define BIT_RST_RDPTR BIT(12) +#define BIT_RST_WRPTR BIT(11) +#define BIT_CHK_PG_TH_EN BIT(10) +#define BIT_DROP_DATA_EN BIT(9) +#define BIT_CHECK_OFFSET_EN BIT(8) + +#define BIT_SHIFT_CHECK_OFFSET 0 +#define BIT_MASK_CHECK_OFFSET 0xff +#define BIT_CHECK_OFFSET(x) \ + (((x) & BIT_MASK_CHECK_OFFSET) << BIT_SHIFT_CHECK_OFFSET) +#define BIT_GET_CHECK_OFFSET(x) \ + (((x) >> BIT_SHIFT_CHECK_OFFSET) & BIT_MASK_CHECK_OFFSET) + +/* 2 REG_TXDMA_STATUS (Offset 0x0210) */ + +#define BIT_HI_OQT_UDN BIT(17) +#define BIT_HI_OQT_OVF BIT(16) +#define BIT_PAYLOAD_CHKSUM_ERR BIT(15) +#define BIT_PAYLOAD_UDN BIT(14) +#define BIT_PAYLOAD_OVF BIT(13) +#define BIT_DSC_CHKSUM_FAIL BIT(12) +#define BIT_UNKNOWN_QSEL BIT(11) +#define BIT_EP_QSEL_DIFF BIT(10) +#define BIT_TX_OFFS_UNMATCH BIT(9) +#define BIT_TXOQT_UDN BIT(8) +#define BIT_TXOQT_OVF BIT(7) +#define BIT_TXDMA_SFF_UDN BIT(6) +#define BIT_TXDMA_SFF_OVF BIT(5) +#define BIT_LLT_NULL_PG BIT(4) +#define BIT_PAGE_UDN BIT(3) +#define BIT_PAGE_OVF BIT(2) +#define BIT_TXFF_PG_UDN BIT(1) +#define BIT_TXFF_PG_OVF BIT(0) + +/* 2 REG_TQPNT1 (Offset 0x0218) */ + +#define BIT_SHIFT_HPQ_HIGH_TH_V1 16 +#define BIT_MASK_HPQ_HIGH_TH_V1 0xfff +#define BIT_HPQ_HIGH_TH_V1(x) \ + (((x) & BIT_MASK_HPQ_HIGH_TH_V1) << BIT_SHIFT_HPQ_HIGH_TH_V1) +#define BIT_GET_HPQ_HIGH_TH_V1(x) \ + (((x) >> BIT_SHIFT_HPQ_HIGH_TH_V1) & BIT_MASK_HPQ_HIGH_TH_V1) + +/* 2 REG_TQPNT1 (Offset 0x0218) */ + +#define BIT_SHIFT_HPQ_LOW_TH_V1 0 +#define BIT_MASK_HPQ_LOW_TH_V1 0xfff +#define BIT_HPQ_LOW_TH_V1(x) \ + (((x) & BIT_MASK_HPQ_LOW_TH_V1) << BIT_SHIFT_HPQ_LOW_TH_V1) +#define BIT_GET_HPQ_LOW_TH_V1(x) \ + (((x) >> BIT_SHIFT_HPQ_LOW_TH_V1) & BIT_MASK_HPQ_LOW_TH_V1) + +/* 2 REG_TQPNT2 (Offset 0x021C) */ + +#define BIT_SHIFT_NPQ_HIGH_TH_V1 16 +#define BIT_MASK_NPQ_HIGH_TH_V1 0xfff +#define BIT_NPQ_HIGH_TH_V1(x) \ + (((x) & BIT_MASK_NPQ_HIGH_TH_V1) << BIT_SHIFT_NPQ_HIGH_TH_V1) +#define BIT_GET_NPQ_HIGH_TH_V1(x) \ + (((x) >> BIT_SHIFT_NPQ_HIGH_TH_V1) & BIT_MASK_NPQ_HIGH_TH_V1) + +/* 2 REG_TQPNT2 (Offset 0x021C) */ + +#define BIT_SHIFT_NPQ_LOW_TH_V1 0 +#define BIT_MASK_NPQ_LOW_TH_V1 0xfff +#define BIT_NPQ_LOW_TH_V1(x) \ + (((x) & BIT_MASK_NPQ_LOW_TH_V1) << BIT_SHIFT_NPQ_LOW_TH_V1) +#define BIT_GET_NPQ_LOW_TH_V1(x) \ + (((x) >> BIT_SHIFT_NPQ_LOW_TH_V1) & BIT_MASK_NPQ_LOW_TH_V1) + +/* 2 REG_TQPNT3 (Offset 0x0220) */ + +#define BIT_SHIFT_LPQ_HIGH_TH_V1 16 +#define BIT_MASK_LPQ_HIGH_TH_V1 0xfff +#define BIT_LPQ_HIGH_TH_V1(x) \ + (((x) & BIT_MASK_LPQ_HIGH_TH_V1) << BIT_SHIFT_LPQ_HIGH_TH_V1) +#define BIT_GET_LPQ_HIGH_TH_V1(x) \ + (((x) >> BIT_SHIFT_LPQ_HIGH_TH_V1) & BIT_MASK_LPQ_HIGH_TH_V1) + +/* 2 REG_TQPNT3 (Offset 0x0220) */ + +#define BIT_SHIFT_LPQ_LOW_TH_V1 0 +#define BIT_MASK_LPQ_LOW_TH_V1 0xfff +#define BIT_LPQ_LOW_TH_V1(x) \ + (((x) & BIT_MASK_LPQ_LOW_TH_V1) << BIT_SHIFT_LPQ_LOW_TH_V1) +#define BIT_GET_LPQ_LOW_TH_V1(x) \ + (((x) >> BIT_SHIFT_LPQ_LOW_TH_V1) & BIT_MASK_LPQ_LOW_TH_V1) + +/* 2 REG_TQPNT4 (Offset 0x0224) */ + +#define BIT_SHIFT_EXQ_HIGH_TH_V1 16 +#define BIT_MASK_EXQ_HIGH_TH_V1 0xfff +#define BIT_EXQ_HIGH_TH_V1(x) \ + (((x) & BIT_MASK_EXQ_HIGH_TH_V1) << BIT_SHIFT_EXQ_HIGH_TH_V1) +#define BIT_GET_EXQ_HIGH_TH_V1(x) \ + (((x) >> BIT_SHIFT_EXQ_HIGH_TH_V1) & BIT_MASK_EXQ_HIGH_TH_V1) + +/* 2 REG_TQPNT4 (Offset 0x0224) */ + +#define BIT_SHIFT_EXQ_LOW_TH_V1 0 +#define BIT_MASK_EXQ_LOW_TH_V1 0xfff +#define BIT_EXQ_LOW_TH_V1(x) \ + (((x) & BIT_MASK_EXQ_LOW_TH_V1) << BIT_SHIFT_EXQ_LOW_TH_V1) +#define BIT_GET_EXQ_LOW_TH_V1(x) \ + (((x) >> BIT_SHIFT_EXQ_LOW_TH_V1) & BIT_MASK_EXQ_LOW_TH_V1) + +/* 2 REG_RQPN_CTRL_1 (Offset 0x0228) */ + +#define BIT_SHIFT_TXPKTNUM_H 16 +#define BIT_MASK_TXPKTNUM_H 0xffff +#define BIT_TXPKTNUM_H(x) (((x) & BIT_MASK_TXPKTNUM_H) << BIT_SHIFT_TXPKTNUM_H) +#define BIT_GET_TXPKTNUM_H(x) \ + (((x) >> BIT_SHIFT_TXPKTNUM_H) & BIT_MASK_TXPKTNUM_H) + +/* 2 REG_RQPN_CTRL_1 (Offset 0x0228) */ + +#define BIT_SHIFT_TXPKTNUM_V2 0 +#define BIT_MASK_TXPKTNUM_V2 0xffff +#define BIT_TXPKTNUM_V2(x) \ + (((x) & BIT_MASK_TXPKTNUM_V2) << BIT_SHIFT_TXPKTNUM_V2) +#define BIT_GET_TXPKTNUM_V2(x) \ + (((x) >> BIT_SHIFT_TXPKTNUM_V2) & BIT_MASK_TXPKTNUM_V2) + +/* 2 REG_RQPN_CTRL_2 (Offset 0x022C) */ + +#define BIT_EXQ_PUBLIC_DIS_V1 BIT(19) +#define BIT_NPQ_PUBLIC_DIS_V1 BIT(18) +#define BIT_LPQ_PUBLIC_DIS_V1 BIT(17) +#define BIT_HPQ_PUBLIC_DIS_V1 BIT(16) + +/* 2 REG_FIFOPAGE_INFO_1 (Offset 0x0230) */ + +#define BIT_SHIFT_HPQ_AVAL_PG_V1 16 +#define BIT_MASK_HPQ_AVAL_PG_V1 0xfff +#define BIT_HPQ_AVAL_PG_V1(x) \ + (((x) & BIT_MASK_HPQ_AVAL_PG_V1) << BIT_SHIFT_HPQ_AVAL_PG_V1) +#define BIT_GET_HPQ_AVAL_PG_V1(x) \ + (((x) >> BIT_SHIFT_HPQ_AVAL_PG_V1) & BIT_MASK_HPQ_AVAL_PG_V1) + +#define BIT_SHIFT_HPQ_V1 0 +#define BIT_MASK_HPQ_V1 0xfff +#define BIT_HPQ_V1(x) (((x) & BIT_MASK_HPQ_V1) << BIT_SHIFT_HPQ_V1) +#define BIT_GET_HPQ_V1(x) (((x) >> BIT_SHIFT_HPQ_V1) & BIT_MASK_HPQ_V1) + +/* 2 REG_FIFOPAGE_INFO_2 (Offset 0x0234) */ + +#define BIT_SHIFT_LPQ_AVAL_PG_V1 16 +#define BIT_MASK_LPQ_AVAL_PG_V1 0xfff +#define BIT_LPQ_AVAL_PG_V1(x) \ + (((x) & BIT_MASK_LPQ_AVAL_PG_V1) << BIT_SHIFT_LPQ_AVAL_PG_V1) +#define BIT_GET_LPQ_AVAL_PG_V1(x) \ + (((x) >> BIT_SHIFT_LPQ_AVAL_PG_V1) & BIT_MASK_LPQ_AVAL_PG_V1) + +#define BIT_SHIFT_LPQ_V1 0 +#define BIT_MASK_LPQ_V1 0xfff +#define BIT_LPQ_V1(x) (((x) & BIT_MASK_LPQ_V1) << BIT_SHIFT_LPQ_V1) +#define BIT_GET_LPQ_V1(x) (((x) >> BIT_SHIFT_LPQ_V1) & BIT_MASK_LPQ_V1) + +/* 2 REG_FIFOPAGE_INFO_3 (Offset 0x0238) */ + +#define BIT_SHIFT_NPQ_AVAL_PG_V1 16 +#define BIT_MASK_NPQ_AVAL_PG_V1 0xfff +#define BIT_NPQ_AVAL_PG_V1(x) \ + (((x) & BIT_MASK_NPQ_AVAL_PG_V1) << BIT_SHIFT_NPQ_AVAL_PG_V1) +#define BIT_GET_NPQ_AVAL_PG_V1(x) \ + (((x) >> BIT_SHIFT_NPQ_AVAL_PG_V1) & BIT_MASK_NPQ_AVAL_PG_V1) + +/* 2 REG_FIFOPAGE_INFO_3 (Offset 0x0238) */ + +#define BIT_SHIFT_NPQ_V1 0 +#define BIT_MASK_NPQ_V1 0xfff +#define BIT_NPQ_V1(x) (((x) & BIT_MASK_NPQ_V1) << BIT_SHIFT_NPQ_V1) +#define BIT_GET_NPQ_V1(x) (((x) >> BIT_SHIFT_NPQ_V1) & BIT_MASK_NPQ_V1) + +/* 2 REG_FIFOPAGE_INFO_4 (Offset 0x023C) */ + +#define BIT_SHIFT_EXQ_AVAL_PG_V1 16 +#define BIT_MASK_EXQ_AVAL_PG_V1 0xfff +#define BIT_EXQ_AVAL_PG_V1(x) \ + (((x) & BIT_MASK_EXQ_AVAL_PG_V1) << BIT_SHIFT_EXQ_AVAL_PG_V1) +#define BIT_GET_EXQ_AVAL_PG_V1(x) \ + (((x) >> BIT_SHIFT_EXQ_AVAL_PG_V1) & BIT_MASK_EXQ_AVAL_PG_V1) + +#define BIT_SHIFT_EXQ_V1 0 +#define BIT_MASK_EXQ_V1 0xfff +#define BIT_EXQ_V1(x) (((x) & BIT_MASK_EXQ_V1) << BIT_SHIFT_EXQ_V1) +#define BIT_GET_EXQ_V1(x) (((x) >> BIT_SHIFT_EXQ_V1) & BIT_MASK_EXQ_V1) + +/* 2 REG_FIFOPAGE_INFO_5 (Offset 0x0240) */ + +#define BIT_SHIFT_PUBQ_AVAL_PG_V1 16 +#define BIT_MASK_PUBQ_AVAL_PG_V1 0xfff +#define BIT_PUBQ_AVAL_PG_V1(x) \ + (((x) & BIT_MASK_PUBQ_AVAL_PG_V1) << BIT_SHIFT_PUBQ_AVAL_PG_V1) +#define BIT_GET_PUBQ_AVAL_PG_V1(x) \ + (((x) >> BIT_SHIFT_PUBQ_AVAL_PG_V1) & BIT_MASK_PUBQ_AVAL_PG_V1) + +#define BIT_SHIFT_PUBQ_V1 0 +#define BIT_MASK_PUBQ_V1 0xfff +#define BIT_PUBQ_V1(x) (((x) & BIT_MASK_PUBQ_V1) << BIT_SHIFT_PUBQ_V1) +#define BIT_GET_PUBQ_V1(x) (((x) >> BIT_SHIFT_PUBQ_V1) & BIT_MASK_PUBQ_V1) + +/* 2 REG_H2C_HEAD (Offset 0x0244) */ + +#define BIT_SHIFT_H2C_HEAD 0 +#define BIT_MASK_H2C_HEAD 0x3ffff +#define BIT_H2C_HEAD(x) (((x) & BIT_MASK_H2C_HEAD) << BIT_SHIFT_H2C_HEAD) +#define BIT_GET_H2C_HEAD(x) (((x) >> BIT_SHIFT_H2C_HEAD) & BIT_MASK_H2C_HEAD) + +/* 2 REG_H2C_TAIL (Offset 0x0248) */ + +#define BIT_SHIFT_H2C_TAIL 0 +#define BIT_MASK_H2C_TAIL 0x3ffff +#define BIT_H2C_TAIL(x) (((x) & BIT_MASK_H2C_TAIL) << BIT_SHIFT_H2C_TAIL) +#define BIT_GET_H2C_TAIL(x) (((x) >> BIT_SHIFT_H2C_TAIL) & BIT_MASK_H2C_TAIL) + +/* 2 REG_H2C_READ_ADDR (Offset 0x024C) */ + +#define BIT_SHIFT_H2C_READ_ADDR 0 +#define BIT_MASK_H2C_READ_ADDR 0x3ffff +#define BIT_H2C_READ_ADDR(x) \ + (((x) & BIT_MASK_H2C_READ_ADDR) << BIT_SHIFT_H2C_READ_ADDR) +#define BIT_GET_H2C_READ_ADDR(x) \ + (((x) >> BIT_SHIFT_H2C_READ_ADDR) & BIT_MASK_H2C_READ_ADDR) + +/* 2 REG_H2C_WR_ADDR (Offset 0x0250) */ + +#define BIT_SHIFT_H2C_WR_ADDR 0 +#define BIT_MASK_H2C_WR_ADDR 0x3ffff +#define BIT_H2C_WR_ADDR(x) \ + (((x) & BIT_MASK_H2C_WR_ADDR) << BIT_SHIFT_H2C_WR_ADDR) +#define BIT_GET_H2C_WR_ADDR(x) \ + (((x) >> BIT_SHIFT_H2C_WR_ADDR) & BIT_MASK_H2C_WR_ADDR) + +/* 2 REG_H2C_INFO (Offset 0x0254) */ + +#define BIT_H2C_SPACE_VLD BIT(3) +#define BIT_H2C_WR_ADDR_RST BIT(2) + +#define BIT_SHIFT_H2C_LEN_SEL 0 +#define BIT_MASK_H2C_LEN_SEL 0x3 +#define BIT_H2C_LEN_SEL(x) \ + (((x) & BIT_MASK_H2C_LEN_SEL) << BIT_SHIFT_H2C_LEN_SEL) +#define BIT_GET_H2C_LEN_SEL(x) \ + (((x) >> BIT_SHIFT_H2C_LEN_SEL) & BIT_MASK_H2C_LEN_SEL) + +/* 2 REG_RXDMA_AGG_PG_TH (Offset 0x0280) */ + +#define BIT_SHIFT_RXDMA_AGG_OLD_MOD 24 +#define BIT_MASK_RXDMA_AGG_OLD_MOD 0xff +#define BIT_RXDMA_AGG_OLD_MOD(x) \ + (((x) & BIT_MASK_RXDMA_AGG_OLD_MOD) << BIT_SHIFT_RXDMA_AGG_OLD_MOD) +#define BIT_GET_RXDMA_AGG_OLD_MOD(x) \ + (((x) >> BIT_SHIFT_RXDMA_AGG_OLD_MOD) & BIT_MASK_RXDMA_AGG_OLD_MOD) + +/* 2 REG_RXDMA_AGG_PG_TH (Offset 0x0280) */ + +#define BIT_SHIFT_PKT_NUM_WOL 16 +#define BIT_MASK_PKT_NUM_WOL 0xff +#define BIT_PKT_NUM_WOL(x) \ + (((x) & BIT_MASK_PKT_NUM_WOL) << BIT_SHIFT_PKT_NUM_WOL) +#define BIT_GET_PKT_NUM_WOL(x) \ + (((x) >> BIT_SHIFT_PKT_NUM_WOL) & BIT_MASK_PKT_NUM_WOL) + +/* 2 REG_RXDMA_AGG_PG_TH (Offset 0x0280) */ + +#define BIT_SHIFT_DMA_AGG_TO 8 +#define BIT_MASK_DMA_AGG_TO 0xf +#define BIT_DMA_AGG_TO(x) (((x) & BIT_MASK_DMA_AGG_TO) << BIT_SHIFT_DMA_AGG_TO) +#define BIT_GET_DMA_AGG_TO(x) \ + (((x) >> BIT_SHIFT_DMA_AGG_TO) & BIT_MASK_DMA_AGG_TO) + +/* 2 REG_RXDMA_AGG_PG_TH (Offset 0x0280) */ + +#define BIT_SHIFT_RXDMA_AGG_PG_TH_V1 0 +#define BIT_MASK_RXDMA_AGG_PG_TH_V1 0xf +#define BIT_RXDMA_AGG_PG_TH_V1(x) \ + (((x) & BIT_MASK_RXDMA_AGG_PG_TH_V1) << BIT_SHIFT_RXDMA_AGG_PG_TH_V1) +#define BIT_GET_RXDMA_AGG_PG_TH_V1(x) \ + (((x) >> BIT_SHIFT_RXDMA_AGG_PG_TH_V1) & BIT_MASK_RXDMA_AGG_PG_TH_V1) + +/* 2 REG_RXPKT_NUM (Offset 0x0284) */ + +#define BIT_SHIFT_RXPKT_NUM 24 +#define BIT_MASK_RXPKT_NUM 0xff +#define BIT_RXPKT_NUM(x) (((x) & BIT_MASK_RXPKT_NUM) << BIT_SHIFT_RXPKT_NUM) +#define BIT_GET_RXPKT_NUM(x) (((x) >> BIT_SHIFT_RXPKT_NUM) & BIT_MASK_RXPKT_NUM) + +/* 2 REG_RXPKT_NUM (Offset 0x0284) */ + +#define BIT_SHIFT_FW_UPD_RDPTR19_TO_16 20 +#define BIT_MASK_FW_UPD_RDPTR19_TO_16 0xf +#define BIT_FW_UPD_RDPTR19_TO_16(x) \ + (((x) & BIT_MASK_FW_UPD_RDPTR19_TO_16) \ + << BIT_SHIFT_FW_UPD_RDPTR19_TO_16) +#define BIT_GET_FW_UPD_RDPTR19_TO_16(x) \ + (((x) >> BIT_SHIFT_FW_UPD_RDPTR19_TO_16) & \ + BIT_MASK_FW_UPD_RDPTR19_TO_16) + +/* 2 REG_RXPKT_NUM (Offset 0x0284) */ + +#define BIT_RXDMA_REQ BIT(19) +#define BIT_RW_RELEASE_EN BIT(18) +#define BIT_RXDMA_IDLE BIT(17) +#define BIT_RXPKT_RELEASE_POLL BIT(16) + +#define BIT_SHIFT_FW_UPD_RDPTR 0 +#define BIT_MASK_FW_UPD_RDPTR 0xffff +#define BIT_FW_UPD_RDPTR(x) \ + (((x) & BIT_MASK_FW_UPD_RDPTR) << BIT_SHIFT_FW_UPD_RDPTR) +#define BIT_GET_FW_UPD_RDPTR(x) \ + (((x) >> BIT_SHIFT_FW_UPD_RDPTR) & BIT_MASK_FW_UPD_RDPTR) + +/* 2 REG_RXDMA_STATUS (Offset 0x0288) */ + +#define BIT_C2H_PKT_OVF BIT(7) + +/* 2 REG_RXDMA_STATUS (Offset 0x0288) */ + +#define BIT_AGG_CONFGI_ISSUE BIT(6) + +/* 2 REG_RXDMA_STATUS (Offset 0x0288) */ + +#define BIT_FW_POLL_ISSUE BIT(5) +#define BIT_RX_DATA_UDN BIT(4) +#define BIT_RX_SFF_UDN BIT(3) +#define BIT_RX_SFF_OVF BIT(2) + +/* 2 REG_RXDMA_STATUS (Offset 0x0288) */ + +#define BIT_RXPKT_OVF BIT(0) + +/* 2 REG_RXDMA_DPR (Offset 0x028C) */ + +#define BIT_SHIFT_RDE_DEBUG 0 +#define BIT_MASK_RDE_DEBUG 0xffffffffL +#define BIT_RDE_DEBUG(x) (((x) & BIT_MASK_RDE_DEBUG) << BIT_SHIFT_RDE_DEBUG) +#define BIT_GET_RDE_DEBUG(x) (((x) >> BIT_SHIFT_RDE_DEBUG) & BIT_MASK_RDE_DEBUG) + +/* 2 REG_RXDMA_MODE (Offset 0x0290) */ + +#define BIT_SHIFT_PKTNUM_TH_V2 24 +#define BIT_MASK_PKTNUM_TH_V2 0x1f +#define BIT_PKTNUM_TH_V2(x) \ + (((x) & BIT_MASK_PKTNUM_TH_V2) << BIT_SHIFT_PKTNUM_TH_V2) +#define BIT_GET_PKTNUM_TH_V2(x) \ + (((x) >> BIT_SHIFT_PKTNUM_TH_V2) & BIT_MASK_PKTNUM_TH_V2) + +#define BIT_TXBA_BREAK_USBAGG BIT(23) + +#define BIT_SHIFT_PKTLEN_PARA 16 +#define BIT_MASK_PKTLEN_PARA 0x7 +#define BIT_PKTLEN_PARA(x) \ + (((x) & BIT_MASK_PKTLEN_PARA) << BIT_SHIFT_PKTLEN_PARA) +#define BIT_GET_PKTLEN_PARA(x) \ + (((x) >> BIT_SHIFT_PKTLEN_PARA) & BIT_MASK_PKTLEN_PARA) + +/* 2 REG_RXDMA_MODE (Offset 0x0290) */ + +#define BIT_SHIFT_BURST_SIZE 4 +#define BIT_MASK_BURST_SIZE 0x3 +#define BIT_BURST_SIZE(x) (((x) & BIT_MASK_BURST_SIZE) << BIT_SHIFT_BURST_SIZE) +#define BIT_GET_BURST_SIZE(x) \ + (((x) >> BIT_SHIFT_BURST_SIZE) & BIT_MASK_BURST_SIZE) + +#define BIT_SHIFT_BURST_CNT 2 +#define BIT_MASK_BURST_CNT 0x3 +#define BIT_BURST_CNT(x) (((x) & BIT_MASK_BURST_CNT) << BIT_SHIFT_BURST_CNT) +#define BIT_GET_BURST_CNT(x) (((x) >> BIT_SHIFT_BURST_CNT) & BIT_MASK_BURST_CNT) + +/* 2 REG_RXDMA_MODE (Offset 0x0290) */ + +#define BIT_DMA_MODE BIT(1) + +/* 2 REG_C2H_PKT (Offset 0x0294) */ + +#define BIT_SHIFT_R_C2H_STR_ADDR_16_TO_19 24 +#define BIT_MASK_R_C2H_STR_ADDR_16_TO_19 0xf +#define BIT_R_C2H_STR_ADDR_16_TO_19(x) \ + (((x) & BIT_MASK_R_C2H_STR_ADDR_16_TO_19) \ + << BIT_SHIFT_R_C2H_STR_ADDR_16_TO_19) +#define BIT_GET_R_C2H_STR_ADDR_16_TO_19(x) \ + (((x) >> BIT_SHIFT_R_C2H_STR_ADDR_16_TO_19) & \ + BIT_MASK_R_C2H_STR_ADDR_16_TO_19) + +#define BIT_SHIFT_MDIO_PHY_ADDR 24 +#define BIT_MASK_MDIO_PHY_ADDR 0x1f +#define BIT_MDIO_PHY_ADDR(x) \ + (((x) & BIT_MASK_MDIO_PHY_ADDR) << BIT_SHIFT_MDIO_PHY_ADDR) +#define BIT_GET_MDIO_PHY_ADDR(x) \ + (((x) >> BIT_SHIFT_MDIO_PHY_ADDR) & BIT_MASK_MDIO_PHY_ADDR) + +/* 2 REG_C2H_PKT (Offset 0x0294) */ + +#define BIT_R_C2H_PKT_REQ BIT(16) +#define BIT_RX_CLOSE_EN BIT(15) +#define BIT_STOP_BCNQ BIT(14) +#define BIT_STOP_MGQ BIT(13) +#define BIT_STOP_VOQ BIT(12) +#define BIT_STOP_VIQ BIT(11) +#define BIT_STOP_BEQ BIT(10) +#define BIT_STOP_BKQ BIT(9) +#define BIT_STOP_RXQ BIT(8) +#define BIT_STOP_HI7Q BIT(7) +#define BIT_STOP_HI6Q BIT(6) +#define BIT_STOP_HI5Q BIT(5) +#define BIT_STOP_HI4Q BIT(4) +#define BIT_STOP_HI3Q BIT(3) +#define BIT_STOP_HI2Q BIT(2) +#define BIT_STOP_HI1Q BIT(1) + +#define BIT_SHIFT_R_C2H_STR_ADDR 0 +#define BIT_MASK_R_C2H_STR_ADDR 0xffff +#define BIT_R_C2H_STR_ADDR(x) \ + (((x) & BIT_MASK_R_C2H_STR_ADDR) << BIT_SHIFT_R_C2H_STR_ADDR) +#define BIT_GET_R_C2H_STR_ADDR(x) \ + (((x) >> BIT_SHIFT_R_C2H_STR_ADDR) & BIT_MASK_R_C2H_STR_ADDR) + +#define BIT_STOP_HI0Q BIT(0) + +/* 2 REG_FWFF_C2H (Offset 0x0298) */ + +#define BIT_SHIFT_C2H_DMA_ADDR 0 +#define BIT_MASK_C2H_DMA_ADDR 0x3ffff +#define BIT_C2H_DMA_ADDR(x) \ + (((x) & BIT_MASK_C2H_DMA_ADDR) << BIT_SHIFT_C2H_DMA_ADDR) +#define BIT_GET_C2H_DMA_ADDR(x) \ + (((x) >> BIT_SHIFT_C2H_DMA_ADDR) & BIT_MASK_C2H_DMA_ADDR) + +/* 2 REG_FWFF_CTRL (Offset 0x029C) */ + +#define BIT_FWFF_DMAPKT_REQ BIT(31) + +#define BIT_SHIFT_FWFF_DMA_PKT_NUM 16 +#define BIT_MASK_FWFF_DMA_PKT_NUM 0xff +#define BIT_FWFF_DMA_PKT_NUM(x) \ + (((x) & BIT_MASK_FWFF_DMA_PKT_NUM) << BIT_SHIFT_FWFF_DMA_PKT_NUM) +#define BIT_GET_FWFF_DMA_PKT_NUM(x) \ + (((x) >> BIT_SHIFT_FWFF_DMA_PKT_NUM) & BIT_MASK_FWFF_DMA_PKT_NUM) + +#define BIT_SHIFT_FWFF_STR_ADDR 0 +#define BIT_MASK_FWFF_STR_ADDR 0xffff +#define BIT_FWFF_STR_ADDR(x) \ + (((x) & BIT_MASK_FWFF_STR_ADDR) << BIT_SHIFT_FWFF_STR_ADDR) +#define BIT_GET_FWFF_STR_ADDR(x) \ + (((x) >> BIT_SHIFT_FWFF_STR_ADDR) & BIT_MASK_FWFF_STR_ADDR) + +/* 2 REG_FWFF_PKT_INFO (Offset 0x02A0) */ + +#define BIT_SHIFT_FWFF_PKT_QUEUED 16 +#define BIT_MASK_FWFF_PKT_QUEUED 0xff +#define BIT_FWFF_PKT_QUEUED(x) \ + (((x) & BIT_MASK_FWFF_PKT_QUEUED) << BIT_SHIFT_FWFF_PKT_QUEUED) +#define BIT_GET_FWFF_PKT_QUEUED(x) \ + (((x) >> BIT_SHIFT_FWFF_PKT_QUEUED) & BIT_MASK_FWFF_PKT_QUEUED) + +/* 2 REG_FWFF_PKT_INFO (Offset 0x02A0) */ + +#define BIT_SHIFT_FWFF_PKT_STR_ADDR 0 +#define BIT_MASK_FWFF_PKT_STR_ADDR 0xffff +#define BIT_FWFF_PKT_STR_ADDR(x) \ + (((x) & BIT_MASK_FWFF_PKT_STR_ADDR) << BIT_SHIFT_FWFF_PKT_STR_ADDR) +#define BIT_GET_FWFF_PKT_STR_ADDR(x) \ + (((x) >> BIT_SHIFT_FWFF_PKT_STR_ADDR) & BIT_MASK_FWFF_PKT_STR_ADDR) + +/* 2 REG_PCIE_CTRL (Offset 0x0300) */ + +#define BIT_PCIEIO_PERSTB_SEL BIT(31) + +/* 2 REG_PCIE_CTRL (Offset 0x0300) */ + +#define BIT_SHIFT_PCIE_MAX_RXDMA 28 +#define BIT_MASK_PCIE_MAX_RXDMA 0x7 +#define BIT_PCIE_MAX_RXDMA(x) \ + (((x) & BIT_MASK_PCIE_MAX_RXDMA) << BIT_SHIFT_PCIE_MAX_RXDMA) +#define BIT_GET_PCIE_MAX_RXDMA(x) \ + (((x) >> BIT_SHIFT_PCIE_MAX_RXDMA) & BIT_MASK_PCIE_MAX_RXDMA) + +/* 2 REG_PCIE_CTRL (Offset 0x0300) */ + +#define BIT_SHIFT_PCIE_MAX_TXDMA 24 +#define BIT_MASK_PCIE_MAX_TXDMA 0x7 +#define BIT_PCIE_MAX_TXDMA(x) \ + (((x) & BIT_MASK_PCIE_MAX_TXDMA) << BIT_SHIFT_PCIE_MAX_TXDMA) +#define BIT_GET_PCIE_MAX_TXDMA(x) \ + (((x) >> BIT_SHIFT_PCIE_MAX_TXDMA) & BIT_MASK_PCIE_MAX_TXDMA) + +/* 2 REG_PCIE_CTRL (Offset 0x0300) */ + +#define BIT_PCIE_RST_TRXDMA_INTF BIT(20) + +/* 2 REG_PCIE_CTRL (Offset 0x0300) */ + +#define BIT_PCIE_EN_SWENT_L23 BIT(17) + +/* 2 REG_PCIE_CTRL (Offset 0x0300) */ + +#define BIT_PCIE_EN_HWEXT_L1 BIT(16) + +/* 2 REG_INT_MIG (Offset 0x0304) */ + +#define BIT_SHIFT_TXTTIMER_MATCH_NUM 28 +#define BIT_MASK_TXTTIMER_MATCH_NUM 0xf +#define BIT_TXTTIMER_MATCH_NUM(x) \ + (((x) & BIT_MASK_TXTTIMER_MATCH_NUM) << BIT_SHIFT_TXTTIMER_MATCH_NUM) +#define BIT_GET_TXTTIMER_MATCH_NUM(x) \ + (((x) >> BIT_SHIFT_TXTTIMER_MATCH_NUM) & BIT_MASK_TXTTIMER_MATCH_NUM) + +#define BIT_SHIFT_TXPKT_NUM_MATCH 24 +#define BIT_MASK_TXPKT_NUM_MATCH 0xf +#define BIT_TXPKT_NUM_MATCH(x) \ + (((x) & BIT_MASK_TXPKT_NUM_MATCH) << BIT_SHIFT_TXPKT_NUM_MATCH) +#define BIT_GET_TXPKT_NUM_MATCH(x) \ + (((x) >> BIT_SHIFT_TXPKT_NUM_MATCH) & BIT_MASK_TXPKT_NUM_MATCH) + +#define BIT_SHIFT_RXTTIMER_MATCH_NUM 20 +#define BIT_MASK_RXTTIMER_MATCH_NUM 0xf +#define BIT_RXTTIMER_MATCH_NUM(x) \ + (((x) & BIT_MASK_RXTTIMER_MATCH_NUM) << BIT_SHIFT_RXTTIMER_MATCH_NUM) +#define BIT_GET_RXTTIMER_MATCH_NUM(x) \ + (((x) >> BIT_SHIFT_RXTTIMER_MATCH_NUM) & BIT_MASK_RXTTIMER_MATCH_NUM) + +#define BIT_SHIFT_RXPKT_NUM_MATCH 16 +#define BIT_MASK_RXPKT_NUM_MATCH 0xf +#define BIT_RXPKT_NUM_MATCH(x) \ + (((x) & BIT_MASK_RXPKT_NUM_MATCH) << BIT_SHIFT_RXPKT_NUM_MATCH) +#define BIT_GET_RXPKT_NUM_MATCH(x) \ + (((x) >> BIT_SHIFT_RXPKT_NUM_MATCH) & BIT_MASK_RXPKT_NUM_MATCH) + +#define BIT_SHIFT_MIGRATE_TIMER 0 +#define BIT_MASK_MIGRATE_TIMER 0xffff +#define BIT_MIGRATE_TIMER(x) \ + (((x) & BIT_MASK_MIGRATE_TIMER) << BIT_SHIFT_MIGRATE_TIMER) +#define BIT_GET_MIGRATE_TIMER(x) \ + (((x) >> BIT_SHIFT_MIGRATE_TIMER) & BIT_MASK_MIGRATE_TIMER) + +/* 2 REG_BCNQ_TXBD_DESA (Offset 0x0308) */ + +#define BIT_SHIFT_BCNQ_TXBD_DESA 0 +#define BIT_MASK_BCNQ_TXBD_DESA 0xffffffffffffffffL +#define BIT_BCNQ_TXBD_DESA(x) \ + (((x) & BIT_MASK_BCNQ_TXBD_DESA) << BIT_SHIFT_BCNQ_TXBD_DESA) +#define BIT_GET_BCNQ_TXBD_DESA(x) \ + (((x) >> BIT_SHIFT_BCNQ_TXBD_DESA) & BIT_MASK_BCNQ_TXBD_DESA) + +/* 2 REG_MGQ_TXBD_DESA (Offset 0x0310) */ + +#define BIT_SHIFT_MGQ_TXBD_DESA 0 +#define BIT_MASK_MGQ_TXBD_DESA 0xffffffffffffffffL +#define BIT_MGQ_TXBD_DESA(x) \ + (((x) & BIT_MASK_MGQ_TXBD_DESA) << BIT_SHIFT_MGQ_TXBD_DESA) +#define BIT_GET_MGQ_TXBD_DESA(x) \ + (((x) >> BIT_SHIFT_MGQ_TXBD_DESA) & BIT_MASK_MGQ_TXBD_DESA) + +/* 2 REG_VOQ_TXBD_DESA (Offset 0x0318) */ + +#define BIT_SHIFT_VOQ_TXBD_DESA 0 +#define BIT_MASK_VOQ_TXBD_DESA 0xffffffffffffffffL +#define BIT_VOQ_TXBD_DESA(x) \ + (((x) & BIT_MASK_VOQ_TXBD_DESA) << BIT_SHIFT_VOQ_TXBD_DESA) +#define BIT_GET_VOQ_TXBD_DESA(x) \ + (((x) >> BIT_SHIFT_VOQ_TXBD_DESA) & BIT_MASK_VOQ_TXBD_DESA) + +/* 2 REG_VIQ_TXBD_DESA (Offset 0x0320) */ + +#define BIT_SHIFT_VIQ_TXBD_DESA 0 +#define BIT_MASK_VIQ_TXBD_DESA 0xffffffffffffffffL +#define BIT_VIQ_TXBD_DESA(x) \ + (((x) & BIT_MASK_VIQ_TXBD_DESA) << BIT_SHIFT_VIQ_TXBD_DESA) +#define BIT_GET_VIQ_TXBD_DESA(x) \ + (((x) >> BIT_SHIFT_VIQ_TXBD_DESA) & BIT_MASK_VIQ_TXBD_DESA) + +/* 2 REG_BEQ_TXBD_DESA (Offset 0x0328) */ + +#define BIT_SHIFT_BEQ_TXBD_DESA 0 +#define BIT_MASK_BEQ_TXBD_DESA 0xffffffffffffffffL +#define BIT_BEQ_TXBD_DESA(x) \ + (((x) & BIT_MASK_BEQ_TXBD_DESA) << BIT_SHIFT_BEQ_TXBD_DESA) +#define BIT_GET_BEQ_TXBD_DESA(x) \ + (((x) >> BIT_SHIFT_BEQ_TXBD_DESA) & BIT_MASK_BEQ_TXBD_DESA) + +/* 2 REG_BKQ_TXBD_DESA (Offset 0x0330) */ + +#define BIT_SHIFT_BKQ_TXBD_DESA 0 +#define BIT_MASK_BKQ_TXBD_DESA 0xffffffffffffffffL +#define BIT_BKQ_TXBD_DESA(x) \ + (((x) & BIT_MASK_BKQ_TXBD_DESA) << BIT_SHIFT_BKQ_TXBD_DESA) +#define BIT_GET_BKQ_TXBD_DESA(x) \ + (((x) >> BIT_SHIFT_BKQ_TXBD_DESA) & BIT_MASK_BKQ_TXBD_DESA) + +/* 2 REG_RXQ_RXBD_DESA (Offset 0x0338) */ + +#define BIT_SHIFT_RXQ_RXBD_DESA 0 +#define BIT_MASK_RXQ_RXBD_DESA 0xffffffffffffffffL +#define BIT_RXQ_RXBD_DESA(x) \ + (((x) & BIT_MASK_RXQ_RXBD_DESA) << BIT_SHIFT_RXQ_RXBD_DESA) +#define BIT_GET_RXQ_RXBD_DESA(x) \ + (((x) >> BIT_SHIFT_RXQ_RXBD_DESA) & BIT_MASK_RXQ_RXBD_DESA) + +/* 2 REG_HI0Q_TXBD_DESA (Offset 0x0340) */ + +#define BIT_SHIFT_HI0Q_TXBD_DESA 0 +#define BIT_MASK_HI0Q_TXBD_DESA 0xffffffffffffffffL +#define BIT_HI0Q_TXBD_DESA(x) \ + (((x) & BIT_MASK_HI0Q_TXBD_DESA) << BIT_SHIFT_HI0Q_TXBD_DESA) +#define BIT_GET_HI0Q_TXBD_DESA(x) \ + (((x) >> BIT_SHIFT_HI0Q_TXBD_DESA) & BIT_MASK_HI0Q_TXBD_DESA) + +/* 2 REG_HI1Q_TXBD_DESA (Offset 0x0348) */ + +#define BIT_SHIFT_HI1Q_TXBD_DESA 0 +#define BIT_MASK_HI1Q_TXBD_DESA 0xffffffffffffffffL +#define BIT_HI1Q_TXBD_DESA(x) \ + (((x) & BIT_MASK_HI1Q_TXBD_DESA) << BIT_SHIFT_HI1Q_TXBD_DESA) +#define BIT_GET_HI1Q_TXBD_DESA(x) \ + (((x) >> BIT_SHIFT_HI1Q_TXBD_DESA) & BIT_MASK_HI1Q_TXBD_DESA) + +/* 2 REG_HI2Q_TXBD_DESA (Offset 0x0350) */ + +#define BIT_SHIFT_HI2Q_TXBD_DESA 0 +#define BIT_MASK_HI2Q_TXBD_DESA 0xffffffffffffffffL +#define BIT_HI2Q_TXBD_DESA(x) \ + (((x) & BIT_MASK_HI2Q_TXBD_DESA) << BIT_SHIFT_HI2Q_TXBD_DESA) +#define BIT_GET_HI2Q_TXBD_DESA(x) \ + (((x) >> BIT_SHIFT_HI2Q_TXBD_DESA) & BIT_MASK_HI2Q_TXBD_DESA) + +/* 2 REG_HI3Q_TXBD_DESA (Offset 0x0358) */ + +#define BIT_SHIFT_HI3Q_TXBD_DESA 0 +#define BIT_MASK_HI3Q_TXBD_DESA 0xffffffffffffffffL +#define BIT_HI3Q_TXBD_DESA(x) \ + (((x) & BIT_MASK_HI3Q_TXBD_DESA) << BIT_SHIFT_HI3Q_TXBD_DESA) +#define BIT_GET_HI3Q_TXBD_DESA(x) \ + (((x) >> BIT_SHIFT_HI3Q_TXBD_DESA) & BIT_MASK_HI3Q_TXBD_DESA) + +/* 2 REG_HI4Q_TXBD_DESA (Offset 0x0360) */ + +#define BIT_SHIFT_HI4Q_TXBD_DESA 0 +#define BIT_MASK_HI4Q_TXBD_DESA 0xffffffffffffffffL +#define BIT_HI4Q_TXBD_DESA(x) \ + (((x) & BIT_MASK_HI4Q_TXBD_DESA) << BIT_SHIFT_HI4Q_TXBD_DESA) +#define BIT_GET_HI4Q_TXBD_DESA(x) \ + (((x) >> BIT_SHIFT_HI4Q_TXBD_DESA) & BIT_MASK_HI4Q_TXBD_DESA) + +/* 2 REG_HI5Q_TXBD_DESA (Offset 0x0368) */ + +#define BIT_SHIFT_HI5Q_TXBD_DESA 0 +#define BIT_MASK_HI5Q_TXBD_DESA 0xffffffffffffffffL +#define BIT_HI5Q_TXBD_DESA(x) \ + (((x) & BIT_MASK_HI5Q_TXBD_DESA) << BIT_SHIFT_HI5Q_TXBD_DESA) +#define BIT_GET_HI5Q_TXBD_DESA(x) \ + (((x) >> BIT_SHIFT_HI5Q_TXBD_DESA) & BIT_MASK_HI5Q_TXBD_DESA) + +/* 2 REG_HI6Q_TXBD_DESA (Offset 0x0370) */ + +#define BIT_SHIFT_HI6Q_TXBD_DESA 0 +#define BIT_MASK_HI6Q_TXBD_DESA 0xffffffffffffffffL +#define BIT_HI6Q_TXBD_DESA(x) \ + (((x) & BIT_MASK_HI6Q_TXBD_DESA) << BIT_SHIFT_HI6Q_TXBD_DESA) +#define BIT_GET_HI6Q_TXBD_DESA(x) \ + (((x) >> BIT_SHIFT_HI6Q_TXBD_DESA) & BIT_MASK_HI6Q_TXBD_DESA) + +/* 2 REG_HI7Q_TXBD_DESA (Offset 0x0378) */ + +#define BIT_SHIFT_HI7Q_TXBD_DESA 0 +#define BIT_MASK_HI7Q_TXBD_DESA 0xffffffffffffffffL +#define BIT_HI7Q_TXBD_DESA(x) \ + (((x) & BIT_MASK_HI7Q_TXBD_DESA) << BIT_SHIFT_HI7Q_TXBD_DESA) +#define BIT_GET_HI7Q_TXBD_DESA(x) \ + (((x) >> BIT_SHIFT_HI7Q_TXBD_DESA) & BIT_MASK_HI7Q_TXBD_DESA) + +/* 2 REG_MGQ_TXBD_NUM (Offset 0x0380) */ + +#define BIT_PCIE_MGQ_FLAG BIT(14) + +/* 2 REG_MGQ_TXBD_NUM (Offset 0x0380) */ + +#define BIT_SHIFT_MGQ_DESC_MODE 12 +#define BIT_MASK_MGQ_DESC_MODE 0x3 +#define BIT_MGQ_DESC_MODE(x) \ + (((x) & BIT_MASK_MGQ_DESC_MODE) << BIT_SHIFT_MGQ_DESC_MODE) +#define BIT_GET_MGQ_DESC_MODE(x) \ + (((x) >> BIT_SHIFT_MGQ_DESC_MODE) & BIT_MASK_MGQ_DESC_MODE) + +#define BIT_SHIFT_MGQ_DESC_NUM 0 +#define BIT_MASK_MGQ_DESC_NUM 0xfff +#define BIT_MGQ_DESC_NUM(x) \ + (((x) & BIT_MASK_MGQ_DESC_NUM) << BIT_SHIFT_MGQ_DESC_NUM) +#define BIT_GET_MGQ_DESC_NUM(x) \ + (((x) >> BIT_SHIFT_MGQ_DESC_NUM) & BIT_MASK_MGQ_DESC_NUM) + +/* 2 REG_RX_RXBD_NUM (Offset 0x0382) */ + +#define BIT_SYS_32_64 BIT(15) + +#define BIT_SHIFT_BCNQ_DESC_MODE 13 +#define BIT_MASK_BCNQ_DESC_MODE 0x3 +#define BIT_BCNQ_DESC_MODE(x) \ + (((x) & BIT_MASK_BCNQ_DESC_MODE) << BIT_SHIFT_BCNQ_DESC_MODE) +#define BIT_GET_BCNQ_DESC_MODE(x) \ + (((x) >> BIT_SHIFT_BCNQ_DESC_MODE) & BIT_MASK_BCNQ_DESC_MODE) + +/* 2 REG_RX_RXBD_NUM (Offset 0x0382) */ + +#define BIT_PCIE_BCNQ_FLAG BIT(12) + +/* 2 REG_RX_RXBD_NUM (Offset 0x0382) */ + +#define BIT_SHIFT_RXQ_DESC_NUM 0 +#define BIT_MASK_RXQ_DESC_NUM 0xfff +#define BIT_RXQ_DESC_NUM(x) \ + (((x) & BIT_MASK_RXQ_DESC_NUM) << BIT_SHIFT_RXQ_DESC_NUM) +#define BIT_GET_RXQ_DESC_NUM(x) \ + (((x) >> BIT_SHIFT_RXQ_DESC_NUM) & BIT_MASK_RXQ_DESC_NUM) + +/* 2 REG_VOQ_TXBD_NUM (Offset 0x0384) */ + +#define BIT_PCIE_VOQ_FLAG BIT(14) + +/* 2 REG_VOQ_TXBD_NUM (Offset 0x0384) */ + +#define BIT_SHIFT_VOQ_DESC_MODE 12 +#define BIT_MASK_VOQ_DESC_MODE 0x3 +#define BIT_VOQ_DESC_MODE(x) \ + (((x) & BIT_MASK_VOQ_DESC_MODE) << BIT_SHIFT_VOQ_DESC_MODE) +#define BIT_GET_VOQ_DESC_MODE(x) \ + (((x) >> BIT_SHIFT_VOQ_DESC_MODE) & BIT_MASK_VOQ_DESC_MODE) + +#define BIT_SHIFT_VOQ_DESC_NUM 0 +#define BIT_MASK_VOQ_DESC_NUM 0xfff +#define BIT_VOQ_DESC_NUM(x) \ + (((x) & BIT_MASK_VOQ_DESC_NUM) << BIT_SHIFT_VOQ_DESC_NUM) +#define BIT_GET_VOQ_DESC_NUM(x) \ + (((x) >> BIT_SHIFT_VOQ_DESC_NUM) & BIT_MASK_VOQ_DESC_NUM) + +/* 2 REG_VIQ_TXBD_NUM (Offset 0x0386) */ + +#define BIT_PCIE_VIQ_FLAG BIT(14) + +/* 2 REG_VIQ_TXBD_NUM (Offset 0x0386) */ + +#define BIT_SHIFT_VIQ_DESC_MODE 12 +#define BIT_MASK_VIQ_DESC_MODE 0x3 +#define BIT_VIQ_DESC_MODE(x) \ + (((x) & BIT_MASK_VIQ_DESC_MODE) << BIT_SHIFT_VIQ_DESC_MODE) +#define BIT_GET_VIQ_DESC_MODE(x) \ + (((x) >> BIT_SHIFT_VIQ_DESC_MODE) & BIT_MASK_VIQ_DESC_MODE) + +#define BIT_SHIFT_VIQ_DESC_NUM 0 +#define BIT_MASK_VIQ_DESC_NUM 0xfff +#define BIT_VIQ_DESC_NUM(x) \ + (((x) & BIT_MASK_VIQ_DESC_NUM) << BIT_SHIFT_VIQ_DESC_NUM) +#define BIT_GET_VIQ_DESC_NUM(x) \ + (((x) >> BIT_SHIFT_VIQ_DESC_NUM) & BIT_MASK_VIQ_DESC_NUM) + +/* 2 REG_BEQ_TXBD_NUM (Offset 0x0388) */ + +#define BIT_PCIE_BEQ_FLAG BIT(14) + +/* 2 REG_BEQ_TXBD_NUM (Offset 0x0388) */ + +#define BIT_SHIFT_BEQ_DESC_MODE 12 +#define BIT_MASK_BEQ_DESC_MODE 0x3 +#define BIT_BEQ_DESC_MODE(x) \ + (((x) & BIT_MASK_BEQ_DESC_MODE) << BIT_SHIFT_BEQ_DESC_MODE) +#define BIT_GET_BEQ_DESC_MODE(x) \ + (((x) >> BIT_SHIFT_BEQ_DESC_MODE) & BIT_MASK_BEQ_DESC_MODE) + +#define BIT_SHIFT_BEQ_DESC_NUM 0 +#define BIT_MASK_BEQ_DESC_NUM 0xfff +#define BIT_BEQ_DESC_NUM(x) \ + (((x) & BIT_MASK_BEQ_DESC_NUM) << BIT_SHIFT_BEQ_DESC_NUM) +#define BIT_GET_BEQ_DESC_NUM(x) \ + (((x) >> BIT_SHIFT_BEQ_DESC_NUM) & BIT_MASK_BEQ_DESC_NUM) + +/* 2 REG_BKQ_TXBD_NUM (Offset 0x038A) */ + +#define BIT_PCIE_BKQ_FLAG BIT(14) + +/* 2 REG_BKQ_TXBD_NUM (Offset 0x038A) */ + +#define BIT_SHIFT_BKQ_DESC_MODE 12 +#define BIT_MASK_BKQ_DESC_MODE 0x3 +#define BIT_BKQ_DESC_MODE(x) \ + (((x) & BIT_MASK_BKQ_DESC_MODE) << BIT_SHIFT_BKQ_DESC_MODE) +#define BIT_GET_BKQ_DESC_MODE(x) \ + (((x) >> BIT_SHIFT_BKQ_DESC_MODE) & BIT_MASK_BKQ_DESC_MODE) + +#define BIT_SHIFT_BKQ_DESC_NUM 0 +#define BIT_MASK_BKQ_DESC_NUM 0xfff +#define BIT_BKQ_DESC_NUM(x) \ + (((x) & BIT_MASK_BKQ_DESC_NUM) << BIT_SHIFT_BKQ_DESC_NUM) +#define BIT_GET_BKQ_DESC_NUM(x) \ + (((x) >> BIT_SHIFT_BKQ_DESC_NUM) & BIT_MASK_BKQ_DESC_NUM) + +/* 2 REG_HI0Q_TXBD_NUM (Offset 0x038C) */ + +#define BIT_HI0Q_FLAG BIT(14) + +#define BIT_SHIFT_HI0Q_DESC_MODE 12 +#define BIT_MASK_HI0Q_DESC_MODE 0x3 +#define BIT_HI0Q_DESC_MODE(x) \ + (((x) & BIT_MASK_HI0Q_DESC_MODE) << BIT_SHIFT_HI0Q_DESC_MODE) +#define BIT_GET_HI0Q_DESC_MODE(x) \ + (((x) >> BIT_SHIFT_HI0Q_DESC_MODE) & BIT_MASK_HI0Q_DESC_MODE) + +#define BIT_SHIFT_HI0Q_DESC_NUM 0 +#define BIT_MASK_HI0Q_DESC_NUM 0xfff +#define BIT_HI0Q_DESC_NUM(x) \ + (((x) & BIT_MASK_HI0Q_DESC_NUM) << BIT_SHIFT_HI0Q_DESC_NUM) +#define BIT_GET_HI0Q_DESC_NUM(x) \ + (((x) >> BIT_SHIFT_HI0Q_DESC_NUM) & BIT_MASK_HI0Q_DESC_NUM) + +/* 2 REG_HI1Q_TXBD_NUM (Offset 0x038E) */ + +#define BIT_HI1Q_FLAG BIT(14) + +#define BIT_SHIFT_HI1Q_DESC_MODE 12 +#define BIT_MASK_HI1Q_DESC_MODE 0x3 +#define BIT_HI1Q_DESC_MODE(x) \ + (((x) & BIT_MASK_HI1Q_DESC_MODE) << BIT_SHIFT_HI1Q_DESC_MODE) +#define BIT_GET_HI1Q_DESC_MODE(x) \ + (((x) >> BIT_SHIFT_HI1Q_DESC_MODE) & BIT_MASK_HI1Q_DESC_MODE) + +#define BIT_SHIFT_HI1Q_DESC_NUM 0 +#define BIT_MASK_HI1Q_DESC_NUM 0xfff +#define BIT_HI1Q_DESC_NUM(x) \ + (((x) & BIT_MASK_HI1Q_DESC_NUM) << BIT_SHIFT_HI1Q_DESC_NUM) +#define BIT_GET_HI1Q_DESC_NUM(x) \ + (((x) >> BIT_SHIFT_HI1Q_DESC_NUM) & BIT_MASK_HI1Q_DESC_NUM) + +/* 2 REG_HI2Q_TXBD_NUM (Offset 0x0390) */ + +#define BIT_HI2Q_FLAG BIT(14) + +#define BIT_SHIFT_HI2Q_DESC_MODE 12 +#define BIT_MASK_HI2Q_DESC_MODE 0x3 +#define BIT_HI2Q_DESC_MODE(x) \ + (((x) & BIT_MASK_HI2Q_DESC_MODE) << BIT_SHIFT_HI2Q_DESC_MODE) +#define BIT_GET_HI2Q_DESC_MODE(x) \ + (((x) >> BIT_SHIFT_HI2Q_DESC_MODE) & BIT_MASK_HI2Q_DESC_MODE) + +#define BIT_SHIFT_HI2Q_DESC_NUM 0 +#define BIT_MASK_HI2Q_DESC_NUM 0xfff +#define BIT_HI2Q_DESC_NUM(x) \ + (((x) & BIT_MASK_HI2Q_DESC_NUM) << BIT_SHIFT_HI2Q_DESC_NUM) +#define BIT_GET_HI2Q_DESC_NUM(x) \ + (((x) >> BIT_SHIFT_HI2Q_DESC_NUM) & BIT_MASK_HI2Q_DESC_NUM) + +/* 2 REG_HI3Q_TXBD_NUM (Offset 0x0392) */ + +#define BIT_HI3Q_FLAG BIT(14) + +#define BIT_SHIFT_HI3Q_DESC_MODE 12 +#define BIT_MASK_HI3Q_DESC_MODE 0x3 +#define BIT_HI3Q_DESC_MODE(x) \ + (((x) & BIT_MASK_HI3Q_DESC_MODE) << BIT_SHIFT_HI3Q_DESC_MODE) +#define BIT_GET_HI3Q_DESC_MODE(x) \ + (((x) >> BIT_SHIFT_HI3Q_DESC_MODE) & BIT_MASK_HI3Q_DESC_MODE) + +#define BIT_SHIFT_HI3Q_DESC_NUM 0 +#define BIT_MASK_HI3Q_DESC_NUM 0xfff +#define BIT_HI3Q_DESC_NUM(x) \ + (((x) & BIT_MASK_HI3Q_DESC_NUM) << BIT_SHIFT_HI3Q_DESC_NUM) +#define BIT_GET_HI3Q_DESC_NUM(x) \ + (((x) >> BIT_SHIFT_HI3Q_DESC_NUM) & BIT_MASK_HI3Q_DESC_NUM) + +/* 2 REG_HI4Q_TXBD_NUM (Offset 0x0394) */ + +#define BIT_HI4Q_FLAG BIT(14) + +#define BIT_SHIFT_HI4Q_DESC_MODE 12 +#define BIT_MASK_HI4Q_DESC_MODE 0x3 +#define BIT_HI4Q_DESC_MODE(x) \ + (((x) & BIT_MASK_HI4Q_DESC_MODE) << BIT_SHIFT_HI4Q_DESC_MODE) +#define BIT_GET_HI4Q_DESC_MODE(x) \ + (((x) >> BIT_SHIFT_HI4Q_DESC_MODE) & BIT_MASK_HI4Q_DESC_MODE) + +#define BIT_SHIFT_HI4Q_DESC_NUM 0 +#define BIT_MASK_HI4Q_DESC_NUM 0xfff +#define BIT_HI4Q_DESC_NUM(x) \ + (((x) & BIT_MASK_HI4Q_DESC_NUM) << BIT_SHIFT_HI4Q_DESC_NUM) +#define BIT_GET_HI4Q_DESC_NUM(x) \ + (((x) >> BIT_SHIFT_HI4Q_DESC_NUM) & BIT_MASK_HI4Q_DESC_NUM) + +/* 2 REG_HI5Q_TXBD_NUM (Offset 0x0396) */ + +#define BIT_HI5Q_FLAG BIT(14) + +#define BIT_SHIFT_HI5Q_DESC_MODE 12 +#define BIT_MASK_HI5Q_DESC_MODE 0x3 +#define BIT_HI5Q_DESC_MODE(x) \ + (((x) & BIT_MASK_HI5Q_DESC_MODE) << BIT_SHIFT_HI5Q_DESC_MODE) +#define BIT_GET_HI5Q_DESC_MODE(x) \ + (((x) >> BIT_SHIFT_HI5Q_DESC_MODE) & BIT_MASK_HI5Q_DESC_MODE) + +#define BIT_SHIFT_HI5Q_DESC_NUM 0 +#define BIT_MASK_HI5Q_DESC_NUM 0xfff +#define BIT_HI5Q_DESC_NUM(x) \ + (((x) & BIT_MASK_HI5Q_DESC_NUM) << BIT_SHIFT_HI5Q_DESC_NUM) +#define BIT_GET_HI5Q_DESC_NUM(x) \ + (((x) >> BIT_SHIFT_HI5Q_DESC_NUM) & BIT_MASK_HI5Q_DESC_NUM) + +/* 2 REG_HI6Q_TXBD_NUM (Offset 0x0398) */ + +#define BIT_HI6Q_FLAG BIT(14) + +#define BIT_SHIFT_HI6Q_DESC_MODE 12 +#define BIT_MASK_HI6Q_DESC_MODE 0x3 +#define BIT_HI6Q_DESC_MODE(x) \ + (((x) & BIT_MASK_HI6Q_DESC_MODE) << BIT_SHIFT_HI6Q_DESC_MODE) +#define BIT_GET_HI6Q_DESC_MODE(x) \ + (((x) >> BIT_SHIFT_HI6Q_DESC_MODE) & BIT_MASK_HI6Q_DESC_MODE) + +#define BIT_SHIFT_HI6Q_DESC_NUM 0 +#define BIT_MASK_HI6Q_DESC_NUM 0xfff +#define BIT_HI6Q_DESC_NUM(x) \ + (((x) & BIT_MASK_HI6Q_DESC_NUM) << BIT_SHIFT_HI6Q_DESC_NUM) +#define BIT_GET_HI6Q_DESC_NUM(x) \ + (((x) >> BIT_SHIFT_HI6Q_DESC_NUM) & BIT_MASK_HI6Q_DESC_NUM) + +/* 2 REG_HI7Q_TXBD_NUM (Offset 0x039A) */ + +#define BIT_HI7Q_FLAG BIT(14) + +#define BIT_SHIFT_HI7Q_DESC_MODE 12 +#define BIT_MASK_HI7Q_DESC_MODE 0x3 +#define BIT_HI7Q_DESC_MODE(x) \ + (((x) & BIT_MASK_HI7Q_DESC_MODE) << BIT_SHIFT_HI7Q_DESC_MODE) +#define BIT_GET_HI7Q_DESC_MODE(x) \ + (((x) >> BIT_SHIFT_HI7Q_DESC_MODE) & BIT_MASK_HI7Q_DESC_MODE) + +#define BIT_SHIFT_HI7Q_DESC_NUM 0 +#define BIT_MASK_HI7Q_DESC_NUM 0xfff +#define BIT_HI7Q_DESC_NUM(x) \ + (((x) & BIT_MASK_HI7Q_DESC_NUM) << BIT_SHIFT_HI7Q_DESC_NUM) +#define BIT_GET_HI7Q_DESC_NUM(x) \ + (((x) >> BIT_SHIFT_HI7Q_DESC_NUM) & BIT_MASK_HI7Q_DESC_NUM) + +/* 2 REG_BD_RWPTR_CLR (Offset 0x039C) */ + +#define BIT_CLR_HI7Q_HW_IDX BIT(29) +#define BIT_CLR_HI6Q_HW_IDX BIT(28) +#define BIT_CLR_HI5Q_HW_IDX BIT(27) +#define BIT_CLR_HI4Q_HW_IDX BIT(26) +#define BIT_CLR_HI3Q_HW_IDX BIT(25) +#define BIT_CLR_HI2Q_HW_IDX BIT(24) +#define BIT_CLR_HI1Q_HW_IDX BIT(23) + +/* 2 REG_BD_RWPTR_CLR (Offset 0x039C) */ + +#define BIT_CLR_HI0Q_HW_IDX BIT(22) + +/* 2 REG_BD_RWPTR_CLR (Offset 0x039C) */ + +#define BIT_CLR_BKQ_HW_IDX BIT(21) + +/* 2 REG_BD_RWPTR_CLR (Offset 0x039C) */ + +#define BIT_CLR_BEQ_HW_IDX BIT(20) + +/* 2 REG_BD_RWPTR_CLR (Offset 0x039C) */ + +#define BIT_CLR_VIQ_HW_IDX BIT(19) + +/* 2 REG_BD_RWPTR_CLR (Offset 0x039C) */ + +#define BIT_CLR_VOQ_HW_IDX BIT(18) + +/* 2 REG_BD_RWPTR_CLR (Offset 0x039C) */ + +#define BIT_CLR_MGQ_HW_IDX BIT(17) + +/* 2 REG_TSFTIMER_HCI (Offset 0x039C) */ + +#define BIT_SHIFT_TSFT2_HCI 16 +#define BIT_MASK_TSFT2_HCI 0xffff +#define BIT_TSFT2_HCI(x) (((x) & BIT_MASK_TSFT2_HCI) << BIT_SHIFT_TSFT2_HCI) +#define BIT_GET_TSFT2_HCI(x) (((x) >> BIT_SHIFT_TSFT2_HCI) & BIT_MASK_TSFT2_HCI) + +#define BIT_CLR_RXQ_HW_IDX BIT(16) + +/* 2 REG_BD_RWPTR_CLR (Offset 0x039C) */ + +#define BIT_CLR_HI7Q_HOST_IDX BIT(13) + +/* 2 REG_BD_RWPTR_CLR (Offset 0x039C) */ + +#define BIT_CLR_HI6Q_HOST_IDX BIT(12) + +/* 2 REG_BD_RWPTR_CLR (Offset 0x039C) */ + +#define BIT_CLR_HI5Q_HOST_IDX BIT(11) + +/* 2 REG_BD_RWPTR_CLR (Offset 0x039C) */ + +#define BIT_CLR_HI4Q_HOST_IDX BIT(10) + +/* 2 REG_BD_RWPTR_CLR (Offset 0x039C) */ + +#define BIT_CLR_HI3Q_HOST_IDX BIT(9) + +/* 2 REG_BD_RWPTR_CLR (Offset 0x039C) */ + +#define BIT_CLR_HI2Q_HOST_IDX BIT(8) + +/* 2 REG_BD_RWPTR_CLR (Offset 0x039C) */ + +#define BIT_CLR_HI1Q_HOST_IDX BIT(7) +#define BIT_CLR_HI0Q_HOST_IDX BIT(6) + +/* 2 REG_BD_RWPTR_CLR (Offset 0x039C) */ + +#define BIT_CLR_BKQ_HOST_IDX BIT(5) + +/* 2 REG_BD_RWPTR_CLR (Offset 0x039C) */ + +#define BIT_CLR_BEQ_HOST_IDX BIT(4) + +/* 2 REG_BD_RWPTR_CLR (Offset 0x039C) */ + +#define BIT_CLR_VIQ_HOST_IDX BIT(3) + +/* 2 REG_BD_RWPTR_CLR (Offset 0x039C) */ + +#define BIT_CLR_VOQ_HOST_IDX BIT(2) + +/* 2 REG_BD_RWPTR_CLR (Offset 0x039C) */ + +#define BIT_CLR_MGQ_HOST_IDX BIT(1) + +/* 2 REG_TSFTIMER_HCI (Offset 0x039C) */ + +#define BIT_SHIFT_TSFT1_HCI 0 +#define BIT_MASK_TSFT1_HCI 0xffff +#define BIT_TSFT1_HCI(x) (((x) & BIT_MASK_TSFT1_HCI) << BIT_SHIFT_TSFT1_HCI) +#define BIT_GET_TSFT1_HCI(x) (((x) >> BIT_SHIFT_TSFT1_HCI) & BIT_MASK_TSFT1_HCI) + +#define BIT_CLR_RXQ_HOST_IDX BIT(0) + +/* 2 REG_VOQ_TXBD_IDX (Offset 0x03A0) */ + +#define BIT_SHIFT_VOQ_HW_IDX 16 +#define BIT_MASK_VOQ_HW_IDX 0xfff +#define BIT_VOQ_HW_IDX(x) (((x) & BIT_MASK_VOQ_HW_IDX) << BIT_SHIFT_VOQ_HW_IDX) +#define BIT_GET_VOQ_HW_IDX(x) \ + (((x) >> BIT_SHIFT_VOQ_HW_IDX) & BIT_MASK_VOQ_HW_IDX) + +#define BIT_SHIFT_VOQ_HOST_IDX 0 +#define BIT_MASK_VOQ_HOST_IDX 0xfff +#define BIT_VOQ_HOST_IDX(x) \ + (((x) & BIT_MASK_VOQ_HOST_IDX) << BIT_SHIFT_VOQ_HOST_IDX) +#define BIT_GET_VOQ_HOST_IDX(x) \ + (((x) >> BIT_SHIFT_VOQ_HOST_IDX) & BIT_MASK_VOQ_HOST_IDX) + +/* 2 REG_VIQ_TXBD_IDX (Offset 0x03A4) */ + +#define BIT_SHIFT_VIQ_HW_IDX 16 +#define BIT_MASK_VIQ_HW_IDX 0xfff +#define BIT_VIQ_HW_IDX(x) (((x) & BIT_MASK_VIQ_HW_IDX) << BIT_SHIFT_VIQ_HW_IDX) +#define BIT_GET_VIQ_HW_IDX(x) \ + (((x) >> BIT_SHIFT_VIQ_HW_IDX) & BIT_MASK_VIQ_HW_IDX) + +#define BIT_SHIFT_VIQ_HOST_IDX 0 +#define BIT_MASK_VIQ_HOST_IDX 0xfff +#define BIT_VIQ_HOST_IDX(x) \ + (((x) & BIT_MASK_VIQ_HOST_IDX) << BIT_SHIFT_VIQ_HOST_IDX) +#define BIT_GET_VIQ_HOST_IDX(x) \ + (((x) >> BIT_SHIFT_VIQ_HOST_IDX) & BIT_MASK_VIQ_HOST_IDX) + +/* 2 REG_BEQ_TXBD_IDX (Offset 0x03A8) */ + +#define BIT_SHIFT_BEQ_HW_IDX 16 +#define BIT_MASK_BEQ_HW_IDX 0xfff +#define BIT_BEQ_HW_IDX(x) (((x) & BIT_MASK_BEQ_HW_IDX) << BIT_SHIFT_BEQ_HW_IDX) +#define BIT_GET_BEQ_HW_IDX(x) \ + (((x) >> BIT_SHIFT_BEQ_HW_IDX) & BIT_MASK_BEQ_HW_IDX) + +#define BIT_SHIFT_BEQ_HOST_IDX 0 +#define BIT_MASK_BEQ_HOST_IDX 0xfff +#define BIT_BEQ_HOST_IDX(x) \ + (((x) & BIT_MASK_BEQ_HOST_IDX) << BIT_SHIFT_BEQ_HOST_IDX) +#define BIT_GET_BEQ_HOST_IDX(x) \ + (((x) >> BIT_SHIFT_BEQ_HOST_IDX) & BIT_MASK_BEQ_HOST_IDX) + +/* 2 REG_BKQ_TXBD_IDX (Offset 0x03AC) */ + +#define BIT_SHIFT_BKQ_HW_IDX 16 +#define BIT_MASK_BKQ_HW_IDX 0xfff +#define BIT_BKQ_HW_IDX(x) (((x) & BIT_MASK_BKQ_HW_IDX) << BIT_SHIFT_BKQ_HW_IDX) +#define BIT_GET_BKQ_HW_IDX(x) \ + (((x) >> BIT_SHIFT_BKQ_HW_IDX) & BIT_MASK_BKQ_HW_IDX) + +#define BIT_SHIFT_BKQ_HOST_IDX 0 +#define BIT_MASK_BKQ_HOST_IDX 0xfff +#define BIT_BKQ_HOST_IDX(x) \ + (((x) & BIT_MASK_BKQ_HOST_IDX) << BIT_SHIFT_BKQ_HOST_IDX) +#define BIT_GET_BKQ_HOST_IDX(x) \ + (((x) >> BIT_SHIFT_BKQ_HOST_IDX) & BIT_MASK_BKQ_HOST_IDX) + +/* 2 REG_MGQ_TXBD_IDX (Offset 0x03B0) */ + +#define BIT_SHIFT_MGQ_HW_IDX 16 +#define BIT_MASK_MGQ_HW_IDX 0xfff +#define BIT_MGQ_HW_IDX(x) (((x) & BIT_MASK_MGQ_HW_IDX) << BIT_SHIFT_MGQ_HW_IDX) +#define BIT_GET_MGQ_HW_IDX(x) \ + (((x) >> BIT_SHIFT_MGQ_HW_IDX) & BIT_MASK_MGQ_HW_IDX) + +#define BIT_SHIFT_MGQ_HOST_IDX 0 +#define BIT_MASK_MGQ_HOST_IDX 0xfff +#define BIT_MGQ_HOST_IDX(x) \ + (((x) & BIT_MASK_MGQ_HOST_IDX) << BIT_SHIFT_MGQ_HOST_IDX) +#define BIT_GET_MGQ_HOST_IDX(x) \ + (((x) >> BIT_SHIFT_MGQ_HOST_IDX) & BIT_MASK_MGQ_HOST_IDX) + +/* 2 REG_RXQ_RXBD_IDX (Offset 0x03B4) */ + +#define BIT_SHIFT_RXQ_HW_IDX 16 +#define BIT_MASK_RXQ_HW_IDX 0xfff +#define BIT_RXQ_HW_IDX(x) (((x) & BIT_MASK_RXQ_HW_IDX) << BIT_SHIFT_RXQ_HW_IDX) +#define BIT_GET_RXQ_HW_IDX(x) \ + (((x) >> BIT_SHIFT_RXQ_HW_IDX) & BIT_MASK_RXQ_HW_IDX) + +#define BIT_SHIFT_RXQ_HOST_IDX 0 +#define BIT_MASK_RXQ_HOST_IDX 0xfff +#define BIT_RXQ_HOST_IDX(x) \ + (((x) & BIT_MASK_RXQ_HOST_IDX) << BIT_SHIFT_RXQ_HOST_IDX) +#define BIT_GET_RXQ_HOST_IDX(x) \ + (((x) >> BIT_SHIFT_RXQ_HOST_IDX) & BIT_MASK_RXQ_HOST_IDX) + +/* 2 REG_HI0Q_TXBD_IDX (Offset 0x03B8) */ + +#define BIT_SHIFT_HI0Q_HW_IDX 16 +#define BIT_MASK_HI0Q_HW_IDX 0xfff +#define BIT_HI0Q_HW_IDX(x) \ + (((x) & BIT_MASK_HI0Q_HW_IDX) << BIT_SHIFT_HI0Q_HW_IDX) +#define BIT_GET_HI0Q_HW_IDX(x) \ + (((x) >> BIT_SHIFT_HI0Q_HW_IDX) & BIT_MASK_HI0Q_HW_IDX) + +#define BIT_SHIFT_HI0Q_HOST_IDX 0 +#define BIT_MASK_HI0Q_HOST_IDX 0xfff +#define BIT_HI0Q_HOST_IDX(x) \ + (((x) & BIT_MASK_HI0Q_HOST_IDX) << BIT_SHIFT_HI0Q_HOST_IDX) +#define BIT_GET_HI0Q_HOST_IDX(x) \ + (((x) >> BIT_SHIFT_HI0Q_HOST_IDX) & BIT_MASK_HI0Q_HOST_IDX) + +/* 2 REG_HI1Q_TXBD_IDX (Offset 0x03BC) */ + +#define BIT_SHIFT_HI1Q_HW_IDX 16 +#define BIT_MASK_HI1Q_HW_IDX 0xfff +#define BIT_HI1Q_HW_IDX(x) \ + (((x) & BIT_MASK_HI1Q_HW_IDX) << BIT_SHIFT_HI1Q_HW_IDX) +#define BIT_GET_HI1Q_HW_IDX(x) \ + (((x) >> BIT_SHIFT_HI1Q_HW_IDX) & BIT_MASK_HI1Q_HW_IDX) + +#define BIT_SHIFT_HI1Q_HOST_IDX 0 +#define BIT_MASK_HI1Q_HOST_IDX 0xfff +#define BIT_HI1Q_HOST_IDX(x) \ + (((x) & BIT_MASK_HI1Q_HOST_IDX) << BIT_SHIFT_HI1Q_HOST_IDX) +#define BIT_GET_HI1Q_HOST_IDX(x) \ + (((x) >> BIT_SHIFT_HI1Q_HOST_IDX) & BIT_MASK_HI1Q_HOST_IDX) + +/* 2 REG_HI2Q_TXBD_IDX (Offset 0x03C0) */ + +#define BIT_SHIFT_HI2Q_HW_IDX 16 +#define BIT_MASK_HI2Q_HW_IDX 0xfff +#define BIT_HI2Q_HW_IDX(x) \ + (((x) & BIT_MASK_HI2Q_HW_IDX) << BIT_SHIFT_HI2Q_HW_IDX) +#define BIT_GET_HI2Q_HW_IDX(x) \ + (((x) >> BIT_SHIFT_HI2Q_HW_IDX) & BIT_MASK_HI2Q_HW_IDX) + +#define BIT_SHIFT_HI2Q_HOST_IDX 0 +#define BIT_MASK_HI2Q_HOST_IDX 0xfff +#define BIT_HI2Q_HOST_IDX(x) \ + (((x) & BIT_MASK_HI2Q_HOST_IDX) << BIT_SHIFT_HI2Q_HOST_IDX) +#define BIT_GET_HI2Q_HOST_IDX(x) \ + (((x) >> BIT_SHIFT_HI2Q_HOST_IDX) & BIT_MASK_HI2Q_HOST_IDX) + +/* 2 REG_HI3Q_TXBD_IDX (Offset 0x03C4) */ + +#define BIT_SHIFT_HI3Q_HW_IDX 16 +#define BIT_MASK_HI3Q_HW_IDX 0xfff +#define BIT_HI3Q_HW_IDX(x) \ + (((x) & BIT_MASK_HI3Q_HW_IDX) << BIT_SHIFT_HI3Q_HW_IDX) +#define BIT_GET_HI3Q_HW_IDX(x) \ + (((x) >> BIT_SHIFT_HI3Q_HW_IDX) & BIT_MASK_HI3Q_HW_IDX) + +#define BIT_SHIFT_HI3Q_HOST_IDX 0 +#define BIT_MASK_HI3Q_HOST_IDX 0xfff +#define BIT_HI3Q_HOST_IDX(x) \ + (((x) & BIT_MASK_HI3Q_HOST_IDX) << BIT_SHIFT_HI3Q_HOST_IDX) +#define BIT_GET_HI3Q_HOST_IDX(x) \ + (((x) >> BIT_SHIFT_HI3Q_HOST_IDX) & BIT_MASK_HI3Q_HOST_IDX) + +/* 2 REG_HI4Q_TXBD_IDX (Offset 0x03C8) */ + +#define BIT_SHIFT_HI4Q_HW_IDX 16 +#define BIT_MASK_HI4Q_HW_IDX 0xfff +#define BIT_HI4Q_HW_IDX(x) \ + (((x) & BIT_MASK_HI4Q_HW_IDX) << BIT_SHIFT_HI4Q_HW_IDX) +#define BIT_GET_HI4Q_HW_IDX(x) \ + (((x) >> BIT_SHIFT_HI4Q_HW_IDX) & BIT_MASK_HI4Q_HW_IDX) + +#define BIT_SHIFT_HI4Q_HOST_IDX 0 +#define BIT_MASK_HI4Q_HOST_IDX 0xfff +#define BIT_HI4Q_HOST_IDX(x) \ + (((x) & BIT_MASK_HI4Q_HOST_IDX) << BIT_SHIFT_HI4Q_HOST_IDX) +#define BIT_GET_HI4Q_HOST_IDX(x) \ + (((x) >> BIT_SHIFT_HI4Q_HOST_IDX) & BIT_MASK_HI4Q_HOST_IDX) + +/* 2 REG_HI5Q_TXBD_IDX (Offset 0x03CC) */ + +#define BIT_SHIFT_HI5Q_HW_IDX 16 +#define BIT_MASK_HI5Q_HW_IDX 0xfff +#define BIT_HI5Q_HW_IDX(x) \ + (((x) & BIT_MASK_HI5Q_HW_IDX) << BIT_SHIFT_HI5Q_HW_IDX) +#define BIT_GET_HI5Q_HW_IDX(x) \ + (((x) >> BIT_SHIFT_HI5Q_HW_IDX) & BIT_MASK_HI5Q_HW_IDX) + +#define BIT_SHIFT_HI5Q_HOST_IDX 0 +#define BIT_MASK_HI5Q_HOST_IDX 0xfff +#define BIT_HI5Q_HOST_IDX(x) \ + (((x) & BIT_MASK_HI5Q_HOST_IDX) << BIT_SHIFT_HI5Q_HOST_IDX) +#define BIT_GET_HI5Q_HOST_IDX(x) \ + (((x) >> BIT_SHIFT_HI5Q_HOST_IDX) & BIT_MASK_HI5Q_HOST_IDX) + +/* 2 REG_HI6Q_TXBD_IDX (Offset 0x03D0) */ + +#define BIT_SHIFT_HI6Q_HW_IDX 16 +#define BIT_MASK_HI6Q_HW_IDX 0xfff +#define BIT_HI6Q_HW_IDX(x) \ + (((x) & BIT_MASK_HI6Q_HW_IDX) << BIT_SHIFT_HI6Q_HW_IDX) +#define BIT_GET_HI6Q_HW_IDX(x) \ + (((x) >> BIT_SHIFT_HI6Q_HW_IDX) & BIT_MASK_HI6Q_HW_IDX) + +#define BIT_SHIFT_HI6Q_HOST_IDX 0 +#define BIT_MASK_HI6Q_HOST_IDX 0xfff +#define BIT_HI6Q_HOST_IDX(x) \ + (((x) & BIT_MASK_HI6Q_HOST_IDX) << BIT_SHIFT_HI6Q_HOST_IDX) +#define BIT_GET_HI6Q_HOST_IDX(x) \ + (((x) >> BIT_SHIFT_HI6Q_HOST_IDX) & BIT_MASK_HI6Q_HOST_IDX) + +/* 2 REG_HI7Q_TXBD_IDX (Offset 0x03D4) */ + +#define BIT_SHIFT_HI7Q_HW_IDX 16 +#define BIT_MASK_HI7Q_HW_IDX 0xfff +#define BIT_HI7Q_HW_IDX(x) \ + (((x) & BIT_MASK_HI7Q_HW_IDX) << BIT_SHIFT_HI7Q_HW_IDX) +#define BIT_GET_HI7Q_HW_IDX(x) \ + (((x) >> BIT_SHIFT_HI7Q_HW_IDX) & BIT_MASK_HI7Q_HW_IDX) + +#define BIT_SHIFT_HI7Q_HOST_IDX 0 +#define BIT_MASK_HI7Q_HOST_IDX 0xfff +#define BIT_HI7Q_HOST_IDX(x) \ + (((x) & BIT_MASK_HI7Q_HOST_IDX) << BIT_SHIFT_HI7Q_HOST_IDX) +#define BIT_GET_HI7Q_HOST_IDX(x) \ + (((x) >> BIT_SHIFT_HI7Q_HOST_IDX) & BIT_MASK_HI7Q_HOST_IDX) + +/* 2 REG_DBG_SEL_V1 (Offset 0x03D8) */ + +#define BIT_DIS_TXDMA_PRE BIT(7) +#define BIT_DIS_RXDMA_PRE BIT(6) +#define BIT_TXFLAG_EXIT_L1_EN BIT(2) + +#define BIT_SHIFT_DBG_SEL 0 +#define BIT_MASK_DBG_SEL 0xff +#define BIT_DBG_SEL(x) (((x) & BIT_MASK_DBG_SEL) << BIT_SHIFT_DBG_SEL) +#define BIT_GET_DBG_SEL(x) (((x) >> BIT_SHIFT_DBG_SEL) & BIT_MASK_DBG_SEL) + +/* 2 REG_PCIE_HRPWM1_V1 (Offset 0x03D9) */ + +#define BIT_SHIFT_PCIE_HRPWM 0 +#define BIT_MASK_PCIE_HRPWM 0xff +#define BIT_PCIE_HRPWM(x) (((x) & BIT_MASK_PCIE_HRPWM) << BIT_SHIFT_PCIE_HRPWM) +#define BIT_GET_PCIE_HRPWM(x) \ + (((x) >> BIT_SHIFT_PCIE_HRPWM) & BIT_MASK_PCIE_HRPWM) + +/* 2 REG_PCIE_HCPWM1_V1 (Offset 0x03DA) */ + +#define BIT_SHIFT_PCIE_HCPWM 0 +#define BIT_MASK_PCIE_HCPWM 0xff +#define BIT_PCIE_HCPWM(x) (((x) & BIT_MASK_PCIE_HCPWM) << BIT_SHIFT_PCIE_HCPWM) +#define BIT_GET_PCIE_HCPWM(x) \ + (((x) >> BIT_SHIFT_PCIE_HCPWM) & BIT_MASK_PCIE_HCPWM) + +/* 2 REG_PCIE_CTRL2 (Offset 0x03DB) */ + +#define BIT_SHIFT_HPS_CLKR_PCIE 4 +#define BIT_MASK_HPS_CLKR_PCIE 0x3 +#define BIT_HPS_CLKR_PCIE(x) \ + (((x) & BIT_MASK_HPS_CLKR_PCIE) << BIT_SHIFT_HPS_CLKR_PCIE) +#define BIT_GET_HPS_CLKR_PCIE(x) \ + (((x) >> BIT_SHIFT_HPS_CLKR_PCIE) & BIT_MASK_HPS_CLKR_PCIE) + +/* 2 REG_PCIE_CTRL2 (Offset 0x03DB) */ + +#define BIT_PCIE_INT BIT(3) + +/* 2 REG_PCIE_CTRL2 (Offset 0x03DB) */ + +#define BIT_EN_RXDMA_ALIGN BIT(1) +#define BIT_EN_TXDMA_ALIGN BIT(0) + +/* 2 REG_PCIE_HRPWM2_V1 (Offset 0x03DC) */ + +#define BIT_SHIFT_PCIE_HRPWM2 0 +#define BIT_MASK_PCIE_HRPWM2 0xffff +#define BIT_PCIE_HRPWM2(x) \ + (((x) & BIT_MASK_PCIE_HRPWM2) << BIT_SHIFT_PCIE_HRPWM2) +#define BIT_GET_PCIE_HRPWM2(x) \ + (((x) >> BIT_SHIFT_PCIE_HRPWM2) & BIT_MASK_PCIE_HRPWM2) + +/* 2 REG_PCIE_HCPWM2_V1 (Offset 0x03DE) */ + +#define BIT_SHIFT_PCIE_HCPWM2 0 +#define BIT_MASK_PCIE_HCPWM2 0xffff +#define BIT_PCIE_HCPWM2(x) \ + (((x) & BIT_MASK_PCIE_HCPWM2) << BIT_SHIFT_PCIE_HCPWM2) +#define BIT_GET_PCIE_HCPWM2(x) \ + (((x) >> BIT_SHIFT_PCIE_HCPWM2) & BIT_MASK_PCIE_HCPWM2) + +/* 2 REG_PCIE_H2C_MSG_V1 (Offset 0x03E0) */ + +#define BIT_SHIFT_DRV2FW_INFO 0 +#define BIT_MASK_DRV2FW_INFO 0xffffffffL +#define BIT_DRV2FW_INFO(x) \ + (((x) & BIT_MASK_DRV2FW_INFO) << BIT_SHIFT_DRV2FW_INFO) +#define BIT_GET_DRV2FW_INFO(x) \ + (((x) >> BIT_SHIFT_DRV2FW_INFO) & BIT_MASK_DRV2FW_INFO) + +/* 2 REG_PCIE_C2H_MSG_V1 (Offset 0x03E4) */ + +#define BIT_SHIFT_HCI_PCIE_C2H_MSG 0 +#define BIT_MASK_HCI_PCIE_C2H_MSG 0xffffffffL +#define BIT_HCI_PCIE_C2H_MSG(x) \ + (((x) & BIT_MASK_HCI_PCIE_C2H_MSG) << BIT_SHIFT_HCI_PCIE_C2H_MSG) +#define BIT_GET_HCI_PCIE_C2H_MSG(x) \ + (((x) >> BIT_SHIFT_HCI_PCIE_C2H_MSG) & BIT_MASK_HCI_PCIE_C2H_MSG) + +/* 2 REG_DBI_WDATA_V1 (Offset 0x03E8) */ + +#define BIT_SHIFT_DBI_WDATA 0 +#define BIT_MASK_DBI_WDATA 0xffffffffL +#define BIT_DBI_WDATA(x) (((x) & BIT_MASK_DBI_WDATA) << BIT_SHIFT_DBI_WDATA) +#define BIT_GET_DBI_WDATA(x) (((x) >> BIT_SHIFT_DBI_WDATA) & BIT_MASK_DBI_WDATA) + +/* 2 REG_DBI_RDATA_V1 (Offset 0x03EC) */ + +#define BIT_SHIFT_DBI_RDATA 0 +#define BIT_MASK_DBI_RDATA 0xffffffffL +#define BIT_DBI_RDATA(x) (((x) & BIT_MASK_DBI_RDATA) << BIT_SHIFT_DBI_RDATA) +#define BIT_GET_DBI_RDATA(x) (((x) >> BIT_SHIFT_DBI_RDATA) & BIT_MASK_DBI_RDATA) + +/* 2 REG_DBI_FLAG_V1 (Offset 0x03F0) */ + +#define BIT_EN_STUCK_DBG BIT(26) +#define BIT_RX_STUCK BIT(25) +#define BIT_TX_STUCK BIT(24) +#define BIT_DBI_RFLAG BIT(17) +#define BIT_DBI_WFLAG BIT(16) + +#define BIT_SHIFT_DBI_WREN 12 +#define BIT_MASK_DBI_WREN 0xf +#define BIT_DBI_WREN(x) (((x) & BIT_MASK_DBI_WREN) << BIT_SHIFT_DBI_WREN) +#define BIT_GET_DBI_WREN(x) (((x) >> BIT_SHIFT_DBI_WREN) & BIT_MASK_DBI_WREN) + +#define BIT_SHIFT_DBI_ADDR 0 +#define BIT_MASK_DBI_ADDR 0xfff +#define BIT_DBI_ADDR(x) (((x) & BIT_MASK_DBI_ADDR) << BIT_SHIFT_DBI_ADDR) +#define BIT_GET_DBI_ADDR(x) (((x) >> BIT_SHIFT_DBI_ADDR) & BIT_MASK_DBI_ADDR) + +/* 2 REG_MDIO_V1 (Offset 0x03F4) */ + +#define BIT_SHIFT_MDIO_RDATA 16 +#define BIT_MASK_MDIO_RDATA 0xffff +#define BIT_MDIO_RDATA(x) (((x) & BIT_MASK_MDIO_RDATA) << BIT_SHIFT_MDIO_RDATA) +#define BIT_GET_MDIO_RDATA(x) \ + (((x) >> BIT_SHIFT_MDIO_RDATA) & BIT_MASK_MDIO_RDATA) + +#define BIT_SHIFT_MDIO_WDATA 0 +#define BIT_MASK_MDIO_WDATA 0xffff +#define BIT_MDIO_WDATA(x) (((x) & BIT_MASK_MDIO_WDATA) << BIT_SHIFT_MDIO_WDATA) +#define BIT_GET_MDIO_WDATA(x) \ + (((x) >> BIT_SHIFT_MDIO_WDATA) & BIT_MASK_MDIO_WDATA) + +/* 2 REG_PCIE_MIX_CFG (Offset 0x03F8) */ + +#define BIT_EN_WATCH_DOG BIT(8) + +/* 2 REG_PCIE_MIX_CFG (Offset 0x03F8) */ + +#define BIT_SHIFT_MDIO_REG_ADDR_V1 0 +#define BIT_MASK_MDIO_REG_ADDR_V1 0x1f +#define BIT_MDIO_REG_ADDR_V1(x) \ + (((x) & BIT_MASK_MDIO_REG_ADDR_V1) << BIT_SHIFT_MDIO_REG_ADDR_V1) +#define BIT_GET_MDIO_REG_ADDR_V1(x) \ + (((x) >> BIT_SHIFT_MDIO_REG_ADDR_V1) & BIT_MASK_MDIO_REG_ADDR_V1) + +/* 2 REG_HCI_MIX_CFG (Offset 0x03FC) */ + +#define BIT_HOST_GEN2_SUPPORT BIT(20) + +#define BIT_SHIFT_TXDMA_ERR_FLAG 16 +#define BIT_MASK_TXDMA_ERR_FLAG 0xf +#define BIT_TXDMA_ERR_FLAG(x) \ + (((x) & BIT_MASK_TXDMA_ERR_FLAG) << BIT_SHIFT_TXDMA_ERR_FLAG) +#define BIT_GET_TXDMA_ERR_FLAG(x) \ + (((x) >> BIT_SHIFT_TXDMA_ERR_FLAG) & BIT_MASK_TXDMA_ERR_FLAG) + +#define BIT_SHIFT_EARLY_MODE_SEL 12 +#define BIT_MASK_EARLY_MODE_SEL 0xf +#define BIT_EARLY_MODE_SEL(x) \ + (((x) & BIT_MASK_EARLY_MODE_SEL) << BIT_SHIFT_EARLY_MODE_SEL) +#define BIT_GET_EARLY_MODE_SEL(x) \ + (((x) >> BIT_SHIFT_EARLY_MODE_SEL) & BIT_MASK_EARLY_MODE_SEL) + +#define BIT_EPHY_RX50_EN BIT(11) + +#define BIT_SHIFT_MSI_TIMEOUT_ID_V1 8 +#define BIT_MASK_MSI_TIMEOUT_ID_V1 0x7 +#define BIT_MSI_TIMEOUT_ID_V1(x) \ + (((x) & BIT_MASK_MSI_TIMEOUT_ID_V1) << BIT_SHIFT_MSI_TIMEOUT_ID_V1) +#define BIT_GET_MSI_TIMEOUT_ID_V1(x) \ + (((x) >> BIT_SHIFT_MSI_TIMEOUT_ID_V1) & BIT_MASK_MSI_TIMEOUT_ID_V1) + +#define BIT_RADDR_RD BIT(7) +#define BIT_EN_MUL_TAG BIT(6) +#define BIT_EN_EARLY_MODE BIT(5) +#define BIT_L0S_LINK_OFF BIT(4) +#define BIT_ACT_LINK_OFF BIT(3) + +/* 2 REG_HCI_MIX_CFG (Offset 0x03FC) */ + +#define BIT_EN_SLOW_MAC_TX BIT(2) +#define BIT_EN_SLOW_MAC_RX BIT(1) + +/* 2 REG_Q0_INFO (Offset 0x0400) */ + +#define BIT_SHIFT_QUEUEMACID_Q0_V1 25 +#define BIT_MASK_QUEUEMACID_Q0_V1 0x7f +#define BIT_QUEUEMACID_Q0_V1(x) \ + (((x) & BIT_MASK_QUEUEMACID_Q0_V1) << BIT_SHIFT_QUEUEMACID_Q0_V1) +#define BIT_GET_QUEUEMACID_Q0_V1(x) \ + (((x) >> BIT_SHIFT_QUEUEMACID_Q0_V1) & BIT_MASK_QUEUEMACID_Q0_V1) + +#define BIT_SHIFT_QUEUEAC_Q0_V1 23 +#define BIT_MASK_QUEUEAC_Q0_V1 0x3 +#define BIT_QUEUEAC_Q0_V1(x) \ + (((x) & BIT_MASK_QUEUEAC_Q0_V1) << BIT_SHIFT_QUEUEAC_Q0_V1) +#define BIT_GET_QUEUEAC_Q0_V1(x) \ + (((x) >> BIT_SHIFT_QUEUEAC_Q0_V1) & BIT_MASK_QUEUEAC_Q0_V1) + +/* 2 REG_Q0_INFO (Offset 0x0400) */ + +#define BIT_TIDEMPTY_Q0_V1 BIT(22) + +/* 2 REG_Q0_INFO (Offset 0x0400) */ + +#define BIT_SHIFT_TAIL_PKT_Q0_V2 11 +#define BIT_MASK_TAIL_PKT_Q0_V2 0x7ff +#define BIT_TAIL_PKT_Q0_V2(x) \ + (((x) & BIT_MASK_TAIL_PKT_Q0_V2) << BIT_SHIFT_TAIL_PKT_Q0_V2) +#define BIT_GET_TAIL_PKT_Q0_V2(x) \ + (((x) >> BIT_SHIFT_TAIL_PKT_Q0_V2) & BIT_MASK_TAIL_PKT_Q0_V2) + +/* 2 REG_Q0_INFO (Offset 0x0400) */ + +#define BIT_SHIFT_HEAD_PKT_Q0_V1 0 +#define BIT_MASK_HEAD_PKT_Q0_V1 0x7ff +#define BIT_HEAD_PKT_Q0_V1(x) \ + (((x) & BIT_MASK_HEAD_PKT_Q0_V1) << BIT_SHIFT_HEAD_PKT_Q0_V1) +#define BIT_GET_HEAD_PKT_Q0_V1(x) \ + (((x) >> BIT_SHIFT_HEAD_PKT_Q0_V1) & BIT_MASK_HEAD_PKT_Q0_V1) + +/* 2 REG_Q1_INFO (Offset 0x0404) */ + +#define BIT_SHIFT_QUEUEMACID_Q1_V1 25 +#define BIT_MASK_QUEUEMACID_Q1_V1 0x7f +#define BIT_QUEUEMACID_Q1_V1(x) \ + (((x) & BIT_MASK_QUEUEMACID_Q1_V1) << BIT_SHIFT_QUEUEMACID_Q1_V1) +#define BIT_GET_QUEUEMACID_Q1_V1(x) \ + (((x) >> BIT_SHIFT_QUEUEMACID_Q1_V1) & BIT_MASK_QUEUEMACID_Q1_V1) + +#define BIT_SHIFT_QUEUEAC_Q1_V1 23 +#define BIT_MASK_QUEUEAC_Q1_V1 0x3 +#define BIT_QUEUEAC_Q1_V1(x) \ + (((x) & BIT_MASK_QUEUEAC_Q1_V1) << BIT_SHIFT_QUEUEAC_Q1_V1) +#define BIT_GET_QUEUEAC_Q1_V1(x) \ + (((x) >> BIT_SHIFT_QUEUEAC_Q1_V1) & BIT_MASK_QUEUEAC_Q1_V1) + +/* 2 REG_Q1_INFO (Offset 0x0404) */ + +#define BIT_TIDEMPTY_Q1_V1 BIT(22) + +/* 2 REG_Q1_INFO (Offset 0x0404) */ + +#define BIT_SHIFT_TAIL_PKT_Q1_V2 11 +#define BIT_MASK_TAIL_PKT_Q1_V2 0x7ff +#define BIT_TAIL_PKT_Q1_V2(x) \ + (((x) & BIT_MASK_TAIL_PKT_Q1_V2) << BIT_SHIFT_TAIL_PKT_Q1_V2) +#define BIT_GET_TAIL_PKT_Q1_V2(x) \ + (((x) >> BIT_SHIFT_TAIL_PKT_Q1_V2) & BIT_MASK_TAIL_PKT_Q1_V2) + +/* 2 REG_Q1_INFO (Offset 0x0404) */ + +#define BIT_SHIFT_HEAD_PKT_Q1_V1 0 +#define BIT_MASK_HEAD_PKT_Q1_V1 0x7ff +#define BIT_HEAD_PKT_Q1_V1(x) \ + (((x) & BIT_MASK_HEAD_PKT_Q1_V1) << BIT_SHIFT_HEAD_PKT_Q1_V1) +#define BIT_GET_HEAD_PKT_Q1_V1(x) \ + (((x) >> BIT_SHIFT_HEAD_PKT_Q1_V1) & BIT_MASK_HEAD_PKT_Q1_V1) + +/* 2 REG_Q2_INFO (Offset 0x0408) */ + +#define BIT_SHIFT_QUEUEMACID_Q2_V1 25 +#define BIT_MASK_QUEUEMACID_Q2_V1 0x7f +#define BIT_QUEUEMACID_Q2_V1(x) \ + (((x) & BIT_MASK_QUEUEMACID_Q2_V1) << BIT_SHIFT_QUEUEMACID_Q2_V1) +#define BIT_GET_QUEUEMACID_Q2_V1(x) \ + (((x) >> BIT_SHIFT_QUEUEMACID_Q2_V1) & BIT_MASK_QUEUEMACID_Q2_V1) + +#define BIT_SHIFT_QUEUEAC_Q2_V1 23 +#define BIT_MASK_QUEUEAC_Q2_V1 0x3 +#define BIT_QUEUEAC_Q2_V1(x) \ + (((x) & BIT_MASK_QUEUEAC_Q2_V1) << BIT_SHIFT_QUEUEAC_Q2_V1) +#define BIT_GET_QUEUEAC_Q2_V1(x) \ + (((x) >> BIT_SHIFT_QUEUEAC_Q2_V1) & BIT_MASK_QUEUEAC_Q2_V1) + +/* 2 REG_Q2_INFO (Offset 0x0408) */ + +#define BIT_TIDEMPTY_Q2_V1 BIT(22) + +/* 2 REG_Q2_INFO (Offset 0x0408) */ + +#define BIT_SHIFT_TAIL_PKT_Q2_V2 11 +#define BIT_MASK_TAIL_PKT_Q2_V2 0x7ff +#define BIT_TAIL_PKT_Q2_V2(x) \ + (((x) & BIT_MASK_TAIL_PKT_Q2_V2) << BIT_SHIFT_TAIL_PKT_Q2_V2) +#define BIT_GET_TAIL_PKT_Q2_V2(x) \ + (((x) >> BIT_SHIFT_TAIL_PKT_Q2_V2) & BIT_MASK_TAIL_PKT_Q2_V2) + +/* 2 REG_Q2_INFO (Offset 0x0408) */ + +#define BIT_SHIFT_HEAD_PKT_Q2_V1 0 +#define BIT_MASK_HEAD_PKT_Q2_V1 0x7ff +#define BIT_HEAD_PKT_Q2_V1(x) \ + (((x) & BIT_MASK_HEAD_PKT_Q2_V1) << BIT_SHIFT_HEAD_PKT_Q2_V1) +#define BIT_GET_HEAD_PKT_Q2_V1(x) \ + (((x) >> BIT_SHIFT_HEAD_PKT_Q2_V1) & BIT_MASK_HEAD_PKT_Q2_V1) + +/* 2 REG_Q3_INFO (Offset 0x040C) */ + +#define BIT_SHIFT_QUEUEMACID_Q3_V1 25 +#define BIT_MASK_QUEUEMACID_Q3_V1 0x7f +#define BIT_QUEUEMACID_Q3_V1(x) \ + (((x) & BIT_MASK_QUEUEMACID_Q3_V1) << BIT_SHIFT_QUEUEMACID_Q3_V1) +#define BIT_GET_QUEUEMACID_Q3_V1(x) \ + (((x) >> BIT_SHIFT_QUEUEMACID_Q3_V1) & BIT_MASK_QUEUEMACID_Q3_V1) + +#define BIT_SHIFT_QUEUEAC_Q3_V1 23 +#define BIT_MASK_QUEUEAC_Q3_V1 0x3 +#define BIT_QUEUEAC_Q3_V1(x) \ + (((x) & BIT_MASK_QUEUEAC_Q3_V1) << BIT_SHIFT_QUEUEAC_Q3_V1) +#define BIT_GET_QUEUEAC_Q3_V1(x) \ + (((x) >> BIT_SHIFT_QUEUEAC_Q3_V1) & BIT_MASK_QUEUEAC_Q3_V1) + +/* 2 REG_Q3_INFO (Offset 0x040C) */ + +#define BIT_TIDEMPTY_Q3_V1 BIT(22) + +/* 2 REG_Q3_INFO (Offset 0x040C) */ + +#define BIT_SHIFT_TAIL_PKT_Q3_V2 11 +#define BIT_MASK_TAIL_PKT_Q3_V2 0x7ff +#define BIT_TAIL_PKT_Q3_V2(x) \ + (((x) & BIT_MASK_TAIL_PKT_Q3_V2) << BIT_SHIFT_TAIL_PKT_Q3_V2) +#define BIT_GET_TAIL_PKT_Q3_V2(x) \ + (((x) >> BIT_SHIFT_TAIL_PKT_Q3_V2) & BIT_MASK_TAIL_PKT_Q3_V2) + +/* 2 REG_Q3_INFO (Offset 0x040C) */ + +#define BIT_SHIFT_HEAD_PKT_Q3_V1 0 +#define BIT_MASK_HEAD_PKT_Q3_V1 0x7ff +#define BIT_HEAD_PKT_Q3_V1(x) \ + (((x) & BIT_MASK_HEAD_PKT_Q3_V1) << BIT_SHIFT_HEAD_PKT_Q3_V1) +#define BIT_GET_HEAD_PKT_Q3_V1(x) \ + (((x) >> BIT_SHIFT_HEAD_PKT_Q3_V1) & BIT_MASK_HEAD_PKT_Q3_V1) + +/* 2 REG_MGQ_INFO (Offset 0x0410) */ + +#define BIT_SHIFT_QUEUEMACID_MGQ_V1 25 +#define BIT_MASK_QUEUEMACID_MGQ_V1 0x7f +#define BIT_QUEUEMACID_MGQ_V1(x) \ + (((x) & BIT_MASK_QUEUEMACID_MGQ_V1) << BIT_SHIFT_QUEUEMACID_MGQ_V1) +#define BIT_GET_QUEUEMACID_MGQ_V1(x) \ + (((x) >> BIT_SHIFT_QUEUEMACID_MGQ_V1) & BIT_MASK_QUEUEMACID_MGQ_V1) + +#define BIT_SHIFT_QUEUEAC_MGQ_V1 23 +#define BIT_MASK_QUEUEAC_MGQ_V1 0x3 +#define BIT_QUEUEAC_MGQ_V1(x) \ + (((x) & BIT_MASK_QUEUEAC_MGQ_V1) << BIT_SHIFT_QUEUEAC_MGQ_V1) +#define BIT_GET_QUEUEAC_MGQ_V1(x) \ + (((x) >> BIT_SHIFT_QUEUEAC_MGQ_V1) & BIT_MASK_QUEUEAC_MGQ_V1) + +/* 2 REG_MGQ_INFO (Offset 0x0410) */ + +#define BIT_TIDEMPTY_MGQ_V1 BIT(22) + +/* 2 REG_MGQ_INFO (Offset 0x0410) */ + +#define BIT_SHIFT_TAIL_PKT_MGQ_V2 11 +#define BIT_MASK_TAIL_PKT_MGQ_V2 0x7ff +#define BIT_TAIL_PKT_MGQ_V2(x) \ + (((x) & BIT_MASK_TAIL_PKT_MGQ_V2) << BIT_SHIFT_TAIL_PKT_MGQ_V2) +#define BIT_GET_TAIL_PKT_MGQ_V2(x) \ + (((x) >> BIT_SHIFT_TAIL_PKT_MGQ_V2) & BIT_MASK_TAIL_PKT_MGQ_V2) + +/* 2 REG_MGQ_INFO (Offset 0x0410) */ + +#define BIT_SHIFT_HEAD_PKT_MGQ_V1 0 +#define BIT_MASK_HEAD_PKT_MGQ_V1 0x7ff +#define BIT_HEAD_PKT_MGQ_V1(x) \ + (((x) & BIT_MASK_HEAD_PKT_MGQ_V1) << BIT_SHIFT_HEAD_PKT_MGQ_V1) +#define BIT_GET_HEAD_PKT_MGQ_V1(x) \ + (((x) >> BIT_SHIFT_HEAD_PKT_MGQ_V1) & BIT_MASK_HEAD_PKT_MGQ_V1) + +/* 2 REG_HIQ_INFO (Offset 0x0414) */ + +#define BIT_SHIFT_QUEUEMACID_HIQ_V1 25 +#define BIT_MASK_QUEUEMACID_HIQ_V1 0x7f +#define BIT_QUEUEMACID_HIQ_V1(x) \ + (((x) & BIT_MASK_QUEUEMACID_HIQ_V1) << BIT_SHIFT_QUEUEMACID_HIQ_V1) +#define BIT_GET_QUEUEMACID_HIQ_V1(x) \ + (((x) >> BIT_SHIFT_QUEUEMACID_HIQ_V1) & BIT_MASK_QUEUEMACID_HIQ_V1) + +#define BIT_SHIFT_QUEUEAC_HIQ_V1 23 +#define BIT_MASK_QUEUEAC_HIQ_V1 0x3 +#define BIT_QUEUEAC_HIQ_V1(x) \ + (((x) & BIT_MASK_QUEUEAC_HIQ_V1) << BIT_SHIFT_QUEUEAC_HIQ_V1) +#define BIT_GET_QUEUEAC_HIQ_V1(x) \ + (((x) >> BIT_SHIFT_QUEUEAC_HIQ_V1) & BIT_MASK_QUEUEAC_HIQ_V1) + +/* 2 REG_HIQ_INFO (Offset 0x0414) */ + +#define BIT_TIDEMPTY_HIQ_V1 BIT(22) + +/* 2 REG_HIQ_INFO (Offset 0x0414) */ + +#define BIT_SHIFT_TAIL_PKT_HIQ_V2 11 +#define BIT_MASK_TAIL_PKT_HIQ_V2 0x7ff +#define BIT_TAIL_PKT_HIQ_V2(x) \ + (((x) & BIT_MASK_TAIL_PKT_HIQ_V2) << BIT_SHIFT_TAIL_PKT_HIQ_V2) +#define BIT_GET_TAIL_PKT_HIQ_V2(x) \ + (((x) >> BIT_SHIFT_TAIL_PKT_HIQ_V2) & BIT_MASK_TAIL_PKT_HIQ_V2) + +/* 2 REG_HIQ_INFO (Offset 0x0414) */ + +#define BIT_SHIFT_HEAD_PKT_HIQ_V1 0 +#define BIT_MASK_HEAD_PKT_HIQ_V1 0x7ff +#define BIT_HEAD_PKT_HIQ_V1(x) \ + (((x) & BIT_MASK_HEAD_PKT_HIQ_V1) << BIT_SHIFT_HEAD_PKT_HIQ_V1) +#define BIT_GET_HEAD_PKT_HIQ_V1(x) \ + (((x) >> BIT_SHIFT_HEAD_PKT_HIQ_V1) & BIT_MASK_HEAD_PKT_HIQ_V1) + +/* 2 REG_BCNQ_INFO (Offset 0x0418) */ + +#define BIT_SHIFT_BCNQ_HEAD_PG_V1 0 +#define BIT_MASK_BCNQ_HEAD_PG_V1 0xfff +#define BIT_BCNQ_HEAD_PG_V1(x) \ + (((x) & BIT_MASK_BCNQ_HEAD_PG_V1) << BIT_SHIFT_BCNQ_HEAD_PG_V1) +#define BIT_GET_BCNQ_HEAD_PG_V1(x) \ + (((x) >> BIT_SHIFT_BCNQ_HEAD_PG_V1) & BIT_MASK_BCNQ_HEAD_PG_V1) + +/* 2 REG_TXPKT_EMPTY (Offset 0x041A) */ + +#define BIT_BCNQ_EMPTY BIT(11) +#define BIT_HQQ_EMPTY BIT(10) +#define BIT_MQQ_EMPTY BIT(9) +#define BIT_MGQ_CPU_EMPTY BIT(8) +#define BIT_AC7Q_EMPTY BIT(7) +#define BIT_AC6Q_EMPTY BIT(6) +#define BIT_AC5Q_EMPTY BIT(5) +#define BIT_AC4Q_EMPTY BIT(4) +#define BIT_AC3Q_EMPTY BIT(3) +#define BIT_AC2Q_EMPTY BIT(2) +#define BIT_AC1Q_EMPTY BIT(1) +#define BIT_AC0Q_EMPTY BIT(0) + +/* 2 REG_CPU_MGQ_INFO (Offset 0x041C) */ + +#define BIT_BCN1_POLL BIT(30) + +/* 2 REG_CPU_MGQ_INFO (Offset 0x041C) */ + +#define BIT_CPUMGT_POLL BIT(29) +#define BIT_BCN_POLL BIT(28) + +/* 2 REG_CPU_MGQ_INFO (Offset 0x041C) */ + +#define BIT_CPUMGQ_FW_NUM_V1 BIT(12) + +/* 2 REG_CPU_MGQ_INFO (Offset 0x041C) */ + +#define BIT_SHIFT_FW_FREE_TAIL_V1 0 +#define BIT_MASK_FW_FREE_TAIL_V1 0xfff +#define BIT_FW_FREE_TAIL_V1(x) \ + (((x) & BIT_MASK_FW_FREE_TAIL_V1) << BIT_SHIFT_FW_FREE_TAIL_V1) +#define BIT_GET_FW_FREE_TAIL_V1(x) \ + (((x) >> BIT_SHIFT_FW_FREE_TAIL_V1) & BIT_MASK_FW_FREE_TAIL_V1) + +/* 2 REG_FWHW_TXQ_CTRL (Offset 0x0420) */ + +#define BIT_RTS_LIMIT_IN_OFDM BIT(23) +#define BIT_EN_BCNQ_DL BIT(22) +#define BIT_EN_RD_RESP_NAV_BK BIT(21) +#define BIT_EN_WR_FREE_TAIL BIT(20) + +#define BIT_SHIFT_EN_QUEUE_RPT 8 +#define BIT_MASK_EN_QUEUE_RPT 0xff +#define BIT_EN_QUEUE_RPT(x) \ + (((x) & BIT_MASK_EN_QUEUE_RPT) << BIT_SHIFT_EN_QUEUE_RPT) +#define BIT_GET_EN_QUEUE_RPT(x) \ + (((x) >> BIT_SHIFT_EN_QUEUE_RPT) & BIT_MASK_EN_QUEUE_RPT) + +#define BIT_EN_RTY_BK BIT(7) +#define BIT_EN_USE_INI_RAT BIT(6) +#define BIT_EN_RTS_NAV_BK BIT(5) +#define BIT_DIS_SSN_CHECK BIT(4) +#define BIT_MACID_MATCH_RTS BIT(3) + +/* 2 REG_FWHW_TXQ_CTRL (Offset 0x0420) */ + +#define BIT_EN_BCN_TRXRPT_V1 BIT(2) + +/* 2 REG_FWHW_TXQ_CTRL (Offset 0x0420) */ + +#define BIT_EN_FTMACKRPT BIT(1) + +/* 2 REG_FWHW_TXQ_CTRL (Offset 0x0420) */ + +#define BIT_EN_FTMRPT BIT(0) + +/* 2 REG_DATAFB_SEL (Offset 0x0423) */ + +#define BIT__R_EN_RTY_BK_COD BIT(2) + +/* 2 REG_DATAFB_SEL (Offset 0x0423) */ + +#define BIT_SHIFT__R_DATA_FALLBACK_SEL 0 +#define BIT_MASK__R_DATA_FALLBACK_SEL 0x3 +#define BIT__R_DATA_FALLBACK_SEL(x) \ + (((x) & BIT_MASK__R_DATA_FALLBACK_SEL) \ + << BIT_SHIFT__R_DATA_FALLBACK_SEL) +#define BIT_GET__R_DATA_FALLBACK_SEL(x) \ + (((x) >> BIT_SHIFT__R_DATA_FALLBACK_SEL) & \ + BIT_MASK__R_DATA_FALLBACK_SEL) + +/* 2 REG_BCNQ_BDNY_V1 (Offset 0x0424) */ + +#define BIT_SHIFT_BCNQ_PGBNDY_V1 0 +#define BIT_MASK_BCNQ_PGBNDY_V1 0xfff +#define BIT_BCNQ_PGBNDY_V1(x) \ + (((x) & BIT_MASK_BCNQ_PGBNDY_V1) << BIT_SHIFT_BCNQ_PGBNDY_V1) +#define BIT_GET_BCNQ_PGBNDY_V1(x) \ + (((x) >> BIT_SHIFT_BCNQ_PGBNDY_V1) & BIT_MASK_BCNQ_PGBNDY_V1) + +/* 2 REG_LIFETIME_EN (Offset 0x0426) */ + +#define BIT_BT_INT_CPU BIT(7) +#define BIT_BT_INT_PTA BIT(6) + +/* 2 REG_LIFETIME_EN (Offset 0x0426) */ + +#define BIT_EN_CTRL_RTYBIT BIT(4) + +/* 2 REG_LIFETIME_EN (Offset 0x0426) */ + +#define BIT_LIFETIME_BK_EN BIT(3) +#define BIT_LIFETIME_BE_EN BIT(2) +#define BIT_LIFETIME_VI_EN BIT(1) +#define BIT_LIFETIME_VO_EN BIT(0) + +/* 2 REG_SPEC_SIFS (Offset 0x0428) */ + +#define BIT_SHIFT_SPEC_SIFS_OFDM_PTCL 8 +#define BIT_MASK_SPEC_SIFS_OFDM_PTCL 0xff +#define BIT_SPEC_SIFS_OFDM_PTCL(x) \ + (((x) & BIT_MASK_SPEC_SIFS_OFDM_PTCL) << BIT_SHIFT_SPEC_SIFS_OFDM_PTCL) +#define BIT_GET_SPEC_SIFS_OFDM_PTCL(x) \ + (((x) >> BIT_SHIFT_SPEC_SIFS_OFDM_PTCL) & BIT_MASK_SPEC_SIFS_OFDM_PTCL) + +#define BIT_SHIFT_SPEC_SIFS_CCK_PTCL 0 +#define BIT_MASK_SPEC_SIFS_CCK_PTCL 0xff +#define BIT_SPEC_SIFS_CCK_PTCL(x) \ + (((x) & BIT_MASK_SPEC_SIFS_CCK_PTCL) << BIT_SHIFT_SPEC_SIFS_CCK_PTCL) +#define BIT_GET_SPEC_SIFS_CCK_PTCL(x) \ + (((x) >> BIT_SHIFT_SPEC_SIFS_CCK_PTCL) & BIT_MASK_SPEC_SIFS_CCK_PTCL) + +/* 2 REG_RETRY_LIMIT (Offset 0x042A) */ + +#define BIT_SHIFT_SRL 8 +#define BIT_MASK_SRL 0x3f +#define BIT_SRL(x) (((x) & BIT_MASK_SRL) << BIT_SHIFT_SRL) +#define BIT_GET_SRL(x) (((x) >> BIT_SHIFT_SRL) & BIT_MASK_SRL) + +#define BIT_SHIFT_LRL 0 +#define BIT_MASK_LRL 0x3f +#define BIT_LRL(x) (((x) & BIT_MASK_LRL) << BIT_SHIFT_LRL) +#define BIT_GET_LRL(x) (((x) >> BIT_SHIFT_LRL) & BIT_MASK_LRL) + +/* 2 REG_TXBF_CTRL (Offset 0x042C) */ + +#define BIT_R_ENABLE_NDPA BIT(31) +#define BIT_USE_NDPA_PARAMETER BIT(30) +#define BIT_R_PROP_TXBF BIT(29) +#define BIT_R_EN_NDPA_INT BIT(28) +#define BIT_R_TXBF1_80M BIT(27) +#define BIT_R_TXBF1_40M BIT(26) +#define BIT_R_TXBF1_20M BIT(25) + +#define BIT_SHIFT_R_TXBF1_AID 16 +#define BIT_MASK_R_TXBF1_AID 0x1ff +#define BIT_R_TXBF1_AID(x) \ + (((x) & BIT_MASK_R_TXBF1_AID) << BIT_SHIFT_R_TXBF1_AID) +#define BIT_GET_R_TXBF1_AID(x) \ + (((x) >> BIT_SHIFT_R_TXBF1_AID) & BIT_MASK_R_TXBF1_AID) + +/* 2 REG_TXBF_CTRL (Offset 0x042C) */ + +#define BIT_DIS_NDP_BFEN BIT(15) + +/* 2 REG_TXBF_CTRL (Offset 0x042C) */ + +#define BIT_R_TXBCN_NOBLOCK_NDP BIT(14) + +/* 2 REG_TXBF_CTRL (Offset 0x042C) */ + +#define BIT_R_TXBF0_80M BIT(11) +#define BIT_R_TXBF0_40M BIT(10) +#define BIT_R_TXBF0_20M BIT(9) + +#define BIT_SHIFT_R_TXBF0_AID 0 +#define BIT_MASK_R_TXBF0_AID 0x1ff +#define BIT_R_TXBF0_AID(x) \ + (((x) & BIT_MASK_R_TXBF0_AID) << BIT_SHIFT_R_TXBF0_AID) +#define BIT_GET_R_TXBF0_AID(x) \ + (((x) >> BIT_SHIFT_R_TXBF0_AID) & BIT_MASK_R_TXBF0_AID) + +/* 2 REG_DARFRC (Offset 0x0430) */ + +#define BIT_SHIFT_DARF_RC8 (56 & CPU_OPT_WIDTH) +#define BIT_MASK_DARF_RC8 0x1f +#define BIT_DARF_RC8(x) (((x) & BIT_MASK_DARF_RC8) << BIT_SHIFT_DARF_RC8) +#define BIT_GET_DARF_RC8(x) (((x) >> BIT_SHIFT_DARF_RC8) & BIT_MASK_DARF_RC8) + +#define BIT_SHIFT_DARF_RC7 (48 & CPU_OPT_WIDTH) +#define BIT_MASK_DARF_RC7 0x1f +#define BIT_DARF_RC7(x) (((x) & BIT_MASK_DARF_RC7) << BIT_SHIFT_DARF_RC7) +#define BIT_GET_DARF_RC7(x) (((x) >> BIT_SHIFT_DARF_RC7) & BIT_MASK_DARF_RC7) + +#define BIT_SHIFT_DARF_RC6 (40 & CPU_OPT_WIDTH) +#define BIT_MASK_DARF_RC6 0x1f +#define BIT_DARF_RC6(x) (((x) & BIT_MASK_DARF_RC6) << BIT_SHIFT_DARF_RC6) +#define BIT_GET_DARF_RC6(x) (((x) >> BIT_SHIFT_DARF_RC6) & BIT_MASK_DARF_RC6) + +#define BIT_SHIFT_DARF_RC5 (32 & CPU_OPT_WIDTH) +#define BIT_MASK_DARF_RC5 0x1f +#define BIT_DARF_RC5(x) (((x) & BIT_MASK_DARF_RC5) << BIT_SHIFT_DARF_RC5) +#define BIT_GET_DARF_RC5(x) (((x) >> BIT_SHIFT_DARF_RC5) & BIT_MASK_DARF_RC5) + +#define BIT_SHIFT_DARF_RC4 24 +#define BIT_MASK_DARF_RC4 0x1f +#define BIT_DARF_RC4(x) (((x) & BIT_MASK_DARF_RC4) << BIT_SHIFT_DARF_RC4) +#define BIT_GET_DARF_RC4(x) (((x) >> BIT_SHIFT_DARF_RC4) & BIT_MASK_DARF_RC4) + +#define BIT_SHIFT_DARF_RC3 16 +#define BIT_MASK_DARF_RC3 0x1f +#define BIT_DARF_RC3(x) (((x) & BIT_MASK_DARF_RC3) << BIT_SHIFT_DARF_RC3) +#define BIT_GET_DARF_RC3(x) (((x) >> BIT_SHIFT_DARF_RC3) & BIT_MASK_DARF_RC3) + +#define BIT_SHIFT_DARF_RC2 8 +#define BIT_MASK_DARF_RC2 0x1f +#define BIT_DARF_RC2(x) (((x) & BIT_MASK_DARF_RC2) << BIT_SHIFT_DARF_RC2) +#define BIT_GET_DARF_RC2(x) (((x) >> BIT_SHIFT_DARF_RC2) & BIT_MASK_DARF_RC2) + +#define BIT_SHIFT_DARF_RC1 0 +#define BIT_MASK_DARF_RC1 0x1f +#define BIT_DARF_RC1(x) (((x) & BIT_MASK_DARF_RC1) << BIT_SHIFT_DARF_RC1) +#define BIT_GET_DARF_RC1(x) (((x) >> BIT_SHIFT_DARF_RC1) & BIT_MASK_DARF_RC1) + +/* 2 REG_RARFRC (Offset 0x0438) */ + +#define BIT_SHIFT_RARF_RC8 (56 & CPU_OPT_WIDTH) +#define BIT_MASK_RARF_RC8 0x1f +#define BIT_RARF_RC8(x) (((x) & BIT_MASK_RARF_RC8) << BIT_SHIFT_RARF_RC8) +#define BIT_GET_RARF_RC8(x) (((x) >> BIT_SHIFT_RARF_RC8) & BIT_MASK_RARF_RC8) + +#define BIT_SHIFT_RARF_RC7 (48 & CPU_OPT_WIDTH) +#define BIT_MASK_RARF_RC7 0x1f +#define BIT_RARF_RC7(x) (((x) & BIT_MASK_RARF_RC7) << BIT_SHIFT_RARF_RC7) +#define BIT_GET_RARF_RC7(x) (((x) >> BIT_SHIFT_RARF_RC7) & BIT_MASK_RARF_RC7) + +#define BIT_SHIFT_RARF_RC6 (40 & CPU_OPT_WIDTH) +#define BIT_MASK_RARF_RC6 0x1f +#define BIT_RARF_RC6(x) (((x) & BIT_MASK_RARF_RC6) << BIT_SHIFT_RARF_RC6) +#define BIT_GET_RARF_RC6(x) (((x) >> BIT_SHIFT_RARF_RC6) & BIT_MASK_RARF_RC6) + +#define BIT_SHIFT_RARF_RC5 (32 & CPU_OPT_WIDTH) +#define BIT_MASK_RARF_RC5 0x1f +#define BIT_RARF_RC5(x) (((x) & BIT_MASK_RARF_RC5) << BIT_SHIFT_RARF_RC5) +#define BIT_GET_RARF_RC5(x) (((x) >> BIT_SHIFT_RARF_RC5) & BIT_MASK_RARF_RC5) + +#define BIT_SHIFT_RARF_RC4 24 +#define BIT_MASK_RARF_RC4 0x1f +#define BIT_RARF_RC4(x) (((x) & BIT_MASK_RARF_RC4) << BIT_SHIFT_RARF_RC4) +#define BIT_GET_RARF_RC4(x) (((x) >> BIT_SHIFT_RARF_RC4) & BIT_MASK_RARF_RC4) + +#define BIT_SHIFT_RARF_RC3 16 +#define BIT_MASK_RARF_RC3 0x1f +#define BIT_RARF_RC3(x) (((x) & BIT_MASK_RARF_RC3) << BIT_SHIFT_RARF_RC3) +#define BIT_GET_RARF_RC3(x) (((x) >> BIT_SHIFT_RARF_RC3) & BIT_MASK_RARF_RC3) + +#define BIT_SHIFT_RARF_RC2 8 +#define BIT_MASK_RARF_RC2 0x1f +#define BIT_RARF_RC2(x) (((x) & BIT_MASK_RARF_RC2) << BIT_SHIFT_RARF_RC2) +#define BIT_GET_RARF_RC2(x) (((x) >> BIT_SHIFT_RARF_RC2) & BIT_MASK_RARF_RC2) + +#define BIT_SHIFT_RARF_RC1 0 +#define BIT_MASK_RARF_RC1 0x1f +#define BIT_RARF_RC1(x) (((x) & BIT_MASK_RARF_RC1) << BIT_SHIFT_RARF_RC1) +#define BIT_GET_RARF_RC1(x) (((x) >> BIT_SHIFT_RARF_RC1) & BIT_MASK_RARF_RC1) + +/* 2 REG_RRSR (Offset 0x0440) */ + +#define BIT_SHIFT_RRSR_RSC 21 +#define BIT_MASK_RRSR_RSC 0x3 +#define BIT_RRSR_RSC(x) (((x) & BIT_MASK_RRSR_RSC) << BIT_SHIFT_RRSR_RSC) +#define BIT_GET_RRSR_RSC(x) (((x) >> BIT_SHIFT_RRSR_RSC) & BIT_MASK_RRSR_RSC) + +#define BIT_RRSR_BW BIT(20) + +#define BIT_SHIFT_RRSC_BITMAP 0 +#define BIT_MASK_RRSC_BITMAP 0xfffff +#define BIT_RRSC_BITMAP(x) \ + (((x) & BIT_MASK_RRSC_BITMAP) << BIT_SHIFT_RRSC_BITMAP) +#define BIT_GET_RRSC_BITMAP(x) \ + (((x) >> BIT_SHIFT_RRSC_BITMAP) & BIT_MASK_RRSC_BITMAP) + +/* 2 REG_ARFR0 (Offset 0x0444) */ + +#define BIT_SHIFT_ARFR0_V1 0 +#define BIT_MASK_ARFR0_V1 0xffffffffffffffffL +#define BIT_ARFR0_V1(x) (((x) & BIT_MASK_ARFR0_V1) << BIT_SHIFT_ARFR0_V1) +#define BIT_GET_ARFR0_V1(x) (((x) >> BIT_SHIFT_ARFR0_V1) & BIT_MASK_ARFR0_V1) + +/* 2 REG_ARFR1_V1 (Offset 0x044C) */ + +#define BIT_SHIFT_ARFR1_V1 0 +#define BIT_MASK_ARFR1_V1 0xffffffffffffffffL +#define BIT_ARFR1_V1(x) (((x) & BIT_MASK_ARFR1_V1) << BIT_SHIFT_ARFR1_V1) +#define BIT_GET_ARFR1_V1(x) (((x) >> BIT_SHIFT_ARFR1_V1) & BIT_MASK_ARFR1_V1) + +/* 2 REG_CCK_CHECK (Offset 0x0454) */ + +#define BIT_CHECK_CCK_EN BIT(7) +#define BIT_EN_BCN_PKT_REL BIT(6) +#define BIT_BCN_PORT_SEL BIT(5) +#define BIT_MOREDATA_BYPASS BIT(4) +#define BIT_EN_CLR_CMD_REL_BCN_PKT BIT(3) + +/* 2 REG_CCK_CHECK (Offset 0x0454) */ + +#define BIT_R_EN_SET_MOREDATA BIT(2) +#define BIT__R_DIS_CLEAR_MACID_RELEASE BIT(1) +#define BIT__R_MACID_RELEASE_EN BIT(0) + +/* 2 REG_AMPDU_MAX_TIME (Offset 0x0456) */ + +#define BIT_SHIFT_AMPDU_MAX_TIME 0 +#define BIT_MASK_AMPDU_MAX_TIME 0xff +#define BIT_AMPDU_MAX_TIME(x) \ + (((x) & BIT_MASK_AMPDU_MAX_TIME) << BIT_SHIFT_AMPDU_MAX_TIME) +#define BIT_GET_AMPDU_MAX_TIME(x) \ + (((x) >> BIT_SHIFT_AMPDU_MAX_TIME) & BIT_MASK_AMPDU_MAX_TIME) + +/* 2 REG_BCNQ1_BDNY_V1 (Offset 0x0456) */ + +#define BIT_SHIFT_BCNQ1_PGBNDY_V1 0 +#define BIT_MASK_BCNQ1_PGBNDY_V1 0xfff +#define BIT_BCNQ1_PGBNDY_V1(x) \ + (((x) & BIT_MASK_BCNQ1_PGBNDY_V1) << BIT_SHIFT_BCNQ1_PGBNDY_V1) +#define BIT_GET_BCNQ1_PGBNDY_V1(x) \ + (((x) >> BIT_SHIFT_BCNQ1_PGBNDY_V1) & BIT_MASK_BCNQ1_PGBNDY_V1) + +/* 2 REG_AMPDU_MAX_LENGTH (Offset 0x0458) */ + +#define BIT_SHIFT_AMPDU_MAX_LENGTH 0 +#define BIT_MASK_AMPDU_MAX_LENGTH 0xffffffffL +#define BIT_AMPDU_MAX_LENGTH(x) \ + (((x) & BIT_MASK_AMPDU_MAX_LENGTH) << BIT_SHIFT_AMPDU_MAX_LENGTH) +#define BIT_GET_AMPDU_MAX_LENGTH(x) \ + (((x) >> BIT_SHIFT_AMPDU_MAX_LENGTH) & BIT_MASK_AMPDU_MAX_LENGTH) + +/* 2 REG_ACQ_STOP (Offset 0x045C) */ + +#define BIT_AC7Q_STOP BIT(7) +#define BIT_AC6Q_STOP BIT(6) +#define BIT_AC5Q_STOP BIT(5) +#define BIT_AC4Q_STOP BIT(4) +#define BIT_AC3Q_STOP BIT(3) +#define BIT_AC2Q_STOP BIT(2) +#define BIT_AC1Q_STOP BIT(1) +#define BIT_AC0Q_STOP BIT(0) + +/* 2 REG_NDPA_RATE (Offset 0x045D) */ + +#define BIT_SHIFT_R_NDPA_RATE_V1 0 +#define BIT_MASK_R_NDPA_RATE_V1 0xff +#define BIT_R_NDPA_RATE_V1(x) \ + (((x) & BIT_MASK_R_NDPA_RATE_V1) << BIT_SHIFT_R_NDPA_RATE_V1) +#define BIT_GET_R_NDPA_RATE_V1(x) \ + (((x) >> BIT_SHIFT_R_NDPA_RATE_V1) & BIT_MASK_R_NDPA_RATE_V1) + +/* 2 REG_TX_HANG_CTRL (Offset 0x045E) */ + +#define BIT_R_EN_GNT_BT_AWAKE BIT(3) + +/* 2 REG_TX_HANG_CTRL (Offset 0x045E) */ + +#define BIT_EN_EOF_V1 BIT(2) + +/* 2 REG_TX_HANG_CTRL (Offset 0x045E) */ + +#define BIT_DIS_OQT_BLOCK BIT(1) +#define BIT_SEARCH_QUEUE_EN BIT(0) + +/* 2 REG_NDPA_OPT_CTRL (Offset 0x045F) */ + +#define BIT_R_DIS_MACID_RELEASE_RTY BIT(5) + +/* 2 REG_NDPA_OPT_CTRL (Offset 0x045F) */ + +#define BIT_SHIFT_BW_SIGTA 3 +#define BIT_MASK_BW_SIGTA 0x3 +#define BIT_BW_SIGTA(x) (((x) & BIT_MASK_BW_SIGTA) << BIT_SHIFT_BW_SIGTA) +#define BIT_GET_BW_SIGTA(x) (((x) >> BIT_SHIFT_BW_SIGTA) & BIT_MASK_BW_SIGTA) + +/* 2 REG_NDPA_OPT_CTRL (Offset 0x045F) */ + +#define BIT_EN_BAR_SIGTA BIT(2) + +/* 2 REG_NDPA_OPT_CTRL (Offset 0x045F) */ + +#define BIT_SHIFT_R_NDPA_BW 0 +#define BIT_MASK_R_NDPA_BW 0x3 +#define BIT_R_NDPA_BW(x) (((x) & BIT_MASK_R_NDPA_BW) << BIT_SHIFT_R_NDPA_BW) +#define BIT_GET_R_NDPA_BW(x) (((x) >> BIT_SHIFT_R_NDPA_BW) & BIT_MASK_R_NDPA_BW) + +/* 2 REG_RD_RESP_PKT_TH (Offset 0x0463) */ + +#define BIT_SHIFT_RD_RESP_PKT_TH_V1 0 +#define BIT_MASK_RD_RESP_PKT_TH_V1 0x3f +#define BIT_RD_RESP_PKT_TH_V1(x) \ + (((x) & BIT_MASK_RD_RESP_PKT_TH_V1) << BIT_SHIFT_RD_RESP_PKT_TH_V1) +#define BIT_GET_RD_RESP_PKT_TH_V1(x) \ + (((x) >> BIT_SHIFT_RD_RESP_PKT_TH_V1) & BIT_MASK_RD_RESP_PKT_TH_V1) + +/* 2 REG_CMDQ_INFO (Offset 0x0464) */ + +#define BIT_SHIFT_QUEUEMACID_CMDQ_V1 25 +#define BIT_MASK_QUEUEMACID_CMDQ_V1 0x7f +#define BIT_QUEUEMACID_CMDQ_V1(x) \ + (((x) & BIT_MASK_QUEUEMACID_CMDQ_V1) << BIT_SHIFT_QUEUEMACID_CMDQ_V1) +#define BIT_GET_QUEUEMACID_CMDQ_V1(x) \ + (((x) >> BIT_SHIFT_QUEUEMACID_CMDQ_V1) & BIT_MASK_QUEUEMACID_CMDQ_V1) + +/* 2 REG_CMDQ_INFO (Offset 0x0464) */ + +#define BIT_SHIFT_QUEUEAC_CMDQ_V1 23 +#define BIT_MASK_QUEUEAC_CMDQ_V1 0x3 +#define BIT_QUEUEAC_CMDQ_V1(x) \ + (((x) & BIT_MASK_QUEUEAC_CMDQ_V1) << BIT_SHIFT_QUEUEAC_CMDQ_V1) +#define BIT_GET_QUEUEAC_CMDQ_V1(x) \ + (((x) >> BIT_SHIFT_QUEUEAC_CMDQ_V1) & BIT_MASK_QUEUEAC_CMDQ_V1) + +/* 2 REG_CMDQ_INFO (Offset 0x0464) */ + +#define BIT_TIDEMPTY_CMDQ_V1 BIT(22) + +/* 2 REG_CMDQ_INFO (Offset 0x0464) */ + +#define BIT_SHIFT_TAIL_PKT_CMDQ_V2 11 +#define BIT_MASK_TAIL_PKT_CMDQ_V2 0x7ff +#define BIT_TAIL_PKT_CMDQ_V2(x) \ + (((x) & BIT_MASK_TAIL_PKT_CMDQ_V2) << BIT_SHIFT_TAIL_PKT_CMDQ_V2) +#define BIT_GET_TAIL_PKT_CMDQ_V2(x) \ + (((x) >> BIT_SHIFT_TAIL_PKT_CMDQ_V2) & BIT_MASK_TAIL_PKT_CMDQ_V2) + +/* 2 REG_CMDQ_INFO (Offset 0x0464) */ + +#define BIT_SHIFT_HEAD_PKT_CMDQ_V1 0 +#define BIT_MASK_HEAD_PKT_CMDQ_V1 0x7ff +#define BIT_HEAD_PKT_CMDQ_V1(x) \ + (((x) & BIT_MASK_HEAD_PKT_CMDQ_V1) << BIT_SHIFT_HEAD_PKT_CMDQ_V1) +#define BIT_GET_HEAD_PKT_CMDQ_V1(x) \ + (((x) >> BIT_SHIFT_HEAD_PKT_CMDQ_V1) & BIT_MASK_HEAD_PKT_CMDQ_V1) + +/* 2 REG_Q4_INFO (Offset 0x0468) */ + +#define BIT_SHIFT_QUEUEMACID_Q4_V1 25 +#define BIT_MASK_QUEUEMACID_Q4_V1 0x7f +#define BIT_QUEUEMACID_Q4_V1(x) \ + (((x) & BIT_MASK_QUEUEMACID_Q4_V1) << BIT_SHIFT_QUEUEMACID_Q4_V1) +#define BIT_GET_QUEUEMACID_Q4_V1(x) \ + (((x) >> BIT_SHIFT_QUEUEMACID_Q4_V1) & BIT_MASK_QUEUEMACID_Q4_V1) + +#define BIT_SHIFT_QUEUEAC_Q4_V1 23 +#define BIT_MASK_QUEUEAC_Q4_V1 0x3 +#define BIT_QUEUEAC_Q4_V1(x) \ + (((x) & BIT_MASK_QUEUEAC_Q4_V1) << BIT_SHIFT_QUEUEAC_Q4_V1) +#define BIT_GET_QUEUEAC_Q4_V1(x) \ + (((x) >> BIT_SHIFT_QUEUEAC_Q4_V1) & BIT_MASK_QUEUEAC_Q4_V1) + +/* 2 REG_Q4_INFO (Offset 0x0468) */ + +#define BIT_TIDEMPTY_Q4_V1 BIT(22) + +/* 2 REG_Q4_INFO (Offset 0x0468) */ + +#define BIT_SHIFT_TAIL_PKT_Q4_V2 11 +#define BIT_MASK_TAIL_PKT_Q4_V2 0x7ff +#define BIT_TAIL_PKT_Q4_V2(x) \ + (((x) & BIT_MASK_TAIL_PKT_Q4_V2) << BIT_SHIFT_TAIL_PKT_Q4_V2) +#define BIT_GET_TAIL_PKT_Q4_V2(x) \ + (((x) >> BIT_SHIFT_TAIL_PKT_Q4_V2) & BIT_MASK_TAIL_PKT_Q4_V2) + +/* 2 REG_Q4_INFO (Offset 0x0468) */ + +#define BIT_SHIFT_HEAD_PKT_Q4_V1 0 +#define BIT_MASK_HEAD_PKT_Q4_V1 0x7ff +#define BIT_HEAD_PKT_Q4_V1(x) \ + (((x) & BIT_MASK_HEAD_PKT_Q4_V1) << BIT_SHIFT_HEAD_PKT_Q4_V1) +#define BIT_GET_HEAD_PKT_Q4_V1(x) \ + (((x) >> BIT_SHIFT_HEAD_PKT_Q4_V1) & BIT_MASK_HEAD_PKT_Q4_V1) + +/* 2 REG_Q5_INFO (Offset 0x046C) */ + +#define BIT_SHIFT_QUEUEMACID_Q5_V1 25 +#define BIT_MASK_QUEUEMACID_Q5_V1 0x7f +#define BIT_QUEUEMACID_Q5_V1(x) \ + (((x) & BIT_MASK_QUEUEMACID_Q5_V1) << BIT_SHIFT_QUEUEMACID_Q5_V1) +#define BIT_GET_QUEUEMACID_Q5_V1(x) \ + (((x) >> BIT_SHIFT_QUEUEMACID_Q5_V1) & BIT_MASK_QUEUEMACID_Q5_V1) + +#define BIT_SHIFT_QUEUEAC_Q5_V1 23 +#define BIT_MASK_QUEUEAC_Q5_V1 0x3 +#define BIT_QUEUEAC_Q5_V1(x) \ + (((x) & BIT_MASK_QUEUEAC_Q5_V1) << BIT_SHIFT_QUEUEAC_Q5_V1) +#define BIT_GET_QUEUEAC_Q5_V1(x) \ + (((x) >> BIT_SHIFT_QUEUEAC_Q5_V1) & BIT_MASK_QUEUEAC_Q5_V1) + +/* 2 REG_Q5_INFO (Offset 0x046C) */ + +#define BIT_TIDEMPTY_Q5_V1 BIT(22) + +/* 2 REG_Q5_INFO (Offset 0x046C) */ + +#define BIT_SHIFT_TAIL_PKT_Q5_V2 11 +#define BIT_MASK_TAIL_PKT_Q5_V2 0x7ff +#define BIT_TAIL_PKT_Q5_V2(x) \ + (((x) & BIT_MASK_TAIL_PKT_Q5_V2) << BIT_SHIFT_TAIL_PKT_Q5_V2) +#define BIT_GET_TAIL_PKT_Q5_V2(x) \ + (((x) >> BIT_SHIFT_TAIL_PKT_Q5_V2) & BIT_MASK_TAIL_PKT_Q5_V2) + +/* 2 REG_Q5_INFO (Offset 0x046C) */ + +#define BIT_SHIFT_HEAD_PKT_Q5_V1 0 +#define BIT_MASK_HEAD_PKT_Q5_V1 0x7ff +#define BIT_HEAD_PKT_Q5_V1(x) \ + (((x) & BIT_MASK_HEAD_PKT_Q5_V1) << BIT_SHIFT_HEAD_PKT_Q5_V1) +#define BIT_GET_HEAD_PKT_Q5_V1(x) \ + (((x) >> BIT_SHIFT_HEAD_PKT_Q5_V1) & BIT_MASK_HEAD_PKT_Q5_V1) + +/* 2 REG_Q6_INFO (Offset 0x0470) */ + +#define BIT_SHIFT_QUEUEMACID_Q6_V1 25 +#define BIT_MASK_QUEUEMACID_Q6_V1 0x7f +#define BIT_QUEUEMACID_Q6_V1(x) \ + (((x) & BIT_MASK_QUEUEMACID_Q6_V1) << BIT_SHIFT_QUEUEMACID_Q6_V1) +#define BIT_GET_QUEUEMACID_Q6_V1(x) \ + (((x) >> BIT_SHIFT_QUEUEMACID_Q6_V1) & BIT_MASK_QUEUEMACID_Q6_V1) + +#define BIT_SHIFT_QUEUEAC_Q6_V1 23 +#define BIT_MASK_QUEUEAC_Q6_V1 0x3 +#define BIT_QUEUEAC_Q6_V1(x) \ + (((x) & BIT_MASK_QUEUEAC_Q6_V1) << BIT_SHIFT_QUEUEAC_Q6_V1) +#define BIT_GET_QUEUEAC_Q6_V1(x) \ + (((x) >> BIT_SHIFT_QUEUEAC_Q6_V1) & BIT_MASK_QUEUEAC_Q6_V1) + +/* 2 REG_Q6_INFO (Offset 0x0470) */ + +#define BIT_TIDEMPTY_Q6_V1 BIT(22) + +/* 2 REG_Q6_INFO (Offset 0x0470) */ + +#define BIT_SHIFT_TAIL_PKT_Q6_V2 11 +#define BIT_MASK_TAIL_PKT_Q6_V2 0x7ff +#define BIT_TAIL_PKT_Q6_V2(x) \ + (((x) & BIT_MASK_TAIL_PKT_Q6_V2) << BIT_SHIFT_TAIL_PKT_Q6_V2) +#define BIT_GET_TAIL_PKT_Q6_V2(x) \ + (((x) >> BIT_SHIFT_TAIL_PKT_Q6_V2) & BIT_MASK_TAIL_PKT_Q6_V2) + +/* 2 REG_Q6_INFO (Offset 0x0470) */ + +#define BIT_SHIFT_HEAD_PKT_Q6_V1 0 +#define BIT_MASK_HEAD_PKT_Q6_V1 0x7ff +#define BIT_HEAD_PKT_Q6_V1(x) \ + (((x) & BIT_MASK_HEAD_PKT_Q6_V1) << BIT_SHIFT_HEAD_PKT_Q6_V1) +#define BIT_GET_HEAD_PKT_Q6_V1(x) \ + (((x) >> BIT_SHIFT_HEAD_PKT_Q6_V1) & BIT_MASK_HEAD_PKT_Q6_V1) + +/* 2 REG_Q7_INFO (Offset 0x0474) */ + +#define BIT_SHIFT_QUEUEMACID_Q7_V1 25 +#define BIT_MASK_QUEUEMACID_Q7_V1 0x7f +#define BIT_QUEUEMACID_Q7_V1(x) \ + (((x) & BIT_MASK_QUEUEMACID_Q7_V1) << BIT_SHIFT_QUEUEMACID_Q7_V1) +#define BIT_GET_QUEUEMACID_Q7_V1(x) \ + (((x) >> BIT_SHIFT_QUEUEMACID_Q7_V1) & BIT_MASK_QUEUEMACID_Q7_V1) + +#define BIT_SHIFT_QUEUEAC_Q7_V1 23 +#define BIT_MASK_QUEUEAC_Q7_V1 0x3 +#define BIT_QUEUEAC_Q7_V1(x) \ + (((x) & BIT_MASK_QUEUEAC_Q7_V1) << BIT_SHIFT_QUEUEAC_Q7_V1) +#define BIT_GET_QUEUEAC_Q7_V1(x) \ + (((x) >> BIT_SHIFT_QUEUEAC_Q7_V1) & BIT_MASK_QUEUEAC_Q7_V1) + +/* 2 REG_Q7_INFO (Offset 0x0474) */ + +#define BIT_TIDEMPTY_Q7_V1 BIT(22) + +/* 2 REG_Q7_INFO (Offset 0x0474) */ + +#define BIT_SHIFT_TAIL_PKT_Q7_V2 11 +#define BIT_MASK_TAIL_PKT_Q7_V2 0x7ff +#define BIT_TAIL_PKT_Q7_V2(x) \ + (((x) & BIT_MASK_TAIL_PKT_Q7_V2) << BIT_SHIFT_TAIL_PKT_Q7_V2) +#define BIT_GET_TAIL_PKT_Q7_V2(x) \ + (((x) >> BIT_SHIFT_TAIL_PKT_Q7_V2) & BIT_MASK_TAIL_PKT_Q7_V2) + +/* 2 REG_Q7_INFO (Offset 0x0474) */ + +#define BIT_SHIFT_HEAD_PKT_Q7_V1 0 +#define BIT_MASK_HEAD_PKT_Q7_V1 0x7ff +#define BIT_HEAD_PKT_Q7_V1(x) \ + (((x) & BIT_MASK_HEAD_PKT_Q7_V1) << BIT_SHIFT_HEAD_PKT_Q7_V1) +#define BIT_GET_HEAD_PKT_Q7_V1(x) \ + (((x) >> BIT_SHIFT_HEAD_PKT_Q7_V1) & BIT_MASK_HEAD_PKT_Q7_V1) + +/* 2 REG_WMAC_LBK_BUF_HD_V1 (Offset 0x0478) */ + +#define BIT_SHIFT_WMAC_LBK_BUF_HEAD_V1 0 +#define BIT_MASK_WMAC_LBK_BUF_HEAD_V1 0xfff +#define BIT_WMAC_LBK_BUF_HEAD_V1(x) \ + (((x) & BIT_MASK_WMAC_LBK_BUF_HEAD_V1) \ + << BIT_SHIFT_WMAC_LBK_BUF_HEAD_V1) +#define BIT_GET_WMAC_LBK_BUF_HEAD_V1(x) \ + (((x) >> BIT_SHIFT_WMAC_LBK_BUF_HEAD_V1) & \ + BIT_MASK_WMAC_LBK_BUF_HEAD_V1) + +/* 2 REG_MGQ_BDNY_V1 (Offset 0x047A) */ + +#define BIT_SHIFT_MGQ_PGBNDY_V1 0 +#define BIT_MASK_MGQ_PGBNDY_V1 0xfff +#define BIT_MGQ_PGBNDY_V1(x) \ + (((x) & BIT_MASK_MGQ_PGBNDY_V1) << BIT_SHIFT_MGQ_PGBNDY_V1) +#define BIT_GET_MGQ_PGBNDY_V1(x) \ + (((x) >> BIT_SHIFT_MGQ_PGBNDY_V1) & BIT_MASK_MGQ_PGBNDY_V1) + +/* 2 REG_TXRPT_CTRL (Offset 0x047C) */ + +#define BIT_SHIFT_TRXRPT_TIMER_TH 24 +#define BIT_MASK_TRXRPT_TIMER_TH 0xff +#define BIT_TRXRPT_TIMER_TH(x) \ + (((x) & BIT_MASK_TRXRPT_TIMER_TH) << BIT_SHIFT_TRXRPT_TIMER_TH) +#define BIT_GET_TRXRPT_TIMER_TH(x) \ + (((x) >> BIT_SHIFT_TRXRPT_TIMER_TH) & BIT_MASK_TRXRPT_TIMER_TH) + +/* 2 REG_TXRPT_CTRL (Offset 0x047C) */ + +#define BIT_SHIFT_TRXRPT_LEN_TH 16 +#define BIT_MASK_TRXRPT_LEN_TH 0xff +#define BIT_TRXRPT_LEN_TH(x) \ + (((x) & BIT_MASK_TRXRPT_LEN_TH) << BIT_SHIFT_TRXRPT_LEN_TH) +#define BIT_GET_TRXRPT_LEN_TH(x) \ + (((x) >> BIT_SHIFT_TRXRPT_LEN_TH) & BIT_MASK_TRXRPT_LEN_TH) + +/* 2 REG_TXRPT_CTRL (Offset 0x047C) */ + +#define BIT_SHIFT_TRXRPT_READ_PTR 8 +#define BIT_MASK_TRXRPT_READ_PTR 0xff +#define BIT_TRXRPT_READ_PTR(x) \ + (((x) & BIT_MASK_TRXRPT_READ_PTR) << BIT_SHIFT_TRXRPT_READ_PTR) +#define BIT_GET_TRXRPT_READ_PTR(x) \ + (((x) >> BIT_SHIFT_TRXRPT_READ_PTR) & BIT_MASK_TRXRPT_READ_PTR) + +/* 2 REG_TXRPT_CTRL (Offset 0x047C) */ + +#define BIT_SHIFT_TRXRPT_WRITE_PTR 0 +#define BIT_MASK_TRXRPT_WRITE_PTR 0xff +#define BIT_TRXRPT_WRITE_PTR(x) \ + (((x) & BIT_MASK_TRXRPT_WRITE_PTR) << BIT_SHIFT_TRXRPT_WRITE_PTR) +#define BIT_GET_TRXRPT_WRITE_PTR(x) \ + (((x) >> BIT_SHIFT_TRXRPT_WRITE_PTR) & BIT_MASK_TRXRPT_WRITE_PTR) + +/* 2 REG_INIRTS_RATE_SEL (Offset 0x0480) */ + +#define BIT_LEAG_RTS_BW_DUP BIT(5) + +/* 2 REG_BASIC_CFEND_RATE (Offset 0x0481) */ + +#define BIT_SHIFT_BASIC_CFEND_RATE 0 +#define BIT_MASK_BASIC_CFEND_RATE 0x1f +#define BIT_BASIC_CFEND_RATE(x) \ + (((x) & BIT_MASK_BASIC_CFEND_RATE) << BIT_SHIFT_BASIC_CFEND_RATE) +#define BIT_GET_BASIC_CFEND_RATE(x) \ + (((x) >> BIT_SHIFT_BASIC_CFEND_RATE) & BIT_MASK_BASIC_CFEND_RATE) + +/* 2 REG_STBC_CFEND_RATE (Offset 0x0482) */ + +#define BIT_SHIFT_STBC_CFEND_RATE 0 +#define BIT_MASK_STBC_CFEND_RATE 0x1f +#define BIT_STBC_CFEND_RATE(x) \ + (((x) & BIT_MASK_STBC_CFEND_RATE) << BIT_SHIFT_STBC_CFEND_RATE) +#define BIT_GET_STBC_CFEND_RATE(x) \ + (((x) >> BIT_SHIFT_STBC_CFEND_RATE) & BIT_MASK_STBC_CFEND_RATE) + +/* 2 REG_DATA_SC (Offset 0x0483) */ + +#define BIT_SHIFT_TXSC_40M 4 +#define BIT_MASK_TXSC_40M 0xf +#define BIT_TXSC_40M(x) (((x) & BIT_MASK_TXSC_40M) << BIT_SHIFT_TXSC_40M) +#define BIT_GET_TXSC_40M(x) (((x) >> BIT_SHIFT_TXSC_40M) & BIT_MASK_TXSC_40M) + +#define BIT_SHIFT_TXSC_20M 0 +#define BIT_MASK_TXSC_20M 0xf +#define BIT_TXSC_20M(x) (((x) & BIT_MASK_TXSC_20M) << BIT_SHIFT_TXSC_20M) +#define BIT_GET_TXSC_20M(x) (((x) >> BIT_SHIFT_TXSC_20M) & BIT_MASK_TXSC_20M) + +/* 2 REG_MACID_SLEEP3 (Offset 0x0484) */ + +#define BIT_SHIFT_MACID127_96_PKTSLEEP 0 +#define BIT_MASK_MACID127_96_PKTSLEEP 0xffffffffL +#define BIT_MACID127_96_PKTSLEEP(x) \ + (((x) & BIT_MASK_MACID127_96_PKTSLEEP) \ + << BIT_SHIFT_MACID127_96_PKTSLEEP) +#define BIT_GET_MACID127_96_PKTSLEEP(x) \ + (((x) >> BIT_SHIFT_MACID127_96_PKTSLEEP) & \ + BIT_MASK_MACID127_96_PKTSLEEP) + +/* 2 REG_MACID_SLEEP1 (Offset 0x0488) */ + +#define BIT_SHIFT_MACID63_32_PKTSLEEP 0 +#define BIT_MASK_MACID63_32_PKTSLEEP 0xffffffffL +#define BIT_MACID63_32_PKTSLEEP(x) \ + (((x) & BIT_MASK_MACID63_32_PKTSLEEP) << BIT_SHIFT_MACID63_32_PKTSLEEP) +#define BIT_GET_MACID63_32_PKTSLEEP(x) \ + (((x) >> BIT_SHIFT_MACID63_32_PKTSLEEP) & BIT_MASK_MACID63_32_PKTSLEEP) + +/* 2 REG_ARFR2_V1 (Offset 0x048C) */ + +#define BIT_SHIFT_ARFR2_V1 0 +#define BIT_MASK_ARFR2_V1 0xffffffffffffffffL +#define BIT_ARFR2_V1(x) (((x) & BIT_MASK_ARFR2_V1) << BIT_SHIFT_ARFR2_V1) +#define BIT_GET_ARFR2_V1(x) (((x) >> BIT_SHIFT_ARFR2_V1) & BIT_MASK_ARFR2_V1) + +/* 2 REG_ARFR3_V1 (Offset 0x0494) */ + +#define BIT_SHIFT_ARFR3_V1 0 +#define BIT_MASK_ARFR3_V1 0xffffffffffffffffL +#define BIT_ARFR3_V1(x) (((x) & BIT_MASK_ARFR3_V1) << BIT_SHIFT_ARFR3_V1) +#define BIT_GET_ARFR3_V1(x) (((x) >> BIT_SHIFT_ARFR3_V1) & BIT_MASK_ARFR3_V1) + +/* 2 REG_ARFR4 (Offset 0x049C) */ + +#define BIT_SHIFT_ARFR4 0 +#define BIT_MASK_ARFR4 0xffffffffffffffffL +#define BIT_ARFR4(x) (((x) & BIT_MASK_ARFR4) << BIT_SHIFT_ARFR4) +#define BIT_GET_ARFR4(x) (((x) >> BIT_SHIFT_ARFR4) & BIT_MASK_ARFR4) + +/* 2 REG_ARFR5 (Offset 0x04A4) */ + +#define BIT_SHIFT_ARFR5 0 +#define BIT_MASK_ARFR5 0xffffffffffffffffL +#define BIT_ARFR5(x) (((x) & BIT_MASK_ARFR5) << BIT_SHIFT_ARFR5) +#define BIT_GET_ARFR5(x) (((x) >> BIT_SHIFT_ARFR5) & BIT_MASK_ARFR5) + +/* 2 REG_TXRPT_START_OFFSET (Offset 0x04AC) */ + +#define BIT_SHIFT_MACID_MURATE_OFFSET 24 +#define BIT_MASK_MACID_MURATE_OFFSET 0xff +#define BIT_MACID_MURATE_OFFSET(x) \ + (((x) & BIT_MASK_MACID_MURATE_OFFSET) << BIT_SHIFT_MACID_MURATE_OFFSET) +#define BIT_GET_MACID_MURATE_OFFSET(x) \ + (((x) >> BIT_SHIFT_MACID_MURATE_OFFSET) & BIT_MASK_MACID_MURATE_OFFSET) + +/* 2 REG_TXRPT_START_OFFSET (Offset 0x04AC) */ + +#define BIT_RPTFIFO_SIZE_OPT BIT(16) + +/* 2 REG_TXRPT_START_OFFSET (Offset 0x04AC) */ + +#define BIT_SHIFT_MACID_CTRL_OFFSET 8 +#define BIT_MASK_MACID_CTRL_OFFSET 0xff +#define BIT_MACID_CTRL_OFFSET(x) \ + (((x) & BIT_MASK_MACID_CTRL_OFFSET) << BIT_SHIFT_MACID_CTRL_OFFSET) +#define BIT_GET_MACID_CTRL_OFFSET(x) \ + (((x) >> BIT_SHIFT_MACID_CTRL_OFFSET) & BIT_MASK_MACID_CTRL_OFFSET) + +/* 2 REG_TXRPT_START_OFFSET (Offset 0x04AC) */ + +#define BIT_SHIFT_AMPDU_TXRPT_OFFSET 0 +#define BIT_MASK_AMPDU_TXRPT_OFFSET 0xff +#define BIT_AMPDU_TXRPT_OFFSET(x) \ + (((x) & BIT_MASK_AMPDU_TXRPT_OFFSET) << BIT_SHIFT_AMPDU_TXRPT_OFFSET) +#define BIT_GET_AMPDU_TXRPT_OFFSET(x) \ + (((x) >> BIT_SHIFT_AMPDU_TXRPT_OFFSET) & BIT_MASK_AMPDU_TXRPT_OFFSET) + +/* 2 REG_POWER_STAGE1 (Offset 0x04B4) */ + +#define BIT_PTA_WL_PRI_MASK_CPU_MGQ BIT(31) +#define BIT_PTA_WL_PRI_MASK_BCNQ BIT(30) +#define BIT_PTA_WL_PRI_MASK_HIQ BIT(29) +#define BIT_PTA_WL_PRI_MASK_MGQ BIT(28) +#define BIT_PTA_WL_PRI_MASK_BK BIT(27) +#define BIT_PTA_WL_PRI_MASK_BE BIT(26) +#define BIT_PTA_WL_PRI_MASK_VI BIT(25) +#define BIT_PTA_WL_PRI_MASK_VO BIT(24) + +/* 2 REG_POWER_STAGE1 (Offset 0x04B4) */ + +#define BIT_SHIFT_POWER_STAGE1 0 +#define BIT_MASK_POWER_STAGE1 0xffffff +#define BIT_POWER_STAGE1(x) \ + (((x) & BIT_MASK_POWER_STAGE1) << BIT_SHIFT_POWER_STAGE1) +#define BIT_GET_POWER_STAGE1(x) \ + (((x) >> BIT_SHIFT_POWER_STAGE1) & BIT_MASK_POWER_STAGE1) + +/* 2 REG_POWER_STAGE2 (Offset 0x04B8) */ + +#define BIT__R_CTRL_PKT_POW_ADJ BIT(24) + +/* 2 REG_POWER_STAGE2 (Offset 0x04B8) */ + +#define BIT_SHIFT_POWER_STAGE2 0 +#define BIT_MASK_POWER_STAGE2 0xffffff +#define BIT_POWER_STAGE2(x) \ + (((x) & BIT_MASK_POWER_STAGE2) << BIT_SHIFT_POWER_STAGE2) +#define BIT_GET_POWER_STAGE2(x) \ + (((x) >> BIT_SHIFT_POWER_STAGE2) & BIT_MASK_POWER_STAGE2) + +/* 2 REG_SW_AMPDU_BURST_MODE_CTRL (Offset 0x04BC) */ + +#define BIT_SHIFT_PAD_NUM_THRES 24 +#define BIT_MASK_PAD_NUM_THRES 0x3f +#define BIT_PAD_NUM_THRES(x) \ + (((x) & BIT_MASK_PAD_NUM_THRES) << BIT_SHIFT_PAD_NUM_THRES) +#define BIT_GET_PAD_NUM_THRES(x) \ + (((x) >> BIT_SHIFT_PAD_NUM_THRES) & BIT_MASK_PAD_NUM_THRES) + +/* 2 REG_SW_AMPDU_BURST_MODE_CTRL (Offset 0x04BC) */ + +#define BIT_R_DMA_THIS_QUEUE_BK BIT(23) +#define BIT_R_DMA_THIS_QUEUE_BE BIT(22) +#define BIT_R_DMA_THIS_QUEUE_VI BIT(21) +#define BIT_R_DMA_THIS_QUEUE_VO BIT(20) + +#define BIT_SHIFT_R_TOTAL_LEN_TH 8 +#define BIT_MASK_R_TOTAL_LEN_TH 0xfff +#define BIT_R_TOTAL_LEN_TH(x) \ + (((x) & BIT_MASK_R_TOTAL_LEN_TH) << BIT_SHIFT_R_TOTAL_LEN_TH) +#define BIT_GET_R_TOTAL_LEN_TH(x) \ + (((x) >> BIT_SHIFT_R_TOTAL_LEN_TH) & BIT_MASK_R_TOTAL_LEN_TH) + +/* 2 REG_SW_AMPDU_BURST_MODE_CTRL (Offset 0x04BC) */ + +#define BIT_EN_NEW_EARLY BIT(7) + +/* 2 REG_SW_AMPDU_BURST_MODE_CTRL (Offset 0x04BC) */ + +#define BIT_PRE_TX_CMD BIT(6) + +#define BIT_SHIFT_NUM_SCL_EN 4 +#define BIT_MASK_NUM_SCL_EN 0x3 +#define BIT_NUM_SCL_EN(x) (((x) & BIT_MASK_NUM_SCL_EN) << BIT_SHIFT_NUM_SCL_EN) +#define BIT_GET_NUM_SCL_EN(x) \ + (((x) >> BIT_SHIFT_NUM_SCL_EN) & BIT_MASK_NUM_SCL_EN) + +#define BIT_BK_EN BIT(3) +#define BIT_BE_EN BIT(2) +#define BIT_VI_EN BIT(1) +#define BIT_VO_EN BIT(0) + +/* 2 REG_PKT_LIFE_TIME (Offset 0x04C0) */ + +#define BIT_SHIFT_PKT_LIFTIME_BEBK 16 +#define BIT_MASK_PKT_LIFTIME_BEBK 0xffff +#define BIT_PKT_LIFTIME_BEBK(x) \ + (((x) & BIT_MASK_PKT_LIFTIME_BEBK) << BIT_SHIFT_PKT_LIFTIME_BEBK) +#define BIT_GET_PKT_LIFTIME_BEBK(x) \ + (((x) >> BIT_SHIFT_PKT_LIFTIME_BEBK) & BIT_MASK_PKT_LIFTIME_BEBK) + +#define BIT_SHIFT_PKT_LIFTIME_VOVI 0 +#define BIT_MASK_PKT_LIFTIME_VOVI 0xffff +#define BIT_PKT_LIFTIME_VOVI(x) \ + (((x) & BIT_MASK_PKT_LIFTIME_VOVI) << BIT_SHIFT_PKT_LIFTIME_VOVI) +#define BIT_GET_PKT_LIFTIME_VOVI(x) \ + (((x) >> BIT_SHIFT_PKT_LIFTIME_VOVI) & BIT_MASK_PKT_LIFTIME_VOVI) + +/* 2 REG_STBC_SETTING (Offset 0x04C4) */ + +#define BIT_SHIFT_CDEND_TXTIME_L 4 +#define BIT_MASK_CDEND_TXTIME_L 0xf +#define BIT_CDEND_TXTIME_L(x) \ + (((x) & BIT_MASK_CDEND_TXTIME_L) << BIT_SHIFT_CDEND_TXTIME_L) +#define BIT_GET_CDEND_TXTIME_L(x) \ + (((x) >> BIT_SHIFT_CDEND_TXTIME_L) & BIT_MASK_CDEND_TXTIME_L) + +#define BIT_SHIFT_NESS 2 +#define BIT_MASK_NESS 0x3 +#define BIT_NESS(x) (((x) & BIT_MASK_NESS) << BIT_SHIFT_NESS) +#define BIT_GET_NESS(x) (((x) >> BIT_SHIFT_NESS) & BIT_MASK_NESS) + +#define BIT_SHIFT_STBC_CFEND 0 +#define BIT_MASK_STBC_CFEND 0x3 +#define BIT_STBC_CFEND(x) (((x) & BIT_MASK_STBC_CFEND) << BIT_SHIFT_STBC_CFEND) +#define BIT_GET_STBC_CFEND(x) \ + (((x) >> BIT_SHIFT_STBC_CFEND) & BIT_MASK_STBC_CFEND) + +/* 2 REG_STBC_SETTING2 (Offset 0x04C5) */ + +#define BIT_SHIFT_CDEND_TXTIME_H 0 +#define BIT_MASK_CDEND_TXTIME_H 0x1f +#define BIT_CDEND_TXTIME_H(x) \ + (((x) & BIT_MASK_CDEND_TXTIME_H) << BIT_SHIFT_CDEND_TXTIME_H) +#define BIT_GET_CDEND_TXTIME_H(x) \ + (((x) >> BIT_SHIFT_CDEND_TXTIME_H) & BIT_MASK_CDEND_TXTIME_H) + +/* 2 REG_QUEUE_CTRL (Offset 0x04C6) */ + +#define BIT_PTA_EDCCA_EN BIT(5) +#define BIT_PTA_WL_TX_EN BIT(4) + +/* 2 REG_QUEUE_CTRL (Offset 0x04C6) */ + +#define BIT_R_USE_DATA_BW BIT(3) +#define BIT_TRI_PKT_INT_MODE1 BIT(2) +#define BIT_TRI_PKT_INT_MODE0 BIT(1) +#define BIT_ACQ_MODE_SEL BIT(0) + +/* 2 REG_SINGLE_AMPDU_CTRL (Offset 0x04C7) */ + +#define BIT_EN_SINGLE_APMDU BIT(7) + +/* 2 REG_PROT_MODE_CTRL (Offset 0x04C8) */ + +#define BIT_SHIFT_RTS_MAX_AGG_NUM 24 +#define BIT_MASK_RTS_MAX_AGG_NUM 0x3f +#define BIT_RTS_MAX_AGG_NUM(x) \ + (((x) & BIT_MASK_RTS_MAX_AGG_NUM) << BIT_SHIFT_RTS_MAX_AGG_NUM) +#define BIT_GET_RTS_MAX_AGG_NUM(x) \ + (((x) >> BIT_SHIFT_RTS_MAX_AGG_NUM) & BIT_MASK_RTS_MAX_AGG_NUM) + +#define BIT_SHIFT_MAX_AGG_NUM 16 +#define BIT_MASK_MAX_AGG_NUM 0x3f +#define BIT_MAX_AGG_NUM(x) \ + (((x) & BIT_MASK_MAX_AGG_NUM) << BIT_SHIFT_MAX_AGG_NUM) +#define BIT_GET_MAX_AGG_NUM(x) \ + (((x) >> BIT_SHIFT_MAX_AGG_NUM) & BIT_MASK_MAX_AGG_NUM) + +#define BIT_SHIFT_RTS_TXTIME_TH 8 +#define BIT_MASK_RTS_TXTIME_TH 0xff +#define BIT_RTS_TXTIME_TH(x) \ + (((x) & BIT_MASK_RTS_TXTIME_TH) << BIT_SHIFT_RTS_TXTIME_TH) +#define BIT_GET_RTS_TXTIME_TH(x) \ + (((x) >> BIT_SHIFT_RTS_TXTIME_TH) & BIT_MASK_RTS_TXTIME_TH) + +#define BIT_SHIFT_RTS_LEN_TH 0 +#define BIT_MASK_RTS_LEN_TH 0xff +#define BIT_RTS_LEN_TH(x) (((x) & BIT_MASK_RTS_LEN_TH) << BIT_SHIFT_RTS_LEN_TH) +#define BIT_GET_RTS_LEN_TH(x) \ + (((x) >> BIT_SHIFT_RTS_LEN_TH) & BIT_MASK_RTS_LEN_TH) + +/* 2 REG_BAR_MODE_CTRL (Offset 0x04CC) */ + +#define BIT_SHIFT_BAR_RTY_LMT 16 +#define BIT_MASK_BAR_RTY_LMT 0x3 +#define BIT_BAR_RTY_LMT(x) \ + (((x) & BIT_MASK_BAR_RTY_LMT) << BIT_SHIFT_BAR_RTY_LMT) +#define BIT_GET_BAR_RTY_LMT(x) \ + (((x) >> BIT_SHIFT_BAR_RTY_LMT) & BIT_MASK_BAR_RTY_LMT) + +#define BIT_SHIFT_BAR_PKT_TXTIME_TH 8 +#define BIT_MASK_BAR_PKT_TXTIME_TH 0xff +#define BIT_BAR_PKT_TXTIME_TH(x) \ + (((x) & BIT_MASK_BAR_PKT_TXTIME_TH) << BIT_SHIFT_BAR_PKT_TXTIME_TH) +#define BIT_GET_BAR_PKT_TXTIME_TH(x) \ + (((x) >> BIT_SHIFT_BAR_PKT_TXTIME_TH) & BIT_MASK_BAR_PKT_TXTIME_TH) + +#define BIT_BAR_EN_V1 BIT(6) + +#define BIT_SHIFT_BAR_PKTNUM_TH_V1 0 +#define BIT_MASK_BAR_PKTNUM_TH_V1 0x3f +#define BIT_BAR_PKTNUM_TH_V1(x) \ + (((x) & BIT_MASK_BAR_PKTNUM_TH_V1) << BIT_SHIFT_BAR_PKTNUM_TH_V1) +#define BIT_GET_BAR_PKTNUM_TH_V1(x) \ + (((x) >> BIT_SHIFT_BAR_PKTNUM_TH_V1) & BIT_MASK_BAR_PKTNUM_TH_V1) + +/* 2 REG_RA_TRY_RATE_AGG_LMT (Offset 0x04CF) */ + +#define BIT_SHIFT_RA_TRY_RATE_AGG_LMT_V1 0 +#define BIT_MASK_RA_TRY_RATE_AGG_LMT_V1 0x3f +#define BIT_RA_TRY_RATE_AGG_LMT_V1(x) \ + (((x) & BIT_MASK_RA_TRY_RATE_AGG_LMT_V1) \ + << BIT_SHIFT_RA_TRY_RATE_AGG_LMT_V1) +#define BIT_GET_RA_TRY_RATE_AGG_LMT_V1(x) \ + (((x) >> BIT_SHIFT_RA_TRY_RATE_AGG_LMT_V1) & \ + BIT_MASK_RA_TRY_RATE_AGG_LMT_V1) + +/* 2 REG_MACID_SLEEP2 (Offset 0x04D0) */ + +#define BIT_SHIFT_MACID95_64PKTSLEEP 0 +#define BIT_MASK_MACID95_64PKTSLEEP 0xffffffffL +#define BIT_MACID95_64PKTSLEEP(x) \ + (((x) & BIT_MASK_MACID95_64PKTSLEEP) << BIT_SHIFT_MACID95_64PKTSLEEP) +#define BIT_GET_MACID95_64PKTSLEEP(x) \ + (((x) >> BIT_SHIFT_MACID95_64PKTSLEEP) & BIT_MASK_MACID95_64PKTSLEEP) + +/* 2 REG_MACID_SLEEP (Offset 0x04D4) */ + +#define BIT_SHIFT_MACID31_0_PKTSLEEP 0 +#define BIT_MASK_MACID31_0_PKTSLEEP 0xffffffffL +#define BIT_MACID31_0_PKTSLEEP(x) \ + (((x) & BIT_MASK_MACID31_0_PKTSLEEP) << BIT_SHIFT_MACID31_0_PKTSLEEP) +#define BIT_GET_MACID31_0_PKTSLEEP(x) \ + (((x) >> BIT_SHIFT_MACID31_0_PKTSLEEP) & BIT_MASK_MACID31_0_PKTSLEEP) + +/* 2 REG_HW_SEQ0 (Offset 0x04D8) */ + +#define BIT_SHIFT_HW_SSN_SEQ0 0 +#define BIT_MASK_HW_SSN_SEQ0 0xfff +#define BIT_HW_SSN_SEQ0(x) \ + (((x) & BIT_MASK_HW_SSN_SEQ0) << BIT_SHIFT_HW_SSN_SEQ0) +#define BIT_GET_HW_SSN_SEQ0(x) \ + (((x) >> BIT_SHIFT_HW_SSN_SEQ0) & BIT_MASK_HW_SSN_SEQ0) + +/* 2 REG_HW_SEQ1 (Offset 0x04DA) */ + +#define BIT_SHIFT_HW_SSN_SEQ1 0 +#define BIT_MASK_HW_SSN_SEQ1 0xfff +#define BIT_HW_SSN_SEQ1(x) \ + (((x) & BIT_MASK_HW_SSN_SEQ1) << BIT_SHIFT_HW_SSN_SEQ1) +#define BIT_GET_HW_SSN_SEQ1(x) \ + (((x) >> BIT_SHIFT_HW_SSN_SEQ1) & BIT_MASK_HW_SSN_SEQ1) + +/* 2 REG_HW_SEQ2 (Offset 0x04DC) */ + +#define BIT_SHIFT_HW_SSN_SEQ2 0 +#define BIT_MASK_HW_SSN_SEQ2 0xfff +#define BIT_HW_SSN_SEQ2(x) \ + (((x) & BIT_MASK_HW_SSN_SEQ2) << BIT_SHIFT_HW_SSN_SEQ2) +#define BIT_GET_HW_SSN_SEQ2(x) \ + (((x) >> BIT_SHIFT_HW_SSN_SEQ2) & BIT_MASK_HW_SSN_SEQ2) + +/* 2 REG_HW_SEQ3 (Offset 0x04DE) */ + +#define BIT_SHIFT_HW_SSN_SEQ3 0 +#define BIT_MASK_HW_SSN_SEQ3 0xfff +#define BIT_HW_SSN_SEQ3(x) \ + (((x) & BIT_MASK_HW_SSN_SEQ3) << BIT_SHIFT_HW_SSN_SEQ3) +#define BIT_GET_HW_SSN_SEQ3(x) \ + (((x) >> BIT_SHIFT_HW_SSN_SEQ3) & BIT_MASK_HW_SSN_SEQ3) + +/* 2 REG_NULL_PKT_STATUS_V1 (Offset 0x04E0) */ + +#define BIT_SHIFT_PTCL_TOTAL_PG_V2 2 +#define BIT_MASK_PTCL_TOTAL_PG_V2 0x3fff +#define BIT_PTCL_TOTAL_PG_V2(x) \ + (((x) & BIT_MASK_PTCL_TOTAL_PG_V2) << BIT_SHIFT_PTCL_TOTAL_PG_V2) +#define BIT_GET_PTCL_TOTAL_PG_V2(x) \ + (((x) >> BIT_SHIFT_PTCL_TOTAL_PG_V2) & BIT_MASK_PTCL_TOTAL_PG_V2) + +/* 2 REG_NULL_PKT_STATUS (Offset 0x04E0) */ + +#define BIT_TX_NULL_1 BIT(1) +#define BIT_TX_NULL_0 BIT(0) + +/* 2 REG_PTCL_ERR_STATUS (Offset 0x04E2) */ + +#define BIT_PTCL_RATE_TABLE_INVALID BIT(7) +#define BIT_FTM_T2R_ERROR BIT(6) + +/* 2 REG_PTCL_ERR_STATUS (Offset 0x04E2) */ + +#define BIT_PTCL_ERR0 BIT(5) +#define BIT_PTCL_ERR1 BIT(4) +#define BIT_PTCL_ERR2 BIT(3) +#define BIT_PTCL_ERR3 BIT(2) +#define BIT_PTCL_ERR4 BIT(1) +#define BIT_PTCL_ERR5 BIT(0) + +/* 2 REG_NULL_PKT_STATUS_EXTEND (Offset 0x04E3) */ + +#define BIT_CLI3_TX_NULL_1 BIT(7) +#define BIT_CLI3_TX_NULL_0 BIT(6) +#define BIT_CLI2_TX_NULL_1 BIT(5) +#define BIT_CLI2_TX_NULL_0 BIT(4) +#define BIT_CLI1_TX_NULL_1 BIT(3) +#define BIT_CLI1_TX_NULL_0 BIT(2) +#define BIT_CLI0_TX_NULL_1 BIT(1) + +/* 2 REG_NULL_PKT_STATUS_EXTEND (Offset 0x04E3) */ + +#define BIT_CLI0_TX_NULL_0 BIT(0) + +/* 2 REG_VIDEO_ENHANCEMENT_FUN (Offset 0x04E4) */ + +#define BIT_VIDEO_JUST_DROP BIT(1) +#define BIT_VIDEO_ENHANCEMENT_FUN_EN BIT(0) + +/* 2 REG_BT_POLLUTE_PKT_CNT (Offset 0x04E8) */ + +#define BIT_SHIFT_BT_POLLUTE_PKT_CNT 0 +#define BIT_MASK_BT_POLLUTE_PKT_CNT 0xffff +#define BIT_BT_POLLUTE_PKT_CNT(x) \ + (((x) & BIT_MASK_BT_POLLUTE_PKT_CNT) << BIT_SHIFT_BT_POLLUTE_PKT_CNT) +#define BIT_GET_BT_POLLUTE_PKT_CNT(x) \ + (((x) >> BIT_SHIFT_BT_POLLUTE_PKT_CNT) & BIT_MASK_BT_POLLUTE_PKT_CNT) + +/* 2 REG_PTCL_DBG (Offset 0x04EC) */ + +#define BIT_SHIFT_PTCL_DBG 0 +#define BIT_MASK_PTCL_DBG 0xffffffffL +#define BIT_PTCL_DBG(x) (((x) & BIT_MASK_PTCL_DBG) << BIT_SHIFT_PTCL_DBG) +#define BIT_GET_PTCL_DBG(x) (((x) >> BIT_SHIFT_PTCL_DBG) & BIT_MASK_PTCL_DBG) + +/* 2 REG_CPUMGQ_TIMER_CTRL2 (Offset 0x04F4) */ + +#define BIT_QUEUE_MACID_AC_NOT_THE_SAME BIT(31) + +#define BIT_SHIFT_GTAB_ID 28 +#define BIT_MASK_GTAB_ID 0x7 +#define BIT_GTAB_ID(x) (((x) & BIT_MASK_GTAB_ID) << BIT_SHIFT_GTAB_ID) +#define BIT_GET_GTAB_ID(x) (((x) >> BIT_SHIFT_GTAB_ID) & BIT_MASK_GTAB_ID) + +#define BIT_SHIFT_TRI_HEAD_ADDR 16 +#define BIT_MASK_TRI_HEAD_ADDR 0xfff +#define BIT_TRI_HEAD_ADDR(x) \ + (((x) & BIT_MASK_TRI_HEAD_ADDR) << BIT_SHIFT_TRI_HEAD_ADDR) +#define BIT_GET_TRI_HEAD_ADDR(x) \ + (((x) >> BIT_SHIFT_TRI_HEAD_ADDR) & BIT_MASK_TRI_HEAD_ADDR) + +#define BIT_QUEUE_MACID_AC_NOT_THE_SAME_V1 BIT(15) + +#define BIT_SHIFT_GTAB_ID_V1 12 +#define BIT_MASK_GTAB_ID_V1 0x7 +#define BIT_GTAB_ID_V1(x) (((x) & BIT_MASK_GTAB_ID_V1) << BIT_SHIFT_GTAB_ID_V1) +#define BIT_GET_GTAB_ID_V1(x) \ + (((x) >> BIT_SHIFT_GTAB_ID_V1) & BIT_MASK_GTAB_ID_V1) + +#define BIT_DROP_TH_EN BIT(8) + +#define BIT_SHIFT_DROP_TH 0 +#define BIT_MASK_DROP_TH 0xff +#define BIT_DROP_TH(x) (((x) & BIT_MASK_DROP_TH) << BIT_SHIFT_DROP_TH) +#define BIT_GET_DROP_TH(x) (((x) >> BIT_SHIFT_DROP_TH) & BIT_MASK_DROP_TH) + +/* 2 REG_DUMMY_PAGE4_V1 (Offset 0x04FC) */ + +#define BIT_BCN_EN_EXTHWSEQ BIT(1) +#define BIT_BCN_EN_HWSEQ BIT(0) + +/* 2 REG_MOREDATA (Offset 0x04FE) */ + +#define BIT_MOREDATA_CTRL2_EN_V1 BIT(3) +#define BIT_MOREDATA_CTRL1_EN_V1 BIT(2) +#define BIT_PKTIN_MOREDATA_REPLACE_ENABLE_V1 BIT(0) + +/* 2 REG_EDCA_VO_PARAM (Offset 0x0500) */ + +#define BIT_SHIFT_TXOPLIMIT 16 +#define BIT_MASK_TXOPLIMIT 0x7ff +#define BIT_TXOPLIMIT(x) (((x) & BIT_MASK_TXOPLIMIT) << BIT_SHIFT_TXOPLIMIT) +#define BIT_GET_TXOPLIMIT(x) (((x) >> BIT_SHIFT_TXOPLIMIT) & BIT_MASK_TXOPLIMIT) + +#define BIT_SHIFT_CW 8 +#define BIT_MASK_CW 0xff +#define BIT_CW(x) (((x) & BIT_MASK_CW) << BIT_SHIFT_CW) +#define BIT_GET_CW(x) (((x) >> BIT_SHIFT_CW) & BIT_MASK_CW) + +#define BIT_SHIFT_AIFS 0 +#define BIT_MASK_AIFS 0xff +#define BIT_AIFS(x) (((x) & BIT_MASK_AIFS) << BIT_SHIFT_AIFS) +#define BIT_GET_AIFS(x) (((x) >> BIT_SHIFT_AIFS) & BIT_MASK_AIFS) + +/* 2 REG_BCNTCFG (Offset 0x0510) */ + +#define BIT_SHIFT_BCNCW_MAX 12 +#define BIT_MASK_BCNCW_MAX 0xf +#define BIT_BCNCW_MAX(x) (((x) & BIT_MASK_BCNCW_MAX) << BIT_SHIFT_BCNCW_MAX) +#define BIT_GET_BCNCW_MAX(x) (((x) >> BIT_SHIFT_BCNCW_MAX) & BIT_MASK_BCNCW_MAX) + +#define BIT_SHIFT_BCNCW_MIN 8 +#define BIT_MASK_BCNCW_MIN 0xf +#define BIT_BCNCW_MIN(x) (((x) & BIT_MASK_BCNCW_MIN) << BIT_SHIFT_BCNCW_MIN) +#define BIT_GET_BCNCW_MIN(x) (((x) >> BIT_SHIFT_BCNCW_MIN) & BIT_MASK_BCNCW_MIN) + +#define BIT_SHIFT_BCNIFS 0 +#define BIT_MASK_BCNIFS 0xff +#define BIT_BCNIFS(x) (((x) & BIT_MASK_BCNIFS) << BIT_SHIFT_BCNIFS) +#define BIT_GET_BCNIFS(x) (((x) >> BIT_SHIFT_BCNIFS) & BIT_MASK_BCNIFS) + +/* 2 REG_PIFS (Offset 0x0512) */ + +#define BIT_SHIFT_PIFS 0 +#define BIT_MASK_PIFS 0xff +#define BIT_PIFS(x) (((x) & BIT_MASK_PIFS) << BIT_SHIFT_PIFS) +#define BIT_GET_PIFS(x) (((x) >> BIT_SHIFT_PIFS) & BIT_MASK_PIFS) + +/* 2 REG_RDG_PIFS (Offset 0x0513) */ + +#define BIT_SHIFT_RDG_PIFS 0 +#define BIT_MASK_RDG_PIFS 0xff +#define BIT_RDG_PIFS(x) (((x) & BIT_MASK_RDG_PIFS) << BIT_SHIFT_RDG_PIFS) +#define BIT_GET_RDG_PIFS(x) (((x) >> BIT_SHIFT_RDG_PIFS) & BIT_MASK_RDG_PIFS) + +/* 2 REG_SIFS (Offset 0x0514) */ + +#define BIT_SHIFT_SIFS_OFDM_TRX 24 +#define BIT_MASK_SIFS_OFDM_TRX 0xff +#define BIT_SIFS_OFDM_TRX(x) \ + (((x) & BIT_MASK_SIFS_OFDM_TRX) << BIT_SHIFT_SIFS_OFDM_TRX) +#define BIT_GET_SIFS_OFDM_TRX(x) \ + (((x) >> BIT_SHIFT_SIFS_OFDM_TRX) & BIT_MASK_SIFS_OFDM_TRX) + +#define BIT_SHIFT_SIFS_CCK_TRX 16 +#define BIT_MASK_SIFS_CCK_TRX 0xff +#define BIT_SIFS_CCK_TRX(x) \ + (((x) & BIT_MASK_SIFS_CCK_TRX) << BIT_SHIFT_SIFS_CCK_TRX) +#define BIT_GET_SIFS_CCK_TRX(x) \ + (((x) >> BIT_SHIFT_SIFS_CCK_TRX) & BIT_MASK_SIFS_CCK_TRX) + +#define BIT_SHIFT_SIFS_OFDM_CTX 8 +#define BIT_MASK_SIFS_OFDM_CTX 0xff +#define BIT_SIFS_OFDM_CTX(x) \ + (((x) & BIT_MASK_SIFS_OFDM_CTX) << BIT_SHIFT_SIFS_OFDM_CTX) +#define BIT_GET_SIFS_OFDM_CTX(x) \ + (((x) >> BIT_SHIFT_SIFS_OFDM_CTX) & BIT_MASK_SIFS_OFDM_CTX) + +#define BIT_SHIFT_SIFS_CCK_CTX 0 +#define BIT_MASK_SIFS_CCK_CTX 0xff +#define BIT_SIFS_CCK_CTX(x) \ + (((x) & BIT_MASK_SIFS_CCK_CTX) << BIT_SHIFT_SIFS_CCK_CTX) +#define BIT_GET_SIFS_CCK_CTX(x) \ + (((x) >> BIT_SHIFT_SIFS_CCK_CTX) & BIT_MASK_SIFS_CCK_CTX) + +/* 2 REG_TSFTR_SYN_OFFSET (Offset 0x0518) */ + +#define BIT_SHIFT_TSFTR_SNC_OFFSET 0 +#define BIT_MASK_TSFTR_SNC_OFFSET 0xffff +#define BIT_TSFTR_SNC_OFFSET(x) \ + (((x) & BIT_MASK_TSFTR_SNC_OFFSET) << BIT_SHIFT_TSFTR_SNC_OFFSET) +#define BIT_GET_TSFTR_SNC_OFFSET(x) \ + (((x) >> BIT_SHIFT_TSFTR_SNC_OFFSET) & BIT_MASK_TSFTR_SNC_OFFSET) + +/* 2 REG_AGGR_BREAK_TIME (Offset 0x051A) */ + +#define BIT_SHIFT_AGGR_BK_TIME 0 +#define BIT_MASK_AGGR_BK_TIME 0xff +#define BIT_AGGR_BK_TIME(x) \ + (((x) & BIT_MASK_AGGR_BK_TIME) << BIT_SHIFT_AGGR_BK_TIME) +#define BIT_GET_AGGR_BK_TIME(x) \ + (((x) >> BIT_SHIFT_AGGR_BK_TIME) & BIT_MASK_AGGR_BK_TIME) + +/* 2 REG_SLOT (Offset 0x051B) */ + +#define BIT_SHIFT_SLOT 0 +#define BIT_MASK_SLOT 0xff +#define BIT_SLOT(x) (((x) & BIT_MASK_SLOT) << BIT_SHIFT_SLOT) +#define BIT_GET_SLOT(x) (((x) >> BIT_SHIFT_SLOT) & BIT_MASK_SLOT) + +/* 2 REG_TX_PTCL_CTRL (Offset 0x0520) */ + +#define BIT_DIS_EDCCA BIT(15) +#define BIT_DIS_CCA BIT(14) +#define BIT_LSIG_TXOP_TXCMD_NAV BIT(13) +#define BIT_SIFS_BK_EN BIT(12) + +#define BIT_SHIFT_TXQ_NAV_MSK 8 +#define BIT_MASK_TXQ_NAV_MSK 0xf +#define BIT_TXQ_NAV_MSK(x) \ + (((x) & BIT_MASK_TXQ_NAV_MSK) << BIT_SHIFT_TXQ_NAV_MSK) +#define BIT_GET_TXQ_NAV_MSK(x) \ + (((x) >> BIT_SHIFT_TXQ_NAV_MSK) & BIT_MASK_TXQ_NAV_MSK) + +#define BIT_DIS_CW BIT(7) +#define BIT_NAV_END_TXOP BIT(6) +#define BIT_RDG_END_TXOP BIT(5) +#define BIT_AC_INBCN_HOLD BIT(4) +#define BIT_MGTQ_TXOP_EN BIT(3) +#define BIT_MGTQ_RTSMF_EN BIT(2) +#define BIT_HIQ_RTSMF_EN BIT(1) +#define BIT_BCN_RTSMF_EN BIT(0) + +/* 2 REG_TXPAUSE (Offset 0x0522) */ + +#define BIT_STOP_BCN_HI_MGT BIT(7) +#define BIT_MAC_STOPBCNQ BIT(6) +#define BIT_MAC_STOPHIQ BIT(5) +#define BIT_MAC_STOPMGQ BIT(4) +#define BIT_MAC_STOPBK BIT(3) +#define BIT_MAC_STOPBE BIT(2) +#define BIT_MAC_STOPVI BIT(1) +#define BIT_MAC_STOPVO BIT(0) + +/* 2 REG_DIS_TXREQ_CLR (Offset 0x0523) */ + +#define BIT_DIS_BT_CCA BIT(7) + +/* 2 REG_DIS_TXREQ_CLR (Offset 0x0523) */ + +#define BIT_DIS_TXREQ_CLR_HI BIT(5) +#define BIT_DIS_TXREQ_CLR_MGQ BIT(4) +#define BIT_DIS_TXREQ_CLR_VO BIT(3) +#define BIT_DIS_TXREQ_CLR_VI BIT(2) +#define BIT_DIS_TXREQ_CLR_BE BIT(1) +#define BIT_DIS_TXREQ_CLR_BK BIT(0) + +/* 2 REG_RD_CTRL (Offset 0x0524) */ + +#define BIT_EN_CLR_TXREQ_INCCA BIT(15) +#define BIT_DIS_TX_OVER_BCNQ BIT(14) + +/* 2 REG_RD_CTRL (Offset 0x0524) */ + +#define BIT_EN_BCNERR_INCCCA BIT(13) + +/* 2 REG_RD_CTRL (Offset 0x0524) */ + +#define BIT_EDCCA_MSK_CNTDOWN_EN BIT(11) +#define BIT_DIS_TXOP_CFE BIT(10) +#define BIT_DIS_LSIG_CFE BIT(9) +#define BIT_DIS_STBC_CFE BIT(8) +#define BIT_BKQ_RD_INIT_EN BIT(7) +#define BIT_BEQ_RD_INIT_EN BIT(6) +#define BIT_VIQ_RD_INIT_EN BIT(5) +#define BIT_VOQ_RD_INIT_EN BIT(4) +#define BIT_BKQ_RD_RESP_EN BIT(3) +#define BIT_BEQ_RD_RESP_EN BIT(2) +#define BIT_VIQ_RD_RESP_EN BIT(1) +#define BIT_VOQ_RD_RESP_EN BIT(0) + +/* 2 REG_MBSSID_CTRL (Offset 0x0526) */ + +#define BIT_MBID_BCNQ7_EN BIT(7) +#define BIT_MBID_BCNQ6_EN BIT(6) +#define BIT_MBID_BCNQ5_EN BIT(5) +#define BIT_MBID_BCNQ4_EN BIT(4) +#define BIT_MBID_BCNQ3_EN BIT(3) +#define BIT_MBID_BCNQ2_EN BIT(2) +#define BIT_MBID_BCNQ1_EN BIT(1) +#define BIT_MBID_BCNQ0_EN BIT(0) + +/* 2 REG_P2PPS_CTRL (Offset 0x0527) */ + +#define BIT_P2P_CTW_ALLSTASLEEP BIT(7) +#define BIT_P2P_OFF_DISTX_EN BIT(6) +#define BIT_PWR_MGT_EN BIT(5) + +/* 2 REG_P2PPS_CTRL (Offset 0x0527) */ + +#define BIT_P2P_NOA1_EN BIT(2) +#define BIT_P2P_NOA0_EN BIT(1) + +/* 2 REG_PKT_LIFETIME_CTRL (Offset 0x0528) */ + +#define BIT_EN_P2P_CTWND1 BIT(23) + +/* 2 REG_PKT_LIFETIME_CTRL (Offset 0x0528) */ + +#define BIT_EN_BKF_CLR_TXREQ BIT(22) +#define BIT_EN_TSFBIT32_RST_P2P BIT(21) +#define BIT_EN_BCN_TX_BTCCA BIT(20) +#define BIT_DIS_PKT_TX_ATIM BIT(19) +#define BIT_DIS_BCN_DIS_CTN BIT(18) +#define BIT_EN_NAVEND_RST_TXOP BIT(17) +#define BIT_EN_FILTER_CCA BIT(16) + +#define BIT_SHIFT_CCA_FILTER_THRS 8 +#define BIT_MASK_CCA_FILTER_THRS 0xff +#define BIT_CCA_FILTER_THRS(x) \ + (((x) & BIT_MASK_CCA_FILTER_THRS) << BIT_SHIFT_CCA_FILTER_THRS) +#define BIT_GET_CCA_FILTER_THRS(x) \ + (((x) >> BIT_SHIFT_CCA_FILTER_THRS) & BIT_MASK_CCA_FILTER_THRS) + +#define BIT_SHIFT_EDCCA_THRS 0 +#define BIT_MASK_EDCCA_THRS 0xff +#define BIT_EDCCA_THRS(x) (((x) & BIT_MASK_EDCCA_THRS) << BIT_SHIFT_EDCCA_THRS) +#define BIT_GET_EDCCA_THRS(x) \ + (((x) >> BIT_SHIFT_EDCCA_THRS) & BIT_MASK_EDCCA_THRS) + +/* 2 REG_P2PPS_SPEC_STATE (Offset 0x052B) */ + +#define BIT_SPEC_POWER_STATE BIT(7) +#define BIT_SPEC_CTWINDOW_ON BIT(6) +#define BIT_SPEC_BEACON_AREA_ON BIT(5) +#define BIT_SPEC_CTWIN_EARLY_DISTX BIT(4) +#define BIT_SPEC_NOA1_OFF_PERIOD BIT(3) +#define BIT_SPEC_FORCE_DOZE1 BIT(2) +#define BIT_SPEC_NOA0_OFF_PERIOD BIT(1) +#define BIT_SPEC_FORCE_DOZE0 BIT(0) + +/* 2 REG_QUEUE_INCOL_THR (Offset 0x0538) */ + +#define BIT_SHIFT_BK_QUEUE_THR 24 +#define BIT_MASK_BK_QUEUE_THR 0xff +#define BIT_BK_QUEUE_THR(x) \ + (((x) & BIT_MASK_BK_QUEUE_THR) << BIT_SHIFT_BK_QUEUE_THR) +#define BIT_GET_BK_QUEUE_THR(x) \ + (((x) >> BIT_SHIFT_BK_QUEUE_THR) & BIT_MASK_BK_QUEUE_THR) + +#define BIT_SHIFT_BE_QUEUE_THR 16 +#define BIT_MASK_BE_QUEUE_THR 0xff +#define BIT_BE_QUEUE_THR(x) \ + (((x) & BIT_MASK_BE_QUEUE_THR) << BIT_SHIFT_BE_QUEUE_THR) +#define BIT_GET_BE_QUEUE_THR(x) \ + (((x) >> BIT_SHIFT_BE_QUEUE_THR) & BIT_MASK_BE_QUEUE_THR) + +#define BIT_SHIFT_VI_QUEUE_THR 8 +#define BIT_MASK_VI_QUEUE_THR 0xff +#define BIT_VI_QUEUE_THR(x) \ + (((x) & BIT_MASK_VI_QUEUE_THR) << BIT_SHIFT_VI_QUEUE_THR) +#define BIT_GET_VI_QUEUE_THR(x) \ + (((x) >> BIT_SHIFT_VI_QUEUE_THR) & BIT_MASK_VI_QUEUE_THR) + +#define BIT_SHIFT_VO_QUEUE_THR 0 +#define BIT_MASK_VO_QUEUE_THR 0xff +#define BIT_VO_QUEUE_THR(x) \ + (((x) & BIT_MASK_VO_QUEUE_THR) << BIT_SHIFT_VO_QUEUE_THR) +#define BIT_GET_VO_QUEUE_THR(x) \ + (((x) >> BIT_SHIFT_VO_QUEUE_THR) & BIT_MASK_VO_QUEUE_THR) + +/* 2 REG_QUEUE_INCOL_EN (Offset 0x053C) */ + +#define BIT_QUEUE_INCOL_EN BIT(16) + +/* 2 REG_QUEUE_INCOL_EN (Offset 0x053C) */ + +#define BIT_SHIFT_BE_TRIGGER_NUM 12 +#define BIT_MASK_BE_TRIGGER_NUM 0xf +#define BIT_BE_TRIGGER_NUM(x) \ + (((x) & BIT_MASK_BE_TRIGGER_NUM) << BIT_SHIFT_BE_TRIGGER_NUM) +#define BIT_GET_BE_TRIGGER_NUM(x) \ + (((x) >> BIT_SHIFT_BE_TRIGGER_NUM) & BIT_MASK_BE_TRIGGER_NUM) + +/* 2 REG_QUEUE_INCOL_EN (Offset 0x053C) */ + +#define BIT_SHIFT_BK_TRIGGER_NUM 8 +#define BIT_MASK_BK_TRIGGER_NUM 0xf +#define BIT_BK_TRIGGER_NUM(x) \ + (((x) & BIT_MASK_BK_TRIGGER_NUM) << BIT_SHIFT_BK_TRIGGER_NUM) +#define BIT_GET_BK_TRIGGER_NUM(x) \ + (((x) >> BIT_SHIFT_BK_TRIGGER_NUM) & BIT_MASK_BK_TRIGGER_NUM) + +/* 2 REG_QUEUE_INCOL_EN (Offset 0x053C) */ + +#define BIT_SHIFT_VI_TRIGGER_NUM 4 +#define BIT_MASK_VI_TRIGGER_NUM 0xf +#define BIT_VI_TRIGGER_NUM(x) \ + (((x) & BIT_MASK_VI_TRIGGER_NUM) << BIT_SHIFT_VI_TRIGGER_NUM) +#define BIT_GET_VI_TRIGGER_NUM(x) \ + (((x) >> BIT_SHIFT_VI_TRIGGER_NUM) & BIT_MASK_VI_TRIGGER_NUM) + +#define BIT_SHIFT_VO_TRIGGER_NUM 0 +#define BIT_MASK_VO_TRIGGER_NUM 0xf +#define BIT_VO_TRIGGER_NUM(x) \ + (((x) & BIT_MASK_VO_TRIGGER_NUM) << BIT_SHIFT_VO_TRIGGER_NUM) +#define BIT_GET_VO_TRIGGER_NUM(x) \ + (((x) >> BIT_SHIFT_VO_TRIGGER_NUM) & BIT_MASK_VO_TRIGGER_NUM) + +/* 2 REG_TBTT_PROHIBIT (Offset 0x0540) */ + +#define BIT_SHIFT_TBTT_HOLD_TIME_AP 8 +#define BIT_MASK_TBTT_HOLD_TIME_AP 0xfff +#define BIT_TBTT_HOLD_TIME_AP(x) \ + (((x) & BIT_MASK_TBTT_HOLD_TIME_AP) << BIT_SHIFT_TBTT_HOLD_TIME_AP) +#define BIT_GET_TBTT_HOLD_TIME_AP(x) \ + (((x) >> BIT_SHIFT_TBTT_HOLD_TIME_AP) & BIT_MASK_TBTT_HOLD_TIME_AP) + +/* 2 REG_TBTT_PROHIBIT (Offset 0x0540) */ + +#define BIT_SHIFT_TBTT_PROHIBIT_SETUP 0 +#define BIT_MASK_TBTT_PROHIBIT_SETUP 0xf +#define BIT_TBTT_PROHIBIT_SETUP(x) \ + (((x) & BIT_MASK_TBTT_PROHIBIT_SETUP) << BIT_SHIFT_TBTT_PROHIBIT_SETUP) +#define BIT_GET_TBTT_PROHIBIT_SETUP(x) \ + (((x) >> BIT_SHIFT_TBTT_PROHIBIT_SETUP) & BIT_MASK_TBTT_PROHIBIT_SETUP) + +/* 2 REG_P2PPS_STATE (Offset 0x0543) */ + +#define BIT_POWER_STATE BIT(7) +#define BIT_CTWINDOW_ON BIT(6) +#define BIT_BEACON_AREA_ON BIT(5) +#define BIT_CTWIN_EARLY_DISTX BIT(4) +#define BIT_NOA1_OFF_PERIOD BIT(3) +#define BIT_FORCE_DOZE1 BIT(2) +#define BIT_NOA0_OFF_PERIOD BIT(1) +#define BIT_FORCE_DOZE0 BIT(0) + +/* 2 REG_RD_NAV_NXT (Offset 0x0544) */ + +#define BIT_SHIFT_RD_NAV_PROT_NXT 0 +#define BIT_MASK_RD_NAV_PROT_NXT 0xffff +#define BIT_RD_NAV_PROT_NXT(x) \ + (((x) & BIT_MASK_RD_NAV_PROT_NXT) << BIT_SHIFT_RD_NAV_PROT_NXT) +#define BIT_GET_RD_NAV_PROT_NXT(x) \ + (((x) >> BIT_SHIFT_RD_NAV_PROT_NXT) & BIT_MASK_RD_NAV_PROT_NXT) + +/* 2 REG_NAV_PROT_LEN (Offset 0x0546) */ + +#define BIT_SHIFT_NAV_PROT_LEN 0 +#define BIT_MASK_NAV_PROT_LEN 0xffff +#define BIT_NAV_PROT_LEN(x) \ + (((x) & BIT_MASK_NAV_PROT_LEN) << BIT_SHIFT_NAV_PROT_LEN) +#define BIT_GET_NAV_PROT_LEN(x) \ + (((x) >> BIT_SHIFT_NAV_PROT_LEN) & BIT_MASK_NAV_PROT_LEN) + +/* 2 REG_BCN_CTRL (Offset 0x0550) */ + +#define BIT_DIS_RX_BSSID_FIT BIT(6) + +/* 2 REG_BCN_CTRL (Offset 0x0550) */ + +#define BIT_P0_EN_TXBCN_RPT BIT(5) + +/* 2 REG_BCN_CTRL (Offset 0x0550) */ + +#define BIT_DIS_TSF_UDT BIT(4) +#define BIT_EN_BCN_FUNCTION BIT(3) + +/* 2 REG_BCN_CTRL (Offset 0x0550) */ + +#define BIT_P0_EN_RXBCN_RPT BIT(2) + +/* 2 REG_BCN_CTRL (Offset 0x0550) */ + +#define BIT_EN_P2P_CTWINDOW BIT(1) +#define BIT_EN_P2P_BCNQ_AREA BIT(0) + +/* 2 REG_BCN_CTRL_CLINT0 (Offset 0x0551) */ + +#define BIT_CLI0_DIS_RX_BSSID_FIT BIT(6) + +/* 2 REG_BCN_CTRL_CLINT0 (Offset 0x0551) */ + +#define BIT_CLI0_DIS_TSF_UDT BIT(4) + +/* 2 REG_BCN_CTRL_CLINT0 (Offset 0x0551) */ + +#define BIT_CLI0_EN_BCN_FUNCTION BIT(3) + +/* 2 REG_BCN_CTRL_CLINT0 (Offset 0x0551) */ + +#define BIT_CLI0_EN_RXBCN_RPT BIT(2) + +/* 2 REG_BCN_CTRL_CLINT0 (Offset 0x0551) */ + +#define BIT_CLI0_ENP2P_CTWINDOW BIT(1) +#define BIT_CLI0_ENP2P_BCNQ_AREA BIT(0) + +/* 2 REG_MBID_NUM (Offset 0x0552) */ + +#define BIT_EN_PRE_DL_BEACON BIT(3) + +#define BIT_SHIFT_MBID_BCN_NUM 0 +#define BIT_MASK_MBID_BCN_NUM 0x7 +#define BIT_MBID_BCN_NUM(x) \ + (((x) & BIT_MASK_MBID_BCN_NUM) << BIT_SHIFT_MBID_BCN_NUM) +#define BIT_GET_MBID_BCN_NUM(x) \ + (((x) >> BIT_SHIFT_MBID_BCN_NUM) & BIT_MASK_MBID_BCN_NUM) + +/* 2 REG_DUAL_TSF_RST (Offset 0x0553) */ + +#define BIT_FREECNT_RST BIT(5) + +/* 2 REG_DUAL_TSF_RST (Offset 0x0553) */ + +#define BIT_TSFTR_CLI3_RST BIT(4) + +/* 2 REG_DUAL_TSF_RST (Offset 0x0553) */ + +#define BIT_TSFTR_CLI2_RST BIT(3) + +/* 2 REG_DUAL_TSF_RST (Offset 0x0553) */ + +#define BIT_TSFTR_CLI1_RST BIT(2) + +/* 2 REG_DUAL_TSF_RST (Offset 0x0553) */ + +#define BIT_TSFTR_CLI0_RST BIT(1) + +/* 2 REG_DUAL_TSF_RST (Offset 0x0553) */ + +#define BIT_TSFTR_RST BIT(0) + +/* 2 REG_MBSSID_BCN_SPACE (Offset 0x0554) */ + +#define BIT_SHIFT_BCN_TIMER_SEL_FWRD 28 +#define BIT_MASK_BCN_TIMER_SEL_FWRD 0x7 +#define BIT_BCN_TIMER_SEL_FWRD(x) \ + (((x) & BIT_MASK_BCN_TIMER_SEL_FWRD) << BIT_SHIFT_BCN_TIMER_SEL_FWRD) +#define BIT_GET_BCN_TIMER_SEL_FWRD(x) \ + (((x) >> BIT_SHIFT_BCN_TIMER_SEL_FWRD) & BIT_MASK_BCN_TIMER_SEL_FWRD) + +/* 2 REG_MBSSID_BCN_SPACE (Offset 0x0554) */ + +#define BIT_SHIFT_BCN_SPACE_CLINT0 16 +#define BIT_MASK_BCN_SPACE_CLINT0 0xfff +#define BIT_BCN_SPACE_CLINT0(x) \ + (((x) & BIT_MASK_BCN_SPACE_CLINT0) << BIT_SHIFT_BCN_SPACE_CLINT0) +#define BIT_GET_BCN_SPACE_CLINT0(x) \ + (((x) >> BIT_SHIFT_BCN_SPACE_CLINT0) & BIT_MASK_BCN_SPACE_CLINT0) + +/* 2 REG_MBSSID_BCN_SPACE (Offset 0x0554) */ + +#define BIT_SHIFT_BCN_SPACE0 0 +#define BIT_MASK_BCN_SPACE0 0xffff +#define BIT_BCN_SPACE0(x) (((x) & BIT_MASK_BCN_SPACE0) << BIT_SHIFT_BCN_SPACE0) +#define BIT_GET_BCN_SPACE0(x) \ + (((x) >> BIT_SHIFT_BCN_SPACE0) & BIT_MASK_BCN_SPACE0) + +/* 2 REG_DRVERLYINT (Offset 0x0558) */ + +#define BIT_SHIFT_DRVERLYITV 0 +#define BIT_MASK_DRVERLYITV 0xff +#define BIT_DRVERLYITV(x) (((x) & BIT_MASK_DRVERLYITV) << BIT_SHIFT_DRVERLYITV) +#define BIT_GET_DRVERLYITV(x) \ + (((x) >> BIT_SHIFT_DRVERLYITV) & BIT_MASK_DRVERLYITV) + +/* 2 REG_BCNDMATIM (Offset 0x0559) */ + +#define BIT_SHIFT_BCNDMATIM 0 +#define BIT_MASK_BCNDMATIM 0xff +#define BIT_BCNDMATIM(x) (((x) & BIT_MASK_BCNDMATIM) << BIT_SHIFT_BCNDMATIM) +#define BIT_GET_BCNDMATIM(x) (((x) >> BIT_SHIFT_BCNDMATIM) & BIT_MASK_BCNDMATIM) + +/* 2 REG_ATIMWND (Offset 0x055A) */ + +#define BIT_SHIFT_ATIMWND0 0 +#define BIT_MASK_ATIMWND0 0xffff +#define BIT_ATIMWND0(x) (((x) & BIT_MASK_ATIMWND0) << BIT_SHIFT_ATIMWND0) +#define BIT_GET_ATIMWND0(x) (((x) >> BIT_SHIFT_ATIMWND0) & BIT_MASK_ATIMWND0) + +/* 2 REG_USTIME_TSF (Offset 0x055C) */ + +#define BIT_SHIFT_USTIME_TSF_V1 0 +#define BIT_MASK_USTIME_TSF_V1 0xff +#define BIT_USTIME_TSF_V1(x) \ + (((x) & BIT_MASK_USTIME_TSF_V1) << BIT_SHIFT_USTIME_TSF_V1) +#define BIT_GET_USTIME_TSF_V1(x) \ + (((x) >> BIT_SHIFT_USTIME_TSF_V1) & BIT_MASK_USTIME_TSF_V1) + +/* 2 REG_BCN_MAX_ERR (Offset 0x055D) */ + +#define BIT_SHIFT_BCN_MAX_ERR 0 +#define BIT_MASK_BCN_MAX_ERR 0xff +#define BIT_BCN_MAX_ERR(x) \ + (((x) & BIT_MASK_BCN_MAX_ERR) << BIT_SHIFT_BCN_MAX_ERR) +#define BIT_GET_BCN_MAX_ERR(x) \ + (((x) >> BIT_SHIFT_BCN_MAX_ERR) & BIT_MASK_BCN_MAX_ERR) + +/* 2 REG_RXTSF_OFFSET_CCK (Offset 0x055E) */ + +#define BIT_SHIFT_CCK_RXTSF_OFFSET 0 +#define BIT_MASK_CCK_RXTSF_OFFSET 0xff +#define BIT_CCK_RXTSF_OFFSET(x) \ + (((x) & BIT_MASK_CCK_RXTSF_OFFSET) << BIT_SHIFT_CCK_RXTSF_OFFSET) +#define BIT_GET_CCK_RXTSF_OFFSET(x) \ + (((x) >> BIT_SHIFT_CCK_RXTSF_OFFSET) & BIT_MASK_CCK_RXTSF_OFFSET) + +/* 2 REG_RXTSF_OFFSET_OFDM (Offset 0x055F) */ + +#define BIT_SHIFT_OFDM_RXTSF_OFFSET 0 +#define BIT_MASK_OFDM_RXTSF_OFFSET 0xff +#define BIT_OFDM_RXTSF_OFFSET(x) \ + (((x) & BIT_MASK_OFDM_RXTSF_OFFSET) << BIT_SHIFT_OFDM_RXTSF_OFFSET) +#define BIT_GET_OFDM_RXTSF_OFFSET(x) \ + (((x) >> BIT_SHIFT_OFDM_RXTSF_OFFSET) & BIT_MASK_OFDM_RXTSF_OFFSET) + +/* 2 REG_TSFTR (Offset 0x0560) */ + +#define BIT_SHIFT_TSF_TIMER 0 +#define BIT_MASK_TSF_TIMER 0xffffffffffffffffL +#define BIT_TSF_TIMER(x) (((x) & BIT_MASK_TSF_TIMER) << BIT_SHIFT_TSF_TIMER) +#define BIT_GET_TSF_TIMER(x) (((x) >> BIT_SHIFT_TSF_TIMER) & BIT_MASK_TSF_TIMER) + +/* 2 REG_FREERUN_CNT (Offset 0x0568) */ + +#define BIT_SHIFT_FREERUN_CNT 0 +#define BIT_MASK_FREERUN_CNT 0xffffffffffffffffL +#define BIT_FREERUN_CNT(x) \ + (((x) & BIT_MASK_FREERUN_CNT) << BIT_SHIFT_FREERUN_CNT) +#define BIT_GET_FREERUN_CNT(x) \ + (((x) >> BIT_SHIFT_FREERUN_CNT) & BIT_MASK_FREERUN_CNT) + +/* 2 REG_ATIMWND1_V1 (Offset 0x0570) */ + +#define BIT_SHIFT_ATIMWND1_V1 0 +#define BIT_MASK_ATIMWND1_V1 0xff +#define BIT_ATIMWND1_V1(x) \ + (((x) & BIT_MASK_ATIMWND1_V1) << BIT_SHIFT_ATIMWND1_V1) +#define BIT_GET_ATIMWND1_V1(x) \ + (((x) >> BIT_SHIFT_ATIMWND1_V1) & BIT_MASK_ATIMWND1_V1) + +/* 2 REG_TBTT_PROHIBIT_INFRA (Offset 0x0571) */ + +#define BIT_SHIFT_TBTT_PROHIBIT_INFRA 0 +#define BIT_MASK_TBTT_PROHIBIT_INFRA 0xff +#define BIT_TBTT_PROHIBIT_INFRA(x) \ + (((x) & BIT_MASK_TBTT_PROHIBIT_INFRA) << BIT_SHIFT_TBTT_PROHIBIT_INFRA) +#define BIT_GET_TBTT_PROHIBIT_INFRA(x) \ + (((x) >> BIT_SHIFT_TBTT_PROHIBIT_INFRA) & BIT_MASK_TBTT_PROHIBIT_INFRA) + +/* 2 REG_CTWND (Offset 0x0572) */ + +#define BIT_SHIFT_CTWND 0 +#define BIT_MASK_CTWND 0xff +#define BIT_CTWND(x) (((x) & BIT_MASK_CTWND) << BIT_SHIFT_CTWND) +#define BIT_GET_CTWND(x) (((x) >> BIT_SHIFT_CTWND) & BIT_MASK_CTWND) + +/* 2 REG_BCNIVLCUNT (Offset 0x0573) */ + +#define BIT_SHIFT_BCNIVLCUNT 0 +#define BIT_MASK_BCNIVLCUNT 0x7f +#define BIT_BCNIVLCUNT(x) (((x) & BIT_MASK_BCNIVLCUNT) << BIT_SHIFT_BCNIVLCUNT) +#define BIT_GET_BCNIVLCUNT(x) \ + (((x) >> BIT_SHIFT_BCNIVLCUNT) & BIT_MASK_BCNIVLCUNT) + +/* 2 REG_BCNDROPCTRL (Offset 0x0574) */ + +#define BIT_BEACON_DROP_EN BIT(7) + +#define BIT_SHIFT_BEACON_DROP_IVL 0 +#define BIT_MASK_BEACON_DROP_IVL 0x7f +#define BIT_BEACON_DROP_IVL(x) \ + (((x) & BIT_MASK_BEACON_DROP_IVL) << BIT_SHIFT_BEACON_DROP_IVL) +#define BIT_GET_BEACON_DROP_IVL(x) \ + (((x) >> BIT_SHIFT_BEACON_DROP_IVL) & BIT_MASK_BEACON_DROP_IVL) + +/* 2 REG_HGQ_TIMEOUT_PERIOD (Offset 0x0575) */ + +#define BIT_SHIFT_HGQ_TIMEOUT_PERIOD 0 +#define BIT_MASK_HGQ_TIMEOUT_PERIOD 0xff +#define BIT_HGQ_TIMEOUT_PERIOD(x) \ + (((x) & BIT_MASK_HGQ_TIMEOUT_PERIOD) << BIT_SHIFT_HGQ_TIMEOUT_PERIOD) +#define BIT_GET_HGQ_TIMEOUT_PERIOD(x) \ + (((x) >> BIT_SHIFT_HGQ_TIMEOUT_PERIOD) & BIT_MASK_HGQ_TIMEOUT_PERIOD) + +/* 2 REG_TXCMD_TIMEOUT_PERIOD (Offset 0x0576) */ + +#define BIT_SHIFT_TXCMD_TIMEOUT_PERIOD 0 +#define BIT_MASK_TXCMD_TIMEOUT_PERIOD 0xff +#define BIT_TXCMD_TIMEOUT_PERIOD(x) \ + (((x) & BIT_MASK_TXCMD_TIMEOUT_PERIOD) \ + << BIT_SHIFT_TXCMD_TIMEOUT_PERIOD) +#define BIT_GET_TXCMD_TIMEOUT_PERIOD(x) \ + (((x) >> BIT_SHIFT_TXCMD_TIMEOUT_PERIOD) & \ + BIT_MASK_TXCMD_TIMEOUT_PERIOD) + +/* 2 REG_MISC_CTRL (Offset 0x0577) */ + +#define BIT_DIS_TRX_CAL_BCN BIT(5) +#define BIT_DIS_TX_CAL_TBTT BIT(4) +#define BIT_EN_FREECNT BIT(3) +#define BIT_BCN_AGGRESSION BIT(2) + +#define BIT_SHIFT_DIS_SECONDARY_CCA 0 +#define BIT_MASK_DIS_SECONDARY_CCA 0x3 +#define BIT_DIS_SECONDARY_CCA(x) \ + (((x) & BIT_MASK_DIS_SECONDARY_CCA) << BIT_SHIFT_DIS_SECONDARY_CCA) +#define BIT_GET_DIS_SECONDARY_CCA(x) \ + (((x) >> BIT_SHIFT_DIS_SECONDARY_CCA) & BIT_MASK_DIS_SECONDARY_CCA) + +/* 2 REG_BCN_CTRL_CLINT1 (Offset 0x0578) */ + +#define BIT_CLI1_DIS_RX_BSSID_FIT BIT(6) +#define BIT_CLI1_DIS_TSF_UDT BIT(4) +#define BIT_CLI1_EN_BCN_FUNCTION BIT(3) + +/* 2 REG_BCN_CTRL_CLINT1 (Offset 0x0578) */ + +#define BIT_CLI1_EN_RXBCN_RPT BIT(2) + +/* 2 REG_BCN_CTRL_CLINT1 (Offset 0x0578) */ + +#define BIT_CLI1_ENP2P_CTWINDOW BIT(1) +#define BIT_CLI1_ENP2P_BCNQ_AREA BIT(0) + +/* 2 REG_BCN_CTRL_CLINT2 (Offset 0x0579) */ + +#define BIT_CLI2_DIS_RX_BSSID_FIT BIT(6) +#define BIT_CLI2_DIS_TSF_UDT BIT(4) +#define BIT_CLI2_EN_BCN_FUNCTION BIT(3) + +/* 2 REG_BCN_CTRL_CLINT2 (Offset 0x0579) */ + +#define BIT_CLI2_EN_RXBCN_RPT BIT(2) + +/* 2 REG_BCN_CTRL_CLINT2 (Offset 0x0579) */ + +#define BIT_CLI2_ENP2P_CTWINDOW BIT(1) +#define BIT_CLI2_ENP2P_BCNQ_AREA BIT(0) + +/* 2 REG_BCN_CTRL_CLINT3 (Offset 0x057A) */ + +#define BIT_CLI3_DIS_RX_BSSID_FIT BIT(6) +#define BIT_CLI3_DIS_TSF_UDT BIT(4) +#define BIT_CLI3_EN_BCN_FUNCTION BIT(3) + +/* 2 REG_BCN_CTRL_CLINT3 (Offset 0x057A) */ + +#define BIT_CLI3_EN_RXBCN_RPT BIT(2) + +/* 2 REG_BCN_CTRL_CLINT3 (Offset 0x057A) */ + +#define BIT_CLI3_ENP2P_CTWINDOW BIT(1) +#define BIT_CLI3_ENP2P_BCNQ_AREA BIT(0) + +/* 2 REG_EXTEND_CTRL (Offset 0x057B) */ + +#define BIT_EN_TSFBIT32_RST_P2P2 BIT(5) +#define BIT_EN_TSFBIT32_RST_P2P1 BIT(4) + +#define BIT_SHIFT_PORT_SEL 0 +#define BIT_MASK_PORT_SEL 0x7 +#define BIT_PORT_SEL(x) (((x) & BIT_MASK_PORT_SEL) << BIT_SHIFT_PORT_SEL) +#define BIT_GET_PORT_SEL(x) (((x) >> BIT_SHIFT_PORT_SEL) & BIT_MASK_PORT_SEL) + +/* 2 REG_P2PPS1_SPEC_STATE (Offset 0x057C) */ + +#define BIT_P2P1_SPEC_POWER_STATE BIT(7) +#define BIT_P2P1_SPEC_CTWINDOW_ON BIT(6) +#define BIT_P2P1_SPEC_BCN_AREA_ON BIT(5) +#define BIT_P2P1_SPEC_CTWIN_EARLY_DISTX BIT(4) +#define BIT_P2P1_SPEC_NOA1_OFF_PERIOD BIT(3) +#define BIT_P2P1_SPEC_FORCE_DOZE1 BIT(2) +#define BIT_P2P1_SPEC_NOA0_OFF_PERIOD BIT(1) +#define BIT_P2P1_SPEC_FORCE_DOZE0 BIT(0) + +/* 2 REG_P2PPS1_STATE (Offset 0x057D) */ + +#define BIT_P2P1_POWER_STATE BIT(7) +#define BIT_P2P1_CTWINDOW_ON BIT(6) +#define BIT_P2P1_BEACON_AREA_ON BIT(5) +#define BIT_P2P1_CTWIN_EARLY_DISTX BIT(4) +#define BIT_P2P1_NOA1_OFF_PERIOD BIT(3) +#define BIT_P2P1_FORCE_DOZE1 BIT(2) +#define BIT_P2P1_NOA0_OFF_PERIOD BIT(1) +#define BIT_P2P1_FORCE_DOZE0 BIT(0) + +/* 2 REG_P2PPS2_SPEC_STATE (Offset 0x057E) */ + +#define BIT_P2P2_SPEC_POWER_STATE BIT(7) +#define BIT_P2P2_SPEC_CTWINDOW_ON BIT(6) +#define BIT_P2P2_SPEC_BCN_AREA_ON BIT(5) +#define BIT_P2P2_SPEC_CTWIN_EARLY_DISTX BIT(4) +#define BIT_P2P2_SPEC_NOA1_OFF_PERIOD BIT(3) +#define BIT_P2P2_SPEC_FORCE_DOZE1 BIT(2) +#define BIT_P2P2_SPEC_NOA0_OFF_PERIOD BIT(1) +#define BIT_P2P2_SPEC_FORCE_DOZE0 BIT(0) + +/* 2 REG_P2PPS2_STATE (Offset 0x057F) */ + +#define BIT_P2P2_POWER_STATE BIT(7) +#define BIT_P2P2_CTWINDOW_ON BIT(6) +#define BIT_P2P2_BEACON_AREA_ON BIT(5) +#define BIT_P2P2_CTWIN_EARLY_DISTX BIT(4) +#define BIT_P2P2_NOA1_OFF_PERIOD BIT(3) +#define BIT_P2P2_FORCE_DOZE1 BIT(2) +#define BIT_P2P2_NOA0_OFF_PERIOD BIT(1) +#define BIT_P2P2_FORCE_DOZE0 BIT(0) + +/* 2 REG_PS_TIMER0 (Offset 0x0580) */ + +#define BIT_SHIFT_PSTIMER0_INT 5 +#define BIT_MASK_PSTIMER0_INT 0x7ffffff +#define BIT_PSTIMER0_INT(x) \ + (((x) & BIT_MASK_PSTIMER0_INT) << BIT_SHIFT_PSTIMER0_INT) +#define BIT_GET_PSTIMER0_INT(x) \ + (((x) >> BIT_SHIFT_PSTIMER0_INT) & BIT_MASK_PSTIMER0_INT) + +/* 2 REG_PS_TIMER1 (Offset 0x0584) */ + +#define BIT_SHIFT_PSTIMER1_INT 5 +#define BIT_MASK_PSTIMER1_INT 0x7ffffff +#define BIT_PSTIMER1_INT(x) \ + (((x) & BIT_MASK_PSTIMER1_INT) << BIT_SHIFT_PSTIMER1_INT) +#define BIT_GET_PSTIMER1_INT(x) \ + (((x) >> BIT_SHIFT_PSTIMER1_INT) & BIT_MASK_PSTIMER1_INT) + +/* 2 REG_PS_TIMER2 (Offset 0x0588) */ + +#define BIT_SHIFT_PSTIMER2_INT 5 +#define BIT_MASK_PSTIMER2_INT 0x7ffffff +#define BIT_PSTIMER2_INT(x) \ + (((x) & BIT_MASK_PSTIMER2_INT) << BIT_SHIFT_PSTIMER2_INT) +#define BIT_GET_PSTIMER2_INT(x) \ + (((x) >> BIT_SHIFT_PSTIMER2_INT) & BIT_MASK_PSTIMER2_INT) + +/* 2 REG_TBTT_CTN_AREA (Offset 0x058C) */ + +#define BIT_SHIFT_TBTT_CTN_AREA 0 +#define BIT_MASK_TBTT_CTN_AREA 0xff +#define BIT_TBTT_CTN_AREA(x) \ + (((x) & BIT_MASK_TBTT_CTN_AREA) << BIT_SHIFT_TBTT_CTN_AREA) +#define BIT_GET_TBTT_CTN_AREA(x) \ + (((x) >> BIT_SHIFT_TBTT_CTN_AREA) & BIT_MASK_TBTT_CTN_AREA) + +/* 2 REG_FORCE_BCN_IFS (Offset 0x058E) */ + +#define BIT_SHIFT_FORCE_BCN_IFS 0 +#define BIT_MASK_FORCE_BCN_IFS 0xff +#define BIT_FORCE_BCN_IFS(x) \ + (((x) & BIT_MASK_FORCE_BCN_IFS) << BIT_SHIFT_FORCE_BCN_IFS) +#define BIT_GET_FORCE_BCN_IFS(x) \ + (((x) >> BIT_SHIFT_FORCE_BCN_IFS) & BIT_MASK_FORCE_BCN_IFS) + +/* 2 REG_TXOP_MIN (Offset 0x0590) */ + +#define BIT_SHIFT_TXOP_MIN 0 +#define BIT_MASK_TXOP_MIN 0x3fff +#define BIT_TXOP_MIN(x) (((x) & BIT_MASK_TXOP_MIN) << BIT_SHIFT_TXOP_MIN) +#define BIT_GET_TXOP_MIN(x) (((x) >> BIT_SHIFT_TXOP_MIN) & BIT_MASK_TXOP_MIN) + +/* 2 REG_PRE_BKF_TIME (Offset 0x0592) */ + +#define BIT_SHIFT_PRE_BKF_TIME 0 +#define BIT_MASK_PRE_BKF_TIME 0xff +#define BIT_PRE_BKF_TIME(x) \ + (((x) & BIT_MASK_PRE_BKF_TIME) << BIT_SHIFT_PRE_BKF_TIME) +#define BIT_GET_PRE_BKF_TIME(x) \ + (((x) >> BIT_SHIFT_PRE_BKF_TIME) & BIT_MASK_PRE_BKF_TIME) + +/* 2 REG_CROSS_TXOP_CTRL (Offset 0x0593) */ + +#define BIT_DTIM_BYPASS BIT(2) +#define BIT_RTS_NAV_TXOP BIT(1) +#define BIT_NOT_CROSS_TXOP BIT(0) + +/* 2 REG_ATIMWND2 (Offset 0x05A0) */ + +#define BIT_SHIFT_ATIMWND2 0 +#define BIT_MASK_ATIMWND2 0xff +#define BIT_ATIMWND2(x) (((x) & BIT_MASK_ATIMWND2) << BIT_SHIFT_ATIMWND2) +#define BIT_GET_ATIMWND2(x) (((x) >> BIT_SHIFT_ATIMWND2) & BIT_MASK_ATIMWND2) + +/* 2 REG_ATIMWND3 (Offset 0x05A1) */ + +#define BIT_SHIFT_ATIMWND3 0 +#define BIT_MASK_ATIMWND3 0xff +#define BIT_ATIMWND3(x) (((x) & BIT_MASK_ATIMWND3) << BIT_SHIFT_ATIMWND3) +#define BIT_GET_ATIMWND3(x) (((x) >> BIT_SHIFT_ATIMWND3) & BIT_MASK_ATIMWND3) + +/* 2 REG_ATIMWND4 (Offset 0x05A2) */ + +#define BIT_SHIFT_ATIMWND4 0 +#define BIT_MASK_ATIMWND4 0xff +#define BIT_ATIMWND4(x) (((x) & BIT_MASK_ATIMWND4) << BIT_SHIFT_ATIMWND4) +#define BIT_GET_ATIMWND4(x) (((x) >> BIT_SHIFT_ATIMWND4) & BIT_MASK_ATIMWND4) + +/* 2 REG_ATIMWND5 (Offset 0x05A3) */ + +#define BIT_SHIFT_ATIMWND5 0 +#define BIT_MASK_ATIMWND5 0xff +#define BIT_ATIMWND5(x) (((x) & BIT_MASK_ATIMWND5) << BIT_SHIFT_ATIMWND5) +#define BIT_GET_ATIMWND5(x) (((x) >> BIT_SHIFT_ATIMWND5) & BIT_MASK_ATIMWND5) + +/* 2 REG_ATIMWND6 (Offset 0x05A4) */ + +#define BIT_SHIFT_ATIMWND6 0 +#define BIT_MASK_ATIMWND6 0xff +#define BIT_ATIMWND6(x) (((x) & BIT_MASK_ATIMWND6) << BIT_SHIFT_ATIMWND6) +#define BIT_GET_ATIMWND6(x) (((x) >> BIT_SHIFT_ATIMWND6) & BIT_MASK_ATIMWND6) + +/* 2 REG_ATIMWND7 (Offset 0x05A5) */ + +#define BIT_SHIFT_ATIMWND7 0 +#define BIT_MASK_ATIMWND7 0xff +#define BIT_ATIMWND7(x) (((x) & BIT_MASK_ATIMWND7) << BIT_SHIFT_ATIMWND7) +#define BIT_GET_ATIMWND7(x) (((x) >> BIT_SHIFT_ATIMWND7) & BIT_MASK_ATIMWND7) + +/* 2 REG_ATIMUGT (Offset 0x05A6) */ + +#define BIT_SHIFT_ATIM_URGENT 0 +#define BIT_MASK_ATIM_URGENT 0xff +#define BIT_ATIM_URGENT(x) \ + (((x) & BIT_MASK_ATIM_URGENT) << BIT_SHIFT_ATIM_URGENT) +#define BIT_GET_ATIM_URGENT(x) \ + (((x) >> BIT_SHIFT_ATIM_URGENT) & BIT_MASK_ATIM_URGENT) + +/* 2 REG_HIQ_NO_LMT_EN (Offset 0x05A7) */ + +#define BIT_HIQ_NO_LMT_EN_VAP7 BIT(7) +#define BIT_HIQ_NO_LMT_EN_VAP6 BIT(6) +#define BIT_HIQ_NO_LMT_EN_VAP5 BIT(5) +#define BIT_HIQ_NO_LMT_EN_VAP4 BIT(4) +#define BIT_HIQ_NO_LMT_EN_VAP3 BIT(3) +#define BIT_HIQ_NO_LMT_EN_VAP2 BIT(2) +#define BIT_HIQ_NO_LMT_EN_VAP1 BIT(1) +#define BIT_HIQ_NO_LMT_EN_ROOT BIT(0) + +/* 2 REG_DTIM_COUNTER_ROOT (Offset 0x05A8) */ + +#define BIT_SHIFT_DTIM_COUNT_ROOT 0 +#define BIT_MASK_DTIM_COUNT_ROOT 0xff +#define BIT_DTIM_COUNT_ROOT(x) \ + (((x) & BIT_MASK_DTIM_COUNT_ROOT) << BIT_SHIFT_DTIM_COUNT_ROOT) +#define BIT_GET_DTIM_COUNT_ROOT(x) \ + (((x) >> BIT_SHIFT_DTIM_COUNT_ROOT) & BIT_MASK_DTIM_COUNT_ROOT) + +/* 2 REG_DTIM_COUNTER_VAP1 (Offset 0x05A9) */ + +#define BIT_SHIFT_DTIM_COUNT_VAP1 0 +#define BIT_MASK_DTIM_COUNT_VAP1 0xff +#define BIT_DTIM_COUNT_VAP1(x) \ + (((x) & BIT_MASK_DTIM_COUNT_VAP1) << BIT_SHIFT_DTIM_COUNT_VAP1) +#define BIT_GET_DTIM_COUNT_VAP1(x) \ + (((x) >> BIT_SHIFT_DTIM_COUNT_VAP1) & BIT_MASK_DTIM_COUNT_VAP1) + +/* 2 REG_DTIM_COUNTER_VAP2 (Offset 0x05AA) */ + +#define BIT_SHIFT_DTIM_COUNT_VAP2 0 +#define BIT_MASK_DTIM_COUNT_VAP2 0xff +#define BIT_DTIM_COUNT_VAP2(x) \ + (((x) & BIT_MASK_DTIM_COUNT_VAP2) << BIT_SHIFT_DTIM_COUNT_VAP2) +#define BIT_GET_DTIM_COUNT_VAP2(x) \ + (((x) >> BIT_SHIFT_DTIM_COUNT_VAP2) & BIT_MASK_DTIM_COUNT_VAP2) + +/* 2 REG_DTIM_COUNTER_VAP3 (Offset 0x05AB) */ + +#define BIT_SHIFT_DTIM_COUNT_VAP3 0 +#define BIT_MASK_DTIM_COUNT_VAP3 0xff +#define BIT_DTIM_COUNT_VAP3(x) \ + (((x) & BIT_MASK_DTIM_COUNT_VAP3) << BIT_SHIFT_DTIM_COUNT_VAP3) +#define BIT_GET_DTIM_COUNT_VAP3(x) \ + (((x) >> BIT_SHIFT_DTIM_COUNT_VAP3) & BIT_MASK_DTIM_COUNT_VAP3) + +/* 2 REG_DTIM_COUNTER_VAP4 (Offset 0x05AC) */ + +#define BIT_SHIFT_DTIM_COUNT_VAP4 0 +#define BIT_MASK_DTIM_COUNT_VAP4 0xff +#define BIT_DTIM_COUNT_VAP4(x) \ + (((x) & BIT_MASK_DTIM_COUNT_VAP4) << BIT_SHIFT_DTIM_COUNT_VAP4) +#define BIT_GET_DTIM_COUNT_VAP4(x) \ + (((x) >> BIT_SHIFT_DTIM_COUNT_VAP4) & BIT_MASK_DTIM_COUNT_VAP4) + +/* 2 REG_DTIM_COUNTER_VAP5 (Offset 0x05AD) */ + +#define BIT_SHIFT_DTIM_COUNT_VAP5 0 +#define BIT_MASK_DTIM_COUNT_VAP5 0xff +#define BIT_DTIM_COUNT_VAP5(x) \ + (((x) & BIT_MASK_DTIM_COUNT_VAP5) << BIT_SHIFT_DTIM_COUNT_VAP5) +#define BIT_GET_DTIM_COUNT_VAP5(x) \ + (((x) >> BIT_SHIFT_DTIM_COUNT_VAP5) & BIT_MASK_DTIM_COUNT_VAP5) + +/* 2 REG_DTIM_COUNTER_VAP6 (Offset 0x05AE) */ + +#define BIT_SHIFT_DTIM_COUNT_VAP6 0 +#define BIT_MASK_DTIM_COUNT_VAP6 0xff +#define BIT_DTIM_COUNT_VAP6(x) \ + (((x) & BIT_MASK_DTIM_COUNT_VAP6) << BIT_SHIFT_DTIM_COUNT_VAP6) +#define BIT_GET_DTIM_COUNT_VAP6(x) \ + (((x) >> BIT_SHIFT_DTIM_COUNT_VAP6) & BIT_MASK_DTIM_COUNT_VAP6) + +/* 2 REG_DTIM_COUNTER_VAP7 (Offset 0x05AF) */ + +#define BIT_SHIFT_DTIM_COUNT_VAP7 0 +#define BIT_MASK_DTIM_COUNT_VAP7 0xff +#define BIT_DTIM_COUNT_VAP7(x) \ + (((x) & BIT_MASK_DTIM_COUNT_VAP7) << BIT_SHIFT_DTIM_COUNT_VAP7) +#define BIT_GET_DTIM_COUNT_VAP7(x) \ + (((x) >> BIT_SHIFT_DTIM_COUNT_VAP7) & BIT_MASK_DTIM_COUNT_VAP7) + +/* 2 REG_DIS_ATIM (Offset 0x05B0) */ + +#define BIT_DIS_ATIM_VAP7 BIT(7) +#define BIT_DIS_ATIM_VAP6 BIT(6) +#define BIT_DIS_ATIM_VAP5 BIT(5) +#define BIT_DIS_ATIM_VAP4 BIT(4) +#define BIT_DIS_ATIM_VAP3 BIT(3) +#define BIT_DIS_ATIM_VAP2 BIT(2) +#define BIT_DIS_ATIM_VAP1 BIT(1) +#define BIT_DIS_ATIM_ROOT BIT(0) + +/* 2 REG_EARLY_128US (Offset 0x05B1) */ + +#define BIT_SHIFT_TSFT_SEL_TIMER1 3 +#define BIT_MASK_TSFT_SEL_TIMER1 0x7 +#define BIT_TSFT_SEL_TIMER1(x) \ + (((x) & BIT_MASK_TSFT_SEL_TIMER1) << BIT_SHIFT_TSFT_SEL_TIMER1) +#define BIT_GET_TSFT_SEL_TIMER1(x) \ + (((x) >> BIT_SHIFT_TSFT_SEL_TIMER1) & BIT_MASK_TSFT_SEL_TIMER1) + +#define BIT_SHIFT_EARLY_128US 0 +#define BIT_MASK_EARLY_128US 0x7 +#define BIT_EARLY_128US(x) \ + (((x) & BIT_MASK_EARLY_128US) << BIT_SHIFT_EARLY_128US) +#define BIT_GET_EARLY_128US(x) \ + (((x) >> BIT_SHIFT_EARLY_128US) & BIT_MASK_EARLY_128US) + +/* 2 REG_P2PPS1_CTRL (Offset 0x05B2) */ + +#define BIT_P2P1_CTW_ALLSTASLEEP BIT(7) +#define BIT_P2P1_OFF_DISTX_EN BIT(6) +#define BIT_P2P1_PWR_MGT_EN BIT(5) +#define BIT_P2P1_NOA1_EN BIT(2) +#define BIT_P2P1_NOA0_EN BIT(1) + +/* 2 REG_P2PPS2_CTRL (Offset 0x05B3) */ + +#define BIT_P2P2_CTW_ALLSTASLEEP BIT(7) +#define BIT_P2P2_OFF_DISTX_EN BIT(6) +#define BIT_P2P2_PWR_MGT_EN BIT(5) +#define BIT_P2P2_NOA1_EN BIT(2) +#define BIT_P2P2_NOA0_EN BIT(1) + +/* 2 REG_TIMER0_SRC_SEL (Offset 0x05B4) */ + +#define BIT_SHIFT_SYNC_CLI_SEL 4 +#define BIT_MASK_SYNC_CLI_SEL 0x7 +#define BIT_SYNC_CLI_SEL(x) \ + (((x) & BIT_MASK_SYNC_CLI_SEL) << BIT_SHIFT_SYNC_CLI_SEL) +#define BIT_GET_SYNC_CLI_SEL(x) \ + (((x) >> BIT_SHIFT_SYNC_CLI_SEL) & BIT_MASK_SYNC_CLI_SEL) + +#define BIT_SHIFT_TSFT_SEL_TIMER0 0 +#define BIT_MASK_TSFT_SEL_TIMER0 0x7 +#define BIT_TSFT_SEL_TIMER0(x) \ + (((x) & BIT_MASK_TSFT_SEL_TIMER0) << BIT_SHIFT_TSFT_SEL_TIMER0) +#define BIT_GET_TSFT_SEL_TIMER0(x) \ + (((x) >> BIT_SHIFT_TSFT_SEL_TIMER0) & BIT_MASK_TSFT_SEL_TIMER0) + +/* 2 REG_NOA_UNIT_SEL (Offset 0x05B5) */ + +#define BIT_SHIFT_NOA_UNIT2_SEL 8 +#define BIT_MASK_NOA_UNIT2_SEL 0x7 +#define BIT_NOA_UNIT2_SEL(x) \ + (((x) & BIT_MASK_NOA_UNIT2_SEL) << BIT_SHIFT_NOA_UNIT2_SEL) +#define BIT_GET_NOA_UNIT2_SEL(x) \ + (((x) >> BIT_SHIFT_NOA_UNIT2_SEL) & BIT_MASK_NOA_UNIT2_SEL) + +#define BIT_SHIFT_NOA_UNIT1_SEL 4 +#define BIT_MASK_NOA_UNIT1_SEL 0x7 +#define BIT_NOA_UNIT1_SEL(x) \ + (((x) & BIT_MASK_NOA_UNIT1_SEL) << BIT_SHIFT_NOA_UNIT1_SEL) +#define BIT_GET_NOA_UNIT1_SEL(x) \ + (((x) >> BIT_SHIFT_NOA_UNIT1_SEL) & BIT_MASK_NOA_UNIT1_SEL) + +#define BIT_SHIFT_NOA_UNIT0_SEL 0 +#define BIT_MASK_NOA_UNIT0_SEL 0x7 +#define BIT_NOA_UNIT0_SEL(x) \ + (((x) & BIT_MASK_NOA_UNIT0_SEL) << BIT_SHIFT_NOA_UNIT0_SEL) +#define BIT_GET_NOA_UNIT0_SEL(x) \ + (((x) >> BIT_SHIFT_NOA_UNIT0_SEL) & BIT_MASK_NOA_UNIT0_SEL) + +/* 2 REG_P2POFF_DIS_TXTIME (Offset 0x05B7) */ + +#define BIT_SHIFT_P2POFF_DIS_TXTIME 0 +#define BIT_MASK_P2POFF_DIS_TXTIME 0xff +#define BIT_P2POFF_DIS_TXTIME(x) \ + (((x) & BIT_MASK_P2POFF_DIS_TXTIME) << BIT_SHIFT_P2POFF_DIS_TXTIME) +#define BIT_GET_P2POFF_DIS_TXTIME(x) \ + (((x) >> BIT_SHIFT_P2POFF_DIS_TXTIME) & BIT_MASK_P2POFF_DIS_TXTIME) + +/* 2 REG_MBSSID_BCN_SPACE2 (Offset 0x05B8) */ + +#define BIT_SHIFT_BCN_SPACE_CLINT2 16 +#define BIT_MASK_BCN_SPACE_CLINT2 0xfff +#define BIT_BCN_SPACE_CLINT2(x) \ + (((x) & BIT_MASK_BCN_SPACE_CLINT2) << BIT_SHIFT_BCN_SPACE_CLINT2) +#define BIT_GET_BCN_SPACE_CLINT2(x) \ + (((x) >> BIT_SHIFT_BCN_SPACE_CLINT2) & BIT_MASK_BCN_SPACE_CLINT2) + +#define BIT_SHIFT_BCN_SPACE_CLINT1 0 +#define BIT_MASK_BCN_SPACE_CLINT1 0xfff +#define BIT_BCN_SPACE_CLINT1(x) \ + (((x) & BIT_MASK_BCN_SPACE_CLINT1) << BIT_SHIFT_BCN_SPACE_CLINT1) +#define BIT_GET_BCN_SPACE_CLINT1(x) \ + (((x) >> BIT_SHIFT_BCN_SPACE_CLINT1) & BIT_MASK_BCN_SPACE_CLINT1) + +/* 2 REG_MBSSID_BCN_SPACE3 (Offset 0x05BC) */ + +#define BIT_SHIFT_SUB_BCN_SPACE 16 +#define BIT_MASK_SUB_BCN_SPACE 0xff +#define BIT_SUB_BCN_SPACE(x) \ + (((x) & BIT_MASK_SUB_BCN_SPACE) << BIT_SHIFT_SUB_BCN_SPACE) +#define BIT_GET_SUB_BCN_SPACE(x) \ + (((x) >> BIT_SHIFT_SUB_BCN_SPACE) & BIT_MASK_SUB_BCN_SPACE) + +/* 2 REG_MBSSID_BCN_SPACE3 (Offset 0x05BC) */ + +#define BIT_SHIFT_BCN_SPACE_CLINT3 0 +#define BIT_MASK_BCN_SPACE_CLINT3 0xfff +#define BIT_BCN_SPACE_CLINT3(x) \ + (((x) & BIT_MASK_BCN_SPACE_CLINT3) << BIT_SHIFT_BCN_SPACE_CLINT3) +#define BIT_GET_BCN_SPACE_CLINT3(x) \ + (((x) >> BIT_SHIFT_BCN_SPACE_CLINT3) & BIT_MASK_BCN_SPACE_CLINT3) + +/* 2 REG_ACMHWCTRL (Offset 0x05C0) */ + +#define BIT_BEQ_ACM_STATUS BIT(7) +#define BIT_VIQ_ACM_STATUS BIT(6) +#define BIT_VOQ_ACM_STATUS BIT(5) +#define BIT_BEQ_ACM_EN BIT(3) +#define BIT_VIQ_ACM_EN BIT(2) +#define BIT_VOQ_ACM_EN BIT(1) +#define BIT_ACMHWEN BIT(0) + +/* 2 REG_ACMRSTCTRL (Offset 0x05C1) */ + +#define BIT_BE_ACM_RESET_USED_TIME BIT(2) +#define BIT_VI_ACM_RESET_USED_TIME BIT(1) +#define BIT_VO_ACM_RESET_USED_TIME BIT(0) + +/* 2 REG_ACMAVG (Offset 0x05C2) */ + +#define BIT_SHIFT_AVGPERIOD 0 +#define BIT_MASK_AVGPERIOD 0xffff +#define BIT_AVGPERIOD(x) (((x) & BIT_MASK_AVGPERIOD) << BIT_SHIFT_AVGPERIOD) +#define BIT_GET_AVGPERIOD(x) (((x) >> BIT_SHIFT_AVGPERIOD) & BIT_MASK_AVGPERIOD) + +/* 2 REG_VO_ADMTIME (Offset 0x05C4) */ + +#define BIT_SHIFT_VO_ADMITTED_TIME 0 +#define BIT_MASK_VO_ADMITTED_TIME 0xffff +#define BIT_VO_ADMITTED_TIME(x) \ + (((x) & BIT_MASK_VO_ADMITTED_TIME) << BIT_SHIFT_VO_ADMITTED_TIME) +#define BIT_GET_VO_ADMITTED_TIME(x) \ + (((x) >> BIT_SHIFT_VO_ADMITTED_TIME) & BIT_MASK_VO_ADMITTED_TIME) + +/* 2 REG_VI_ADMTIME (Offset 0x05C6) */ + +#define BIT_SHIFT_VI_ADMITTED_TIME 0 +#define BIT_MASK_VI_ADMITTED_TIME 0xffff +#define BIT_VI_ADMITTED_TIME(x) \ + (((x) & BIT_MASK_VI_ADMITTED_TIME) << BIT_SHIFT_VI_ADMITTED_TIME) +#define BIT_GET_VI_ADMITTED_TIME(x) \ + (((x) >> BIT_SHIFT_VI_ADMITTED_TIME) & BIT_MASK_VI_ADMITTED_TIME) + +/* 2 REG_BE_ADMTIME (Offset 0x05C8) */ + +#define BIT_SHIFT_BE_ADMITTED_TIME 0 +#define BIT_MASK_BE_ADMITTED_TIME 0xffff +#define BIT_BE_ADMITTED_TIME(x) \ + (((x) & BIT_MASK_BE_ADMITTED_TIME) << BIT_SHIFT_BE_ADMITTED_TIME) +#define BIT_GET_BE_ADMITTED_TIME(x) \ + (((x) >> BIT_SHIFT_BE_ADMITTED_TIME) & BIT_MASK_BE_ADMITTED_TIME) + +/* 2 REG_EDCA_RANDOM_GEN (Offset 0x05CC) */ + +#define BIT_SHIFT_RANDOM_GEN 0 +#define BIT_MASK_RANDOM_GEN 0xffffff +#define BIT_RANDOM_GEN(x) (((x) & BIT_MASK_RANDOM_GEN) << BIT_SHIFT_RANDOM_GEN) +#define BIT_GET_RANDOM_GEN(x) \ + (((x) >> BIT_SHIFT_RANDOM_GEN) & BIT_MASK_RANDOM_GEN) + +/* 2 REG_TXCMD_NOA_SEL (Offset 0x05CF) */ + +#define BIT_SHIFT_NOA_SEL 4 +#define BIT_MASK_NOA_SEL 0x7 +#define BIT_NOA_SEL(x) (((x) & BIT_MASK_NOA_SEL) << BIT_SHIFT_NOA_SEL) +#define BIT_GET_NOA_SEL(x) (((x) >> BIT_SHIFT_NOA_SEL) & BIT_MASK_NOA_SEL) + +/* 2 REG_TXCMD_NOA_SEL (Offset 0x05CF) */ + +#define BIT_SHIFT_TXCMD_SEG_SEL 0 +#define BIT_MASK_TXCMD_SEG_SEL 0xf +#define BIT_TXCMD_SEG_SEL(x) \ + (((x) & BIT_MASK_TXCMD_SEG_SEL) << BIT_SHIFT_TXCMD_SEG_SEL) +#define BIT_GET_TXCMD_SEG_SEL(x) \ + (((x) >> BIT_SHIFT_TXCMD_SEG_SEL) & BIT_MASK_TXCMD_SEG_SEL) + +/* 2 REG_NOA_PARAM (Offset 0x05E0) */ + +#define BIT_SHIFT_NOA_COUNT (96 & CPU_OPT_WIDTH) +#define BIT_MASK_NOA_COUNT 0xff +#define BIT_NOA_COUNT(x) (((x) & BIT_MASK_NOA_COUNT) << BIT_SHIFT_NOA_COUNT) +#define BIT_GET_NOA_COUNT(x) (((x) >> BIT_SHIFT_NOA_COUNT) & BIT_MASK_NOA_COUNT) + +#define BIT_SHIFT_NOA_START_TIME (64 & CPU_OPT_WIDTH) +#define BIT_MASK_NOA_START_TIME 0xffffffffL +#define BIT_NOA_START_TIME(x) \ + (((x) & BIT_MASK_NOA_START_TIME) << BIT_SHIFT_NOA_START_TIME) +#define BIT_GET_NOA_START_TIME(x) \ + (((x) >> BIT_SHIFT_NOA_START_TIME) & BIT_MASK_NOA_START_TIME) + +#define BIT_SHIFT_NOA_INTERVAL (32 & CPU_OPT_WIDTH) +#define BIT_MASK_NOA_INTERVAL 0xffffffffL +#define BIT_NOA_INTERVAL(x) \ + (((x) & BIT_MASK_NOA_INTERVAL) << BIT_SHIFT_NOA_INTERVAL) +#define BIT_GET_NOA_INTERVAL(x) \ + (((x) >> BIT_SHIFT_NOA_INTERVAL) & BIT_MASK_NOA_INTERVAL) + +#define BIT_SHIFT_NOA_DURATION 0 +#define BIT_MASK_NOA_DURATION 0xffffffffL +#define BIT_NOA_DURATION(x) \ + (((x) & BIT_MASK_NOA_DURATION) << BIT_SHIFT_NOA_DURATION) +#define BIT_GET_NOA_DURATION(x) \ + (((x) >> BIT_SHIFT_NOA_DURATION) & BIT_MASK_NOA_DURATION) + +/* 2 REG_P2P_RST (Offset 0x05F0) */ + +#define BIT_P2P2_PWR_RST1 BIT(5) +#define BIT_P2P2_PWR_RST0 BIT(4) +#define BIT_P2P1_PWR_RST1 BIT(3) +#define BIT_P2P1_PWR_RST0 BIT(2) +#define BIT_P2P_PWR_RST1_V1 BIT(1) +#define BIT_P2P_PWR_RST0_V1 BIT(0) + +/* 2 REG_SCHEDULER_RST (Offset 0x05F1) */ + +#define BIT_SYNC_CLI BIT(1) +#define BIT_SCHEDULER_RST_V1 BIT(0) + +/* 2 REG_SCH_TXCMD (Offset 0x05F8) */ + +#define BIT_SHIFT_SCH_TXCMD 0 +#define BIT_MASK_SCH_TXCMD 0xffffffffL +#define BIT_SCH_TXCMD(x) (((x) & BIT_MASK_SCH_TXCMD) << BIT_SHIFT_SCH_TXCMD) +#define BIT_GET_SCH_TXCMD(x) (((x) >> BIT_SHIFT_SCH_TXCMD) & BIT_MASK_SCH_TXCMD) + +/* 2 REG_WMAC_CR (Offset 0x0600) */ + +#define BIT_IC_MACPHY_M BIT(0) + +/* 2 REG_WMAC_FWPKT_CR (Offset 0x0601) */ + +#define BIT_FWEN BIT(7) + +/* 2 REG_WMAC_FWPKT_CR (Offset 0x0601) */ + +#define BIT_PHYSTS_PKT_CTRL BIT(6) + +/* 2 REG_WMAC_FWPKT_CR (Offset 0x0601) */ + +#define BIT_APPHDR_MIDSRCH_FAIL BIT(4) +#define BIT_FWPARSING_EN BIT(3) + +#define BIT_SHIFT_APPEND_MHDR_LEN 0 +#define BIT_MASK_APPEND_MHDR_LEN 0x7 +#define BIT_APPEND_MHDR_LEN(x) \ + (((x) & BIT_MASK_APPEND_MHDR_LEN) << BIT_SHIFT_APPEND_MHDR_LEN) +#define BIT_GET_APPEND_MHDR_LEN(x) \ + (((x) >> BIT_SHIFT_APPEND_MHDR_LEN) & BIT_MASK_APPEND_MHDR_LEN) + +/* 2 REG_TCR (Offset 0x0604) */ + +#define BIT_WMAC_EN_RTS_ADDR BIT(31) +#define BIT_WMAC_DISABLE_CCK BIT(30) +#define BIT_WMAC_RAW_LEN BIT(29) +#define BIT_WMAC_NOTX_IN_RXNDP BIT(28) +#define BIT_WMAC_EN_EOF BIT(27) +#define BIT_WMAC_BF_SEL BIT(26) +#define BIT_WMAC_ANTMODE_SEL BIT(25) + +/* 2 REG_TCR (Offset 0x0604) */ + +#define BIT_WMAC_TCRPWRMGT_HWCTL BIT(24) + +/* 2 REG_TCR (Offset 0x0604) */ + +#define BIT_WMAC_SMOOTH_VAL BIT(23) + +/* 2 REG_TCR (Offset 0x0604) */ + +#define BIT_FETCH_MPDU_AFTER_WSEC_RDY BIT(20) + +/* 2 REG_TCR (Offset 0x0604) */ + +#define BIT_WMAC_TCR_EN_20MST BIT(19) +#define BIT_WMAC_DIS_SIGTA BIT(18) +#define BIT_WMAC_DIS_A2B0 BIT(17) +#define BIT_WMAC_MSK_SIGBCRC BIT(16) + +/* 2 REG_TCR (Offset 0x0604) */ + +#define BIT_WMAC_TCR_ERRSTEN_3 BIT(15) +#define BIT_WMAC_TCR_ERRSTEN_2 BIT(14) +#define BIT_WMAC_TCR_ERRSTEN_1 BIT(13) +#define BIT_WMAC_TCR_ERRSTEN_0 BIT(12) +#define BIT_WMAC_TCR_TXSK_PERPKT BIT(11) +#define BIT_ICV BIT(10) +#define BIT_CFEND_FORMAT BIT(9) +#define BIT_CRC BIT(8) +#define BIT_PWRBIT_OW_EN BIT(7) +#define BIT_PWR_ST BIT(6) +#define BIT_WMAC_TCR_UPD_TIMIE BIT(5) +#define BIT_WMAC_TCR_UPD_HGQMD BIT(4) + +/* 2 REG_TCR (Offset 0x0604) */ + +#define BIT_VHTSIGA1_TXPS BIT(3) + +/* 2 REG_TCR (Offset 0x0604) */ + +#define BIT_PAD_SEL BIT(2) +#define BIT_DIS_GCLK BIT(1) + +/* 2 REG_RCR (Offset 0x0608) */ + +#define BIT_APP_FCS BIT(31) +#define BIT_APP_MIC BIT(30) +#define BIT_APP_ICV BIT(29) +#define BIT_APP_PHYSTS BIT(28) +#define BIT_APP_BASSN BIT(27) + +/* 2 REG_RCR (Offset 0x0608) */ + +#define BIT_VHT_DACK BIT(26) + +/* 2 REG_RCR (Offset 0x0608) */ + +#define BIT_TCPOFLD_EN BIT(25) +#define BIT_ENMBID BIT(24) +#define BIT_LSIGEN BIT(23) +#define BIT_MFBEN BIT(22) +#define BIT_DISCHKPPDLLEN BIT(21) +#define BIT_PKTCTL_DLEN BIT(20) +#define BIT_TIM_PARSER_EN BIT(18) +#define BIT_BC_MD_EN BIT(17) +#define BIT_UC_MD_EN BIT(16) +#define BIT_RXSK_PERPKT BIT(15) +#define BIT_HTC_LOC_CTRL BIT(14) + +/* 2 REG_RCR (Offset 0x0608) */ + +#define BIT_RPFM_CAM_ENABLE BIT(12) + +/* 2 REG_RCR (Offset 0x0608) */ + +#define BIT_TA_BCN BIT(11) + +/* 2 REG_RCR (Offset 0x0608) */ + +#define BIT_DISDECMYPKT BIT(10) +#define BIT_AICV BIT(9) +#define BIT_ACRC32 BIT(8) +#define BIT_CBSSID_BCN BIT(7) +#define BIT_CBSSID_DATA BIT(6) +#define BIT_APWRMGT BIT(5) +#define BIT_ADD3 BIT(4) +#define BIT_AB BIT(3) +#define BIT_AM BIT(2) +#define BIT_APM BIT(1) +#define BIT_AAP BIT(0) + +/* 2 REG_RX_PKT_LIMIT (Offset 0x060C) */ + +#define BIT_SHIFT_RXPKTLMT 0 +#define BIT_MASK_RXPKTLMT 0x3f +#define BIT_RXPKTLMT(x) (((x) & BIT_MASK_RXPKTLMT) << BIT_SHIFT_RXPKTLMT) +#define BIT_GET_RXPKTLMT(x) (((x) >> BIT_SHIFT_RXPKTLMT) & BIT_MASK_RXPKTLMT) + +/* 2 REG_RX_DLK_TIME (Offset 0x060D) */ + +#define BIT_SHIFT_RX_DLK_TIME 0 +#define BIT_MASK_RX_DLK_TIME 0xff +#define BIT_RX_DLK_TIME(x) \ + (((x) & BIT_MASK_RX_DLK_TIME) << BIT_SHIFT_RX_DLK_TIME) +#define BIT_GET_RX_DLK_TIME(x) \ + (((x) >> BIT_SHIFT_RX_DLK_TIME) & BIT_MASK_RX_DLK_TIME) + +/* 2 REG_RX_DRVINFO_SZ (Offset 0x060F) */ + +#define BIT_DATA_RPFM15EN BIT(15) +#define BIT_DATA_RPFM14EN BIT(14) +#define BIT_DATA_RPFM13EN BIT(13) +#define BIT_DATA_RPFM12EN BIT(12) +#define BIT_DATA_RPFM11EN BIT(11) +#define BIT_DATA_RPFM10EN BIT(10) +#define BIT_DATA_RPFM9EN BIT(9) +#define BIT_DATA_RPFM8EN BIT(8) + +/* 2 REG_RX_DRVINFO_SZ (Offset 0x060F) */ + +#define BIT_PHYSTS_PER_PKT_MODE BIT(7) +#define BIT_DATA_RPFM7EN BIT(7) + +/* 2 REG_RX_DRVINFO_SZ (Offset 0x060F) */ + +#define BIT_DATA_RPFM6EN BIT(6) + +/* 2 REG_RX_DRVINFO_SZ (Offset 0x060F) */ + +#define BIT_DATA_RPFM5EN BIT(5) +#define BIT_DATA_RPFM4EN BIT(4) +#define BIT_DATA_RPFM3EN BIT(3) +#define BIT_DATA_RPFM2EN BIT(2) +#define BIT_DATA_RPFM1EN BIT(1) + +/* 2 REG_RX_DRVINFO_SZ (Offset 0x060F) */ + +#define BIT_SHIFT_DRVINFO_SZ_V1 0 +#define BIT_MASK_DRVINFO_SZ_V1 0xf +#define BIT_DRVINFO_SZ_V1(x) \ + (((x) & BIT_MASK_DRVINFO_SZ_V1) << BIT_SHIFT_DRVINFO_SZ_V1) +#define BIT_GET_DRVINFO_SZ_V1(x) \ + (((x) >> BIT_SHIFT_DRVINFO_SZ_V1) & BIT_MASK_DRVINFO_SZ_V1) + +/* 2 REG_RX_DRVINFO_SZ (Offset 0x060F) */ + +#define BIT_DATA_RPFM0EN BIT(0) + +/* 2 REG_MACID (Offset 0x0610) */ + +#define BIT_SHIFT_MACID 0 +#define BIT_MASK_MACID 0xffffffffffffL +#define BIT_MACID(x) (((x) & BIT_MASK_MACID) << BIT_SHIFT_MACID) +#define BIT_GET_MACID(x) (((x) >> BIT_SHIFT_MACID) & BIT_MASK_MACID) + +/* 2 REG_BSSID (Offset 0x0618) */ + +#define BIT_SHIFT_BSSID 0 +#define BIT_MASK_BSSID 0xffffffffffffL +#define BIT_BSSID(x) (((x) & BIT_MASK_BSSID) << BIT_SHIFT_BSSID) +#define BIT_GET_BSSID(x) (((x) >> BIT_SHIFT_BSSID) & BIT_MASK_BSSID) + +/* 2 REG_MAR (Offset 0x0620) */ + +#define BIT_SHIFT_MAR 0 +#define BIT_MASK_MAR 0xffffffffffffffffL +#define BIT_MAR(x) (((x) & BIT_MASK_MAR) << BIT_SHIFT_MAR) +#define BIT_GET_MAR(x) (((x) >> BIT_SHIFT_MAR) & BIT_MASK_MAR) + +/* 2 REG_MBIDCAMCFG_1 (Offset 0x0628) */ + +#define BIT_SHIFT_MBIDCAM_RWDATA_L 0 +#define BIT_MASK_MBIDCAM_RWDATA_L 0xffffffffL +#define BIT_MBIDCAM_RWDATA_L(x) \ + (((x) & BIT_MASK_MBIDCAM_RWDATA_L) << BIT_SHIFT_MBIDCAM_RWDATA_L) +#define BIT_GET_MBIDCAM_RWDATA_L(x) \ + (((x) >> BIT_SHIFT_MBIDCAM_RWDATA_L) & BIT_MASK_MBIDCAM_RWDATA_L) + +/* 2 REG_MBIDCAMCFG_2 (Offset 0x062C) */ + +#define BIT_MBIDCAM_POLL BIT(31) +#define BIT_MBIDCAM_WT_EN BIT(30) + +#define BIT_SHIFT_MBIDCAM_ADDR 24 +#define BIT_MASK_MBIDCAM_ADDR 0x1f +#define BIT_MBIDCAM_ADDR(x) \ + (((x) & BIT_MASK_MBIDCAM_ADDR) << BIT_SHIFT_MBIDCAM_ADDR) +#define BIT_GET_MBIDCAM_ADDR(x) \ + (((x) >> BIT_SHIFT_MBIDCAM_ADDR) & BIT_MASK_MBIDCAM_ADDR) + +#define BIT_MBIDCAM_VALID BIT(23) +#define BIT_LSIC_TXOP_EN BIT(17) + +/* 2 REG_MBIDCAMCFG_2 (Offset 0x062C) */ + +#define BIT_CTS_EN BIT(16) + +/* 2 REG_MBIDCAMCFG_2 (Offset 0x062C) */ + +#define BIT_SHIFT_MBIDCAM_RWDATA_H 0 +#define BIT_MASK_MBIDCAM_RWDATA_H 0xffff +#define BIT_MBIDCAM_RWDATA_H(x) \ + (((x) & BIT_MASK_MBIDCAM_RWDATA_H) << BIT_SHIFT_MBIDCAM_RWDATA_H) +#define BIT_GET_MBIDCAM_RWDATA_H(x) \ + (((x) >> BIT_SHIFT_MBIDCAM_RWDATA_H) & BIT_MASK_MBIDCAM_RWDATA_H) + +/* 2 REG_WMAC_TCR_TSFT_OFS (Offset 0x0630) */ + +#define BIT_SHIFT_WMAC_TCR_TSFT_OFS 0 +#define BIT_MASK_WMAC_TCR_TSFT_OFS 0xffff +#define BIT_WMAC_TCR_TSFT_OFS(x) \ + (((x) & BIT_MASK_WMAC_TCR_TSFT_OFS) << BIT_SHIFT_WMAC_TCR_TSFT_OFS) +#define BIT_GET_WMAC_TCR_TSFT_OFS(x) \ + (((x) >> BIT_SHIFT_WMAC_TCR_TSFT_OFS) & BIT_MASK_WMAC_TCR_TSFT_OFS) + +/* 2 REG_UDF_THSD (Offset 0x0632) */ + +#define BIT_SHIFT_UDF_THSD 0 +#define BIT_MASK_UDF_THSD 0xff +#define BIT_UDF_THSD(x) (((x) & BIT_MASK_UDF_THSD) << BIT_SHIFT_UDF_THSD) +#define BIT_GET_UDF_THSD(x) (((x) >> BIT_SHIFT_UDF_THSD) & BIT_MASK_UDF_THSD) + +/* 2 REG_ZLD_NUM (Offset 0x0633) */ + +#define BIT_SHIFT_ZLD_NUM 0 +#define BIT_MASK_ZLD_NUM 0xff +#define BIT_ZLD_NUM(x) (((x) & BIT_MASK_ZLD_NUM) << BIT_SHIFT_ZLD_NUM) +#define BIT_GET_ZLD_NUM(x) (((x) >> BIT_SHIFT_ZLD_NUM) & BIT_MASK_ZLD_NUM) + +/* 2 REG_STMP_THSD (Offset 0x0634) */ + +#define BIT_SHIFT_STMP_THSD 0 +#define BIT_MASK_STMP_THSD 0xff +#define BIT_STMP_THSD(x) (((x) & BIT_MASK_STMP_THSD) << BIT_SHIFT_STMP_THSD) +#define BIT_GET_STMP_THSD(x) (((x) >> BIT_SHIFT_STMP_THSD) & BIT_MASK_STMP_THSD) + +/* 2 REG_WMAC_TXTIMEOUT (Offset 0x0635) */ + +#define BIT_SHIFT_WMAC_TXTIMEOUT 0 +#define BIT_MASK_WMAC_TXTIMEOUT 0xff +#define BIT_WMAC_TXTIMEOUT(x) \ + (((x) & BIT_MASK_WMAC_TXTIMEOUT) << BIT_SHIFT_WMAC_TXTIMEOUT) +#define BIT_GET_WMAC_TXTIMEOUT(x) \ + (((x) >> BIT_SHIFT_WMAC_TXTIMEOUT) & BIT_MASK_WMAC_TXTIMEOUT) + +/* 2 REG_MCU_TEST_2_V1 (Offset 0x0636) */ + +#define BIT_SHIFT_MCU_RSVD_2_V1 0 +#define BIT_MASK_MCU_RSVD_2_V1 0xffff +#define BIT_MCU_RSVD_2_V1(x) \ + (((x) & BIT_MASK_MCU_RSVD_2_V1) << BIT_SHIFT_MCU_RSVD_2_V1) +#define BIT_GET_MCU_RSVD_2_V1(x) \ + (((x) >> BIT_SHIFT_MCU_RSVD_2_V1) & BIT_MASK_MCU_RSVD_2_V1) + +/* 2 REG_USTIME_EDCA (Offset 0x0638) */ + +#define BIT_SHIFT_USTIME_EDCA_V1 0 +#define BIT_MASK_USTIME_EDCA_V1 0x1ff +#define BIT_USTIME_EDCA_V1(x) \ + (((x) & BIT_MASK_USTIME_EDCA_V1) << BIT_SHIFT_USTIME_EDCA_V1) +#define BIT_GET_USTIME_EDCA_V1(x) \ + (((x) >> BIT_SHIFT_USTIME_EDCA_V1) & BIT_MASK_USTIME_EDCA_V1) + +/* 2 REG_MAC_SPEC_SIFS (Offset 0x063A) */ + +#define BIT_SHIFT_SPEC_SIFS_OFDM 8 +#define BIT_MASK_SPEC_SIFS_OFDM 0xff +#define BIT_SPEC_SIFS_OFDM(x) \ + (((x) & BIT_MASK_SPEC_SIFS_OFDM) << BIT_SHIFT_SPEC_SIFS_OFDM) +#define BIT_GET_SPEC_SIFS_OFDM(x) \ + (((x) >> BIT_SHIFT_SPEC_SIFS_OFDM) & BIT_MASK_SPEC_SIFS_OFDM) + +#define BIT_SHIFT_SPEC_SIFS_CCK 0 +#define BIT_MASK_SPEC_SIFS_CCK 0xff +#define BIT_SPEC_SIFS_CCK(x) \ + (((x) & BIT_MASK_SPEC_SIFS_CCK) << BIT_SHIFT_SPEC_SIFS_CCK) +#define BIT_GET_SPEC_SIFS_CCK(x) \ + (((x) >> BIT_SHIFT_SPEC_SIFS_CCK) & BIT_MASK_SPEC_SIFS_CCK) + +/* 2 REG_RESP_SIFS_CCK (Offset 0x063C) */ + +#define BIT_SHIFT_SIFS_R2T_CCK 8 +#define BIT_MASK_SIFS_R2T_CCK 0xff +#define BIT_SIFS_R2T_CCK(x) \ + (((x) & BIT_MASK_SIFS_R2T_CCK) << BIT_SHIFT_SIFS_R2T_CCK) +#define BIT_GET_SIFS_R2T_CCK(x) \ + (((x) >> BIT_SHIFT_SIFS_R2T_CCK) & BIT_MASK_SIFS_R2T_CCK) + +#define BIT_SHIFT_SIFS_T2T_CCK 0 +#define BIT_MASK_SIFS_T2T_CCK 0xff +#define BIT_SIFS_T2T_CCK(x) \ + (((x) & BIT_MASK_SIFS_T2T_CCK) << BIT_SHIFT_SIFS_T2T_CCK) +#define BIT_GET_SIFS_T2T_CCK(x) \ + (((x) >> BIT_SHIFT_SIFS_T2T_CCK) & BIT_MASK_SIFS_T2T_CCK) + +/* 2 REG_RESP_SIFS_OFDM (Offset 0x063E) */ + +#define BIT_SHIFT_SIFS_R2T_OFDM 8 +#define BIT_MASK_SIFS_R2T_OFDM 0xff +#define BIT_SIFS_R2T_OFDM(x) \ + (((x) & BIT_MASK_SIFS_R2T_OFDM) << BIT_SHIFT_SIFS_R2T_OFDM) +#define BIT_GET_SIFS_R2T_OFDM(x) \ + (((x) >> BIT_SHIFT_SIFS_R2T_OFDM) & BIT_MASK_SIFS_R2T_OFDM) + +#define BIT_SHIFT_SIFS_T2T_OFDM 0 +#define BIT_MASK_SIFS_T2T_OFDM 0xff +#define BIT_SIFS_T2T_OFDM(x) \ + (((x) & BIT_MASK_SIFS_T2T_OFDM) << BIT_SHIFT_SIFS_T2T_OFDM) +#define BIT_GET_SIFS_T2T_OFDM(x) \ + (((x) >> BIT_SHIFT_SIFS_T2T_OFDM) & BIT_MASK_SIFS_T2T_OFDM) + +/* 2 REG_ACKTO (Offset 0x0640) */ + +#define BIT_SHIFT_ACKTO 0 +#define BIT_MASK_ACKTO 0xff +#define BIT_ACKTO(x) (((x) & BIT_MASK_ACKTO) << BIT_SHIFT_ACKTO) +#define BIT_GET_ACKTO(x) (((x) >> BIT_SHIFT_ACKTO) & BIT_MASK_ACKTO) + +/* 2 REG_CTS2TO (Offset 0x0641) */ + +#define BIT_SHIFT_CTS2TO 0 +#define BIT_MASK_CTS2TO 0xff +#define BIT_CTS2TO(x) (((x) & BIT_MASK_CTS2TO) << BIT_SHIFT_CTS2TO) +#define BIT_GET_CTS2TO(x) (((x) >> BIT_SHIFT_CTS2TO) & BIT_MASK_CTS2TO) + +/* 2 REG_EIFS (Offset 0x0642) */ + +#define BIT_SHIFT_EIFS 0 +#define BIT_MASK_EIFS 0xffff +#define BIT_EIFS(x) (((x) & BIT_MASK_EIFS) << BIT_SHIFT_EIFS) +#define BIT_GET_EIFS(x) (((x) >> BIT_SHIFT_EIFS) & BIT_MASK_EIFS) + +/* 2 REG_NAV_CTRL (Offset 0x0650) */ + +#define BIT_SHIFT_NAV_UPPER 16 +#define BIT_MASK_NAV_UPPER 0xff +#define BIT_NAV_UPPER(x) (((x) & BIT_MASK_NAV_UPPER) << BIT_SHIFT_NAV_UPPER) +#define BIT_GET_NAV_UPPER(x) (((x) >> BIT_SHIFT_NAV_UPPER) & BIT_MASK_NAV_UPPER) + +#define BIT_SHIFT_RXMYRTS_NAV 8 +#define BIT_MASK_RXMYRTS_NAV 0xf +#define BIT_RXMYRTS_NAV(x) \ + (((x) & BIT_MASK_RXMYRTS_NAV) << BIT_SHIFT_RXMYRTS_NAV) +#define BIT_GET_RXMYRTS_NAV(x) \ + (((x) >> BIT_SHIFT_RXMYRTS_NAV) & BIT_MASK_RXMYRTS_NAV) + +#define BIT_SHIFT_RTSRST 0 +#define BIT_MASK_RTSRST 0xff +#define BIT_RTSRST(x) (((x) & BIT_MASK_RTSRST) << BIT_SHIFT_RTSRST) +#define BIT_GET_RTSRST(x) (((x) >> BIT_SHIFT_RTSRST) & BIT_MASK_RTSRST) + +/* 2 REG_BACAMCMD (Offset 0x0654) */ + +#define BIT_BACAM_POLL BIT(31) +#define BIT_BACAM_RST BIT(17) +#define BIT_BACAM_RW BIT(16) + +#define BIT_SHIFT_TXSBM 14 +#define BIT_MASK_TXSBM 0x3 +#define BIT_TXSBM(x) (((x) & BIT_MASK_TXSBM) << BIT_SHIFT_TXSBM) +#define BIT_GET_TXSBM(x) (((x) >> BIT_SHIFT_TXSBM) & BIT_MASK_TXSBM) + +#define BIT_SHIFT_BACAM_ADDR 0 +#define BIT_MASK_BACAM_ADDR 0x3f +#define BIT_BACAM_ADDR(x) (((x) & BIT_MASK_BACAM_ADDR) << BIT_SHIFT_BACAM_ADDR) +#define BIT_GET_BACAM_ADDR(x) \ + (((x) >> BIT_SHIFT_BACAM_ADDR) & BIT_MASK_BACAM_ADDR) + +/* 2 REG_BACAMCONTENT (Offset 0x0658) */ + +#define BIT_SHIFT_BA_CONTENT_H (32 & CPU_OPT_WIDTH) +#define BIT_MASK_BA_CONTENT_H 0xffffffffL +#define BIT_BA_CONTENT_H(x) \ + (((x) & BIT_MASK_BA_CONTENT_H) << BIT_SHIFT_BA_CONTENT_H) +#define BIT_GET_BA_CONTENT_H(x) \ + (((x) >> BIT_SHIFT_BA_CONTENT_H) & BIT_MASK_BA_CONTENT_H) + +#define BIT_SHIFT_BA_CONTENT_L 0 +#define BIT_MASK_BA_CONTENT_L 0xffffffffL +#define BIT_BA_CONTENT_L(x) \ + (((x) & BIT_MASK_BA_CONTENT_L) << BIT_SHIFT_BA_CONTENT_L) +#define BIT_GET_BA_CONTENT_L(x) \ + (((x) >> BIT_SHIFT_BA_CONTENT_L) & BIT_MASK_BA_CONTENT_L) + +/* 2 REG_LBDLY (Offset 0x0660) */ + +#define BIT_SHIFT_LBDLY 0 +#define BIT_MASK_LBDLY 0x1f +#define BIT_LBDLY(x) (((x) & BIT_MASK_LBDLY) << BIT_SHIFT_LBDLY) +#define BIT_GET_LBDLY(x) (((x) >> BIT_SHIFT_LBDLY) & BIT_MASK_LBDLY) + +/* 2 REG_WMAC_BACAM_RPMEN (Offset 0x0661) */ + +#define BIT_SHIFT_BITMAP_SSNBK_COUNTER 2 +#define BIT_MASK_BITMAP_SSNBK_COUNTER 0x3f +#define BIT_BITMAP_SSNBK_COUNTER(x) \ + (((x) & BIT_MASK_BITMAP_SSNBK_COUNTER) \ + << BIT_SHIFT_BITMAP_SSNBK_COUNTER) +#define BIT_GET_BITMAP_SSNBK_COUNTER(x) \ + (((x) >> BIT_SHIFT_BITMAP_SSNBK_COUNTER) & \ + BIT_MASK_BITMAP_SSNBK_COUNTER) + +#define BIT_BITMAP_EN BIT(1) + +/* 2 REG_WMAC_BACAM_RPMEN (Offset 0x0661) */ + +#define BIT_WMAC_BACAM_RPMEN BIT(0) + +/* 2 REG_TX_RX (Offset 0x0662) */ + +#define BIT_SHIFT_RXPKT_TYPE 2 +#define BIT_MASK_RXPKT_TYPE 0x3f +#define BIT_RXPKT_TYPE(x) (((x) & BIT_MASK_RXPKT_TYPE) << BIT_SHIFT_RXPKT_TYPE) +#define BIT_GET_RXPKT_TYPE(x) \ + (((x) >> BIT_SHIFT_RXPKT_TYPE) & BIT_MASK_RXPKT_TYPE) + +#define BIT_TXACT_IND BIT(1) +#define BIT_RXACT_IND BIT(0) + +/* 2 REG_WMAC_BITMAP_CTL (Offset 0x0663) */ + +#define BIT_BITMAP_VO BIT(7) +#define BIT_BITMAP_VI BIT(6) +#define BIT_BITMAP_BE BIT(5) +#define BIT_BITMAP_BK BIT(4) + +#define BIT_SHIFT_BITMAP_CONDITION 2 +#define BIT_MASK_BITMAP_CONDITION 0x3 +#define BIT_BITMAP_CONDITION(x) \ + (((x) & BIT_MASK_BITMAP_CONDITION) << BIT_SHIFT_BITMAP_CONDITION) +#define BIT_GET_BITMAP_CONDITION(x) \ + (((x) >> BIT_SHIFT_BITMAP_CONDITION) & BIT_MASK_BITMAP_CONDITION) + +#define BIT_BITMAP_SSNBK_COUNTER_CLR BIT(1) +#define BIT_BITMAP_FORCE BIT(0) + +/* 2 REG_RXERR_RPT (Offset 0x0664) */ + +#define BIT_SHIFT_RXERR_RPT_SEL_V1_3_0 28 +#define BIT_MASK_RXERR_RPT_SEL_V1_3_0 0xf +#define BIT_RXERR_RPT_SEL_V1_3_0(x) \ + (((x) & BIT_MASK_RXERR_RPT_SEL_V1_3_0) \ + << BIT_SHIFT_RXERR_RPT_SEL_V1_3_0) +#define BIT_GET_RXERR_RPT_SEL_V1_3_0(x) \ + (((x) >> BIT_SHIFT_RXERR_RPT_SEL_V1_3_0) & \ + BIT_MASK_RXERR_RPT_SEL_V1_3_0) + +/* 2 REG_RXERR_RPT (Offset 0x0664) */ + +#define BIT_RXERR_RPT_RST BIT(27) + +/* 2 REG_RXERR_RPT (Offset 0x0664) */ + +#define BIT_RXERR_RPT_SEL_V1_4 BIT(26) + +/* 2 REG_RXERR_RPT (Offset 0x0664) */ + +#define BIT_W1S BIT(23) + +/* 2 REG_RXERR_RPT (Offset 0x0664) */ + +#define BIT_UD_SELECT_BSSID BIT(22) + +/* 2 REG_RXERR_RPT (Offset 0x0664) */ + +#define BIT_SHIFT_UD_SUB_TYPE 18 +#define BIT_MASK_UD_SUB_TYPE 0xf +#define BIT_UD_SUB_TYPE(x) \ + (((x) & BIT_MASK_UD_SUB_TYPE) << BIT_SHIFT_UD_SUB_TYPE) +#define BIT_GET_UD_SUB_TYPE(x) \ + (((x) >> BIT_SHIFT_UD_SUB_TYPE) & BIT_MASK_UD_SUB_TYPE) + +#define BIT_SHIFT_UD_TYPE 16 +#define BIT_MASK_UD_TYPE 0x3 +#define BIT_UD_TYPE(x) (((x) & BIT_MASK_UD_TYPE) << BIT_SHIFT_UD_TYPE) +#define BIT_GET_UD_TYPE(x) (((x) >> BIT_SHIFT_UD_TYPE) & BIT_MASK_UD_TYPE) + +#define BIT_SHIFT_RPT_COUNTER 0 +#define BIT_MASK_RPT_COUNTER 0xffff +#define BIT_RPT_COUNTER(x) \ + (((x) & BIT_MASK_RPT_COUNTER) << BIT_SHIFT_RPT_COUNTER) +#define BIT_GET_RPT_COUNTER(x) \ + (((x) >> BIT_SHIFT_RPT_COUNTER) & BIT_MASK_RPT_COUNTER) + +/* 2 REG_WMAC_TRXPTCL_CTL (Offset 0x0668) */ + +#define BIT_SHIFT_ACKBA_TYPSEL (60 & CPU_OPT_WIDTH) +#define BIT_MASK_ACKBA_TYPSEL 0xf +#define BIT_ACKBA_TYPSEL(x) \ + (((x) & BIT_MASK_ACKBA_TYPSEL) << BIT_SHIFT_ACKBA_TYPSEL) +#define BIT_GET_ACKBA_TYPSEL(x) \ + (((x) >> BIT_SHIFT_ACKBA_TYPSEL) & BIT_MASK_ACKBA_TYPSEL) + +#define BIT_SHIFT_ACKBA_ACKPCHK (56 & CPU_OPT_WIDTH) +#define BIT_MASK_ACKBA_ACKPCHK 0xf +#define BIT_ACKBA_ACKPCHK(x) \ + (((x) & BIT_MASK_ACKBA_ACKPCHK) << BIT_SHIFT_ACKBA_ACKPCHK) +#define BIT_GET_ACKBA_ACKPCHK(x) \ + (((x) >> BIT_SHIFT_ACKBA_ACKPCHK) & BIT_MASK_ACKBA_ACKPCHK) + +#define BIT_SHIFT_ACKBAR_TYPESEL (48 & CPU_OPT_WIDTH) +#define BIT_MASK_ACKBAR_TYPESEL 0xff +#define BIT_ACKBAR_TYPESEL(x) \ + (((x) & BIT_MASK_ACKBAR_TYPESEL) << BIT_SHIFT_ACKBAR_TYPESEL) +#define BIT_GET_ACKBAR_TYPESEL(x) \ + (((x) >> BIT_SHIFT_ACKBAR_TYPESEL) & BIT_MASK_ACKBAR_TYPESEL) + +#define BIT_SHIFT_ACKBAR_ACKPCHK (44 & CPU_OPT_WIDTH) +#define BIT_MASK_ACKBAR_ACKPCHK 0xf +#define BIT_ACKBAR_ACKPCHK(x) \ + (((x) & BIT_MASK_ACKBAR_ACKPCHK) << BIT_SHIFT_ACKBAR_ACKPCHK) +#define BIT_GET_ACKBAR_ACKPCHK(x) \ + (((x) >> BIT_SHIFT_ACKBAR_ACKPCHK) & BIT_MASK_ACKBAR_ACKPCHK) + +/* 2 REG_WMAC_TRXPTCL_CTL (Offset 0x0668) */ + +#define BIT_RXBA_IGNOREA2 BIT(42) +#define BIT_EN_SAVE_ALL_TXOPADDR BIT(41) +#define BIT_EN_TXCTS_TO_TXOPOWNER_INRXNAV BIT(40) + +/* 2 REG_WMAC_TRXPTCL_CTL (Offset 0x0668) */ + +#define BIT_DIS_TXBA_AMPDUFCSERR BIT(39) +#define BIT_DIS_TXBA_RXBARINFULL BIT(38) +#define BIT_DIS_TXCFE_INFULL BIT(37) +#define BIT_DIS_TXCTS_INFULL BIT(36) +#define BIT_EN_TXACKBA_IN_TX_RDG BIT(35) +#define BIT_EN_TXACKBA_IN_TXOP BIT(34) +#define BIT_EN_TXCTS_IN_RXNAV BIT(33) +#define BIT_EN_TXCTS_INTXOP BIT(32) +#define BIT_BLK_EDCA_BBSLP BIT(31) +#define BIT_BLK_EDCA_BBSBY BIT(30) +#define BIT_ACKTO_BLOCK_SCH_EN BIT(27) +#define BIT_EIFS_BLOCK_SCH_EN BIT(26) +#define BIT_PLCPCHK_RST_EIFS BIT(25) +#define BIT_CCA_RST_EIFS BIT(24) +#define BIT_DIS_UPD_MYRXPKTNAV BIT(23) +#define BIT_EARLY_TXBA BIT(22) + +#define BIT_SHIFT_RESP_CHNBUSY 20 +#define BIT_MASK_RESP_CHNBUSY 0x3 +#define BIT_RESP_CHNBUSY(x) \ + (((x) & BIT_MASK_RESP_CHNBUSY) << BIT_SHIFT_RESP_CHNBUSY) +#define BIT_GET_RESP_CHNBUSY(x) \ + (((x) >> BIT_SHIFT_RESP_CHNBUSY) & BIT_MASK_RESP_CHNBUSY) + +#define BIT_RESP_DCTS_EN BIT(19) +#define BIT_RESP_DCFE_EN BIT(18) +#define BIT_RESP_SPLCPEN BIT(17) +#define BIT_RESP_SGIEN BIT(16) + +/* 2 REG_WMAC_TRXPTCL_CTL (Offset 0x0668) */ + +#define BIT_RESP_LDPC_EN BIT(15) +#define BIT_DIS_RESP_ACKINCCA BIT(14) +#define BIT_DIS_RESP_CTSINCCA BIT(13) + +/* 2 REG_WMAC_TRXPTCL_CTL (Offset 0x0668) */ + +#define BIT_SHIFT_R_WMAC_SECOND_CCA_TIMER 10 +#define BIT_MASK_R_WMAC_SECOND_CCA_TIMER 0x7 +#define BIT_R_WMAC_SECOND_CCA_TIMER(x) \ + (((x) & BIT_MASK_R_WMAC_SECOND_CCA_TIMER) \ + << BIT_SHIFT_R_WMAC_SECOND_CCA_TIMER) +#define BIT_GET_R_WMAC_SECOND_CCA_TIMER(x) \ + (((x) >> BIT_SHIFT_R_WMAC_SECOND_CCA_TIMER) & \ + BIT_MASK_R_WMAC_SECOND_CCA_TIMER) + +/* 2 REG_WMAC_TRXPTCL_CTL (Offset 0x0668) */ + +#define BIT_SHIFT_RFMOD 7 +#define BIT_MASK_RFMOD 0x3 +#define BIT_RFMOD(x) (((x) & BIT_MASK_RFMOD) << BIT_SHIFT_RFMOD) +#define BIT_GET_RFMOD(x) (((x) >> BIT_SHIFT_RFMOD) & BIT_MASK_RFMOD) + +/* 2 REG_WMAC_TRXPTCL_CTL (Offset 0x0668) */ + +#define BIT_SHIFT_RESP_CTS_DYNBW_SEL 5 +#define BIT_MASK_RESP_CTS_DYNBW_SEL 0x3 +#define BIT_RESP_CTS_DYNBW_SEL(x) \ + (((x) & BIT_MASK_RESP_CTS_DYNBW_SEL) << BIT_SHIFT_RESP_CTS_DYNBW_SEL) +#define BIT_GET_RESP_CTS_DYNBW_SEL(x) \ + (((x) >> BIT_SHIFT_RESP_CTS_DYNBW_SEL) & BIT_MASK_RESP_CTS_DYNBW_SEL) + +/* 2 REG_WMAC_TRXPTCL_CTL (Offset 0x0668) */ + +#define BIT_DLY_TX_WAIT_RXANTSEL BIT(4) + +/* 2 REG_WMAC_TRXPTCL_CTL (Offset 0x0668) */ + +#define BIT_TXRESP_BY_RXANTSEL BIT(3) + +/* 2 REG_WMAC_TRXPTCL_CTL (Offset 0x0668) */ + +#define BIT_SHIFT_ORIG_DCTS_CHK 0 +#define BIT_MASK_ORIG_DCTS_CHK 0x3 +#define BIT_ORIG_DCTS_CHK(x) \ + (((x) & BIT_MASK_ORIG_DCTS_CHK) << BIT_SHIFT_ORIG_DCTS_CHK) +#define BIT_GET_ORIG_DCTS_CHK(x) \ + (((x) >> BIT_SHIFT_ORIG_DCTS_CHK) & BIT_MASK_ORIG_DCTS_CHK) + +/* 2 REG_CAMCMD (Offset 0x0670) */ + +#define BIT_SECCAM_POLLING BIT(31) +#define BIT_SECCAM_CLR BIT(30) +#define BIT_MFBCAM_CLR BIT(29) + +/* 2 REG_CAMCMD (Offset 0x0670) */ + +#define BIT_SECCAM_WE BIT(16) + +/* 2 REG_CAMCMD (Offset 0x0670) */ + +#define BIT_SHIFT_SECCAM_ADDR_V2 0 +#define BIT_MASK_SECCAM_ADDR_V2 0x3ff +#define BIT_SECCAM_ADDR_V2(x) \ + (((x) & BIT_MASK_SECCAM_ADDR_V2) << BIT_SHIFT_SECCAM_ADDR_V2) +#define BIT_GET_SECCAM_ADDR_V2(x) \ + (((x) >> BIT_SHIFT_SECCAM_ADDR_V2) & BIT_MASK_SECCAM_ADDR_V2) + +/* 2 REG_CAMWRITE (Offset 0x0674) */ + +#define BIT_SHIFT_CAMW_DATA 0 +#define BIT_MASK_CAMW_DATA 0xffffffffL +#define BIT_CAMW_DATA(x) (((x) & BIT_MASK_CAMW_DATA) << BIT_SHIFT_CAMW_DATA) +#define BIT_GET_CAMW_DATA(x) (((x) >> BIT_SHIFT_CAMW_DATA) & BIT_MASK_CAMW_DATA) + +/* 2 REG_CAMREAD (Offset 0x0678) */ + +#define BIT_SHIFT_CAMR_DATA 0 +#define BIT_MASK_CAMR_DATA 0xffffffffL +#define BIT_CAMR_DATA(x) (((x) & BIT_MASK_CAMR_DATA) << BIT_SHIFT_CAMR_DATA) +#define BIT_GET_CAMR_DATA(x) (((x) >> BIT_SHIFT_CAMR_DATA) & BIT_MASK_CAMR_DATA) + +/* 2 REG_CAMDBG (Offset 0x067C) */ + +#define BIT_SECCAM_INFO BIT(31) +#define BIT_SEC_KEYFOUND BIT(15) + +#define BIT_SHIFT_CAMDBG_SEC_TYPE 12 +#define BIT_MASK_CAMDBG_SEC_TYPE 0x7 +#define BIT_CAMDBG_SEC_TYPE(x) \ + (((x) & BIT_MASK_CAMDBG_SEC_TYPE) << BIT_SHIFT_CAMDBG_SEC_TYPE) +#define BIT_GET_CAMDBG_SEC_TYPE(x) \ + (((x) >> BIT_SHIFT_CAMDBG_SEC_TYPE) & BIT_MASK_CAMDBG_SEC_TYPE) + +/* 2 REG_CAMDBG (Offset 0x067C) */ + +#define BIT_CAMDBG_EXT_SECTYPE BIT(11) + +/* 2 REG_CAMDBG (Offset 0x067C) */ + +#define BIT_SHIFT_CAMDBG_MIC_KEY_IDX 5 +#define BIT_MASK_CAMDBG_MIC_KEY_IDX 0x1f +#define BIT_CAMDBG_MIC_KEY_IDX(x) \ + (((x) & BIT_MASK_CAMDBG_MIC_KEY_IDX) << BIT_SHIFT_CAMDBG_MIC_KEY_IDX) +#define BIT_GET_CAMDBG_MIC_KEY_IDX(x) \ + (((x) >> BIT_SHIFT_CAMDBG_MIC_KEY_IDX) & BIT_MASK_CAMDBG_MIC_KEY_IDX) + +#define BIT_SHIFT_CAMDBG_SEC_KEY_IDX 0 +#define BIT_MASK_CAMDBG_SEC_KEY_IDX 0x1f +#define BIT_CAMDBG_SEC_KEY_IDX(x) \ + (((x) & BIT_MASK_CAMDBG_SEC_KEY_IDX) << BIT_SHIFT_CAMDBG_SEC_KEY_IDX) +#define BIT_GET_CAMDBG_SEC_KEY_IDX(x) \ + (((x) >> BIT_SHIFT_CAMDBG_SEC_KEY_IDX) & BIT_MASK_CAMDBG_SEC_KEY_IDX) + +/* 2 REG_SECCFG (Offset 0x0680) */ + +#define BIT_DIS_GCLK_WAPI BIT(15) +#define BIT_DIS_GCLK_AES BIT(14) +#define BIT_DIS_GCLK_TKIP BIT(13) + +/* 2 REG_SECCFG (Offset 0x0680) */ + +#define BIT_AES_SEL_QC_1 BIT(12) +#define BIT_AES_SEL_QC_0 BIT(11) + +/* 2 REG_SECCFG (Offset 0x0680) */ + +#define BIT_CHK_BMC BIT(9) + +/* 2 REG_SECCFG (Offset 0x0680) */ + +#define BIT_CHK_KEYID BIT(8) +#define BIT_RXBCUSEDK BIT(7) +#define BIT_TXBCUSEDK BIT(6) +#define BIT_NOSKMC BIT(5) +#define BIT_SKBYA2 BIT(4) +#define BIT_RXDEC BIT(3) +#define BIT_TXENC BIT(2) +#define BIT_RXUHUSEDK BIT(1) +#define BIT_TXUHUSEDK BIT(0) + +/* 2 REG_RXFILTER_CATEGORY_1 (Offset 0x0682) */ + +#define BIT_SHIFT_RXFILTER_CATEGORY_1 0 +#define BIT_MASK_RXFILTER_CATEGORY_1 0xff +#define BIT_RXFILTER_CATEGORY_1(x) \ + (((x) & BIT_MASK_RXFILTER_CATEGORY_1) << BIT_SHIFT_RXFILTER_CATEGORY_1) +#define BIT_GET_RXFILTER_CATEGORY_1(x) \ + (((x) >> BIT_SHIFT_RXFILTER_CATEGORY_1) & BIT_MASK_RXFILTER_CATEGORY_1) + +/* 2 REG_RXFILTER_ACTION_1 (Offset 0x0683) */ + +#define BIT_SHIFT_RXFILTER_ACTION_1 0 +#define BIT_MASK_RXFILTER_ACTION_1 0xff +#define BIT_RXFILTER_ACTION_1(x) \ + (((x) & BIT_MASK_RXFILTER_ACTION_1) << BIT_SHIFT_RXFILTER_ACTION_1) +#define BIT_GET_RXFILTER_ACTION_1(x) \ + (((x) >> BIT_SHIFT_RXFILTER_ACTION_1) & BIT_MASK_RXFILTER_ACTION_1) + +/* 2 REG_RXFILTER_CATEGORY_2 (Offset 0x0684) */ + +#define BIT_SHIFT_RXFILTER_CATEGORY_2 0 +#define BIT_MASK_RXFILTER_CATEGORY_2 0xff +#define BIT_RXFILTER_CATEGORY_2(x) \ + (((x) & BIT_MASK_RXFILTER_CATEGORY_2) << BIT_SHIFT_RXFILTER_CATEGORY_2) +#define BIT_GET_RXFILTER_CATEGORY_2(x) \ + (((x) >> BIT_SHIFT_RXFILTER_CATEGORY_2) & BIT_MASK_RXFILTER_CATEGORY_2) + +/* 2 REG_RXFILTER_ACTION_2 (Offset 0x0685) */ + +#define BIT_SHIFT_RXFILTER_ACTION_2 0 +#define BIT_MASK_RXFILTER_ACTION_2 0xff +#define BIT_RXFILTER_ACTION_2(x) \ + (((x) & BIT_MASK_RXFILTER_ACTION_2) << BIT_SHIFT_RXFILTER_ACTION_2) +#define BIT_GET_RXFILTER_ACTION_2(x) \ + (((x) >> BIT_SHIFT_RXFILTER_ACTION_2) & BIT_MASK_RXFILTER_ACTION_2) + +/* 2 REG_RXFILTER_CATEGORY_3 (Offset 0x0686) */ + +#define BIT_SHIFT_RXFILTER_CATEGORY_3 0 +#define BIT_MASK_RXFILTER_CATEGORY_3 0xff +#define BIT_RXFILTER_CATEGORY_3(x) \ + (((x) & BIT_MASK_RXFILTER_CATEGORY_3) << BIT_SHIFT_RXFILTER_CATEGORY_3) +#define BIT_GET_RXFILTER_CATEGORY_3(x) \ + (((x) >> BIT_SHIFT_RXFILTER_CATEGORY_3) & BIT_MASK_RXFILTER_CATEGORY_3) + +/* 2 REG_RXFILTER_ACTION_3 (Offset 0x0687) */ + +#define BIT_SHIFT_RXFILTER_ACTION_3 0 +#define BIT_MASK_RXFILTER_ACTION_3 0xff +#define BIT_RXFILTER_ACTION_3(x) \ + (((x) & BIT_MASK_RXFILTER_ACTION_3) << BIT_SHIFT_RXFILTER_ACTION_3) +#define BIT_GET_RXFILTER_ACTION_3(x) \ + (((x) >> BIT_SHIFT_RXFILTER_ACTION_3) & BIT_MASK_RXFILTER_ACTION_3) + +/* 2 REG_RXFLTMAP3 (Offset 0x0688) */ + +#define BIT_MGTFLT15EN_FW BIT(15) +#define BIT_MGTFLT14EN_FW BIT(14) +#define BIT_MGTFLT13EN_FW BIT(13) +#define BIT_MGTFLT12EN_FW BIT(12) +#define BIT_MGTFLT11EN_FW BIT(11) +#define BIT_MGTFLT10EN_FW BIT(10) +#define BIT_MGTFLT9EN_FW BIT(9) +#define BIT_MGTFLT8EN_FW BIT(8) +#define BIT_MGTFLT7EN_FW BIT(7) +#define BIT_MGTFLT6EN_FW BIT(6) +#define BIT_MGTFLT5EN_FW BIT(5) +#define BIT_MGTFLT4EN_FW BIT(4) +#define BIT_MGTFLT3EN_FW BIT(3) +#define BIT_MGTFLT2EN_FW BIT(2) +#define BIT_MGTFLT1EN_FW BIT(1) +#define BIT_MGTFLT0EN_FW BIT(0) + +/* 2 REG_RXFLTMAP4 (Offset 0x068A) */ + +#define BIT_CTRLFLT15EN_FW BIT(15) +#define BIT_CTRLFLT14EN_FW BIT(14) +#define BIT_CTRLFLT13EN_FW BIT(13) +#define BIT_CTRLFLT12EN_FW BIT(12) +#define BIT_CTRLFLT11EN_FW BIT(11) +#define BIT_CTRLFLT10EN_FW BIT(10) +#define BIT_CTRLFLT9EN_FW BIT(9) +#define BIT_CTRLFLT8EN_FW BIT(8) +#define BIT_CTRLFLT7EN_FW BIT(7) +#define BIT_CTRLFLT6EN_FW BIT(6) +#define BIT_CTRLFLT5EN_FW BIT(5) +#define BIT_CTRLFLT4EN_FW BIT(4) +#define BIT_CTRLFLT3EN_FW BIT(3) +#define BIT_CTRLFLT2EN_FW BIT(2) +#define BIT_CTRLFLT1EN_FW BIT(1) +#define BIT_CTRLFLT0EN_FW BIT(0) + +/* 2 REG_RXFLTMAP5 (Offset 0x068C) */ + +#define BIT_DATAFLT15EN_FW BIT(15) +#define BIT_DATAFLT14EN_FW BIT(14) +#define BIT_DATAFLT13EN_FW BIT(13) +#define BIT_DATAFLT12EN_FW BIT(12) +#define BIT_DATAFLT11EN_FW BIT(11) +#define BIT_DATAFLT10EN_FW BIT(10) +#define BIT_DATAFLT9EN_FW BIT(9) +#define BIT_DATAFLT8EN_FW BIT(8) +#define BIT_DATAFLT7EN_FW BIT(7) +#define BIT_DATAFLT6EN_FW BIT(6) +#define BIT_DATAFLT5EN_FW BIT(5) +#define BIT_DATAFLT4EN_FW BIT(4) +#define BIT_DATAFLT3EN_FW BIT(3) +#define BIT_DATAFLT2EN_FW BIT(2) +#define BIT_DATAFLT1EN_FW BIT(1) +#define BIT_DATAFLT0EN_FW BIT(0) + +/* 2 REG_RXFLTMAP6 (Offset 0x068E) */ + +#define BIT_ACTIONFLT15EN_FW BIT(15) +#define BIT_ACTIONFLT14EN_FW BIT(14) +#define BIT_ACTIONFLT13EN_FW BIT(13) +#define BIT_ACTIONFLT12EN_FW BIT(12) +#define BIT_ACTIONFLT11EN_FW BIT(11) +#define BIT_ACTIONFLT10EN_FW BIT(10) +#define BIT_ACTIONFLT9EN_FW BIT(9) +#define BIT_ACTIONFLT8EN_FW BIT(8) +#define BIT_ACTIONFLT7EN_FW BIT(7) +#define BIT_ACTIONFLT6EN_FW BIT(6) +#define BIT_ACTIONFLT5EN_FW BIT(5) +#define BIT_ACTIONFLT4EN_FW BIT(4) +#define BIT_ACTIONFLT3EN_FW BIT(3) +#define BIT_ACTIONFLT2EN_FW BIT(2) +#define BIT_ACTIONFLT1EN_FW BIT(1) +#define BIT_ACTIONFLT0EN_FW BIT(0) + +/* 2 REG_WOW_CTRL (Offset 0x0690) */ + +#define BIT_SHIFT_PSF_BSSIDSEL_B2B1 6 +#define BIT_MASK_PSF_BSSIDSEL_B2B1 0x3 +#define BIT_PSF_BSSIDSEL_B2B1(x) \ + (((x) & BIT_MASK_PSF_BSSIDSEL_B2B1) << BIT_SHIFT_PSF_BSSIDSEL_B2B1) +#define BIT_GET_PSF_BSSIDSEL_B2B1(x) \ + (((x) >> BIT_SHIFT_PSF_BSSIDSEL_B2B1) & BIT_MASK_PSF_BSSIDSEL_B2B1) + +/* 2 REG_WOW_CTRL (Offset 0x0690) */ + +#define BIT_WOWHCI BIT(5) + +/* 2 REG_WOW_CTRL (Offset 0x0690) */ + +#define BIT_PSF_BSSIDSEL_B0 BIT(4) + +/* 2 REG_WOW_CTRL (Offset 0x0690) */ + +#define BIT_UWF BIT(3) +#define BIT_MAGIC BIT(2) +#define BIT_WOWEN BIT(1) +#define BIT_FORCE_WAKEUP BIT(0) + +/* 2 REG_NAN_RX_TSF_FILTER (Offset 0x0691) */ + +#define BIT_CHK_TSF_TA BIT(2) +#define BIT_CHK_TSF_CBSSID BIT(1) +#define BIT_CHK_TSF_EN BIT(0) + +/* 2 REG_PS_RX_INFO (Offset 0x0692) */ + +#define BIT_SHIFT_PORTSEL__PS_RX_INFO 5 +#define BIT_MASK_PORTSEL__PS_RX_INFO 0x7 +#define BIT_PORTSEL__PS_RX_INFO(x) \ + (((x) & BIT_MASK_PORTSEL__PS_RX_INFO) << BIT_SHIFT_PORTSEL__PS_RX_INFO) +#define BIT_GET_PORTSEL__PS_RX_INFO(x) \ + (((x) >> BIT_SHIFT_PORTSEL__PS_RX_INFO) & BIT_MASK_PORTSEL__PS_RX_INFO) + +/* 2 REG_PS_RX_INFO (Offset 0x0692) */ + +#define BIT_RXCTRLIN0 BIT(4) +#define BIT_RXMGTIN0 BIT(3) +#define BIT_RXDATAIN2 BIT(2) +#define BIT_RXDATAIN1 BIT(1) +#define BIT_RXDATAIN0 BIT(0) + +/* 2 REG_WMMPS_UAPSD_TID (Offset 0x0693) */ + +#define BIT_WMMPS_UAPSD_TID7 BIT(7) +#define BIT_WMMPS_UAPSD_TID6 BIT(6) +#define BIT_WMMPS_UAPSD_TID5 BIT(5) +#define BIT_WMMPS_UAPSD_TID4 BIT(4) +#define BIT_WMMPS_UAPSD_TID3 BIT(3) +#define BIT_WMMPS_UAPSD_TID2 BIT(2) +#define BIT_WMMPS_UAPSD_TID1 BIT(1) +#define BIT_WMMPS_UAPSD_TID0 BIT(0) + +/* 2 REG_LPNAV_CTRL (Offset 0x0694) */ + +#define BIT_LPNAV_EN BIT(31) + +#define BIT_SHIFT_LPNAV_EARLY 16 +#define BIT_MASK_LPNAV_EARLY 0x7fff +#define BIT_LPNAV_EARLY(x) \ + (((x) & BIT_MASK_LPNAV_EARLY) << BIT_SHIFT_LPNAV_EARLY) +#define BIT_GET_LPNAV_EARLY(x) \ + (((x) >> BIT_SHIFT_LPNAV_EARLY) & BIT_MASK_LPNAV_EARLY) + +#define BIT_SHIFT_LPNAV_TH 0 +#define BIT_MASK_LPNAV_TH 0xffff +#define BIT_LPNAV_TH(x) (((x) & BIT_MASK_LPNAV_TH) << BIT_SHIFT_LPNAV_TH) +#define BIT_GET_LPNAV_TH(x) (((x) >> BIT_SHIFT_LPNAV_TH) & BIT_MASK_LPNAV_TH) + +/* 2 REG_WKFMCAM_CMD (Offset 0x0698) */ + +#define BIT_WKFCAM_POLLING_V1 BIT(31) +#define BIT_WKFCAM_CLR_V1 BIT(30) + +/* 2 REG_WKFMCAM_CMD (Offset 0x0698) */ + +#define BIT_WKFCAM_WE BIT(16) + +/* 2 REG_WKFMCAM_CMD (Offset 0x0698) */ + +#define BIT_SHIFT_WKFCAM_ADDR_V2 8 +#define BIT_MASK_WKFCAM_ADDR_V2 0xff +#define BIT_WKFCAM_ADDR_V2(x) \ + (((x) & BIT_MASK_WKFCAM_ADDR_V2) << BIT_SHIFT_WKFCAM_ADDR_V2) +#define BIT_GET_WKFCAM_ADDR_V2(x) \ + (((x) >> BIT_SHIFT_WKFCAM_ADDR_V2) & BIT_MASK_WKFCAM_ADDR_V2) + +#define BIT_SHIFT_WKFCAM_CAM_NUM_V1 0 +#define BIT_MASK_WKFCAM_CAM_NUM_V1 0xff +#define BIT_WKFCAM_CAM_NUM_V1(x) \ + (((x) & BIT_MASK_WKFCAM_CAM_NUM_V1) << BIT_SHIFT_WKFCAM_CAM_NUM_V1) +#define BIT_GET_WKFCAM_CAM_NUM_V1(x) \ + (((x) >> BIT_SHIFT_WKFCAM_CAM_NUM_V1) & BIT_MASK_WKFCAM_CAM_NUM_V1) + +/* 2 REG_WKFMCAM_RWD (Offset 0x069C) */ + +#define BIT_SHIFT_WKFMCAM_RWD 0 +#define BIT_MASK_WKFMCAM_RWD 0xffffffffL +#define BIT_WKFMCAM_RWD(x) \ + (((x) & BIT_MASK_WKFMCAM_RWD) << BIT_SHIFT_WKFMCAM_RWD) +#define BIT_GET_WKFMCAM_RWD(x) \ + (((x) >> BIT_SHIFT_WKFMCAM_RWD) & BIT_MASK_WKFMCAM_RWD) + +/* 2 REG_RXFLTMAP0 (Offset 0x06A0) */ + +#define BIT_MGTFLT15EN BIT(15) +#define BIT_MGTFLT14EN BIT(14) + +/* 2 REG_RXFLTMAP0 (Offset 0x06A0) */ + +#define BIT_MGTFLT13EN BIT(13) +#define BIT_MGTFLT12EN BIT(12) +#define BIT_MGTFLT11EN BIT(11) +#define BIT_MGTFLT10EN BIT(10) +#define BIT_MGTFLT9EN BIT(9) +#define BIT_MGTFLT8EN BIT(8) + +/* 2 REG_RXFLTMAP0 (Offset 0x06A0) */ + +#define BIT_MGTFLT7EN BIT(7) +#define BIT_MGTFLT6EN BIT(6) + +/* 2 REG_RXFLTMAP0 (Offset 0x06A0) */ + +#define BIT_MGTFLT5EN BIT(5) +#define BIT_MGTFLT4EN BIT(4) +#define BIT_MGTFLT3EN BIT(3) +#define BIT_MGTFLT2EN BIT(2) +#define BIT_MGTFLT1EN BIT(1) +#define BIT_MGTFLT0EN BIT(0) + +/* 2 REG_RXFLTMAP1 (Offset 0x06A2) */ + +#define BIT_CTRLFLT15EN BIT(15) +#define BIT_CTRLFLT14EN BIT(14) +#define BIT_CTRLFLT13EN BIT(13) +#define BIT_CTRLFLT12EN BIT(12) +#define BIT_CTRLFLT11EN BIT(11) +#define BIT_CTRLFLT10EN BIT(10) +#define BIT_CTRLFLT9EN BIT(9) +#define BIT_CTRLFLT8EN BIT(8) +#define BIT_CTRLFLT7EN BIT(7) +#define BIT_CTRLFLT6EN BIT(6) + +/* 2 REG_RXFLTMAP1 (Offset 0x06A2) */ + +#define BIT_CTRLFLT5EN BIT(5) +#define BIT_CTRLFLT4EN BIT(4) +#define BIT_CTRLFLT3EN BIT(3) +#define BIT_CTRLFLT2EN BIT(2) +#define BIT_CTRLFLT1EN BIT(1) +#define BIT_CTRLFLT0EN BIT(0) + +/* 2 REG_RXFLTMAP (Offset 0x06A4) */ + +#define BIT_DATAFLT15EN BIT(15) +#define BIT_DATAFLT14EN BIT(14) +#define BIT_DATAFLT13EN BIT(13) +#define BIT_DATAFLT12EN BIT(12) +#define BIT_DATAFLT11EN BIT(11) +#define BIT_DATAFLT10EN BIT(10) +#define BIT_DATAFLT9EN BIT(9) +#define BIT_DATAFLT8EN BIT(8) +#define BIT_DATAFLT7EN BIT(7) +#define BIT_DATAFLT6EN BIT(6) +#define BIT_DATAFLT5EN BIT(5) +#define BIT_DATAFLT4EN BIT(4) +#define BIT_DATAFLT3EN BIT(3) +#define BIT_DATAFLT2EN BIT(2) +#define BIT_DATAFLT1EN BIT(1) +#define BIT_DATAFLT0EN BIT(0) + +/* 2 REG_BCN_PSR_RPT (Offset 0x06A8) */ + +#define BIT_SHIFT_DTIM_CNT 24 +#define BIT_MASK_DTIM_CNT 0xff +#define BIT_DTIM_CNT(x) (((x) & BIT_MASK_DTIM_CNT) << BIT_SHIFT_DTIM_CNT) +#define BIT_GET_DTIM_CNT(x) (((x) >> BIT_SHIFT_DTIM_CNT) & BIT_MASK_DTIM_CNT) + +#define BIT_SHIFT_DTIM_PERIOD 16 +#define BIT_MASK_DTIM_PERIOD 0xff +#define BIT_DTIM_PERIOD(x) \ + (((x) & BIT_MASK_DTIM_PERIOD) << BIT_SHIFT_DTIM_PERIOD) +#define BIT_GET_DTIM_PERIOD(x) \ + (((x) >> BIT_SHIFT_DTIM_PERIOD) & BIT_MASK_DTIM_PERIOD) + +#define BIT_DTIM BIT(15) +#define BIT_TIM BIT(14) + +#define BIT_SHIFT_PS_AID_0 0 +#define BIT_MASK_PS_AID_0 0x7ff +#define BIT_PS_AID_0(x) (((x) & BIT_MASK_PS_AID_0) << BIT_SHIFT_PS_AID_0) +#define BIT_GET_PS_AID_0(x) (((x) >> BIT_SHIFT_PS_AID_0) & BIT_MASK_PS_AID_0) + +/* 2 REG_FLC_RPC (Offset 0x06AC) */ + +#define BIT_SHIFT_FLC_RPC 0 +#define BIT_MASK_FLC_RPC 0xff +#define BIT_FLC_RPC(x) (((x) & BIT_MASK_FLC_RPC) << BIT_SHIFT_FLC_RPC) +#define BIT_GET_FLC_RPC(x) (((x) >> BIT_SHIFT_FLC_RPC) & BIT_MASK_FLC_RPC) + +/* 2 REG_FLC_RPCT (Offset 0x06AD) */ + +#define BIT_SHIFT_FLC_RPCT 0 +#define BIT_MASK_FLC_RPCT 0xff +#define BIT_FLC_RPCT(x) (((x) & BIT_MASK_FLC_RPCT) << BIT_SHIFT_FLC_RPCT) +#define BIT_GET_FLC_RPCT(x) (((x) >> BIT_SHIFT_FLC_RPCT) & BIT_MASK_FLC_RPCT) + +/* 2 REG_FLC_PTS (Offset 0x06AE) */ + +#define BIT_CMF BIT(2) +#define BIT_CCF BIT(1) +#define BIT_CDF BIT(0) + +/* 2 REG_FLC_TRPC (Offset 0x06AF) */ + +#define BIT_FLC_RPCT_V1 BIT(7) +#define BIT_MODE BIT(6) + +#define BIT_SHIFT_TRPCD 0 +#define BIT_MASK_TRPCD 0x3f +#define BIT_TRPCD(x) (((x) & BIT_MASK_TRPCD) << BIT_SHIFT_TRPCD) +#define BIT_GET_TRPCD(x) (((x) >> BIT_SHIFT_TRPCD) & BIT_MASK_TRPCD) + +/* 2 REG_RXPKTMON_CTRL (Offset 0x06B0) */ + +#define BIT_SHIFT_RXBKQPKT_SEQ 20 +#define BIT_MASK_RXBKQPKT_SEQ 0xf +#define BIT_RXBKQPKT_SEQ(x) \ + (((x) & BIT_MASK_RXBKQPKT_SEQ) << BIT_SHIFT_RXBKQPKT_SEQ) +#define BIT_GET_RXBKQPKT_SEQ(x) \ + (((x) >> BIT_SHIFT_RXBKQPKT_SEQ) & BIT_MASK_RXBKQPKT_SEQ) + +#define BIT_SHIFT_RXBEQPKT_SEQ 16 +#define BIT_MASK_RXBEQPKT_SEQ 0xf +#define BIT_RXBEQPKT_SEQ(x) \ + (((x) & BIT_MASK_RXBEQPKT_SEQ) << BIT_SHIFT_RXBEQPKT_SEQ) +#define BIT_GET_RXBEQPKT_SEQ(x) \ + (((x) >> BIT_SHIFT_RXBEQPKT_SEQ) & BIT_MASK_RXBEQPKT_SEQ) + +#define BIT_SHIFT_RXVIQPKT_SEQ 12 +#define BIT_MASK_RXVIQPKT_SEQ 0xf +#define BIT_RXVIQPKT_SEQ(x) \ + (((x) & BIT_MASK_RXVIQPKT_SEQ) << BIT_SHIFT_RXVIQPKT_SEQ) +#define BIT_GET_RXVIQPKT_SEQ(x) \ + (((x) >> BIT_SHIFT_RXVIQPKT_SEQ) & BIT_MASK_RXVIQPKT_SEQ) + +#define BIT_SHIFT_RXVOQPKT_SEQ 8 +#define BIT_MASK_RXVOQPKT_SEQ 0xf +#define BIT_RXVOQPKT_SEQ(x) \ + (((x) & BIT_MASK_RXVOQPKT_SEQ) << BIT_SHIFT_RXVOQPKT_SEQ) +#define BIT_GET_RXVOQPKT_SEQ(x) \ + (((x) >> BIT_SHIFT_RXVOQPKT_SEQ) & BIT_MASK_RXVOQPKT_SEQ) + +#define BIT_RXBKQPKT_ERR BIT(7) +#define BIT_RXBEQPKT_ERR BIT(6) +#define BIT_RXVIQPKT_ERR BIT(5) +#define BIT_RXVOQPKT_ERR BIT(4) +#define BIT_RXDMA_MON_EN BIT(2) +#define BIT_RXPKT_MON_RST BIT(1) +#define BIT_RXPKT_MON_EN BIT(0) + +/* 2 REG_STATE_MON (Offset 0x06B4) */ + +#define BIT_SHIFT_STATE_SEL 24 +#define BIT_MASK_STATE_SEL 0x1f +#define BIT_STATE_SEL(x) (((x) & BIT_MASK_STATE_SEL) << BIT_SHIFT_STATE_SEL) +#define BIT_GET_STATE_SEL(x) (((x) >> BIT_SHIFT_STATE_SEL) & BIT_MASK_STATE_SEL) + +#define BIT_SHIFT_STATE_INFO 8 +#define BIT_MASK_STATE_INFO 0xff +#define BIT_STATE_INFO(x) (((x) & BIT_MASK_STATE_INFO) << BIT_SHIFT_STATE_INFO) +#define BIT_GET_STATE_INFO(x) \ + (((x) >> BIT_SHIFT_STATE_INFO) & BIT_MASK_STATE_INFO) + +#define BIT_UPD_NXT_STATE BIT(7) + +/* 2 REG_STATE_MON (Offset 0x06B4) */ + +#define BIT_SHIFT_CUR_STATE 0 +#define BIT_MASK_CUR_STATE 0x7f +#define BIT_CUR_STATE(x) (((x) & BIT_MASK_CUR_STATE) << BIT_SHIFT_CUR_STATE) +#define BIT_GET_CUR_STATE(x) (((x) >> BIT_SHIFT_CUR_STATE) & BIT_MASK_CUR_STATE) + +/* 2 REG_ERROR_MON (Offset 0x06B8) */ + +#define BIT_MACRX_ERR_1 BIT(17) +#define BIT_MACRX_ERR_0 BIT(16) +#define BIT_MACTX_ERR_3 BIT(3) +#define BIT_MACTX_ERR_2 BIT(2) +#define BIT_MACTX_ERR_1 BIT(1) +#define BIT_MACTX_ERR_0 BIT(0) + +/* 2 REG_SEARCH_MACID (Offset 0x06BC) */ + +#define BIT_EN_TXRPTBUF_CLK BIT(31) + +#define BIT_SHIFT_INFO_INDEX_OFFSET 16 +#define BIT_MASK_INFO_INDEX_OFFSET 0x1fff +#define BIT_INFO_INDEX_OFFSET(x) \ + (((x) & BIT_MASK_INFO_INDEX_OFFSET) << BIT_SHIFT_INFO_INDEX_OFFSET) +#define BIT_GET_INFO_INDEX_OFFSET(x) \ + (((x) >> BIT_SHIFT_INFO_INDEX_OFFSET) & BIT_MASK_INFO_INDEX_OFFSET) + +/* 2 REG_SEARCH_MACID (Offset 0x06BC) */ + +#define BIT_WMAC_SRCH_FIFOFULL BIT(15) + +/* 2 REG_SEARCH_MACID (Offset 0x06BC) */ + +#define BIT_DIS_INFOSRCH BIT(14) +#define BIT_DISABLE_B0 BIT(13) + +#define BIT_SHIFT_INFO_ADDR_OFFSET 0 +#define BIT_MASK_INFO_ADDR_OFFSET 0x1fff +#define BIT_INFO_ADDR_OFFSET(x) \ + (((x) & BIT_MASK_INFO_ADDR_OFFSET) << BIT_SHIFT_INFO_ADDR_OFFSET) +#define BIT_GET_INFO_ADDR_OFFSET(x) \ + (((x) >> BIT_SHIFT_INFO_ADDR_OFFSET) & BIT_MASK_INFO_ADDR_OFFSET) + +/* 2 REG_BT_COEX_TABLE (Offset 0x06C0) */ + +#define BIT_PRI_MASK_RX_RESP BIT(126) +#define BIT_PRI_MASK_RXOFDM BIT(125) +#define BIT_PRI_MASK_RXCCK BIT(124) + +#define BIT_SHIFT_PRI_MASK_TXAC (117 & CPU_OPT_WIDTH) +#define BIT_MASK_PRI_MASK_TXAC 0x7f +#define BIT_PRI_MASK_TXAC(x) \ + (((x) & BIT_MASK_PRI_MASK_TXAC) << BIT_SHIFT_PRI_MASK_TXAC) +#define BIT_GET_PRI_MASK_TXAC(x) \ + (((x) >> BIT_SHIFT_PRI_MASK_TXAC) & BIT_MASK_PRI_MASK_TXAC) + +#define BIT_SHIFT_PRI_MASK_NAV (109 & CPU_OPT_WIDTH) +#define BIT_MASK_PRI_MASK_NAV 0xff +#define BIT_PRI_MASK_NAV(x) \ + (((x) & BIT_MASK_PRI_MASK_NAV) << BIT_SHIFT_PRI_MASK_NAV) +#define BIT_GET_PRI_MASK_NAV(x) \ + (((x) >> BIT_SHIFT_PRI_MASK_NAV) & BIT_MASK_PRI_MASK_NAV) + +#define BIT_PRI_MASK_CCK BIT(108) +#define BIT_PRI_MASK_OFDM BIT(107) +#define BIT_PRI_MASK_RTY BIT(106) + +#define BIT_SHIFT_PRI_MASK_NUM (102 & CPU_OPT_WIDTH) +#define BIT_MASK_PRI_MASK_NUM 0xf +#define BIT_PRI_MASK_NUM(x) \ + (((x) & BIT_MASK_PRI_MASK_NUM) << BIT_SHIFT_PRI_MASK_NUM) +#define BIT_GET_PRI_MASK_NUM(x) \ + (((x) >> BIT_SHIFT_PRI_MASK_NUM) & BIT_MASK_PRI_MASK_NUM) + +#define BIT_SHIFT_PRI_MASK_TYPE (98 & CPU_OPT_WIDTH) +#define BIT_MASK_PRI_MASK_TYPE 0xf +#define BIT_PRI_MASK_TYPE(x) \ + (((x) & BIT_MASK_PRI_MASK_TYPE) << BIT_SHIFT_PRI_MASK_TYPE) +#define BIT_GET_PRI_MASK_TYPE(x) \ + (((x) >> BIT_SHIFT_PRI_MASK_TYPE) & BIT_MASK_PRI_MASK_TYPE) + +#define BIT_OOB BIT(97) +#define BIT_ANT_SEL BIT(96) + +#define BIT_SHIFT_BREAK_TABLE_2 (80 & CPU_OPT_WIDTH) +#define BIT_MASK_BREAK_TABLE_2 0xffff +#define BIT_BREAK_TABLE_2(x) \ + (((x) & BIT_MASK_BREAK_TABLE_2) << BIT_SHIFT_BREAK_TABLE_2) +#define BIT_GET_BREAK_TABLE_2(x) \ + (((x) >> BIT_SHIFT_BREAK_TABLE_2) & BIT_MASK_BREAK_TABLE_2) + +#define BIT_SHIFT_BREAK_TABLE_1 (64 & CPU_OPT_WIDTH) +#define BIT_MASK_BREAK_TABLE_1 0xffff +#define BIT_BREAK_TABLE_1(x) \ + (((x) & BIT_MASK_BREAK_TABLE_1) << BIT_SHIFT_BREAK_TABLE_1) +#define BIT_GET_BREAK_TABLE_1(x) \ + (((x) >> BIT_SHIFT_BREAK_TABLE_1) & BIT_MASK_BREAK_TABLE_1) + +#define BIT_SHIFT_COEX_TABLE_2 (32 & CPU_OPT_WIDTH) +#define BIT_MASK_COEX_TABLE_2 0xffffffffL +#define BIT_COEX_TABLE_2(x) \ + (((x) & BIT_MASK_COEX_TABLE_2) << BIT_SHIFT_COEX_TABLE_2) +#define BIT_GET_COEX_TABLE_2(x) \ + (((x) >> BIT_SHIFT_COEX_TABLE_2) & BIT_MASK_COEX_TABLE_2) + +#define BIT_SHIFT_COEX_TABLE_1 0 +#define BIT_MASK_COEX_TABLE_1 0xffffffffL +#define BIT_COEX_TABLE_1(x) \ + (((x) & BIT_MASK_COEX_TABLE_1) << BIT_SHIFT_COEX_TABLE_1) +#define BIT_GET_COEX_TABLE_1(x) \ + (((x) >> BIT_SHIFT_COEX_TABLE_1) & BIT_MASK_COEX_TABLE_1) + +/* 2 REG_RXCMD_0 (Offset 0x06D0) */ + +#define BIT_RXCMD_EN BIT(31) + +#define BIT_SHIFT_RXCMD_INFO 0 +#define BIT_MASK_RXCMD_INFO 0x7fffffffL +#define BIT_RXCMD_INFO(x) (((x) & BIT_MASK_RXCMD_INFO) << BIT_SHIFT_RXCMD_INFO) +#define BIT_GET_RXCMD_INFO(x) \ + (((x) >> BIT_SHIFT_RXCMD_INFO) & BIT_MASK_RXCMD_INFO) + +/* 2 REG_RXCMD_1 (Offset 0x06D4) */ + +#define BIT_SHIFT_RXCMD_PRD 0 +#define BIT_MASK_RXCMD_PRD 0xffff +#define BIT_RXCMD_PRD(x) (((x) & BIT_MASK_RXCMD_PRD) << BIT_SHIFT_RXCMD_PRD) +#define BIT_GET_RXCMD_PRD(x) (((x) >> BIT_SHIFT_RXCMD_PRD) & BIT_MASK_RXCMD_PRD) + +/* 2 REG_WMAC_RESP_TXINFO (Offset 0x06D8) */ + +#define BIT_SHIFT_WMAC_RESP_MFB 25 +#define BIT_MASK_WMAC_RESP_MFB 0x7f +#define BIT_WMAC_RESP_MFB(x) \ + (((x) & BIT_MASK_WMAC_RESP_MFB) << BIT_SHIFT_WMAC_RESP_MFB) +#define BIT_GET_WMAC_RESP_MFB(x) \ + (((x) >> BIT_SHIFT_WMAC_RESP_MFB) & BIT_MASK_WMAC_RESP_MFB) + +#define BIT_SHIFT_WMAC_ANTINF_SEL 23 +#define BIT_MASK_WMAC_ANTINF_SEL 0x3 +#define BIT_WMAC_ANTINF_SEL(x) \ + (((x) & BIT_MASK_WMAC_ANTINF_SEL) << BIT_SHIFT_WMAC_ANTINF_SEL) +#define BIT_GET_WMAC_ANTINF_SEL(x) \ + (((x) >> BIT_SHIFT_WMAC_ANTINF_SEL) & BIT_MASK_WMAC_ANTINF_SEL) + +#define BIT_SHIFT_WMAC_ANTSEL_SEL 21 +#define BIT_MASK_WMAC_ANTSEL_SEL 0x3 +#define BIT_WMAC_ANTSEL_SEL(x) \ + (((x) & BIT_MASK_WMAC_ANTSEL_SEL) << BIT_SHIFT_WMAC_ANTSEL_SEL) +#define BIT_GET_WMAC_ANTSEL_SEL(x) \ + (((x) >> BIT_SHIFT_WMAC_ANTSEL_SEL) & BIT_MASK_WMAC_ANTSEL_SEL) + +/* 2 REG_WMAC_RESP_TXINFO (Offset 0x06D8) */ + +#define BIT_SHIFT_R_WMAC_RESP_TXPOWER 18 +#define BIT_MASK_R_WMAC_RESP_TXPOWER 0x7 +#define BIT_R_WMAC_RESP_TXPOWER(x) \ + (((x) & BIT_MASK_R_WMAC_RESP_TXPOWER) << BIT_SHIFT_R_WMAC_RESP_TXPOWER) +#define BIT_GET_R_WMAC_RESP_TXPOWER(x) \ + (((x) >> BIT_SHIFT_R_WMAC_RESP_TXPOWER) & BIT_MASK_R_WMAC_RESP_TXPOWER) + +/* 2 REG_WMAC_RESP_TXINFO (Offset 0x06D8) */ + +#define BIT_SHIFT_WMAC_RESP_TXANT 0 +#define BIT_MASK_WMAC_RESP_TXANT 0x3ffff +#define BIT_WMAC_RESP_TXANT(x) \ + (((x) & BIT_MASK_WMAC_RESP_TXANT) << BIT_SHIFT_WMAC_RESP_TXANT) +#define BIT_GET_WMAC_RESP_TXANT(x) \ + (((x) >> BIT_SHIFT_WMAC_RESP_TXANT) & BIT_MASK_WMAC_RESP_TXANT) + +/* 2 REG_BBPSF_CTRL (Offset 0x06DC) */ + +#define BIT_CTL_IDLE_CLR_CSI_RPT BIT(31) + +/* 2 REG_BBPSF_CTRL (Offset 0x06DC) */ + +#define BIT_WMAC_USE_NDPARATE BIT(30) + +#define BIT_SHIFT_WMAC_CSI_RATE 24 +#define BIT_MASK_WMAC_CSI_RATE 0x3f +#define BIT_WMAC_CSI_RATE(x) \ + (((x) & BIT_MASK_WMAC_CSI_RATE) << BIT_SHIFT_WMAC_CSI_RATE) +#define BIT_GET_WMAC_CSI_RATE(x) \ + (((x) >> BIT_SHIFT_WMAC_CSI_RATE) & BIT_MASK_WMAC_CSI_RATE) + +#define BIT_SHIFT_WMAC_RESP_TXRATE 16 +#define BIT_MASK_WMAC_RESP_TXRATE 0xff +#define BIT_WMAC_RESP_TXRATE(x) \ + (((x) & BIT_MASK_WMAC_RESP_TXRATE) << BIT_SHIFT_WMAC_RESP_TXRATE) +#define BIT_GET_WMAC_RESP_TXRATE(x) \ + (((x) >> BIT_SHIFT_WMAC_RESP_TXRATE) & BIT_MASK_WMAC_RESP_TXRATE) + +/* 2 REG_BBPSF_CTRL (Offset 0x06DC) */ + +#define BIT_BBPSF_MPDUCHKEN BIT(5) + +/* 2 REG_BBPSF_CTRL (Offset 0x06DC) */ + +#define BIT_BBPSF_MHCHKEN BIT(4) +#define BIT_BBPSF_ERRCHKEN BIT(3) + +#define BIT_SHIFT_BBPSF_ERRTHR 0 +#define BIT_MASK_BBPSF_ERRTHR 0x7 +#define BIT_BBPSF_ERRTHR(x) \ + (((x) & BIT_MASK_BBPSF_ERRTHR) << BIT_SHIFT_BBPSF_ERRTHR) +#define BIT_GET_BBPSF_ERRTHR(x) \ + (((x) >> BIT_SHIFT_BBPSF_ERRTHR) & BIT_MASK_BBPSF_ERRTHR) + +/* 2 REG_P2P_RX_BCN_NOA (Offset 0x06E0) */ + +#define BIT_NOA_PARSER_EN BIT(15) + +/* 2 REG_P2P_RX_BCN_NOA (Offset 0x06E0) */ + +#define BIT_BSSID_SEL BIT(14) + +/* 2 REG_P2P_RX_BCN_NOA (Offset 0x06E0) */ + +#define BIT_SHIFT_P2P_OUI_TYPE 0 +#define BIT_MASK_P2P_OUI_TYPE 0xff +#define BIT_P2P_OUI_TYPE(x) \ + (((x) & BIT_MASK_P2P_OUI_TYPE) << BIT_SHIFT_P2P_OUI_TYPE) +#define BIT_GET_P2P_OUI_TYPE(x) \ + (((x) >> BIT_SHIFT_P2P_OUI_TYPE) & BIT_MASK_P2P_OUI_TYPE) + +/* 2 REG_ASSOCIATED_BFMER0_INFO (Offset 0x06E4) */ + +#define BIT_SHIFT_R_WMAC_TXCSI_AID0 (48 & CPU_OPT_WIDTH) +#define BIT_MASK_R_WMAC_TXCSI_AID0 0x1ff +#define BIT_R_WMAC_TXCSI_AID0(x) \ + (((x) & BIT_MASK_R_WMAC_TXCSI_AID0) << BIT_SHIFT_R_WMAC_TXCSI_AID0) +#define BIT_GET_R_WMAC_TXCSI_AID0(x) \ + (((x) >> BIT_SHIFT_R_WMAC_TXCSI_AID0) & BIT_MASK_R_WMAC_TXCSI_AID0) + +#define BIT_SHIFT_R_WMAC_SOUNDING_RXADD_R0 0 +#define BIT_MASK_R_WMAC_SOUNDING_RXADD_R0 0xffffffffffffL +#define BIT_R_WMAC_SOUNDING_RXADD_R0(x) \ + (((x) & BIT_MASK_R_WMAC_SOUNDING_RXADD_R0) \ + << BIT_SHIFT_R_WMAC_SOUNDING_RXADD_R0) +#define BIT_GET_R_WMAC_SOUNDING_RXADD_R0(x) \ + (((x) >> BIT_SHIFT_R_WMAC_SOUNDING_RXADD_R0) & \ + BIT_MASK_R_WMAC_SOUNDING_RXADD_R0) + +/* 2 REG_ASSOCIATED_BFMER1_INFO (Offset 0x06EC) */ + +#define BIT_SHIFT_R_WMAC_TXCSI_AID1 (48 & CPU_OPT_WIDTH) +#define BIT_MASK_R_WMAC_TXCSI_AID1 0x1ff +#define BIT_R_WMAC_TXCSI_AID1(x) \ + (((x) & BIT_MASK_R_WMAC_TXCSI_AID1) << BIT_SHIFT_R_WMAC_TXCSI_AID1) +#define BIT_GET_R_WMAC_TXCSI_AID1(x) \ + (((x) >> BIT_SHIFT_R_WMAC_TXCSI_AID1) & BIT_MASK_R_WMAC_TXCSI_AID1) + +#define BIT_SHIFT_R_WMAC_SOUNDING_RXADD_R1 0 +#define BIT_MASK_R_WMAC_SOUNDING_RXADD_R1 0xffffffffffffL +#define BIT_R_WMAC_SOUNDING_RXADD_R1(x) \ + (((x) & BIT_MASK_R_WMAC_SOUNDING_RXADD_R1) \ + << BIT_SHIFT_R_WMAC_SOUNDING_RXADD_R1) +#define BIT_GET_R_WMAC_SOUNDING_RXADD_R1(x) \ + (((x) >> BIT_SHIFT_R_WMAC_SOUNDING_RXADD_R1) & \ + BIT_MASK_R_WMAC_SOUNDING_RXADD_R1) + +/* 2 REG_TX_CSI_RPT_PARAM_BW20 (Offset 0x06F4) */ + +#define BIT_SHIFT_R_WMAC_BFINFO_20M_1 16 +#define BIT_MASK_R_WMAC_BFINFO_20M_1 0xfff +#define BIT_R_WMAC_BFINFO_20M_1(x) \ + (((x) & BIT_MASK_R_WMAC_BFINFO_20M_1) << BIT_SHIFT_R_WMAC_BFINFO_20M_1) +#define BIT_GET_R_WMAC_BFINFO_20M_1(x) \ + (((x) >> BIT_SHIFT_R_WMAC_BFINFO_20M_1) & BIT_MASK_R_WMAC_BFINFO_20M_1) + +#define BIT_SHIFT_R_WMAC_BFINFO_20M_0 0 +#define BIT_MASK_R_WMAC_BFINFO_20M_0 0xfff +#define BIT_R_WMAC_BFINFO_20M_0(x) \ + (((x) & BIT_MASK_R_WMAC_BFINFO_20M_0) << BIT_SHIFT_R_WMAC_BFINFO_20M_0) +#define BIT_GET_R_WMAC_BFINFO_20M_0(x) \ + (((x) >> BIT_SHIFT_R_WMAC_BFINFO_20M_0) & BIT_MASK_R_WMAC_BFINFO_20M_0) + +/* 2 REG_TX_CSI_RPT_PARAM_BW40 (Offset 0x06F8) */ + +#define BIT_SHIFT_WMAC_RESP_ANTCD 0 +#define BIT_MASK_WMAC_RESP_ANTCD 0xf +#define BIT_WMAC_RESP_ANTCD(x) \ + (((x) & BIT_MASK_WMAC_RESP_ANTCD) << BIT_SHIFT_WMAC_RESP_ANTCD) +#define BIT_GET_WMAC_RESP_ANTCD(x) \ + (((x) >> BIT_SHIFT_WMAC_RESP_ANTCD) & BIT_MASK_WMAC_RESP_ANTCD) + +/* 2 REG_MACID1 (Offset 0x0700) */ + +#define BIT_SHIFT_MACID1 0 +#define BIT_MASK_MACID1 0xffffffffffffL +#define BIT_MACID1(x) (((x) & BIT_MASK_MACID1) << BIT_SHIFT_MACID1) +#define BIT_GET_MACID1(x) (((x) >> BIT_SHIFT_MACID1) & BIT_MASK_MACID1) + +/* 2 REG_BSSID1 (Offset 0x0708) */ + +#define BIT_SHIFT_BSSID1 0 +#define BIT_MASK_BSSID1 0xffffffffffffL +#define BIT_BSSID1(x) (((x) & BIT_MASK_BSSID1) << BIT_SHIFT_BSSID1) +#define BIT_GET_BSSID1(x) (((x) >> BIT_SHIFT_BSSID1) & BIT_MASK_BSSID1) + +/* 2 REG_BCN_PSR_RPT1 (Offset 0x0710) */ + +#define BIT_SHIFT_DTIM_CNT1 24 +#define BIT_MASK_DTIM_CNT1 0xff +#define BIT_DTIM_CNT1(x) (((x) & BIT_MASK_DTIM_CNT1) << BIT_SHIFT_DTIM_CNT1) +#define BIT_GET_DTIM_CNT1(x) (((x) >> BIT_SHIFT_DTIM_CNT1) & BIT_MASK_DTIM_CNT1) + +#define BIT_SHIFT_DTIM_PERIOD1 16 +#define BIT_MASK_DTIM_PERIOD1 0xff +#define BIT_DTIM_PERIOD1(x) \ + (((x) & BIT_MASK_DTIM_PERIOD1) << BIT_SHIFT_DTIM_PERIOD1) +#define BIT_GET_DTIM_PERIOD1(x) \ + (((x) >> BIT_SHIFT_DTIM_PERIOD1) & BIT_MASK_DTIM_PERIOD1) + +#define BIT_DTIM1 BIT(15) +#define BIT_TIM1 BIT(14) + +#define BIT_SHIFT_PS_AID_1 0 +#define BIT_MASK_PS_AID_1 0x7ff +#define BIT_PS_AID_1(x) (((x) & BIT_MASK_PS_AID_1) << BIT_SHIFT_PS_AID_1) +#define BIT_GET_PS_AID_1(x) (((x) >> BIT_SHIFT_PS_AID_1) & BIT_MASK_PS_AID_1) + +/* 2 REG_ASSOCIATED_BFMEE_SEL (Offset 0x0714) */ + +#define BIT_TXUSER_ID1 BIT(25) + +#define BIT_SHIFT_AID1 16 +#define BIT_MASK_AID1 0x1ff +#define BIT_AID1(x) (((x) & BIT_MASK_AID1) << BIT_SHIFT_AID1) +#define BIT_GET_AID1(x) (((x) >> BIT_SHIFT_AID1) & BIT_MASK_AID1) + +#define BIT_TXUSER_ID0 BIT(9) + +#define BIT_SHIFT_AID0 0 +#define BIT_MASK_AID0 0x1ff +#define BIT_AID0(x) (((x) & BIT_MASK_AID0) << BIT_SHIFT_AID0) +#define BIT_GET_AID0(x) (((x) >> BIT_SHIFT_AID0) & BIT_MASK_AID0) + +/* 2 REG_SND_PTCL_CTRL (Offset 0x0718) */ + +#define BIT_SHIFT_NDP_RX_STANDBY_TIMER 24 +#define BIT_MASK_NDP_RX_STANDBY_TIMER 0xff +#define BIT_NDP_RX_STANDBY_TIMER(x) \ + (((x) & BIT_MASK_NDP_RX_STANDBY_TIMER) \ + << BIT_SHIFT_NDP_RX_STANDBY_TIMER) +#define BIT_GET_NDP_RX_STANDBY_TIMER(x) \ + (((x) >> BIT_SHIFT_NDP_RX_STANDBY_TIMER) & \ + BIT_MASK_NDP_RX_STANDBY_TIMER) + +#define BIT_SHIFT_CSI_RPT_OFFSET_HT 16 +#define BIT_MASK_CSI_RPT_OFFSET_HT 0xff +#define BIT_CSI_RPT_OFFSET_HT(x) \ + (((x) & BIT_MASK_CSI_RPT_OFFSET_HT) << BIT_SHIFT_CSI_RPT_OFFSET_HT) +#define BIT_GET_CSI_RPT_OFFSET_HT(x) \ + (((x) >> BIT_SHIFT_CSI_RPT_OFFSET_HT) & BIT_MASK_CSI_RPT_OFFSET_HT) + +/* 2 REG_SND_PTCL_CTRL (Offset 0x0718) */ + +#define BIT_SHIFT_R_WMAC_VHT_CATEGORY 8 +#define BIT_MASK_R_WMAC_VHT_CATEGORY 0xff +#define BIT_R_WMAC_VHT_CATEGORY(x) \ + (((x) & BIT_MASK_R_WMAC_VHT_CATEGORY) << BIT_SHIFT_R_WMAC_VHT_CATEGORY) +#define BIT_GET_R_WMAC_VHT_CATEGORY(x) \ + (((x) >> BIT_SHIFT_R_WMAC_VHT_CATEGORY) & BIT_MASK_R_WMAC_VHT_CATEGORY) + +/* 2 REG_SND_PTCL_CTRL (Offset 0x0718) */ + +#define BIT_R_WMAC_USE_NSTS BIT(7) +#define BIT_R_DISABLE_CHECK_VHTSIGB_CRC BIT(6) +#define BIT_R_DISABLE_CHECK_VHTSIGA_CRC BIT(5) +#define BIT_R_WMAC_BFPARAM_SEL BIT(4) +#define BIT_R_WMAC_CSISEQ_SEL BIT(3) +#define BIT_R_WMAC_CSI_WITHHTC_EN BIT(2) +#define BIT_R_WMAC_HT_NDPA_EN BIT(1) +#define BIT_R_WMAC_VHT_NDPA_EN BIT(0) + +/* 2 REG_NS_ARP_CTRL (Offset 0x0720) */ + +#define BIT_R_WMAC_NSARP_RSPEN BIT(15) +#define BIT_R_WMAC_NSARP_RARP BIT(9) +#define BIT_R_WMAC_NSARP_RIPV6 BIT(8) + +#define BIT_SHIFT_R_WMAC_NSARP_MODEN 6 +#define BIT_MASK_R_WMAC_NSARP_MODEN 0x3 +#define BIT_R_WMAC_NSARP_MODEN(x) \ + (((x) & BIT_MASK_R_WMAC_NSARP_MODEN) << BIT_SHIFT_R_WMAC_NSARP_MODEN) +#define BIT_GET_R_WMAC_NSARP_MODEN(x) \ + (((x) >> BIT_SHIFT_R_WMAC_NSARP_MODEN) & BIT_MASK_R_WMAC_NSARP_MODEN) + +#define BIT_SHIFT_R_WMAC_NSARP_RSPFTP 4 +#define BIT_MASK_R_WMAC_NSARP_RSPFTP 0x3 +#define BIT_R_WMAC_NSARP_RSPFTP(x) \ + (((x) & BIT_MASK_R_WMAC_NSARP_RSPFTP) << BIT_SHIFT_R_WMAC_NSARP_RSPFTP) +#define BIT_GET_R_WMAC_NSARP_RSPFTP(x) \ + (((x) >> BIT_SHIFT_R_WMAC_NSARP_RSPFTP) & BIT_MASK_R_WMAC_NSARP_RSPFTP) + +#define BIT_SHIFT_R_WMAC_NSARP_RSPSEC 0 +#define BIT_MASK_R_WMAC_NSARP_RSPSEC 0xf +#define BIT_R_WMAC_NSARP_RSPSEC(x) \ + (((x) & BIT_MASK_R_WMAC_NSARP_RSPSEC) << BIT_SHIFT_R_WMAC_NSARP_RSPSEC) +#define BIT_GET_R_WMAC_NSARP_RSPSEC(x) \ + (((x) >> BIT_SHIFT_R_WMAC_NSARP_RSPSEC) & BIT_MASK_R_WMAC_NSARP_RSPSEC) + +/* 2 REG_NS_ARP_INFO (Offset 0x0724) */ + +#define BIT_REQ_IS_MCNS BIT(23) +#define BIT_REQ_IS_UCNS BIT(22) +#define BIT_REQ_IS_USNS BIT(21) +#define BIT_REQ_IS_ARP BIT(20) +#define BIT_EXPRSP_MH_WITHQC BIT(19) + +#define BIT_SHIFT_EXPRSP_SECTYPE 16 +#define BIT_MASK_EXPRSP_SECTYPE 0x7 +#define BIT_EXPRSP_SECTYPE(x) \ + (((x) & BIT_MASK_EXPRSP_SECTYPE) << BIT_SHIFT_EXPRSP_SECTYPE) +#define BIT_GET_EXPRSP_SECTYPE(x) \ + (((x) >> BIT_SHIFT_EXPRSP_SECTYPE) & BIT_MASK_EXPRSP_SECTYPE) + +#define BIT_SHIFT_EXPRSP_CHKSM_7_TO_0 8 +#define BIT_MASK_EXPRSP_CHKSM_7_TO_0 0xff +#define BIT_EXPRSP_CHKSM_7_TO_0(x) \ + (((x) & BIT_MASK_EXPRSP_CHKSM_7_TO_0) << BIT_SHIFT_EXPRSP_CHKSM_7_TO_0) +#define BIT_GET_EXPRSP_CHKSM_7_TO_0(x) \ + (((x) >> BIT_SHIFT_EXPRSP_CHKSM_7_TO_0) & BIT_MASK_EXPRSP_CHKSM_7_TO_0) + +#define BIT_SHIFT_EXPRSP_CHKSM_15_TO_8 0 +#define BIT_MASK_EXPRSP_CHKSM_15_TO_8 0xff +#define BIT_EXPRSP_CHKSM_15_TO_8(x) \ + (((x) & BIT_MASK_EXPRSP_CHKSM_15_TO_8) \ + << BIT_SHIFT_EXPRSP_CHKSM_15_TO_8) +#define BIT_GET_EXPRSP_CHKSM_15_TO_8(x) \ + (((x) >> BIT_SHIFT_EXPRSP_CHKSM_15_TO_8) & \ + BIT_MASK_EXPRSP_CHKSM_15_TO_8) + +/* 2 REG_BEAMFORMING_INFO_NSARP_V1 (Offset 0x0728) */ + +#define BIT_SHIFT_WMAC_ARPIP 0 +#define BIT_MASK_WMAC_ARPIP 0xffffffffL +#define BIT_WMAC_ARPIP(x) (((x) & BIT_MASK_WMAC_ARPIP) << BIT_SHIFT_WMAC_ARPIP) +#define BIT_GET_WMAC_ARPIP(x) \ + (((x) >> BIT_SHIFT_WMAC_ARPIP) & BIT_MASK_WMAC_ARPIP) + +/* 2 REG_BEAMFORMING_INFO_NSARP (Offset 0x072C) */ + +#define BIT_SHIFT_BEAMFORMING_INFO 0 +#define BIT_MASK_BEAMFORMING_INFO 0xffffffffL +#define BIT_BEAMFORMING_INFO(x) \ + (((x) & BIT_MASK_BEAMFORMING_INFO) << BIT_SHIFT_BEAMFORMING_INFO) +#define BIT_GET_BEAMFORMING_INFO(x) \ + (((x) >> BIT_SHIFT_BEAMFORMING_INFO) & BIT_MASK_BEAMFORMING_INFO) + +/* 2 REG_WMAC_RTX_CTX_SUBTYPE_CFG (Offset 0x0750) */ + +#define BIT_SHIFT_R_WMAC_CTX_SUBTYPE 4 +#define BIT_MASK_R_WMAC_CTX_SUBTYPE 0xf +#define BIT_R_WMAC_CTX_SUBTYPE(x) \ + (((x) & BIT_MASK_R_WMAC_CTX_SUBTYPE) << BIT_SHIFT_R_WMAC_CTX_SUBTYPE) +#define BIT_GET_R_WMAC_CTX_SUBTYPE(x) \ + (((x) >> BIT_SHIFT_R_WMAC_CTX_SUBTYPE) & BIT_MASK_R_WMAC_CTX_SUBTYPE) + +#define BIT_SHIFT_R_WMAC_RTX_SUBTYPE 0 +#define BIT_MASK_R_WMAC_RTX_SUBTYPE 0xf +#define BIT_R_WMAC_RTX_SUBTYPE(x) \ + (((x) & BIT_MASK_R_WMAC_RTX_SUBTYPE) << BIT_SHIFT_R_WMAC_RTX_SUBTYPE) +#define BIT_GET_R_WMAC_RTX_SUBTYPE(x) \ + (((x) >> BIT_SHIFT_R_WMAC_RTX_SUBTYPE) & BIT_MASK_R_WMAC_RTX_SUBTYPE) + +/* 2 REG_BT_COEX_V2 (Offset 0x0762) */ + +#define BIT_GNT_BT_POLARITY BIT(12) +#define BIT_GNT_BT_BYPASS_PRIORITY BIT(8) + +#define BIT_SHIFT_TIMER 0 +#define BIT_MASK_TIMER 0xff +#define BIT_TIMER(x) (((x) & BIT_MASK_TIMER) << BIT_SHIFT_TIMER) +#define BIT_GET_TIMER(x) (((x) >> BIT_SHIFT_TIMER) & BIT_MASK_TIMER) + +/* 2 REG_BT_COEX (Offset 0x0764) */ + +#define BIT_R_GNT_BT_RFC_SW BIT(12) +#define BIT_R_GNT_BT_RFC_SW_EN BIT(11) +#define BIT_R_GNT_BT_BB_SW BIT(10) +#define BIT_R_GNT_BT_BB_SW_EN BIT(9) +#define BIT_R_BT_CNT_THREN BIT(8) + +#define BIT_SHIFT_R_BT_CNT_THR 0 +#define BIT_MASK_R_BT_CNT_THR 0xff +#define BIT_R_BT_CNT_THR(x) \ + (((x) & BIT_MASK_R_BT_CNT_THR) << BIT_SHIFT_R_BT_CNT_THR) +#define BIT_GET_R_BT_CNT_THR(x) \ + (((x) >> BIT_SHIFT_R_BT_CNT_THR) & BIT_MASK_R_BT_CNT_THR) + +/* 2 REG_WLAN_ACT_MASK_CTRL (Offset 0x0768) */ + +#define BIT_WLRX_TER_BY_CTL BIT(43) +#define BIT_WLRX_TER_BY_AD BIT(42) +#define BIT_ANT_DIVERSITY_SEL BIT(41) +#define BIT_ANTSEL_FOR_BT_CTRL_EN BIT(40) +#define BIT_WLACT_LOW_GNTWL_EN BIT(34) +#define BIT_WLACT_HIGH_GNTBT_EN BIT(33) + +/* 2 REG_WLAN_ACT_MASK_CTRL (Offset 0x0768) */ + +#define BIT_NAV_UPPER_V1 BIT(32) + +/* 2 REG_WLAN_ACT_MASK_CTRL (Offset 0x0768) */ + +#define BIT_SHIFT_RXMYRTS_NAV_V1 8 +#define BIT_MASK_RXMYRTS_NAV_V1 0xff +#define BIT_RXMYRTS_NAV_V1(x) \ + (((x) & BIT_MASK_RXMYRTS_NAV_V1) << BIT_SHIFT_RXMYRTS_NAV_V1) +#define BIT_GET_RXMYRTS_NAV_V1(x) \ + (((x) >> BIT_SHIFT_RXMYRTS_NAV_V1) & BIT_MASK_RXMYRTS_NAV_V1) + +#define BIT_SHIFT_RTSRST_V1 0 +#define BIT_MASK_RTSRST_V1 0xff +#define BIT_RTSRST_V1(x) (((x) & BIT_MASK_RTSRST_V1) << BIT_SHIFT_RTSRST_V1) +#define BIT_GET_RTSRST_V1(x) (((x) >> BIT_SHIFT_RTSRST_V1) & BIT_MASK_RTSRST_V1) + +/* 2 REG_BT_COEX_ENHANCED_INTR_CTRL (Offset 0x076E) */ + +#define BIT_SHIFT_BT_STAT_DELAY 12 +#define BIT_MASK_BT_STAT_DELAY 0xf +#define BIT_BT_STAT_DELAY(x) \ + (((x) & BIT_MASK_BT_STAT_DELAY) << BIT_SHIFT_BT_STAT_DELAY) +#define BIT_GET_BT_STAT_DELAY(x) \ + (((x) >> BIT_SHIFT_BT_STAT_DELAY) & BIT_MASK_BT_STAT_DELAY) + +#define BIT_SHIFT_BT_TRX_INIT_DETECT 8 +#define BIT_MASK_BT_TRX_INIT_DETECT 0xf +#define BIT_BT_TRX_INIT_DETECT(x) \ + (((x) & BIT_MASK_BT_TRX_INIT_DETECT) << BIT_SHIFT_BT_TRX_INIT_DETECT) +#define BIT_GET_BT_TRX_INIT_DETECT(x) \ + (((x) >> BIT_SHIFT_BT_TRX_INIT_DETECT) & BIT_MASK_BT_TRX_INIT_DETECT) + +#define BIT_SHIFT_BT_PRI_DETECT_TO 4 +#define BIT_MASK_BT_PRI_DETECT_TO 0xf +#define BIT_BT_PRI_DETECT_TO(x) \ + (((x) & BIT_MASK_BT_PRI_DETECT_TO) << BIT_SHIFT_BT_PRI_DETECT_TO) +#define BIT_GET_BT_PRI_DETECT_TO(x) \ + (((x) >> BIT_SHIFT_BT_PRI_DETECT_TO) & BIT_MASK_BT_PRI_DETECT_TO) + +#define BIT_R_GRANTALL_WLMASK BIT(3) +#define BIT_STATIS_BT_EN BIT(2) +#define BIT_WL_ACT_MASK_ENABLE BIT(1) +#define BIT_ENHANCED_BT BIT(0) + +/* 2 REG_BT_ACT_STATISTICS (Offset 0x0770) */ + +#define BIT_SHIFT_STATIS_BT_LO_RX (48 & CPU_OPT_WIDTH) +#define BIT_MASK_STATIS_BT_LO_RX 0xffff +#define BIT_STATIS_BT_LO_RX(x) \ + (((x) & BIT_MASK_STATIS_BT_LO_RX) << BIT_SHIFT_STATIS_BT_LO_RX) +#define BIT_GET_STATIS_BT_LO_RX(x) \ + (((x) >> BIT_SHIFT_STATIS_BT_LO_RX) & BIT_MASK_STATIS_BT_LO_RX) + +#define BIT_SHIFT_STATIS_BT_LO_TX (32 & CPU_OPT_WIDTH) +#define BIT_MASK_STATIS_BT_LO_TX 0xffff +#define BIT_STATIS_BT_LO_TX(x) \ + (((x) & BIT_MASK_STATIS_BT_LO_TX) << BIT_SHIFT_STATIS_BT_LO_TX) +#define BIT_GET_STATIS_BT_LO_TX(x) \ + (((x) >> BIT_SHIFT_STATIS_BT_LO_TX) & BIT_MASK_STATIS_BT_LO_TX) + +/* 2 REG_BT_ACT_STATISTICS (Offset 0x0770) */ + +#define BIT_SHIFT_STATIS_BT_HI_RX 16 +#define BIT_MASK_STATIS_BT_HI_RX 0xffff +#define BIT_STATIS_BT_HI_RX(x) \ + (((x) & BIT_MASK_STATIS_BT_HI_RX) << BIT_SHIFT_STATIS_BT_HI_RX) +#define BIT_GET_STATIS_BT_HI_RX(x) \ + (((x) >> BIT_SHIFT_STATIS_BT_HI_RX) & BIT_MASK_STATIS_BT_HI_RX) + +#define BIT_SHIFT_STATIS_BT_HI_TX 0 +#define BIT_MASK_STATIS_BT_HI_TX 0xffff +#define BIT_STATIS_BT_HI_TX(x) \ + (((x) & BIT_MASK_STATIS_BT_HI_TX) << BIT_SHIFT_STATIS_BT_HI_TX) +#define BIT_GET_STATIS_BT_HI_TX(x) \ + (((x) >> BIT_SHIFT_STATIS_BT_HI_TX) & BIT_MASK_STATIS_BT_HI_TX) + +/* 2 REG_BT_STATISTICS_CONTROL_REGISTER (Offset 0x0778) */ + +#define BIT_SHIFT_R_BT_CMD_RPT 16 +#define BIT_MASK_R_BT_CMD_RPT 0xffff +#define BIT_R_BT_CMD_RPT(x) \ + (((x) & BIT_MASK_R_BT_CMD_RPT) << BIT_SHIFT_R_BT_CMD_RPT) +#define BIT_GET_R_BT_CMD_RPT(x) \ + (((x) >> BIT_SHIFT_R_BT_CMD_RPT) & BIT_MASK_R_BT_CMD_RPT) + +#define BIT_SHIFT_R_RPT_FROM_BT 8 +#define BIT_MASK_R_RPT_FROM_BT 0xff +#define BIT_R_RPT_FROM_BT(x) \ + (((x) & BIT_MASK_R_RPT_FROM_BT) << BIT_SHIFT_R_RPT_FROM_BT) +#define BIT_GET_R_RPT_FROM_BT(x) \ + (((x) >> BIT_SHIFT_R_RPT_FROM_BT) & BIT_MASK_R_RPT_FROM_BT) + +#define BIT_SHIFT_BT_HID_ISR_SET 6 +#define BIT_MASK_BT_HID_ISR_SET 0x3 +#define BIT_BT_HID_ISR_SET(x) \ + (((x) & BIT_MASK_BT_HID_ISR_SET) << BIT_SHIFT_BT_HID_ISR_SET) +#define BIT_GET_BT_HID_ISR_SET(x) \ + (((x) >> BIT_SHIFT_BT_HID_ISR_SET) & BIT_MASK_BT_HID_ISR_SET) + +#define BIT_TDMA_BT_START_NOTIFY BIT(5) +#define BIT_ENABLE_TDMA_FW_MODE BIT(4) +#define BIT_ENABLE_PTA_TDMA_MODE BIT(3) +#define BIT_ENABLE_COEXIST_TAB_IN_TDMA BIT(2) +#define BIT_GPIO2_GPIO3_EXANGE_OR_NO_BT_CCA BIT(1) +#define BIT_RTK_BT_ENABLE BIT(0) + +/* 2 REG_BT_STATUS_REPORT_REGISTER (Offset 0x077C) */ + +#define BIT_SHIFT_BT_PROFILE 24 +#define BIT_MASK_BT_PROFILE 0xff +#define BIT_BT_PROFILE(x) (((x) & BIT_MASK_BT_PROFILE) << BIT_SHIFT_BT_PROFILE) +#define BIT_GET_BT_PROFILE(x) \ + (((x) >> BIT_SHIFT_BT_PROFILE) & BIT_MASK_BT_PROFILE) + +#define BIT_SHIFT_BT_POWER 16 +#define BIT_MASK_BT_POWER 0xff +#define BIT_BT_POWER(x) (((x) & BIT_MASK_BT_POWER) << BIT_SHIFT_BT_POWER) +#define BIT_GET_BT_POWER(x) (((x) >> BIT_SHIFT_BT_POWER) & BIT_MASK_BT_POWER) + +#define BIT_SHIFT_BT_PREDECT_STATUS 8 +#define BIT_MASK_BT_PREDECT_STATUS 0xff +#define BIT_BT_PREDECT_STATUS(x) \ + (((x) & BIT_MASK_BT_PREDECT_STATUS) << BIT_SHIFT_BT_PREDECT_STATUS) +#define BIT_GET_BT_PREDECT_STATUS(x) \ + (((x) >> BIT_SHIFT_BT_PREDECT_STATUS) & BIT_MASK_BT_PREDECT_STATUS) + +#define BIT_SHIFT_BT_CMD_INFO 0 +#define BIT_MASK_BT_CMD_INFO 0xff +#define BIT_BT_CMD_INFO(x) \ + (((x) & BIT_MASK_BT_CMD_INFO) << BIT_SHIFT_BT_CMD_INFO) +#define BIT_GET_BT_CMD_INFO(x) \ + (((x) >> BIT_SHIFT_BT_CMD_INFO) & BIT_MASK_BT_CMD_INFO) + +/* 2 REG_BT_INTERRUPT_CONTROL_REGISTER (Offset 0x0780) */ + +#define BIT_EN_MAC_NULL_PKT_NOTIFY BIT(31) +#define BIT_EN_WLAN_RPT_AND_BT_QUERY BIT(30) +#define BIT_EN_BT_STSTUS_RPT BIT(29) +#define BIT_EN_BT_POWER BIT(28) +#define BIT_EN_BT_CHANNEL BIT(27) +#define BIT_EN_BT_SLOT_CHANGE BIT(26) +#define BIT_EN_BT_PROFILE_OR_HID BIT(25) +#define BIT_WLAN_RPT_NOTIFY BIT(24) + +#define BIT_SHIFT_WLAN_RPT_DATA 16 +#define BIT_MASK_WLAN_RPT_DATA 0xff +#define BIT_WLAN_RPT_DATA(x) \ + (((x) & BIT_MASK_WLAN_RPT_DATA) << BIT_SHIFT_WLAN_RPT_DATA) +#define BIT_GET_WLAN_RPT_DATA(x) \ + (((x) >> BIT_SHIFT_WLAN_RPT_DATA) & BIT_MASK_WLAN_RPT_DATA) + +#define BIT_SHIFT_CMD_ID 8 +#define BIT_MASK_CMD_ID 0xff +#define BIT_CMD_ID(x) (((x) & BIT_MASK_CMD_ID) << BIT_SHIFT_CMD_ID) +#define BIT_GET_CMD_ID(x) (((x) >> BIT_SHIFT_CMD_ID) & BIT_MASK_CMD_ID) + +#define BIT_SHIFT_BT_DATA 0 +#define BIT_MASK_BT_DATA 0xff +#define BIT_BT_DATA(x) (((x) & BIT_MASK_BT_DATA) << BIT_SHIFT_BT_DATA) +#define BIT_GET_BT_DATA(x) (((x) >> BIT_SHIFT_BT_DATA) & BIT_MASK_BT_DATA) + +/* 2 REG_WLAN_REPORT_TIME_OUT_CONTROL_REGISTER (Offset 0x0784) */ + +#define BIT_SHIFT_WLAN_RPT_TO 0 +#define BIT_MASK_WLAN_RPT_TO 0xff +#define BIT_WLAN_RPT_TO(x) \ + (((x) & BIT_MASK_WLAN_RPT_TO) << BIT_SHIFT_WLAN_RPT_TO) +#define BIT_GET_WLAN_RPT_TO(x) \ + (((x) >> BIT_SHIFT_WLAN_RPT_TO) & BIT_MASK_WLAN_RPT_TO) + +/* 2 REG_BT_ISOLATION_TABLE_REGISTER_REGISTER (Offset 0x0785) */ + +#define BIT_SHIFT_ISOLATION_CHK 1 +#define BIT_MASK_ISOLATION_CHK 0x7fffffffffffffffffffL +#define BIT_ISOLATION_CHK(x) \ + (((x) & BIT_MASK_ISOLATION_CHK) << BIT_SHIFT_ISOLATION_CHK) +#define BIT_GET_ISOLATION_CHK(x) \ + (((x) >> BIT_SHIFT_ISOLATION_CHK) & BIT_MASK_ISOLATION_CHK) + +/* 2 REG_BT_ISOLATION_TABLE_REGISTER_REGISTER (Offset 0x0785) */ + +#define BIT_ISOLATION_EN BIT(0) + +/* 2 REG_BT_INTERRUPT_STATUS_REGISTER (Offset 0x078F) */ + +#define BIT_BT_HID_ISR BIT(7) +#define BIT_BT_QUERY_ISR BIT(6) +#define BIT_MAC_NULL_PKT_NOTIFY_ISR BIT(5) +#define BIT_WLAN_RPT_ISR BIT(4) +#define BIT_BT_POWER_ISR BIT(3) +#define BIT_BT_CHANNEL_ISR BIT(2) +#define BIT_BT_SLOT_CHANGE_ISR BIT(1) +#define BIT_BT_PROFILE_ISR BIT(0) + +/* 2 REG_BT_TDMA_TIME_REGISTER (Offset 0x0790) */ + +#define BIT_SHIFT_BT_TIME 6 +#define BIT_MASK_BT_TIME 0x3ffffff +#define BIT_BT_TIME(x) (((x) & BIT_MASK_BT_TIME) << BIT_SHIFT_BT_TIME) +#define BIT_GET_BT_TIME(x) (((x) >> BIT_SHIFT_BT_TIME) & BIT_MASK_BT_TIME) + +#define BIT_SHIFT_BT_RPT_SAMPLE_RATE 0 +#define BIT_MASK_BT_RPT_SAMPLE_RATE 0x3f +#define BIT_BT_RPT_SAMPLE_RATE(x) \ + (((x) & BIT_MASK_BT_RPT_SAMPLE_RATE) << BIT_SHIFT_BT_RPT_SAMPLE_RATE) +#define BIT_GET_BT_RPT_SAMPLE_RATE(x) \ + (((x) >> BIT_SHIFT_BT_RPT_SAMPLE_RATE) & BIT_MASK_BT_RPT_SAMPLE_RATE) + +/* 2 REG_BT_ACT_REGISTER (Offset 0x0794) */ + +#define BIT_SHIFT_BT_EISR_EN 16 +#define BIT_MASK_BT_EISR_EN 0xff +#define BIT_BT_EISR_EN(x) (((x) & BIT_MASK_BT_EISR_EN) << BIT_SHIFT_BT_EISR_EN) +#define BIT_GET_BT_EISR_EN(x) \ + (((x) >> BIT_SHIFT_BT_EISR_EN) & BIT_MASK_BT_EISR_EN) + +#define BIT_BT_ACT_FALLING_ISR BIT(10) +#define BIT_BT_ACT_RISING_ISR BIT(9) +#define BIT_TDMA_TO_ISR BIT(8) + +#define BIT_SHIFT_BT_CH 0 +#define BIT_MASK_BT_CH 0xff +#define BIT_BT_CH(x) (((x) & BIT_MASK_BT_CH) << BIT_SHIFT_BT_CH) +#define BIT_GET_BT_CH(x) (((x) >> BIT_SHIFT_BT_CH) & BIT_MASK_BT_CH) + +/* 2 REG_OBFF_CTRL_BASIC (Offset 0x0798) */ + +#define BIT_OBFF_EN_V1 BIT(31) + +#define BIT_SHIFT_OBFF_STATE_V1 28 +#define BIT_MASK_OBFF_STATE_V1 0x3 +#define BIT_OBFF_STATE_V1(x) \ + (((x) & BIT_MASK_OBFF_STATE_V1) << BIT_SHIFT_OBFF_STATE_V1) +#define BIT_GET_OBFF_STATE_V1(x) \ + (((x) >> BIT_SHIFT_OBFF_STATE_V1) & BIT_MASK_OBFF_STATE_V1) + +#define BIT_OBFF_ACT_RXDMA_EN BIT(27) +#define BIT_OBFF_BLOCK_INT_EN BIT(26) +#define BIT_OBFF_AUTOACT_EN BIT(25) +#define BIT_OBFF_AUTOIDLE_EN BIT(24) + +#define BIT_SHIFT_WAKE_MAX_PLS 20 +#define BIT_MASK_WAKE_MAX_PLS 0x7 +#define BIT_WAKE_MAX_PLS(x) \ + (((x) & BIT_MASK_WAKE_MAX_PLS) << BIT_SHIFT_WAKE_MAX_PLS) +#define BIT_GET_WAKE_MAX_PLS(x) \ + (((x) >> BIT_SHIFT_WAKE_MAX_PLS) & BIT_MASK_WAKE_MAX_PLS) + +#define BIT_SHIFT_WAKE_MIN_PLS 16 +#define BIT_MASK_WAKE_MIN_PLS 0x7 +#define BIT_WAKE_MIN_PLS(x) \ + (((x) & BIT_MASK_WAKE_MIN_PLS) << BIT_SHIFT_WAKE_MIN_PLS) +#define BIT_GET_WAKE_MIN_PLS(x) \ + (((x) >> BIT_SHIFT_WAKE_MIN_PLS) & BIT_MASK_WAKE_MIN_PLS) + +#define BIT_SHIFT_WAKE_MAX_F2F 12 +#define BIT_MASK_WAKE_MAX_F2F 0x7 +#define BIT_WAKE_MAX_F2F(x) \ + (((x) & BIT_MASK_WAKE_MAX_F2F) << BIT_SHIFT_WAKE_MAX_F2F) +#define BIT_GET_WAKE_MAX_F2F(x) \ + (((x) >> BIT_SHIFT_WAKE_MAX_F2F) & BIT_MASK_WAKE_MAX_F2F) + +#define BIT_SHIFT_WAKE_MIN_F2F 8 +#define BIT_MASK_WAKE_MIN_F2F 0x7 +#define BIT_WAKE_MIN_F2F(x) \ + (((x) & BIT_MASK_WAKE_MIN_F2F) << BIT_SHIFT_WAKE_MIN_F2F) +#define BIT_GET_WAKE_MIN_F2F(x) \ + (((x) >> BIT_SHIFT_WAKE_MIN_F2F) & BIT_MASK_WAKE_MIN_F2F) + +#define BIT_APP_CPU_ACT_V1 BIT(3) +#define BIT_APP_OBFF_V1 BIT(2) +#define BIT_APP_IDLE_V1 BIT(1) +#define BIT_APP_INIT_V1 BIT(0) + +/* 2 REG_OBFF_CTRL2_TIMER (Offset 0x079C) */ + +#define BIT_SHIFT_RX_HIGH_TIMER_IDX 24 +#define BIT_MASK_RX_HIGH_TIMER_IDX 0x7 +#define BIT_RX_HIGH_TIMER_IDX(x) \ + (((x) & BIT_MASK_RX_HIGH_TIMER_IDX) << BIT_SHIFT_RX_HIGH_TIMER_IDX) +#define BIT_GET_RX_HIGH_TIMER_IDX(x) \ + (((x) >> BIT_SHIFT_RX_HIGH_TIMER_IDX) & BIT_MASK_RX_HIGH_TIMER_IDX) + +#define BIT_SHIFT_RX_MED_TIMER_IDX 16 +#define BIT_MASK_RX_MED_TIMER_IDX 0x7 +#define BIT_RX_MED_TIMER_IDX(x) \ + (((x) & BIT_MASK_RX_MED_TIMER_IDX) << BIT_SHIFT_RX_MED_TIMER_IDX) +#define BIT_GET_RX_MED_TIMER_IDX(x) \ + (((x) >> BIT_SHIFT_RX_MED_TIMER_IDX) & BIT_MASK_RX_MED_TIMER_IDX) + +#define BIT_SHIFT_RX_LOW_TIMER_IDX 8 +#define BIT_MASK_RX_LOW_TIMER_IDX 0x7 +#define BIT_RX_LOW_TIMER_IDX(x) \ + (((x) & BIT_MASK_RX_LOW_TIMER_IDX) << BIT_SHIFT_RX_LOW_TIMER_IDX) +#define BIT_GET_RX_LOW_TIMER_IDX(x) \ + (((x) >> BIT_SHIFT_RX_LOW_TIMER_IDX) & BIT_MASK_RX_LOW_TIMER_IDX) + +#define BIT_SHIFT_OBFF_INT_TIMER_IDX 0 +#define BIT_MASK_OBFF_INT_TIMER_IDX 0x7 +#define BIT_OBFF_INT_TIMER_IDX(x) \ + (((x) & BIT_MASK_OBFF_INT_TIMER_IDX) << BIT_SHIFT_OBFF_INT_TIMER_IDX) +#define BIT_GET_OBFF_INT_TIMER_IDX(x) \ + (((x) >> BIT_SHIFT_OBFF_INT_TIMER_IDX) & BIT_MASK_OBFF_INT_TIMER_IDX) + +/* 2 REG_LTR_CTRL_BASIC (Offset 0x07A0) */ + +#define BIT_LTR_EN_V1 BIT(31) +#define BIT_LTR_HW_EN_V1 BIT(30) +#define BIT_LRT_ACT_CTS_EN BIT(29) +#define BIT_LTR_ACT_RXPKT_EN BIT(28) +#define BIT_LTR_ACT_RXDMA_EN BIT(27) +#define BIT_LTR_IDLE_NO_SNOOP BIT(26) +#define BIT_SPDUP_MGTPKT BIT(25) +#define BIT_RX_AGG_EN BIT(24) +#define BIT_APP_LTR_ACT BIT(23) +#define BIT_APP_LTR_IDLE BIT(22) + +#define BIT_SHIFT_HIGH_RATE_TRIG_SEL 20 +#define BIT_MASK_HIGH_RATE_TRIG_SEL 0x3 +#define BIT_HIGH_RATE_TRIG_SEL(x) \ + (((x) & BIT_MASK_HIGH_RATE_TRIG_SEL) << BIT_SHIFT_HIGH_RATE_TRIG_SEL) +#define BIT_GET_HIGH_RATE_TRIG_SEL(x) \ + (((x) >> BIT_SHIFT_HIGH_RATE_TRIG_SEL) & BIT_MASK_HIGH_RATE_TRIG_SEL) + +#define BIT_SHIFT_MED_RATE_TRIG_SEL 18 +#define BIT_MASK_MED_RATE_TRIG_SEL 0x3 +#define BIT_MED_RATE_TRIG_SEL(x) \ + (((x) & BIT_MASK_MED_RATE_TRIG_SEL) << BIT_SHIFT_MED_RATE_TRIG_SEL) +#define BIT_GET_MED_RATE_TRIG_SEL(x) \ + (((x) >> BIT_SHIFT_MED_RATE_TRIG_SEL) & BIT_MASK_MED_RATE_TRIG_SEL) + +#define BIT_SHIFT_LOW_RATE_TRIG_SEL 16 +#define BIT_MASK_LOW_RATE_TRIG_SEL 0x3 +#define BIT_LOW_RATE_TRIG_SEL(x) \ + (((x) & BIT_MASK_LOW_RATE_TRIG_SEL) << BIT_SHIFT_LOW_RATE_TRIG_SEL) +#define BIT_GET_LOW_RATE_TRIG_SEL(x) \ + (((x) >> BIT_SHIFT_LOW_RATE_TRIG_SEL) & BIT_MASK_LOW_RATE_TRIG_SEL) + +#define BIT_SHIFT_HIGH_RATE_BD_IDX 8 +#define BIT_MASK_HIGH_RATE_BD_IDX 0x7f +#define BIT_HIGH_RATE_BD_IDX(x) \ + (((x) & BIT_MASK_HIGH_RATE_BD_IDX) << BIT_SHIFT_HIGH_RATE_BD_IDX) +#define BIT_GET_HIGH_RATE_BD_IDX(x) \ + (((x) >> BIT_SHIFT_HIGH_RATE_BD_IDX) & BIT_MASK_HIGH_RATE_BD_IDX) + +#define BIT_SHIFT_LOW_RATE_BD_IDX 0 +#define BIT_MASK_LOW_RATE_BD_IDX 0x7f +#define BIT_LOW_RATE_BD_IDX(x) \ + (((x) & BIT_MASK_LOW_RATE_BD_IDX) << BIT_SHIFT_LOW_RATE_BD_IDX) +#define BIT_GET_LOW_RATE_BD_IDX(x) \ + (((x) >> BIT_SHIFT_LOW_RATE_BD_IDX) & BIT_MASK_LOW_RATE_BD_IDX) + +/* 2 REG_LTR_CTRL2_TIMER_THRESHOLD (Offset 0x07A4) */ + +#define BIT_SHIFT_RX_EMPTY_TIMER_IDX 24 +#define BIT_MASK_RX_EMPTY_TIMER_IDX 0x7 +#define BIT_RX_EMPTY_TIMER_IDX(x) \ + (((x) & BIT_MASK_RX_EMPTY_TIMER_IDX) << BIT_SHIFT_RX_EMPTY_TIMER_IDX) +#define BIT_GET_RX_EMPTY_TIMER_IDX(x) \ + (((x) >> BIT_SHIFT_RX_EMPTY_TIMER_IDX) & BIT_MASK_RX_EMPTY_TIMER_IDX) + +#define BIT_SHIFT_RX_AFULL_TH_IDX 20 +#define BIT_MASK_RX_AFULL_TH_IDX 0x7 +#define BIT_RX_AFULL_TH_IDX(x) \ + (((x) & BIT_MASK_RX_AFULL_TH_IDX) << BIT_SHIFT_RX_AFULL_TH_IDX) +#define BIT_GET_RX_AFULL_TH_IDX(x) \ + (((x) >> BIT_SHIFT_RX_AFULL_TH_IDX) & BIT_MASK_RX_AFULL_TH_IDX) + +#define BIT_SHIFT_RX_HIGH_TH_IDX 16 +#define BIT_MASK_RX_HIGH_TH_IDX 0x7 +#define BIT_RX_HIGH_TH_IDX(x) \ + (((x) & BIT_MASK_RX_HIGH_TH_IDX) << BIT_SHIFT_RX_HIGH_TH_IDX) +#define BIT_GET_RX_HIGH_TH_IDX(x) \ + (((x) >> BIT_SHIFT_RX_HIGH_TH_IDX) & BIT_MASK_RX_HIGH_TH_IDX) + +#define BIT_SHIFT_RX_MED_TH_IDX 12 +#define BIT_MASK_RX_MED_TH_IDX 0x7 +#define BIT_RX_MED_TH_IDX(x) \ + (((x) & BIT_MASK_RX_MED_TH_IDX) << BIT_SHIFT_RX_MED_TH_IDX) +#define BIT_GET_RX_MED_TH_IDX(x) \ + (((x) >> BIT_SHIFT_RX_MED_TH_IDX) & BIT_MASK_RX_MED_TH_IDX) + +#define BIT_SHIFT_RX_LOW_TH_IDX 8 +#define BIT_MASK_RX_LOW_TH_IDX 0x7 +#define BIT_RX_LOW_TH_IDX(x) \ + (((x) & BIT_MASK_RX_LOW_TH_IDX) << BIT_SHIFT_RX_LOW_TH_IDX) +#define BIT_GET_RX_LOW_TH_IDX(x) \ + (((x) >> BIT_SHIFT_RX_LOW_TH_IDX) & BIT_MASK_RX_LOW_TH_IDX) + +#define BIT_SHIFT_LTR_SPACE_IDX 4 +#define BIT_MASK_LTR_SPACE_IDX 0x3 +#define BIT_LTR_SPACE_IDX(x) \ + (((x) & BIT_MASK_LTR_SPACE_IDX) << BIT_SHIFT_LTR_SPACE_IDX) +#define BIT_GET_LTR_SPACE_IDX(x) \ + (((x) >> BIT_SHIFT_LTR_SPACE_IDX) & BIT_MASK_LTR_SPACE_IDX) + +#define BIT_SHIFT_LTR_IDLE_TIMER_IDX 0 +#define BIT_MASK_LTR_IDLE_TIMER_IDX 0x7 +#define BIT_LTR_IDLE_TIMER_IDX(x) \ + (((x) & BIT_MASK_LTR_IDLE_TIMER_IDX) << BIT_SHIFT_LTR_IDLE_TIMER_IDX) +#define BIT_GET_LTR_IDLE_TIMER_IDX(x) \ + (((x) >> BIT_SHIFT_LTR_IDLE_TIMER_IDX) & BIT_MASK_LTR_IDLE_TIMER_IDX) + +/* 2 REG_LTR_IDLE_LATENCY_V1 (Offset 0x07A8) */ + +#define BIT_SHIFT_LTR_IDLE_L 0 +#define BIT_MASK_LTR_IDLE_L 0xffffffffL +#define BIT_LTR_IDLE_L(x) (((x) & BIT_MASK_LTR_IDLE_L) << BIT_SHIFT_LTR_IDLE_L) +#define BIT_GET_LTR_IDLE_L(x) \ + (((x) >> BIT_SHIFT_LTR_IDLE_L) & BIT_MASK_LTR_IDLE_L) + +/* 2 REG_LTR_ACTIVE_LATENCY_V1 (Offset 0x07AC) */ + +#define BIT_SHIFT_LTR_ACT_L 0 +#define BIT_MASK_LTR_ACT_L 0xffffffffL +#define BIT_LTR_ACT_L(x) (((x) & BIT_MASK_LTR_ACT_L) << BIT_SHIFT_LTR_ACT_L) +#define BIT_GET_LTR_ACT_L(x) (((x) >> BIT_SHIFT_LTR_ACT_L) & BIT_MASK_LTR_ACT_L) + +/* 2 REG_ANTENNA_TRAINING_CONTROL_REGISTER (Offset 0x07B0) */ + +#define BIT_APPEND_MACID_IN_RESP_EN BIT(50) +#define BIT_ADDR2_MATCH_EN BIT(49) +#define BIT_ANTTRN_EN BIT(48) + +#define BIT_SHIFT_TRAIN_STA_ADDR 0 +#define BIT_MASK_TRAIN_STA_ADDR 0xffffffffffffL +#define BIT_TRAIN_STA_ADDR(x) \ + (((x) & BIT_MASK_TRAIN_STA_ADDR) << BIT_SHIFT_TRAIN_STA_ADDR) +#define BIT_GET_TRAIN_STA_ADDR(x) \ + (((x) >> BIT_SHIFT_TRAIN_STA_ADDR) & BIT_MASK_TRAIN_STA_ADDR) + +/* 2 REG_WMAC_PKTCNT_RWD (Offset 0x07B8) */ + +#define BIT_SHIFT_PKTCNT_BSSIDMAP 4 +#define BIT_MASK_PKTCNT_BSSIDMAP 0xf +#define BIT_PKTCNT_BSSIDMAP(x) \ + (((x) & BIT_MASK_PKTCNT_BSSIDMAP) << BIT_SHIFT_PKTCNT_BSSIDMAP) +#define BIT_GET_PKTCNT_BSSIDMAP(x) \ + (((x) >> BIT_SHIFT_PKTCNT_BSSIDMAP) & BIT_MASK_PKTCNT_BSSIDMAP) + +#define BIT_PKTCNT_CNTRST BIT(1) +#define BIT_PKTCNT_CNTEN BIT(0) + +/* 2 REG_WMAC_PKTCNT_CTRL (Offset 0x07BC) */ + +#define BIT_WMAC_PKTCNT_TRST BIT(9) +#define BIT_WMAC_PKTCNT_FEN BIT(8) + +#define BIT_SHIFT_WMAC_PKTCNT_CFGAD 0 +#define BIT_MASK_WMAC_PKTCNT_CFGAD 0xff +#define BIT_WMAC_PKTCNT_CFGAD(x) \ + (((x) & BIT_MASK_WMAC_PKTCNT_CFGAD) << BIT_SHIFT_WMAC_PKTCNT_CFGAD) +#define BIT_GET_WMAC_PKTCNT_CFGAD(x) \ + (((x) >> BIT_SHIFT_WMAC_PKTCNT_CFGAD) & BIT_MASK_WMAC_PKTCNT_CFGAD) + +/* 2 REG_IQ_DUMP (Offset 0x07C0) */ + +#define BIT_SHIFT_R_WMAC_MATCH_REF_MAC (64 & CPU_OPT_WIDTH) +#define BIT_MASK_R_WMAC_MATCH_REF_MAC 0xffffffffL +#define BIT_R_WMAC_MATCH_REF_MAC(x) \ + (((x) & BIT_MASK_R_WMAC_MATCH_REF_MAC) \ + << BIT_SHIFT_R_WMAC_MATCH_REF_MAC) +#define BIT_GET_R_WMAC_MATCH_REF_MAC(x) \ + (((x) >> BIT_SHIFT_R_WMAC_MATCH_REF_MAC) & \ + BIT_MASK_R_WMAC_MATCH_REF_MAC) + +#define BIT_SHIFT_R_WMAC_RX_FIL_LEN (64 & CPU_OPT_WIDTH) +#define BIT_MASK_R_WMAC_RX_FIL_LEN 0xffff +#define BIT_R_WMAC_RX_FIL_LEN(x) \ + (((x) & BIT_MASK_R_WMAC_RX_FIL_LEN) << BIT_SHIFT_R_WMAC_RX_FIL_LEN) +#define BIT_GET_R_WMAC_RX_FIL_LEN(x) \ + (((x) >> BIT_SHIFT_R_WMAC_RX_FIL_LEN) & BIT_MASK_R_WMAC_RX_FIL_LEN) + +#define BIT_SHIFT_R_WMAC_RXFIFO_FULL_TH (56 & CPU_OPT_WIDTH) +#define BIT_MASK_R_WMAC_RXFIFO_FULL_TH 0xff +#define BIT_R_WMAC_RXFIFO_FULL_TH(x) \ + (((x) & BIT_MASK_R_WMAC_RXFIFO_FULL_TH) \ + << BIT_SHIFT_R_WMAC_RXFIFO_FULL_TH) +#define BIT_GET_R_WMAC_RXFIFO_FULL_TH(x) \ + (((x) >> BIT_SHIFT_R_WMAC_RXFIFO_FULL_TH) & \ + BIT_MASK_R_WMAC_RXFIFO_FULL_TH) + +#define BIT_R_WMAC_SRCH_TXRPT_TYPE BIT(51) +#define BIT_R_WMAC_NDP_RST BIT(50) +#define BIT_R_WMAC_POWINT_EN BIT(49) +#define BIT_R_WMAC_SRCH_TXRPT_PERPKT BIT(48) +#define BIT_R_WMAC_SRCH_TXRPT_MID BIT(47) +#define BIT_R_WMAC_PFIN_TOEN BIT(46) +#define BIT_R_WMAC_FIL_SECERR BIT(45) +#define BIT_R_WMAC_FIL_CTLPKTLEN BIT(44) +#define BIT_R_WMAC_FIL_FCTYPE BIT(43) +#define BIT_R_WMAC_FIL_FCPROVER BIT(42) +#define BIT_R_WMAC_PHYSTS_SNIF BIT(41) +#define BIT_R_WMAC_PHYSTS_PLCP BIT(40) +#define BIT_R_MAC_TCR_VBONF_RD BIT(39) +#define BIT_R_WMAC_TCR_MPAR_NDP BIT(38) +#define BIT_R_WMAC_NDP_FILTER BIT(37) +#define BIT_R_WMAC_RXLEN_SEL BIT(36) +#define BIT_R_WMAC_RXLEN_SEL1 BIT(35) +#define BIT_R_OFDM_FILTER BIT(34) +#define BIT_R_WMAC_CHK_OFDM_LEN BIT(33) + +#define BIT_SHIFT_R_WMAC_MASK_LA_MAC (32 & CPU_OPT_WIDTH) +#define BIT_MASK_R_WMAC_MASK_LA_MAC 0xffffffffL +#define BIT_R_WMAC_MASK_LA_MAC(x) \ + (((x) & BIT_MASK_R_WMAC_MASK_LA_MAC) << BIT_SHIFT_R_WMAC_MASK_LA_MAC) +#define BIT_GET_R_WMAC_MASK_LA_MAC(x) \ + (((x) >> BIT_SHIFT_R_WMAC_MASK_LA_MAC) & BIT_MASK_R_WMAC_MASK_LA_MAC) + +#define BIT_R_WMAC_CHK_CCK_LEN BIT(32) + +/* 2 REG_IQ_DUMP (Offset 0x07C0) */ + +#define BIT_SHIFT_R_OFDM_LEN 26 +#define BIT_MASK_R_OFDM_LEN 0x3f +#define BIT_R_OFDM_LEN(x) (((x) & BIT_MASK_R_OFDM_LEN) << BIT_SHIFT_R_OFDM_LEN) +#define BIT_GET_R_OFDM_LEN(x) \ + (((x) >> BIT_SHIFT_R_OFDM_LEN) & BIT_MASK_R_OFDM_LEN) + +#define BIT_SHIFT_DUMP_OK_ADDR 15 +#define BIT_MASK_DUMP_OK_ADDR 0x1ffff +#define BIT_DUMP_OK_ADDR(x) \ + (((x) & BIT_MASK_DUMP_OK_ADDR) << BIT_SHIFT_DUMP_OK_ADDR) +#define BIT_GET_DUMP_OK_ADDR(x) \ + (((x) >> BIT_SHIFT_DUMP_OK_ADDR) & BIT_MASK_DUMP_OK_ADDR) + +#define BIT_SHIFT_R_TRIG_TIME_SEL 8 +#define BIT_MASK_R_TRIG_TIME_SEL 0x7f +#define BIT_R_TRIG_TIME_SEL(x) \ + (((x) & BIT_MASK_R_TRIG_TIME_SEL) << BIT_SHIFT_R_TRIG_TIME_SEL) +#define BIT_GET_R_TRIG_TIME_SEL(x) \ + (((x) >> BIT_SHIFT_R_TRIG_TIME_SEL) & BIT_MASK_R_TRIG_TIME_SEL) + +#define BIT_SHIFT_R_MAC_TRIG_SEL 6 +#define BIT_MASK_R_MAC_TRIG_SEL 0x3 +#define BIT_R_MAC_TRIG_SEL(x) \ + (((x) & BIT_MASK_R_MAC_TRIG_SEL) << BIT_SHIFT_R_MAC_TRIG_SEL) +#define BIT_GET_R_MAC_TRIG_SEL(x) \ + (((x) >> BIT_SHIFT_R_MAC_TRIG_SEL) & BIT_MASK_R_MAC_TRIG_SEL) + +#define BIT_MAC_TRIG_REG BIT(5) + +#define BIT_SHIFT_R_LEVEL_PULSE_SEL 3 +#define BIT_MASK_R_LEVEL_PULSE_SEL 0x3 +#define BIT_R_LEVEL_PULSE_SEL(x) \ + (((x) & BIT_MASK_R_LEVEL_PULSE_SEL) << BIT_SHIFT_R_LEVEL_PULSE_SEL) +#define BIT_GET_R_LEVEL_PULSE_SEL(x) \ + (((x) >> BIT_SHIFT_R_LEVEL_PULSE_SEL) & BIT_MASK_R_LEVEL_PULSE_SEL) + +#define BIT_EN_LA_MAC BIT(2) +#define BIT_R_EN_IQDUMP BIT(1) +#define BIT_R_IQDATA_DUMP BIT(0) + +#define BIT_SHIFT_R_CCK_LEN 0 +#define BIT_MASK_R_CCK_LEN 0xffff +#define BIT_R_CCK_LEN(x) (((x) & BIT_MASK_R_CCK_LEN) << BIT_SHIFT_R_CCK_LEN) +#define BIT_GET_R_CCK_LEN(x) (((x) >> BIT_SHIFT_R_CCK_LEN) & BIT_MASK_R_CCK_LEN) + +/* 2 REG_WMAC_FTM_CTL (Offset 0x07CC) */ + +#define BIT_RXFTM_TXACK_SC BIT(6) +#define BIT_RXFTM_TXACK_BW BIT(5) +#define BIT_RXFTM_EN BIT(3) +#define BIT_RXFTMREQ_BYDRV BIT(2) +#define BIT_RXFTMREQ_EN BIT(1) +#define BIT_FTM_EN BIT(0) + +/* 2 REG_RX_FILTER_FUNCTION (Offset 0x07DA) */ + +#define BIT_R_WMAC_MHRDDY_LATCH BIT(14) + +/* 2 REG_RX_FILTER_FUNCTION (Offset 0x07DA) */ + +#define BIT_R_WMAC_MHRDDY_CLR BIT(13) + +/* 2 REG_RX_FILTER_FUNCTION (Offset 0x07DA) */ + +#define BIT_R_RXPKTCTL_FSM_BASED_MPDURDY1 BIT(12) + +/* 2 REG_RX_FILTER_FUNCTION (Offset 0x07DA) */ + +#define BIT_WMAC_DIS_VHT_PLCP_CHK_MU BIT(11) + +/* 2 REG_RX_FILTER_FUNCTION (Offset 0x07DA) */ + +#define BIT_R_CHK_DELIMIT_LEN BIT(10) +#define BIT_R_REAPTER_ADDR_MATCH BIT(9) +#define BIT_R_RXPKTCTL_FSM_BASED_MPDURDY BIT(8) +#define BIT_R_LATCH_MACHRDY BIT(7) +#define BIT_R_WMAC_RXFIL_REND BIT(6) +#define BIT_R_WMAC_MPDURDY_CLR BIT(5) +#define BIT_R_WMAC_CLRRXSEC BIT(4) +#define BIT_R_WMAC_RXFIL_RDEL BIT(3) +#define BIT_R_WMAC_RXFIL_FCSE BIT(2) +#define BIT_R_WMAC_RXFIL_MESH_DEL BIT(1) +#define BIT_R_WMAC_RXFIL_MASKM BIT(0) + +/* 2 REG_NDP_SIG (Offset 0x07E0) */ + +#define BIT_SHIFT_R_WMAC_TXNDP_SIGB 0 +#define BIT_MASK_R_WMAC_TXNDP_SIGB 0x1fffff +#define BIT_R_WMAC_TXNDP_SIGB(x) \ + (((x) & BIT_MASK_R_WMAC_TXNDP_SIGB) << BIT_SHIFT_R_WMAC_TXNDP_SIGB) +#define BIT_GET_R_WMAC_TXNDP_SIGB(x) \ + (((x) >> BIT_SHIFT_R_WMAC_TXNDP_SIGB) & BIT_MASK_R_WMAC_TXNDP_SIGB) + +/* 2 REG_TXCMD_INFO_FOR_RSP_PKT (Offset 0x07E4) */ + +#define BIT_SHIFT_R_MAC_DEBUG (32 & CPU_OPT_WIDTH) +#define BIT_MASK_R_MAC_DEBUG 0xffffffffL +#define BIT_R_MAC_DEBUG(x) \ + (((x) & BIT_MASK_R_MAC_DEBUG) << BIT_SHIFT_R_MAC_DEBUG) +#define BIT_GET_R_MAC_DEBUG(x) \ + (((x) >> BIT_SHIFT_R_MAC_DEBUG) & BIT_MASK_R_MAC_DEBUG) + +/* 2 REG_TXCMD_INFO_FOR_RSP_PKT (Offset 0x07E4) */ + +#define BIT_SHIFT_R_MAC_DBG_SHIFT 8 +#define BIT_MASK_R_MAC_DBG_SHIFT 0x7 +#define BIT_R_MAC_DBG_SHIFT(x) \ + (((x) & BIT_MASK_R_MAC_DBG_SHIFT) << BIT_SHIFT_R_MAC_DBG_SHIFT) +#define BIT_GET_R_MAC_DBG_SHIFT(x) \ + (((x) >> BIT_SHIFT_R_MAC_DBG_SHIFT) & BIT_MASK_R_MAC_DBG_SHIFT) + +#define BIT_SHIFT_R_MAC_DBG_SEL 0 +#define BIT_MASK_R_MAC_DBG_SEL 0x3 +#define BIT_R_MAC_DBG_SEL(x) \ + (((x) & BIT_MASK_R_MAC_DBG_SEL) << BIT_SHIFT_R_MAC_DBG_SEL) +#define BIT_GET_R_MAC_DBG_SEL(x) \ + (((x) >> BIT_SHIFT_R_MAC_DBG_SEL) & BIT_MASK_R_MAC_DBG_SEL) + +/* 2 REG_SYS_CFG3 (Offset 0x1000) */ + +#define BIT_PWC_MA33V BIT(15) + +/* 2 REG_SYS_CFG3 (Offset 0x1000) */ + +#define BIT_PWC_MA12V BIT(14) +#define BIT_PWC_MD12V BIT(13) +#define BIT_PWC_PD12V BIT(12) +#define BIT_PWC_UD12V BIT(11) +#define BIT_ISO_MA2MD BIT(1) + +/* 2 REG_SYS_CFG5 (Offset 0x1070) */ + +#define BIT_LPS_STATUS BIT(3) +#define BIT_HCI_TXDMA_BUSY BIT(2) +#define BIT_HCI_TXDMA_ALLOW BIT(1) +#define BIT_FW_CTRL_HCI_TXDMA_EN BIT(0) + +/* 2 REG_CPU_DMEM_CON (Offset 0x1080) */ + +#define BIT_WDT_OPT_IOWRAPPER BIT(19) + +/* 2 REG_CPU_DMEM_CON (Offset 0x1080) */ + +#define BIT_ANA_PORT_IDLE BIT(18) +#define BIT_MAC_PORT_IDLE BIT(17) +#define BIT_WL_PLATFORM_RST BIT(16) +#define BIT_WL_SECURITY_CLK BIT(15) + +/* 2 REG_CPU_DMEM_CON (Offset 0x1080) */ + +#define BIT_SHIFT_CPU_DMEM_CON 0 +#define BIT_MASK_CPU_DMEM_CON 0xff +#define BIT_CPU_DMEM_CON(x) \ + (((x) & BIT_MASK_CPU_DMEM_CON) << BIT_SHIFT_CPU_DMEM_CON) +#define BIT_GET_CPU_DMEM_CON(x) \ + (((x) >> BIT_SHIFT_CPU_DMEM_CON) & BIT_MASK_CPU_DMEM_CON) + +/* 2 REG_BOOT_REASON (Offset 0x1088) */ + +#define BIT_SHIFT_BOOT_REASON 0 +#define BIT_MASK_BOOT_REASON 0x7 +#define BIT_BOOT_REASON(x) \ + (((x) & BIT_MASK_BOOT_REASON) << BIT_SHIFT_BOOT_REASON) +#define BIT_GET_BOOT_REASON(x) \ + (((x) >> BIT_SHIFT_BOOT_REASON) & BIT_MASK_BOOT_REASON) + +/* 2 REG_NFCPAD_CTRL (Offset 0x10A8) */ + +#define BIT_PAD_SHUTDW BIT(18) +#define BIT_SYSON_NFC_PAD BIT(17) +#define BIT_NFC_INT_PAD_CTRL BIT(16) +#define BIT_NFC_RFDIS_PAD_CTRL BIT(15) +#define BIT_NFC_CLK_PAD_CTRL BIT(14) +#define BIT_NFC_DATA_PAD_CTRL BIT(13) +#define BIT_NFC_PAD_PULL_CTRL BIT(12) + +#define BIT_SHIFT_NFCPAD_IO_SEL 8 +#define BIT_MASK_NFCPAD_IO_SEL 0xf +#define BIT_NFCPAD_IO_SEL(x) \ + (((x) & BIT_MASK_NFCPAD_IO_SEL) << BIT_SHIFT_NFCPAD_IO_SEL) +#define BIT_GET_NFCPAD_IO_SEL(x) \ + (((x) >> BIT_SHIFT_NFCPAD_IO_SEL) & BIT_MASK_NFCPAD_IO_SEL) + +#define BIT_SHIFT_NFCPAD_OUT 4 +#define BIT_MASK_NFCPAD_OUT 0xf +#define BIT_NFCPAD_OUT(x) (((x) & BIT_MASK_NFCPAD_OUT) << BIT_SHIFT_NFCPAD_OUT) +#define BIT_GET_NFCPAD_OUT(x) \ + (((x) >> BIT_SHIFT_NFCPAD_OUT) & BIT_MASK_NFCPAD_OUT) + +#define BIT_SHIFT_NFCPAD_IN 0 +#define BIT_MASK_NFCPAD_IN 0xf +#define BIT_NFCPAD_IN(x) (((x) & BIT_MASK_NFCPAD_IN) << BIT_SHIFT_NFCPAD_IN) +#define BIT_GET_NFCPAD_IN(x) (((x) >> BIT_SHIFT_NFCPAD_IN) & BIT_MASK_NFCPAD_IN) + +/* 2 REG_HIMR2 (Offset 0x10B0) */ + +#define BIT_BCNDMAINT_P4_MSK BIT(31) +#define BIT_BCNDMAINT_P3_MSK BIT(30) +#define BIT_BCNDMAINT_P2_MSK BIT(29) +#define BIT_BCNDMAINT_P1_MSK BIT(28) +#define BIT_ATIMEND7_MSK BIT(22) +#define BIT_ATIMEND6_MSK BIT(21) +#define BIT_ATIMEND5_MSK BIT(20) +#define BIT_ATIMEND4_MSK BIT(19) +#define BIT_ATIMEND3_MSK BIT(18) +#define BIT_ATIMEND2_MSK BIT(17) +#define BIT_ATIMEND1_MSK BIT(16) +#define BIT_TXBCN7OK_MSK BIT(14) +#define BIT_TXBCN6OK_MSK BIT(13) +#define BIT_TXBCN5OK_MSK BIT(12) +#define BIT_TXBCN4OK_MSK BIT(11) +#define BIT_TXBCN3OK_MSK BIT(10) +#define BIT_TXBCN2OK_MSK BIT(9) +#define BIT_TXBCN1OK_MSK_V1 BIT(8) +#define BIT_TXBCN7ERR_MSK BIT(6) +#define BIT_TXBCN6ERR_MSK BIT(5) +#define BIT_TXBCN5ERR_MSK BIT(4) +#define BIT_TXBCN4ERR_MSK BIT(3) +#define BIT_TXBCN3ERR_MSK BIT(2) +#define BIT_TXBCN2ERR_MSK BIT(1) +#define BIT_TXBCN1ERR_MSK_V1 BIT(0) + +/* 2 REG_HISR2 (Offset 0x10B4) */ + +#define BIT_BCNDMAINT_P4 BIT(31) +#define BIT_BCNDMAINT_P3 BIT(30) +#define BIT_BCNDMAINT_P2 BIT(29) +#define BIT_BCNDMAINT_P1 BIT(28) +#define BIT_ATIMEND7 BIT(22) +#define BIT_ATIMEND6 BIT(21) +#define BIT_ATIMEND5 BIT(20) +#define BIT_ATIMEND4 BIT(19) +#define BIT_ATIMEND3 BIT(18) +#define BIT_ATIMEND2 BIT(17) +#define BIT_ATIMEND1 BIT(16) +#define BIT_TXBCN7OK BIT(14) +#define BIT_TXBCN6OK BIT(13) +#define BIT_TXBCN5OK BIT(12) +#define BIT_TXBCN4OK BIT(11) +#define BIT_TXBCN3OK BIT(10) +#define BIT_TXBCN2OK BIT(9) +#define BIT_TXBCN1OK BIT(8) +#define BIT_TXBCN7ERR BIT(6) +#define BIT_TXBCN6ERR BIT(5) +#define BIT_TXBCN5ERR BIT(4) +#define BIT_TXBCN4ERR BIT(3) +#define BIT_TXBCN3ERR BIT(2) +#define BIT_TXBCN2ERR BIT(1) +#define BIT_TXBCN1ERR BIT(0) + +/* 2 REG_HIMR3 (Offset 0x10B8) */ + +#define BIT_WDT_PLATFORM_INT_MSK BIT(18) +#define BIT_WDT_CPU_INT_MSK BIT(17) + +/* 2 REG_HIMR3 (Offset 0x10B8) */ + +#define BIT_SETH2CDOK_MASK BIT(16) +#define BIT_H2C_CMD_FULL_MASK BIT(15) +#define BIT_PWR_INT_127_MASK BIT(14) +#define BIT_TXSHORTCUT_TXDESUPDATEOK_MASK BIT(13) +#define BIT_TXSHORTCUT_BKUPDATEOK_MASK BIT(12) +#define BIT_TXSHORTCUT_BEUPDATEOK_MASK BIT(11) +#define BIT_TXSHORTCUT_VIUPDATEOK_MAS BIT(10) +#define BIT_TXSHORTCUT_VOUPDATEOK_MASK BIT(9) +#define BIT_PWR_INT_127_MASK_V1 BIT(8) +#define BIT_PWR_INT_126TO96_MASK BIT(7) +#define BIT_PWR_INT_95TO64_MASK BIT(6) +#define BIT_PWR_INT_63TO32_MASK BIT(5) +#define BIT_PWR_INT_31TO0_MASK BIT(4) +#define BIT_DDMA0_LP_INT_MSK BIT(1) +#define BIT_DDMA0_HP_INT_MSK BIT(0) + +/* 2 REG_HISR3 (Offset 0x10BC) */ + +#define BIT_WDT_PLATFORM_INT BIT(18) +#define BIT_WDT_CPU_INT BIT(17) + +/* 2 REG_HISR3 (Offset 0x10BC) */ + +#define BIT_SETH2CDOK BIT(16) +#define BIT_H2C_CMD_FULL BIT(15) +#define BIT_PWR_INT_127 BIT(14) +#define BIT_TXSHORTCUT_TXDESUPDATEOK BIT(13) +#define BIT_TXSHORTCUT_BKUPDATEOK BIT(12) +#define BIT_TXSHORTCUT_BEUPDATEOK BIT(11) +#define BIT_TXSHORTCUT_VIUPDATEOK BIT(10) +#define BIT_TXSHORTCUT_VOUPDATEOK BIT(9) +#define BIT_PWR_INT_127_V1 BIT(8) +#define BIT_PWR_INT_126TO96 BIT(7) +#define BIT_PWR_INT_95TO64 BIT(6) +#define BIT_PWR_INT_63TO32 BIT(5) +#define BIT_PWR_INT_31TO0 BIT(4) +#define BIT_DDMA0_LP_INT BIT(1) +#define BIT_DDMA0_HP_INT BIT(0) + +/* 2 REG_SW_MDIO (Offset 0x10C0) */ + +#define BIT_DIS_TIMEOUT_IO BIT(24) + +/* 2 REG_SW_FLUSH (Offset 0x10C4) */ + +#define BIT_FLUSH_HOLDN_EN BIT(25) +#define BIT_FLUSH_WR_EN BIT(24) +#define BIT_SW_FLASH_CONTROL BIT(23) +#define BIT_SW_FLASH_WEN_E BIT(19) +#define BIT_SW_FLASH_HOLDN_E BIT(18) +#define BIT_SW_FLASH_SO_E BIT(17) +#define BIT_SW_FLASH_SI_E BIT(16) +#define BIT_SW_FLASH_SK_O BIT(13) +#define BIT_SW_FLASH_CEN_O BIT(12) +#define BIT_SW_FLASH_WEN_O BIT(11) +#define BIT_SW_FLASH_HOLDN_O BIT(10) +#define BIT_SW_FLASH_SO_O BIT(9) +#define BIT_SW_FLASH_SI_O BIT(8) +#define BIT_SW_FLASH_WEN_I BIT(3) +#define BIT_SW_FLASH_HOLDN_I BIT(2) +#define BIT_SW_FLASH_SO_I BIT(1) +#define BIT_SW_FLASH_SI_I BIT(0) + +/* 2 REG_H2C_PKT_READADDR (Offset 0x10D0) */ + +#define BIT_SHIFT_H2C_PKT_READADDR 0 +#define BIT_MASK_H2C_PKT_READADDR 0x3ffff +#define BIT_H2C_PKT_READADDR(x) \ + (((x) & BIT_MASK_H2C_PKT_READADDR) << BIT_SHIFT_H2C_PKT_READADDR) +#define BIT_GET_H2C_PKT_READADDR(x) \ + (((x) >> BIT_SHIFT_H2C_PKT_READADDR) & BIT_MASK_H2C_PKT_READADDR) + +/* 2 REG_H2C_PKT_WRITEADDR (Offset 0x10D4) */ + +#define BIT_SHIFT_H2C_PKT_WRITEADDR 0 +#define BIT_MASK_H2C_PKT_WRITEADDR 0x3ffff +#define BIT_H2C_PKT_WRITEADDR(x) \ + (((x) & BIT_MASK_H2C_PKT_WRITEADDR) << BIT_SHIFT_H2C_PKT_WRITEADDR) +#define BIT_GET_H2C_PKT_WRITEADDR(x) \ + (((x) >> BIT_SHIFT_H2C_PKT_WRITEADDR) & BIT_MASK_H2C_PKT_WRITEADDR) + +/* 2 REG_MEM_PWR_CRTL (Offset 0x10D8) */ + +#define BIT_MEM_BB_SD BIT(17) +#define BIT_MEM_BB_DS BIT(16) +#define BIT_MEM_BT_DS BIT(10) +#define BIT_MEM_SDIO_LS BIT(9) +#define BIT_MEM_SDIO_DS BIT(8) +#define BIT_MEM_USB_LS BIT(7) +#define BIT_MEM_USB_DS BIT(6) +#define BIT_MEM_PCI_LS BIT(5) +#define BIT_MEM_PCI_DS BIT(4) +#define BIT_MEM_WLMAC_LS BIT(3) +#define BIT_MEM_WLMAC_DS BIT(2) +#define BIT_MEM_WLMCU_LS BIT(1) + +/* 2 REG_MEM_PWR_CRTL (Offset 0x10D8) */ + +#define BIT_MEM_WLMCU_DS BIT(0) + +/* 2 REG_FW_DBG0 (Offset 0x10E0) */ + +#define BIT_SHIFT_FW_DBG0 0 +#define BIT_MASK_FW_DBG0 0xffffffffL +#define BIT_FW_DBG0(x) (((x) & BIT_MASK_FW_DBG0) << BIT_SHIFT_FW_DBG0) +#define BIT_GET_FW_DBG0(x) (((x) >> BIT_SHIFT_FW_DBG0) & BIT_MASK_FW_DBG0) + +/* 2 REG_FW_DBG1 (Offset 0x10E4) */ + +#define BIT_SHIFT_FW_DBG1 0 +#define BIT_MASK_FW_DBG1 0xffffffffL +#define BIT_FW_DBG1(x) (((x) & BIT_MASK_FW_DBG1) << BIT_SHIFT_FW_DBG1) +#define BIT_GET_FW_DBG1(x) (((x) >> BIT_SHIFT_FW_DBG1) & BIT_MASK_FW_DBG1) + +/* 2 REG_FW_DBG2 (Offset 0x10E8) */ + +#define BIT_SHIFT_FW_DBG2 0 +#define BIT_MASK_FW_DBG2 0xffffffffL +#define BIT_FW_DBG2(x) (((x) & BIT_MASK_FW_DBG2) << BIT_SHIFT_FW_DBG2) +#define BIT_GET_FW_DBG2(x) (((x) >> BIT_SHIFT_FW_DBG2) & BIT_MASK_FW_DBG2) + +/* 2 REG_FW_DBG3 (Offset 0x10EC) */ + +#define BIT_SHIFT_FW_DBG3 0 +#define BIT_MASK_FW_DBG3 0xffffffffL +#define BIT_FW_DBG3(x) (((x) & BIT_MASK_FW_DBG3) << BIT_SHIFT_FW_DBG3) +#define BIT_GET_FW_DBG3(x) (((x) >> BIT_SHIFT_FW_DBG3) & BIT_MASK_FW_DBG3) + +/* 2 REG_FW_DBG4 (Offset 0x10F0) */ + +#define BIT_SHIFT_FW_DBG4 0 +#define BIT_MASK_FW_DBG4 0xffffffffL +#define BIT_FW_DBG4(x) (((x) & BIT_MASK_FW_DBG4) << BIT_SHIFT_FW_DBG4) +#define BIT_GET_FW_DBG4(x) (((x) >> BIT_SHIFT_FW_DBG4) & BIT_MASK_FW_DBG4) + +/* 2 REG_FW_DBG5 (Offset 0x10F4) */ + +#define BIT_SHIFT_FW_DBG5 0 +#define BIT_MASK_FW_DBG5 0xffffffffL +#define BIT_FW_DBG5(x) (((x) & BIT_MASK_FW_DBG5) << BIT_SHIFT_FW_DBG5) +#define BIT_GET_FW_DBG5(x) (((x) >> BIT_SHIFT_FW_DBG5) & BIT_MASK_FW_DBG5) + +/* 2 REG_FW_DBG6 (Offset 0x10F8) */ + +#define BIT_SHIFT_FW_DBG6 0 +#define BIT_MASK_FW_DBG6 0xffffffffL +#define BIT_FW_DBG6(x) (((x) & BIT_MASK_FW_DBG6) << BIT_SHIFT_FW_DBG6) +#define BIT_GET_FW_DBG6(x) (((x) >> BIT_SHIFT_FW_DBG6) & BIT_MASK_FW_DBG6) + +/* 2 REG_FW_DBG7 (Offset 0x10FC) */ + +#define BIT_SHIFT_FW_DBG7 0 +#define BIT_MASK_FW_DBG7 0xffffffffL +#define BIT_FW_DBG7(x) (((x) & BIT_MASK_FW_DBG7) << BIT_SHIFT_FW_DBG7) +#define BIT_GET_FW_DBG7(x) (((x) >> BIT_SHIFT_FW_DBG7) & BIT_MASK_FW_DBG7) + +/* 2 REG_CR_EXT (Offset 0x1100) */ + +#define BIT_SHIFT_PHY_REQ_DELAY 24 +#define BIT_MASK_PHY_REQ_DELAY 0xf +#define BIT_PHY_REQ_DELAY(x) \ + (((x) & BIT_MASK_PHY_REQ_DELAY) << BIT_SHIFT_PHY_REQ_DELAY) +#define BIT_GET_PHY_REQ_DELAY(x) \ + (((x) >> BIT_SHIFT_PHY_REQ_DELAY) & BIT_MASK_PHY_REQ_DELAY) + +#define BIT_SPD_DOWN BIT(16) + +#define BIT_SHIFT_NETYPE4 4 +#define BIT_MASK_NETYPE4 0x3 +#define BIT_NETYPE4(x) (((x) & BIT_MASK_NETYPE4) << BIT_SHIFT_NETYPE4) +#define BIT_GET_NETYPE4(x) (((x) >> BIT_SHIFT_NETYPE4) & BIT_MASK_NETYPE4) + +#define BIT_SHIFT_NETYPE3 2 +#define BIT_MASK_NETYPE3 0x3 +#define BIT_NETYPE3(x) (((x) & BIT_MASK_NETYPE3) << BIT_SHIFT_NETYPE3) +#define BIT_GET_NETYPE3(x) (((x) >> BIT_SHIFT_NETYPE3) & BIT_MASK_NETYPE3) + +#define BIT_SHIFT_NETYPE2 0 +#define BIT_MASK_NETYPE2 0x3 +#define BIT_NETYPE2(x) (((x) & BIT_MASK_NETYPE2) << BIT_SHIFT_NETYPE2) +#define BIT_GET_NETYPE2(x) (((x) >> BIT_SHIFT_NETYPE2) & BIT_MASK_NETYPE2) + +/* 2 REG_FWFF (Offset 0x1114) */ + +#define BIT_SHIFT_PKTNUM_TH_V1 24 +#define BIT_MASK_PKTNUM_TH_V1 0xff +#define BIT_PKTNUM_TH_V1(x) \ + (((x) & BIT_MASK_PKTNUM_TH_V1) << BIT_SHIFT_PKTNUM_TH_V1) +#define BIT_GET_PKTNUM_TH_V1(x) \ + (((x) >> BIT_SHIFT_PKTNUM_TH_V1) & BIT_MASK_PKTNUM_TH_V1) + +/* 2 REG_FWFF (Offset 0x1114) */ + +#define BIT_SHIFT_TIMER_TH 16 +#define BIT_MASK_TIMER_TH 0xff +#define BIT_TIMER_TH(x) (((x) & BIT_MASK_TIMER_TH) << BIT_SHIFT_TIMER_TH) +#define BIT_GET_TIMER_TH(x) (((x) >> BIT_SHIFT_TIMER_TH) & BIT_MASK_TIMER_TH) + +/* 2 REG_FWFF (Offset 0x1114) */ + +#define BIT_SHIFT_RXPKT1ENADDR 0 +#define BIT_MASK_RXPKT1ENADDR 0xffff +#define BIT_RXPKT1ENADDR(x) \ + (((x) & BIT_MASK_RXPKT1ENADDR) << BIT_SHIFT_RXPKT1ENADDR) +#define BIT_GET_RXPKT1ENADDR(x) \ + (((x) >> BIT_SHIFT_RXPKT1ENADDR) & BIT_MASK_RXPKT1ENADDR) + +/* 2 REG_FE2IMR (Offset 0x1120) */ + +#define BIT__FE4ISR__IND_MSK BIT(29) + +/* 2 REG_FE2IMR (Offset 0x1120) */ + +#define BIT_FS_TXSC_DESC_DONE_INT_EN BIT(28) +#define BIT_FS_TXSC_BKDONE_INT_EN BIT(27) +#define BIT_FS_TXSC_BEDONE_INT_EN BIT(26) +#define BIT_FS_TXSC_VIDONE_INT_EN BIT(25) +#define BIT_FS_TXSC_VODONE_INT_EN BIT(24) + +/* 2 REG_FE2IMR (Offset 0x1120) */ + +#define BIT_FS_ATIM_MB7_INT_EN BIT(23) +#define BIT_FS_ATIM_MB6_INT_EN BIT(22) +#define BIT_FS_ATIM_MB5_INT_EN BIT(21) +#define BIT_FS_ATIM_MB4_INT_EN BIT(20) +#define BIT_FS_ATIM_MB3_INT_EN BIT(19) +#define BIT_FS_ATIM_MB2_INT_EN BIT(18) +#define BIT_FS_ATIM_MB1_INT_EN BIT(17) +#define BIT_FS_ATIM_MB0_INT_EN BIT(16) +#define BIT_FS_TBTT4INT_EN BIT(11) +#define BIT_FS_TBTT3INT_EN BIT(10) +#define BIT_FS_TBTT2INT_EN BIT(9) +#define BIT_FS_TBTT1INT_EN BIT(8) +#define BIT_FS_TBTT0_MB7INT_EN BIT(7) +#define BIT_FS_TBTT0_MB6INT_EN BIT(6) +#define BIT_FS_TBTT0_MB5INT_EN BIT(5) +#define BIT_FS_TBTT0_MB4INT_EN BIT(4) +#define BIT_FS_TBTT0_MB3INT_EN BIT(3) +#define BIT_FS_TBTT0_MB2INT_EN BIT(2) +#define BIT_FS_TBTT0_MB1INT_EN BIT(1) +#define BIT_FS_TBTT0_INT_EN BIT(0) + +/* 2 REG_FE2ISR (Offset 0x1124) */ + +#define BIT__FE4ISR__IND_INT BIT(29) + +/* 2 REG_FE2ISR (Offset 0x1124) */ + +#define BIT_FS_TXSC_DESC_DONE_INT BIT(28) +#define BIT_FS_TXSC_BKDONE_INT BIT(27) +#define BIT_FS_TXSC_BEDONE_INT BIT(26) +#define BIT_FS_TXSC_VIDONE_INT BIT(25) +#define BIT_FS_TXSC_VODONE_INT BIT(24) + +/* 2 REG_FE2ISR (Offset 0x1124) */ + +#define BIT_FS_ATIM_MB7_INT BIT(23) +#define BIT_FS_ATIM_MB6_INT BIT(22) +#define BIT_FS_ATIM_MB5_INT BIT(21) +#define BIT_FS_ATIM_MB4_INT BIT(20) +#define BIT_FS_ATIM_MB3_INT BIT(19) +#define BIT_FS_ATIM_MB2_INT BIT(18) +#define BIT_FS_ATIM_MB1_INT BIT(17) +#define BIT_FS_ATIM_MB0_INT BIT(16) +#define BIT_FS_TBTT4INT BIT(11) +#define BIT_FS_TBTT3INT BIT(10) +#define BIT_FS_TBTT2INT BIT(9) +#define BIT_FS_TBTT1INT BIT(8) +#define BIT_FS_TBTT0_MB7INT BIT(7) +#define BIT_FS_TBTT0_MB6INT BIT(6) +#define BIT_FS_TBTT0_MB5INT BIT(5) +#define BIT_FS_TBTT0_MB4INT BIT(4) +#define BIT_FS_TBTT0_MB3INT BIT(3) +#define BIT_FS_TBTT0_MB2INT BIT(2) +#define BIT_FS_TBTT0_MB1INT BIT(1) +#define BIT_FS_TBTT0_INT BIT(0) + +/* 2 REG_FE3IMR (Offset 0x1128) */ + +#define BIT_FS_CLI3_MTI_BCNIVLEAR_INT__EN BIT(31) + +/* 2 REG_FE3IMR (Offset 0x1128) */ + +#define BIT_FS_CLI2_MTI_BCNIVLEAR_INT__EN BIT(30) + +/* 2 REG_FE3IMR (Offset 0x1128) */ + +#define BIT_FS_CLI1_MTI_BCNIVLEAR_INT__EN BIT(29) + +/* 2 REG_FE3IMR (Offset 0x1128) */ + +#define BIT_FS_CLI0_MTI_BCNIVLEAR_INT__EN BIT(28) + +/* 2 REG_FE3IMR (Offset 0x1128) */ + +#define BIT_FS_BCNDMA4_INT_EN BIT(27) +#define BIT_FS_BCNDMA3_INT_EN BIT(26) +#define BIT_FS_BCNDMA2_INT_EN BIT(25) +#define BIT_FS_BCNDMA1_INT_EN BIT(24) +#define BIT_FS_BCNDMA0_MB7_INT_EN BIT(23) +#define BIT_FS_BCNDMA0_MB6_INT_EN BIT(22) +#define BIT_FS_BCNDMA0_MB5_INT_EN BIT(21) +#define BIT_FS_BCNDMA0_MB4_INT_EN BIT(20) +#define BIT_FS_BCNDMA0_MB3_INT_EN BIT(19) +#define BIT_FS_BCNDMA0_MB2_INT_EN BIT(18) +#define BIT_FS_BCNDMA0_MB1_INT_EN BIT(17) +#define BIT_FS_BCNDMA0_INT_EN BIT(16) +#define BIT_FS_MTI_BCNIVLEAR_INT__EN BIT(15) +#define BIT_FS_BCNERLY4_INT_EN BIT(11) +#define BIT_FS_BCNERLY3_INT_EN BIT(10) +#define BIT_FS_BCNERLY2_INT_EN BIT(9) +#define BIT_FS_BCNERLY1_INT_EN BIT(8) +#define BIT_FS_BCNERLY0_MB7INT_EN BIT(7) +#define BIT_FS_BCNERLY0_MB6INT_EN BIT(6) +#define BIT_FS_BCNERLY0_MB5INT_EN BIT(5) +#define BIT_FS_BCNERLY0_MB4INT_EN BIT(4) +#define BIT_FS_BCNERLY0_MB3INT_EN BIT(3) +#define BIT_FS_BCNERLY0_MB2INT_EN BIT(2) +#define BIT_FS_BCNERLY0_MB1INT_EN BIT(1) +#define BIT_FS_BCNERLY0_INT_EN BIT(0) + +/* 2 REG_FE3ISR (Offset 0x112C) */ + +#define BIT_FS_CLI3_MTI_BCNIVLEAR_INT BIT(31) + +/* 2 REG_FE3ISR (Offset 0x112C) */ + +#define BIT_FS_CLI2_MTI_BCNIVLEAR_INT BIT(30) + +/* 2 REG_FE3ISR (Offset 0x112C) */ + +#define BIT_FS_CLI1_MTI_BCNIVLEAR_INT BIT(29) + +/* 2 REG_FE3ISR (Offset 0x112C) */ + +#define BIT_FS_CLI0_MTI_BCNIVLEAR_INT BIT(28) + +/* 2 REG_FE3ISR (Offset 0x112C) */ + +#define BIT_FS_BCNDMA4_INT BIT(27) +#define BIT_FS_BCNDMA3_INT BIT(26) +#define BIT_FS_BCNDMA2_INT BIT(25) +#define BIT_FS_BCNDMA1_INT BIT(24) +#define BIT_FS_BCNDMA0_MB7_INT BIT(23) +#define BIT_FS_BCNDMA0_MB6_INT BIT(22) +#define BIT_FS_BCNDMA0_MB5_INT BIT(21) +#define BIT_FS_BCNDMA0_MB4_INT BIT(20) +#define BIT_FS_BCNDMA0_MB3_INT BIT(19) +#define BIT_FS_BCNDMA0_MB2_INT BIT(18) +#define BIT_FS_BCNDMA0_MB1_INT BIT(17) +#define BIT_FS_BCNDMA0_INT BIT(16) +#define BIT_FS_MTI_BCNIVLEAR_INT BIT(15) +#define BIT_FS_BCNERLY4_INT BIT(11) +#define BIT_FS_BCNERLY3_INT BIT(10) +#define BIT_FS_BCNERLY2_INT BIT(9) +#define BIT_FS_BCNERLY1_INT BIT(8) +#define BIT_FS_BCNERLY0_MB7INT BIT(7) +#define BIT_FS_BCNERLY0_MB6INT BIT(6) +#define BIT_FS_BCNERLY0_MB5INT BIT(5) +#define BIT_FS_BCNERLY0_MB4INT BIT(4) +#define BIT_FS_BCNERLY0_MB3INT BIT(3) +#define BIT_FS_BCNERLY0_MB2INT BIT(2) +#define BIT_FS_BCNERLY0_MB1INT BIT(1) +#define BIT_FS_BCNERLY0_INT BIT(0) + +/* 2 REG_FE4IMR (Offset 0x1130) */ + +#define BIT_FS_CLI3_TXPKTIN_INT_EN BIT(19) + +/* 2 REG_FE4IMR (Offset 0x1130) */ + +#define BIT_FS_CLI2_TXPKTIN_INT_EN BIT(18) + +/* 2 REG_FE4IMR (Offset 0x1130) */ + +#define BIT_FS_CLI1_TXPKTIN_INT_EN BIT(17) + +/* 2 REG_FE4IMR (Offset 0x1130) */ + +#define BIT_FS_CLI0_TXPKTIN_INT_EN BIT(16) + +/* 2 REG_FE4IMR (Offset 0x1130) */ + +#define BIT_FS_CLI3_RX_UMD0_INT_EN BIT(15) + +/* 2 REG_FE4IMR (Offset 0x1130) */ + +#define BIT_FS_CLI3_RX_UMD1_INT_EN BIT(14) + +/* 2 REG_FE4IMR (Offset 0x1130) */ + +#define BIT_FS_CLI3_RX_BMD0_INT_EN BIT(13) + +/* 2 REG_FE4IMR (Offset 0x1130) */ + +#define BIT_FS_CLI3_RX_BMD1_INT_EN BIT(12) + +/* 2 REG_FE4IMR (Offset 0x1130) */ + +#define BIT_FS_CLI2_RX_UMD0_INT_EN BIT(11) + +/* 2 REG_FE4IMR (Offset 0x1130) */ + +#define BIT_FS_CLI2_RX_UMD1_INT_EN BIT(10) + +/* 2 REG_FE4IMR (Offset 0x1130) */ + +#define BIT_FS_CLI2_RX_BMD0_INT_EN BIT(9) + +/* 2 REG_FE4IMR (Offset 0x1130) */ + +#define BIT_FS_CLI2_RX_BMD1_INT_EN BIT(8) + +/* 2 REG_FE4IMR (Offset 0x1130) */ + +#define BIT_FS_CLI1_RX_UMD0_INT_EN BIT(7) + +/* 2 REG_FE4IMR (Offset 0x1130) */ + +#define BIT_FS_CLI1_RX_UMD1_INT_EN BIT(6) + +/* 2 REG_FE4IMR (Offset 0x1130) */ + +#define BIT_FS_CLI1_RX_BMD0_INT_EN BIT(5) + +/* 2 REG_FE4IMR (Offset 0x1130) */ + +#define BIT_FS_CLI1_RX_BMD1_INT_EN BIT(4) + +/* 2 REG_FE4IMR (Offset 0x1130) */ + +#define BIT_FS_CLI0_RX_UMD0_INT_EN BIT(3) + +/* 2 REG_FE4IMR (Offset 0x1130) */ + +#define BIT_FS_CLI0_RX_UMD1_INT_EN BIT(2) + +/* 2 REG_FE4IMR (Offset 0x1130) */ + +#define BIT_FS_CLI0_RX_BMD0_INT_EN BIT(1) + +/* 2 REG_FE4IMR (Offset 0x1130) */ + +#define BIT_FS_CLI0_RX_BMD1_INT_EN BIT(0) + +/* 2 REG_FE4ISR (Offset 0x1134) */ + +#define BIT_FS_CLI3_TXPKTIN_INT BIT(19) + +/* 2 REG_FE4ISR (Offset 0x1134) */ + +#define BIT_FS_CLI2_TXPKTIN_INT BIT(18) + +/* 2 REG_FE4ISR (Offset 0x1134) */ + +#define BIT_FS_CLI1_TXPKTIN_INT BIT(17) + +/* 2 REG_FE4ISR (Offset 0x1134) */ + +#define BIT_FS_CLI0_TXPKTIN_INT BIT(16) + +/* 2 REG_FE4ISR (Offset 0x1134) */ + +#define BIT_FS_CLI3_RX_UMD0_INT BIT(15) + +/* 2 REG_FE4ISR (Offset 0x1134) */ + +#define BIT_FS_CLI3_RX_UMD1_INT BIT(14) + +/* 2 REG_FE4ISR (Offset 0x1134) */ + +#define BIT_FS_CLI3_RX_BMD0_INT BIT(13) + +/* 2 REG_FE4ISR (Offset 0x1134) */ + +#define BIT_FS_CLI3_RX_BMD1_INT BIT(12) + +/* 2 REG_FE4ISR (Offset 0x1134) */ + +#define BIT_FS_CLI2_RX_UMD0_INT BIT(11) + +/* 2 REG_FE4ISR (Offset 0x1134) */ + +#define BIT_FS_CLI2_RX_UMD1_INT BIT(10) + +/* 2 REG_FE4ISR (Offset 0x1134) */ + +#define BIT_FS_CLI2_RX_BMD0_INT BIT(9) + +/* 2 REG_FE4ISR (Offset 0x1134) */ + +#define BIT_FS_CLI2_RX_BMD1_INT BIT(8) + +/* 2 REG_FE4ISR (Offset 0x1134) */ + +#define BIT_FS_CLI1_RX_UMD0_INT BIT(7) + +/* 2 REG_FE4ISR (Offset 0x1134) */ + +#define BIT_FS_CLI1_RX_UMD1_INT BIT(6) + +/* 2 REG_FE4ISR (Offset 0x1134) */ + +#define BIT_FS_CLI1_RX_BMD0_INT BIT(5) + +/* 2 REG_FE4ISR (Offset 0x1134) */ + +#define BIT_FS_CLI1_RX_BMD1_INT BIT(4) + +/* 2 REG_FE4ISR (Offset 0x1134) */ + +#define BIT_FS_CLI0_RX_UMD0_INT BIT(3) + +/* 2 REG_FE4ISR (Offset 0x1134) */ + +#define BIT_FS_CLI0_RX_UMD1_INT BIT(2) + +/* 2 REG_FE4ISR (Offset 0x1134) */ + +#define BIT_FS_CLI0_RX_BMD0_INT BIT(1) + +/* 2 REG_FE4ISR (Offset 0x1134) */ + +#define BIT_FS_CLI0_RX_BMD1_INT BIT(0) + +/* 2 REG_FT1IMR (Offset 0x1138) */ + +#define BIT__FT2ISR__IND_MSK BIT(30) +#define BIT_FTM_PTT_INT_EN BIT(29) +#define BIT_RXFTMREQ_INT_EN BIT(28) +#define BIT_RXFTM_INT_EN BIT(27) +#define BIT_TXFTM_INT_EN BIT(26) + +/* 2 REG_FT1IMR (Offset 0x1138) */ + +#define BIT_FS_H2C_CMD_OK_INT_EN BIT(25) +#define BIT_FS_H2C_CMD_FULL_INT_EN BIT(24) + +/* 2 REG_FT1IMR (Offset 0x1138) */ + +#define BIT_FS_MACID_PWRCHANGE5_INT_EN BIT(23) +#define BIT_FS_MACID_PWRCHANGE4_INT_EN BIT(22) +#define BIT_FS_MACID_PWRCHANGE3_INT_EN BIT(21) +#define BIT_FS_MACID_PWRCHANGE2_INT_EN BIT(20) +#define BIT_FS_MACID_PWRCHANGE1_INT_EN BIT(19) +#define BIT_FS_MACID_PWRCHANGE0_INT_EN BIT(18) +#define BIT_FS_CTWEND2_INT_EN BIT(17) +#define BIT_FS_CTWEND1_INT_EN BIT(16) +#define BIT_FS_CTWEND0_INT_EN BIT(15) +#define BIT_FS_TX_NULL1_INT_EN BIT(14) +#define BIT_FS_TX_NULL0_INT_EN BIT(13) +#define BIT_FS_TSF_BIT32_TOGGLE_EN BIT(12) +#define BIT_FS_P2P_RFON2_INT_EN BIT(11) +#define BIT_FS_P2P_RFOFF2_INT_EN BIT(10) +#define BIT_FS_P2P_RFON1_INT_EN BIT(9) +#define BIT_FS_P2P_RFOFF1_INT_EN BIT(8) +#define BIT_FS_P2P_RFON0_INT_EN BIT(7) +#define BIT_FS_P2P_RFOFF0_INT_EN BIT(6) +#define BIT_FS_RX_UAPSDMD1_EN BIT(5) +#define BIT_FS_RX_UAPSDMD0_EN BIT(4) +#define BIT_FS_TRIGGER_PKT_EN BIT(3) +#define BIT_FS_EOSP_INT_EN BIT(2) +#define BIT_FS_RPWM2_INT_EN BIT(1) +#define BIT_FS_RPWM_INT_EN BIT(0) + +/* 2 REG_FT1ISR (Offset 0x113C) */ + +#define BIT__FT2ISR__IND_INT BIT(30) +#define BIT_FTM_PTT_INT BIT(29) +#define BIT_RXFTMREQ_INT BIT(28) +#define BIT_RXFTM_INT BIT(27) +#define BIT_TXFTM_INT BIT(26) + +/* 2 REG_FT1ISR (Offset 0x113C) */ + +#define BIT_FS_H2C_CMD_OK_INT BIT(25) +#define BIT_FS_H2C_CMD_FULL_INT BIT(24) + +/* 2 REG_FT1ISR (Offset 0x113C) */ + +#define BIT_FS_MACID_PWRCHANGE5_INT BIT(23) +#define BIT_FS_MACID_PWRCHANGE4_INT BIT(22) +#define BIT_FS_MACID_PWRCHANGE3_INT BIT(21) +#define BIT_FS_MACID_PWRCHANGE2_INT BIT(20) +#define BIT_FS_MACID_PWRCHANGE1_INT BIT(19) +#define BIT_FS_MACID_PWRCHANGE0_INT BIT(18) +#define BIT_FS_CTWEND2_INT BIT(17) +#define BIT_FS_CTWEND1_INT BIT(16) +#define BIT_FS_CTWEND0_INT BIT(15) +#define BIT_FS_TX_NULL1_INT BIT(14) +#define BIT_FS_TX_NULL0_INT BIT(13) +#define BIT_FS_TSF_BIT32_TOGGLE_INT BIT(12) +#define BIT_FS_P2P_RFON2_INT BIT(11) +#define BIT_FS_P2P_RFOFF2_INT BIT(10) +#define BIT_FS_P2P_RFON1_INT BIT(9) +#define BIT_FS_P2P_RFOFF1_INT BIT(8) +#define BIT_FS_P2P_RFON0_INT BIT(7) +#define BIT_FS_P2P_RFOFF0_INT BIT(6) +#define BIT_FS_RX_UAPSDMD1_INT BIT(5) +#define BIT_FS_RX_UAPSDMD0_INT BIT(4) +#define BIT_FS_TRIGGER_PKT_INT BIT(3) +#define BIT_FS_EOSP_INT BIT(2) +#define BIT_FS_RPWM2_INT BIT(1) +#define BIT_FS_RPWM_INT BIT(0) + +/* 2 REG_SPWR0 (Offset 0x1140) */ + +#define BIT_SHIFT_MID_31TO0 0 +#define BIT_MASK_MID_31TO0 0xffffffffL +#define BIT_MID_31TO0(x) (((x) & BIT_MASK_MID_31TO0) << BIT_SHIFT_MID_31TO0) +#define BIT_GET_MID_31TO0(x) (((x) >> BIT_SHIFT_MID_31TO0) & BIT_MASK_MID_31TO0) + +/* 2 REG_SPWR1 (Offset 0x1144) */ + +#define BIT_SHIFT_MID_63TO32 0 +#define BIT_MASK_MID_63TO32 0xffffffffL +#define BIT_MID_63TO32(x) (((x) & BIT_MASK_MID_63TO32) << BIT_SHIFT_MID_63TO32) +#define BIT_GET_MID_63TO32(x) \ + (((x) >> BIT_SHIFT_MID_63TO32) & BIT_MASK_MID_63TO32) + +/* 2 REG_SPWR2 (Offset 0x1148) */ + +#define BIT_SHIFT_MID_95O64 0 +#define BIT_MASK_MID_95O64 0xffffffffL +#define BIT_MID_95O64(x) (((x) & BIT_MASK_MID_95O64) << BIT_SHIFT_MID_95O64) +#define BIT_GET_MID_95O64(x) (((x) >> BIT_SHIFT_MID_95O64) & BIT_MASK_MID_95O64) + +/* 2 REG_SPWR3 (Offset 0x114C) */ + +#define BIT_SHIFT_MID_127TO96 0 +#define BIT_MASK_MID_127TO96 0xffffffffL +#define BIT_MID_127TO96(x) \ + (((x) & BIT_MASK_MID_127TO96) << BIT_SHIFT_MID_127TO96) +#define BIT_GET_MID_127TO96(x) \ + (((x) >> BIT_SHIFT_MID_127TO96) & BIT_MASK_MID_127TO96) + +/* 2 REG_POWSEQ (Offset 0x1150) */ + +#define BIT_SHIFT_SEQNUM_MID 16 +#define BIT_MASK_SEQNUM_MID 0xffff +#define BIT_SEQNUM_MID(x) (((x) & BIT_MASK_SEQNUM_MID) << BIT_SHIFT_SEQNUM_MID) +#define BIT_GET_SEQNUM_MID(x) \ + (((x) >> BIT_SHIFT_SEQNUM_MID) & BIT_MASK_SEQNUM_MID) + +#define BIT_SHIFT_REF_MID 0 +#define BIT_MASK_REF_MID 0x7f +#define BIT_REF_MID(x) (((x) & BIT_MASK_REF_MID) << BIT_SHIFT_REF_MID) +#define BIT_GET_REF_MID(x) (((x) >> BIT_SHIFT_REF_MID) & BIT_MASK_REF_MID) + +/* 2 REG_TC7_CTRL_V1 (Offset 0x1158) */ + +#define BIT_TC7INT_EN BIT(26) +#define BIT_TC7MODE BIT(25) +#define BIT_TC7EN BIT(24) + +#define BIT_SHIFT_TC7DATA 0 +#define BIT_MASK_TC7DATA 0xffffff +#define BIT_TC7DATA(x) (((x) & BIT_MASK_TC7DATA) << BIT_SHIFT_TC7DATA) +#define BIT_GET_TC7DATA(x) (((x) >> BIT_SHIFT_TC7DATA) & BIT_MASK_TC7DATA) + +/* 2 REG_TC8_CTRL_V1 (Offset 0x115C) */ + +#define BIT_TC8INT_EN BIT(26) +#define BIT_TC8MODE BIT(25) +#define BIT_TC8EN BIT(24) + +#define BIT_SHIFT_TC8DATA 0 +#define BIT_MASK_TC8DATA 0xffffff +#define BIT_TC8DATA(x) (((x) & BIT_MASK_TC8DATA) << BIT_SHIFT_TC8DATA) +#define BIT_GET_TC8DATA(x) (((x) >> BIT_SHIFT_TC8DATA) & BIT_MASK_TC8DATA) + +/* 2 REG_FT2IMR (Offset 0x11E0) */ + +#define BIT_FS_CLI3_RX_UAPSDMD1_EN BIT(31) + +/* 2 REG_FT2IMR (Offset 0x11E0) */ + +#define BIT_FS_CLI3_RX_UAPSDMD0_EN BIT(30) + +/* 2 REG_FT2IMR (Offset 0x11E0) */ + +#define BIT_FS_CLI3_TRIGGER_PKT_EN BIT(29) + +/* 2 REG_FT2IMR (Offset 0x11E0) */ + +#define BIT_FS_CLI3_EOSP_INT_EN BIT(28) + +/* 2 REG_FT2IMR (Offset 0x11E0) */ + +#define BIT_FS_CLI2_RX_UAPSDMD1_EN BIT(27) + +/* 2 REG_FT2IMR (Offset 0x11E0) */ + +#define BIT_FS_CLI2_RX_UAPSDMD0_EN BIT(26) + +/* 2 REG_FT2IMR (Offset 0x11E0) */ + +#define BIT_FS_CLI2_TRIGGER_PKT_EN BIT(25) + +/* 2 REG_FT2IMR (Offset 0x11E0) */ + +#define BIT_FS_CLI2_EOSP_INT_EN BIT(24) + +/* 2 REG_FT2IMR (Offset 0x11E0) */ + +#define BIT_FS_CLI1_RX_UAPSDMD1_EN BIT(23) + +/* 2 REG_FT2IMR (Offset 0x11E0) */ + +#define BIT_FS_CLI1_RX_UAPSDMD0_EN BIT(22) + +/* 2 REG_FT2IMR (Offset 0x11E0) */ + +#define BIT_FS_CLI1_TRIGGER_PKT_EN BIT(21) + +/* 2 REG_FT2IMR (Offset 0x11E0) */ + +#define BIT_FS_CLI1_EOSP_INT_EN BIT(20) + +/* 2 REG_FT2IMR (Offset 0x11E0) */ + +#define BIT_FS_CLI0_RX_UAPSDMD1_EN BIT(19) + +/* 2 REG_FT2IMR (Offset 0x11E0) */ + +#define BIT_FS_CLI0_RX_UAPSDMD0_EN BIT(18) + +/* 2 REG_FT2IMR (Offset 0x11E0) */ + +#define BIT_FS_CLI0_TRIGGER_PKT_EN BIT(17) + +/* 2 REG_FT2IMR (Offset 0x11E0) */ + +#define BIT_FS_CLI0_EOSP_INT_EN BIT(16) + +/* 2 REG_FT2IMR (Offset 0x11E0) */ + +#define BIT_FS_TSF_BIT32_TOGGLE_P2P2_EN BIT(9) + +/* 2 REG_FT2IMR (Offset 0x11E0) */ + +#define BIT_FS_TSF_BIT32_TOGGLE_P2P1_EN BIT(8) + +/* 2 REG_FT2IMR (Offset 0x11E0) */ + +#define BIT_FS_CLI3_TX_NULL1_INT_EN BIT(7) + +/* 2 REG_FT2IMR (Offset 0x11E0) */ + +#define BIT_FS_CLI3_TX_NULL0_INT_EN BIT(6) + +/* 2 REG_FT2IMR (Offset 0x11E0) */ + +#define BIT_FS_CLI2_TX_NULL1_INT_EN BIT(5) + +/* 2 REG_FT2IMR (Offset 0x11E0) */ + +#define BIT_FS_CLI2_TX_NULL0_INT_EN BIT(4) + +/* 2 REG_FT2IMR (Offset 0x11E0) */ + +#define BIT_FS_CLI1_TX_NULL1_INT_EN BIT(3) + +/* 2 REG_FT2IMR (Offset 0x11E0) */ + +#define BIT_FS_CLI1_TX_NULL0_INT_EN BIT(2) + +/* 2 REG_FT2IMR (Offset 0x11E0) */ + +#define BIT_FS_CLI0_TX_NULL1_INT_EN BIT(1) + +/* 2 REG_FT2IMR (Offset 0x11E0) */ + +#define BIT_FS_CLI0_TX_NULL0_INT_EN BIT(0) + +/* 2 REG_FT2ISR (Offset 0x11E4) */ + +#define BIT_FS_CLI3_RX_UAPSDMD1_INT BIT(31) + +/* 2 REG_FT2ISR (Offset 0x11E4) */ + +#define BIT_FS_CLI3_RX_UAPSDMD0_INT BIT(30) + +/* 2 REG_FT2ISR (Offset 0x11E4) */ + +#define BIT_FS_CLI3_TRIGGER_PKT_INT BIT(29) + +/* 2 REG_FT2ISR (Offset 0x11E4) */ + +#define BIT_FS_CLI3_EOSP_INT BIT(28) + +/* 2 REG_FT2ISR (Offset 0x11E4) */ + +#define BIT_FS_CLI2_RX_UAPSDMD1_INT BIT(27) + +/* 2 REG_FT2ISR (Offset 0x11E4) */ + +#define BIT_FS_CLI2_RX_UAPSDMD0_INT BIT(26) + +/* 2 REG_FT2ISR (Offset 0x11E4) */ + +#define BIT_FS_CLI2_TRIGGER_PKT_INT BIT(25) + +/* 2 REG_FT2ISR (Offset 0x11E4) */ + +#define BIT_FS_CLI2_EOSP_INT BIT(24) + +/* 2 REG_FT2ISR (Offset 0x11E4) */ + +#define BIT_FS_CLI1_RX_UAPSDMD1_INT BIT(23) + +/* 2 REG_FT2ISR (Offset 0x11E4) */ + +#define BIT_FS_CLI1_RX_UAPSDMD0_INT BIT(22) + +/* 2 REG_FT2ISR (Offset 0x11E4) */ + +#define BIT_FS_CLI1_TRIGGER_PKT_INT BIT(21) + +/* 2 REG_FT2ISR (Offset 0x11E4) */ + +#define BIT_FS_CLI1_EOSP_INT BIT(20) + +/* 2 REG_FT2ISR (Offset 0x11E4) */ + +#define BIT_FS_CLI0_RX_UAPSDMD1_INT BIT(19) + +/* 2 REG_FT2ISR (Offset 0x11E4) */ + +#define BIT_FS_CLI0_RX_UAPSDMD0_INT BIT(18) + +/* 2 REG_FT2ISR (Offset 0x11E4) */ + +#define BIT_FS_CLI0_TRIGGER_PKT_INT BIT(17) + +/* 2 REG_FT2ISR (Offset 0x11E4) */ + +#define BIT_FS_CLI0_EOSP_INT BIT(16) + +/* 2 REG_FT2ISR (Offset 0x11E4) */ + +#define BIT_FS_TSF_BIT32_TOGGLE_P2P2_INT BIT(9) + +/* 2 REG_FT2ISR (Offset 0x11E4) */ + +#define BIT_FS_TSF_BIT32_TOGGLE_P2P1_INT BIT(8) + +/* 2 REG_FT2ISR (Offset 0x11E4) */ + +#define BIT_FS_CLI3_TX_NULL1_INT BIT(7) + +/* 2 REG_FT2ISR (Offset 0x11E4) */ + +#define BIT_FS_CLI3_TX_NULL0_INT BIT(6) + +/* 2 REG_FT2ISR (Offset 0x11E4) */ + +#define BIT_FS_CLI2_TX_NULL1_INT BIT(5) + +/* 2 REG_FT2ISR (Offset 0x11E4) */ + +#define BIT_FS_CLI2_TX_NULL0_INT BIT(4) + +/* 2 REG_FT2ISR (Offset 0x11E4) */ + +#define BIT_FS_CLI1_TX_NULL1_INT BIT(3) + +/* 2 REG_FT2ISR (Offset 0x11E4) */ + +#define BIT_FS_CLI1_TX_NULL0_INT BIT(2) + +/* 2 REG_FT2ISR (Offset 0x11E4) */ + +#define BIT_FS_CLI0_TX_NULL1_INT BIT(1) + +/* 2 REG_FT2ISR (Offset 0x11E4) */ + +#define BIT_FS_CLI0_TX_NULL0_INT BIT(0) + +/* 2 REG_MSG2 (Offset 0x11F0) */ + +#define BIT_SHIFT_FW_MSG2 0 +#define BIT_MASK_FW_MSG2 0xffffffffL +#define BIT_FW_MSG2(x) (((x) & BIT_MASK_FW_MSG2) << BIT_SHIFT_FW_MSG2) +#define BIT_GET_FW_MSG2(x) (((x) >> BIT_SHIFT_FW_MSG2) & BIT_MASK_FW_MSG2) + +/* 2 REG_MSG3 (Offset 0x11F4) */ + +#define BIT_SHIFT_FW_MSG3 0 +#define BIT_MASK_FW_MSG3 0xffffffffL +#define BIT_FW_MSG3(x) (((x) & BIT_MASK_FW_MSG3) << BIT_SHIFT_FW_MSG3) +#define BIT_GET_FW_MSG3(x) (((x) >> BIT_SHIFT_FW_MSG3) & BIT_MASK_FW_MSG3) + +/* 2 REG_MSG4 (Offset 0x11F8) */ + +#define BIT_SHIFT_FW_MSG4 0 +#define BIT_MASK_FW_MSG4 0xffffffffL +#define BIT_FW_MSG4(x) (((x) & BIT_MASK_FW_MSG4) << BIT_SHIFT_FW_MSG4) +#define BIT_GET_FW_MSG4(x) (((x) >> BIT_SHIFT_FW_MSG4) & BIT_MASK_FW_MSG4) + +/* 2 REG_MSG5 (Offset 0x11FC) */ + +#define BIT_SHIFT_FW_MSG5 0 +#define BIT_MASK_FW_MSG5 0xffffffffL +#define BIT_FW_MSG5(x) (((x) & BIT_MASK_FW_MSG5) << BIT_SHIFT_FW_MSG5) +#define BIT_GET_FW_MSG5(x) (((x) >> BIT_SHIFT_FW_MSG5) & BIT_MASK_FW_MSG5) + +/* 2 REG_DDMA_CH0SA (Offset 0x1200) */ + +#define BIT_SHIFT_DDMACH0_SA 0 +#define BIT_MASK_DDMACH0_SA 0xffffffffL +#define BIT_DDMACH0_SA(x) (((x) & BIT_MASK_DDMACH0_SA) << BIT_SHIFT_DDMACH0_SA) +#define BIT_GET_DDMACH0_SA(x) \ + (((x) >> BIT_SHIFT_DDMACH0_SA) & BIT_MASK_DDMACH0_SA) + +/* 2 REG_DDMA_CH0DA (Offset 0x1204) */ + +#define BIT_SHIFT_DDMACH0_DA 0 +#define BIT_MASK_DDMACH0_DA 0xffffffffL +#define BIT_DDMACH0_DA(x) (((x) & BIT_MASK_DDMACH0_DA) << BIT_SHIFT_DDMACH0_DA) +#define BIT_GET_DDMACH0_DA(x) \ + (((x) >> BIT_SHIFT_DDMACH0_DA) & BIT_MASK_DDMACH0_DA) + +/* 2 REG_DDMA_CH0CTRL (Offset 0x1208) */ + +#define BIT_DDMACH0_OWN BIT(31) +#define BIT_DDMACH0_CHKSUM_EN BIT(29) +#define BIT_DDMACH0_DA_W_DISABLE BIT(28) +#define BIT_DDMACH0_CHKSUM_STS BIT(27) +#define BIT_DDMACH0_DDMA_MODE BIT(26) +#define BIT_DDMACH0_RESET_CHKSUM_STS BIT(25) +#define BIT_DDMACH0_CHKSUM_CONT BIT(24) + +#define BIT_SHIFT_DDMACH0_DLEN 0 +#define BIT_MASK_DDMACH0_DLEN 0x3ffff +#define BIT_DDMACH0_DLEN(x) \ + (((x) & BIT_MASK_DDMACH0_DLEN) << BIT_SHIFT_DDMACH0_DLEN) +#define BIT_GET_DDMACH0_DLEN(x) \ + (((x) >> BIT_SHIFT_DDMACH0_DLEN) & BIT_MASK_DDMACH0_DLEN) + +/* 2 REG_DDMA_CH1SA (Offset 0x1210) */ + +#define BIT_SHIFT_DDMACH1_SA 0 +#define BIT_MASK_DDMACH1_SA 0xffffffffL +#define BIT_DDMACH1_SA(x) (((x) & BIT_MASK_DDMACH1_SA) << BIT_SHIFT_DDMACH1_SA) +#define BIT_GET_DDMACH1_SA(x) \ + (((x) >> BIT_SHIFT_DDMACH1_SA) & BIT_MASK_DDMACH1_SA) + +/* 2 REG_DDMA_CH1DA (Offset 0x1214) */ + +#define BIT_SHIFT_DDMACH1_DA 0 +#define BIT_MASK_DDMACH1_DA 0xffffffffL +#define BIT_DDMACH1_DA(x) (((x) & BIT_MASK_DDMACH1_DA) << BIT_SHIFT_DDMACH1_DA) +#define BIT_GET_DDMACH1_DA(x) \ + (((x) >> BIT_SHIFT_DDMACH1_DA) & BIT_MASK_DDMACH1_DA) + +/* 2 REG_DDMA_CH1CTRL (Offset 0x1218) */ + +#define BIT_DDMACH1_OWN BIT(31) +#define BIT_DDMACH1_CHKSUM_EN BIT(29) +#define BIT_DDMACH1_DA_W_DISABLE BIT(28) +#define BIT_DDMACH1_CHKSUM_STS BIT(27) +#define BIT_DDMACH1_DDMA_MODE BIT(26) +#define BIT_DDMACH1_RESET_CHKSUM_STS BIT(25) +#define BIT_DDMACH1_CHKSUM_CONT BIT(24) + +#define BIT_SHIFT_DDMACH1_DLEN 0 +#define BIT_MASK_DDMACH1_DLEN 0x3ffff +#define BIT_DDMACH1_DLEN(x) \ + (((x) & BIT_MASK_DDMACH1_DLEN) << BIT_SHIFT_DDMACH1_DLEN) +#define BIT_GET_DDMACH1_DLEN(x) \ + (((x) >> BIT_SHIFT_DDMACH1_DLEN) & BIT_MASK_DDMACH1_DLEN) + +/* 2 REG_DDMA_CH2SA (Offset 0x1220) */ + +#define BIT_SHIFT_DDMACH2_SA 0 +#define BIT_MASK_DDMACH2_SA 0xffffffffL +#define BIT_DDMACH2_SA(x) (((x) & BIT_MASK_DDMACH2_SA) << BIT_SHIFT_DDMACH2_SA) +#define BIT_GET_DDMACH2_SA(x) \ + (((x) >> BIT_SHIFT_DDMACH2_SA) & BIT_MASK_DDMACH2_SA) + +/* 2 REG_DDMA_CH2DA (Offset 0x1224) */ + +#define BIT_SHIFT_DDMACH2_DA 0 +#define BIT_MASK_DDMACH2_DA 0xffffffffL +#define BIT_DDMACH2_DA(x) (((x) & BIT_MASK_DDMACH2_DA) << BIT_SHIFT_DDMACH2_DA) +#define BIT_GET_DDMACH2_DA(x) \ + (((x) >> BIT_SHIFT_DDMACH2_DA) & BIT_MASK_DDMACH2_DA) + +/* 2 REG_DDMA_CH2CTRL (Offset 0x1228) */ + +#define BIT_DDMACH2_OWN BIT(31) +#define BIT_DDMACH2_CHKSUM_EN BIT(29) +#define BIT_DDMACH2_DA_W_DISABLE BIT(28) +#define BIT_DDMACH2_CHKSUM_STS BIT(27) +#define BIT_DDMACH2_DDMA_MODE BIT(26) +#define BIT_DDMACH2_RESET_CHKSUM_STS BIT(25) +#define BIT_DDMACH2_CHKSUM_CONT BIT(24) + +#define BIT_SHIFT_DDMACH2_DLEN 0 +#define BIT_MASK_DDMACH2_DLEN 0x3ffff +#define BIT_DDMACH2_DLEN(x) \ + (((x) & BIT_MASK_DDMACH2_DLEN) << BIT_SHIFT_DDMACH2_DLEN) +#define BIT_GET_DDMACH2_DLEN(x) \ + (((x) >> BIT_SHIFT_DDMACH2_DLEN) & BIT_MASK_DDMACH2_DLEN) + +/* 2 REG_DDMA_CH3SA (Offset 0x1230) */ + +#define BIT_SHIFT_DDMACH3_SA 0 +#define BIT_MASK_DDMACH3_SA 0xffffffffL +#define BIT_DDMACH3_SA(x) (((x) & BIT_MASK_DDMACH3_SA) << BIT_SHIFT_DDMACH3_SA) +#define BIT_GET_DDMACH3_SA(x) \ + (((x) >> BIT_SHIFT_DDMACH3_SA) & BIT_MASK_DDMACH3_SA) + +/* 2 REG_DDMA_CH3DA (Offset 0x1234) */ + +#define BIT_SHIFT_DDMACH3_DA 0 +#define BIT_MASK_DDMACH3_DA 0xffffffffL +#define BIT_DDMACH3_DA(x) (((x) & BIT_MASK_DDMACH3_DA) << BIT_SHIFT_DDMACH3_DA) +#define BIT_GET_DDMACH3_DA(x) \ + (((x) >> BIT_SHIFT_DDMACH3_DA) & BIT_MASK_DDMACH3_DA) + +/* 2 REG_DDMA_CH3CTRL (Offset 0x1238) */ + +#define BIT_DDMACH3_OWN BIT(31) +#define BIT_DDMACH3_CHKSUM_EN BIT(29) +#define BIT_DDMACH3_DA_W_DISABLE BIT(28) +#define BIT_DDMACH3_CHKSUM_STS BIT(27) +#define BIT_DDMACH3_DDMA_MODE BIT(26) +#define BIT_DDMACH3_RESET_CHKSUM_STS BIT(25) +#define BIT_DDMACH3_CHKSUM_CONT BIT(24) + +#define BIT_SHIFT_DDMACH3_DLEN 0 +#define BIT_MASK_DDMACH3_DLEN 0x3ffff +#define BIT_DDMACH3_DLEN(x) \ + (((x) & BIT_MASK_DDMACH3_DLEN) << BIT_SHIFT_DDMACH3_DLEN) +#define BIT_GET_DDMACH3_DLEN(x) \ + (((x) >> BIT_SHIFT_DDMACH3_DLEN) & BIT_MASK_DDMACH3_DLEN) + +/* 2 REG_DDMA_CH4SA (Offset 0x1240) */ + +#define BIT_SHIFT_DDMACH4_SA 0 +#define BIT_MASK_DDMACH4_SA 0xffffffffL +#define BIT_DDMACH4_SA(x) (((x) & BIT_MASK_DDMACH4_SA) << BIT_SHIFT_DDMACH4_SA) +#define BIT_GET_DDMACH4_SA(x) \ + (((x) >> BIT_SHIFT_DDMACH4_SA) & BIT_MASK_DDMACH4_SA) + +/* 2 REG_DDMA_CH4DA (Offset 0x1244) */ + +#define BIT_SHIFT_DDMACH4_DA 0 +#define BIT_MASK_DDMACH4_DA 0xffffffffL +#define BIT_DDMACH4_DA(x) (((x) & BIT_MASK_DDMACH4_DA) << BIT_SHIFT_DDMACH4_DA) +#define BIT_GET_DDMACH4_DA(x) \ + (((x) >> BIT_SHIFT_DDMACH4_DA) & BIT_MASK_DDMACH4_DA) + +/* 2 REG_DDMA_CH4CTRL (Offset 0x1248) */ + +#define BIT_DDMACH4_OWN BIT(31) +#define BIT_DDMACH4_CHKSUM_EN BIT(29) +#define BIT_DDMACH4_DA_W_DISABLE BIT(28) +#define BIT_DDMACH4_CHKSUM_STS BIT(27) +#define BIT_DDMACH4_DDMA_MODE BIT(26) +#define BIT_DDMACH4_RESET_CHKSUM_STS BIT(25) +#define BIT_DDMACH4_CHKSUM_CONT BIT(24) + +#define BIT_SHIFT_DDMACH4_DLEN 0 +#define BIT_MASK_DDMACH4_DLEN 0x3ffff +#define BIT_DDMACH4_DLEN(x) \ + (((x) & BIT_MASK_DDMACH4_DLEN) << BIT_SHIFT_DDMACH4_DLEN) +#define BIT_GET_DDMACH4_DLEN(x) \ + (((x) >> BIT_SHIFT_DDMACH4_DLEN) & BIT_MASK_DDMACH4_DLEN) + +/* 2 REG_DDMA_CH5SA (Offset 0x1250) */ + +#define BIT_SHIFT_DDMACH5_SA 0 +#define BIT_MASK_DDMACH5_SA 0xffffffffL +#define BIT_DDMACH5_SA(x) (((x) & BIT_MASK_DDMACH5_SA) << BIT_SHIFT_DDMACH5_SA) +#define BIT_GET_DDMACH5_SA(x) \ + (((x) >> BIT_SHIFT_DDMACH5_SA) & BIT_MASK_DDMACH5_SA) + +/* 2 REG_DDMA_CH5DA (Offset 0x1254) */ + +#define BIT_DDMACH5_OWN BIT(31) +#define BIT_DDMACH5_CHKSUM_EN BIT(29) +#define BIT_DDMACH5_DA_W_DISABLE BIT(28) +#define BIT_DDMACH5_CHKSUM_STS BIT(27) +#define BIT_DDMACH5_DDMA_MODE BIT(26) +#define BIT_DDMACH5_RESET_CHKSUM_STS BIT(25) +#define BIT_DDMACH5_CHKSUM_CONT BIT(24) + +#define BIT_SHIFT_DDMACH5_DA 0 +#define BIT_MASK_DDMACH5_DA 0xffffffffL +#define BIT_DDMACH5_DA(x) (((x) & BIT_MASK_DDMACH5_DA) << BIT_SHIFT_DDMACH5_DA) +#define BIT_GET_DDMACH5_DA(x) \ + (((x) >> BIT_SHIFT_DDMACH5_DA) & BIT_MASK_DDMACH5_DA) + +#define BIT_SHIFT_DDMACH5_DLEN 0 +#define BIT_MASK_DDMACH5_DLEN 0x3ffff +#define BIT_DDMACH5_DLEN(x) \ + (((x) & BIT_MASK_DDMACH5_DLEN) << BIT_SHIFT_DDMACH5_DLEN) +#define BIT_GET_DDMACH5_DLEN(x) \ + (((x) >> BIT_SHIFT_DDMACH5_DLEN) & BIT_MASK_DDMACH5_DLEN) + +/* 2 REG_DDMA_INT_MSK (Offset 0x12E0) */ + +#define BIT_DDMACH5_MSK BIT(5) +#define BIT_DDMACH4_MSK BIT(4) +#define BIT_DDMACH3_MSK BIT(3) +#define BIT_DDMACH2_MSK BIT(2) +#define BIT_DDMACH1_MSK BIT(1) +#define BIT_DDMACH0_MSK BIT(0) + +/* 2 REG_DDMA_CHSTATUS (Offset 0x12E8) */ + +#define BIT_DDMACH5_BUSY BIT(5) +#define BIT_DDMACH4_BUSY BIT(4) +#define BIT_DDMACH3_BUSY BIT(3) +#define BIT_DDMACH2_BUSY BIT(2) +#define BIT_DDMACH1_BUSY BIT(1) +#define BIT_DDMACH0_BUSY BIT(0) + +/* 2 REG_DDMA_CHKSUM (Offset 0x12F0) */ + +#define BIT_SHIFT_IDDMA0_CHKSUM 0 +#define BIT_MASK_IDDMA0_CHKSUM 0xffff +#define BIT_IDDMA0_CHKSUM(x) \ + (((x) & BIT_MASK_IDDMA0_CHKSUM) << BIT_SHIFT_IDDMA0_CHKSUM) +#define BIT_GET_IDDMA0_CHKSUM(x) \ + (((x) >> BIT_SHIFT_IDDMA0_CHKSUM) & BIT_MASK_IDDMA0_CHKSUM) + +/* 2 REG_DDMA_MONITOR (Offset 0x12FC) */ + +#define BIT_IDDMA0_PERMU_UNDERFLOW BIT(14) +#define BIT_IDDMA0_FIFO_UNDERFLOW BIT(13) +#define BIT_IDDMA0_FIFO_OVERFLOW BIT(12) +#define BIT_ECRC_EN_V1 BIT(7) +#define BIT_MDIO_RFLAG_V1 BIT(6) +#define BIT_CH5_ERR BIT(5) +#define BIT_MDIO_WFLAG_V1 BIT(5) +#define BIT_CH4_ERR BIT(4) +#define BIT_CH3_ERR BIT(3) +#define BIT_CH2_ERR BIT(2) +#define BIT_CH1_ERR BIT(1) +#define BIT_CH0_ERR BIT(0) + +/* 2 REG_STC_INT_CS (Offset 0x1300) */ + +#define BIT_STC_INT_EN BIT(31) + +#define BIT_SHIFT_STC_INT_FLAG 16 +#define BIT_MASK_STC_INT_FLAG 0xff +#define BIT_STC_INT_FLAG(x) \ + (((x) & BIT_MASK_STC_INT_FLAG) << BIT_SHIFT_STC_INT_FLAG) +#define BIT_GET_STC_INT_FLAG(x) \ + (((x) >> BIT_SHIFT_STC_INT_FLAG) & BIT_MASK_STC_INT_FLAG) + +#define BIT_SHIFT_STC_INT_IDX 8 +#define BIT_MASK_STC_INT_IDX 0x7 +#define BIT_STC_INT_IDX(x) \ + (((x) & BIT_MASK_STC_INT_IDX) << BIT_SHIFT_STC_INT_IDX) +#define BIT_GET_STC_INT_IDX(x) \ + (((x) >> BIT_SHIFT_STC_INT_IDX) & BIT_MASK_STC_INT_IDX) + +#define BIT_SHIFT_STC_INT_REALTIME_CS 0 +#define BIT_MASK_STC_INT_REALTIME_CS 0x3f +#define BIT_STC_INT_REALTIME_CS(x) \ + (((x) & BIT_MASK_STC_INT_REALTIME_CS) << BIT_SHIFT_STC_INT_REALTIME_CS) +#define BIT_GET_STC_INT_REALTIME_CS(x) \ + (((x) >> BIT_SHIFT_STC_INT_REALTIME_CS) & BIT_MASK_STC_INT_REALTIME_CS) + +/* 2 REG_ST_INT_CFG (Offset 0x1304) */ + +#define BIT_STC_INT_GRP_EN BIT(31) + +#define BIT_SHIFT_STC_INT_EXPECT_LS 8 +#define BIT_MASK_STC_INT_EXPECT_LS 0x3f +#define BIT_STC_INT_EXPECT_LS(x) \ + (((x) & BIT_MASK_STC_INT_EXPECT_LS) << BIT_SHIFT_STC_INT_EXPECT_LS) +#define BIT_GET_STC_INT_EXPECT_LS(x) \ + (((x) >> BIT_SHIFT_STC_INT_EXPECT_LS) & BIT_MASK_STC_INT_EXPECT_LS) + +#define BIT_SHIFT_STC_INT_EXPECT_CS 0 +#define BIT_MASK_STC_INT_EXPECT_CS 0x3f +#define BIT_STC_INT_EXPECT_CS(x) \ + (((x) & BIT_MASK_STC_INT_EXPECT_CS) << BIT_SHIFT_STC_INT_EXPECT_CS) +#define BIT_GET_STC_INT_EXPECT_CS(x) \ + (((x) >> BIT_SHIFT_STC_INT_EXPECT_CS) & BIT_MASK_STC_INT_EXPECT_CS) + +/* 2 REG_CMU_DLY_CTRL (Offset 0x1310) */ + +#define BIT_CMU_DLY_EN BIT(31) +#define BIT_CMU_DLY_MODE BIT(30) + +#define BIT_SHIFT_CMU_DLY_PRE_DIV 0 +#define BIT_MASK_CMU_DLY_PRE_DIV 0xff +#define BIT_CMU_DLY_PRE_DIV(x) \ + (((x) & BIT_MASK_CMU_DLY_PRE_DIV) << BIT_SHIFT_CMU_DLY_PRE_DIV) +#define BIT_GET_CMU_DLY_PRE_DIV(x) \ + (((x) >> BIT_SHIFT_CMU_DLY_PRE_DIV) & BIT_MASK_CMU_DLY_PRE_DIV) + +/* 2 REG_CMU_DLY_CFG (Offset 0x1314) */ + +#define BIT_SHIFT_CMU_DLY_LTR_A2I 24 +#define BIT_MASK_CMU_DLY_LTR_A2I 0xff +#define BIT_CMU_DLY_LTR_A2I(x) \ + (((x) & BIT_MASK_CMU_DLY_LTR_A2I) << BIT_SHIFT_CMU_DLY_LTR_A2I) +#define BIT_GET_CMU_DLY_LTR_A2I(x) \ + (((x) >> BIT_SHIFT_CMU_DLY_LTR_A2I) & BIT_MASK_CMU_DLY_LTR_A2I) + +#define BIT_SHIFT_CMU_DLY_LTR_I2A 16 +#define BIT_MASK_CMU_DLY_LTR_I2A 0xff +#define BIT_CMU_DLY_LTR_I2A(x) \ + (((x) & BIT_MASK_CMU_DLY_LTR_I2A) << BIT_SHIFT_CMU_DLY_LTR_I2A) +#define BIT_GET_CMU_DLY_LTR_I2A(x) \ + (((x) >> BIT_SHIFT_CMU_DLY_LTR_I2A) & BIT_MASK_CMU_DLY_LTR_I2A) + +#define BIT_SHIFT_CMU_DLY_LTR_IDLE 8 +#define BIT_MASK_CMU_DLY_LTR_IDLE 0xff +#define BIT_CMU_DLY_LTR_IDLE(x) \ + (((x) & BIT_MASK_CMU_DLY_LTR_IDLE) << BIT_SHIFT_CMU_DLY_LTR_IDLE) +#define BIT_GET_CMU_DLY_LTR_IDLE(x) \ + (((x) >> BIT_SHIFT_CMU_DLY_LTR_IDLE) & BIT_MASK_CMU_DLY_LTR_IDLE) + +#define BIT_SHIFT_CMU_DLY_LTR_ACT 0 +#define BIT_MASK_CMU_DLY_LTR_ACT 0xff +#define BIT_CMU_DLY_LTR_ACT(x) \ + (((x) & BIT_MASK_CMU_DLY_LTR_ACT) << BIT_SHIFT_CMU_DLY_LTR_ACT) +#define BIT_GET_CMU_DLY_LTR_ACT(x) \ + (((x) >> BIT_SHIFT_CMU_DLY_LTR_ACT) & BIT_MASK_CMU_DLY_LTR_ACT) + +/* 2 REG_H2CQ_TXBD_DESA (Offset 0x1320) */ + +#define BIT_SHIFT_H2CQ_TXBD_DESA 0 +#define BIT_MASK_H2CQ_TXBD_DESA 0xffffffffffffffffL +#define BIT_H2CQ_TXBD_DESA(x) \ + (((x) & BIT_MASK_H2CQ_TXBD_DESA) << BIT_SHIFT_H2CQ_TXBD_DESA) +#define BIT_GET_H2CQ_TXBD_DESA(x) \ + (((x) >> BIT_SHIFT_H2CQ_TXBD_DESA) & BIT_MASK_H2CQ_TXBD_DESA) + +/* 2 REG_H2CQ_TXBD_NUM (Offset 0x1328) */ + +#define BIT_PCIE_H2CQ_FLAG BIT(14) + +/* 2 REG_H2CQ_TXBD_NUM (Offset 0x1328) */ + +#define BIT_SHIFT_H2CQ_DESC_MODE 12 +#define BIT_MASK_H2CQ_DESC_MODE 0x3 +#define BIT_H2CQ_DESC_MODE(x) \ + (((x) & BIT_MASK_H2CQ_DESC_MODE) << BIT_SHIFT_H2CQ_DESC_MODE) +#define BIT_GET_H2CQ_DESC_MODE(x) \ + (((x) >> BIT_SHIFT_H2CQ_DESC_MODE) & BIT_MASK_H2CQ_DESC_MODE) + +#define BIT_SHIFT_H2CQ_DESC_NUM 0 +#define BIT_MASK_H2CQ_DESC_NUM 0xfff +#define BIT_H2CQ_DESC_NUM(x) \ + (((x) & BIT_MASK_H2CQ_DESC_NUM) << BIT_SHIFT_H2CQ_DESC_NUM) +#define BIT_GET_H2CQ_DESC_NUM(x) \ + (((x) >> BIT_SHIFT_H2CQ_DESC_NUM) & BIT_MASK_H2CQ_DESC_NUM) + +/* 2 REG_H2CQ_TXBD_IDX (Offset 0x132C) */ + +#define BIT_SHIFT_H2CQ_HW_IDX 16 +#define BIT_MASK_H2CQ_HW_IDX 0xfff +#define BIT_H2CQ_HW_IDX(x) \ + (((x) & BIT_MASK_H2CQ_HW_IDX) << BIT_SHIFT_H2CQ_HW_IDX) +#define BIT_GET_H2CQ_HW_IDX(x) \ + (((x) >> BIT_SHIFT_H2CQ_HW_IDX) & BIT_MASK_H2CQ_HW_IDX) + +#define BIT_SHIFT_H2CQ_HOST_IDX 0 +#define BIT_MASK_H2CQ_HOST_IDX 0xfff +#define BIT_H2CQ_HOST_IDX(x) \ + (((x) & BIT_MASK_H2CQ_HOST_IDX) << BIT_SHIFT_H2CQ_HOST_IDX) +#define BIT_GET_H2CQ_HOST_IDX(x) \ + (((x) >> BIT_SHIFT_H2CQ_HOST_IDX) & BIT_MASK_H2CQ_HOST_IDX) + +/* 2 REG_H2CQ_CSR (Offset 0x1330) */ + +#define BIT_H2CQ_FULL BIT(31) +#define BIT_CLR_H2CQ_HOST_IDX BIT(16) +#define BIT_CLR_H2CQ_HW_IDX BIT(8) + +/* 2 REG_CHANGE_PCIE_SPEED (Offset 0x1350) */ + +#define BIT_CHANGE_PCIE_SPEED BIT(18) + +/* 2 REG_CHANGE_PCIE_SPEED (Offset 0x1350) */ + +#define BIT_SHIFT_GEN1_GEN2 16 +#define BIT_MASK_GEN1_GEN2 0x3 +#define BIT_GEN1_GEN2(x) (((x) & BIT_MASK_GEN1_GEN2) << BIT_SHIFT_GEN1_GEN2) +#define BIT_GET_GEN1_GEN2(x) (((x) >> BIT_SHIFT_GEN1_GEN2) & BIT_MASK_GEN1_GEN2) + +/* 2 REG_CHANGE_PCIE_SPEED (Offset 0x1350) */ + +#define BIT_SHIFT_AUTO_HANG_RELEASE 0 +#define BIT_MASK_AUTO_HANG_RELEASE 0x7 +#define BIT_AUTO_HANG_RELEASE(x) \ + (((x) & BIT_MASK_AUTO_HANG_RELEASE) << BIT_SHIFT_AUTO_HANG_RELEASE) +#define BIT_GET_AUTO_HANG_RELEASE(x) \ + (((x) >> BIT_SHIFT_AUTO_HANG_RELEASE) & BIT_MASK_AUTO_HANG_RELEASE) + +/* 2 REG_OLD_DEHANG (Offset 0x13F4) */ + +#define BIT_OLD_DEHANG BIT(1) + +/* 2 REG_Q0_Q1_INFO (Offset 0x1400) */ + +#define BIT_SHIFT_AC1_PKT_INFO 16 +#define BIT_MASK_AC1_PKT_INFO 0xfff +#define BIT_AC1_PKT_INFO(x) \ + (((x) & BIT_MASK_AC1_PKT_INFO) << BIT_SHIFT_AC1_PKT_INFO) +#define BIT_GET_AC1_PKT_INFO(x) \ + (((x) >> BIT_SHIFT_AC1_PKT_INFO) & BIT_MASK_AC1_PKT_INFO) + +#define BIT_SHIFT_AC0_PKT_INFO 0 +#define BIT_MASK_AC0_PKT_INFO 0xfff +#define BIT_AC0_PKT_INFO(x) \ + (((x) & BIT_MASK_AC0_PKT_INFO) << BIT_SHIFT_AC0_PKT_INFO) +#define BIT_GET_AC0_PKT_INFO(x) \ + (((x) >> BIT_SHIFT_AC0_PKT_INFO) & BIT_MASK_AC0_PKT_INFO) + +/* 2 REG_Q2_Q3_INFO (Offset 0x1404) */ + +#define BIT_SHIFT_AC3_PKT_INFO 16 +#define BIT_MASK_AC3_PKT_INFO 0xfff +#define BIT_AC3_PKT_INFO(x) \ + (((x) & BIT_MASK_AC3_PKT_INFO) << BIT_SHIFT_AC3_PKT_INFO) +#define BIT_GET_AC3_PKT_INFO(x) \ + (((x) >> BIT_SHIFT_AC3_PKT_INFO) & BIT_MASK_AC3_PKT_INFO) + +#define BIT_SHIFT_AC2_PKT_INFO 0 +#define BIT_MASK_AC2_PKT_INFO 0xfff +#define BIT_AC2_PKT_INFO(x) \ + (((x) & BIT_MASK_AC2_PKT_INFO) << BIT_SHIFT_AC2_PKT_INFO) +#define BIT_GET_AC2_PKT_INFO(x) \ + (((x) >> BIT_SHIFT_AC2_PKT_INFO) & BIT_MASK_AC2_PKT_INFO) + +/* 2 REG_Q4_Q5_INFO (Offset 0x1408) */ + +#define BIT_SHIFT_AC5_PKT_INFO 16 +#define BIT_MASK_AC5_PKT_INFO 0xfff +#define BIT_AC5_PKT_INFO(x) \ + (((x) & BIT_MASK_AC5_PKT_INFO) << BIT_SHIFT_AC5_PKT_INFO) +#define BIT_GET_AC5_PKT_INFO(x) \ + (((x) >> BIT_SHIFT_AC5_PKT_INFO) & BIT_MASK_AC5_PKT_INFO) + +#define BIT_SHIFT_AC4_PKT_INFO 0 +#define BIT_MASK_AC4_PKT_INFO 0xfff +#define BIT_AC4_PKT_INFO(x) \ + (((x) & BIT_MASK_AC4_PKT_INFO) << BIT_SHIFT_AC4_PKT_INFO) +#define BIT_GET_AC4_PKT_INFO(x) \ + (((x) >> BIT_SHIFT_AC4_PKT_INFO) & BIT_MASK_AC4_PKT_INFO) + +/* 2 REG_Q6_Q7_INFO (Offset 0x140C) */ + +#define BIT_SHIFT_AC7_PKT_INFO 16 +#define BIT_MASK_AC7_PKT_INFO 0xfff +#define BIT_AC7_PKT_INFO(x) \ + (((x) & BIT_MASK_AC7_PKT_INFO) << BIT_SHIFT_AC7_PKT_INFO) +#define BIT_GET_AC7_PKT_INFO(x) \ + (((x) >> BIT_SHIFT_AC7_PKT_INFO) & BIT_MASK_AC7_PKT_INFO) + +#define BIT_SHIFT_AC6_PKT_INFO 0 +#define BIT_MASK_AC6_PKT_INFO 0xfff +#define BIT_AC6_PKT_INFO(x) \ + (((x) & BIT_MASK_AC6_PKT_INFO) << BIT_SHIFT_AC6_PKT_INFO) +#define BIT_GET_AC6_PKT_INFO(x) \ + (((x) >> BIT_SHIFT_AC6_PKT_INFO) & BIT_MASK_AC6_PKT_INFO) + +/* 2 REG_MGQ_HIQ_INFO (Offset 0x1410) */ + +#define BIT_SHIFT_HIQ_PKT_INFO 16 +#define BIT_MASK_HIQ_PKT_INFO 0xfff +#define BIT_HIQ_PKT_INFO(x) \ + (((x) & BIT_MASK_HIQ_PKT_INFO) << BIT_SHIFT_HIQ_PKT_INFO) +#define BIT_GET_HIQ_PKT_INFO(x) \ + (((x) >> BIT_SHIFT_HIQ_PKT_INFO) & BIT_MASK_HIQ_PKT_INFO) + +#define BIT_SHIFT_MGQ_PKT_INFO 0 +#define BIT_MASK_MGQ_PKT_INFO 0xfff +#define BIT_MGQ_PKT_INFO(x) \ + (((x) & BIT_MASK_MGQ_PKT_INFO) << BIT_SHIFT_MGQ_PKT_INFO) +#define BIT_GET_MGQ_PKT_INFO(x) \ + (((x) >> BIT_SHIFT_MGQ_PKT_INFO) & BIT_MASK_MGQ_PKT_INFO) + +/* 2 REG_CMDQ_BCNQ_INFO (Offset 0x1414) */ + +#define BIT_SHIFT_CMDQ_PKT_INFO 16 +#define BIT_MASK_CMDQ_PKT_INFO 0xfff +#define BIT_CMDQ_PKT_INFO(x) \ + (((x) & BIT_MASK_CMDQ_PKT_INFO) << BIT_SHIFT_CMDQ_PKT_INFO) +#define BIT_GET_CMDQ_PKT_INFO(x) \ + (((x) >> BIT_SHIFT_CMDQ_PKT_INFO) & BIT_MASK_CMDQ_PKT_INFO) + +/* 2 REG_CMDQ_BCNQ_INFO (Offset 0x1414) */ + +#define BIT_SHIFT_BCNQ_PKT_INFO 0 +#define BIT_MASK_BCNQ_PKT_INFO 0xfff +#define BIT_BCNQ_PKT_INFO(x) \ + (((x) & BIT_MASK_BCNQ_PKT_INFO) << BIT_SHIFT_BCNQ_PKT_INFO) +#define BIT_GET_BCNQ_PKT_INFO(x) \ + (((x) >> BIT_SHIFT_BCNQ_PKT_INFO) & BIT_MASK_BCNQ_PKT_INFO) + +/* 2 REG_USEREG_SETTING (Offset 0x1420) */ + +#define BIT_NDPA_USEREG BIT(21) + +#define BIT_SHIFT_RETRY_USEREG 19 +#define BIT_MASK_RETRY_USEREG 0x3 +#define BIT_RETRY_USEREG(x) \ + (((x) & BIT_MASK_RETRY_USEREG) << BIT_SHIFT_RETRY_USEREG) +#define BIT_GET_RETRY_USEREG(x) \ + (((x) >> BIT_SHIFT_RETRY_USEREG) & BIT_MASK_RETRY_USEREG) + +#define BIT_SHIFT_TRYPKT_USEREG 17 +#define BIT_MASK_TRYPKT_USEREG 0x3 +#define BIT_TRYPKT_USEREG(x) \ + (((x) & BIT_MASK_TRYPKT_USEREG) << BIT_SHIFT_TRYPKT_USEREG) +#define BIT_GET_TRYPKT_USEREG(x) \ + (((x) >> BIT_SHIFT_TRYPKT_USEREG) & BIT_MASK_TRYPKT_USEREG) + +#define BIT_CTLPKT_USEREG BIT(16) + +/* 2 REG_AESIV_SETTING (Offset 0x1424) */ + +#define BIT_SHIFT_AESIV_OFFSET 0 +#define BIT_MASK_AESIV_OFFSET 0xfff +#define BIT_AESIV_OFFSET(x) \ + (((x) & BIT_MASK_AESIV_OFFSET) << BIT_SHIFT_AESIV_OFFSET) +#define BIT_GET_AESIV_OFFSET(x) \ + (((x) >> BIT_SHIFT_AESIV_OFFSET) & BIT_MASK_AESIV_OFFSET) + +/* 2 REG_BF0_TIME_SETTING (Offset 0x1428) */ + +#define BIT_BF0_TIMER_SET BIT(31) +#define BIT_BF0_TIMER_CLR BIT(30) +#define BIT_BF0_UPDATE_EN BIT(29) +#define BIT_BF0_TIMER_EN BIT(28) + +#define BIT_SHIFT_BF0_PRETIME_OVER 16 +#define BIT_MASK_BF0_PRETIME_OVER 0xfff +#define BIT_BF0_PRETIME_OVER(x) \ + (((x) & BIT_MASK_BF0_PRETIME_OVER) << BIT_SHIFT_BF0_PRETIME_OVER) +#define BIT_GET_BF0_PRETIME_OVER(x) \ + (((x) >> BIT_SHIFT_BF0_PRETIME_OVER) & BIT_MASK_BF0_PRETIME_OVER) + +#define BIT_SHIFT_BF0_LIFETIME 0 +#define BIT_MASK_BF0_LIFETIME 0xffff +#define BIT_BF0_LIFETIME(x) \ + (((x) & BIT_MASK_BF0_LIFETIME) << BIT_SHIFT_BF0_LIFETIME) +#define BIT_GET_BF0_LIFETIME(x) \ + (((x) >> BIT_SHIFT_BF0_LIFETIME) & BIT_MASK_BF0_LIFETIME) + +/* 2 REG_BF1_TIME_SETTING (Offset 0x142C) */ + +#define BIT_BF1_TIMER_SET BIT(31) +#define BIT_BF1_TIMER_CLR BIT(30) +#define BIT_BF1_UPDATE_EN BIT(29) +#define BIT_BF1_TIMER_EN BIT(28) + +#define BIT_SHIFT_BF1_PRETIME_OVER 16 +#define BIT_MASK_BF1_PRETIME_OVER 0xfff +#define BIT_BF1_PRETIME_OVER(x) \ + (((x) & BIT_MASK_BF1_PRETIME_OVER) << BIT_SHIFT_BF1_PRETIME_OVER) +#define BIT_GET_BF1_PRETIME_OVER(x) \ + (((x) >> BIT_SHIFT_BF1_PRETIME_OVER) & BIT_MASK_BF1_PRETIME_OVER) + +#define BIT_SHIFT_BF1_LIFETIME 0 +#define BIT_MASK_BF1_LIFETIME 0xffff +#define BIT_BF1_LIFETIME(x) \ + (((x) & BIT_MASK_BF1_LIFETIME) << BIT_SHIFT_BF1_LIFETIME) +#define BIT_GET_BF1_LIFETIME(x) \ + (((x) >> BIT_SHIFT_BF1_LIFETIME) & BIT_MASK_BF1_LIFETIME) + +/* 2 REG_BF_TIMEOUT_EN (Offset 0x1430) */ + +#define BIT_EN_VHT_LDPC BIT(9) +#define BIT_EN_HT_LDPC BIT(8) +#define BIT_BF1_TIMEOUT_EN BIT(1) +#define BIT_BF0_TIMEOUT_EN BIT(0) + +/* 2 REG_MACID_RELEASE0 (Offset 0x1434) */ + +#define BIT_SHIFT_MACID31_0_RELEASE 0 +#define BIT_MASK_MACID31_0_RELEASE 0xffffffffL +#define BIT_MACID31_0_RELEASE(x) \ + (((x) & BIT_MASK_MACID31_0_RELEASE) << BIT_SHIFT_MACID31_0_RELEASE) +#define BIT_GET_MACID31_0_RELEASE(x) \ + (((x) >> BIT_SHIFT_MACID31_0_RELEASE) & BIT_MASK_MACID31_0_RELEASE) + +/* 2 REG_MACID_RELEASE1 (Offset 0x1438) */ + +#define BIT_SHIFT_MACID63_32_RELEASE 0 +#define BIT_MASK_MACID63_32_RELEASE 0xffffffffL +#define BIT_MACID63_32_RELEASE(x) \ + (((x) & BIT_MASK_MACID63_32_RELEASE) << BIT_SHIFT_MACID63_32_RELEASE) +#define BIT_GET_MACID63_32_RELEASE(x) \ + (((x) >> BIT_SHIFT_MACID63_32_RELEASE) & BIT_MASK_MACID63_32_RELEASE) + +/* 2 REG_MACID_RELEASE2 (Offset 0x143C) */ + +#define BIT_SHIFT_MACID95_64_RELEASE 0 +#define BIT_MASK_MACID95_64_RELEASE 0xffffffffL +#define BIT_MACID95_64_RELEASE(x) \ + (((x) & BIT_MASK_MACID95_64_RELEASE) << BIT_SHIFT_MACID95_64_RELEASE) +#define BIT_GET_MACID95_64_RELEASE(x) \ + (((x) >> BIT_SHIFT_MACID95_64_RELEASE) & BIT_MASK_MACID95_64_RELEASE) + +/* 2 REG_MACID_RELEASE3 (Offset 0x1440) */ + +#define BIT_SHIFT_MACID127_96_RELEASE 0 +#define BIT_MASK_MACID127_96_RELEASE 0xffffffffL +#define BIT_MACID127_96_RELEASE(x) \ + (((x) & BIT_MASK_MACID127_96_RELEASE) << BIT_SHIFT_MACID127_96_RELEASE) +#define BIT_GET_MACID127_96_RELEASE(x) \ + (((x) >> BIT_SHIFT_MACID127_96_RELEASE) & BIT_MASK_MACID127_96_RELEASE) + +/* 2 REG_MACID_RELEASE_SETTING (Offset 0x1444) */ + +#define BIT_MACID_VALUE BIT(7) + +#define BIT_SHIFT_MACID_OFFSET 0 +#define BIT_MASK_MACID_OFFSET 0x7f +#define BIT_MACID_OFFSET(x) \ + (((x) & BIT_MASK_MACID_OFFSET) << BIT_SHIFT_MACID_OFFSET) +#define BIT_GET_MACID_OFFSET(x) \ + (((x) >> BIT_SHIFT_MACID_OFFSET) & BIT_MASK_MACID_OFFSET) + +/* 2 REG_FAST_EDCA_VOVI_SETTING (Offset 0x1448) */ + +#define BIT_SHIFT_VI_FAST_EDCA_TO 24 +#define BIT_MASK_VI_FAST_EDCA_TO 0xff +#define BIT_VI_FAST_EDCA_TO(x) \ + (((x) & BIT_MASK_VI_FAST_EDCA_TO) << BIT_SHIFT_VI_FAST_EDCA_TO) +#define BIT_GET_VI_FAST_EDCA_TO(x) \ + (((x) >> BIT_SHIFT_VI_FAST_EDCA_TO) & BIT_MASK_VI_FAST_EDCA_TO) + +#define BIT_VI_THRESHOLD_SEL BIT(23) + +#define BIT_SHIFT_VI_FAST_EDCA_PKT_TH 16 +#define BIT_MASK_VI_FAST_EDCA_PKT_TH 0x7f +#define BIT_VI_FAST_EDCA_PKT_TH(x) \ + (((x) & BIT_MASK_VI_FAST_EDCA_PKT_TH) << BIT_SHIFT_VI_FAST_EDCA_PKT_TH) +#define BIT_GET_VI_FAST_EDCA_PKT_TH(x) \ + (((x) >> BIT_SHIFT_VI_FAST_EDCA_PKT_TH) & BIT_MASK_VI_FAST_EDCA_PKT_TH) + +#define BIT_SHIFT_VO_FAST_EDCA_TO 8 +#define BIT_MASK_VO_FAST_EDCA_TO 0xff +#define BIT_VO_FAST_EDCA_TO(x) \ + (((x) & BIT_MASK_VO_FAST_EDCA_TO) << BIT_SHIFT_VO_FAST_EDCA_TO) +#define BIT_GET_VO_FAST_EDCA_TO(x) \ + (((x) >> BIT_SHIFT_VO_FAST_EDCA_TO) & BIT_MASK_VO_FAST_EDCA_TO) + +#define BIT_VO_THRESHOLD_SEL BIT(7) + +#define BIT_SHIFT_VO_FAST_EDCA_PKT_TH 0 +#define BIT_MASK_VO_FAST_EDCA_PKT_TH 0x7f +#define BIT_VO_FAST_EDCA_PKT_TH(x) \ + (((x) & BIT_MASK_VO_FAST_EDCA_PKT_TH) << BIT_SHIFT_VO_FAST_EDCA_PKT_TH) +#define BIT_GET_VO_FAST_EDCA_PKT_TH(x) \ + (((x) >> BIT_SHIFT_VO_FAST_EDCA_PKT_TH) & BIT_MASK_VO_FAST_EDCA_PKT_TH) + +/* 2 REG_FAST_EDCA_BEBK_SETTING (Offset 0x144C) */ + +#define BIT_SHIFT_BK_FAST_EDCA_TO 24 +#define BIT_MASK_BK_FAST_EDCA_TO 0xff +#define BIT_BK_FAST_EDCA_TO(x) \ + (((x) & BIT_MASK_BK_FAST_EDCA_TO) << BIT_SHIFT_BK_FAST_EDCA_TO) +#define BIT_GET_BK_FAST_EDCA_TO(x) \ + (((x) >> BIT_SHIFT_BK_FAST_EDCA_TO) & BIT_MASK_BK_FAST_EDCA_TO) + +#define BIT_BK_THRESHOLD_SEL BIT(23) + +#define BIT_SHIFT_BK_FAST_EDCA_PKT_TH 16 +#define BIT_MASK_BK_FAST_EDCA_PKT_TH 0x7f +#define BIT_BK_FAST_EDCA_PKT_TH(x) \ + (((x) & BIT_MASK_BK_FAST_EDCA_PKT_TH) << BIT_SHIFT_BK_FAST_EDCA_PKT_TH) +#define BIT_GET_BK_FAST_EDCA_PKT_TH(x) \ + (((x) >> BIT_SHIFT_BK_FAST_EDCA_PKT_TH) & BIT_MASK_BK_FAST_EDCA_PKT_TH) + +#define BIT_SHIFT_BE_FAST_EDCA_TO 8 +#define BIT_MASK_BE_FAST_EDCA_TO 0xff +#define BIT_BE_FAST_EDCA_TO(x) \ + (((x) & BIT_MASK_BE_FAST_EDCA_TO) << BIT_SHIFT_BE_FAST_EDCA_TO) +#define BIT_GET_BE_FAST_EDCA_TO(x) \ + (((x) >> BIT_SHIFT_BE_FAST_EDCA_TO) & BIT_MASK_BE_FAST_EDCA_TO) + +#define BIT_BE_THRESHOLD_SEL BIT(7) + +#define BIT_SHIFT_BE_FAST_EDCA_PKT_TH 0 +#define BIT_MASK_BE_FAST_EDCA_PKT_TH 0x7f +#define BIT_BE_FAST_EDCA_PKT_TH(x) \ + (((x) & BIT_MASK_BE_FAST_EDCA_PKT_TH) << BIT_SHIFT_BE_FAST_EDCA_PKT_TH) +#define BIT_GET_BE_FAST_EDCA_PKT_TH(x) \ + (((x) >> BIT_SHIFT_BE_FAST_EDCA_PKT_TH) & BIT_MASK_BE_FAST_EDCA_PKT_TH) + +/* 2 REG_MACID_DROP0 (Offset 0x1450) */ + +#define BIT_SHIFT_MACID31_0_DROP 0 +#define BIT_MASK_MACID31_0_DROP 0xffffffffL +#define BIT_MACID31_0_DROP(x) \ + (((x) & BIT_MASK_MACID31_0_DROP) << BIT_SHIFT_MACID31_0_DROP) +#define BIT_GET_MACID31_0_DROP(x) \ + (((x) >> BIT_SHIFT_MACID31_0_DROP) & BIT_MASK_MACID31_0_DROP) + +/* 2 REG_MACID_DROP1 (Offset 0x1454) */ + +#define BIT_SHIFT_MACID63_32_DROP 0 +#define BIT_MASK_MACID63_32_DROP 0xffffffffL +#define BIT_MACID63_32_DROP(x) \ + (((x) & BIT_MASK_MACID63_32_DROP) << BIT_SHIFT_MACID63_32_DROP) +#define BIT_GET_MACID63_32_DROP(x) \ + (((x) >> BIT_SHIFT_MACID63_32_DROP) & BIT_MASK_MACID63_32_DROP) + +/* 2 REG_MACID_DROP2 (Offset 0x1458) */ + +#define BIT_SHIFT_MACID95_64_DROP 0 +#define BIT_MASK_MACID95_64_DROP 0xffffffffL +#define BIT_MACID95_64_DROP(x) \ + (((x) & BIT_MASK_MACID95_64_DROP) << BIT_SHIFT_MACID95_64_DROP) +#define BIT_GET_MACID95_64_DROP(x) \ + (((x) >> BIT_SHIFT_MACID95_64_DROP) & BIT_MASK_MACID95_64_DROP) + +/* 2 REG_MACID_DROP3 (Offset 0x145C) */ + +#define BIT_SHIFT_MACID127_96_DROP 0 +#define BIT_MASK_MACID127_96_DROP 0xffffffffL +#define BIT_MACID127_96_DROP(x) \ + (((x) & BIT_MASK_MACID127_96_DROP) << BIT_SHIFT_MACID127_96_DROP) +#define BIT_GET_MACID127_96_DROP(x) \ + (((x) >> BIT_SHIFT_MACID127_96_DROP) & BIT_MASK_MACID127_96_DROP) + +/* 2 REG_R_MACID_RELEASE_SUCCESS_0 (Offset 0x1460) */ + +#define BIT_SHIFT_R_MACID_RELEASE_SUCCESS_0 0 +#define BIT_MASK_R_MACID_RELEASE_SUCCESS_0 0xffffffffL +#define BIT_R_MACID_RELEASE_SUCCESS_0(x) \ + (((x) & BIT_MASK_R_MACID_RELEASE_SUCCESS_0) \ + << BIT_SHIFT_R_MACID_RELEASE_SUCCESS_0) +#define BIT_GET_R_MACID_RELEASE_SUCCESS_0(x) \ + (((x) >> BIT_SHIFT_R_MACID_RELEASE_SUCCESS_0) & \ + BIT_MASK_R_MACID_RELEASE_SUCCESS_0) + +/* 2 REG_R_MACID_RELEASE_SUCCESS_1 (Offset 0x1464) */ + +#define BIT_SHIFT_R_MACID_RELEASE_SUCCESS_1 0 +#define BIT_MASK_R_MACID_RELEASE_SUCCESS_1 0xffffffffL +#define BIT_R_MACID_RELEASE_SUCCESS_1(x) \ + (((x) & BIT_MASK_R_MACID_RELEASE_SUCCESS_1) \ + << BIT_SHIFT_R_MACID_RELEASE_SUCCESS_1) +#define BIT_GET_R_MACID_RELEASE_SUCCESS_1(x) \ + (((x) >> BIT_SHIFT_R_MACID_RELEASE_SUCCESS_1) & \ + BIT_MASK_R_MACID_RELEASE_SUCCESS_1) + +/* 2 REG_R_MACID_RELEASE_SUCCESS_2 (Offset 0x1468) */ + +#define BIT_SHIFT_R_MACID_RELEASE_SUCCESS_2 0 +#define BIT_MASK_R_MACID_RELEASE_SUCCESS_2 0xffffffffL +#define BIT_R_MACID_RELEASE_SUCCESS_2(x) \ + (((x) & BIT_MASK_R_MACID_RELEASE_SUCCESS_2) \ + << BIT_SHIFT_R_MACID_RELEASE_SUCCESS_2) +#define BIT_GET_R_MACID_RELEASE_SUCCESS_2(x) \ + (((x) >> BIT_SHIFT_R_MACID_RELEASE_SUCCESS_2) & \ + BIT_MASK_R_MACID_RELEASE_SUCCESS_2) + +/* 2 REG_R_MACID_RELEASE_SUCCESS_3 (Offset 0x146C) */ + +#define BIT_SHIFT_R_MACID_RELEASE_SUCCESS_3 0 +#define BIT_MASK_R_MACID_RELEASE_SUCCESS_3 0xffffffffL +#define BIT_R_MACID_RELEASE_SUCCESS_3(x) \ + (((x) & BIT_MASK_R_MACID_RELEASE_SUCCESS_3) \ + << BIT_SHIFT_R_MACID_RELEASE_SUCCESS_3) +#define BIT_GET_R_MACID_RELEASE_SUCCESS_3(x) \ + (((x) >> BIT_SHIFT_R_MACID_RELEASE_SUCCESS_3) & \ + BIT_MASK_R_MACID_RELEASE_SUCCESS_3) + +/* 2 REG_MGG_FIFO_CRTL (Offset 0x1470) */ + +#define BIT_R_MGG_FIFO_EN BIT(31) + +#define BIT_SHIFT_R_MGG_FIFO_PG_SIZE 28 +#define BIT_MASK_R_MGG_FIFO_PG_SIZE 0x7 +#define BIT_R_MGG_FIFO_PG_SIZE(x) \ + (((x) & BIT_MASK_R_MGG_FIFO_PG_SIZE) << BIT_SHIFT_R_MGG_FIFO_PG_SIZE) +#define BIT_GET_R_MGG_FIFO_PG_SIZE(x) \ + (((x) >> BIT_SHIFT_R_MGG_FIFO_PG_SIZE) & BIT_MASK_R_MGG_FIFO_PG_SIZE) + +#define BIT_SHIFT_R_MGG_FIFO_START_PG 16 +#define BIT_MASK_R_MGG_FIFO_START_PG 0xfff +#define BIT_R_MGG_FIFO_START_PG(x) \ + (((x) & BIT_MASK_R_MGG_FIFO_START_PG) << BIT_SHIFT_R_MGG_FIFO_START_PG) +#define BIT_GET_R_MGG_FIFO_START_PG(x) \ + (((x) >> BIT_SHIFT_R_MGG_FIFO_START_PG) & BIT_MASK_R_MGG_FIFO_START_PG) + +#define BIT_SHIFT_R_MGG_FIFO_SIZE 14 +#define BIT_MASK_R_MGG_FIFO_SIZE 0x3 +#define BIT_R_MGG_FIFO_SIZE(x) \ + (((x) & BIT_MASK_R_MGG_FIFO_SIZE) << BIT_SHIFT_R_MGG_FIFO_SIZE) +#define BIT_GET_R_MGG_FIFO_SIZE(x) \ + (((x) >> BIT_SHIFT_R_MGG_FIFO_SIZE) & BIT_MASK_R_MGG_FIFO_SIZE) + +#define BIT_R_MGG_FIFO_PAUSE BIT(13) + +#define BIT_SHIFT_R_MGG_FIFO_RPTR 8 +#define BIT_MASK_R_MGG_FIFO_RPTR 0x1f +#define BIT_R_MGG_FIFO_RPTR(x) \ + (((x) & BIT_MASK_R_MGG_FIFO_RPTR) << BIT_SHIFT_R_MGG_FIFO_RPTR) +#define BIT_GET_R_MGG_FIFO_RPTR(x) \ + (((x) >> BIT_SHIFT_R_MGG_FIFO_RPTR) & BIT_MASK_R_MGG_FIFO_RPTR) + +#define BIT_R_MGG_FIFO_OV BIT(7) +#define BIT_R_MGG_FIFO_WPTR_ERROR BIT(6) +#define BIT_R_EN_CPU_LIFETIME BIT(5) + +#define BIT_SHIFT_R_MGG_FIFO_WPTR 0 +#define BIT_MASK_R_MGG_FIFO_WPTR 0x1f +#define BIT_R_MGG_FIFO_WPTR(x) \ + (((x) & BIT_MASK_R_MGG_FIFO_WPTR) << BIT_SHIFT_R_MGG_FIFO_WPTR) +#define BIT_GET_R_MGG_FIFO_WPTR(x) \ + (((x) >> BIT_SHIFT_R_MGG_FIFO_WPTR) & BIT_MASK_R_MGG_FIFO_WPTR) + +/* 2 REG_MGG_FIFO_INT (Offset 0x1474) */ + +#define BIT_SHIFT_R_MGG_FIFO_INT_FLAG 16 +#define BIT_MASK_R_MGG_FIFO_INT_FLAG 0xffff +#define BIT_R_MGG_FIFO_INT_FLAG(x) \ + (((x) & BIT_MASK_R_MGG_FIFO_INT_FLAG) << BIT_SHIFT_R_MGG_FIFO_INT_FLAG) +#define BIT_GET_R_MGG_FIFO_INT_FLAG(x) \ + (((x) >> BIT_SHIFT_R_MGG_FIFO_INT_FLAG) & BIT_MASK_R_MGG_FIFO_INT_FLAG) + +#define BIT_SHIFT_R_MGG_FIFO_INT_MASK 0 +#define BIT_MASK_R_MGG_FIFO_INT_MASK 0xffff +#define BIT_R_MGG_FIFO_INT_MASK(x) \ + (((x) & BIT_MASK_R_MGG_FIFO_INT_MASK) << BIT_SHIFT_R_MGG_FIFO_INT_MASK) +#define BIT_GET_R_MGG_FIFO_INT_MASK(x) \ + (((x) >> BIT_SHIFT_R_MGG_FIFO_INT_MASK) & BIT_MASK_R_MGG_FIFO_INT_MASK) + +/* 2 REG_MGG_FIFO_LIFETIME (Offset 0x1478) */ + +#define BIT_SHIFT_R_MGG_FIFO_LIFETIME 16 +#define BIT_MASK_R_MGG_FIFO_LIFETIME 0xffff +#define BIT_R_MGG_FIFO_LIFETIME(x) \ + (((x) & BIT_MASK_R_MGG_FIFO_LIFETIME) << BIT_SHIFT_R_MGG_FIFO_LIFETIME) +#define BIT_GET_R_MGG_FIFO_LIFETIME(x) \ + (((x) >> BIT_SHIFT_R_MGG_FIFO_LIFETIME) & BIT_MASK_R_MGG_FIFO_LIFETIME) + +#define BIT_SHIFT_R_MGG_FIFO_VALID_MAP 0 +#define BIT_MASK_R_MGG_FIFO_VALID_MAP 0xffff +#define BIT_R_MGG_FIFO_VALID_MAP(x) \ + (((x) & BIT_MASK_R_MGG_FIFO_VALID_MAP) \ + << BIT_SHIFT_R_MGG_FIFO_VALID_MAP) +#define BIT_GET_R_MGG_FIFO_VALID_MAP(x) \ + (((x) >> BIT_SHIFT_R_MGG_FIFO_VALID_MAP) & \ + BIT_MASK_R_MGG_FIFO_VALID_MAP) + +/* 2 REG_R_MACID_RELEASE_SUCCESS_CLEAR_OFFSET (Offset 0x147C) */ + +#define BIT_SHIFT_R_MACID_RELEASE_SUCCESS_CLEAR_OFFSET 0 +#define BIT_MASK_R_MACID_RELEASE_SUCCESS_CLEAR_OFFSET 0x7f +#define BIT_R_MACID_RELEASE_SUCCESS_CLEAR_OFFSET(x) \ + (((x) & BIT_MASK_R_MACID_RELEASE_SUCCESS_CLEAR_OFFSET) \ + << BIT_SHIFT_R_MACID_RELEASE_SUCCESS_CLEAR_OFFSET) +#define BIT_GET_R_MACID_RELEASE_SUCCESS_CLEAR_OFFSET(x) \ + (((x) >> BIT_SHIFT_R_MACID_RELEASE_SUCCESS_CLEAR_OFFSET) & \ + BIT_MASK_R_MACID_RELEASE_SUCCESS_CLEAR_OFFSET) + +#define BIT_SHIFT_P2PON_DIS_TXTIME 0 +#define BIT_MASK_P2PON_DIS_TXTIME 0xff +#define BIT_P2PON_DIS_TXTIME(x) \ + (((x) & BIT_MASK_P2PON_DIS_TXTIME) << BIT_SHIFT_P2PON_DIS_TXTIME) +#define BIT_GET_P2PON_DIS_TXTIME(x) \ + (((x) >> BIT_SHIFT_P2PON_DIS_TXTIME) & BIT_MASK_P2PON_DIS_TXTIME) + +/* 2 REG_MACID_SHCUT_OFFSET (Offset 0x1480) */ + +#define BIT_SHIFT_MACID_SHCUT_OFFSET_V1 0 +#define BIT_MASK_MACID_SHCUT_OFFSET_V1 0xff +#define BIT_MACID_SHCUT_OFFSET_V1(x) \ + (((x) & BIT_MASK_MACID_SHCUT_OFFSET_V1) \ + << BIT_SHIFT_MACID_SHCUT_OFFSET_V1) +#define BIT_GET_MACID_SHCUT_OFFSET_V1(x) \ + (((x) >> BIT_SHIFT_MACID_SHCUT_OFFSET_V1) & \ + BIT_MASK_MACID_SHCUT_OFFSET_V1) + +/* 2 REG_MU_TX_CTL (Offset 0x14C0) */ + +#define BIT_R_EN_REVERS_GTAB BIT(6) + +#define BIT_SHIFT_R_MU_TABLE_VALID 0 +#define BIT_MASK_R_MU_TABLE_VALID 0x3f +#define BIT_R_MU_TABLE_VALID(x) \ + (((x) & BIT_MASK_R_MU_TABLE_VALID) << BIT_SHIFT_R_MU_TABLE_VALID) +#define BIT_GET_R_MU_TABLE_VALID(x) \ + (((x) >> BIT_SHIFT_R_MU_TABLE_VALID) & BIT_MASK_R_MU_TABLE_VALID) + +#define BIT_SHIFT_R_MU_STA_GTAB_VALID 0 +#define BIT_MASK_R_MU_STA_GTAB_VALID 0xffffffffL +#define BIT_R_MU_STA_GTAB_VALID(x) \ + (((x) & BIT_MASK_R_MU_STA_GTAB_VALID) << BIT_SHIFT_R_MU_STA_GTAB_VALID) +#define BIT_GET_R_MU_STA_GTAB_VALID(x) \ + (((x) >> BIT_SHIFT_R_MU_STA_GTAB_VALID) & BIT_MASK_R_MU_STA_GTAB_VALID) + +#define BIT_SHIFT_R_MU_STA_GTAB_POSITION 0 +#define BIT_MASK_R_MU_STA_GTAB_POSITION 0xffffffffffffffffL +#define BIT_R_MU_STA_GTAB_POSITION(x) \ + (((x) & BIT_MASK_R_MU_STA_GTAB_POSITION) \ + << BIT_SHIFT_R_MU_STA_GTAB_POSITION) +#define BIT_GET_R_MU_STA_GTAB_POSITION(x) \ + (((x) >> BIT_SHIFT_R_MU_STA_GTAB_POSITION) & \ + BIT_MASK_R_MU_STA_GTAB_POSITION) + +/* 2 REG_MU_TRX_DBG_CNT (Offset 0x14D0) */ + +#define BIT_MU_DNGCNT_RST BIT(20) + +#define BIT_SHIFT_MU_DBGCNT_SEL 16 +#define BIT_MASK_MU_DBGCNT_SEL 0xf +#define BIT_MU_DBGCNT_SEL(x) \ + (((x) & BIT_MASK_MU_DBGCNT_SEL) << BIT_SHIFT_MU_DBGCNT_SEL) +#define BIT_GET_MU_DBGCNT_SEL(x) \ + (((x) >> BIT_SHIFT_MU_DBGCNT_SEL) & BIT_MASK_MU_DBGCNT_SEL) + +#define BIT_SHIFT_MU_DNGCNT 0 +#define BIT_MASK_MU_DNGCNT 0xffff +#define BIT_MU_DNGCNT(x) (((x) & BIT_MASK_MU_DNGCNT) << BIT_SHIFT_MU_DNGCNT) +#define BIT_GET_MU_DNGCNT(x) (((x) >> BIT_SHIFT_MU_DNGCNT) & BIT_MASK_MU_DNGCNT) + +/* 2 REG_CPUMGQ_TX_TIMER (Offset 0x1500) */ + +#define BIT_SHIFT_CPUMGQ_TX_TIMER_V1 0 +#define BIT_MASK_CPUMGQ_TX_TIMER_V1 0xffffffffL +#define BIT_CPUMGQ_TX_TIMER_V1(x) \ + (((x) & BIT_MASK_CPUMGQ_TX_TIMER_V1) << BIT_SHIFT_CPUMGQ_TX_TIMER_V1) +#define BIT_GET_CPUMGQ_TX_TIMER_V1(x) \ + (((x) >> BIT_SHIFT_CPUMGQ_TX_TIMER_V1) & BIT_MASK_CPUMGQ_TX_TIMER_V1) + +/* 2 REG_PS_TIMER_A (Offset 0x1504) */ + +#define BIT_SHIFT_PS_TIMER_A_V1 0 +#define BIT_MASK_PS_TIMER_A_V1 0xffffffffL +#define BIT_PS_TIMER_A_V1(x) \ + (((x) & BIT_MASK_PS_TIMER_A_V1) << BIT_SHIFT_PS_TIMER_A_V1) +#define BIT_GET_PS_TIMER_A_V1(x) \ + (((x) >> BIT_SHIFT_PS_TIMER_A_V1) & BIT_MASK_PS_TIMER_A_V1) + +/* 2 REG_PS_TIMER_B (Offset 0x1508) */ + +#define BIT_SHIFT_PS_TIMER_B_V1 0 +#define BIT_MASK_PS_TIMER_B_V1 0xffffffffL +#define BIT_PS_TIMER_B_V1(x) \ + (((x) & BIT_MASK_PS_TIMER_B_V1) << BIT_SHIFT_PS_TIMER_B_V1) +#define BIT_GET_PS_TIMER_B_V1(x) \ + (((x) >> BIT_SHIFT_PS_TIMER_B_V1) & BIT_MASK_PS_TIMER_B_V1) + +/* 2 REG_PS_TIMER_C (Offset 0x150C) */ + +#define BIT_SHIFT_PS_TIMER_C_V1 0 +#define BIT_MASK_PS_TIMER_C_V1 0xffffffffL +#define BIT_PS_TIMER_C_V1(x) \ + (((x) & BIT_MASK_PS_TIMER_C_V1) << BIT_SHIFT_PS_TIMER_C_V1) +#define BIT_GET_PS_TIMER_C_V1(x) \ + (((x) >> BIT_SHIFT_PS_TIMER_C_V1) & BIT_MASK_PS_TIMER_C_V1) + +/* 2 REG_PS_TIMER_ABC_CPUMGQ_TIMER_CRTL (Offset 0x1510) */ + +#define BIT_CPUMGQ_TIMER_EN BIT(31) +#define BIT_CPUMGQ_TX_EN BIT(28) + +#define BIT_SHIFT_CPUMGQ_TIMER_TSF_SEL 24 +#define BIT_MASK_CPUMGQ_TIMER_TSF_SEL 0x7 +#define BIT_CPUMGQ_TIMER_TSF_SEL(x) \ + (((x) & BIT_MASK_CPUMGQ_TIMER_TSF_SEL) \ + << BIT_SHIFT_CPUMGQ_TIMER_TSF_SEL) +#define BIT_GET_CPUMGQ_TIMER_TSF_SEL(x) \ + (((x) >> BIT_SHIFT_CPUMGQ_TIMER_TSF_SEL) & \ + BIT_MASK_CPUMGQ_TIMER_TSF_SEL) + +#define BIT_PS_TIMER_C_EN BIT(23) + +#define BIT_SHIFT_PS_TIMER_C_TSF_SEL 16 +#define BIT_MASK_PS_TIMER_C_TSF_SEL 0x7 +#define BIT_PS_TIMER_C_TSF_SEL(x) \ + (((x) & BIT_MASK_PS_TIMER_C_TSF_SEL) << BIT_SHIFT_PS_TIMER_C_TSF_SEL) +#define BIT_GET_PS_TIMER_C_TSF_SEL(x) \ + (((x) >> BIT_SHIFT_PS_TIMER_C_TSF_SEL) & BIT_MASK_PS_TIMER_C_TSF_SEL) + +#define BIT_PS_TIMER_B_EN BIT(15) + +#define BIT_SHIFT_PS_TIMER_B_TSF_SEL 8 +#define BIT_MASK_PS_TIMER_B_TSF_SEL 0x7 +#define BIT_PS_TIMER_B_TSF_SEL(x) \ + (((x) & BIT_MASK_PS_TIMER_B_TSF_SEL) << BIT_SHIFT_PS_TIMER_B_TSF_SEL) +#define BIT_GET_PS_TIMER_B_TSF_SEL(x) \ + (((x) >> BIT_SHIFT_PS_TIMER_B_TSF_SEL) & BIT_MASK_PS_TIMER_B_TSF_SEL) + +#define BIT_PS_TIMER_A_EN BIT(7) + +#define BIT_SHIFT_PS_TIMER_A_TSF_SEL 0 +#define BIT_MASK_PS_TIMER_A_TSF_SEL 0x7 +#define BIT_PS_TIMER_A_TSF_SEL(x) \ + (((x) & BIT_MASK_PS_TIMER_A_TSF_SEL) << BIT_SHIFT_PS_TIMER_A_TSF_SEL) +#define BIT_GET_PS_TIMER_A_TSF_SEL(x) \ + (((x) >> BIT_SHIFT_PS_TIMER_A_TSF_SEL) & BIT_MASK_PS_TIMER_A_TSF_SEL) + +/* 2 REG_CPUMGQ_TX_TIMER_EARLY (Offset 0x1514) */ + +#define BIT_SHIFT_CPUMGQ_TX_TIMER_EARLY 0 +#define BIT_MASK_CPUMGQ_TX_TIMER_EARLY 0xff +#define BIT_CPUMGQ_TX_TIMER_EARLY(x) \ + (((x) & BIT_MASK_CPUMGQ_TX_TIMER_EARLY) \ + << BIT_SHIFT_CPUMGQ_TX_TIMER_EARLY) +#define BIT_GET_CPUMGQ_TX_TIMER_EARLY(x) \ + (((x) >> BIT_SHIFT_CPUMGQ_TX_TIMER_EARLY) & \ + BIT_MASK_CPUMGQ_TX_TIMER_EARLY) + +/* 2 REG_PS_TIMER_A_EARLY (Offset 0x1515) */ + +#define BIT_SHIFT_PS_TIMER_A_EARLY 0 +#define BIT_MASK_PS_TIMER_A_EARLY 0xff +#define BIT_PS_TIMER_A_EARLY(x) \ + (((x) & BIT_MASK_PS_TIMER_A_EARLY) << BIT_SHIFT_PS_TIMER_A_EARLY) +#define BIT_GET_PS_TIMER_A_EARLY(x) \ + (((x) >> BIT_SHIFT_PS_TIMER_A_EARLY) & BIT_MASK_PS_TIMER_A_EARLY) + +/* 2 REG_PS_TIMER_B_EARLY (Offset 0x1516) */ + +#define BIT_SHIFT_PS_TIMER_B_EARLY 0 +#define BIT_MASK_PS_TIMER_B_EARLY 0xff +#define BIT_PS_TIMER_B_EARLY(x) \ + (((x) & BIT_MASK_PS_TIMER_B_EARLY) << BIT_SHIFT_PS_TIMER_B_EARLY) +#define BIT_GET_PS_TIMER_B_EARLY(x) \ + (((x) >> BIT_SHIFT_PS_TIMER_B_EARLY) & BIT_MASK_PS_TIMER_B_EARLY) + +/* 2 REG_PS_TIMER_C_EARLY (Offset 0x1517) */ + +#define BIT_SHIFT_PS_TIMER_C_EARLY 0 +#define BIT_MASK_PS_TIMER_C_EARLY 0xff +#define BIT_PS_TIMER_C_EARLY(x) \ + (((x) & BIT_MASK_PS_TIMER_C_EARLY) << BIT_SHIFT_PS_TIMER_C_EARLY) +#define BIT_GET_PS_TIMER_C_EARLY(x) \ + (((x) >> BIT_SHIFT_PS_TIMER_C_EARLY) & BIT_MASK_PS_TIMER_C_EARLY) + +/* 2 REG_BCN_PSR_RPT2 (Offset 0x1600) */ + +#define BIT_SHIFT_DTIM_CNT2 24 +#define BIT_MASK_DTIM_CNT2 0xff +#define BIT_DTIM_CNT2(x) (((x) & BIT_MASK_DTIM_CNT2) << BIT_SHIFT_DTIM_CNT2) +#define BIT_GET_DTIM_CNT2(x) (((x) >> BIT_SHIFT_DTIM_CNT2) & BIT_MASK_DTIM_CNT2) + +#define BIT_SHIFT_DTIM_PERIOD2 16 +#define BIT_MASK_DTIM_PERIOD2 0xff +#define BIT_DTIM_PERIOD2(x) \ + (((x) & BIT_MASK_DTIM_PERIOD2) << BIT_SHIFT_DTIM_PERIOD2) +#define BIT_GET_DTIM_PERIOD2(x) \ + (((x) >> BIT_SHIFT_DTIM_PERIOD2) & BIT_MASK_DTIM_PERIOD2) + +#define BIT_DTIM2 BIT(15) +#define BIT_TIM2 BIT(14) + +#define BIT_SHIFT_PS_AID_2 0 +#define BIT_MASK_PS_AID_2 0x7ff +#define BIT_PS_AID_2(x) (((x) & BIT_MASK_PS_AID_2) << BIT_SHIFT_PS_AID_2) +#define BIT_GET_PS_AID_2(x) (((x) >> BIT_SHIFT_PS_AID_2) & BIT_MASK_PS_AID_2) + +/* 2 REG_BCN_PSR_RPT3 (Offset 0x1604) */ + +#define BIT_SHIFT_DTIM_CNT3 24 +#define BIT_MASK_DTIM_CNT3 0xff +#define BIT_DTIM_CNT3(x) (((x) & BIT_MASK_DTIM_CNT3) << BIT_SHIFT_DTIM_CNT3) +#define BIT_GET_DTIM_CNT3(x) (((x) >> BIT_SHIFT_DTIM_CNT3) & BIT_MASK_DTIM_CNT3) + +#define BIT_SHIFT_DTIM_PERIOD3 16 +#define BIT_MASK_DTIM_PERIOD3 0xff +#define BIT_DTIM_PERIOD3(x) \ + (((x) & BIT_MASK_DTIM_PERIOD3) << BIT_SHIFT_DTIM_PERIOD3) +#define BIT_GET_DTIM_PERIOD3(x) \ + (((x) >> BIT_SHIFT_DTIM_PERIOD3) & BIT_MASK_DTIM_PERIOD3) + +#define BIT_DTIM3 BIT(15) +#define BIT_TIM3 BIT(14) + +#define BIT_SHIFT_PS_AID_3 0 +#define BIT_MASK_PS_AID_3 0x7ff +#define BIT_PS_AID_3(x) (((x) & BIT_MASK_PS_AID_3) << BIT_SHIFT_PS_AID_3) +#define BIT_GET_PS_AID_3(x) (((x) >> BIT_SHIFT_PS_AID_3) & BIT_MASK_PS_AID_3) + +/* 2 REG_BCN_PSR_RPT4 (Offset 0x1608) */ + +#define BIT_SHIFT_DTIM_CNT4 24 +#define BIT_MASK_DTIM_CNT4 0xff +#define BIT_DTIM_CNT4(x) (((x) & BIT_MASK_DTIM_CNT4) << BIT_SHIFT_DTIM_CNT4) +#define BIT_GET_DTIM_CNT4(x) (((x) >> BIT_SHIFT_DTIM_CNT4) & BIT_MASK_DTIM_CNT4) + +#define BIT_SHIFT_DTIM_PERIOD4 16 +#define BIT_MASK_DTIM_PERIOD4 0xff +#define BIT_DTIM_PERIOD4(x) \ + (((x) & BIT_MASK_DTIM_PERIOD4) << BIT_SHIFT_DTIM_PERIOD4) +#define BIT_GET_DTIM_PERIOD4(x) \ + (((x) >> BIT_SHIFT_DTIM_PERIOD4) & BIT_MASK_DTIM_PERIOD4) + +#define BIT_DTIM4 BIT(15) +#define BIT_TIM4 BIT(14) + +#define BIT_SHIFT_PS_AID_4 0 +#define BIT_MASK_PS_AID_4 0x7ff +#define BIT_PS_AID_4(x) (((x) & BIT_MASK_PS_AID_4) << BIT_SHIFT_PS_AID_4) +#define BIT_GET_PS_AID_4(x) (((x) >> BIT_SHIFT_PS_AID_4) & BIT_MASK_PS_AID_4) + +/* 2 REG_A1_ADDR_MASK (Offset 0x160C) */ + +#define BIT_SHIFT_A1_ADDR_MASK 0 +#define BIT_MASK_A1_ADDR_MASK 0xffffffffL +#define BIT_A1_ADDR_MASK(x) \ + (((x) & BIT_MASK_A1_ADDR_MASK) << BIT_SHIFT_A1_ADDR_MASK) +#define BIT_GET_A1_ADDR_MASK(x) \ + (((x) >> BIT_SHIFT_A1_ADDR_MASK) & BIT_MASK_A1_ADDR_MASK) + +/* 2 REG_MACID2 (Offset 0x1620) */ + +#define BIT_SHIFT_MACID2 0 +#define BIT_MASK_MACID2 0xffffffffffffL +#define BIT_MACID2(x) (((x) & BIT_MASK_MACID2) << BIT_SHIFT_MACID2) +#define BIT_GET_MACID2(x) (((x) >> BIT_SHIFT_MACID2) & BIT_MASK_MACID2) + +/* 2 REG_BSSID2 (Offset 0x1628) */ + +#define BIT_SHIFT_BSSID2 0 +#define BIT_MASK_BSSID2 0xffffffffffffL +#define BIT_BSSID2(x) (((x) & BIT_MASK_BSSID2) << BIT_SHIFT_BSSID2) +#define BIT_GET_BSSID2(x) (((x) >> BIT_SHIFT_BSSID2) & BIT_MASK_BSSID2) + +/* 2 REG_MACID3 (Offset 0x1630) */ + +#define BIT_SHIFT_MACID3 0 +#define BIT_MASK_MACID3 0xffffffffffffL +#define BIT_MACID3(x) (((x) & BIT_MASK_MACID3) << BIT_SHIFT_MACID3) +#define BIT_GET_MACID3(x) (((x) >> BIT_SHIFT_MACID3) & BIT_MASK_MACID3) + +/* 2 REG_BSSID3 (Offset 0x1638) */ + +#define BIT_SHIFT_BSSID3 0 +#define BIT_MASK_BSSID3 0xffffffffffffL +#define BIT_BSSID3(x) (((x) & BIT_MASK_BSSID3) << BIT_SHIFT_BSSID3) +#define BIT_GET_BSSID3(x) (((x) >> BIT_SHIFT_BSSID3) & BIT_MASK_BSSID3) + +/* 2 REG_MACID4 (Offset 0x1640) */ + +#define BIT_SHIFT_MACID4 0 +#define BIT_MASK_MACID4 0xffffffffffffL +#define BIT_MACID4(x) (((x) & BIT_MASK_MACID4) << BIT_SHIFT_MACID4) +#define BIT_GET_MACID4(x) (((x) >> BIT_SHIFT_MACID4) & BIT_MASK_MACID4) + +/* 2 REG_BSSID4 (Offset 0x1648) */ + +#define BIT_SHIFT_BSSID4 0 +#define BIT_MASK_BSSID4 0xffffffffffffL +#define BIT_BSSID4(x) (((x) & BIT_MASK_BSSID4) << BIT_SHIFT_BSSID4) +#define BIT_GET_BSSID4(x) (((x) >> BIT_SHIFT_BSSID4) & BIT_MASK_BSSID4) + +/* 2 REG_PWRBIT_SETTING (Offset 0x1660) */ + +#define BIT_CLI3_PWRBIT_OW_EN BIT(7) +#define BIT_CLI3_PWR_ST BIT(6) +#define BIT_CLI2_PWRBIT_OW_EN BIT(5) +#define BIT_CLI2_PWR_ST BIT(4) +#define BIT_CLI1_PWRBIT_OW_EN BIT(3) +#define BIT_CLI1_PWR_ST BIT(2) +#define BIT_CLI0_PWRBIT_OW_EN BIT(1) +#define BIT_CLI0_PWR_ST BIT(0) + +/* 2 REG_WMAC_MU_BF_OPTION (Offset 0x167C) */ + +#define BIT_WMAC_RESP_NONSTA1_DIS BIT(7) + +/* 2 REG_WMAC_MU_BF_OPTION (Offset 0x167C) */ + +#define BIT_BIT_WMAC_TXMU_ACKPOLICY_EN BIT(6) + +/* 2 REG_WMAC_MU_BF_OPTION (Offset 0x167C) */ + +#define BIT_SHIFT_WMAC_TXMU_ACKPOLICY 4 +#define BIT_MASK_WMAC_TXMU_ACKPOLICY 0x3 +#define BIT_WMAC_TXMU_ACKPOLICY(x) \ + (((x) & BIT_MASK_WMAC_TXMU_ACKPOLICY) << BIT_SHIFT_WMAC_TXMU_ACKPOLICY) +#define BIT_GET_WMAC_TXMU_ACKPOLICY(x) \ + (((x) >> BIT_SHIFT_WMAC_TXMU_ACKPOLICY) & BIT_MASK_WMAC_TXMU_ACKPOLICY) + +#define BIT_SHIFT_WMAC_MU_BFEE_PORT_SEL 1 +#define BIT_MASK_WMAC_MU_BFEE_PORT_SEL 0x7 +#define BIT_WMAC_MU_BFEE_PORT_SEL(x) \ + (((x) & BIT_MASK_WMAC_MU_BFEE_PORT_SEL) \ + << BIT_SHIFT_WMAC_MU_BFEE_PORT_SEL) +#define BIT_GET_WMAC_MU_BFEE_PORT_SEL(x) \ + (((x) >> BIT_SHIFT_WMAC_MU_BFEE_PORT_SEL) & \ + BIT_MASK_WMAC_MU_BFEE_PORT_SEL) + +#define BIT_WMAC_MU_BFEE_DIS BIT(0) + +/* 2 REG_WMAC_PAUSE_BB_CLR_TH (Offset 0x167D) */ + +#define BIT_SHIFT_WMAC_PAUSE_BB_CLR_TH 0 +#define BIT_MASK_WMAC_PAUSE_BB_CLR_TH 0xff +#define BIT_WMAC_PAUSE_BB_CLR_TH(x) \ + (((x) & BIT_MASK_WMAC_PAUSE_BB_CLR_TH) \ + << BIT_SHIFT_WMAC_PAUSE_BB_CLR_TH) +#define BIT_GET_WMAC_PAUSE_BB_CLR_TH(x) \ + (((x) >> BIT_SHIFT_WMAC_PAUSE_BB_CLR_TH) & \ + BIT_MASK_WMAC_PAUSE_BB_CLR_TH) + +/* 2 REG_WMAC_MU_ARB (Offset 0x167E) */ + +#define BIT_WMAC_ARB_HW_ADAPT_EN BIT(7) +#define BIT_WMAC_ARB_SW_EN BIT(6) + +#define BIT_SHIFT_WMAC_ARB_SW_STATE 0 +#define BIT_MASK_WMAC_ARB_SW_STATE 0x3f +#define BIT_WMAC_ARB_SW_STATE(x) \ + (((x) & BIT_MASK_WMAC_ARB_SW_STATE) << BIT_SHIFT_WMAC_ARB_SW_STATE) +#define BIT_GET_WMAC_ARB_SW_STATE(x) \ + (((x) >> BIT_SHIFT_WMAC_ARB_SW_STATE) & BIT_MASK_WMAC_ARB_SW_STATE) + +/* 2 REG_WMAC_MU_OPTION (Offset 0x167F) */ + +#define BIT_SHIFT_WMAC_MU_DBGSEL 5 +#define BIT_MASK_WMAC_MU_DBGSEL 0x3 +#define BIT_WMAC_MU_DBGSEL(x) \ + (((x) & BIT_MASK_WMAC_MU_DBGSEL) << BIT_SHIFT_WMAC_MU_DBGSEL) +#define BIT_GET_WMAC_MU_DBGSEL(x) \ + (((x) >> BIT_SHIFT_WMAC_MU_DBGSEL) & BIT_MASK_WMAC_MU_DBGSEL) + +#define BIT_SHIFT_WMAC_MU_CPRD_TIMEOUT 0 +#define BIT_MASK_WMAC_MU_CPRD_TIMEOUT 0x1f +#define BIT_WMAC_MU_CPRD_TIMEOUT(x) \ + (((x) & BIT_MASK_WMAC_MU_CPRD_TIMEOUT) \ + << BIT_SHIFT_WMAC_MU_CPRD_TIMEOUT) +#define BIT_GET_WMAC_MU_CPRD_TIMEOUT(x) \ + (((x) >> BIT_SHIFT_WMAC_MU_CPRD_TIMEOUT) & \ + BIT_MASK_WMAC_MU_CPRD_TIMEOUT) + +/* 2 REG_WMAC_MU_BF_CTL (Offset 0x1680) */ + +#define BIT_WMAC_INVLD_BFPRT_CHK BIT(15) +#define BIT_WMAC_RETXBFRPTSEQ_UPD BIT(14) + +#define BIT_SHIFT_WMAC_MU_BFRPTSEG_SEL 12 +#define BIT_MASK_WMAC_MU_BFRPTSEG_SEL 0x3 +#define BIT_WMAC_MU_BFRPTSEG_SEL(x) \ + (((x) & BIT_MASK_WMAC_MU_BFRPTSEG_SEL) \ + << BIT_SHIFT_WMAC_MU_BFRPTSEG_SEL) +#define BIT_GET_WMAC_MU_BFRPTSEG_SEL(x) \ + (((x) >> BIT_SHIFT_WMAC_MU_BFRPTSEG_SEL) & \ + BIT_MASK_WMAC_MU_BFRPTSEG_SEL) + +#define BIT_SHIFT_WMAC_MU_BF_MYAID 0 +#define BIT_MASK_WMAC_MU_BF_MYAID 0xfff +#define BIT_WMAC_MU_BF_MYAID(x) \ + (((x) & BIT_MASK_WMAC_MU_BF_MYAID) << BIT_SHIFT_WMAC_MU_BF_MYAID) +#define BIT_GET_WMAC_MU_BF_MYAID(x) \ + (((x) >> BIT_SHIFT_WMAC_MU_BF_MYAID) & BIT_MASK_WMAC_MU_BF_MYAID) + +#define BIT_SHIFT_BFRPT_PARA 0 +#define BIT_MASK_BFRPT_PARA 0xfff +#define BIT_BFRPT_PARA(x) (((x) & BIT_MASK_BFRPT_PARA) << BIT_SHIFT_BFRPT_PARA) +#define BIT_GET_BFRPT_PARA(x) \ + (((x) >> BIT_SHIFT_BFRPT_PARA) & BIT_MASK_BFRPT_PARA) + +/* 2 REG_WMAC_MU_BFRPT_PARA (Offset 0x1682) */ + +#define BIT_SHIFT_BIT_BFRPT_PARA_USERID_SEL 12 +#define BIT_MASK_BIT_BFRPT_PARA_USERID_SEL 0x7 +#define BIT_BIT_BFRPT_PARA_USERID_SEL(x) \ + (((x) & BIT_MASK_BIT_BFRPT_PARA_USERID_SEL) \ + << BIT_SHIFT_BIT_BFRPT_PARA_USERID_SEL) +#define BIT_GET_BIT_BFRPT_PARA_USERID_SEL(x) \ + (((x) >> BIT_SHIFT_BIT_BFRPT_PARA_USERID_SEL) & \ + BIT_MASK_BIT_BFRPT_PARA_USERID_SEL) + +/* 2 REG_WMAC_ASSOCIATED_MU_BFMEE2 (Offset 0x1684) */ + +#define BIT_STATUS_BFEE2 BIT(10) +#define BIT_WMAC_MU_BFEE2_EN BIT(9) + +#define BIT_SHIFT_WMAC_MU_BFEE2_AID 0 +#define BIT_MASK_WMAC_MU_BFEE2_AID 0x1ff +#define BIT_WMAC_MU_BFEE2_AID(x) \ + (((x) & BIT_MASK_WMAC_MU_BFEE2_AID) << BIT_SHIFT_WMAC_MU_BFEE2_AID) +#define BIT_GET_WMAC_MU_BFEE2_AID(x) \ + (((x) >> BIT_SHIFT_WMAC_MU_BFEE2_AID) & BIT_MASK_WMAC_MU_BFEE2_AID) + +/* 2 REG_WMAC_ASSOCIATED_MU_BFMEE3 (Offset 0x1686) */ + +#define BIT_STATUS_BFEE3 BIT(10) +#define BIT_WMAC_MU_BFEE3_EN BIT(9) + +#define BIT_SHIFT_WMAC_MU_BFEE3_AID 0 +#define BIT_MASK_WMAC_MU_BFEE3_AID 0x1ff +#define BIT_WMAC_MU_BFEE3_AID(x) \ + (((x) & BIT_MASK_WMAC_MU_BFEE3_AID) << BIT_SHIFT_WMAC_MU_BFEE3_AID) +#define BIT_GET_WMAC_MU_BFEE3_AID(x) \ + (((x) >> BIT_SHIFT_WMAC_MU_BFEE3_AID) & BIT_MASK_WMAC_MU_BFEE3_AID) + +/* 2 REG_WMAC_ASSOCIATED_MU_BFMEE4 (Offset 0x1688) */ + +#define BIT_STATUS_BFEE4 BIT(10) +#define BIT_WMAC_MU_BFEE4_EN BIT(9) + +#define BIT_SHIFT_WMAC_MU_BFEE4_AID 0 +#define BIT_MASK_WMAC_MU_BFEE4_AID 0x1ff +#define BIT_WMAC_MU_BFEE4_AID(x) \ + (((x) & BIT_MASK_WMAC_MU_BFEE4_AID) << BIT_SHIFT_WMAC_MU_BFEE4_AID) +#define BIT_GET_WMAC_MU_BFEE4_AID(x) \ + (((x) >> BIT_SHIFT_WMAC_MU_BFEE4_AID) & BIT_MASK_WMAC_MU_BFEE4_AID) + +/* 2 REG_WMAC_ASSOCIATED_MU_BFMEE5 (Offset 0x168A) */ + +#define BIT_R_WMAC_RX_SYNCFIFO_SYNC BIT(55) +#define BIT_R_WMAC_RXRST_DLY BIT(54) +#define BIT_R_WMAC_SRCH_TXRPT_REF_DROP BIT(53) +#define BIT_R_WMAC_SRCH_TXRPT_UA1 BIT(52) +#define BIT_STATUS_BFEE5 BIT(10) + +/* 2 REG_WMAC_ASSOCIATED_MU_BFMEE5 (Offset 0x168A) */ + +#define BIT_WMAC_MU_BFEE5_EN BIT(9) + +#define BIT_SHIFT_WMAC_MU_BFEE5_AID 0 +#define BIT_MASK_WMAC_MU_BFEE5_AID 0x1ff +#define BIT_WMAC_MU_BFEE5_AID(x) \ + (((x) & BIT_MASK_WMAC_MU_BFEE5_AID) << BIT_SHIFT_WMAC_MU_BFEE5_AID) +#define BIT_GET_WMAC_MU_BFEE5_AID(x) \ + (((x) >> BIT_SHIFT_WMAC_MU_BFEE5_AID) & BIT_MASK_WMAC_MU_BFEE5_AID) + +/* 2 REG_WMAC_ASSOCIATED_MU_BFMEE6 (Offset 0x168C) */ + +#define BIT_STATUS_BFEE6 BIT(10) +#define BIT_WMAC_MU_BFEE6_EN BIT(9) + +#define BIT_SHIFT_WMAC_MU_BFEE6_AID 0 +#define BIT_MASK_WMAC_MU_BFEE6_AID 0x1ff +#define BIT_WMAC_MU_BFEE6_AID(x) \ + (((x) & BIT_MASK_WMAC_MU_BFEE6_AID) << BIT_SHIFT_WMAC_MU_BFEE6_AID) +#define BIT_GET_WMAC_MU_BFEE6_AID(x) \ + (((x) >> BIT_SHIFT_WMAC_MU_BFEE6_AID) & BIT_MASK_WMAC_MU_BFEE6_AID) + +/* 2 REG_WMAC_ASSOCIATED_MU_BFMEE7 (Offset 0x168E) */ + +#define BIT_BIT_STATUS_BFEE4 BIT(10) +#define BIT_WMAC_MU_BFEE7_EN BIT(9) + +#define BIT_SHIFT_WMAC_MU_BFEE7_AID 0 +#define BIT_MASK_WMAC_MU_BFEE7_AID 0x1ff +#define BIT_WMAC_MU_BFEE7_AID(x) \ + (((x) & BIT_MASK_WMAC_MU_BFEE7_AID) << BIT_SHIFT_WMAC_MU_BFEE7_AID) +#define BIT_GET_WMAC_MU_BFEE7_AID(x) \ + (((x) >> BIT_SHIFT_WMAC_MU_BFEE7_AID) & BIT_MASK_WMAC_MU_BFEE7_AID) + +/* 2 REG_WMAC_BB_STOP_RX_COUNTER (Offset 0x1690) */ + +#define BIT_RST_ALL_COUNTER BIT(31) + +#define BIT_SHIFT_ABORT_RX_VBON_COUNTER 16 +#define BIT_MASK_ABORT_RX_VBON_COUNTER 0xff +#define BIT_ABORT_RX_VBON_COUNTER(x) \ + (((x) & BIT_MASK_ABORT_RX_VBON_COUNTER) \ + << BIT_SHIFT_ABORT_RX_VBON_COUNTER) +#define BIT_GET_ABORT_RX_VBON_COUNTER(x) \ + (((x) >> BIT_SHIFT_ABORT_RX_VBON_COUNTER) & \ + BIT_MASK_ABORT_RX_VBON_COUNTER) + +#define BIT_SHIFT_ABORT_RX_RDRDY_COUNTER 8 +#define BIT_MASK_ABORT_RX_RDRDY_COUNTER 0xff +#define BIT_ABORT_RX_RDRDY_COUNTER(x) \ + (((x) & BIT_MASK_ABORT_RX_RDRDY_COUNTER) \ + << BIT_SHIFT_ABORT_RX_RDRDY_COUNTER) +#define BIT_GET_ABORT_RX_RDRDY_COUNTER(x) \ + (((x) >> BIT_SHIFT_ABORT_RX_RDRDY_COUNTER) & \ + BIT_MASK_ABORT_RX_RDRDY_COUNTER) + +#define BIT_SHIFT_VBON_EARLY_FALLING_COUNTER 0 +#define BIT_MASK_VBON_EARLY_FALLING_COUNTER 0xff +#define BIT_VBON_EARLY_FALLING_COUNTER(x) \ + (((x) & BIT_MASK_VBON_EARLY_FALLING_COUNTER) \ + << BIT_SHIFT_VBON_EARLY_FALLING_COUNTER) +#define BIT_GET_VBON_EARLY_FALLING_COUNTER(x) \ + (((x) >> BIT_SHIFT_VBON_EARLY_FALLING_COUNTER) & \ + BIT_MASK_VBON_EARLY_FALLING_COUNTER) + +/* 2 REG_WMAC_PLCP_MONITOR (Offset 0x1694) */ + +#define BIT_WMAC_PLCP_TRX_SEL BIT(31) + +#define BIT_SHIFT_WMAC_PLCP_RDSIG_SEL 28 +#define BIT_MASK_WMAC_PLCP_RDSIG_SEL 0x7 +#define BIT_WMAC_PLCP_RDSIG_SEL(x) \ + (((x) & BIT_MASK_WMAC_PLCP_RDSIG_SEL) << BIT_SHIFT_WMAC_PLCP_RDSIG_SEL) +#define BIT_GET_WMAC_PLCP_RDSIG_SEL(x) \ + (((x) >> BIT_SHIFT_WMAC_PLCP_RDSIG_SEL) & BIT_MASK_WMAC_PLCP_RDSIG_SEL) + +#define BIT_SHIFT_WMAC_RATE_IDX 24 +#define BIT_MASK_WMAC_RATE_IDX 0xf +#define BIT_WMAC_RATE_IDX(x) \ + (((x) & BIT_MASK_WMAC_RATE_IDX) << BIT_SHIFT_WMAC_RATE_IDX) +#define BIT_GET_WMAC_RATE_IDX(x) \ + (((x) >> BIT_SHIFT_WMAC_RATE_IDX) & BIT_MASK_WMAC_RATE_IDX) + +#define BIT_SHIFT_WMAC_PLCP_RDSIG 0 +#define BIT_MASK_WMAC_PLCP_RDSIG 0xffffff +#define BIT_WMAC_PLCP_RDSIG(x) \ + (((x) & BIT_MASK_WMAC_PLCP_RDSIG) << BIT_SHIFT_WMAC_PLCP_RDSIG) +#define BIT_GET_WMAC_PLCP_RDSIG(x) \ + (((x) >> BIT_SHIFT_WMAC_PLCP_RDSIG) & BIT_MASK_WMAC_PLCP_RDSIG) + +/* 2 REG_WMAC_PLCP_MONITOR_MUTX (Offset 0x1698) */ + +#define BIT_WMAC_MUTX_IDX BIT(24) + +/* 2 REG_TRANSMIT_ADDRSS_0 (Offset 0x16A0) */ + +#define BIT_SHIFT_TA0 0 +#define BIT_MASK_TA0 0xffffffffffffL +#define BIT_TA0(x) (((x) & BIT_MASK_TA0) << BIT_SHIFT_TA0) +#define BIT_GET_TA0(x) (((x) >> BIT_SHIFT_TA0) & BIT_MASK_TA0) + +/* 2 REG_TRANSMIT_ADDRSS_1 (Offset 0x16A8) */ + +#define BIT_SHIFT_TA1 0 +#define BIT_MASK_TA1 0xffffffffffffL +#define BIT_TA1(x) (((x) & BIT_MASK_TA1) << BIT_SHIFT_TA1) +#define BIT_GET_TA1(x) (((x) >> BIT_SHIFT_TA1) & BIT_MASK_TA1) + +/* 2 REG_TRANSMIT_ADDRSS_2 (Offset 0x16B0) */ + +#define BIT_SHIFT_TA2 0 +#define BIT_MASK_TA2 0xffffffffffffL +#define BIT_TA2(x) (((x) & BIT_MASK_TA2) << BIT_SHIFT_TA2) +#define BIT_GET_TA2(x) (((x) >> BIT_SHIFT_TA2) & BIT_MASK_TA2) + +/* 2 REG_TRANSMIT_ADDRSS_3 (Offset 0x16B8) */ + +#define BIT_SHIFT_TA3 0 +#define BIT_MASK_TA3 0xffffffffffffL +#define BIT_TA3(x) (((x) & BIT_MASK_TA3) << BIT_SHIFT_TA3) +#define BIT_GET_TA3(x) (((x) >> BIT_SHIFT_TA3) & BIT_MASK_TA3) + +/* 2 REG_TRANSMIT_ADDRSS_4 (Offset 0x16C0) */ + +#define BIT_SHIFT_TA4 0 +#define BIT_MASK_TA4 0xffffffffffffL +#define BIT_TA4(x) (((x) & BIT_MASK_TA4) << BIT_SHIFT_TA4) +#define BIT_GET_TA4(x) (((x) >> BIT_SHIFT_TA4) & BIT_MASK_TA4) + +/* 2 REG_WL2LTECOEX_INDIRECT_ACCESS_CTRL_V1 (Offset 0x1700) */ + +#define BIT_LTECOEX_ACCESS_START_V1 BIT(31) +#define BIT_LTECOEX_WRITE_MODE_V1 BIT(30) +#define BIT_LTECOEX_READY_BIT_V1 BIT(29) + +#define BIT_SHIFT_WRITE_BYTE_EN_V1 16 +#define BIT_MASK_WRITE_BYTE_EN_V1 0xf +#define BIT_WRITE_BYTE_EN_V1(x) \ + (((x) & BIT_MASK_WRITE_BYTE_EN_V1) << BIT_SHIFT_WRITE_BYTE_EN_V1) +#define BIT_GET_WRITE_BYTE_EN_V1(x) \ + (((x) >> BIT_SHIFT_WRITE_BYTE_EN_V1) & BIT_MASK_WRITE_BYTE_EN_V1) + +#define BIT_SHIFT_LTECOEX_REG_ADDR_V1 0 +#define BIT_MASK_LTECOEX_REG_ADDR_V1 0xffff +#define BIT_LTECOEX_REG_ADDR_V1(x) \ + (((x) & BIT_MASK_LTECOEX_REG_ADDR_V1) << BIT_SHIFT_LTECOEX_REG_ADDR_V1) +#define BIT_GET_LTECOEX_REG_ADDR_V1(x) \ + (((x) >> BIT_SHIFT_LTECOEX_REG_ADDR_V1) & BIT_MASK_LTECOEX_REG_ADDR_V1) + +/* 2 REG_WL2LTECOEX_INDIRECT_ACCESS_WRITE_DATA_V1 (Offset 0x1704) */ + +#define BIT_SHIFT_LTECOEX_W_DATA_V1 0 +#define BIT_MASK_LTECOEX_W_DATA_V1 0xffffffffL +#define BIT_LTECOEX_W_DATA_V1(x) \ + (((x) & BIT_MASK_LTECOEX_W_DATA_V1) << BIT_SHIFT_LTECOEX_W_DATA_V1) +#define BIT_GET_LTECOEX_W_DATA_V1(x) \ + (((x) >> BIT_SHIFT_LTECOEX_W_DATA_V1) & BIT_MASK_LTECOEX_W_DATA_V1) + +/* 2 REG_WL2LTECOEX_INDIRECT_ACCESS_READ_DATA_V1 (Offset 0x1708) */ + +#define BIT_SHIFT_LTECOEX_R_DATA_V1 0 +#define BIT_MASK_LTECOEX_R_DATA_V1 0xffffffffL +#define BIT_LTECOEX_R_DATA_V1(x) \ + (((x) & BIT_MASK_LTECOEX_R_DATA_V1) << BIT_SHIFT_LTECOEX_R_DATA_V1) +#define BIT_GET_LTECOEX_R_DATA_V1(x) \ + (((x) >> BIT_SHIFT_LTECOEX_R_DATA_V1) & BIT_MASK_LTECOEX_R_DATA_V1) + +#endif /* __RTL_WLAN_BITDEF_H__ */ diff --git a/drivers/staging/rtlwifi/halmac/halmac_bit_8822b.h b/drivers/staging/rtlwifi/halmac/halmac_bit_8822b.h new file mode 100644 index 000000000000..7d02553f229e --- /dev/null +++ b/drivers/staging/rtlwifi/halmac/halmac_bit_8822b.h @@ -0,0 +1,12103 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef __INC_HALMAC_BIT_8822B_H +#define __INC_HALMAC_BIT_8822B_H + +#define CPU_OPT_WIDTH 0x1F + +/* 2 REG_NOT_VALID_8822B */ + +/* 2 REG_SYS_ISO_CTRL_8822B */ +#define BIT_PWC_EV12V_8822B BIT(15) +#define BIT_PWC_EV25V_8822B BIT(14) +#define BIT_PA33V_EN_8822B BIT(13) +#define BIT_PA12V_EN_8822B BIT(12) +#define BIT_UA33V_EN_8822B BIT(11) +#define BIT_UA12V_EN_8822B BIT(10) +#define BIT_ISO_RFDIO_8822B BIT(9) +#define BIT_ISO_EB2CORE_8822B BIT(8) +#define BIT_ISO_DIOE_8822B BIT(7) +#define BIT_ISO_WLPON2PP_8822B BIT(6) +#define BIT_ISO_IP2MAC_WA2PP_8822B BIT(5) +#define BIT_ISO_PD2CORE_8822B BIT(4) +#define BIT_ISO_PA2PCIE_8822B BIT(3) +#define BIT_ISO_UD2CORE_8822B BIT(2) +#define BIT_ISO_UA2USB_8822B BIT(1) +#define BIT_ISO_WD2PP_8822B BIT(0) + +/* 2 REG_SYS_FUNC_EN_8822B */ +#define BIT_FEN_MREGEN_8822B BIT(15) +#define BIT_FEN_HWPDN_8822B BIT(14) +#define BIT_EN_25_1_8822B BIT(13) +#define BIT_FEN_ELDR_8822B BIT(12) +#define BIT_FEN_DCORE_8822B BIT(11) +#define BIT_FEN_CPUEN_8822B BIT(10) +#define BIT_FEN_DIOE_8822B BIT(9) +#define BIT_FEN_PCIED_8822B BIT(8) +#define BIT_FEN_PPLL_8822B BIT(7) +#define BIT_FEN_PCIEA_8822B BIT(6) +#define BIT_FEN_DIO_PCIE_8822B BIT(5) +#define BIT_FEN_USBD_8822B BIT(4) +#define BIT_FEN_UPLL_8822B BIT(3) +#define BIT_FEN_USBA_8822B BIT(2) +#define BIT_FEN_BB_GLB_RSTN_8822B BIT(1) +#define BIT_FEN_BBRSTB_8822B BIT(0) + +/* 2 REG_SYS_PW_CTRL_8822B */ +#define BIT_SOP_EABM_8822B BIT(31) +#define BIT_SOP_ACKF_8822B BIT(30) +#define BIT_SOP_ERCK_8822B BIT(29) +#define BIT_SOP_ESWR_8822B BIT(28) +#define BIT_SOP_PWMM_8822B BIT(27) +#define BIT_SOP_EECK_8822B BIT(26) +#define BIT_SOP_EXTL_8822B BIT(24) +#define BIT_SYM_OP_RING_12M_8822B BIT(22) +#define BIT_ROP_SWPR_8822B BIT(21) +#define BIT_DIS_HW_LPLDM_8822B BIT(20) +#define BIT_OPT_SWRST_WLMCU_8822B BIT(19) +#define BIT_RDY_SYSPWR_8822B BIT(17) +#define BIT_EN_WLON_8822B BIT(16) +#define BIT_APDM_HPDN_8822B BIT(15) +#define BIT_AFSM_PCIE_SUS_EN_8822B BIT(12) +#define BIT_AFSM_WLSUS_EN_8822B BIT(11) +#define BIT_APFM_SWLPS_8822B BIT(10) +#define BIT_APFM_OFFMAC_8822B BIT(9) +#define BIT_APFN_ONMAC_8822B BIT(8) +#define BIT_CHIP_PDN_EN_8822B BIT(7) +#define BIT_RDY_MACDIS_8822B BIT(6) +#define BIT_RING_CLK_12M_EN_8822B BIT(4) +#define BIT_PFM_WOWL_8822B BIT(3) +#define BIT_PFM_LDKP_8822B BIT(2) +#define BIT_WL_HCI_ALD_8822B BIT(1) +#define BIT_PFM_LDALL_8822B BIT(0) + +/* 2 REG_SYS_CLK_CTRL_8822B */ +#define BIT_LDO_DUMMY_8822B BIT(15) +#define BIT_CPU_CLK_EN_8822B BIT(14) +#define BIT_SYMREG_CLK_EN_8822B BIT(13) +#define BIT_HCI_CLK_EN_8822B BIT(12) +#define BIT_MAC_CLK_EN_8822B BIT(11) +#define BIT_SEC_CLK_EN_8822B BIT(10) +#define BIT_PHY_SSC_RSTB_8822B BIT(9) +#define BIT_EXT_32K_EN_8822B BIT(8) +#define BIT_WL_CLK_TEST_8822B BIT(7) +#define BIT_OP_SPS_PWM_EN_8822B BIT(6) +#define BIT_LOADER_CLK_EN_8822B BIT(5) +#define BIT_MACSLP_8822B BIT(4) +#define BIT_WAKEPAD_EN_8822B BIT(3) +#define BIT_ROMD16V_EN_8822B BIT(2) +#define BIT_CKANA12M_EN_8822B BIT(1) +#define BIT_CNTD16V_EN_8822B BIT(0) + +/* 2 REG_SYS_EEPROM_CTRL_8822B */ + +#define BIT_SHIFT_VPDIDX_8822B 8 +#define BIT_MASK_VPDIDX_8822B 0xff +#define BIT_VPDIDX_8822B(x) \ + (((x) & BIT_MASK_VPDIDX_8822B) << BIT_SHIFT_VPDIDX_8822B) +#define BIT_GET_VPDIDX_8822B(x) \ + (((x) >> BIT_SHIFT_VPDIDX_8822B) & BIT_MASK_VPDIDX_8822B) + +#define BIT_SHIFT_EEM1_0_8822B 6 +#define BIT_MASK_EEM1_0_8822B 0x3 +#define BIT_EEM1_0_8822B(x) \ + (((x) & BIT_MASK_EEM1_0_8822B) << BIT_SHIFT_EEM1_0_8822B) +#define BIT_GET_EEM1_0_8822B(x) \ + (((x) >> BIT_SHIFT_EEM1_0_8822B) & BIT_MASK_EEM1_0_8822B) + +#define BIT_AUTOLOAD_SUS_8822B BIT(5) +#define BIT_EERPOMSEL_8822B BIT(4) +#define BIT_EECS_V1_8822B BIT(3) +#define BIT_EESK_V1_8822B BIT(2) +#define BIT_EEDI_V1_8822B BIT(1) +#define BIT_EEDO_V1_8822B BIT(0) + +/* 2 REG_EE_VPD_8822B */ + +#define BIT_SHIFT_VPD_DATA_8822B 0 +#define BIT_MASK_VPD_DATA_8822B 0xffffffffL +#define BIT_VPD_DATA_8822B(x) \ + (((x) & BIT_MASK_VPD_DATA_8822B) << BIT_SHIFT_VPD_DATA_8822B) +#define BIT_GET_VPD_DATA_8822B(x) \ + (((x) >> BIT_SHIFT_VPD_DATA_8822B) & BIT_MASK_VPD_DATA_8822B) + +/* 2 REG_SYS_SWR_CTRL1_8822B */ +#define BIT_C2_L_BIT0_8822B BIT(31) + +#define BIT_SHIFT_C1_L_8822B 29 +#define BIT_MASK_C1_L_8822B 0x3 +#define BIT_C1_L_8822B(x) (((x) & BIT_MASK_C1_L_8822B) << BIT_SHIFT_C1_L_8822B) +#define BIT_GET_C1_L_8822B(x) \ + (((x) >> BIT_SHIFT_C1_L_8822B) & BIT_MASK_C1_L_8822B) + +#define BIT_SHIFT_REG_FREQ_L_8822B 25 +#define BIT_MASK_REG_FREQ_L_8822B 0x7 +#define BIT_REG_FREQ_L_8822B(x) \ + (((x) & BIT_MASK_REG_FREQ_L_8822B) << BIT_SHIFT_REG_FREQ_L_8822B) +#define BIT_GET_REG_FREQ_L_8822B(x) \ + (((x) >> BIT_SHIFT_REG_FREQ_L_8822B) & BIT_MASK_REG_FREQ_L_8822B) + +#define BIT_REG_EN_DUTY_8822B BIT(24) + +#define BIT_SHIFT_REG_MODE_8822B 22 +#define BIT_MASK_REG_MODE_8822B 0x3 +#define BIT_REG_MODE_8822B(x) \ + (((x) & BIT_MASK_REG_MODE_8822B) << BIT_SHIFT_REG_MODE_8822B) +#define BIT_GET_REG_MODE_8822B(x) \ + (((x) >> BIT_SHIFT_REG_MODE_8822B) & BIT_MASK_REG_MODE_8822B) + +#define BIT_REG_EN_SP_8822B BIT(21) +#define BIT_REG_AUTO_L_8822B BIT(20) +#define BIT_SW18_SELD_BIT0_8822B BIT(19) +#define BIT_SW18_POWOCP_8822B BIT(18) + +#define BIT_SHIFT_OCP_L1_8822B 15 +#define BIT_MASK_OCP_L1_8822B 0x7 +#define BIT_OCP_L1_8822B(x) \ + (((x) & BIT_MASK_OCP_L1_8822B) << BIT_SHIFT_OCP_L1_8822B) +#define BIT_GET_OCP_L1_8822B(x) \ + (((x) >> BIT_SHIFT_OCP_L1_8822B) & BIT_MASK_OCP_L1_8822B) + +#define BIT_SHIFT_CF_L_8822B 13 +#define BIT_MASK_CF_L_8822B 0x3 +#define BIT_CF_L_8822B(x) (((x) & BIT_MASK_CF_L_8822B) << BIT_SHIFT_CF_L_8822B) +#define BIT_GET_CF_L_8822B(x) \ + (((x) >> BIT_SHIFT_CF_L_8822B) & BIT_MASK_CF_L_8822B) + +#define BIT_SW18_FPWM_8822B BIT(11) +#define BIT_SW18_SWEN_8822B BIT(9) +#define BIT_SW18_LDEN_8822B BIT(8) +#define BIT_MAC_ID_EN_8822B BIT(7) +#define BIT_AFE_BGEN_8822B BIT(0) + +/* 2 REG_SYS_SWR_CTRL2_8822B */ +#define BIT_POW_ZCD_L_8822B BIT(31) +#define BIT_AUTOZCD_L_8822B BIT(30) + +#define BIT_SHIFT_REG_DELAY_8822B 28 +#define BIT_MASK_REG_DELAY_8822B 0x3 +#define BIT_REG_DELAY_8822B(x) \ + (((x) & BIT_MASK_REG_DELAY_8822B) << BIT_SHIFT_REG_DELAY_8822B) +#define BIT_GET_REG_DELAY_8822B(x) \ + (((x) >> BIT_SHIFT_REG_DELAY_8822B) & BIT_MASK_REG_DELAY_8822B) + +#define BIT_SHIFT_V15ADJ_L1_V1_8822B 24 +#define BIT_MASK_V15ADJ_L1_V1_8822B 0x7 +#define BIT_V15ADJ_L1_V1_8822B(x) \ + (((x) & BIT_MASK_V15ADJ_L1_V1_8822B) << BIT_SHIFT_V15ADJ_L1_V1_8822B) +#define BIT_GET_V15ADJ_L1_V1_8822B(x) \ + (((x) >> BIT_SHIFT_V15ADJ_L1_V1_8822B) & BIT_MASK_V15ADJ_L1_V1_8822B) + +#define BIT_SHIFT_VOL_L1_V1_8822B 20 +#define BIT_MASK_VOL_L1_V1_8822B 0xf +#define BIT_VOL_L1_V1_8822B(x) \ + (((x) & BIT_MASK_VOL_L1_V1_8822B) << BIT_SHIFT_VOL_L1_V1_8822B) +#define BIT_GET_VOL_L1_V1_8822B(x) \ + (((x) >> BIT_SHIFT_VOL_L1_V1_8822B) & BIT_MASK_VOL_L1_V1_8822B) + +#define BIT_SHIFT_IN_L1_V1_8822B 17 +#define BIT_MASK_IN_L1_V1_8822B 0x7 +#define BIT_IN_L1_V1_8822B(x) \ + (((x) & BIT_MASK_IN_L1_V1_8822B) << BIT_SHIFT_IN_L1_V1_8822B) +#define BIT_GET_IN_L1_V1_8822B(x) \ + (((x) >> BIT_SHIFT_IN_L1_V1_8822B) & BIT_MASK_IN_L1_V1_8822B) + +#define BIT_SHIFT_TBOX_L1_8822B 15 +#define BIT_MASK_TBOX_L1_8822B 0x3 +#define BIT_TBOX_L1_8822B(x) \ + (((x) & BIT_MASK_TBOX_L1_8822B) << BIT_SHIFT_TBOX_L1_8822B) +#define BIT_GET_TBOX_L1_8822B(x) \ + (((x) >> BIT_SHIFT_TBOX_L1_8822B) & BIT_MASK_TBOX_L1_8822B) + +#define BIT_SW18_SEL_8822B BIT(13) + +/* 2 REG_NOT_VALID_8822B */ +#define BIT_SW18_SD_8822B BIT(10) + +#define BIT_SHIFT_R3_L_8822B 7 +#define BIT_MASK_R3_L_8822B 0x3 +#define BIT_R3_L_8822B(x) (((x) & BIT_MASK_R3_L_8822B) << BIT_SHIFT_R3_L_8822B) +#define BIT_GET_R3_L_8822B(x) \ + (((x) >> BIT_SHIFT_R3_L_8822B) & BIT_MASK_R3_L_8822B) + +#define BIT_SHIFT_SW18_R2_8822B 5 +#define BIT_MASK_SW18_R2_8822B 0x3 +#define BIT_SW18_R2_8822B(x) \ + (((x) & BIT_MASK_SW18_R2_8822B) << BIT_SHIFT_SW18_R2_8822B) +#define BIT_GET_SW18_R2_8822B(x) \ + (((x) >> BIT_SHIFT_SW18_R2_8822B) & BIT_MASK_SW18_R2_8822B) + +#define BIT_SHIFT_SW18_R1_8822B 3 +#define BIT_MASK_SW18_R1_8822B 0x3 +#define BIT_SW18_R1_8822B(x) \ + (((x) & BIT_MASK_SW18_R1_8822B) << BIT_SHIFT_SW18_R1_8822B) +#define BIT_GET_SW18_R1_8822B(x) \ + (((x) >> BIT_SHIFT_SW18_R1_8822B) & BIT_MASK_SW18_R1_8822B) + +#define BIT_SHIFT_C3_L_C3_8822B 1 +#define BIT_MASK_C3_L_C3_8822B 0x3 +#define BIT_C3_L_C3_8822B(x) \ + (((x) & BIT_MASK_C3_L_C3_8822B) << BIT_SHIFT_C3_L_C3_8822B) +#define BIT_GET_C3_L_C3_8822B(x) \ + (((x) >> BIT_SHIFT_C3_L_C3_8822B) & BIT_MASK_C3_L_C3_8822B) + +#define BIT_C2_L_BIT1_8822B BIT(0) + +/* 2 REG_SYS_SWR_CTRL3_8822B */ +#define BIT_SPS18_OCP_DIS_8822B BIT(31) + +#define BIT_SHIFT_SPS18_OCP_TH_8822B 16 +#define BIT_MASK_SPS18_OCP_TH_8822B 0x7fff +#define BIT_SPS18_OCP_TH_8822B(x) \ + (((x) & BIT_MASK_SPS18_OCP_TH_8822B) << BIT_SHIFT_SPS18_OCP_TH_8822B) +#define BIT_GET_SPS18_OCP_TH_8822B(x) \ + (((x) >> BIT_SHIFT_SPS18_OCP_TH_8822B) & BIT_MASK_SPS18_OCP_TH_8822B) + +#define BIT_SHIFT_OCP_WINDOW_8822B 0 +#define BIT_MASK_OCP_WINDOW_8822B 0xffff +#define BIT_OCP_WINDOW_8822B(x) \ + (((x) & BIT_MASK_OCP_WINDOW_8822B) << BIT_SHIFT_OCP_WINDOW_8822B) +#define BIT_GET_OCP_WINDOW_8822B(x) \ + (((x) >> BIT_SHIFT_OCP_WINDOW_8822B) & BIT_MASK_OCP_WINDOW_8822B) + +/* 2 REG_RSV_CTRL_8822B */ +#define BIT_HREG_DBG_8822B BIT(23) +#define BIT_WLMCUIOIF_8822B BIT(8) +#define BIT_LOCK_ALL_EN_8822B BIT(7) +#define BIT_R_DIS_PRST_8822B BIT(6) +#define BIT_WLOCK_1C_B6_8822B BIT(5) +#define BIT_WLOCK_40_8822B BIT(4) +#define BIT_WLOCK_08_8822B BIT(3) +#define BIT_WLOCK_04_8822B BIT(2) +#define BIT_WLOCK_00_8822B BIT(1) +#define BIT_WLOCK_ALL_8822B BIT(0) + +/* 2 REG_RF_CTRL_8822B */ +#define BIT_RF_SDMRSTB_8822B BIT(2) +#define BIT_RF_RSTB_8822B BIT(1) +#define BIT_RF_EN_8822B BIT(0) + +/* 2 REG_AFE_LDO_CTRL_8822B */ + +#define BIT_SHIFT_LPLDH12_RSV_8822B 29 +#define BIT_MASK_LPLDH12_RSV_8822B 0x7 +#define BIT_LPLDH12_RSV_8822B(x) \ + (((x) & BIT_MASK_LPLDH12_RSV_8822B) << BIT_SHIFT_LPLDH12_RSV_8822B) +#define BIT_GET_LPLDH12_RSV_8822B(x) \ + (((x) >> BIT_SHIFT_LPLDH12_RSV_8822B) & BIT_MASK_LPLDH12_RSV_8822B) + +#define BIT_LPLDH12_SLP_8822B BIT(28) + +#define BIT_SHIFT_LPLDH12_VADJ_8822B 24 +#define BIT_MASK_LPLDH12_VADJ_8822B 0xf +#define BIT_LPLDH12_VADJ_8822B(x) \ + (((x) & BIT_MASK_LPLDH12_VADJ_8822B) << BIT_SHIFT_LPLDH12_VADJ_8822B) +#define BIT_GET_LPLDH12_VADJ_8822B(x) \ + (((x) >> BIT_SHIFT_LPLDH12_VADJ_8822B) & BIT_MASK_LPLDH12_VADJ_8822B) + +#define BIT_LDH12_EN_8822B BIT(16) +#define BIT_WLBBOFF_BIG_PWC_EN_8822B BIT(14) +#define BIT_WLBBOFF_SMALL_PWC_EN_8822B BIT(13) +#define BIT_WLMACOFF_BIG_PWC_EN_8822B BIT(12) +#define BIT_WLPON_PWC_EN_8822B BIT(11) +#define BIT_POW_REGU_P1_8822B BIT(10) +#define BIT_LDOV12W_EN_8822B BIT(8) +#define BIT_EX_XTAL_DRV_DIGI_8822B BIT(7) +#define BIT_EX_XTAL_DRV_USB_8822B BIT(6) +#define BIT_EX_XTAL_DRV_AFE_8822B BIT(5) +#define BIT_EX_XTAL_DRV_RF2_8822B BIT(4) +#define BIT_EX_XTAL_DRV_RF1_8822B BIT(3) +#define BIT_POW_REGU_P0_8822B BIT(2) + +/* 2 REG_NOT_VALID_8822B */ +#define BIT_POW_PLL_LDO_8822B BIT(0) + +/* 2 REG_AFE_CTRL1_8822B */ +#define BIT_AGPIO_GPE_8822B BIT(31) + +#define BIT_SHIFT_XTAL_CAP_XI_8822B 25 +#define BIT_MASK_XTAL_CAP_XI_8822B 0x3f +#define BIT_XTAL_CAP_XI_8822B(x) \ + (((x) & BIT_MASK_XTAL_CAP_XI_8822B) << BIT_SHIFT_XTAL_CAP_XI_8822B) +#define BIT_GET_XTAL_CAP_XI_8822B(x) \ + (((x) >> BIT_SHIFT_XTAL_CAP_XI_8822B) & BIT_MASK_XTAL_CAP_XI_8822B) + +#define BIT_SHIFT_XTAL_DRV_DIGI_8822B 23 +#define BIT_MASK_XTAL_DRV_DIGI_8822B 0x3 +#define BIT_XTAL_DRV_DIGI_8822B(x) \ + (((x) & BIT_MASK_XTAL_DRV_DIGI_8822B) << BIT_SHIFT_XTAL_DRV_DIGI_8822B) +#define BIT_GET_XTAL_DRV_DIGI_8822B(x) \ + (((x) >> BIT_SHIFT_XTAL_DRV_DIGI_8822B) & BIT_MASK_XTAL_DRV_DIGI_8822B) + +#define BIT_XTAL_DRV_USB_BIT1_8822B BIT(22) + +#define BIT_SHIFT_MAC_CLK_SEL_8822B 20 +#define BIT_MASK_MAC_CLK_SEL_8822B 0x3 +#define BIT_MAC_CLK_SEL_8822B(x) \ + (((x) & BIT_MASK_MAC_CLK_SEL_8822B) << BIT_SHIFT_MAC_CLK_SEL_8822B) +#define BIT_GET_MAC_CLK_SEL_8822B(x) \ + (((x) >> BIT_SHIFT_MAC_CLK_SEL_8822B) & BIT_MASK_MAC_CLK_SEL_8822B) + +#define BIT_XTAL_DRV_USB_BIT0_8822B BIT(19) + +#define BIT_SHIFT_XTAL_DRV_AFE_8822B 17 +#define BIT_MASK_XTAL_DRV_AFE_8822B 0x3 +#define BIT_XTAL_DRV_AFE_8822B(x) \ + (((x) & BIT_MASK_XTAL_DRV_AFE_8822B) << BIT_SHIFT_XTAL_DRV_AFE_8822B) +#define BIT_GET_XTAL_DRV_AFE_8822B(x) \ + (((x) >> BIT_SHIFT_XTAL_DRV_AFE_8822B) & BIT_MASK_XTAL_DRV_AFE_8822B) + +#define BIT_SHIFT_XTAL_DRV_RF2_8822B 15 +#define BIT_MASK_XTAL_DRV_RF2_8822B 0x3 +#define BIT_XTAL_DRV_RF2_8822B(x) \ + (((x) & BIT_MASK_XTAL_DRV_RF2_8822B) << BIT_SHIFT_XTAL_DRV_RF2_8822B) +#define BIT_GET_XTAL_DRV_RF2_8822B(x) \ + (((x) >> BIT_SHIFT_XTAL_DRV_RF2_8822B) & BIT_MASK_XTAL_DRV_RF2_8822B) + +#define BIT_SHIFT_XTAL_DRV_RF1_8822B 13 +#define BIT_MASK_XTAL_DRV_RF1_8822B 0x3 +#define BIT_XTAL_DRV_RF1_8822B(x) \ + (((x) & BIT_MASK_XTAL_DRV_RF1_8822B) << BIT_SHIFT_XTAL_DRV_RF1_8822B) +#define BIT_GET_XTAL_DRV_RF1_8822B(x) \ + (((x) >> BIT_SHIFT_XTAL_DRV_RF1_8822B) & BIT_MASK_XTAL_DRV_RF1_8822B) + +#define BIT_XTAL_DELAY_DIGI_8822B BIT(12) +#define BIT_XTAL_DELAY_USB_8822B BIT(11) +#define BIT_XTAL_DELAY_AFE_8822B BIT(10) + +#define BIT_SHIFT_XTAL_LDO_VREF_8822B 7 +#define BIT_MASK_XTAL_LDO_VREF_8822B 0x7 +#define BIT_XTAL_LDO_VREF_8822B(x) \ + (((x) & BIT_MASK_XTAL_LDO_VREF_8822B) << BIT_SHIFT_XTAL_LDO_VREF_8822B) +#define BIT_GET_XTAL_LDO_VREF_8822B(x) \ + (((x) >> BIT_SHIFT_XTAL_LDO_VREF_8822B) & BIT_MASK_XTAL_LDO_VREF_8822B) + +#define BIT_XTAL_XQSEL_RF_8822B BIT(6) +#define BIT_XTAL_XQSEL_8822B BIT(5) + +#define BIT_SHIFT_XTAL_GMN_V2_8822B 3 +#define BIT_MASK_XTAL_GMN_V2_8822B 0x3 +#define BIT_XTAL_GMN_V2_8822B(x) \ + (((x) & BIT_MASK_XTAL_GMN_V2_8822B) << BIT_SHIFT_XTAL_GMN_V2_8822B) +#define BIT_GET_XTAL_GMN_V2_8822B(x) \ + (((x) >> BIT_SHIFT_XTAL_GMN_V2_8822B) & BIT_MASK_XTAL_GMN_V2_8822B) + +#define BIT_SHIFT_XTAL_GMP_V2_8822B 1 +#define BIT_MASK_XTAL_GMP_V2_8822B 0x3 +#define BIT_XTAL_GMP_V2_8822B(x) \ + (((x) & BIT_MASK_XTAL_GMP_V2_8822B) << BIT_SHIFT_XTAL_GMP_V2_8822B) +#define BIT_GET_XTAL_GMP_V2_8822B(x) \ + (((x) >> BIT_SHIFT_XTAL_GMP_V2_8822B) & BIT_MASK_XTAL_GMP_V2_8822B) + +#define BIT_XTAL_EN_8822B BIT(0) + +/* 2 REG_AFE_CTRL2_8822B */ + +#define BIT_SHIFT_REG_C3_V4_8822B 30 +#define BIT_MASK_REG_C3_V4_8822B 0x3 +#define BIT_REG_C3_V4_8822B(x) \ + (((x) & BIT_MASK_REG_C3_V4_8822B) << BIT_SHIFT_REG_C3_V4_8822B) +#define BIT_GET_REG_C3_V4_8822B(x) \ + (((x) >> BIT_SHIFT_REG_C3_V4_8822B) & BIT_MASK_REG_C3_V4_8822B) + +#define BIT_REG_CP_BIT1_8822B BIT(29) + +#define BIT_SHIFT_REG_RS_V4_8822B 26 +#define BIT_MASK_REG_RS_V4_8822B 0x7 +#define BIT_REG_RS_V4_8822B(x) \ + (((x) & BIT_MASK_REG_RS_V4_8822B) << BIT_SHIFT_REG_RS_V4_8822B) +#define BIT_GET_REG_RS_V4_8822B(x) \ + (((x) >> BIT_SHIFT_REG_RS_V4_8822B) & BIT_MASK_REG_RS_V4_8822B) + +#define BIT_SHIFT_REG__CS_8822B 24 +#define BIT_MASK_REG__CS_8822B 0x3 +#define BIT_REG__CS_8822B(x) \ + (((x) & BIT_MASK_REG__CS_8822B) << BIT_SHIFT_REG__CS_8822B) +#define BIT_GET_REG__CS_8822B(x) \ + (((x) >> BIT_SHIFT_REG__CS_8822B) & BIT_MASK_REG__CS_8822B) + +#define BIT_SHIFT_REG_CP_OFFSET_8822B 21 +#define BIT_MASK_REG_CP_OFFSET_8822B 0x7 +#define BIT_REG_CP_OFFSET_8822B(x) \ + (((x) & BIT_MASK_REG_CP_OFFSET_8822B) << BIT_SHIFT_REG_CP_OFFSET_8822B) +#define BIT_GET_REG_CP_OFFSET_8822B(x) \ + (((x) >> BIT_SHIFT_REG_CP_OFFSET_8822B) & BIT_MASK_REG_CP_OFFSET_8822B) + +#define BIT_SHIFT_CP_BIAS_8822B 18 +#define BIT_MASK_CP_BIAS_8822B 0x7 +#define BIT_CP_BIAS_8822B(x) \ + (((x) & BIT_MASK_CP_BIAS_8822B) << BIT_SHIFT_CP_BIAS_8822B) +#define BIT_GET_CP_BIAS_8822B(x) \ + (((x) >> BIT_SHIFT_CP_BIAS_8822B) & BIT_MASK_CP_BIAS_8822B) + +#define BIT_REG_IDOUBLE_V2_8822B BIT(17) +#define BIT_EN_SYN_8822B BIT(16) + +#define BIT_SHIFT_MCCO_8822B 14 +#define BIT_MASK_MCCO_8822B 0x3 +#define BIT_MCCO_8822B(x) (((x) & BIT_MASK_MCCO_8822B) << BIT_SHIFT_MCCO_8822B) +#define BIT_GET_MCCO_8822B(x) \ + (((x) >> BIT_SHIFT_MCCO_8822B) & BIT_MASK_MCCO_8822B) + +#define BIT_SHIFT_REG_LDO_SEL_8822B 12 +#define BIT_MASK_REG_LDO_SEL_8822B 0x3 +#define BIT_REG_LDO_SEL_8822B(x) \ + (((x) & BIT_MASK_REG_LDO_SEL_8822B) << BIT_SHIFT_REG_LDO_SEL_8822B) +#define BIT_GET_REG_LDO_SEL_8822B(x) \ + (((x) >> BIT_SHIFT_REG_LDO_SEL_8822B) & BIT_MASK_REG_LDO_SEL_8822B) + +#define BIT_REG_KVCO_V2_8822B BIT(10) +#define BIT_AGPIO_GPO_8822B BIT(9) + +#define BIT_SHIFT_AGPIO_DRV_8822B 7 +#define BIT_MASK_AGPIO_DRV_8822B 0x3 +#define BIT_AGPIO_DRV_8822B(x) \ + (((x) & BIT_MASK_AGPIO_DRV_8822B) << BIT_SHIFT_AGPIO_DRV_8822B) +#define BIT_GET_AGPIO_DRV_8822B(x) \ + (((x) >> BIT_SHIFT_AGPIO_DRV_8822B) & BIT_MASK_AGPIO_DRV_8822B) + +#define BIT_SHIFT_XTAL_CAP_XO_8822B 1 +#define BIT_MASK_XTAL_CAP_XO_8822B 0x3f +#define BIT_XTAL_CAP_XO_8822B(x) \ + (((x) & BIT_MASK_XTAL_CAP_XO_8822B) << BIT_SHIFT_XTAL_CAP_XO_8822B) +#define BIT_GET_XTAL_CAP_XO_8822B(x) \ + (((x) >> BIT_SHIFT_XTAL_CAP_XO_8822B) & BIT_MASK_XTAL_CAP_XO_8822B) + +#define BIT_POW_PLL_8822B BIT(0) + +/* 2 REG_AFE_CTRL3_8822B */ + +#define BIT_SHIFT_PS_8822B 7 +#define BIT_MASK_PS_8822B 0x7 +#define BIT_PS_8822B(x) (((x) & BIT_MASK_PS_8822B) << BIT_SHIFT_PS_8822B) +#define BIT_GET_PS_8822B(x) (((x) >> BIT_SHIFT_PS_8822B) & BIT_MASK_PS_8822B) + +#define BIT_PSEN_8822B BIT(6) +#define BIT_DOGENB_8822B BIT(5) +#define BIT_REG_MBIAS_8822B BIT(4) + +#define BIT_SHIFT_REG_R3_V4_8822B 1 +#define BIT_MASK_REG_R3_V4_8822B 0x7 +#define BIT_REG_R3_V4_8822B(x) \ + (((x) & BIT_MASK_REG_R3_V4_8822B) << BIT_SHIFT_REG_R3_V4_8822B) +#define BIT_GET_REG_R3_V4_8822B(x) \ + (((x) >> BIT_SHIFT_REG_R3_V4_8822B) & BIT_MASK_REG_R3_V4_8822B) + +#define BIT_REG_CP_BIT0_8822B BIT(0) + +/* 2 REG_EFUSE_CTRL_8822B */ +#define BIT_EF_FLAG_8822B BIT(31) + +#define BIT_SHIFT_EF_PGPD_8822B 28 +#define BIT_MASK_EF_PGPD_8822B 0x7 +#define BIT_EF_PGPD_8822B(x) \ + (((x) & BIT_MASK_EF_PGPD_8822B) << BIT_SHIFT_EF_PGPD_8822B) +#define BIT_GET_EF_PGPD_8822B(x) \ + (((x) >> BIT_SHIFT_EF_PGPD_8822B) & BIT_MASK_EF_PGPD_8822B) + +#define BIT_SHIFT_EF_RDT_8822B 24 +#define BIT_MASK_EF_RDT_8822B 0xf +#define BIT_EF_RDT_8822B(x) \ + (((x) & BIT_MASK_EF_RDT_8822B) << BIT_SHIFT_EF_RDT_8822B) +#define BIT_GET_EF_RDT_8822B(x) \ + (((x) >> BIT_SHIFT_EF_RDT_8822B) & BIT_MASK_EF_RDT_8822B) + +#define BIT_SHIFT_EF_PGTS_8822B 20 +#define BIT_MASK_EF_PGTS_8822B 0xf +#define BIT_EF_PGTS_8822B(x) \ + (((x) & BIT_MASK_EF_PGTS_8822B) << BIT_SHIFT_EF_PGTS_8822B) +#define BIT_GET_EF_PGTS_8822B(x) \ + (((x) >> BIT_SHIFT_EF_PGTS_8822B) & BIT_MASK_EF_PGTS_8822B) + +#define BIT_EF_PDWN_8822B BIT(19) +#define BIT_EF_ALDEN_8822B BIT(18) + +#define BIT_SHIFT_EF_ADDR_8822B 8 +#define BIT_MASK_EF_ADDR_8822B 0x3ff +#define BIT_EF_ADDR_8822B(x) \ + (((x) & BIT_MASK_EF_ADDR_8822B) << BIT_SHIFT_EF_ADDR_8822B) +#define BIT_GET_EF_ADDR_8822B(x) \ + (((x) >> BIT_SHIFT_EF_ADDR_8822B) & BIT_MASK_EF_ADDR_8822B) + +#define BIT_SHIFT_EF_DATA_8822B 0 +#define BIT_MASK_EF_DATA_8822B 0xff +#define BIT_EF_DATA_8822B(x) \ + (((x) & BIT_MASK_EF_DATA_8822B) << BIT_SHIFT_EF_DATA_8822B) +#define BIT_GET_EF_DATA_8822B(x) \ + (((x) >> BIT_SHIFT_EF_DATA_8822B) & BIT_MASK_EF_DATA_8822B) + +/* 2 REG_LDO_EFUSE_CTRL_8822B */ +#define BIT_LDOE25_EN_8822B BIT(31) + +#define BIT_SHIFT_LDOE25_V12ADJ_L_8822B 27 +#define BIT_MASK_LDOE25_V12ADJ_L_8822B 0xf +#define BIT_LDOE25_V12ADJ_L_8822B(x) \ + (((x) & BIT_MASK_LDOE25_V12ADJ_L_8822B) \ + << BIT_SHIFT_LDOE25_V12ADJ_L_8822B) +#define BIT_GET_LDOE25_V12ADJ_L_8822B(x) \ + (((x) >> BIT_SHIFT_LDOE25_V12ADJ_L_8822B) & \ + BIT_MASK_LDOE25_V12ADJ_L_8822B) + +#define BIT_EF_CRES_SEL_8822B BIT(26) + +#define BIT_SHIFT_EF_SCAN_START_V1_8822B 16 +#define BIT_MASK_EF_SCAN_START_V1_8822B 0x3ff +#define BIT_EF_SCAN_START_V1_8822B(x) \ + (((x) & BIT_MASK_EF_SCAN_START_V1_8822B) \ + << BIT_SHIFT_EF_SCAN_START_V1_8822B) +#define BIT_GET_EF_SCAN_START_V1_8822B(x) \ + (((x) >> BIT_SHIFT_EF_SCAN_START_V1_8822B) & \ + BIT_MASK_EF_SCAN_START_V1_8822B) + +#define BIT_SHIFT_EF_SCAN_END_8822B 12 +#define BIT_MASK_EF_SCAN_END_8822B 0xf +#define BIT_EF_SCAN_END_8822B(x) \ + (((x) & BIT_MASK_EF_SCAN_END_8822B) << BIT_SHIFT_EF_SCAN_END_8822B) +#define BIT_GET_EF_SCAN_END_8822B(x) \ + (((x) >> BIT_SHIFT_EF_SCAN_END_8822B) & BIT_MASK_EF_SCAN_END_8822B) + +#define BIT_EF_PD_DIS_8822B BIT(11) + +#define BIT_SHIFT_EF_CELL_SEL_8822B 8 +#define BIT_MASK_EF_CELL_SEL_8822B 0x3 +#define BIT_EF_CELL_SEL_8822B(x) \ + (((x) & BIT_MASK_EF_CELL_SEL_8822B) << BIT_SHIFT_EF_CELL_SEL_8822B) +#define BIT_GET_EF_CELL_SEL_8822B(x) \ + (((x) >> BIT_SHIFT_EF_CELL_SEL_8822B) & BIT_MASK_EF_CELL_SEL_8822B) + +#define BIT_EF_TRPT_8822B BIT(7) + +#define BIT_SHIFT_EF_TTHD_8822B 0 +#define BIT_MASK_EF_TTHD_8822B 0x7f +#define BIT_EF_TTHD_8822B(x) \ + (((x) & BIT_MASK_EF_TTHD_8822B) << BIT_SHIFT_EF_TTHD_8822B) +#define BIT_GET_EF_TTHD_8822B(x) \ + (((x) >> BIT_SHIFT_EF_TTHD_8822B) & BIT_MASK_EF_TTHD_8822B) + +/* 2 REG_PWR_OPTION_CTRL_8822B */ + +#define BIT_SHIFT_DBG_SEL_V1_8822B 16 +#define BIT_MASK_DBG_SEL_V1_8822B 0xff +#define BIT_DBG_SEL_V1_8822B(x) \ + (((x) & BIT_MASK_DBG_SEL_V1_8822B) << BIT_SHIFT_DBG_SEL_V1_8822B) +#define BIT_GET_DBG_SEL_V1_8822B(x) \ + (((x) >> BIT_SHIFT_DBG_SEL_V1_8822B) & BIT_MASK_DBG_SEL_V1_8822B) + +#define BIT_SHIFT_DBG_SEL_BYTE_8822B 14 +#define BIT_MASK_DBG_SEL_BYTE_8822B 0x3 +#define BIT_DBG_SEL_BYTE_8822B(x) \ + (((x) & BIT_MASK_DBG_SEL_BYTE_8822B) << BIT_SHIFT_DBG_SEL_BYTE_8822B) +#define BIT_GET_DBG_SEL_BYTE_8822B(x) \ + (((x) >> BIT_SHIFT_DBG_SEL_BYTE_8822B) & BIT_MASK_DBG_SEL_BYTE_8822B) + +#define BIT_SHIFT_STD_L1_V1_8822B 12 +#define BIT_MASK_STD_L1_V1_8822B 0x3 +#define BIT_STD_L1_V1_8822B(x) \ + (((x) & BIT_MASK_STD_L1_V1_8822B) << BIT_SHIFT_STD_L1_V1_8822B) +#define BIT_GET_STD_L1_V1_8822B(x) \ + (((x) >> BIT_SHIFT_STD_L1_V1_8822B) & BIT_MASK_STD_L1_V1_8822B) + +#define BIT_SYSON_DBG_PAD_E2_8822B BIT(11) +#define BIT_SYSON_LED_PAD_E2_8822B BIT(10) +#define BIT_SYSON_GPEE_PAD_E2_8822B BIT(9) +#define BIT_SYSON_PCI_PAD_E2_8822B BIT(8) +#define BIT_AUTO_SW_LDO_VOL_EN_8822B BIT(7) + +#define BIT_SHIFT_SYSON_SPS0WWV_WT_8822B 4 +#define BIT_MASK_SYSON_SPS0WWV_WT_8822B 0x3 +#define BIT_SYSON_SPS0WWV_WT_8822B(x) \ + (((x) & BIT_MASK_SYSON_SPS0WWV_WT_8822B) \ + << BIT_SHIFT_SYSON_SPS0WWV_WT_8822B) +#define BIT_GET_SYSON_SPS0WWV_WT_8822B(x) \ + (((x) >> BIT_SHIFT_SYSON_SPS0WWV_WT_8822B) & \ + BIT_MASK_SYSON_SPS0WWV_WT_8822B) + +#define BIT_SHIFT_SYSON_SPS0LDO_WT_8822B 2 +#define BIT_MASK_SYSON_SPS0LDO_WT_8822B 0x3 +#define BIT_SYSON_SPS0LDO_WT_8822B(x) \ + (((x) & BIT_MASK_SYSON_SPS0LDO_WT_8822B) \ + << BIT_SHIFT_SYSON_SPS0LDO_WT_8822B) +#define BIT_GET_SYSON_SPS0LDO_WT_8822B(x) \ + (((x) >> BIT_SHIFT_SYSON_SPS0LDO_WT_8822B) & \ + BIT_MASK_SYSON_SPS0LDO_WT_8822B) + +#define BIT_SHIFT_SYSON_RCLK_SCALE_8822B 0 +#define BIT_MASK_SYSON_RCLK_SCALE_8822B 0x3 +#define BIT_SYSON_RCLK_SCALE_8822B(x) \ + (((x) & BIT_MASK_SYSON_RCLK_SCALE_8822B) \ + << BIT_SHIFT_SYSON_RCLK_SCALE_8822B) +#define BIT_GET_SYSON_RCLK_SCALE_8822B(x) \ + (((x) >> BIT_SHIFT_SYSON_RCLK_SCALE_8822B) & \ + BIT_MASK_SYSON_RCLK_SCALE_8822B) + +/* 2 REG_CAL_TIMER_8822B */ + +#define BIT_SHIFT_MATCH_CNT_8822B 8 +#define BIT_MASK_MATCH_CNT_8822B 0xff +#define BIT_MATCH_CNT_8822B(x) \ + (((x) & BIT_MASK_MATCH_CNT_8822B) << BIT_SHIFT_MATCH_CNT_8822B) +#define BIT_GET_MATCH_CNT_8822B(x) \ + (((x) >> BIT_SHIFT_MATCH_CNT_8822B) & BIT_MASK_MATCH_CNT_8822B) + +#define BIT_SHIFT_CAL_SCAL_8822B 0 +#define BIT_MASK_CAL_SCAL_8822B 0xff +#define BIT_CAL_SCAL_8822B(x) \ + (((x) & BIT_MASK_CAL_SCAL_8822B) << BIT_SHIFT_CAL_SCAL_8822B) +#define BIT_GET_CAL_SCAL_8822B(x) \ + (((x) >> BIT_SHIFT_CAL_SCAL_8822B) & BIT_MASK_CAL_SCAL_8822B) + +/* 2 REG_ACLK_MON_8822B */ + +#define BIT_SHIFT_RCLK_MON_8822B 5 +#define BIT_MASK_RCLK_MON_8822B 0x7ff +#define BIT_RCLK_MON_8822B(x) \ + (((x) & BIT_MASK_RCLK_MON_8822B) << BIT_SHIFT_RCLK_MON_8822B) +#define BIT_GET_RCLK_MON_8822B(x) \ + (((x) >> BIT_SHIFT_RCLK_MON_8822B) & BIT_MASK_RCLK_MON_8822B) + +#define BIT_CAL_EN_8822B BIT(4) + +#define BIT_SHIFT_DPSTU_8822B 2 +#define BIT_MASK_DPSTU_8822B 0x3 +#define BIT_DPSTU_8822B(x) \ + (((x) & BIT_MASK_DPSTU_8822B) << BIT_SHIFT_DPSTU_8822B) +#define BIT_GET_DPSTU_8822B(x) \ + (((x) >> BIT_SHIFT_DPSTU_8822B) & BIT_MASK_DPSTU_8822B) + +#define BIT_SUS_16X_8822B BIT(1) + +/* 2 REG_GPIO_MUXCFG_8822B */ +#define BIT_FSPI_EN_8822B BIT(19) +#define BIT_WL_RTS_EXT_32K_SEL_8822B BIT(18) +#define BIT_WLGP_SPI_EN_8822B BIT(16) +#define BIT_SIC_LBK_8822B BIT(15) +#define BIT_ENHTP_8822B BIT(14) +#define BIT_ENSIC_8822B BIT(12) +#define BIT_SIC_SWRST_8822B BIT(11) +#define BIT_PO_WIFI_PTA_PINS_8822B BIT(10) +#define BIT_PO_BT_PTA_PINS_8822B BIT(9) +#define BIT_ENUART_8822B BIT(8) + +#define BIT_SHIFT_BTMODE_8822B 6 +#define BIT_MASK_BTMODE_8822B 0x3 +#define BIT_BTMODE_8822B(x) \ + (((x) & BIT_MASK_BTMODE_8822B) << BIT_SHIFT_BTMODE_8822B) +#define BIT_GET_BTMODE_8822B(x) \ + (((x) >> BIT_SHIFT_BTMODE_8822B) & BIT_MASK_BTMODE_8822B) + +#define BIT_ENBT_8822B BIT(5) +#define BIT_EROM_EN_8822B BIT(4) +#define BIT_WLRFE_6_7_EN_8822B BIT(3) +#define BIT_WLRFE_4_5_EN_8822B BIT(2) + +#define BIT_SHIFT_GPIOSEL_8822B 0 +#define BIT_MASK_GPIOSEL_8822B 0x3 +#define BIT_GPIOSEL_8822B(x) \ + (((x) & BIT_MASK_GPIOSEL_8822B) << BIT_SHIFT_GPIOSEL_8822B) +#define BIT_GET_GPIOSEL_8822B(x) \ + (((x) >> BIT_SHIFT_GPIOSEL_8822B) & BIT_MASK_GPIOSEL_8822B) + +/* 2 REG_GPIO_PIN_CTRL_8822B */ + +#define BIT_SHIFT_GPIO_MOD_7_TO_0_8822B 24 +#define BIT_MASK_GPIO_MOD_7_TO_0_8822B 0xff +#define BIT_GPIO_MOD_7_TO_0_8822B(x) \ + (((x) & BIT_MASK_GPIO_MOD_7_TO_0_8822B) \ + << BIT_SHIFT_GPIO_MOD_7_TO_0_8822B) +#define BIT_GET_GPIO_MOD_7_TO_0_8822B(x) \ + (((x) >> BIT_SHIFT_GPIO_MOD_7_TO_0_8822B) & \ + BIT_MASK_GPIO_MOD_7_TO_0_8822B) + +#define BIT_SHIFT_GPIO_IO_SEL_7_TO_0_8822B 16 +#define BIT_MASK_GPIO_IO_SEL_7_TO_0_8822B 0xff +#define BIT_GPIO_IO_SEL_7_TO_0_8822B(x) \ + (((x) & BIT_MASK_GPIO_IO_SEL_7_TO_0_8822B) \ + << BIT_SHIFT_GPIO_IO_SEL_7_TO_0_8822B) +#define BIT_GET_GPIO_IO_SEL_7_TO_0_8822B(x) \ + (((x) >> BIT_SHIFT_GPIO_IO_SEL_7_TO_0_8822B) & \ + BIT_MASK_GPIO_IO_SEL_7_TO_0_8822B) + +#define BIT_SHIFT_GPIO_OUT_7_TO_0_8822B 8 +#define BIT_MASK_GPIO_OUT_7_TO_0_8822B 0xff +#define BIT_GPIO_OUT_7_TO_0_8822B(x) \ + (((x) & BIT_MASK_GPIO_OUT_7_TO_0_8822B) \ + << BIT_SHIFT_GPIO_OUT_7_TO_0_8822B) +#define BIT_GET_GPIO_OUT_7_TO_0_8822B(x) \ + (((x) >> BIT_SHIFT_GPIO_OUT_7_TO_0_8822B) & \ + BIT_MASK_GPIO_OUT_7_TO_0_8822B) + +#define BIT_SHIFT_GPIO_IN_7_TO_0_8822B 0 +#define BIT_MASK_GPIO_IN_7_TO_0_8822B 0xff +#define BIT_GPIO_IN_7_TO_0_8822B(x) \ + (((x) & BIT_MASK_GPIO_IN_7_TO_0_8822B) \ + << BIT_SHIFT_GPIO_IN_7_TO_0_8822B) +#define BIT_GET_GPIO_IN_7_TO_0_8822B(x) \ + (((x) >> BIT_SHIFT_GPIO_IN_7_TO_0_8822B) & \ + BIT_MASK_GPIO_IN_7_TO_0_8822B) + +/* 2 REG_GPIO_INTM_8822B */ + +#define BIT_SHIFT_MUXDBG_SEL_8822B 30 +#define BIT_MASK_MUXDBG_SEL_8822B 0x3 +#define BIT_MUXDBG_SEL_8822B(x) \ + (((x) & BIT_MASK_MUXDBG_SEL_8822B) << BIT_SHIFT_MUXDBG_SEL_8822B) +#define BIT_GET_MUXDBG_SEL_8822B(x) \ + (((x) >> BIT_SHIFT_MUXDBG_SEL_8822B) & BIT_MASK_MUXDBG_SEL_8822B) + +#define BIT_EXTWOL_SEL_8822B BIT(17) +#define BIT_EXTWOL_EN_8822B BIT(16) +#define BIT_GPIOF_INT_MD_8822B BIT(15) +#define BIT_GPIOE_INT_MD_8822B BIT(14) +#define BIT_GPIOD_INT_MD_8822B BIT(13) +#define BIT_GPIOF_INT_MD_8822B BIT(15) +#define BIT_GPIOE_INT_MD_8822B BIT(14) +#define BIT_GPIOD_INT_MD_8822B BIT(13) +#define BIT_GPIOC_INT_MD_8822B BIT(12) +#define BIT_GPIOB_INT_MD_8822B BIT(11) +#define BIT_GPIOA_INT_MD_8822B BIT(10) +#define BIT_GPIO9_INT_MD_8822B BIT(9) +#define BIT_GPIO8_INT_MD_8822B BIT(8) +#define BIT_GPIO7_INT_MD_8822B BIT(7) +#define BIT_GPIO6_INT_MD_8822B BIT(6) +#define BIT_GPIO5_INT_MD_8822B BIT(5) +#define BIT_GPIO4_INT_MD_8822B BIT(4) +#define BIT_GPIO3_INT_MD_8822B BIT(3) +#define BIT_GPIO2_INT_MD_8822B BIT(2) +#define BIT_GPIO1_INT_MD_8822B BIT(1) +#define BIT_GPIO0_INT_MD_8822B BIT(0) + +/* 2 REG_LED_CFG_8822B */ +#define BIT_GPIO3_WL_CTRL_EN_8822B BIT(27) +#define BIT_LNAON_SEL_EN_8822B BIT(26) +#define BIT_PAPE_SEL_EN_8822B BIT(25) +#define BIT_DPDT_WLBT_SEL_8822B BIT(24) +#define BIT_DPDT_SEL_EN_8822B BIT(23) +#define BIT_GPIO13_14_WL_CTRL_EN_8822B BIT(22) +#define BIT_GPIO13_14_WL_CTRL_EN_8822B BIT(22) +#define BIT_LED2DIS_8822B BIT(21) +#define BIT_LED2PL_8822B BIT(20) +#define BIT_LED2SV_8822B BIT(19) + +#define BIT_SHIFT_LED2CM_8822B 16 +#define BIT_MASK_LED2CM_8822B 0x7 +#define BIT_LED2CM_8822B(x) \ + (((x) & BIT_MASK_LED2CM_8822B) << BIT_SHIFT_LED2CM_8822B) +#define BIT_GET_LED2CM_8822B(x) \ + (((x) >> BIT_SHIFT_LED2CM_8822B) & BIT_MASK_LED2CM_8822B) + +#define BIT_LED1DIS_8822B BIT(15) +#define BIT_LED1PL_8822B BIT(12) +#define BIT_LED1SV_8822B BIT(11) + +#define BIT_SHIFT_LED1CM_8822B 8 +#define BIT_MASK_LED1CM_8822B 0x7 +#define BIT_LED1CM_8822B(x) \ + (((x) & BIT_MASK_LED1CM_8822B) << BIT_SHIFT_LED1CM_8822B) +#define BIT_GET_LED1CM_8822B(x) \ + (((x) >> BIT_SHIFT_LED1CM_8822B) & BIT_MASK_LED1CM_8822B) + +#define BIT_LED0DIS_8822B BIT(7) + +#define BIT_SHIFT_AFE_LDO_SWR_CHECK_8822B 5 +#define BIT_MASK_AFE_LDO_SWR_CHECK_8822B 0x3 +#define BIT_AFE_LDO_SWR_CHECK_8822B(x) \ + (((x) & BIT_MASK_AFE_LDO_SWR_CHECK_8822B) \ + << BIT_SHIFT_AFE_LDO_SWR_CHECK_8822B) +#define BIT_GET_AFE_LDO_SWR_CHECK_8822B(x) \ + (((x) >> BIT_SHIFT_AFE_LDO_SWR_CHECK_8822B) & \ + BIT_MASK_AFE_LDO_SWR_CHECK_8822B) + +#define BIT_LED0PL_8822B BIT(4) +#define BIT_LED0SV_8822B BIT(3) + +#define BIT_SHIFT_LED0CM_8822B 0 +#define BIT_MASK_LED0CM_8822B 0x7 +#define BIT_LED0CM_8822B(x) \ + (((x) & BIT_MASK_LED0CM_8822B) << BIT_SHIFT_LED0CM_8822B) +#define BIT_GET_LED0CM_8822B(x) \ + (((x) >> BIT_SHIFT_LED0CM_8822B) & BIT_MASK_LED0CM_8822B) + +/* 2 REG_FSIMR_8822B */ +#define BIT_FS_PDNINT_EN_8822B BIT(31) +#define BIT_NFC_INT_PAD_EN_8822B BIT(30) +#define BIT_FS_SPS_OCP_INT_EN_8822B BIT(29) +#define BIT_FS_PWMERR_INT_EN_8822B BIT(28) +#define BIT_FS_GPIOF_INT_EN_8822B BIT(27) +#define BIT_FS_GPIOE_INT_EN_8822B BIT(26) +#define BIT_FS_GPIOD_INT_EN_8822B BIT(25) +#define BIT_FS_GPIOC_INT_EN_8822B BIT(24) +#define BIT_FS_GPIOB_INT_EN_8822B BIT(23) +#define BIT_FS_GPIOA_INT_EN_8822B BIT(22) +#define BIT_FS_GPIO9_INT_EN_8822B BIT(21) +#define BIT_FS_GPIO8_INT_EN_8822B BIT(20) +#define BIT_FS_GPIO7_INT_EN_8822B BIT(19) +#define BIT_FS_GPIO6_INT_EN_8822B BIT(18) +#define BIT_FS_GPIO5_INT_EN_8822B BIT(17) +#define BIT_FS_GPIO4_INT_EN_8822B BIT(16) +#define BIT_FS_GPIO3_INT_EN_8822B BIT(15) +#define BIT_FS_GPIO2_INT_EN_8822B BIT(14) +#define BIT_FS_GPIO1_INT_EN_8822B BIT(13) +#define BIT_FS_GPIO0_INT_EN_8822B BIT(12) +#define BIT_FS_HCI_SUS_EN_8822B BIT(11) +#define BIT_FS_HCI_RES_EN_8822B BIT(10) +#define BIT_FS_HCI_RESET_EN_8822B BIT(9) +#define BIT_FS_BTON_STS_UPDATE_MSK_EN_8822B BIT(7) +#define BIT_ACT2RECOVERY_INT_EN_V1_8822B BIT(6) +#define BIT_GEN1GEN2_SWITCH_8822B BIT(5) +#define BIT_HCI_TXDMA_REQ_HIMR_8822B BIT(4) +#define BIT_FS_32K_LEAVE_SETTING_MAK_8822B BIT(3) +#define BIT_FS_32K_ENTER_SETTING_MAK_8822B BIT(2) +#define BIT_FS_USB_LPMRSM_MSK_8822B BIT(1) +#define BIT_FS_USB_LPMINT_MSK_8822B BIT(0) + +/* 2 REG_FSISR_8822B */ +#define BIT_FS_PDNINT_8822B BIT(31) +#define BIT_FS_SPS_OCP_INT_8822B BIT(29) +#define BIT_FS_PWMERR_INT_8822B BIT(28) +#define BIT_FS_GPIOF_INT_8822B BIT(27) +#define BIT_FS_GPIOE_INT_8822B BIT(26) +#define BIT_FS_GPIOD_INT_8822B BIT(25) +#define BIT_FS_GPIOC_INT_8822B BIT(24) +#define BIT_FS_GPIOB_INT_8822B BIT(23) +#define BIT_FS_GPIOA_INT_8822B BIT(22) +#define BIT_FS_GPIO9_INT_8822B BIT(21) +#define BIT_FS_GPIO8_INT_8822B BIT(20) +#define BIT_FS_GPIO7_INT_8822B BIT(19) +#define BIT_FS_GPIO6_INT_8822B BIT(18) +#define BIT_FS_GPIO5_INT_8822B BIT(17) +#define BIT_FS_GPIO4_INT_8822B BIT(16) +#define BIT_FS_GPIO3_INT_8822B BIT(15) +#define BIT_FS_GPIO2_INT_8822B BIT(14) +#define BIT_FS_GPIO1_INT_8822B BIT(13) +#define BIT_FS_GPIO0_INT_8822B BIT(12) +#define BIT_FS_HCI_SUS_INT_8822B BIT(11) +#define BIT_FS_HCI_RES_INT_8822B BIT(10) +#define BIT_FS_HCI_RESET_INT_8822B BIT(9) +#define BIT_ACT2RECOVERY_8822B BIT(6) +#define BIT_GEN1GEN2_SWITCH_8822B BIT(5) +#define BIT_HCI_TXDMA_REQ_HISR_8822B BIT(4) +#define BIT_FS_32K_LEAVE_SETTING_INT_8822B BIT(3) +#define BIT_FS_32K_ENTER_SETTING_INT_8822B BIT(2) +#define BIT_FS_USB_LPMRSM_INT_8822B BIT(1) +#define BIT_FS_USB_LPMINT_INT_8822B BIT(0) + +/* 2 REG_HSIMR_8822B */ +#define BIT_GPIOF_INT_EN_8822B BIT(31) +#define BIT_GPIOE_INT_EN_8822B BIT(30) +#define BIT_GPIOD_INT_EN_8822B BIT(29) +#define BIT_GPIOC_INT_EN_8822B BIT(28) +#define BIT_GPIOB_INT_EN_8822B BIT(27) +#define BIT_GPIOA_INT_EN_8822B BIT(26) +#define BIT_GPIO9_INT_EN_8822B BIT(25) +#define BIT_GPIO8_INT_EN_8822B BIT(24) +#define BIT_GPIO7_INT_EN_8822B BIT(23) +#define BIT_GPIO6_INT_EN_8822B BIT(22) +#define BIT_GPIO5_INT_EN_8822B BIT(21) +#define BIT_GPIO4_INT_EN_8822B BIT(20) +#define BIT_GPIO3_INT_EN_8822B BIT(19) +#define BIT_GPIO2_INT_EN_V1_8822B BIT(16) +#define BIT_GPIO1_INT_EN_8822B BIT(17) +#define BIT_GPIO0_INT_EN_8822B BIT(16) +#define BIT_PDNINT_EN_8822B BIT(7) +#define BIT_RON_INT_EN_8822B BIT(6) +#define BIT_SPS_OCP_INT_EN_8822B BIT(5) +#define BIT_GPIO15_0_INT_EN_8822B BIT(0) + +/* 2 REG_HSISR_8822B */ +#define BIT_GPIOF_INT_8822B BIT(31) +#define BIT_GPIOE_INT_8822B BIT(30) +#define BIT_GPIOD_INT_8822B BIT(29) +#define BIT_GPIOC_INT_8822B BIT(28) +#define BIT_GPIOB_INT_8822B BIT(27) +#define BIT_GPIOA_INT_8822B BIT(26) +#define BIT_GPIO9_INT_8822B BIT(25) +#define BIT_GPIO8_INT_8822B BIT(24) +#define BIT_GPIO7_INT_8822B BIT(23) +#define BIT_GPIO6_INT_8822B BIT(22) +#define BIT_GPIO5_INT_8822B BIT(21) +#define BIT_GPIO4_INT_8822B BIT(20) +#define BIT_GPIO3_INT_8822B BIT(19) +#define BIT_GPIO2_INT_V1_8822B BIT(16) +#define BIT_GPIO1_INT_8822B BIT(17) +#define BIT_GPIO0_INT_8822B BIT(16) +#define BIT_PDNINT_8822B BIT(7) +#define BIT_RON_INT_8822B BIT(6) +#define BIT_SPS_OCP_INT_8822B BIT(5) +#define BIT_GPIO15_0_INT_8822B BIT(0) + +/* 2 REG_GPIO_EXT_CTRL_8822B */ + +#define BIT_SHIFT_GPIO_MOD_15_TO_8_8822B 24 +#define BIT_MASK_GPIO_MOD_15_TO_8_8822B 0xff +#define BIT_GPIO_MOD_15_TO_8_8822B(x) \ + (((x) & BIT_MASK_GPIO_MOD_15_TO_8_8822B) \ + << BIT_SHIFT_GPIO_MOD_15_TO_8_8822B) +#define BIT_GET_GPIO_MOD_15_TO_8_8822B(x) \ + (((x) >> BIT_SHIFT_GPIO_MOD_15_TO_8_8822B) & \ + BIT_MASK_GPIO_MOD_15_TO_8_8822B) + +#define BIT_SHIFT_GPIO_IO_SEL_15_TO_8_8822B 16 +#define BIT_MASK_GPIO_IO_SEL_15_TO_8_8822B 0xff +#define BIT_GPIO_IO_SEL_15_TO_8_8822B(x) \ + (((x) & BIT_MASK_GPIO_IO_SEL_15_TO_8_8822B) \ + << BIT_SHIFT_GPIO_IO_SEL_15_TO_8_8822B) +#define BIT_GET_GPIO_IO_SEL_15_TO_8_8822B(x) \ + (((x) >> BIT_SHIFT_GPIO_IO_SEL_15_TO_8_8822B) & \ + BIT_MASK_GPIO_IO_SEL_15_TO_8_8822B) + +#define BIT_SHIFT_GPIO_OUT_15_TO_8_8822B 8 +#define BIT_MASK_GPIO_OUT_15_TO_8_8822B 0xff +#define BIT_GPIO_OUT_15_TO_8_8822B(x) \ + (((x) & BIT_MASK_GPIO_OUT_15_TO_8_8822B) \ + << BIT_SHIFT_GPIO_OUT_15_TO_8_8822B) +#define BIT_GET_GPIO_OUT_15_TO_8_8822B(x) \ + (((x) >> BIT_SHIFT_GPIO_OUT_15_TO_8_8822B) & \ + BIT_MASK_GPIO_OUT_15_TO_8_8822B) + +#define BIT_SHIFT_GPIO_IN_15_TO_8_8822B 0 +#define BIT_MASK_GPIO_IN_15_TO_8_8822B 0xff +#define BIT_GPIO_IN_15_TO_8_8822B(x) \ + (((x) & BIT_MASK_GPIO_IN_15_TO_8_8822B) \ + << BIT_SHIFT_GPIO_IN_15_TO_8_8822B) +#define BIT_GET_GPIO_IN_15_TO_8_8822B(x) \ + (((x) >> BIT_SHIFT_GPIO_IN_15_TO_8_8822B) & \ + BIT_MASK_GPIO_IN_15_TO_8_8822B) + +/* 2 REG_PAD_CTRL1_8822B */ +#define BIT_PAPE_WLBT_SEL_8822B BIT(29) +#define BIT_LNAON_WLBT_SEL_8822B BIT(28) +#define BIT_BTGP_GPG3_FEN_8822B BIT(26) +#define BIT_BTGP_GPG2_FEN_8822B BIT(25) +#define BIT_BTGP_JTAG_EN_8822B BIT(24) +#define BIT_XTAL_CLK_EXTARNAL_EN_8822B BIT(23) +#define BIT_BTGP_UART0_EN_8822B BIT(22) +#define BIT_BTGP_UART1_EN_8822B BIT(21) +#define BIT_BTGP_SPI_EN_8822B BIT(20) +#define BIT_BTGP_GPIO_E2_8822B BIT(19) +#define BIT_BTGP_GPIO_EN_8822B BIT(18) + +#define BIT_SHIFT_BTGP_GPIO_SL_8822B 16 +#define BIT_MASK_BTGP_GPIO_SL_8822B 0x3 +#define BIT_BTGP_GPIO_SL_8822B(x) \ + (((x) & BIT_MASK_BTGP_GPIO_SL_8822B) << BIT_SHIFT_BTGP_GPIO_SL_8822B) +#define BIT_GET_BTGP_GPIO_SL_8822B(x) \ + (((x) >> BIT_SHIFT_BTGP_GPIO_SL_8822B) & BIT_MASK_BTGP_GPIO_SL_8822B) + +#define BIT_PAD_SDIO_SR_8822B BIT(14) +#define BIT_GPIO14_OUTPUT_PL_8822B BIT(13) +#define BIT_HOST_WAKE_PAD_PULL_EN_8822B BIT(12) +#define BIT_HOST_WAKE_PAD_SL_8822B BIT(11) +#define BIT_PAD_LNAON_SR_8822B BIT(10) +#define BIT_PAD_LNAON_E2_8822B BIT(9) +#define BIT_SW_LNAON_G_SEL_DATA_8822B BIT(8) +#define BIT_SW_LNAON_A_SEL_DATA_8822B BIT(7) +#define BIT_PAD_PAPE_SR_8822B BIT(6) +#define BIT_PAD_PAPE_E2_8822B BIT(5) +#define BIT_SW_PAPE_G_SEL_DATA_8822B BIT(4) +#define BIT_SW_PAPE_A_SEL_DATA_8822B BIT(3) +#define BIT_PAD_DPDT_SR_8822B BIT(2) +#define BIT_PAD_DPDT_PAD_E2_8822B BIT(1) +#define BIT_SW_DPDT_SEL_DATA_8822B BIT(0) + +/* 2 REG_WL_BT_PWR_CTRL_8822B */ +#define BIT_ISO_BD2PP_8822B BIT(31) +#define BIT_LDOV12B_EN_8822B BIT(30) +#define BIT_CKEN_BTGPS_8822B BIT(29) +#define BIT_FEN_BTGPS_8822B BIT(28) +#define BIT_BTCPU_BOOTSEL_8822B BIT(27) +#define BIT_SPI_SPEEDUP_8822B BIT(26) +#define BIT_DEVWAKE_PAD_TYPE_SEL_8822B BIT(24) +#define BIT_CLKREQ_PAD_TYPE_SEL_8822B BIT(23) +#define BIT_ISO_BTPON2PP_8822B BIT(22) +#define BIT_BT_HWROF_EN_8822B BIT(19) +#define BIT_BT_FUNC_EN_8822B BIT(18) +#define BIT_BT_HWPDN_SL_8822B BIT(17) +#define BIT_BT_DISN_EN_8822B BIT(16) +#define BIT_BT_PDN_PULL_EN_8822B BIT(15) +#define BIT_WL_PDN_PULL_EN_8822B BIT(14) +#define BIT_EXTERNAL_REQUEST_PL_8822B BIT(13) +#define BIT_GPIO0_2_3_PULL_LOW_EN_8822B BIT(12) +#define BIT_ISO_BA2PP_8822B BIT(11) +#define BIT_BT_AFE_LDO_EN_8822B BIT(10) +#define BIT_BT_AFE_PLL_EN_8822B BIT(9) +#define BIT_BT_DIG_CLK_EN_8822B BIT(8) +#define BIT_WL_DRV_EXIST_IDX_8822B BIT(5) +#define BIT_DOP_EHPAD_8822B BIT(4) +#define BIT_WL_HWROF_EN_8822B BIT(3) +#define BIT_WL_FUNC_EN_8822B BIT(2) +#define BIT_WL_HWPDN_SL_8822B BIT(1) +#define BIT_WL_HWPDN_EN_8822B BIT(0) + +/* 2 REG_SDM_DEBUG_8822B */ + +#define BIT_SHIFT_WLCLK_PHASE_8822B 0 +#define BIT_MASK_WLCLK_PHASE_8822B 0x1f +#define BIT_WLCLK_PHASE_8822B(x) \ + (((x) & BIT_MASK_WLCLK_PHASE_8822B) << BIT_SHIFT_WLCLK_PHASE_8822B) +#define BIT_GET_WLCLK_PHASE_8822B(x) \ + (((x) >> BIT_SHIFT_WLCLK_PHASE_8822B) & BIT_MASK_WLCLK_PHASE_8822B) + +/* 2 REG_SYS_SDIO_CTRL_8822B */ +#define BIT_DBG_GNT_WL_BT_8822B BIT(27) +#define BIT_LTE_MUX_CTRL_PATH_8822B BIT(26) +#define BIT_LTE_COEX_UART_8822B BIT(25) +#define BIT_3W_LTE_WL_GPIO_8822B BIT(24) +#define BIT_SDIO_INT_POLARITY_8822B BIT(19) +#define BIT_SDIO_INT_8822B BIT(18) +#define BIT_SDIO_OFF_EN_8822B BIT(17) +#define BIT_SDIO_ON_EN_8822B BIT(16) +#define BIT_PCIE_WAIT_TIMEOUT_EVENT_8822B BIT(10) +#define BIT_PCIE_WAIT_TIME_8822B BIT(9) +#define BIT_MPCIE_REFCLK_XTAL_SEL_8822B BIT(8) + +/* 2 REG_HCI_OPT_CTRL_8822B */ + +#define BIT_SHIFT_TSFT_SEL_8822B 29 +#define BIT_MASK_TSFT_SEL_8822B 0x7 +#define BIT_TSFT_SEL_8822B(x) \ + (((x) & BIT_MASK_TSFT_SEL_8822B) << BIT_SHIFT_TSFT_SEL_8822B) +#define BIT_GET_TSFT_SEL_8822B(x) \ + (((x) >> BIT_SHIFT_TSFT_SEL_8822B) & BIT_MASK_TSFT_SEL_8822B) + +#define BIT_USB_HOST_PWR_OFF_EN_8822B BIT(12) +#define BIT_SYM_LPS_BLOCK_EN_8822B BIT(11) +#define BIT_USB_LPM_ACT_EN_8822B BIT(10) +#define BIT_USB_LPM_NY_8822B BIT(9) +#define BIT_USB_SUS_DIS_8822B BIT(8) + +#define BIT_SHIFT_SDIO_PAD_E_8822B 5 +#define BIT_MASK_SDIO_PAD_E_8822B 0x7 +#define BIT_SDIO_PAD_E_8822B(x) \ + (((x) & BIT_MASK_SDIO_PAD_E_8822B) << BIT_SHIFT_SDIO_PAD_E_8822B) +#define BIT_GET_SDIO_PAD_E_8822B(x) \ + (((x) >> BIT_SHIFT_SDIO_PAD_E_8822B) & BIT_MASK_SDIO_PAD_E_8822B) + +#define BIT_USB_LPPLL_EN_8822B BIT(4) +#define BIT_ROP_SW15_8822B BIT(2) +#define BIT_PCI_CKRDY_OPT_8822B BIT(1) +#define BIT_PCI_VAUX_EN_8822B BIT(0) + +/* 2 REG_AFE_CTRL4_8822B */ + +/* 2 REG_LDO_SWR_CTRL_8822B */ +#define BIT_ZCD_HW_AUTO_EN_8822B BIT(27) +#define BIT_ZCD_REGSEL_8822B BIT(26) + +#define BIT_SHIFT_AUTO_ZCD_IN_CODE_8822B 21 +#define BIT_MASK_AUTO_ZCD_IN_CODE_8822B 0x1f +#define BIT_AUTO_ZCD_IN_CODE_8822B(x) \ + (((x) & BIT_MASK_AUTO_ZCD_IN_CODE_8822B) \ + << BIT_SHIFT_AUTO_ZCD_IN_CODE_8822B) +#define BIT_GET_AUTO_ZCD_IN_CODE_8822B(x) \ + (((x) >> BIT_SHIFT_AUTO_ZCD_IN_CODE_8822B) & \ + BIT_MASK_AUTO_ZCD_IN_CODE_8822B) + +#define BIT_SHIFT_ZCD_CODE_IN_L_8822B 16 +#define BIT_MASK_ZCD_CODE_IN_L_8822B 0x1f +#define BIT_ZCD_CODE_IN_L_8822B(x) \ + (((x) & BIT_MASK_ZCD_CODE_IN_L_8822B) << BIT_SHIFT_ZCD_CODE_IN_L_8822B) +#define BIT_GET_ZCD_CODE_IN_L_8822B(x) \ + (((x) >> BIT_SHIFT_ZCD_CODE_IN_L_8822B) & BIT_MASK_ZCD_CODE_IN_L_8822B) + +#define BIT_SHIFT_LDO_HV5_DUMMY_8822B 14 +#define BIT_MASK_LDO_HV5_DUMMY_8822B 0x3 +#define BIT_LDO_HV5_DUMMY_8822B(x) \ + (((x) & BIT_MASK_LDO_HV5_DUMMY_8822B) << BIT_SHIFT_LDO_HV5_DUMMY_8822B) +#define BIT_GET_LDO_HV5_DUMMY_8822B(x) \ + (((x) >> BIT_SHIFT_LDO_HV5_DUMMY_8822B) & BIT_MASK_LDO_HV5_DUMMY_8822B) + +#define BIT_SHIFT_REG_VTUNE33_BIT0_TO_BIT1_8822B 12 +#define BIT_MASK_REG_VTUNE33_BIT0_TO_BIT1_8822B 0x3 +#define BIT_REG_VTUNE33_BIT0_TO_BIT1_8822B(x) \ + (((x) & BIT_MASK_REG_VTUNE33_BIT0_TO_BIT1_8822B) \ + << BIT_SHIFT_REG_VTUNE33_BIT0_TO_BIT1_8822B) +#define BIT_GET_REG_VTUNE33_BIT0_TO_BIT1_8822B(x) \ + (((x) >> BIT_SHIFT_REG_VTUNE33_BIT0_TO_BIT1_8822B) & \ + BIT_MASK_REG_VTUNE33_BIT0_TO_BIT1_8822B) + +#define BIT_SHIFT_REG_STANDBY33_BIT0_TO_BIT1_8822B 10 +#define BIT_MASK_REG_STANDBY33_BIT0_TO_BIT1_8822B 0x3 +#define BIT_REG_STANDBY33_BIT0_TO_BIT1_8822B(x) \ + (((x) & BIT_MASK_REG_STANDBY33_BIT0_TO_BIT1_8822B) \ + << BIT_SHIFT_REG_STANDBY33_BIT0_TO_BIT1_8822B) +#define BIT_GET_REG_STANDBY33_BIT0_TO_BIT1_8822B(x) \ + (((x) >> BIT_SHIFT_REG_STANDBY33_BIT0_TO_BIT1_8822B) & \ + BIT_MASK_REG_STANDBY33_BIT0_TO_BIT1_8822B) + +#define BIT_SHIFT_REG_LOAD33_BIT0_TO_BIT1_8822B 8 +#define BIT_MASK_REG_LOAD33_BIT0_TO_BIT1_8822B 0x3 +#define BIT_REG_LOAD33_BIT0_TO_BIT1_8822B(x) \ + (((x) & BIT_MASK_REG_LOAD33_BIT0_TO_BIT1_8822B) \ + << BIT_SHIFT_REG_LOAD33_BIT0_TO_BIT1_8822B) +#define BIT_GET_REG_LOAD33_BIT0_TO_BIT1_8822B(x) \ + (((x) >> BIT_SHIFT_REG_LOAD33_BIT0_TO_BIT1_8822B) & \ + BIT_MASK_REG_LOAD33_BIT0_TO_BIT1_8822B) + +#define BIT_REG_BYPASS_L_8822B BIT(7) +#define BIT_REG_LDOF_L_8822B BIT(6) +#define BIT_REG_TYPE_L_V1_8822B BIT(5) +#define BIT_ARENB_L_8822B BIT(3) + +#define BIT_SHIFT_CFC_L_8822B 1 +#define BIT_MASK_CFC_L_8822B 0x3 +#define BIT_CFC_L_8822B(x) \ + (((x) & BIT_MASK_CFC_L_8822B) << BIT_SHIFT_CFC_L_8822B) +#define BIT_GET_CFC_L_8822B(x) \ + (((x) >> BIT_SHIFT_CFC_L_8822B) & BIT_MASK_CFC_L_8822B) + +#define BIT_REG_OCPS_L_V1_8822B BIT(0) + +/* 2 REG_MCUFW_CTRL_8822B */ + +#define BIT_SHIFT_RPWM_8822B 24 +#define BIT_MASK_RPWM_8822B 0xff +#define BIT_RPWM_8822B(x) (((x) & BIT_MASK_RPWM_8822B) << BIT_SHIFT_RPWM_8822B) +#define BIT_GET_RPWM_8822B(x) \ + (((x) >> BIT_SHIFT_RPWM_8822B) & BIT_MASK_RPWM_8822B) + +#define BIT_ANA_PORT_EN_8822B BIT(22) +#define BIT_MAC_PORT_EN_8822B BIT(21) +#define BIT_BOOT_FSPI_EN_8822B BIT(20) +#define BIT_ROM_DLEN_8822B BIT(19) + +#define BIT_SHIFT_ROM_PGE_8822B 16 +#define BIT_MASK_ROM_PGE_8822B 0x7 +#define BIT_ROM_PGE_8822B(x) \ + (((x) & BIT_MASK_ROM_PGE_8822B) << BIT_SHIFT_ROM_PGE_8822B) +#define BIT_GET_ROM_PGE_8822B(x) \ + (((x) >> BIT_SHIFT_ROM_PGE_8822B) & BIT_MASK_ROM_PGE_8822B) + +#define BIT_FW_INIT_RDY_8822B BIT(15) +#define BIT_FW_DW_RDY_8822B BIT(14) + +#define BIT_SHIFT_CPU_CLK_SEL_8822B 12 +#define BIT_MASK_CPU_CLK_SEL_8822B 0x3 +#define BIT_CPU_CLK_SEL_8822B(x) \ + (((x) & BIT_MASK_CPU_CLK_SEL_8822B) << BIT_SHIFT_CPU_CLK_SEL_8822B) +#define BIT_GET_CPU_CLK_SEL_8822B(x) \ + (((x) >> BIT_SHIFT_CPU_CLK_SEL_8822B) & BIT_MASK_CPU_CLK_SEL_8822B) + +#define BIT_CCLK_CHG_MASK_8822B BIT(11) +#define BIT_EMEM__TXBUF_CHKSUM_OK_8822B BIT(10) +#define BIT_EMEM_TXBUF_DW_RDY_8822B BIT(9) +#define BIT_EMEM_CHKSUM_OK_8822B BIT(8) +#define BIT_EMEM_DW_OK_8822B BIT(7) +#define BIT_DMEM_CHKSUM_OK_8822B BIT(6) +#define BIT_DMEM_DW_OK_8822B BIT(5) +#define BIT_IMEM_CHKSUM_OK_8822B BIT(4) +#define BIT_IMEM_DW_OK_8822B BIT(3) +#define BIT_IMEM_BOOT_LOAD_CHKSUM_OK_8822B BIT(2) +#define BIT_IMEM_BOOT_LOAD_DW_OK_8822B BIT(1) +#define BIT_MCUFWDL_EN_8822B BIT(0) + +/* 2 REG_MCU_TST_CFG_8822B */ + +#define BIT_SHIFT_LBKTST_8822B 0 +#define BIT_MASK_LBKTST_8822B 0xffff +#define BIT_LBKTST_8822B(x) \ + (((x) & BIT_MASK_LBKTST_8822B) << BIT_SHIFT_LBKTST_8822B) +#define BIT_GET_LBKTST_8822B(x) \ + (((x) >> BIT_SHIFT_LBKTST_8822B) & BIT_MASK_LBKTST_8822B) + +/* 2 REG_HMEBOX_E0_E1_8822B */ + +#define BIT_SHIFT_HOST_MSG_E1_8822B 16 +#define BIT_MASK_HOST_MSG_E1_8822B 0xffff +#define BIT_HOST_MSG_E1_8822B(x) \ + (((x) & BIT_MASK_HOST_MSG_E1_8822B) << BIT_SHIFT_HOST_MSG_E1_8822B) +#define BIT_GET_HOST_MSG_E1_8822B(x) \ + (((x) >> BIT_SHIFT_HOST_MSG_E1_8822B) & BIT_MASK_HOST_MSG_E1_8822B) + +#define BIT_SHIFT_HOST_MSG_E0_8822B 0 +#define BIT_MASK_HOST_MSG_E0_8822B 0xffff +#define BIT_HOST_MSG_E0_8822B(x) \ + (((x) & BIT_MASK_HOST_MSG_E0_8822B) << BIT_SHIFT_HOST_MSG_E0_8822B) +#define BIT_GET_HOST_MSG_E0_8822B(x) \ + (((x) >> BIT_SHIFT_HOST_MSG_E0_8822B) & BIT_MASK_HOST_MSG_E0_8822B) + +/* 2 REG_HMEBOX_E2_E3_8822B */ + +#define BIT_SHIFT_HOST_MSG_E3_8822B 16 +#define BIT_MASK_HOST_MSG_E3_8822B 0xffff +#define BIT_HOST_MSG_E3_8822B(x) \ + (((x) & BIT_MASK_HOST_MSG_E3_8822B) << BIT_SHIFT_HOST_MSG_E3_8822B) +#define BIT_GET_HOST_MSG_E3_8822B(x) \ + (((x) >> BIT_SHIFT_HOST_MSG_E3_8822B) & BIT_MASK_HOST_MSG_E3_8822B) + +#define BIT_SHIFT_HOST_MSG_E2_8822B 0 +#define BIT_MASK_HOST_MSG_E2_8822B 0xffff +#define BIT_HOST_MSG_E2_8822B(x) \ + (((x) & BIT_MASK_HOST_MSG_E2_8822B) << BIT_SHIFT_HOST_MSG_E2_8822B) +#define BIT_GET_HOST_MSG_E2_8822B(x) \ + (((x) >> BIT_SHIFT_HOST_MSG_E2_8822B) & BIT_MASK_HOST_MSG_E2_8822B) + +/* 2 REG_WLLPS_CTRL_8822B */ +#define BIT_WLLPSOP_EABM_8822B BIT(31) +#define BIT_WLLPSOP_ACKF_8822B BIT(30) +#define BIT_WLLPSOP_DLDM_8822B BIT(29) +#define BIT_WLLPSOP_ESWR_8822B BIT(28) +#define BIT_WLLPSOP_PWMM_8822B BIT(27) +#define BIT_WLLPSOP_EECK_8822B BIT(26) +#define BIT_WLLPSOP_WLMACOFF_8822B BIT(25) +#define BIT_WLLPSOP_EXTAL_8822B BIT(24) +#define BIT_WL_SYNPON_VOLTSPDN_8822B BIT(23) +#define BIT_WLLPSOP_WLBBOFF_8822B BIT(22) +#define BIT_WLLPSOP_WLMEM_DS_8822B BIT(21) + +#define BIT_SHIFT_LPLDH12_VADJ_STEP_DN_8822B 12 +#define BIT_MASK_LPLDH12_VADJ_STEP_DN_8822B 0xf +#define BIT_LPLDH12_VADJ_STEP_DN_8822B(x) \ + (((x) & BIT_MASK_LPLDH12_VADJ_STEP_DN_8822B) \ + << BIT_SHIFT_LPLDH12_VADJ_STEP_DN_8822B) +#define BIT_GET_LPLDH12_VADJ_STEP_DN_8822B(x) \ + (((x) >> BIT_SHIFT_LPLDH12_VADJ_STEP_DN_8822B) & \ + BIT_MASK_LPLDH12_VADJ_STEP_DN_8822B) + +#define BIT_SHIFT_V15ADJ_L1_STEP_DN_8822B 8 +#define BIT_MASK_V15ADJ_L1_STEP_DN_8822B 0x7 +#define BIT_V15ADJ_L1_STEP_DN_8822B(x) \ + (((x) & BIT_MASK_V15ADJ_L1_STEP_DN_8822B) \ + << BIT_SHIFT_V15ADJ_L1_STEP_DN_8822B) +#define BIT_GET_V15ADJ_L1_STEP_DN_8822B(x) \ + (((x) >> BIT_SHIFT_V15ADJ_L1_STEP_DN_8822B) & \ + BIT_MASK_V15ADJ_L1_STEP_DN_8822B) + +#define BIT_REGU_32K_CLK_EN_8822B BIT(1) +#define BIT_WL_LPS_EN_8822B BIT(0) + +/* 2 REG_AFE_CTRL5_8822B */ +#define BIT_BB_DBG_SEL_AFE_SDM_BIT0_8822B BIT(31) +#define BIT_ORDER_SDM_8822B BIT(30) +#define BIT_RFE_SEL_SDM_8822B BIT(29) + +#define BIT_SHIFT_REF_SEL_8822B 25 +#define BIT_MASK_REF_SEL_8822B 0xf +#define BIT_REF_SEL_8822B(x) \ + (((x) & BIT_MASK_REF_SEL_8822B) << BIT_SHIFT_REF_SEL_8822B) +#define BIT_GET_REF_SEL_8822B(x) \ + (((x) >> BIT_SHIFT_REF_SEL_8822B) & BIT_MASK_REF_SEL_8822B) + +#define BIT_SHIFT_F0F_SDM_8822B 12 +#define BIT_MASK_F0F_SDM_8822B 0x1fff +#define BIT_F0F_SDM_8822B(x) \ + (((x) & BIT_MASK_F0F_SDM_8822B) << BIT_SHIFT_F0F_SDM_8822B) +#define BIT_GET_F0F_SDM_8822B(x) \ + (((x) >> BIT_SHIFT_F0F_SDM_8822B) & BIT_MASK_F0F_SDM_8822B) + +#define BIT_SHIFT_F0N_SDM_8822B 9 +#define BIT_MASK_F0N_SDM_8822B 0x7 +#define BIT_F0N_SDM_8822B(x) \ + (((x) & BIT_MASK_F0N_SDM_8822B) << BIT_SHIFT_F0N_SDM_8822B) +#define BIT_GET_F0N_SDM_8822B(x) \ + (((x) >> BIT_SHIFT_F0N_SDM_8822B) & BIT_MASK_F0N_SDM_8822B) + +#define BIT_SHIFT_DIVN_SDM_8822B 3 +#define BIT_MASK_DIVN_SDM_8822B 0x3f +#define BIT_DIVN_SDM_8822B(x) \ + (((x) & BIT_MASK_DIVN_SDM_8822B) << BIT_SHIFT_DIVN_SDM_8822B) +#define BIT_GET_DIVN_SDM_8822B(x) \ + (((x) >> BIT_SHIFT_DIVN_SDM_8822B) & BIT_MASK_DIVN_SDM_8822B) + +/* 2 REG_GPIO_DEBOUNCE_CTRL_8822B */ +#define BIT_WLGP_DBC1EN_8822B BIT(15) + +#define BIT_SHIFT_WLGP_DBC1_8822B 8 +#define BIT_MASK_WLGP_DBC1_8822B 0xf +#define BIT_WLGP_DBC1_8822B(x) \ + (((x) & BIT_MASK_WLGP_DBC1_8822B) << BIT_SHIFT_WLGP_DBC1_8822B) +#define BIT_GET_WLGP_DBC1_8822B(x) \ + (((x) >> BIT_SHIFT_WLGP_DBC1_8822B) & BIT_MASK_WLGP_DBC1_8822B) + +#define BIT_WLGP_DBC0EN_8822B BIT(7) + +#define BIT_SHIFT_WLGP_DBC0_8822B 0 +#define BIT_MASK_WLGP_DBC0_8822B 0xf +#define BIT_WLGP_DBC0_8822B(x) \ + (((x) & BIT_MASK_WLGP_DBC0_8822B) << BIT_SHIFT_WLGP_DBC0_8822B) +#define BIT_GET_WLGP_DBC0_8822B(x) \ + (((x) >> BIT_SHIFT_WLGP_DBC0_8822B) & BIT_MASK_WLGP_DBC0_8822B) + +/* 2 REG_RPWM2_8822B */ + +#define BIT_SHIFT_RPWM2_8822B 16 +#define BIT_MASK_RPWM2_8822B 0xffff +#define BIT_RPWM2_8822B(x) \ + (((x) & BIT_MASK_RPWM2_8822B) << BIT_SHIFT_RPWM2_8822B) +#define BIT_GET_RPWM2_8822B(x) \ + (((x) >> BIT_SHIFT_RPWM2_8822B) & BIT_MASK_RPWM2_8822B) + +/* 2 REG_SYSON_FSM_MON_8822B */ + +#define BIT_SHIFT_FSM_MON_SEL_8822B 24 +#define BIT_MASK_FSM_MON_SEL_8822B 0x7 +#define BIT_FSM_MON_SEL_8822B(x) \ + (((x) & BIT_MASK_FSM_MON_SEL_8822B) << BIT_SHIFT_FSM_MON_SEL_8822B) +#define BIT_GET_FSM_MON_SEL_8822B(x) \ + (((x) >> BIT_SHIFT_FSM_MON_SEL_8822B) & BIT_MASK_FSM_MON_SEL_8822B) + +#define BIT_DOP_ELDO_8822B BIT(23) +#define BIT_FSM_MON_UPD_8822B BIT(15) + +#define BIT_SHIFT_FSM_PAR_8822B 0 +#define BIT_MASK_FSM_PAR_8822B 0x7fff +#define BIT_FSM_PAR_8822B(x) \ + (((x) & BIT_MASK_FSM_PAR_8822B) << BIT_SHIFT_FSM_PAR_8822B) +#define BIT_GET_FSM_PAR_8822B(x) \ + (((x) >> BIT_SHIFT_FSM_PAR_8822B) & BIT_MASK_FSM_PAR_8822B) + +/* 2 REG_AFE_CTRL6_8822B */ + +#define BIT_SHIFT_BB_DBG_SEL_AFE_SDM_BIT3_1_8822B 0 +#define BIT_MASK_BB_DBG_SEL_AFE_SDM_BIT3_1_8822B 0x7 +#define BIT_BB_DBG_SEL_AFE_SDM_BIT3_1_8822B(x) \ + (((x) & BIT_MASK_BB_DBG_SEL_AFE_SDM_BIT3_1_8822B) \ + << BIT_SHIFT_BB_DBG_SEL_AFE_SDM_BIT3_1_8822B) +#define BIT_GET_BB_DBG_SEL_AFE_SDM_BIT3_1_8822B(x) \ + (((x) >> BIT_SHIFT_BB_DBG_SEL_AFE_SDM_BIT3_1_8822B) & \ + BIT_MASK_BB_DBG_SEL_AFE_SDM_BIT3_1_8822B) + +/* 2 REG_PMC_DBG_CTRL1_8822B */ +#define BIT_BT_INT_EN_8822B BIT(31) + +#define BIT_SHIFT_RD_WR_WIFI_BT_INFO_8822B 16 +#define BIT_MASK_RD_WR_WIFI_BT_INFO_8822B 0x7fff +#define BIT_RD_WR_WIFI_BT_INFO_8822B(x) \ + (((x) & BIT_MASK_RD_WR_WIFI_BT_INFO_8822B) \ + << BIT_SHIFT_RD_WR_WIFI_BT_INFO_8822B) +#define BIT_GET_RD_WR_WIFI_BT_INFO_8822B(x) \ + (((x) >> BIT_SHIFT_RD_WR_WIFI_BT_INFO_8822B) & \ + BIT_MASK_RD_WR_WIFI_BT_INFO_8822B) + +#define BIT_PMC_WR_OVF_8822B BIT(8) + +#define BIT_SHIFT_WLPMC_ERRINT_8822B 0 +#define BIT_MASK_WLPMC_ERRINT_8822B 0xff +#define BIT_WLPMC_ERRINT_8822B(x) \ + (((x) & BIT_MASK_WLPMC_ERRINT_8822B) << BIT_SHIFT_WLPMC_ERRINT_8822B) +#define BIT_GET_WLPMC_ERRINT_8822B(x) \ + (((x) >> BIT_SHIFT_WLPMC_ERRINT_8822B) & BIT_MASK_WLPMC_ERRINT_8822B) + +/* 2 REG_AFE_CTRL7_8822B */ + +#define BIT_SHIFT_SEL_V_8822B 30 +#define BIT_MASK_SEL_V_8822B 0x3 +#define BIT_SEL_V_8822B(x) \ + (((x) & BIT_MASK_SEL_V_8822B) << BIT_SHIFT_SEL_V_8822B) +#define BIT_GET_SEL_V_8822B(x) \ + (((x) >> BIT_SHIFT_SEL_V_8822B) & BIT_MASK_SEL_V_8822B) + +#define BIT_SEL_LDO_PC_8822B BIT(29) + +#define BIT_SHIFT_CK_MON_SEL_8822B 26 +#define BIT_MASK_CK_MON_SEL_8822B 0x7 +#define BIT_CK_MON_SEL_8822B(x) \ + (((x) & BIT_MASK_CK_MON_SEL_8822B) << BIT_SHIFT_CK_MON_SEL_8822B) +#define BIT_GET_CK_MON_SEL_8822B(x) \ + (((x) >> BIT_SHIFT_CK_MON_SEL_8822B) & BIT_MASK_CK_MON_SEL_8822B) + +#define BIT_CK_MON_EN_8822B BIT(25) +#define BIT_FREF_EDGE_8822B BIT(24) +#define BIT_CK320M_EN_8822B BIT(23) +#define BIT_CK_5M_EN_8822B BIT(22) +#define BIT_TESTEN_8822B BIT(21) + +/* 2 REG_HIMR0_8822B */ +#define BIT_TIMEOUT_INTERRUPT2_MASK_8822B BIT(31) +#define BIT_TIMEOUT_INTERRUTP1_MASK_8822B BIT(30) +#define BIT_PSTIMEOUT_MSK_8822B BIT(29) +#define BIT_GTINT4_MSK_8822B BIT(28) +#define BIT_GTINT3_MSK_8822B BIT(27) +#define BIT_TXBCN0ERR_MSK_8822B BIT(26) +#define BIT_TXBCN0OK_MSK_8822B BIT(25) +#define BIT_TSF_BIT32_TOGGLE_MSK_8822B BIT(24) +#define BIT_BCNDMAINT0_MSK_8822B BIT(20) +#define BIT_BCNDERR0_MSK_8822B BIT(16) +#define BIT_HSISR_IND_ON_INT_MSK_8822B BIT(15) +#define BIT_BCNDMAINT_E_MSK_8822B BIT(14) +#define BIT_CTWEND_MSK_8822B BIT(12) +#define BIT_HISR1_IND_MSK_8822B BIT(11) +#define BIT_C2HCMD_MSK_8822B BIT(10) +#define BIT_CPWM2_MSK_8822B BIT(9) +#define BIT_CPWM_MSK_8822B BIT(8) +#define BIT_HIGHDOK_MSK_8822B BIT(7) +#define BIT_MGTDOK_MSK_8822B BIT(6) +#define BIT_BKDOK_MSK_8822B BIT(5) +#define BIT_BEDOK_MSK_8822B BIT(4) +#define BIT_VIDOK_MSK_8822B BIT(3) +#define BIT_VODOK_MSK_8822B BIT(2) +#define BIT_RDU_MSK_8822B BIT(1) +#define BIT_RXOK_MSK_8822B BIT(0) + +/* 2 REG_HISR0_8822B */ +#define BIT_TIMEOUT_INTERRUPT2_8822B BIT(31) +#define BIT_TIMEOUT_INTERRUTP1_8822B BIT(30) +#define BIT_PSTIMEOUT_8822B BIT(29) +#define BIT_GTINT4_8822B BIT(28) +#define BIT_GTINT3_8822B BIT(27) +#define BIT_TXBCN0ERR_8822B BIT(26) +#define BIT_TXBCN0OK_8822B BIT(25) +#define BIT_TSF_BIT32_TOGGLE_8822B BIT(24) +#define BIT_BCNDMAINT0_8822B BIT(20) +#define BIT_BCNDERR0_8822B BIT(16) +#define BIT_HSISR_IND_ON_INT_8822B BIT(15) +#define BIT_BCNDMAINT_E_8822B BIT(14) +#define BIT_CTWEND_8822B BIT(12) +#define BIT_HISR1_IND_INT_8822B BIT(11) +#define BIT_C2HCMD_8822B BIT(10) +#define BIT_CPWM2_8822B BIT(9) +#define BIT_CPWM_8822B BIT(8) +#define BIT_HIGHDOK_8822B BIT(7) +#define BIT_MGTDOK_8822B BIT(6) +#define BIT_BKDOK_8822B BIT(5) +#define BIT_BEDOK_8822B BIT(4) +#define BIT_VIDOK_8822B BIT(3) +#define BIT_VODOK_8822B BIT(2) +#define BIT_RDU_8822B BIT(1) +#define BIT_RXOK_8822B BIT(0) + +/* 2 REG_HIMR1_8822B */ +#define BIT_TXFIFO_TH_INT_8822B BIT(30) +#define BIT_BTON_STS_UPDATE_MASK_8822B BIT(29) +#define BIT_MCU_ERR_MASK_8822B BIT(28) +#define BIT_BCNDMAINT7__MSK_8822B BIT(27) +#define BIT_BCNDMAINT6__MSK_8822B BIT(26) +#define BIT_BCNDMAINT5__MSK_8822B BIT(25) +#define BIT_BCNDMAINT4__MSK_8822B BIT(24) +#define BIT_BCNDMAINT3_MSK_8822B BIT(23) +#define BIT_BCNDMAINT2_MSK_8822B BIT(22) +#define BIT_BCNDMAINT1_MSK_8822B BIT(21) +#define BIT_BCNDERR7_MSK_8822B BIT(20) +#define BIT_BCNDERR6_MSK_8822B BIT(19) +#define BIT_BCNDERR5_MSK_8822B BIT(18) +#define BIT_BCNDERR4_MSK_8822B BIT(17) +#define BIT_BCNDERR3_MSK_8822B BIT(16) +#define BIT_BCNDERR2_MSK_8822B BIT(15) +#define BIT_BCNDERR1_MSK_8822B BIT(14) +#define BIT_ATIMEND_E_MSK_8822B BIT(13) +#define BIT_ATIMEND__MSK_8822B BIT(12) +#define BIT_TXERR_MSK_8822B BIT(11) +#define BIT_RXERR_MSK_8822B BIT(10) +#define BIT_TXFOVW_MSK_8822B BIT(9) +#define BIT_FOVW_MSK_8822B BIT(8) +#define BIT_CPU_MGQ_TXDONE_MSK_8822B BIT(5) +#define BIT_PS_TIMER_C_MSK_8822B BIT(4) +#define BIT_PS_TIMER_B_MSK_8822B BIT(3) +#define BIT_PS_TIMER_A_MSK_8822B BIT(2) +#define BIT_CPUMGQ_TX_TIMER_MSK_8822B BIT(1) + +/* 2 REG_HISR1_8822B */ +#define BIT_TXFIFO_TH_INT_8822B BIT(30) +#define BIT_BTON_STS_UPDATE_INT_8822B BIT(29) +#define BIT_MCU_ERR_8822B BIT(28) +#define BIT_BCNDMAINT7_8822B BIT(27) +#define BIT_BCNDMAINT6_8822B BIT(26) +#define BIT_BCNDMAINT5_8822B BIT(25) +#define BIT_BCNDMAINT4_8822B BIT(24) +#define BIT_BCNDMAINT3_8822B BIT(23) +#define BIT_BCNDMAINT2_8822B BIT(22) +#define BIT_BCNDMAINT1_8822B BIT(21) +#define BIT_BCNDERR7_8822B BIT(20) +#define BIT_BCNDERR6_8822B BIT(19) +#define BIT_BCNDERR5_8822B BIT(18) +#define BIT_BCNDERR4_8822B BIT(17) +#define BIT_BCNDERR3_8822B BIT(16) +#define BIT_BCNDERR2_8822B BIT(15) +#define BIT_BCNDERR1_8822B BIT(14) +#define BIT_ATIMEND_E_8822B BIT(13) +#define BIT_ATIMEND_8822B BIT(12) +#define BIT_TXERR_INT_8822B BIT(11) +#define BIT_RXERR_INT_8822B BIT(10) +#define BIT_TXFOVW_8822B BIT(9) +#define BIT_FOVW_8822B BIT(8) +#define BIT_CPU_MGQ_TXDONE_8822B BIT(5) +#define BIT_PS_TIMER_C_8822B BIT(4) +#define BIT_PS_TIMER_B_8822B BIT(3) +#define BIT_PS_TIMER_A_8822B BIT(2) +#define BIT_CPUMGQ_TX_TIMER_8822B BIT(1) + +/* 2 REG_DBG_PORT_SEL_8822B */ + +#define BIT_SHIFT_DEBUG_ST_8822B 0 +#define BIT_MASK_DEBUG_ST_8822B 0xffffffffL +#define BIT_DEBUG_ST_8822B(x) \ + (((x) & BIT_MASK_DEBUG_ST_8822B) << BIT_SHIFT_DEBUG_ST_8822B) +#define BIT_GET_DEBUG_ST_8822B(x) \ + (((x) >> BIT_SHIFT_DEBUG_ST_8822B) & BIT_MASK_DEBUG_ST_8822B) + +/* 2 REG_PAD_CTRL2_8822B */ +#define BIT_USB3_USB2_TRANSITION_8822B BIT(20) + +#define BIT_SHIFT_USB23_SW_MODE_V1_8822B 18 +#define BIT_MASK_USB23_SW_MODE_V1_8822B 0x3 +#define BIT_USB23_SW_MODE_V1_8822B(x) \ + (((x) & BIT_MASK_USB23_SW_MODE_V1_8822B) \ + << BIT_SHIFT_USB23_SW_MODE_V1_8822B) +#define BIT_GET_USB23_SW_MODE_V1_8822B(x) \ + (((x) >> BIT_SHIFT_USB23_SW_MODE_V1_8822B) & \ + BIT_MASK_USB23_SW_MODE_V1_8822B) + +#define BIT_NO_PDN_CHIPOFF_V1_8822B BIT(17) +#define BIT_RSM_EN_V1_8822B BIT(16) + +#define BIT_SHIFT_MATCH_CNT_8822B 8 +#define BIT_MASK_MATCH_CNT_8822B 0xff +#define BIT_MATCH_CNT_8822B(x) \ + (((x) & BIT_MASK_MATCH_CNT_8822B) << BIT_SHIFT_MATCH_CNT_8822B) +#define BIT_GET_MATCH_CNT_8822B(x) \ + (((x) >> BIT_SHIFT_MATCH_CNT_8822B) & BIT_MASK_MATCH_CNT_8822B) + +#define BIT_LD_B12V_EN_8822B BIT(7) +#define BIT_EECS_IOSEL_V1_8822B BIT(6) +#define BIT_EECS_DATA_O_V1_8822B BIT(5) +#define BIT_EECS_DATA_I_V1_8822B BIT(4) +#define BIT_EESK_IOSEL_V1_8822B BIT(2) +#define BIT_EESK_DATA_O_V1_8822B BIT(1) +#define BIT_EESK_DATA_I_V1_8822B BIT(0) + +/* 2 REG_NOT_VALID_8822B */ + +/* 2 REG_PMC_DBG_CTRL2_8822B */ + +#define BIT_SHIFT_EFUSE_BURN_GNT_8822B 24 +#define BIT_MASK_EFUSE_BURN_GNT_8822B 0xff +#define BIT_EFUSE_BURN_GNT_8822B(x) \ + (((x) & BIT_MASK_EFUSE_BURN_GNT_8822B) \ + << BIT_SHIFT_EFUSE_BURN_GNT_8822B) +#define BIT_GET_EFUSE_BURN_GNT_8822B(x) \ + (((x) >> BIT_SHIFT_EFUSE_BURN_GNT_8822B) & \ + BIT_MASK_EFUSE_BURN_GNT_8822B) + +#define BIT_STOP_WL_PMC_8822B BIT(9) +#define BIT_STOP_SYM_PMC_8822B BIT(8) +#define BIT_REG_RST_WLPMC_8822B BIT(5) +#define BIT_REG_RST_PD12N_8822B BIT(4) +#define BIT_SYSON_DIS_WLREG_WRMSK_8822B BIT(3) +#define BIT_SYSON_DIS_PMCREG_WRMSK_8822B BIT(2) + +#define BIT_SHIFT_SYSON_REG_ARB_8822B 0 +#define BIT_MASK_SYSON_REG_ARB_8822B 0x3 +#define BIT_SYSON_REG_ARB_8822B(x) \ + (((x) & BIT_MASK_SYSON_REG_ARB_8822B) << BIT_SHIFT_SYSON_REG_ARB_8822B) +#define BIT_GET_SYSON_REG_ARB_8822B(x) \ + (((x) >> BIT_SHIFT_SYSON_REG_ARB_8822B) & BIT_MASK_SYSON_REG_ARB_8822B) + +/* 2 REG_BIST_CTRL_8822B */ +#define BIT_BIST_USB_DIS_8822B BIT(27) +#define BIT_BIST_PCI_DIS_8822B BIT(26) +#define BIT_BIST_BT_DIS_8822B BIT(25) +#define BIT_BIST_WL_DIS_8822B BIT(24) + +#define BIT_SHIFT_BIST_RPT_SEL_8822B 16 +#define BIT_MASK_BIST_RPT_SEL_8822B 0xf +#define BIT_BIST_RPT_SEL_8822B(x) \ + (((x) & BIT_MASK_BIST_RPT_SEL_8822B) << BIT_SHIFT_BIST_RPT_SEL_8822B) +#define BIT_GET_BIST_RPT_SEL_8822B(x) \ + (((x) >> BIT_SHIFT_BIST_RPT_SEL_8822B) & BIT_MASK_BIST_RPT_SEL_8822B) + +#define BIT_BIST_RESUME_PS_8822B BIT(4) +#define BIT_BIST_RESUME_8822B BIT(3) +#define BIT_BIST_NORMAL_8822B BIT(2) +#define BIT_BIST_RSTN_8822B BIT(1) +#define BIT_BIST_CLK_EN_8822B BIT(0) + +/* 2 REG_BIST_RPT_8822B */ + +#define BIT_SHIFT_MBIST_REPORT_8822B 0 +#define BIT_MASK_MBIST_REPORT_8822B 0xffffffffL +#define BIT_MBIST_REPORT_8822B(x) \ + (((x) & BIT_MASK_MBIST_REPORT_8822B) << BIT_SHIFT_MBIST_REPORT_8822B) +#define BIT_GET_MBIST_REPORT_8822B(x) \ + (((x) >> BIT_SHIFT_MBIST_REPORT_8822B) & BIT_MASK_MBIST_REPORT_8822B) + +/* 2 REG_MEM_CTRL_8822B */ +#define BIT_UMEM_RME_8822B BIT(31) + +#define BIT_SHIFT_BT_SPRAM_8822B 28 +#define BIT_MASK_BT_SPRAM_8822B 0x3 +#define BIT_BT_SPRAM_8822B(x) \ + (((x) & BIT_MASK_BT_SPRAM_8822B) << BIT_SHIFT_BT_SPRAM_8822B) +#define BIT_GET_BT_SPRAM_8822B(x) \ + (((x) >> BIT_SHIFT_BT_SPRAM_8822B) & BIT_MASK_BT_SPRAM_8822B) + +#define BIT_SHIFT_BT_ROM_8822B 24 +#define BIT_MASK_BT_ROM_8822B 0xf +#define BIT_BT_ROM_8822B(x) \ + (((x) & BIT_MASK_BT_ROM_8822B) << BIT_SHIFT_BT_ROM_8822B) +#define BIT_GET_BT_ROM_8822B(x) \ + (((x) >> BIT_SHIFT_BT_ROM_8822B) & BIT_MASK_BT_ROM_8822B) + +#define BIT_SHIFT_PCI_DPRAM_8822B 10 +#define BIT_MASK_PCI_DPRAM_8822B 0x3 +#define BIT_PCI_DPRAM_8822B(x) \ + (((x) & BIT_MASK_PCI_DPRAM_8822B) << BIT_SHIFT_PCI_DPRAM_8822B) +#define BIT_GET_PCI_DPRAM_8822B(x) \ + (((x) >> BIT_SHIFT_PCI_DPRAM_8822B) & BIT_MASK_PCI_DPRAM_8822B) + +#define BIT_SHIFT_PCI_SPRAM_8822B 8 +#define BIT_MASK_PCI_SPRAM_8822B 0x3 +#define BIT_PCI_SPRAM_8822B(x) \ + (((x) & BIT_MASK_PCI_SPRAM_8822B) << BIT_SHIFT_PCI_SPRAM_8822B) +#define BIT_GET_PCI_SPRAM_8822B(x) \ + (((x) >> BIT_SHIFT_PCI_SPRAM_8822B) & BIT_MASK_PCI_SPRAM_8822B) + +#define BIT_SHIFT_USB_SPRAM_8822B 6 +#define BIT_MASK_USB_SPRAM_8822B 0x3 +#define BIT_USB_SPRAM_8822B(x) \ + (((x) & BIT_MASK_USB_SPRAM_8822B) << BIT_SHIFT_USB_SPRAM_8822B) +#define BIT_GET_USB_SPRAM_8822B(x) \ + (((x) >> BIT_SHIFT_USB_SPRAM_8822B) & BIT_MASK_USB_SPRAM_8822B) + +#define BIT_SHIFT_USB_SPRF_8822B 4 +#define BIT_MASK_USB_SPRF_8822B 0x3 +#define BIT_USB_SPRF_8822B(x) \ + (((x) & BIT_MASK_USB_SPRF_8822B) << BIT_SHIFT_USB_SPRF_8822B) +#define BIT_GET_USB_SPRF_8822B(x) \ + (((x) >> BIT_SHIFT_USB_SPRF_8822B) & BIT_MASK_USB_SPRF_8822B) + +#define BIT_SHIFT_MCU_ROM_8822B 0 +#define BIT_MASK_MCU_ROM_8822B 0xf +#define BIT_MCU_ROM_8822B(x) \ + (((x) & BIT_MASK_MCU_ROM_8822B) << BIT_SHIFT_MCU_ROM_8822B) +#define BIT_GET_MCU_ROM_8822B(x) \ + (((x) >> BIT_SHIFT_MCU_ROM_8822B) & BIT_MASK_MCU_ROM_8822B) + +/* 2 REG_AFE_CTRL8_8822B */ +#define BIT_SYN_AGPIO_8822B BIT(20) +#define BIT_XTAL_LP_8822B BIT(4) +#define BIT_XTAL_GM_SEP_8822B BIT(3) + +#define BIT_SHIFT_XTAL_SEL_TOK_8822B 0 +#define BIT_MASK_XTAL_SEL_TOK_8822B 0x7 +#define BIT_XTAL_SEL_TOK_8822B(x) \ + (((x) & BIT_MASK_XTAL_SEL_TOK_8822B) << BIT_SHIFT_XTAL_SEL_TOK_8822B) +#define BIT_GET_XTAL_SEL_TOK_8822B(x) \ + (((x) >> BIT_SHIFT_XTAL_SEL_TOK_8822B) & BIT_MASK_XTAL_SEL_TOK_8822B) + +/* 2 REG_USB_SIE_INTF_8822B */ +#define BIT_RD_SEL_8822B BIT(31) +#define BIT_USB_SIE_INTF_WE_V1_8822B BIT(30) +#define BIT_USB_SIE_INTF_BYIOREG_V1_8822B BIT(29) +#define BIT_USB_SIE_SELECT_8822B BIT(28) + +#define BIT_SHIFT_USB_SIE_INTF_ADDR_V1_8822B 16 +#define BIT_MASK_USB_SIE_INTF_ADDR_V1_8822B 0x1ff +#define BIT_USB_SIE_INTF_ADDR_V1_8822B(x) \ + (((x) & BIT_MASK_USB_SIE_INTF_ADDR_V1_8822B) \ + << BIT_SHIFT_USB_SIE_INTF_ADDR_V1_8822B) +#define BIT_GET_USB_SIE_INTF_ADDR_V1_8822B(x) \ + (((x) >> BIT_SHIFT_USB_SIE_INTF_ADDR_V1_8822B) & \ + BIT_MASK_USB_SIE_INTF_ADDR_V1_8822B) + +#define BIT_SHIFT_USB_SIE_INTF_RD_8822B 8 +#define BIT_MASK_USB_SIE_INTF_RD_8822B 0xff +#define BIT_USB_SIE_INTF_RD_8822B(x) \ + (((x) & BIT_MASK_USB_SIE_INTF_RD_8822B) \ + << BIT_SHIFT_USB_SIE_INTF_RD_8822B) +#define BIT_GET_USB_SIE_INTF_RD_8822B(x) \ + (((x) >> BIT_SHIFT_USB_SIE_INTF_RD_8822B) & \ + BIT_MASK_USB_SIE_INTF_RD_8822B) + +#define BIT_SHIFT_USB_SIE_INTF_WD_8822B 0 +#define BIT_MASK_USB_SIE_INTF_WD_8822B 0xff +#define BIT_USB_SIE_INTF_WD_8822B(x) \ + (((x) & BIT_MASK_USB_SIE_INTF_WD_8822B) \ + << BIT_SHIFT_USB_SIE_INTF_WD_8822B) +#define BIT_GET_USB_SIE_INTF_WD_8822B(x) \ + (((x) >> BIT_SHIFT_USB_SIE_INTF_WD_8822B) & \ + BIT_MASK_USB_SIE_INTF_WD_8822B) + +/* 2 REG_PCIE_MIO_INTF_8822B */ +#define BIT_PCIE_MIO_BYIOREG_8822B BIT(13) +#define BIT_PCIE_MIO_RE_8822B BIT(12) + +#define BIT_SHIFT_PCIE_MIO_WE_8822B 8 +#define BIT_MASK_PCIE_MIO_WE_8822B 0xf +#define BIT_PCIE_MIO_WE_8822B(x) \ + (((x) & BIT_MASK_PCIE_MIO_WE_8822B) << BIT_SHIFT_PCIE_MIO_WE_8822B) +#define BIT_GET_PCIE_MIO_WE_8822B(x) \ + (((x) >> BIT_SHIFT_PCIE_MIO_WE_8822B) & BIT_MASK_PCIE_MIO_WE_8822B) + +#define BIT_SHIFT_PCIE_MIO_ADDR_8822B 0 +#define BIT_MASK_PCIE_MIO_ADDR_8822B 0xff +#define BIT_PCIE_MIO_ADDR_8822B(x) \ + (((x) & BIT_MASK_PCIE_MIO_ADDR_8822B) << BIT_SHIFT_PCIE_MIO_ADDR_8822B) +#define BIT_GET_PCIE_MIO_ADDR_8822B(x) \ + (((x) >> BIT_SHIFT_PCIE_MIO_ADDR_8822B) & BIT_MASK_PCIE_MIO_ADDR_8822B) + +/* 2 REG_PCIE_MIO_INTD_8822B */ + +#define BIT_SHIFT_PCIE_MIO_DATA_8822B 0 +#define BIT_MASK_PCIE_MIO_DATA_8822B 0xffffffffL +#define BIT_PCIE_MIO_DATA_8822B(x) \ + (((x) & BIT_MASK_PCIE_MIO_DATA_8822B) << BIT_SHIFT_PCIE_MIO_DATA_8822B) +#define BIT_GET_PCIE_MIO_DATA_8822B(x) \ + (((x) >> BIT_SHIFT_PCIE_MIO_DATA_8822B) & BIT_MASK_PCIE_MIO_DATA_8822B) + +/* 2 REG_WLRF1_8822B */ + +#define BIT_SHIFT_WLRF1_CTRL_8822B 24 +#define BIT_MASK_WLRF1_CTRL_8822B 0xff +#define BIT_WLRF1_CTRL_8822B(x) \ + (((x) & BIT_MASK_WLRF1_CTRL_8822B) << BIT_SHIFT_WLRF1_CTRL_8822B) +#define BIT_GET_WLRF1_CTRL_8822B(x) \ + (((x) >> BIT_SHIFT_WLRF1_CTRL_8822B) & BIT_MASK_WLRF1_CTRL_8822B) + +/* 2 REG_SYS_CFG1_8822B */ + +#define BIT_SHIFT_TRP_ICFG_8822B 28 +#define BIT_MASK_TRP_ICFG_8822B 0xf +#define BIT_TRP_ICFG_8822B(x) \ + (((x) & BIT_MASK_TRP_ICFG_8822B) << BIT_SHIFT_TRP_ICFG_8822B) +#define BIT_GET_TRP_ICFG_8822B(x) \ + (((x) >> BIT_SHIFT_TRP_ICFG_8822B) & BIT_MASK_TRP_ICFG_8822B) + +#define BIT_RF_TYPE_ID_8822B BIT(27) +#define BIT_BD_HCI_SEL_8822B BIT(26) +#define BIT_BD_PKG_SEL_8822B BIT(25) +#define BIT_SPSLDO_SEL_8822B BIT(24) +#define BIT_RTL_ID_8822B BIT(23) +#define BIT_PAD_HWPD_IDN_8822B BIT(22) +#define BIT_TESTMODE_8822B BIT(20) + +#define BIT_SHIFT_VENDOR_ID_8822B 16 +#define BIT_MASK_VENDOR_ID_8822B 0xf +#define BIT_VENDOR_ID_8822B(x) \ + (((x) & BIT_MASK_VENDOR_ID_8822B) << BIT_SHIFT_VENDOR_ID_8822B) +#define BIT_GET_VENDOR_ID_8822B(x) \ + (((x) >> BIT_SHIFT_VENDOR_ID_8822B) & BIT_MASK_VENDOR_ID_8822B) + +#define BIT_SHIFT_CHIP_VER_8822B 12 +#define BIT_MASK_CHIP_VER_8822B 0xf +#define BIT_CHIP_VER_8822B(x) \ + (((x) & BIT_MASK_CHIP_VER_8822B) << BIT_SHIFT_CHIP_VER_8822B) +#define BIT_GET_CHIP_VER_8822B(x) \ + (((x) >> BIT_SHIFT_CHIP_VER_8822B) & BIT_MASK_CHIP_VER_8822B) + +#define BIT_BD_MAC3_8822B BIT(11) +#define BIT_BD_MAC1_8822B BIT(10) +#define BIT_BD_MAC2_8822B BIT(9) +#define BIT_SIC_IDLE_8822B BIT(8) +#define BIT_SW_OFFLOAD_EN_8822B BIT(7) +#define BIT_OCP_SHUTDN_8822B BIT(6) +#define BIT_V15_VLD_8822B BIT(5) +#define BIT_PCIRSTB_8822B BIT(4) +#define BIT_PCLK_VLD_8822B BIT(3) +#define BIT_UCLK_VLD_8822B BIT(2) +#define BIT_ACLK_VLD_8822B BIT(1) +#define BIT_XCLK_VLD_8822B BIT(0) + +/* 2 REG_SYS_STATUS1_8822B */ + +#define BIT_SHIFT_RF_RL_ID_8822B 28 +#define BIT_MASK_RF_RL_ID_8822B 0xf +#define BIT_RF_RL_ID_8822B(x) \ + (((x) & BIT_MASK_RF_RL_ID_8822B) << BIT_SHIFT_RF_RL_ID_8822B) +#define BIT_GET_RF_RL_ID_8822B(x) \ + (((x) >> BIT_SHIFT_RF_RL_ID_8822B) & BIT_MASK_RF_RL_ID_8822B) + +#define BIT_HPHY_ICFG_8822B BIT(19) + +#define BIT_SHIFT_SEL_0XC0_8822B 16 +#define BIT_MASK_SEL_0XC0_8822B 0x3 +#define BIT_SEL_0XC0_8822B(x) \ + (((x) & BIT_MASK_SEL_0XC0_8822B) << BIT_SHIFT_SEL_0XC0_8822B) +#define BIT_GET_SEL_0XC0_8822B(x) \ + (((x) >> BIT_SHIFT_SEL_0XC0_8822B) & BIT_MASK_SEL_0XC0_8822B) + +#define BIT_SHIFT_HCI_SEL_V3_8822B 12 +#define BIT_MASK_HCI_SEL_V3_8822B 0x7 +#define BIT_HCI_SEL_V3_8822B(x) \ + (((x) & BIT_MASK_HCI_SEL_V3_8822B) << BIT_SHIFT_HCI_SEL_V3_8822B) +#define BIT_GET_HCI_SEL_V3_8822B(x) \ + (((x) >> BIT_SHIFT_HCI_SEL_V3_8822B) & BIT_MASK_HCI_SEL_V3_8822B) + +#define BIT_USB_OPERATION_MODE_8822B BIT(10) +#define BIT_BT_PDN_8822B BIT(9) +#define BIT_AUTO_WLPON_8822B BIT(8) +#define BIT_WL_MODE_8822B BIT(7) +#define BIT_PKG_SEL_HCI_8822B BIT(6) + +#define BIT_SHIFT_PAD_HCI_SEL_V1_8822B 3 +#define BIT_MASK_PAD_HCI_SEL_V1_8822B 0x7 +#define BIT_PAD_HCI_SEL_V1_8822B(x) \ + (((x) & BIT_MASK_PAD_HCI_SEL_V1_8822B) \ + << BIT_SHIFT_PAD_HCI_SEL_V1_8822B) +#define BIT_GET_PAD_HCI_SEL_V1_8822B(x) \ + (((x) >> BIT_SHIFT_PAD_HCI_SEL_V1_8822B) & \ + BIT_MASK_PAD_HCI_SEL_V1_8822B) + +#define BIT_SHIFT_EFS_HCI_SEL_V1_8822B 0 +#define BIT_MASK_EFS_HCI_SEL_V1_8822B 0x7 +#define BIT_EFS_HCI_SEL_V1_8822B(x) \ + (((x) & BIT_MASK_EFS_HCI_SEL_V1_8822B) \ + << BIT_SHIFT_EFS_HCI_SEL_V1_8822B) +#define BIT_GET_EFS_HCI_SEL_V1_8822B(x) \ + (((x) >> BIT_SHIFT_EFS_HCI_SEL_V1_8822B) & \ + BIT_MASK_EFS_HCI_SEL_V1_8822B) + +/* 2 REG_SYS_STATUS2_8822B */ +#define BIT_SIO_ALDN_8822B BIT(19) +#define BIT_USB_ALDN_8822B BIT(18) +#define BIT_PCI_ALDN_8822B BIT(17) +#define BIT_SYS_ALDN_8822B BIT(16) + +#define BIT_SHIFT_EPVID1_8822B 8 +#define BIT_MASK_EPVID1_8822B 0xff +#define BIT_EPVID1_8822B(x) \ + (((x) & BIT_MASK_EPVID1_8822B) << BIT_SHIFT_EPVID1_8822B) +#define BIT_GET_EPVID1_8822B(x) \ + (((x) >> BIT_SHIFT_EPVID1_8822B) & BIT_MASK_EPVID1_8822B) + +#define BIT_SHIFT_EPVID0_8822B 0 +#define BIT_MASK_EPVID0_8822B 0xff +#define BIT_EPVID0_8822B(x) \ + (((x) & BIT_MASK_EPVID0_8822B) << BIT_SHIFT_EPVID0_8822B) +#define BIT_GET_EPVID0_8822B(x) \ + (((x) >> BIT_SHIFT_EPVID0_8822B) & BIT_MASK_EPVID0_8822B) + +/* 2 REG_SYS_CFG2_8822B */ +#define BIT_HCI_SEL_EMBEDDED_8822B BIT(8) + +#define BIT_SHIFT_HW_ID_8822B 0 +#define BIT_MASK_HW_ID_8822B 0xff +#define BIT_HW_ID_8822B(x) \ + (((x) & BIT_MASK_HW_ID_8822B) << BIT_SHIFT_HW_ID_8822B) +#define BIT_GET_HW_ID_8822B(x) \ + (((x) >> BIT_SHIFT_HW_ID_8822B) & BIT_MASK_HW_ID_8822B) + +/* 2 REG_SYS_CFG3_8822B */ +#define BIT_PWC_MA33V_8822B BIT(15) +#define BIT_PWC_MA12V_8822B BIT(14) +#define BIT_PWC_MD12V_8822B BIT(13) +#define BIT_PWC_PD12V_8822B BIT(12) +#define BIT_PWC_UD12V_8822B BIT(11) +#define BIT_ISO_MA2MD_8822B BIT(1) +#define BIT_ISO_MD2PP_8822B BIT(0) + +/* 2 REG_SYS_CFG4_8822B */ + +/* 2 REG_SYS_CFG5_8822B */ +#define BIT_LPS_STATUS_8822B BIT(3) +#define BIT_HCI_TXDMA_BUSY_8822B BIT(2) +#define BIT_HCI_TXDMA_ALLOW_8822B BIT(1) +#define BIT_FW_CTRL_HCI_TXDMA_EN_8822B BIT(0) + +/* 2 REG_CPU_DMEM_CON_8822B */ +#define BIT_WDT_OPT_IOWRAPPER_8822B BIT(19) +#define BIT_ANA_PORT_IDLE_8822B BIT(18) +#define BIT_MAC_PORT_IDLE_8822B BIT(17) +#define BIT_WL_PLATFORM_RST_8822B BIT(16) +#define BIT_WL_SECURITY_CLK_8822B BIT(15) + +#define BIT_SHIFT_CPU_DMEM_CON_8822B 0 +#define BIT_MASK_CPU_DMEM_CON_8822B 0xff +#define BIT_CPU_DMEM_CON_8822B(x) \ + (((x) & BIT_MASK_CPU_DMEM_CON_8822B) << BIT_SHIFT_CPU_DMEM_CON_8822B) +#define BIT_GET_CPU_DMEM_CON_8822B(x) \ + (((x) >> BIT_SHIFT_CPU_DMEM_CON_8822B) & BIT_MASK_CPU_DMEM_CON_8822B) + +/* 2 REG_BOOT_REASON_8822B */ + +#define BIT_SHIFT_BOOT_REASON_8822B 0 +#define BIT_MASK_BOOT_REASON_8822B 0x7 +#define BIT_BOOT_REASON_8822B(x) \ + (((x) & BIT_MASK_BOOT_REASON_8822B) << BIT_SHIFT_BOOT_REASON_8822B) +#define BIT_GET_BOOT_REASON_8822B(x) \ + (((x) >> BIT_SHIFT_BOOT_REASON_8822B) & BIT_MASK_BOOT_REASON_8822B) + +/* 2 REG_NFCPAD_CTRL_8822B */ +#define BIT_PAD_SHUTDW_8822B BIT(18) +#define BIT_SYSON_NFC_PAD_8822B BIT(17) +#define BIT_NFC_INT_PAD_CTRL_8822B BIT(16) +#define BIT_NFC_RFDIS_PAD_CTRL_8822B BIT(15) +#define BIT_NFC_CLK_PAD_CTRL_8822B BIT(14) +#define BIT_NFC_DATA_PAD_CTRL_8822B BIT(13) +#define BIT_NFC_PAD_PULL_CTRL_8822B BIT(12) + +#define BIT_SHIFT_NFCPAD_IO_SEL_8822B 8 +#define BIT_MASK_NFCPAD_IO_SEL_8822B 0xf +#define BIT_NFCPAD_IO_SEL_8822B(x) \ + (((x) & BIT_MASK_NFCPAD_IO_SEL_8822B) << BIT_SHIFT_NFCPAD_IO_SEL_8822B) +#define BIT_GET_NFCPAD_IO_SEL_8822B(x) \ + (((x) >> BIT_SHIFT_NFCPAD_IO_SEL_8822B) & BIT_MASK_NFCPAD_IO_SEL_8822B) + +#define BIT_SHIFT_NFCPAD_OUT_8822B 4 +#define BIT_MASK_NFCPAD_OUT_8822B 0xf +#define BIT_NFCPAD_OUT_8822B(x) \ + (((x) & BIT_MASK_NFCPAD_OUT_8822B) << BIT_SHIFT_NFCPAD_OUT_8822B) +#define BIT_GET_NFCPAD_OUT_8822B(x) \ + (((x) >> BIT_SHIFT_NFCPAD_OUT_8822B) & BIT_MASK_NFCPAD_OUT_8822B) + +#define BIT_SHIFT_NFCPAD_IN_8822B 0 +#define BIT_MASK_NFCPAD_IN_8822B 0xf +#define BIT_NFCPAD_IN_8822B(x) \ + (((x) & BIT_MASK_NFCPAD_IN_8822B) << BIT_SHIFT_NFCPAD_IN_8822B) +#define BIT_GET_NFCPAD_IN_8822B(x) \ + (((x) >> BIT_SHIFT_NFCPAD_IN_8822B) & BIT_MASK_NFCPAD_IN_8822B) + +/* 2 REG_HIMR2_8822B */ +#define BIT_BCNDMAINT_P4_MSK_8822B BIT(31) +#define BIT_BCNDMAINT_P3_MSK_8822B BIT(30) +#define BIT_BCNDMAINT_P2_MSK_8822B BIT(29) +#define BIT_BCNDMAINT_P1_MSK_8822B BIT(28) +#define BIT_ATIMEND7_MSK_8822B BIT(22) +#define BIT_ATIMEND6_MSK_8822B BIT(21) +#define BIT_ATIMEND5_MSK_8822B BIT(20) +#define BIT_ATIMEND4_MSK_8822B BIT(19) +#define BIT_ATIMEND3_MSK_8822B BIT(18) +#define BIT_ATIMEND2_MSK_8822B BIT(17) +#define BIT_ATIMEND1_MSK_8822B BIT(16) +#define BIT_TXBCN7OK_MSK_8822B BIT(14) +#define BIT_TXBCN6OK_MSK_8822B BIT(13) +#define BIT_TXBCN5OK_MSK_8822B BIT(12) +#define BIT_TXBCN4OK_MSK_8822B BIT(11) +#define BIT_TXBCN3OK_MSK_8822B BIT(10) +#define BIT_TXBCN2OK_MSK_8822B BIT(9) +#define BIT_TXBCN1OK_MSK_V1_8822B BIT(8) +#define BIT_TXBCN7ERR_MSK_8822B BIT(6) +#define BIT_TXBCN6ERR_MSK_8822B BIT(5) +#define BIT_TXBCN5ERR_MSK_8822B BIT(4) +#define BIT_TXBCN4ERR_MSK_8822B BIT(3) +#define BIT_TXBCN3ERR_MSK_8822B BIT(2) +#define BIT_TXBCN2ERR_MSK_8822B BIT(1) +#define BIT_TXBCN1ERR_MSK_V1_8822B BIT(0) + +/* 2 REG_HISR2_8822B */ +#define BIT_BCNDMAINT_P4_8822B BIT(31) +#define BIT_BCNDMAINT_P3_8822B BIT(30) +#define BIT_BCNDMAINT_P2_8822B BIT(29) +#define BIT_BCNDMAINT_P1_8822B BIT(28) +#define BIT_ATIMEND7_8822B BIT(22) +#define BIT_ATIMEND6_8822B BIT(21) +#define BIT_ATIMEND5_8822B BIT(20) +#define BIT_ATIMEND4_8822B BIT(19) +#define BIT_ATIMEND3_8822B BIT(18) +#define BIT_ATIMEND2_8822B BIT(17) +#define BIT_ATIMEND1_8822B BIT(16) +#define BIT_TXBCN7OK_8822B BIT(14) +#define BIT_TXBCN6OK_8822B BIT(13) +#define BIT_TXBCN5OK_8822B BIT(12) +#define BIT_TXBCN4OK_8822B BIT(11) +#define BIT_TXBCN3OK_8822B BIT(10) +#define BIT_TXBCN2OK_8822B BIT(9) +#define BIT_TXBCN1OK_8822B BIT(8) +#define BIT_TXBCN7ERR_8822B BIT(6) +#define BIT_TXBCN6ERR_8822B BIT(5) +#define BIT_TXBCN5ERR_8822B BIT(4) +#define BIT_TXBCN4ERR_8822B BIT(3) +#define BIT_TXBCN3ERR_8822B BIT(2) +#define BIT_TXBCN2ERR_8822B BIT(1) +#define BIT_TXBCN1ERR_8822B BIT(0) + +/* 2 REG_HIMR3_8822B */ +#define BIT_WDT_PLATFORM_INT_MSK_8822B BIT(18) +#define BIT_WDT_CPU_INT_MSK_8822B BIT(17) +#define BIT_SETH2CDOK_MASK_8822B BIT(16) +#define BIT_H2C_CMD_FULL_MASK_8822B BIT(15) +#define BIT_PWR_INT_127_MASK_8822B BIT(14) +#define BIT_TXSHORTCUT_TXDESUPDATEOK_MASK_8822B BIT(13) +#define BIT_TXSHORTCUT_BKUPDATEOK_MASK_8822B BIT(12) +#define BIT_TXSHORTCUT_BEUPDATEOK_MASK_8822B BIT(11) +#define BIT_TXSHORTCUT_VIUPDATEOK_MAS_8822B BIT(10) +#define BIT_TXSHORTCUT_VOUPDATEOK_MASK_8822B BIT(9) +#define BIT_PWR_INT_127_MASK_V1_8822B BIT(8) +#define BIT_PWR_INT_126TO96_MASK_8822B BIT(7) +#define BIT_PWR_INT_95TO64_MASK_8822B BIT(6) +#define BIT_PWR_INT_63TO32_MASK_8822B BIT(5) +#define BIT_PWR_INT_31TO0_MASK_8822B BIT(4) +#define BIT_DDMA0_LP_INT_MSK_8822B BIT(1) +#define BIT_DDMA0_HP_INT_MSK_8822B BIT(0) + +/* 2 REG_HISR3_8822B */ +#define BIT_WDT_PLATFORM_INT_8822B BIT(18) +#define BIT_WDT_CPU_INT_8822B BIT(17) +#define BIT_SETH2CDOK_8822B BIT(16) +#define BIT_H2C_CMD_FULL_8822B BIT(15) +#define BIT_PWR_INT_127_8822B BIT(14) +#define BIT_TXSHORTCUT_TXDESUPDATEOK_8822B BIT(13) +#define BIT_TXSHORTCUT_BKUPDATEOK_8822B BIT(12) +#define BIT_TXSHORTCUT_BEUPDATEOK_8822B BIT(11) +#define BIT_TXSHORTCUT_VIUPDATEOK_8822B BIT(10) +#define BIT_TXSHORTCUT_VOUPDATEOK_8822B BIT(9) +#define BIT_PWR_INT_127_V1_8822B BIT(8) +#define BIT_PWR_INT_126TO96_8822B BIT(7) +#define BIT_PWR_INT_95TO64_8822B BIT(6) +#define BIT_PWR_INT_63TO32_8822B BIT(5) +#define BIT_PWR_INT_31TO0_8822B BIT(4) +#define BIT_DDMA0_LP_INT_8822B BIT(1) +#define BIT_DDMA0_HP_INT_8822B BIT(0) + +/* 2 REG_SW_MDIO_8822B */ +#define BIT_DIS_TIMEOUT_IO_8822B BIT(24) + +/* 2 REG_SW_FLUSH_8822B */ +#define BIT_FLUSH_HOLDN_EN_8822B BIT(25) +#define BIT_FLUSH_WR_EN_8822B BIT(24) +#define BIT_SW_FLASH_CONTROL_8822B BIT(23) +#define BIT_SW_FLASH_WEN_E_8822B BIT(19) +#define BIT_SW_FLASH_HOLDN_E_8822B BIT(18) +#define BIT_SW_FLASH_SO_E_8822B BIT(17) +#define BIT_SW_FLASH_SI_E_8822B BIT(16) +#define BIT_SW_FLASH_SK_O_8822B BIT(13) +#define BIT_SW_FLASH_CEN_O_8822B BIT(12) +#define BIT_SW_FLASH_WEN_O_8822B BIT(11) +#define BIT_SW_FLASH_HOLDN_O_8822B BIT(10) +#define BIT_SW_FLASH_SO_O_8822B BIT(9) +#define BIT_SW_FLASH_SI_O_8822B BIT(8) +#define BIT_SW_FLASH_WEN_I_8822B BIT(3) +#define BIT_SW_FLASH_HOLDN_I_8822B BIT(2) +#define BIT_SW_FLASH_SO_I_8822B BIT(1) +#define BIT_SW_FLASH_SI_I_8822B BIT(0) + +/* 2 REG_H2C_PKT_READADDR_8822B */ + +#define BIT_SHIFT_H2C_PKT_READADDR_8822B 0 +#define BIT_MASK_H2C_PKT_READADDR_8822B 0x3ffff +#define BIT_H2C_PKT_READADDR_8822B(x) \ + (((x) & BIT_MASK_H2C_PKT_READADDR_8822B) \ + << BIT_SHIFT_H2C_PKT_READADDR_8822B) +#define BIT_GET_H2C_PKT_READADDR_8822B(x) \ + (((x) >> BIT_SHIFT_H2C_PKT_READADDR_8822B) & \ + BIT_MASK_H2C_PKT_READADDR_8822B) + +/* 2 REG_H2C_PKT_WRITEADDR_8822B */ + +#define BIT_SHIFT_H2C_PKT_WRITEADDR_8822B 0 +#define BIT_MASK_H2C_PKT_WRITEADDR_8822B 0x3ffff +#define BIT_H2C_PKT_WRITEADDR_8822B(x) \ + (((x) & BIT_MASK_H2C_PKT_WRITEADDR_8822B) \ + << BIT_SHIFT_H2C_PKT_WRITEADDR_8822B) +#define BIT_GET_H2C_PKT_WRITEADDR_8822B(x) \ + (((x) >> BIT_SHIFT_H2C_PKT_WRITEADDR_8822B) & \ + BIT_MASK_H2C_PKT_WRITEADDR_8822B) + +/* 2 REG_MEM_PWR_CRTL_8822B */ +#define BIT_MEM_BB_SD_8822B BIT(17) +#define BIT_MEM_BB_DS_8822B BIT(16) +#define BIT_MEM_BT_DS_8822B BIT(10) +#define BIT_MEM_SDIO_LS_8822B BIT(9) +#define BIT_MEM_SDIO_DS_8822B BIT(8) +#define BIT_MEM_USB_LS_8822B BIT(7) +#define BIT_MEM_USB_DS_8822B BIT(6) +#define BIT_MEM_PCI_LS_8822B BIT(5) +#define BIT_MEM_PCI_DS_8822B BIT(4) +#define BIT_MEM_WLMAC_LS_8822B BIT(3) +#define BIT_MEM_WLMAC_DS_8822B BIT(2) +#define BIT_MEM_WLMCU_LS_8822B BIT(1) +#define BIT_MEM_WLMCU_DS_8822B BIT(0) + +/* 2 REG_FW_DBG0_8822B */ + +#define BIT_SHIFT_FW_DBG0_8822B 0 +#define BIT_MASK_FW_DBG0_8822B 0xffffffffL +#define BIT_FW_DBG0_8822B(x) \ + (((x) & BIT_MASK_FW_DBG0_8822B) << BIT_SHIFT_FW_DBG0_8822B) +#define BIT_GET_FW_DBG0_8822B(x) \ + (((x) >> BIT_SHIFT_FW_DBG0_8822B) & BIT_MASK_FW_DBG0_8822B) + +/* 2 REG_FW_DBG1_8822B */ + +#define BIT_SHIFT_FW_DBG1_8822B 0 +#define BIT_MASK_FW_DBG1_8822B 0xffffffffL +#define BIT_FW_DBG1_8822B(x) \ + (((x) & BIT_MASK_FW_DBG1_8822B) << BIT_SHIFT_FW_DBG1_8822B) +#define BIT_GET_FW_DBG1_8822B(x) \ + (((x) >> BIT_SHIFT_FW_DBG1_8822B) & BIT_MASK_FW_DBG1_8822B) + +/* 2 REG_FW_DBG2_8822B */ + +#define BIT_SHIFT_FW_DBG2_8822B 0 +#define BIT_MASK_FW_DBG2_8822B 0xffffffffL +#define BIT_FW_DBG2_8822B(x) \ + (((x) & BIT_MASK_FW_DBG2_8822B) << BIT_SHIFT_FW_DBG2_8822B) +#define BIT_GET_FW_DBG2_8822B(x) \ + (((x) >> BIT_SHIFT_FW_DBG2_8822B) & BIT_MASK_FW_DBG2_8822B) + +/* 2 REG_FW_DBG3_8822B */ + +#define BIT_SHIFT_FW_DBG3_8822B 0 +#define BIT_MASK_FW_DBG3_8822B 0xffffffffL +#define BIT_FW_DBG3_8822B(x) \ + (((x) & BIT_MASK_FW_DBG3_8822B) << BIT_SHIFT_FW_DBG3_8822B) +#define BIT_GET_FW_DBG3_8822B(x) \ + (((x) >> BIT_SHIFT_FW_DBG3_8822B) & BIT_MASK_FW_DBG3_8822B) + +/* 2 REG_FW_DBG4_8822B */ + +#define BIT_SHIFT_FW_DBG4_8822B 0 +#define BIT_MASK_FW_DBG4_8822B 0xffffffffL +#define BIT_FW_DBG4_8822B(x) \ + (((x) & BIT_MASK_FW_DBG4_8822B) << BIT_SHIFT_FW_DBG4_8822B) +#define BIT_GET_FW_DBG4_8822B(x) \ + (((x) >> BIT_SHIFT_FW_DBG4_8822B) & BIT_MASK_FW_DBG4_8822B) + +/* 2 REG_FW_DBG5_8822B */ + +#define BIT_SHIFT_FW_DBG5_8822B 0 +#define BIT_MASK_FW_DBG5_8822B 0xffffffffL +#define BIT_FW_DBG5_8822B(x) \ + (((x) & BIT_MASK_FW_DBG5_8822B) << BIT_SHIFT_FW_DBG5_8822B) +#define BIT_GET_FW_DBG5_8822B(x) \ + (((x) >> BIT_SHIFT_FW_DBG5_8822B) & BIT_MASK_FW_DBG5_8822B) + +/* 2 REG_FW_DBG6_8822B */ + +#define BIT_SHIFT_FW_DBG6_8822B 0 +#define BIT_MASK_FW_DBG6_8822B 0xffffffffL +#define BIT_FW_DBG6_8822B(x) \ + (((x) & BIT_MASK_FW_DBG6_8822B) << BIT_SHIFT_FW_DBG6_8822B) +#define BIT_GET_FW_DBG6_8822B(x) \ + (((x) >> BIT_SHIFT_FW_DBG6_8822B) & BIT_MASK_FW_DBG6_8822B) + +/* 2 REG_FW_DBG7_8822B */ + +#define BIT_SHIFT_FW_DBG7_8822B 0 +#define BIT_MASK_FW_DBG7_8822B 0xffffffffL +#define BIT_FW_DBG7_8822B(x) \ + (((x) & BIT_MASK_FW_DBG7_8822B) << BIT_SHIFT_FW_DBG7_8822B) +#define BIT_GET_FW_DBG7_8822B(x) \ + (((x) >> BIT_SHIFT_FW_DBG7_8822B) & BIT_MASK_FW_DBG7_8822B) + +/* 2 REG_NOT_VALID_8822B */ + +/* 2 REG_CR_8822B */ + +#define BIT_SHIFT_LBMODE_8822B 24 +#define BIT_MASK_LBMODE_8822B 0x1f +#define BIT_LBMODE_8822B(x) \ + (((x) & BIT_MASK_LBMODE_8822B) << BIT_SHIFT_LBMODE_8822B) +#define BIT_GET_LBMODE_8822B(x) \ + (((x) >> BIT_SHIFT_LBMODE_8822B) & BIT_MASK_LBMODE_8822B) + +#define BIT_SHIFT_NETYPE1_8822B 18 +#define BIT_MASK_NETYPE1_8822B 0x3 +#define BIT_NETYPE1_8822B(x) \ + (((x) & BIT_MASK_NETYPE1_8822B) << BIT_SHIFT_NETYPE1_8822B) +#define BIT_GET_NETYPE1_8822B(x) \ + (((x) >> BIT_SHIFT_NETYPE1_8822B) & BIT_MASK_NETYPE1_8822B) + +#define BIT_SHIFT_NETYPE0_8822B 16 +#define BIT_MASK_NETYPE0_8822B 0x3 +#define BIT_NETYPE0_8822B(x) \ + (((x) & BIT_MASK_NETYPE0_8822B) << BIT_SHIFT_NETYPE0_8822B) +#define BIT_GET_NETYPE0_8822B(x) \ + (((x) >> BIT_SHIFT_NETYPE0_8822B) & BIT_MASK_NETYPE0_8822B) + +#define BIT_I2C_MAILBOX_EN_8822B BIT(12) +#define BIT_SHCUT_EN_8822B BIT(11) +#define BIT_32K_CAL_TMR_EN_8822B BIT(10) +#define BIT_MAC_SEC_EN_8822B BIT(9) +#define BIT_ENSWBCN_8822B BIT(8) +#define BIT_MACRXEN_8822B BIT(7) +#define BIT_MACTXEN_8822B BIT(6) +#define BIT_SCHEDULE_EN_8822B BIT(5) +#define BIT_PROTOCOL_EN_8822B BIT(4) +#define BIT_RXDMA_EN_8822B BIT(3) +#define BIT_TXDMA_EN_8822B BIT(2) +#define BIT_HCI_RXDMA_EN_8822B BIT(1) +#define BIT_HCI_TXDMA_EN_8822B BIT(0) + +/* 2 REG_PKT_BUFF_ACCESS_CTRL_8822B */ + +#define BIT_SHIFT_PKT_BUFF_ACCESS_CTRL_8822B 0 +#define BIT_MASK_PKT_BUFF_ACCESS_CTRL_8822B 0xff +#define BIT_PKT_BUFF_ACCESS_CTRL_8822B(x) \ + (((x) & BIT_MASK_PKT_BUFF_ACCESS_CTRL_8822B) \ + << BIT_SHIFT_PKT_BUFF_ACCESS_CTRL_8822B) +#define BIT_GET_PKT_BUFF_ACCESS_CTRL_8822B(x) \ + (((x) >> BIT_SHIFT_PKT_BUFF_ACCESS_CTRL_8822B) & \ + BIT_MASK_PKT_BUFF_ACCESS_CTRL_8822B) + +/* 2 REG_TSF_CLK_STATE_8822B */ +#define BIT_TSF_CLK_STABLE_8822B BIT(15) + +/* 2 REG_TXDMA_PQ_MAP_8822B */ + +#define BIT_SHIFT_TXDMA_HIQ_MAP_8822B 14 +#define BIT_MASK_TXDMA_HIQ_MAP_8822B 0x3 +#define BIT_TXDMA_HIQ_MAP_8822B(x) \ + (((x) & BIT_MASK_TXDMA_HIQ_MAP_8822B) << BIT_SHIFT_TXDMA_HIQ_MAP_8822B) +#define BIT_GET_TXDMA_HIQ_MAP_8822B(x) \ + (((x) >> BIT_SHIFT_TXDMA_HIQ_MAP_8822B) & BIT_MASK_TXDMA_HIQ_MAP_8822B) + +#define BIT_SHIFT_TXDMA_MGQ_MAP_8822B 12 +#define BIT_MASK_TXDMA_MGQ_MAP_8822B 0x3 +#define BIT_TXDMA_MGQ_MAP_8822B(x) \ + (((x) & BIT_MASK_TXDMA_MGQ_MAP_8822B) << BIT_SHIFT_TXDMA_MGQ_MAP_8822B) +#define BIT_GET_TXDMA_MGQ_MAP_8822B(x) \ + (((x) >> BIT_SHIFT_TXDMA_MGQ_MAP_8822B) & BIT_MASK_TXDMA_MGQ_MAP_8822B) + +#define BIT_SHIFT_TXDMA_BKQ_MAP_8822B 10 +#define BIT_MASK_TXDMA_BKQ_MAP_8822B 0x3 +#define BIT_TXDMA_BKQ_MAP_8822B(x) \ + (((x) & BIT_MASK_TXDMA_BKQ_MAP_8822B) << BIT_SHIFT_TXDMA_BKQ_MAP_8822B) +#define BIT_GET_TXDMA_BKQ_MAP_8822B(x) \ + (((x) >> BIT_SHIFT_TXDMA_BKQ_MAP_8822B) & BIT_MASK_TXDMA_BKQ_MAP_8822B) + +#define BIT_SHIFT_TXDMA_BEQ_MAP_8822B 8 +#define BIT_MASK_TXDMA_BEQ_MAP_8822B 0x3 +#define BIT_TXDMA_BEQ_MAP_8822B(x) \ + (((x) & BIT_MASK_TXDMA_BEQ_MAP_8822B) << BIT_SHIFT_TXDMA_BEQ_MAP_8822B) +#define BIT_GET_TXDMA_BEQ_MAP_8822B(x) \ + (((x) >> BIT_SHIFT_TXDMA_BEQ_MAP_8822B) & BIT_MASK_TXDMA_BEQ_MAP_8822B) + +#define BIT_SHIFT_TXDMA_VIQ_MAP_8822B 6 +#define BIT_MASK_TXDMA_VIQ_MAP_8822B 0x3 +#define BIT_TXDMA_VIQ_MAP_8822B(x) \ + (((x) & BIT_MASK_TXDMA_VIQ_MAP_8822B) << BIT_SHIFT_TXDMA_VIQ_MAP_8822B) +#define BIT_GET_TXDMA_VIQ_MAP_8822B(x) \ + (((x) >> BIT_SHIFT_TXDMA_VIQ_MAP_8822B) & BIT_MASK_TXDMA_VIQ_MAP_8822B) + +#define BIT_SHIFT_TXDMA_VOQ_MAP_8822B 4 +#define BIT_MASK_TXDMA_VOQ_MAP_8822B 0x3 +#define BIT_TXDMA_VOQ_MAP_8822B(x) \ + (((x) & BIT_MASK_TXDMA_VOQ_MAP_8822B) << BIT_SHIFT_TXDMA_VOQ_MAP_8822B) +#define BIT_GET_TXDMA_VOQ_MAP_8822B(x) \ + (((x) >> BIT_SHIFT_TXDMA_VOQ_MAP_8822B) & BIT_MASK_TXDMA_VOQ_MAP_8822B) + +#define BIT_RXDMA_AGG_EN_8822B BIT(2) +#define BIT_RXSHFT_EN_8822B BIT(1) +#define BIT_RXDMA_ARBBW_EN_8822B BIT(0) + +/* 2 REG_TRXFF_BNDY_8822B */ + +#define BIT_SHIFT_RXFFOVFL_RSV_V2_8822B 8 +#define BIT_MASK_RXFFOVFL_RSV_V2_8822B 0xf +#define BIT_RXFFOVFL_RSV_V2_8822B(x) \ + (((x) & BIT_MASK_RXFFOVFL_RSV_V2_8822B) \ + << BIT_SHIFT_RXFFOVFL_RSV_V2_8822B) +#define BIT_GET_RXFFOVFL_RSV_V2_8822B(x) \ + (((x) >> BIT_SHIFT_RXFFOVFL_RSV_V2_8822B) & \ + BIT_MASK_RXFFOVFL_RSV_V2_8822B) + +#define BIT_SHIFT_TXPKTBUF_PGBNDY_8822B 0 +#define BIT_MASK_TXPKTBUF_PGBNDY_8822B 0xff +#define BIT_TXPKTBUF_PGBNDY_8822B(x) \ + (((x) & BIT_MASK_TXPKTBUF_PGBNDY_8822B) \ + << BIT_SHIFT_TXPKTBUF_PGBNDY_8822B) +#define BIT_GET_TXPKTBUF_PGBNDY_8822B(x) \ + (((x) >> BIT_SHIFT_TXPKTBUF_PGBNDY_8822B) & \ + BIT_MASK_TXPKTBUF_PGBNDY_8822B) + +/* 2 REG_PTA_I2C_MBOX_8822B */ + +/* 2 REG_NOT_VALID_8822B */ + +#define BIT_SHIFT_I2C_M_STATUS_8822B 8 +#define BIT_MASK_I2C_M_STATUS_8822B 0xf +#define BIT_I2C_M_STATUS_8822B(x) \ + (((x) & BIT_MASK_I2C_M_STATUS_8822B) << BIT_SHIFT_I2C_M_STATUS_8822B) +#define BIT_GET_I2C_M_STATUS_8822B(x) \ + (((x) >> BIT_SHIFT_I2C_M_STATUS_8822B) & BIT_MASK_I2C_M_STATUS_8822B) + +#define BIT_SHIFT_I2C_M_BUS_GNT_FW_8822B 4 +#define BIT_MASK_I2C_M_BUS_GNT_FW_8822B 0x7 +#define BIT_I2C_M_BUS_GNT_FW_8822B(x) \ + (((x) & BIT_MASK_I2C_M_BUS_GNT_FW_8822B) \ + << BIT_SHIFT_I2C_M_BUS_GNT_FW_8822B) +#define BIT_GET_I2C_M_BUS_GNT_FW_8822B(x) \ + (((x) >> BIT_SHIFT_I2C_M_BUS_GNT_FW_8822B) & \ + BIT_MASK_I2C_M_BUS_GNT_FW_8822B) + +#define BIT_I2C_M_GNT_FW_8822B BIT(3) + +#define BIT_SHIFT_I2C_M_SPEED_8822B 1 +#define BIT_MASK_I2C_M_SPEED_8822B 0x3 +#define BIT_I2C_M_SPEED_8822B(x) \ + (((x) & BIT_MASK_I2C_M_SPEED_8822B) << BIT_SHIFT_I2C_M_SPEED_8822B) +#define BIT_GET_I2C_M_SPEED_8822B(x) \ + (((x) >> BIT_SHIFT_I2C_M_SPEED_8822B) & BIT_MASK_I2C_M_SPEED_8822B) + +#define BIT_I2C_M_UNLOCK_8822B BIT(0) + +/* 2 REG_RXFF_BNDY_8822B */ + +/* 2 REG_NOT_VALID_8822B */ + +#define BIT_SHIFT_RXFF0_BNDY_V2_8822B 0 +#define BIT_MASK_RXFF0_BNDY_V2_8822B 0x3ffff +#define BIT_RXFF0_BNDY_V2_8822B(x) \ + (((x) & BIT_MASK_RXFF0_BNDY_V2_8822B) << BIT_SHIFT_RXFF0_BNDY_V2_8822B) +#define BIT_GET_RXFF0_BNDY_V2_8822B(x) \ + (((x) >> BIT_SHIFT_RXFF0_BNDY_V2_8822B) & BIT_MASK_RXFF0_BNDY_V2_8822B) + +/* 2 REG_FE1IMR_8822B */ +#define BIT_FS_RXDMA2_DONE_INT_EN_8822B BIT(28) +#define BIT_FS_RXDONE3_INT_EN_8822B BIT(27) +#define BIT_FS_RXDONE2_INT_EN_8822B BIT(26) +#define BIT_FS_RX_BCN_P4_INT_EN_8822B BIT(25) +#define BIT_FS_RX_BCN_P3_INT_EN_8822B BIT(24) +#define BIT_FS_RX_BCN_P2_INT_EN_8822B BIT(23) +#define BIT_FS_RX_BCN_P1_INT_EN_8822B BIT(22) +#define BIT_FS_RX_BCN_P0_INT_EN_8822B BIT(21) +#define BIT_FS_RX_UMD0_INT_EN_8822B BIT(20) +#define BIT_FS_RX_UMD1_INT_EN_8822B BIT(19) +#define BIT_FS_RX_BMD0_INT_EN_8822B BIT(18) +#define BIT_FS_RX_BMD1_INT_EN_8822B BIT(17) +#define BIT_FS_RXDONE_INT_EN_8822B BIT(16) +#define BIT_FS_WWLAN_INT_EN_8822B BIT(15) +#define BIT_FS_SOUND_DONE_INT_EN_8822B BIT(14) +#define BIT_FS_LP_STBY_INT_EN_8822B BIT(13) +#define BIT_FS_TRL_MTR_INT_EN_8822B BIT(12) +#define BIT_FS_BF1_PRETO_INT_EN_8822B BIT(11) +#define BIT_FS_BF0_PRETO_INT_EN_8822B BIT(10) +#define BIT_FS_PTCL_RELEASE_MACID_INT_EN_8822B BIT(9) +#define BIT_FS_LTE_COEX_EN_8822B BIT(6) +#define BIT_FS_WLACTOFF_INT_EN_8822B BIT(5) +#define BIT_FS_WLACTON_INT_EN_8822B BIT(4) +#define BIT_FS_BTCMD_INT_EN_8822B BIT(3) +#define BIT_FS_REG_MAILBOX_TO_I2C_INT_EN_8822B BIT(2) +#define BIT_FS_TRPC_TO_INT_EN_V1_8822B BIT(1) +#define BIT_FS_RPC_O_T_INT_EN_V1_8822B BIT(0) + +/* 2 REG_FE1ISR_8822B */ +#define BIT_FS_RXDMA2_DONE_INT_8822B BIT(28) +#define BIT_FS_RXDONE3_INT_8822B BIT(27) +#define BIT_FS_RXDONE2_INT_8822B BIT(26) +#define BIT_FS_RX_BCN_P4_INT_8822B BIT(25) +#define BIT_FS_RX_BCN_P3_INT_8822B BIT(24) +#define BIT_FS_RX_BCN_P2_INT_8822B BIT(23) +#define BIT_FS_RX_BCN_P1_INT_8822B BIT(22) +#define BIT_FS_RX_BCN_P0_INT_8822B BIT(21) +#define BIT_FS_RX_UMD0_INT_8822B BIT(20) +#define BIT_FS_RX_UMD1_INT_8822B BIT(19) +#define BIT_FS_RX_BMD0_INT_8822B BIT(18) +#define BIT_FS_RX_BMD1_INT_8822B BIT(17) +#define BIT_FS_RXDONE_INT_8822B BIT(16) +#define BIT_FS_WWLAN_INT_8822B BIT(15) +#define BIT_FS_SOUND_DONE_INT_8822B BIT(14) +#define BIT_FS_LP_STBY_INT_8822B BIT(13) +#define BIT_FS_TRL_MTR_INT_8822B BIT(12) +#define BIT_FS_BF1_PRETO_INT_8822B BIT(11) +#define BIT_FS_BF0_PRETO_INT_8822B BIT(10) +#define BIT_FS_PTCL_RELEASE_MACID_INT_8822B BIT(9) +#define BIT_FS_LTE_COEX_INT_8822B BIT(6) +#define BIT_FS_WLACTOFF_INT_8822B BIT(5) +#define BIT_FS_WLACTON_INT_8822B BIT(4) +#define BIT_FS_BCN_RX_INT_INT_8822B BIT(3) +#define BIT_FS_MAILBOX_TO_I2C_INT_8822B BIT(2) +#define BIT_FS_TRPC_TO_INT_8822B BIT(1) +#define BIT_FS_RPC_O_T_INT_8822B BIT(0) + +/* 2 REG_NOT_VALID_8822B */ + +/* 2 REG_CPWM_8822B */ +#define BIT_CPWM_TOGGLING_8822B BIT(31) + +#define BIT_SHIFT_CPWM_MOD_8822B 24 +#define BIT_MASK_CPWM_MOD_8822B 0x7f +#define BIT_CPWM_MOD_8822B(x) \ + (((x) & BIT_MASK_CPWM_MOD_8822B) << BIT_SHIFT_CPWM_MOD_8822B) +#define BIT_GET_CPWM_MOD_8822B(x) \ + (((x) >> BIT_SHIFT_CPWM_MOD_8822B) & BIT_MASK_CPWM_MOD_8822B) + +/* 2 REG_FWIMR_8822B */ +#define BIT_FS_TXBCNOK_MB7_INT_EN_8822B BIT(31) +#define BIT_FS_TXBCNOK_MB6_INT_EN_8822B BIT(30) +#define BIT_FS_TXBCNOK_MB5_INT_EN_8822B BIT(29) +#define BIT_FS_TXBCNOK_MB4_INT_EN_8822B BIT(28) +#define BIT_FS_TXBCNOK_MB3_INT_EN_8822B BIT(27) +#define BIT_FS_TXBCNOK_MB2_INT_EN_8822B BIT(26) +#define BIT_FS_TXBCNOK_MB1_INT_EN_8822B BIT(25) +#define BIT_FS_TXBCNOK_MB0_INT_EN_8822B BIT(24) +#define BIT_FS_TXBCNERR_MB7_INT_EN_8822B BIT(23) +#define BIT_FS_TXBCNERR_MB6_INT_EN_8822B BIT(22) +#define BIT_FS_TXBCNERR_MB5_INT_EN_8822B BIT(21) +#define BIT_FS_TXBCNERR_MB4_INT_EN_8822B BIT(20) +#define BIT_FS_TXBCNERR_MB3_INT_EN_8822B BIT(19) +#define BIT_FS_TXBCNERR_MB2_INT_EN_8822B BIT(18) +#define BIT_FS_TXBCNERR_MB1_INT_EN_8822B BIT(17) +#define BIT_FS_TXBCNERR_MB0_INT_EN_8822B BIT(16) +#define BIT_CPU_MGQ_TXDONE_INT_EN_8822B BIT(15) +#define BIT_SIFS_OVERSPEC_INT_EN_8822B BIT(14) +#define BIT_FS_MGNTQ_RPTR_RELEASE_INT_EN_8822B BIT(13) +#define BIT_FS_MGNTQFF_TO_INT_EN_8822B BIT(12) +#define BIT_FS_DDMA1_LP_INT_EN_8822B BIT(11) +#define BIT_FS_DDMA1_HP_INT_EN_8822B BIT(10) +#define BIT_FS_DDMA0_LP_INT_EN_8822B BIT(9) +#define BIT_FS_DDMA0_HP_INT_EN_8822B BIT(8) +#define BIT_FS_TRXRPT_INT_EN_8822B BIT(7) +#define BIT_FS_C2H_W_READY_INT_EN_8822B BIT(6) +#define BIT_FS_HRCV_INT_EN_8822B BIT(5) +#define BIT_FS_H2CCMD_INT_EN_8822B BIT(4) +#define BIT_FS_TXPKTIN_INT_EN_8822B BIT(3) +#define BIT_FS_ERRORHDL_INT_EN_8822B BIT(2) +#define BIT_FS_TXCCX_INT_EN_8822B BIT(1) +#define BIT_FS_TXCLOSE_INT_EN_8822B BIT(0) + +/* 2 REG_FWISR_8822B */ +#define BIT_FS_TXBCNOK_MB7_INT_8822B BIT(31) +#define BIT_FS_TXBCNOK_MB6_INT_8822B BIT(30) +#define BIT_FS_TXBCNOK_MB5_INT_8822B BIT(29) +#define BIT_FS_TXBCNOK_MB4_INT_8822B BIT(28) +#define BIT_FS_TXBCNOK_MB3_INT_8822B BIT(27) +#define BIT_FS_TXBCNOK_MB2_INT_8822B BIT(26) +#define BIT_FS_TXBCNOK_MB1_INT_8822B BIT(25) +#define BIT_FS_TXBCNOK_MB0_INT_8822B BIT(24) +#define BIT_FS_TXBCNERR_MB7_INT_8822B BIT(23) +#define BIT_FS_TXBCNERR_MB6_INT_8822B BIT(22) +#define BIT_FS_TXBCNERR_MB5_INT_8822B BIT(21) +#define BIT_FS_TXBCNERR_MB4_INT_8822B BIT(20) +#define BIT_FS_TXBCNERR_MB3_INT_8822B BIT(19) +#define BIT_FS_TXBCNERR_MB2_INT_8822B BIT(18) +#define BIT_FS_TXBCNERR_MB1_INT_8822B BIT(17) +#define BIT_FS_TXBCNERR_MB0_INT_8822B BIT(16) +#define BIT_CPU_MGQ_TXDONE_INT_8822B BIT(15) +#define BIT_SIFS_OVERSPEC_INT_8822B BIT(14) +#define BIT_FS_MGNTQ_RPTR_RELEASE_INT_8822B BIT(13) +#define BIT_FS_MGNTQFF_TO_INT_8822B BIT(12) +#define BIT_FS_DDMA1_LP_INT_8822B BIT(11) +#define BIT_FS_DDMA1_HP_INT_8822B BIT(10) +#define BIT_FS_DDMA0_LP_INT_8822B BIT(9) +#define BIT_FS_DDMA0_HP_INT_8822B BIT(8) +#define BIT_FS_TRXRPT_INT_8822B BIT(7) +#define BIT_FS_C2H_W_READY_INT_8822B BIT(6) +#define BIT_FS_HRCV_INT_8822B BIT(5) +#define BIT_FS_H2CCMD_INT_8822B BIT(4) +#define BIT_FS_TXPKTIN_INT_8822B BIT(3) +#define BIT_FS_ERRORHDL_INT_8822B BIT(2) +#define BIT_FS_TXCCX_INT_8822B BIT(1) +#define BIT_FS_TXCLOSE_INT_8822B BIT(0) + +/* 2 REG_FTIMR_8822B */ +#define BIT_PS_TIMER_C_EARLY_INT_EN_8822B BIT(23) +#define BIT_PS_TIMER_B_EARLY_INT_EN_8822B BIT(22) +#define BIT_PS_TIMER_A_EARLY_INT_EN_8822B BIT(21) +#define BIT_CPUMGQ_TX_TIMER_EARLY_INT_EN_8822B BIT(20) +#define BIT_PS_TIMER_C_INT_EN_8822B BIT(19) +#define BIT_PS_TIMER_B_INT_EN_8822B BIT(18) +#define BIT_PS_TIMER_A_INT_EN_8822B BIT(17) +#define BIT_CPUMGQ_TX_TIMER_INT_EN_8822B BIT(16) +#define BIT_FS_PS_TIMEOUT2_EN_8822B BIT(15) +#define BIT_FS_PS_TIMEOUT1_EN_8822B BIT(14) +#define BIT_FS_PS_TIMEOUT0_EN_8822B BIT(13) +#define BIT_FS_GTINT8_EN_8822B BIT(8) +#define BIT_FS_GTINT7_EN_8822B BIT(7) +#define BIT_FS_GTINT6_EN_8822B BIT(6) +#define BIT_FS_GTINT5_EN_8822B BIT(5) +#define BIT_FS_GTINT4_EN_8822B BIT(4) +#define BIT_FS_GTINT3_EN_8822B BIT(3) +#define BIT_FS_GTINT2_EN_8822B BIT(2) +#define BIT_FS_GTINT1_EN_8822B BIT(1) +#define BIT_FS_GTINT0_EN_8822B BIT(0) + +/* 2 REG_FTISR_8822B */ +#define BIT_PS_TIMER_C_EARLY__INT_8822B BIT(23) +#define BIT_PS_TIMER_B_EARLY__INT_8822B BIT(22) +#define BIT_PS_TIMER_A_EARLY__INT_8822B BIT(21) +#define BIT_CPUMGQ_TX_TIMER_EARLY_INT_8822B BIT(20) +#define BIT_PS_TIMER_C_INT_8822B BIT(19) +#define BIT_PS_TIMER_B_INT_8822B BIT(18) +#define BIT_PS_TIMER_A_INT_8822B BIT(17) +#define BIT_CPUMGQ_TX_TIMER_INT_8822B BIT(16) +#define BIT_FS_PS_TIMEOUT2_INT_8822B BIT(15) +#define BIT_FS_PS_TIMEOUT1_INT_8822B BIT(14) +#define BIT_FS_PS_TIMEOUT0_INT_8822B BIT(13) +#define BIT_FS_GTINT8_INT_8822B BIT(8) +#define BIT_FS_GTINT7_INT_8822B BIT(7) +#define BIT_FS_GTINT6_INT_8822B BIT(6) +#define BIT_FS_GTINT5_INT_8822B BIT(5) +#define BIT_FS_GTINT4_INT_8822B BIT(4) +#define BIT_FS_GTINT3_INT_8822B BIT(3) +#define BIT_FS_GTINT2_INT_8822B BIT(2) +#define BIT_FS_GTINT1_INT_8822B BIT(1) +#define BIT_FS_GTINT0_INT_8822B BIT(0) + +/* 2 REG_PKTBUF_DBG_CTRL_8822B */ + +#define BIT_SHIFT_PKTBUF_WRITE_EN_8822B 24 +#define BIT_MASK_PKTBUF_WRITE_EN_8822B 0xff +#define BIT_PKTBUF_WRITE_EN_8822B(x) \ + (((x) & BIT_MASK_PKTBUF_WRITE_EN_8822B) \ + << BIT_SHIFT_PKTBUF_WRITE_EN_8822B) +#define BIT_GET_PKTBUF_WRITE_EN_8822B(x) \ + (((x) >> BIT_SHIFT_PKTBUF_WRITE_EN_8822B) & \ + BIT_MASK_PKTBUF_WRITE_EN_8822B) + +#define BIT_TXRPTBUF_DBG_8822B BIT(23) + +/* 2 REG_NOT_VALID_8822B */ +#define BIT_TXPKTBUF_DBG_V2_8822B BIT(20) +#define BIT_RXPKTBUF_DBG_8822B BIT(16) + +#define BIT_SHIFT_PKTBUF_DBG_ADDR_8822B 0 +#define BIT_MASK_PKTBUF_DBG_ADDR_8822B 0x1fff +#define BIT_PKTBUF_DBG_ADDR_8822B(x) \ + (((x) & BIT_MASK_PKTBUF_DBG_ADDR_8822B) \ + << BIT_SHIFT_PKTBUF_DBG_ADDR_8822B) +#define BIT_GET_PKTBUF_DBG_ADDR_8822B(x) \ + (((x) >> BIT_SHIFT_PKTBUF_DBG_ADDR_8822B) & \ + BIT_MASK_PKTBUF_DBG_ADDR_8822B) + +/* 2 REG_PKTBUF_DBG_DATA_L_8822B */ + +#define BIT_SHIFT_PKTBUF_DBG_DATA_L_8822B 0 +#define BIT_MASK_PKTBUF_DBG_DATA_L_8822B 0xffffffffL +#define BIT_PKTBUF_DBG_DATA_L_8822B(x) \ + (((x) & BIT_MASK_PKTBUF_DBG_DATA_L_8822B) \ + << BIT_SHIFT_PKTBUF_DBG_DATA_L_8822B) +#define BIT_GET_PKTBUF_DBG_DATA_L_8822B(x) \ + (((x) >> BIT_SHIFT_PKTBUF_DBG_DATA_L_8822B) & \ + BIT_MASK_PKTBUF_DBG_DATA_L_8822B) + +/* 2 REG_PKTBUF_DBG_DATA_H_8822B */ + +#define BIT_SHIFT_PKTBUF_DBG_DATA_H_8822B 0 +#define BIT_MASK_PKTBUF_DBG_DATA_H_8822B 0xffffffffL +#define BIT_PKTBUF_DBG_DATA_H_8822B(x) \ + (((x) & BIT_MASK_PKTBUF_DBG_DATA_H_8822B) \ + << BIT_SHIFT_PKTBUF_DBG_DATA_H_8822B) +#define BIT_GET_PKTBUF_DBG_DATA_H_8822B(x) \ + (((x) >> BIT_SHIFT_PKTBUF_DBG_DATA_H_8822B) & \ + BIT_MASK_PKTBUF_DBG_DATA_H_8822B) + +/* 2 REG_CPWM2_8822B */ + +#define BIT_SHIFT_L0S_TO_RCVY_NUM_8822B 16 +#define BIT_MASK_L0S_TO_RCVY_NUM_8822B 0xff +#define BIT_L0S_TO_RCVY_NUM_8822B(x) \ + (((x) & BIT_MASK_L0S_TO_RCVY_NUM_8822B) \ + << BIT_SHIFT_L0S_TO_RCVY_NUM_8822B) +#define BIT_GET_L0S_TO_RCVY_NUM_8822B(x) \ + (((x) >> BIT_SHIFT_L0S_TO_RCVY_NUM_8822B) & \ + BIT_MASK_L0S_TO_RCVY_NUM_8822B) + +#define BIT_CPWM2_TOGGLING_8822B BIT(15) + +#define BIT_SHIFT_CPWM2_MOD_8822B 0 +#define BIT_MASK_CPWM2_MOD_8822B 0x7fff +#define BIT_CPWM2_MOD_8822B(x) \ + (((x) & BIT_MASK_CPWM2_MOD_8822B) << BIT_SHIFT_CPWM2_MOD_8822B) +#define BIT_GET_CPWM2_MOD_8822B(x) \ + (((x) >> BIT_SHIFT_CPWM2_MOD_8822B) & BIT_MASK_CPWM2_MOD_8822B) + +/* 2 REG_NOT_VALID_8822B */ + +/* 2 REG_TC0_CTRL_8822B */ +#define BIT_TC0INT_EN_8822B BIT(26) +#define BIT_TC0MODE_8822B BIT(25) +#define BIT_TC0EN_8822B BIT(24) + +#define BIT_SHIFT_TC0DATA_8822B 0 +#define BIT_MASK_TC0DATA_8822B 0xffffff +#define BIT_TC0DATA_8822B(x) \ + (((x) & BIT_MASK_TC0DATA_8822B) << BIT_SHIFT_TC0DATA_8822B) +#define BIT_GET_TC0DATA_8822B(x) \ + (((x) >> BIT_SHIFT_TC0DATA_8822B) & BIT_MASK_TC0DATA_8822B) + +/* 2 REG_TC1_CTRL_8822B */ +#define BIT_TC1INT_EN_8822B BIT(26) +#define BIT_TC1MODE_8822B BIT(25) +#define BIT_TC1EN_8822B BIT(24) + +#define BIT_SHIFT_TC1DATA_8822B 0 +#define BIT_MASK_TC1DATA_8822B 0xffffff +#define BIT_TC1DATA_8822B(x) \ + (((x) & BIT_MASK_TC1DATA_8822B) << BIT_SHIFT_TC1DATA_8822B) +#define BIT_GET_TC1DATA_8822B(x) \ + (((x) >> BIT_SHIFT_TC1DATA_8822B) & BIT_MASK_TC1DATA_8822B) + +/* 2 REG_TC2_CTRL_8822B */ +#define BIT_TC2INT_EN_8822B BIT(26) +#define BIT_TC2MODE_8822B BIT(25) +#define BIT_TC2EN_8822B BIT(24) + +#define BIT_SHIFT_TC2DATA_8822B 0 +#define BIT_MASK_TC2DATA_8822B 0xffffff +#define BIT_TC2DATA_8822B(x) \ + (((x) & BIT_MASK_TC2DATA_8822B) << BIT_SHIFT_TC2DATA_8822B) +#define BIT_GET_TC2DATA_8822B(x) \ + (((x) >> BIT_SHIFT_TC2DATA_8822B) & BIT_MASK_TC2DATA_8822B) + +/* 2 REG_TC3_CTRL_8822B */ +#define BIT_TC3INT_EN_8822B BIT(26) +#define BIT_TC3MODE_8822B BIT(25) +#define BIT_TC3EN_8822B BIT(24) + +#define BIT_SHIFT_TC3DATA_8822B 0 +#define BIT_MASK_TC3DATA_8822B 0xffffff +#define BIT_TC3DATA_8822B(x) \ + (((x) & BIT_MASK_TC3DATA_8822B) << BIT_SHIFT_TC3DATA_8822B) +#define BIT_GET_TC3DATA_8822B(x) \ + (((x) >> BIT_SHIFT_TC3DATA_8822B) & BIT_MASK_TC3DATA_8822B) + +/* 2 REG_TC4_CTRL_8822B */ +#define BIT_TC4INT_EN_8822B BIT(26) +#define BIT_TC4MODE_8822B BIT(25) +#define BIT_TC4EN_8822B BIT(24) + +#define BIT_SHIFT_TC4DATA_8822B 0 +#define BIT_MASK_TC4DATA_8822B 0xffffff +#define BIT_TC4DATA_8822B(x) \ + (((x) & BIT_MASK_TC4DATA_8822B) << BIT_SHIFT_TC4DATA_8822B) +#define BIT_GET_TC4DATA_8822B(x) \ + (((x) >> BIT_SHIFT_TC4DATA_8822B) & BIT_MASK_TC4DATA_8822B) + +/* 2 REG_TCUNIT_BASE_8822B */ + +#define BIT_SHIFT_TCUNIT_BASE_8822B 0 +#define BIT_MASK_TCUNIT_BASE_8822B 0x3fff +#define BIT_TCUNIT_BASE_8822B(x) \ + (((x) & BIT_MASK_TCUNIT_BASE_8822B) << BIT_SHIFT_TCUNIT_BASE_8822B) +#define BIT_GET_TCUNIT_BASE_8822B(x) \ + (((x) >> BIT_SHIFT_TCUNIT_BASE_8822B) & BIT_MASK_TCUNIT_BASE_8822B) + +/* 2 REG_TC5_CTRL_8822B */ +#define BIT_TC5INT_EN_8822B BIT(26) +#define BIT_TC5MODE_8822B BIT(25) +#define BIT_TC5EN_8822B BIT(24) + +#define BIT_SHIFT_TC5DATA_8822B 0 +#define BIT_MASK_TC5DATA_8822B 0xffffff +#define BIT_TC5DATA_8822B(x) \ + (((x) & BIT_MASK_TC5DATA_8822B) << BIT_SHIFT_TC5DATA_8822B) +#define BIT_GET_TC5DATA_8822B(x) \ + (((x) >> BIT_SHIFT_TC5DATA_8822B) & BIT_MASK_TC5DATA_8822B) + +/* 2 REG_TC6_CTRL_8822B */ +#define BIT_TC6INT_EN_8822B BIT(26) +#define BIT_TC6MODE_8822B BIT(25) +#define BIT_TC6EN_8822B BIT(24) + +#define BIT_SHIFT_TC6DATA_8822B 0 +#define BIT_MASK_TC6DATA_8822B 0xffffff +#define BIT_TC6DATA_8822B(x) \ + (((x) & BIT_MASK_TC6DATA_8822B) << BIT_SHIFT_TC6DATA_8822B) +#define BIT_GET_TC6DATA_8822B(x) \ + (((x) >> BIT_SHIFT_TC6DATA_8822B) & BIT_MASK_TC6DATA_8822B) + +/* 2 REG_MBIST_FAIL_8822B */ + +#define BIT_SHIFT_8051_MBIST_FAIL_8822B 26 +#define BIT_MASK_8051_MBIST_FAIL_8822B 0x7 +#define BIT_8051_MBIST_FAIL_8822B(x) \ + (((x) & BIT_MASK_8051_MBIST_FAIL_8822B) \ + << BIT_SHIFT_8051_MBIST_FAIL_8822B) +#define BIT_GET_8051_MBIST_FAIL_8822B(x) \ + (((x) >> BIT_SHIFT_8051_MBIST_FAIL_8822B) & \ + BIT_MASK_8051_MBIST_FAIL_8822B) + +#define BIT_SHIFT_USB_MBIST_FAIL_8822B 24 +#define BIT_MASK_USB_MBIST_FAIL_8822B 0x3 +#define BIT_USB_MBIST_FAIL_8822B(x) \ + (((x) & BIT_MASK_USB_MBIST_FAIL_8822B) \ + << BIT_SHIFT_USB_MBIST_FAIL_8822B) +#define BIT_GET_USB_MBIST_FAIL_8822B(x) \ + (((x) >> BIT_SHIFT_USB_MBIST_FAIL_8822B) & \ + BIT_MASK_USB_MBIST_FAIL_8822B) + +#define BIT_SHIFT_PCIE_MBIST_FAIL_8822B 16 +#define BIT_MASK_PCIE_MBIST_FAIL_8822B 0x3f +#define BIT_PCIE_MBIST_FAIL_8822B(x) \ + (((x) & BIT_MASK_PCIE_MBIST_FAIL_8822B) \ + << BIT_SHIFT_PCIE_MBIST_FAIL_8822B) +#define BIT_GET_PCIE_MBIST_FAIL_8822B(x) \ + (((x) >> BIT_SHIFT_PCIE_MBIST_FAIL_8822B) & \ + BIT_MASK_PCIE_MBIST_FAIL_8822B) + +#define BIT_SHIFT_MAC_MBIST_FAIL_8822B 0 +#define BIT_MASK_MAC_MBIST_FAIL_8822B 0xfff +#define BIT_MAC_MBIST_FAIL_8822B(x) \ + (((x) & BIT_MASK_MAC_MBIST_FAIL_8822B) \ + << BIT_SHIFT_MAC_MBIST_FAIL_8822B) +#define BIT_GET_MAC_MBIST_FAIL_8822B(x) \ + (((x) >> BIT_SHIFT_MAC_MBIST_FAIL_8822B) & \ + BIT_MASK_MAC_MBIST_FAIL_8822B) + +/* 2 REG_MBIST_START_PAUSE_8822B */ + +#define BIT_SHIFT_8051_MBIST_START_PAUSE_8822B 26 +#define BIT_MASK_8051_MBIST_START_PAUSE_8822B 0x7 +#define BIT_8051_MBIST_START_PAUSE_8822B(x) \ + (((x) & BIT_MASK_8051_MBIST_START_PAUSE_8822B) \ + << BIT_SHIFT_8051_MBIST_START_PAUSE_8822B) +#define BIT_GET_8051_MBIST_START_PAUSE_8822B(x) \ + (((x) >> BIT_SHIFT_8051_MBIST_START_PAUSE_8822B) & \ + BIT_MASK_8051_MBIST_START_PAUSE_8822B) + +#define BIT_SHIFT_USB_MBIST_START_PAUSE_8822B 24 +#define BIT_MASK_USB_MBIST_START_PAUSE_8822B 0x3 +#define BIT_USB_MBIST_START_PAUSE_8822B(x) \ + (((x) & BIT_MASK_USB_MBIST_START_PAUSE_8822B) \ + << BIT_SHIFT_USB_MBIST_START_PAUSE_8822B) +#define BIT_GET_USB_MBIST_START_PAUSE_8822B(x) \ + (((x) >> BIT_SHIFT_USB_MBIST_START_PAUSE_8822B) & \ + BIT_MASK_USB_MBIST_START_PAUSE_8822B) + +#define BIT_SHIFT_PCIE_MBIST_START_PAUSE_8822B 16 +#define BIT_MASK_PCIE_MBIST_START_PAUSE_8822B 0x3f +#define BIT_PCIE_MBIST_START_PAUSE_8822B(x) \ + (((x) & BIT_MASK_PCIE_MBIST_START_PAUSE_8822B) \ + << BIT_SHIFT_PCIE_MBIST_START_PAUSE_8822B) +#define BIT_GET_PCIE_MBIST_START_PAUSE_8822B(x) \ + (((x) >> BIT_SHIFT_PCIE_MBIST_START_PAUSE_8822B) & \ + BIT_MASK_PCIE_MBIST_START_PAUSE_8822B) + +#define BIT_SHIFT_MAC_MBIST_START_PAUSE_8822B 0 +#define BIT_MASK_MAC_MBIST_START_PAUSE_8822B 0xfff +#define BIT_MAC_MBIST_START_PAUSE_8822B(x) \ + (((x) & BIT_MASK_MAC_MBIST_START_PAUSE_8822B) \ + << BIT_SHIFT_MAC_MBIST_START_PAUSE_8822B) +#define BIT_GET_MAC_MBIST_START_PAUSE_8822B(x) \ + (((x) >> BIT_SHIFT_MAC_MBIST_START_PAUSE_8822B) & \ + BIT_MASK_MAC_MBIST_START_PAUSE_8822B) + +/* 2 REG_MBIST_DONE_8822B */ + +#define BIT_SHIFT_8051_MBIST_DONE_8822B 26 +#define BIT_MASK_8051_MBIST_DONE_8822B 0x7 +#define BIT_8051_MBIST_DONE_8822B(x) \ + (((x) & BIT_MASK_8051_MBIST_DONE_8822B) \ + << BIT_SHIFT_8051_MBIST_DONE_8822B) +#define BIT_GET_8051_MBIST_DONE_8822B(x) \ + (((x) >> BIT_SHIFT_8051_MBIST_DONE_8822B) & \ + BIT_MASK_8051_MBIST_DONE_8822B) + +#define BIT_SHIFT_USB_MBIST_DONE_8822B 24 +#define BIT_MASK_USB_MBIST_DONE_8822B 0x3 +#define BIT_USB_MBIST_DONE_8822B(x) \ + (((x) & BIT_MASK_USB_MBIST_DONE_8822B) \ + << BIT_SHIFT_USB_MBIST_DONE_8822B) +#define BIT_GET_USB_MBIST_DONE_8822B(x) \ + (((x) >> BIT_SHIFT_USB_MBIST_DONE_8822B) & \ + BIT_MASK_USB_MBIST_DONE_8822B) + +#define BIT_SHIFT_PCIE_MBIST_DONE_8822B 16 +#define BIT_MASK_PCIE_MBIST_DONE_8822B 0x3f +#define BIT_PCIE_MBIST_DONE_8822B(x) \ + (((x) & BIT_MASK_PCIE_MBIST_DONE_8822B) \ + << BIT_SHIFT_PCIE_MBIST_DONE_8822B) +#define BIT_GET_PCIE_MBIST_DONE_8822B(x) \ + (((x) >> BIT_SHIFT_PCIE_MBIST_DONE_8822B) & \ + BIT_MASK_PCIE_MBIST_DONE_8822B) + +#define BIT_SHIFT_MAC_MBIST_DONE_8822B 0 +#define BIT_MASK_MAC_MBIST_DONE_8822B 0xfff +#define BIT_MAC_MBIST_DONE_8822B(x) \ + (((x) & BIT_MASK_MAC_MBIST_DONE_8822B) \ + << BIT_SHIFT_MAC_MBIST_DONE_8822B) +#define BIT_GET_MAC_MBIST_DONE_8822B(x) \ + (((x) >> BIT_SHIFT_MAC_MBIST_DONE_8822B) & \ + BIT_MASK_MAC_MBIST_DONE_8822B) + +/* 2 REG_MBIST_FAIL_NRML_8822B */ + +#define BIT_SHIFT_MBIST_FAIL_NRML_8822B 0 +#define BIT_MASK_MBIST_FAIL_NRML_8822B 0xffffffffL +#define BIT_MBIST_FAIL_NRML_8822B(x) \ + (((x) & BIT_MASK_MBIST_FAIL_NRML_8822B) \ + << BIT_SHIFT_MBIST_FAIL_NRML_8822B) +#define BIT_GET_MBIST_FAIL_NRML_8822B(x) \ + (((x) >> BIT_SHIFT_MBIST_FAIL_NRML_8822B) & \ + BIT_MASK_MBIST_FAIL_NRML_8822B) + +/* 2 REG_AES_DECRPT_DATA_8822B */ + +#define BIT_SHIFT_IPS_CFG_ADDR_8822B 0 +#define BIT_MASK_IPS_CFG_ADDR_8822B 0xff +#define BIT_IPS_CFG_ADDR_8822B(x) \ + (((x) & BIT_MASK_IPS_CFG_ADDR_8822B) << BIT_SHIFT_IPS_CFG_ADDR_8822B) +#define BIT_GET_IPS_CFG_ADDR_8822B(x) \ + (((x) >> BIT_SHIFT_IPS_CFG_ADDR_8822B) & BIT_MASK_IPS_CFG_ADDR_8822B) + +/* 2 REG_AES_DECRPT_CFG_8822B */ + +#define BIT_SHIFT_IPS_CFG_DATA_8822B 0 +#define BIT_MASK_IPS_CFG_DATA_8822B 0xffffffffL +#define BIT_IPS_CFG_DATA_8822B(x) \ + (((x) & BIT_MASK_IPS_CFG_DATA_8822B) << BIT_SHIFT_IPS_CFG_DATA_8822B) +#define BIT_GET_IPS_CFG_DATA_8822B(x) \ + (((x) >> BIT_SHIFT_IPS_CFG_DATA_8822B) & BIT_MASK_IPS_CFG_DATA_8822B) + +/* 2 REG_NOT_VALID_8822B */ + +/* 2 REG_NOT_VALID_8822B */ + +/* 2 REG_TMETER_8822B */ +#define BIT_TEMP_VALID_8822B BIT(31) + +#define BIT_SHIFT_TEMP_VALUE_8822B 24 +#define BIT_MASK_TEMP_VALUE_8822B 0x3f +#define BIT_TEMP_VALUE_8822B(x) \ + (((x) & BIT_MASK_TEMP_VALUE_8822B) << BIT_SHIFT_TEMP_VALUE_8822B) +#define BIT_GET_TEMP_VALUE_8822B(x) \ + (((x) >> BIT_SHIFT_TEMP_VALUE_8822B) & BIT_MASK_TEMP_VALUE_8822B) + +#define BIT_SHIFT_REG_TMETER_TIMER_8822B 8 +#define BIT_MASK_REG_TMETER_TIMER_8822B 0xfff +#define BIT_REG_TMETER_TIMER_8822B(x) \ + (((x) & BIT_MASK_REG_TMETER_TIMER_8822B) \ + << BIT_SHIFT_REG_TMETER_TIMER_8822B) +#define BIT_GET_REG_TMETER_TIMER_8822B(x) \ + (((x) >> BIT_SHIFT_REG_TMETER_TIMER_8822B) & \ + BIT_MASK_REG_TMETER_TIMER_8822B) + +#define BIT_SHIFT_REG_TEMP_DELTA_8822B 2 +#define BIT_MASK_REG_TEMP_DELTA_8822B 0x3f +#define BIT_REG_TEMP_DELTA_8822B(x) \ + (((x) & BIT_MASK_REG_TEMP_DELTA_8822B) \ + << BIT_SHIFT_REG_TEMP_DELTA_8822B) +#define BIT_GET_REG_TEMP_DELTA_8822B(x) \ + (((x) >> BIT_SHIFT_REG_TEMP_DELTA_8822B) & \ + BIT_MASK_REG_TEMP_DELTA_8822B) + +#define BIT_REG_TMETER_EN_8822B BIT(0) + +/* 2 REG_OSC_32K_CTRL_8822B */ + +#define BIT_SHIFT_OSC_32K_CLKGEN_0_8822B 16 +#define BIT_MASK_OSC_32K_CLKGEN_0_8822B 0xffff +#define BIT_OSC_32K_CLKGEN_0_8822B(x) \ + (((x) & BIT_MASK_OSC_32K_CLKGEN_0_8822B) \ + << BIT_SHIFT_OSC_32K_CLKGEN_0_8822B) +#define BIT_GET_OSC_32K_CLKGEN_0_8822B(x) \ + (((x) >> BIT_SHIFT_OSC_32K_CLKGEN_0_8822B) & \ + BIT_MASK_OSC_32K_CLKGEN_0_8822B) + +#define BIT_SHIFT_OSC_32K_RES_COMP_8822B 4 +#define BIT_MASK_OSC_32K_RES_COMP_8822B 0x3 +#define BIT_OSC_32K_RES_COMP_8822B(x) \ + (((x) & BIT_MASK_OSC_32K_RES_COMP_8822B) \ + << BIT_SHIFT_OSC_32K_RES_COMP_8822B) +#define BIT_GET_OSC_32K_RES_COMP_8822B(x) \ + (((x) >> BIT_SHIFT_OSC_32K_RES_COMP_8822B) & \ + BIT_MASK_OSC_32K_RES_COMP_8822B) + +#define BIT_OSC_32K_OUT_SEL_8822B BIT(3) +#define BIT_ISO_WL_2_OSC_32K_8822B BIT(1) +#define BIT_POW_CKGEN_8822B BIT(0) + +/* 2 REG_32K_CAL_REG1_8822B */ +#define BIT_CAL_32K_REG_WR_8822B BIT(31) +#define BIT_CAL_32K_DBG_SEL_8822B BIT(22) + +#define BIT_SHIFT_CAL_32K_REG_ADDR_8822B 16 +#define BIT_MASK_CAL_32K_REG_ADDR_8822B 0x3f +#define BIT_CAL_32K_REG_ADDR_8822B(x) \ + (((x) & BIT_MASK_CAL_32K_REG_ADDR_8822B) \ + << BIT_SHIFT_CAL_32K_REG_ADDR_8822B) +#define BIT_GET_CAL_32K_REG_ADDR_8822B(x) \ + (((x) >> BIT_SHIFT_CAL_32K_REG_ADDR_8822B) & \ + BIT_MASK_CAL_32K_REG_ADDR_8822B) + +#define BIT_SHIFT_CAL_32K_REG_DATA_8822B 0 +#define BIT_MASK_CAL_32K_REG_DATA_8822B 0xffff +#define BIT_CAL_32K_REG_DATA_8822B(x) \ + (((x) & BIT_MASK_CAL_32K_REG_DATA_8822B) \ + << BIT_SHIFT_CAL_32K_REG_DATA_8822B) +#define BIT_GET_CAL_32K_REG_DATA_8822B(x) \ + (((x) >> BIT_SHIFT_CAL_32K_REG_DATA_8822B) & \ + BIT_MASK_CAL_32K_REG_DATA_8822B) + +/* 2 REG_NOT_VALID_8822B */ + +/* 2 REG_C2HEVT_8822B */ + +#define BIT_SHIFT_C2HEVT_MSG_8822B 0 +#define BIT_MASK_C2HEVT_MSG_8822B 0xffffffffffffffffffffffffffffffffL +#define BIT_C2HEVT_MSG_8822B(x) \ + (((x) & BIT_MASK_C2HEVT_MSG_8822B) << BIT_SHIFT_C2HEVT_MSG_8822B) +#define BIT_GET_C2HEVT_MSG_8822B(x) \ + (((x) >> BIT_SHIFT_C2HEVT_MSG_8822B) & BIT_MASK_C2HEVT_MSG_8822B) + +/* 2 REG_SW_DEFINED_PAGE1_8822B */ + +#define BIT_SHIFT_SW_DEFINED_PAGE1_8822B 0 +#define BIT_MASK_SW_DEFINED_PAGE1_8822B 0xffffffffffffffffL +#define BIT_SW_DEFINED_PAGE1_8822B(x) \ + (((x) & BIT_MASK_SW_DEFINED_PAGE1_8822B) \ + << BIT_SHIFT_SW_DEFINED_PAGE1_8822B) +#define BIT_GET_SW_DEFINED_PAGE1_8822B(x) \ + (((x) >> BIT_SHIFT_SW_DEFINED_PAGE1_8822B) & \ + BIT_MASK_SW_DEFINED_PAGE1_8822B) + +/* 2 REG_MCUTST_I_8822B */ + +#define BIT_SHIFT_MCUDMSG_I_8822B 0 +#define BIT_MASK_MCUDMSG_I_8822B 0xffffffffL +#define BIT_MCUDMSG_I_8822B(x) \ + (((x) & BIT_MASK_MCUDMSG_I_8822B) << BIT_SHIFT_MCUDMSG_I_8822B) +#define BIT_GET_MCUDMSG_I_8822B(x) \ + (((x) >> BIT_SHIFT_MCUDMSG_I_8822B) & BIT_MASK_MCUDMSG_I_8822B) + +/* 2 REG_MCUTST_II_8822B */ + +#define BIT_SHIFT_MCUDMSG_II_8822B 0 +#define BIT_MASK_MCUDMSG_II_8822B 0xffffffffL +#define BIT_MCUDMSG_II_8822B(x) \ + (((x) & BIT_MASK_MCUDMSG_II_8822B) << BIT_SHIFT_MCUDMSG_II_8822B) +#define BIT_GET_MCUDMSG_II_8822B(x) \ + (((x) >> BIT_SHIFT_MCUDMSG_II_8822B) & BIT_MASK_MCUDMSG_II_8822B) + +/* 2 REG_FMETHR_8822B */ +#define BIT_FMSG_INT_8822B BIT(31) + +#define BIT_SHIFT_FW_MSG_8822B 0 +#define BIT_MASK_FW_MSG_8822B 0xffffffffL +#define BIT_FW_MSG_8822B(x) \ + (((x) & BIT_MASK_FW_MSG_8822B) << BIT_SHIFT_FW_MSG_8822B) +#define BIT_GET_FW_MSG_8822B(x) \ + (((x) >> BIT_SHIFT_FW_MSG_8822B) & BIT_MASK_FW_MSG_8822B) + +/* 2 REG_HMETFR_8822B */ + +#define BIT_SHIFT_HRCV_MSG_8822B 24 +#define BIT_MASK_HRCV_MSG_8822B 0xff +#define BIT_HRCV_MSG_8822B(x) \ + (((x) & BIT_MASK_HRCV_MSG_8822B) << BIT_SHIFT_HRCV_MSG_8822B) +#define BIT_GET_HRCV_MSG_8822B(x) \ + (((x) >> BIT_SHIFT_HRCV_MSG_8822B) & BIT_MASK_HRCV_MSG_8822B) + +#define BIT_INT_BOX3_8822B BIT(3) +#define BIT_INT_BOX2_8822B BIT(2) +#define BIT_INT_BOX1_8822B BIT(1) +#define BIT_INT_BOX0_8822B BIT(0) + +/* 2 REG_HMEBOX0_8822B */ + +#define BIT_SHIFT_HOST_MSG_0_8822B 0 +#define BIT_MASK_HOST_MSG_0_8822B 0xffffffffL +#define BIT_HOST_MSG_0_8822B(x) \ + (((x) & BIT_MASK_HOST_MSG_0_8822B) << BIT_SHIFT_HOST_MSG_0_8822B) +#define BIT_GET_HOST_MSG_0_8822B(x) \ + (((x) >> BIT_SHIFT_HOST_MSG_0_8822B) & BIT_MASK_HOST_MSG_0_8822B) + +/* 2 REG_HMEBOX1_8822B */ + +#define BIT_SHIFT_HOST_MSG_1_8822B 0 +#define BIT_MASK_HOST_MSG_1_8822B 0xffffffffL +#define BIT_HOST_MSG_1_8822B(x) \ + (((x) & BIT_MASK_HOST_MSG_1_8822B) << BIT_SHIFT_HOST_MSG_1_8822B) +#define BIT_GET_HOST_MSG_1_8822B(x) \ + (((x) >> BIT_SHIFT_HOST_MSG_1_8822B) & BIT_MASK_HOST_MSG_1_8822B) + +/* 2 REG_HMEBOX2_8822B */ + +#define BIT_SHIFT_HOST_MSG_2_8822B 0 +#define BIT_MASK_HOST_MSG_2_8822B 0xffffffffL +#define BIT_HOST_MSG_2_8822B(x) \ + (((x) & BIT_MASK_HOST_MSG_2_8822B) << BIT_SHIFT_HOST_MSG_2_8822B) +#define BIT_GET_HOST_MSG_2_8822B(x) \ + (((x) >> BIT_SHIFT_HOST_MSG_2_8822B) & BIT_MASK_HOST_MSG_2_8822B) + +/* 2 REG_HMEBOX3_8822B */ + +#define BIT_SHIFT_HOST_MSG_3_8822B 0 +#define BIT_MASK_HOST_MSG_3_8822B 0xffffffffL +#define BIT_HOST_MSG_3_8822B(x) \ + (((x) & BIT_MASK_HOST_MSG_3_8822B) << BIT_SHIFT_HOST_MSG_3_8822B) +#define BIT_GET_HOST_MSG_3_8822B(x) \ + (((x) >> BIT_SHIFT_HOST_MSG_3_8822B) & BIT_MASK_HOST_MSG_3_8822B) + +/* 2 REG_LLT_INIT_8822B */ + +#define BIT_SHIFT_LLTE_RWM_8822B 30 +#define BIT_MASK_LLTE_RWM_8822B 0x3 +#define BIT_LLTE_RWM_8822B(x) \ + (((x) & BIT_MASK_LLTE_RWM_8822B) << BIT_SHIFT_LLTE_RWM_8822B) +#define BIT_GET_LLTE_RWM_8822B(x) \ + (((x) >> BIT_SHIFT_LLTE_RWM_8822B) & BIT_MASK_LLTE_RWM_8822B) + +#define BIT_SHIFT_LLTINI_PDATA_V1_8822B 16 +#define BIT_MASK_LLTINI_PDATA_V1_8822B 0xfff +#define BIT_LLTINI_PDATA_V1_8822B(x) \ + (((x) & BIT_MASK_LLTINI_PDATA_V1_8822B) \ + << BIT_SHIFT_LLTINI_PDATA_V1_8822B) +#define BIT_GET_LLTINI_PDATA_V1_8822B(x) \ + (((x) >> BIT_SHIFT_LLTINI_PDATA_V1_8822B) & \ + BIT_MASK_LLTINI_PDATA_V1_8822B) + +#define BIT_SHIFT_LLTINI_HDATA_V1_8822B 0 +#define BIT_MASK_LLTINI_HDATA_V1_8822B 0xfff +#define BIT_LLTINI_HDATA_V1_8822B(x) \ + (((x) & BIT_MASK_LLTINI_HDATA_V1_8822B) \ + << BIT_SHIFT_LLTINI_HDATA_V1_8822B) +#define BIT_GET_LLTINI_HDATA_V1_8822B(x) \ + (((x) >> BIT_SHIFT_LLTINI_HDATA_V1_8822B) & \ + BIT_MASK_LLTINI_HDATA_V1_8822B) + +/* 2 REG_LLT_INIT_ADDR_8822B */ + +#define BIT_SHIFT_LLTINI_ADDR_V1_8822B 0 +#define BIT_MASK_LLTINI_ADDR_V1_8822B 0xfff +#define BIT_LLTINI_ADDR_V1_8822B(x) \ + (((x) & BIT_MASK_LLTINI_ADDR_V1_8822B) \ + << BIT_SHIFT_LLTINI_ADDR_V1_8822B) +#define BIT_GET_LLTINI_ADDR_V1_8822B(x) \ + (((x) >> BIT_SHIFT_LLTINI_ADDR_V1_8822B) & \ + BIT_MASK_LLTINI_ADDR_V1_8822B) + +/* 2 REG_BB_ACCESS_CTRL_8822B */ + +#define BIT_SHIFT_BB_WRITE_READ_8822B 30 +#define BIT_MASK_BB_WRITE_READ_8822B 0x3 +#define BIT_BB_WRITE_READ_8822B(x) \ + (((x) & BIT_MASK_BB_WRITE_READ_8822B) << BIT_SHIFT_BB_WRITE_READ_8822B) +#define BIT_GET_BB_WRITE_READ_8822B(x) \ + (((x) >> BIT_SHIFT_BB_WRITE_READ_8822B) & BIT_MASK_BB_WRITE_READ_8822B) + +#define BIT_SHIFT_BB_WRITE_EN_8822B 12 +#define BIT_MASK_BB_WRITE_EN_8822B 0xf +#define BIT_BB_WRITE_EN_8822B(x) \ + (((x) & BIT_MASK_BB_WRITE_EN_8822B) << BIT_SHIFT_BB_WRITE_EN_8822B) +#define BIT_GET_BB_WRITE_EN_8822B(x) \ + (((x) >> BIT_SHIFT_BB_WRITE_EN_8822B) & BIT_MASK_BB_WRITE_EN_8822B) + +#define BIT_SHIFT_BB_ADDR_8822B 2 +#define BIT_MASK_BB_ADDR_8822B 0x1ff +#define BIT_BB_ADDR_8822B(x) \ + (((x) & BIT_MASK_BB_ADDR_8822B) << BIT_SHIFT_BB_ADDR_8822B) +#define BIT_GET_BB_ADDR_8822B(x) \ + (((x) >> BIT_SHIFT_BB_ADDR_8822B) & BIT_MASK_BB_ADDR_8822B) + +#define BIT_BB_ERRACC_8822B BIT(0) + +/* 2 REG_BB_ACCESS_DATA_8822B */ + +#define BIT_SHIFT_BB_DATA_8822B 0 +#define BIT_MASK_BB_DATA_8822B 0xffffffffL +#define BIT_BB_DATA_8822B(x) \ + (((x) & BIT_MASK_BB_DATA_8822B) << BIT_SHIFT_BB_DATA_8822B) +#define BIT_GET_BB_DATA_8822B(x) \ + (((x) >> BIT_SHIFT_BB_DATA_8822B) & BIT_MASK_BB_DATA_8822B) + +/* 2 REG_HMEBOX_E0_8822B */ + +#define BIT_SHIFT_HMEBOX_E0_8822B 0 +#define BIT_MASK_HMEBOX_E0_8822B 0xffffffffL +#define BIT_HMEBOX_E0_8822B(x) \ + (((x) & BIT_MASK_HMEBOX_E0_8822B) << BIT_SHIFT_HMEBOX_E0_8822B) +#define BIT_GET_HMEBOX_E0_8822B(x) \ + (((x) >> BIT_SHIFT_HMEBOX_E0_8822B) & BIT_MASK_HMEBOX_E0_8822B) + +/* 2 REG_HMEBOX_E1_8822B */ + +#define BIT_SHIFT_HMEBOX_E1_8822B 0 +#define BIT_MASK_HMEBOX_E1_8822B 0xffffffffL +#define BIT_HMEBOX_E1_8822B(x) \ + (((x) & BIT_MASK_HMEBOX_E1_8822B) << BIT_SHIFT_HMEBOX_E1_8822B) +#define BIT_GET_HMEBOX_E1_8822B(x) \ + (((x) >> BIT_SHIFT_HMEBOX_E1_8822B) & BIT_MASK_HMEBOX_E1_8822B) + +/* 2 REG_HMEBOX_E2_8822B */ + +#define BIT_SHIFT_HMEBOX_E2_8822B 0 +#define BIT_MASK_HMEBOX_E2_8822B 0xffffffffL +#define BIT_HMEBOX_E2_8822B(x) \ + (((x) & BIT_MASK_HMEBOX_E2_8822B) << BIT_SHIFT_HMEBOX_E2_8822B) +#define BIT_GET_HMEBOX_E2_8822B(x) \ + (((x) >> BIT_SHIFT_HMEBOX_E2_8822B) & BIT_MASK_HMEBOX_E2_8822B) + +/* 2 REG_HMEBOX_E3_8822B */ + +#define BIT_SHIFT_HMEBOX_E3_8822B 0 +#define BIT_MASK_HMEBOX_E3_8822B 0xffffffffL +#define BIT_HMEBOX_E3_8822B(x) \ + (((x) & BIT_MASK_HMEBOX_E3_8822B) << BIT_SHIFT_HMEBOX_E3_8822B) +#define BIT_GET_HMEBOX_E3_8822B(x) \ + (((x) >> BIT_SHIFT_HMEBOX_E3_8822B) & BIT_MASK_HMEBOX_E3_8822B) + +/* 2 REG_NOT_VALID_8822B */ + +/* 2 REG_CR_EXT_8822B */ + +#define BIT_SHIFT_PHY_REQ_DELAY_8822B 24 +#define BIT_MASK_PHY_REQ_DELAY_8822B 0xf +#define BIT_PHY_REQ_DELAY_8822B(x) \ + (((x) & BIT_MASK_PHY_REQ_DELAY_8822B) << BIT_SHIFT_PHY_REQ_DELAY_8822B) +#define BIT_GET_PHY_REQ_DELAY_8822B(x) \ + (((x) >> BIT_SHIFT_PHY_REQ_DELAY_8822B) & BIT_MASK_PHY_REQ_DELAY_8822B) + +#define BIT_SPD_DOWN_8822B BIT(16) + +#define BIT_SHIFT_NETYPE4_8822B 4 +#define BIT_MASK_NETYPE4_8822B 0x3 +#define BIT_NETYPE4_8822B(x) \ + (((x) & BIT_MASK_NETYPE4_8822B) << BIT_SHIFT_NETYPE4_8822B) +#define BIT_GET_NETYPE4_8822B(x) \ + (((x) >> BIT_SHIFT_NETYPE4_8822B) & BIT_MASK_NETYPE4_8822B) + +#define BIT_SHIFT_NETYPE3_8822B 2 +#define BIT_MASK_NETYPE3_8822B 0x3 +#define BIT_NETYPE3_8822B(x) \ + (((x) & BIT_MASK_NETYPE3_8822B) << BIT_SHIFT_NETYPE3_8822B) +#define BIT_GET_NETYPE3_8822B(x) \ + (((x) >> BIT_SHIFT_NETYPE3_8822B) & BIT_MASK_NETYPE3_8822B) + +#define BIT_SHIFT_NETYPE2_8822B 0 +#define BIT_MASK_NETYPE2_8822B 0x3 +#define BIT_NETYPE2_8822B(x) \ + (((x) & BIT_MASK_NETYPE2_8822B) << BIT_SHIFT_NETYPE2_8822B) +#define BIT_GET_NETYPE2_8822B(x) \ + (((x) >> BIT_SHIFT_NETYPE2_8822B) & BIT_MASK_NETYPE2_8822B) + +/* 2 REG_FWFF_8822B */ + +#define BIT_SHIFT_PKTNUM_TH_V1_8822B 24 +#define BIT_MASK_PKTNUM_TH_V1_8822B 0xff +#define BIT_PKTNUM_TH_V1_8822B(x) \ + (((x) & BIT_MASK_PKTNUM_TH_V1_8822B) << BIT_SHIFT_PKTNUM_TH_V1_8822B) +#define BIT_GET_PKTNUM_TH_V1_8822B(x) \ + (((x) >> BIT_SHIFT_PKTNUM_TH_V1_8822B) & BIT_MASK_PKTNUM_TH_V1_8822B) + +#define BIT_SHIFT_TIMER_TH_8822B 16 +#define BIT_MASK_TIMER_TH_8822B 0xff +#define BIT_TIMER_TH_8822B(x) \ + (((x) & BIT_MASK_TIMER_TH_8822B) << BIT_SHIFT_TIMER_TH_8822B) +#define BIT_GET_TIMER_TH_8822B(x) \ + (((x) >> BIT_SHIFT_TIMER_TH_8822B) & BIT_MASK_TIMER_TH_8822B) + +#define BIT_SHIFT_RXPKT1ENADDR_8822B 0 +#define BIT_MASK_RXPKT1ENADDR_8822B 0xffff +#define BIT_RXPKT1ENADDR_8822B(x) \ + (((x) & BIT_MASK_RXPKT1ENADDR_8822B) << BIT_SHIFT_RXPKT1ENADDR_8822B) +#define BIT_GET_RXPKT1ENADDR_8822B(x) \ + (((x) >> BIT_SHIFT_RXPKT1ENADDR_8822B) & BIT_MASK_RXPKT1ENADDR_8822B) + +/* 2 REG_RXFF_PTR_V1_8822B */ + +/* 2 REG_NOT_VALID_8822B */ + +#define BIT_SHIFT_RXFF0_RDPTR_V2_8822B 0 +#define BIT_MASK_RXFF0_RDPTR_V2_8822B 0x3ffff +#define BIT_RXFF0_RDPTR_V2_8822B(x) \ + (((x) & BIT_MASK_RXFF0_RDPTR_V2_8822B) \ + << BIT_SHIFT_RXFF0_RDPTR_V2_8822B) +#define BIT_GET_RXFF0_RDPTR_V2_8822B(x) \ + (((x) >> BIT_SHIFT_RXFF0_RDPTR_V2_8822B) & \ + BIT_MASK_RXFF0_RDPTR_V2_8822B) + +/* 2 REG_RXFF_WTR_V1_8822B */ + +/* 2 REG_NOT_VALID_8822B */ + +#define BIT_SHIFT_RXFF0_WTPTR_V2_8822B 0 +#define BIT_MASK_RXFF0_WTPTR_V2_8822B 0x3ffff +#define BIT_RXFF0_WTPTR_V2_8822B(x) \ + (((x) & BIT_MASK_RXFF0_WTPTR_V2_8822B) \ + << BIT_SHIFT_RXFF0_WTPTR_V2_8822B) +#define BIT_GET_RXFF0_WTPTR_V2_8822B(x) \ + (((x) >> BIT_SHIFT_RXFF0_WTPTR_V2_8822B) & \ + BIT_MASK_RXFF0_WTPTR_V2_8822B) + +/* 2 REG_FE2IMR_8822B */ +#define BIT__FE4ISR__IND_MSK_8822B BIT(29) +#define BIT_FS_TXSC_DESC_DONE_INT_EN_8822B BIT(28) +#define BIT_FS_TXSC_BKDONE_INT_EN_8822B BIT(27) +#define BIT_FS_TXSC_BEDONE_INT_EN_8822B BIT(26) +#define BIT_FS_TXSC_VIDONE_INT_EN_8822B BIT(25) +#define BIT_FS_TXSC_VODONE_INT_EN_8822B BIT(24) +#define BIT_FS_ATIM_MB7_INT_EN_8822B BIT(23) +#define BIT_FS_ATIM_MB6_INT_EN_8822B BIT(22) +#define BIT_FS_ATIM_MB5_INT_EN_8822B BIT(21) +#define BIT_FS_ATIM_MB4_INT_EN_8822B BIT(20) +#define BIT_FS_ATIM_MB3_INT_EN_8822B BIT(19) +#define BIT_FS_ATIM_MB2_INT_EN_8822B BIT(18) +#define BIT_FS_ATIM_MB1_INT_EN_8822B BIT(17) +#define BIT_FS_ATIM_MB0_INT_EN_8822B BIT(16) +#define BIT_FS_TBTT4INT_EN_8822B BIT(11) +#define BIT_FS_TBTT3INT_EN_8822B BIT(10) +#define BIT_FS_TBTT2INT_EN_8822B BIT(9) +#define BIT_FS_TBTT1INT_EN_8822B BIT(8) +#define BIT_FS_TBTT0_MB7INT_EN_8822B BIT(7) +#define BIT_FS_TBTT0_MB6INT_EN_8822B BIT(6) +#define BIT_FS_TBTT0_MB5INT_EN_8822B BIT(5) +#define BIT_FS_TBTT0_MB4INT_EN_8822B BIT(4) +#define BIT_FS_TBTT0_MB3INT_EN_8822B BIT(3) +#define BIT_FS_TBTT0_MB2INT_EN_8822B BIT(2) +#define BIT_FS_TBTT0_MB1INT_EN_8822B BIT(1) +#define BIT_FS_TBTT0_INT_EN_8822B BIT(0) + +/* 2 REG_FE2ISR_8822B */ +#define BIT__FE4ISR__IND_INT_8822B BIT(29) +#define BIT_FS_TXSC_DESC_DONE_INT_8822B BIT(28) +#define BIT_FS_TXSC_BKDONE_INT_8822B BIT(27) +#define BIT_FS_TXSC_BEDONE_INT_8822B BIT(26) +#define BIT_FS_TXSC_VIDONE_INT_8822B BIT(25) +#define BIT_FS_TXSC_VODONE_INT_8822B BIT(24) +#define BIT_FS_ATIM_MB7_INT_8822B BIT(23) +#define BIT_FS_ATIM_MB6_INT_8822B BIT(22) +#define BIT_FS_ATIM_MB5_INT_8822B BIT(21) +#define BIT_FS_ATIM_MB4_INT_8822B BIT(20) +#define BIT_FS_ATIM_MB3_INT_8822B BIT(19) +#define BIT_FS_ATIM_MB2_INT_8822B BIT(18) +#define BIT_FS_ATIM_MB1_INT_8822B BIT(17) +#define BIT_FS_ATIM_MB0_INT_8822B BIT(16) +#define BIT_FS_TBTT4INT_8822B BIT(11) +#define BIT_FS_TBTT3INT_8822B BIT(10) +#define BIT_FS_TBTT2INT_8822B BIT(9) +#define BIT_FS_TBTT1INT_8822B BIT(8) +#define BIT_FS_TBTT0_MB7INT_8822B BIT(7) +#define BIT_FS_TBTT0_MB6INT_8822B BIT(6) +#define BIT_FS_TBTT0_MB5INT_8822B BIT(5) +#define BIT_FS_TBTT0_MB4INT_8822B BIT(4) +#define BIT_FS_TBTT0_MB3INT_8822B BIT(3) +#define BIT_FS_TBTT0_MB2INT_8822B BIT(2) +#define BIT_FS_TBTT0_MB1INT_8822B BIT(1) +#define BIT_FS_TBTT0_INT_8822B BIT(0) + +/* 2 REG_FE3IMR_8822B */ +#define BIT_FS_CLI3_MTI_BCNIVLEAR_INT__EN_8822B BIT(31) +#define BIT_FS_CLI2_MTI_BCNIVLEAR_INT__EN_8822B BIT(30) +#define BIT_FS_CLI1_MTI_BCNIVLEAR_INT__EN_8822B BIT(29) +#define BIT_FS_CLI0_MTI_BCNIVLEAR_INT__EN_8822B BIT(28) +#define BIT_FS_BCNDMA4_INT_EN_8822B BIT(27) +#define BIT_FS_BCNDMA3_INT_EN_8822B BIT(26) +#define BIT_FS_BCNDMA2_INT_EN_8822B BIT(25) +#define BIT_FS_BCNDMA1_INT_EN_8822B BIT(24) +#define BIT_FS_BCNDMA0_MB7_INT_EN_8822B BIT(23) +#define BIT_FS_BCNDMA0_MB6_INT_EN_8822B BIT(22) +#define BIT_FS_BCNDMA0_MB5_INT_EN_8822B BIT(21) +#define BIT_FS_BCNDMA0_MB4_INT_EN_8822B BIT(20) +#define BIT_FS_BCNDMA0_MB3_INT_EN_8822B BIT(19) +#define BIT_FS_BCNDMA0_MB2_INT_EN_8822B BIT(18) +#define BIT_FS_BCNDMA0_MB1_INT_EN_8822B BIT(17) +#define BIT_FS_BCNDMA0_INT_EN_8822B BIT(16) +#define BIT_FS_MTI_BCNIVLEAR_INT__EN_8822B BIT(15) +#define BIT_FS_BCNERLY4_INT_EN_8822B BIT(11) +#define BIT_FS_BCNERLY3_INT_EN_8822B BIT(10) +#define BIT_FS_BCNERLY2_INT_EN_8822B BIT(9) +#define BIT_FS_BCNERLY1_INT_EN_8822B BIT(8) +#define BIT_FS_BCNERLY0_MB7INT_EN_8822B BIT(7) +#define BIT_FS_BCNERLY0_MB6INT_EN_8822B BIT(6) +#define BIT_FS_BCNERLY0_MB5INT_EN_8822B BIT(5) +#define BIT_FS_BCNERLY0_MB4INT_EN_8822B BIT(4) +#define BIT_FS_BCNERLY0_MB3INT_EN_8822B BIT(3) +#define BIT_FS_BCNERLY0_MB2INT_EN_8822B BIT(2) +#define BIT_FS_BCNERLY0_MB1INT_EN_8822B BIT(1) +#define BIT_FS_BCNERLY0_INT_EN_8822B BIT(0) + +/* 2 REG_FE3ISR_8822B */ +#define BIT_FS_CLI3_MTI_BCNIVLEAR_INT_8822B BIT(31) +#define BIT_FS_CLI2_MTI_BCNIVLEAR_INT_8822B BIT(30) +#define BIT_FS_CLI1_MTI_BCNIVLEAR_INT_8822B BIT(29) +#define BIT_FS_CLI0_MTI_BCNIVLEAR_INT_8822B BIT(28) +#define BIT_FS_BCNDMA4_INT_8822B BIT(27) +#define BIT_FS_BCNDMA3_INT_8822B BIT(26) +#define BIT_FS_BCNDMA2_INT_8822B BIT(25) +#define BIT_FS_BCNDMA1_INT_8822B BIT(24) +#define BIT_FS_BCNDMA0_MB7_INT_8822B BIT(23) +#define BIT_FS_BCNDMA0_MB6_INT_8822B BIT(22) +#define BIT_FS_BCNDMA0_MB5_INT_8822B BIT(21) +#define BIT_FS_BCNDMA0_MB4_INT_8822B BIT(20) +#define BIT_FS_BCNDMA0_MB3_INT_8822B BIT(19) +#define BIT_FS_BCNDMA0_MB2_INT_8822B BIT(18) +#define BIT_FS_BCNDMA0_MB1_INT_8822B BIT(17) +#define BIT_FS_BCNDMA0_INT_8822B BIT(16) +#define BIT_FS_MTI_BCNIVLEAR_INT_8822B BIT(15) +#define BIT_FS_BCNERLY4_INT_8822B BIT(11) +#define BIT_FS_BCNERLY3_INT_8822B BIT(10) +#define BIT_FS_BCNERLY2_INT_8822B BIT(9) +#define BIT_FS_BCNERLY1_INT_8822B BIT(8) +#define BIT_FS_BCNERLY0_MB7INT_8822B BIT(7) +#define BIT_FS_BCNERLY0_MB6INT_8822B BIT(6) +#define BIT_FS_BCNERLY0_MB5INT_8822B BIT(5) +#define BIT_FS_BCNERLY0_MB4INT_8822B BIT(4) +#define BIT_FS_BCNERLY0_MB3INT_8822B BIT(3) +#define BIT_FS_BCNERLY0_MB2INT_8822B BIT(2) +#define BIT_FS_BCNERLY0_MB1INT_8822B BIT(1) +#define BIT_FS_BCNERLY0_INT_8822B BIT(0) + +/* 2 REG_FE4IMR_8822B */ +#define BIT_FS_CLI3_TXPKTIN_INT_EN_8822B BIT(19) +#define BIT_FS_CLI2_TXPKTIN_INT_EN_8822B BIT(18) +#define BIT_FS_CLI1_TXPKTIN_INT_EN_8822B BIT(17) +#define BIT_FS_CLI0_TXPKTIN_INT_EN_8822B BIT(16) +#define BIT_FS_CLI3_RX_UMD0_INT_EN_8822B BIT(15) +#define BIT_FS_CLI3_RX_UMD1_INT_EN_8822B BIT(14) +#define BIT_FS_CLI3_RX_BMD0_INT_EN_8822B BIT(13) +#define BIT_FS_CLI3_RX_BMD1_INT_EN_8822B BIT(12) +#define BIT_FS_CLI2_RX_UMD0_INT_EN_8822B BIT(11) +#define BIT_FS_CLI2_RX_UMD1_INT_EN_8822B BIT(10) +#define BIT_FS_CLI2_RX_BMD0_INT_EN_8822B BIT(9) +#define BIT_FS_CLI2_RX_BMD1_INT_EN_8822B BIT(8) +#define BIT_FS_CLI1_RX_UMD0_INT_EN_8822B BIT(7) +#define BIT_FS_CLI1_RX_UMD1_INT_EN_8822B BIT(6) +#define BIT_FS_CLI1_RX_BMD0_INT_EN_8822B BIT(5) +#define BIT_FS_CLI1_RX_BMD1_INT_EN_8822B BIT(4) +#define BIT_FS_CLI0_RX_UMD0_INT_EN_8822B BIT(3) +#define BIT_FS_CLI0_RX_UMD1_INT_EN_8822B BIT(2) +#define BIT_FS_CLI0_RX_BMD0_INT_EN_8822B BIT(1) +#define BIT_FS_CLI0_RX_BMD1_INT_EN_8822B BIT(0) + +/* 2 REG_FE4ISR_8822B */ +#define BIT_FS_CLI3_TXPKTIN_INT_8822B BIT(19) +#define BIT_FS_CLI2_TXPKTIN_INT_8822B BIT(18) +#define BIT_FS_CLI1_TXPKTIN_INT_8822B BIT(17) +#define BIT_FS_CLI0_TXPKTIN_INT_8822B BIT(16) +#define BIT_FS_CLI3_RX_UMD0_INT_8822B BIT(15) +#define BIT_FS_CLI3_RX_UMD1_INT_8822B BIT(14) +#define BIT_FS_CLI3_RX_BMD0_INT_8822B BIT(13) +#define BIT_FS_CLI3_RX_BMD1_INT_8822B BIT(12) +#define BIT_FS_CLI2_RX_UMD0_INT_8822B BIT(11) +#define BIT_FS_CLI2_RX_UMD1_INT_8822B BIT(10) +#define BIT_FS_CLI2_RX_BMD0_INT_8822B BIT(9) +#define BIT_FS_CLI2_RX_BMD1_INT_8822B BIT(8) +#define BIT_FS_CLI1_RX_UMD0_INT_8822B BIT(7) +#define BIT_FS_CLI1_RX_UMD1_INT_8822B BIT(6) +#define BIT_FS_CLI1_RX_BMD0_INT_8822B BIT(5) +#define BIT_FS_CLI1_RX_BMD1_INT_8822B BIT(4) +#define BIT_FS_CLI0_RX_UMD0_INT_8822B BIT(3) +#define BIT_FS_CLI0_RX_UMD1_INT_8822B BIT(2) +#define BIT_FS_CLI0_RX_BMD0_INT_8822B BIT(1) +#define BIT_FS_CLI0_RX_BMD1_INT_8822B BIT(0) + +/* 2 REG_FT1IMR_8822B */ +#define BIT__FT2ISR__IND_MSK_8822B BIT(30) +#define BIT_FTM_PTT_INT_EN_8822B BIT(29) +#define BIT_RXFTMREQ_INT_EN_8822B BIT(28) +#define BIT_RXFTM_INT_EN_8822B BIT(27) +#define BIT_TXFTM_INT_EN_8822B BIT(26) +#define BIT_FS_H2C_CMD_OK_INT_EN_8822B BIT(25) +#define BIT_FS_H2C_CMD_FULL_INT_EN_8822B BIT(24) +#define BIT_FS_MACID_PWRCHANGE5_INT_EN_8822B BIT(23) +#define BIT_FS_MACID_PWRCHANGE4_INT_EN_8822B BIT(22) +#define BIT_FS_MACID_PWRCHANGE3_INT_EN_8822B BIT(21) +#define BIT_FS_MACID_PWRCHANGE2_INT_EN_8822B BIT(20) +#define BIT_FS_MACID_PWRCHANGE1_INT_EN_8822B BIT(19) +#define BIT_FS_MACID_PWRCHANGE0_INT_EN_8822B BIT(18) +#define BIT_FS_CTWEND2_INT_EN_8822B BIT(17) +#define BIT_FS_CTWEND1_INT_EN_8822B BIT(16) +#define BIT_FS_CTWEND0_INT_EN_8822B BIT(15) +#define BIT_FS_TX_NULL1_INT_EN_8822B BIT(14) +#define BIT_FS_TX_NULL0_INT_EN_8822B BIT(13) +#define BIT_FS_TSF_BIT32_TOGGLE_EN_8822B BIT(12) +#define BIT_FS_P2P_RFON2_INT_EN_8822B BIT(11) +#define BIT_FS_P2P_RFOFF2_INT_EN_8822B BIT(10) +#define BIT_FS_P2P_RFON1_INT_EN_8822B BIT(9) +#define BIT_FS_P2P_RFOFF1_INT_EN_8822B BIT(8) +#define BIT_FS_P2P_RFON0_INT_EN_8822B BIT(7) +#define BIT_FS_P2P_RFOFF0_INT_EN_8822B BIT(6) +#define BIT_FS_RX_UAPSDMD1_EN_8822B BIT(5) +#define BIT_FS_RX_UAPSDMD0_EN_8822B BIT(4) +#define BIT_FS_TRIGGER_PKT_EN_8822B BIT(3) +#define BIT_FS_EOSP_INT_EN_8822B BIT(2) +#define BIT_FS_RPWM2_INT_EN_8822B BIT(1) +#define BIT_FS_RPWM_INT_EN_8822B BIT(0) + +/* 2 REG_FT1ISR_8822B */ +#define BIT__FT2ISR__IND_INT_8822B BIT(30) +#define BIT_FTM_PTT_INT_8822B BIT(29) +#define BIT_RXFTMREQ_INT_8822B BIT(28) +#define BIT_RXFTM_INT_8822B BIT(27) +#define BIT_TXFTM_INT_8822B BIT(26) +#define BIT_FS_H2C_CMD_OK_INT_8822B BIT(25) +#define BIT_FS_H2C_CMD_FULL_INT_8822B BIT(24) +#define BIT_FS_MACID_PWRCHANGE5_INT_8822B BIT(23) +#define BIT_FS_MACID_PWRCHANGE4_INT_8822B BIT(22) +#define BIT_FS_MACID_PWRCHANGE3_INT_8822B BIT(21) +#define BIT_FS_MACID_PWRCHANGE2_INT_8822B BIT(20) +#define BIT_FS_MACID_PWRCHANGE1_INT_8822B BIT(19) +#define BIT_FS_MACID_PWRCHANGE0_INT_8822B BIT(18) +#define BIT_FS_CTWEND2_INT_8822B BIT(17) +#define BIT_FS_CTWEND1_INT_8822B BIT(16) +#define BIT_FS_CTWEND0_INT_8822B BIT(15) +#define BIT_FS_TX_NULL1_INT_8822B BIT(14) +#define BIT_FS_TX_NULL0_INT_8822B BIT(13) +#define BIT_FS_TSF_BIT32_TOGGLE_INT_8822B BIT(12) +#define BIT_FS_P2P_RFON2_INT_8822B BIT(11) +#define BIT_FS_P2P_RFOFF2_INT_8822B BIT(10) +#define BIT_FS_P2P_RFON1_INT_8822B BIT(9) +#define BIT_FS_P2P_RFOFF1_INT_8822B BIT(8) +#define BIT_FS_P2P_RFON0_INT_8822B BIT(7) +#define BIT_FS_P2P_RFOFF0_INT_8822B BIT(6) +#define BIT_FS_RX_UAPSDMD1_INT_8822B BIT(5) +#define BIT_FS_RX_UAPSDMD0_INT_8822B BIT(4) +#define BIT_FS_TRIGGER_PKT_INT_8822B BIT(3) +#define BIT_FS_EOSP_INT_8822B BIT(2) +#define BIT_FS_RPWM2_INT_8822B BIT(1) +#define BIT_FS_RPWM_INT_8822B BIT(0) + +/* 2 REG_SPWR0_8822B */ + +#define BIT_SHIFT_MID_31TO0_8822B 0 +#define BIT_MASK_MID_31TO0_8822B 0xffffffffL +#define BIT_MID_31TO0_8822B(x) \ + (((x) & BIT_MASK_MID_31TO0_8822B) << BIT_SHIFT_MID_31TO0_8822B) +#define BIT_GET_MID_31TO0_8822B(x) \ + (((x) >> BIT_SHIFT_MID_31TO0_8822B) & BIT_MASK_MID_31TO0_8822B) + +/* 2 REG_SPWR1_8822B */ + +#define BIT_SHIFT_MID_63TO32_8822B 0 +#define BIT_MASK_MID_63TO32_8822B 0xffffffffL +#define BIT_MID_63TO32_8822B(x) \ + (((x) & BIT_MASK_MID_63TO32_8822B) << BIT_SHIFT_MID_63TO32_8822B) +#define BIT_GET_MID_63TO32_8822B(x) \ + (((x) >> BIT_SHIFT_MID_63TO32_8822B) & BIT_MASK_MID_63TO32_8822B) + +/* 2 REG_SPWR2_8822B */ + +#define BIT_SHIFT_MID_95O64_8822B 0 +#define BIT_MASK_MID_95O64_8822B 0xffffffffL +#define BIT_MID_95O64_8822B(x) \ + (((x) & BIT_MASK_MID_95O64_8822B) << BIT_SHIFT_MID_95O64_8822B) +#define BIT_GET_MID_95O64_8822B(x) \ + (((x) >> BIT_SHIFT_MID_95O64_8822B) & BIT_MASK_MID_95O64_8822B) + +/* 2 REG_SPWR3_8822B */ + +#define BIT_SHIFT_MID_127TO96_8822B 0 +#define BIT_MASK_MID_127TO96_8822B 0xffffffffL +#define BIT_MID_127TO96_8822B(x) \ + (((x) & BIT_MASK_MID_127TO96_8822B) << BIT_SHIFT_MID_127TO96_8822B) +#define BIT_GET_MID_127TO96_8822B(x) \ + (((x) >> BIT_SHIFT_MID_127TO96_8822B) & BIT_MASK_MID_127TO96_8822B) + +/* 2 REG_POWSEQ_8822B */ + +#define BIT_SHIFT_SEQNUM_MID_8822B 16 +#define BIT_MASK_SEQNUM_MID_8822B 0xffff +#define BIT_SEQNUM_MID_8822B(x) \ + (((x) & BIT_MASK_SEQNUM_MID_8822B) << BIT_SHIFT_SEQNUM_MID_8822B) +#define BIT_GET_SEQNUM_MID_8822B(x) \ + (((x) >> BIT_SHIFT_SEQNUM_MID_8822B) & BIT_MASK_SEQNUM_MID_8822B) + +#define BIT_SHIFT_REF_MID_8822B 0 +#define BIT_MASK_REF_MID_8822B 0x7f +#define BIT_REF_MID_8822B(x) \ + (((x) & BIT_MASK_REF_MID_8822B) << BIT_SHIFT_REF_MID_8822B) +#define BIT_GET_REF_MID_8822B(x) \ + (((x) >> BIT_SHIFT_REF_MID_8822B) & BIT_MASK_REF_MID_8822B) + +/* 2 REG_TC7_CTRL_V1_8822B */ +#define BIT_TC7INT_EN_8822B BIT(26) +#define BIT_TC7MODE_8822B BIT(25) +#define BIT_TC7EN_8822B BIT(24) + +#define BIT_SHIFT_TC7DATA_8822B 0 +#define BIT_MASK_TC7DATA_8822B 0xffffff +#define BIT_TC7DATA_8822B(x) \ + (((x) & BIT_MASK_TC7DATA_8822B) << BIT_SHIFT_TC7DATA_8822B) +#define BIT_GET_TC7DATA_8822B(x) \ + (((x) >> BIT_SHIFT_TC7DATA_8822B) & BIT_MASK_TC7DATA_8822B) + +/* 2 REG_TC8_CTRL_V1_8822B */ +#define BIT_TC8INT_EN_8822B BIT(26) +#define BIT_TC8MODE_8822B BIT(25) +#define BIT_TC8EN_8822B BIT(24) + +#define BIT_SHIFT_TC8DATA_8822B 0 +#define BIT_MASK_TC8DATA_8822B 0xffffff +#define BIT_TC8DATA_8822B(x) \ + (((x) & BIT_MASK_TC8DATA_8822B) << BIT_SHIFT_TC8DATA_8822B) +#define BIT_GET_TC8DATA_8822B(x) \ + (((x) >> BIT_SHIFT_TC8DATA_8822B) & BIT_MASK_TC8DATA_8822B) + +/* 2 REG_FT2IMR_8822B */ +#define BIT_FS_CLI3_RX_UAPSDMD1_EN_8822B BIT(31) +#define BIT_FS_CLI3_RX_UAPSDMD0_EN_8822B BIT(30) +#define BIT_FS_CLI3_TRIGGER_PKT_EN_8822B BIT(29) +#define BIT_FS_CLI3_EOSP_INT_EN_8822B BIT(28) +#define BIT_FS_CLI2_RX_UAPSDMD1_EN_8822B BIT(27) +#define BIT_FS_CLI2_RX_UAPSDMD0_EN_8822B BIT(26) +#define BIT_FS_CLI2_TRIGGER_PKT_EN_8822B BIT(25) +#define BIT_FS_CLI2_EOSP_INT_EN_8822B BIT(24) +#define BIT_FS_CLI1_RX_UAPSDMD1_EN_8822B BIT(23) +#define BIT_FS_CLI1_RX_UAPSDMD0_EN_8822B BIT(22) +#define BIT_FS_CLI1_TRIGGER_PKT_EN_8822B BIT(21) +#define BIT_FS_CLI1_EOSP_INT_EN_8822B BIT(20) +#define BIT_FS_CLI0_RX_UAPSDMD1_EN_8822B BIT(19) +#define BIT_FS_CLI0_RX_UAPSDMD0_EN_8822B BIT(18) +#define BIT_FS_CLI0_TRIGGER_PKT_EN_8822B BIT(17) +#define BIT_FS_CLI0_EOSP_INT_EN_8822B BIT(16) +#define BIT_FS_TSF_BIT32_TOGGLE_P2P2_EN_8822B BIT(9) +#define BIT_FS_TSF_BIT32_TOGGLE_P2P1_EN_8822B BIT(8) +#define BIT_FS_CLI3_TX_NULL1_INT_EN_8822B BIT(7) +#define BIT_FS_CLI3_TX_NULL0_INT_EN_8822B BIT(6) +#define BIT_FS_CLI2_TX_NULL1_INT_EN_8822B BIT(5) +#define BIT_FS_CLI2_TX_NULL0_INT_EN_8822B BIT(4) +#define BIT_FS_CLI1_TX_NULL1_INT_EN_8822B BIT(3) +#define BIT_FS_CLI1_TX_NULL0_INT_EN_8822B BIT(2) +#define BIT_FS_CLI0_TX_NULL1_INT_EN_8822B BIT(1) +#define BIT_FS_CLI0_TX_NULL0_INT_EN_8822B BIT(0) + +/* 2 REG_FT2ISR_8822B */ +#define BIT_FS_CLI3_RX_UAPSDMD1_INT_8822B BIT(31) +#define BIT_FS_CLI3_RX_UAPSDMD0_INT_8822B BIT(30) +#define BIT_FS_CLI3_TRIGGER_PKT_INT_8822B BIT(29) +#define BIT_FS_CLI3_EOSP_INT_8822B BIT(28) +#define BIT_FS_CLI2_RX_UAPSDMD1_INT_8822B BIT(27) +#define BIT_FS_CLI2_RX_UAPSDMD0_INT_8822B BIT(26) +#define BIT_FS_CLI2_TRIGGER_PKT_INT_8822B BIT(25) +#define BIT_FS_CLI2_EOSP_INT_8822B BIT(24) +#define BIT_FS_CLI1_RX_UAPSDMD1_INT_8822B BIT(23) +#define BIT_FS_CLI1_RX_UAPSDMD0_INT_8822B BIT(22) +#define BIT_FS_CLI1_TRIGGER_PKT_INT_8822B BIT(21) +#define BIT_FS_CLI1_EOSP_INT_8822B BIT(20) +#define BIT_FS_CLI0_RX_UAPSDMD1_INT_8822B BIT(19) +#define BIT_FS_CLI0_RX_UAPSDMD0_INT_8822B BIT(18) +#define BIT_FS_CLI0_TRIGGER_PKT_INT_8822B BIT(17) +#define BIT_FS_CLI0_EOSP_INT_8822B BIT(16) +#define BIT_FS_TSF_BIT32_TOGGLE_P2P2_INT_8822B BIT(9) +#define BIT_FS_TSF_BIT32_TOGGLE_P2P1_INT_8822B BIT(8) +#define BIT_FS_CLI3_TX_NULL1_INT_8822B BIT(7) +#define BIT_FS_CLI3_TX_NULL0_INT_8822B BIT(6) +#define BIT_FS_CLI2_TX_NULL1_INT_8822B BIT(5) +#define BIT_FS_CLI2_TX_NULL0_INT_8822B BIT(4) +#define BIT_FS_CLI1_TX_NULL1_INT_8822B BIT(3) +#define BIT_FS_CLI1_TX_NULL0_INT_8822B BIT(2) +#define BIT_FS_CLI0_TX_NULL1_INT_8822B BIT(1) +#define BIT_FS_CLI0_TX_NULL0_INT_8822B BIT(0) + +/* 2 REG_MSG2_8822B */ + +#define BIT_SHIFT_FW_MSG2_8822B 0 +#define BIT_MASK_FW_MSG2_8822B 0xffffffffL +#define BIT_FW_MSG2_8822B(x) \ + (((x) & BIT_MASK_FW_MSG2_8822B) << BIT_SHIFT_FW_MSG2_8822B) +#define BIT_GET_FW_MSG2_8822B(x) \ + (((x) >> BIT_SHIFT_FW_MSG2_8822B) & BIT_MASK_FW_MSG2_8822B) + +/* 2 REG_MSG3_8822B */ + +#define BIT_SHIFT_FW_MSG3_8822B 0 +#define BIT_MASK_FW_MSG3_8822B 0xffffffffL +#define BIT_FW_MSG3_8822B(x) \ + (((x) & BIT_MASK_FW_MSG3_8822B) << BIT_SHIFT_FW_MSG3_8822B) +#define BIT_GET_FW_MSG3_8822B(x) \ + (((x) >> BIT_SHIFT_FW_MSG3_8822B) & BIT_MASK_FW_MSG3_8822B) + +/* 2 REG_MSG4_8822B */ + +#define BIT_SHIFT_FW_MSG4_8822B 0 +#define BIT_MASK_FW_MSG4_8822B 0xffffffffL +#define BIT_FW_MSG4_8822B(x) \ + (((x) & BIT_MASK_FW_MSG4_8822B) << BIT_SHIFT_FW_MSG4_8822B) +#define BIT_GET_FW_MSG4_8822B(x) \ + (((x) >> BIT_SHIFT_FW_MSG4_8822B) & BIT_MASK_FW_MSG4_8822B) + +/* 2 REG_MSG5_8822B */ + +#define BIT_SHIFT_FW_MSG5_8822B 0 +#define BIT_MASK_FW_MSG5_8822B 0xffffffffL +#define BIT_FW_MSG5_8822B(x) \ + (((x) & BIT_MASK_FW_MSG5_8822B) << BIT_SHIFT_FW_MSG5_8822B) +#define BIT_GET_FW_MSG5_8822B(x) \ + (((x) >> BIT_SHIFT_FW_MSG5_8822B) & BIT_MASK_FW_MSG5_8822B) + +/* 2 REG_NOT_VALID_8822B */ + +/* 2 REG_FIFOPAGE_CTRL_1_8822B */ + +#define BIT_SHIFT_TX_OQT_HE_FREE_SPACE_V1_8822B 16 +#define BIT_MASK_TX_OQT_HE_FREE_SPACE_V1_8822B 0xff +#define BIT_TX_OQT_HE_FREE_SPACE_V1_8822B(x) \ + (((x) & BIT_MASK_TX_OQT_HE_FREE_SPACE_V1_8822B) \ + << BIT_SHIFT_TX_OQT_HE_FREE_SPACE_V1_8822B) +#define BIT_GET_TX_OQT_HE_FREE_SPACE_V1_8822B(x) \ + (((x) >> BIT_SHIFT_TX_OQT_HE_FREE_SPACE_V1_8822B) & \ + BIT_MASK_TX_OQT_HE_FREE_SPACE_V1_8822B) + +#define BIT_SHIFT_TX_OQT_NL_FREE_SPACE_V1_8822B 0 +#define BIT_MASK_TX_OQT_NL_FREE_SPACE_V1_8822B 0xff +#define BIT_TX_OQT_NL_FREE_SPACE_V1_8822B(x) \ + (((x) & BIT_MASK_TX_OQT_NL_FREE_SPACE_V1_8822B) \ + << BIT_SHIFT_TX_OQT_NL_FREE_SPACE_V1_8822B) +#define BIT_GET_TX_OQT_NL_FREE_SPACE_V1_8822B(x) \ + (((x) >> BIT_SHIFT_TX_OQT_NL_FREE_SPACE_V1_8822B) & \ + BIT_MASK_TX_OQT_NL_FREE_SPACE_V1_8822B) + +/* 2 REG_FIFOPAGE_CTRL_2_8822B */ +#define BIT_BCN_VALID_1_V1_8822B BIT(31) + +#define BIT_SHIFT_BCN_HEAD_1_V1_8822B 16 +#define BIT_MASK_BCN_HEAD_1_V1_8822B 0xfff +#define BIT_BCN_HEAD_1_V1_8822B(x) \ + (((x) & BIT_MASK_BCN_HEAD_1_V1_8822B) << BIT_SHIFT_BCN_HEAD_1_V1_8822B) +#define BIT_GET_BCN_HEAD_1_V1_8822B(x) \ + (((x) >> BIT_SHIFT_BCN_HEAD_1_V1_8822B) & BIT_MASK_BCN_HEAD_1_V1_8822B) + +#define BIT_BCN_VALID_V1_8822B BIT(15) + +#define BIT_SHIFT_BCN_HEAD_V1_8822B 0 +#define BIT_MASK_BCN_HEAD_V1_8822B 0xfff +#define BIT_BCN_HEAD_V1_8822B(x) \ + (((x) & BIT_MASK_BCN_HEAD_V1_8822B) << BIT_SHIFT_BCN_HEAD_V1_8822B) +#define BIT_GET_BCN_HEAD_V1_8822B(x) \ + (((x) >> BIT_SHIFT_BCN_HEAD_V1_8822B) & BIT_MASK_BCN_HEAD_V1_8822B) + +/* 2 REG_AUTO_LLT_V1_8822B */ + +#define BIT_SHIFT_MAX_TX_PKT_FOR_USB_AND_SDIO_V1_8822B 24 +#define BIT_MASK_MAX_TX_PKT_FOR_USB_AND_SDIO_V1_8822B 0xff +#define BIT_MAX_TX_PKT_FOR_USB_AND_SDIO_V1_8822B(x) \ + (((x) & BIT_MASK_MAX_TX_PKT_FOR_USB_AND_SDIO_V1_8822B) \ + << BIT_SHIFT_MAX_TX_PKT_FOR_USB_AND_SDIO_V1_8822B) +#define BIT_GET_MAX_TX_PKT_FOR_USB_AND_SDIO_V1_8822B(x) \ + (((x) >> BIT_SHIFT_MAX_TX_PKT_FOR_USB_AND_SDIO_V1_8822B) & \ + BIT_MASK_MAX_TX_PKT_FOR_USB_AND_SDIO_V1_8822B) + +#define BIT_SHIFT_LLT_FREE_PAGE_V1_8822B 8 +#define BIT_MASK_LLT_FREE_PAGE_V1_8822B 0xffff +#define BIT_LLT_FREE_PAGE_V1_8822B(x) \ + (((x) & BIT_MASK_LLT_FREE_PAGE_V1_8822B) \ + << BIT_SHIFT_LLT_FREE_PAGE_V1_8822B) +#define BIT_GET_LLT_FREE_PAGE_V1_8822B(x) \ + (((x) >> BIT_SHIFT_LLT_FREE_PAGE_V1_8822B) & \ + BIT_MASK_LLT_FREE_PAGE_V1_8822B) + +#define BIT_SHIFT_BLK_DESC_NUM_8822B 4 +#define BIT_MASK_BLK_DESC_NUM_8822B 0xf +#define BIT_BLK_DESC_NUM_8822B(x) \ + (((x) & BIT_MASK_BLK_DESC_NUM_8822B) << BIT_SHIFT_BLK_DESC_NUM_8822B) +#define BIT_GET_BLK_DESC_NUM_8822B(x) \ + (((x) >> BIT_SHIFT_BLK_DESC_NUM_8822B) & BIT_MASK_BLK_DESC_NUM_8822B) + +#define BIT_R_BCN_HEAD_SEL_8822B BIT(3) +#define BIT_R_EN_BCN_SW_HEAD_SEL_8822B BIT(2) +#define BIT_LLT_DBG_SEL_8822B BIT(1) +#define BIT_AUTO_INIT_LLT_V1_8822B BIT(0) + +/* 2 REG_TXDMA_OFFSET_CHK_8822B */ +#define BIT_EM_CHKSUM_FIN_8822B BIT(31) +#define BIT_EMN_PCIE_DMA_MOD_8822B BIT(30) +#define BIT_EN_TXQUE_CLR_8822B BIT(29) +#define BIT_EN_PCIE_FIFO_MODE_8822B BIT(28) + +#define BIT_SHIFT_PG_UNDER_TH_V1_8822B 16 +#define BIT_MASK_PG_UNDER_TH_V1_8822B 0xfff +#define BIT_PG_UNDER_TH_V1_8822B(x) \ + (((x) & BIT_MASK_PG_UNDER_TH_V1_8822B) \ + << BIT_SHIFT_PG_UNDER_TH_V1_8822B) +#define BIT_GET_PG_UNDER_TH_V1_8822B(x) \ + (((x) >> BIT_SHIFT_PG_UNDER_TH_V1_8822B) & \ + BIT_MASK_PG_UNDER_TH_V1_8822B) + +#define BIT_RESTORE_H2C_ADDRESS_8822B BIT(15) +#define BIT_SDIO_TXDESC_CHKSUM_EN_8822B BIT(13) +#define BIT_RST_RDPTR_8822B BIT(12) +#define BIT_RST_WRPTR_8822B BIT(11) +#define BIT_CHK_PG_TH_EN_8822B BIT(10) +#define BIT_DROP_DATA_EN_8822B BIT(9) +#define BIT_CHECK_OFFSET_EN_8822B BIT(8) + +#define BIT_SHIFT_CHECK_OFFSET_8822B 0 +#define BIT_MASK_CHECK_OFFSET_8822B 0xff +#define BIT_CHECK_OFFSET_8822B(x) \ + (((x) & BIT_MASK_CHECK_OFFSET_8822B) << BIT_SHIFT_CHECK_OFFSET_8822B) +#define BIT_GET_CHECK_OFFSET_8822B(x) \ + (((x) >> BIT_SHIFT_CHECK_OFFSET_8822B) & BIT_MASK_CHECK_OFFSET_8822B) + +/* 2 REG_TXDMA_STATUS_8822B */ +#define BIT_HI_OQT_UDN_8822B BIT(17) +#define BIT_HI_OQT_OVF_8822B BIT(16) +#define BIT_PAYLOAD_CHKSUM_ERR_8822B BIT(15) +#define BIT_PAYLOAD_UDN_8822B BIT(14) +#define BIT_PAYLOAD_OVF_8822B BIT(13) +#define BIT_DSC_CHKSUM_FAIL_8822B BIT(12) +#define BIT_UNKNOWN_QSEL_8822B BIT(11) +#define BIT_EP_QSEL_DIFF_8822B BIT(10) +#define BIT_TX_OFFS_UNMATCH_8822B BIT(9) +#define BIT_TXOQT_UDN_8822B BIT(8) +#define BIT_TXOQT_OVF_8822B BIT(7) +#define BIT_TXDMA_SFF_UDN_8822B BIT(6) +#define BIT_TXDMA_SFF_OVF_8822B BIT(5) +#define BIT_LLT_NULL_PG_8822B BIT(4) +#define BIT_PAGE_UDN_8822B BIT(3) +#define BIT_PAGE_OVF_8822B BIT(2) +#define BIT_TXFF_PG_UDN_8822B BIT(1) +#define BIT_TXFF_PG_OVF_8822B BIT(0) + +/* 2 REG_TX_DMA_DBG_8822B */ + +/* 2 REG_TQPNT1_8822B */ + +#define BIT_SHIFT_HPQ_HIGH_TH_V1_8822B 16 +#define BIT_MASK_HPQ_HIGH_TH_V1_8822B 0xfff +#define BIT_HPQ_HIGH_TH_V1_8822B(x) \ + (((x) & BIT_MASK_HPQ_HIGH_TH_V1_8822B) \ + << BIT_SHIFT_HPQ_HIGH_TH_V1_8822B) +#define BIT_GET_HPQ_HIGH_TH_V1_8822B(x) \ + (((x) >> BIT_SHIFT_HPQ_HIGH_TH_V1_8822B) & \ + BIT_MASK_HPQ_HIGH_TH_V1_8822B) + +#define BIT_SHIFT_HPQ_LOW_TH_V1_8822B 0 +#define BIT_MASK_HPQ_LOW_TH_V1_8822B 0xfff +#define BIT_HPQ_LOW_TH_V1_8822B(x) \ + (((x) & BIT_MASK_HPQ_LOW_TH_V1_8822B) << BIT_SHIFT_HPQ_LOW_TH_V1_8822B) +#define BIT_GET_HPQ_LOW_TH_V1_8822B(x) \ + (((x) >> BIT_SHIFT_HPQ_LOW_TH_V1_8822B) & BIT_MASK_HPQ_LOW_TH_V1_8822B) + +/* 2 REG_TQPNT2_8822B */ + +#define BIT_SHIFT_NPQ_HIGH_TH_V1_8822B 16 +#define BIT_MASK_NPQ_HIGH_TH_V1_8822B 0xfff +#define BIT_NPQ_HIGH_TH_V1_8822B(x) \ + (((x) & BIT_MASK_NPQ_HIGH_TH_V1_8822B) \ + << BIT_SHIFT_NPQ_HIGH_TH_V1_8822B) +#define BIT_GET_NPQ_HIGH_TH_V1_8822B(x) \ + (((x) >> BIT_SHIFT_NPQ_HIGH_TH_V1_8822B) & \ + BIT_MASK_NPQ_HIGH_TH_V1_8822B) + +#define BIT_SHIFT_NPQ_LOW_TH_V1_8822B 0 +#define BIT_MASK_NPQ_LOW_TH_V1_8822B 0xfff +#define BIT_NPQ_LOW_TH_V1_8822B(x) \ + (((x) & BIT_MASK_NPQ_LOW_TH_V1_8822B) << BIT_SHIFT_NPQ_LOW_TH_V1_8822B) +#define BIT_GET_NPQ_LOW_TH_V1_8822B(x) \ + (((x) >> BIT_SHIFT_NPQ_LOW_TH_V1_8822B) & BIT_MASK_NPQ_LOW_TH_V1_8822B) + +/* 2 REG_TQPNT3_8822B */ + +#define BIT_SHIFT_LPQ_HIGH_TH_V1_8822B 16 +#define BIT_MASK_LPQ_HIGH_TH_V1_8822B 0xfff +#define BIT_LPQ_HIGH_TH_V1_8822B(x) \ + (((x) & BIT_MASK_LPQ_HIGH_TH_V1_8822B) \ + << BIT_SHIFT_LPQ_HIGH_TH_V1_8822B) +#define BIT_GET_LPQ_HIGH_TH_V1_8822B(x) \ + (((x) >> BIT_SHIFT_LPQ_HIGH_TH_V1_8822B) & \ + BIT_MASK_LPQ_HIGH_TH_V1_8822B) + +#define BIT_SHIFT_LPQ_LOW_TH_V1_8822B 0 +#define BIT_MASK_LPQ_LOW_TH_V1_8822B 0xfff +#define BIT_LPQ_LOW_TH_V1_8822B(x) \ + (((x) & BIT_MASK_LPQ_LOW_TH_V1_8822B) << BIT_SHIFT_LPQ_LOW_TH_V1_8822B) +#define BIT_GET_LPQ_LOW_TH_V1_8822B(x) \ + (((x) >> BIT_SHIFT_LPQ_LOW_TH_V1_8822B) & BIT_MASK_LPQ_LOW_TH_V1_8822B) + +/* 2 REG_TQPNT4_8822B */ + +#define BIT_SHIFT_EXQ_HIGH_TH_V1_8822B 16 +#define BIT_MASK_EXQ_HIGH_TH_V1_8822B 0xfff +#define BIT_EXQ_HIGH_TH_V1_8822B(x) \ + (((x) & BIT_MASK_EXQ_HIGH_TH_V1_8822B) \ + << BIT_SHIFT_EXQ_HIGH_TH_V1_8822B) +#define BIT_GET_EXQ_HIGH_TH_V1_8822B(x) \ + (((x) >> BIT_SHIFT_EXQ_HIGH_TH_V1_8822B) & \ + BIT_MASK_EXQ_HIGH_TH_V1_8822B) + +#define BIT_SHIFT_EXQ_LOW_TH_V1_8822B 0 +#define BIT_MASK_EXQ_LOW_TH_V1_8822B 0xfff +#define BIT_EXQ_LOW_TH_V1_8822B(x) \ + (((x) & BIT_MASK_EXQ_LOW_TH_V1_8822B) << BIT_SHIFT_EXQ_LOW_TH_V1_8822B) +#define BIT_GET_EXQ_LOW_TH_V1_8822B(x) \ + (((x) >> BIT_SHIFT_EXQ_LOW_TH_V1_8822B) & BIT_MASK_EXQ_LOW_TH_V1_8822B) + +/* 2 REG_RQPN_CTRL_1_8822B */ + +#define BIT_SHIFT_TXPKTNUM_H_8822B 16 +#define BIT_MASK_TXPKTNUM_H_8822B 0xffff +#define BIT_TXPKTNUM_H_8822B(x) \ + (((x) & BIT_MASK_TXPKTNUM_H_8822B) << BIT_SHIFT_TXPKTNUM_H_8822B) +#define BIT_GET_TXPKTNUM_H_8822B(x) \ + (((x) >> BIT_SHIFT_TXPKTNUM_H_8822B) & BIT_MASK_TXPKTNUM_H_8822B) + +#define BIT_SHIFT_TXPKTNUM_V2_8822B 0 +#define BIT_MASK_TXPKTNUM_V2_8822B 0xffff +#define BIT_TXPKTNUM_V2_8822B(x) \ + (((x) & BIT_MASK_TXPKTNUM_V2_8822B) << BIT_SHIFT_TXPKTNUM_V2_8822B) +#define BIT_GET_TXPKTNUM_V2_8822B(x) \ + (((x) >> BIT_SHIFT_TXPKTNUM_V2_8822B) & BIT_MASK_TXPKTNUM_V2_8822B) + +/* 2 REG_RQPN_CTRL_2_8822B */ +#define BIT_LD_RQPN_8822B BIT(31) +#define BIT_EXQ_PUBLIC_DIS_V1_8822B BIT(19) +#define BIT_NPQ_PUBLIC_DIS_V1_8822B BIT(18) +#define BIT_LPQ_PUBLIC_DIS_V1_8822B BIT(17) +#define BIT_HPQ_PUBLIC_DIS_V1_8822B BIT(16) + +/* 2 REG_FIFOPAGE_INFO_1_8822B */ + +#define BIT_SHIFT_HPQ_AVAL_PG_V1_8822B 16 +#define BIT_MASK_HPQ_AVAL_PG_V1_8822B 0xfff +#define BIT_HPQ_AVAL_PG_V1_8822B(x) \ + (((x) & BIT_MASK_HPQ_AVAL_PG_V1_8822B) \ + << BIT_SHIFT_HPQ_AVAL_PG_V1_8822B) +#define BIT_GET_HPQ_AVAL_PG_V1_8822B(x) \ + (((x) >> BIT_SHIFT_HPQ_AVAL_PG_V1_8822B) & \ + BIT_MASK_HPQ_AVAL_PG_V1_8822B) + +#define BIT_SHIFT_HPQ_V1_8822B 0 +#define BIT_MASK_HPQ_V1_8822B 0xfff +#define BIT_HPQ_V1_8822B(x) \ + (((x) & BIT_MASK_HPQ_V1_8822B) << BIT_SHIFT_HPQ_V1_8822B) +#define BIT_GET_HPQ_V1_8822B(x) \ + (((x) >> BIT_SHIFT_HPQ_V1_8822B) & BIT_MASK_HPQ_V1_8822B) + +/* 2 REG_FIFOPAGE_INFO_2_8822B */ + +#define BIT_SHIFT_LPQ_AVAL_PG_V1_8822B 16 +#define BIT_MASK_LPQ_AVAL_PG_V1_8822B 0xfff +#define BIT_LPQ_AVAL_PG_V1_8822B(x) \ + (((x) & BIT_MASK_LPQ_AVAL_PG_V1_8822B) \ + << BIT_SHIFT_LPQ_AVAL_PG_V1_8822B) +#define BIT_GET_LPQ_AVAL_PG_V1_8822B(x) \ + (((x) >> BIT_SHIFT_LPQ_AVAL_PG_V1_8822B) & \ + BIT_MASK_LPQ_AVAL_PG_V1_8822B) + +#define BIT_SHIFT_LPQ_V1_8822B 0 +#define BIT_MASK_LPQ_V1_8822B 0xfff +#define BIT_LPQ_V1_8822B(x) \ + (((x) & BIT_MASK_LPQ_V1_8822B) << BIT_SHIFT_LPQ_V1_8822B) +#define BIT_GET_LPQ_V1_8822B(x) \ + (((x) >> BIT_SHIFT_LPQ_V1_8822B) & BIT_MASK_LPQ_V1_8822B) + +/* 2 REG_FIFOPAGE_INFO_3_8822B */ + +#define BIT_SHIFT_NPQ_AVAL_PG_V1_8822B 16 +#define BIT_MASK_NPQ_AVAL_PG_V1_8822B 0xfff +#define BIT_NPQ_AVAL_PG_V1_8822B(x) \ + (((x) & BIT_MASK_NPQ_AVAL_PG_V1_8822B) \ + << BIT_SHIFT_NPQ_AVAL_PG_V1_8822B) +#define BIT_GET_NPQ_AVAL_PG_V1_8822B(x) \ + (((x) >> BIT_SHIFT_NPQ_AVAL_PG_V1_8822B) & \ + BIT_MASK_NPQ_AVAL_PG_V1_8822B) + +#define BIT_SHIFT_NPQ_V1_8822B 0 +#define BIT_MASK_NPQ_V1_8822B 0xfff +#define BIT_NPQ_V1_8822B(x) \ + (((x) & BIT_MASK_NPQ_V1_8822B) << BIT_SHIFT_NPQ_V1_8822B) +#define BIT_GET_NPQ_V1_8822B(x) \ + (((x) >> BIT_SHIFT_NPQ_V1_8822B) & BIT_MASK_NPQ_V1_8822B) + +/* 2 REG_FIFOPAGE_INFO_4_8822B */ + +#define BIT_SHIFT_EXQ_AVAL_PG_V1_8822B 16 +#define BIT_MASK_EXQ_AVAL_PG_V1_8822B 0xfff +#define BIT_EXQ_AVAL_PG_V1_8822B(x) \ + (((x) & BIT_MASK_EXQ_AVAL_PG_V1_8822B) \ + << BIT_SHIFT_EXQ_AVAL_PG_V1_8822B) +#define BIT_GET_EXQ_AVAL_PG_V1_8822B(x) \ + (((x) >> BIT_SHIFT_EXQ_AVAL_PG_V1_8822B) & \ + BIT_MASK_EXQ_AVAL_PG_V1_8822B) + +#define BIT_SHIFT_EXQ_V1_8822B 0 +#define BIT_MASK_EXQ_V1_8822B 0xfff +#define BIT_EXQ_V1_8822B(x) \ + (((x) & BIT_MASK_EXQ_V1_8822B) << BIT_SHIFT_EXQ_V1_8822B) +#define BIT_GET_EXQ_V1_8822B(x) \ + (((x) >> BIT_SHIFT_EXQ_V1_8822B) & BIT_MASK_EXQ_V1_8822B) + +/* 2 REG_FIFOPAGE_INFO_5_8822B */ + +#define BIT_SHIFT_PUBQ_AVAL_PG_V1_8822B 16 +#define BIT_MASK_PUBQ_AVAL_PG_V1_8822B 0xfff +#define BIT_PUBQ_AVAL_PG_V1_8822B(x) \ + (((x) & BIT_MASK_PUBQ_AVAL_PG_V1_8822B) \ + << BIT_SHIFT_PUBQ_AVAL_PG_V1_8822B) +#define BIT_GET_PUBQ_AVAL_PG_V1_8822B(x) \ + (((x) >> BIT_SHIFT_PUBQ_AVAL_PG_V1_8822B) & \ + BIT_MASK_PUBQ_AVAL_PG_V1_8822B) + +#define BIT_SHIFT_PUBQ_V1_8822B 0 +#define BIT_MASK_PUBQ_V1_8822B 0xfff +#define BIT_PUBQ_V1_8822B(x) \ + (((x) & BIT_MASK_PUBQ_V1_8822B) << BIT_SHIFT_PUBQ_V1_8822B) +#define BIT_GET_PUBQ_V1_8822B(x) \ + (((x) >> BIT_SHIFT_PUBQ_V1_8822B) & BIT_MASK_PUBQ_V1_8822B) + +/* 2 REG_H2C_HEAD_8822B */ + +#define BIT_SHIFT_H2C_HEAD_8822B 0 +#define BIT_MASK_H2C_HEAD_8822B 0x3ffff +#define BIT_H2C_HEAD_8822B(x) \ + (((x) & BIT_MASK_H2C_HEAD_8822B) << BIT_SHIFT_H2C_HEAD_8822B) +#define BIT_GET_H2C_HEAD_8822B(x) \ + (((x) >> BIT_SHIFT_H2C_HEAD_8822B) & BIT_MASK_H2C_HEAD_8822B) + +/* 2 REG_H2C_TAIL_8822B */ + +#define BIT_SHIFT_H2C_TAIL_8822B 0 +#define BIT_MASK_H2C_TAIL_8822B 0x3ffff +#define BIT_H2C_TAIL_8822B(x) \ + (((x) & BIT_MASK_H2C_TAIL_8822B) << BIT_SHIFT_H2C_TAIL_8822B) +#define BIT_GET_H2C_TAIL_8822B(x) \ + (((x) >> BIT_SHIFT_H2C_TAIL_8822B) & BIT_MASK_H2C_TAIL_8822B) + +/* 2 REG_H2C_READ_ADDR_8822B */ + +#define BIT_SHIFT_H2C_READ_ADDR_8822B 0 +#define BIT_MASK_H2C_READ_ADDR_8822B 0x3ffff +#define BIT_H2C_READ_ADDR_8822B(x) \ + (((x) & BIT_MASK_H2C_READ_ADDR_8822B) << BIT_SHIFT_H2C_READ_ADDR_8822B) +#define BIT_GET_H2C_READ_ADDR_8822B(x) \ + (((x) >> BIT_SHIFT_H2C_READ_ADDR_8822B) & BIT_MASK_H2C_READ_ADDR_8822B) + +/* 2 REG_H2C_WR_ADDR_8822B */ + +#define BIT_SHIFT_H2C_WR_ADDR_8822B 0 +#define BIT_MASK_H2C_WR_ADDR_8822B 0x3ffff +#define BIT_H2C_WR_ADDR_8822B(x) \ + (((x) & BIT_MASK_H2C_WR_ADDR_8822B) << BIT_SHIFT_H2C_WR_ADDR_8822B) +#define BIT_GET_H2C_WR_ADDR_8822B(x) \ + (((x) >> BIT_SHIFT_H2C_WR_ADDR_8822B) & BIT_MASK_H2C_WR_ADDR_8822B) + +/* 2 REG_H2C_INFO_8822B */ +#define BIT_H2C_SPACE_VLD_8822B BIT(3) +#define BIT_H2C_WR_ADDR_RST_8822B BIT(2) + +#define BIT_SHIFT_H2C_LEN_SEL_8822B 0 +#define BIT_MASK_H2C_LEN_SEL_8822B 0x3 +#define BIT_H2C_LEN_SEL_8822B(x) \ + (((x) & BIT_MASK_H2C_LEN_SEL_8822B) << BIT_SHIFT_H2C_LEN_SEL_8822B) +#define BIT_GET_H2C_LEN_SEL_8822B(x) \ + (((x) >> BIT_SHIFT_H2C_LEN_SEL_8822B) & BIT_MASK_H2C_LEN_SEL_8822B) + +/* 2 REG_RXDMA_AGG_PG_TH_8822B */ + +#define BIT_SHIFT_RXDMA_AGG_OLD_MOD_8822B 24 +#define BIT_MASK_RXDMA_AGG_OLD_MOD_8822B 0xff +#define BIT_RXDMA_AGG_OLD_MOD_8822B(x) \ + (((x) & BIT_MASK_RXDMA_AGG_OLD_MOD_8822B) \ + << BIT_SHIFT_RXDMA_AGG_OLD_MOD_8822B) +#define BIT_GET_RXDMA_AGG_OLD_MOD_8822B(x) \ + (((x) >> BIT_SHIFT_RXDMA_AGG_OLD_MOD_8822B) & \ + BIT_MASK_RXDMA_AGG_OLD_MOD_8822B) + +#define BIT_SHIFT_PKT_NUM_WOL_8822B 16 +#define BIT_MASK_PKT_NUM_WOL_8822B 0xff +#define BIT_PKT_NUM_WOL_8822B(x) \ + (((x) & BIT_MASK_PKT_NUM_WOL_8822B) << BIT_SHIFT_PKT_NUM_WOL_8822B) +#define BIT_GET_PKT_NUM_WOL_8822B(x) \ + (((x) >> BIT_SHIFT_PKT_NUM_WOL_8822B) & BIT_MASK_PKT_NUM_WOL_8822B) + +#define BIT_SHIFT_DMA_AGG_TO_8822B 8 +#define BIT_MASK_DMA_AGG_TO_8822B 0xf +#define BIT_DMA_AGG_TO_8822B(x) \ + (((x) & BIT_MASK_DMA_AGG_TO_8822B) << BIT_SHIFT_DMA_AGG_TO_8822B) +#define BIT_GET_DMA_AGG_TO_8822B(x) \ + (((x) >> BIT_SHIFT_DMA_AGG_TO_8822B) & BIT_MASK_DMA_AGG_TO_8822B) + +#define BIT_SHIFT_RXDMA_AGG_PG_TH_V1_8822B 0 +#define BIT_MASK_RXDMA_AGG_PG_TH_V1_8822B 0xf +#define BIT_RXDMA_AGG_PG_TH_V1_8822B(x) \ + (((x) & BIT_MASK_RXDMA_AGG_PG_TH_V1_8822B) \ + << BIT_SHIFT_RXDMA_AGG_PG_TH_V1_8822B) +#define BIT_GET_RXDMA_AGG_PG_TH_V1_8822B(x) \ + (((x) >> BIT_SHIFT_RXDMA_AGG_PG_TH_V1_8822B) & \ + BIT_MASK_RXDMA_AGG_PG_TH_V1_8822B) + +/* 2 REG_RXPKT_NUM_8822B */ + +#define BIT_SHIFT_RXPKT_NUM_8822B 24 +#define BIT_MASK_RXPKT_NUM_8822B 0xff +#define BIT_RXPKT_NUM_8822B(x) \ + (((x) & BIT_MASK_RXPKT_NUM_8822B) << BIT_SHIFT_RXPKT_NUM_8822B) +#define BIT_GET_RXPKT_NUM_8822B(x) \ + (((x) >> BIT_SHIFT_RXPKT_NUM_8822B) & BIT_MASK_RXPKT_NUM_8822B) + +#define BIT_SHIFT_FW_UPD_RDPTR19_TO_16_8822B 20 +#define BIT_MASK_FW_UPD_RDPTR19_TO_16_8822B 0xf +#define BIT_FW_UPD_RDPTR19_TO_16_8822B(x) \ + (((x) & BIT_MASK_FW_UPD_RDPTR19_TO_16_8822B) \ + << BIT_SHIFT_FW_UPD_RDPTR19_TO_16_8822B) +#define BIT_GET_FW_UPD_RDPTR19_TO_16_8822B(x) \ + (((x) >> BIT_SHIFT_FW_UPD_RDPTR19_TO_16_8822B) & \ + BIT_MASK_FW_UPD_RDPTR19_TO_16_8822B) + +#define BIT_RXDMA_REQ_8822B BIT(19) +#define BIT_RW_RELEASE_EN_8822B BIT(18) +#define BIT_RXDMA_IDLE_8822B BIT(17) +#define BIT_RXPKT_RELEASE_POLL_8822B BIT(16) + +#define BIT_SHIFT_FW_UPD_RDPTR_8822B 0 +#define BIT_MASK_FW_UPD_RDPTR_8822B 0xffff +#define BIT_FW_UPD_RDPTR_8822B(x) \ + (((x) & BIT_MASK_FW_UPD_RDPTR_8822B) << BIT_SHIFT_FW_UPD_RDPTR_8822B) +#define BIT_GET_FW_UPD_RDPTR_8822B(x) \ + (((x) >> BIT_SHIFT_FW_UPD_RDPTR_8822B) & BIT_MASK_FW_UPD_RDPTR_8822B) + +/* 2 REG_RXDMA_STATUS_8822B */ +#define BIT_C2H_PKT_OVF_8822B BIT(7) +#define BIT_AGG_CONFGI_ISSUE_8822B BIT(6) +#define BIT_FW_POLL_ISSUE_8822B BIT(5) +#define BIT_RX_DATA_UDN_8822B BIT(4) +#define BIT_RX_SFF_UDN_8822B BIT(3) +#define BIT_RX_SFF_OVF_8822B BIT(2) +#define BIT_RXPKT_OVF_8822B BIT(0) + +/* 2 REG_RXDMA_DPR_8822B */ + +#define BIT_SHIFT_RDE_DEBUG_8822B 0 +#define BIT_MASK_RDE_DEBUG_8822B 0xffffffffL +#define BIT_RDE_DEBUG_8822B(x) \ + (((x) & BIT_MASK_RDE_DEBUG_8822B) << BIT_SHIFT_RDE_DEBUG_8822B) +#define BIT_GET_RDE_DEBUG_8822B(x) \ + (((x) >> BIT_SHIFT_RDE_DEBUG_8822B) & BIT_MASK_RDE_DEBUG_8822B) + +/* 2 REG_RXDMA_MODE_8822B */ + +#define BIT_SHIFT_PKTNUM_TH_V2_8822B 24 +#define BIT_MASK_PKTNUM_TH_V2_8822B 0x1f +#define BIT_PKTNUM_TH_V2_8822B(x) \ + (((x) & BIT_MASK_PKTNUM_TH_V2_8822B) << BIT_SHIFT_PKTNUM_TH_V2_8822B) +#define BIT_GET_PKTNUM_TH_V2_8822B(x) \ + (((x) >> BIT_SHIFT_PKTNUM_TH_V2_8822B) & BIT_MASK_PKTNUM_TH_V2_8822B) + +#define BIT_TXBA_BREAK_USBAGG_8822B BIT(23) + +#define BIT_SHIFT_PKTLEN_PARA_8822B 16 +#define BIT_MASK_PKTLEN_PARA_8822B 0x7 +#define BIT_PKTLEN_PARA_8822B(x) \ + (((x) & BIT_MASK_PKTLEN_PARA_8822B) << BIT_SHIFT_PKTLEN_PARA_8822B) +#define BIT_GET_PKTLEN_PARA_8822B(x) \ + (((x) >> BIT_SHIFT_PKTLEN_PARA_8822B) & BIT_MASK_PKTLEN_PARA_8822B) + +/* 2 REG_NOT_VALID_8822B */ + +/* 2 REG_NOT_VALID_8822B */ + +/* 2 REG_NOT_VALID_8822B */ + +#define BIT_SHIFT_BURST_SIZE_8822B 4 +#define BIT_MASK_BURST_SIZE_8822B 0x3 +#define BIT_BURST_SIZE_8822B(x) \ + (((x) & BIT_MASK_BURST_SIZE_8822B) << BIT_SHIFT_BURST_SIZE_8822B) +#define BIT_GET_BURST_SIZE_8822B(x) \ + (((x) >> BIT_SHIFT_BURST_SIZE_8822B) & BIT_MASK_BURST_SIZE_8822B) + +#define BIT_SHIFT_BURST_CNT_8822B 2 +#define BIT_MASK_BURST_CNT_8822B 0x3 +#define BIT_BURST_CNT_8822B(x) \ + (((x) & BIT_MASK_BURST_CNT_8822B) << BIT_SHIFT_BURST_CNT_8822B) +#define BIT_GET_BURST_CNT_8822B(x) \ + (((x) >> BIT_SHIFT_BURST_CNT_8822B) & BIT_MASK_BURST_CNT_8822B) + +#define BIT_DMA_MODE_8822B BIT(1) + +/* 2 REG_C2H_PKT_8822B */ + +#define BIT_SHIFT_R_C2H_STR_ADDR_16_TO_19_8822B 24 +#define BIT_MASK_R_C2H_STR_ADDR_16_TO_19_8822B 0xf +#define BIT_R_C2H_STR_ADDR_16_TO_19_8822B(x) \ + (((x) & BIT_MASK_R_C2H_STR_ADDR_16_TO_19_8822B) \ + << BIT_SHIFT_R_C2H_STR_ADDR_16_TO_19_8822B) +#define BIT_GET_R_C2H_STR_ADDR_16_TO_19_8822B(x) \ + (((x) >> BIT_SHIFT_R_C2H_STR_ADDR_16_TO_19_8822B) & \ + BIT_MASK_R_C2H_STR_ADDR_16_TO_19_8822B) + +#define BIT_R_C2H_PKT_REQ_8822B BIT(16) + +#define BIT_SHIFT_R_C2H_STR_ADDR_8822B 0 +#define BIT_MASK_R_C2H_STR_ADDR_8822B 0xffff +#define BIT_R_C2H_STR_ADDR_8822B(x) \ + (((x) & BIT_MASK_R_C2H_STR_ADDR_8822B) \ + << BIT_SHIFT_R_C2H_STR_ADDR_8822B) +#define BIT_GET_R_C2H_STR_ADDR_8822B(x) \ + (((x) >> BIT_SHIFT_R_C2H_STR_ADDR_8822B) & \ + BIT_MASK_R_C2H_STR_ADDR_8822B) + +/* 2 REG_FWFF_C2H_8822B */ + +#define BIT_SHIFT_C2H_DMA_ADDR_8822B 0 +#define BIT_MASK_C2H_DMA_ADDR_8822B 0x3ffff +#define BIT_C2H_DMA_ADDR_8822B(x) \ + (((x) & BIT_MASK_C2H_DMA_ADDR_8822B) << BIT_SHIFT_C2H_DMA_ADDR_8822B) +#define BIT_GET_C2H_DMA_ADDR_8822B(x) \ + (((x) >> BIT_SHIFT_C2H_DMA_ADDR_8822B) & BIT_MASK_C2H_DMA_ADDR_8822B) + +/* 2 REG_FWFF_CTRL_8822B */ +#define BIT_FWFF_DMAPKT_REQ_8822B BIT(31) + +#define BIT_SHIFT_FWFF_DMA_PKT_NUM_8822B 16 +#define BIT_MASK_FWFF_DMA_PKT_NUM_8822B 0xff +#define BIT_FWFF_DMA_PKT_NUM_8822B(x) \ + (((x) & BIT_MASK_FWFF_DMA_PKT_NUM_8822B) \ + << BIT_SHIFT_FWFF_DMA_PKT_NUM_8822B) +#define BIT_GET_FWFF_DMA_PKT_NUM_8822B(x) \ + (((x) >> BIT_SHIFT_FWFF_DMA_PKT_NUM_8822B) & \ + BIT_MASK_FWFF_DMA_PKT_NUM_8822B) + +#define BIT_SHIFT_FWFF_STR_ADDR_8822B 0 +#define BIT_MASK_FWFF_STR_ADDR_8822B 0xffff +#define BIT_FWFF_STR_ADDR_8822B(x) \ + (((x) & BIT_MASK_FWFF_STR_ADDR_8822B) << BIT_SHIFT_FWFF_STR_ADDR_8822B) +#define BIT_GET_FWFF_STR_ADDR_8822B(x) \ + (((x) >> BIT_SHIFT_FWFF_STR_ADDR_8822B) & BIT_MASK_FWFF_STR_ADDR_8822B) + +/* 2 REG_FWFF_PKT_INFO_8822B */ + +#define BIT_SHIFT_FWFF_PKT_QUEUED_8822B 16 +#define BIT_MASK_FWFF_PKT_QUEUED_8822B 0xff +#define BIT_FWFF_PKT_QUEUED_8822B(x) \ + (((x) & BIT_MASK_FWFF_PKT_QUEUED_8822B) \ + << BIT_SHIFT_FWFF_PKT_QUEUED_8822B) +#define BIT_GET_FWFF_PKT_QUEUED_8822B(x) \ + (((x) >> BIT_SHIFT_FWFF_PKT_QUEUED_8822B) & \ + BIT_MASK_FWFF_PKT_QUEUED_8822B) + +#define BIT_SHIFT_FWFF_PKT_STR_ADDR_8822B 0 +#define BIT_MASK_FWFF_PKT_STR_ADDR_8822B 0xffff +#define BIT_FWFF_PKT_STR_ADDR_8822B(x) \ + (((x) & BIT_MASK_FWFF_PKT_STR_ADDR_8822B) \ + << BIT_SHIFT_FWFF_PKT_STR_ADDR_8822B) +#define BIT_GET_FWFF_PKT_STR_ADDR_8822B(x) \ + (((x) >> BIT_SHIFT_FWFF_PKT_STR_ADDR_8822B) & \ + BIT_MASK_FWFF_PKT_STR_ADDR_8822B) + +/* 2 REG_NOT_VALID_8822B */ + +/* 2 REG_DDMA_CH0SA_8822B */ + +#define BIT_SHIFT_DDMACH0_SA_8822B 0 +#define BIT_MASK_DDMACH0_SA_8822B 0xffffffffL +#define BIT_DDMACH0_SA_8822B(x) \ + (((x) & BIT_MASK_DDMACH0_SA_8822B) << BIT_SHIFT_DDMACH0_SA_8822B) +#define BIT_GET_DDMACH0_SA_8822B(x) \ + (((x) >> BIT_SHIFT_DDMACH0_SA_8822B) & BIT_MASK_DDMACH0_SA_8822B) + +/* 2 REG_DDMA_CH0DA_8822B */ + +#define BIT_SHIFT_DDMACH0_DA_8822B 0 +#define BIT_MASK_DDMACH0_DA_8822B 0xffffffffL +#define BIT_DDMACH0_DA_8822B(x) \ + (((x) & BIT_MASK_DDMACH0_DA_8822B) << BIT_SHIFT_DDMACH0_DA_8822B) +#define BIT_GET_DDMACH0_DA_8822B(x) \ + (((x) >> BIT_SHIFT_DDMACH0_DA_8822B) & BIT_MASK_DDMACH0_DA_8822B) + +/* 2 REG_DDMA_CH0CTRL_8822B */ +#define BIT_DDMACH0_OWN_8822B BIT(31) +#define BIT_DDMACH0_CHKSUM_EN_8822B BIT(29) +#define BIT_DDMACH0_DA_W_DISABLE_8822B BIT(28) +#define BIT_DDMACH0_CHKSUM_STS_8822B BIT(27) +#define BIT_DDMACH0_DDMA_MODE_8822B BIT(26) +#define BIT_DDMACH0_RESET_CHKSUM_STS_8822B BIT(25) +#define BIT_DDMACH0_CHKSUM_CONT_8822B BIT(24) + +#define BIT_SHIFT_DDMACH0_DLEN_8822B 0 +#define BIT_MASK_DDMACH0_DLEN_8822B 0x3ffff +#define BIT_DDMACH0_DLEN_8822B(x) \ + (((x) & BIT_MASK_DDMACH0_DLEN_8822B) << BIT_SHIFT_DDMACH0_DLEN_8822B) +#define BIT_GET_DDMACH0_DLEN_8822B(x) \ + (((x) >> BIT_SHIFT_DDMACH0_DLEN_8822B) & BIT_MASK_DDMACH0_DLEN_8822B) + +/* 2 REG_DDMA_CH1SA_8822B */ + +#define BIT_SHIFT_DDMACH1_SA_8822B 0 +#define BIT_MASK_DDMACH1_SA_8822B 0xffffffffL +#define BIT_DDMACH1_SA_8822B(x) \ + (((x) & BIT_MASK_DDMACH1_SA_8822B) << BIT_SHIFT_DDMACH1_SA_8822B) +#define BIT_GET_DDMACH1_SA_8822B(x) \ + (((x) >> BIT_SHIFT_DDMACH1_SA_8822B) & BIT_MASK_DDMACH1_SA_8822B) + +/* 2 REG_DDMA_CH1DA_8822B */ + +#define BIT_SHIFT_DDMACH1_DA_8822B 0 +#define BIT_MASK_DDMACH1_DA_8822B 0xffffffffL +#define BIT_DDMACH1_DA_8822B(x) \ + (((x) & BIT_MASK_DDMACH1_DA_8822B) << BIT_SHIFT_DDMACH1_DA_8822B) +#define BIT_GET_DDMACH1_DA_8822B(x) \ + (((x) >> BIT_SHIFT_DDMACH1_DA_8822B) & BIT_MASK_DDMACH1_DA_8822B) + +/* 2 REG_DDMA_CH1CTRL_8822B */ +#define BIT_DDMACH1_OWN_8822B BIT(31) +#define BIT_DDMACH1_CHKSUM_EN_8822B BIT(29) +#define BIT_DDMACH1_DA_W_DISABLE_8822B BIT(28) +#define BIT_DDMACH1_CHKSUM_STS_8822B BIT(27) +#define BIT_DDMACH1_DDMA_MODE_8822B BIT(26) +#define BIT_DDMACH1_RESET_CHKSUM_STS_8822B BIT(25) +#define BIT_DDMACH1_CHKSUM_CONT_8822B BIT(24) + +#define BIT_SHIFT_DDMACH1_DLEN_8822B 0 +#define BIT_MASK_DDMACH1_DLEN_8822B 0x3ffff +#define BIT_DDMACH1_DLEN_8822B(x) \ + (((x) & BIT_MASK_DDMACH1_DLEN_8822B) << BIT_SHIFT_DDMACH1_DLEN_8822B) +#define BIT_GET_DDMACH1_DLEN_8822B(x) \ + (((x) >> BIT_SHIFT_DDMACH1_DLEN_8822B) & BIT_MASK_DDMACH1_DLEN_8822B) + +/* 2 REG_DDMA_CH2SA_8822B */ + +#define BIT_SHIFT_DDMACH2_SA_8822B 0 +#define BIT_MASK_DDMACH2_SA_8822B 0xffffffffL +#define BIT_DDMACH2_SA_8822B(x) \ + (((x) & BIT_MASK_DDMACH2_SA_8822B) << BIT_SHIFT_DDMACH2_SA_8822B) +#define BIT_GET_DDMACH2_SA_8822B(x) \ + (((x) >> BIT_SHIFT_DDMACH2_SA_8822B) & BIT_MASK_DDMACH2_SA_8822B) + +/* 2 REG_DDMA_CH2DA_8822B */ + +#define BIT_SHIFT_DDMACH2_DA_8822B 0 +#define BIT_MASK_DDMACH2_DA_8822B 0xffffffffL +#define BIT_DDMACH2_DA_8822B(x) \ + (((x) & BIT_MASK_DDMACH2_DA_8822B) << BIT_SHIFT_DDMACH2_DA_8822B) +#define BIT_GET_DDMACH2_DA_8822B(x) \ + (((x) >> BIT_SHIFT_DDMACH2_DA_8822B) & BIT_MASK_DDMACH2_DA_8822B) + +/* 2 REG_DDMA_CH2CTRL_8822B */ +#define BIT_DDMACH2_OWN_8822B BIT(31) +#define BIT_DDMACH2_CHKSUM_EN_8822B BIT(29) +#define BIT_DDMACH2_DA_W_DISABLE_8822B BIT(28) +#define BIT_DDMACH2_CHKSUM_STS_8822B BIT(27) +#define BIT_DDMACH2_DDMA_MODE_8822B BIT(26) +#define BIT_DDMACH2_RESET_CHKSUM_STS_8822B BIT(25) +#define BIT_DDMACH2_CHKSUM_CONT_8822B BIT(24) + +#define BIT_SHIFT_DDMACH2_DLEN_8822B 0 +#define BIT_MASK_DDMACH2_DLEN_8822B 0x3ffff +#define BIT_DDMACH2_DLEN_8822B(x) \ + (((x) & BIT_MASK_DDMACH2_DLEN_8822B) << BIT_SHIFT_DDMACH2_DLEN_8822B) +#define BIT_GET_DDMACH2_DLEN_8822B(x) \ + (((x) >> BIT_SHIFT_DDMACH2_DLEN_8822B) & BIT_MASK_DDMACH2_DLEN_8822B) + +/* 2 REG_DDMA_CH3SA_8822B */ + +#define BIT_SHIFT_DDMACH3_SA_8822B 0 +#define BIT_MASK_DDMACH3_SA_8822B 0xffffffffL +#define BIT_DDMACH3_SA_8822B(x) \ + (((x) & BIT_MASK_DDMACH3_SA_8822B) << BIT_SHIFT_DDMACH3_SA_8822B) +#define BIT_GET_DDMACH3_SA_8822B(x) \ + (((x) >> BIT_SHIFT_DDMACH3_SA_8822B) & BIT_MASK_DDMACH3_SA_8822B) + +/* 2 REG_DDMA_CH3DA_8822B */ + +#define BIT_SHIFT_DDMACH3_DA_8822B 0 +#define BIT_MASK_DDMACH3_DA_8822B 0xffffffffL +#define BIT_DDMACH3_DA_8822B(x) \ + (((x) & BIT_MASK_DDMACH3_DA_8822B) << BIT_SHIFT_DDMACH3_DA_8822B) +#define BIT_GET_DDMACH3_DA_8822B(x) \ + (((x) >> BIT_SHIFT_DDMACH3_DA_8822B) & BIT_MASK_DDMACH3_DA_8822B) + +/* 2 REG_DDMA_CH3CTRL_8822B */ +#define BIT_DDMACH3_OWN_8822B BIT(31) +#define BIT_DDMACH3_CHKSUM_EN_8822B BIT(29) +#define BIT_DDMACH3_DA_W_DISABLE_8822B BIT(28) +#define BIT_DDMACH3_CHKSUM_STS_8822B BIT(27) +#define BIT_DDMACH3_DDMA_MODE_8822B BIT(26) +#define BIT_DDMACH3_RESET_CHKSUM_STS_8822B BIT(25) +#define BIT_DDMACH3_CHKSUM_CONT_8822B BIT(24) + +#define BIT_SHIFT_DDMACH3_DLEN_8822B 0 +#define BIT_MASK_DDMACH3_DLEN_8822B 0x3ffff +#define BIT_DDMACH3_DLEN_8822B(x) \ + (((x) & BIT_MASK_DDMACH3_DLEN_8822B) << BIT_SHIFT_DDMACH3_DLEN_8822B) +#define BIT_GET_DDMACH3_DLEN_8822B(x) \ + (((x) >> BIT_SHIFT_DDMACH3_DLEN_8822B) & BIT_MASK_DDMACH3_DLEN_8822B) + +/* 2 REG_DDMA_CH4SA_8822B */ + +#define BIT_SHIFT_DDMACH4_SA_8822B 0 +#define BIT_MASK_DDMACH4_SA_8822B 0xffffffffL +#define BIT_DDMACH4_SA_8822B(x) \ + (((x) & BIT_MASK_DDMACH4_SA_8822B) << BIT_SHIFT_DDMACH4_SA_8822B) +#define BIT_GET_DDMACH4_SA_8822B(x) \ + (((x) >> BIT_SHIFT_DDMACH4_SA_8822B) & BIT_MASK_DDMACH4_SA_8822B) + +/* 2 REG_DDMA_CH4DA_8822B */ + +#define BIT_SHIFT_DDMACH4_DA_8822B 0 +#define BIT_MASK_DDMACH4_DA_8822B 0xffffffffL +#define BIT_DDMACH4_DA_8822B(x) \ + (((x) & BIT_MASK_DDMACH4_DA_8822B) << BIT_SHIFT_DDMACH4_DA_8822B) +#define BIT_GET_DDMACH4_DA_8822B(x) \ + (((x) >> BIT_SHIFT_DDMACH4_DA_8822B) & BIT_MASK_DDMACH4_DA_8822B) + +/* 2 REG_DDMA_CH4CTRL_8822B */ +#define BIT_DDMACH4_OWN_8822B BIT(31) +#define BIT_DDMACH4_CHKSUM_EN_8822B BIT(29) +#define BIT_DDMACH4_DA_W_DISABLE_8822B BIT(28) +#define BIT_DDMACH4_CHKSUM_STS_8822B BIT(27) +#define BIT_DDMACH4_DDMA_MODE_8822B BIT(26) +#define BIT_DDMACH4_RESET_CHKSUM_STS_8822B BIT(25) +#define BIT_DDMACH4_CHKSUM_CONT_8822B BIT(24) + +#define BIT_SHIFT_DDMACH4_DLEN_8822B 0 +#define BIT_MASK_DDMACH4_DLEN_8822B 0x3ffff +#define BIT_DDMACH4_DLEN_8822B(x) \ + (((x) & BIT_MASK_DDMACH4_DLEN_8822B) << BIT_SHIFT_DDMACH4_DLEN_8822B) +#define BIT_GET_DDMACH4_DLEN_8822B(x) \ + (((x) >> BIT_SHIFT_DDMACH4_DLEN_8822B) & BIT_MASK_DDMACH4_DLEN_8822B) + +/* 2 REG_DDMA_CH5SA_8822B */ + +#define BIT_SHIFT_DDMACH5_SA_8822B 0 +#define BIT_MASK_DDMACH5_SA_8822B 0xffffffffL +#define BIT_DDMACH5_SA_8822B(x) \ + (((x) & BIT_MASK_DDMACH5_SA_8822B) << BIT_SHIFT_DDMACH5_SA_8822B) +#define BIT_GET_DDMACH5_SA_8822B(x) \ + (((x) >> BIT_SHIFT_DDMACH5_SA_8822B) & BIT_MASK_DDMACH5_SA_8822B) + +/* 2 REG_DDMA_CH5DA_8822B */ + +#define BIT_SHIFT_DDMACH5_DA_8822B 0 +#define BIT_MASK_DDMACH5_DA_8822B 0xffffffffL +#define BIT_DDMACH5_DA_8822B(x) \ + (((x) & BIT_MASK_DDMACH5_DA_8822B) << BIT_SHIFT_DDMACH5_DA_8822B) +#define BIT_GET_DDMACH5_DA_8822B(x) \ + (((x) >> BIT_SHIFT_DDMACH5_DA_8822B) & BIT_MASK_DDMACH5_DA_8822B) + +/* 2 REG_REG_DDMA_CH5CTRL_8822B */ +#define BIT_DDMACH5_OWN_8822B BIT(31) +#define BIT_DDMACH5_CHKSUM_EN_8822B BIT(29) +#define BIT_DDMACH5_DA_W_DISABLE_8822B BIT(28) +#define BIT_DDMACH5_CHKSUM_STS_8822B BIT(27) +#define BIT_DDMACH5_DDMA_MODE_8822B BIT(26) +#define BIT_DDMACH5_RESET_CHKSUM_STS_8822B BIT(25) +#define BIT_DDMACH5_CHKSUM_CONT_8822B BIT(24) + +#define BIT_SHIFT_DDMACH5_DLEN_8822B 0 +#define BIT_MASK_DDMACH5_DLEN_8822B 0x3ffff +#define BIT_DDMACH5_DLEN_8822B(x) \ + (((x) & BIT_MASK_DDMACH5_DLEN_8822B) << BIT_SHIFT_DDMACH5_DLEN_8822B) +#define BIT_GET_DDMACH5_DLEN_8822B(x) \ + (((x) >> BIT_SHIFT_DDMACH5_DLEN_8822B) & BIT_MASK_DDMACH5_DLEN_8822B) + +/* 2 REG_DDMA_INT_MSK_8822B */ +#define BIT_DDMACH5_MSK_8822B BIT(5) +#define BIT_DDMACH4_MSK_8822B BIT(4) +#define BIT_DDMACH3_MSK_8822B BIT(3) +#define BIT_DDMACH2_MSK_8822B BIT(2) +#define BIT_DDMACH1_MSK_8822B BIT(1) +#define BIT_DDMACH0_MSK_8822B BIT(0) + +/* 2 REG_DDMA_CHSTATUS_8822B */ +#define BIT_DDMACH5_BUSY_8822B BIT(5) +#define BIT_DDMACH4_BUSY_8822B BIT(4) +#define BIT_DDMACH3_BUSY_8822B BIT(3) +#define BIT_DDMACH2_BUSY_8822B BIT(2) +#define BIT_DDMACH1_BUSY_8822B BIT(1) +#define BIT_DDMACH0_BUSY_8822B BIT(0) + +/* 2 REG_DDMA_CHKSUM_8822B */ + +#define BIT_SHIFT_IDDMA0_CHKSUM_8822B 0 +#define BIT_MASK_IDDMA0_CHKSUM_8822B 0xffff +#define BIT_IDDMA0_CHKSUM_8822B(x) \ + (((x) & BIT_MASK_IDDMA0_CHKSUM_8822B) << BIT_SHIFT_IDDMA0_CHKSUM_8822B) +#define BIT_GET_IDDMA0_CHKSUM_8822B(x) \ + (((x) >> BIT_SHIFT_IDDMA0_CHKSUM_8822B) & BIT_MASK_IDDMA0_CHKSUM_8822B) + +/* 2 REG_DDMA_MONITOR_8822B */ +#define BIT_IDDMA0_PERMU_UNDERFLOW_8822B BIT(14) +#define BIT_IDDMA0_FIFO_UNDERFLOW_8822B BIT(13) +#define BIT_IDDMA0_FIFO_OVERFLOW_8822B BIT(12) +#define BIT_CH5_ERR_8822B BIT(5) +#define BIT_CH4_ERR_8822B BIT(4) +#define BIT_CH3_ERR_8822B BIT(3) +#define BIT_CH2_ERR_8822B BIT(2) +#define BIT_CH1_ERR_8822B BIT(1) +#define BIT_CH0_ERR_8822B BIT(0) + +/* 2 REG_NOT_VALID_8822B */ + +/* 2 REG_PCIE_CTRL_8822B */ +#define BIT_PCIEIO_PERSTB_SEL_8822B BIT(31) + +#define BIT_SHIFT_PCIE_MAX_RXDMA_8822B 28 +#define BIT_MASK_PCIE_MAX_RXDMA_8822B 0x7 +#define BIT_PCIE_MAX_RXDMA_8822B(x) \ + (((x) & BIT_MASK_PCIE_MAX_RXDMA_8822B) \ + << BIT_SHIFT_PCIE_MAX_RXDMA_8822B) +#define BIT_GET_PCIE_MAX_RXDMA_8822B(x) \ + (((x) >> BIT_SHIFT_PCIE_MAX_RXDMA_8822B) & \ + BIT_MASK_PCIE_MAX_RXDMA_8822B) + +#define BIT_MULRW_8822B BIT(27) + +#define BIT_SHIFT_PCIE_MAX_TXDMA_8822B 24 +#define BIT_MASK_PCIE_MAX_TXDMA_8822B 0x7 +#define BIT_PCIE_MAX_TXDMA_8822B(x) \ + (((x) & BIT_MASK_PCIE_MAX_TXDMA_8822B) \ + << BIT_SHIFT_PCIE_MAX_TXDMA_8822B) +#define BIT_GET_PCIE_MAX_TXDMA_8822B(x) \ + (((x) >> BIT_SHIFT_PCIE_MAX_TXDMA_8822B) & \ + BIT_MASK_PCIE_MAX_TXDMA_8822B) + +#define BIT_EN_CPL_TIMEOUT_PS_8822B BIT(22) +#define BIT_REG_TXDMA_FAIL_PS_8822B BIT(21) +#define BIT_PCIE_RST_TRXDMA_INTF_8822B BIT(20) +#define BIT_EN_HWENTR_L1_8822B BIT(19) +#define BIT_EN_ADV_CLKGATE_8822B BIT(18) +#define BIT_PCIE_EN_SWENT_L23_8822B BIT(17) +#define BIT_PCIE_EN_HWEXT_L1_8822B BIT(16) +#define BIT_RX_CLOSE_EN_8822B BIT(15) +#define BIT_STOP_BCNQ_8822B BIT(14) +#define BIT_STOP_MGQ_8822B BIT(13) +#define BIT_STOP_VOQ_8822B BIT(12) +#define BIT_STOP_VIQ_8822B BIT(11) +#define BIT_STOP_BEQ_8822B BIT(10) +#define BIT_STOP_BKQ_8822B BIT(9) +#define BIT_STOP_RXQ_8822B BIT(8) +#define BIT_STOP_HI7Q_8822B BIT(7) +#define BIT_STOP_HI6Q_8822B BIT(6) +#define BIT_STOP_HI5Q_8822B BIT(5) +#define BIT_STOP_HI4Q_8822B BIT(4) +#define BIT_STOP_HI3Q_8822B BIT(3) +#define BIT_STOP_HI2Q_8822B BIT(2) +#define BIT_STOP_HI1Q_8822B BIT(1) +#define BIT_STOP_HI0Q_8822B BIT(0) + +/* 2 REG_INT_MIG_8822B */ + +#define BIT_SHIFT_TXTTIMER_MATCH_NUM_8822B 28 +#define BIT_MASK_TXTTIMER_MATCH_NUM_8822B 0xf +#define BIT_TXTTIMER_MATCH_NUM_8822B(x) \ + (((x) & BIT_MASK_TXTTIMER_MATCH_NUM_8822B) \ + << BIT_SHIFT_TXTTIMER_MATCH_NUM_8822B) +#define BIT_GET_TXTTIMER_MATCH_NUM_8822B(x) \ + (((x) >> BIT_SHIFT_TXTTIMER_MATCH_NUM_8822B) & \ + BIT_MASK_TXTTIMER_MATCH_NUM_8822B) + +#define BIT_SHIFT_TXPKT_NUM_MATCH_8822B 24 +#define BIT_MASK_TXPKT_NUM_MATCH_8822B 0xf +#define BIT_TXPKT_NUM_MATCH_8822B(x) \ + (((x) & BIT_MASK_TXPKT_NUM_MATCH_8822B) \ + << BIT_SHIFT_TXPKT_NUM_MATCH_8822B) +#define BIT_GET_TXPKT_NUM_MATCH_8822B(x) \ + (((x) >> BIT_SHIFT_TXPKT_NUM_MATCH_8822B) & \ + BIT_MASK_TXPKT_NUM_MATCH_8822B) + +#define BIT_SHIFT_RXTTIMER_MATCH_NUM_8822B 20 +#define BIT_MASK_RXTTIMER_MATCH_NUM_8822B 0xf +#define BIT_RXTTIMER_MATCH_NUM_8822B(x) \ + (((x) & BIT_MASK_RXTTIMER_MATCH_NUM_8822B) \ + << BIT_SHIFT_RXTTIMER_MATCH_NUM_8822B) +#define BIT_GET_RXTTIMER_MATCH_NUM_8822B(x) \ + (((x) >> BIT_SHIFT_RXTTIMER_MATCH_NUM_8822B) & \ + BIT_MASK_RXTTIMER_MATCH_NUM_8822B) + +#define BIT_SHIFT_RXPKT_NUM_MATCH_8822B 16 +#define BIT_MASK_RXPKT_NUM_MATCH_8822B 0xf +#define BIT_RXPKT_NUM_MATCH_8822B(x) \ + (((x) & BIT_MASK_RXPKT_NUM_MATCH_8822B) \ + << BIT_SHIFT_RXPKT_NUM_MATCH_8822B) +#define BIT_GET_RXPKT_NUM_MATCH_8822B(x) \ + (((x) >> BIT_SHIFT_RXPKT_NUM_MATCH_8822B) & \ + BIT_MASK_RXPKT_NUM_MATCH_8822B) + +#define BIT_SHIFT_MIGRATE_TIMER_8822B 0 +#define BIT_MASK_MIGRATE_TIMER_8822B 0xffff +#define BIT_MIGRATE_TIMER_8822B(x) \ + (((x) & BIT_MASK_MIGRATE_TIMER_8822B) << BIT_SHIFT_MIGRATE_TIMER_8822B) +#define BIT_GET_MIGRATE_TIMER_8822B(x) \ + (((x) >> BIT_SHIFT_MIGRATE_TIMER_8822B) & BIT_MASK_MIGRATE_TIMER_8822B) + +/* 2 REG_BCNQ_TXBD_DESA_8822B */ + +#define BIT_SHIFT_BCNQ_TXBD_DESA_8822B 0 +#define BIT_MASK_BCNQ_TXBD_DESA_8822B 0xffffffffffffffffL +#define BIT_BCNQ_TXBD_DESA_8822B(x) \ + (((x) & BIT_MASK_BCNQ_TXBD_DESA_8822B) \ + << BIT_SHIFT_BCNQ_TXBD_DESA_8822B) +#define BIT_GET_BCNQ_TXBD_DESA_8822B(x) \ + (((x) >> BIT_SHIFT_BCNQ_TXBD_DESA_8822B) & \ + BIT_MASK_BCNQ_TXBD_DESA_8822B) + +/* 2 REG_MGQ_TXBD_DESA_8822B */ + +#define BIT_SHIFT_MGQ_TXBD_DESA_8822B 0 +#define BIT_MASK_MGQ_TXBD_DESA_8822B 0xffffffffffffffffL +#define BIT_MGQ_TXBD_DESA_8822B(x) \ + (((x) & BIT_MASK_MGQ_TXBD_DESA_8822B) << BIT_SHIFT_MGQ_TXBD_DESA_8822B) +#define BIT_GET_MGQ_TXBD_DESA_8822B(x) \ + (((x) >> BIT_SHIFT_MGQ_TXBD_DESA_8822B) & BIT_MASK_MGQ_TXBD_DESA_8822B) + +/* 2 REG_VOQ_TXBD_DESA_8822B */ + +#define BIT_SHIFT_VOQ_TXBD_DESA_8822B 0 +#define BIT_MASK_VOQ_TXBD_DESA_8822B 0xffffffffffffffffL +#define BIT_VOQ_TXBD_DESA_8822B(x) \ + (((x) & BIT_MASK_VOQ_TXBD_DESA_8822B) << BIT_SHIFT_VOQ_TXBD_DESA_8822B) +#define BIT_GET_VOQ_TXBD_DESA_8822B(x) \ + (((x) >> BIT_SHIFT_VOQ_TXBD_DESA_8822B) & BIT_MASK_VOQ_TXBD_DESA_8822B) + +/* 2 REG_VIQ_TXBD_DESA_8822B */ + +#define BIT_SHIFT_VIQ_TXBD_DESA_8822B 0 +#define BIT_MASK_VIQ_TXBD_DESA_8822B 0xffffffffffffffffL +#define BIT_VIQ_TXBD_DESA_8822B(x) \ + (((x) & BIT_MASK_VIQ_TXBD_DESA_8822B) << BIT_SHIFT_VIQ_TXBD_DESA_8822B) +#define BIT_GET_VIQ_TXBD_DESA_8822B(x) \ + (((x) >> BIT_SHIFT_VIQ_TXBD_DESA_8822B) & BIT_MASK_VIQ_TXBD_DESA_8822B) + +/* 2 REG_BEQ_TXBD_DESA_8822B */ + +#define BIT_SHIFT_BEQ_TXBD_DESA_8822B 0 +#define BIT_MASK_BEQ_TXBD_DESA_8822B 0xffffffffffffffffL +#define BIT_BEQ_TXBD_DESA_8822B(x) \ + (((x) & BIT_MASK_BEQ_TXBD_DESA_8822B) << BIT_SHIFT_BEQ_TXBD_DESA_8822B) +#define BIT_GET_BEQ_TXBD_DESA_8822B(x) \ + (((x) >> BIT_SHIFT_BEQ_TXBD_DESA_8822B) & BIT_MASK_BEQ_TXBD_DESA_8822B) + +/* 2 REG_BKQ_TXBD_DESA_8822B */ + +#define BIT_SHIFT_BKQ_TXBD_DESA_8822B 0 +#define BIT_MASK_BKQ_TXBD_DESA_8822B 0xffffffffffffffffL +#define BIT_BKQ_TXBD_DESA_8822B(x) \ + (((x) & BIT_MASK_BKQ_TXBD_DESA_8822B) << BIT_SHIFT_BKQ_TXBD_DESA_8822B) +#define BIT_GET_BKQ_TXBD_DESA_8822B(x) \ + (((x) >> BIT_SHIFT_BKQ_TXBD_DESA_8822B) & BIT_MASK_BKQ_TXBD_DESA_8822B) + +/* 2 REG_RXQ_RXBD_DESA_8822B */ + +#define BIT_SHIFT_RXQ_RXBD_DESA_8822B 0 +#define BIT_MASK_RXQ_RXBD_DESA_8822B 0xffffffffffffffffL +#define BIT_RXQ_RXBD_DESA_8822B(x) \ + (((x) & BIT_MASK_RXQ_RXBD_DESA_8822B) << BIT_SHIFT_RXQ_RXBD_DESA_8822B) +#define BIT_GET_RXQ_RXBD_DESA_8822B(x) \ + (((x) >> BIT_SHIFT_RXQ_RXBD_DESA_8822B) & BIT_MASK_RXQ_RXBD_DESA_8822B) + +/* 2 REG_HI0Q_TXBD_DESA_8822B */ + +#define BIT_SHIFT_HI0Q_TXBD_DESA_8822B 0 +#define BIT_MASK_HI0Q_TXBD_DESA_8822B 0xffffffffffffffffL +#define BIT_HI0Q_TXBD_DESA_8822B(x) \ + (((x) & BIT_MASK_HI0Q_TXBD_DESA_8822B) \ + << BIT_SHIFT_HI0Q_TXBD_DESA_8822B) +#define BIT_GET_HI0Q_TXBD_DESA_8822B(x) \ + (((x) >> BIT_SHIFT_HI0Q_TXBD_DESA_8822B) & \ + BIT_MASK_HI0Q_TXBD_DESA_8822B) + +/* 2 REG_HI1Q_TXBD_DESA_8822B */ + +#define BIT_SHIFT_HI1Q_TXBD_DESA_8822B 0 +#define BIT_MASK_HI1Q_TXBD_DESA_8822B 0xffffffffffffffffL +#define BIT_HI1Q_TXBD_DESA_8822B(x) \ + (((x) & BIT_MASK_HI1Q_TXBD_DESA_8822B) \ + << BIT_SHIFT_HI1Q_TXBD_DESA_8822B) +#define BIT_GET_HI1Q_TXBD_DESA_8822B(x) \ + (((x) >> BIT_SHIFT_HI1Q_TXBD_DESA_8822B) & \ + BIT_MASK_HI1Q_TXBD_DESA_8822B) + +/* 2 REG_HI2Q_TXBD_DESA_8822B */ + +#define BIT_SHIFT_HI2Q_TXBD_DESA_8822B 0 +#define BIT_MASK_HI2Q_TXBD_DESA_8822B 0xffffffffffffffffL +#define BIT_HI2Q_TXBD_DESA_8822B(x) \ + (((x) & BIT_MASK_HI2Q_TXBD_DESA_8822B) \ + << BIT_SHIFT_HI2Q_TXBD_DESA_8822B) +#define BIT_GET_HI2Q_TXBD_DESA_8822B(x) \ + (((x) >> BIT_SHIFT_HI2Q_TXBD_DESA_8822B) & \ + BIT_MASK_HI2Q_TXBD_DESA_8822B) + +/* 2 REG_HI3Q_TXBD_DESA_8822B */ + +#define BIT_SHIFT_HI3Q_TXBD_DESA_8822B 0 +#define BIT_MASK_HI3Q_TXBD_DESA_8822B 0xffffffffffffffffL +#define BIT_HI3Q_TXBD_DESA_8822B(x) \ + (((x) & BIT_MASK_HI3Q_TXBD_DESA_8822B) \ + << BIT_SHIFT_HI3Q_TXBD_DESA_8822B) +#define BIT_GET_HI3Q_TXBD_DESA_8822B(x) \ + (((x) >> BIT_SHIFT_HI3Q_TXBD_DESA_8822B) & \ + BIT_MASK_HI3Q_TXBD_DESA_8822B) + +/* 2 REG_HI4Q_TXBD_DESA_8822B */ + +#define BIT_SHIFT_HI4Q_TXBD_DESA_8822B 0 +#define BIT_MASK_HI4Q_TXBD_DESA_8822B 0xffffffffffffffffL +#define BIT_HI4Q_TXBD_DESA_8822B(x) \ + (((x) & BIT_MASK_HI4Q_TXBD_DESA_8822B) \ + << BIT_SHIFT_HI4Q_TXBD_DESA_8822B) +#define BIT_GET_HI4Q_TXBD_DESA_8822B(x) \ + (((x) >> BIT_SHIFT_HI4Q_TXBD_DESA_8822B) & \ + BIT_MASK_HI4Q_TXBD_DESA_8822B) + +/* 2 REG_HI5Q_TXBD_DESA_8822B */ + +#define BIT_SHIFT_HI5Q_TXBD_DESA_8822B 0 +#define BIT_MASK_HI5Q_TXBD_DESA_8822B 0xffffffffffffffffL +#define BIT_HI5Q_TXBD_DESA_8822B(x) \ + (((x) & BIT_MASK_HI5Q_TXBD_DESA_8822B) \ + << BIT_SHIFT_HI5Q_TXBD_DESA_8822B) +#define BIT_GET_HI5Q_TXBD_DESA_8822B(x) \ + (((x) >> BIT_SHIFT_HI5Q_TXBD_DESA_8822B) & \ + BIT_MASK_HI5Q_TXBD_DESA_8822B) + +/* 2 REG_HI6Q_TXBD_DESA_8822B */ + +#define BIT_SHIFT_HI6Q_TXBD_DESA_8822B 0 +#define BIT_MASK_HI6Q_TXBD_DESA_8822B 0xffffffffffffffffL +#define BIT_HI6Q_TXBD_DESA_8822B(x) \ + (((x) & BIT_MASK_HI6Q_TXBD_DESA_8822B) \ + << BIT_SHIFT_HI6Q_TXBD_DESA_8822B) +#define BIT_GET_HI6Q_TXBD_DESA_8822B(x) \ + (((x) >> BIT_SHIFT_HI6Q_TXBD_DESA_8822B) & \ + BIT_MASK_HI6Q_TXBD_DESA_8822B) + +/* 2 REG_HI7Q_TXBD_DESA_8822B */ + +#define BIT_SHIFT_HI7Q_TXBD_DESA_8822B 0 +#define BIT_MASK_HI7Q_TXBD_DESA_8822B 0xffffffffffffffffL +#define BIT_HI7Q_TXBD_DESA_8822B(x) \ + (((x) & BIT_MASK_HI7Q_TXBD_DESA_8822B) \ + << BIT_SHIFT_HI7Q_TXBD_DESA_8822B) +#define BIT_GET_HI7Q_TXBD_DESA_8822B(x) \ + (((x) >> BIT_SHIFT_HI7Q_TXBD_DESA_8822B) & \ + BIT_MASK_HI7Q_TXBD_DESA_8822B) + +/* 2 REG_MGQ_TXBD_NUM_8822B */ +#define BIT_PCIE_MGQ_FLAG_8822B BIT(14) + +#define BIT_SHIFT_MGQ_DESC_MODE_8822B 12 +#define BIT_MASK_MGQ_DESC_MODE_8822B 0x3 +#define BIT_MGQ_DESC_MODE_8822B(x) \ + (((x) & BIT_MASK_MGQ_DESC_MODE_8822B) << BIT_SHIFT_MGQ_DESC_MODE_8822B) +#define BIT_GET_MGQ_DESC_MODE_8822B(x) \ + (((x) >> BIT_SHIFT_MGQ_DESC_MODE_8822B) & BIT_MASK_MGQ_DESC_MODE_8822B) + +#define BIT_SHIFT_MGQ_DESC_NUM_8822B 0 +#define BIT_MASK_MGQ_DESC_NUM_8822B 0xfff +#define BIT_MGQ_DESC_NUM_8822B(x) \ + (((x) & BIT_MASK_MGQ_DESC_NUM_8822B) << BIT_SHIFT_MGQ_DESC_NUM_8822B) +#define BIT_GET_MGQ_DESC_NUM_8822B(x) \ + (((x) >> BIT_SHIFT_MGQ_DESC_NUM_8822B) & BIT_MASK_MGQ_DESC_NUM_8822B) + +/* 2 REG_RX_RXBD_NUM_8822B */ +#define BIT_SYS_32_64_8822B BIT(15) + +#define BIT_SHIFT_BCNQ_DESC_MODE_8822B 13 +#define BIT_MASK_BCNQ_DESC_MODE_8822B 0x3 +#define BIT_BCNQ_DESC_MODE_8822B(x) \ + (((x) & BIT_MASK_BCNQ_DESC_MODE_8822B) \ + << BIT_SHIFT_BCNQ_DESC_MODE_8822B) +#define BIT_GET_BCNQ_DESC_MODE_8822B(x) \ + (((x) >> BIT_SHIFT_BCNQ_DESC_MODE_8822B) & \ + BIT_MASK_BCNQ_DESC_MODE_8822B) + +#define BIT_PCIE_BCNQ_FLAG_8822B BIT(12) + +#define BIT_SHIFT_RXQ_DESC_NUM_8822B 0 +#define BIT_MASK_RXQ_DESC_NUM_8822B 0xfff +#define BIT_RXQ_DESC_NUM_8822B(x) \ + (((x) & BIT_MASK_RXQ_DESC_NUM_8822B) << BIT_SHIFT_RXQ_DESC_NUM_8822B) +#define BIT_GET_RXQ_DESC_NUM_8822B(x) \ + (((x) >> BIT_SHIFT_RXQ_DESC_NUM_8822B) & BIT_MASK_RXQ_DESC_NUM_8822B) + +/* 2 REG_VOQ_TXBD_NUM_8822B */ +#define BIT_PCIE_VOQ_FLAG_8822B BIT(14) + +#define BIT_SHIFT_VOQ_DESC_MODE_8822B 12 +#define BIT_MASK_VOQ_DESC_MODE_8822B 0x3 +#define BIT_VOQ_DESC_MODE_8822B(x) \ + (((x) & BIT_MASK_VOQ_DESC_MODE_8822B) << BIT_SHIFT_VOQ_DESC_MODE_8822B) +#define BIT_GET_VOQ_DESC_MODE_8822B(x) \ + (((x) >> BIT_SHIFT_VOQ_DESC_MODE_8822B) & BIT_MASK_VOQ_DESC_MODE_8822B) + +#define BIT_SHIFT_VOQ_DESC_NUM_8822B 0 +#define BIT_MASK_VOQ_DESC_NUM_8822B 0xfff +#define BIT_VOQ_DESC_NUM_8822B(x) \ + (((x) & BIT_MASK_VOQ_DESC_NUM_8822B) << BIT_SHIFT_VOQ_DESC_NUM_8822B) +#define BIT_GET_VOQ_DESC_NUM_8822B(x) \ + (((x) >> BIT_SHIFT_VOQ_DESC_NUM_8822B) & BIT_MASK_VOQ_DESC_NUM_8822B) + +/* 2 REG_VIQ_TXBD_NUM_8822B */ +#define BIT_PCIE_VIQ_FLAG_8822B BIT(14) + +#define BIT_SHIFT_VIQ_DESC_MODE_8822B 12 +#define BIT_MASK_VIQ_DESC_MODE_8822B 0x3 +#define BIT_VIQ_DESC_MODE_8822B(x) \ + (((x) & BIT_MASK_VIQ_DESC_MODE_8822B) << BIT_SHIFT_VIQ_DESC_MODE_8822B) +#define BIT_GET_VIQ_DESC_MODE_8822B(x) \ + (((x) >> BIT_SHIFT_VIQ_DESC_MODE_8822B) & BIT_MASK_VIQ_DESC_MODE_8822B) + +#define BIT_SHIFT_VIQ_DESC_NUM_8822B 0 +#define BIT_MASK_VIQ_DESC_NUM_8822B 0xfff +#define BIT_VIQ_DESC_NUM_8822B(x) \ + (((x) & BIT_MASK_VIQ_DESC_NUM_8822B) << BIT_SHIFT_VIQ_DESC_NUM_8822B) +#define BIT_GET_VIQ_DESC_NUM_8822B(x) \ + (((x) >> BIT_SHIFT_VIQ_DESC_NUM_8822B) & BIT_MASK_VIQ_DESC_NUM_8822B) + +/* 2 REG_BEQ_TXBD_NUM_8822B */ +#define BIT_PCIE_BEQ_FLAG_8822B BIT(14) + +#define BIT_SHIFT_BEQ_DESC_MODE_8822B 12 +#define BIT_MASK_BEQ_DESC_MODE_8822B 0x3 +#define BIT_BEQ_DESC_MODE_8822B(x) \ + (((x) & BIT_MASK_BEQ_DESC_MODE_8822B) << BIT_SHIFT_BEQ_DESC_MODE_8822B) +#define BIT_GET_BEQ_DESC_MODE_8822B(x) \ + (((x) >> BIT_SHIFT_BEQ_DESC_MODE_8822B) & BIT_MASK_BEQ_DESC_MODE_8822B) + +#define BIT_SHIFT_BEQ_DESC_NUM_8822B 0 +#define BIT_MASK_BEQ_DESC_NUM_8822B 0xfff +#define BIT_BEQ_DESC_NUM_8822B(x) \ + (((x) & BIT_MASK_BEQ_DESC_NUM_8822B) << BIT_SHIFT_BEQ_DESC_NUM_8822B) +#define BIT_GET_BEQ_DESC_NUM_8822B(x) \ + (((x) >> BIT_SHIFT_BEQ_DESC_NUM_8822B) & BIT_MASK_BEQ_DESC_NUM_8822B) + +/* 2 REG_BKQ_TXBD_NUM_8822B */ +#define BIT_PCIE_BKQ_FLAG_8822B BIT(14) + +#define BIT_SHIFT_BKQ_DESC_MODE_8822B 12 +#define BIT_MASK_BKQ_DESC_MODE_8822B 0x3 +#define BIT_BKQ_DESC_MODE_8822B(x) \ + (((x) & BIT_MASK_BKQ_DESC_MODE_8822B) << BIT_SHIFT_BKQ_DESC_MODE_8822B) +#define BIT_GET_BKQ_DESC_MODE_8822B(x) \ + (((x) >> BIT_SHIFT_BKQ_DESC_MODE_8822B) & BIT_MASK_BKQ_DESC_MODE_8822B) + +#define BIT_SHIFT_BKQ_DESC_NUM_8822B 0 +#define BIT_MASK_BKQ_DESC_NUM_8822B 0xfff +#define BIT_BKQ_DESC_NUM_8822B(x) \ + (((x) & BIT_MASK_BKQ_DESC_NUM_8822B) << BIT_SHIFT_BKQ_DESC_NUM_8822B) +#define BIT_GET_BKQ_DESC_NUM_8822B(x) \ + (((x) >> BIT_SHIFT_BKQ_DESC_NUM_8822B) & BIT_MASK_BKQ_DESC_NUM_8822B) + +/* 2 REG_HI0Q_TXBD_NUM_8822B */ +#define BIT_HI0Q_FLAG_8822B BIT(14) + +#define BIT_SHIFT_HI0Q_DESC_MODE_8822B 12 +#define BIT_MASK_HI0Q_DESC_MODE_8822B 0x3 +#define BIT_HI0Q_DESC_MODE_8822B(x) \ + (((x) & BIT_MASK_HI0Q_DESC_MODE_8822B) \ + << BIT_SHIFT_HI0Q_DESC_MODE_8822B) +#define BIT_GET_HI0Q_DESC_MODE_8822B(x) \ + (((x) >> BIT_SHIFT_HI0Q_DESC_MODE_8822B) & \ + BIT_MASK_HI0Q_DESC_MODE_8822B) + +#define BIT_SHIFT_HI0Q_DESC_NUM_8822B 0 +#define BIT_MASK_HI0Q_DESC_NUM_8822B 0xfff +#define BIT_HI0Q_DESC_NUM_8822B(x) \ + (((x) & BIT_MASK_HI0Q_DESC_NUM_8822B) << BIT_SHIFT_HI0Q_DESC_NUM_8822B) +#define BIT_GET_HI0Q_DESC_NUM_8822B(x) \ + (((x) >> BIT_SHIFT_HI0Q_DESC_NUM_8822B) & BIT_MASK_HI0Q_DESC_NUM_8822B) + +/* 2 REG_HI1Q_TXBD_NUM_8822B */ +#define BIT_HI1Q_FLAG_8822B BIT(14) + +#define BIT_SHIFT_HI1Q_DESC_MODE_8822B 12 +#define BIT_MASK_HI1Q_DESC_MODE_8822B 0x3 +#define BIT_HI1Q_DESC_MODE_8822B(x) \ + (((x) & BIT_MASK_HI1Q_DESC_MODE_8822B) \ + << BIT_SHIFT_HI1Q_DESC_MODE_8822B) +#define BIT_GET_HI1Q_DESC_MODE_8822B(x) \ + (((x) >> BIT_SHIFT_HI1Q_DESC_MODE_8822B) & \ + BIT_MASK_HI1Q_DESC_MODE_8822B) + +#define BIT_SHIFT_HI1Q_DESC_NUM_8822B 0 +#define BIT_MASK_HI1Q_DESC_NUM_8822B 0xfff +#define BIT_HI1Q_DESC_NUM_8822B(x) \ + (((x) & BIT_MASK_HI1Q_DESC_NUM_8822B) << BIT_SHIFT_HI1Q_DESC_NUM_8822B) +#define BIT_GET_HI1Q_DESC_NUM_8822B(x) \ + (((x) >> BIT_SHIFT_HI1Q_DESC_NUM_8822B) & BIT_MASK_HI1Q_DESC_NUM_8822B) + +/* 2 REG_HI2Q_TXBD_NUM_8822B */ +#define BIT_HI2Q_FLAG_8822B BIT(14) + +#define BIT_SHIFT_HI2Q_DESC_MODE_8822B 12 +#define BIT_MASK_HI2Q_DESC_MODE_8822B 0x3 +#define BIT_HI2Q_DESC_MODE_8822B(x) \ + (((x) & BIT_MASK_HI2Q_DESC_MODE_8822B) \ + << BIT_SHIFT_HI2Q_DESC_MODE_8822B) +#define BIT_GET_HI2Q_DESC_MODE_8822B(x) \ + (((x) >> BIT_SHIFT_HI2Q_DESC_MODE_8822B) & \ + BIT_MASK_HI2Q_DESC_MODE_8822B) + +#define BIT_SHIFT_HI2Q_DESC_NUM_8822B 0 +#define BIT_MASK_HI2Q_DESC_NUM_8822B 0xfff +#define BIT_HI2Q_DESC_NUM_8822B(x) \ + (((x) & BIT_MASK_HI2Q_DESC_NUM_8822B) << BIT_SHIFT_HI2Q_DESC_NUM_8822B) +#define BIT_GET_HI2Q_DESC_NUM_8822B(x) \ + (((x) >> BIT_SHIFT_HI2Q_DESC_NUM_8822B) & BIT_MASK_HI2Q_DESC_NUM_8822B) + +/* 2 REG_HI3Q_TXBD_NUM_8822B */ +#define BIT_HI3Q_FLAG_8822B BIT(14) + +#define BIT_SHIFT_HI3Q_DESC_MODE_8822B 12 +#define BIT_MASK_HI3Q_DESC_MODE_8822B 0x3 +#define BIT_HI3Q_DESC_MODE_8822B(x) \ + (((x) & BIT_MASK_HI3Q_DESC_MODE_8822B) \ + << BIT_SHIFT_HI3Q_DESC_MODE_8822B) +#define BIT_GET_HI3Q_DESC_MODE_8822B(x) \ + (((x) >> BIT_SHIFT_HI3Q_DESC_MODE_8822B) & \ + BIT_MASK_HI3Q_DESC_MODE_8822B) + +#define BIT_SHIFT_HI3Q_DESC_NUM_8822B 0 +#define BIT_MASK_HI3Q_DESC_NUM_8822B 0xfff +#define BIT_HI3Q_DESC_NUM_8822B(x) \ + (((x) & BIT_MASK_HI3Q_DESC_NUM_8822B) << BIT_SHIFT_HI3Q_DESC_NUM_8822B) +#define BIT_GET_HI3Q_DESC_NUM_8822B(x) \ + (((x) >> BIT_SHIFT_HI3Q_DESC_NUM_8822B) & BIT_MASK_HI3Q_DESC_NUM_8822B) + +/* 2 REG_HI4Q_TXBD_NUM_8822B */ +#define BIT_HI4Q_FLAG_8822B BIT(14) + +#define BIT_SHIFT_HI4Q_DESC_MODE_8822B 12 +#define BIT_MASK_HI4Q_DESC_MODE_8822B 0x3 +#define BIT_HI4Q_DESC_MODE_8822B(x) \ + (((x) & BIT_MASK_HI4Q_DESC_MODE_8822B) \ + << BIT_SHIFT_HI4Q_DESC_MODE_8822B) +#define BIT_GET_HI4Q_DESC_MODE_8822B(x) \ + (((x) >> BIT_SHIFT_HI4Q_DESC_MODE_8822B) & \ + BIT_MASK_HI4Q_DESC_MODE_8822B) + +#define BIT_SHIFT_HI4Q_DESC_NUM_8822B 0 +#define BIT_MASK_HI4Q_DESC_NUM_8822B 0xfff +#define BIT_HI4Q_DESC_NUM_8822B(x) \ + (((x) & BIT_MASK_HI4Q_DESC_NUM_8822B) << BIT_SHIFT_HI4Q_DESC_NUM_8822B) +#define BIT_GET_HI4Q_DESC_NUM_8822B(x) \ + (((x) >> BIT_SHIFT_HI4Q_DESC_NUM_8822B) & BIT_MASK_HI4Q_DESC_NUM_8822B) + +/* 2 REG_HI5Q_TXBD_NUM_8822B */ +#define BIT_HI5Q_FLAG_8822B BIT(14) + +#define BIT_SHIFT_HI5Q_DESC_MODE_8822B 12 +#define BIT_MASK_HI5Q_DESC_MODE_8822B 0x3 +#define BIT_HI5Q_DESC_MODE_8822B(x) \ + (((x) & BIT_MASK_HI5Q_DESC_MODE_8822B) \ + << BIT_SHIFT_HI5Q_DESC_MODE_8822B) +#define BIT_GET_HI5Q_DESC_MODE_8822B(x) \ + (((x) >> BIT_SHIFT_HI5Q_DESC_MODE_8822B) & \ + BIT_MASK_HI5Q_DESC_MODE_8822B) + +#define BIT_SHIFT_HI5Q_DESC_NUM_8822B 0 +#define BIT_MASK_HI5Q_DESC_NUM_8822B 0xfff +#define BIT_HI5Q_DESC_NUM_8822B(x) \ + (((x) & BIT_MASK_HI5Q_DESC_NUM_8822B) << BIT_SHIFT_HI5Q_DESC_NUM_8822B) +#define BIT_GET_HI5Q_DESC_NUM_8822B(x) \ + (((x) >> BIT_SHIFT_HI5Q_DESC_NUM_8822B) & BIT_MASK_HI5Q_DESC_NUM_8822B) + +/* 2 REG_HI6Q_TXBD_NUM_8822B */ +#define BIT_HI6Q_FLAG_8822B BIT(14) + +#define BIT_SHIFT_HI6Q_DESC_MODE_8822B 12 +#define BIT_MASK_HI6Q_DESC_MODE_8822B 0x3 +#define BIT_HI6Q_DESC_MODE_8822B(x) \ + (((x) & BIT_MASK_HI6Q_DESC_MODE_8822B) \ + << BIT_SHIFT_HI6Q_DESC_MODE_8822B) +#define BIT_GET_HI6Q_DESC_MODE_8822B(x) \ + (((x) >> BIT_SHIFT_HI6Q_DESC_MODE_8822B) & \ + BIT_MASK_HI6Q_DESC_MODE_8822B) + +#define BIT_SHIFT_HI6Q_DESC_NUM_8822B 0 +#define BIT_MASK_HI6Q_DESC_NUM_8822B 0xfff +#define BIT_HI6Q_DESC_NUM_8822B(x) \ + (((x) & BIT_MASK_HI6Q_DESC_NUM_8822B) << BIT_SHIFT_HI6Q_DESC_NUM_8822B) +#define BIT_GET_HI6Q_DESC_NUM_8822B(x) \ + (((x) >> BIT_SHIFT_HI6Q_DESC_NUM_8822B) & BIT_MASK_HI6Q_DESC_NUM_8822B) + +/* 2 REG_HI7Q_TXBD_NUM_8822B */ +#define BIT_HI7Q_FLAG_8822B BIT(14) + +#define BIT_SHIFT_HI7Q_DESC_MODE_8822B 12 +#define BIT_MASK_HI7Q_DESC_MODE_8822B 0x3 +#define BIT_HI7Q_DESC_MODE_8822B(x) \ + (((x) & BIT_MASK_HI7Q_DESC_MODE_8822B) \ + << BIT_SHIFT_HI7Q_DESC_MODE_8822B) +#define BIT_GET_HI7Q_DESC_MODE_8822B(x) \ + (((x) >> BIT_SHIFT_HI7Q_DESC_MODE_8822B) & \ + BIT_MASK_HI7Q_DESC_MODE_8822B) + +#define BIT_SHIFT_HI7Q_DESC_NUM_8822B 0 +#define BIT_MASK_HI7Q_DESC_NUM_8822B 0xfff +#define BIT_HI7Q_DESC_NUM_8822B(x) \ + (((x) & BIT_MASK_HI7Q_DESC_NUM_8822B) << BIT_SHIFT_HI7Q_DESC_NUM_8822B) +#define BIT_GET_HI7Q_DESC_NUM_8822B(x) \ + (((x) >> BIT_SHIFT_HI7Q_DESC_NUM_8822B) & BIT_MASK_HI7Q_DESC_NUM_8822B) + +/* 2 REG_TSFTIMER_HCI_8822B */ + +#define BIT_SHIFT_TSFT2_HCI_8822B 16 +#define BIT_MASK_TSFT2_HCI_8822B 0xffff +#define BIT_TSFT2_HCI_8822B(x) \ + (((x) & BIT_MASK_TSFT2_HCI_8822B) << BIT_SHIFT_TSFT2_HCI_8822B) +#define BIT_GET_TSFT2_HCI_8822B(x) \ + (((x) >> BIT_SHIFT_TSFT2_HCI_8822B) & BIT_MASK_TSFT2_HCI_8822B) + +#define BIT_SHIFT_TSFT1_HCI_8822B 0 +#define BIT_MASK_TSFT1_HCI_8822B 0xffff +#define BIT_TSFT1_HCI_8822B(x) \ + (((x) & BIT_MASK_TSFT1_HCI_8822B) << BIT_SHIFT_TSFT1_HCI_8822B) +#define BIT_GET_TSFT1_HCI_8822B(x) \ + (((x) >> BIT_SHIFT_TSFT1_HCI_8822B) & BIT_MASK_TSFT1_HCI_8822B) + +/* 2 REG_BD_RWPTR_CLR_8822B */ +#define BIT_CLR_HI7Q_HW_IDX_8822B BIT(29) +#define BIT_CLR_HI6Q_HW_IDX_8822B BIT(28) +#define BIT_CLR_HI5Q_HW_IDX_8822B BIT(27) +#define BIT_CLR_HI4Q_HW_IDX_8822B BIT(26) +#define BIT_CLR_HI3Q_HW_IDX_8822B BIT(25) +#define BIT_CLR_HI2Q_HW_IDX_8822B BIT(24) +#define BIT_CLR_HI1Q_HW_IDX_8822B BIT(23) +#define BIT_CLR_HI0Q_HW_IDX_8822B BIT(22) +#define BIT_CLR_BKQ_HW_IDX_8822B BIT(21) +#define BIT_CLR_BEQ_HW_IDX_8822B BIT(20) +#define BIT_CLR_VIQ_HW_IDX_8822B BIT(19) +#define BIT_CLR_VOQ_HW_IDX_8822B BIT(18) +#define BIT_CLR_MGQ_HW_IDX_8822B BIT(17) +#define BIT_CLR_RXQ_HW_IDX_8822B BIT(16) +#define BIT_CLR_HI7Q_HOST_IDX_8822B BIT(13) +#define BIT_CLR_HI6Q_HOST_IDX_8822B BIT(12) +#define BIT_CLR_HI5Q_HOST_IDX_8822B BIT(11) +#define BIT_CLR_HI4Q_HOST_IDX_8822B BIT(10) +#define BIT_CLR_HI3Q_HOST_IDX_8822B BIT(9) +#define BIT_CLR_HI2Q_HOST_IDX_8822B BIT(8) +#define BIT_CLR_HI1Q_HOST_IDX_8822B BIT(7) +#define BIT_CLR_HI0Q_HOST_IDX_8822B BIT(6) +#define BIT_CLR_BKQ_HOST_IDX_8822B BIT(5) +#define BIT_CLR_BEQ_HOST_IDX_8822B BIT(4) +#define BIT_CLR_VIQ_HOST_IDX_8822B BIT(3) +#define BIT_CLR_VOQ_HOST_IDX_8822B BIT(2) +#define BIT_CLR_MGQ_HOST_IDX_8822B BIT(1) +#define BIT_CLR_RXQ_HOST_IDX_8822B BIT(0) + +/* 2 REG_VOQ_TXBD_IDX_8822B */ + +#define BIT_SHIFT_VOQ_HW_IDX_8822B 16 +#define BIT_MASK_VOQ_HW_IDX_8822B 0xfff +#define BIT_VOQ_HW_IDX_8822B(x) \ + (((x) & BIT_MASK_VOQ_HW_IDX_8822B) << BIT_SHIFT_VOQ_HW_IDX_8822B) +#define BIT_GET_VOQ_HW_IDX_8822B(x) \ + (((x) >> BIT_SHIFT_VOQ_HW_IDX_8822B) & BIT_MASK_VOQ_HW_IDX_8822B) + +#define BIT_SHIFT_VOQ_HOST_IDX_8822B 0 +#define BIT_MASK_VOQ_HOST_IDX_8822B 0xfff +#define BIT_VOQ_HOST_IDX_8822B(x) \ + (((x) & BIT_MASK_VOQ_HOST_IDX_8822B) << BIT_SHIFT_VOQ_HOST_IDX_8822B) +#define BIT_GET_VOQ_HOST_IDX_8822B(x) \ + (((x) >> BIT_SHIFT_VOQ_HOST_IDX_8822B) & BIT_MASK_VOQ_HOST_IDX_8822B) + +/* 2 REG_VIQ_TXBD_IDX_8822B */ + +#define BIT_SHIFT_VIQ_HW_IDX_8822B 16 +#define BIT_MASK_VIQ_HW_IDX_8822B 0xfff +#define BIT_VIQ_HW_IDX_8822B(x) \ + (((x) & BIT_MASK_VIQ_HW_IDX_8822B) << BIT_SHIFT_VIQ_HW_IDX_8822B) +#define BIT_GET_VIQ_HW_IDX_8822B(x) \ + (((x) >> BIT_SHIFT_VIQ_HW_IDX_8822B) & BIT_MASK_VIQ_HW_IDX_8822B) + +#define BIT_SHIFT_VIQ_HOST_IDX_8822B 0 +#define BIT_MASK_VIQ_HOST_IDX_8822B 0xfff +#define BIT_VIQ_HOST_IDX_8822B(x) \ + (((x) & BIT_MASK_VIQ_HOST_IDX_8822B) << BIT_SHIFT_VIQ_HOST_IDX_8822B) +#define BIT_GET_VIQ_HOST_IDX_8822B(x) \ + (((x) >> BIT_SHIFT_VIQ_HOST_IDX_8822B) & BIT_MASK_VIQ_HOST_IDX_8822B) + +/* 2 REG_BEQ_TXBD_IDX_8822B */ + +#define BIT_SHIFT_BEQ_HW_IDX_8822B 16 +#define BIT_MASK_BEQ_HW_IDX_8822B 0xfff +#define BIT_BEQ_HW_IDX_8822B(x) \ + (((x) & BIT_MASK_BEQ_HW_IDX_8822B) << BIT_SHIFT_BEQ_HW_IDX_8822B) +#define BIT_GET_BEQ_HW_IDX_8822B(x) \ + (((x) >> BIT_SHIFT_BEQ_HW_IDX_8822B) & BIT_MASK_BEQ_HW_IDX_8822B) + +#define BIT_SHIFT_BEQ_HOST_IDX_8822B 0 +#define BIT_MASK_BEQ_HOST_IDX_8822B 0xfff +#define BIT_BEQ_HOST_IDX_8822B(x) \ + (((x) & BIT_MASK_BEQ_HOST_IDX_8822B) << BIT_SHIFT_BEQ_HOST_IDX_8822B) +#define BIT_GET_BEQ_HOST_IDX_8822B(x) \ + (((x) >> BIT_SHIFT_BEQ_HOST_IDX_8822B) & BIT_MASK_BEQ_HOST_IDX_8822B) + +/* 2 REG_BKQ_TXBD_IDX_8822B */ + +#define BIT_SHIFT_BKQ_HW_IDX_8822B 16 +#define BIT_MASK_BKQ_HW_IDX_8822B 0xfff +#define BIT_BKQ_HW_IDX_8822B(x) \ + (((x) & BIT_MASK_BKQ_HW_IDX_8822B) << BIT_SHIFT_BKQ_HW_IDX_8822B) +#define BIT_GET_BKQ_HW_IDX_8822B(x) \ + (((x) >> BIT_SHIFT_BKQ_HW_IDX_8822B) & BIT_MASK_BKQ_HW_IDX_8822B) + +#define BIT_SHIFT_BKQ_HOST_IDX_8822B 0 +#define BIT_MASK_BKQ_HOST_IDX_8822B 0xfff +#define BIT_BKQ_HOST_IDX_8822B(x) \ + (((x) & BIT_MASK_BKQ_HOST_IDX_8822B) << BIT_SHIFT_BKQ_HOST_IDX_8822B) +#define BIT_GET_BKQ_HOST_IDX_8822B(x) \ + (((x) >> BIT_SHIFT_BKQ_HOST_IDX_8822B) & BIT_MASK_BKQ_HOST_IDX_8822B) + +/* 2 REG_MGQ_TXBD_IDX_8822B */ + +#define BIT_SHIFT_MGQ_HW_IDX_8822B 16 +#define BIT_MASK_MGQ_HW_IDX_8822B 0xfff +#define BIT_MGQ_HW_IDX_8822B(x) \ + (((x) & BIT_MASK_MGQ_HW_IDX_8822B) << BIT_SHIFT_MGQ_HW_IDX_8822B) +#define BIT_GET_MGQ_HW_IDX_8822B(x) \ + (((x) >> BIT_SHIFT_MGQ_HW_IDX_8822B) & BIT_MASK_MGQ_HW_IDX_8822B) + +#define BIT_SHIFT_MGQ_HOST_IDX_8822B 0 +#define BIT_MASK_MGQ_HOST_IDX_8822B 0xfff +#define BIT_MGQ_HOST_IDX_8822B(x) \ + (((x) & BIT_MASK_MGQ_HOST_IDX_8822B) << BIT_SHIFT_MGQ_HOST_IDX_8822B) +#define BIT_GET_MGQ_HOST_IDX_8822B(x) \ + (((x) >> BIT_SHIFT_MGQ_HOST_IDX_8822B) & BIT_MASK_MGQ_HOST_IDX_8822B) + +/* 2 REG_RXQ_RXBD_IDX_8822B */ + +#define BIT_SHIFT_RXQ_HW_IDX_8822B 16 +#define BIT_MASK_RXQ_HW_IDX_8822B 0xfff +#define BIT_RXQ_HW_IDX_8822B(x) \ + (((x) & BIT_MASK_RXQ_HW_IDX_8822B) << BIT_SHIFT_RXQ_HW_IDX_8822B) +#define BIT_GET_RXQ_HW_IDX_8822B(x) \ + (((x) >> BIT_SHIFT_RXQ_HW_IDX_8822B) & BIT_MASK_RXQ_HW_IDX_8822B) + +#define BIT_SHIFT_RXQ_HOST_IDX_8822B 0 +#define BIT_MASK_RXQ_HOST_IDX_8822B 0xfff +#define BIT_RXQ_HOST_IDX_8822B(x) \ + (((x) & BIT_MASK_RXQ_HOST_IDX_8822B) << BIT_SHIFT_RXQ_HOST_IDX_8822B) +#define BIT_GET_RXQ_HOST_IDX_8822B(x) \ + (((x) >> BIT_SHIFT_RXQ_HOST_IDX_8822B) & BIT_MASK_RXQ_HOST_IDX_8822B) + +/* 2 REG_HI0Q_TXBD_IDX_8822B */ + +#define BIT_SHIFT_HI0Q_HW_IDX_8822B 16 +#define BIT_MASK_HI0Q_HW_IDX_8822B 0xfff +#define BIT_HI0Q_HW_IDX_8822B(x) \ + (((x) & BIT_MASK_HI0Q_HW_IDX_8822B) << BIT_SHIFT_HI0Q_HW_IDX_8822B) +#define BIT_GET_HI0Q_HW_IDX_8822B(x) \ + (((x) >> BIT_SHIFT_HI0Q_HW_IDX_8822B) & BIT_MASK_HI0Q_HW_IDX_8822B) + +#define BIT_SHIFT_HI0Q_HOST_IDX_8822B 0 +#define BIT_MASK_HI0Q_HOST_IDX_8822B 0xfff +#define BIT_HI0Q_HOST_IDX_8822B(x) \ + (((x) & BIT_MASK_HI0Q_HOST_IDX_8822B) << BIT_SHIFT_HI0Q_HOST_IDX_8822B) +#define BIT_GET_HI0Q_HOST_IDX_8822B(x) \ + (((x) >> BIT_SHIFT_HI0Q_HOST_IDX_8822B) & BIT_MASK_HI0Q_HOST_IDX_8822B) + +/* 2 REG_HI1Q_TXBD_IDX_8822B */ + +#define BIT_SHIFT_HI1Q_HW_IDX_8822B 16 +#define BIT_MASK_HI1Q_HW_IDX_8822B 0xfff +#define BIT_HI1Q_HW_IDX_8822B(x) \ + (((x) & BIT_MASK_HI1Q_HW_IDX_8822B) << BIT_SHIFT_HI1Q_HW_IDX_8822B) +#define BIT_GET_HI1Q_HW_IDX_8822B(x) \ + (((x) >> BIT_SHIFT_HI1Q_HW_IDX_8822B) & BIT_MASK_HI1Q_HW_IDX_8822B) + +#define BIT_SHIFT_HI1Q_HOST_IDX_8822B 0 +#define BIT_MASK_HI1Q_HOST_IDX_8822B 0xfff +#define BIT_HI1Q_HOST_IDX_8822B(x) \ + (((x) & BIT_MASK_HI1Q_HOST_IDX_8822B) << BIT_SHIFT_HI1Q_HOST_IDX_8822B) +#define BIT_GET_HI1Q_HOST_IDX_8822B(x) \ + (((x) >> BIT_SHIFT_HI1Q_HOST_IDX_8822B) & BIT_MASK_HI1Q_HOST_IDX_8822B) + +/* 2 REG_HI2Q_TXBD_IDX_8822B */ + +#define BIT_SHIFT_HI2Q_HW_IDX_8822B 16 +#define BIT_MASK_HI2Q_HW_IDX_8822B 0xfff +#define BIT_HI2Q_HW_IDX_8822B(x) \ + (((x) & BIT_MASK_HI2Q_HW_IDX_8822B) << BIT_SHIFT_HI2Q_HW_IDX_8822B) +#define BIT_GET_HI2Q_HW_IDX_8822B(x) \ + (((x) >> BIT_SHIFT_HI2Q_HW_IDX_8822B) & BIT_MASK_HI2Q_HW_IDX_8822B) + +#define BIT_SHIFT_HI2Q_HOST_IDX_8822B 0 +#define BIT_MASK_HI2Q_HOST_IDX_8822B 0xfff +#define BIT_HI2Q_HOST_IDX_8822B(x) \ + (((x) & BIT_MASK_HI2Q_HOST_IDX_8822B) << BIT_SHIFT_HI2Q_HOST_IDX_8822B) +#define BIT_GET_HI2Q_HOST_IDX_8822B(x) \ + (((x) >> BIT_SHIFT_HI2Q_HOST_IDX_8822B) & BIT_MASK_HI2Q_HOST_IDX_8822B) + +/* 2 REG_HI3Q_TXBD_IDX_8822B */ + +#define BIT_SHIFT_HI3Q_HW_IDX_8822B 16 +#define BIT_MASK_HI3Q_HW_IDX_8822B 0xfff +#define BIT_HI3Q_HW_IDX_8822B(x) \ + (((x) & BIT_MASK_HI3Q_HW_IDX_8822B) << BIT_SHIFT_HI3Q_HW_IDX_8822B) +#define BIT_GET_HI3Q_HW_IDX_8822B(x) \ + (((x) >> BIT_SHIFT_HI3Q_HW_IDX_8822B) & BIT_MASK_HI3Q_HW_IDX_8822B) + +#define BIT_SHIFT_HI3Q_HOST_IDX_8822B 0 +#define BIT_MASK_HI3Q_HOST_IDX_8822B 0xfff +#define BIT_HI3Q_HOST_IDX_8822B(x) \ + (((x) & BIT_MASK_HI3Q_HOST_IDX_8822B) << BIT_SHIFT_HI3Q_HOST_IDX_8822B) +#define BIT_GET_HI3Q_HOST_IDX_8822B(x) \ + (((x) >> BIT_SHIFT_HI3Q_HOST_IDX_8822B) & BIT_MASK_HI3Q_HOST_IDX_8822B) + +/* 2 REG_HI4Q_TXBD_IDX_8822B */ + +#define BIT_SHIFT_HI4Q_HW_IDX_8822B 16 +#define BIT_MASK_HI4Q_HW_IDX_8822B 0xfff +#define BIT_HI4Q_HW_IDX_8822B(x) \ + (((x) & BIT_MASK_HI4Q_HW_IDX_8822B) << BIT_SHIFT_HI4Q_HW_IDX_8822B) +#define BIT_GET_HI4Q_HW_IDX_8822B(x) \ + (((x) >> BIT_SHIFT_HI4Q_HW_IDX_8822B) & BIT_MASK_HI4Q_HW_IDX_8822B) + +#define BIT_SHIFT_HI4Q_HOST_IDX_8822B 0 +#define BIT_MASK_HI4Q_HOST_IDX_8822B 0xfff +#define BIT_HI4Q_HOST_IDX_8822B(x) \ + (((x) & BIT_MASK_HI4Q_HOST_IDX_8822B) << BIT_SHIFT_HI4Q_HOST_IDX_8822B) +#define BIT_GET_HI4Q_HOST_IDX_8822B(x) \ + (((x) >> BIT_SHIFT_HI4Q_HOST_IDX_8822B) & BIT_MASK_HI4Q_HOST_IDX_8822B) + +/* 2 REG_HI5Q_TXBD_IDX_8822B */ + +#define BIT_SHIFT_HI5Q_HW_IDX_8822B 16 +#define BIT_MASK_HI5Q_HW_IDX_8822B 0xfff +#define BIT_HI5Q_HW_IDX_8822B(x) \ + (((x) & BIT_MASK_HI5Q_HW_IDX_8822B) << BIT_SHIFT_HI5Q_HW_IDX_8822B) +#define BIT_GET_HI5Q_HW_IDX_8822B(x) \ + (((x) >> BIT_SHIFT_HI5Q_HW_IDX_8822B) & BIT_MASK_HI5Q_HW_IDX_8822B) + +#define BIT_SHIFT_HI5Q_HOST_IDX_8822B 0 +#define BIT_MASK_HI5Q_HOST_IDX_8822B 0xfff +#define BIT_HI5Q_HOST_IDX_8822B(x) \ + (((x) & BIT_MASK_HI5Q_HOST_IDX_8822B) << BIT_SHIFT_HI5Q_HOST_IDX_8822B) +#define BIT_GET_HI5Q_HOST_IDX_8822B(x) \ + (((x) >> BIT_SHIFT_HI5Q_HOST_IDX_8822B) & BIT_MASK_HI5Q_HOST_IDX_8822B) + +/* 2 REG_HI6Q_TXBD_IDX_8822B */ + +#define BIT_SHIFT_HI6Q_HW_IDX_8822B 16 +#define BIT_MASK_HI6Q_HW_IDX_8822B 0xfff +#define BIT_HI6Q_HW_IDX_8822B(x) \ + (((x) & BIT_MASK_HI6Q_HW_IDX_8822B) << BIT_SHIFT_HI6Q_HW_IDX_8822B) +#define BIT_GET_HI6Q_HW_IDX_8822B(x) \ + (((x) >> BIT_SHIFT_HI6Q_HW_IDX_8822B) & BIT_MASK_HI6Q_HW_IDX_8822B) + +#define BIT_SHIFT_HI6Q_HOST_IDX_8822B 0 +#define BIT_MASK_HI6Q_HOST_IDX_8822B 0xfff +#define BIT_HI6Q_HOST_IDX_8822B(x) \ + (((x) & BIT_MASK_HI6Q_HOST_IDX_8822B) << BIT_SHIFT_HI6Q_HOST_IDX_8822B) +#define BIT_GET_HI6Q_HOST_IDX_8822B(x) \ + (((x) >> BIT_SHIFT_HI6Q_HOST_IDX_8822B) & BIT_MASK_HI6Q_HOST_IDX_8822B) + +/* 2 REG_HI7Q_TXBD_IDX_8822B */ + +#define BIT_SHIFT_HI7Q_HW_IDX_8822B 16 +#define BIT_MASK_HI7Q_HW_IDX_8822B 0xfff +#define BIT_HI7Q_HW_IDX_8822B(x) \ + (((x) & BIT_MASK_HI7Q_HW_IDX_8822B) << BIT_SHIFT_HI7Q_HW_IDX_8822B) +#define BIT_GET_HI7Q_HW_IDX_8822B(x) \ + (((x) >> BIT_SHIFT_HI7Q_HW_IDX_8822B) & BIT_MASK_HI7Q_HW_IDX_8822B) + +#define BIT_SHIFT_HI7Q_HOST_IDX_8822B 0 +#define BIT_MASK_HI7Q_HOST_IDX_8822B 0xfff +#define BIT_HI7Q_HOST_IDX_8822B(x) \ + (((x) & BIT_MASK_HI7Q_HOST_IDX_8822B) << BIT_SHIFT_HI7Q_HOST_IDX_8822B) +#define BIT_GET_HI7Q_HOST_IDX_8822B(x) \ + (((x) >> BIT_SHIFT_HI7Q_HOST_IDX_8822B) & BIT_MASK_HI7Q_HOST_IDX_8822B) + +/* 2 REG_DBG_SEL_V1_8822B */ + +#define BIT_SHIFT_DBG_SEL_8822B 0 +#define BIT_MASK_DBG_SEL_8822B 0xff +#define BIT_DBG_SEL_8822B(x) \ + (((x) & BIT_MASK_DBG_SEL_8822B) << BIT_SHIFT_DBG_SEL_8822B) +#define BIT_GET_DBG_SEL_8822B(x) \ + (((x) >> BIT_SHIFT_DBG_SEL_8822B) & BIT_MASK_DBG_SEL_8822B) + +/* 2 REG_PCIE_HRPWM1_V1_8822B */ + +#define BIT_SHIFT_PCIE_HRPWM_8822B 0 +#define BIT_MASK_PCIE_HRPWM_8822B 0xff +#define BIT_PCIE_HRPWM_8822B(x) \ + (((x) & BIT_MASK_PCIE_HRPWM_8822B) << BIT_SHIFT_PCIE_HRPWM_8822B) +#define BIT_GET_PCIE_HRPWM_8822B(x) \ + (((x) >> BIT_SHIFT_PCIE_HRPWM_8822B) & BIT_MASK_PCIE_HRPWM_8822B) + +/* 2 REG_PCIE_HCPWM1_V1_8822B */ + +#define BIT_SHIFT_PCIE_HCPWM_8822B 0 +#define BIT_MASK_PCIE_HCPWM_8822B 0xff +#define BIT_PCIE_HCPWM_8822B(x) \ + (((x) & BIT_MASK_PCIE_HCPWM_8822B) << BIT_SHIFT_PCIE_HCPWM_8822B) +#define BIT_GET_PCIE_HCPWM_8822B(x) \ + (((x) >> BIT_SHIFT_PCIE_HCPWM_8822B) & BIT_MASK_PCIE_HCPWM_8822B) + +/* 2 REG_PCIE_CTRL2_8822B */ +#define BIT_DIS_TXDMA_PRE_8822B BIT(7) +#define BIT_DIS_RXDMA_PRE_8822B BIT(6) + +#define BIT_SHIFT_HPS_CLKR_PCIE_8822B 4 +#define BIT_MASK_HPS_CLKR_PCIE_8822B 0x3 +#define BIT_HPS_CLKR_PCIE_8822B(x) \ + (((x) & BIT_MASK_HPS_CLKR_PCIE_8822B) << BIT_SHIFT_HPS_CLKR_PCIE_8822B) +#define BIT_GET_HPS_CLKR_PCIE_8822B(x) \ + (((x) >> BIT_SHIFT_HPS_CLKR_PCIE_8822B) & BIT_MASK_HPS_CLKR_PCIE_8822B) + +#define BIT_PCIE_INT_8822B BIT(3) +#define BIT_TXFLAG_EXIT_L1_EN_8822B BIT(2) +#define BIT_EN_RXDMA_ALIGN_8822B BIT(1) +#define BIT_EN_TXDMA_ALIGN_8822B BIT(0) + +/* 2 REG_PCIE_HRPWM2_V1_8822B */ + +#define BIT_SHIFT_PCIE_HRPWM2_8822B 0 +#define BIT_MASK_PCIE_HRPWM2_8822B 0xffff +#define BIT_PCIE_HRPWM2_8822B(x) \ + (((x) & BIT_MASK_PCIE_HRPWM2_8822B) << BIT_SHIFT_PCIE_HRPWM2_8822B) +#define BIT_GET_PCIE_HRPWM2_8822B(x) \ + (((x) >> BIT_SHIFT_PCIE_HRPWM2_8822B) & BIT_MASK_PCIE_HRPWM2_8822B) + +/* 2 REG_PCIE_HCPWM2_V1_8822B */ + +#define BIT_SHIFT_PCIE_HCPWM2_8822B 0 +#define BIT_MASK_PCIE_HCPWM2_8822B 0xffff +#define BIT_PCIE_HCPWM2_8822B(x) \ + (((x) & BIT_MASK_PCIE_HCPWM2_8822B) << BIT_SHIFT_PCIE_HCPWM2_8822B) +#define BIT_GET_PCIE_HCPWM2_8822B(x) \ + (((x) >> BIT_SHIFT_PCIE_HCPWM2_8822B) & BIT_MASK_PCIE_HCPWM2_8822B) + +/* 2 REG_PCIE_H2C_MSG_V1_8822B */ + +#define BIT_SHIFT_DRV2FW_INFO_8822B 0 +#define BIT_MASK_DRV2FW_INFO_8822B 0xffffffffL +#define BIT_DRV2FW_INFO_8822B(x) \ + (((x) & BIT_MASK_DRV2FW_INFO_8822B) << BIT_SHIFT_DRV2FW_INFO_8822B) +#define BIT_GET_DRV2FW_INFO_8822B(x) \ + (((x) >> BIT_SHIFT_DRV2FW_INFO_8822B) & BIT_MASK_DRV2FW_INFO_8822B) + +/* 2 REG_PCIE_C2H_MSG_V1_8822B */ + +#define BIT_SHIFT_HCI_PCIE_C2H_MSG_8822B 0 +#define BIT_MASK_HCI_PCIE_C2H_MSG_8822B 0xffffffffL +#define BIT_HCI_PCIE_C2H_MSG_8822B(x) \ + (((x) & BIT_MASK_HCI_PCIE_C2H_MSG_8822B) \ + << BIT_SHIFT_HCI_PCIE_C2H_MSG_8822B) +#define BIT_GET_HCI_PCIE_C2H_MSG_8822B(x) \ + (((x) >> BIT_SHIFT_HCI_PCIE_C2H_MSG_8822B) & \ + BIT_MASK_HCI_PCIE_C2H_MSG_8822B) + +/* 2 REG_DBI_WDATA_V1_8822B */ + +#define BIT_SHIFT_DBI_WDATA_8822B 0 +#define BIT_MASK_DBI_WDATA_8822B 0xffffffffL +#define BIT_DBI_WDATA_8822B(x) \ + (((x) & BIT_MASK_DBI_WDATA_8822B) << BIT_SHIFT_DBI_WDATA_8822B) +#define BIT_GET_DBI_WDATA_8822B(x) \ + (((x) >> BIT_SHIFT_DBI_WDATA_8822B) & BIT_MASK_DBI_WDATA_8822B) + +/* 2 REG_DBI_RDATA_V1_8822B */ + +#define BIT_SHIFT_DBI_RDATA_8822B 0 +#define BIT_MASK_DBI_RDATA_8822B 0xffffffffL +#define BIT_DBI_RDATA_8822B(x) \ + (((x) & BIT_MASK_DBI_RDATA_8822B) << BIT_SHIFT_DBI_RDATA_8822B) +#define BIT_GET_DBI_RDATA_8822B(x) \ + (((x) >> BIT_SHIFT_DBI_RDATA_8822B) & BIT_MASK_DBI_RDATA_8822B) + +/* 2 REG_DBI_FLAG_V1_8822B */ +#define BIT_EN_STUCK_DBG_8822B BIT(26) +#define BIT_RX_STUCK_8822B BIT(25) +#define BIT_TX_STUCK_8822B BIT(24) +#define BIT_DBI_RFLAG_8822B BIT(17) +#define BIT_DBI_WFLAG_8822B BIT(16) + +#define BIT_SHIFT_DBI_WREN_8822B 12 +#define BIT_MASK_DBI_WREN_8822B 0xf +#define BIT_DBI_WREN_8822B(x) \ + (((x) & BIT_MASK_DBI_WREN_8822B) << BIT_SHIFT_DBI_WREN_8822B) +#define BIT_GET_DBI_WREN_8822B(x) \ + (((x) >> BIT_SHIFT_DBI_WREN_8822B) & BIT_MASK_DBI_WREN_8822B) + +#define BIT_SHIFT_DBI_ADDR_8822B 0 +#define BIT_MASK_DBI_ADDR_8822B 0xfff +#define BIT_DBI_ADDR_8822B(x) \ + (((x) & BIT_MASK_DBI_ADDR_8822B) << BIT_SHIFT_DBI_ADDR_8822B) +#define BIT_GET_DBI_ADDR_8822B(x) \ + (((x) >> BIT_SHIFT_DBI_ADDR_8822B) & BIT_MASK_DBI_ADDR_8822B) + +/* 2 REG_MDIO_V1_8822B */ + +#define BIT_SHIFT_MDIO_RDATA_8822B 16 +#define BIT_MASK_MDIO_RDATA_8822B 0xffff +#define BIT_MDIO_RDATA_8822B(x) \ + (((x) & BIT_MASK_MDIO_RDATA_8822B) << BIT_SHIFT_MDIO_RDATA_8822B) +#define BIT_GET_MDIO_RDATA_8822B(x) \ + (((x) >> BIT_SHIFT_MDIO_RDATA_8822B) & BIT_MASK_MDIO_RDATA_8822B) + +#define BIT_SHIFT_MDIO_WDATA_8822B 0 +#define BIT_MASK_MDIO_WDATA_8822B 0xffff +#define BIT_MDIO_WDATA_8822B(x) \ + (((x) & BIT_MASK_MDIO_WDATA_8822B) << BIT_SHIFT_MDIO_WDATA_8822B) +#define BIT_GET_MDIO_WDATA_8822B(x) \ + (((x) >> BIT_SHIFT_MDIO_WDATA_8822B) & BIT_MASK_MDIO_WDATA_8822B) + +/* 2 REG_PCIE_MIX_CFG_8822B */ + +#define BIT_SHIFT_MDIO_PHY_ADDR_8822B 24 +#define BIT_MASK_MDIO_PHY_ADDR_8822B 0x1f +#define BIT_MDIO_PHY_ADDR_8822B(x) \ + (((x) & BIT_MASK_MDIO_PHY_ADDR_8822B) << BIT_SHIFT_MDIO_PHY_ADDR_8822B) +#define BIT_GET_MDIO_PHY_ADDR_8822B(x) \ + (((x) >> BIT_SHIFT_MDIO_PHY_ADDR_8822B) & BIT_MASK_MDIO_PHY_ADDR_8822B) + +#define BIT_SHIFT_WATCH_DOG_RECORD_V1_8822B 10 +#define BIT_MASK_WATCH_DOG_RECORD_V1_8822B 0x3fff +#define BIT_WATCH_DOG_RECORD_V1_8822B(x) \ + (((x) & BIT_MASK_WATCH_DOG_RECORD_V1_8822B) \ + << BIT_SHIFT_WATCH_DOG_RECORD_V1_8822B) +#define BIT_GET_WATCH_DOG_RECORD_V1_8822B(x) \ + (((x) >> BIT_SHIFT_WATCH_DOG_RECORD_V1_8822B) & \ + BIT_MASK_WATCH_DOG_RECORD_V1_8822B) + +#define BIT_R_IO_TIMEOUT_FLAG_V1_8822B BIT(9) +#define BIT_EN_WATCH_DOG_8822B BIT(8) +#define BIT_ECRC_EN_V1_8822B BIT(7) +#define BIT_MDIO_RFLAG_V1_8822B BIT(6) +#define BIT_MDIO_WFLAG_V1_8822B BIT(5) + +#define BIT_SHIFT_MDIO_REG_ADDR_V1_8822B 0 +#define BIT_MASK_MDIO_REG_ADDR_V1_8822B 0x1f +#define BIT_MDIO_REG_ADDR_V1_8822B(x) \ + (((x) & BIT_MASK_MDIO_REG_ADDR_V1_8822B) \ + << BIT_SHIFT_MDIO_REG_ADDR_V1_8822B) +#define BIT_GET_MDIO_REG_ADDR_V1_8822B(x) \ + (((x) >> BIT_SHIFT_MDIO_REG_ADDR_V1_8822B) & \ + BIT_MASK_MDIO_REG_ADDR_V1_8822B) + +/* 2 REG_HCI_MIX_CFG_8822B */ +#define BIT_HOST_GEN2_SUPPORT_8822B BIT(20) + +#define BIT_SHIFT_TXDMA_ERR_FLAG_8822B 16 +#define BIT_MASK_TXDMA_ERR_FLAG_8822B 0xf +#define BIT_TXDMA_ERR_FLAG_8822B(x) \ + (((x) & BIT_MASK_TXDMA_ERR_FLAG_8822B) \ + << BIT_SHIFT_TXDMA_ERR_FLAG_8822B) +#define BIT_GET_TXDMA_ERR_FLAG_8822B(x) \ + (((x) >> BIT_SHIFT_TXDMA_ERR_FLAG_8822B) & \ + BIT_MASK_TXDMA_ERR_FLAG_8822B) + +#define BIT_SHIFT_EARLY_MODE_SEL_8822B 12 +#define BIT_MASK_EARLY_MODE_SEL_8822B 0xf +#define BIT_EARLY_MODE_SEL_8822B(x) \ + (((x) & BIT_MASK_EARLY_MODE_SEL_8822B) \ + << BIT_SHIFT_EARLY_MODE_SEL_8822B) +#define BIT_GET_EARLY_MODE_SEL_8822B(x) \ + (((x) >> BIT_SHIFT_EARLY_MODE_SEL_8822B) & \ + BIT_MASK_EARLY_MODE_SEL_8822B) + +#define BIT_EPHY_RX50_EN_8822B BIT(11) + +#define BIT_SHIFT_MSI_TIMEOUT_ID_V1_8822B 8 +#define BIT_MASK_MSI_TIMEOUT_ID_V1_8822B 0x7 +#define BIT_MSI_TIMEOUT_ID_V1_8822B(x) \ + (((x) & BIT_MASK_MSI_TIMEOUT_ID_V1_8822B) \ + << BIT_SHIFT_MSI_TIMEOUT_ID_V1_8822B) +#define BIT_GET_MSI_TIMEOUT_ID_V1_8822B(x) \ + (((x) >> BIT_SHIFT_MSI_TIMEOUT_ID_V1_8822B) & \ + BIT_MASK_MSI_TIMEOUT_ID_V1_8822B) + +#define BIT_RADDR_RD_8822B BIT(7) +#define BIT_EN_MUL_TAG_8822B BIT(6) +#define BIT_EN_EARLY_MODE_8822B BIT(5) +#define BIT_L0S_LINK_OFF_8822B BIT(4) +#define BIT_ACT_LINK_OFF_8822B BIT(3) +#define BIT_EN_SLOW_MAC_TX_8822B BIT(2) +#define BIT_EN_SLOW_MAC_RX_8822B BIT(1) + +/* 2 REG_STC_INT_CS_8822B(PCIE STATE CHANGE INTERRUPT CONTROL AND STATUS) */ +#define BIT_STC_INT_EN_8822B BIT(31) + +#define BIT_SHIFT_STC_INT_FLAG_8822B 16 +#define BIT_MASK_STC_INT_FLAG_8822B 0xff +#define BIT_STC_INT_FLAG_8822B(x) \ + (((x) & BIT_MASK_STC_INT_FLAG_8822B) << BIT_SHIFT_STC_INT_FLAG_8822B) +#define BIT_GET_STC_INT_FLAG_8822B(x) \ + (((x) >> BIT_SHIFT_STC_INT_FLAG_8822B) & BIT_MASK_STC_INT_FLAG_8822B) + +#define BIT_SHIFT_STC_INT_IDX_8822B 8 +#define BIT_MASK_STC_INT_IDX_8822B 0x7 +#define BIT_STC_INT_IDX_8822B(x) \ + (((x) & BIT_MASK_STC_INT_IDX_8822B) << BIT_SHIFT_STC_INT_IDX_8822B) +#define BIT_GET_STC_INT_IDX_8822B(x) \ + (((x) >> BIT_SHIFT_STC_INT_IDX_8822B) & BIT_MASK_STC_INT_IDX_8822B) + +#define BIT_SHIFT_STC_INT_REALTIME_CS_8822B 0 +#define BIT_MASK_STC_INT_REALTIME_CS_8822B 0x3f +#define BIT_STC_INT_REALTIME_CS_8822B(x) \ + (((x) & BIT_MASK_STC_INT_REALTIME_CS_8822B) \ + << BIT_SHIFT_STC_INT_REALTIME_CS_8822B) +#define BIT_GET_STC_INT_REALTIME_CS_8822B(x) \ + (((x) >> BIT_SHIFT_STC_INT_REALTIME_CS_8822B) & \ + BIT_MASK_STC_INT_REALTIME_CS_8822B) + +/* 2 REG_ST_INT_CFG_8822B(PCIE STATE CHANGE INTERRUPT CONFIGURATION) */ +#define BIT_STC_INT_GRP_EN_8822B BIT(31) + +#define BIT_SHIFT_STC_INT_EXPECT_LS_8822B 8 +#define BIT_MASK_STC_INT_EXPECT_LS_8822B 0x3f +#define BIT_STC_INT_EXPECT_LS_8822B(x) \ + (((x) & BIT_MASK_STC_INT_EXPECT_LS_8822B) \ + << BIT_SHIFT_STC_INT_EXPECT_LS_8822B) +#define BIT_GET_STC_INT_EXPECT_LS_8822B(x) \ + (((x) >> BIT_SHIFT_STC_INT_EXPECT_LS_8822B) & \ + BIT_MASK_STC_INT_EXPECT_LS_8822B) + +#define BIT_SHIFT_STC_INT_EXPECT_CS_8822B 0 +#define BIT_MASK_STC_INT_EXPECT_CS_8822B 0x3f +#define BIT_STC_INT_EXPECT_CS_8822B(x) \ + (((x) & BIT_MASK_STC_INT_EXPECT_CS_8822B) \ + << BIT_SHIFT_STC_INT_EXPECT_CS_8822B) +#define BIT_GET_STC_INT_EXPECT_CS_8822B(x) \ + (((x) >> BIT_SHIFT_STC_INT_EXPECT_CS_8822B) & \ + BIT_MASK_STC_INT_EXPECT_CS_8822B) + +/* 2 REG_CMU_DLY_CTRL_8822B(PCIE PHY CLOCK MGT UNIT DELAY CONTROL ) */ +#define BIT_CMU_DLY_EN_8822B BIT(31) +#define BIT_CMU_DLY_MODE_8822B BIT(30) + +#define BIT_SHIFT_CMU_DLY_PRE_DIV_8822B 0 +#define BIT_MASK_CMU_DLY_PRE_DIV_8822B 0xff +#define BIT_CMU_DLY_PRE_DIV_8822B(x) \ + (((x) & BIT_MASK_CMU_DLY_PRE_DIV_8822B) \ + << BIT_SHIFT_CMU_DLY_PRE_DIV_8822B) +#define BIT_GET_CMU_DLY_PRE_DIV_8822B(x) \ + (((x) >> BIT_SHIFT_CMU_DLY_PRE_DIV_8822B) & \ + BIT_MASK_CMU_DLY_PRE_DIV_8822B) + +/* 2 REG_CMU_DLY_CFG_8822B(PCIE PHY CLOCK MGT UNIT DELAY CONFIGURATION ) */ + +#define BIT_SHIFT_CMU_DLY_LTR_A2I_8822B 24 +#define BIT_MASK_CMU_DLY_LTR_A2I_8822B 0xff +#define BIT_CMU_DLY_LTR_A2I_8822B(x) \ + (((x) & BIT_MASK_CMU_DLY_LTR_A2I_8822B) \ + << BIT_SHIFT_CMU_DLY_LTR_A2I_8822B) +#define BIT_GET_CMU_DLY_LTR_A2I_8822B(x) \ + (((x) >> BIT_SHIFT_CMU_DLY_LTR_A2I_8822B) & \ + BIT_MASK_CMU_DLY_LTR_A2I_8822B) + +#define BIT_SHIFT_CMU_DLY_LTR_I2A_8822B 16 +#define BIT_MASK_CMU_DLY_LTR_I2A_8822B 0xff +#define BIT_CMU_DLY_LTR_I2A_8822B(x) \ + (((x) & BIT_MASK_CMU_DLY_LTR_I2A_8822B) \ + << BIT_SHIFT_CMU_DLY_LTR_I2A_8822B) +#define BIT_GET_CMU_DLY_LTR_I2A_8822B(x) \ + (((x) >> BIT_SHIFT_CMU_DLY_LTR_I2A_8822B) & \ + BIT_MASK_CMU_DLY_LTR_I2A_8822B) + +#define BIT_SHIFT_CMU_DLY_LTR_IDLE_8822B 8 +#define BIT_MASK_CMU_DLY_LTR_IDLE_8822B 0xff +#define BIT_CMU_DLY_LTR_IDLE_8822B(x) \ + (((x) & BIT_MASK_CMU_DLY_LTR_IDLE_8822B) \ + << BIT_SHIFT_CMU_DLY_LTR_IDLE_8822B) +#define BIT_GET_CMU_DLY_LTR_IDLE_8822B(x) \ + (((x) >> BIT_SHIFT_CMU_DLY_LTR_IDLE_8822B) & \ + BIT_MASK_CMU_DLY_LTR_IDLE_8822B) + +#define BIT_SHIFT_CMU_DLY_LTR_ACT_8822B 0 +#define BIT_MASK_CMU_DLY_LTR_ACT_8822B 0xff +#define BIT_CMU_DLY_LTR_ACT_8822B(x) \ + (((x) & BIT_MASK_CMU_DLY_LTR_ACT_8822B) \ + << BIT_SHIFT_CMU_DLY_LTR_ACT_8822B) +#define BIT_GET_CMU_DLY_LTR_ACT_8822B(x) \ + (((x) >> BIT_SHIFT_CMU_DLY_LTR_ACT_8822B) & \ + BIT_MASK_CMU_DLY_LTR_ACT_8822B) + +/* 2 REG_H2CQ_TXBD_DESA_8822B */ + +#define BIT_SHIFT_H2CQ_TXBD_DESA_8822B 0 +#define BIT_MASK_H2CQ_TXBD_DESA_8822B 0xffffffffffffffffL +#define BIT_H2CQ_TXBD_DESA_8822B(x) \ + (((x) & BIT_MASK_H2CQ_TXBD_DESA_8822B) \ + << BIT_SHIFT_H2CQ_TXBD_DESA_8822B) +#define BIT_GET_H2CQ_TXBD_DESA_8822B(x) \ + (((x) >> BIT_SHIFT_H2CQ_TXBD_DESA_8822B) & \ + BIT_MASK_H2CQ_TXBD_DESA_8822B) + +/* 2 REG_H2CQ_TXBD_NUM_8822B */ +#define BIT_PCIE_H2CQ_FLAG_8822B BIT(14) + +#define BIT_SHIFT_H2CQ_DESC_MODE_8822B 12 +#define BIT_MASK_H2CQ_DESC_MODE_8822B 0x3 +#define BIT_H2CQ_DESC_MODE_8822B(x) \ + (((x) & BIT_MASK_H2CQ_DESC_MODE_8822B) \ + << BIT_SHIFT_H2CQ_DESC_MODE_8822B) +#define BIT_GET_H2CQ_DESC_MODE_8822B(x) \ + (((x) >> BIT_SHIFT_H2CQ_DESC_MODE_8822B) & \ + BIT_MASK_H2CQ_DESC_MODE_8822B) + +#define BIT_SHIFT_H2CQ_DESC_NUM_8822B 0 +#define BIT_MASK_H2CQ_DESC_NUM_8822B 0xfff +#define BIT_H2CQ_DESC_NUM_8822B(x) \ + (((x) & BIT_MASK_H2CQ_DESC_NUM_8822B) << BIT_SHIFT_H2CQ_DESC_NUM_8822B) +#define BIT_GET_H2CQ_DESC_NUM_8822B(x) \ + (((x) >> BIT_SHIFT_H2CQ_DESC_NUM_8822B) & BIT_MASK_H2CQ_DESC_NUM_8822B) + +/* 2 REG_H2CQ_TXBD_IDX_8822B */ + +#define BIT_SHIFT_H2CQ_HW_IDX_8822B 16 +#define BIT_MASK_H2CQ_HW_IDX_8822B 0xfff +#define BIT_H2CQ_HW_IDX_8822B(x) \ + (((x) & BIT_MASK_H2CQ_HW_IDX_8822B) << BIT_SHIFT_H2CQ_HW_IDX_8822B) +#define BIT_GET_H2CQ_HW_IDX_8822B(x) \ + (((x) >> BIT_SHIFT_H2CQ_HW_IDX_8822B) & BIT_MASK_H2CQ_HW_IDX_8822B) + +#define BIT_SHIFT_H2CQ_HOST_IDX_8822B 0 +#define BIT_MASK_H2CQ_HOST_IDX_8822B 0xfff +#define BIT_H2CQ_HOST_IDX_8822B(x) \ + (((x) & BIT_MASK_H2CQ_HOST_IDX_8822B) << BIT_SHIFT_H2CQ_HOST_IDX_8822B) +#define BIT_GET_H2CQ_HOST_IDX_8822B(x) \ + (((x) >> BIT_SHIFT_H2CQ_HOST_IDX_8822B) & BIT_MASK_H2CQ_HOST_IDX_8822B) + +/* 2 REG_H2CQ_CSR_8822B[31:0] (H2CQ CONTROL AND STATUS) */ +#define BIT_H2CQ_FULL_8822B BIT(31) +#define BIT_CLR_H2CQ_HOST_IDX_8822B BIT(16) +#define BIT_CLR_H2CQ_HW_IDX_8822B BIT(8) + +/* 2 REG_CHANGE_PCIE_SPEED_8822B */ +#define BIT_CHANGE_PCIE_SPEED_8822B BIT(18) + +#define BIT_SHIFT_GEN1_GEN2_8822B 16 +#define BIT_MASK_GEN1_GEN2_8822B 0x3 +#define BIT_GEN1_GEN2_8822B(x) \ + (((x) & BIT_MASK_GEN1_GEN2_8822B) << BIT_SHIFT_GEN1_GEN2_8822B) +#define BIT_GET_GEN1_GEN2_8822B(x) \ + (((x) >> BIT_SHIFT_GEN1_GEN2_8822B) & BIT_MASK_GEN1_GEN2_8822B) + +#define BIT_SHIFT_AUTO_HANG_RELEASE_8822B 0 +#define BIT_MASK_AUTO_HANG_RELEASE_8822B 0x7 +#define BIT_AUTO_HANG_RELEASE_8822B(x) \ + (((x) & BIT_MASK_AUTO_HANG_RELEASE_8822B) \ + << BIT_SHIFT_AUTO_HANG_RELEASE_8822B) +#define BIT_GET_AUTO_HANG_RELEASE_8822B(x) \ + (((x) >> BIT_SHIFT_AUTO_HANG_RELEASE_8822B) & \ + BIT_MASK_AUTO_HANG_RELEASE_8822B) + +/* 2 REG_OLD_DEHANG_8822B */ +#define BIT_OLD_DEHANG_8822B BIT(1) + +/* 2 REG_Q0_INFO_8822B */ + +#define BIT_SHIFT_QUEUEMACID_Q0_V1_8822B 25 +#define BIT_MASK_QUEUEMACID_Q0_V1_8822B 0x7f +#define BIT_QUEUEMACID_Q0_V1_8822B(x) \ + (((x) & BIT_MASK_QUEUEMACID_Q0_V1_8822B) \ + << BIT_SHIFT_QUEUEMACID_Q0_V1_8822B) +#define BIT_GET_QUEUEMACID_Q0_V1_8822B(x) \ + (((x) >> BIT_SHIFT_QUEUEMACID_Q0_V1_8822B) & \ + BIT_MASK_QUEUEMACID_Q0_V1_8822B) + +#define BIT_SHIFT_QUEUEAC_Q0_V1_8822B 23 +#define BIT_MASK_QUEUEAC_Q0_V1_8822B 0x3 +#define BIT_QUEUEAC_Q0_V1_8822B(x) \ + (((x) & BIT_MASK_QUEUEAC_Q0_V1_8822B) << BIT_SHIFT_QUEUEAC_Q0_V1_8822B) +#define BIT_GET_QUEUEAC_Q0_V1_8822B(x) \ + (((x) >> BIT_SHIFT_QUEUEAC_Q0_V1_8822B) & BIT_MASK_QUEUEAC_Q0_V1_8822B) + +#define BIT_TIDEMPTY_Q0_V1_8822B BIT(22) + +#define BIT_SHIFT_TAIL_PKT_Q0_V2_8822B 11 +#define BIT_MASK_TAIL_PKT_Q0_V2_8822B 0x7ff +#define BIT_TAIL_PKT_Q0_V2_8822B(x) \ + (((x) & BIT_MASK_TAIL_PKT_Q0_V2_8822B) \ + << BIT_SHIFT_TAIL_PKT_Q0_V2_8822B) +#define BIT_GET_TAIL_PKT_Q0_V2_8822B(x) \ + (((x) >> BIT_SHIFT_TAIL_PKT_Q0_V2_8822B) & \ + BIT_MASK_TAIL_PKT_Q0_V2_8822B) + +#define BIT_SHIFT_HEAD_PKT_Q0_V1_8822B 0 +#define BIT_MASK_HEAD_PKT_Q0_V1_8822B 0x7ff +#define BIT_HEAD_PKT_Q0_V1_8822B(x) \ + (((x) & BIT_MASK_HEAD_PKT_Q0_V1_8822B) \ + << BIT_SHIFT_HEAD_PKT_Q0_V1_8822B) +#define BIT_GET_HEAD_PKT_Q0_V1_8822B(x) \ + (((x) >> BIT_SHIFT_HEAD_PKT_Q0_V1_8822B) & \ + BIT_MASK_HEAD_PKT_Q0_V1_8822B) + +/* 2 REG_Q1_INFO_8822B */ + +#define BIT_SHIFT_QUEUEMACID_Q1_V1_8822B 25 +#define BIT_MASK_QUEUEMACID_Q1_V1_8822B 0x7f +#define BIT_QUEUEMACID_Q1_V1_8822B(x) \ + (((x) & BIT_MASK_QUEUEMACID_Q1_V1_8822B) \ + << BIT_SHIFT_QUEUEMACID_Q1_V1_8822B) +#define BIT_GET_QUEUEMACID_Q1_V1_8822B(x) \ + (((x) >> BIT_SHIFT_QUEUEMACID_Q1_V1_8822B) & \ + BIT_MASK_QUEUEMACID_Q1_V1_8822B) + +#define BIT_SHIFT_QUEUEAC_Q1_V1_8822B 23 +#define BIT_MASK_QUEUEAC_Q1_V1_8822B 0x3 +#define BIT_QUEUEAC_Q1_V1_8822B(x) \ + (((x) & BIT_MASK_QUEUEAC_Q1_V1_8822B) << BIT_SHIFT_QUEUEAC_Q1_V1_8822B) +#define BIT_GET_QUEUEAC_Q1_V1_8822B(x) \ + (((x) >> BIT_SHIFT_QUEUEAC_Q1_V1_8822B) & BIT_MASK_QUEUEAC_Q1_V1_8822B) + +#define BIT_TIDEMPTY_Q1_V1_8822B BIT(22) + +#define BIT_SHIFT_TAIL_PKT_Q1_V2_8822B 11 +#define BIT_MASK_TAIL_PKT_Q1_V2_8822B 0x7ff +#define BIT_TAIL_PKT_Q1_V2_8822B(x) \ + (((x) & BIT_MASK_TAIL_PKT_Q1_V2_8822B) \ + << BIT_SHIFT_TAIL_PKT_Q1_V2_8822B) +#define BIT_GET_TAIL_PKT_Q1_V2_8822B(x) \ + (((x) >> BIT_SHIFT_TAIL_PKT_Q1_V2_8822B) & \ + BIT_MASK_TAIL_PKT_Q1_V2_8822B) + +#define BIT_SHIFT_HEAD_PKT_Q1_V1_8822B 0 +#define BIT_MASK_HEAD_PKT_Q1_V1_8822B 0x7ff +#define BIT_HEAD_PKT_Q1_V1_8822B(x) \ + (((x) & BIT_MASK_HEAD_PKT_Q1_V1_8822B) \ + << BIT_SHIFT_HEAD_PKT_Q1_V1_8822B) +#define BIT_GET_HEAD_PKT_Q1_V1_8822B(x) \ + (((x) >> BIT_SHIFT_HEAD_PKT_Q1_V1_8822B) & \ + BIT_MASK_HEAD_PKT_Q1_V1_8822B) + +/* 2 REG_Q2_INFO_8822B */ + +#define BIT_SHIFT_QUEUEMACID_Q2_V1_8822B 25 +#define BIT_MASK_QUEUEMACID_Q2_V1_8822B 0x7f +#define BIT_QUEUEMACID_Q2_V1_8822B(x) \ + (((x) & BIT_MASK_QUEUEMACID_Q2_V1_8822B) \ + << BIT_SHIFT_QUEUEMACID_Q2_V1_8822B) +#define BIT_GET_QUEUEMACID_Q2_V1_8822B(x) \ + (((x) >> BIT_SHIFT_QUEUEMACID_Q2_V1_8822B) & \ + BIT_MASK_QUEUEMACID_Q2_V1_8822B) + +#define BIT_SHIFT_QUEUEAC_Q2_V1_8822B 23 +#define BIT_MASK_QUEUEAC_Q2_V1_8822B 0x3 +#define BIT_QUEUEAC_Q2_V1_8822B(x) \ + (((x) & BIT_MASK_QUEUEAC_Q2_V1_8822B) << BIT_SHIFT_QUEUEAC_Q2_V1_8822B) +#define BIT_GET_QUEUEAC_Q2_V1_8822B(x) \ + (((x) >> BIT_SHIFT_QUEUEAC_Q2_V1_8822B) & BIT_MASK_QUEUEAC_Q2_V1_8822B) + +#define BIT_TIDEMPTY_Q2_V1_8822B BIT(22) + +#define BIT_SHIFT_TAIL_PKT_Q2_V2_8822B 11 +#define BIT_MASK_TAIL_PKT_Q2_V2_8822B 0x7ff +#define BIT_TAIL_PKT_Q2_V2_8822B(x) \ + (((x) & BIT_MASK_TAIL_PKT_Q2_V2_8822B) \ + << BIT_SHIFT_TAIL_PKT_Q2_V2_8822B) +#define BIT_GET_TAIL_PKT_Q2_V2_8822B(x) \ + (((x) >> BIT_SHIFT_TAIL_PKT_Q2_V2_8822B) & \ + BIT_MASK_TAIL_PKT_Q2_V2_8822B) + +#define BIT_SHIFT_HEAD_PKT_Q2_V1_8822B 0 +#define BIT_MASK_HEAD_PKT_Q2_V1_8822B 0x7ff +#define BIT_HEAD_PKT_Q2_V1_8822B(x) \ + (((x) & BIT_MASK_HEAD_PKT_Q2_V1_8822B) \ + << BIT_SHIFT_HEAD_PKT_Q2_V1_8822B) +#define BIT_GET_HEAD_PKT_Q2_V1_8822B(x) \ + (((x) >> BIT_SHIFT_HEAD_PKT_Q2_V1_8822B) & \ + BIT_MASK_HEAD_PKT_Q2_V1_8822B) + +/* 2 REG_Q3_INFO_8822B */ + +#define BIT_SHIFT_QUEUEMACID_Q3_V1_8822B 25 +#define BIT_MASK_QUEUEMACID_Q3_V1_8822B 0x7f +#define BIT_QUEUEMACID_Q3_V1_8822B(x) \ + (((x) & BIT_MASK_QUEUEMACID_Q3_V1_8822B) \ + << BIT_SHIFT_QUEUEMACID_Q3_V1_8822B) +#define BIT_GET_QUEUEMACID_Q3_V1_8822B(x) \ + (((x) >> BIT_SHIFT_QUEUEMACID_Q3_V1_8822B) & \ + BIT_MASK_QUEUEMACID_Q3_V1_8822B) + +#define BIT_SHIFT_QUEUEAC_Q3_V1_8822B 23 +#define BIT_MASK_QUEUEAC_Q3_V1_8822B 0x3 +#define BIT_QUEUEAC_Q3_V1_8822B(x) \ + (((x) & BIT_MASK_QUEUEAC_Q3_V1_8822B) << BIT_SHIFT_QUEUEAC_Q3_V1_8822B) +#define BIT_GET_QUEUEAC_Q3_V1_8822B(x) \ + (((x) >> BIT_SHIFT_QUEUEAC_Q3_V1_8822B) & BIT_MASK_QUEUEAC_Q3_V1_8822B) + +#define BIT_TIDEMPTY_Q3_V1_8822B BIT(22) + +#define BIT_SHIFT_TAIL_PKT_Q3_V2_8822B 11 +#define BIT_MASK_TAIL_PKT_Q3_V2_8822B 0x7ff +#define BIT_TAIL_PKT_Q3_V2_8822B(x) \ + (((x) & BIT_MASK_TAIL_PKT_Q3_V2_8822B) \ + << BIT_SHIFT_TAIL_PKT_Q3_V2_8822B) +#define BIT_GET_TAIL_PKT_Q3_V2_8822B(x) \ + (((x) >> BIT_SHIFT_TAIL_PKT_Q3_V2_8822B) & \ + BIT_MASK_TAIL_PKT_Q3_V2_8822B) + +#define BIT_SHIFT_HEAD_PKT_Q3_V1_8822B 0 +#define BIT_MASK_HEAD_PKT_Q3_V1_8822B 0x7ff +#define BIT_HEAD_PKT_Q3_V1_8822B(x) \ + (((x) & BIT_MASK_HEAD_PKT_Q3_V1_8822B) \ + << BIT_SHIFT_HEAD_PKT_Q3_V1_8822B) +#define BIT_GET_HEAD_PKT_Q3_V1_8822B(x) \ + (((x) >> BIT_SHIFT_HEAD_PKT_Q3_V1_8822B) & \ + BIT_MASK_HEAD_PKT_Q3_V1_8822B) + +/* 2 REG_MGQ_INFO_8822B */ + +#define BIT_SHIFT_QUEUEMACID_MGQ_V1_8822B 25 +#define BIT_MASK_QUEUEMACID_MGQ_V1_8822B 0x7f +#define BIT_QUEUEMACID_MGQ_V1_8822B(x) \ + (((x) & BIT_MASK_QUEUEMACID_MGQ_V1_8822B) \ + << BIT_SHIFT_QUEUEMACID_MGQ_V1_8822B) +#define BIT_GET_QUEUEMACID_MGQ_V1_8822B(x) \ + (((x) >> BIT_SHIFT_QUEUEMACID_MGQ_V1_8822B) & \ + BIT_MASK_QUEUEMACID_MGQ_V1_8822B) + +#define BIT_SHIFT_QUEUEAC_MGQ_V1_8822B 23 +#define BIT_MASK_QUEUEAC_MGQ_V1_8822B 0x3 +#define BIT_QUEUEAC_MGQ_V1_8822B(x) \ + (((x) & BIT_MASK_QUEUEAC_MGQ_V1_8822B) \ + << BIT_SHIFT_QUEUEAC_MGQ_V1_8822B) +#define BIT_GET_QUEUEAC_MGQ_V1_8822B(x) \ + (((x) >> BIT_SHIFT_QUEUEAC_MGQ_V1_8822B) & \ + BIT_MASK_QUEUEAC_MGQ_V1_8822B) + +#define BIT_TIDEMPTY_MGQ_V1_8822B BIT(22) + +#define BIT_SHIFT_TAIL_PKT_MGQ_V2_8822B 11 +#define BIT_MASK_TAIL_PKT_MGQ_V2_8822B 0x7ff +#define BIT_TAIL_PKT_MGQ_V2_8822B(x) \ + (((x) & BIT_MASK_TAIL_PKT_MGQ_V2_8822B) \ + << BIT_SHIFT_TAIL_PKT_MGQ_V2_8822B) +#define BIT_GET_TAIL_PKT_MGQ_V2_8822B(x) \ + (((x) >> BIT_SHIFT_TAIL_PKT_MGQ_V2_8822B) & \ + BIT_MASK_TAIL_PKT_MGQ_V2_8822B) + +#define BIT_SHIFT_HEAD_PKT_MGQ_V1_8822B 0 +#define BIT_MASK_HEAD_PKT_MGQ_V1_8822B 0x7ff +#define BIT_HEAD_PKT_MGQ_V1_8822B(x) \ + (((x) & BIT_MASK_HEAD_PKT_MGQ_V1_8822B) \ + << BIT_SHIFT_HEAD_PKT_MGQ_V1_8822B) +#define BIT_GET_HEAD_PKT_MGQ_V1_8822B(x) \ + (((x) >> BIT_SHIFT_HEAD_PKT_MGQ_V1_8822B) & \ + BIT_MASK_HEAD_PKT_MGQ_V1_8822B) + +/* 2 REG_HIQ_INFO_8822B */ + +#define BIT_SHIFT_QUEUEMACID_HIQ_V1_8822B 25 +#define BIT_MASK_QUEUEMACID_HIQ_V1_8822B 0x7f +#define BIT_QUEUEMACID_HIQ_V1_8822B(x) \ + (((x) & BIT_MASK_QUEUEMACID_HIQ_V1_8822B) \ + << BIT_SHIFT_QUEUEMACID_HIQ_V1_8822B) +#define BIT_GET_QUEUEMACID_HIQ_V1_8822B(x) \ + (((x) >> BIT_SHIFT_QUEUEMACID_HIQ_V1_8822B) & \ + BIT_MASK_QUEUEMACID_HIQ_V1_8822B) + +#define BIT_SHIFT_QUEUEAC_HIQ_V1_8822B 23 +#define BIT_MASK_QUEUEAC_HIQ_V1_8822B 0x3 +#define BIT_QUEUEAC_HIQ_V1_8822B(x) \ + (((x) & BIT_MASK_QUEUEAC_HIQ_V1_8822B) \ + << BIT_SHIFT_QUEUEAC_HIQ_V1_8822B) +#define BIT_GET_QUEUEAC_HIQ_V1_8822B(x) \ + (((x) >> BIT_SHIFT_QUEUEAC_HIQ_V1_8822B) & \ + BIT_MASK_QUEUEAC_HIQ_V1_8822B) + +#define BIT_TIDEMPTY_HIQ_V1_8822B BIT(22) + +#define BIT_SHIFT_TAIL_PKT_HIQ_V2_8822B 11 +#define BIT_MASK_TAIL_PKT_HIQ_V2_8822B 0x7ff +#define BIT_TAIL_PKT_HIQ_V2_8822B(x) \ + (((x) & BIT_MASK_TAIL_PKT_HIQ_V2_8822B) \ + << BIT_SHIFT_TAIL_PKT_HIQ_V2_8822B) +#define BIT_GET_TAIL_PKT_HIQ_V2_8822B(x) \ + (((x) >> BIT_SHIFT_TAIL_PKT_HIQ_V2_8822B) & \ + BIT_MASK_TAIL_PKT_HIQ_V2_8822B) + +#define BIT_SHIFT_HEAD_PKT_HIQ_V1_8822B 0 +#define BIT_MASK_HEAD_PKT_HIQ_V1_8822B 0x7ff +#define BIT_HEAD_PKT_HIQ_V1_8822B(x) \ + (((x) & BIT_MASK_HEAD_PKT_HIQ_V1_8822B) \ + << BIT_SHIFT_HEAD_PKT_HIQ_V1_8822B) +#define BIT_GET_HEAD_PKT_HIQ_V1_8822B(x) \ + (((x) >> BIT_SHIFT_HEAD_PKT_HIQ_V1_8822B) & \ + BIT_MASK_HEAD_PKT_HIQ_V1_8822B) + +/* 2 REG_BCNQ_INFO_8822B */ + +#define BIT_SHIFT_BCNQ_HEAD_PG_V1_8822B 0 +#define BIT_MASK_BCNQ_HEAD_PG_V1_8822B 0xfff +#define BIT_BCNQ_HEAD_PG_V1_8822B(x) \ + (((x) & BIT_MASK_BCNQ_HEAD_PG_V1_8822B) \ + << BIT_SHIFT_BCNQ_HEAD_PG_V1_8822B) +#define BIT_GET_BCNQ_HEAD_PG_V1_8822B(x) \ + (((x) >> BIT_SHIFT_BCNQ_HEAD_PG_V1_8822B) & \ + BIT_MASK_BCNQ_HEAD_PG_V1_8822B) + +/* 2 REG_TXPKT_EMPTY_8822B */ +#define BIT_BCNQ_EMPTY_8822B BIT(11) +#define BIT_HQQ_EMPTY_8822B BIT(10) +#define BIT_MQQ_EMPTY_8822B BIT(9) +#define BIT_MGQ_CPU_EMPTY_8822B BIT(8) +#define BIT_AC7Q_EMPTY_8822B BIT(7) +#define BIT_AC6Q_EMPTY_8822B BIT(6) +#define BIT_AC5Q_EMPTY_8822B BIT(5) +#define BIT_AC4Q_EMPTY_8822B BIT(4) +#define BIT_AC3Q_EMPTY_8822B BIT(3) +#define BIT_AC2Q_EMPTY_8822B BIT(2) +#define BIT_AC1Q_EMPTY_8822B BIT(1) +#define BIT_AC0Q_EMPTY_8822B BIT(0) + +/* 2 REG_CPU_MGQ_INFO_8822B */ +#define BIT_BCN1_POLL_8822B BIT(30) +#define BIT_CPUMGT_POLL_8822B BIT(29) +#define BIT_BCN_POLL_8822B BIT(28) +#define BIT_CPUMGQ_FW_NUM_V1_8822B BIT(12) + +#define BIT_SHIFT_FW_FREE_TAIL_V1_8822B 0 +#define BIT_MASK_FW_FREE_TAIL_V1_8822B 0xfff +#define BIT_FW_FREE_TAIL_V1_8822B(x) \ + (((x) & BIT_MASK_FW_FREE_TAIL_V1_8822B) \ + << BIT_SHIFT_FW_FREE_TAIL_V1_8822B) +#define BIT_GET_FW_FREE_TAIL_V1_8822B(x) \ + (((x) >> BIT_SHIFT_FW_FREE_TAIL_V1_8822B) & \ + BIT_MASK_FW_FREE_TAIL_V1_8822B) + +/* 2 REG_FWHW_TXQ_CTRL_8822B */ +#define BIT_RTS_LIMIT_IN_OFDM_8822B BIT(23) +#define BIT_EN_BCNQ_DL_8822B BIT(22) +#define BIT_EN_RD_RESP_NAV_BK_8822B BIT(21) +#define BIT_EN_WR_FREE_TAIL_8822B BIT(20) + +#define BIT_SHIFT_EN_QUEUE_RPT_8822B 8 +#define BIT_MASK_EN_QUEUE_RPT_8822B 0xff +#define BIT_EN_QUEUE_RPT_8822B(x) \ + (((x) & BIT_MASK_EN_QUEUE_RPT_8822B) << BIT_SHIFT_EN_QUEUE_RPT_8822B) +#define BIT_GET_EN_QUEUE_RPT_8822B(x) \ + (((x) >> BIT_SHIFT_EN_QUEUE_RPT_8822B) & BIT_MASK_EN_QUEUE_RPT_8822B) + +#define BIT_EN_RTY_BK_8822B BIT(7) +#define BIT_EN_USE_INI_RAT_8822B BIT(6) +#define BIT_EN_RTS_NAV_BK_8822B BIT(5) +#define BIT_DIS_SSN_CHECK_8822B BIT(4) +#define BIT_MACID_MATCH_RTS_8822B BIT(3) +#define BIT_EN_BCN_TRXRPT_V1_8822B BIT(2) +#define BIT_EN_FTMACKRPT_8822B BIT(1) +#define BIT_EN_FTMRPT_8822B BIT(0) + +/* 2 REG_DATAFB_SEL_8822B */ +#define BIT__R_EN_RTY_BK_COD_8822B BIT(2) + +#define BIT_SHIFT__R_DATA_FALLBACK_SEL_8822B 0 +#define BIT_MASK__R_DATA_FALLBACK_SEL_8822B 0x3 +#define BIT__R_DATA_FALLBACK_SEL_8822B(x) \ + (((x) & BIT_MASK__R_DATA_FALLBACK_SEL_8822B) \ + << BIT_SHIFT__R_DATA_FALLBACK_SEL_8822B) +#define BIT_GET__R_DATA_FALLBACK_SEL_8822B(x) \ + (((x) >> BIT_SHIFT__R_DATA_FALLBACK_SEL_8822B) & \ + BIT_MASK__R_DATA_FALLBACK_SEL_8822B) + +/* 2 REG_BCNQ_BDNY_V1_8822B */ + +#define BIT_SHIFT_BCNQ_PGBNDY_V1_8822B 0 +#define BIT_MASK_BCNQ_PGBNDY_V1_8822B 0xfff +#define BIT_BCNQ_PGBNDY_V1_8822B(x) \ + (((x) & BIT_MASK_BCNQ_PGBNDY_V1_8822B) \ + << BIT_SHIFT_BCNQ_PGBNDY_V1_8822B) +#define BIT_GET_BCNQ_PGBNDY_V1_8822B(x) \ + (((x) >> BIT_SHIFT_BCNQ_PGBNDY_V1_8822B) & \ + BIT_MASK_BCNQ_PGBNDY_V1_8822B) + +/* 2 REG_LIFETIME_EN_8822B */ +#define BIT_BT_INT_CPU_8822B BIT(7) +#define BIT_BT_INT_PTA_8822B BIT(6) +#define BIT_EN_CTRL_RTYBIT_8822B BIT(4) +#define BIT_LIFETIME_BK_EN_8822B BIT(3) +#define BIT_LIFETIME_BE_EN_8822B BIT(2) +#define BIT_LIFETIME_VI_EN_8822B BIT(1) +#define BIT_LIFETIME_VO_EN_8822B BIT(0) + +/* 2 REG_SPEC_SIFS_8822B */ + +#define BIT_SHIFT_SPEC_SIFS_OFDM_PTCL_8822B 8 +#define BIT_MASK_SPEC_SIFS_OFDM_PTCL_8822B 0xff +#define BIT_SPEC_SIFS_OFDM_PTCL_8822B(x) \ + (((x) & BIT_MASK_SPEC_SIFS_OFDM_PTCL_8822B) \ + << BIT_SHIFT_SPEC_SIFS_OFDM_PTCL_8822B) +#define BIT_GET_SPEC_SIFS_OFDM_PTCL_8822B(x) \ + (((x) >> BIT_SHIFT_SPEC_SIFS_OFDM_PTCL_8822B) & \ + BIT_MASK_SPEC_SIFS_OFDM_PTCL_8822B) + +#define BIT_SHIFT_SPEC_SIFS_CCK_PTCL_8822B 0 +#define BIT_MASK_SPEC_SIFS_CCK_PTCL_8822B 0xff +#define BIT_SPEC_SIFS_CCK_PTCL_8822B(x) \ + (((x) & BIT_MASK_SPEC_SIFS_CCK_PTCL_8822B) \ + << BIT_SHIFT_SPEC_SIFS_CCK_PTCL_8822B) +#define BIT_GET_SPEC_SIFS_CCK_PTCL_8822B(x) \ + (((x) >> BIT_SHIFT_SPEC_SIFS_CCK_PTCL_8822B) & \ + BIT_MASK_SPEC_SIFS_CCK_PTCL_8822B) + +/* 2 REG_RETRY_LIMIT_8822B */ + +#define BIT_SHIFT_SRL_8822B 8 +#define BIT_MASK_SRL_8822B 0x3f +#define BIT_SRL_8822B(x) (((x) & BIT_MASK_SRL_8822B) << BIT_SHIFT_SRL_8822B) +#define BIT_GET_SRL_8822B(x) (((x) >> BIT_SHIFT_SRL_8822B) & BIT_MASK_SRL_8822B) + +#define BIT_SHIFT_LRL_8822B 0 +#define BIT_MASK_LRL_8822B 0x3f +#define BIT_LRL_8822B(x) (((x) & BIT_MASK_LRL_8822B) << BIT_SHIFT_LRL_8822B) +#define BIT_GET_LRL_8822B(x) (((x) >> BIT_SHIFT_LRL_8822B) & BIT_MASK_LRL_8822B) + +/* 2 REG_TXBF_CTRL_8822B */ +#define BIT_R_ENABLE_NDPA_8822B BIT(31) +#define BIT_USE_NDPA_PARAMETER_8822B BIT(30) +#define BIT_R_PROP_TXBF_8822B BIT(29) +#define BIT_R_EN_NDPA_INT_8822B BIT(28) +#define BIT_R_TXBF1_80M_8822B BIT(27) +#define BIT_R_TXBF1_40M_8822B BIT(26) +#define BIT_R_TXBF1_20M_8822B BIT(25) + +#define BIT_SHIFT_R_TXBF1_AID_8822B 16 +#define BIT_MASK_R_TXBF1_AID_8822B 0x1ff +#define BIT_R_TXBF1_AID_8822B(x) \ + (((x) & BIT_MASK_R_TXBF1_AID_8822B) << BIT_SHIFT_R_TXBF1_AID_8822B) +#define BIT_GET_R_TXBF1_AID_8822B(x) \ + (((x) >> BIT_SHIFT_R_TXBF1_AID_8822B) & BIT_MASK_R_TXBF1_AID_8822B) + +#define BIT_DIS_NDP_BFEN_8822B BIT(15) +#define BIT_R_TXBCN_NOBLOCK_NDP_8822B BIT(14) +#define BIT_R_TXBF0_80M_8822B BIT(11) +#define BIT_R_TXBF0_40M_8822B BIT(10) +#define BIT_R_TXBF0_20M_8822B BIT(9) + +#define BIT_SHIFT_R_TXBF0_AID_8822B 0 +#define BIT_MASK_R_TXBF0_AID_8822B 0x1ff +#define BIT_R_TXBF0_AID_8822B(x) \ + (((x) & BIT_MASK_R_TXBF0_AID_8822B) << BIT_SHIFT_R_TXBF0_AID_8822B) +#define BIT_GET_R_TXBF0_AID_8822B(x) \ + (((x) >> BIT_SHIFT_R_TXBF0_AID_8822B) & BIT_MASK_R_TXBF0_AID_8822B) + +/* 2 REG_DARFRC_8822B */ + +#define BIT_SHIFT_DARF_RC8_8822B (56 & CPU_OPT_WIDTH) +#define BIT_MASK_DARF_RC8_8822B 0x1f +#define BIT_DARF_RC8_8822B(x) \ + (((x) & BIT_MASK_DARF_RC8_8822B) << BIT_SHIFT_DARF_RC8_8822B) +#define BIT_GET_DARF_RC8_8822B(x) \ + (((x) >> BIT_SHIFT_DARF_RC8_8822B) & BIT_MASK_DARF_RC8_8822B) + +#define BIT_SHIFT_DARF_RC7_8822B (48 & CPU_OPT_WIDTH) +#define BIT_MASK_DARF_RC7_8822B 0x1f +#define BIT_DARF_RC7_8822B(x) \ + (((x) & BIT_MASK_DARF_RC7_8822B) << BIT_SHIFT_DARF_RC7_8822B) +#define BIT_GET_DARF_RC7_8822B(x) \ + (((x) >> BIT_SHIFT_DARF_RC7_8822B) & BIT_MASK_DARF_RC7_8822B) + +#define BIT_SHIFT_DARF_RC6_8822B (40 & CPU_OPT_WIDTH) +#define BIT_MASK_DARF_RC6_8822B 0x1f +#define BIT_DARF_RC6_8822B(x) \ + (((x) & BIT_MASK_DARF_RC6_8822B) << BIT_SHIFT_DARF_RC6_8822B) +#define BIT_GET_DARF_RC6_8822B(x) \ + (((x) >> BIT_SHIFT_DARF_RC6_8822B) & BIT_MASK_DARF_RC6_8822B) + +#define BIT_SHIFT_DARF_RC5_8822B (32 & CPU_OPT_WIDTH) +#define BIT_MASK_DARF_RC5_8822B 0x1f +#define BIT_DARF_RC5_8822B(x) \ + (((x) & BIT_MASK_DARF_RC5_8822B) << BIT_SHIFT_DARF_RC5_8822B) +#define BIT_GET_DARF_RC5_8822B(x) \ + (((x) >> BIT_SHIFT_DARF_RC5_8822B) & BIT_MASK_DARF_RC5_8822B) + +#define BIT_SHIFT_DARF_RC4_8822B 24 +#define BIT_MASK_DARF_RC4_8822B 0x1f +#define BIT_DARF_RC4_8822B(x) \ + (((x) & BIT_MASK_DARF_RC4_8822B) << BIT_SHIFT_DARF_RC4_8822B) +#define BIT_GET_DARF_RC4_8822B(x) \ + (((x) >> BIT_SHIFT_DARF_RC4_8822B) & BIT_MASK_DARF_RC4_8822B) + +#define BIT_SHIFT_DARF_RC3_8822B 16 +#define BIT_MASK_DARF_RC3_8822B 0x1f +#define BIT_DARF_RC3_8822B(x) \ + (((x) & BIT_MASK_DARF_RC3_8822B) << BIT_SHIFT_DARF_RC3_8822B) +#define BIT_GET_DARF_RC3_8822B(x) \ + (((x) >> BIT_SHIFT_DARF_RC3_8822B) & BIT_MASK_DARF_RC3_8822B) + +#define BIT_SHIFT_DARF_RC2_8822B 8 +#define BIT_MASK_DARF_RC2_8822B 0x1f +#define BIT_DARF_RC2_8822B(x) \ + (((x) & BIT_MASK_DARF_RC2_8822B) << BIT_SHIFT_DARF_RC2_8822B) +#define BIT_GET_DARF_RC2_8822B(x) \ + (((x) >> BIT_SHIFT_DARF_RC2_8822B) & BIT_MASK_DARF_RC2_8822B) + +#define BIT_SHIFT_DARF_RC1_8822B 0 +#define BIT_MASK_DARF_RC1_8822B 0x1f +#define BIT_DARF_RC1_8822B(x) \ + (((x) & BIT_MASK_DARF_RC1_8822B) << BIT_SHIFT_DARF_RC1_8822B) +#define BIT_GET_DARF_RC1_8822B(x) \ + (((x) >> BIT_SHIFT_DARF_RC1_8822B) & BIT_MASK_DARF_RC1_8822B) + +/* 2 REG_RARFRC_8822B */ + +#define BIT_SHIFT_RARF_RC8_8822B (56 & CPU_OPT_WIDTH) +#define BIT_MASK_RARF_RC8_8822B 0x1f +#define BIT_RARF_RC8_8822B(x) \ + (((x) & BIT_MASK_RARF_RC8_8822B) << BIT_SHIFT_RARF_RC8_8822B) +#define BIT_GET_RARF_RC8_8822B(x) \ + (((x) >> BIT_SHIFT_RARF_RC8_8822B) & BIT_MASK_RARF_RC8_8822B) + +#define BIT_SHIFT_RARF_RC7_8822B (48 & CPU_OPT_WIDTH) +#define BIT_MASK_RARF_RC7_8822B 0x1f +#define BIT_RARF_RC7_8822B(x) \ + (((x) & BIT_MASK_RARF_RC7_8822B) << BIT_SHIFT_RARF_RC7_8822B) +#define BIT_GET_RARF_RC7_8822B(x) \ + (((x) >> BIT_SHIFT_RARF_RC7_8822B) & BIT_MASK_RARF_RC7_8822B) + +#define BIT_SHIFT_RARF_RC6_8822B (40 & CPU_OPT_WIDTH) +#define BIT_MASK_RARF_RC6_8822B 0x1f +#define BIT_RARF_RC6_8822B(x) \ + (((x) & BIT_MASK_RARF_RC6_8822B) << BIT_SHIFT_RARF_RC6_8822B) +#define BIT_GET_RARF_RC6_8822B(x) \ + (((x) >> BIT_SHIFT_RARF_RC6_8822B) & BIT_MASK_RARF_RC6_8822B) + +#define BIT_SHIFT_RARF_RC5_8822B (32 & CPU_OPT_WIDTH) +#define BIT_MASK_RARF_RC5_8822B 0x1f +#define BIT_RARF_RC5_8822B(x) \ + (((x) & BIT_MASK_RARF_RC5_8822B) << BIT_SHIFT_RARF_RC5_8822B) +#define BIT_GET_RARF_RC5_8822B(x) \ + (((x) >> BIT_SHIFT_RARF_RC5_8822B) & BIT_MASK_RARF_RC5_8822B) + +#define BIT_SHIFT_RARF_RC4_8822B 24 +#define BIT_MASK_RARF_RC4_8822B 0x1f +#define BIT_RARF_RC4_8822B(x) \ + (((x) & BIT_MASK_RARF_RC4_8822B) << BIT_SHIFT_RARF_RC4_8822B) +#define BIT_GET_RARF_RC4_8822B(x) \ + (((x) >> BIT_SHIFT_RARF_RC4_8822B) & BIT_MASK_RARF_RC4_8822B) + +#define BIT_SHIFT_RARF_RC3_8822B 16 +#define BIT_MASK_RARF_RC3_8822B 0x1f +#define BIT_RARF_RC3_8822B(x) \ + (((x) & BIT_MASK_RARF_RC3_8822B) << BIT_SHIFT_RARF_RC3_8822B) +#define BIT_GET_RARF_RC3_8822B(x) \ + (((x) >> BIT_SHIFT_RARF_RC3_8822B) & BIT_MASK_RARF_RC3_8822B) + +#define BIT_SHIFT_RARF_RC2_8822B 8 +#define BIT_MASK_RARF_RC2_8822B 0x1f +#define BIT_RARF_RC2_8822B(x) \ + (((x) & BIT_MASK_RARF_RC2_8822B) << BIT_SHIFT_RARF_RC2_8822B) +#define BIT_GET_RARF_RC2_8822B(x) \ + (((x) >> BIT_SHIFT_RARF_RC2_8822B) & BIT_MASK_RARF_RC2_8822B) + +#define BIT_SHIFT_RARF_RC1_8822B 0 +#define BIT_MASK_RARF_RC1_8822B 0x1f +#define BIT_RARF_RC1_8822B(x) \ + (((x) & BIT_MASK_RARF_RC1_8822B) << BIT_SHIFT_RARF_RC1_8822B) +#define BIT_GET_RARF_RC1_8822B(x) \ + (((x) >> BIT_SHIFT_RARF_RC1_8822B) & BIT_MASK_RARF_RC1_8822B) + +/* 2 REG_RRSR_8822B */ + +#define BIT_SHIFT_RRSR_RSC_8822B 21 +#define BIT_MASK_RRSR_RSC_8822B 0x3 +#define BIT_RRSR_RSC_8822B(x) \ + (((x) & BIT_MASK_RRSR_RSC_8822B) << BIT_SHIFT_RRSR_RSC_8822B) +#define BIT_GET_RRSR_RSC_8822B(x) \ + (((x) >> BIT_SHIFT_RRSR_RSC_8822B) & BIT_MASK_RRSR_RSC_8822B) + +#define BIT_RRSR_BW_8822B BIT(20) + +#define BIT_SHIFT_RRSC_BITMAP_8822B 0 +#define BIT_MASK_RRSC_BITMAP_8822B 0xfffff +#define BIT_RRSC_BITMAP_8822B(x) \ + (((x) & BIT_MASK_RRSC_BITMAP_8822B) << BIT_SHIFT_RRSC_BITMAP_8822B) +#define BIT_GET_RRSC_BITMAP_8822B(x) \ + (((x) >> BIT_SHIFT_RRSC_BITMAP_8822B) & BIT_MASK_RRSC_BITMAP_8822B) + +/* 2 REG_ARFR0_8822B */ + +#define BIT_SHIFT_ARFR0_V1_8822B 0 +#define BIT_MASK_ARFR0_V1_8822B 0xffffffffffffffffL +#define BIT_ARFR0_V1_8822B(x) \ + (((x) & BIT_MASK_ARFR0_V1_8822B) << BIT_SHIFT_ARFR0_V1_8822B) +#define BIT_GET_ARFR0_V1_8822B(x) \ + (((x) >> BIT_SHIFT_ARFR0_V1_8822B) & BIT_MASK_ARFR0_V1_8822B) + +/* 2 REG_ARFR1_V1_8822B */ + +#define BIT_SHIFT_ARFR1_V1_8822B 0 +#define BIT_MASK_ARFR1_V1_8822B 0xffffffffffffffffL +#define BIT_ARFR1_V1_8822B(x) \ + (((x) & BIT_MASK_ARFR1_V1_8822B) << BIT_SHIFT_ARFR1_V1_8822B) +#define BIT_GET_ARFR1_V1_8822B(x) \ + (((x) >> BIT_SHIFT_ARFR1_V1_8822B) & BIT_MASK_ARFR1_V1_8822B) + +/* 2 REG_CCK_CHECK_8822B */ +#define BIT_CHECK_CCK_EN_8822B BIT(7) +#define BIT_EN_BCN_PKT_REL_8822B BIT(6) +#define BIT_BCN_PORT_SEL_8822B BIT(5) +#define BIT_MOREDATA_BYPASS_8822B BIT(4) +#define BIT_EN_CLR_CMD_REL_BCN_PKT_8822B BIT(3) +#define BIT_R_EN_SET_MOREDATA_8822B BIT(2) +#define BIT__R_DIS_CLEAR_MACID_RELEASE_8822B BIT(1) +#define BIT__R_MACID_RELEASE_EN_8822B BIT(0) + +/* 2 REG_AMPDU_MAX_TIME_V1_8822B */ + +#define BIT_SHIFT_AMPDU_MAX_TIME_8822B 0 +#define BIT_MASK_AMPDU_MAX_TIME_8822B 0xff +#define BIT_AMPDU_MAX_TIME_8822B(x) \ + (((x) & BIT_MASK_AMPDU_MAX_TIME_8822B) \ + << BIT_SHIFT_AMPDU_MAX_TIME_8822B) +#define BIT_GET_AMPDU_MAX_TIME_8822B(x) \ + (((x) >> BIT_SHIFT_AMPDU_MAX_TIME_8822B) & \ + BIT_MASK_AMPDU_MAX_TIME_8822B) + +/* 2 REG_BCNQ1_BDNY_V1_8822B */ + +#define BIT_SHIFT_BCNQ1_PGBNDY_V1_8822B 0 +#define BIT_MASK_BCNQ1_PGBNDY_V1_8822B 0xfff +#define BIT_BCNQ1_PGBNDY_V1_8822B(x) \ + (((x) & BIT_MASK_BCNQ1_PGBNDY_V1_8822B) \ + << BIT_SHIFT_BCNQ1_PGBNDY_V1_8822B) +#define BIT_GET_BCNQ1_PGBNDY_V1_8822B(x) \ + (((x) >> BIT_SHIFT_BCNQ1_PGBNDY_V1_8822B) & \ + BIT_MASK_BCNQ1_PGBNDY_V1_8822B) + +/* 2 REG_AMPDU_MAX_LENGTH_8822B */ + +#define BIT_SHIFT_AMPDU_MAX_LENGTH_8822B 0 +#define BIT_MASK_AMPDU_MAX_LENGTH_8822B 0xffffffffL +#define BIT_AMPDU_MAX_LENGTH_8822B(x) \ + (((x) & BIT_MASK_AMPDU_MAX_LENGTH_8822B) \ + << BIT_SHIFT_AMPDU_MAX_LENGTH_8822B) +#define BIT_GET_AMPDU_MAX_LENGTH_8822B(x) \ + (((x) >> BIT_SHIFT_AMPDU_MAX_LENGTH_8822B) & \ + BIT_MASK_AMPDU_MAX_LENGTH_8822B) + +/* 2 REG_ACQ_STOP_8822B */ +#define BIT_AC7Q_STOP_8822B BIT(7) +#define BIT_AC6Q_STOP_8822B BIT(6) +#define BIT_AC5Q_STOP_8822B BIT(5) +#define BIT_AC4Q_STOP_8822B BIT(4) +#define BIT_AC3Q_STOP_8822B BIT(3) +#define BIT_AC2Q_STOP_8822B BIT(2) +#define BIT_AC1Q_STOP_8822B BIT(1) +#define BIT_AC0Q_STOP_8822B BIT(0) + +/* 2 REG_NDPA_RATE_8822B */ + +#define BIT_SHIFT_R_NDPA_RATE_V1_8822B 0 +#define BIT_MASK_R_NDPA_RATE_V1_8822B 0xff +#define BIT_R_NDPA_RATE_V1_8822B(x) \ + (((x) & BIT_MASK_R_NDPA_RATE_V1_8822B) \ + << BIT_SHIFT_R_NDPA_RATE_V1_8822B) +#define BIT_GET_R_NDPA_RATE_V1_8822B(x) \ + (((x) >> BIT_SHIFT_R_NDPA_RATE_V1_8822B) & \ + BIT_MASK_R_NDPA_RATE_V1_8822B) + +/* 2 REG_TX_HANG_CTRL_8822B */ +#define BIT_R_EN_GNT_BT_AWAKE_8822B BIT(3) +#define BIT_EN_EOF_V1_8822B BIT(2) +#define BIT_DIS_OQT_BLOCK_8822B BIT(1) +#define BIT_SEARCH_QUEUE_EN_8822B BIT(0) + +/* 2 REG_NDPA_OPT_CTRL_8822B */ +#define BIT_R_DIS_MACID_RELEASE_RTY_8822B BIT(5) + +#define BIT_SHIFT_BW_SIGTA_8822B 3 +#define BIT_MASK_BW_SIGTA_8822B 0x3 +#define BIT_BW_SIGTA_8822B(x) \ + (((x) & BIT_MASK_BW_SIGTA_8822B) << BIT_SHIFT_BW_SIGTA_8822B) +#define BIT_GET_BW_SIGTA_8822B(x) \ + (((x) >> BIT_SHIFT_BW_SIGTA_8822B) & BIT_MASK_BW_SIGTA_8822B) + +#define BIT_EN_BAR_SIGTA_8822B BIT(2) + +#define BIT_SHIFT_R_NDPA_BW_8822B 0 +#define BIT_MASK_R_NDPA_BW_8822B 0x3 +#define BIT_R_NDPA_BW_8822B(x) \ + (((x) & BIT_MASK_R_NDPA_BW_8822B) << BIT_SHIFT_R_NDPA_BW_8822B) +#define BIT_GET_R_NDPA_BW_8822B(x) \ + (((x) >> BIT_SHIFT_R_NDPA_BW_8822B) & BIT_MASK_R_NDPA_BW_8822B) + +/* 2 REG_RD_RESP_PKT_TH_8822B */ + +#define BIT_SHIFT_RD_RESP_PKT_TH_V1_8822B 0 +#define BIT_MASK_RD_RESP_PKT_TH_V1_8822B 0x3f +#define BIT_RD_RESP_PKT_TH_V1_8822B(x) \ + (((x) & BIT_MASK_RD_RESP_PKT_TH_V1_8822B) \ + << BIT_SHIFT_RD_RESP_PKT_TH_V1_8822B) +#define BIT_GET_RD_RESP_PKT_TH_V1_8822B(x) \ + (((x) >> BIT_SHIFT_RD_RESP_PKT_TH_V1_8822B) & \ + BIT_MASK_RD_RESP_PKT_TH_V1_8822B) + +/* 2 REG_CMDQ_INFO_8822B */ + +#define BIT_SHIFT_QUEUEMACID_CMDQ_V1_8822B 25 +#define BIT_MASK_QUEUEMACID_CMDQ_V1_8822B 0x7f +#define BIT_QUEUEMACID_CMDQ_V1_8822B(x) \ + (((x) & BIT_MASK_QUEUEMACID_CMDQ_V1_8822B) \ + << BIT_SHIFT_QUEUEMACID_CMDQ_V1_8822B) +#define BIT_GET_QUEUEMACID_CMDQ_V1_8822B(x) \ + (((x) >> BIT_SHIFT_QUEUEMACID_CMDQ_V1_8822B) & \ + BIT_MASK_QUEUEMACID_CMDQ_V1_8822B) + +#define BIT_SHIFT_QUEUEAC_CMDQ_V1_8822B 23 +#define BIT_MASK_QUEUEAC_CMDQ_V1_8822B 0x3 +#define BIT_QUEUEAC_CMDQ_V1_8822B(x) \ + (((x) & BIT_MASK_QUEUEAC_CMDQ_V1_8822B) \ + << BIT_SHIFT_QUEUEAC_CMDQ_V1_8822B) +#define BIT_GET_QUEUEAC_CMDQ_V1_8822B(x) \ + (((x) >> BIT_SHIFT_QUEUEAC_CMDQ_V1_8822B) & \ + BIT_MASK_QUEUEAC_CMDQ_V1_8822B) + +#define BIT_TIDEMPTY_CMDQ_V1_8822B BIT(22) + +#define BIT_SHIFT_TAIL_PKT_CMDQ_V2_8822B 11 +#define BIT_MASK_TAIL_PKT_CMDQ_V2_8822B 0x7ff +#define BIT_TAIL_PKT_CMDQ_V2_8822B(x) \ + (((x) & BIT_MASK_TAIL_PKT_CMDQ_V2_8822B) \ + << BIT_SHIFT_TAIL_PKT_CMDQ_V2_8822B) +#define BIT_GET_TAIL_PKT_CMDQ_V2_8822B(x) \ + (((x) >> BIT_SHIFT_TAIL_PKT_CMDQ_V2_8822B) & \ + BIT_MASK_TAIL_PKT_CMDQ_V2_8822B) + +#define BIT_SHIFT_HEAD_PKT_CMDQ_V1_8822B 0 +#define BIT_MASK_HEAD_PKT_CMDQ_V1_8822B 0x7ff +#define BIT_HEAD_PKT_CMDQ_V1_8822B(x) \ + (((x) & BIT_MASK_HEAD_PKT_CMDQ_V1_8822B) \ + << BIT_SHIFT_HEAD_PKT_CMDQ_V1_8822B) +#define BIT_GET_HEAD_PKT_CMDQ_V1_8822B(x) \ + (((x) >> BIT_SHIFT_HEAD_PKT_CMDQ_V1_8822B) & \ + BIT_MASK_HEAD_PKT_CMDQ_V1_8822B) + +/* 2 REG_Q4_INFO_8822B */ + +#define BIT_SHIFT_QUEUEMACID_Q4_V1_8822B 25 +#define BIT_MASK_QUEUEMACID_Q4_V1_8822B 0x7f +#define BIT_QUEUEMACID_Q4_V1_8822B(x) \ + (((x) & BIT_MASK_QUEUEMACID_Q4_V1_8822B) \ + << BIT_SHIFT_QUEUEMACID_Q4_V1_8822B) +#define BIT_GET_QUEUEMACID_Q4_V1_8822B(x) \ + (((x) >> BIT_SHIFT_QUEUEMACID_Q4_V1_8822B) & \ + BIT_MASK_QUEUEMACID_Q4_V1_8822B) + +#define BIT_SHIFT_QUEUEAC_Q4_V1_8822B 23 +#define BIT_MASK_QUEUEAC_Q4_V1_8822B 0x3 +#define BIT_QUEUEAC_Q4_V1_8822B(x) \ + (((x) & BIT_MASK_QUEUEAC_Q4_V1_8822B) << BIT_SHIFT_QUEUEAC_Q4_V1_8822B) +#define BIT_GET_QUEUEAC_Q4_V1_8822B(x) \ + (((x) >> BIT_SHIFT_QUEUEAC_Q4_V1_8822B) & BIT_MASK_QUEUEAC_Q4_V1_8822B) + +#define BIT_TIDEMPTY_Q4_V1_8822B BIT(22) + +#define BIT_SHIFT_TAIL_PKT_Q4_V2_8822B 11 +#define BIT_MASK_TAIL_PKT_Q4_V2_8822B 0x7ff +#define BIT_TAIL_PKT_Q4_V2_8822B(x) \ + (((x) & BIT_MASK_TAIL_PKT_Q4_V2_8822B) \ + << BIT_SHIFT_TAIL_PKT_Q4_V2_8822B) +#define BIT_GET_TAIL_PKT_Q4_V2_8822B(x) \ + (((x) >> BIT_SHIFT_TAIL_PKT_Q4_V2_8822B) & \ + BIT_MASK_TAIL_PKT_Q4_V2_8822B) + +#define BIT_SHIFT_HEAD_PKT_Q4_V1_8822B 0 +#define BIT_MASK_HEAD_PKT_Q4_V1_8822B 0x7ff +#define BIT_HEAD_PKT_Q4_V1_8822B(x) \ + (((x) & BIT_MASK_HEAD_PKT_Q4_V1_8822B) \ + << BIT_SHIFT_HEAD_PKT_Q4_V1_8822B) +#define BIT_GET_HEAD_PKT_Q4_V1_8822B(x) \ + (((x) >> BIT_SHIFT_HEAD_PKT_Q4_V1_8822B) & \ + BIT_MASK_HEAD_PKT_Q4_V1_8822B) + +/* 2 REG_Q5_INFO_8822B */ + +#define BIT_SHIFT_QUEUEMACID_Q5_V1_8822B 25 +#define BIT_MASK_QUEUEMACID_Q5_V1_8822B 0x7f +#define BIT_QUEUEMACID_Q5_V1_8822B(x) \ + (((x) & BIT_MASK_QUEUEMACID_Q5_V1_8822B) \ + << BIT_SHIFT_QUEUEMACID_Q5_V1_8822B) +#define BIT_GET_QUEUEMACID_Q5_V1_8822B(x) \ + (((x) >> BIT_SHIFT_QUEUEMACID_Q5_V1_8822B) & \ + BIT_MASK_QUEUEMACID_Q5_V1_8822B) + +#define BIT_SHIFT_QUEUEAC_Q5_V1_8822B 23 +#define BIT_MASK_QUEUEAC_Q5_V1_8822B 0x3 +#define BIT_QUEUEAC_Q5_V1_8822B(x) \ + (((x) & BIT_MASK_QUEUEAC_Q5_V1_8822B) << BIT_SHIFT_QUEUEAC_Q5_V1_8822B) +#define BIT_GET_QUEUEAC_Q5_V1_8822B(x) \ + (((x) >> BIT_SHIFT_QUEUEAC_Q5_V1_8822B) & BIT_MASK_QUEUEAC_Q5_V1_8822B) + +#define BIT_TIDEMPTY_Q5_V1_8822B BIT(22) + +#define BIT_SHIFT_TAIL_PKT_Q5_V2_8822B 11 +#define BIT_MASK_TAIL_PKT_Q5_V2_8822B 0x7ff +#define BIT_TAIL_PKT_Q5_V2_8822B(x) \ + (((x) & BIT_MASK_TAIL_PKT_Q5_V2_8822B) \ + << BIT_SHIFT_TAIL_PKT_Q5_V2_8822B) +#define BIT_GET_TAIL_PKT_Q5_V2_8822B(x) \ + (((x) >> BIT_SHIFT_TAIL_PKT_Q5_V2_8822B) & \ + BIT_MASK_TAIL_PKT_Q5_V2_8822B) + +#define BIT_SHIFT_HEAD_PKT_Q5_V1_8822B 0 +#define BIT_MASK_HEAD_PKT_Q5_V1_8822B 0x7ff +#define BIT_HEAD_PKT_Q5_V1_8822B(x) \ + (((x) & BIT_MASK_HEAD_PKT_Q5_V1_8822B) \ + << BIT_SHIFT_HEAD_PKT_Q5_V1_8822B) +#define BIT_GET_HEAD_PKT_Q5_V1_8822B(x) \ + (((x) >> BIT_SHIFT_HEAD_PKT_Q5_V1_8822B) & \ + BIT_MASK_HEAD_PKT_Q5_V1_8822B) + +/* 2 REG_Q6_INFO_8822B */ + +#define BIT_SHIFT_QUEUEMACID_Q6_V1_8822B 25 +#define BIT_MASK_QUEUEMACID_Q6_V1_8822B 0x7f +#define BIT_QUEUEMACID_Q6_V1_8822B(x) \ + (((x) & BIT_MASK_QUEUEMACID_Q6_V1_8822B) \ + << BIT_SHIFT_QUEUEMACID_Q6_V1_8822B) +#define BIT_GET_QUEUEMACID_Q6_V1_8822B(x) \ + (((x) >> BIT_SHIFT_QUEUEMACID_Q6_V1_8822B) & \ + BIT_MASK_QUEUEMACID_Q6_V1_8822B) + +#define BIT_SHIFT_QUEUEAC_Q6_V1_8822B 23 +#define BIT_MASK_QUEUEAC_Q6_V1_8822B 0x3 +#define BIT_QUEUEAC_Q6_V1_8822B(x) \ + (((x) & BIT_MASK_QUEUEAC_Q6_V1_8822B) << BIT_SHIFT_QUEUEAC_Q6_V1_8822B) +#define BIT_GET_QUEUEAC_Q6_V1_8822B(x) \ + (((x) >> BIT_SHIFT_QUEUEAC_Q6_V1_8822B) & BIT_MASK_QUEUEAC_Q6_V1_8822B) + +#define BIT_TIDEMPTY_Q6_V1_8822B BIT(22) + +#define BIT_SHIFT_TAIL_PKT_Q6_V2_8822B 11 +#define BIT_MASK_TAIL_PKT_Q6_V2_8822B 0x7ff +#define BIT_TAIL_PKT_Q6_V2_8822B(x) \ + (((x) & BIT_MASK_TAIL_PKT_Q6_V2_8822B) \ + << BIT_SHIFT_TAIL_PKT_Q6_V2_8822B) +#define BIT_GET_TAIL_PKT_Q6_V2_8822B(x) \ + (((x) >> BIT_SHIFT_TAIL_PKT_Q6_V2_8822B) & \ + BIT_MASK_TAIL_PKT_Q6_V2_8822B) + +#define BIT_SHIFT_HEAD_PKT_Q6_V1_8822B 0 +#define BIT_MASK_HEAD_PKT_Q6_V1_8822B 0x7ff +#define BIT_HEAD_PKT_Q6_V1_8822B(x) \ + (((x) & BIT_MASK_HEAD_PKT_Q6_V1_8822B) \ + << BIT_SHIFT_HEAD_PKT_Q6_V1_8822B) +#define BIT_GET_HEAD_PKT_Q6_V1_8822B(x) \ + (((x) >> BIT_SHIFT_HEAD_PKT_Q6_V1_8822B) & \ + BIT_MASK_HEAD_PKT_Q6_V1_8822B) + +/* 2 REG_Q7_INFO_8822B */ + +#define BIT_SHIFT_QUEUEMACID_Q7_V1_8822B 25 +#define BIT_MASK_QUEUEMACID_Q7_V1_8822B 0x7f +#define BIT_QUEUEMACID_Q7_V1_8822B(x) \ + (((x) & BIT_MASK_QUEUEMACID_Q7_V1_8822B) \ + << BIT_SHIFT_QUEUEMACID_Q7_V1_8822B) +#define BIT_GET_QUEUEMACID_Q7_V1_8822B(x) \ + (((x) >> BIT_SHIFT_QUEUEMACID_Q7_V1_8822B) & \ + BIT_MASK_QUEUEMACID_Q7_V1_8822B) + +#define BIT_SHIFT_QUEUEAC_Q7_V1_8822B 23 +#define BIT_MASK_QUEUEAC_Q7_V1_8822B 0x3 +#define BIT_QUEUEAC_Q7_V1_8822B(x) \ + (((x) & BIT_MASK_QUEUEAC_Q7_V1_8822B) << BIT_SHIFT_QUEUEAC_Q7_V1_8822B) +#define BIT_GET_QUEUEAC_Q7_V1_8822B(x) \ + (((x) >> BIT_SHIFT_QUEUEAC_Q7_V1_8822B) & BIT_MASK_QUEUEAC_Q7_V1_8822B) + +#define BIT_TIDEMPTY_Q7_V1_8822B BIT(22) + +#define BIT_SHIFT_TAIL_PKT_Q7_V2_8822B 11 +#define BIT_MASK_TAIL_PKT_Q7_V2_8822B 0x7ff +#define BIT_TAIL_PKT_Q7_V2_8822B(x) \ + (((x) & BIT_MASK_TAIL_PKT_Q7_V2_8822B) \ + << BIT_SHIFT_TAIL_PKT_Q7_V2_8822B) +#define BIT_GET_TAIL_PKT_Q7_V2_8822B(x) \ + (((x) >> BIT_SHIFT_TAIL_PKT_Q7_V2_8822B) & \ + BIT_MASK_TAIL_PKT_Q7_V2_8822B) + +#define BIT_SHIFT_HEAD_PKT_Q7_V1_8822B 0 +#define BIT_MASK_HEAD_PKT_Q7_V1_8822B 0x7ff +#define BIT_HEAD_PKT_Q7_V1_8822B(x) \ + (((x) & BIT_MASK_HEAD_PKT_Q7_V1_8822B) \ + << BIT_SHIFT_HEAD_PKT_Q7_V1_8822B) +#define BIT_GET_HEAD_PKT_Q7_V1_8822B(x) \ + (((x) >> BIT_SHIFT_HEAD_PKT_Q7_V1_8822B) & \ + BIT_MASK_HEAD_PKT_Q7_V1_8822B) + +/* 2 REG_WMAC_LBK_BUF_HD_V1_8822B */ + +#define BIT_SHIFT_WMAC_LBK_BUF_HEAD_V1_8822B 0 +#define BIT_MASK_WMAC_LBK_BUF_HEAD_V1_8822B 0xfff +#define BIT_WMAC_LBK_BUF_HEAD_V1_8822B(x) \ + (((x) & BIT_MASK_WMAC_LBK_BUF_HEAD_V1_8822B) \ + << BIT_SHIFT_WMAC_LBK_BUF_HEAD_V1_8822B) +#define BIT_GET_WMAC_LBK_BUF_HEAD_V1_8822B(x) \ + (((x) >> BIT_SHIFT_WMAC_LBK_BUF_HEAD_V1_8822B) & \ + BIT_MASK_WMAC_LBK_BUF_HEAD_V1_8822B) + +/* 2 REG_MGQ_BDNY_V1_8822B */ + +#define BIT_SHIFT_MGQ_PGBNDY_V1_8822B 0 +#define BIT_MASK_MGQ_PGBNDY_V1_8822B 0xfff +#define BIT_MGQ_PGBNDY_V1_8822B(x) \ + (((x) & BIT_MASK_MGQ_PGBNDY_V1_8822B) << BIT_SHIFT_MGQ_PGBNDY_V1_8822B) +#define BIT_GET_MGQ_PGBNDY_V1_8822B(x) \ + (((x) >> BIT_SHIFT_MGQ_PGBNDY_V1_8822B) & BIT_MASK_MGQ_PGBNDY_V1_8822B) + +/* 2 REG_TXRPT_CTRL_8822B */ + +#define BIT_SHIFT_TRXRPT_TIMER_TH_8822B 24 +#define BIT_MASK_TRXRPT_TIMER_TH_8822B 0xff +#define BIT_TRXRPT_TIMER_TH_8822B(x) \ + (((x) & BIT_MASK_TRXRPT_TIMER_TH_8822B) \ + << BIT_SHIFT_TRXRPT_TIMER_TH_8822B) +#define BIT_GET_TRXRPT_TIMER_TH_8822B(x) \ + (((x) >> BIT_SHIFT_TRXRPT_TIMER_TH_8822B) & \ + BIT_MASK_TRXRPT_TIMER_TH_8822B) + +#define BIT_SHIFT_TRXRPT_LEN_TH_8822B 16 +#define BIT_MASK_TRXRPT_LEN_TH_8822B 0xff +#define BIT_TRXRPT_LEN_TH_8822B(x) \ + (((x) & BIT_MASK_TRXRPT_LEN_TH_8822B) << BIT_SHIFT_TRXRPT_LEN_TH_8822B) +#define BIT_GET_TRXRPT_LEN_TH_8822B(x) \ + (((x) >> BIT_SHIFT_TRXRPT_LEN_TH_8822B) & BIT_MASK_TRXRPT_LEN_TH_8822B) + +#define BIT_SHIFT_TRXRPT_READ_PTR_8822B 8 +#define BIT_MASK_TRXRPT_READ_PTR_8822B 0xff +#define BIT_TRXRPT_READ_PTR_8822B(x) \ + (((x) & BIT_MASK_TRXRPT_READ_PTR_8822B) \ + << BIT_SHIFT_TRXRPT_READ_PTR_8822B) +#define BIT_GET_TRXRPT_READ_PTR_8822B(x) \ + (((x) >> BIT_SHIFT_TRXRPT_READ_PTR_8822B) & \ + BIT_MASK_TRXRPT_READ_PTR_8822B) + +#define BIT_SHIFT_TRXRPT_WRITE_PTR_8822B 0 +#define BIT_MASK_TRXRPT_WRITE_PTR_8822B 0xff +#define BIT_TRXRPT_WRITE_PTR_8822B(x) \ + (((x) & BIT_MASK_TRXRPT_WRITE_PTR_8822B) \ + << BIT_SHIFT_TRXRPT_WRITE_PTR_8822B) +#define BIT_GET_TRXRPT_WRITE_PTR_8822B(x) \ + (((x) >> BIT_SHIFT_TRXRPT_WRITE_PTR_8822B) & \ + BIT_MASK_TRXRPT_WRITE_PTR_8822B) + +/* 2 REG_INIRTS_RATE_SEL_8822B */ +#define BIT_LEAG_RTS_BW_DUP_8822B BIT(5) + +/* 2 REG_BASIC_CFEND_RATE_8822B */ + +#define BIT_SHIFT_BASIC_CFEND_RATE_8822B 0 +#define BIT_MASK_BASIC_CFEND_RATE_8822B 0x1f +#define BIT_BASIC_CFEND_RATE_8822B(x) \ + (((x) & BIT_MASK_BASIC_CFEND_RATE_8822B) \ + << BIT_SHIFT_BASIC_CFEND_RATE_8822B) +#define BIT_GET_BASIC_CFEND_RATE_8822B(x) \ + (((x) >> BIT_SHIFT_BASIC_CFEND_RATE_8822B) & \ + BIT_MASK_BASIC_CFEND_RATE_8822B) + +/* 2 REG_STBC_CFEND_RATE_8822B */ + +#define BIT_SHIFT_STBC_CFEND_RATE_8822B 0 +#define BIT_MASK_STBC_CFEND_RATE_8822B 0x1f +#define BIT_STBC_CFEND_RATE_8822B(x) \ + (((x) & BIT_MASK_STBC_CFEND_RATE_8822B) \ + << BIT_SHIFT_STBC_CFEND_RATE_8822B) +#define BIT_GET_STBC_CFEND_RATE_8822B(x) \ + (((x) >> BIT_SHIFT_STBC_CFEND_RATE_8822B) & \ + BIT_MASK_STBC_CFEND_RATE_8822B) + +/* 2 REG_DATA_SC_8822B */ + +#define BIT_SHIFT_TXSC_40M_8822B 4 +#define BIT_MASK_TXSC_40M_8822B 0xf +#define BIT_TXSC_40M_8822B(x) \ + (((x) & BIT_MASK_TXSC_40M_8822B) << BIT_SHIFT_TXSC_40M_8822B) +#define BIT_GET_TXSC_40M_8822B(x) \ + (((x) >> BIT_SHIFT_TXSC_40M_8822B) & BIT_MASK_TXSC_40M_8822B) + +#define BIT_SHIFT_TXSC_20M_8822B 0 +#define BIT_MASK_TXSC_20M_8822B 0xf +#define BIT_TXSC_20M_8822B(x) \ + (((x) & BIT_MASK_TXSC_20M_8822B) << BIT_SHIFT_TXSC_20M_8822B) +#define BIT_GET_TXSC_20M_8822B(x) \ + (((x) >> BIT_SHIFT_TXSC_20M_8822B) & BIT_MASK_TXSC_20M_8822B) + +/* 2 REG_MACID_SLEEP3_8822B */ + +#define BIT_SHIFT_MACID127_96_PKTSLEEP_8822B 0 +#define BIT_MASK_MACID127_96_PKTSLEEP_8822B 0xffffffffL +#define BIT_MACID127_96_PKTSLEEP_8822B(x) \ + (((x) & BIT_MASK_MACID127_96_PKTSLEEP_8822B) \ + << BIT_SHIFT_MACID127_96_PKTSLEEP_8822B) +#define BIT_GET_MACID127_96_PKTSLEEP_8822B(x) \ + (((x) >> BIT_SHIFT_MACID127_96_PKTSLEEP_8822B) & \ + BIT_MASK_MACID127_96_PKTSLEEP_8822B) + +/* 2 REG_MACID_SLEEP1_8822B */ + +#define BIT_SHIFT_MACID63_32_PKTSLEEP_8822B 0 +#define BIT_MASK_MACID63_32_PKTSLEEP_8822B 0xffffffffL +#define BIT_MACID63_32_PKTSLEEP_8822B(x) \ + (((x) & BIT_MASK_MACID63_32_PKTSLEEP_8822B) \ + << BIT_SHIFT_MACID63_32_PKTSLEEP_8822B) +#define BIT_GET_MACID63_32_PKTSLEEP_8822B(x) \ + (((x) >> BIT_SHIFT_MACID63_32_PKTSLEEP_8822B) & \ + BIT_MASK_MACID63_32_PKTSLEEP_8822B) + +/* 2 REG_ARFR2_V1_8822B */ + +#define BIT_SHIFT_ARFR2_V1_8822B 0 +#define BIT_MASK_ARFR2_V1_8822B 0xffffffffffffffffL +#define BIT_ARFR2_V1_8822B(x) \ + (((x) & BIT_MASK_ARFR2_V1_8822B) << BIT_SHIFT_ARFR2_V1_8822B) +#define BIT_GET_ARFR2_V1_8822B(x) \ + (((x) >> BIT_SHIFT_ARFR2_V1_8822B) & BIT_MASK_ARFR2_V1_8822B) + +/* 2 REG_ARFR3_V1_8822B */ + +#define BIT_SHIFT_ARFR3_V1_8822B 0 +#define BIT_MASK_ARFR3_V1_8822B 0xffffffffffffffffL +#define BIT_ARFR3_V1_8822B(x) \ + (((x) & BIT_MASK_ARFR3_V1_8822B) << BIT_SHIFT_ARFR3_V1_8822B) +#define BIT_GET_ARFR3_V1_8822B(x) \ + (((x) >> BIT_SHIFT_ARFR3_V1_8822B) & BIT_MASK_ARFR3_V1_8822B) + +/* 2 REG_ARFR4_8822B */ + +#define BIT_SHIFT_ARFR4_8822B 0 +#define BIT_MASK_ARFR4_8822B 0xffffffffffffffffL +#define BIT_ARFR4_8822B(x) \ + (((x) & BIT_MASK_ARFR4_8822B) << BIT_SHIFT_ARFR4_8822B) +#define BIT_GET_ARFR4_8822B(x) \ + (((x) >> BIT_SHIFT_ARFR4_8822B) & BIT_MASK_ARFR4_8822B) + +/* 2 REG_ARFR5_8822B */ + +#define BIT_SHIFT_ARFR5_8822B 0 +#define BIT_MASK_ARFR5_8822B 0xffffffffffffffffL +#define BIT_ARFR5_8822B(x) \ + (((x) & BIT_MASK_ARFR5_8822B) << BIT_SHIFT_ARFR5_8822B) +#define BIT_GET_ARFR5_8822B(x) \ + (((x) >> BIT_SHIFT_ARFR5_8822B) & BIT_MASK_ARFR5_8822B) + +/* 2 REG_TXRPT_START_OFFSET_8822B */ + +#define BIT_SHIFT_MACID_MURATE_OFFSET_8822B 24 +#define BIT_MASK_MACID_MURATE_OFFSET_8822B 0xff +#define BIT_MACID_MURATE_OFFSET_8822B(x) \ + (((x) & BIT_MASK_MACID_MURATE_OFFSET_8822B) \ + << BIT_SHIFT_MACID_MURATE_OFFSET_8822B) +#define BIT_GET_MACID_MURATE_OFFSET_8822B(x) \ + (((x) >> BIT_SHIFT_MACID_MURATE_OFFSET_8822B) & \ + BIT_MASK_MACID_MURATE_OFFSET_8822B) + +#define BIT_RPTFIFO_SIZE_OPT_8822B BIT(16) + +#define BIT_SHIFT_MACID_CTRL_OFFSET_8822B 8 +#define BIT_MASK_MACID_CTRL_OFFSET_8822B 0xff +#define BIT_MACID_CTRL_OFFSET_8822B(x) \ + (((x) & BIT_MASK_MACID_CTRL_OFFSET_8822B) \ + << BIT_SHIFT_MACID_CTRL_OFFSET_8822B) +#define BIT_GET_MACID_CTRL_OFFSET_8822B(x) \ + (((x) >> BIT_SHIFT_MACID_CTRL_OFFSET_8822B) & \ + BIT_MASK_MACID_CTRL_OFFSET_8822B) + +#define BIT_SHIFT_AMPDU_TXRPT_OFFSET_8822B 0 +#define BIT_MASK_AMPDU_TXRPT_OFFSET_8822B 0xff +#define BIT_AMPDU_TXRPT_OFFSET_8822B(x) \ + (((x) & BIT_MASK_AMPDU_TXRPT_OFFSET_8822B) \ + << BIT_SHIFT_AMPDU_TXRPT_OFFSET_8822B) +#define BIT_GET_AMPDU_TXRPT_OFFSET_8822B(x) \ + (((x) >> BIT_SHIFT_AMPDU_TXRPT_OFFSET_8822B) & \ + BIT_MASK_AMPDU_TXRPT_OFFSET_8822B) + +/* 2 REG_POWER_STAGE1_8822B */ +#define BIT_PTA_WL_PRI_MASK_CPU_MGQ_8822B BIT(31) +#define BIT_PTA_WL_PRI_MASK_BCNQ_8822B BIT(30) +#define BIT_PTA_WL_PRI_MASK_HIQ_8822B BIT(29) +#define BIT_PTA_WL_PRI_MASK_MGQ_8822B BIT(28) +#define BIT_PTA_WL_PRI_MASK_BK_8822B BIT(27) +#define BIT_PTA_WL_PRI_MASK_BE_8822B BIT(26) +#define BIT_PTA_WL_PRI_MASK_VI_8822B BIT(25) +#define BIT_PTA_WL_PRI_MASK_VO_8822B BIT(24) + +#define BIT_SHIFT_POWER_STAGE1_8822B 0 +#define BIT_MASK_POWER_STAGE1_8822B 0xffffff +#define BIT_POWER_STAGE1_8822B(x) \ + (((x) & BIT_MASK_POWER_STAGE1_8822B) << BIT_SHIFT_POWER_STAGE1_8822B) +#define BIT_GET_POWER_STAGE1_8822B(x) \ + (((x) >> BIT_SHIFT_POWER_STAGE1_8822B) & BIT_MASK_POWER_STAGE1_8822B) + +/* 2 REG_POWER_STAGE2_8822B */ +#define BIT__R_CTRL_PKT_POW_ADJ_8822B BIT(24) + +#define BIT_SHIFT_POWER_STAGE2_8822B 0 +#define BIT_MASK_POWER_STAGE2_8822B 0xffffff +#define BIT_POWER_STAGE2_8822B(x) \ + (((x) & BIT_MASK_POWER_STAGE2_8822B) << BIT_SHIFT_POWER_STAGE2_8822B) +#define BIT_GET_POWER_STAGE2_8822B(x) \ + (((x) >> BIT_SHIFT_POWER_STAGE2_8822B) & BIT_MASK_POWER_STAGE2_8822B) + +/* 2 REG_SW_AMPDU_BURST_MODE_CTRL_8822B */ + +#define BIT_SHIFT_PAD_NUM_THRES_8822B 24 +#define BIT_MASK_PAD_NUM_THRES_8822B 0x3f +#define BIT_PAD_NUM_THRES_8822B(x) \ + (((x) & BIT_MASK_PAD_NUM_THRES_8822B) << BIT_SHIFT_PAD_NUM_THRES_8822B) +#define BIT_GET_PAD_NUM_THRES_8822B(x) \ + (((x) >> BIT_SHIFT_PAD_NUM_THRES_8822B) & BIT_MASK_PAD_NUM_THRES_8822B) + +#define BIT_R_DMA_THIS_QUEUE_BK_8822B BIT(23) +#define BIT_R_DMA_THIS_QUEUE_BE_8822B BIT(22) +#define BIT_R_DMA_THIS_QUEUE_VI_8822B BIT(21) +#define BIT_R_DMA_THIS_QUEUE_VO_8822B BIT(20) + +#define BIT_SHIFT_R_TOTAL_LEN_TH_8822B 8 +#define BIT_MASK_R_TOTAL_LEN_TH_8822B 0xfff +#define BIT_R_TOTAL_LEN_TH_8822B(x) \ + (((x) & BIT_MASK_R_TOTAL_LEN_TH_8822B) \ + << BIT_SHIFT_R_TOTAL_LEN_TH_8822B) +#define BIT_GET_R_TOTAL_LEN_TH_8822B(x) \ + (((x) >> BIT_SHIFT_R_TOTAL_LEN_TH_8822B) & \ + BIT_MASK_R_TOTAL_LEN_TH_8822B) + +#define BIT_EN_NEW_EARLY_8822B BIT(7) +#define BIT_PRE_TX_CMD_8822B BIT(6) + +#define BIT_SHIFT_NUM_SCL_EN_8822B 4 +#define BIT_MASK_NUM_SCL_EN_8822B 0x3 +#define BIT_NUM_SCL_EN_8822B(x) \ + (((x) & BIT_MASK_NUM_SCL_EN_8822B) << BIT_SHIFT_NUM_SCL_EN_8822B) +#define BIT_GET_NUM_SCL_EN_8822B(x) \ + (((x) >> BIT_SHIFT_NUM_SCL_EN_8822B) & BIT_MASK_NUM_SCL_EN_8822B) + +#define BIT_BK_EN_8822B BIT(3) +#define BIT_BE_EN_8822B BIT(2) +#define BIT_VI_EN_8822B BIT(1) +#define BIT_VO_EN_8822B BIT(0) + +/* 2 REG_PKT_LIFE_TIME_8822B */ + +#define BIT_SHIFT_PKT_LIFTIME_BEBK_8822B 16 +#define BIT_MASK_PKT_LIFTIME_BEBK_8822B 0xffff +#define BIT_PKT_LIFTIME_BEBK_8822B(x) \ + (((x) & BIT_MASK_PKT_LIFTIME_BEBK_8822B) \ + << BIT_SHIFT_PKT_LIFTIME_BEBK_8822B) +#define BIT_GET_PKT_LIFTIME_BEBK_8822B(x) \ + (((x) >> BIT_SHIFT_PKT_LIFTIME_BEBK_8822B) & \ + BIT_MASK_PKT_LIFTIME_BEBK_8822B) + +#define BIT_SHIFT_PKT_LIFTIME_VOVI_8822B 0 +#define BIT_MASK_PKT_LIFTIME_VOVI_8822B 0xffff +#define BIT_PKT_LIFTIME_VOVI_8822B(x) \ + (((x) & BIT_MASK_PKT_LIFTIME_VOVI_8822B) \ + << BIT_SHIFT_PKT_LIFTIME_VOVI_8822B) +#define BIT_GET_PKT_LIFTIME_VOVI_8822B(x) \ + (((x) >> BIT_SHIFT_PKT_LIFTIME_VOVI_8822B) & \ + BIT_MASK_PKT_LIFTIME_VOVI_8822B) + +/* 2 REG_STBC_SETTING_8822B */ + +#define BIT_SHIFT_CDEND_TXTIME_L_8822B 4 +#define BIT_MASK_CDEND_TXTIME_L_8822B 0xf +#define BIT_CDEND_TXTIME_L_8822B(x) \ + (((x) & BIT_MASK_CDEND_TXTIME_L_8822B) \ + << BIT_SHIFT_CDEND_TXTIME_L_8822B) +#define BIT_GET_CDEND_TXTIME_L_8822B(x) \ + (((x) >> BIT_SHIFT_CDEND_TXTIME_L_8822B) & \ + BIT_MASK_CDEND_TXTIME_L_8822B) + +#define BIT_SHIFT_NESS_8822B 2 +#define BIT_MASK_NESS_8822B 0x3 +#define BIT_NESS_8822B(x) (((x) & BIT_MASK_NESS_8822B) << BIT_SHIFT_NESS_8822B) +#define BIT_GET_NESS_8822B(x) \ + (((x) >> BIT_SHIFT_NESS_8822B) & BIT_MASK_NESS_8822B) + +#define BIT_SHIFT_STBC_CFEND_8822B 0 +#define BIT_MASK_STBC_CFEND_8822B 0x3 +#define BIT_STBC_CFEND_8822B(x) \ + (((x) & BIT_MASK_STBC_CFEND_8822B) << BIT_SHIFT_STBC_CFEND_8822B) +#define BIT_GET_STBC_CFEND_8822B(x) \ + (((x) >> BIT_SHIFT_STBC_CFEND_8822B) & BIT_MASK_STBC_CFEND_8822B) + +/* 2 REG_STBC_SETTING2_8822B */ + +#define BIT_SHIFT_CDEND_TXTIME_H_8822B 0 +#define BIT_MASK_CDEND_TXTIME_H_8822B 0x1f +#define BIT_CDEND_TXTIME_H_8822B(x) \ + (((x) & BIT_MASK_CDEND_TXTIME_H_8822B) \ + << BIT_SHIFT_CDEND_TXTIME_H_8822B) +#define BIT_GET_CDEND_TXTIME_H_8822B(x) \ + (((x) >> BIT_SHIFT_CDEND_TXTIME_H_8822B) & \ + BIT_MASK_CDEND_TXTIME_H_8822B) + +/* 2 REG_QUEUE_CTRL_8822B */ +#define BIT_PTA_EDCCA_EN_8822B BIT(5) +#define BIT_PTA_WL_TX_EN_8822B BIT(4) +#define BIT_R_USE_DATA_BW_8822B BIT(3) +#define BIT_TRI_PKT_INT_MODE1_8822B BIT(2) +#define BIT_TRI_PKT_INT_MODE0_8822B BIT(1) +#define BIT_ACQ_MODE_SEL_8822B BIT(0) + +/* 2 REG_SINGLE_AMPDU_CTRL_8822B */ +#define BIT_EN_SINGLE_APMDU_8822B BIT(7) + +/* 2 REG_PROT_MODE_CTRL_8822B */ + +#define BIT_SHIFT_RTS_MAX_AGG_NUM_8822B 24 +#define BIT_MASK_RTS_MAX_AGG_NUM_8822B 0x3f +#define BIT_RTS_MAX_AGG_NUM_8822B(x) \ + (((x) & BIT_MASK_RTS_MAX_AGG_NUM_8822B) \ + << BIT_SHIFT_RTS_MAX_AGG_NUM_8822B) +#define BIT_GET_RTS_MAX_AGG_NUM_8822B(x) \ + (((x) >> BIT_SHIFT_RTS_MAX_AGG_NUM_8822B) & \ + BIT_MASK_RTS_MAX_AGG_NUM_8822B) + +#define BIT_SHIFT_MAX_AGG_NUM_8822B 16 +#define BIT_MASK_MAX_AGG_NUM_8822B 0x3f +#define BIT_MAX_AGG_NUM_8822B(x) \ + (((x) & BIT_MASK_MAX_AGG_NUM_8822B) << BIT_SHIFT_MAX_AGG_NUM_8822B) +#define BIT_GET_MAX_AGG_NUM_8822B(x) \ + (((x) >> BIT_SHIFT_MAX_AGG_NUM_8822B) & BIT_MASK_MAX_AGG_NUM_8822B) + +#define BIT_SHIFT_RTS_TXTIME_TH_8822B 8 +#define BIT_MASK_RTS_TXTIME_TH_8822B 0xff +#define BIT_RTS_TXTIME_TH_8822B(x) \ + (((x) & BIT_MASK_RTS_TXTIME_TH_8822B) << BIT_SHIFT_RTS_TXTIME_TH_8822B) +#define BIT_GET_RTS_TXTIME_TH_8822B(x) \ + (((x) >> BIT_SHIFT_RTS_TXTIME_TH_8822B) & BIT_MASK_RTS_TXTIME_TH_8822B) + +#define BIT_SHIFT_RTS_LEN_TH_8822B 0 +#define BIT_MASK_RTS_LEN_TH_8822B 0xff +#define BIT_RTS_LEN_TH_8822B(x) \ + (((x) & BIT_MASK_RTS_LEN_TH_8822B) << BIT_SHIFT_RTS_LEN_TH_8822B) +#define BIT_GET_RTS_LEN_TH_8822B(x) \ + (((x) >> BIT_SHIFT_RTS_LEN_TH_8822B) & BIT_MASK_RTS_LEN_TH_8822B) + +/* 2 REG_BAR_MODE_CTRL_8822B */ + +#define BIT_SHIFT_BAR_RTY_LMT_8822B 16 +#define BIT_MASK_BAR_RTY_LMT_8822B 0x3 +#define BIT_BAR_RTY_LMT_8822B(x) \ + (((x) & BIT_MASK_BAR_RTY_LMT_8822B) << BIT_SHIFT_BAR_RTY_LMT_8822B) +#define BIT_GET_BAR_RTY_LMT_8822B(x) \ + (((x) >> BIT_SHIFT_BAR_RTY_LMT_8822B) & BIT_MASK_BAR_RTY_LMT_8822B) + +#define BIT_SHIFT_BAR_PKT_TXTIME_TH_8822B 8 +#define BIT_MASK_BAR_PKT_TXTIME_TH_8822B 0xff +#define BIT_BAR_PKT_TXTIME_TH_8822B(x) \ + (((x) & BIT_MASK_BAR_PKT_TXTIME_TH_8822B) \ + << BIT_SHIFT_BAR_PKT_TXTIME_TH_8822B) +#define BIT_GET_BAR_PKT_TXTIME_TH_8822B(x) \ + (((x) >> BIT_SHIFT_BAR_PKT_TXTIME_TH_8822B) & \ + BIT_MASK_BAR_PKT_TXTIME_TH_8822B) + +#define BIT_BAR_EN_V1_8822B BIT(6) + +#define BIT_SHIFT_BAR_PKTNUM_TH_V1_8822B 0 +#define BIT_MASK_BAR_PKTNUM_TH_V1_8822B 0x3f +#define BIT_BAR_PKTNUM_TH_V1_8822B(x) \ + (((x) & BIT_MASK_BAR_PKTNUM_TH_V1_8822B) \ + << BIT_SHIFT_BAR_PKTNUM_TH_V1_8822B) +#define BIT_GET_BAR_PKTNUM_TH_V1_8822B(x) \ + (((x) >> BIT_SHIFT_BAR_PKTNUM_TH_V1_8822B) & \ + BIT_MASK_BAR_PKTNUM_TH_V1_8822B) + +/* 2 REG_RA_TRY_RATE_AGG_LMT_8822B */ + +#define BIT_SHIFT_RA_TRY_RATE_AGG_LMT_V1_8822B 0 +#define BIT_MASK_RA_TRY_RATE_AGG_LMT_V1_8822B 0x3f +#define BIT_RA_TRY_RATE_AGG_LMT_V1_8822B(x) \ + (((x) & BIT_MASK_RA_TRY_RATE_AGG_LMT_V1_8822B) \ + << BIT_SHIFT_RA_TRY_RATE_AGG_LMT_V1_8822B) +#define BIT_GET_RA_TRY_RATE_AGG_LMT_V1_8822B(x) \ + (((x) >> BIT_SHIFT_RA_TRY_RATE_AGG_LMT_V1_8822B) & \ + BIT_MASK_RA_TRY_RATE_AGG_LMT_V1_8822B) + +/* 2 REG_MACID_SLEEP2_8822B */ + +#define BIT_SHIFT_MACID95_64PKTSLEEP_8822B 0 +#define BIT_MASK_MACID95_64PKTSLEEP_8822B 0xffffffffL +#define BIT_MACID95_64PKTSLEEP_8822B(x) \ + (((x) & BIT_MASK_MACID95_64PKTSLEEP_8822B) \ + << BIT_SHIFT_MACID95_64PKTSLEEP_8822B) +#define BIT_GET_MACID95_64PKTSLEEP_8822B(x) \ + (((x) >> BIT_SHIFT_MACID95_64PKTSLEEP_8822B) & \ + BIT_MASK_MACID95_64PKTSLEEP_8822B) + +/* 2 REG_MACID_SLEEP_8822B */ + +#define BIT_SHIFT_MACID31_0_PKTSLEEP_8822B 0 +#define BIT_MASK_MACID31_0_PKTSLEEP_8822B 0xffffffffL +#define BIT_MACID31_0_PKTSLEEP_8822B(x) \ + (((x) & BIT_MASK_MACID31_0_PKTSLEEP_8822B) \ + << BIT_SHIFT_MACID31_0_PKTSLEEP_8822B) +#define BIT_GET_MACID31_0_PKTSLEEP_8822B(x) \ + (((x) >> BIT_SHIFT_MACID31_0_PKTSLEEP_8822B) & \ + BIT_MASK_MACID31_0_PKTSLEEP_8822B) + +/* 2 REG_HW_SEQ0_8822B */ + +#define BIT_SHIFT_HW_SSN_SEQ0_8822B 0 +#define BIT_MASK_HW_SSN_SEQ0_8822B 0xfff +#define BIT_HW_SSN_SEQ0_8822B(x) \ + (((x) & BIT_MASK_HW_SSN_SEQ0_8822B) << BIT_SHIFT_HW_SSN_SEQ0_8822B) +#define BIT_GET_HW_SSN_SEQ0_8822B(x) \ + (((x) >> BIT_SHIFT_HW_SSN_SEQ0_8822B) & BIT_MASK_HW_SSN_SEQ0_8822B) + +/* 2 REG_HW_SEQ1_8822B */ + +#define BIT_SHIFT_HW_SSN_SEQ1_8822B 0 +#define BIT_MASK_HW_SSN_SEQ1_8822B 0xfff +#define BIT_HW_SSN_SEQ1_8822B(x) \ + (((x) & BIT_MASK_HW_SSN_SEQ1_8822B) << BIT_SHIFT_HW_SSN_SEQ1_8822B) +#define BIT_GET_HW_SSN_SEQ1_8822B(x) \ + (((x) >> BIT_SHIFT_HW_SSN_SEQ1_8822B) & BIT_MASK_HW_SSN_SEQ1_8822B) + +/* 2 REG_HW_SEQ2_8822B */ + +#define BIT_SHIFT_HW_SSN_SEQ2_8822B 0 +#define BIT_MASK_HW_SSN_SEQ2_8822B 0xfff +#define BIT_HW_SSN_SEQ2_8822B(x) \ + (((x) & BIT_MASK_HW_SSN_SEQ2_8822B) << BIT_SHIFT_HW_SSN_SEQ2_8822B) +#define BIT_GET_HW_SSN_SEQ2_8822B(x) \ + (((x) >> BIT_SHIFT_HW_SSN_SEQ2_8822B) & BIT_MASK_HW_SSN_SEQ2_8822B) + +/* 2 REG_HW_SEQ3_8822B */ + +#define BIT_SHIFT_HW_SSN_SEQ3_8822B 0 +#define BIT_MASK_HW_SSN_SEQ3_8822B 0xfff +#define BIT_HW_SSN_SEQ3_8822B(x) \ + (((x) & BIT_MASK_HW_SSN_SEQ3_8822B) << BIT_SHIFT_HW_SSN_SEQ3_8822B) +#define BIT_GET_HW_SSN_SEQ3_8822B(x) \ + (((x) >> BIT_SHIFT_HW_SSN_SEQ3_8822B) & BIT_MASK_HW_SSN_SEQ3_8822B) + +/* 2 REG_NULL_PKT_STATUS_V1_8822B */ + +#define BIT_SHIFT_PTCL_TOTAL_PG_V2_8822B 2 +#define BIT_MASK_PTCL_TOTAL_PG_V2_8822B 0x3fff +#define BIT_PTCL_TOTAL_PG_V2_8822B(x) \ + (((x) & BIT_MASK_PTCL_TOTAL_PG_V2_8822B) \ + << BIT_SHIFT_PTCL_TOTAL_PG_V2_8822B) +#define BIT_GET_PTCL_TOTAL_PG_V2_8822B(x) \ + (((x) >> BIT_SHIFT_PTCL_TOTAL_PG_V2_8822B) & \ + BIT_MASK_PTCL_TOTAL_PG_V2_8822B) + +#define BIT_TX_NULL_1_8822B BIT(1) +#define BIT_TX_NULL_0_8822B BIT(0) + +/* 2 REG_PTCL_ERR_STATUS_8822B */ +#define BIT_PTCL_RATE_TABLE_INVALID_8822B BIT(7) +#define BIT_FTM_T2R_ERROR_8822B BIT(6) +#define BIT_PTCL_ERR0_8822B BIT(5) +#define BIT_PTCL_ERR1_8822B BIT(4) +#define BIT_PTCL_ERR2_8822B BIT(3) +#define BIT_PTCL_ERR3_8822B BIT(2) +#define BIT_PTCL_ERR4_8822B BIT(1) +#define BIT_PTCL_ERR5_8822B BIT(0) + +/* 2 REG_NULL_PKT_STATUS_EXTEND_8822B */ +#define BIT_CLI3_TX_NULL_1_8822B BIT(7) +#define BIT_CLI3_TX_NULL_0_8822B BIT(6) +#define BIT_CLI2_TX_NULL_1_8822B BIT(5) +#define BIT_CLI2_TX_NULL_0_8822B BIT(4) +#define BIT_CLI1_TX_NULL_1_8822B BIT(3) +#define BIT_CLI1_TX_NULL_0_8822B BIT(2) +#define BIT_CLI0_TX_NULL_1_8822B BIT(1) +#define BIT_CLI0_TX_NULL_0_8822B BIT(0) + +/* 2 REG_VIDEO_ENHANCEMENT_FUN_8822B */ +#define BIT_VIDEO_JUST_DROP_8822B BIT(1) +#define BIT_VIDEO_ENHANCEMENT_FUN_EN_8822B BIT(0) + +/* 2 REG_BT_POLLUTE_PKT_CNT_8822B */ + +#define BIT_SHIFT_BT_POLLUTE_PKT_CNT_8822B 0 +#define BIT_MASK_BT_POLLUTE_PKT_CNT_8822B 0xffff +#define BIT_BT_POLLUTE_PKT_CNT_8822B(x) \ + (((x) & BIT_MASK_BT_POLLUTE_PKT_CNT_8822B) \ + << BIT_SHIFT_BT_POLLUTE_PKT_CNT_8822B) +#define BIT_GET_BT_POLLUTE_PKT_CNT_8822B(x) \ + (((x) >> BIT_SHIFT_BT_POLLUTE_PKT_CNT_8822B) & \ + BIT_MASK_BT_POLLUTE_PKT_CNT_8822B) + +/* 2 REG_NOT_VALID_8822B */ + +/* 2 REG_PTCL_DBG_8822B */ + +#define BIT_SHIFT_PTCL_DBG_8822B 0 +#define BIT_MASK_PTCL_DBG_8822B 0xffffffffL +#define BIT_PTCL_DBG_8822B(x) \ + (((x) & BIT_MASK_PTCL_DBG_8822B) << BIT_SHIFT_PTCL_DBG_8822B) +#define BIT_GET_PTCL_DBG_8822B(x) \ + (((x) >> BIT_SHIFT_PTCL_DBG_8822B) & BIT_MASK_PTCL_DBG_8822B) + +/* 2 REG_NOT_VALID_8822B */ + +/* 2 REG_CPUMGQ_TIMER_CTRL2_8822B */ + +#define BIT_SHIFT_TRI_HEAD_ADDR_8822B 16 +#define BIT_MASK_TRI_HEAD_ADDR_8822B 0xfff +#define BIT_TRI_HEAD_ADDR_8822B(x) \ + (((x) & BIT_MASK_TRI_HEAD_ADDR_8822B) << BIT_SHIFT_TRI_HEAD_ADDR_8822B) +#define BIT_GET_TRI_HEAD_ADDR_8822B(x) \ + (((x) >> BIT_SHIFT_TRI_HEAD_ADDR_8822B) & BIT_MASK_TRI_HEAD_ADDR_8822B) + +#define BIT_DROP_TH_EN_8822B BIT(8) + +#define BIT_SHIFT_DROP_TH_8822B 0 +#define BIT_MASK_DROP_TH_8822B 0xff +#define BIT_DROP_TH_8822B(x) \ + (((x) & BIT_MASK_DROP_TH_8822B) << BIT_SHIFT_DROP_TH_8822B) +#define BIT_GET_DROP_TH_8822B(x) \ + (((x) >> BIT_SHIFT_DROP_TH_8822B) & BIT_MASK_DROP_TH_8822B) + +/* 2 REG_NOT_VALID_8822B */ + +/* 2 REG_DUMMY_PAGE4_V1_8822B */ +#define BIT_BCN_EN_EXTHWSEQ_8822B BIT(1) +#define BIT_BCN_EN_HWSEQ_8822B BIT(0) + +/* 2 REG_MOREDATA_8822B */ +#define BIT_MOREDATA_CTRL2_EN_V1_8822B BIT(3) +#define BIT_MOREDATA_CTRL1_EN_V1_8822B BIT(2) +#define BIT_PKTIN_MOREDATA_REPLACE_ENABLE_V1_8822B BIT(0) + +/* 2 REG_NOT_VALID_8822B */ + +/* 2 REG_Q0_Q1_INFO_8822B */ +#define BIT_QUEUE_MACID_AC_NOT_THE_SAME_8822B BIT(31) + +#define BIT_SHIFT_GTAB_ID_8822B 28 +#define BIT_MASK_GTAB_ID_8822B 0x7 +#define BIT_GTAB_ID_8822B(x) \ + (((x) & BIT_MASK_GTAB_ID_8822B) << BIT_SHIFT_GTAB_ID_8822B) +#define BIT_GET_GTAB_ID_8822B(x) \ + (((x) >> BIT_SHIFT_GTAB_ID_8822B) & BIT_MASK_GTAB_ID_8822B) + +#define BIT_SHIFT_AC1_PKT_INFO_8822B 16 +#define BIT_MASK_AC1_PKT_INFO_8822B 0xfff +#define BIT_AC1_PKT_INFO_8822B(x) \ + (((x) & BIT_MASK_AC1_PKT_INFO_8822B) << BIT_SHIFT_AC1_PKT_INFO_8822B) +#define BIT_GET_AC1_PKT_INFO_8822B(x) \ + (((x) >> BIT_SHIFT_AC1_PKT_INFO_8822B) & BIT_MASK_AC1_PKT_INFO_8822B) + +#define BIT_QUEUE_MACID_AC_NOT_THE_SAME_V1_8822B BIT(15) + +#define BIT_SHIFT_GTAB_ID_V1_8822B 12 +#define BIT_MASK_GTAB_ID_V1_8822B 0x7 +#define BIT_GTAB_ID_V1_8822B(x) \ + (((x) & BIT_MASK_GTAB_ID_V1_8822B) << BIT_SHIFT_GTAB_ID_V1_8822B) +#define BIT_GET_GTAB_ID_V1_8822B(x) \ + (((x) >> BIT_SHIFT_GTAB_ID_V1_8822B) & BIT_MASK_GTAB_ID_V1_8822B) + +#define BIT_SHIFT_AC0_PKT_INFO_8822B 0 +#define BIT_MASK_AC0_PKT_INFO_8822B 0xfff +#define BIT_AC0_PKT_INFO_8822B(x) \ + (((x) & BIT_MASK_AC0_PKT_INFO_8822B) << BIT_SHIFT_AC0_PKT_INFO_8822B) +#define BIT_GET_AC0_PKT_INFO_8822B(x) \ + (((x) >> BIT_SHIFT_AC0_PKT_INFO_8822B) & BIT_MASK_AC0_PKT_INFO_8822B) + +/* 2 REG_Q2_Q3_INFO_8822B */ +#define BIT_QUEUE_MACID_AC_NOT_THE_SAME_8822B BIT(31) + +#define BIT_SHIFT_GTAB_ID_8822B 28 +#define BIT_MASK_GTAB_ID_8822B 0x7 +#define BIT_GTAB_ID_8822B(x) \ + (((x) & BIT_MASK_GTAB_ID_8822B) << BIT_SHIFT_GTAB_ID_8822B) +#define BIT_GET_GTAB_ID_8822B(x) \ + (((x) >> BIT_SHIFT_GTAB_ID_8822B) & BIT_MASK_GTAB_ID_8822B) + +#define BIT_SHIFT_AC3_PKT_INFO_8822B 16 +#define BIT_MASK_AC3_PKT_INFO_8822B 0xfff +#define BIT_AC3_PKT_INFO_8822B(x) \ + (((x) & BIT_MASK_AC3_PKT_INFO_8822B) << BIT_SHIFT_AC3_PKT_INFO_8822B) +#define BIT_GET_AC3_PKT_INFO_8822B(x) \ + (((x) >> BIT_SHIFT_AC3_PKT_INFO_8822B) & BIT_MASK_AC3_PKT_INFO_8822B) + +#define BIT_QUEUE_MACID_AC_NOT_THE_SAME_V1_8822B BIT(15) + +#define BIT_SHIFT_GTAB_ID_V1_8822B 12 +#define BIT_MASK_GTAB_ID_V1_8822B 0x7 +#define BIT_GTAB_ID_V1_8822B(x) \ + (((x) & BIT_MASK_GTAB_ID_V1_8822B) << BIT_SHIFT_GTAB_ID_V1_8822B) +#define BIT_GET_GTAB_ID_V1_8822B(x) \ + (((x) >> BIT_SHIFT_GTAB_ID_V1_8822B) & BIT_MASK_GTAB_ID_V1_8822B) + +#define BIT_SHIFT_AC2_PKT_INFO_8822B 0 +#define BIT_MASK_AC2_PKT_INFO_8822B 0xfff +#define BIT_AC2_PKT_INFO_8822B(x) \ + (((x) & BIT_MASK_AC2_PKT_INFO_8822B) << BIT_SHIFT_AC2_PKT_INFO_8822B) +#define BIT_GET_AC2_PKT_INFO_8822B(x) \ + (((x) >> BIT_SHIFT_AC2_PKT_INFO_8822B) & BIT_MASK_AC2_PKT_INFO_8822B) + +/* 2 REG_Q4_Q5_INFO_8822B */ +#define BIT_QUEUE_MACID_AC_NOT_THE_SAME_8822B BIT(31) + +#define BIT_SHIFT_GTAB_ID_8822B 28 +#define BIT_MASK_GTAB_ID_8822B 0x7 +#define BIT_GTAB_ID_8822B(x) \ + (((x) & BIT_MASK_GTAB_ID_8822B) << BIT_SHIFT_GTAB_ID_8822B) +#define BIT_GET_GTAB_ID_8822B(x) \ + (((x) >> BIT_SHIFT_GTAB_ID_8822B) & BIT_MASK_GTAB_ID_8822B) + +#define BIT_SHIFT_AC5_PKT_INFO_8822B 16 +#define BIT_MASK_AC5_PKT_INFO_8822B 0xfff +#define BIT_AC5_PKT_INFO_8822B(x) \ + (((x) & BIT_MASK_AC5_PKT_INFO_8822B) << BIT_SHIFT_AC5_PKT_INFO_8822B) +#define BIT_GET_AC5_PKT_INFO_8822B(x) \ + (((x) >> BIT_SHIFT_AC5_PKT_INFO_8822B) & BIT_MASK_AC5_PKT_INFO_8822B) + +#define BIT_QUEUE_MACID_AC_NOT_THE_SAME_V1_8822B BIT(15) + +#define BIT_SHIFT_GTAB_ID_V1_8822B 12 +#define BIT_MASK_GTAB_ID_V1_8822B 0x7 +#define BIT_GTAB_ID_V1_8822B(x) \ + (((x) & BIT_MASK_GTAB_ID_V1_8822B) << BIT_SHIFT_GTAB_ID_V1_8822B) +#define BIT_GET_GTAB_ID_V1_8822B(x) \ + (((x) >> BIT_SHIFT_GTAB_ID_V1_8822B) & BIT_MASK_GTAB_ID_V1_8822B) + +#define BIT_SHIFT_AC4_PKT_INFO_8822B 0 +#define BIT_MASK_AC4_PKT_INFO_8822B 0xfff +#define BIT_AC4_PKT_INFO_8822B(x) \ + (((x) & BIT_MASK_AC4_PKT_INFO_8822B) << BIT_SHIFT_AC4_PKT_INFO_8822B) +#define BIT_GET_AC4_PKT_INFO_8822B(x) \ + (((x) >> BIT_SHIFT_AC4_PKT_INFO_8822B) & BIT_MASK_AC4_PKT_INFO_8822B) + +/* 2 REG_Q6_Q7_INFO_8822B */ +#define BIT_QUEUE_MACID_AC_NOT_THE_SAME_8822B BIT(31) + +#define BIT_SHIFT_GTAB_ID_8822B 28 +#define BIT_MASK_GTAB_ID_8822B 0x7 +#define BIT_GTAB_ID_8822B(x) \ + (((x) & BIT_MASK_GTAB_ID_8822B) << BIT_SHIFT_GTAB_ID_8822B) +#define BIT_GET_GTAB_ID_8822B(x) \ + (((x) >> BIT_SHIFT_GTAB_ID_8822B) & BIT_MASK_GTAB_ID_8822B) + +#define BIT_SHIFT_AC7_PKT_INFO_8822B 16 +#define BIT_MASK_AC7_PKT_INFO_8822B 0xfff +#define BIT_AC7_PKT_INFO_8822B(x) \ + (((x) & BIT_MASK_AC7_PKT_INFO_8822B) << BIT_SHIFT_AC7_PKT_INFO_8822B) +#define BIT_GET_AC7_PKT_INFO_8822B(x) \ + (((x) >> BIT_SHIFT_AC7_PKT_INFO_8822B) & BIT_MASK_AC7_PKT_INFO_8822B) + +#define BIT_QUEUE_MACID_AC_NOT_THE_SAME_V1_8822B BIT(15) + +#define BIT_SHIFT_GTAB_ID_V1_8822B 12 +#define BIT_MASK_GTAB_ID_V1_8822B 0x7 +#define BIT_GTAB_ID_V1_8822B(x) \ + (((x) & BIT_MASK_GTAB_ID_V1_8822B) << BIT_SHIFT_GTAB_ID_V1_8822B) +#define BIT_GET_GTAB_ID_V1_8822B(x) \ + (((x) >> BIT_SHIFT_GTAB_ID_V1_8822B) & BIT_MASK_GTAB_ID_V1_8822B) + +#define BIT_SHIFT_AC6_PKT_INFO_8822B 0 +#define BIT_MASK_AC6_PKT_INFO_8822B 0xfff +#define BIT_AC6_PKT_INFO_8822B(x) \ + (((x) & BIT_MASK_AC6_PKT_INFO_8822B) << BIT_SHIFT_AC6_PKT_INFO_8822B) +#define BIT_GET_AC6_PKT_INFO_8822B(x) \ + (((x) >> BIT_SHIFT_AC6_PKT_INFO_8822B) & BIT_MASK_AC6_PKT_INFO_8822B) + +/* 2 REG_MGQ_HIQ_INFO_8822B */ + +#define BIT_SHIFT_HIQ_PKT_INFO_8822B 16 +#define BIT_MASK_HIQ_PKT_INFO_8822B 0xfff +#define BIT_HIQ_PKT_INFO_8822B(x) \ + (((x) & BIT_MASK_HIQ_PKT_INFO_8822B) << BIT_SHIFT_HIQ_PKT_INFO_8822B) +#define BIT_GET_HIQ_PKT_INFO_8822B(x) \ + (((x) >> BIT_SHIFT_HIQ_PKT_INFO_8822B) & BIT_MASK_HIQ_PKT_INFO_8822B) + +#define BIT_SHIFT_MGQ_PKT_INFO_8822B 0 +#define BIT_MASK_MGQ_PKT_INFO_8822B 0xfff +#define BIT_MGQ_PKT_INFO_8822B(x) \ + (((x) & BIT_MASK_MGQ_PKT_INFO_8822B) << BIT_SHIFT_MGQ_PKT_INFO_8822B) +#define BIT_GET_MGQ_PKT_INFO_8822B(x) \ + (((x) >> BIT_SHIFT_MGQ_PKT_INFO_8822B) & BIT_MASK_MGQ_PKT_INFO_8822B) + +/* 2 REG_CMDQ_BCNQ_INFO_8822B */ + +#define BIT_SHIFT_CMDQ_PKT_INFO_8822B 16 +#define BIT_MASK_CMDQ_PKT_INFO_8822B 0xfff +#define BIT_CMDQ_PKT_INFO_8822B(x) \ + (((x) & BIT_MASK_CMDQ_PKT_INFO_8822B) << BIT_SHIFT_CMDQ_PKT_INFO_8822B) +#define BIT_GET_CMDQ_PKT_INFO_8822B(x) \ + (((x) >> BIT_SHIFT_CMDQ_PKT_INFO_8822B) & BIT_MASK_CMDQ_PKT_INFO_8822B) + +#define BIT_SHIFT_BCNQ_PKT_INFO_8822B 0 +#define BIT_MASK_BCNQ_PKT_INFO_8822B 0xfff +#define BIT_BCNQ_PKT_INFO_8822B(x) \ + (((x) & BIT_MASK_BCNQ_PKT_INFO_8822B) << BIT_SHIFT_BCNQ_PKT_INFO_8822B) +#define BIT_GET_BCNQ_PKT_INFO_8822B(x) \ + (((x) >> BIT_SHIFT_BCNQ_PKT_INFO_8822B) & BIT_MASK_BCNQ_PKT_INFO_8822B) + +/* 2 REG_USEREG_SETTING_8822B */ +#define BIT_NDPA_USEREG_8822B BIT(21) + +#define BIT_SHIFT_RETRY_USEREG_8822B 19 +#define BIT_MASK_RETRY_USEREG_8822B 0x3 +#define BIT_RETRY_USEREG_8822B(x) \ + (((x) & BIT_MASK_RETRY_USEREG_8822B) << BIT_SHIFT_RETRY_USEREG_8822B) +#define BIT_GET_RETRY_USEREG_8822B(x) \ + (((x) >> BIT_SHIFT_RETRY_USEREG_8822B) & BIT_MASK_RETRY_USEREG_8822B) + +#define BIT_SHIFT_TRYPKT_USEREG_8822B 17 +#define BIT_MASK_TRYPKT_USEREG_8822B 0x3 +#define BIT_TRYPKT_USEREG_8822B(x) \ + (((x) & BIT_MASK_TRYPKT_USEREG_8822B) << BIT_SHIFT_TRYPKT_USEREG_8822B) +#define BIT_GET_TRYPKT_USEREG_8822B(x) \ + (((x) >> BIT_SHIFT_TRYPKT_USEREG_8822B) & BIT_MASK_TRYPKT_USEREG_8822B) + +#define BIT_CTLPKT_USEREG_8822B BIT(16) + +/* 2 REG_AESIV_SETTING_8822B */ + +#define BIT_SHIFT_AESIV_OFFSET_8822B 0 +#define BIT_MASK_AESIV_OFFSET_8822B 0xfff +#define BIT_AESIV_OFFSET_8822B(x) \ + (((x) & BIT_MASK_AESIV_OFFSET_8822B) << BIT_SHIFT_AESIV_OFFSET_8822B) +#define BIT_GET_AESIV_OFFSET_8822B(x) \ + (((x) >> BIT_SHIFT_AESIV_OFFSET_8822B) & BIT_MASK_AESIV_OFFSET_8822B) + +/* 2 REG_BF0_TIME_SETTING_8822B */ +#define BIT_BF0_TIMER_SET_8822B BIT(31) +#define BIT_BF0_TIMER_CLR_8822B BIT(30) +#define BIT_BF0_UPDATE_EN_8822B BIT(29) +#define BIT_BF0_TIMER_EN_8822B BIT(28) + +#define BIT_SHIFT_BF0_PRETIME_OVER_8822B 16 +#define BIT_MASK_BF0_PRETIME_OVER_8822B 0xfff +#define BIT_BF0_PRETIME_OVER_8822B(x) \ + (((x) & BIT_MASK_BF0_PRETIME_OVER_8822B) \ + << BIT_SHIFT_BF0_PRETIME_OVER_8822B) +#define BIT_GET_BF0_PRETIME_OVER_8822B(x) \ + (((x) >> BIT_SHIFT_BF0_PRETIME_OVER_8822B) & \ + BIT_MASK_BF0_PRETIME_OVER_8822B) + +#define BIT_SHIFT_BF0_LIFETIME_8822B 0 +#define BIT_MASK_BF0_LIFETIME_8822B 0xffff +#define BIT_BF0_LIFETIME_8822B(x) \ + (((x) & BIT_MASK_BF0_LIFETIME_8822B) << BIT_SHIFT_BF0_LIFETIME_8822B) +#define BIT_GET_BF0_LIFETIME_8822B(x) \ + (((x) >> BIT_SHIFT_BF0_LIFETIME_8822B) & BIT_MASK_BF0_LIFETIME_8822B) + +/* 2 REG_BF1_TIME_SETTING_8822B */ +#define BIT_BF1_TIMER_SET_8822B BIT(31) +#define BIT_BF1_TIMER_CLR_8822B BIT(30) +#define BIT_BF1_UPDATE_EN_8822B BIT(29) +#define BIT_BF1_TIMER_EN_8822B BIT(28) + +#define BIT_SHIFT_BF1_PRETIME_OVER_8822B 16 +#define BIT_MASK_BF1_PRETIME_OVER_8822B 0xfff +#define BIT_BF1_PRETIME_OVER_8822B(x) \ + (((x) & BIT_MASK_BF1_PRETIME_OVER_8822B) \ + << BIT_SHIFT_BF1_PRETIME_OVER_8822B) +#define BIT_GET_BF1_PRETIME_OVER_8822B(x) \ + (((x) >> BIT_SHIFT_BF1_PRETIME_OVER_8822B) & \ + BIT_MASK_BF1_PRETIME_OVER_8822B) + +#define BIT_SHIFT_BF1_LIFETIME_8822B 0 +#define BIT_MASK_BF1_LIFETIME_8822B 0xffff +#define BIT_BF1_LIFETIME_8822B(x) \ + (((x) & BIT_MASK_BF1_LIFETIME_8822B) << BIT_SHIFT_BF1_LIFETIME_8822B) +#define BIT_GET_BF1_LIFETIME_8822B(x) \ + (((x) >> BIT_SHIFT_BF1_LIFETIME_8822B) & BIT_MASK_BF1_LIFETIME_8822B) + +/* 2 REG_BF_TIMEOUT_EN_8822B */ +#define BIT_EN_VHT_LDPC_8822B BIT(9) +#define BIT_EN_HT_LDPC_8822B BIT(8) +#define BIT_BF1_TIMEOUT_EN_8822B BIT(1) +#define BIT_BF0_TIMEOUT_EN_8822B BIT(0) + +/* 2 REG_MACID_RELEASE0_8822B */ + +#define BIT_SHIFT_MACID31_0_RELEASE_8822B 0 +#define BIT_MASK_MACID31_0_RELEASE_8822B 0xffffffffL +#define BIT_MACID31_0_RELEASE_8822B(x) \ + (((x) & BIT_MASK_MACID31_0_RELEASE_8822B) \ + << BIT_SHIFT_MACID31_0_RELEASE_8822B) +#define BIT_GET_MACID31_0_RELEASE_8822B(x) \ + (((x) >> BIT_SHIFT_MACID31_0_RELEASE_8822B) & \ + BIT_MASK_MACID31_0_RELEASE_8822B) + +/* 2 REG_MACID_RELEASE1_8822B */ + +#define BIT_SHIFT_MACID63_32_RELEASE_8822B 0 +#define BIT_MASK_MACID63_32_RELEASE_8822B 0xffffffffL +#define BIT_MACID63_32_RELEASE_8822B(x) \ + (((x) & BIT_MASK_MACID63_32_RELEASE_8822B) \ + << BIT_SHIFT_MACID63_32_RELEASE_8822B) +#define BIT_GET_MACID63_32_RELEASE_8822B(x) \ + (((x) >> BIT_SHIFT_MACID63_32_RELEASE_8822B) & \ + BIT_MASK_MACID63_32_RELEASE_8822B) + +/* 2 REG_MACID_RELEASE2_8822B */ + +#define BIT_SHIFT_MACID95_64_RELEASE_8822B 0 +#define BIT_MASK_MACID95_64_RELEASE_8822B 0xffffffffL +#define BIT_MACID95_64_RELEASE_8822B(x) \ + (((x) & BIT_MASK_MACID95_64_RELEASE_8822B) \ + << BIT_SHIFT_MACID95_64_RELEASE_8822B) +#define BIT_GET_MACID95_64_RELEASE_8822B(x) \ + (((x) >> BIT_SHIFT_MACID95_64_RELEASE_8822B) & \ + BIT_MASK_MACID95_64_RELEASE_8822B) + +/* 2 REG_MACID_RELEASE3_8822B */ + +#define BIT_SHIFT_MACID127_96_RELEASE_8822B 0 +#define BIT_MASK_MACID127_96_RELEASE_8822B 0xffffffffL +#define BIT_MACID127_96_RELEASE_8822B(x) \ + (((x) & BIT_MASK_MACID127_96_RELEASE_8822B) \ + << BIT_SHIFT_MACID127_96_RELEASE_8822B) +#define BIT_GET_MACID127_96_RELEASE_8822B(x) \ + (((x) >> BIT_SHIFT_MACID127_96_RELEASE_8822B) & \ + BIT_MASK_MACID127_96_RELEASE_8822B) + +/* 2 REG_MACID_RELEASE_SETTING_8822B */ +#define BIT_MACID_VALUE_8822B BIT(7) + +#define BIT_SHIFT_MACID_OFFSET_8822B 0 +#define BIT_MASK_MACID_OFFSET_8822B 0x7f +#define BIT_MACID_OFFSET_8822B(x) \ + (((x) & BIT_MASK_MACID_OFFSET_8822B) << BIT_SHIFT_MACID_OFFSET_8822B) +#define BIT_GET_MACID_OFFSET_8822B(x) \ + (((x) >> BIT_SHIFT_MACID_OFFSET_8822B) & BIT_MASK_MACID_OFFSET_8822B) + +/* 2 REG_FAST_EDCA_VOVI_SETTING_8822B */ + +#define BIT_SHIFT_VI_FAST_EDCA_TO_8822B 24 +#define BIT_MASK_VI_FAST_EDCA_TO_8822B 0xff +#define BIT_VI_FAST_EDCA_TO_8822B(x) \ + (((x) & BIT_MASK_VI_FAST_EDCA_TO_8822B) \ + << BIT_SHIFT_VI_FAST_EDCA_TO_8822B) +#define BIT_GET_VI_FAST_EDCA_TO_8822B(x) \ + (((x) >> BIT_SHIFT_VI_FAST_EDCA_TO_8822B) & \ + BIT_MASK_VI_FAST_EDCA_TO_8822B) + +#define BIT_VI_THRESHOLD_SEL_8822B BIT(23) + +#define BIT_SHIFT_VI_FAST_EDCA_PKT_TH_8822B 16 +#define BIT_MASK_VI_FAST_EDCA_PKT_TH_8822B 0x7f +#define BIT_VI_FAST_EDCA_PKT_TH_8822B(x) \ + (((x) & BIT_MASK_VI_FAST_EDCA_PKT_TH_8822B) \ + << BIT_SHIFT_VI_FAST_EDCA_PKT_TH_8822B) +#define BIT_GET_VI_FAST_EDCA_PKT_TH_8822B(x) \ + (((x) >> BIT_SHIFT_VI_FAST_EDCA_PKT_TH_8822B) & \ + BIT_MASK_VI_FAST_EDCA_PKT_TH_8822B) + +#define BIT_SHIFT_VO_FAST_EDCA_TO_8822B 8 +#define BIT_MASK_VO_FAST_EDCA_TO_8822B 0xff +#define BIT_VO_FAST_EDCA_TO_8822B(x) \ + (((x) & BIT_MASK_VO_FAST_EDCA_TO_8822B) \ + << BIT_SHIFT_VO_FAST_EDCA_TO_8822B) +#define BIT_GET_VO_FAST_EDCA_TO_8822B(x) \ + (((x) >> BIT_SHIFT_VO_FAST_EDCA_TO_8822B) & \ + BIT_MASK_VO_FAST_EDCA_TO_8822B) + +#define BIT_VO_THRESHOLD_SEL_8822B BIT(7) + +#define BIT_SHIFT_VO_FAST_EDCA_PKT_TH_8822B 0 +#define BIT_MASK_VO_FAST_EDCA_PKT_TH_8822B 0x7f +#define BIT_VO_FAST_EDCA_PKT_TH_8822B(x) \ + (((x) & BIT_MASK_VO_FAST_EDCA_PKT_TH_8822B) \ + << BIT_SHIFT_VO_FAST_EDCA_PKT_TH_8822B) +#define BIT_GET_VO_FAST_EDCA_PKT_TH_8822B(x) \ + (((x) >> BIT_SHIFT_VO_FAST_EDCA_PKT_TH_8822B) & \ + BIT_MASK_VO_FAST_EDCA_PKT_TH_8822B) + +/* 2 REG_FAST_EDCA_BEBK_SETTING_8822B */ + +#define BIT_SHIFT_BK_FAST_EDCA_TO_8822B 24 +#define BIT_MASK_BK_FAST_EDCA_TO_8822B 0xff +#define BIT_BK_FAST_EDCA_TO_8822B(x) \ + (((x) & BIT_MASK_BK_FAST_EDCA_TO_8822B) \ + << BIT_SHIFT_BK_FAST_EDCA_TO_8822B) +#define BIT_GET_BK_FAST_EDCA_TO_8822B(x) \ + (((x) >> BIT_SHIFT_BK_FAST_EDCA_TO_8822B) & \ + BIT_MASK_BK_FAST_EDCA_TO_8822B) + +#define BIT_BK_THRESHOLD_SEL_8822B BIT(23) + +#define BIT_SHIFT_BK_FAST_EDCA_PKT_TH_8822B 16 +#define BIT_MASK_BK_FAST_EDCA_PKT_TH_8822B 0x7f +#define BIT_BK_FAST_EDCA_PKT_TH_8822B(x) \ + (((x) & BIT_MASK_BK_FAST_EDCA_PKT_TH_8822B) \ + << BIT_SHIFT_BK_FAST_EDCA_PKT_TH_8822B) +#define BIT_GET_BK_FAST_EDCA_PKT_TH_8822B(x) \ + (((x) >> BIT_SHIFT_BK_FAST_EDCA_PKT_TH_8822B) & \ + BIT_MASK_BK_FAST_EDCA_PKT_TH_8822B) + +#define BIT_SHIFT_BE_FAST_EDCA_TO_8822B 8 +#define BIT_MASK_BE_FAST_EDCA_TO_8822B 0xff +#define BIT_BE_FAST_EDCA_TO_8822B(x) \ + (((x) & BIT_MASK_BE_FAST_EDCA_TO_8822B) \ + << BIT_SHIFT_BE_FAST_EDCA_TO_8822B) +#define BIT_GET_BE_FAST_EDCA_TO_8822B(x) \ + (((x) >> BIT_SHIFT_BE_FAST_EDCA_TO_8822B) & \ + BIT_MASK_BE_FAST_EDCA_TO_8822B) + +#define BIT_BE_THRESHOLD_SEL_8822B BIT(7) + +#define BIT_SHIFT_BE_FAST_EDCA_PKT_TH_8822B 0 +#define BIT_MASK_BE_FAST_EDCA_PKT_TH_8822B 0x7f +#define BIT_BE_FAST_EDCA_PKT_TH_8822B(x) \ + (((x) & BIT_MASK_BE_FAST_EDCA_PKT_TH_8822B) \ + << BIT_SHIFT_BE_FAST_EDCA_PKT_TH_8822B) +#define BIT_GET_BE_FAST_EDCA_PKT_TH_8822B(x) \ + (((x) >> BIT_SHIFT_BE_FAST_EDCA_PKT_TH_8822B) & \ + BIT_MASK_BE_FAST_EDCA_PKT_TH_8822B) + +/* 2 REG_MACID_DROP0_8822B */ + +#define BIT_SHIFT_MACID31_0_DROP_8822B 0 +#define BIT_MASK_MACID31_0_DROP_8822B 0xffffffffL +#define BIT_MACID31_0_DROP_8822B(x) \ + (((x) & BIT_MASK_MACID31_0_DROP_8822B) \ + << BIT_SHIFT_MACID31_0_DROP_8822B) +#define BIT_GET_MACID31_0_DROP_8822B(x) \ + (((x) >> BIT_SHIFT_MACID31_0_DROP_8822B) & \ + BIT_MASK_MACID31_0_DROP_8822B) + +/* 2 REG_MACID_DROP1_8822B */ + +#define BIT_SHIFT_MACID63_32_DROP_8822B 0 +#define BIT_MASK_MACID63_32_DROP_8822B 0xffffffffL +#define BIT_MACID63_32_DROP_8822B(x) \ + (((x) & BIT_MASK_MACID63_32_DROP_8822B) \ + << BIT_SHIFT_MACID63_32_DROP_8822B) +#define BIT_GET_MACID63_32_DROP_8822B(x) \ + (((x) >> BIT_SHIFT_MACID63_32_DROP_8822B) & \ + BIT_MASK_MACID63_32_DROP_8822B) + +/* 2 REG_MACID_DROP2_8822B */ + +#define BIT_SHIFT_MACID95_64_DROP_8822B 0 +#define BIT_MASK_MACID95_64_DROP_8822B 0xffffffffL +#define BIT_MACID95_64_DROP_8822B(x) \ + (((x) & BIT_MASK_MACID95_64_DROP_8822B) \ + << BIT_SHIFT_MACID95_64_DROP_8822B) +#define BIT_GET_MACID95_64_DROP_8822B(x) \ + (((x) >> BIT_SHIFT_MACID95_64_DROP_8822B) & \ + BIT_MASK_MACID95_64_DROP_8822B) + +/* 2 REG_MACID_DROP3_8822B */ + +#define BIT_SHIFT_MACID127_96_DROP_8822B 0 +#define BIT_MASK_MACID127_96_DROP_8822B 0xffffffffL +#define BIT_MACID127_96_DROP_8822B(x) \ + (((x) & BIT_MASK_MACID127_96_DROP_8822B) \ + << BIT_SHIFT_MACID127_96_DROP_8822B) +#define BIT_GET_MACID127_96_DROP_8822B(x) \ + (((x) >> BIT_SHIFT_MACID127_96_DROP_8822B) & \ + BIT_MASK_MACID127_96_DROP_8822B) + +/* 2 REG_R_MACID_RELEASE_SUCCESS_0_8822B */ + +#define BIT_SHIFT_R_MACID_RELEASE_SUCCESS_0_8822B 0 +#define BIT_MASK_R_MACID_RELEASE_SUCCESS_0_8822B 0xffffffffL +#define BIT_R_MACID_RELEASE_SUCCESS_0_8822B(x) \ + (((x) & BIT_MASK_R_MACID_RELEASE_SUCCESS_0_8822B) \ + << BIT_SHIFT_R_MACID_RELEASE_SUCCESS_0_8822B) +#define BIT_GET_R_MACID_RELEASE_SUCCESS_0_8822B(x) \ + (((x) >> BIT_SHIFT_R_MACID_RELEASE_SUCCESS_0_8822B) & \ + BIT_MASK_R_MACID_RELEASE_SUCCESS_0_8822B) + +/* 2 REG_R_MACID_RELEASE_SUCCESS_1_8822B */ + +#define BIT_SHIFT_R_MACID_RELEASE_SUCCESS_1_8822B 0 +#define BIT_MASK_R_MACID_RELEASE_SUCCESS_1_8822B 0xffffffffL +#define BIT_R_MACID_RELEASE_SUCCESS_1_8822B(x) \ + (((x) & BIT_MASK_R_MACID_RELEASE_SUCCESS_1_8822B) \ + << BIT_SHIFT_R_MACID_RELEASE_SUCCESS_1_8822B) +#define BIT_GET_R_MACID_RELEASE_SUCCESS_1_8822B(x) \ + (((x) >> BIT_SHIFT_R_MACID_RELEASE_SUCCESS_1_8822B) & \ + BIT_MASK_R_MACID_RELEASE_SUCCESS_1_8822B) + +/* 2 REG_R_MACID_RELEASE_SUCCESS_2_8822B */ + +#define BIT_SHIFT_R_MACID_RELEASE_SUCCESS_2_8822B 0 +#define BIT_MASK_R_MACID_RELEASE_SUCCESS_2_8822B 0xffffffffL +#define BIT_R_MACID_RELEASE_SUCCESS_2_8822B(x) \ + (((x) & BIT_MASK_R_MACID_RELEASE_SUCCESS_2_8822B) \ + << BIT_SHIFT_R_MACID_RELEASE_SUCCESS_2_8822B) +#define BIT_GET_R_MACID_RELEASE_SUCCESS_2_8822B(x) \ + (((x) >> BIT_SHIFT_R_MACID_RELEASE_SUCCESS_2_8822B) & \ + BIT_MASK_R_MACID_RELEASE_SUCCESS_2_8822B) + +/* 2 REG_R_MACID_RELEASE_SUCCESS_3_8822B */ + +#define BIT_SHIFT_R_MACID_RELEASE_SUCCESS_3_8822B 0 +#define BIT_MASK_R_MACID_RELEASE_SUCCESS_3_8822B 0xffffffffL +#define BIT_R_MACID_RELEASE_SUCCESS_3_8822B(x) \ + (((x) & BIT_MASK_R_MACID_RELEASE_SUCCESS_3_8822B) \ + << BIT_SHIFT_R_MACID_RELEASE_SUCCESS_3_8822B) +#define BIT_GET_R_MACID_RELEASE_SUCCESS_3_8822B(x) \ + (((x) >> BIT_SHIFT_R_MACID_RELEASE_SUCCESS_3_8822B) & \ + BIT_MASK_R_MACID_RELEASE_SUCCESS_3_8822B) + +/* 2 REG_MGG_FIFO_CRTL_8822B */ +#define BIT_R_MGG_FIFO_EN_8822B BIT(31) + +#define BIT_SHIFT_R_MGG_FIFO_PG_SIZE_8822B 28 +#define BIT_MASK_R_MGG_FIFO_PG_SIZE_8822B 0x7 +#define BIT_R_MGG_FIFO_PG_SIZE_8822B(x) \ + (((x) & BIT_MASK_R_MGG_FIFO_PG_SIZE_8822B) \ + << BIT_SHIFT_R_MGG_FIFO_PG_SIZE_8822B) +#define BIT_GET_R_MGG_FIFO_PG_SIZE_8822B(x) \ + (((x) >> BIT_SHIFT_R_MGG_FIFO_PG_SIZE_8822B) & \ + BIT_MASK_R_MGG_FIFO_PG_SIZE_8822B) + +#define BIT_SHIFT_R_MGG_FIFO_START_PG_8822B 16 +#define BIT_MASK_R_MGG_FIFO_START_PG_8822B 0xfff +#define BIT_R_MGG_FIFO_START_PG_8822B(x) \ + (((x) & BIT_MASK_R_MGG_FIFO_START_PG_8822B) \ + << BIT_SHIFT_R_MGG_FIFO_START_PG_8822B) +#define BIT_GET_R_MGG_FIFO_START_PG_8822B(x) \ + (((x) >> BIT_SHIFT_R_MGG_FIFO_START_PG_8822B) & \ + BIT_MASK_R_MGG_FIFO_START_PG_8822B) + +#define BIT_SHIFT_R_MGG_FIFO_SIZE_8822B 14 +#define BIT_MASK_R_MGG_FIFO_SIZE_8822B 0x3 +#define BIT_R_MGG_FIFO_SIZE_8822B(x) \ + (((x) & BIT_MASK_R_MGG_FIFO_SIZE_8822B) \ + << BIT_SHIFT_R_MGG_FIFO_SIZE_8822B) +#define BIT_GET_R_MGG_FIFO_SIZE_8822B(x) \ + (((x) >> BIT_SHIFT_R_MGG_FIFO_SIZE_8822B) & \ + BIT_MASK_R_MGG_FIFO_SIZE_8822B) + +#define BIT_R_MGG_FIFO_PAUSE_8822B BIT(13) + +#define BIT_SHIFT_R_MGG_FIFO_RPTR_8822B 8 +#define BIT_MASK_R_MGG_FIFO_RPTR_8822B 0x1f +#define BIT_R_MGG_FIFO_RPTR_8822B(x) \ + (((x) & BIT_MASK_R_MGG_FIFO_RPTR_8822B) \ + << BIT_SHIFT_R_MGG_FIFO_RPTR_8822B) +#define BIT_GET_R_MGG_FIFO_RPTR_8822B(x) \ + (((x) >> BIT_SHIFT_R_MGG_FIFO_RPTR_8822B) & \ + BIT_MASK_R_MGG_FIFO_RPTR_8822B) + +#define BIT_R_MGG_FIFO_OV_8822B BIT(7) +#define BIT_R_MGG_FIFO_WPTR_ERROR_8822B BIT(6) +#define BIT_R_EN_CPU_LIFETIME_8822B BIT(5) + +#define BIT_SHIFT_R_MGG_FIFO_WPTR_8822B 0 +#define BIT_MASK_R_MGG_FIFO_WPTR_8822B 0x1f +#define BIT_R_MGG_FIFO_WPTR_8822B(x) \ + (((x) & BIT_MASK_R_MGG_FIFO_WPTR_8822B) \ + << BIT_SHIFT_R_MGG_FIFO_WPTR_8822B) +#define BIT_GET_R_MGG_FIFO_WPTR_8822B(x) \ + (((x) >> BIT_SHIFT_R_MGG_FIFO_WPTR_8822B) & \ + BIT_MASK_R_MGG_FIFO_WPTR_8822B) + +/* 2 REG_MGG_FIFO_INT_8822B */ + +#define BIT_SHIFT_R_MGG_FIFO_INT_FLAG_8822B 16 +#define BIT_MASK_R_MGG_FIFO_INT_FLAG_8822B 0xffff +#define BIT_R_MGG_FIFO_INT_FLAG_8822B(x) \ + (((x) & BIT_MASK_R_MGG_FIFO_INT_FLAG_8822B) \ + << BIT_SHIFT_R_MGG_FIFO_INT_FLAG_8822B) +#define BIT_GET_R_MGG_FIFO_INT_FLAG_8822B(x) \ + (((x) >> BIT_SHIFT_R_MGG_FIFO_INT_FLAG_8822B) & \ + BIT_MASK_R_MGG_FIFO_INT_FLAG_8822B) + +#define BIT_SHIFT_R_MGG_FIFO_INT_MASK_8822B 0 +#define BIT_MASK_R_MGG_FIFO_INT_MASK_8822B 0xffff +#define BIT_R_MGG_FIFO_INT_MASK_8822B(x) \ + (((x) & BIT_MASK_R_MGG_FIFO_INT_MASK_8822B) \ + << BIT_SHIFT_R_MGG_FIFO_INT_MASK_8822B) +#define BIT_GET_R_MGG_FIFO_INT_MASK_8822B(x) \ + (((x) >> BIT_SHIFT_R_MGG_FIFO_INT_MASK_8822B) & \ + BIT_MASK_R_MGG_FIFO_INT_MASK_8822B) + +/* 2 REG_MGG_FIFO_LIFETIME_8822B */ + +#define BIT_SHIFT_R_MGG_FIFO_LIFETIME_8822B 16 +#define BIT_MASK_R_MGG_FIFO_LIFETIME_8822B 0xffff +#define BIT_R_MGG_FIFO_LIFETIME_8822B(x) \ + (((x) & BIT_MASK_R_MGG_FIFO_LIFETIME_8822B) \ + << BIT_SHIFT_R_MGG_FIFO_LIFETIME_8822B) +#define BIT_GET_R_MGG_FIFO_LIFETIME_8822B(x) \ + (((x) >> BIT_SHIFT_R_MGG_FIFO_LIFETIME_8822B) & \ + BIT_MASK_R_MGG_FIFO_LIFETIME_8822B) + +#define BIT_SHIFT_R_MGG_FIFO_VALID_MAP_8822B 0 +#define BIT_MASK_R_MGG_FIFO_VALID_MAP_8822B 0xffff +#define BIT_R_MGG_FIFO_VALID_MAP_8822B(x) \ + (((x) & BIT_MASK_R_MGG_FIFO_VALID_MAP_8822B) \ + << BIT_SHIFT_R_MGG_FIFO_VALID_MAP_8822B) +#define BIT_GET_R_MGG_FIFO_VALID_MAP_8822B(x) \ + (((x) >> BIT_SHIFT_R_MGG_FIFO_VALID_MAP_8822B) & \ + BIT_MASK_R_MGG_FIFO_VALID_MAP_8822B) + +/* 2 REG_R_MACID_RELEASE_SUCCESS_CLEAR_OFFSET_8822B */ + +#define BIT_SHIFT_R_MACID_RELEASE_SUCCESS_CLEAR_OFFSET_8822B 0 +#define BIT_MASK_R_MACID_RELEASE_SUCCESS_CLEAR_OFFSET_8822B 0x7f +#define BIT_R_MACID_RELEASE_SUCCESS_CLEAR_OFFSET_8822B(x) \ + (((x) & BIT_MASK_R_MACID_RELEASE_SUCCESS_CLEAR_OFFSET_8822B) \ + << BIT_SHIFT_R_MACID_RELEASE_SUCCESS_CLEAR_OFFSET_8822B) +#define BIT_GET_R_MACID_RELEASE_SUCCESS_CLEAR_OFFSET_8822B(x) \ + (((x) >> BIT_SHIFT_R_MACID_RELEASE_SUCCESS_CLEAR_OFFSET_8822B) & \ + BIT_MASK_R_MACID_RELEASE_SUCCESS_CLEAR_OFFSET_8822B) + +/* 2 REG_MACID_SHCUT_OFFSET_8822B */ + +#define BIT_SHIFT_MACID_SHCUT_OFFSET_V1_8822B 0 +#define BIT_MASK_MACID_SHCUT_OFFSET_V1_8822B 0xff +#define BIT_MACID_SHCUT_OFFSET_V1_8822B(x) \ + (((x) & BIT_MASK_MACID_SHCUT_OFFSET_V1_8822B) \ + << BIT_SHIFT_MACID_SHCUT_OFFSET_V1_8822B) +#define BIT_GET_MACID_SHCUT_OFFSET_V1_8822B(x) \ + (((x) >> BIT_SHIFT_MACID_SHCUT_OFFSET_V1_8822B) & \ + BIT_MASK_MACID_SHCUT_OFFSET_V1_8822B) + +/* 2 REG_MU_TX_CTL_8822B */ +#define BIT_R_EN_REVERS_GTAB_8822B BIT(6) + +#define BIT_SHIFT_R_MU_TABLE_VALID_8822B 0 +#define BIT_MASK_R_MU_TABLE_VALID_8822B 0x3f +#define BIT_R_MU_TABLE_VALID_8822B(x) \ + (((x) & BIT_MASK_R_MU_TABLE_VALID_8822B) \ + << BIT_SHIFT_R_MU_TABLE_VALID_8822B) +#define BIT_GET_R_MU_TABLE_VALID_8822B(x) \ + (((x) >> BIT_SHIFT_R_MU_TABLE_VALID_8822B) & \ + BIT_MASK_R_MU_TABLE_VALID_8822B) + +/* 2 REG_MU_STA_GID_VLD_8822B */ + +/* 2 REG_NOT_VALID_8822B */ + +#define BIT_SHIFT_R_MU_STA_GTAB_VALID_8822B 0 +#define BIT_MASK_R_MU_STA_GTAB_VALID_8822B 0xffffffffL +#define BIT_R_MU_STA_GTAB_VALID_8822B(x) \ + (((x) & BIT_MASK_R_MU_STA_GTAB_VALID_8822B) \ + << BIT_SHIFT_R_MU_STA_GTAB_VALID_8822B) +#define BIT_GET_R_MU_STA_GTAB_VALID_8822B(x) \ + (((x) >> BIT_SHIFT_R_MU_STA_GTAB_VALID_8822B) & \ + BIT_MASK_R_MU_STA_GTAB_VALID_8822B) + +#define BIT_SHIFT_R_MU_STA_GTAB_VALID_8822B 0 +#define BIT_MASK_R_MU_STA_GTAB_VALID_8822B 0xffffffffL +#define BIT_R_MU_STA_GTAB_VALID_8822B(x) \ + (((x) & BIT_MASK_R_MU_STA_GTAB_VALID_8822B) \ + << BIT_SHIFT_R_MU_STA_GTAB_VALID_8822B) +#define BIT_GET_R_MU_STA_GTAB_VALID_8822B(x) \ + (((x) >> BIT_SHIFT_R_MU_STA_GTAB_VALID_8822B) & \ + BIT_MASK_R_MU_STA_GTAB_VALID_8822B) + +/* 2 REG_MU_STA_USER_POS_INFO_8822B */ + +/* 2 REG_NOT_VALID_8822B */ + +#define BIT_SHIFT_R_MU_STA_GTAB_POSITION_8822B 0 +#define BIT_MASK_R_MU_STA_GTAB_POSITION_8822B 0xffffffffffffffffL +#define BIT_R_MU_STA_GTAB_POSITION_8822B(x) \ + (((x) & BIT_MASK_R_MU_STA_GTAB_POSITION_8822B) \ + << BIT_SHIFT_R_MU_STA_GTAB_POSITION_8822B) +#define BIT_GET_R_MU_STA_GTAB_POSITION_8822B(x) \ + (((x) >> BIT_SHIFT_R_MU_STA_GTAB_POSITION_8822B) & \ + BIT_MASK_R_MU_STA_GTAB_POSITION_8822B) + +#define BIT_SHIFT_R_MU_STA_GTAB_POSITION_8822B 0 +#define BIT_MASK_R_MU_STA_GTAB_POSITION_8822B 0xffffffffffffffffL +#define BIT_R_MU_STA_GTAB_POSITION_8822B(x) \ + (((x) & BIT_MASK_R_MU_STA_GTAB_POSITION_8822B) \ + << BIT_SHIFT_R_MU_STA_GTAB_POSITION_8822B) +#define BIT_GET_R_MU_STA_GTAB_POSITION_8822B(x) \ + (((x) >> BIT_SHIFT_R_MU_STA_GTAB_POSITION_8822B) & \ + BIT_MASK_R_MU_STA_GTAB_POSITION_8822B) + +/* 2 REG_MU_TRX_DBG_CNT_8822B */ +#define BIT_MU_DNGCNT_RST_8822B BIT(20) + +#define BIT_SHIFT_MU_DBGCNT_SEL_8822B 16 +#define BIT_MASK_MU_DBGCNT_SEL_8822B 0xf +#define BIT_MU_DBGCNT_SEL_8822B(x) \ + (((x) & BIT_MASK_MU_DBGCNT_SEL_8822B) << BIT_SHIFT_MU_DBGCNT_SEL_8822B) +#define BIT_GET_MU_DBGCNT_SEL_8822B(x) \ + (((x) >> BIT_SHIFT_MU_DBGCNT_SEL_8822B) & BIT_MASK_MU_DBGCNT_SEL_8822B) + +#define BIT_SHIFT_MU_DNGCNT_8822B 0 +#define BIT_MASK_MU_DNGCNT_8822B 0xffff +#define BIT_MU_DNGCNT_8822B(x) \ + (((x) & BIT_MASK_MU_DNGCNT_8822B) << BIT_SHIFT_MU_DNGCNT_8822B) +#define BIT_GET_MU_DNGCNT_8822B(x) \ + (((x) >> BIT_SHIFT_MU_DNGCNT_8822B) & BIT_MASK_MU_DNGCNT_8822B) + +/* 2 REG_NOT_VALID_8822B */ + +/* 2 REG_EDCA_VO_PARAM_8822B */ + +#define BIT_SHIFT_TXOPLIMIT_8822B 16 +#define BIT_MASK_TXOPLIMIT_8822B 0x7ff +#define BIT_TXOPLIMIT_8822B(x) \ + (((x) & BIT_MASK_TXOPLIMIT_8822B) << BIT_SHIFT_TXOPLIMIT_8822B) +#define BIT_GET_TXOPLIMIT_8822B(x) \ + (((x) >> BIT_SHIFT_TXOPLIMIT_8822B) & BIT_MASK_TXOPLIMIT_8822B) + +#define BIT_SHIFT_CW_8822B 8 +#define BIT_MASK_CW_8822B 0xff +#define BIT_CW_8822B(x) (((x) & BIT_MASK_CW_8822B) << BIT_SHIFT_CW_8822B) +#define BIT_GET_CW_8822B(x) (((x) >> BIT_SHIFT_CW_8822B) & BIT_MASK_CW_8822B) + +#define BIT_SHIFT_AIFS_8822B 0 +#define BIT_MASK_AIFS_8822B 0xff +#define BIT_AIFS_8822B(x) (((x) & BIT_MASK_AIFS_8822B) << BIT_SHIFT_AIFS_8822B) +#define BIT_GET_AIFS_8822B(x) \ + (((x) >> BIT_SHIFT_AIFS_8822B) & BIT_MASK_AIFS_8822B) + +/* 2 REG_EDCA_VI_PARAM_8822B */ + +/* 2 REG_NOT_VALID_8822B */ + +#define BIT_SHIFT_TXOPLIMIT_8822B 16 +#define BIT_MASK_TXOPLIMIT_8822B 0x7ff +#define BIT_TXOPLIMIT_8822B(x) \ + (((x) & BIT_MASK_TXOPLIMIT_8822B) << BIT_SHIFT_TXOPLIMIT_8822B) +#define BIT_GET_TXOPLIMIT_8822B(x) \ + (((x) >> BIT_SHIFT_TXOPLIMIT_8822B) & BIT_MASK_TXOPLIMIT_8822B) + +#define BIT_SHIFT_CW_8822B 8 +#define BIT_MASK_CW_8822B 0xff +#define BIT_CW_8822B(x) (((x) & BIT_MASK_CW_8822B) << BIT_SHIFT_CW_8822B) +#define BIT_GET_CW_8822B(x) (((x) >> BIT_SHIFT_CW_8822B) & BIT_MASK_CW_8822B) + +#define BIT_SHIFT_AIFS_8822B 0 +#define BIT_MASK_AIFS_8822B 0xff +#define BIT_AIFS_8822B(x) (((x) & BIT_MASK_AIFS_8822B) << BIT_SHIFT_AIFS_8822B) +#define BIT_GET_AIFS_8822B(x) \ + (((x) >> BIT_SHIFT_AIFS_8822B) & BIT_MASK_AIFS_8822B) + +/* 2 REG_EDCA_BE_PARAM_8822B */ + +/* 2 REG_NOT_VALID_8822B */ + +#define BIT_SHIFT_TXOPLIMIT_8822B 16 +#define BIT_MASK_TXOPLIMIT_8822B 0x7ff +#define BIT_TXOPLIMIT_8822B(x) \ + (((x) & BIT_MASK_TXOPLIMIT_8822B) << BIT_SHIFT_TXOPLIMIT_8822B) +#define BIT_GET_TXOPLIMIT_8822B(x) \ + (((x) >> BIT_SHIFT_TXOPLIMIT_8822B) & BIT_MASK_TXOPLIMIT_8822B) + +#define BIT_SHIFT_CW_8822B 8 +#define BIT_MASK_CW_8822B 0xff +#define BIT_CW_8822B(x) (((x) & BIT_MASK_CW_8822B) << BIT_SHIFT_CW_8822B) +#define BIT_GET_CW_8822B(x) (((x) >> BIT_SHIFT_CW_8822B) & BIT_MASK_CW_8822B) + +#define BIT_SHIFT_AIFS_8822B 0 +#define BIT_MASK_AIFS_8822B 0xff +#define BIT_AIFS_8822B(x) (((x) & BIT_MASK_AIFS_8822B) << BIT_SHIFT_AIFS_8822B) +#define BIT_GET_AIFS_8822B(x) \ + (((x) >> BIT_SHIFT_AIFS_8822B) & BIT_MASK_AIFS_8822B) + +/* 2 REG_EDCA_BK_PARAM_8822B */ + +/* 2 REG_NOT_VALID_8822B */ + +#define BIT_SHIFT_TXOPLIMIT_8822B 16 +#define BIT_MASK_TXOPLIMIT_8822B 0x7ff +#define BIT_TXOPLIMIT_8822B(x) \ + (((x) & BIT_MASK_TXOPLIMIT_8822B) << BIT_SHIFT_TXOPLIMIT_8822B) +#define BIT_GET_TXOPLIMIT_8822B(x) \ + (((x) >> BIT_SHIFT_TXOPLIMIT_8822B) & BIT_MASK_TXOPLIMIT_8822B) + +#define BIT_SHIFT_CW_8822B 8 +#define BIT_MASK_CW_8822B 0xff +#define BIT_CW_8822B(x) (((x) & BIT_MASK_CW_8822B) << BIT_SHIFT_CW_8822B) +#define BIT_GET_CW_8822B(x) (((x) >> BIT_SHIFT_CW_8822B) & BIT_MASK_CW_8822B) + +#define BIT_SHIFT_AIFS_8822B 0 +#define BIT_MASK_AIFS_8822B 0xff +#define BIT_AIFS_8822B(x) (((x) & BIT_MASK_AIFS_8822B) << BIT_SHIFT_AIFS_8822B) +#define BIT_GET_AIFS_8822B(x) \ + (((x) >> BIT_SHIFT_AIFS_8822B) & BIT_MASK_AIFS_8822B) + +/* 2 REG_BCNTCFG_8822B */ + +#define BIT_SHIFT_BCNCW_MAX_8822B 12 +#define BIT_MASK_BCNCW_MAX_8822B 0xf +#define BIT_BCNCW_MAX_8822B(x) \ + (((x) & BIT_MASK_BCNCW_MAX_8822B) << BIT_SHIFT_BCNCW_MAX_8822B) +#define BIT_GET_BCNCW_MAX_8822B(x) \ + (((x) >> BIT_SHIFT_BCNCW_MAX_8822B) & BIT_MASK_BCNCW_MAX_8822B) + +#define BIT_SHIFT_BCNCW_MIN_8822B 8 +#define BIT_MASK_BCNCW_MIN_8822B 0xf +#define BIT_BCNCW_MIN_8822B(x) \ + (((x) & BIT_MASK_BCNCW_MIN_8822B) << BIT_SHIFT_BCNCW_MIN_8822B) +#define BIT_GET_BCNCW_MIN_8822B(x) \ + (((x) >> BIT_SHIFT_BCNCW_MIN_8822B) & BIT_MASK_BCNCW_MIN_8822B) + +#define BIT_SHIFT_BCNIFS_8822B 0 +#define BIT_MASK_BCNIFS_8822B 0xff +#define BIT_BCNIFS_8822B(x) \ + (((x) & BIT_MASK_BCNIFS_8822B) << BIT_SHIFT_BCNIFS_8822B) +#define BIT_GET_BCNIFS_8822B(x) \ + (((x) >> BIT_SHIFT_BCNIFS_8822B) & BIT_MASK_BCNIFS_8822B) + +/* 2 REG_PIFS_8822B */ + +#define BIT_SHIFT_PIFS_8822B 0 +#define BIT_MASK_PIFS_8822B 0xff +#define BIT_PIFS_8822B(x) (((x) & BIT_MASK_PIFS_8822B) << BIT_SHIFT_PIFS_8822B) +#define BIT_GET_PIFS_8822B(x) \ + (((x) >> BIT_SHIFT_PIFS_8822B) & BIT_MASK_PIFS_8822B) + +/* 2 REG_RDG_PIFS_8822B */ + +#define BIT_SHIFT_RDG_PIFS_8822B 0 +#define BIT_MASK_RDG_PIFS_8822B 0xff +#define BIT_RDG_PIFS_8822B(x) \ + (((x) & BIT_MASK_RDG_PIFS_8822B) << BIT_SHIFT_RDG_PIFS_8822B) +#define BIT_GET_RDG_PIFS_8822B(x) \ + (((x) >> BIT_SHIFT_RDG_PIFS_8822B) & BIT_MASK_RDG_PIFS_8822B) + +/* 2 REG_SIFS_8822B */ + +#define BIT_SHIFT_SIFS_OFDM_TRX_8822B 24 +#define BIT_MASK_SIFS_OFDM_TRX_8822B 0xff +#define BIT_SIFS_OFDM_TRX_8822B(x) \ + (((x) & BIT_MASK_SIFS_OFDM_TRX_8822B) << BIT_SHIFT_SIFS_OFDM_TRX_8822B) +#define BIT_GET_SIFS_OFDM_TRX_8822B(x) \ + (((x) >> BIT_SHIFT_SIFS_OFDM_TRX_8822B) & BIT_MASK_SIFS_OFDM_TRX_8822B) + +#define BIT_SHIFT_SIFS_CCK_TRX_8822B 16 +#define BIT_MASK_SIFS_CCK_TRX_8822B 0xff +#define BIT_SIFS_CCK_TRX_8822B(x) \ + (((x) & BIT_MASK_SIFS_CCK_TRX_8822B) << BIT_SHIFT_SIFS_CCK_TRX_8822B) +#define BIT_GET_SIFS_CCK_TRX_8822B(x) \ + (((x) >> BIT_SHIFT_SIFS_CCK_TRX_8822B) & BIT_MASK_SIFS_CCK_TRX_8822B) + +#define BIT_SHIFT_SIFS_OFDM_CTX_8822B 8 +#define BIT_MASK_SIFS_OFDM_CTX_8822B 0xff +#define BIT_SIFS_OFDM_CTX_8822B(x) \ + (((x) & BIT_MASK_SIFS_OFDM_CTX_8822B) << BIT_SHIFT_SIFS_OFDM_CTX_8822B) +#define BIT_GET_SIFS_OFDM_CTX_8822B(x) \ + (((x) >> BIT_SHIFT_SIFS_OFDM_CTX_8822B) & BIT_MASK_SIFS_OFDM_CTX_8822B) + +#define BIT_SHIFT_SIFS_CCK_CTX_8822B 0 +#define BIT_MASK_SIFS_CCK_CTX_8822B 0xff +#define BIT_SIFS_CCK_CTX_8822B(x) \ + (((x) & BIT_MASK_SIFS_CCK_CTX_8822B) << BIT_SHIFT_SIFS_CCK_CTX_8822B) +#define BIT_GET_SIFS_CCK_CTX_8822B(x) \ + (((x) >> BIT_SHIFT_SIFS_CCK_CTX_8822B) & BIT_MASK_SIFS_CCK_CTX_8822B) + +/* 2 REG_TSFTR_SYN_OFFSET_8822B */ + +#define BIT_SHIFT_TSFTR_SNC_OFFSET_8822B 0 +#define BIT_MASK_TSFTR_SNC_OFFSET_8822B 0xffff +#define BIT_TSFTR_SNC_OFFSET_8822B(x) \ + (((x) & BIT_MASK_TSFTR_SNC_OFFSET_8822B) \ + << BIT_SHIFT_TSFTR_SNC_OFFSET_8822B) +#define BIT_GET_TSFTR_SNC_OFFSET_8822B(x) \ + (((x) >> BIT_SHIFT_TSFTR_SNC_OFFSET_8822B) & \ + BIT_MASK_TSFTR_SNC_OFFSET_8822B) + +/* 2 REG_AGGR_BREAK_TIME_8822B */ + +#define BIT_SHIFT_AGGR_BK_TIME_8822B 0 +#define BIT_MASK_AGGR_BK_TIME_8822B 0xff +#define BIT_AGGR_BK_TIME_8822B(x) \ + (((x) & BIT_MASK_AGGR_BK_TIME_8822B) << BIT_SHIFT_AGGR_BK_TIME_8822B) +#define BIT_GET_AGGR_BK_TIME_8822B(x) \ + (((x) >> BIT_SHIFT_AGGR_BK_TIME_8822B) & BIT_MASK_AGGR_BK_TIME_8822B) + +/* 2 REG_SLOT_8822B */ + +#define BIT_SHIFT_SLOT_8822B 0 +#define BIT_MASK_SLOT_8822B 0xff +#define BIT_SLOT_8822B(x) (((x) & BIT_MASK_SLOT_8822B) << BIT_SHIFT_SLOT_8822B) +#define BIT_GET_SLOT_8822B(x) \ + (((x) >> BIT_SHIFT_SLOT_8822B) & BIT_MASK_SLOT_8822B) + +/* 2 REG_TX_PTCL_CTRL_8822B */ +#define BIT_DIS_EDCCA_8822B BIT(15) +#define BIT_DIS_CCA_8822B BIT(14) +#define BIT_LSIG_TXOP_TXCMD_NAV_8822B BIT(13) +#define BIT_SIFS_BK_EN_8822B BIT(12) + +#define BIT_SHIFT_TXQ_NAV_MSK_8822B 8 +#define BIT_MASK_TXQ_NAV_MSK_8822B 0xf +#define BIT_TXQ_NAV_MSK_8822B(x) \ + (((x) & BIT_MASK_TXQ_NAV_MSK_8822B) << BIT_SHIFT_TXQ_NAV_MSK_8822B) +#define BIT_GET_TXQ_NAV_MSK_8822B(x) \ + (((x) >> BIT_SHIFT_TXQ_NAV_MSK_8822B) & BIT_MASK_TXQ_NAV_MSK_8822B) + +#define BIT_DIS_CW_8822B BIT(7) +#define BIT_NAV_END_TXOP_8822B BIT(6) +#define BIT_RDG_END_TXOP_8822B BIT(5) +#define BIT_AC_INBCN_HOLD_8822B BIT(4) +#define BIT_MGTQ_TXOP_EN_8822B BIT(3) +#define BIT_MGTQ_RTSMF_EN_8822B BIT(2) +#define BIT_HIQ_RTSMF_EN_8822B BIT(1) +#define BIT_BCN_RTSMF_EN_8822B BIT(0) + +/* 2 REG_TXPAUSE_8822B */ +#define BIT_STOP_BCN_HI_MGT_8822B BIT(7) +#define BIT_MAC_STOPBCNQ_8822B BIT(6) +#define BIT_MAC_STOPHIQ_8822B BIT(5) +#define BIT_MAC_STOPMGQ_8822B BIT(4) +#define BIT_MAC_STOPBK_8822B BIT(3) +#define BIT_MAC_STOPBE_8822B BIT(2) +#define BIT_MAC_STOPVI_8822B BIT(1) +#define BIT_MAC_STOPVO_8822B BIT(0) + +/* 2 REG_DIS_TXREQ_CLR_8822B */ +#define BIT_DIS_BT_CCA_8822B BIT(7) +#define BIT_DIS_TXREQ_CLR_HI_8822B BIT(5) +#define BIT_DIS_TXREQ_CLR_MGQ_8822B BIT(4) +#define BIT_DIS_TXREQ_CLR_VO_8822B BIT(3) +#define BIT_DIS_TXREQ_CLR_VI_8822B BIT(2) +#define BIT_DIS_TXREQ_CLR_BE_8822B BIT(1) +#define BIT_DIS_TXREQ_CLR_BK_8822B BIT(0) + +/* 2 REG_RD_CTRL_8822B */ +#define BIT_EN_CLR_TXREQ_INCCA_8822B BIT(15) +#define BIT_DIS_TX_OVER_BCNQ_8822B BIT(14) +#define BIT_EN_BCNERR_INCCCA_8822B BIT(13) +#define BIT_EDCCA_MSK_CNTDOWN_EN_8822B BIT(11) +#define BIT_DIS_TXOP_CFE_8822B BIT(10) +#define BIT_DIS_LSIG_CFE_8822B BIT(9) +#define BIT_DIS_STBC_CFE_8822B BIT(8) +#define BIT_BKQ_RD_INIT_EN_8822B BIT(7) +#define BIT_BEQ_RD_INIT_EN_8822B BIT(6) +#define BIT_VIQ_RD_INIT_EN_8822B BIT(5) +#define BIT_VOQ_RD_INIT_EN_8822B BIT(4) +#define BIT_BKQ_RD_RESP_EN_8822B BIT(3) +#define BIT_BEQ_RD_RESP_EN_8822B BIT(2) +#define BIT_VIQ_RD_RESP_EN_8822B BIT(1) +#define BIT_VOQ_RD_RESP_EN_8822B BIT(0) + +/* 2 REG_MBSSID_CTRL_8822B */ +#define BIT_MBID_BCNQ7_EN_8822B BIT(7) +#define BIT_MBID_BCNQ6_EN_8822B BIT(6) +#define BIT_MBID_BCNQ5_EN_8822B BIT(5) +#define BIT_MBID_BCNQ4_EN_8822B BIT(4) +#define BIT_MBID_BCNQ3_EN_8822B BIT(3) +#define BIT_MBID_BCNQ2_EN_8822B BIT(2) +#define BIT_MBID_BCNQ1_EN_8822B BIT(1) +#define BIT_MBID_BCNQ0_EN_8822B BIT(0) + +/* 2 REG_P2PPS_CTRL_8822B */ +#define BIT_P2P_CTW_ALLSTASLEEP_8822B BIT(7) +#define BIT_P2P_OFF_DISTX_EN_8822B BIT(6) +#define BIT_PWR_MGT_EN_8822B BIT(5) +#define BIT_P2P_NOA1_EN_8822B BIT(2) +#define BIT_P2P_NOA0_EN_8822B BIT(1) + +/* 2 REG_PKT_LIFETIME_CTRL_8822B */ +#define BIT_EN_P2P_CTWND1_8822B BIT(23) +#define BIT_EN_BKF_CLR_TXREQ_8822B BIT(22) +#define BIT_EN_TSFBIT32_RST_P2P_8822B BIT(21) +#define BIT_EN_BCN_TX_BTCCA_8822B BIT(20) +#define BIT_DIS_PKT_TX_ATIM_8822B BIT(19) +#define BIT_DIS_BCN_DIS_CTN_8822B BIT(18) +#define BIT_EN_NAVEND_RST_TXOP_8822B BIT(17) +#define BIT_EN_FILTER_CCA_8822B BIT(16) + +#define BIT_SHIFT_CCA_FILTER_THRS_8822B 8 +#define BIT_MASK_CCA_FILTER_THRS_8822B 0xff +#define BIT_CCA_FILTER_THRS_8822B(x) \ + (((x) & BIT_MASK_CCA_FILTER_THRS_8822B) \ + << BIT_SHIFT_CCA_FILTER_THRS_8822B) +#define BIT_GET_CCA_FILTER_THRS_8822B(x) \ + (((x) >> BIT_SHIFT_CCA_FILTER_THRS_8822B) & \ + BIT_MASK_CCA_FILTER_THRS_8822B) + +#define BIT_SHIFT_EDCCA_THRS_8822B 0 +#define BIT_MASK_EDCCA_THRS_8822B 0xff +#define BIT_EDCCA_THRS_8822B(x) \ + (((x) & BIT_MASK_EDCCA_THRS_8822B) << BIT_SHIFT_EDCCA_THRS_8822B) +#define BIT_GET_EDCCA_THRS_8822B(x) \ + (((x) >> BIT_SHIFT_EDCCA_THRS_8822B) & BIT_MASK_EDCCA_THRS_8822B) + +/* 2 REG_P2PPS_SPEC_STATE_8822B */ +#define BIT_SPEC_POWER_STATE_8822B BIT(7) +#define BIT_SPEC_CTWINDOW_ON_8822B BIT(6) +#define BIT_SPEC_BEACON_AREA_ON_8822B BIT(5) +#define BIT_SPEC_CTWIN_EARLY_DISTX_8822B BIT(4) +#define BIT_SPEC_NOA1_OFF_PERIOD_8822B BIT(3) +#define BIT_SPEC_FORCE_DOZE1_8822B BIT(2) +#define BIT_SPEC_NOA0_OFF_PERIOD_8822B BIT(1) +#define BIT_SPEC_FORCE_DOZE0_8822B BIT(0) + +/* 2 REG_BAR_TX_CTRL_8822B */ + +/* 2 REG_NOT_VALID_8822B */ + +#define BIT_SHIFT_P2PON_DIS_TXTIME_8822B 0 +#define BIT_MASK_P2PON_DIS_TXTIME_8822B 0xff +#define BIT_P2PON_DIS_TXTIME_8822B(x) \ + (((x) & BIT_MASK_P2PON_DIS_TXTIME_8822B) \ + << BIT_SHIFT_P2PON_DIS_TXTIME_8822B) +#define BIT_GET_P2PON_DIS_TXTIME_8822B(x) \ + (((x) >> BIT_SHIFT_P2PON_DIS_TXTIME_8822B) & \ + BIT_MASK_P2PON_DIS_TXTIME_8822B) + +/* 2 REG_QUEUE_INCOL_THR_8822B */ + +#define BIT_SHIFT_BK_QUEUE_THR_8822B 24 +#define BIT_MASK_BK_QUEUE_THR_8822B 0xff +#define BIT_BK_QUEUE_THR_8822B(x) \ + (((x) & BIT_MASK_BK_QUEUE_THR_8822B) << BIT_SHIFT_BK_QUEUE_THR_8822B) +#define BIT_GET_BK_QUEUE_THR_8822B(x) \ + (((x) >> BIT_SHIFT_BK_QUEUE_THR_8822B) & BIT_MASK_BK_QUEUE_THR_8822B) + +#define BIT_SHIFT_BE_QUEUE_THR_8822B 16 +#define BIT_MASK_BE_QUEUE_THR_8822B 0xff +#define BIT_BE_QUEUE_THR_8822B(x) \ + (((x) & BIT_MASK_BE_QUEUE_THR_8822B) << BIT_SHIFT_BE_QUEUE_THR_8822B) +#define BIT_GET_BE_QUEUE_THR_8822B(x) \ + (((x) >> BIT_SHIFT_BE_QUEUE_THR_8822B) & BIT_MASK_BE_QUEUE_THR_8822B) + +#define BIT_SHIFT_VI_QUEUE_THR_8822B 8 +#define BIT_MASK_VI_QUEUE_THR_8822B 0xff +#define BIT_VI_QUEUE_THR_8822B(x) \ + (((x) & BIT_MASK_VI_QUEUE_THR_8822B) << BIT_SHIFT_VI_QUEUE_THR_8822B) +#define BIT_GET_VI_QUEUE_THR_8822B(x) \ + (((x) >> BIT_SHIFT_VI_QUEUE_THR_8822B) & BIT_MASK_VI_QUEUE_THR_8822B) + +#define BIT_SHIFT_VO_QUEUE_THR_8822B 0 +#define BIT_MASK_VO_QUEUE_THR_8822B 0xff +#define BIT_VO_QUEUE_THR_8822B(x) \ + (((x) & BIT_MASK_VO_QUEUE_THR_8822B) << BIT_SHIFT_VO_QUEUE_THR_8822B) +#define BIT_GET_VO_QUEUE_THR_8822B(x) \ + (((x) >> BIT_SHIFT_VO_QUEUE_THR_8822B) & BIT_MASK_VO_QUEUE_THR_8822B) + +/* 2 REG_QUEUE_INCOL_EN_8822B */ +#define BIT_QUEUE_INCOL_EN_8822B BIT(16) + +#define BIT_SHIFT_BE_TRIGGER_NUM_8822B 12 +#define BIT_MASK_BE_TRIGGER_NUM_8822B 0xf +#define BIT_BE_TRIGGER_NUM_8822B(x) \ + (((x) & BIT_MASK_BE_TRIGGER_NUM_8822B) \ + << BIT_SHIFT_BE_TRIGGER_NUM_8822B) +#define BIT_GET_BE_TRIGGER_NUM_8822B(x) \ + (((x) >> BIT_SHIFT_BE_TRIGGER_NUM_8822B) & \ + BIT_MASK_BE_TRIGGER_NUM_8822B) + +#define BIT_SHIFT_BK_TRIGGER_NUM_8822B 8 +#define BIT_MASK_BK_TRIGGER_NUM_8822B 0xf +#define BIT_BK_TRIGGER_NUM_8822B(x) \ + (((x) & BIT_MASK_BK_TRIGGER_NUM_8822B) \ + << BIT_SHIFT_BK_TRIGGER_NUM_8822B) +#define BIT_GET_BK_TRIGGER_NUM_8822B(x) \ + (((x) >> BIT_SHIFT_BK_TRIGGER_NUM_8822B) & \ + BIT_MASK_BK_TRIGGER_NUM_8822B) + +#define BIT_SHIFT_VI_TRIGGER_NUM_8822B 4 +#define BIT_MASK_VI_TRIGGER_NUM_8822B 0xf +#define BIT_VI_TRIGGER_NUM_8822B(x) \ + (((x) & BIT_MASK_VI_TRIGGER_NUM_8822B) \ + << BIT_SHIFT_VI_TRIGGER_NUM_8822B) +#define BIT_GET_VI_TRIGGER_NUM_8822B(x) \ + (((x) >> BIT_SHIFT_VI_TRIGGER_NUM_8822B) & \ + BIT_MASK_VI_TRIGGER_NUM_8822B) + +#define BIT_SHIFT_VO_TRIGGER_NUM_8822B 0 +#define BIT_MASK_VO_TRIGGER_NUM_8822B 0xf +#define BIT_VO_TRIGGER_NUM_8822B(x) \ + (((x) & BIT_MASK_VO_TRIGGER_NUM_8822B) \ + << BIT_SHIFT_VO_TRIGGER_NUM_8822B) +#define BIT_GET_VO_TRIGGER_NUM_8822B(x) \ + (((x) >> BIT_SHIFT_VO_TRIGGER_NUM_8822B) & \ + BIT_MASK_VO_TRIGGER_NUM_8822B) + +/* 2 REG_TBTT_PROHIBIT_8822B */ + +#define BIT_SHIFT_TBTT_HOLD_TIME_AP_8822B 8 +#define BIT_MASK_TBTT_HOLD_TIME_AP_8822B 0xfff +#define BIT_TBTT_HOLD_TIME_AP_8822B(x) \ + (((x) & BIT_MASK_TBTT_HOLD_TIME_AP_8822B) \ + << BIT_SHIFT_TBTT_HOLD_TIME_AP_8822B) +#define BIT_GET_TBTT_HOLD_TIME_AP_8822B(x) \ + (((x) >> BIT_SHIFT_TBTT_HOLD_TIME_AP_8822B) & \ + BIT_MASK_TBTT_HOLD_TIME_AP_8822B) + +#define BIT_SHIFT_TBTT_PROHIBIT_SETUP_8822B 0 +#define BIT_MASK_TBTT_PROHIBIT_SETUP_8822B 0xf +#define BIT_TBTT_PROHIBIT_SETUP_8822B(x) \ + (((x) & BIT_MASK_TBTT_PROHIBIT_SETUP_8822B) \ + << BIT_SHIFT_TBTT_PROHIBIT_SETUP_8822B) +#define BIT_GET_TBTT_PROHIBIT_SETUP_8822B(x) \ + (((x) >> BIT_SHIFT_TBTT_PROHIBIT_SETUP_8822B) & \ + BIT_MASK_TBTT_PROHIBIT_SETUP_8822B) + +/* 2 REG_P2PPS_STATE_8822B */ +#define BIT_POWER_STATE_8822B BIT(7) +#define BIT_CTWINDOW_ON_8822B BIT(6) +#define BIT_BEACON_AREA_ON_8822B BIT(5) +#define BIT_CTWIN_EARLY_DISTX_8822B BIT(4) +#define BIT_NOA1_OFF_PERIOD_8822B BIT(3) +#define BIT_FORCE_DOZE1_8822B BIT(2) +#define BIT_NOA0_OFF_PERIOD_8822B BIT(1) +#define BIT_FORCE_DOZE0_8822B BIT(0) + +/* 2 REG_RD_NAV_NXT_8822B */ + +#define BIT_SHIFT_RD_NAV_PROT_NXT_8822B 0 +#define BIT_MASK_RD_NAV_PROT_NXT_8822B 0xffff +#define BIT_RD_NAV_PROT_NXT_8822B(x) \ + (((x) & BIT_MASK_RD_NAV_PROT_NXT_8822B) \ + << BIT_SHIFT_RD_NAV_PROT_NXT_8822B) +#define BIT_GET_RD_NAV_PROT_NXT_8822B(x) \ + (((x) >> BIT_SHIFT_RD_NAV_PROT_NXT_8822B) & \ + BIT_MASK_RD_NAV_PROT_NXT_8822B) + +/* 2 REG_NAV_PROT_LEN_8822B */ + +#define BIT_SHIFT_NAV_PROT_LEN_8822B 0 +#define BIT_MASK_NAV_PROT_LEN_8822B 0xffff +#define BIT_NAV_PROT_LEN_8822B(x) \ + (((x) & BIT_MASK_NAV_PROT_LEN_8822B) << BIT_SHIFT_NAV_PROT_LEN_8822B) +#define BIT_GET_NAV_PROT_LEN_8822B(x) \ + (((x) >> BIT_SHIFT_NAV_PROT_LEN_8822B) & BIT_MASK_NAV_PROT_LEN_8822B) + +/* 2 REG_BCN_CTRL_8822B */ +#define BIT_DIS_RX_BSSID_FIT_8822B BIT(6) +#define BIT_P0_EN_TXBCN_RPT_8822B BIT(5) +#define BIT_DIS_TSF_UDT_8822B BIT(4) +#define BIT_EN_BCN_FUNCTION_8822B BIT(3) +#define BIT_P0_EN_RXBCN_RPT_8822B BIT(2) +#define BIT_EN_P2P_CTWINDOW_8822B BIT(1) +#define BIT_EN_P2P_BCNQ_AREA_8822B BIT(0) + +/* 2 REG_BCN_CTRL_CLINT0_8822B */ +#define BIT_CLI0_DIS_RX_BSSID_FIT_8822B BIT(6) +#define BIT_CLI0_DIS_TSF_UDT_8822B BIT(4) +#define BIT_CLI0_EN_BCN_FUNCTION_8822B BIT(3) +#define BIT_CLI0_EN_RXBCN_RPT_8822B BIT(2) +#define BIT_CLI0_ENP2P_CTWINDOW_8822B BIT(1) +#define BIT_CLI0_ENP2P_BCNQ_AREA_8822B BIT(0) + +/* 2 REG_MBID_NUM_8822B */ +#define BIT_EN_PRE_DL_BEACON_8822B BIT(3) + +#define BIT_SHIFT_MBID_BCN_NUM_8822B 0 +#define BIT_MASK_MBID_BCN_NUM_8822B 0x7 +#define BIT_MBID_BCN_NUM_8822B(x) \ + (((x) & BIT_MASK_MBID_BCN_NUM_8822B) << BIT_SHIFT_MBID_BCN_NUM_8822B) +#define BIT_GET_MBID_BCN_NUM_8822B(x) \ + (((x) >> BIT_SHIFT_MBID_BCN_NUM_8822B) & BIT_MASK_MBID_BCN_NUM_8822B) + +/* 2 REG_DUAL_TSF_RST_8822B */ +#define BIT_FREECNT_RST_8822B BIT(5) +#define BIT_TSFTR_CLI3_RST_8822B BIT(4) +#define BIT_TSFTR_CLI2_RST_8822B BIT(3) +#define BIT_TSFTR_CLI1_RST_8822B BIT(2) +#define BIT_TSFTR_CLI0_RST_8822B BIT(1) +#define BIT_TSFTR_RST_8822B BIT(0) + +/* 2 REG_MBSSID_BCN_SPACE_8822B */ + +#define BIT_SHIFT_BCN_TIMER_SEL_FWRD_8822B 28 +#define BIT_MASK_BCN_TIMER_SEL_FWRD_8822B 0x7 +#define BIT_BCN_TIMER_SEL_FWRD_8822B(x) \ + (((x) & BIT_MASK_BCN_TIMER_SEL_FWRD_8822B) \ + << BIT_SHIFT_BCN_TIMER_SEL_FWRD_8822B) +#define BIT_GET_BCN_TIMER_SEL_FWRD_8822B(x) \ + (((x) >> BIT_SHIFT_BCN_TIMER_SEL_FWRD_8822B) & \ + BIT_MASK_BCN_TIMER_SEL_FWRD_8822B) + +#define BIT_SHIFT_BCN_SPACE_CLINT0_8822B 16 +#define BIT_MASK_BCN_SPACE_CLINT0_8822B 0xfff +#define BIT_BCN_SPACE_CLINT0_8822B(x) \ + (((x) & BIT_MASK_BCN_SPACE_CLINT0_8822B) \ + << BIT_SHIFT_BCN_SPACE_CLINT0_8822B) +#define BIT_GET_BCN_SPACE_CLINT0_8822B(x) \ + (((x) >> BIT_SHIFT_BCN_SPACE_CLINT0_8822B) & \ + BIT_MASK_BCN_SPACE_CLINT0_8822B) + +#define BIT_SHIFT_BCN_SPACE0_8822B 0 +#define BIT_MASK_BCN_SPACE0_8822B 0xffff +#define BIT_BCN_SPACE0_8822B(x) \ + (((x) & BIT_MASK_BCN_SPACE0_8822B) << BIT_SHIFT_BCN_SPACE0_8822B) +#define BIT_GET_BCN_SPACE0_8822B(x) \ + (((x) >> BIT_SHIFT_BCN_SPACE0_8822B) & BIT_MASK_BCN_SPACE0_8822B) + +/* 2 REG_DRVERLYINT_8822B */ + +#define BIT_SHIFT_DRVERLYITV_8822B 0 +#define BIT_MASK_DRVERLYITV_8822B 0xff +#define BIT_DRVERLYITV_8822B(x) \ + (((x) & BIT_MASK_DRVERLYITV_8822B) << BIT_SHIFT_DRVERLYITV_8822B) +#define BIT_GET_DRVERLYITV_8822B(x) \ + (((x) >> BIT_SHIFT_DRVERLYITV_8822B) & BIT_MASK_DRVERLYITV_8822B) + +/* 2 REG_BCNDMATIM_8822B */ + +#define BIT_SHIFT_BCNDMATIM_8822B 0 +#define BIT_MASK_BCNDMATIM_8822B 0xff +#define BIT_BCNDMATIM_8822B(x) \ + (((x) & BIT_MASK_BCNDMATIM_8822B) << BIT_SHIFT_BCNDMATIM_8822B) +#define BIT_GET_BCNDMATIM_8822B(x) \ + (((x) >> BIT_SHIFT_BCNDMATIM_8822B) & BIT_MASK_BCNDMATIM_8822B) + +/* 2 REG_ATIMWND_8822B */ + +#define BIT_SHIFT_ATIMWND0_8822B 0 +#define BIT_MASK_ATIMWND0_8822B 0xffff +#define BIT_ATIMWND0_8822B(x) \ + (((x) & BIT_MASK_ATIMWND0_8822B) << BIT_SHIFT_ATIMWND0_8822B) +#define BIT_GET_ATIMWND0_8822B(x) \ + (((x) >> BIT_SHIFT_ATIMWND0_8822B) & BIT_MASK_ATIMWND0_8822B) + +/* 2 REG_USTIME_TSF_8822B */ + +#define BIT_SHIFT_USTIME_TSF_V1_8822B 0 +#define BIT_MASK_USTIME_TSF_V1_8822B 0xff +#define BIT_USTIME_TSF_V1_8822B(x) \ + (((x) & BIT_MASK_USTIME_TSF_V1_8822B) << BIT_SHIFT_USTIME_TSF_V1_8822B) +#define BIT_GET_USTIME_TSF_V1_8822B(x) \ + (((x) >> BIT_SHIFT_USTIME_TSF_V1_8822B) & BIT_MASK_USTIME_TSF_V1_8822B) + +/* 2 REG_BCN_MAX_ERR_8822B */ + +#define BIT_SHIFT_BCN_MAX_ERR_8822B 0 +#define BIT_MASK_BCN_MAX_ERR_8822B 0xff +#define BIT_BCN_MAX_ERR_8822B(x) \ + (((x) & BIT_MASK_BCN_MAX_ERR_8822B) << BIT_SHIFT_BCN_MAX_ERR_8822B) +#define BIT_GET_BCN_MAX_ERR_8822B(x) \ + (((x) >> BIT_SHIFT_BCN_MAX_ERR_8822B) & BIT_MASK_BCN_MAX_ERR_8822B) + +/* 2 REG_RXTSF_OFFSET_CCK_8822B */ + +#define BIT_SHIFT_CCK_RXTSF_OFFSET_8822B 0 +#define BIT_MASK_CCK_RXTSF_OFFSET_8822B 0xff +#define BIT_CCK_RXTSF_OFFSET_8822B(x) \ + (((x) & BIT_MASK_CCK_RXTSF_OFFSET_8822B) \ + << BIT_SHIFT_CCK_RXTSF_OFFSET_8822B) +#define BIT_GET_CCK_RXTSF_OFFSET_8822B(x) \ + (((x) >> BIT_SHIFT_CCK_RXTSF_OFFSET_8822B) & \ + BIT_MASK_CCK_RXTSF_OFFSET_8822B) + +/* 2 REG_RXTSF_OFFSET_OFDM_8822B */ + +#define BIT_SHIFT_OFDM_RXTSF_OFFSET_8822B 0 +#define BIT_MASK_OFDM_RXTSF_OFFSET_8822B 0xff +#define BIT_OFDM_RXTSF_OFFSET_8822B(x) \ + (((x) & BIT_MASK_OFDM_RXTSF_OFFSET_8822B) \ + << BIT_SHIFT_OFDM_RXTSF_OFFSET_8822B) +#define BIT_GET_OFDM_RXTSF_OFFSET_8822B(x) \ + (((x) >> BIT_SHIFT_OFDM_RXTSF_OFFSET_8822B) & \ + BIT_MASK_OFDM_RXTSF_OFFSET_8822B) + +/* 2 REG_TSFTR_8822B */ + +#define BIT_SHIFT_TSF_TIMER_8822B 0 +#define BIT_MASK_TSF_TIMER_8822B 0xffffffffffffffffL +#define BIT_TSF_TIMER_8822B(x) \ + (((x) & BIT_MASK_TSF_TIMER_8822B) << BIT_SHIFT_TSF_TIMER_8822B) +#define BIT_GET_TSF_TIMER_8822B(x) \ + (((x) >> BIT_SHIFT_TSF_TIMER_8822B) & BIT_MASK_TSF_TIMER_8822B) + +/* 2 REG_FREERUN_CNT_8822B */ + +#define BIT_SHIFT_FREERUN_CNT_8822B 0 +#define BIT_MASK_FREERUN_CNT_8822B 0xffffffffffffffffL +#define BIT_FREERUN_CNT_8822B(x) \ + (((x) & BIT_MASK_FREERUN_CNT_8822B) << BIT_SHIFT_FREERUN_CNT_8822B) +#define BIT_GET_FREERUN_CNT_8822B(x) \ + (((x) >> BIT_SHIFT_FREERUN_CNT_8822B) & BIT_MASK_FREERUN_CNT_8822B) + +/* 2 REG_ATIMWND1_V1_8822B */ + +#define BIT_SHIFT_ATIMWND1_V1_8822B 0 +#define BIT_MASK_ATIMWND1_V1_8822B 0xff +#define BIT_ATIMWND1_V1_8822B(x) \ + (((x) & BIT_MASK_ATIMWND1_V1_8822B) << BIT_SHIFT_ATIMWND1_V1_8822B) +#define BIT_GET_ATIMWND1_V1_8822B(x) \ + (((x) >> BIT_SHIFT_ATIMWND1_V1_8822B) & BIT_MASK_ATIMWND1_V1_8822B) + +/* 2 REG_TBTT_PROHIBIT_INFRA_8822B */ + +#define BIT_SHIFT_TBTT_PROHIBIT_INFRA_8822B 0 +#define BIT_MASK_TBTT_PROHIBIT_INFRA_8822B 0xff +#define BIT_TBTT_PROHIBIT_INFRA_8822B(x) \ + (((x) & BIT_MASK_TBTT_PROHIBIT_INFRA_8822B) \ + << BIT_SHIFT_TBTT_PROHIBIT_INFRA_8822B) +#define BIT_GET_TBTT_PROHIBIT_INFRA_8822B(x) \ + (((x) >> BIT_SHIFT_TBTT_PROHIBIT_INFRA_8822B) & \ + BIT_MASK_TBTT_PROHIBIT_INFRA_8822B) + +/* 2 REG_CTWND_8822B */ + +#define BIT_SHIFT_CTWND_8822B 0 +#define BIT_MASK_CTWND_8822B 0xff +#define BIT_CTWND_8822B(x) \ + (((x) & BIT_MASK_CTWND_8822B) << BIT_SHIFT_CTWND_8822B) +#define BIT_GET_CTWND_8822B(x) \ + (((x) >> BIT_SHIFT_CTWND_8822B) & BIT_MASK_CTWND_8822B) + +/* 2 REG_BCNIVLCUNT_8822B */ + +#define BIT_SHIFT_BCNIVLCUNT_8822B 0 +#define BIT_MASK_BCNIVLCUNT_8822B 0x7f +#define BIT_BCNIVLCUNT_8822B(x) \ + (((x) & BIT_MASK_BCNIVLCUNT_8822B) << BIT_SHIFT_BCNIVLCUNT_8822B) +#define BIT_GET_BCNIVLCUNT_8822B(x) \ + (((x) >> BIT_SHIFT_BCNIVLCUNT_8822B) & BIT_MASK_BCNIVLCUNT_8822B) + +/* 2 REG_BCNDROPCTRL_8822B */ +#define BIT_BEACON_DROP_EN_8822B BIT(7) + +#define BIT_SHIFT_BEACON_DROP_IVL_8822B 0 +#define BIT_MASK_BEACON_DROP_IVL_8822B 0x7f +#define BIT_BEACON_DROP_IVL_8822B(x) \ + (((x) & BIT_MASK_BEACON_DROP_IVL_8822B) \ + << BIT_SHIFT_BEACON_DROP_IVL_8822B) +#define BIT_GET_BEACON_DROP_IVL_8822B(x) \ + (((x) >> BIT_SHIFT_BEACON_DROP_IVL_8822B) & \ + BIT_MASK_BEACON_DROP_IVL_8822B) + +/* 2 REG_HGQ_TIMEOUT_PERIOD_8822B */ + +#define BIT_SHIFT_HGQ_TIMEOUT_PERIOD_8822B 0 +#define BIT_MASK_HGQ_TIMEOUT_PERIOD_8822B 0xff +#define BIT_HGQ_TIMEOUT_PERIOD_8822B(x) \ + (((x) & BIT_MASK_HGQ_TIMEOUT_PERIOD_8822B) \ + << BIT_SHIFT_HGQ_TIMEOUT_PERIOD_8822B) +#define BIT_GET_HGQ_TIMEOUT_PERIOD_8822B(x) \ + (((x) >> BIT_SHIFT_HGQ_TIMEOUT_PERIOD_8822B) & \ + BIT_MASK_HGQ_TIMEOUT_PERIOD_8822B) + +/* 2 REG_TXCMD_TIMEOUT_PERIOD_8822B */ + +#define BIT_SHIFT_TXCMD_TIMEOUT_PERIOD_8822B 0 +#define BIT_MASK_TXCMD_TIMEOUT_PERIOD_8822B 0xff +#define BIT_TXCMD_TIMEOUT_PERIOD_8822B(x) \ + (((x) & BIT_MASK_TXCMD_TIMEOUT_PERIOD_8822B) \ + << BIT_SHIFT_TXCMD_TIMEOUT_PERIOD_8822B) +#define BIT_GET_TXCMD_TIMEOUT_PERIOD_8822B(x) \ + (((x) >> BIT_SHIFT_TXCMD_TIMEOUT_PERIOD_8822B) & \ + BIT_MASK_TXCMD_TIMEOUT_PERIOD_8822B) + +/* 2 REG_MISC_CTRL_8822B */ +#define BIT_DIS_TRX_CAL_BCN_8822B BIT(5) +#define BIT_DIS_TX_CAL_TBTT_8822B BIT(4) +#define BIT_EN_FREECNT_8822B BIT(3) +#define BIT_BCN_AGGRESSION_8822B BIT(2) + +#define BIT_SHIFT_DIS_SECONDARY_CCA_8822B 0 +#define BIT_MASK_DIS_SECONDARY_CCA_8822B 0x3 +#define BIT_DIS_SECONDARY_CCA_8822B(x) \ + (((x) & BIT_MASK_DIS_SECONDARY_CCA_8822B) \ + << BIT_SHIFT_DIS_SECONDARY_CCA_8822B) +#define BIT_GET_DIS_SECONDARY_CCA_8822B(x) \ + (((x) >> BIT_SHIFT_DIS_SECONDARY_CCA_8822B) & \ + BIT_MASK_DIS_SECONDARY_CCA_8822B) + +/* 2 REG_BCN_CTRL_CLINT1_8822B */ +#define BIT_CLI1_DIS_RX_BSSID_FIT_8822B BIT(6) +#define BIT_CLI1_DIS_TSF_UDT_8822B BIT(4) +#define BIT_CLI1_EN_BCN_FUNCTION_8822B BIT(3) +#define BIT_CLI1_EN_RXBCN_RPT_8822B BIT(2) +#define BIT_CLI1_ENP2P_CTWINDOW_8822B BIT(1) +#define BIT_CLI1_ENP2P_BCNQ_AREA_8822B BIT(0) + +/* 2 REG_BCN_CTRL_CLINT2_8822B */ +#define BIT_CLI2_DIS_RX_BSSID_FIT_8822B BIT(6) +#define BIT_CLI2_DIS_TSF_UDT_8822B BIT(4) +#define BIT_CLI2_EN_BCN_FUNCTION_8822B BIT(3) +#define BIT_CLI2_EN_RXBCN_RPT_8822B BIT(2) +#define BIT_CLI2_ENP2P_CTWINDOW_8822B BIT(1) +#define BIT_CLI2_ENP2P_BCNQ_AREA_8822B BIT(0) + +/* 2 REG_BCN_CTRL_CLINT3_8822B */ +#define BIT_CLI3_DIS_RX_BSSID_FIT_8822B BIT(6) +#define BIT_CLI3_DIS_TSF_UDT_8822B BIT(4) +#define BIT_CLI3_EN_BCN_FUNCTION_8822B BIT(3) +#define BIT_CLI3_EN_RXBCN_RPT_8822B BIT(2) +#define BIT_CLI3_ENP2P_CTWINDOW_8822B BIT(1) +#define BIT_CLI3_ENP2P_BCNQ_AREA_8822B BIT(0) + +/* 2 REG_EXTEND_CTRL_8822B */ +#define BIT_EN_TSFBIT32_RST_P2P2_8822B BIT(5) +#define BIT_EN_TSFBIT32_RST_P2P1_8822B BIT(4) + +#define BIT_SHIFT_PORT_SEL_8822B 0 +#define BIT_MASK_PORT_SEL_8822B 0x7 +#define BIT_PORT_SEL_8822B(x) \ + (((x) & BIT_MASK_PORT_SEL_8822B) << BIT_SHIFT_PORT_SEL_8822B) +#define BIT_GET_PORT_SEL_8822B(x) \ + (((x) >> BIT_SHIFT_PORT_SEL_8822B) & BIT_MASK_PORT_SEL_8822B) + +/* 2 REG_P2PPS1_SPEC_STATE_8822B */ +#define BIT_P2P1_SPEC_POWER_STATE_8822B BIT(7) +#define BIT_P2P1_SPEC_CTWINDOW_ON_8822B BIT(6) +#define BIT_P2P1_SPEC_BCN_AREA_ON_8822B BIT(5) +#define BIT_P2P1_SPEC_CTWIN_EARLY_DISTX_8822B BIT(4) +#define BIT_P2P1_SPEC_NOA1_OFF_PERIOD_8822B BIT(3) +#define BIT_P2P1_SPEC_FORCE_DOZE1_8822B BIT(2) +#define BIT_P2P1_SPEC_NOA0_OFF_PERIOD_8822B BIT(1) +#define BIT_P2P1_SPEC_FORCE_DOZE0_8822B BIT(0) + +/* 2 REG_P2PPS1_STATE_8822B */ +#define BIT_P2P1_POWER_STATE_8822B BIT(7) +#define BIT_P2P1_CTWINDOW_ON_8822B BIT(6) +#define BIT_P2P1_BEACON_AREA_ON_8822B BIT(5) +#define BIT_P2P1_CTWIN_EARLY_DISTX_8822B BIT(4) +#define BIT_P2P1_NOA1_OFF_PERIOD_8822B BIT(3) +#define BIT_P2P1_FORCE_DOZE1_8822B BIT(2) +#define BIT_P2P1_NOA0_OFF_PERIOD_8822B BIT(1) +#define BIT_P2P1_FORCE_DOZE0_8822B BIT(0) + +/* 2 REG_P2PPS2_SPEC_STATE_8822B */ +#define BIT_P2P2_SPEC_POWER_STATE_8822B BIT(7) +#define BIT_P2P2_SPEC_CTWINDOW_ON_8822B BIT(6) +#define BIT_P2P2_SPEC_BCN_AREA_ON_8822B BIT(5) +#define BIT_P2P2_SPEC_CTWIN_EARLY_DISTX_8822B BIT(4) +#define BIT_P2P2_SPEC_NOA1_OFF_PERIOD_8822B BIT(3) +#define BIT_P2P2_SPEC_FORCE_DOZE1_8822B BIT(2) +#define BIT_P2P2_SPEC_NOA0_OFF_PERIOD_8822B BIT(1) +#define BIT_P2P2_SPEC_FORCE_DOZE0_8822B BIT(0) + +/* 2 REG_P2PPS2_STATE_8822B */ +#define BIT_P2P2_POWER_STATE_8822B BIT(7) +#define BIT_P2P2_CTWINDOW_ON_8822B BIT(6) +#define BIT_P2P2_BEACON_AREA_ON_8822B BIT(5) +#define BIT_P2P2_CTWIN_EARLY_DISTX_8822B BIT(4) +#define BIT_P2P2_NOA1_OFF_PERIOD_8822B BIT(3) +#define BIT_P2P2_FORCE_DOZE1_8822B BIT(2) +#define BIT_P2P2_NOA0_OFF_PERIOD_8822B BIT(1) +#define BIT_P2P2_FORCE_DOZE0_8822B BIT(0) + +/* 2 REG_PS_TIMER0_8822B */ + +#define BIT_SHIFT_PSTIMER0_INT_8822B 5 +#define BIT_MASK_PSTIMER0_INT_8822B 0x7ffffff +#define BIT_PSTIMER0_INT_8822B(x) \ + (((x) & BIT_MASK_PSTIMER0_INT_8822B) << BIT_SHIFT_PSTIMER0_INT_8822B) +#define BIT_GET_PSTIMER0_INT_8822B(x) \ + (((x) >> BIT_SHIFT_PSTIMER0_INT_8822B) & BIT_MASK_PSTIMER0_INT_8822B) + +/* 2 REG_PS_TIMER1_8822B */ + +#define BIT_SHIFT_PSTIMER1_INT_8822B 5 +#define BIT_MASK_PSTIMER1_INT_8822B 0x7ffffff +#define BIT_PSTIMER1_INT_8822B(x) \ + (((x) & BIT_MASK_PSTIMER1_INT_8822B) << BIT_SHIFT_PSTIMER1_INT_8822B) +#define BIT_GET_PSTIMER1_INT_8822B(x) \ + (((x) >> BIT_SHIFT_PSTIMER1_INT_8822B) & BIT_MASK_PSTIMER1_INT_8822B) + +/* 2 REG_PS_TIMER2_8822B */ + +#define BIT_SHIFT_PSTIMER2_INT_8822B 5 +#define BIT_MASK_PSTIMER2_INT_8822B 0x7ffffff +#define BIT_PSTIMER2_INT_8822B(x) \ + (((x) & BIT_MASK_PSTIMER2_INT_8822B) << BIT_SHIFT_PSTIMER2_INT_8822B) +#define BIT_GET_PSTIMER2_INT_8822B(x) \ + (((x) >> BIT_SHIFT_PSTIMER2_INT_8822B) & BIT_MASK_PSTIMER2_INT_8822B) + +/* 2 REG_TBTT_CTN_AREA_8822B */ + +#define BIT_SHIFT_TBTT_CTN_AREA_8822B 0 +#define BIT_MASK_TBTT_CTN_AREA_8822B 0xff +#define BIT_TBTT_CTN_AREA_8822B(x) \ + (((x) & BIT_MASK_TBTT_CTN_AREA_8822B) << BIT_SHIFT_TBTT_CTN_AREA_8822B) +#define BIT_GET_TBTT_CTN_AREA_8822B(x) \ + (((x) >> BIT_SHIFT_TBTT_CTN_AREA_8822B) & BIT_MASK_TBTT_CTN_AREA_8822B) + +/* 2 REG_FORCE_BCN_IFS_8822B */ + +#define BIT_SHIFT_FORCE_BCN_IFS_8822B 0 +#define BIT_MASK_FORCE_BCN_IFS_8822B 0xff +#define BIT_FORCE_BCN_IFS_8822B(x) \ + (((x) & BIT_MASK_FORCE_BCN_IFS_8822B) << BIT_SHIFT_FORCE_BCN_IFS_8822B) +#define BIT_GET_FORCE_BCN_IFS_8822B(x) \ + (((x) >> BIT_SHIFT_FORCE_BCN_IFS_8822B) & BIT_MASK_FORCE_BCN_IFS_8822B) + +/* 2 REG_TXOP_MIN_8822B */ + +#define BIT_SHIFT_TXOP_MIN_8822B 0 +#define BIT_MASK_TXOP_MIN_8822B 0x3fff +#define BIT_TXOP_MIN_8822B(x) \ + (((x) & BIT_MASK_TXOP_MIN_8822B) << BIT_SHIFT_TXOP_MIN_8822B) +#define BIT_GET_TXOP_MIN_8822B(x) \ + (((x) >> BIT_SHIFT_TXOP_MIN_8822B) & BIT_MASK_TXOP_MIN_8822B) + +/* 2 REG_PRE_BKF_TIME_8822B */ + +#define BIT_SHIFT_PRE_BKF_TIME_8822B 0 +#define BIT_MASK_PRE_BKF_TIME_8822B 0xff +#define BIT_PRE_BKF_TIME_8822B(x) \ + (((x) & BIT_MASK_PRE_BKF_TIME_8822B) << BIT_SHIFT_PRE_BKF_TIME_8822B) +#define BIT_GET_PRE_BKF_TIME_8822B(x) \ + (((x) >> BIT_SHIFT_PRE_BKF_TIME_8822B) & BIT_MASK_PRE_BKF_TIME_8822B) + +/* 2 REG_CROSS_TXOP_CTRL_8822B */ +#define BIT_DTIM_BYPASS_8822B BIT(2) +#define BIT_RTS_NAV_TXOP_8822B BIT(1) +#define BIT_NOT_CROSS_TXOP_8822B BIT(0) + +/* 2 REG_ATIMWND2_8822B */ + +#define BIT_SHIFT_ATIMWND2_8822B 0 +#define BIT_MASK_ATIMWND2_8822B 0xff +#define BIT_ATIMWND2_8822B(x) \ + (((x) & BIT_MASK_ATIMWND2_8822B) << BIT_SHIFT_ATIMWND2_8822B) +#define BIT_GET_ATIMWND2_8822B(x) \ + (((x) >> BIT_SHIFT_ATIMWND2_8822B) & BIT_MASK_ATIMWND2_8822B) + +/* 2 REG_ATIMWND3_8822B */ + +#define BIT_SHIFT_ATIMWND3_8822B 0 +#define BIT_MASK_ATIMWND3_8822B 0xff +#define BIT_ATIMWND3_8822B(x) \ + (((x) & BIT_MASK_ATIMWND3_8822B) << BIT_SHIFT_ATIMWND3_8822B) +#define BIT_GET_ATIMWND3_8822B(x) \ + (((x) >> BIT_SHIFT_ATIMWND3_8822B) & BIT_MASK_ATIMWND3_8822B) + +/* 2 REG_ATIMWND4_8822B */ + +#define BIT_SHIFT_ATIMWND4_8822B 0 +#define BIT_MASK_ATIMWND4_8822B 0xff +#define BIT_ATIMWND4_8822B(x) \ + (((x) & BIT_MASK_ATIMWND4_8822B) << BIT_SHIFT_ATIMWND4_8822B) +#define BIT_GET_ATIMWND4_8822B(x) \ + (((x) >> BIT_SHIFT_ATIMWND4_8822B) & BIT_MASK_ATIMWND4_8822B) + +/* 2 REG_ATIMWND5_8822B */ + +#define BIT_SHIFT_ATIMWND5_8822B 0 +#define BIT_MASK_ATIMWND5_8822B 0xff +#define BIT_ATIMWND5_8822B(x) \ + (((x) & BIT_MASK_ATIMWND5_8822B) << BIT_SHIFT_ATIMWND5_8822B) +#define BIT_GET_ATIMWND5_8822B(x) \ + (((x) >> BIT_SHIFT_ATIMWND5_8822B) & BIT_MASK_ATIMWND5_8822B) + +/* 2 REG_ATIMWND6_8822B */ + +#define BIT_SHIFT_ATIMWND6_8822B 0 +#define BIT_MASK_ATIMWND6_8822B 0xff +#define BIT_ATIMWND6_8822B(x) \ + (((x) & BIT_MASK_ATIMWND6_8822B) << BIT_SHIFT_ATIMWND6_8822B) +#define BIT_GET_ATIMWND6_8822B(x) \ + (((x) >> BIT_SHIFT_ATIMWND6_8822B) & BIT_MASK_ATIMWND6_8822B) + +/* 2 REG_ATIMWND7_8822B */ + +#define BIT_SHIFT_ATIMWND7_8822B 0 +#define BIT_MASK_ATIMWND7_8822B 0xff +#define BIT_ATIMWND7_8822B(x) \ + (((x) & BIT_MASK_ATIMWND7_8822B) << BIT_SHIFT_ATIMWND7_8822B) +#define BIT_GET_ATIMWND7_8822B(x) \ + (((x) >> BIT_SHIFT_ATIMWND7_8822B) & BIT_MASK_ATIMWND7_8822B) + +/* 2 REG_ATIMUGT_8822B */ + +#define BIT_SHIFT_ATIM_URGENT_8822B 0 +#define BIT_MASK_ATIM_URGENT_8822B 0xff +#define BIT_ATIM_URGENT_8822B(x) \ + (((x) & BIT_MASK_ATIM_URGENT_8822B) << BIT_SHIFT_ATIM_URGENT_8822B) +#define BIT_GET_ATIM_URGENT_8822B(x) \ + (((x) >> BIT_SHIFT_ATIM_URGENT_8822B) & BIT_MASK_ATIM_URGENT_8822B) + +/* 2 REG_HIQ_NO_LMT_EN_8822B */ +#define BIT_HIQ_NO_LMT_EN_VAP7_8822B BIT(7) +#define BIT_HIQ_NO_LMT_EN_VAP6_8822B BIT(6) +#define BIT_HIQ_NO_LMT_EN_VAP5_8822B BIT(5) +#define BIT_HIQ_NO_LMT_EN_VAP4_8822B BIT(4) +#define BIT_HIQ_NO_LMT_EN_VAP3_8822B BIT(3) +#define BIT_HIQ_NO_LMT_EN_VAP2_8822B BIT(2) +#define BIT_HIQ_NO_LMT_EN_VAP1_8822B BIT(1) +#define BIT_HIQ_NO_LMT_EN_ROOT_8822B BIT(0) + +/* 2 REG_DTIM_COUNTER_ROOT_8822B */ + +#define BIT_SHIFT_DTIM_COUNT_ROOT_8822B 0 +#define BIT_MASK_DTIM_COUNT_ROOT_8822B 0xff +#define BIT_DTIM_COUNT_ROOT_8822B(x) \ + (((x) & BIT_MASK_DTIM_COUNT_ROOT_8822B) \ + << BIT_SHIFT_DTIM_COUNT_ROOT_8822B) +#define BIT_GET_DTIM_COUNT_ROOT_8822B(x) \ + (((x) >> BIT_SHIFT_DTIM_COUNT_ROOT_8822B) & \ + BIT_MASK_DTIM_COUNT_ROOT_8822B) + +/* 2 REG_DTIM_COUNTER_VAP1_8822B */ + +#define BIT_SHIFT_DTIM_COUNT_VAP1_8822B 0 +#define BIT_MASK_DTIM_COUNT_VAP1_8822B 0xff +#define BIT_DTIM_COUNT_VAP1_8822B(x) \ + (((x) & BIT_MASK_DTIM_COUNT_VAP1_8822B) \ + << BIT_SHIFT_DTIM_COUNT_VAP1_8822B) +#define BIT_GET_DTIM_COUNT_VAP1_8822B(x) \ + (((x) >> BIT_SHIFT_DTIM_COUNT_VAP1_8822B) & \ + BIT_MASK_DTIM_COUNT_VAP1_8822B) + +/* 2 REG_DTIM_COUNTER_VAP2_8822B */ + +#define BIT_SHIFT_DTIM_COUNT_VAP2_8822B 0 +#define BIT_MASK_DTIM_COUNT_VAP2_8822B 0xff +#define BIT_DTIM_COUNT_VAP2_8822B(x) \ + (((x) & BIT_MASK_DTIM_COUNT_VAP2_8822B) \ + << BIT_SHIFT_DTIM_COUNT_VAP2_8822B) +#define BIT_GET_DTIM_COUNT_VAP2_8822B(x) \ + (((x) >> BIT_SHIFT_DTIM_COUNT_VAP2_8822B) & \ + BIT_MASK_DTIM_COUNT_VAP2_8822B) + +/* 2 REG_DTIM_COUNTER_VAP3_8822B */ + +#define BIT_SHIFT_DTIM_COUNT_VAP3_8822B 0 +#define BIT_MASK_DTIM_COUNT_VAP3_8822B 0xff +#define BIT_DTIM_COUNT_VAP3_8822B(x) \ + (((x) & BIT_MASK_DTIM_COUNT_VAP3_8822B) \ + << BIT_SHIFT_DTIM_COUNT_VAP3_8822B) +#define BIT_GET_DTIM_COUNT_VAP3_8822B(x) \ + (((x) >> BIT_SHIFT_DTIM_COUNT_VAP3_8822B) & \ + BIT_MASK_DTIM_COUNT_VAP3_8822B) + +/* 2 REG_DTIM_COUNTER_VAP4_8822B */ + +#define BIT_SHIFT_DTIM_COUNT_VAP4_8822B 0 +#define BIT_MASK_DTIM_COUNT_VAP4_8822B 0xff +#define BIT_DTIM_COUNT_VAP4_8822B(x) \ + (((x) & BIT_MASK_DTIM_COUNT_VAP4_8822B) \ + << BIT_SHIFT_DTIM_COUNT_VAP4_8822B) +#define BIT_GET_DTIM_COUNT_VAP4_8822B(x) \ + (((x) >> BIT_SHIFT_DTIM_COUNT_VAP4_8822B) & \ + BIT_MASK_DTIM_COUNT_VAP4_8822B) + +/* 2 REG_DTIM_COUNTER_VAP5_8822B */ + +#define BIT_SHIFT_DTIM_COUNT_VAP5_8822B 0 +#define BIT_MASK_DTIM_COUNT_VAP5_8822B 0xff +#define BIT_DTIM_COUNT_VAP5_8822B(x) \ + (((x) & BIT_MASK_DTIM_COUNT_VAP5_8822B) \ + << BIT_SHIFT_DTIM_COUNT_VAP5_8822B) +#define BIT_GET_DTIM_COUNT_VAP5_8822B(x) \ + (((x) >> BIT_SHIFT_DTIM_COUNT_VAP5_8822B) & \ + BIT_MASK_DTIM_COUNT_VAP5_8822B) + +/* 2 REG_DTIM_COUNTER_VAP6_8822B */ + +#define BIT_SHIFT_DTIM_COUNT_VAP6_8822B 0 +#define BIT_MASK_DTIM_COUNT_VAP6_8822B 0xff +#define BIT_DTIM_COUNT_VAP6_8822B(x) \ + (((x) & BIT_MASK_DTIM_COUNT_VAP6_8822B) \ + << BIT_SHIFT_DTIM_COUNT_VAP6_8822B) +#define BIT_GET_DTIM_COUNT_VAP6_8822B(x) \ + (((x) >> BIT_SHIFT_DTIM_COUNT_VAP6_8822B) & \ + BIT_MASK_DTIM_COUNT_VAP6_8822B) + +/* 2 REG_DTIM_COUNTER_VAP7_8822B */ + +#define BIT_SHIFT_DTIM_COUNT_VAP7_8822B 0 +#define BIT_MASK_DTIM_COUNT_VAP7_8822B 0xff +#define BIT_DTIM_COUNT_VAP7_8822B(x) \ + (((x) & BIT_MASK_DTIM_COUNT_VAP7_8822B) \ + << BIT_SHIFT_DTIM_COUNT_VAP7_8822B) +#define BIT_GET_DTIM_COUNT_VAP7_8822B(x) \ + (((x) >> BIT_SHIFT_DTIM_COUNT_VAP7_8822B) & \ + BIT_MASK_DTIM_COUNT_VAP7_8822B) + +/* 2 REG_DIS_ATIM_8822B */ +#define BIT_DIS_ATIM_VAP7_8822B BIT(7) +#define BIT_DIS_ATIM_VAP6_8822B BIT(6) +#define BIT_DIS_ATIM_VAP5_8822B BIT(5) +#define BIT_DIS_ATIM_VAP4_8822B BIT(4) +#define BIT_DIS_ATIM_VAP3_8822B BIT(3) +#define BIT_DIS_ATIM_VAP2_8822B BIT(2) +#define BIT_DIS_ATIM_VAP1_8822B BIT(1) +#define BIT_DIS_ATIM_ROOT_8822B BIT(0) + +/* 2 REG_EARLY_128US_8822B */ + +#define BIT_SHIFT_TSFT_SEL_TIMER1_8822B 3 +#define BIT_MASK_TSFT_SEL_TIMER1_8822B 0x7 +#define BIT_TSFT_SEL_TIMER1_8822B(x) \ + (((x) & BIT_MASK_TSFT_SEL_TIMER1_8822B) \ + << BIT_SHIFT_TSFT_SEL_TIMER1_8822B) +#define BIT_GET_TSFT_SEL_TIMER1_8822B(x) \ + (((x) >> BIT_SHIFT_TSFT_SEL_TIMER1_8822B) & \ + BIT_MASK_TSFT_SEL_TIMER1_8822B) + +#define BIT_SHIFT_EARLY_128US_8822B 0 +#define BIT_MASK_EARLY_128US_8822B 0x7 +#define BIT_EARLY_128US_8822B(x) \ + (((x) & BIT_MASK_EARLY_128US_8822B) << BIT_SHIFT_EARLY_128US_8822B) +#define BIT_GET_EARLY_128US_8822B(x) \ + (((x) >> BIT_SHIFT_EARLY_128US_8822B) & BIT_MASK_EARLY_128US_8822B) + +/* 2 REG_P2PPS1_CTRL_8822B */ +#define BIT_P2P1_CTW_ALLSTASLEEP_8822B BIT(7) +#define BIT_P2P1_OFF_DISTX_EN_8822B BIT(6) +#define BIT_P2P1_PWR_MGT_EN_8822B BIT(5) +#define BIT_P2P1_NOA1_EN_8822B BIT(2) +#define BIT_P2P1_NOA0_EN_8822B BIT(1) + +/* 2 REG_P2PPS2_CTRL_8822B */ +#define BIT_P2P2_CTW_ALLSTASLEEP_8822B BIT(7) +#define BIT_P2P2_OFF_DISTX_EN_8822B BIT(6) +#define BIT_P2P2_PWR_MGT_EN_8822B BIT(5) +#define BIT_P2P2_NOA1_EN_8822B BIT(2) +#define BIT_P2P2_NOA0_EN_8822B BIT(1) + +/* 2 REG_TIMER0_SRC_SEL_8822B */ + +#define BIT_SHIFT_SYNC_CLI_SEL_8822B 4 +#define BIT_MASK_SYNC_CLI_SEL_8822B 0x7 +#define BIT_SYNC_CLI_SEL_8822B(x) \ + (((x) & BIT_MASK_SYNC_CLI_SEL_8822B) << BIT_SHIFT_SYNC_CLI_SEL_8822B) +#define BIT_GET_SYNC_CLI_SEL_8822B(x) \ + (((x) >> BIT_SHIFT_SYNC_CLI_SEL_8822B) & BIT_MASK_SYNC_CLI_SEL_8822B) + +#define BIT_SHIFT_TSFT_SEL_TIMER0_8822B 0 +#define BIT_MASK_TSFT_SEL_TIMER0_8822B 0x7 +#define BIT_TSFT_SEL_TIMER0_8822B(x) \ + (((x) & BIT_MASK_TSFT_SEL_TIMER0_8822B) \ + << BIT_SHIFT_TSFT_SEL_TIMER0_8822B) +#define BIT_GET_TSFT_SEL_TIMER0_8822B(x) \ + (((x) >> BIT_SHIFT_TSFT_SEL_TIMER0_8822B) & \ + BIT_MASK_TSFT_SEL_TIMER0_8822B) + +/* 2 REG_NOA_UNIT_SEL_8822B */ + +#define BIT_SHIFT_NOA_UNIT2_SEL_8822B 8 +#define BIT_MASK_NOA_UNIT2_SEL_8822B 0x7 +#define BIT_NOA_UNIT2_SEL_8822B(x) \ + (((x) & BIT_MASK_NOA_UNIT2_SEL_8822B) << BIT_SHIFT_NOA_UNIT2_SEL_8822B) +#define BIT_GET_NOA_UNIT2_SEL_8822B(x) \ + (((x) >> BIT_SHIFT_NOA_UNIT2_SEL_8822B) & BIT_MASK_NOA_UNIT2_SEL_8822B) + +#define BIT_SHIFT_NOA_UNIT1_SEL_8822B 4 +#define BIT_MASK_NOA_UNIT1_SEL_8822B 0x7 +#define BIT_NOA_UNIT1_SEL_8822B(x) \ + (((x) & BIT_MASK_NOA_UNIT1_SEL_8822B) << BIT_SHIFT_NOA_UNIT1_SEL_8822B) +#define BIT_GET_NOA_UNIT1_SEL_8822B(x) \ + (((x) >> BIT_SHIFT_NOA_UNIT1_SEL_8822B) & BIT_MASK_NOA_UNIT1_SEL_8822B) + +#define BIT_SHIFT_NOA_UNIT0_SEL_8822B 0 +#define BIT_MASK_NOA_UNIT0_SEL_8822B 0x7 +#define BIT_NOA_UNIT0_SEL_8822B(x) \ + (((x) & BIT_MASK_NOA_UNIT0_SEL_8822B) << BIT_SHIFT_NOA_UNIT0_SEL_8822B) +#define BIT_GET_NOA_UNIT0_SEL_8822B(x) \ + (((x) >> BIT_SHIFT_NOA_UNIT0_SEL_8822B) & BIT_MASK_NOA_UNIT0_SEL_8822B) + +/* 2 REG_P2POFF_DIS_TXTIME_8822B */ + +#define BIT_SHIFT_P2POFF_DIS_TXTIME_8822B 0 +#define BIT_MASK_P2POFF_DIS_TXTIME_8822B 0xff +#define BIT_P2POFF_DIS_TXTIME_8822B(x) \ + (((x) & BIT_MASK_P2POFF_DIS_TXTIME_8822B) \ + << BIT_SHIFT_P2POFF_DIS_TXTIME_8822B) +#define BIT_GET_P2POFF_DIS_TXTIME_8822B(x) \ + (((x) >> BIT_SHIFT_P2POFF_DIS_TXTIME_8822B) & \ + BIT_MASK_P2POFF_DIS_TXTIME_8822B) + +/* 2 REG_MBSSID_BCN_SPACE2_8822B */ + +#define BIT_SHIFT_BCN_SPACE_CLINT2_8822B 16 +#define BIT_MASK_BCN_SPACE_CLINT2_8822B 0xfff +#define BIT_BCN_SPACE_CLINT2_8822B(x) \ + (((x) & BIT_MASK_BCN_SPACE_CLINT2_8822B) \ + << BIT_SHIFT_BCN_SPACE_CLINT2_8822B) +#define BIT_GET_BCN_SPACE_CLINT2_8822B(x) \ + (((x) >> BIT_SHIFT_BCN_SPACE_CLINT2_8822B) & \ + BIT_MASK_BCN_SPACE_CLINT2_8822B) + +#define BIT_SHIFT_BCN_SPACE_CLINT1_8822B 0 +#define BIT_MASK_BCN_SPACE_CLINT1_8822B 0xfff +#define BIT_BCN_SPACE_CLINT1_8822B(x) \ + (((x) & BIT_MASK_BCN_SPACE_CLINT1_8822B) \ + << BIT_SHIFT_BCN_SPACE_CLINT1_8822B) +#define BIT_GET_BCN_SPACE_CLINT1_8822B(x) \ + (((x) >> BIT_SHIFT_BCN_SPACE_CLINT1_8822B) & \ + BIT_MASK_BCN_SPACE_CLINT1_8822B) + +/* 2 REG_MBSSID_BCN_SPACE3_8822B */ + +#define BIT_SHIFT_SUB_BCN_SPACE_8822B 16 +#define BIT_MASK_SUB_BCN_SPACE_8822B 0xff +#define BIT_SUB_BCN_SPACE_8822B(x) \ + (((x) & BIT_MASK_SUB_BCN_SPACE_8822B) << BIT_SHIFT_SUB_BCN_SPACE_8822B) +#define BIT_GET_SUB_BCN_SPACE_8822B(x) \ + (((x) >> BIT_SHIFT_SUB_BCN_SPACE_8822B) & BIT_MASK_SUB_BCN_SPACE_8822B) + +#define BIT_SHIFT_BCN_SPACE_CLINT3_8822B 0 +#define BIT_MASK_BCN_SPACE_CLINT3_8822B 0xfff +#define BIT_BCN_SPACE_CLINT3_8822B(x) \ + (((x) & BIT_MASK_BCN_SPACE_CLINT3_8822B) \ + << BIT_SHIFT_BCN_SPACE_CLINT3_8822B) +#define BIT_GET_BCN_SPACE_CLINT3_8822B(x) \ + (((x) >> BIT_SHIFT_BCN_SPACE_CLINT3_8822B) & \ + BIT_MASK_BCN_SPACE_CLINT3_8822B) + +/* 2 REG_ACMHWCTRL_8822B */ +#define BIT_BEQ_ACM_STATUS_8822B BIT(7) +#define BIT_VIQ_ACM_STATUS_8822B BIT(6) +#define BIT_VOQ_ACM_STATUS_8822B BIT(5) +#define BIT_BEQ_ACM_EN_8822B BIT(3) +#define BIT_VIQ_ACM_EN_8822B BIT(2) +#define BIT_VOQ_ACM_EN_8822B BIT(1) +#define BIT_ACMHWEN_8822B BIT(0) + +/* 2 REG_ACMRSTCTRL_8822B */ +#define BIT_BE_ACM_RESET_USED_TIME_8822B BIT(2) +#define BIT_VI_ACM_RESET_USED_TIME_8822B BIT(1) +#define BIT_VO_ACM_RESET_USED_TIME_8822B BIT(0) + +/* 2 REG_ACMAVG_8822B */ + +#define BIT_SHIFT_AVGPERIOD_8822B 0 +#define BIT_MASK_AVGPERIOD_8822B 0xffff +#define BIT_AVGPERIOD_8822B(x) \ + (((x) & BIT_MASK_AVGPERIOD_8822B) << BIT_SHIFT_AVGPERIOD_8822B) +#define BIT_GET_AVGPERIOD_8822B(x) \ + (((x) >> BIT_SHIFT_AVGPERIOD_8822B) & BIT_MASK_AVGPERIOD_8822B) + +/* 2 REG_VO_ADMTIME_8822B */ + +#define BIT_SHIFT_VO_ADMITTED_TIME_8822B 0 +#define BIT_MASK_VO_ADMITTED_TIME_8822B 0xffff +#define BIT_VO_ADMITTED_TIME_8822B(x) \ + (((x) & BIT_MASK_VO_ADMITTED_TIME_8822B) \ + << BIT_SHIFT_VO_ADMITTED_TIME_8822B) +#define BIT_GET_VO_ADMITTED_TIME_8822B(x) \ + (((x) >> BIT_SHIFT_VO_ADMITTED_TIME_8822B) & \ + BIT_MASK_VO_ADMITTED_TIME_8822B) + +/* 2 REG_VI_ADMTIME_8822B */ + +#define BIT_SHIFT_VI_ADMITTED_TIME_8822B 0 +#define BIT_MASK_VI_ADMITTED_TIME_8822B 0xffff +#define BIT_VI_ADMITTED_TIME_8822B(x) \ + (((x) & BIT_MASK_VI_ADMITTED_TIME_8822B) \ + << BIT_SHIFT_VI_ADMITTED_TIME_8822B) +#define BIT_GET_VI_ADMITTED_TIME_8822B(x) \ + (((x) >> BIT_SHIFT_VI_ADMITTED_TIME_8822B) & \ + BIT_MASK_VI_ADMITTED_TIME_8822B) + +/* 2 REG_BE_ADMTIME_8822B */ + +#define BIT_SHIFT_BE_ADMITTED_TIME_8822B 0 +#define BIT_MASK_BE_ADMITTED_TIME_8822B 0xffff +#define BIT_BE_ADMITTED_TIME_8822B(x) \ + (((x) & BIT_MASK_BE_ADMITTED_TIME_8822B) \ + << BIT_SHIFT_BE_ADMITTED_TIME_8822B) +#define BIT_GET_BE_ADMITTED_TIME_8822B(x) \ + (((x) >> BIT_SHIFT_BE_ADMITTED_TIME_8822B) & \ + BIT_MASK_BE_ADMITTED_TIME_8822B) + +/* 2 REG_EDCA_RANDOM_GEN_8822B */ + +#define BIT_SHIFT_RANDOM_GEN_8822B 0 +#define BIT_MASK_RANDOM_GEN_8822B 0xffffff +#define BIT_RANDOM_GEN_8822B(x) \ + (((x) & BIT_MASK_RANDOM_GEN_8822B) << BIT_SHIFT_RANDOM_GEN_8822B) +#define BIT_GET_RANDOM_GEN_8822B(x) \ + (((x) >> BIT_SHIFT_RANDOM_GEN_8822B) & BIT_MASK_RANDOM_GEN_8822B) + +/* 2 REG_TXCMD_NOA_SEL_8822B */ + +#define BIT_SHIFT_NOA_SEL_8822B 4 +#define BIT_MASK_NOA_SEL_8822B 0x7 +#define BIT_NOA_SEL_8822B(x) \ + (((x) & BIT_MASK_NOA_SEL_8822B) << BIT_SHIFT_NOA_SEL_8822B) +#define BIT_GET_NOA_SEL_8822B(x) \ + (((x) >> BIT_SHIFT_NOA_SEL_8822B) & BIT_MASK_NOA_SEL_8822B) + +#define BIT_SHIFT_TXCMD_SEG_SEL_8822B 0 +#define BIT_MASK_TXCMD_SEG_SEL_8822B 0xf +#define BIT_TXCMD_SEG_SEL_8822B(x) \ + (((x) & BIT_MASK_TXCMD_SEG_SEL_8822B) << BIT_SHIFT_TXCMD_SEG_SEL_8822B) +#define BIT_GET_TXCMD_SEG_SEL_8822B(x) \ + (((x) >> BIT_SHIFT_TXCMD_SEG_SEL_8822B) & BIT_MASK_TXCMD_SEG_SEL_8822B) + +/* 2 REG_NOA_PARAM_8822B */ + +#define BIT_SHIFT_NOA_COUNT_8822B (96 & CPU_OPT_WIDTH) +#define BIT_MASK_NOA_COUNT_8822B 0xff +#define BIT_NOA_COUNT_8822B(x) \ + (((x) & BIT_MASK_NOA_COUNT_8822B) << BIT_SHIFT_NOA_COUNT_8822B) +#define BIT_GET_NOA_COUNT_8822B(x) \ + (((x) >> BIT_SHIFT_NOA_COUNT_8822B) & BIT_MASK_NOA_COUNT_8822B) + +#define BIT_SHIFT_NOA_START_TIME_8822B (64 & CPU_OPT_WIDTH) +#define BIT_MASK_NOA_START_TIME_8822B 0xffffffffL +#define BIT_NOA_START_TIME_8822B(x) \ + (((x) & BIT_MASK_NOA_START_TIME_8822B) \ + << BIT_SHIFT_NOA_START_TIME_8822B) +#define BIT_GET_NOA_START_TIME_8822B(x) \ + (((x) >> BIT_SHIFT_NOA_START_TIME_8822B) & \ + BIT_MASK_NOA_START_TIME_8822B) + +#define BIT_SHIFT_NOA_INTERVAL_8822B (32 & CPU_OPT_WIDTH) +#define BIT_MASK_NOA_INTERVAL_8822B 0xffffffffL +#define BIT_NOA_INTERVAL_8822B(x) \ + (((x) & BIT_MASK_NOA_INTERVAL_8822B) << BIT_SHIFT_NOA_INTERVAL_8822B) +#define BIT_GET_NOA_INTERVAL_8822B(x) \ + (((x) >> BIT_SHIFT_NOA_INTERVAL_8822B) & BIT_MASK_NOA_INTERVAL_8822B) + +#define BIT_SHIFT_NOA_DURATION_8822B 0 +#define BIT_MASK_NOA_DURATION_8822B 0xffffffffL +#define BIT_NOA_DURATION_8822B(x) \ + (((x) & BIT_MASK_NOA_DURATION_8822B) << BIT_SHIFT_NOA_DURATION_8822B) +#define BIT_GET_NOA_DURATION_8822B(x) \ + (((x) >> BIT_SHIFT_NOA_DURATION_8822B) & BIT_MASK_NOA_DURATION_8822B) + +/* 2 REG_P2P_RST_8822B */ +#define BIT_P2P2_PWR_RST1_8822B BIT(5) +#define BIT_P2P2_PWR_RST0_8822B BIT(4) +#define BIT_P2P1_PWR_RST1_8822B BIT(3) +#define BIT_P2P1_PWR_RST0_8822B BIT(2) +#define BIT_P2P_PWR_RST1_V1_8822B BIT(1) +#define BIT_P2P_PWR_RST0_V1_8822B BIT(0) + +/* 2 REG_SCHEDULER_RST_8822B */ +#define BIT_SYNC_CLI_8822B BIT(1) +#define BIT_SCHEDULER_RST_V1_8822B BIT(0) + +/* 2 REG_SCH_TXCMD_8822B */ + +#define BIT_SHIFT_SCH_TXCMD_8822B 0 +#define BIT_MASK_SCH_TXCMD_8822B 0xffffffffL +#define BIT_SCH_TXCMD_8822B(x) \ + (((x) & BIT_MASK_SCH_TXCMD_8822B) << BIT_SHIFT_SCH_TXCMD_8822B) +#define BIT_GET_SCH_TXCMD_8822B(x) \ + (((x) >> BIT_SHIFT_SCH_TXCMD_8822B) & BIT_MASK_SCH_TXCMD_8822B) + +/* 2 REG_PAGE5_DUMMY_8822B */ + +/* 2 REG_CPUMGQ_TX_TIMER_8822B */ + +#define BIT_SHIFT_CPUMGQ_TX_TIMER_V1_8822B 0 +#define BIT_MASK_CPUMGQ_TX_TIMER_V1_8822B 0xffffffffL +#define BIT_CPUMGQ_TX_TIMER_V1_8822B(x) \ + (((x) & BIT_MASK_CPUMGQ_TX_TIMER_V1_8822B) \ + << BIT_SHIFT_CPUMGQ_TX_TIMER_V1_8822B) +#define BIT_GET_CPUMGQ_TX_TIMER_V1_8822B(x) \ + (((x) >> BIT_SHIFT_CPUMGQ_TX_TIMER_V1_8822B) & \ + BIT_MASK_CPUMGQ_TX_TIMER_V1_8822B) + +/* 2 REG_PS_TIMER_A_8822B */ + +#define BIT_SHIFT_PS_TIMER_A_V1_8822B 0 +#define BIT_MASK_PS_TIMER_A_V1_8822B 0xffffffffL +#define BIT_PS_TIMER_A_V1_8822B(x) \ + (((x) & BIT_MASK_PS_TIMER_A_V1_8822B) << BIT_SHIFT_PS_TIMER_A_V1_8822B) +#define BIT_GET_PS_TIMER_A_V1_8822B(x) \ + (((x) >> BIT_SHIFT_PS_TIMER_A_V1_8822B) & BIT_MASK_PS_TIMER_A_V1_8822B) + +/* 2 REG_PS_TIMER_B_8822B */ + +#define BIT_SHIFT_PS_TIMER_B_V1_8822B 0 +#define BIT_MASK_PS_TIMER_B_V1_8822B 0xffffffffL +#define BIT_PS_TIMER_B_V1_8822B(x) \ + (((x) & BIT_MASK_PS_TIMER_B_V1_8822B) << BIT_SHIFT_PS_TIMER_B_V1_8822B) +#define BIT_GET_PS_TIMER_B_V1_8822B(x) \ + (((x) >> BIT_SHIFT_PS_TIMER_B_V1_8822B) & BIT_MASK_PS_TIMER_B_V1_8822B) + +/* 2 REG_PS_TIMER_C_8822B */ + +#define BIT_SHIFT_PS_TIMER_C_V1_8822B 0 +#define BIT_MASK_PS_TIMER_C_V1_8822B 0xffffffffL +#define BIT_PS_TIMER_C_V1_8822B(x) \ + (((x) & BIT_MASK_PS_TIMER_C_V1_8822B) << BIT_SHIFT_PS_TIMER_C_V1_8822B) +#define BIT_GET_PS_TIMER_C_V1_8822B(x) \ + (((x) >> BIT_SHIFT_PS_TIMER_C_V1_8822B) & BIT_MASK_PS_TIMER_C_V1_8822B) + +/* 2 REG_PS_TIMER_ABC_CPUMGQ_TIMER_CRTL_8822B */ +#define BIT_CPUMGQ_TIMER_EN_8822B BIT(31) +#define BIT_CPUMGQ_TX_EN_8822B BIT(28) + +#define BIT_SHIFT_CPUMGQ_TIMER_TSF_SEL_8822B 24 +#define BIT_MASK_CPUMGQ_TIMER_TSF_SEL_8822B 0x7 +#define BIT_CPUMGQ_TIMER_TSF_SEL_8822B(x) \ + (((x) & BIT_MASK_CPUMGQ_TIMER_TSF_SEL_8822B) \ + << BIT_SHIFT_CPUMGQ_TIMER_TSF_SEL_8822B) +#define BIT_GET_CPUMGQ_TIMER_TSF_SEL_8822B(x) \ + (((x) >> BIT_SHIFT_CPUMGQ_TIMER_TSF_SEL_8822B) & \ + BIT_MASK_CPUMGQ_TIMER_TSF_SEL_8822B) + +#define BIT_PS_TIMER_C_EN_8822B BIT(23) + +#define BIT_SHIFT_PS_TIMER_C_TSF_SEL_8822B 16 +#define BIT_MASK_PS_TIMER_C_TSF_SEL_8822B 0x7 +#define BIT_PS_TIMER_C_TSF_SEL_8822B(x) \ + (((x) & BIT_MASK_PS_TIMER_C_TSF_SEL_8822B) \ + << BIT_SHIFT_PS_TIMER_C_TSF_SEL_8822B) +#define BIT_GET_PS_TIMER_C_TSF_SEL_8822B(x) \ + (((x) >> BIT_SHIFT_PS_TIMER_C_TSF_SEL_8822B) & \ + BIT_MASK_PS_TIMER_C_TSF_SEL_8822B) + +#define BIT_PS_TIMER_B_EN_8822B BIT(15) + +#define BIT_SHIFT_PS_TIMER_B_TSF_SEL_8822B 8 +#define BIT_MASK_PS_TIMER_B_TSF_SEL_8822B 0x7 +#define BIT_PS_TIMER_B_TSF_SEL_8822B(x) \ + (((x) & BIT_MASK_PS_TIMER_B_TSF_SEL_8822B) \ + << BIT_SHIFT_PS_TIMER_B_TSF_SEL_8822B) +#define BIT_GET_PS_TIMER_B_TSF_SEL_8822B(x) \ + (((x) >> BIT_SHIFT_PS_TIMER_B_TSF_SEL_8822B) & \ + BIT_MASK_PS_TIMER_B_TSF_SEL_8822B) + +#define BIT_PS_TIMER_A_EN_8822B BIT(7) + +#define BIT_SHIFT_PS_TIMER_A_TSF_SEL_8822B 0 +#define BIT_MASK_PS_TIMER_A_TSF_SEL_8822B 0x7 +#define BIT_PS_TIMER_A_TSF_SEL_8822B(x) \ + (((x) & BIT_MASK_PS_TIMER_A_TSF_SEL_8822B) \ + << BIT_SHIFT_PS_TIMER_A_TSF_SEL_8822B) +#define BIT_GET_PS_TIMER_A_TSF_SEL_8822B(x) \ + (((x) >> BIT_SHIFT_PS_TIMER_A_TSF_SEL_8822B) & \ + BIT_MASK_PS_TIMER_A_TSF_SEL_8822B) + +/* 2 REG_CPUMGQ_TX_TIMER_EARLY_8822B */ + +#define BIT_SHIFT_CPUMGQ_TX_TIMER_EARLY_8822B 0 +#define BIT_MASK_CPUMGQ_TX_TIMER_EARLY_8822B 0xff +#define BIT_CPUMGQ_TX_TIMER_EARLY_8822B(x) \ + (((x) & BIT_MASK_CPUMGQ_TX_TIMER_EARLY_8822B) \ + << BIT_SHIFT_CPUMGQ_TX_TIMER_EARLY_8822B) +#define BIT_GET_CPUMGQ_TX_TIMER_EARLY_8822B(x) \ + (((x) >> BIT_SHIFT_CPUMGQ_TX_TIMER_EARLY_8822B) & \ + BIT_MASK_CPUMGQ_TX_TIMER_EARLY_8822B) + +/* 2 REG_PS_TIMER_A_EARLY_8822B */ + +#define BIT_SHIFT_PS_TIMER_A_EARLY_8822B 0 +#define BIT_MASK_PS_TIMER_A_EARLY_8822B 0xff +#define BIT_PS_TIMER_A_EARLY_8822B(x) \ + (((x) & BIT_MASK_PS_TIMER_A_EARLY_8822B) \ + << BIT_SHIFT_PS_TIMER_A_EARLY_8822B) +#define BIT_GET_PS_TIMER_A_EARLY_8822B(x) \ + (((x) >> BIT_SHIFT_PS_TIMER_A_EARLY_8822B) & \ + BIT_MASK_PS_TIMER_A_EARLY_8822B) + +/* 2 REG_PS_TIMER_B_EARLY_8822B */ + +#define BIT_SHIFT_PS_TIMER_B_EARLY_8822B 0 +#define BIT_MASK_PS_TIMER_B_EARLY_8822B 0xff +#define BIT_PS_TIMER_B_EARLY_8822B(x) \ + (((x) & BIT_MASK_PS_TIMER_B_EARLY_8822B) \ + << BIT_SHIFT_PS_TIMER_B_EARLY_8822B) +#define BIT_GET_PS_TIMER_B_EARLY_8822B(x) \ + (((x) >> BIT_SHIFT_PS_TIMER_B_EARLY_8822B) & \ + BIT_MASK_PS_TIMER_B_EARLY_8822B) + +/* 2 REG_PS_TIMER_C_EARLY_8822B */ + +#define BIT_SHIFT_PS_TIMER_C_EARLY_8822B 0 +#define BIT_MASK_PS_TIMER_C_EARLY_8822B 0xff +#define BIT_PS_TIMER_C_EARLY_8822B(x) \ + (((x) & BIT_MASK_PS_TIMER_C_EARLY_8822B) \ + << BIT_SHIFT_PS_TIMER_C_EARLY_8822B) +#define BIT_GET_PS_TIMER_C_EARLY_8822B(x) \ + (((x) >> BIT_SHIFT_PS_TIMER_C_EARLY_8822B) & \ + BIT_MASK_PS_TIMER_C_EARLY_8822B) + +/* 2 REG_NOT_VALID_8822B */ + +/* 2 REG_BWOPMODE_8822B (BW OPERATION MODE REGISTER) */ + +/* 2 REG_WMAC_FWPKT_CR_8822B */ +#define BIT_FWEN_8822B BIT(7) +#define BIT_PHYSTS_PKT_CTRL_8822B BIT(6) +#define BIT_APPHDR_MIDSRCH_FAIL_8822B BIT(4) +#define BIT_FWPARSING_EN_8822B BIT(3) + +#define BIT_SHIFT_APPEND_MHDR_LEN_8822B 0 +#define BIT_MASK_APPEND_MHDR_LEN_8822B 0x7 +#define BIT_APPEND_MHDR_LEN_8822B(x) \ + (((x) & BIT_MASK_APPEND_MHDR_LEN_8822B) \ + << BIT_SHIFT_APPEND_MHDR_LEN_8822B) +#define BIT_GET_APPEND_MHDR_LEN_8822B(x) \ + (((x) >> BIT_SHIFT_APPEND_MHDR_LEN_8822B) & \ + BIT_MASK_APPEND_MHDR_LEN_8822B) + +/* 2 REG_WMAC_CR_8822B (WMAC CR AND APSD CONTROL REGISTER) */ +#define BIT_IC_MACPHY_M_8822B BIT(0) + +/* 2 REG_TCR_8822B (TRANSMISSION CONFIGURATION REGISTER) */ +#define BIT_WMAC_EN_RTS_ADDR_8822B BIT(31) +#define BIT_WMAC_DISABLE_CCK_8822B BIT(30) +#define BIT_WMAC_RAW_LEN_8822B BIT(29) +#define BIT_WMAC_NOTX_IN_RXNDP_8822B BIT(28) +#define BIT_WMAC_EN_EOF_8822B BIT(27) +#define BIT_WMAC_BF_SEL_8822B BIT(26) +#define BIT_WMAC_ANTMODE_SEL_8822B BIT(25) +#define BIT_WMAC_TCRPWRMGT_HWCTL_8822B BIT(24) +#define BIT_WMAC_SMOOTH_VAL_8822B BIT(23) +#define BIT_FETCH_MPDU_AFTER_WSEC_RDY_8822B BIT(20) +#define BIT_WMAC_TCR_EN_20MST_8822B BIT(19) +#define BIT_WMAC_DIS_SIGTA_8822B BIT(18) +#define BIT_WMAC_DIS_A2B0_8822B BIT(17) +#define BIT_WMAC_MSK_SIGBCRC_8822B BIT(16) +#define BIT_WMAC_TCR_ERRSTEN_3_8822B BIT(15) +#define BIT_WMAC_TCR_ERRSTEN_2_8822B BIT(14) +#define BIT_WMAC_TCR_ERRSTEN_1_8822B BIT(13) +#define BIT_WMAC_TCR_ERRSTEN_0_8822B BIT(12) +#define BIT_WMAC_TCR_TXSK_PERPKT_8822B BIT(11) +#define BIT_ICV_8822B BIT(10) +#define BIT_CFEND_FORMAT_8822B BIT(9) +#define BIT_CRC_8822B BIT(8) +#define BIT_PWRBIT_OW_EN_8822B BIT(7) +#define BIT_PWR_ST_8822B BIT(6) +#define BIT_WMAC_TCR_UPD_TIMIE_8822B BIT(5) +#define BIT_WMAC_TCR_UPD_HGQMD_8822B BIT(4) +#define BIT_VHTSIGA1_TXPS_8822B BIT(3) +#define BIT_PAD_SEL_8822B BIT(2) +#define BIT_DIS_GCLK_8822B BIT(1) + +/* 2 REG_RCR_8822B (RECEIVE CONFIGURATION REGISTER) */ +#define BIT_APP_FCS_8822B BIT(31) +#define BIT_APP_MIC_8822B BIT(30) +#define BIT_APP_ICV_8822B BIT(29) +#define BIT_APP_PHYSTS_8822B BIT(28) +#define BIT_APP_BASSN_8822B BIT(27) +#define BIT_VHT_DACK_8822B BIT(26) +#define BIT_TCPOFLD_EN_8822B BIT(25) +#define BIT_ENMBID_8822B BIT(24) +#define BIT_LSIGEN_8822B BIT(23) +#define BIT_MFBEN_8822B BIT(22) +#define BIT_DISCHKPPDLLEN_8822B BIT(21) +#define BIT_PKTCTL_DLEN_8822B BIT(20) +#define BIT_TIM_PARSER_EN_8822B BIT(18) +#define BIT_BC_MD_EN_8822B BIT(17) +#define BIT_UC_MD_EN_8822B BIT(16) +#define BIT_RXSK_PERPKT_8822B BIT(15) +#define BIT_HTC_LOC_CTRL_8822B BIT(14) +#define BIT_RPFM_CAM_ENABLE_8822B BIT(12) +#define BIT_TA_BCN_8822B BIT(11) +#define BIT_DISDECMYPKT_8822B BIT(10) +#define BIT_AICV_8822B BIT(9) +#define BIT_ACRC32_8822B BIT(8) +#define BIT_CBSSID_BCN_8822B BIT(7) +#define BIT_CBSSID_DATA_8822B BIT(6) +#define BIT_APWRMGT_8822B BIT(5) +#define BIT_ADD3_8822B BIT(4) +#define BIT_AB_8822B BIT(3) +#define BIT_AM_8822B BIT(2) +#define BIT_APM_8822B BIT(1) +#define BIT_AAP_8822B BIT(0) + +/* 2 REG_RX_DRVINFO_SZ_8822B (RX DRIVER INFO SIZE REGISTER) */ +#define BIT_PHYSTS_PER_PKT_MODE_8822B BIT(7) + +#define BIT_SHIFT_DRVINFO_SZ_V1_8822B 0 +#define BIT_MASK_DRVINFO_SZ_V1_8822B 0xf +#define BIT_DRVINFO_SZ_V1_8822B(x) \ + (((x) & BIT_MASK_DRVINFO_SZ_V1_8822B) << BIT_SHIFT_DRVINFO_SZ_V1_8822B) +#define BIT_GET_DRVINFO_SZ_V1_8822B(x) \ + (((x) >> BIT_SHIFT_DRVINFO_SZ_V1_8822B) & BIT_MASK_DRVINFO_SZ_V1_8822B) + +/* 2 REG_RX_DLK_TIME_8822B (RX DEADLOCK TIME REGISTER) */ + +#define BIT_SHIFT_RX_DLK_TIME_8822B 0 +#define BIT_MASK_RX_DLK_TIME_8822B 0xff +#define BIT_RX_DLK_TIME_8822B(x) \ + (((x) & BIT_MASK_RX_DLK_TIME_8822B) << BIT_SHIFT_RX_DLK_TIME_8822B) +#define BIT_GET_RX_DLK_TIME_8822B(x) \ + (((x) >> BIT_SHIFT_RX_DLK_TIME_8822B) & BIT_MASK_RX_DLK_TIME_8822B) + +/* 2 REG_RX_PKT_LIMIT_8822B (RX PACKET LENGTH LIMIT REGISTER) */ + +#define BIT_SHIFT_RXPKTLMT_8822B 0 +#define BIT_MASK_RXPKTLMT_8822B 0x3f +#define BIT_RXPKTLMT_8822B(x) \ + (((x) & BIT_MASK_RXPKTLMT_8822B) << BIT_SHIFT_RXPKTLMT_8822B) +#define BIT_GET_RXPKTLMT_8822B(x) \ + (((x) >> BIT_SHIFT_RXPKTLMT_8822B) & BIT_MASK_RXPKTLMT_8822B) + +/* 2 REG_MACID_8822B (MAC ID REGISTER) */ + +#define BIT_SHIFT_MACID_8822B 0 +#define BIT_MASK_MACID_8822B 0xffffffffffffL +#define BIT_MACID_8822B(x) \ + (((x) & BIT_MASK_MACID_8822B) << BIT_SHIFT_MACID_8822B) +#define BIT_GET_MACID_8822B(x) \ + (((x) >> BIT_SHIFT_MACID_8822B) & BIT_MASK_MACID_8822B) + +/* 2 REG_BSSID_8822B (BSSID REGISTER) */ + +#define BIT_SHIFT_BSSID_8822B 0 +#define BIT_MASK_BSSID_8822B 0xffffffffffffL +#define BIT_BSSID_8822B(x) \ + (((x) & BIT_MASK_BSSID_8822B) << BIT_SHIFT_BSSID_8822B) +#define BIT_GET_BSSID_8822B(x) \ + (((x) >> BIT_SHIFT_BSSID_8822B) & BIT_MASK_BSSID_8822B) + +/* 2 REG_MAR_8822B (MULTICAST ADDRESS REGISTER) */ + +#define BIT_SHIFT_MAR_8822B 0 +#define BIT_MASK_MAR_8822B 0xffffffffffffffffL +#define BIT_MAR_8822B(x) (((x) & BIT_MASK_MAR_8822B) << BIT_SHIFT_MAR_8822B) +#define BIT_GET_MAR_8822B(x) (((x) >> BIT_SHIFT_MAR_8822B) & BIT_MASK_MAR_8822B) + +/* 2 REG_MBIDCAMCFG_1_8822B (MBSSID CAM CONFIGURATION REGISTER) */ + +#define BIT_SHIFT_MBIDCAM_RWDATA_L_8822B 0 +#define BIT_MASK_MBIDCAM_RWDATA_L_8822B 0xffffffffL +#define BIT_MBIDCAM_RWDATA_L_8822B(x) \ + (((x) & BIT_MASK_MBIDCAM_RWDATA_L_8822B) \ + << BIT_SHIFT_MBIDCAM_RWDATA_L_8822B) +#define BIT_GET_MBIDCAM_RWDATA_L_8822B(x) \ + (((x) >> BIT_SHIFT_MBIDCAM_RWDATA_L_8822B) & \ + BIT_MASK_MBIDCAM_RWDATA_L_8822B) + +/* 2 REG_MBIDCAMCFG_2_8822B (MBSSID CAM CONFIGURATION REGISTER) */ +#define BIT_MBIDCAM_POLL_8822B BIT(31) +#define BIT_MBIDCAM_WT_EN_8822B BIT(30) + +#define BIT_SHIFT_MBIDCAM_ADDR_8822B 24 +#define BIT_MASK_MBIDCAM_ADDR_8822B 0x1f +#define BIT_MBIDCAM_ADDR_8822B(x) \ + (((x) & BIT_MASK_MBIDCAM_ADDR_8822B) << BIT_SHIFT_MBIDCAM_ADDR_8822B) +#define BIT_GET_MBIDCAM_ADDR_8822B(x) \ + (((x) >> BIT_SHIFT_MBIDCAM_ADDR_8822B) & BIT_MASK_MBIDCAM_ADDR_8822B) + +#define BIT_MBIDCAM_VALID_8822B BIT(23) +#define BIT_LSIC_TXOP_EN_8822B BIT(17) +#define BIT_CTS_EN_8822B BIT(16) + +#define BIT_SHIFT_MBIDCAM_RWDATA_H_8822B 0 +#define BIT_MASK_MBIDCAM_RWDATA_H_8822B 0xffff +#define BIT_MBIDCAM_RWDATA_H_8822B(x) \ + (((x) & BIT_MASK_MBIDCAM_RWDATA_H_8822B) \ + << BIT_SHIFT_MBIDCAM_RWDATA_H_8822B) +#define BIT_GET_MBIDCAM_RWDATA_H_8822B(x) \ + (((x) >> BIT_SHIFT_MBIDCAM_RWDATA_H_8822B) & \ + BIT_MASK_MBIDCAM_RWDATA_H_8822B) + +/* 2 REG_ZLD_NUM_8822B */ + +#define BIT_SHIFT_ZLD_NUM_8822B 0 +#define BIT_MASK_ZLD_NUM_8822B 0xff +#define BIT_ZLD_NUM_8822B(x) \ + (((x) & BIT_MASK_ZLD_NUM_8822B) << BIT_SHIFT_ZLD_NUM_8822B) +#define BIT_GET_ZLD_NUM_8822B(x) \ + (((x) >> BIT_SHIFT_ZLD_NUM_8822B) & BIT_MASK_ZLD_NUM_8822B) + +/* 2 REG_UDF_THSD_8822B */ + +#define BIT_SHIFT_UDF_THSD_8822B 0 +#define BIT_MASK_UDF_THSD_8822B 0xff +#define BIT_UDF_THSD_8822B(x) \ + (((x) & BIT_MASK_UDF_THSD_8822B) << BIT_SHIFT_UDF_THSD_8822B) +#define BIT_GET_UDF_THSD_8822B(x) \ + (((x) >> BIT_SHIFT_UDF_THSD_8822B) & BIT_MASK_UDF_THSD_8822B) + +/* 2 REG_WMAC_TCR_TSFT_OFS_8822B */ + +#define BIT_SHIFT_WMAC_TCR_TSFT_OFS_8822B 0 +#define BIT_MASK_WMAC_TCR_TSFT_OFS_8822B 0xffff +#define BIT_WMAC_TCR_TSFT_OFS_8822B(x) \ + (((x) & BIT_MASK_WMAC_TCR_TSFT_OFS_8822B) \ + << BIT_SHIFT_WMAC_TCR_TSFT_OFS_8822B) +#define BIT_GET_WMAC_TCR_TSFT_OFS_8822B(x) \ + (((x) >> BIT_SHIFT_WMAC_TCR_TSFT_OFS_8822B) & \ + BIT_MASK_WMAC_TCR_TSFT_OFS_8822B) + +/* 2 REG_MCU_TEST_2_V1_8822B */ + +#define BIT_SHIFT_MCU_RSVD_2_V1_8822B 0 +#define BIT_MASK_MCU_RSVD_2_V1_8822B 0xffff +#define BIT_MCU_RSVD_2_V1_8822B(x) \ + (((x) & BIT_MASK_MCU_RSVD_2_V1_8822B) << BIT_SHIFT_MCU_RSVD_2_V1_8822B) +#define BIT_GET_MCU_RSVD_2_V1_8822B(x) \ + (((x) >> BIT_SHIFT_MCU_RSVD_2_V1_8822B) & BIT_MASK_MCU_RSVD_2_V1_8822B) + +/* 2 REG_WMAC_TXTIMEOUT_8822B */ + +#define BIT_SHIFT_WMAC_TXTIMEOUT_8822B 0 +#define BIT_MASK_WMAC_TXTIMEOUT_8822B 0xff +#define BIT_WMAC_TXTIMEOUT_8822B(x) \ + (((x) & BIT_MASK_WMAC_TXTIMEOUT_8822B) \ + << BIT_SHIFT_WMAC_TXTIMEOUT_8822B) +#define BIT_GET_WMAC_TXTIMEOUT_8822B(x) \ + (((x) >> BIT_SHIFT_WMAC_TXTIMEOUT_8822B) & \ + BIT_MASK_WMAC_TXTIMEOUT_8822B) + +/* 2 REG_STMP_THSD_8822B */ + +#define BIT_SHIFT_STMP_THSD_8822B 0 +#define BIT_MASK_STMP_THSD_8822B 0xff +#define BIT_STMP_THSD_8822B(x) \ + (((x) & BIT_MASK_STMP_THSD_8822B) << BIT_SHIFT_STMP_THSD_8822B) +#define BIT_GET_STMP_THSD_8822B(x) \ + (((x) >> BIT_SHIFT_STMP_THSD_8822B) & BIT_MASK_STMP_THSD_8822B) + +/* 2 REG_MAC_SPEC_SIFS_8822B (SPECIFICATION SIFS REGISTER) */ + +#define BIT_SHIFT_SPEC_SIFS_OFDM_8822B 8 +#define BIT_MASK_SPEC_SIFS_OFDM_8822B 0xff +#define BIT_SPEC_SIFS_OFDM_8822B(x) \ + (((x) & BIT_MASK_SPEC_SIFS_OFDM_8822B) \ + << BIT_SHIFT_SPEC_SIFS_OFDM_8822B) +#define BIT_GET_SPEC_SIFS_OFDM_8822B(x) \ + (((x) >> BIT_SHIFT_SPEC_SIFS_OFDM_8822B) & \ + BIT_MASK_SPEC_SIFS_OFDM_8822B) + +#define BIT_SHIFT_SPEC_SIFS_CCK_8822B 0 +#define BIT_MASK_SPEC_SIFS_CCK_8822B 0xff +#define BIT_SPEC_SIFS_CCK_8822B(x) \ + (((x) & BIT_MASK_SPEC_SIFS_CCK_8822B) << BIT_SHIFT_SPEC_SIFS_CCK_8822B) +#define BIT_GET_SPEC_SIFS_CCK_8822B(x) \ + (((x) >> BIT_SHIFT_SPEC_SIFS_CCK_8822B) & BIT_MASK_SPEC_SIFS_CCK_8822B) + +/* 2 REG_USTIME_EDCA_8822B (US TIME TUNING FOR EDCA REGISTER) */ + +#define BIT_SHIFT_USTIME_EDCA_V1_8822B 0 +#define BIT_MASK_USTIME_EDCA_V1_8822B 0x1ff +#define BIT_USTIME_EDCA_V1_8822B(x) \ + (((x) & BIT_MASK_USTIME_EDCA_V1_8822B) \ + << BIT_SHIFT_USTIME_EDCA_V1_8822B) +#define BIT_GET_USTIME_EDCA_V1_8822B(x) \ + (((x) >> BIT_SHIFT_USTIME_EDCA_V1_8822B) & \ + BIT_MASK_USTIME_EDCA_V1_8822B) + +/* 2 REG_RESP_SIFS_OFDM_8822B (RESPONSE SIFS FOR OFDM REGISTER) */ + +#define BIT_SHIFT_SIFS_R2T_OFDM_8822B 8 +#define BIT_MASK_SIFS_R2T_OFDM_8822B 0xff +#define BIT_SIFS_R2T_OFDM_8822B(x) \ + (((x) & BIT_MASK_SIFS_R2T_OFDM_8822B) << BIT_SHIFT_SIFS_R2T_OFDM_8822B) +#define BIT_GET_SIFS_R2T_OFDM_8822B(x) \ + (((x) >> BIT_SHIFT_SIFS_R2T_OFDM_8822B) & BIT_MASK_SIFS_R2T_OFDM_8822B) + +#define BIT_SHIFT_SIFS_T2T_OFDM_8822B 0 +#define BIT_MASK_SIFS_T2T_OFDM_8822B 0xff +#define BIT_SIFS_T2T_OFDM_8822B(x) \ + (((x) & BIT_MASK_SIFS_T2T_OFDM_8822B) << BIT_SHIFT_SIFS_T2T_OFDM_8822B) +#define BIT_GET_SIFS_T2T_OFDM_8822B(x) \ + (((x) >> BIT_SHIFT_SIFS_T2T_OFDM_8822B) & BIT_MASK_SIFS_T2T_OFDM_8822B) + +/* 2 REG_RESP_SIFS_CCK_8822B (RESPONSE SIFS FOR CCK REGISTER) */ + +#define BIT_SHIFT_SIFS_R2T_CCK_8822B 8 +#define BIT_MASK_SIFS_R2T_CCK_8822B 0xff +#define BIT_SIFS_R2T_CCK_8822B(x) \ + (((x) & BIT_MASK_SIFS_R2T_CCK_8822B) << BIT_SHIFT_SIFS_R2T_CCK_8822B) +#define BIT_GET_SIFS_R2T_CCK_8822B(x) \ + (((x) >> BIT_SHIFT_SIFS_R2T_CCK_8822B) & BIT_MASK_SIFS_R2T_CCK_8822B) + +#define BIT_SHIFT_SIFS_T2T_CCK_8822B 0 +#define BIT_MASK_SIFS_T2T_CCK_8822B 0xff +#define BIT_SIFS_T2T_CCK_8822B(x) \ + (((x) & BIT_MASK_SIFS_T2T_CCK_8822B) << BIT_SHIFT_SIFS_T2T_CCK_8822B) +#define BIT_GET_SIFS_T2T_CCK_8822B(x) \ + (((x) >> BIT_SHIFT_SIFS_T2T_CCK_8822B) & BIT_MASK_SIFS_T2T_CCK_8822B) + +/* 2 REG_EIFS_8822B (EIFS REGISTER) */ + +#define BIT_SHIFT_EIFS_8822B 0 +#define BIT_MASK_EIFS_8822B 0xffff +#define BIT_EIFS_8822B(x) (((x) & BIT_MASK_EIFS_8822B) << BIT_SHIFT_EIFS_8822B) +#define BIT_GET_EIFS_8822B(x) \ + (((x) >> BIT_SHIFT_EIFS_8822B) & BIT_MASK_EIFS_8822B) + +/* 2 REG_CTS2TO_8822B (CTS2 TIMEOUT REGISTER) */ + +#define BIT_SHIFT_CTS2TO_8822B 0 +#define BIT_MASK_CTS2TO_8822B 0xff +#define BIT_CTS2TO_8822B(x) \ + (((x) & BIT_MASK_CTS2TO_8822B) << BIT_SHIFT_CTS2TO_8822B) +#define BIT_GET_CTS2TO_8822B(x) \ + (((x) >> BIT_SHIFT_CTS2TO_8822B) & BIT_MASK_CTS2TO_8822B) + +/* 2 REG_ACKTO_8822B (ACK TIMEOUT REGISTER) */ + +#define BIT_SHIFT_ACKTO_8822B 0 +#define BIT_MASK_ACKTO_8822B 0xff +#define BIT_ACKTO_8822B(x) \ + (((x) & BIT_MASK_ACKTO_8822B) << BIT_SHIFT_ACKTO_8822B) +#define BIT_GET_ACKTO_8822B(x) \ + (((x) >> BIT_SHIFT_ACKTO_8822B) & BIT_MASK_ACKTO_8822B) + +/* 2 REG_NAV_CTRL_8822B (NAV CONTROL REGISTER) */ + +#define BIT_SHIFT_NAV_UPPER_8822B 16 +#define BIT_MASK_NAV_UPPER_8822B 0xff +#define BIT_NAV_UPPER_8822B(x) \ + (((x) & BIT_MASK_NAV_UPPER_8822B) << BIT_SHIFT_NAV_UPPER_8822B) +#define BIT_GET_NAV_UPPER_8822B(x) \ + (((x) >> BIT_SHIFT_NAV_UPPER_8822B) & BIT_MASK_NAV_UPPER_8822B) + +#define BIT_SHIFT_RXMYRTS_NAV_8822B 8 +#define BIT_MASK_RXMYRTS_NAV_8822B 0xf +#define BIT_RXMYRTS_NAV_8822B(x) \ + (((x) & BIT_MASK_RXMYRTS_NAV_8822B) << BIT_SHIFT_RXMYRTS_NAV_8822B) +#define BIT_GET_RXMYRTS_NAV_8822B(x) \ + (((x) >> BIT_SHIFT_RXMYRTS_NAV_8822B) & BIT_MASK_RXMYRTS_NAV_8822B) + +#define BIT_SHIFT_RTSRST_8822B 0 +#define BIT_MASK_RTSRST_8822B 0xff +#define BIT_RTSRST_8822B(x) \ + (((x) & BIT_MASK_RTSRST_8822B) << BIT_SHIFT_RTSRST_8822B) +#define BIT_GET_RTSRST_8822B(x) \ + (((x) >> BIT_SHIFT_RTSRST_8822B) & BIT_MASK_RTSRST_8822B) + +/* 2 REG_BACAMCMD_8822B (BLOCK ACK CAM COMMAND REGISTER) */ +#define BIT_BACAM_POLL_8822B BIT(31) +#define BIT_BACAM_RST_8822B BIT(17) +#define BIT_BACAM_RW_8822B BIT(16) + +#define BIT_SHIFT_TXSBM_8822B 14 +#define BIT_MASK_TXSBM_8822B 0x3 +#define BIT_TXSBM_8822B(x) \ + (((x) & BIT_MASK_TXSBM_8822B) << BIT_SHIFT_TXSBM_8822B) +#define BIT_GET_TXSBM_8822B(x) \ + (((x) >> BIT_SHIFT_TXSBM_8822B) & BIT_MASK_TXSBM_8822B) + +#define BIT_SHIFT_BACAM_ADDR_8822B 0 +#define BIT_MASK_BACAM_ADDR_8822B 0x3f +#define BIT_BACAM_ADDR_8822B(x) \ + (((x) & BIT_MASK_BACAM_ADDR_8822B) << BIT_SHIFT_BACAM_ADDR_8822B) +#define BIT_GET_BACAM_ADDR_8822B(x) \ + (((x) >> BIT_SHIFT_BACAM_ADDR_8822B) & BIT_MASK_BACAM_ADDR_8822B) + +/* 2 REG_BACAMCONTENT_8822B (BLOCK ACK CAM CONTENT REGISTER) */ + +#define BIT_SHIFT_BA_CONTENT_H_8822B (32 & CPU_OPT_WIDTH) +#define BIT_MASK_BA_CONTENT_H_8822B 0xffffffffL +#define BIT_BA_CONTENT_H_8822B(x) \ + (((x) & BIT_MASK_BA_CONTENT_H_8822B) << BIT_SHIFT_BA_CONTENT_H_8822B) +#define BIT_GET_BA_CONTENT_H_8822B(x) \ + (((x) >> BIT_SHIFT_BA_CONTENT_H_8822B) & BIT_MASK_BA_CONTENT_H_8822B) + +#define BIT_SHIFT_BA_CONTENT_L_8822B 0 +#define BIT_MASK_BA_CONTENT_L_8822B 0xffffffffL +#define BIT_BA_CONTENT_L_8822B(x) \ + (((x) & BIT_MASK_BA_CONTENT_L_8822B) << BIT_SHIFT_BA_CONTENT_L_8822B) +#define BIT_GET_BA_CONTENT_L_8822B(x) \ + (((x) >> BIT_SHIFT_BA_CONTENT_L_8822B) & BIT_MASK_BA_CONTENT_L_8822B) + +/* 2 REG_WMAC_BITMAP_CTL_8822B */ +#define BIT_BITMAP_VO_8822B BIT(7) +#define BIT_BITMAP_VI_8822B BIT(6) +#define BIT_BITMAP_BE_8822B BIT(5) +#define BIT_BITMAP_BK_8822B BIT(4) + +#define BIT_SHIFT_BITMAP_CONDITION_8822B 2 +#define BIT_MASK_BITMAP_CONDITION_8822B 0x3 +#define BIT_BITMAP_CONDITION_8822B(x) \ + (((x) & BIT_MASK_BITMAP_CONDITION_8822B) \ + << BIT_SHIFT_BITMAP_CONDITION_8822B) +#define BIT_GET_BITMAP_CONDITION_8822B(x) \ + (((x) >> BIT_SHIFT_BITMAP_CONDITION_8822B) & \ + BIT_MASK_BITMAP_CONDITION_8822B) + +#define BIT_BITMAP_SSNBK_COUNTER_CLR_8822B BIT(1) +#define BIT_BITMAP_FORCE_8822B BIT(0) + +/* 2 REG_TX_RX_8822B STATUS */ + +#define BIT_SHIFT_RXPKT_TYPE_8822B 2 +#define BIT_MASK_RXPKT_TYPE_8822B 0x3f +#define BIT_RXPKT_TYPE_8822B(x) \ + (((x) & BIT_MASK_RXPKT_TYPE_8822B) << BIT_SHIFT_RXPKT_TYPE_8822B) +#define BIT_GET_RXPKT_TYPE_8822B(x) \ + (((x) >> BIT_SHIFT_RXPKT_TYPE_8822B) & BIT_MASK_RXPKT_TYPE_8822B) + +#define BIT_TXACT_IND_8822B BIT(1) +#define BIT_RXACT_IND_8822B BIT(0) + +/* 2 REG_WMAC_BACAM_RPMEN_8822B */ + +#define BIT_SHIFT_BITMAP_SSNBK_COUNTER_8822B 2 +#define BIT_MASK_BITMAP_SSNBK_COUNTER_8822B 0x3f +#define BIT_BITMAP_SSNBK_COUNTER_8822B(x) \ + (((x) & BIT_MASK_BITMAP_SSNBK_COUNTER_8822B) \ + << BIT_SHIFT_BITMAP_SSNBK_COUNTER_8822B) +#define BIT_GET_BITMAP_SSNBK_COUNTER_8822B(x) \ + (((x) >> BIT_SHIFT_BITMAP_SSNBK_COUNTER_8822B) & \ + BIT_MASK_BITMAP_SSNBK_COUNTER_8822B) + +#define BIT_BITMAP_EN_8822B BIT(1) +#define BIT_WMAC_BACAM_RPMEN_8822B BIT(0) + +/* 2 REG_LBDLY_8822B (LOOPBACK DELAY REGISTER) */ + +#define BIT_SHIFT_LBDLY_8822B 0 +#define BIT_MASK_LBDLY_8822B 0x1f +#define BIT_LBDLY_8822B(x) \ + (((x) & BIT_MASK_LBDLY_8822B) << BIT_SHIFT_LBDLY_8822B) +#define BIT_GET_LBDLY_8822B(x) \ + (((x) >> BIT_SHIFT_LBDLY_8822B) & BIT_MASK_LBDLY_8822B) + +/* 2 REG_RXERR_RPT_8822B (RX ERROR REPORT REGISTER) */ + +#define BIT_SHIFT_RXERR_RPT_SEL_V1_3_0_8822B 28 +#define BIT_MASK_RXERR_RPT_SEL_V1_3_0_8822B 0xf +#define BIT_RXERR_RPT_SEL_V1_3_0_8822B(x) \ + (((x) & BIT_MASK_RXERR_RPT_SEL_V1_3_0_8822B) \ + << BIT_SHIFT_RXERR_RPT_SEL_V1_3_0_8822B) +#define BIT_GET_RXERR_RPT_SEL_V1_3_0_8822B(x) \ + (((x) >> BIT_SHIFT_RXERR_RPT_SEL_V1_3_0_8822B) & \ + BIT_MASK_RXERR_RPT_SEL_V1_3_0_8822B) + +#define BIT_RXERR_RPT_RST_8822B BIT(27) +#define BIT_RXERR_RPT_SEL_V1_4_8822B BIT(26) +#define BIT_W1S_8822B BIT(23) +#define BIT_UD_SELECT_BSSID_8822B BIT(22) + +#define BIT_SHIFT_UD_SUB_TYPE_8822B 18 +#define BIT_MASK_UD_SUB_TYPE_8822B 0xf +#define BIT_UD_SUB_TYPE_8822B(x) \ + (((x) & BIT_MASK_UD_SUB_TYPE_8822B) << BIT_SHIFT_UD_SUB_TYPE_8822B) +#define BIT_GET_UD_SUB_TYPE_8822B(x) \ + (((x) >> BIT_SHIFT_UD_SUB_TYPE_8822B) & BIT_MASK_UD_SUB_TYPE_8822B) + +#define BIT_SHIFT_UD_TYPE_8822B 16 +#define BIT_MASK_UD_TYPE_8822B 0x3 +#define BIT_UD_TYPE_8822B(x) \ + (((x) & BIT_MASK_UD_TYPE_8822B) << BIT_SHIFT_UD_TYPE_8822B) +#define BIT_GET_UD_TYPE_8822B(x) \ + (((x) >> BIT_SHIFT_UD_TYPE_8822B) & BIT_MASK_UD_TYPE_8822B) + +#define BIT_SHIFT_RPT_COUNTER_8822B 0 +#define BIT_MASK_RPT_COUNTER_8822B 0xffff +#define BIT_RPT_COUNTER_8822B(x) \ + (((x) & BIT_MASK_RPT_COUNTER_8822B) << BIT_SHIFT_RPT_COUNTER_8822B) +#define BIT_GET_RPT_COUNTER_8822B(x) \ + (((x) >> BIT_SHIFT_RPT_COUNTER_8822B) & BIT_MASK_RPT_COUNTER_8822B) + +/* 2 REG_WMAC_TRXPTCL_CTL_8822B (WMAC TX/RX PROTOCOL CONTROL REGISTER) */ + +#define BIT_SHIFT_ACKBA_TYPSEL_8822B (60 & CPU_OPT_WIDTH) +#define BIT_MASK_ACKBA_TYPSEL_8822B 0xf +#define BIT_ACKBA_TYPSEL_8822B(x) \ + (((x) & BIT_MASK_ACKBA_TYPSEL_8822B) << BIT_SHIFT_ACKBA_TYPSEL_8822B) +#define BIT_GET_ACKBA_TYPSEL_8822B(x) \ + (((x) >> BIT_SHIFT_ACKBA_TYPSEL_8822B) & BIT_MASK_ACKBA_TYPSEL_8822B) + +#define BIT_SHIFT_ACKBA_ACKPCHK_8822B (56 & CPU_OPT_WIDTH) +#define BIT_MASK_ACKBA_ACKPCHK_8822B 0xf +#define BIT_ACKBA_ACKPCHK_8822B(x) \ + (((x) & BIT_MASK_ACKBA_ACKPCHK_8822B) << BIT_SHIFT_ACKBA_ACKPCHK_8822B) +#define BIT_GET_ACKBA_ACKPCHK_8822B(x) \ + (((x) >> BIT_SHIFT_ACKBA_ACKPCHK_8822B) & BIT_MASK_ACKBA_ACKPCHK_8822B) + +#define BIT_SHIFT_ACKBAR_TYPESEL_8822B (48 & CPU_OPT_WIDTH) +#define BIT_MASK_ACKBAR_TYPESEL_8822B 0xff +#define BIT_ACKBAR_TYPESEL_8822B(x) \ + (((x) & BIT_MASK_ACKBAR_TYPESEL_8822B) \ + << BIT_SHIFT_ACKBAR_TYPESEL_8822B) +#define BIT_GET_ACKBAR_TYPESEL_8822B(x) \ + (((x) >> BIT_SHIFT_ACKBAR_TYPESEL_8822B) & \ + BIT_MASK_ACKBAR_TYPESEL_8822B) + +#define BIT_SHIFT_ACKBAR_ACKPCHK_8822B (44 & CPU_OPT_WIDTH) +#define BIT_MASK_ACKBAR_ACKPCHK_8822B 0xf +#define BIT_ACKBAR_ACKPCHK_8822B(x) \ + (((x) & BIT_MASK_ACKBAR_ACKPCHK_8822B) \ + << BIT_SHIFT_ACKBAR_ACKPCHK_8822B) +#define BIT_GET_ACKBAR_ACKPCHK_8822B(x) \ + (((x) >> BIT_SHIFT_ACKBAR_ACKPCHK_8822B) & \ + BIT_MASK_ACKBAR_ACKPCHK_8822B) + +#define BIT_RXBA_IGNOREA2_8822B BIT(42) +#define BIT_EN_SAVE_ALL_TXOPADDR_8822B BIT(41) +#define BIT_EN_TXCTS_TO_TXOPOWNER_INRXNAV_8822B BIT(40) +#define BIT_DIS_TXBA_AMPDUFCSERR_8822B BIT(39) +#define BIT_DIS_TXBA_RXBARINFULL_8822B BIT(38) +#define BIT_DIS_TXCFE_INFULL_8822B BIT(37) +#define BIT_DIS_TXCTS_INFULL_8822B BIT(36) +#define BIT_EN_TXACKBA_IN_TX_RDG_8822B BIT(35) +#define BIT_EN_TXACKBA_IN_TXOP_8822B BIT(34) +#define BIT_EN_TXCTS_IN_RXNAV_8822B BIT(33) +#define BIT_EN_TXCTS_INTXOP_8822B BIT(32) +#define BIT_BLK_EDCA_BBSLP_8822B BIT(31) +#define BIT_BLK_EDCA_BBSBY_8822B BIT(30) +#define BIT_ACKTO_BLOCK_SCH_EN_8822B BIT(27) +#define BIT_EIFS_BLOCK_SCH_EN_8822B BIT(26) +#define BIT_PLCPCHK_RST_EIFS_8822B BIT(25) +#define BIT_CCA_RST_EIFS_8822B BIT(24) +#define BIT_DIS_UPD_MYRXPKTNAV_8822B BIT(23) +#define BIT_EARLY_TXBA_8822B BIT(22) + +#define BIT_SHIFT_RESP_CHNBUSY_8822B 20 +#define BIT_MASK_RESP_CHNBUSY_8822B 0x3 +#define BIT_RESP_CHNBUSY_8822B(x) \ + (((x) & BIT_MASK_RESP_CHNBUSY_8822B) << BIT_SHIFT_RESP_CHNBUSY_8822B) +#define BIT_GET_RESP_CHNBUSY_8822B(x) \ + (((x) >> BIT_SHIFT_RESP_CHNBUSY_8822B) & BIT_MASK_RESP_CHNBUSY_8822B) + +#define BIT_RESP_DCTS_EN_8822B BIT(19) +#define BIT_RESP_DCFE_EN_8822B BIT(18) +#define BIT_RESP_SPLCPEN_8822B BIT(17) +#define BIT_RESP_SGIEN_8822B BIT(16) +#define BIT_RESP_LDPC_EN_8822B BIT(15) +#define BIT_DIS_RESP_ACKINCCA_8822B BIT(14) +#define BIT_DIS_RESP_CTSINCCA_8822B BIT(13) + +#define BIT_SHIFT_R_WMAC_SECOND_CCA_TIMER_8822B 10 +#define BIT_MASK_R_WMAC_SECOND_CCA_TIMER_8822B 0x7 +#define BIT_R_WMAC_SECOND_CCA_TIMER_8822B(x) \ + (((x) & BIT_MASK_R_WMAC_SECOND_CCA_TIMER_8822B) \ + << BIT_SHIFT_R_WMAC_SECOND_CCA_TIMER_8822B) +#define BIT_GET_R_WMAC_SECOND_CCA_TIMER_8822B(x) \ + (((x) >> BIT_SHIFT_R_WMAC_SECOND_CCA_TIMER_8822B) & \ + BIT_MASK_R_WMAC_SECOND_CCA_TIMER_8822B) + +#define BIT_SHIFT_RFMOD_8822B 7 +#define BIT_MASK_RFMOD_8822B 0x3 +#define BIT_RFMOD_8822B(x) \ + (((x) & BIT_MASK_RFMOD_8822B) << BIT_SHIFT_RFMOD_8822B) +#define BIT_GET_RFMOD_8822B(x) \ + (((x) >> BIT_SHIFT_RFMOD_8822B) & BIT_MASK_RFMOD_8822B) + +#define BIT_SHIFT_RESP_CTS_DYNBW_SEL_8822B 5 +#define BIT_MASK_RESP_CTS_DYNBW_SEL_8822B 0x3 +#define BIT_RESP_CTS_DYNBW_SEL_8822B(x) \ + (((x) & BIT_MASK_RESP_CTS_DYNBW_SEL_8822B) \ + << BIT_SHIFT_RESP_CTS_DYNBW_SEL_8822B) +#define BIT_GET_RESP_CTS_DYNBW_SEL_8822B(x) \ + (((x) >> BIT_SHIFT_RESP_CTS_DYNBW_SEL_8822B) & \ + BIT_MASK_RESP_CTS_DYNBW_SEL_8822B) + +#define BIT_DLY_TX_WAIT_RXANTSEL_8822B BIT(4) +#define BIT_TXRESP_BY_RXANTSEL_8822B BIT(3) + +#define BIT_SHIFT_ORIG_DCTS_CHK_8822B 0 +#define BIT_MASK_ORIG_DCTS_CHK_8822B 0x3 +#define BIT_ORIG_DCTS_CHK_8822B(x) \ + (((x) & BIT_MASK_ORIG_DCTS_CHK_8822B) << BIT_SHIFT_ORIG_DCTS_CHK_8822B) +#define BIT_GET_ORIG_DCTS_CHK_8822B(x) \ + (((x) >> BIT_SHIFT_ORIG_DCTS_CHK_8822B) & BIT_MASK_ORIG_DCTS_CHK_8822B) + +/* 2 REG_CAMCMD_8822B (CAM COMMAND REGISTER) */ +#define BIT_SECCAM_POLLING_8822B BIT(31) +#define BIT_SECCAM_CLR_8822B BIT(30) +#define BIT_MFBCAM_CLR_8822B BIT(29) +#define BIT_SECCAM_WE_8822B BIT(16) + +#define BIT_SHIFT_SECCAM_ADDR_V2_8822B 0 +#define BIT_MASK_SECCAM_ADDR_V2_8822B 0x3ff +#define BIT_SECCAM_ADDR_V2_8822B(x) \ + (((x) & BIT_MASK_SECCAM_ADDR_V2_8822B) \ + << BIT_SHIFT_SECCAM_ADDR_V2_8822B) +#define BIT_GET_SECCAM_ADDR_V2_8822B(x) \ + (((x) >> BIT_SHIFT_SECCAM_ADDR_V2_8822B) & \ + BIT_MASK_SECCAM_ADDR_V2_8822B) + +/* 2 REG_CAMWRITE_8822B (CAM WRITE REGISTER) */ + +#define BIT_SHIFT_CAMW_DATA_8822B 0 +#define BIT_MASK_CAMW_DATA_8822B 0xffffffffL +#define BIT_CAMW_DATA_8822B(x) \ + (((x) & BIT_MASK_CAMW_DATA_8822B) << BIT_SHIFT_CAMW_DATA_8822B) +#define BIT_GET_CAMW_DATA_8822B(x) \ + (((x) >> BIT_SHIFT_CAMW_DATA_8822B) & BIT_MASK_CAMW_DATA_8822B) + +/* 2 REG_CAMREAD_8822B (CAM READ REGISTER) */ + +#define BIT_SHIFT_CAMR_DATA_8822B 0 +#define BIT_MASK_CAMR_DATA_8822B 0xffffffffL +#define BIT_CAMR_DATA_8822B(x) \ + (((x) & BIT_MASK_CAMR_DATA_8822B) << BIT_SHIFT_CAMR_DATA_8822B) +#define BIT_GET_CAMR_DATA_8822B(x) \ + (((x) >> BIT_SHIFT_CAMR_DATA_8822B) & BIT_MASK_CAMR_DATA_8822B) + +/* 2 REG_CAMDBG_8822B (CAM DEBUG REGISTER) */ +#define BIT_SECCAM_INFO_8822B BIT(31) +#define BIT_SEC_KEYFOUND_8822B BIT(15) + +#define BIT_SHIFT_CAMDBG_SEC_TYPE_8822B 12 +#define BIT_MASK_CAMDBG_SEC_TYPE_8822B 0x7 +#define BIT_CAMDBG_SEC_TYPE_8822B(x) \ + (((x) & BIT_MASK_CAMDBG_SEC_TYPE_8822B) \ + << BIT_SHIFT_CAMDBG_SEC_TYPE_8822B) +#define BIT_GET_CAMDBG_SEC_TYPE_8822B(x) \ + (((x) >> BIT_SHIFT_CAMDBG_SEC_TYPE_8822B) & \ + BIT_MASK_CAMDBG_SEC_TYPE_8822B) + +#define BIT_CAMDBG_EXT_SECTYPE_8822B BIT(11) + +#define BIT_SHIFT_CAMDBG_MIC_KEY_IDX_8822B 5 +#define BIT_MASK_CAMDBG_MIC_KEY_IDX_8822B 0x1f +#define BIT_CAMDBG_MIC_KEY_IDX_8822B(x) \ + (((x) & BIT_MASK_CAMDBG_MIC_KEY_IDX_8822B) \ + << BIT_SHIFT_CAMDBG_MIC_KEY_IDX_8822B) +#define BIT_GET_CAMDBG_MIC_KEY_IDX_8822B(x) \ + (((x) >> BIT_SHIFT_CAMDBG_MIC_KEY_IDX_8822B) & \ + BIT_MASK_CAMDBG_MIC_KEY_IDX_8822B) + +#define BIT_SHIFT_CAMDBG_SEC_KEY_IDX_8822B 0 +#define BIT_MASK_CAMDBG_SEC_KEY_IDX_8822B 0x1f +#define BIT_CAMDBG_SEC_KEY_IDX_8822B(x) \ + (((x) & BIT_MASK_CAMDBG_SEC_KEY_IDX_8822B) \ + << BIT_SHIFT_CAMDBG_SEC_KEY_IDX_8822B) +#define BIT_GET_CAMDBG_SEC_KEY_IDX_8822B(x) \ + (((x) >> BIT_SHIFT_CAMDBG_SEC_KEY_IDX_8822B) & \ + BIT_MASK_CAMDBG_SEC_KEY_IDX_8822B) + +/* 2 REG_RXFILTER_ACTION_1_8822B */ + +#define BIT_SHIFT_RXFILTER_ACTION_1_8822B 0 +#define BIT_MASK_RXFILTER_ACTION_1_8822B 0xff +#define BIT_RXFILTER_ACTION_1_8822B(x) \ + (((x) & BIT_MASK_RXFILTER_ACTION_1_8822B) \ + << BIT_SHIFT_RXFILTER_ACTION_1_8822B) +#define BIT_GET_RXFILTER_ACTION_1_8822B(x) \ + (((x) >> BIT_SHIFT_RXFILTER_ACTION_1_8822B) & \ + BIT_MASK_RXFILTER_ACTION_1_8822B) + +/* 2 REG_RXFILTER_CATEGORY_1_8822B */ + +#define BIT_SHIFT_RXFILTER_CATEGORY_1_8822B 0 +#define BIT_MASK_RXFILTER_CATEGORY_1_8822B 0xff +#define BIT_RXFILTER_CATEGORY_1_8822B(x) \ + (((x) & BIT_MASK_RXFILTER_CATEGORY_1_8822B) \ + << BIT_SHIFT_RXFILTER_CATEGORY_1_8822B) +#define BIT_GET_RXFILTER_CATEGORY_1_8822B(x) \ + (((x) >> BIT_SHIFT_RXFILTER_CATEGORY_1_8822B) & \ + BIT_MASK_RXFILTER_CATEGORY_1_8822B) + +/* 2 REG_SECCFG_8822B (SECURITY CONFIGURATION REGISTER) */ +#define BIT_DIS_GCLK_WAPI_8822B BIT(15) +#define BIT_DIS_GCLK_AES_8822B BIT(14) +#define BIT_DIS_GCLK_TKIP_8822B BIT(13) +#define BIT_AES_SEL_QC_1_8822B BIT(12) +#define BIT_AES_SEL_QC_0_8822B BIT(11) +#define BIT_CHK_BMC_8822B BIT(9) +#define BIT_CHK_KEYID_8822B BIT(8) +#define BIT_RXBCUSEDK_8822B BIT(7) +#define BIT_TXBCUSEDK_8822B BIT(6) +#define BIT_NOSKMC_8822B BIT(5) +#define BIT_SKBYA2_8822B BIT(4) +#define BIT_RXDEC_8822B BIT(3) +#define BIT_TXENC_8822B BIT(2) +#define BIT_RXUHUSEDK_8822B BIT(1) +#define BIT_TXUHUSEDK_8822B BIT(0) + +/* 2 REG_RXFILTER_ACTION_3_8822B */ + +#define BIT_SHIFT_RXFILTER_ACTION_3_8822B 0 +#define BIT_MASK_RXFILTER_ACTION_3_8822B 0xff +#define BIT_RXFILTER_ACTION_3_8822B(x) \ + (((x) & BIT_MASK_RXFILTER_ACTION_3_8822B) \ + << BIT_SHIFT_RXFILTER_ACTION_3_8822B) +#define BIT_GET_RXFILTER_ACTION_3_8822B(x) \ + (((x) >> BIT_SHIFT_RXFILTER_ACTION_3_8822B) & \ + BIT_MASK_RXFILTER_ACTION_3_8822B) + +/* 2 REG_RXFILTER_CATEGORY_3_8822B */ + +#define BIT_SHIFT_RXFILTER_CATEGORY_3_8822B 0 +#define BIT_MASK_RXFILTER_CATEGORY_3_8822B 0xff +#define BIT_RXFILTER_CATEGORY_3_8822B(x) \ + (((x) & BIT_MASK_RXFILTER_CATEGORY_3_8822B) \ + << BIT_SHIFT_RXFILTER_CATEGORY_3_8822B) +#define BIT_GET_RXFILTER_CATEGORY_3_8822B(x) \ + (((x) >> BIT_SHIFT_RXFILTER_CATEGORY_3_8822B) & \ + BIT_MASK_RXFILTER_CATEGORY_3_8822B) + +/* 2 REG_RXFILTER_ACTION_2_8822B */ + +#define BIT_SHIFT_RXFILTER_ACTION_2_8822B 0 +#define BIT_MASK_RXFILTER_ACTION_2_8822B 0xff +#define BIT_RXFILTER_ACTION_2_8822B(x) \ + (((x) & BIT_MASK_RXFILTER_ACTION_2_8822B) \ + << BIT_SHIFT_RXFILTER_ACTION_2_8822B) +#define BIT_GET_RXFILTER_ACTION_2_8822B(x) \ + (((x) >> BIT_SHIFT_RXFILTER_ACTION_2_8822B) & \ + BIT_MASK_RXFILTER_ACTION_2_8822B) + +/* 2 REG_RXFILTER_CATEGORY_2_8822B */ + +#define BIT_SHIFT_RXFILTER_CATEGORY_2_8822B 0 +#define BIT_MASK_RXFILTER_CATEGORY_2_8822B 0xff +#define BIT_RXFILTER_CATEGORY_2_8822B(x) \ + (((x) & BIT_MASK_RXFILTER_CATEGORY_2_8822B) \ + << BIT_SHIFT_RXFILTER_CATEGORY_2_8822B) +#define BIT_GET_RXFILTER_CATEGORY_2_8822B(x) \ + (((x) >> BIT_SHIFT_RXFILTER_CATEGORY_2_8822B) & \ + BIT_MASK_RXFILTER_CATEGORY_2_8822B) + +/* 2 REG_RXFLTMAP4_8822B (RX FILTER MAP GROUP 4) */ +#define BIT_CTRLFLT15EN_FW_8822B BIT(15) +#define BIT_CTRLFLT14EN_FW_8822B BIT(14) +#define BIT_CTRLFLT13EN_FW_8822B BIT(13) +#define BIT_CTRLFLT12EN_FW_8822B BIT(12) +#define BIT_CTRLFLT11EN_FW_8822B BIT(11) +#define BIT_CTRLFLT10EN_FW_8822B BIT(10) +#define BIT_CTRLFLT9EN_FW_8822B BIT(9) +#define BIT_CTRLFLT8EN_FW_8822B BIT(8) +#define BIT_CTRLFLT7EN_FW_8822B BIT(7) +#define BIT_CTRLFLT6EN_FW_8822B BIT(6) +#define BIT_CTRLFLT5EN_FW_8822B BIT(5) +#define BIT_CTRLFLT4EN_FW_8822B BIT(4) +#define BIT_CTRLFLT3EN_FW_8822B BIT(3) +#define BIT_CTRLFLT2EN_FW_8822B BIT(2) +#define BIT_CTRLFLT1EN_FW_8822B BIT(1) +#define BIT_CTRLFLT0EN_FW_8822B BIT(0) + +/* 2 REG_RXFLTMAP3_8822B (RX FILTER MAP GROUP 3) */ +#define BIT_MGTFLT15EN_FW_8822B BIT(15) +#define BIT_MGTFLT14EN_FW_8822B BIT(14) +#define BIT_MGTFLT13EN_FW_8822B BIT(13) +#define BIT_MGTFLT12EN_FW_8822B BIT(12) +#define BIT_MGTFLT11EN_FW_8822B BIT(11) +#define BIT_MGTFLT10EN_FW_8822B BIT(10) +#define BIT_MGTFLT9EN_FW_8822B BIT(9) +#define BIT_MGTFLT8EN_FW_8822B BIT(8) +#define BIT_MGTFLT7EN_FW_8822B BIT(7) +#define BIT_MGTFLT6EN_FW_8822B BIT(6) +#define BIT_MGTFLT5EN_FW_8822B BIT(5) +#define BIT_MGTFLT4EN_FW_8822B BIT(4) +#define BIT_MGTFLT3EN_FW_8822B BIT(3) +#define BIT_MGTFLT2EN_FW_8822B BIT(2) +#define BIT_MGTFLT1EN_FW_8822B BIT(1) +#define BIT_MGTFLT0EN_FW_8822B BIT(0) + +/* 2 REG_RXFLTMAP6_8822B (RX FILTER MAP GROUP 3) */ +#define BIT_ACTIONFLT15EN_FW_8822B BIT(15) +#define BIT_ACTIONFLT14EN_FW_8822B BIT(14) +#define BIT_ACTIONFLT13EN_FW_8822B BIT(13) +#define BIT_ACTIONFLT12EN_FW_8822B BIT(12) +#define BIT_ACTIONFLT11EN_FW_8822B BIT(11) +#define BIT_ACTIONFLT10EN_FW_8822B BIT(10) +#define BIT_ACTIONFLT9EN_FW_8822B BIT(9) +#define BIT_ACTIONFLT8EN_FW_8822B BIT(8) +#define BIT_ACTIONFLT7EN_FW_8822B BIT(7) +#define BIT_ACTIONFLT6EN_FW_8822B BIT(6) +#define BIT_ACTIONFLT5EN_FW_8822B BIT(5) +#define BIT_ACTIONFLT4EN_FW_8822B BIT(4) +#define BIT_ACTIONFLT3EN_FW_8822B BIT(3) +#define BIT_ACTIONFLT2EN_FW_8822B BIT(2) +#define BIT_ACTIONFLT1EN_FW_8822B BIT(1) +#define BIT_ACTIONFLT0EN_FW_8822B BIT(0) + +/* 2 REG_RXFLTMAP5_8822B (RX FILTER MAP GROUP 3) */ +#define BIT_DATAFLT15EN_FW_8822B BIT(15) +#define BIT_DATAFLT14EN_FW_8822B BIT(14) +#define BIT_DATAFLT13EN_FW_8822B BIT(13) +#define BIT_DATAFLT12EN_FW_8822B BIT(12) +#define BIT_DATAFLT11EN_FW_8822B BIT(11) +#define BIT_DATAFLT10EN_FW_8822B BIT(10) +#define BIT_DATAFLT9EN_FW_8822B BIT(9) +#define BIT_DATAFLT8EN_FW_8822B BIT(8) +#define BIT_DATAFLT7EN_FW_8822B BIT(7) +#define BIT_DATAFLT6EN_FW_8822B BIT(6) +#define BIT_DATAFLT5EN_FW_8822B BIT(5) +#define BIT_DATAFLT4EN_FW_8822B BIT(4) +#define BIT_DATAFLT3EN_FW_8822B BIT(3) +#define BIT_DATAFLT2EN_FW_8822B BIT(2) +#define BIT_DATAFLT1EN_FW_8822B BIT(1) +#define BIT_DATAFLT0EN_FW_8822B BIT(0) + +/* 2 REG_WMMPS_UAPSD_TID_8822B (WMM POWER SAVE UAPSD TID REGISTER) */ +#define BIT_WMMPS_UAPSD_TID7_8822B BIT(7) +#define BIT_WMMPS_UAPSD_TID6_8822B BIT(6) +#define BIT_WMMPS_UAPSD_TID5_8822B BIT(5) +#define BIT_WMMPS_UAPSD_TID4_8822B BIT(4) +#define BIT_WMMPS_UAPSD_TID3_8822B BIT(3) +#define BIT_WMMPS_UAPSD_TID2_8822B BIT(2) +#define BIT_WMMPS_UAPSD_TID1_8822B BIT(1) +#define BIT_WMMPS_UAPSD_TID0_8822B BIT(0) + +/* 2 REG_PS_RX_INFO_8822B (POWER SAVE RX INFORMATION REGISTER) */ + +#define BIT_SHIFT_PORTSEL__PS_RX_INFO_8822B 5 +#define BIT_MASK_PORTSEL__PS_RX_INFO_8822B 0x7 +#define BIT_PORTSEL__PS_RX_INFO_8822B(x) \ + (((x) & BIT_MASK_PORTSEL__PS_RX_INFO_8822B) \ + << BIT_SHIFT_PORTSEL__PS_RX_INFO_8822B) +#define BIT_GET_PORTSEL__PS_RX_INFO_8822B(x) \ + (((x) >> BIT_SHIFT_PORTSEL__PS_RX_INFO_8822B) & \ + BIT_MASK_PORTSEL__PS_RX_INFO_8822B) + +#define BIT_RXCTRLIN0_8822B BIT(4) +#define BIT_RXMGTIN0_8822B BIT(3) +#define BIT_RXDATAIN2_8822B BIT(2) +#define BIT_RXDATAIN1_8822B BIT(1) +#define BIT_RXDATAIN0_8822B BIT(0) + +/* 2 REG_NAN_RX_TSF_FILTER_8822B(NAN_RX_TSF_ADDRESS_FILTER) */ +#define BIT_CHK_TSF_TA_8822B BIT(2) +#define BIT_CHK_TSF_CBSSID_8822B BIT(1) +#define BIT_CHK_TSF_EN_8822B BIT(0) + +/* 2 REG_WOW_CTRL_8822B (WAKE ON WLAN CONTROL REGISTER) */ + +#define BIT_SHIFT_PSF_BSSIDSEL_B2B1_8822B 6 +#define BIT_MASK_PSF_BSSIDSEL_B2B1_8822B 0x3 +#define BIT_PSF_BSSIDSEL_B2B1_8822B(x) \ + (((x) & BIT_MASK_PSF_BSSIDSEL_B2B1_8822B) \ + << BIT_SHIFT_PSF_BSSIDSEL_B2B1_8822B) +#define BIT_GET_PSF_BSSIDSEL_B2B1_8822B(x) \ + (((x) >> BIT_SHIFT_PSF_BSSIDSEL_B2B1_8822B) & \ + BIT_MASK_PSF_BSSIDSEL_B2B1_8822B) + +#define BIT_WOWHCI_8822B BIT(5) +#define BIT_PSF_BSSIDSEL_B0_8822B BIT(4) +#define BIT_UWF_8822B BIT(3) +#define BIT_MAGIC_8822B BIT(2) +#define BIT_WOWEN_8822B BIT(1) +#define BIT_FORCE_WAKEUP_8822B BIT(0) + +/* 2 REG_LPNAV_CTRL_8822B (LOW POWER NAV CONTROL REGISTER) */ +#define BIT_LPNAV_EN_8822B BIT(31) + +#define BIT_SHIFT_LPNAV_EARLY_8822B 16 +#define BIT_MASK_LPNAV_EARLY_8822B 0x7fff +#define BIT_LPNAV_EARLY_8822B(x) \ + (((x) & BIT_MASK_LPNAV_EARLY_8822B) << BIT_SHIFT_LPNAV_EARLY_8822B) +#define BIT_GET_LPNAV_EARLY_8822B(x) \ + (((x) >> BIT_SHIFT_LPNAV_EARLY_8822B) & BIT_MASK_LPNAV_EARLY_8822B) + +#define BIT_SHIFT_LPNAV_TH_8822B 0 +#define BIT_MASK_LPNAV_TH_8822B 0xffff +#define BIT_LPNAV_TH_8822B(x) \ + (((x) & BIT_MASK_LPNAV_TH_8822B) << BIT_SHIFT_LPNAV_TH_8822B) +#define BIT_GET_LPNAV_TH_8822B(x) \ + (((x) >> BIT_SHIFT_LPNAV_TH_8822B) & BIT_MASK_LPNAV_TH_8822B) + +/* 2 REG_WKFMCAM_CMD_8822B (WAKEUP FRAME CAM COMMAND REGISTER) */ +#define BIT_WKFCAM_POLLING_V1_8822B BIT(31) +#define BIT_WKFCAM_CLR_V1_8822B BIT(30) +#define BIT_WKFCAM_WE_8822B BIT(16) + +#define BIT_SHIFT_WKFCAM_ADDR_V2_8822B 8 +#define BIT_MASK_WKFCAM_ADDR_V2_8822B 0xff +#define BIT_WKFCAM_ADDR_V2_8822B(x) \ + (((x) & BIT_MASK_WKFCAM_ADDR_V2_8822B) \ + << BIT_SHIFT_WKFCAM_ADDR_V2_8822B) +#define BIT_GET_WKFCAM_ADDR_V2_8822B(x) \ + (((x) >> BIT_SHIFT_WKFCAM_ADDR_V2_8822B) & \ + BIT_MASK_WKFCAM_ADDR_V2_8822B) + +#define BIT_SHIFT_WKFCAM_CAM_NUM_V1_8822B 0 +#define BIT_MASK_WKFCAM_CAM_NUM_V1_8822B 0xff +#define BIT_WKFCAM_CAM_NUM_V1_8822B(x) \ + (((x) & BIT_MASK_WKFCAM_CAM_NUM_V1_8822B) \ + << BIT_SHIFT_WKFCAM_CAM_NUM_V1_8822B) +#define BIT_GET_WKFCAM_CAM_NUM_V1_8822B(x) \ + (((x) >> BIT_SHIFT_WKFCAM_CAM_NUM_V1_8822B) & \ + BIT_MASK_WKFCAM_CAM_NUM_V1_8822B) + +/* 2 REG_WKFMCAM_RWD_8822B (WAKEUP FRAME READ/WRITE DATA) */ + +#define BIT_SHIFT_WKFMCAM_RWD_8822B 0 +#define BIT_MASK_WKFMCAM_RWD_8822B 0xffffffffL +#define BIT_WKFMCAM_RWD_8822B(x) \ + (((x) & BIT_MASK_WKFMCAM_RWD_8822B) << BIT_SHIFT_WKFMCAM_RWD_8822B) +#define BIT_GET_WKFMCAM_RWD_8822B(x) \ + (((x) >> BIT_SHIFT_WKFMCAM_RWD_8822B) & BIT_MASK_WKFMCAM_RWD_8822B) + +/* 2 REG_RXFLTMAP1_8822B (RX FILTER MAP GROUP 1) */ +#define BIT_CTRLFLT15EN_8822B BIT(15) +#define BIT_CTRLFLT14EN_8822B BIT(14) +#define BIT_CTRLFLT13EN_8822B BIT(13) +#define BIT_CTRLFLT12EN_8822B BIT(12) +#define BIT_CTRLFLT11EN_8822B BIT(11) +#define BIT_CTRLFLT10EN_8822B BIT(10) +#define BIT_CTRLFLT9EN_8822B BIT(9) +#define BIT_CTRLFLT8EN_8822B BIT(8) +#define BIT_CTRLFLT7EN_8822B BIT(7) +#define BIT_CTRLFLT6EN_8822B BIT(6) +#define BIT_CTRLFLT5EN_8822B BIT(5) +#define BIT_CTRLFLT4EN_8822B BIT(4) +#define BIT_CTRLFLT3EN_8822B BIT(3) +#define BIT_CTRLFLT2EN_8822B BIT(2) +#define BIT_CTRLFLT1EN_8822B BIT(1) +#define BIT_CTRLFLT0EN_8822B BIT(0) + +/* 2 REG_RXFLTMAP0_8822B (RX FILTER MAP GROUP 0) */ +#define BIT_MGTFLT15EN_8822B BIT(15) +#define BIT_MGTFLT14EN_8822B BIT(14) +#define BIT_MGTFLT13EN_8822B BIT(13) +#define BIT_MGTFLT12EN_8822B BIT(12) +#define BIT_MGTFLT11EN_8822B BIT(11) +#define BIT_MGTFLT10EN_8822B BIT(10) +#define BIT_MGTFLT9EN_8822B BIT(9) +#define BIT_MGTFLT8EN_8822B BIT(8) +#define BIT_MGTFLT7EN_8822B BIT(7) +#define BIT_MGTFLT6EN_8822B BIT(6) +#define BIT_MGTFLT5EN_8822B BIT(5) +#define BIT_MGTFLT4EN_8822B BIT(4) +#define BIT_MGTFLT3EN_8822B BIT(3) +#define BIT_MGTFLT2EN_8822B BIT(2) +#define BIT_MGTFLT1EN_8822B BIT(1) +#define BIT_MGTFLT0EN_8822B BIT(0) + +/* 2 REG_NOT_VALID_8822B */ + +/* 2 REG_RXFLTMAP_8822B (RX FILTER MAP GROUP 2) */ +#define BIT_DATAFLT15EN_8822B BIT(15) +#define BIT_DATAFLT14EN_8822B BIT(14) +#define BIT_DATAFLT13EN_8822B BIT(13) +#define BIT_DATAFLT12EN_8822B BIT(12) +#define BIT_DATAFLT11EN_8822B BIT(11) +#define BIT_DATAFLT10EN_8822B BIT(10) +#define BIT_DATAFLT9EN_8822B BIT(9) +#define BIT_DATAFLT8EN_8822B BIT(8) +#define BIT_DATAFLT7EN_8822B BIT(7) +#define BIT_DATAFLT6EN_8822B BIT(6) +#define BIT_DATAFLT5EN_8822B BIT(5) +#define BIT_DATAFLT4EN_8822B BIT(4) +#define BIT_DATAFLT3EN_8822B BIT(3) +#define BIT_DATAFLT2EN_8822B BIT(2) +#define BIT_DATAFLT1EN_8822B BIT(1) +#define BIT_DATAFLT0EN_8822B BIT(0) + +/* 2 REG_BCN_PSR_RPT_8822B (BEACON PARSER REPORT REGISTER) */ + +#define BIT_SHIFT_DTIM_CNT_8822B 24 +#define BIT_MASK_DTIM_CNT_8822B 0xff +#define BIT_DTIM_CNT_8822B(x) \ + (((x) & BIT_MASK_DTIM_CNT_8822B) << BIT_SHIFT_DTIM_CNT_8822B) +#define BIT_GET_DTIM_CNT_8822B(x) \ + (((x) >> BIT_SHIFT_DTIM_CNT_8822B) & BIT_MASK_DTIM_CNT_8822B) + +#define BIT_SHIFT_DTIM_PERIOD_8822B 16 +#define BIT_MASK_DTIM_PERIOD_8822B 0xff +#define BIT_DTIM_PERIOD_8822B(x) \ + (((x) & BIT_MASK_DTIM_PERIOD_8822B) << BIT_SHIFT_DTIM_PERIOD_8822B) +#define BIT_GET_DTIM_PERIOD_8822B(x) \ + (((x) >> BIT_SHIFT_DTIM_PERIOD_8822B) & BIT_MASK_DTIM_PERIOD_8822B) + +#define BIT_DTIM_8822B BIT(15) +#define BIT_TIM_8822B BIT(14) + +#define BIT_SHIFT_PS_AID_0_8822B 0 +#define BIT_MASK_PS_AID_0_8822B 0x7ff +#define BIT_PS_AID_0_8822B(x) \ + (((x) & BIT_MASK_PS_AID_0_8822B) << BIT_SHIFT_PS_AID_0_8822B) +#define BIT_GET_PS_AID_0_8822B(x) \ + (((x) >> BIT_SHIFT_PS_AID_0_8822B) & BIT_MASK_PS_AID_0_8822B) + +/* 2 REG_FLC_TRPC_8822B (TIMER OF FLC_RPC) */ +#define BIT_FLC_RPCT_V1_8822B BIT(7) +#define BIT_MODE_8822B BIT(6) + +#define BIT_SHIFT_TRPCD_8822B 0 +#define BIT_MASK_TRPCD_8822B 0x3f +#define BIT_TRPCD_8822B(x) \ + (((x) & BIT_MASK_TRPCD_8822B) << BIT_SHIFT_TRPCD_8822B) +#define BIT_GET_TRPCD_8822B(x) \ + (((x) >> BIT_SHIFT_TRPCD_8822B) & BIT_MASK_TRPCD_8822B) + +/* 2 REG_FLC_PTS_8822B (PKT TYPE SELECTION OF FLC_RPC T) */ +#define BIT_CMF_8822B BIT(2) +#define BIT_CCF_8822B BIT(1) +#define BIT_CDF_8822B BIT(0) + +/* 2 REG_FLC_RPCT_8822B (FLC_RPC THRESHOLD) */ + +#define BIT_SHIFT_FLC_RPCT_8822B 0 +#define BIT_MASK_FLC_RPCT_8822B 0xff +#define BIT_FLC_RPCT_8822B(x) \ + (((x) & BIT_MASK_FLC_RPCT_8822B) << BIT_SHIFT_FLC_RPCT_8822B) +#define BIT_GET_FLC_RPCT_8822B(x) \ + (((x) >> BIT_SHIFT_FLC_RPCT_8822B) & BIT_MASK_FLC_RPCT_8822B) + +/* 2 REG_FLC_RPC_8822B (FW LPS CONDITION -- RX PKT COUNTER) */ + +#define BIT_SHIFT_FLC_RPC_8822B 0 +#define BIT_MASK_FLC_RPC_8822B 0xff +#define BIT_FLC_RPC_8822B(x) \ + (((x) & BIT_MASK_FLC_RPC_8822B) << BIT_SHIFT_FLC_RPC_8822B) +#define BIT_GET_FLC_RPC_8822B(x) \ + (((x) >> BIT_SHIFT_FLC_RPC_8822B) & BIT_MASK_FLC_RPC_8822B) + +/* 2 REG_RXPKTMON_CTRL_8822B */ + +#define BIT_SHIFT_RXBKQPKT_SEQ_8822B 20 +#define BIT_MASK_RXBKQPKT_SEQ_8822B 0xf +#define BIT_RXBKQPKT_SEQ_8822B(x) \ + (((x) & BIT_MASK_RXBKQPKT_SEQ_8822B) << BIT_SHIFT_RXBKQPKT_SEQ_8822B) +#define BIT_GET_RXBKQPKT_SEQ_8822B(x) \ + (((x) >> BIT_SHIFT_RXBKQPKT_SEQ_8822B) & BIT_MASK_RXBKQPKT_SEQ_8822B) + +#define BIT_SHIFT_RXBEQPKT_SEQ_8822B 16 +#define BIT_MASK_RXBEQPKT_SEQ_8822B 0xf +#define BIT_RXBEQPKT_SEQ_8822B(x) \ + (((x) & BIT_MASK_RXBEQPKT_SEQ_8822B) << BIT_SHIFT_RXBEQPKT_SEQ_8822B) +#define BIT_GET_RXBEQPKT_SEQ_8822B(x) \ + (((x) >> BIT_SHIFT_RXBEQPKT_SEQ_8822B) & BIT_MASK_RXBEQPKT_SEQ_8822B) + +#define BIT_SHIFT_RXVIQPKT_SEQ_8822B 12 +#define BIT_MASK_RXVIQPKT_SEQ_8822B 0xf +#define BIT_RXVIQPKT_SEQ_8822B(x) \ + (((x) & BIT_MASK_RXVIQPKT_SEQ_8822B) << BIT_SHIFT_RXVIQPKT_SEQ_8822B) +#define BIT_GET_RXVIQPKT_SEQ_8822B(x) \ + (((x) >> BIT_SHIFT_RXVIQPKT_SEQ_8822B) & BIT_MASK_RXVIQPKT_SEQ_8822B) + +#define BIT_SHIFT_RXVOQPKT_SEQ_8822B 8 +#define BIT_MASK_RXVOQPKT_SEQ_8822B 0xf +#define BIT_RXVOQPKT_SEQ_8822B(x) \ + (((x) & BIT_MASK_RXVOQPKT_SEQ_8822B) << BIT_SHIFT_RXVOQPKT_SEQ_8822B) +#define BIT_GET_RXVOQPKT_SEQ_8822B(x) \ + (((x) >> BIT_SHIFT_RXVOQPKT_SEQ_8822B) & BIT_MASK_RXVOQPKT_SEQ_8822B) + +#define BIT_RXBKQPKT_ERR_8822B BIT(7) +#define BIT_RXBEQPKT_ERR_8822B BIT(6) +#define BIT_RXVIQPKT_ERR_8822B BIT(5) +#define BIT_RXVOQPKT_ERR_8822B BIT(4) +#define BIT_RXDMA_MON_EN_8822B BIT(2) +#define BIT_RXPKT_MON_RST_8822B BIT(1) +#define BIT_RXPKT_MON_EN_8822B BIT(0) + +/* 2 REG_STATE_MON_8822B */ + +#define BIT_SHIFT_STATE_SEL_8822B 24 +#define BIT_MASK_STATE_SEL_8822B 0x1f +#define BIT_STATE_SEL_8822B(x) \ + (((x) & BIT_MASK_STATE_SEL_8822B) << BIT_SHIFT_STATE_SEL_8822B) +#define BIT_GET_STATE_SEL_8822B(x) \ + (((x) >> BIT_SHIFT_STATE_SEL_8822B) & BIT_MASK_STATE_SEL_8822B) + +#define BIT_SHIFT_STATE_INFO_8822B 8 +#define BIT_MASK_STATE_INFO_8822B 0xff +#define BIT_STATE_INFO_8822B(x) \ + (((x) & BIT_MASK_STATE_INFO_8822B) << BIT_SHIFT_STATE_INFO_8822B) +#define BIT_GET_STATE_INFO_8822B(x) \ + (((x) >> BIT_SHIFT_STATE_INFO_8822B) & BIT_MASK_STATE_INFO_8822B) + +#define BIT_UPD_NXT_STATE_8822B BIT(7) + +#define BIT_SHIFT_CUR_STATE_8822B 0 +#define BIT_MASK_CUR_STATE_8822B 0x7f +#define BIT_CUR_STATE_8822B(x) \ + (((x) & BIT_MASK_CUR_STATE_8822B) << BIT_SHIFT_CUR_STATE_8822B) +#define BIT_GET_CUR_STATE_8822B(x) \ + (((x) >> BIT_SHIFT_CUR_STATE_8822B) & BIT_MASK_CUR_STATE_8822B) + +/* 2 REG_ERROR_MON_8822B */ +#define BIT_MACRX_ERR_1_8822B BIT(17) +#define BIT_MACRX_ERR_0_8822B BIT(16) +#define BIT_MACTX_ERR_3_8822B BIT(3) +#define BIT_MACTX_ERR_2_8822B BIT(2) +#define BIT_MACTX_ERR_1_8822B BIT(1) +#define BIT_MACTX_ERR_0_8822B BIT(0) + +/* 2 REG_SEARCH_MACID_8822B */ +#define BIT_EN_TXRPTBUF_CLK_8822B BIT(31) + +#define BIT_SHIFT_INFO_INDEX_OFFSET_8822B 16 +#define BIT_MASK_INFO_INDEX_OFFSET_8822B 0x1fff +#define BIT_INFO_INDEX_OFFSET_8822B(x) \ + (((x) & BIT_MASK_INFO_INDEX_OFFSET_8822B) \ + << BIT_SHIFT_INFO_INDEX_OFFSET_8822B) +#define BIT_GET_INFO_INDEX_OFFSET_8822B(x) \ + (((x) >> BIT_SHIFT_INFO_INDEX_OFFSET_8822B) & \ + BIT_MASK_INFO_INDEX_OFFSET_8822B) + +#define BIT_WMAC_SRCH_FIFOFULL_8822B BIT(15) +#define BIT_DIS_INFOSRCH_8822B BIT(14) +#define BIT_DISABLE_B0_8822B BIT(13) + +#define BIT_SHIFT_INFO_ADDR_OFFSET_8822B 0 +#define BIT_MASK_INFO_ADDR_OFFSET_8822B 0x1fff +#define BIT_INFO_ADDR_OFFSET_8822B(x) \ + (((x) & BIT_MASK_INFO_ADDR_OFFSET_8822B) \ + << BIT_SHIFT_INFO_ADDR_OFFSET_8822B) +#define BIT_GET_INFO_ADDR_OFFSET_8822B(x) \ + (((x) >> BIT_SHIFT_INFO_ADDR_OFFSET_8822B) & \ + BIT_MASK_INFO_ADDR_OFFSET_8822B) + +/* 2 REG_BT_COEX_TABLE_8822B (BT-COEXISTENCE CONTROL REGISTER) */ +#define BIT_PRI_MASK_RX_RESP_8822B BIT(126) +#define BIT_PRI_MASK_RXOFDM_8822B BIT(125) +#define BIT_PRI_MASK_RXCCK_8822B BIT(124) + +#define BIT_SHIFT_PRI_MASK_TXAC_8822B (117 & CPU_OPT_WIDTH) +#define BIT_MASK_PRI_MASK_TXAC_8822B 0x7f +#define BIT_PRI_MASK_TXAC_8822B(x) \ + (((x) & BIT_MASK_PRI_MASK_TXAC_8822B) << BIT_SHIFT_PRI_MASK_TXAC_8822B) +#define BIT_GET_PRI_MASK_TXAC_8822B(x) \ + (((x) >> BIT_SHIFT_PRI_MASK_TXAC_8822B) & BIT_MASK_PRI_MASK_TXAC_8822B) + +#define BIT_SHIFT_PRI_MASK_NAV_8822B (109 & CPU_OPT_WIDTH) +#define BIT_MASK_PRI_MASK_NAV_8822B 0xff +#define BIT_PRI_MASK_NAV_8822B(x) \ + (((x) & BIT_MASK_PRI_MASK_NAV_8822B) << BIT_SHIFT_PRI_MASK_NAV_8822B) +#define BIT_GET_PRI_MASK_NAV_8822B(x) \ + (((x) >> BIT_SHIFT_PRI_MASK_NAV_8822B) & BIT_MASK_PRI_MASK_NAV_8822B) + +#define BIT_PRI_MASK_CCK_8822B BIT(108) +#define BIT_PRI_MASK_OFDM_8822B BIT(107) +#define BIT_PRI_MASK_RTY_8822B BIT(106) + +#define BIT_SHIFT_PRI_MASK_NUM_8822B (102 & CPU_OPT_WIDTH) +#define BIT_MASK_PRI_MASK_NUM_8822B 0xf +#define BIT_PRI_MASK_NUM_8822B(x) \ + (((x) & BIT_MASK_PRI_MASK_NUM_8822B) << BIT_SHIFT_PRI_MASK_NUM_8822B) +#define BIT_GET_PRI_MASK_NUM_8822B(x) \ + (((x) >> BIT_SHIFT_PRI_MASK_NUM_8822B) & BIT_MASK_PRI_MASK_NUM_8822B) + +#define BIT_SHIFT_PRI_MASK_TYPE_8822B (98 & CPU_OPT_WIDTH) +#define BIT_MASK_PRI_MASK_TYPE_8822B 0xf +#define BIT_PRI_MASK_TYPE_8822B(x) \ + (((x) & BIT_MASK_PRI_MASK_TYPE_8822B) << BIT_SHIFT_PRI_MASK_TYPE_8822B) +#define BIT_GET_PRI_MASK_TYPE_8822B(x) \ + (((x) >> BIT_SHIFT_PRI_MASK_TYPE_8822B) & BIT_MASK_PRI_MASK_TYPE_8822B) + +#define BIT_OOB_8822B BIT(97) +#define BIT_ANT_SEL_8822B BIT(96) + +#define BIT_SHIFT_BREAK_TABLE_2_8822B (80 & CPU_OPT_WIDTH) +#define BIT_MASK_BREAK_TABLE_2_8822B 0xffff +#define BIT_BREAK_TABLE_2_8822B(x) \ + (((x) & BIT_MASK_BREAK_TABLE_2_8822B) << BIT_SHIFT_BREAK_TABLE_2_8822B) +#define BIT_GET_BREAK_TABLE_2_8822B(x) \ + (((x) >> BIT_SHIFT_BREAK_TABLE_2_8822B) & BIT_MASK_BREAK_TABLE_2_8822B) + +#define BIT_SHIFT_BREAK_TABLE_1_8822B (64 & CPU_OPT_WIDTH) +#define BIT_MASK_BREAK_TABLE_1_8822B 0xffff +#define BIT_BREAK_TABLE_1_8822B(x) \ + (((x) & BIT_MASK_BREAK_TABLE_1_8822B) << BIT_SHIFT_BREAK_TABLE_1_8822B) +#define BIT_GET_BREAK_TABLE_1_8822B(x) \ + (((x) >> BIT_SHIFT_BREAK_TABLE_1_8822B) & BIT_MASK_BREAK_TABLE_1_8822B) + +#define BIT_SHIFT_COEX_TABLE_2_8822B (32 & CPU_OPT_WIDTH) +#define BIT_MASK_COEX_TABLE_2_8822B 0xffffffffL +#define BIT_COEX_TABLE_2_8822B(x) \ + (((x) & BIT_MASK_COEX_TABLE_2_8822B) << BIT_SHIFT_COEX_TABLE_2_8822B) +#define BIT_GET_COEX_TABLE_2_8822B(x) \ + (((x) >> BIT_SHIFT_COEX_TABLE_2_8822B) & BIT_MASK_COEX_TABLE_2_8822B) + +#define BIT_SHIFT_COEX_TABLE_1_8822B 0 +#define BIT_MASK_COEX_TABLE_1_8822B 0xffffffffL +#define BIT_COEX_TABLE_1_8822B(x) \ + (((x) & BIT_MASK_COEX_TABLE_1_8822B) << BIT_SHIFT_COEX_TABLE_1_8822B) +#define BIT_GET_COEX_TABLE_1_8822B(x) \ + (((x) >> BIT_SHIFT_COEX_TABLE_1_8822B) & BIT_MASK_COEX_TABLE_1_8822B) + +/* 2 REG_RXCMD_0_8822B */ +#define BIT_RXCMD_EN_8822B BIT(31) + +#define BIT_SHIFT_RXCMD_INFO_8822B 0 +#define BIT_MASK_RXCMD_INFO_8822B 0x7fffffffL +#define BIT_RXCMD_INFO_8822B(x) \ + (((x) & BIT_MASK_RXCMD_INFO_8822B) << BIT_SHIFT_RXCMD_INFO_8822B) +#define BIT_GET_RXCMD_INFO_8822B(x) \ + (((x) >> BIT_SHIFT_RXCMD_INFO_8822B) & BIT_MASK_RXCMD_INFO_8822B) + +/* 2 REG_RXCMD_1_8822B */ + +#define BIT_SHIFT_RXCMD_PRD_8822B 0 +#define BIT_MASK_RXCMD_PRD_8822B 0xffff +#define BIT_RXCMD_PRD_8822B(x) \ + (((x) & BIT_MASK_RXCMD_PRD_8822B) << BIT_SHIFT_RXCMD_PRD_8822B) +#define BIT_GET_RXCMD_PRD_8822B(x) \ + (((x) >> BIT_SHIFT_RXCMD_PRD_8822B) & BIT_MASK_RXCMD_PRD_8822B) + +/* 2 REG_NOT_VALID_8822B */ + +/* 2 REG_WMAC_RESP_TXINFO_8822B (RESPONSE TXINFO REGISTER) */ + +#define BIT_SHIFT_WMAC_RESP_MFB_8822B 25 +#define BIT_MASK_WMAC_RESP_MFB_8822B 0x7f +#define BIT_WMAC_RESP_MFB_8822B(x) \ + (((x) & BIT_MASK_WMAC_RESP_MFB_8822B) << BIT_SHIFT_WMAC_RESP_MFB_8822B) +#define BIT_GET_WMAC_RESP_MFB_8822B(x) \ + (((x) >> BIT_SHIFT_WMAC_RESP_MFB_8822B) & BIT_MASK_WMAC_RESP_MFB_8822B) + +#define BIT_SHIFT_WMAC_ANTINF_SEL_8822B 23 +#define BIT_MASK_WMAC_ANTINF_SEL_8822B 0x3 +#define BIT_WMAC_ANTINF_SEL_8822B(x) \ + (((x) & BIT_MASK_WMAC_ANTINF_SEL_8822B) \ + << BIT_SHIFT_WMAC_ANTINF_SEL_8822B) +#define BIT_GET_WMAC_ANTINF_SEL_8822B(x) \ + (((x) >> BIT_SHIFT_WMAC_ANTINF_SEL_8822B) & \ + BIT_MASK_WMAC_ANTINF_SEL_8822B) + +#define BIT_SHIFT_WMAC_ANTSEL_SEL_8822B 21 +#define BIT_MASK_WMAC_ANTSEL_SEL_8822B 0x3 +#define BIT_WMAC_ANTSEL_SEL_8822B(x) \ + (((x) & BIT_MASK_WMAC_ANTSEL_SEL_8822B) \ + << BIT_SHIFT_WMAC_ANTSEL_SEL_8822B) +#define BIT_GET_WMAC_ANTSEL_SEL_8822B(x) \ + (((x) >> BIT_SHIFT_WMAC_ANTSEL_SEL_8822B) & \ + BIT_MASK_WMAC_ANTSEL_SEL_8822B) + +#define BIT_SHIFT_R_WMAC_RESP_TXPOWER_8822B 18 +#define BIT_MASK_R_WMAC_RESP_TXPOWER_8822B 0x7 +#define BIT_R_WMAC_RESP_TXPOWER_8822B(x) \ + (((x) & BIT_MASK_R_WMAC_RESP_TXPOWER_8822B) \ + << BIT_SHIFT_R_WMAC_RESP_TXPOWER_8822B) +#define BIT_GET_R_WMAC_RESP_TXPOWER_8822B(x) \ + (((x) >> BIT_SHIFT_R_WMAC_RESP_TXPOWER_8822B) & \ + BIT_MASK_R_WMAC_RESP_TXPOWER_8822B) + +#define BIT_SHIFT_WMAC_RESP_TXANT_8822B 0 +#define BIT_MASK_WMAC_RESP_TXANT_8822B 0x3ffff +#define BIT_WMAC_RESP_TXANT_8822B(x) \ + (((x) & BIT_MASK_WMAC_RESP_TXANT_8822B) \ + << BIT_SHIFT_WMAC_RESP_TXANT_8822B) +#define BIT_GET_WMAC_RESP_TXANT_8822B(x) \ + (((x) >> BIT_SHIFT_WMAC_RESP_TXANT_8822B) & \ + BIT_MASK_WMAC_RESP_TXANT_8822B) + +/* 2 REG_BBPSF_CTRL_8822B */ +#define BIT_CTL_IDLE_CLR_CSI_RPT_8822B BIT(31) +#define BIT_WMAC_USE_NDPARATE_8822B BIT(30) + +#define BIT_SHIFT_WMAC_CSI_RATE_8822B 24 +#define BIT_MASK_WMAC_CSI_RATE_8822B 0x3f +#define BIT_WMAC_CSI_RATE_8822B(x) \ + (((x) & BIT_MASK_WMAC_CSI_RATE_8822B) << BIT_SHIFT_WMAC_CSI_RATE_8822B) +#define BIT_GET_WMAC_CSI_RATE_8822B(x) \ + (((x) >> BIT_SHIFT_WMAC_CSI_RATE_8822B) & BIT_MASK_WMAC_CSI_RATE_8822B) + +#define BIT_SHIFT_WMAC_RESP_TXRATE_8822B 16 +#define BIT_MASK_WMAC_RESP_TXRATE_8822B 0xff +#define BIT_WMAC_RESP_TXRATE_8822B(x) \ + (((x) & BIT_MASK_WMAC_RESP_TXRATE_8822B) \ + << BIT_SHIFT_WMAC_RESP_TXRATE_8822B) +#define BIT_GET_WMAC_RESP_TXRATE_8822B(x) \ + (((x) >> BIT_SHIFT_WMAC_RESP_TXRATE_8822B) & \ + BIT_MASK_WMAC_RESP_TXRATE_8822B) + +#define BIT_BBPSF_MPDUCHKEN_8822B BIT(5) +#define BIT_BBPSF_MHCHKEN_8822B BIT(4) +#define BIT_BBPSF_ERRCHKEN_8822B BIT(3) + +#define BIT_SHIFT_BBPSF_ERRTHR_8822B 0 +#define BIT_MASK_BBPSF_ERRTHR_8822B 0x7 +#define BIT_BBPSF_ERRTHR_8822B(x) \ + (((x) & BIT_MASK_BBPSF_ERRTHR_8822B) << BIT_SHIFT_BBPSF_ERRTHR_8822B) +#define BIT_GET_BBPSF_ERRTHR_8822B(x) \ + (((x) >> BIT_SHIFT_BBPSF_ERRTHR_8822B) & BIT_MASK_BBPSF_ERRTHR_8822B) + +/* 2 REG_NOT_VALID_8822B */ + +/* 2 REG_P2P_RX_BCN_NOA_8822B (P2P RX BEACON NOA REGISTER) */ +#define BIT_NOA_PARSER_EN_8822B BIT(15) +#define BIT_BSSID_SEL_8822B BIT(14) + +#define BIT_SHIFT_P2P_OUI_TYPE_8822B 0 +#define BIT_MASK_P2P_OUI_TYPE_8822B 0xff +#define BIT_P2P_OUI_TYPE_8822B(x) \ + (((x) & BIT_MASK_P2P_OUI_TYPE_8822B) << BIT_SHIFT_P2P_OUI_TYPE_8822B) +#define BIT_GET_P2P_OUI_TYPE_8822B(x) \ + (((x) >> BIT_SHIFT_P2P_OUI_TYPE_8822B) & BIT_MASK_P2P_OUI_TYPE_8822B) + +/* 2 REG_ASSOCIATED_BFMER0_INFO_8822B (ASSOCIATED BEAMFORMER0 INFO REGISTER) */ + +#define BIT_SHIFT_R_WMAC_TXCSI_AID0_8822B (48 & CPU_OPT_WIDTH) +#define BIT_MASK_R_WMAC_TXCSI_AID0_8822B 0x1ff +#define BIT_R_WMAC_TXCSI_AID0_8822B(x) \ + (((x) & BIT_MASK_R_WMAC_TXCSI_AID0_8822B) \ + << BIT_SHIFT_R_WMAC_TXCSI_AID0_8822B) +#define BIT_GET_R_WMAC_TXCSI_AID0_8822B(x) \ + (((x) >> BIT_SHIFT_R_WMAC_TXCSI_AID0_8822B) & \ + BIT_MASK_R_WMAC_TXCSI_AID0_8822B) + +#define BIT_SHIFT_R_WMAC_SOUNDING_RXADD_R0_8822B 0 +#define BIT_MASK_R_WMAC_SOUNDING_RXADD_R0_8822B 0xffffffffffffL +#define BIT_R_WMAC_SOUNDING_RXADD_R0_8822B(x) \ + (((x) & BIT_MASK_R_WMAC_SOUNDING_RXADD_R0_8822B) \ + << BIT_SHIFT_R_WMAC_SOUNDING_RXADD_R0_8822B) +#define BIT_GET_R_WMAC_SOUNDING_RXADD_R0_8822B(x) \ + (((x) >> BIT_SHIFT_R_WMAC_SOUNDING_RXADD_R0_8822B) & \ + BIT_MASK_R_WMAC_SOUNDING_RXADD_R0_8822B) + +/* 2 REG_ASSOCIATED_BFMER1_INFO_8822B (ASSOCIATED BEAMFORMER1 INFO REGISTER) */ + +#define BIT_SHIFT_R_WMAC_TXCSI_AID1_8822B (48 & CPU_OPT_WIDTH) +#define BIT_MASK_R_WMAC_TXCSI_AID1_8822B 0x1ff +#define BIT_R_WMAC_TXCSI_AID1_8822B(x) \ + (((x) & BIT_MASK_R_WMAC_TXCSI_AID1_8822B) \ + << BIT_SHIFT_R_WMAC_TXCSI_AID1_8822B) +#define BIT_GET_R_WMAC_TXCSI_AID1_8822B(x) \ + (((x) >> BIT_SHIFT_R_WMAC_TXCSI_AID1_8822B) & \ + BIT_MASK_R_WMAC_TXCSI_AID1_8822B) + +#define BIT_SHIFT_R_WMAC_SOUNDING_RXADD_R1_8822B 0 +#define BIT_MASK_R_WMAC_SOUNDING_RXADD_R1_8822B 0xffffffffffffL +#define BIT_R_WMAC_SOUNDING_RXADD_R1_8822B(x) \ + (((x) & BIT_MASK_R_WMAC_SOUNDING_RXADD_R1_8822B) \ + << BIT_SHIFT_R_WMAC_SOUNDING_RXADD_R1_8822B) +#define BIT_GET_R_WMAC_SOUNDING_RXADD_R1_8822B(x) \ + (((x) >> BIT_SHIFT_R_WMAC_SOUNDING_RXADD_R1_8822B) & \ + BIT_MASK_R_WMAC_SOUNDING_RXADD_R1_8822B) + +/* 2 REG_TX_CSI_RPT_PARAM_BW20_8822B (TX CSI REPORT PARAMETER REGISTER) */ + +#define BIT_SHIFT_R_WMAC_BFINFO_20M_1_8822B 16 +#define BIT_MASK_R_WMAC_BFINFO_20M_1_8822B 0xfff +#define BIT_R_WMAC_BFINFO_20M_1_8822B(x) \ + (((x) & BIT_MASK_R_WMAC_BFINFO_20M_1_8822B) \ + << BIT_SHIFT_R_WMAC_BFINFO_20M_1_8822B) +#define BIT_GET_R_WMAC_BFINFO_20M_1_8822B(x) \ + (((x) >> BIT_SHIFT_R_WMAC_BFINFO_20M_1_8822B) & \ + BIT_MASK_R_WMAC_BFINFO_20M_1_8822B) + +#define BIT_SHIFT_R_WMAC_BFINFO_20M_0_8822B 0 +#define BIT_MASK_R_WMAC_BFINFO_20M_0_8822B 0xfff +#define BIT_R_WMAC_BFINFO_20M_0_8822B(x) \ + (((x) & BIT_MASK_R_WMAC_BFINFO_20M_0_8822B) \ + << BIT_SHIFT_R_WMAC_BFINFO_20M_0_8822B) +#define BIT_GET_R_WMAC_BFINFO_20M_0_8822B(x) \ + (((x) >> BIT_SHIFT_R_WMAC_BFINFO_20M_0_8822B) & \ + BIT_MASK_R_WMAC_BFINFO_20M_0_8822B) + +/* 2 REG_TX_CSI_RPT_PARAM_BW40_8822B (TX CSI REPORT PARAMETER_BW40 REGISTER) */ + +#define BIT_SHIFT_WMAC_RESP_ANTCD_8822B 0 +#define BIT_MASK_WMAC_RESP_ANTCD_8822B 0xf +#define BIT_WMAC_RESP_ANTCD_8822B(x) \ + (((x) & BIT_MASK_WMAC_RESP_ANTCD_8822B) \ + << BIT_SHIFT_WMAC_RESP_ANTCD_8822B) +#define BIT_GET_WMAC_RESP_ANTCD_8822B(x) \ + (((x) >> BIT_SHIFT_WMAC_RESP_ANTCD_8822B) & \ + BIT_MASK_WMAC_RESP_ANTCD_8822B) + +/* 2 REG_TX_CSI_RPT_PARAM_BW80_8822B (TX CSI REPORT PARAMETER_BW80 REGISTER) */ + +/* 2 REG_BCN_PSR_RPT2_8822B (BEACON PARSER REPORT REGISTER2) */ + +#define BIT_SHIFT_DTIM_CNT2_8822B 24 +#define BIT_MASK_DTIM_CNT2_8822B 0xff +#define BIT_DTIM_CNT2_8822B(x) \ + (((x) & BIT_MASK_DTIM_CNT2_8822B) << BIT_SHIFT_DTIM_CNT2_8822B) +#define BIT_GET_DTIM_CNT2_8822B(x) \ + (((x) >> BIT_SHIFT_DTIM_CNT2_8822B) & BIT_MASK_DTIM_CNT2_8822B) + +#define BIT_SHIFT_DTIM_PERIOD2_8822B 16 +#define BIT_MASK_DTIM_PERIOD2_8822B 0xff +#define BIT_DTIM_PERIOD2_8822B(x) \ + (((x) & BIT_MASK_DTIM_PERIOD2_8822B) << BIT_SHIFT_DTIM_PERIOD2_8822B) +#define BIT_GET_DTIM_PERIOD2_8822B(x) \ + (((x) >> BIT_SHIFT_DTIM_PERIOD2_8822B) & BIT_MASK_DTIM_PERIOD2_8822B) + +#define BIT_DTIM2_8822B BIT(15) +#define BIT_TIM2_8822B BIT(14) + +#define BIT_SHIFT_PS_AID_2_8822B 0 +#define BIT_MASK_PS_AID_2_8822B 0x7ff +#define BIT_PS_AID_2_8822B(x) \ + (((x) & BIT_MASK_PS_AID_2_8822B) << BIT_SHIFT_PS_AID_2_8822B) +#define BIT_GET_PS_AID_2_8822B(x) \ + (((x) >> BIT_SHIFT_PS_AID_2_8822B) & BIT_MASK_PS_AID_2_8822B) + +/* 2 REG_BCN_PSR_RPT3_8822B (BEACON PARSER REPORT REGISTER3) */ + +#define BIT_SHIFT_DTIM_CNT3_8822B 24 +#define BIT_MASK_DTIM_CNT3_8822B 0xff +#define BIT_DTIM_CNT3_8822B(x) \ + (((x) & BIT_MASK_DTIM_CNT3_8822B) << BIT_SHIFT_DTIM_CNT3_8822B) +#define BIT_GET_DTIM_CNT3_8822B(x) \ + (((x) >> BIT_SHIFT_DTIM_CNT3_8822B) & BIT_MASK_DTIM_CNT3_8822B) + +#define BIT_SHIFT_DTIM_PERIOD3_8822B 16 +#define BIT_MASK_DTIM_PERIOD3_8822B 0xff +#define BIT_DTIM_PERIOD3_8822B(x) \ + (((x) & BIT_MASK_DTIM_PERIOD3_8822B) << BIT_SHIFT_DTIM_PERIOD3_8822B) +#define BIT_GET_DTIM_PERIOD3_8822B(x) \ + (((x) >> BIT_SHIFT_DTIM_PERIOD3_8822B) & BIT_MASK_DTIM_PERIOD3_8822B) + +#define BIT_DTIM3_8822B BIT(15) +#define BIT_TIM3_8822B BIT(14) + +#define BIT_SHIFT_PS_AID_3_8822B 0 +#define BIT_MASK_PS_AID_3_8822B 0x7ff +#define BIT_PS_AID_3_8822B(x) \ + (((x) & BIT_MASK_PS_AID_3_8822B) << BIT_SHIFT_PS_AID_3_8822B) +#define BIT_GET_PS_AID_3_8822B(x) \ + (((x) >> BIT_SHIFT_PS_AID_3_8822B) & BIT_MASK_PS_AID_3_8822B) + +/* 2 REG_BCN_PSR_RPT4_8822B (BEACON PARSER REPORT REGISTER4) */ + +#define BIT_SHIFT_DTIM_CNT4_8822B 24 +#define BIT_MASK_DTIM_CNT4_8822B 0xff +#define BIT_DTIM_CNT4_8822B(x) \ + (((x) & BIT_MASK_DTIM_CNT4_8822B) << BIT_SHIFT_DTIM_CNT4_8822B) +#define BIT_GET_DTIM_CNT4_8822B(x) \ + (((x) >> BIT_SHIFT_DTIM_CNT4_8822B) & BIT_MASK_DTIM_CNT4_8822B) + +#define BIT_SHIFT_DTIM_PERIOD4_8822B 16 +#define BIT_MASK_DTIM_PERIOD4_8822B 0xff +#define BIT_DTIM_PERIOD4_8822B(x) \ + (((x) & BIT_MASK_DTIM_PERIOD4_8822B) << BIT_SHIFT_DTIM_PERIOD4_8822B) +#define BIT_GET_DTIM_PERIOD4_8822B(x) \ + (((x) >> BIT_SHIFT_DTIM_PERIOD4_8822B) & BIT_MASK_DTIM_PERIOD4_8822B) + +#define BIT_DTIM4_8822B BIT(15) +#define BIT_TIM4_8822B BIT(14) + +#define BIT_SHIFT_PS_AID_4_8822B 0 +#define BIT_MASK_PS_AID_4_8822B 0x7ff +#define BIT_PS_AID_4_8822B(x) \ + (((x) & BIT_MASK_PS_AID_4_8822B) << BIT_SHIFT_PS_AID_4_8822B) +#define BIT_GET_PS_AID_4_8822B(x) \ + (((x) >> BIT_SHIFT_PS_AID_4_8822B) & BIT_MASK_PS_AID_4_8822B) + +/* 2 REG_A1_ADDR_MASK_8822B (A1 ADDR MASK REGISTER) */ + +#define BIT_SHIFT_A1_ADDR_MASK_8822B 0 +#define BIT_MASK_A1_ADDR_MASK_8822B 0xffffffffL +#define BIT_A1_ADDR_MASK_8822B(x) \ + (((x) & BIT_MASK_A1_ADDR_MASK_8822B) << BIT_SHIFT_A1_ADDR_MASK_8822B) +#define BIT_GET_A1_ADDR_MASK_8822B(x) \ + (((x) >> BIT_SHIFT_A1_ADDR_MASK_8822B) & BIT_MASK_A1_ADDR_MASK_8822B) + +/* 2 REG_MACID2_8822B (MAC ID2 REGISTER) */ + +#define BIT_SHIFT_MACID2_8822B 0 +#define BIT_MASK_MACID2_8822B 0xffffffffffffL +#define BIT_MACID2_8822B(x) \ + (((x) & BIT_MASK_MACID2_8822B) << BIT_SHIFT_MACID2_8822B) +#define BIT_GET_MACID2_8822B(x) \ + (((x) >> BIT_SHIFT_MACID2_8822B) & BIT_MASK_MACID2_8822B) + +/* 2 REG_BSSID2_8822B (BSSID2 REGISTER) */ + +#define BIT_SHIFT_BSSID2_8822B 0 +#define BIT_MASK_BSSID2_8822B 0xffffffffffffL +#define BIT_BSSID2_8822B(x) \ + (((x) & BIT_MASK_BSSID2_8822B) << BIT_SHIFT_BSSID2_8822B) +#define BIT_GET_BSSID2_8822B(x) \ + (((x) >> BIT_SHIFT_BSSID2_8822B) & BIT_MASK_BSSID2_8822B) + +/* 2 REG_MACID3_8822B (MAC ID3 REGISTER) */ + +#define BIT_SHIFT_MACID3_8822B 0 +#define BIT_MASK_MACID3_8822B 0xffffffffffffL +#define BIT_MACID3_8822B(x) \ + (((x) & BIT_MASK_MACID3_8822B) << BIT_SHIFT_MACID3_8822B) +#define BIT_GET_MACID3_8822B(x) \ + (((x) >> BIT_SHIFT_MACID3_8822B) & BIT_MASK_MACID3_8822B) + +/* 2 REG_BSSID3_8822B (BSSID3 REGISTER) */ + +#define BIT_SHIFT_BSSID3_8822B 0 +#define BIT_MASK_BSSID3_8822B 0xffffffffffffL +#define BIT_BSSID3_8822B(x) \ + (((x) & BIT_MASK_BSSID3_8822B) << BIT_SHIFT_BSSID3_8822B) +#define BIT_GET_BSSID3_8822B(x) \ + (((x) >> BIT_SHIFT_BSSID3_8822B) & BIT_MASK_BSSID3_8822B) + +/* 2 REG_MACID4_8822B (MAC ID4 REGISTER) */ + +#define BIT_SHIFT_MACID4_8822B 0 +#define BIT_MASK_MACID4_8822B 0xffffffffffffL +#define BIT_MACID4_8822B(x) \ + (((x) & BIT_MASK_MACID4_8822B) << BIT_SHIFT_MACID4_8822B) +#define BIT_GET_MACID4_8822B(x) \ + (((x) >> BIT_SHIFT_MACID4_8822B) & BIT_MASK_MACID4_8822B) + +/* 2 REG_BSSID4_8822B (BSSID4 REGISTER) */ + +#define BIT_SHIFT_BSSID4_8822B 0 +#define BIT_MASK_BSSID4_8822B 0xffffffffffffL +#define BIT_BSSID4_8822B(x) \ + (((x) & BIT_MASK_BSSID4_8822B) << BIT_SHIFT_BSSID4_8822B) +#define BIT_GET_BSSID4_8822B(x) \ + (((x) >> BIT_SHIFT_BSSID4_8822B) & BIT_MASK_BSSID4_8822B) + +/* 2 REG_NOA_REPORT_8822B */ + +/* 2 REG_PWRBIT_SETTING_8822B */ +#define BIT_CLI3_PWRBIT_OW_EN_8822B BIT(7) +#define BIT_CLI3_PWR_ST_8822B BIT(6) +#define BIT_CLI2_PWRBIT_OW_EN_8822B BIT(5) +#define BIT_CLI2_PWR_ST_8822B BIT(4) +#define BIT_CLI1_PWRBIT_OW_EN_8822B BIT(3) +#define BIT_CLI1_PWR_ST_8822B BIT(2) +#define BIT_CLI0_PWRBIT_OW_EN_8822B BIT(1) +#define BIT_CLI0_PWR_ST_8822B BIT(0) + +/* 2 REG_WMAC_MU_BF_OPTION_8822B */ +#define BIT_WMAC_RESP_NONSTA1_DIS_8822B BIT(7) +#define BIT_BIT_WMAC_TXMU_ACKPOLICY_EN_8822B BIT(6) + +#define BIT_SHIFT_WMAC_TXMU_ACKPOLICY_8822B 4 +#define BIT_MASK_WMAC_TXMU_ACKPOLICY_8822B 0x3 +#define BIT_WMAC_TXMU_ACKPOLICY_8822B(x) \ + (((x) & BIT_MASK_WMAC_TXMU_ACKPOLICY_8822B) \ + << BIT_SHIFT_WMAC_TXMU_ACKPOLICY_8822B) +#define BIT_GET_WMAC_TXMU_ACKPOLICY_8822B(x) \ + (((x) >> BIT_SHIFT_WMAC_TXMU_ACKPOLICY_8822B) & \ + BIT_MASK_WMAC_TXMU_ACKPOLICY_8822B) + +#define BIT_SHIFT_WMAC_MU_BFEE_PORT_SEL_8822B 1 +#define BIT_MASK_WMAC_MU_BFEE_PORT_SEL_8822B 0x7 +#define BIT_WMAC_MU_BFEE_PORT_SEL_8822B(x) \ + (((x) & BIT_MASK_WMAC_MU_BFEE_PORT_SEL_8822B) \ + << BIT_SHIFT_WMAC_MU_BFEE_PORT_SEL_8822B) +#define BIT_GET_WMAC_MU_BFEE_PORT_SEL_8822B(x) \ + (((x) >> BIT_SHIFT_WMAC_MU_BFEE_PORT_SEL_8822B) & \ + BIT_MASK_WMAC_MU_BFEE_PORT_SEL_8822B) + +#define BIT_WMAC_MU_BFEE_DIS_8822B BIT(0) + +/* 2 REG_NOT_VALID_8822B */ + +#define BIT_SHIFT_WMAC_PAUSE_BB_CLR_TH_8822B 0 +#define BIT_MASK_WMAC_PAUSE_BB_CLR_TH_8822B 0xff +#define BIT_WMAC_PAUSE_BB_CLR_TH_8822B(x) \ + (((x) & BIT_MASK_WMAC_PAUSE_BB_CLR_TH_8822B) \ + << BIT_SHIFT_WMAC_PAUSE_BB_CLR_TH_8822B) +#define BIT_GET_WMAC_PAUSE_BB_CLR_TH_8822B(x) \ + (((x) >> BIT_SHIFT_WMAC_PAUSE_BB_CLR_TH_8822B) & \ + BIT_MASK_WMAC_PAUSE_BB_CLR_TH_8822B) + +/* 2 REG_WMAC_MU_ARB_8822B */ +#define BIT_WMAC_ARB_HW_ADAPT_EN_8822B BIT(7) +#define BIT_WMAC_ARB_SW_EN_8822B BIT(6) + +#define BIT_SHIFT_WMAC_ARB_SW_STATE_8822B 0 +#define BIT_MASK_WMAC_ARB_SW_STATE_8822B 0x3f +#define BIT_WMAC_ARB_SW_STATE_8822B(x) \ + (((x) & BIT_MASK_WMAC_ARB_SW_STATE_8822B) \ + << BIT_SHIFT_WMAC_ARB_SW_STATE_8822B) +#define BIT_GET_WMAC_ARB_SW_STATE_8822B(x) \ + (((x) >> BIT_SHIFT_WMAC_ARB_SW_STATE_8822B) & \ + BIT_MASK_WMAC_ARB_SW_STATE_8822B) + +/* 2 REG_WMAC_MU_OPTION_8822B */ + +#define BIT_SHIFT_WMAC_MU_DBGSEL_8822B 5 +#define BIT_MASK_WMAC_MU_DBGSEL_8822B 0x3 +#define BIT_WMAC_MU_DBGSEL_8822B(x) \ + (((x) & BIT_MASK_WMAC_MU_DBGSEL_8822B) \ + << BIT_SHIFT_WMAC_MU_DBGSEL_8822B) +#define BIT_GET_WMAC_MU_DBGSEL_8822B(x) \ + (((x) >> BIT_SHIFT_WMAC_MU_DBGSEL_8822B) & \ + BIT_MASK_WMAC_MU_DBGSEL_8822B) + +#define BIT_SHIFT_WMAC_MU_CPRD_TIMEOUT_8822B 0 +#define BIT_MASK_WMAC_MU_CPRD_TIMEOUT_8822B 0x1f +#define BIT_WMAC_MU_CPRD_TIMEOUT_8822B(x) \ + (((x) & BIT_MASK_WMAC_MU_CPRD_TIMEOUT_8822B) \ + << BIT_SHIFT_WMAC_MU_CPRD_TIMEOUT_8822B) +#define BIT_GET_WMAC_MU_CPRD_TIMEOUT_8822B(x) \ + (((x) >> BIT_SHIFT_WMAC_MU_CPRD_TIMEOUT_8822B) & \ + BIT_MASK_WMAC_MU_CPRD_TIMEOUT_8822B) + +/* 2 REG_WMAC_MU_BF_CTL_8822B */ +#define BIT_WMAC_INVLD_BFPRT_CHK_8822B BIT(15) +#define BIT_WMAC_RETXBFRPTSEQ_UPD_8822B BIT(14) + +#define BIT_SHIFT_WMAC_MU_BFRPTSEG_SEL_8822B 12 +#define BIT_MASK_WMAC_MU_BFRPTSEG_SEL_8822B 0x3 +#define BIT_WMAC_MU_BFRPTSEG_SEL_8822B(x) \ + (((x) & BIT_MASK_WMAC_MU_BFRPTSEG_SEL_8822B) \ + << BIT_SHIFT_WMAC_MU_BFRPTSEG_SEL_8822B) +#define BIT_GET_WMAC_MU_BFRPTSEG_SEL_8822B(x) \ + (((x) >> BIT_SHIFT_WMAC_MU_BFRPTSEG_SEL_8822B) & \ + BIT_MASK_WMAC_MU_BFRPTSEG_SEL_8822B) + +#define BIT_SHIFT_WMAC_MU_BF_MYAID_8822B 0 +#define BIT_MASK_WMAC_MU_BF_MYAID_8822B 0xfff +#define BIT_WMAC_MU_BF_MYAID_8822B(x) \ + (((x) & BIT_MASK_WMAC_MU_BF_MYAID_8822B) \ + << BIT_SHIFT_WMAC_MU_BF_MYAID_8822B) +#define BIT_GET_WMAC_MU_BF_MYAID_8822B(x) \ + (((x) >> BIT_SHIFT_WMAC_MU_BF_MYAID_8822B) & \ + BIT_MASK_WMAC_MU_BF_MYAID_8822B) + +/* 2 REG_WMAC_MU_BFRPT_PARA_8822B */ + +#define BIT_SHIFT_BIT_BFRPT_PARA_USERID_SEL_8822B 12 +#define BIT_MASK_BIT_BFRPT_PARA_USERID_SEL_8822B 0x7 +#define BIT_BIT_BFRPT_PARA_USERID_SEL_8822B(x) \ + (((x) & BIT_MASK_BIT_BFRPT_PARA_USERID_SEL_8822B) \ + << BIT_SHIFT_BIT_BFRPT_PARA_USERID_SEL_8822B) +#define BIT_GET_BIT_BFRPT_PARA_USERID_SEL_8822B(x) \ + (((x) >> BIT_SHIFT_BIT_BFRPT_PARA_USERID_SEL_8822B) & \ + BIT_MASK_BIT_BFRPT_PARA_USERID_SEL_8822B) + +#define BIT_SHIFT_BFRPT_PARA_8822B 0 +#define BIT_MASK_BFRPT_PARA_8822B 0xfff +#define BIT_BFRPT_PARA_8822B(x) \ + (((x) & BIT_MASK_BFRPT_PARA_8822B) << BIT_SHIFT_BFRPT_PARA_8822B) +#define BIT_GET_BFRPT_PARA_8822B(x) \ + (((x) >> BIT_SHIFT_BFRPT_PARA_8822B) & BIT_MASK_BFRPT_PARA_8822B) + +/* 2 REG_WMAC_ASSOCIATED_MU_BFMEE2_8822B */ +#define BIT_STATUS_BFEE2_8822B BIT(10) +#define BIT_WMAC_MU_BFEE2_EN_8822B BIT(9) + +#define BIT_SHIFT_WMAC_MU_BFEE2_AID_8822B 0 +#define BIT_MASK_WMAC_MU_BFEE2_AID_8822B 0x1ff +#define BIT_WMAC_MU_BFEE2_AID_8822B(x) \ + (((x) & BIT_MASK_WMAC_MU_BFEE2_AID_8822B) \ + << BIT_SHIFT_WMAC_MU_BFEE2_AID_8822B) +#define BIT_GET_WMAC_MU_BFEE2_AID_8822B(x) \ + (((x) >> BIT_SHIFT_WMAC_MU_BFEE2_AID_8822B) & \ + BIT_MASK_WMAC_MU_BFEE2_AID_8822B) + +/* 2 REG_WMAC_ASSOCIATED_MU_BFMEE3_8822B */ +#define BIT_STATUS_BFEE3_8822B BIT(10) +#define BIT_WMAC_MU_BFEE3_EN_8822B BIT(9) + +#define BIT_SHIFT_WMAC_MU_BFEE3_AID_8822B 0 +#define BIT_MASK_WMAC_MU_BFEE3_AID_8822B 0x1ff +#define BIT_WMAC_MU_BFEE3_AID_8822B(x) \ + (((x) & BIT_MASK_WMAC_MU_BFEE3_AID_8822B) \ + << BIT_SHIFT_WMAC_MU_BFEE3_AID_8822B) +#define BIT_GET_WMAC_MU_BFEE3_AID_8822B(x) \ + (((x) >> BIT_SHIFT_WMAC_MU_BFEE3_AID_8822B) & \ + BIT_MASK_WMAC_MU_BFEE3_AID_8822B) + +/* 2 REG_WMAC_ASSOCIATED_MU_BFMEE4_8822B */ +#define BIT_STATUS_BFEE4_8822B BIT(10) +#define BIT_WMAC_MU_BFEE4_EN_8822B BIT(9) + +#define BIT_SHIFT_WMAC_MU_BFEE4_AID_8822B 0 +#define BIT_MASK_WMAC_MU_BFEE4_AID_8822B 0x1ff +#define BIT_WMAC_MU_BFEE4_AID_8822B(x) \ + (((x) & BIT_MASK_WMAC_MU_BFEE4_AID_8822B) \ + << BIT_SHIFT_WMAC_MU_BFEE4_AID_8822B) +#define BIT_GET_WMAC_MU_BFEE4_AID_8822B(x) \ + (((x) >> BIT_SHIFT_WMAC_MU_BFEE4_AID_8822B) & \ + BIT_MASK_WMAC_MU_BFEE4_AID_8822B) + +/* 2 REG_WMAC_ASSOCIATED_MU_BFMEE5_8822B */ +#define BIT_STATUS_BFEE5_8822B BIT(10) +#define BIT_WMAC_MU_BFEE5_EN_8822B BIT(9) + +#define BIT_SHIFT_WMAC_MU_BFEE5_AID_8822B 0 +#define BIT_MASK_WMAC_MU_BFEE5_AID_8822B 0x1ff +#define BIT_WMAC_MU_BFEE5_AID_8822B(x) \ + (((x) & BIT_MASK_WMAC_MU_BFEE5_AID_8822B) \ + << BIT_SHIFT_WMAC_MU_BFEE5_AID_8822B) +#define BIT_GET_WMAC_MU_BFEE5_AID_8822B(x) \ + (((x) >> BIT_SHIFT_WMAC_MU_BFEE5_AID_8822B) & \ + BIT_MASK_WMAC_MU_BFEE5_AID_8822B) + +/* 2 REG_WMAC_ASSOCIATED_MU_BFMEE6_8822B */ +#define BIT_STATUS_BFEE6_8822B BIT(10) +#define BIT_WMAC_MU_BFEE6_EN_8822B BIT(9) + +#define BIT_SHIFT_WMAC_MU_BFEE6_AID_8822B 0 +#define BIT_MASK_WMAC_MU_BFEE6_AID_8822B 0x1ff +#define BIT_WMAC_MU_BFEE6_AID_8822B(x) \ + (((x) & BIT_MASK_WMAC_MU_BFEE6_AID_8822B) \ + << BIT_SHIFT_WMAC_MU_BFEE6_AID_8822B) +#define BIT_GET_WMAC_MU_BFEE6_AID_8822B(x) \ + (((x) >> BIT_SHIFT_WMAC_MU_BFEE6_AID_8822B) & \ + BIT_MASK_WMAC_MU_BFEE6_AID_8822B) + +/* 2 REG_WMAC_ASSOCIATED_MU_BFMEE7_8822B */ +#define BIT_BIT_STATUS_BFEE4_8822B BIT(10) +#define BIT_WMAC_MU_BFEE7_EN_8822B BIT(9) + +#define BIT_SHIFT_WMAC_MU_BFEE7_AID_8822B 0 +#define BIT_MASK_WMAC_MU_BFEE7_AID_8822B 0x1ff +#define BIT_WMAC_MU_BFEE7_AID_8822B(x) \ + (((x) & BIT_MASK_WMAC_MU_BFEE7_AID_8822B) \ + << BIT_SHIFT_WMAC_MU_BFEE7_AID_8822B) +#define BIT_GET_WMAC_MU_BFEE7_AID_8822B(x) \ + (((x) >> BIT_SHIFT_WMAC_MU_BFEE7_AID_8822B) & \ + BIT_MASK_WMAC_MU_BFEE7_AID_8822B) + +/* 2 REG_NOT_VALID_8822B */ +#define BIT_RST_ALL_COUNTER_8822B BIT(31) + +#define BIT_SHIFT_ABORT_RX_VBON_COUNTER_8822B 16 +#define BIT_MASK_ABORT_RX_VBON_COUNTER_8822B 0xff +#define BIT_ABORT_RX_VBON_COUNTER_8822B(x) \ + (((x) & BIT_MASK_ABORT_RX_VBON_COUNTER_8822B) \ + << BIT_SHIFT_ABORT_RX_VBON_COUNTER_8822B) +#define BIT_GET_ABORT_RX_VBON_COUNTER_8822B(x) \ + (((x) >> BIT_SHIFT_ABORT_RX_VBON_COUNTER_8822B) & \ + BIT_MASK_ABORT_RX_VBON_COUNTER_8822B) + +#define BIT_SHIFT_ABORT_RX_RDRDY_COUNTER_8822B 8 +#define BIT_MASK_ABORT_RX_RDRDY_COUNTER_8822B 0xff +#define BIT_ABORT_RX_RDRDY_COUNTER_8822B(x) \ + (((x) & BIT_MASK_ABORT_RX_RDRDY_COUNTER_8822B) \ + << BIT_SHIFT_ABORT_RX_RDRDY_COUNTER_8822B) +#define BIT_GET_ABORT_RX_RDRDY_COUNTER_8822B(x) \ + (((x) >> BIT_SHIFT_ABORT_RX_RDRDY_COUNTER_8822B) & \ + BIT_MASK_ABORT_RX_RDRDY_COUNTER_8822B) + +#define BIT_SHIFT_VBON_EARLY_FALLING_COUNTER_8822B 0 +#define BIT_MASK_VBON_EARLY_FALLING_COUNTER_8822B 0xff +#define BIT_VBON_EARLY_FALLING_COUNTER_8822B(x) \ + (((x) & BIT_MASK_VBON_EARLY_FALLING_COUNTER_8822B) \ + << BIT_SHIFT_VBON_EARLY_FALLING_COUNTER_8822B) +#define BIT_GET_VBON_EARLY_FALLING_COUNTER_8822B(x) \ + (((x) >> BIT_SHIFT_VBON_EARLY_FALLING_COUNTER_8822B) & \ + BIT_MASK_VBON_EARLY_FALLING_COUNTER_8822B) + +/* 2 REG_NOT_VALID_8822B */ +#define BIT_WMAC_PLCP_TRX_SEL_8822B BIT(31) + +#define BIT_SHIFT_WMAC_PLCP_RDSIG_SEL_8822B 28 +#define BIT_MASK_WMAC_PLCP_RDSIG_SEL_8822B 0x7 +#define BIT_WMAC_PLCP_RDSIG_SEL_8822B(x) \ + (((x) & BIT_MASK_WMAC_PLCP_RDSIG_SEL_8822B) \ + << BIT_SHIFT_WMAC_PLCP_RDSIG_SEL_8822B) +#define BIT_GET_WMAC_PLCP_RDSIG_SEL_8822B(x) \ + (((x) >> BIT_SHIFT_WMAC_PLCP_RDSIG_SEL_8822B) & \ + BIT_MASK_WMAC_PLCP_RDSIG_SEL_8822B) + +#define BIT_SHIFT_WMAC_RATE_IDX_8822B 24 +#define BIT_MASK_WMAC_RATE_IDX_8822B 0xf +#define BIT_WMAC_RATE_IDX_8822B(x) \ + (((x) & BIT_MASK_WMAC_RATE_IDX_8822B) << BIT_SHIFT_WMAC_RATE_IDX_8822B) +#define BIT_GET_WMAC_RATE_IDX_8822B(x) \ + (((x) >> BIT_SHIFT_WMAC_RATE_IDX_8822B) & BIT_MASK_WMAC_RATE_IDX_8822B) + +#define BIT_SHIFT_WMAC_PLCP_RDSIG_8822B 0 +#define BIT_MASK_WMAC_PLCP_RDSIG_8822B 0xffffff +#define BIT_WMAC_PLCP_RDSIG_8822B(x) \ + (((x) & BIT_MASK_WMAC_PLCP_RDSIG_8822B) \ + << BIT_SHIFT_WMAC_PLCP_RDSIG_8822B) +#define BIT_GET_WMAC_PLCP_RDSIG_8822B(x) \ + (((x) >> BIT_SHIFT_WMAC_PLCP_RDSIG_8822B) & \ + BIT_MASK_WMAC_PLCP_RDSIG_8822B) + +/* 2 REG_NOT_VALID_8822B */ +#define BIT_WMAC_MUTX_IDX_8822B BIT(24) + +#define BIT_SHIFT_WMAC_PLCP_RDSIG_8822B 0 +#define BIT_MASK_WMAC_PLCP_RDSIG_8822B 0xffffff +#define BIT_WMAC_PLCP_RDSIG_8822B(x) \ + (((x) & BIT_MASK_WMAC_PLCP_RDSIG_8822B) \ + << BIT_SHIFT_WMAC_PLCP_RDSIG_8822B) +#define BIT_GET_WMAC_PLCP_RDSIG_8822B(x) \ + (((x) >> BIT_SHIFT_WMAC_PLCP_RDSIG_8822B) & \ + BIT_MASK_WMAC_PLCP_RDSIG_8822B) + +/* 2 REG_TRANSMIT_ADDRSS_0_8822B (TA0 REGISTER) */ + +#define BIT_SHIFT_TA0_8822B 0 +#define BIT_MASK_TA0_8822B 0xffffffffffffL +#define BIT_TA0_8822B(x) (((x) & BIT_MASK_TA0_8822B) << BIT_SHIFT_TA0_8822B) +#define BIT_GET_TA0_8822B(x) (((x) >> BIT_SHIFT_TA0_8822B) & BIT_MASK_TA0_8822B) + +/* 2 REG_TRANSMIT_ADDRSS_1_8822B (TA1 REGISTER) */ + +#define BIT_SHIFT_TA1_8822B 0 +#define BIT_MASK_TA1_8822B 0xffffffffffffL +#define BIT_TA1_8822B(x) (((x) & BIT_MASK_TA1_8822B) << BIT_SHIFT_TA1_8822B) +#define BIT_GET_TA1_8822B(x) (((x) >> BIT_SHIFT_TA1_8822B) & BIT_MASK_TA1_8822B) + +/* 2 REG_TRANSMIT_ADDRSS_2_8822B (TA2 REGISTER) */ + +#define BIT_SHIFT_TA2_8822B 0 +#define BIT_MASK_TA2_8822B 0xffffffffffffL +#define BIT_TA2_8822B(x) (((x) & BIT_MASK_TA2_8822B) << BIT_SHIFT_TA2_8822B) +#define BIT_GET_TA2_8822B(x) (((x) >> BIT_SHIFT_TA2_8822B) & BIT_MASK_TA2_8822B) + +/* 2 REG_TRANSMIT_ADDRSS_3_8822B (TA3 REGISTER) */ + +#define BIT_SHIFT_TA3_8822B 0 +#define BIT_MASK_TA3_8822B 0xffffffffffffL +#define BIT_TA3_8822B(x) (((x) & BIT_MASK_TA3_8822B) << BIT_SHIFT_TA3_8822B) +#define BIT_GET_TA3_8822B(x) (((x) >> BIT_SHIFT_TA3_8822B) & BIT_MASK_TA3_8822B) + +/* 2 REG_TRANSMIT_ADDRSS_4_8822B (TA4 REGISTER) */ + +#define BIT_SHIFT_TA4_8822B 0 +#define BIT_MASK_TA4_8822B 0xffffffffffffL +#define BIT_TA4_8822B(x) (((x) & BIT_MASK_TA4_8822B) << BIT_SHIFT_TA4_8822B) +#define BIT_GET_TA4_8822B(x) (((x) >> BIT_SHIFT_TA4_8822B) & BIT_MASK_TA4_8822B) + +/* 2 REG_NOT_VALID_8822B */ + +/* 2 REG_MACID1_8822B */ + +#define BIT_SHIFT_MACID1_8822B 0 +#define BIT_MASK_MACID1_8822B 0xffffffffffffL +#define BIT_MACID1_8822B(x) \ + (((x) & BIT_MASK_MACID1_8822B) << BIT_SHIFT_MACID1_8822B) +#define BIT_GET_MACID1_8822B(x) \ + (((x) >> BIT_SHIFT_MACID1_8822B) & BIT_MASK_MACID1_8822B) + +/* 2 REG_BSSID1_8822B */ + +#define BIT_SHIFT_BSSID1_8822B 0 +#define BIT_MASK_BSSID1_8822B 0xffffffffffffL +#define BIT_BSSID1_8822B(x) \ + (((x) & BIT_MASK_BSSID1_8822B) << BIT_SHIFT_BSSID1_8822B) +#define BIT_GET_BSSID1_8822B(x) \ + (((x) >> BIT_SHIFT_BSSID1_8822B) & BIT_MASK_BSSID1_8822B) + +/* 2 REG_BCN_PSR_RPT1_8822B */ + +#define BIT_SHIFT_DTIM_CNT1_8822B 24 +#define BIT_MASK_DTIM_CNT1_8822B 0xff +#define BIT_DTIM_CNT1_8822B(x) \ + (((x) & BIT_MASK_DTIM_CNT1_8822B) << BIT_SHIFT_DTIM_CNT1_8822B) +#define BIT_GET_DTIM_CNT1_8822B(x) \ + (((x) >> BIT_SHIFT_DTIM_CNT1_8822B) & BIT_MASK_DTIM_CNT1_8822B) + +#define BIT_SHIFT_DTIM_PERIOD1_8822B 16 +#define BIT_MASK_DTIM_PERIOD1_8822B 0xff +#define BIT_DTIM_PERIOD1_8822B(x) \ + (((x) & BIT_MASK_DTIM_PERIOD1_8822B) << BIT_SHIFT_DTIM_PERIOD1_8822B) +#define BIT_GET_DTIM_PERIOD1_8822B(x) \ + (((x) >> BIT_SHIFT_DTIM_PERIOD1_8822B) & BIT_MASK_DTIM_PERIOD1_8822B) + +#define BIT_DTIM1_8822B BIT(15) +#define BIT_TIM1_8822B BIT(14) + +#define BIT_SHIFT_PS_AID_1_8822B 0 +#define BIT_MASK_PS_AID_1_8822B 0x7ff +#define BIT_PS_AID_1_8822B(x) \ + (((x) & BIT_MASK_PS_AID_1_8822B) << BIT_SHIFT_PS_AID_1_8822B) +#define BIT_GET_PS_AID_1_8822B(x) \ + (((x) >> BIT_SHIFT_PS_AID_1_8822B) & BIT_MASK_PS_AID_1_8822B) + +/* 2 REG_ASSOCIATED_BFMEE_SEL_8822B */ +#define BIT_TXUSER_ID1_8822B BIT(25) + +#define BIT_SHIFT_AID1_8822B 16 +#define BIT_MASK_AID1_8822B 0x1ff +#define BIT_AID1_8822B(x) (((x) & BIT_MASK_AID1_8822B) << BIT_SHIFT_AID1_8822B) +#define BIT_GET_AID1_8822B(x) \ + (((x) >> BIT_SHIFT_AID1_8822B) & BIT_MASK_AID1_8822B) + +#define BIT_TXUSER_ID0_8822B BIT(9) + +#define BIT_SHIFT_AID0_8822B 0 +#define BIT_MASK_AID0_8822B 0x1ff +#define BIT_AID0_8822B(x) (((x) & BIT_MASK_AID0_8822B) << BIT_SHIFT_AID0_8822B) +#define BIT_GET_AID0_8822B(x) \ + (((x) >> BIT_SHIFT_AID0_8822B) & BIT_MASK_AID0_8822B) + +/* 2 REG_SND_PTCL_CTRL_8822B */ + +#define BIT_SHIFT_NDP_RX_STANDBY_TIMER_8822B 24 +#define BIT_MASK_NDP_RX_STANDBY_TIMER_8822B 0xff +#define BIT_NDP_RX_STANDBY_TIMER_8822B(x) \ + (((x) & BIT_MASK_NDP_RX_STANDBY_TIMER_8822B) \ + << BIT_SHIFT_NDP_RX_STANDBY_TIMER_8822B) +#define BIT_GET_NDP_RX_STANDBY_TIMER_8822B(x) \ + (((x) >> BIT_SHIFT_NDP_RX_STANDBY_TIMER_8822B) & \ + BIT_MASK_NDP_RX_STANDBY_TIMER_8822B) + +#define BIT_SHIFT_CSI_RPT_OFFSET_HT_8822B 16 +#define BIT_MASK_CSI_RPT_OFFSET_HT_8822B 0xff +#define BIT_CSI_RPT_OFFSET_HT_8822B(x) \ + (((x) & BIT_MASK_CSI_RPT_OFFSET_HT_8822B) \ + << BIT_SHIFT_CSI_RPT_OFFSET_HT_8822B) +#define BIT_GET_CSI_RPT_OFFSET_HT_8822B(x) \ + (((x) >> BIT_SHIFT_CSI_RPT_OFFSET_HT_8822B) & \ + BIT_MASK_CSI_RPT_OFFSET_HT_8822B) + +#define BIT_SHIFT_R_WMAC_VHT_CATEGORY_8822B 8 +#define BIT_MASK_R_WMAC_VHT_CATEGORY_8822B 0xff +#define BIT_R_WMAC_VHT_CATEGORY_8822B(x) \ + (((x) & BIT_MASK_R_WMAC_VHT_CATEGORY_8822B) \ + << BIT_SHIFT_R_WMAC_VHT_CATEGORY_8822B) +#define BIT_GET_R_WMAC_VHT_CATEGORY_8822B(x) \ + (((x) >> BIT_SHIFT_R_WMAC_VHT_CATEGORY_8822B) & \ + BIT_MASK_R_WMAC_VHT_CATEGORY_8822B) + +#define BIT_R_WMAC_USE_NSTS_8822B BIT(7) +#define BIT_R_DISABLE_CHECK_VHTSIGB_CRC_8822B BIT(6) +#define BIT_R_DISABLE_CHECK_VHTSIGA_CRC_8822B BIT(5) +#define BIT_R_WMAC_BFPARAM_SEL_8822B BIT(4) +#define BIT_R_WMAC_CSISEQ_SEL_8822B BIT(3) +#define BIT_R_WMAC_CSI_WITHHTC_EN_8822B BIT(2) +#define BIT_R_WMAC_HT_NDPA_EN_8822B BIT(1) +#define BIT_R_WMAC_VHT_NDPA_EN_8822B BIT(0) + +/* 2 REG_RX_CSI_RPT_INFO_8822B */ + +/* 2 REG_NS_ARP_CTRL_8822B */ +#define BIT_R_WMAC_NSARP_RSPEN_8822B BIT(15) +#define BIT_R_WMAC_NSARP_RARP_8822B BIT(9) +#define BIT_R_WMAC_NSARP_RIPV6_8822B BIT(8) + +#define BIT_SHIFT_R_WMAC_NSARP_MODEN_8822B 6 +#define BIT_MASK_R_WMAC_NSARP_MODEN_8822B 0x3 +#define BIT_R_WMAC_NSARP_MODEN_8822B(x) \ + (((x) & BIT_MASK_R_WMAC_NSARP_MODEN_8822B) \ + << BIT_SHIFT_R_WMAC_NSARP_MODEN_8822B) +#define BIT_GET_R_WMAC_NSARP_MODEN_8822B(x) \ + (((x) >> BIT_SHIFT_R_WMAC_NSARP_MODEN_8822B) & \ + BIT_MASK_R_WMAC_NSARP_MODEN_8822B) + +#define BIT_SHIFT_R_WMAC_NSARP_RSPFTP_8822B 4 +#define BIT_MASK_R_WMAC_NSARP_RSPFTP_8822B 0x3 +#define BIT_R_WMAC_NSARP_RSPFTP_8822B(x) \ + (((x) & BIT_MASK_R_WMAC_NSARP_RSPFTP_8822B) \ + << BIT_SHIFT_R_WMAC_NSARP_RSPFTP_8822B) +#define BIT_GET_R_WMAC_NSARP_RSPFTP_8822B(x) \ + (((x) >> BIT_SHIFT_R_WMAC_NSARP_RSPFTP_8822B) & \ + BIT_MASK_R_WMAC_NSARP_RSPFTP_8822B) + +#define BIT_SHIFT_R_WMAC_NSARP_RSPSEC_8822B 0 +#define BIT_MASK_R_WMAC_NSARP_RSPSEC_8822B 0xf +#define BIT_R_WMAC_NSARP_RSPSEC_8822B(x) \ + (((x) & BIT_MASK_R_WMAC_NSARP_RSPSEC_8822B) \ + << BIT_SHIFT_R_WMAC_NSARP_RSPSEC_8822B) +#define BIT_GET_R_WMAC_NSARP_RSPSEC_8822B(x) \ + (((x) >> BIT_SHIFT_R_WMAC_NSARP_RSPSEC_8822B) & \ + BIT_MASK_R_WMAC_NSARP_RSPSEC_8822B) + +/* 2 REG_NS_ARP_INFO_8822B */ +#define BIT_REQ_IS_MCNS_8822B BIT(23) +#define BIT_REQ_IS_UCNS_8822B BIT(22) +#define BIT_REQ_IS_USNS_8822B BIT(21) +#define BIT_REQ_IS_ARP_8822B BIT(20) +#define BIT_EXPRSP_MH_WITHQC_8822B BIT(19) + +#define BIT_SHIFT_EXPRSP_SECTYPE_8822B 16 +#define BIT_MASK_EXPRSP_SECTYPE_8822B 0x7 +#define BIT_EXPRSP_SECTYPE_8822B(x) \ + (((x) & BIT_MASK_EXPRSP_SECTYPE_8822B) \ + << BIT_SHIFT_EXPRSP_SECTYPE_8822B) +#define BIT_GET_EXPRSP_SECTYPE_8822B(x) \ + (((x) >> BIT_SHIFT_EXPRSP_SECTYPE_8822B) & \ + BIT_MASK_EXPRSP_SECTYPE_8822B) + +#define BIT_SHIFT_EXPRSP_CHKSM_7_TO_0_8822B 8 +#define BIT_MASK_EXPRSP_CHKSM_7_TO_0_8822B 0xff +#define BIT_EXPRSP_CHKSM_7_TO_0_8822B(x) \ + (((x) & BIT_MASK_EXPRSP_CHKSM_7_TO_0_8822B) \ + << BIT_SHIFT_EXPRSP_CHKSM_7_TO_0_8822B) +#define BIT_GET_EXPRSP_CHKSM_7_TO_0_8822B(x) \ + (((x) >> BIT_SHIFT_EXPRSP_CHKSM_7_TO_0_8822B) & \ + BIT_MASK_EXPRSP_CHKSM_7_TO_0_8822B) + +#define BIT_SHIFT_EXPRSP_CHKSM_15_TO_8_8822B 0 +#define BIT_MASK_EXPRSP_CHKSM_15_TO_8_8822B 0xff +#define BIT_EXPRSP_CHKSM_15_TO_8_8822B(x) \ + (((x) & BIT_MASK_EXPRSP_CHKSM_15_TO_8_8822B) \ + << BIT_SHIFT_EXPRSP_CHKSM_15_TO_8_8822B) +#define BIT_GET_EXPRSP_CHKSM_15_TO_8_8822B(x) \ + (((x) >> BIT_SHIFT_EXPRSP_CHKSM_15_TO_8_8822B) & \ + BIT_MASK_EXPRSP_CHKSM_15_TO_8_8822B) + +/* 2 REG_BEAMFORMING_INFO_NSARP_V1_8822B */ + +#define BIT_SHIFT_WMAC_ARPIP_8822B 0 +#define BIT_MASK_WMAC_ARPIP_8822B 0xffffffffL +#define BIT_WMAC_ARPIP_8822B(x) \ + (((x) & BIT_MASK_WMAC_ARPIP_8822B) << BIT_SHIFT_WMAC_ARPIP_8822B) +#define BIT_GET_WMAC_ARPIP_8822B(x) \ + (((x) >> BIT_SHIFT_WMAC_ARPIP_8822B) & BIT_MASK_WMAC_ARPIP_8822B) + +/* 2 REG_BEAMFORMING_INFO_NSARP_8822B */ + +#define BIT_SHIFT_BEAMFORMING_INFO_8822B 0 +#define BIT_MASK_BEAMFORMING_INFO_8822B 0xffffffffL +#define BIT_BEAMFORMING_INFO_8822B(x) \ + (((x) & BIT_MASK_BEAMFORMING_INFO_8822B) \ + << BIT_SHIFT_BEAMFORMING_INFO_8822B) +#define BIT_GET_BEAMFORMING_INFO_8822B(x) \ + (((x) >> BIT_SHIFT_BEAMFORMING_INFO_8822B) & \ + BIT_MASK_BEAMFORMING_INFO_8822B) + +/* 2 REG_NOT_VALID_8822B */ + +#define BIT_SHIFT_R_WMAC_IPV6_MYIPAD_8822B 0 +#define BIT_MASK_R_WMAC_IPV6_MYIPAD_8822B 0xffffffffffffffffffffffffffffffffL +#define BIT_R_WMAC_IPV6_MYIPAD_8822B(x) \ + (((x) & BIT_MASK_R_WMAC_IPV6_MYIPAD_8822B) \ + << BIT_SHIFT_R_WMAC_IPV6_MYIPAD_8822B) +#define BIT_GET_R_WMAC_IPV6_MYIPAD_8822B(x) \ + (((x) >> BIT_SHIFT_R_WMAC_IPV6_MYIPAD_8822B) & \ + BIT_MASK_R_WMAC_IPV6_MYIPAD_8822B) + +/* 2 REG_RSVD_0X740_8822B */ + +/* 2 REG_WMAC_RTX_CTX_SUBTYPE_CFG_8822B */ + +#define BIT_SHIFT_R_WMAC_CTX_SUBTYPE_8822B 4 +#define BIT_MASK_R_WMAC_CTX_SUBTYPE_8822B 0xf +#define BIT_R_WMAC_CTX_SUBTYPE_8822B(x) \ + (((x) & BIT_MASK_R_WMAC_CTX_SUBTYPE_8822B) \ + << BIT_SHIFT_R_WMAC_CTX_SUBTYPE_8822B) +#define BIT_GET_R_WMAC_CTX_SUBTYPE_8822B(x) \ + (((x) >> BIT_SHIFT_R_WMAC_CTX_SUBTYPE_8822B) & \ + BIT_MASK_R_WMAC_CTX_SUBTYPE_8822B) + +#define BIT_SHIFT_R_WMAC_RTX_SUBTYPE_8822B 0 +#define BIT_MASK_R_WMAC_RTX_SUBTYPE_8822B 0xf +#define BIT_R_WMAC_RTX_SUBTYPE_8822B(x) \ + (((x) & BIT_MASK_R_WMAC_RTX_SUBTYPE_8822B) \ + << BIT_SHIFT_R_WMAC_RTX_SUBTYPE_8822B) +#define BIT_GET_R_WMAC_RTX_SUBTYPE_8822B(x) \ + (((x) >> BIT_SHIFT_R_WMAC_RTX_SUBTYPE_8822B) & \ + BIT_MASK_R_WMAC_RTX_SUBTYPE_8822B) + +/* 2 REG_WMAC_SWAES_CFG_8822B */ + +/* 2 REG_BT_COEX_V2_8822B */ +#define BIT_GNT_BT_POLARITY_8822B BIT(12) +#define BIT_GNT_BT_BYPASS_PRIORITY_8822B BIT(8) + +#define BIT_SHIFT_TIMER_8822B 0 +#define BIT_MASK_TIMER_8822B 0xff +#define BIT_TIMER_8822B(x) \ + (((x) & BIT_MASK_TIMER_8822B) << BIT_SHIFT_TIMER_8822B) +#define BIT_GET_TIMER_8822B(x) \ + (((x) >> BIT_SHIFT_TIMER_8822B) & BIT_MASK_TIMER_8822B) + +/* 2 REG_BT_COEX_8822B */ +#define BIT_R_GNT_BT_RFC_SW_8822B BIT(12) +#define BIT_R_GNT_BT_RFC_SW_EN_8822B BIT(11) +#define BIT_R_GNT_BT_BB_SW_8822B BIT(10) +#define BIT_R_GNT_BT_BB_SW_EN_8822B BIT(9) +#define BIT_R_BT_CNT_THREN_8822B BIT(8) + +#define BIT_SHIFT_R_BT_CNT_THR_8822B 0 +#define BIT_MASK_R_BT_CNT_THR_8822B 0xff +#define BIT_R_BT_CNT_THR_8822B(x) \ + (((x) & BIT_MASK_R_BT_CNT_THR_8822B) << BIT_SHIFT_R_BT_CNT_THR_8822B) +#define BIT_GET_R_BT_CNT_THR_8822B(x) \ + (((x) >> BIT_SHIFT_R_BT_CNT_THR_8822B) & BIT_MASK_R_BT_CNT_THR_8822B) + +/* 2 REG_WLAN_ACT_MASK_CTRL_8822B */ +#define BIT_WLRX_TER_BY_CTL_8822B BIT(43) +#define BIT_WLRX_TER_BY_AD_8822B BIT(42) +#define BIT_ANT_DIVERSITY_SEL_8822B BIT(41) +#define BIT_ANTSEL_FOR_BT_CTRL_EN_8822B BIT(40) +#define BIT_WLACT_LOW_GNTWL_EN_8822B BIT(34) +#define BIT_WLACT_HIGH_GNTBT_EN_8822B BIT(33) +#define BIT_NAV_UPPER_V1_8822B BIT(32) + +#define BIT_SHIFT_RXMYRTS_NAV_V1_8822B 8 +#define BIT_MASK_RXMYRTS_NAV_V1_8822B 0xff +#define BIT_RXMYRTS_NAV_V1_8822B(x) \ + (((x) & BIT_MASK_RXMYRTS_NAV_V1_8822B) \ + << BIT_SHIFT_RXMYRTS_NAV_V1_8822B) +#define BIT_GET_RXMYRTS_NAV_V1_8822B(x) \ + (((x) >> BIT_SHIFT_RXMYRTS_NAV_V1_8822B) & \ + BIT_MASK_RXMYRTS_NAV_V1_8822B) + +#define BIT_SHIFT_RTSRST_V1_8822B 0 +#define BIT_MASK_RTSRST_V1_8822B 0xff +#define BIT_RTSRST_V1_8822B(x) \ + (((x) & BIT_MASK_RTSRST_V1_8822B) << BIT_SHIFT_RTSRST_V1_8822B) +#define BIT_GET_RTSRST_V1_8822B(x) \ + (((x) >> BIT_SHIFT_RTSRST_V1_8822B) & BIT_MASK_RTSRST_V1_8822B) + +/* 2 REG_BT_COEX_ENHANCED_INTR_CTRL_8822B */ + +#define BIT_SHIFT_BT_STAT_DELAY_8822B 12 +#define BIT_MASK_BT_STAT_DELAY_8822B 0xf +#define BIT_BT_STAT_DELAY_8822B(x) \ + (((x) & BIT_MASK_BT_STAT_DELAY_8822B) << BIT_SHIFT_BT_STAT_DELAY_8822B) +#define BIT_GET_BT_STAT_DELAY_8822B(x) \ + (((x) >> BIT_SHIFT_BT_STAT_DELAY_8822B) & BIT_MASK_BT_STAT_DELAY_8822B) + +#define BIT_SHIFT_BT_TRX_INIT_DETECT_8822B 8 +#define BIT_MASK_BT_TRX_INIT_DETECT_8822B 0xf +#define BIT_BT_TRX_INIT_DETECT_8822B(x) \ + (((x) & BIT_MASK_BT_TRX_INIT_DETECT_8822B) \ + << BIT_SHIFT_BT_TRX_INIT_DETECT_8822B) +#define BIT_GET_BT_TRX_INIT_DETECT_8822B(x) \ + (((x) >> BIT_SHIFT_BT_TRX_INIT_DETECT_8822B) & \ + BIT_MASK_BT_TRX_INIT_DETECT_8822B) + +#define BIT_SHIFT_BT_PRI_DETECT_TO_8822B 4 +#define BIT_MASK_BT_PRI_DETECT_TO_8822B 0xf +#define BIT_BT_PRI_DETECT_TO_8822B(x) \ + (((x) & BIT_MASK_BT_PRI_DETECT_TO_8822B) \ + << BIT_SHIFT_BT_PRI_DETECT_TO_8822B) +#define BIT_GET_BT_PRI_DETECT_TO_8822B(x) \ + (((x) >> BIT_SHIFT_BT_PRI_DETECT_TO_8822B) & \ + BIT_MASK_BT_PRI_DETECT_TO_8822B) + +#define BIT_R_GRANTALL_WLMASK_8822B BIT(3) +#define BIT_STATIS_BT_EN_8822B BIT(2) +#define BIT_WL_ACT_MASK_ENABLE_8822B BIT(1) +#define BIT_ENHANCED_BT_8822B BIT(0) + +/* 2 REG_BT_ACT_STATISTICS_8822B */ + +#define BIT_SHIFT_STATIS_BT_LO_RX_8822B (48 & CPU_OPT_WIDTH) +#define BIT_MASK_STATIS_BT_LO_RX_8822B 0xffff +#define BIT_STATIS_BT_LO_RX_8822B(x) \ + (((x) & BIT_MASK_STATIS_BT_LO_RX_8822B) \ + << BIT_SHIFT_STATIS_BT_LO_RX_8822B) +#define BIT_GET_STATIS_BT_LO_RX_8822B(x) \ + (((x) >> BIT_SHIFT_STATIS_BT_LO_RX_8822B) & \ + BIT_MASK_STATIS_BT_LO_RX_8822B) + +#define BIT_SHIFT_STATIS_BT_LO_TX_8822B (32 & CPU_OPT_WIDTH) +#define BIT_MASK_STATIS_BT_LO_TX_8822B 0xffff +#define BIT_STATIS_BT_LO_TX_8822B(x) \ + (((x) & BIT_MASK_STATIS_BT_LO_TX_8822B) \ + << BIT_SHIFT_STATIS_BT_LO_TX_8822B) +#define BIT_GET_STATIS_BT_LO_TX_8822B(x) \ + (((x) >> BIT_SHIFT_STATIS_BT_LO_TX_8822B) & \ + BIT_MASK_STATIS_BT_LO_TX_8822B) + +#define BIT_SHIFT_STATIS_BT_HI_RX_8822B 16 +#define BIT_MASK_STATIS_BT_HI_RX_8822B 0xffff +#define BIT_STATIS_BT_HI_RX_8822B(x) \ + (((x) & BIT_MASK_STATIS_BT_HI_RX_8822B) \ + << BIT_SHIFT_STATIS_BT_HI_RX_8822B) +#define BIT_GET_STATIS_BT_HI_RX_8822B(x) \ + (((x) >> BIT_SHIFT_STATIS_BT_HI_RX_8822B) & \ + BIT_MASK_STATIS_BT_HI_RX_8822B) + +#define BIT_SHIFT_STATIS_BT_HI_TX_8822B 0 +#define BIT_MASK_STATIS_BT_HI_TX_8822B 0xffff +#define BIT_STATIS_BT_HI_TX_8822B(x) \ + (((x) & BIT_MASK_STATIS_BT_HI_TX_8822B) \ + << BIT_SHIFT_STATIS_BT_HI_TX_8822B) +#define BIT_GET_STATIS_BT_HI_TX_8822B(x) \ + (((x) >> BIT_SHIFT_STATIS_BT_HI_TX_8822B) & \ + BIT_MASK_STATIS_BT_HI_TX_8822B) + +/* 2 REG_BT_STATISTICS_CONTROL_REGISTER_8822B */ + +#define BIT_SHIFT_R_BT_CMD_RPT_8822B 16 +#define BIT_MASK_R_BT_CMD_RPT_8822B 0xffff +#define BIT_R_BT_CMD_RPT_8822B(x) \ + (((x) & BIT_MASK_R_BT_CMD_RPT_8822B) << BIT_SHIFT_R_BT_CMD_RPT_8822B) +#define BIT_GET_R_BT_CMD_RPT_8822B(x) \ + (((x) >> BIT_SHIFT_R_BT_CMD_RPT_8822B) & BIT_MASK_R_BT_CMD_RPT_8822B) + +#define BIT_SHIFT_R_RPT_FROM_BT_8822B 8 +#define BIT_MASK_R_RPT_FROM_BT_8822B 0xff +#define BIT_R_RPT_FROM_BT_8822B(x) \ + (((x) & BIT_MASK_R_RPT_FROM_BT_8822B) << BIT_SHIFT_R_RPT_FROM_BT_8822B) +#define BIT_GET_R_RPT_FROM_BT_8822B(x) \ + (((x) >> BIT_SHIFT_R_RPT_FROM_BT_8822B) & BIT_MASK_R_RPT_FROM_BT_8822B) + +#define BIT_SHIFT_BT_HID_ISR_SET_8822B 6 +#define BIT_MASK_BT_HID_ISR_SET_8822B 0x3 +#define BIT_BT_HID_ISR_SET_8822B(x) \ + (((x) & BIT_MASK_BT_HID_ISR_SET_8822B) \ + << BIT_SHIFT_BT_HID_ISR_SET_8822B) +#define BIT_GET_BT_HID_ISR_SET_8822B(x) \ + (((x) >> BIT_SHIFT_BT_HID_ISR_SET_8822B) & \ + BIT_MASK_BT_HID_ISR_SET_8822B) + +#define BIT_TDMA_BT_START_NOTIFY_8822B BIT(5) +#define BIT_ENABLE_TDMA_FW_MODE_8822B BIT(4) +#define BIT_ENABLE_PTA_TDMA_MODE_8822B BIT(3) +#define BIT_ENABLE_COEXIST_TAB_IN_TDMA_8822B BIT(2) +#define BIT_GPIO2_GPIO3_EXANGE_OR_NO_BT_CCA_8822B BIT(1) +#define BIT_RTK_BT_ENABLE_8822B BIT(0) + +/* 2 REG_BT_STATUS_REPORT_REGISTER_8822B */ + +#define BIT_SHIFT_BT_PROFILE_8822B 24 +#define BIT_MASK_BT_PROFILE_8822B 0xff +#define BIT_BT_PROFILE_8822B(x) \ + (((x) & BIT_MASK_BT_PROFILE_8822B) << BIT_SHIFT_BT_PROFILE_8822B) +#define BIT_GET_BT_PROFILE_8822B(x) \ + (((x) >> BIT_SHIFT_BT_PROFILE_8822B) & BIT_MASK_BT_PROFILE_8822B) + +#define BIT_SHIFT_BT_POWER_8822B 16 +#define BIT_MASK_BT_POWER_8822B 0xff +#define BIT_BT_POWER_8822B(x) \ + (((x) & BIT_MASK_BT_POWER_8822B) << BIT_SHIFT_BT_POWER_8822B) +#define BIT_GET_BT_POWER_8822B(x) \ + (((x) >> BIT_SHIFT_BT_POWER_8822B) & BIT_MASK_BT_POWER_8822B) + +#define BIT_SHIFT_BT_PREDECT_STATUS_8822B 8 +#define BIT_MASK_BT_PREDECT_STATUS_8822B 0xff +#define BIT_BT_PREDECT_STATUS_8822B(x) \ + (((x) & BIT_MASK_BT_PREDECT_STATUS_8822B) \ + << BIT_SHIFT_BT_PREDECT_STATUS_8822B) +#define BIT_GET_BT_PREDECT_STATUS_8822B(x) \ + (((x) >> BIT_SHIFT_BT_PREDECT_STATUS_8822B) & \ + BIT_MASK_BT_PREDECT_STATUS_8822B) + +#define BIT_SHIFT_BT_CMD_INFO_8822B 0 +#define BIT_MASK_BT_CMD_INFO_8822B 0xff +#define BIT_BT_CMD_INFO_8822B(x) \ + (((x) & BIT_MASK_BT_CMD_INFO_8822B) << BIT_SHIFT_BT_CMD_INFO_8822B) +#define BIT_GET_BT_CMD_INFO_8822B(x) \ + (((x) >> BIT_SHIFT_BT_CMD_INFO_8822B) & BIT_MASK_BT_CMD_INFO_8822B) + +/* 2 REG_BT_INTERRUPT_CONTROL_REGISTER_8822B */ +#define BIT_EN_MAC_NULL_PKT_NOTIFY_8822B BIT(31) +#define BIT_EN_WLAN_RPT_AND_BT_QUERY_8822B BIT(30) +#define BIT_EN_BT_STSTUS_RPT_8822B BIT(29) +#define BIT_EN_BT_POWER_8822B BIT(28) +#define BIT_EN_BT_CHANNEL_8822B BIT(27) +#define BIT_EN_BT_SLOT_CHANGE_8822B BIT(26) +#define BIT_EN_BT_PROFILE_OR_HID_8822B BIT(25) +#define BIT_WLAN_RPT_NOTIFY_8822B BIT(24) + +#define BIT_SHIFT_WLAN_RPT_DATA_8822B 16 +#define BIT_MASK_WLAN_RPT_DATA_8822B 0xff +#define BIT_WLAN_RPT_DATA_8822B(x) \ + (((x) & BIT_MASK_WLAN_RPT_DATA_8822B) << BIT_SHIFT_WLAN_RPT_DATA_8822B) +#define BIT_GET_WLAN_RPT_DATA_8822B(x) \ + (((x) >> BIT_SHIFT_WLAN_RPT_DATA_8822B) & BIT_MASK_WLAN_RPT_DATA_8822B) + +#define BIT_SHIFT_CMD_ID_8822B 8 +#define BIT_MASK_CMD_ID_8822B 0xff +#define BIT_CMD_ID_8822B(x) \ + (((x) & BIT_MASK_CMD_ID_8822B) << BIT_SHIFT_CMD_ID_8822B) +#define BIT_GET_CMD_ID_8822B(x) \ + (((x) >> BIT_SHIFT_CMD_ID_8822B) & BIT_MASK_CMD_ID_8822B) + +#define BIT_SHIFT_BT_DATA_8822B 0 +#define BIT_MASK_BT_DATA_8822B 0xff +#define BIT_BT_DATA_8822B(x) \ + (((x) & BIT_MASK_BT_DATA_8822B) << BIT_SHIFT_BT_DATA_8822B) +#define BIT_GET_BT_DATA_8822B(x) \ + (((x) >> BIT_SHIFT_BT_DATA_8822B) & BIT_MASK_BT_DATA_8822B) + +/* 2 REG_WLAN_REPORT_TIME_OUT_CONTROL_REGISTER_8822B */ + +#define BIT_SHIFT_WLAN_RPT_TO_8822B 0 +#define BIT_MASK_WLAN_RPT_TO_8822B 0xff +#define BIT_WLAN_RPT_TO_8822B(x) \ + (((x) & BIT_MASK_WLAN_RPT_TO_8822B) << BIT_SHIFT_WLAN_RPT_TO_8822B) +#define BIT_GET_WLAN_RPT_TO_8822B(x) \ + (((x) >> BIT_SHIFT_WLAN_RPT_TO_8822B) & BIT_MASK_WLAN_RPT_TO_8822B) + +/* 2 REG_BT_ISOLATION_TABLE_REGISTER_REGISTER_8822B */ + +#define BIT_SHIFT_ISOLATION_CHK_8822B 1 +#define BIT_MASK_ISOLATION_CHK_8822B 0x7fffffffffffffffffffL +#define BIT_ISOLATION_CHK_8822B(x) \ + (((x) & BIT_MASK_ISOLATION_CHK_8822B) << BIT_SHIFT_ISOLATION_CHK_8822B) +#define BIT_GET_ISOLATION_CHK_8822B(x) \ + (((x) >> BIT_SHIFT_ISOLATION_CHK_8822B) & BIT_MASK_ISOLATION_CHK_8822B) + +#define BIT_ISOLATION_EN_8822B BIT(0) + +/* 2 REG_BT_INTERRUPT_STATUS_REGISTER_8822B */ +#define BIT_BT_HID_ISR_8822B BIT(7) +#define BIT_BT_QUERY_ISR_8822B BIT(6) +#define BIT_MAC_NULL_PKT_NOTIFY_ISR_8822B BIT(5) +#define BIT_WLAN_RPT_ISR_8822B BIT(4) +#define BIT_BT_POWER_ISR_8822B BIT(3) +#define BIT_BT_CHANNEL_ISR_8822B BIT(2) +#define BIT_BT_SLOT_CHANGE_ISR_8822B BIT(1) +#define BIT_BT_PROFILE_ISR_8822B BIT(0) + +/* 2 REG_BT_TDMA_TIME_REGISTER_8822B */ + +#define BIT_SHIFT_BT_TIME_8822B 6 +#define BIT_MASK_BT_TIME_8822B 0x3ffffff +#define BIT_BT_TIME_8822B(x) \ + (((x) & BIT_MASK_BT_TIME_8822B) << BIT_SHIFT_BT_TIME_8822B) +#define BIT_GET_BT_TIME_8822B(x) \ + (((x) >> BIT_SHIFT_BT_TIME_8822B) & BIT_MASK_BT_TIME_8822B) + +#define BIT_SHIFT_BT_RPT_SAMPLE_RATE_8822B 0 +#define BIT_MASK_BT_RPT_SAMPLE_RATE_8822B 0x3f +#define BIT_BT_RPT_SAMPLE_RATE_8822B(x) \ + (((x) & BIT_MASK_BT_RPT_SAMPLE_RATE_8822B) \ + << BIT_SHIFT_BT_RPT_SAMPLE_RATE_8822B) +#define BIT_GET_BT_RPT_SAMPLE_RATE_8822B(x) \ + (((x) >> BIT_SHIFT_BT_RPT_SAMPLE_RATE_8822B) & \ + BIT_MASK_BT_RPT_SAMPLE_RATE_8822B) + +/* 2 REG_BT_ACT_REGISTER_8822B */ + +#define BIT_SHIFT_BT_EISR_EN_8822B 16 +#define BIT_MASK_BT_EISR_EN_8822B 0xff +#define BIT_BT_EISR_EN_8822B(x) \ + (((x) & BIT_MASK_BT_EISR_EN_8822B) << BIT_SHIFT_BT_EISR_EN_8822B) +#define BIT_GET_BT_EISR_EN_8822B(x) \ + (((x) >> BIT_SHIFT_BT_EISR_EN_8822B) & BIT_MASK_BT_EISR_EN_8822B) + +#define BIT_BT_ACT_FALLING_ISR_8822B BIT(10) +#define BIT_BT_ACT_RISING_ISR_8822B BIT(9) +#define BIT_TDMA_TO_ISR_8822B BIT(8) + +#define BIT_SHIFT_BT_CH_8822B 0 +#define BIT_MASK_BT_CH_8822B 0xff +#define BIT_BT_CH_8822B(x) \ + (((x) & BIT_MASK_BT_CH_8822B) << BIT_SHIFT_BT_CH_8822B) +#define BIT_GET_BT_CH_8822B(x) \ + (((x) >> BIT_SHIFT_BT_CH_8822B) & BIT_MASK_BT_CH_8822B) + +/* 2 REG_OBFF_CTRL_BASIC_8822B */ +#define BIT_OBFF_EN_V1_8822B BIT(31) + +#define BIT_SHIFT_OBFF_STATE_V1_8822B 28 +#define BIT_MASK_OBFF_STATE_V1_8822B 0x3 +#define BIT_OBFF_STATE_V1_8822B(x) \ + (((x) & BIT_MASK_OBFF_STATE_V1_8822B) << BIT_SHIFT_OBFF_STATE_V1_8822B) +#define BIT_GET_OBFF_STATE_V1_8822B(x) \ + (((x) >> BIT_SHIFT_OBFF_STATE_V1_8822B) & BIT_MASK_OBFF_STATE_V1_8822B) + +#define BIT_OBFF_ACT_RXDMA_EN_8822B BIT(27) +#define BIT_OBFF_BLOCK_INT_EN_8822B BIT(26) +#define BIT_OBFF_AUTOACT_EN_8822B BIT(25) +#define BIT_OBFF_AUTOIDLE_EN_8822B BIT(24) + +#define BIT_SHIFT_WAKE_MAX_PLS_8822B 20 +#define BIT_MASK_WAKE_MAX_PLS_8822B 0x7 +#define BIT_WAKE_MAX_PLS_8822B(x) \ + (((x) & BIT_MASK_WAKE_MAX_PLS_8822B) << BIT_SHIFT_WAKE_MAX_PLS_8822B) +#define BIT_GET_WAKE_MAX_PLS_8822B(x) \ + (((x) >> BIT_SHIFT_WAKE_MAX_PLS_8822B) & BIT_MASK_WAKE_MAX_PLS_8822B) + +#define BIT_SHIFT_WAKE_MIN_PLS_8822B 16 +#define BIT_MASK_WAKE_MIN_PLS_8822B 0x7 +#define BIT_WAKE_MIN_PLS_8822B(x) \ + (((x) & BIT_MASK_WAKE_MIN_PLS_8822B) << BIT_SHIFT_WAKE_MIN_PLS_8822B) +#define BIT_GET_WAKE_MIN_PLS_8822B(x) \ + (((x) >> BIT_SHIFT_WAKE_MIN_PLS_8822B) & BIT_MASK_WAKE_MIN_PLS_8822B) + +#define BIT_SHIFT_WAKE_MAX_F2F_8822B 12 +#define BIT_MASK_WAKE_MAX_F2F_8822B 0x7 +#define BIT_WAKE_MAX_F2F_8822B(x) \ + (((x) & BIT_MASK_WAKE_MAX_F2F_8822B) << BIT_SHIFT_WAKE_MAX_F2F_8822B) +#define BIT_GET_WAKE_MAX_F2F_8822B(x) \ + (((x) >> BIT_SHIFT_WAKE_MAX_F2F_8822B) & BIT_MASK_WAKE_MAX_F2F_8822B) + +#define BIT_SHIFT_WAKE_MIN_F2F_8822B 8 +#define BIT_MASK_WAKE_MIN_F2F_8822B 0x7 +#define BIT_WAKE_MIN_F2F_8822B(x) \ + (((x) & BIT_MASK_WAKE_MIN_F2F_8822B) << BIT_SHIFT_WAKE_MIN_F2F_8822B) +#define BIT_GET_WAKE_MIN_F2F_8822B(x) \ + (((x) >> BIT_SHIFT_WAKE_MIN_F2F_8822B) & BIT_MASK_WAKE_MIN_F2F_8822B) + +#define BIT_APP_CPU_ACT_V1_8822B BIT(3) +#define BIT_APP_OBFF_V1_8822B BIT(2) +#define BIT_APP_IDLE_V1_8822B BIT(1) +#define BIT_APP_INIT_V1_8822B BIT(0) + +/* 2 REG_OBFF_CTRL2_TIMER_8822B */ + +#define BIT_SHIFT_RX_HIGH_TIMER_IDX_8822B 24 +#define BIT_MASK_RX_HIGH_TIMER_IDX_8822B 0x7 +#define BIT_RX_HIGH_TIMER_IDX_8822B(x) \ + (((x) & BIT_MASK_RX_HIGH_TIMER_IDX_8822B) \ + << BIT_SHIFT_RX_HIGH_TIMER_IDX_8822B) +#define BIT_GET_RX_HIGH_TIMER_IDX_8822B(x) \ + (((x) >> BIT_SHIFT_RX_HIGH_TIMER_IDX_8822B) & \ + BIT_MASK_RX_HIGH_TIMER_IDX_8822B) + +#define BIT_SHIFT_RX_MED_TIMER_IDX_8822B 16 +#define BIT_MASK_RX_MED_TIMER_IDX_8822B 0x7 +#define BIT_RX_MED_TIMER_IDX_8822B(x) \ + (((x) & BIT_MASK_RX_MED_TIMER_IDX_8822B) \ + << BIT_SHIFT_RX_MED_TIMER_IDX_8822B) +#define BIT_GET_RX_MED_TIMER_IDX_8822B(x) \ + (((x) >> BIT_SHIFT_RX_MED_TIMER_IDX_8822B) & \ + BIT_MASK_RX_MED_TIMER_IDX_8822B) + +#define BIT_SHIFT_RX_LOW_TIMER_IDX_8822B 8 +#define BIT_MASK_RX_LOW_TIMER_IDX_8822B 0x7 +#define BIT_RX_LOW_TIMER_IDX_8822B(x) \ + (((x) & BIT_MASK_RX_LOW_TIMER_IDX_8822B) \ + << BIT_SHIFT_RX_LOW_TIMER_IDX_8822B) +#define BIT_GET_RX_LOW_TIMER_IDX_8822B(x) \ + (((x) >> BIT_SHIFT_RX_LOW_TIMER_IDX_8822B) & \ + BIT_MASK_RX_LOW_TIMER_IDX_8822B) + +#define BIT_SHIFT_OBFF_INT_TIMER_IDX_8822B 0 +#define BIT_MASK_OBFF_INT_TIMER_IDX_8822B 0x7 +#define BIT_OBFF_INT_TIMER_IDX_8822B(x) \ + (((x) & BIT_MASK_OBFF_INT_TIMER_IDX_8822B) \ + << BIT_SHIFT_OBFF_INT_TIMER_IDX_8822B) +#define BIT_GET_OBFF_INT_TIMER_IDX_8822B(x) \ + (((x) >> BIT_SHIFT_OBFF_INT_TIMER_IDX_8822B) & \ + BIT_MASK_OBFF_INT_TIMER_IDX_8822B) + +/* 2 REG_LTR_CTRL_BASIC_8822B */ +#define BIT_LTR_EN_V1_8822B BIT(31) +#define BIT_LTR_HW_EN_V1_8822B BIT(30) +#define BIT_LRT_ACT_CTS_EN_8822B BIT(29) +#define BIT_LTR_ACT_RXPKT_EN_8822B BIT(28) +#define BIT_LTR_ACT_RXDMA_EN_8822B BIT(27) +#define BIT_LTR_IDLE_NO_SNOOP_8822B BIT(26) +#define BIT_SPDUP_MGTPKT_8822B BIT(25) +#define BIT_RX_AGG_EN_8822B BIT(24) +#define BIT_APP_LTR_ACT_8822B BIT(23) +#define BIT_APP_LTR_IDLE_8822B BIT(22) + +#define BIT_SHIFT_HIGH_RATE_TRIG_SEL_8822B 20 +#define BIT_MASK_HIGH_RATE_TRIG_SEL_8822B 0x3 +#define BIT_HIGH_RATE_TRIG_SEL_8822B(x) \ + (((x) & BIT_MASK_HIGH_RATE_TRIG_SEL_8822B) \ + << BIT_SHIFT_HIGH_RATE_TRIG_SEL_8822B) +#define BIT_GET_HIGH_RATE_TRIG_SEL_8822B(x) \ + (((x) >> BIT_SHIFT_HIGH_RATE_TRIG_SEL_8822B) & \ + BIT_MASK_HIGH_RATE_TRIG_SEL_8822B) + +#define BIT_SHIFT_MED_RATE_TRIG_SEL_8822B 18 +#define BIT_MASK_MED_RATE_TRIG_SEL_8822B 0x3 +#define BIT_MED_RATE_TRIG_SEL_8822B(x) \ + (((x) & BIT_MASK_MED_RATE_TRIG_SEL_8822B) \ + << BIT_SHIFT_MED_RATE_TRIG_SEL_8822B) +#define BIT_GET_MED_RATE_TRIG_SEL_8822B(x) \ + (((x) >> BIT_SHIFT_MED_RATE_TRIG_SEL_8822B) & \ + BIT_MASK_MED_RATE_TRIG_SEL_8822B) + +#define BIT_SHIFT_LOW_RATE_TRIG_SEL_8822B 16 +#define BIT_MASK_LOW_RATE_TRIG_SEL_8822B 0x3 +#define BIT_LOW_RATE_TRIG_SEL_8822B(x) \ + (((x) & BIT_MASK_LOW_RATE_TRIG_SEL_8822B) \ + << BIT_SHIFT_LOW_RATE_TRIG_SEL_8822B) +#define BIT_GET_LOW_RATE_TRIG_SEL_8822B(x) \ + (((x) >> BIT_SHIFT_LOW_RATE_TRIG_SEL_8822B) & \ + BIT_MASK_LOW_RATE_TRIG_SEL_8822B) + +#define BIT_SHIFT_HIGH_RATE_BD_IDX_8822B 8 +#define BIT_MASK_HIGH_RATE_BD_IDX_8822B 0x7f +#define BIT_HIGH_RATE_BD_IDX_8822B(x) \ + (((x) & BIT_MASK_HIGH_RATE_BD_IDX_8822B) \ + << BIT_SHIFT_HIGH_RATE_BD_IDX_8822B) +#define BIT_GET_HIGH_RATE_BD_IDX_8822B(x) \ + (((x) >> BIT_SHIFT_HIGH_RATE_BD_IDX_8822B) & \ + BIT_MASK_HIGH_RATE_BD_IDX_8822B) + +#define BIT_SHIFT_LOW_RATE_BD_IDX_8822B 0 +#define BIT_MASK_LOW_RATE_BD_IDX_8822B 0x7f +#define BIT_LOW_RATE_BD_IDX_8822B(x) \ + (((x) & BIT_MASK_LOW_RATE_BD_IDX_8822B) \ + << BIT_SHIFT_LOW_RATE_BD_IDX_8822B) +#define BIT_GET_LOW_RATE_BD_IDX_8822B(x) \ + (((x) >> BIT_SHIFT_LOW_RATE_BD_IDX_8822B) & \ + BIT_MASK_LOW_RATE_BD_IDX_8822B) + +/* 2 REG_LTR_CTRL2_TIMER_THRESHOLD_8822B */ + +#define BIT_SHIFT_RX_EMPTY_TIMER_IDX_8822B 24 +#define BIT_MASK_RX_EMPTY_TIMER_IDX_8822B 0x7 +#define BIT_RX_EMPTY_TIMER_IDX_8822B(x) \ + (((x) & BIT_MASK_RX_EMPTY_TIMER_IDX_8822B) \ + << BIT_SHIFT_RX_EMPTY_TIMER_IDX_8822B) +#define BIT_GET_RX_EMPTY_TIMER_IDX_8822B(x) \ + (((x) >> BIT_SHIFT_RX_EMPTY_TIMER_IDX_8822B) & \ + BIT_MASK_RX_EMPTY_TIMER_IDX_8822B) + +#define BIT_SHIFT_RX_AFULL_TH_IDX_8822B 20 +#define BIT_MASK_RX_AFULL_TH_IDX_8822B 0x7 +#define BIT_RX_AFULL_TH_IDX_8822B(x) \ + (((x) & BIT_MASK_RX_AFULL_TH_IDX_8822B) \ + << BIT_SHIFT_RX_AFULL_TH_IDX_8822B) +#define BIT_GET_RX_AFULL_TH_IDX_8822B(x) \ + (((x) >> BIT_SHIFT_RX_AFULL_TH_IDX_8822B) & \ + BIT_MASK_RX_AFULL_TH_IDX_8822B) + +#define BIT_SHIFT_RX_HIGH_TH_IDX_8822B 16 +#define BIT_MASK_RX_HIGH_TH_IDX_8822B 0x7 +#define BIT_RX_HIGH_TH_IDX_8822B(x) \ + (((x) & BIT_MASK_RX_HIGH_TH_IDX_8822B) \ + << BIT_SHIFT_RX_HIGH_TH_IDX_8822B) +#define BIT_GET_RX_HIGH_TH_IDX_8822B(x) \ + (((x) >> BIT_SHIFT_RX_HIGH_TH_IDX_8822B) & \ + BIT_MASK_RX_HIGH_TH_IDX_8822B) + +#define BIT_SHIFT_RX_MED_TH_IDX_8822B 12 +#define BIT_MASK_RX_MED_TH_IDX_8822B 0x7 +#define BIT_RX_MED_TH_IDX_8822B(x) \ + (((x) & BIT_MASK_RX_MED_TH_IDX_8822B) << BIT_SHIFT_RX_MED_TH_IDX_8822B) +#define BIT_GET_RX_MED_TH_IDX_8822B(x) \ + (((x) >> BIT_SHIFT_RX_MED_TH_IDX_8822B) & BIT_MASK_RX_MED_TH_IDX_8822B) + +#define BIT_SHIFT_RX_LOW_TH_IDX_8822B 8 +#define BIT_MASK_RX_LOW_TH_IDX_8822B 0x7 +#define BIT_RX_LOW_TH_IDX_8822B(x) \ + (((x) & BIT_MASK_RX_LOW_TH_IDX_8822B) << BIT_SHIFT_RX_LOW_TH_IDX_8822B) +#define BIT_GET_RX_LOW_TH_IDX_8822B(x) \ + (((x) >> BIT_SHIFT_RX_LOW_TH_IDX_8822B) & BIT_MASK_RX_LOW_TH_IDX_8822B) + +#define BIT_SHIFT_LTR_SPACE_IDX_8822B 4 +#define BIT_MASK_LTR_SPACE_IDX_8822B 0x3 +#define BIT_LTR_SPACE_IDX_8822B(x) \ + (((x) & BIT_MASK_LTR_SPACE_IDX_8822B) << BIT_SHIFT_LTR_SPACE_IDX_8822B) +#define BIT_GET_LTR_SPACE_IDX_8822B(x) \ + (((x) >> BIT_SHIFT_LTR_SPACE_IDX_8822B) & BIT_MASK_LTR_SPACE_IDX_8822B) + +#define BIT_SHIFT_LTR_IDLE_TIMER_IDX_8822B 0 +#define BIT_MASK_LTR_IDLE_TIMER_IDX_8822B 0x7 +#define BIT_LTR_IDLE_TIMER_IDX_8822B(x) \ + (((x) & BIT_MASK_LTR_IDLE_TIMER_IDX_8822B) \ + << BIT_SHIFT_LTR_IDLE_TIMER_IDX_8822B) +#define BIT_GET_LTR_IDLE_TIMER_IDX_8822B(x) \ + (((x) >> BIT_SHIFT_LTR_IDLE_TIMER_IDX_8822B) & \ + BIT_MASK_LTR_IDLE_TIMER_IDX_8822B) + +/* 2 REG_LTR_IDLE_LATENCY_V1_8822B */ + +#define BIT_SHIFT_LTR_IDLE_L_8822B 0 +#define BIT_MASK_LTR_IDLE_L_8822B 0xffffffffL +#define BIT_LTR_IDLE_L_8822B(x) \ + (((x) & BIT_MASK_LTR_IDLE_L_8822B) << BIT_SHIFT_LTR_IDLE_L_8822B) +#define BIT_GET_LTR_IDLE_L_8822B(x) \ + (((x) >> BIT_SHIFT_LTR_IDLE_L_8822B) & BIT_MASK_LTR_IDLE_L_8822B) + +/* 2 REG_LTR_ACTIVE_LATENCY_V1_8822B */ + +#define BIT_SHIFT_LTR_ACT_L_8822B 0 +#define BIT_MASK_LTR_ACT_L_8822B 0xffffffffL +#define BIT_LTR_ACT_L_8822B(x) \ + (((x) & BIT_MASK_LTR_ACT_L_8822B) << BIT_SHIFT_LTR_ACT_L_8822B) +#define BIT_GET_LTR_ACT_L_8822B(x) \ + (((x) >> BIT_SHIFT_LTR_ACT_L_8822B) & BIT_MASK_LTR_ACT_L_8822B) + +/* 2 REG_ANTENNA_TRAINING_CONTROL_REGISTER_8822B */ +#define BIT_APPEND_MACID_IN_RESP_EN_8822B BIT(50) +#define BIT_ADDR2_MATCH_EN_8822B BIT(49) +#define BIT_ANTTRN_EN_8822B BIT(48) + +#define BIT_SHIFT_TRAIN_STA_ADDR_8822B 0 +#define BIT_MASK_TRAIN_STA_ADDR_8822B 0xffffffffffffL +#define BIT_TRAIN_STA_ADDR_8822B(x) \ + (((x) & BIT_MASK_TRAIN_STA_ADDR_8822B) \ + << BIT_SHIFT_TRAIN_STA_ADDR_8822B) +#define BIT_GET_TRAIN_STA_ADDR_8822B(x) \ + (((x) >> BIT_SHIFT_TRAIN_STA_ADDR_8822B) & \ + BIT_MASK_TRAIN_STA_ADDR_8822B) + +/* 2 REG_RSVD_0X7B4_8822B */ + +/* 2 REG_WMAC_PKTCNT_RWD_8822B */ + +#define BIT_SHIFT_PKTCNT_BSSIDMAP_8822B 4 +#define BIT_MASK_PKTCNT_BSSIDMAP_8822B 0xf +#define BIT_PKTCNT_BSSIDMAP_8822B(x) \ + (((x) & BIT_MASK_PKTCNT_BSSIDMAP_8822B) \ + << BIT_SHIFT_PKTCNT_BSSIDMAP_8822B) +#define BIT_GET_PKTCNT_BSSIDMAP_8822B(x) \ + (((x) >> BIT_SHIFT_PKTCNT_BSSIDMAP_8822B) & \ + BIT_MASK_PKTCNT_BSSIDMAP_8822B) + +#define BIT_PKTCNT_CNTRST_8822B BIT(1) +#define BIT_PKTCNT_CNTEN_8822B BIT(0) + +/* 2 REG_WMAC_PKTCNT_CTRL_8822B */ +#define BIT_WMAC_PKTCNT_TRST_8822B BIT(9) +#define BIT_WMAC_PKTCNT_FEN_8822B BIT(8) + +#define BIT_SHIFT_WMAC_PKTCNT_CFGAD_8822B 0 +#define BIT_MASK_WMAC_PKTCNT_CFGAD_8822B 0xff +#define BIT_WMAC_PKTCNT_CFGAD_8822B(x) \ + (((x) & BIT_MASK_WMAC_PKTCNT_CFGAD_8822B) \ + << BIT_SHIFT_WMAC_PKTCNT_CFGAD_8822B) +#define BIT_GET_WMAC_PKTCNT_CFGAD_8822B(x) \ + (((x) >> BIT_SHIFT_WMAC_PKTCNT_CFGAD_8822B) & \ + BIT_MASK_WMAC_PKTCNT_CFGAD_8822B) + +/* 2 REG_IQ_DUMP_8822B */ + +#define BIT_SHIFT_R_WMAC_MATCH_REF_MAC_8822B (64 & CPU_OPT_WIDTH) +#define BIT_MASK_R_WMAC_MATCH_REF_MAC_8822B 0xffffffffL +#define BIT_R_WMAC_MATCH_REF_MAC_8822B(x) \ + (((x) & BIT_MASK_R_WMAC_MATCH_REF_MAC_8822B) \ + << BIT_SHIFT_R_WMAC_MATCH_REF_MAC_8822B) +#define BIT_GET_R_WMAC_MATCH_REF_MAC_8822B(x) \ + (((x) >> BIT_SHIFT_R_WMAC_MATCH_REF_MAC_8822B) & \ + BIT_MASK_R_WMAC_MATCH_REF_MAC_8822B) + +#define BIT_SHIFT_R_WMAC_MASK_LA_MAC_8822B (32 & CPU_OPT_WIDTH) +#define BIT_MASK_R_WMAC_MASK_LA_MAC_8822B 0xffffffffL +#define BIT_R_WMAC_MASK_LA_MAC_8822B(x) \ + (((x) & BIT_MASK_R_WMAC_MASK_LA_MAC_8822B) \ + << BIT_SHIFT_R_WMAC_MASK_LA_MAC_8822B) +#define BIT_GET_R_WMAC_MASK_LA_MAC_8822B(x) \ + (((x) >> BIT_SHIFT_R_WMAC_MASK_LA_MAC_8822B) & \ + BIT_MASK_R_WMAC_MASK_LA_MAC_8822B) + +#define BIT_SHIFT_DUMP_OK_ADDR_8822B 15 +#define BIT_MASK_DUMP_OK_ADDR_8822B 0x1ffff +#define BIT_DUMP_OK_ADDR_8822B(x) \ + (((x) & BIT_MASK_DUMP_OK_ADDR_8822B) << BIT_SHIFT_DUMP_OK_ADDR_8822B) +#define BIT_GET_DUMP_OK_ADDR_8822B(x) \ + (((x) >> BIT_SHIFT_DUMP_OK_ADDR_8822B) & BIT_MASK_DUMP_OK_ADDR_8822B) + +#define BIT_SHIFT_R_TRIG_TIME_SEL_8822B 8 +#define BIT_MASK_R_TRIG_TIME_SEL_8822B 0x7f +#define BIT_R_TRIG_TIME_SEL_8822B(x) \ + (((x) & BIT_MASK_R_TRIG_TIME_SEL_8822B) \ + << BIT_SHIFT_R_TRIG_TIME_SEL_8822B) +#define BIT_GET_R_TRIG_TIME_SEL_8822B(x) \ + (((x) >> BIT_SHIFT_R_TRIG_TIME_SEL_8822B) & \ + BIT_MASK_R_TRIG_TIME_SEL_8822B) + +#define BIT_SHIFT_R_MAC_TRIG_SEL_8822B 6 +#define BIT_MASK_R_MAC_TRIG_SEL_8822B 0x3 +#define BIT_R_MAC_TRIG_SEL_8822B(x) \ + (((x) & BIT_MASK_R_MAC_TRIG_SEL_8822B) \ + << BIT_SHIFT_R_MAC_TRIG_SEL_8822B) +#define BIT_GET_R_MAC_TRIG_SEL_8822B(x) \ + (((x) >> BIT_SHIFT_R_MAC_TRIG_SEL_8822B) & \ + BIT_MASK_R_MAC_TRIG_SEL_8822B) + +#define BIT_MAC_TRIG_REG_8822B BIT(5) + +#define BIT_SHIFT_R_LEVEL_PULSE_SEL_8822B 3 +#define BIT_MASK_R_LEVEL_PULSE_SEL_8822B 0x3 +#define BIT_R_LEVEL_PULSE_SEL_8822B(x) \ + (((x) & BIT_MASK_R_LEVEL_PULSE_SEL_8822B) \ + << BIT_SHIFT_R_LEVEL_PULSE_SEL_8822B) +#define BIT_GET_R_LEVEL_PULSE_SEL_8822B(x) \ + (((x) >> BIT_SHIFT_R_LEVEL_PULSE_SEL_8822B) & \ + BIT_MASK_R_LEVEL_PULSE_SEL_8822B) + +#define BIT_EN_LA_MAC_8822B BIT(2) +#define BIT_R_EN_IQDUMP_8822B BIT(1) +#define BIT_R_IQDATA_DUMP_8822B BIT(0) + +/* 2 REG_WMAC_FTM_CTL_8822B */ +#define BIT_RXFTM_TXACK_SC_8822B BIT(6) +#define BIT_RXFTM_TXACK_BW_8822B BIT(5) +#define BIT_RXFTM_EN_8822B BIT(3) +#define BIT_RXFTMREQ_BYDRV_8822B BIT(2) +#define BIT_RXFTMREQ_EN_8822B BIT(1) +#define BIT_FTM_EN_8822B BIT(0) + +/* 2 REG_WMAC_IQ_MDPK_FUNC_8822B */ + +/* 2 REG_WMAC_OPTION_FUNCTION_8822B */ + +#define BIT_SHIFT_R_WMAC_RX_FIL_LEN_8822B (64 & CPU_OPT_WIDTH) +#define BIT_MASK_R_WMAC_RX_FIL_LEN_8822B 0xffff +#define BIT_R_WMAC_RX_FIL_LEN_8822B(x) \ + (((x) & BIT_MASK_R_WMAC_RX_FIL_LEN_8822B) \ + << BIT_SHIFT_R_WMAC_RX_FIL_LEN_8822B) +#define BIT_GET_R_WMAC_RX_FIL_LEN_8822B(x) \ + (((x) >> BIT_SHIFT_R_WMAC_RX_FIL_LEN_8822B) & \ + BIT_MASK_R_WMAC_RX_FIL_LEN_8822B) + +#define BIT_SHIFT_R_WMAC_RXFIFO_FULL_TH_8822B (56 & CPU_OPT_WIDTH) +#define BIT_MASK_R_WMAC_RXFIFO_FULL_TH_8822B 0xff +#define BIT_R_WMAC_RXFIFO_FULL_TH_8822B(x) \ + (((x) & BIT_MASK_R_WMAC_RXFIFO_FULL_TH_8822B) \ + << BIT_SHIFT_R_WMAC_RXFIFO_FULL_TH_8822B) +#define BIT_GET_R_WMAC_RXFIFO_FULL_TH_8822B(x) \ + (((x) >> BIT_SHIFT_R_WMAC_RXFIFO_FULL_TH_8822B) & \ + BIT_MASK_R_WMAC_RXFIFO_FULL_TH_8822B) + +#define BIT_R_WMAC_RX_SYNCFIFO_SYNC_8822B BIT(55) +#define BIT_R_WMAC_RXRST_DLY_8822B BIT(54) +#define BIT_R_WMAC_SRCH_TXRPT_REF_DROP_8822B BIT(53) +#define BIT_R_WMAC_SRCH_TXRPT_UA1_8822B BIT(52) +#define BIT_R_WMAC_SRCH_TXRPT_TYPE_8822B BIT(51) +#define BIT_R_WMAC_NDP_RST_8822B BIT(50) +#define BIT_R_WMAC_POWINT_EN_8822B BIT(49) +#define BIT_R_WMAC_SRCH_TXRPT_PERPKT_8822B BIT(48) +#define BIT_R_WMAC_SRCH_TXRPT_MID_8822B BIT(47) +#define BIT_R_WMAC_PFIN_TOEN_8822B BIT(46) +#define BIT_R_WMAC_FIL_SECERR_8822B BIT(45) +#define BIT_R_WMAC_FIL_CTLPKTLEN_8822B BIT(44) +#define BIT_R_WMAC_FIL_FCTYPE_8822B BIT(43) +#define BIT_R_WMAC_FIL_FCPROVER_8822B BIT(42) +#define BIT_R_WMAC_PHYSTS_SNIF_8822B BIT(41) +#define BIT_R_WMAC_PHYSTS_PLCP_8822B BIT(40) +#define BIT_R_MAC_TCR_VBONF_RD_8822B BIT(39) +#define BIT_R_WMAC_TCR_MPAR_NDP_8822B BIT(38) +#define BIT_R_WMAC_NDP_FILTER_8822B BIT(37) +#define BIT_R_WMAC_RXLEN_SEL_8822B BIT(36) +#define BIT_R_WMAC_RXLEN_SEL1_8822B BIT(35) +#define BIT_R_OFDM_FILTER_8822B BIT(34) +#define BIT_R_WMAC_CHK_OFDM_LEN_8822B BIT(33) +#define BIT_R_WMAC_CHK_CCK_LEN_8822B BIT(32) + +#define BIT_SHIFT_R_OFDM_LEN_8822B 26 +#define BIT_MASK_R_OFDM_LEN_8822B 0x3f +#define BIT_R_OFDM_LEN_8822B(x) \ + (((x) & BIT_MASK_R_OFDM_LEN_8822B) << BIT_SHIFT_R_OFDM_LEN_8822B) +#define BIT_GET_R_OFDM_LEN_8822B(x) \ + (((x) >> BIT_SHIFT_R_OFDM_LEN_8822B) & BIT_MASK_R_OFDM_LEN_8822B) + +#define BIT_SHIFT_R_CCK_LEN_8822B 0 +#define BIT_MASK_R_CCK_LEN_8822B 0xffff +#define BIT_R_CCK_LEN_8822B(x) \ + (((x) & BIT_MASK_R_CCK_LEN_8822B) << BIT_SHIFT_R_CCK_LEN_8822B) +#define BIT_GET_R_CCK_LEN_8822B(x) \ + (((x) >> BIT_SHIFT_R_CCK_LEN_8822B) & BIT_MASK_R_CCK_LEN_8822B) + +/* 2 REG_RX_FILTER_FUNCTION_8822B */ +#define BIT_R_WMAC_MHRDDY_LATCH_8822B BIT(14) +#define BIT_R_WMAC_MHRDDY_CLR_8822B BIT(13) +#define BIT_R_RXPKTCTL_FSM_BASED_MPDURDY1_8822B BIT(12) +#define BIT_WMAC_DIS_VHT_PLCP_CHK_MU_8822B BIT(11) +#define BIT_R_CHK_DELIMIT_LEN_8822B BIT(10) +#define BIT_R_REAPTER_ADDR_MATCH_8822B BIT(9) +#define BIT_R_RXPKTCTL_FSM_BASED_MPDURDY_8822B BIT(8) +#define BIT_R_LATCH_MACHRDY_8822B BIT(7) +#define BIT_R_WMAC_RXFIL_REND_8822B BIT(6) +#define BIT_R_WMAC_MPDURDY_CLR_8822B BIT(5) +#define BIT_R_WMAC_CLRRXSEC_8822B BIT(4) +#define BIT_R_WMAC_RXFIL_RDEL_8822B BIT(3) +#define BIT_R_WMAC_RXFIL_FCSE_8822B BIT(2) +#define BIT_R_WMAC_RXFIL_MESH_DEL_8822B BIT(1) +#define BIT_R_WMAC_RXFIL_MASKM_8822B BIT(0) + +/* 2 REG_NDP_SIG_8822B */ + +#define BIT_SHIFT_R_WMAC_TXNDP_SIGB_8822B 0 +#define BIT_MASK_R_WMAC_TXNDP_SIGB_8822B 0x1fffff +#define BIT_R_WMAC_TXNDP_SIGB_8822B(x) \ + (((x) & BIT_MASK_R_WMAC_TXNDP_SIGB_8822B) \ + << BIT_SHIFT_R_WMAC_TXNDP_SIGB_8822B) +#define BIT_GET_R_WMAC_TXNDP_SIGB_8822B(x) \ + (((x) >> BIT_SHIFT_R_WMAC_TXNDP_SIGB_8822B) & \ + BIT_MASK_R_WMAC_TXNDP_SIGB_8822B) + +/* 2 REG_TXCMD_INFO_FOR_RSP_PKT_8822B */ + +#define BIT_SHIFT_R_MAC_DEBUG_8822B (32 & CPU_OPT_WIDTH) +#define BIT_MASK_R_MAC_DEBUG_8822B 0xffffffffL +#define BIT_R_MAC_DEBUG_8822B(x) \ + (((x) & BIT_MASK_R_MAC_DEBUG_8822B) << BIT_SHIFT_R_MAC_DEBUG_8822B) +#define BIT_GET_R_MAC_DEBUG_8822B(x) \ + (((x) >> BIT_SHIFT_R_MAC_DEBUG_8822B) & BIT_MASK_R_MAC_DEBUG_8822B) + +#define BIT_SHIFT_R_MAC_DBG_SHIFT_8822B 8 +#define BIT_MASK_R_MAC_DBG_SHIFT_8822B 0x7 +#define BIT_R_MAC_DBG_SHIFT_8822B(x) \ + (((x) & BIT_MASK_R_MAC_DBG_SHIFT_8822B) \ + << BIT_SHIFT_R_MAC_DBG_SHIFT_8822B) +#define BIT_GET_R_MAC_DBG_SHIFT_8822B(x) \ + (((x) >> BIT_SHIFT_R_MAC_DBG_SHIFT_8822B) & \ + BIT_MASK_R_MAC_DBG_SHIFT_8822B) + +#define BIT_SHIFT_R_MAC_DBG_SEL_8822B 0 +#define BIT_MASK_R_MAC_DBG_SEL_8822B 0x3 +#define BIT_R_MAC_DBG_SEL_8822B(x) \ + (((x) & BIT_MASK_R_MAC_DBG_SEL_8822B) << BIT_SHIFT_R_MAC_DBG_SEL_8822B) +#define BIT_GET_R_MAC_DBG_SEL_8822B(x) \ + (((x) >> BIT_SHIFT_R_MAC_DBG_SEL_8822B) & BIT_MASK_R_MAC_DBG_SEL_8822B) + +/* 2 REG_RTS_ADDRESS_0_8822B */ + +/* 2 REG_RTS_ADDRESS_1_8822B */ + +/* 2 REG__RPFM_MAP1_8822B + * (RX PAYLOAD FILTER MAP FRAME TYPE CONTROL REGISTER GROUP 1 + */ +#define BIT_DATA_RPFM15EN_8822B BIT(15) +#define BIT_DATA_RPFM14EN_8822B BIT(14) +#define BIT_DATA_RPFM13EN_8822B BIT(13) +#define BIT_DATA_RPFM12EN_8822B BIT(12) +#define BIT_DATA_RPFM11EN_8822B BIT(11) +#define BIT_DATA_RPFM10EN_8822B BIT(10) +#define BIT_DATA_RPFM9EN_8822B BIT(9) +#define BIT_DATA_RPFM8EN_8822B BIT(8) +#define BIT_DATA_RPFM7EN_8822B BIT(7) +#define BIT_DATA_RPFM6EN_8822B BIT(6) +#define BIT_DATA_RPFM5EN_8822B BIT(5) +#define BIT_DATA_RPFM4EN_8822B BIT(4) +#define BIT_DATA_RPFM3EN_8822B BIT(3) +#define BIT_DATA_RPFM2EN_8822B BIT(2) +#define BIT_DATA_RPFM1EN_8822B BIT(1) +#define BIT_DATA_RPFM0EN_8822B BIT(0) + +/* 2 REG_WL2LTECOEX_INDIRECT_ACCESS_CTRL_V1_8822B */ +#define BIT_LTECOEX_ACCESS_START_V1_8822B BIT(31) +#define BIT_LTECOEX_WRITE_MODE_V1_8822B BIT(30) +#define BIT_LTECOEX_READY_BIT_V1_8822B BIT(29) + +#define BIT_SHIFT_WRITE_BYTE_EN_V1_8822B 16 +#define BIT_MASK_WRITE_BYTE_EN_V1_8822B 0xf +#define BIT_WRITE_BYTE_EN_V1_8822B(x) \ + (((x) & BIT_MASK_WRITE_BYTE_EN_V1_8822B) \ + << BIT_SHIFT_WRITE_BYTE_EN_V1_8822B) +#define BIT_GET_WRITE_BYTE_EN_V1_8822B(x) \ + (((x) >> BIT_SHIFT_WRITE_BYTE_EN_V1_8822B) & \ + BIT_MASK_WRITE_BYTE_EN_V1_8822B) + +#define BIT_SHIFT_LTECOEX_REG_ADDR_V1_8822B 0 +#define BIT_MASK_LTECOEX_REG_ADDR_V1_8822B 0xffff +#define BIT_LTECOEX_REG_ADDR_V1_8822B(x) \ + (((x) & BIT_MASK_LTECOEX_REG_ADDR_V1_8822B) \ + << BIT_SHIFT_LTECOEX_REG_ADDR_V1_8822B) +#define BIT_GET_LTECOEX_REG_ADDR_V1_8822B(x) \ + (((x) >> BIT_SHIFT_LTECOEX_REG_ADDR_V1_8822B) & \ + BIT_MASK_LTECOEX_REG_ADDR_V1_8822B) + +/* 2 REG_WL2LTECOEX_INDIRECT_ACCESS_WRITE_DATA_V1_8822B */ + +#define BIT_SHIFT_LTECOEX_W_DATA_V1_8822B 0 +#define BIT_MASK_LTECOEX_W_DATA_V1_8822B 0xffffffffL +#define BIT_LTECOEX_W_DATA_V1_8822B(x) \ + (((x) & BIT_MASK_LTECOEX_W_DATA_V1_8822B) \ + << BIT_SHIFT_LTECOEX_W_DATA_V1_8822B) +#define BIT_GET_LTECOEX_W_DATA_V1_8822B(x) \ + (((x) >> BIT_SHIFT_LTECOEX_W_DATA_V1_8822B) & \ + BIT_MASK_LTECOEX_W_DATA_V1_8822B) + +/* 2 REG_WL2LTECOEX_INDIRECT_ACCESS_READ_DATA_V1_8822B */ + +#define BIT_SHIFT_LTECOEX_R_DATA_V1_8822B 0 +#define BIT_MASK_LTECOEX_R_DATA_V1_8822B 0xffffffffL +#define BIT_LTECOEX_R_DATA_V1_8822B(x) \ + (((x) & BIT_MASK_LTECOEX_R_DATA_V1_8822B) \ + << BIT_SHIFT_LTECOEX_R_DATA_V1_8822B) +#define BIT_GET_LTECOEX_R_DATA_V1_8822B(x) \ + (((x) >> BIT_SHIFT_LTECOEX_R_DATA_V1_8822B) & \ + BIT_MASK_LTECOEX_R_DATA_V1_8822B) + +/* 2 REG_NOT_VALID_8822B */ + +/* 2 REG_SDIO_TX_CTRL_8822B */ + +#define BIT_SHIFT_SDIO_INT_TIMEOUT_8822B 16 +#define BIT_MASK_SDIO_INT_TIMEOUT_8822B 0xffff +#define BIT_SDIO_INT_TIMEOUT_8822B(x) \ + (((x) & BIT_MASK_SDIO_INT_TIMEOUT_8822B) \ + << BIT_SHIFT_SDIO_INT_TIMEOUT_8822B) +#define BIT_GET_SDIO_INT_TIMEOUT_8822B(x) \ + (((x) >> BIT_SHIFT_SDIO_INT_TIMEOUT_8822B) & \ + BIT_MASK_SDIO_INT_TIMEOUT_8822B) + +#define BIT_IO_ERR_STATUS_8822B BIT(15) +#define BIT_REPLY_ERRCRC_IN_DATA_8822B BIT(9) +#define BIT_EN_CMD53_OVERLAP_8822B BIT(8) +#define BIT_REPLY_ERR_IN_R5_8822B BIT(7) +#define BIT_R18A_EN_8822B BIT(6) +#define BIT_INIT_CMD_EN_8822B BIT(5) +#define BIT_EN_RXDMA_MASK_INT_8822B BIT(2) +#define BIT_EN_MASK_TIMER_8822B BIT(1) +#define BIT_CMD_ERR_STOP_INT_EN_8822B BIT(0) + +/* 2 REG_SDIO_HIMR_8822B */ +#define BIT_SDIO_CRCERR_MSK_8822B BIT(31) +#define BIT_SDIO_HSISR3_IND_MSK_8822B BIT(30) +#define BIT_SDIO_HSISR2_IND_MSK_8822B BIT(29) +#define BIT_SDIO_HEISR_IND_MSK_8822B BIT(28) +#define BIT_SDIO_CTWEND_MSK_8822B BIT(27) +#define BIT_SDIO_ATIMEND_E_MSK_8822B BIT(26) +#define BIT_SDIIO_ATIMEND_MSK_8822B BIT(25) +#define BIT_SDIO_OCPINT_MSK_8822B BIT(24) +#define BIT_SDIO_PSTIMEOUT_MSK_8822B BIT(23) +#define BIT_SDIO_GTINT4_MSK_8822B BIT(22) +#define BIT_SDIO_GTINT3_MSK_8822B BIT(21) +#define BIT_SDIO_HSISR_IND_MSK_8822B BIT(20) +#define BIT_SDIO_CPWM2_MSK_8822B BIT(19) +#define BIT_SDIO_CPWM1_MSK_8822B BIT(18) +#define BIT_SDIO_C2HCMD_INT_MSK_8822B BIT(17) +#define BIT_SDIO_BCNERLY_INT_MSK_8822B BIT(16) +#define BIT_SDIO_TXBCNERR_MSK_8822B BIT(7) +#define BIT_SDIO_TXBCNOK_MSK_8822B BIT(6) +#define BIT_SDIO_RXFOVW_MSK_8822B BIT(5) +#define BIT_SDIO_TXFOVW_MSK_8822B BIT(4) +#define BIT_SDIO_RXERR_MSK_8822B BIT(3) +#define BIT_SDIO_TXERR_MSK_8822B BIT(2) +#define BIT_SDIO_AVAL_MSK_8822B BIT(1) +#define BIT_RX_REQUEST_MSK_8822B BIT(0) + +/* 2 REG_SDIO_HISR_8822B */ +#define BIT_SDIO_CRCERR_8822B BIT(31) +#define BIT_SDIO_HSISR3_IND_8822B BIT(30) +#define BIT_SDIO_HSISR2_IND_8822B BIT(29) +#define BIT_SDIO_HEISR_IND_8822B BIT(28) +#define BIT_SDIO_CTWEND_8822B BIT(27) +#define BIT_SDIO_ATIMEND_E_8822B BIT(26) +#define BIT_SDIO_ATIMEND_8822B BIT(25) +#define BIT_SDIO_OCPINT_8822B BIT(24) +#define BIT_SDIO_PSTIMEOUT_8822B BIT(23) +#define BIT_SDIO_GTINT4_8822B BIT(22) +#define BIT_SDIO_GTINT3_8822B BIT(21) +#define BIT_SDIO_HSISR_IND_8822B BIT(20) +#define BIT_SDIO_CPWM2_8822B BIT(19) +#define BIT_SDIO_CPWM1_8822B BIT(18) +#define BIT_SDIO_C2HCMD_INT_8822B BIT(17) +#define BIT_SDIO_BCNERLY_INT_8822B BIT(16) +#define BIT_SDIO_TXBCNERR_8822B BIT(7) +#define BIT_SDIO_TXBCNOK_8822B BIT(6) +#define BIT_SDIO_RXFOVW_8822B BIT(5) +#define BIT_SDIO_TXFOVW_8822B BIT(4) +#define BIT_SDIO_RXERR_8822B BIT(3) +#define BIT_SDIO_TXERR_8822B BIT(2) +#define BIT_SDIO_AVAL_8822B BIT(1) +#define BIT_RX_REQUEST_8822B BIT(0) + +/* 2 REG_SDIO_RX_REQ_LEN_8822B */ + +#define BIT_SHIFT_RX_REQ_LEN_V1_8822B 0 +#define BIT_MASK_RX_REQ_LEN_V1_8822B 0x3ffff +#define BIT_RX_REQ_LEN_V1_8822B(x) \ + (((x) & BIT_MASK_RX_REQ_LEN_V1_8822B) << BIT_SHIFT_RX_REQ_LEN_V1_8822B) +#define BIT_GET_RX_REQ_LEN_V1_8822B(x) \ + (((x) >> BIT_SHIFT_RX_REQ_LEN_V1_8822B) & BIT_MASK_RX_REQ_LEN_V1_8822B) + +/* 2 REG_SDIO_FREE_TXPG_SEQ_V1_8822B */ + +#define BIT_SHIFT_FREE_TXPG_SEQ_8822B 0 +#define BIT_MASK_FREE_TXPG_SEQ_8822B 0xff +#define BIT_FREE_TXPG_SEQ_8822B(x) \ + (((x) & BIT_MASK_FREE_TXPG_SEQ_8822B) << BIT_SHIFT_FREE_TXPG_SEQ_8822B) +#define BIT_GET_FREE_TXPG_SEQ_8822B(x) \ + (((x) >> BIT_SHIFT_FREE_TXPG_SEQ_8822B) & BIT_MASK_FREE_TXPG_SEQ_8822B) + +/* 2 REG_SDIO_FREE_TXPG_8822B */ + +#define BIT_SHIFT_MID_FREEPG_V1_8822B 16 +#define BIT_MASK_MID_FREEPG_V1_8822B 0xfff +#define BIT_MID_FREEPG_V1_8822B(x) \ + (((x) & BIT_MASK_MID_FREEPG_V1_8822B) << BIT_SHIFT_MID_FREEPG_V1_8822B) +#define BIT_GET_MID_FREEPG_V1_8822B(x) \ + (((x) >> BIT_SHIFT_MID_FREEPG_V1_8822B) & BIT_MASK_MID_FREEPG_V1_8822B) + +#define BIT_SHIFT_HIQ_FREEPG_V1_8822B 0 +#define BIT_MASK_HIQ_FREEPG_V1_8822B 0xfff +#define BIT_HIQ_FREEPG_V1_8822B(x) \ + (((x) & BIT_MASK_HIQ_FREEPG_V1_8822B) << BIT_SHIFT_HIQ_FREEPG_V1_8822B) +#define BIT_GET_HIQ_FREEPG_V1_8822B(x) \ + (((x) >> BIT_SHIFT_HIQ_FREEPG_V1_8822B) & BIT_MASK_HIQ_FREEPG_V1_8822B) + +/* 2 REG_SDIO_FREE_TXPG2_8822B */ + +#define BIT_SHIFT_PUB_FREEPG_V1_8822B 16 +#define BIT_MASK_PUB_FREEPG_V1_8822B 0xfff +#define BIT_PUB_FREEPG_V1_8822B(x) \ + (((x) & BIT_MASK_PUB_FREEPG_V1_8822B) << BIT_SHIFT_PUB_FREEPG_V1_8822B) +#define BIT_GET_PUB_FREEPG_V1_8822B(x) \ + (((x) >> BIT_SHIFT_PUB_FREEPG_V1_8822B) & BIT_MASK_PUB_FREEPG_V1_8822B) + +#define BIT_SHIFT_LOW_FREEPG_V1_8822B 0 +#define BIT_MASK_LOW_FREEPG_V1_8822B 0xfff +#define BIT_LOW_FREEPG_V1_8822B(x) \ + (((x) & BIT_MASK_LOW_FREEPG_V1_8822B) << BIT_SHIFT_LOW_FREEPG_V1_8822B) +#define BIT_GET_LOW_FREEPG_V1_8822B(x) \ + (((x) >> BIT_SHIFT_LOW_FREEPG_V1_8822B) & BIT_MASK_LOW_FREEPG_V1_8822B) + +/* 2 REG_SDIO_OQT_FREE_TXPG_V1_8822B */ + +#define BIT_SHIFT_NOAC_OQT_FREEPG_V1_8822B 24 +#define BIT_MASK_NOAC_OQT_FREEPG_V1_8822B 0xff +#define BIT_NOAC_OQT_FREEPG_V1_8822B(x) \ + (((x) & BIT_MASK_NOAC_OQT_FREEPG_V1_8822B) \ + << BIT_SHIFT_NOAC_OQT_FREEPG_V1_8822B) +#define BIT_GET_NOAC_OQT_FREEPG_V1_8822B(x) \ + (((x) >> BIT_SHIFT_NOAC_OQT_FREEPG_V1_8822B) & \ + BIT_MASK_NOAC_OQT_FREEPG_V1_8822B) + +#define BIT_SHIFT_AC_OQT_FREEPG_V1_8822B 16 +#define BIT_MASK_AC_OQT_FREEPG_V1_8822B 0xff +#define BIT_AC_OQT_FREEPG_V1_8822B(x) \ + (((x) & BIT_MASK_AC_OQT_FREEPG_V1_8822B) \ + << BIT_SHIFT_AC_OQT_FREEPG_V1_8822B) +#define BIT_GET_AC_OQT_FREEPG_V1_8822B(x) \ + (((x) >> BIT_SHIFT_AC_OQT_FREEPG_V1_8822B) & \ + BIT_MASK_AC_OQT_FREEPG_V1_8822B) + +#define BIT_SHIFT_EXQ_FREEPG_V1_8822B 0 +#define BIT_MASK_EXQ_FREEPG_V1_8822B 0xfff +#define BIT_EXQ_FREEPG_V1_8822B(x) \ + (((x) & BIT_MASK_EXQ_FREEPG_V1_8822B) << BIT_SHIFT_EXQ_FREEPG_V1_8822B) +#define BIT_GET_EXQ_FREEPG_V1_8822B(x) \ + (((x) >> BIT_SHIFT_EXQ_FREEPG_V1_8822B) & BIT_MASK_EXQ_FREEPG_V1_8822B) + +/* 2 REG_SDIO_HTSFR_INFO_8822B */ + +#define BIT_SHIFT_HTSFR1_8822B 16 +#define BIT_MASK_HTSFR1_8822B 0xffff +#define BIT_HTSFR1_8822B(x) \ + (((x) & BIT_MASK_HTSFR1_8822B) << BIT_SHIFT_HTSFR1_8822B) +#define BIT_GET_HTSFR1_8822B(x) \ + (((x) >> BIT_SHIFT_HTSFR1_8822B) & BIT_MASK_HTSFR1_8822B) + +#define BIT_SHIFT_HTSFR0_8822B 0 +#define BIT_MASK_HTSFR0_8822B 0xffff +#define BIT_HTSFR0_8822B(x) \ + (((x) & BIT_MASK_HTSFR0_8822B) << BIT_SHIFT_HTSFR0_8822B) +#define BIT_GET_HTSFR0_8822B(x) \ + (((x) >> BIT_SHIFT_HTSFR0_8822B) & BIT_MASK_HTSFR0_8822B) + +/* 2 REG_SDIO_HCPWM1_V2_8822B */ +#define BIT_TOGGLING_8822B BIT(7) +#define BIT_ACK_8822B BIT(6) +#define BIT_SYS_CLK_8822B BIT(0) + +/* 2 REG_SDIO_HCPWM2_V2_8822B */ + +/* 2 REG_SDIO_INDIRECT_REG_CFG_8822B */ +#define BIT_INDIRECT_REG_RDY_8822B BIT(20) +#define BIT_INDIRECT_REG_R_8822B BIT(19) +#define BIT_INDIRECT_REG_W_8822B BIT(18) + +#define BIT_SHIFT_INDIRECT_REG_SIZE_8822B 16 +#define BIT_MASK_INDIRECT_REG_SIZE_8822B 0x3 +#define BIT_INDIRECT_REG_SIZE_8822B(x) \ + (((x) & BIT_MASK_INDIRECT_REG_SIZE_8822B) \ + << BIT_SHIFT_INDIRECT_REG_SIZE_8822B) +#define BIT_GET_INDIRECT_REG_SIZE_8822B(x) \ + (((x) >> BIT_SHIFT_INDIRECT_REG_SIZE_8822B) & \ + BIT_MASK_INDIRECT_REG_SIZE_8822B) + +#define BIT_SHIFT_INDIRECT_REG_ADDR_8822B 0 +#define BIT_MASK_INDIRECT_REG_ADDR_8822B 0xffff +#define BIT_INDIRECT_REG_ADDR_8822B(x) \ + (((x) & BIT_MASK_INDIRECT_REG_ADDR_8822B) \ + << BIT_SHIFT_INDIRECT_REG_ADDR_8822B) +#define BIT_GET_INDIRECT_REG_ADDR_8822B(x) \ + (((x) >> BIT_SHIFT_INDIRECT_REG_ADDR_8822B) & \ + BIT_MASK_INDIRECT_REG_ADDR_8822B) + +/* 2 REG_SDIO_INDIRECT_REG_DATA_8822B */ + +#define BIT_SHIFT_INDIRECT_REG_DATA_8822B 0 +#define BIT_MASK_INDIRECT_REG_DATA_8822B 0xffffffffL +#define BIT_INDIRECT_REG_DATA_8822B(x) \ + (((x) & BIT_MASK_INDIRECT_REG_DATA_8822B) \ + << BIT_SHIFT_INDIRECT_REG_DATA_8822B) +#define BIT_GET_INDIRECT_REG_DATA_8822B(x) \ + (((x) >> BIT_SHIFT_INDIRECT_REG_DATA_8822B) & \ + BIT_MASK_INDIRECT_REG_DATA_8822B) + +/* 2 REG_SDIO_H2C_8822B */ + +#define BIT_SHIFT_SDIO_H2C_MSG_8822B 0 +#define BIT_MASK_SDIO_H2C_MSG_8822B 0xffffffffL +#define BIT_SDIO_H2C_MSG_8822B(x) \ + (((x) & BIT_MASK_SDIO_H2C_MSG_8822B) << BIT_SHIFT_SDIO_H2C_MSG_8822B) +#define BIT_GET_SDIO_H2C_MSG_8822B(x) \ + (((x) >> BIT_SHIFT_SDIO_H2C_MSG_8822B) & BIT_MASK_SDIO_H2C_MSG_8822B) + +/* 2 REG_SDIO_C2H_8822B */ + +#define BIT_SHIFT_SDIO_C2H_MSG_8822B 0 +#define BIT_MASK_SDIO_C2H_MSG_8822B 0xffffffffL +#define BIT_SDIO_C2H_MSG_8822B(x) \ + (((x) & BIT_MASK_SDIO_C2H_MSG_8822B) << BIT_SHIFT_SDIO_C2H_MSG_8822B) +#define BIT_GET_SDIO_C2H_MSG_8822B(x) \ + (((x) >> BIT_SHIFT_SDIO_C2H_MSG_8822B) & BIT_MASK_SDIO_C2H_MSG_8822B) + +/* 2 REG_SDIO_HRPWM1_8822B */ +#define BIT_TOGGLING_8822B BIT(7) +#define BIT_ACK_8822B BIT(6) +#define BIT_32K_PERMISSION_8822B BIT(0) + +/* 2 REG_SDIO_HRPWM2_8822B */ + +/* 2 REG_SDIO_HPS_CLKR_8822B */ + +/* 2 REG_SDIO_BUS_CTRL_8822B */ +#define BIT_PAD_CLK_XHGE_EN_8822B BIT(3) +#define BIT_INTER_CLK_EN_8822B BIT(2) +#define BIT_EN_RPT_TXCRC_8822B BIT(1) +#define BIT_DIS_RXDMA_STS_8822B BIT(0) + +/* 2 REG_SDIO_HSUS_CTRL_8822B */ +#define BIT_INTR_CTRL_8822B BIT(4) +#define BIT_SDIO_VOLTAGE_8822B BIT(3) +#define BIT_BYPASS_INIT_8822B BIT(2) +#define BIT_HCI_RESUME_RDY_8822B BIT(1) +#define BIT_HCI_SUS_REQ_8822B BIT(0) + +/* 2 REG_SDIO_RESPONSE_TIMER_8822B */ + +#define BIT_SHIFT_CMDIN_2RESP_TIMER_8822B 0 +#define BIT_MASK_CMDIN_2RESP_TIMER_8822B 0xffff +#define BIT_CMDIN_2RESP_TIMER_8822B(x) \ + (((x) & BIT_MASK_CMDIN_2RESP_TIMER_8822B) \ + << BIT_SHIFT_CMDIN_2RESP_TIMER_8822B) +#define BIT_GET_CMDIN_2RESP_TIMER_8822B(x) \ + (((x) >> BIT_SHIFT_CMDIN_2RESP_TIMER_8822B) & \ + BIT_MASK_CMDIN_2RESP_TIMER_8822B) + +/* 2 REG_SDIO_CMD_CRC_8822B */ + +#define BIT_SHIFT_SDIO_CMD_CRC_V1_8822B 0 +#define BIT_MASK_SDIO_CMD_CRC_V1_8822B 0xff +#define BIT_SDIO_CMD_CRC_V1_8822B(x) \ + (((x) & BIT_MASK_SDIO_CMD_CRC_V1_8822B) \ + << BIT_SHIFT_SDIO_CMD_CRC_V1_8822B) +#define BIT_GET_SDIO_CMD_CRC_V1_8822B(x) \ + (((x) >> BIT_SHIFT_SDIO_CMD_CRC_V1_8822B) & \ + BIT_MASK_SDIO_CMD_CRC_V1_8822B) + +/* 2 REG_SDIO_HSISR_8822B */ +#define BIT_DRV_WLAN_INT_CLR_8822B BIT(1) +#define BIT_DRV_WLAN_INT_8822B BIT(0) + +/* 2 REG_SDIO_HSIMR_8822B */ +#define BIT_HISR_MASK_8822B BIT(0) + +/* 2 REG_SDIO_ERR_RPT_8822B */ +#define BIT_HR_FF_OVF_8822B BIT(6) +#define BIT_HR_FF_UDN_8822B BIT(5) +#define BIT_TXDMA_BUSY_ERR_8822B BIT(4) +#define BIT_TXDMA_VLD_ERR_8822B BIT(3) +#define BIT_QSEL_UNKNOWN_ERR_8822B BIT(2) +#define BIT_QSEL_MIS_ERR_8822B BIT(1) +#define BIT_SDIO_OVERRD_ERR_8822B BIT(0) + +/* 2 REG_SDIO_CMD_ERRCNT_8822B */ + +#define BIT_SHIFT_CMD_CRC_ERR_CNT_8822B 0 +#define BIT_MASK_CMD_CRC_ERR_CNT_8822B 0xff +#define BIT_CMD_CRC_ERR_CNT_8822B(x) \ + (((x) & BIT_MASK_CMD_CRC_ERR_CNT_8822B) \ + << BIT_SHIFT_CMD_CRC_ERR_CNT_8822B) +#define BIT_GET_CMD_CRC_ERR_CNT_8822B(x) \ + (((x) >> BIT_SHIFT_CMD_CRC_ERR_CNT_8822B) & \ + BIT_MASK_CMD_CRC_ERR_CNT_8822B) + +/* 2 REG_SDIO_DATA_ERRCNT_8822B */ + +#define BIT_SHIFT_DATA_CRC_ERR_CNT_8822B 0 +#define BIT_MASK_DATA_CRC_ERR_CNT_8822B 0xff +#define BIT_DATA_CRC_ERR_CNT_8822B(x) \ + (((x) & BIT_MASK_DATA_CRC_ERR_CNT_8822B) \ + << BIT_SHIFT_DATA_CRC_ERR_CNT_8822B) +#define BIT_GET_DATA_CRC_ERR_CNT_8822B(x) \ + (((x) >> BIT_SHIFT_DATA_CRC_ERR_CNT_8822B) & \ + BIT_MASK_DATA_CRC_ERR_CNT_8822B) + +/* 2 REG_SDIO_CMD_ERR_CONTENT_8822B */ + +#define BIT_SHIFT_SDIO_CMD_ERR_CONTENT_8822B 0 +#define BIT_MASK_SDIO_CMD_ERR_CONTENT_8822B 0xffffffffffL +#define BIT_SDIO_CMD_ERR_CONTENT_8822B(x) \ + (((x) & BIT_MASK_SDIO_CMD_ERR_CONTENT_8822B) \ + << BIT_SHIFT_SDIO_CMD_ERR_CONTENT_8822B) +#define BIT_GET_SDIO_CMD_ERR_CONTENT_8822B(x) \ + (((x) >> BIT_SHIFT_SDIO_CMD_ERR_CONTENT_8822B) & \ + BIT_MASK_SDIO_CMD_ERR_CONTENT_8822B) + +/* 2 REG_SDIO_CRC_ERR_IDX_8822B */ +#define BIT_D3_CRC_ERR_8822B BIT(4) +#define BIT_D2_CRC_ERR_8822B BIT(3) +#define BIT_D1_CRC_ERR_8822B BIT(2) +#define BIT_D0_CRC_ERR_8822B BIT(1) +#define BIT_CMD_CRC_ERR_8822B BIT(0) + +/* 2 REG_SDIO_DATA_CRC_8822B */ + +#define BIT_SHIFT_SDIO_DATA_CRC_8822B 0 +#define BIT_MASK_SDIO_DATA_CRC_8822B 0xff +#define BIT_SDIO_DATA_CRC_8822B(x) \ + (((x) & BIT_MASK_SDIO_DATA_CRC_8822B) << BIT_SHIFT_SDIO_DATA_CRC_8822B) +#define BIT_GET_SDIO_DATA_CRC_8822B(x) \ + (((x) >> BIT_SHIFT_SDIO_DATA_CRC_8822B) & BIT_MASK_SDIO_DATA_CRC_8822B) + +/* 2 REG_SDIO_DATA_REPLY_TIME_8822B */ + +#define BIT_SHIFT_SDIO_DATA_REPLY_TIME_8822B 0 +#define BIT_MASK_SDIO_DATA_REPLY_TIME_8822B 0x7 +#define BIT_SDIO_DATA_REPLY_TIME_8822B(x) \ + (((x) & BIT_MASK_SDIO_DATA_REPLY_TIME_8822B) \ + << BIT_SHIFT_SDIO_DATA_REPLY_TIME_8822B) +#define BIT_GET_SDIO_DATA_REPLY_TIME_8822B(x) \ + (((x) >> BIT_SHIFT_SDIO_DATA_REPLY_TIME_8822B) & \ + BIT_MASK_SDIO_DATA_REPLY_TIME_8822B) + +#endif diff --git a/drivers/staging/rtlwifi/halmac/halmac_fw_info.h b/drivers/staging/rtlwifi/halmac/halmac_fw_info.h new file mode 100644 index 000000000000..dad8be311ff2 --- /dev/null +++ b/drivers/staging/rtlwifi/halmac/halmac_fw_info.h @@ -0,0 +1,122 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef _HALMAC_FW_INFO_H_ +#define _HALMAC_FW_INFO_H_ + +#define H2C_FORMAT_VERSION 6 + +#define H2C_ACK_HDR_CONTENT_LENGTH 8 +#define CFG_PARAMETER_ACK_CONTENT_LENGTH 16 +#define SCAN_STATUS_RPT_CONTENT_LENGTH 4 +#define C2H_DBG_HEADER_LENGTH 4 +#define C2H_DBG_CONTENT_MAX_LENGTH 228 + +#define C2H_DBG_CONTENT_SEQ_OFFSET 1 + +/* Rename from FW SysHalCom_Debug_RAM.h */ +#define FW_REG_H2CPKT_DONE_SEQ 0x1C8 +#define fw_reg_wow_reason 0x1C7 + +enum halmac_data_type { + HALMAC_DATA_TYPE_MAC_REG = 0x00, + HALMAC_DATA_TYPE_BB_REG = 0x01, + HALMAC_DATA_TYPE_RADIO_A = 0x02, + HALMAC_DATA_TYPE_RADIO_B = 0x03, + HALMAC_DATA_TYPE_RADIO_C = 0x04, + HALMAC_DATA_TYPE_RADIO_D = 0x05, + + HALMAC_DATA_TYPE_DRV_DEFINE_0 = 0x80, + HALMAC_DATA_TYPE_DRV_DEFINE_1 = 0x81, + HALMAC_DATA_TYPE_DRV_DEFINE_2 = 0x82, + HALMAC_DATA_TYPE_DRV_DEFINE_3 = 0x83, + HALMAC_DATA_TYPE_UNDEFINE = 0x7FFFFFFF, +}; + +enum halmac_packet_id { + HALMAC_PACKET_PROBE_REQ = 0x00, + HALMAC_PACKET_SYNC_BCN = 0x01, + HALMAC_PACKET_DISCOVERY_BCN = 0x02, + + HALMAC_PACKET_UNDEFINE = 0x7FFFFFFF, +}; + +/* Channel Switch Action ID */ +enum halmac_cs_action_id { + HALMAC_CS_ACTION_NONE = 0x00, + HALMAC_CS_ACTIVE_SCAN = 0x01, + HALMAC_CS_NAN_NONMASTER_DW = 0x02, + HALMAC_CS_NAN_NONMASTER_NONDW = 0x03, + HALMAC_CS_NAN_MASTER_NONDW = 0x04, + HALMAC_CS_NAN_MASTER_DW = 0x05, + + HALMAC_CS_ACTION_UNDEFINE = 0x7FFFFFFF, +}; + +/* Channel Switch Extra Action ID */ +enum halmac_cs_extra_action_id { + HALMAC_CS_EXTRA_ACTION_NONE = 0x00, + HALMAC_CS_EXTRA_UPDATE_PROBE = 0x01, + HALMAC_CS_EXTRA_UPDATE_BEACON = 0x02, + + HALMAC_CS_EXTRA_ACTION_UNDEFINE = 0x7FFFFFFF, +}; + +enum halmac_h2c_return_code { + HALMAC_H2C_RETURN_SUCCESS = 0x00, + HALMAC_H2C_RETURN_CFG_ERR_LEN = 0x01, + HALMAC_H2C_RETURN_CFG_ERR_CMD = 0x02, + + HALMAC_H2C_RETURN_EFUSE_ERR_DUMP = 0x03, + + HALMAC_H2C_RETURN_DATAPACK_ERR_FULL = 0x04, /* DMEM buffer full */ + HALMAC_H2C_RETURN_DATAPACK_ERR_ID = 0x05, /* Invalid pack id */ + + HALMAC_H2C_RETURN_RUN_ERR_EMPTY = + 0x06, /* No data in dedicated buffer */ + HALMAC_H2C_RETURN_RUN_ERR_LEN = 0x07, + HALMAC_H2C_RETURN_RUN_ERR_CMD = 0x08, + HALMAC_H2C_RETURN_RUN_ERR_ID = 0x09, /* Invalid pack id */ + + HALMAC_H2C_RETURN_PACKET_ERR_FULL = 0x0A, /* DMEM buffer full */ + HALMAC_H2C_RETURN_PACKET_ERR_ID = 0x0B, /* Invalid packet id */ + + HALMAC_H2C_RETURN_SCAN_ERR_FULL = 0x0C, /* DMEM buffer full */ + HALMAC_H2C_RETURN_SCAN_ERR_PHYDM = 0x0D, /* PHYDM API return fail */ + + HALMAC_H2C_RETURN_ORIG_ERR_ID = 0x0E, /* Invalid original H2C cmd id */ + + HALMAC_H2C_RETURN_UNDEFINE = 0x7FFFFFFF, +}; + +enum halmac_scan_report_code { + HALMAC_SCAN_REPORT_DONE = 0x00, + HALMAC_SCAN_REPORT_ERR_PHYDM = 0x01, /* PHYDM API return fail */ + HALMAC_SCAN_REPORT_ERR_ID = 0x02, /* Invalid ActionID */ + HALMAC_SCAN_REPORT_ERR_TX = 0x03, /* Tx RsvdPage fail */ + + HALMAC_SCAN_REPORT_UNDEFINE = 0x7FFFFFFF, +}; + +#endif diff --git a/drivers/staging/rtlwifi/halmac/halmac_fw_offload_c2h_nic.h b/drivers/staging/rtlwifi/halmac/halmac_fw_offload_c2h_nic.h new file mode 100644 index 000000000000..0e99967f3663 --- /dev/null +++ b/drivers/staging/rtlwifi/halmac/halmac_fw_offload_c2h_nic.h @@ -0,0 +1,184 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef _HAL_FWOFFLOADC2HFORMAT_H2C_C2H_NIC_H_ +#define _HAL_FWOFFLOADC2HFORMAT_H2C_C2H_NIC_H_ +#define C2H_SUB_CMD_ID_C2H_DBG 0X00 +#define C2H_SUB_CMD_ID_BT_COEX_INFO 0X02 +#define C2H_SUB_CMD_ID_SCAN_STATUS_RPT 0X03 +#define C2H_SUB_CMD_ID_H2C_ACK_HDR 0X01 +#define C2H_SUB_CMD_ID_CFG_PARAMETER_ACK 0X01 +#define C2H_SUB_CMD_ID_BT_COEX_ACK 0X01 +#define C2H_SUB_CMD_ID_DUMP_PHYSICAL_EFUSE_ACK 0X01 +#define C2H_SUB_CMD_ID_UPDATE_PACKET_ACK 0X01 +#define C2H_SUB_CMD_ID_UPDATE_DATAPACK_ACK 0X01 +#define C2H_SUB_CMD_ID_RUN_DATAPACK_ACK 0X01 +#define C2H_SUB_CMD_ID_CHANNEL_SWITCH_ACK 0X01 +#define C2H_SUB_CMD_ID_IQK_ACK 0X01 +#define C2H_SUB_CMD_ID_POWER_TRACKING_ACK 0X01 +#define C2H_SUB_CMD_ID_PSD_ACK 0X01 +#define C2H_SUB_CMD_ID_PSD_DATA 0X04 +#define C2H_SUB_CMD_ID_EFUSE_DATA 0X05 +#define C2H_SUB_CMD_ID_IQK_DATA 0X06 +#define C2H_SUB_CMD_ID_C2H_PKT_FTM_DBG 0X07 +#define C2H_SUB_CMD_ID_C2H_PKT_FTM_2_DBG 0X08 +#define C2H_SUB_CMD_ID_C2H_PKT_FTM_3_DBG 0X09 +#define C2H_SUB_CMD_ID_C2H_PKT_FTM_4_DBG 0X0A +#define C2H_SUB_CMD_ID_FTMACKRPT_HDL_DBG 0X0B +#define C2H_SUB_CMD_ID_FTMC2H_RPT 0X0C +#define C2H_SUB_CMD_ID_DRVFTMC2H_RPT 0X0D +#define C2H_SUB_CMD_ID_C2H_PKT_FTM_5_DBG 0X0E +#define C2H_SUB_CMD_ID_CCX_RPT 0X0F +#define C2H_SUB_CMD_ID_C2H_PKT_NAN_RPT 0X10 +#define H2C_SUB_CMD_ID_CFG_PARAMETER_ACK SUB_CMD_ID_CFG_PARAMETER +#define H2C_SUB_CMD_ID_BT_COEX_ACK SUB_CMD_ID_BT_COEX +#define H2C_SUB_CMD_ID_DUMP_PHYSICAL_EFUSE_ACK SUB_CMD_ID_DUMP_PHYSICAL_EFUSE +#define H2C_SUB_CMD_ID_UPDATE_PACKET_ACK SUB_CMD_ID_UPDATE_PACKET +#define H2C_SUB_CMD_ID_UPDATE_DATAPACK_ACK SUB_CMD_ID_UPDATE_DATAPACK +#define H2C_SUB_CMD_ID_RUN_DATAPACK_ACK SUB_CMD_ID_RUN_DATAPACK +#define H2C_SUB_CMD_ID_CHANNEL_SWITCH_ACK SUB_CMD_ID_CHANNEL_SWITCH +#define H2C_SUB_CMD_ID_IQK_ACK SUB_CMD_ID_IQK +#define H2C_SUB_CMD_ID_POWER_TRACKING_ACK SUB_CMD_ID_POWER_TRACKING +#define H2C_SUB_CMD_ID_PSD_ACK SUB_CMD_ID_PSD +#define H2C_SUB_CMD_ID_CCX_RPT SUB_CMD_ID_CCX_RPT +#define H2C_CMD_ID_CFG_PARAMETER_ACK 0XFF +#define H2C_CMD_ID_BT_COEX_ACK 0XFF +#define H2C_CMD_ID_DUMP_PHYSICAL_EFUSE_ACK 0XFF +#define H2C_CMD_ID_UPDATE_PACKET_ACK 0XFF +#define H2C_CMD_ID_UPDATE_DATAPACK_ACK 0XFF +#define H2C_CMD_ID_RUN_DATAPACK_ACK 0XFF +#define H2C_CMD_ID_CHANNEL_SWITCH_ACK 0XFF +#define H2C_CMD_ID_IQK_ACK 0XFF +#define H2C_CMD_ID_POWER_TRACKING_ACK 0XFF +#define H2C_CMD_ID_PSD_ACK 0XFF +#define H2C_CMD_ID_CCX_RPT 0XFF +#define C2H_HDR_GET_CMD_ID(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X00, 0, 8) +#define C2H_HDR_SET_CMD_ID(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X00, 0, 8, __value) +#define C2H_HDR_GET_SEQ(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X00, 8, 8) +#define C2H_HDR_SET_SEQ(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X00, 8, 8, __value) +#define C2H_HDR_GET_C2H_SUB_CMD_ID(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X00, 16, 8) +#define C2H_HDR_SET_C2H_SUB_CMD_ID(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X00, 16, 8, __value) +#define C2H_HDR_GET_LEN(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X00, 24, 8) +#define C2H_HDR_SET_LEN(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X00, 24, 8, __value) +#define C2H_DBG_GET_DBG_MSG(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X04, 0, 8) +#define C2H_DBG_SET_DBG_MSG(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X04, 0, 8, __value) +#define BT_COEX_INFO_GET_DATA_START(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X04, 0, 8) +#define BT_COEX_INFO_SET_DATA_START(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X04, 0, 8, __value) +#define SCAN_STATUS_RPT_GET_H2C_RETURN_CODE(__c2h) \ + LE_BITS_TO_4BYTE(__c2h + 0X04, 0, 8) +#define SCAN_STATUS_RPT_SET_H2C_RETURN_CODE(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X04, 0, 8, __value) +#define SCAN_STATUS_RPT_GET_H2C_SEQ(__c2h) \ + LE_BITS_TO_4BYTE(__c2h + 0X04, 16, 16) +#define SCAN_STATUS_RPT_SET_H2C_SEQ(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X04, 16, 16, __value) +#define H2C_ACK_HDR_GET_H2C_RETURN_CODE(__c2h) \ + LE_BITS_TO_4BYTE(__c2h + 0X04, 0, 8) +#define H2C_ACK_HDR_SET_H2C_RETURN_CODE(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X04, 0, 8, __value) +#define H2C_ACK_HDR_GET_H2C_CMD_ID(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X04, 8, 8) +#define H2C_ACK_HDR_SET_H2C_CMD_ID(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X04, 8, 8, __value) +#define H2C_ACK_HDR_GET_H2C_SUB_CMD_ID(__c2h) \ + LE_BITS_TO_4BYTE(__c2h + 0X04, 16, 16) +#define H2C_ACK_HDR_SET_H2C_SUB_CMD_ID(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X04, 16, 16, __value) +#define H2C_ACK_HDR_GET_H2C_SEQ(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X08, 0, 16) +#define H2C_ACK_HDR_SET_H2C_SEQ(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X08, 0, 16, __value) +#define CFG_PARAMETER_ACK_GET_OFFSET_ACCUMULATION(__c2h) \ + LE_BITS_TO_4BYTE(__c2h + 0XC, 0, 32) +#define CFG_PARAMETER_ACK_SET_OFFSET_ACCUMULATION(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0XC, 0, 32, __value) +#define CFG_PARAMETER_ACK_GET_VALUE_ACCUMULATION(__c2h) \ + LE_BITS_TO_4BYTE(__c2h + 0X10, 0, 32) +#define CFG_PARAMETER_ACK_SET_VALUE_ACCUMULATION(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X10, 0, 32, __value) +#define BT_COEX_ACK_GET_DATA_START(__c2h) LE_BITS_TO_4BYTE(__c2h + 0XC, 0, 8) +#define BT_COEX_ACK_SET_DATA_START(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0XC, 0, 8, __value) +#define PSD_DATA_GET_SEGMENT_ID(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X04, 0, 7) +#define PSD_DATA_SET_SEGMENT_ID(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X04, 0, 7, __value) +#define PSD_DATA_GET_END_SEGMENT(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X04, 7, 1) +#define PSD_DATA_SET_END_SEGMENT(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X04, 7, 1, __value) +#define PSD_DATA_GET_SEGMENT_SIZE(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X04, 8, 8) +#define PSD_DATA_SET_SEGMENT_SIZE(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X04, 8, 8, __value) +#define PSD_DATA_GET_TOTAL_SIZE(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X04, 16, 16) +#define PSD_DATA_SET_TOTAL_SIZE(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X04, 16, 16, __value) +#define PSD_DATA_GET_H2C_SEQ(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X8, 0, 16) +#define PSD_DATA_SET_H2C_SEQ(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X8, 0, 16, __value) +#define PSD_DATA_GET_DATA_START(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X8, 16, 8) +#define PSD_DATA_SET_DATA_START(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X8, 16, 8, __value) +#define EFUSE_DATA_GET_SEGMENT_ID(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X04, 0, 7) +#define EFUSE_DATA_SET_SEGMENT_ID(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X04, 0, 7, __value) +#define EFUSE_DATA_GET_END_SEGMENT(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X04, 7, 1) +#define EFUSE_DATA_SET_END_SEGMENT(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X04, 7, 1, __value) +#define EFUSE_DATA_GET_SEGMENT_SIZE(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X04, 8, 8) +#define EFUSE_DATA_SET_SEGMENT_SIZE(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X04, 8, 8, __value) +#define EFUSE_DATA_GET_TOTAL_SIZE(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X04, 16, 16) +#define EFUSE_DATA_SET_TOTAL_SIZE(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X04, 16, 16, __value) +#define EFUSE_DATA_GET_H2C_SEQ(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X8, 0, 16) +#define EFUSE_DATA_SET_H2C_SEQ(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X8, 0, 16, __value) +#define EFUSE_DATA_GET_DATA_START(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X8, 16, 8) +#define EFUSE_DATA_SET_DATA_START(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X8, 16, 8, __value) +#define IQK_DATA_GET_SEGMENT_ID(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X04, 0, 7) +#define IQK_DATA_SET_SEGMENT_ID(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X04, 0, 7, __value) +#define IQK_DATA_GET_END_SEGMENT(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X04, 7, 1) +#define IQK_DATA_SET_END_SEGMENT(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X04, 7, 1, __value) +#define IQK_DATA_GET_SEGMENT_SIZE(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X04, 8, 8) +#define IQK_DATA_SET_SEGMENT_SIZE(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X04, 8, 8, __value) +#define IQK_DATA_GET_TOTAL_SIZE(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X04, 16, 16) +#define IQK_DATA_SET_TOTAL_SIZE(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X04, 16, 16, __value) +#define IQK_DATA_GET_H2C_SEQ(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X8, 0, 16) +#define IQK_DATA_SET_H2C_SEQ(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X8, 0, 16, __value) +#define IQK_DATA_GET_DATA_START(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X8, 16, 8) +#define IQK_DATA_SET_DATA_START(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X8, 16, 8, __value) +#define CCX_RPT_GET_CCX_RPT(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X4, 0, 129) +#define CCX_RPT_SET_CCX_RPT(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X4, 0, 129, __value) +#endif diff --git a/drivers/staging/rtlwifi/halmac/halmac_fw_offload_h2c_nic.h b/drivers/staging/rtlwifi/halmac/halmac_fw_offload_h2c_nic.h new file mode 100644 index 000000000000..7adc3cdb38c9 --- /dev/null +++ b/drivers/staging/rtlwifi/halmac/halmac_fw_offload_h2c_nic.h @@ -0,0 +1,515 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef _HAL_FWOFFLOADH2CFORMAT_H2C_C2H_NIC_H_ +#define _HAL_FWOFFLOADH2CFORMAT_H2C_C2H_NIC_H_ +#define CMD_ID_FW_OFFLOAD_H2C 0XFF +#define CMD_ID_CHANNEL_SWITCH 0XFF +#define CMD_ID_DUMP_PHYSICAL_EFUSE 0XFF +#define CMD_ID_UPDATE_BEACON_PARSING_INFO 0XFF +#define CMD_ID_CFG_PARAMETER 0XFF +#define CMD_ID_UPDATE_DATAPACK 0XFF +#define CMD_ID_RUN_DATAPACK 0XFF +#define CMD_ID_DOWNLOAD_FLASH 0XFF +#define CMD_ID_UPDATE_PACKET 0XFF +#define CMD_ID_GENERAL_INFO 0XFF +#define CMD_ID_IQK 0XFF +#define CMD_ID_POWER_TRACKING 0XFF +#define CMD_ID_PSD 0XFF +#define CMD_ID_P2PPS 0XFF +#define CMD_ID_BT_COEX 0XFF +#define CMD_ID_NAN_CTRL 0XFF +#define CMD_ID_NAN_CHANNEL_PLAN_0 0XFF +#define CMD_ID_NAN_CHANNEL_PLAN_1 0XFF +#define CATEGORY_H2C_CMD_HEADER 0X00 +#define CATEGORY_FW_OFFLOAD_H2C 0X01 +#define CATEGORY_CHANNEL_SWITCH 0X01 +#define CATEGORY_DUMP_PHYSICAL_EFUSE 0X01 +#define CATEGORY_UPDATE_BEACON_PARSING_INFO 0X01 +#define CATEGORY_CFG_PARAMETER 0X01 +#define CATEGORY_UPDATE_DATAPACK 0X01 +#define CATEGORY_RUN_DATAPACK 0X01 +#define CATEGORY_DOWNLOAD_FLASH 0X01 +#define CATEGORY_UPDATE_PACKET 0X01 +#define CATEGORY_GENERAL_INFO 0X01 +#define CATEGORY_IQK 0X01 +#define CATEGORY_POWER_TRACKING 0X01 +#define CATEGORY_PSD 0X01 +#define CATEGORY_P2PPS 0X01 +#define CATEGORY_BT_COEX 0X01 +#define CATEGORY_NAN_CTRL 0X01 +#define CATEGORY_NAN_CHANNEL_PLAN_0 0X01 +#define CATEGORY_NAN_CHANNEL_PLAN_1 0X01 +#define SUB_CMD_ID_CHANNEL_SWITCH 0X02 +#define SUB_CMD_ID_DUMP_PHYSICAL_EFUSE 0X03 +#define SUB_CMD_ID_UPDATE_BEACON_PARSING_INFO 0X05 +#define SUB_CMD_ID_CFG_PARAMETER 0X08 +#define SUB_CMD_ID_UPDATE_DATAPACK 0X09 +#define SUB_CMD_ID_RUN_DATAPACK 0X0A +#define SUB_CMD_ID_DOWNLOAD_FLASH 0X0B +#define SUB_CMD_ID_UPDATE_PACKET 0X0C +#define SUB_CMD_ID_GENERAL_INFO 0X0D +#define SUB_CMD_ID_IQK 0X0E +#define SUB_CMD_ID_POWER_TRACKING 0X0F +#define SUB_CMD_ID_PSD 0X10 +#define SUB_CMD_ID_P2PPS 0X24 +#define SUB_CMD_ID_BT_COEX 0X60 +#define SUB_CMD_ID_NAN_CTRL 0XB2 +#define SUB_CMD_ID_NAN_CHANNEL_PLAN_0 0XB4 +#define SUB_CMD_ID_NAN_CHANNEL_PLAN_1 0XB5 +#define H2C_CMD_HEADER_GET_CATEGORY(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 0, 7) +#define H2C_CMD_HEADER_SET_CATEGORY(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 0, 7, __value) +#define H2C_CMD_HEADER_GET_ACK(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 7, 1) +#define H2C_CMD_HEADER_SET_ACK(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 7, 1, __value) +#define H2C_CMD_HEADER_GET_TOTAL_LEN(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X04, 0, 16) +#define H2C_CMD_HEADER_SET_TOTAL_LEN(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 0, 16, __value) +#define H2C_CMD_HEADER_GET_SEQ_NUM(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X04, 16, 16) +#define H2C_CMD_HEADER_SET_SEQ_NUM(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 16, 16, __value) +#define FW_OFFLOAD_H2C_GET_CATEGORY(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 0, 7) +#define FW_OFFLOAD_H2C_SET_CATEGORY(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 0, 7, __value) +#define FW_OFFLOAD_H2C_GET_ACK(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 7, 1) +#define FW_OFFLOAD_H2C_SET_ACK(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 7, 1, __value) +#define FW_OFFLOAD_H2C_GET_CMD_ID(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 8, 8) +#define FW_OFFLOAD_H2C_SET_CMD_ID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 8, 8, __value) +#define FW_OFFLOAD_H2C_GET_SUB_CMD_ID(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 16, 16) +#define FW_OFFLOAD_H2C_SET_SUB_CMD_ID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 16, 16, __value) +#define FW_OFFLOAD_H2C_GET_TOTAL_LEN(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X04, 0, 16) +#define FW_OFFLOAD_H2C_SET_TOTAL_LEN(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 0, 16, __value) +#define FW_OFFLOAD_H2C_GET_SEQ_NUM(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X04, 16, 16) +#define FW_OFFLOAD_H2C_SET_SEQ_NUM(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 16, 16, __value) +#define CHANNEL_SWITCH_GET_SWITCH_START(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X08, 0, 1) +#define CHANNEL_SWITCH_SET_SWITCH_START(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 0, 1, __value) +#define CHANNEL_SWITCH_GET_DEST_CH_EN(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X08, 1, 1) +#define CHANNEL_SWITCH_SET_DEST_CH_EN(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 1, 1, __value) +#define CHANNEL_SWITCH_GET_ABSOLUTE_TIME(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X08, 2, 1) +#define CHANNEL_SWITCH_SET_ABSOLUTE_TIME(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 2, 1, __value) +#define CHANNEL_SWITCH_GET_PERIODIC_OPTION(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X08, 3, 2) +#define CHANNEL_SWITCH_SET_PERIODIC_OPTION(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 3, 2, __value) +#define CHANNEL_SWITCH_GET_CHANNEL_INFO_LOC(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X08, 8, 8) +#define CHANNEL_SWITCH_SET_CHANNEL_INFO_LOC(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 8, 8, __value) +#define CHANNEL_SWITCH_GET_CHANNEL_NUM(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X08, 16, 8) +#define CHANNEL_SWITCH_SET_CHANNEL_NUM(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 16, 8, __value) +#define CHANNEL_SWITCH_GET_PRI_CH_IDX(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X08, 24, 4) +#define CHANNEL_SWITCH_SET_PRI_CH_IDX(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 24, 4, __value) +#define CHANNEL_SWITCH_GET_DEST_BW(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X08, 28, 4) +#define CHANNEL_SWITCH_SET_DEST_BW(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 28, 4, __value) +#define CHANNEL_SWITCH_GET_DEST_CH(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X0C, 0, 8) +#define CHANNEL_SWITCH_SET_DEST_CH(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X0C, 0, 8, __value) +#define CHANNEL_SWITCH_GET_NORMAL_PERIOD(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X0C, 8, 8) +#define CHANNEL_SWITCH_SET_NORMAL_PERIOD(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X0C, 8, 8, __value) +#define CHANNEL_SWITCH_GET_SLOW_PERIOD(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X0C, 16, 8) +#define CHANNEL_SWITCH_SET_SLOW_PERIOD(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X0C, 16, 8, __value) +#define CHANNEL_SWITCH_GET_NORMAL_CYCLE(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X0C, 24, 8) +#define CHANNEL_SWITCH_SET_NORMAL_CYCLE(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X0C, 24, 8, __value) +#define CHANNEL_SWITCH_GET_TSF_HIGH(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X10, 0, 32) +#define CHANNEL_SWITCH_SET_TSF_HIGH(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X10, 0, 32, __value) +#define CHANNEL_SWITCH_GET_TSF_LOW(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X14, 0, 32) +#define CHANNEL_SWITCH_SET_TSF_LOW(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X14, 0, 32, __value) +#define CHANNEL_SWITCH_GET_CHANNEL_INFO_SIZE(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X18, 0, 16) +#define CHANNEL_SWITCH_SET_CHANNEL_INFO_SIZE(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X18, 0, 16, __value) +#define UPDATE_BEACON_PARSING_INFO_GET_FUNC_EN(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X08, 0, 1) +#define UPDATE_BEACON_PARSING_INFO_SET_FUNC_EN(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 0, 1, __value) +#define UPDATE_BEACON_PARSING_INFO_GET_SIZE_TH(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X08, 8, 4) +#define UPDATE_BEACON_PARSING_INFO_SET_SIZE_TH(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 8, 4, __value) +#define UPDATE_BEACON_PARSING_INFO_GET_TIMEOUT(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X08, 12, 4) +#define UPDATE_BEACON_PARSING_INFO_SET_TIMEOUT(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 12, 4, __value) +#define UPDATE_BEACON_PARSING_INFO_GET_IE_ID_BMP_0(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X0C, 0, 32) +#define UPDATE_BEACON_PARSING_INFO_SET_IE_ID_BMP_0(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X0C, 0, 32, __value) +#define UPDATE_BEACON_PARSING_INFO_GET_IE_ID_BMP_1(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X10, 0, 32) +#define UPDATE_BEACON_PARSING_INFO_SET_IE_ID_BMP_1(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X10, 0, 32, __value) +#define UPDATE_BEACON_PARSING_INFO_GET_IE_ID_BMP_2(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X14, 0, 32) +#define UPDATE_BEACON_PARSING_INFO_SET_IE_ID_BMP_2(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X14, 0, 32, __value) +#define UPDATE_BEACON_PARSING_INFO_GET_IE_ID_BMP_3(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X18, 0, 32) +#define UPDATE_BEACON_PARSING_INFO_SET_IE_ID_BMP_3(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X18, 0, 32, __value) +#define UPDATE_BEACON_PARSING_INFO_GET_IE_ID_BMP_4(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X1C, 0, 32) +#define UPDATE_BEACON_PARSING_INFO_SET_IE_ID_BMP_4(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X1C, 0, 32, __value) +#define CFG_PARAMETER_GET_NUM(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X08, 0, 16) +#define CFG_PARAMETER_SET_NUM(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 0, 16, __value) +#define CFG_PARAMETER_GET_INIT_CASE(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X08, 16, 1) +#define CFG_PARAMETER_SET_INIT_CASE(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 16, 1, __value) +#define CFG_PARAMETER_GET_PHY_PARAMETER_LOC(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X08, 24, 8) +#define CFG_PARAMETER_SET_PHY_PARAMETER_LOC(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 24, 8, __value) +#define UPDATE_DATAPACK_GET_SIZE(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X08, 0, 16) +#define UPDATE_DATAPACK_SET_SIZE(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 0, 16, __value) +#define UPDATE_DATAPACK_GET_DATAPACK_ID(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X08, 16, 8) +#define UPDATE_DATAPACK_SET_DATAPACK_ID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 16, 8, __value) +#define UPDATE_DATAPACK_GET_DATAPACK_LOC(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X08, 24, 8) +#define UPDATE_DATAPACK_SET_DATAPACK_LOC(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 24, 8, __value) +#define UPDATE_DATAPACK_GET_DATAPACK_SEGMENT(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X0C, 0, 8) +#define UPDATE_DATAPACK_SET_DATAPACK_SEGMENT(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X0C, 0, 8, __value) +#define UPDATE_DATAPACK_GET_END_SEGMENT(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X0C, 8, 1) +#define UPDATE_DATAPACK_SET_END_SEGMENT(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X0C, 8, 1, __value) +#define RUN_DATAPACK_GET_DATAPACK_ID(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X08, 0, 8) +#define RUN_DATAPACK_SET_DATAPACK_ID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 0, 8, __value) +#define DOWNLOAD_FLASH_GET_SPI_CMD(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X08, 0, 8) +#define DOWNLOAD_FLASH_SET_SPI_CMD(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 0, 8, __value) +#define DOWNLOAD_FLASH_GET_LOCATION(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X08, 8, 16) +#define DOWNLOAD_FLASH_SET_LOCATION(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 8, 16, __value) +#define DOWNLOAD_FLASH_GET_SIZE(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X0C, 0, 32) +#define DOWNLOAD_FLASH_SET_SIZE(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X0C, 0, 32, __value) +#define DOWNLOAD_FLASH_GET_START_ADDR(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X10, 0, 32) +#define DOWNLOAD_FLASH_SET_START_ADDR(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X10, 0, 32, __value) +#define UPDATE_PACKET_GET_SIZE(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X08, 0, 16) +#define UPDATE_PACKET_SET_SIZE(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 0, 16, __value) +#define UPDATE_PACKET_GET_PACKET_ID(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X08, 16, 8) +#define UPDATE_PACKET_SET_PACKET_ID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 16, 8, __value) +#define UPDATE_PACKET_GET_PACKET_LOC(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X08, 24, 8) +#define UPDATE_PACKET_SET_PACKET_LOC(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 24, 8, __value) +#define GENERAL_INFO_GET_REF_TYPE(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X08, 0, 8) +#define GENERAL_INFO_SET_REF_TYPE(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 0, 8, __value) +#define GENERAL_INFO_GET_RF_TYPE(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X08, 8, 9) +#define GENERAL_INFO_SET_RF_TYPE(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 8, 9, __value) +#define GENERAL_INFO_GET_FW_TX_BOUNDARY(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X08, 16, 8) +#define GENERAL_INFO_SET_FW_TX_BOUNDARY(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 16, 8, __value) +#define IQK_GET_CLEAR(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X08, 0, 1) +#define IQK_SET_CLEAR(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 0, 1, __value) +#define IQK_GET_SEGMENT_IQK(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X08, 1, 1) +#define IQK_SET_SEGMENT_IQK(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 1, 1, __value) +#define POWER_TRACKING_GET_ENABLE_A(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X08, 0, 1) +#define POWER_TRACKING_SET_ENABLE_A(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 0, 1, __value) +#define POWER_TRACKING_GET_ENABLE_B(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X08, 1, 1) +#define POWER_TRACKING_SET_ENABLE_B(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 1, 1, __value) +#define POWER_TRACKING_GET_ENABLE_C(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X08, 2, 1) +#define POWER_TRACKING_SET_ENABLE_C(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 2, 1, __value) +#define POWER_TRACKING_GET_ENABLE_D(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X08, 3, 1) +#define POWER_TRACKING_SET_ENABLE_D(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 3, 1, __value) +#define POWER_TRACKING_GET_TYPE(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X08, 4, 3) +#define POWER_TRACKING_SET_TYPE(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 4, 3, __value) +#define POWER_TRACKING_GET_BBSWING_INDEX(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X08, 8, 8) +#define POWER_TRACKING_SET_BBSWING_INDEX(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 8, 8, __value) +#define POWER_TRACKING_GET_TX_PWR_INDEX_A(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X0C, 0, 8) +#define POWER_TRACKING_SET_TX_PWR_INDEX_A(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X0C, 0, 8, __value) +#define POWER_TRACKING_GET_PWR_TRACKING_OFFSET_VALUE_A(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X0C, 8, 8) +#define POWER_TRACKING_SET_PWR_TRACKING_OFFSET_VALUE_A(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X0C, 8, 8, __value) +#define POWER_TRACKING_GET_TSSI_VALUE_A(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X0C, 16, 8) +#define POWER_TRACKING_SET_TSSI_VALUE_A(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X0C, 16, 8, __value) +#define POWER_TRACKING_GET_TX_PWR_INDEX_B(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X10, 0, 8) +#define POWER_TRACKING_SET_TX_PWR_INDEX_B(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X10, 0, 8, __value) +#define POWER_TRACKING_GET_PWR_TRACKING_OFFSET_VALUE_B(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X10, 8, 8) +#define POWER_TRACKING_SET_PWR_TRACKING_OFFSET_VALUE_B(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X10, 8, 8, __value) +#define POWER_TRACKING_GET_TSSI_VALUE_B(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X10, 16, 8) +#define POWER_TRACKING_SET_TSSI_VALUE_B(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X10, 16, 8, __value) +#define POWER_TRACKING_GET_TX_PWR_INDEX_C(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X14, 0, 8) +#define POWER_TRACKING_SET_TX_PWR_INDEX_C(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X14, 0, 8, __value) +#define POWER_TRACKING_GET_PWR_TRACKING_OFFSET_VALUE_C(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X14, 8, 8) +#define POWER_TRACKING_SET_PWR_TRACKING_OFFSET_VALUE_C(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X14, 8, 8, __value) +#define POWER_TRACKING_GET_TSSI_VALUE_C(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X14, 16, 8) +#define POWER_TRACKING_SET_TSSI_VALUE_C(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X14, 16, 8, __value) +#define POWER_TRACKING_GET_TX_PWR_INDEX_D(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X18, 0, 8) +#define POWER_TRACKING_SET_TX_PWR_INDEX_D(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X18, 0, 8, __value) +#define POWER_TRACKING_GET_PWR_TRACKING_OFFSET_VALUE_D(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X18, 8, 8) +#define POWER_TRACKING_SET_PWR_TRACKING_OFFSET_VALUE_D(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X18, 8, 8, __value) +#define POWER_TRACKING_GET_TSSI_VALUE_D(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X18, 16, 8) +#define POWER_TRACKING_SET_TSSI_VALUE_D(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X18, 16, 8, __value) +#define PSD_GET_START_PSD(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X08, 0, 16) +#define PSD_SET_START_PSD(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 0, 16, __value) +#define PSD_GET_END_PSD(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X08, 16, 16) +#define PSD_SET_END_PSD(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 16, 16, __value) +#define P2PPS_GET_OFFLOAD_EN(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X08, 0, 1) +#define P2PPS_SET_OFFLOAD_EN(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 0, 1, __value) +#define P2PPS_GET_ROLE(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X08, 1, 1) +#define P2PPS_SET_ROLE(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 1, 1, __value) +#define P2PPS_GET_CTWINDOW_EN(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X08, 2, 1) +#define P2PPS_SET_CTWINDOW_EN(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 2, 1, __value) +#define P2PPS_GET_NOA_EN(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X08, 3, 1) +#define P2PPS_SET_NOA_EN(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 3, 1, __value) +#define P2PPS_GET_NOA_SEL(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X08, 4, 1) +#define P2PPS_SET_NOA_SEL(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 4, 1, __value) +#define P2PPS_GET_ALLSTASLEEP(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X08, 5, 1) +#define P2PPS_SET_ALLSTASLEEP(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 5, 1, __value) +#define P2PPS_GET_DISCOVERY(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X08, 6, 1) +#define P2PPS_SET_DISCOVERY(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 6, 1, __value) +#define P2PPS_GET_P2P_PORT_ID(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X08, 8, 8) +#define P2PPS_SET_P2P_PORT_ID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 8, 8, __value) +#define P2PPS_GET_P2P_GROUP(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X08, 16, 8) +#define P2PPS_SET_P2P_GROUP(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 16, 8, __value) +#define P2PPS_GET_P2P_MACID(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X08, 24, 8) +#define P2PPS_SET_P2P_MACID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 24, 8, __value) +#define P2PPS_GET_CTWINDOW_LENGTH(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X0C, 0, 8) +#define P2PPS_SET_CTWINDOW_LENGTH(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X0C, 0, 8, __value) +#define P2PPS_GET_NOA_DURATION_PARA(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X10, 0, 32) +#define P2PPS_SET_NOA_DURATION_PARA(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X10, 0, 32, __value) +#define P2PPS_GET_NOA_INTERVAL_PARA(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X14, 0, 32) +#define P2PPS_SET_NOA_INTERVAL_PARA(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X14, 0, 32, __value) +#define P2PPS_GET_NOA_START_TIME_PARA(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X18, 0, 32) +#define P2PPS_SET_NOA_START_TIME_PARA(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X18, 0, 32, __value) +#define P2PPS_GET_NOA_COUNT_PARA(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X1C, 0, 32) +#define P2PPS_SET_NOA_COUNT_PARA(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X1C, 0, 32, __value) +#define BT_COEX_GET_DATA_START(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X08, 0, 8) +#define BT_COEX_SET_DATA_START(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 0, 8, __value) +#define NAN_CTRL_GET_NAN_EN(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X08, 0, 2) +#define NAN_CTRL_SET_NAN_EN(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 0, 2, __value) +#define NAN_CTRL_GET_SUPPORT_BAND(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X08, 8, 2) +#define NAN_CTRL_SET_SUPPORT_BAND(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 8, 2, __value) +#define NAN_CTRL_GET_DISABLE_2G_DISC_BCN(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X08, 10, 1) +#define NAN_CTRL_SET_DISABLE_2G_DISC_BCN(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 10, 1, __value) +#define NAN_CTRL_GET_DISABLE_5G_DISC_BCN(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X08, 11, 1) +#define NAN_CTRL_SET_DISABLE_5G_DISC_BCN(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 11, 1, __value) +#define NAN_CTRL_GET_BCN_RSVD_PAGE_OFFSET(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X08, 16, 8) +#define NAN_CTRL_SET_BCN_RSVD_PAGE_OFFSET(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 16, 8, __value) +#define NAN_CTRL_GET_CHANNEL_2G(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X08, 24, 8) +#define NAN_CTRL_SET_CHANNEL_2G(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 24, 8, __value) +#define NAN_CTRL_GET_CHANNEL_5G(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X0C, 0, 8) +#define NAN_CTRL_SET_CHANNEL_5G(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X0C, 0, 8, __value) +#define NAN_CHANNEL_PLAN_0_GET_CHANNEL_NUMBER_0(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X08, 0, 8) +#define NAN_CHANNEL_PLAN_0_SET_CHANNEL_NUMBER_0(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 0, 8, __value) +#define NAN_CHANNEL_PLAN_0_GET_UNPAUSE_MACID_0(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X08, 8, 8) +#define NAN_CHANNEL_PLAN_0_SET_UNPAUSE_MACID_0(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 8, 8, __value) +#define NAN_CHANNEL_PLAN_0_GET_START_TIME_SLOT_0(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X0C, 0, 16) +#define NAN_CHANNEL_PLAN_0_SET_START_TIME_SLOT_0(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X0C, 0, 16, __value) +#define NAN_CHANNEL_PLAN_0_GET_DURATION_0(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X0C, 16, 16) +#define NAN_CHANNEL_PLAN_0_SET_DURATION_0(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X0C, 16, 16, __value) +#define NAN_CHANNEL_PLAN_0_GET_CHANNEL_NUMBER_1(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X10, 0, 8) +#define NAN_CHANNEL_PLAN_0_SET_CHANNEL_NUMBER_1(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X10, 0, 8, __value) +#define NAN_CHANNEL_PLAN_0_GET_UNPAUSE_MACID_1(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X10, 8, 8) +#define NAN_CHANNEL_PLAN_0_SET_UNPAUSE_MACID_1(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X10, 8, 8, __value) +#define NAN_CHANNEL_PLAN_0_GET_START_TIME_SLOT_1(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X14, 0, 16) +#define NAN_CHANNEL_PLAN_0_SET_START_TIME_SLOT_1(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X14, 0, 16, __value) +#define NAN_CHANNEL_PLAN_0_GET_DURATION_1(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X14, 16, 16) +#define NAN_CHANNEL_PLAN_0_SET_DURATION_1(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X14, 16, 16, __value) +#define NAN_CHANNEL_PLAN_0_GET_CHANNEL_NUMBER_2(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X18, 0, 8) +#define NAN_CHANNEL_PLAN_0_SET_CHANNEL_NUMBER_2(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X18, 0, 8, __value) +#define NAN_CHANNEL_PLAN_0_GET_UNPAUSE_MACID_2(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X18, 8, 8) +#define NAN_CHANNEL_PLAN_0_SET_UNPAUSE_MACID_2(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X18, 8, 8, __value) +#define NAN_CHANNEL_PLAN_0_GET_START_TIME_SLOT_2(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X1C, 0, 16) +#define NAN_CHANNEL_PLAN_0_SET_START_TIME_SLOT_2(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X1C, 0, 16, __value) +#define NAN_CHANNEL_PLAN_0_GET_DURATION_2(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X1C, 16, 16) +#define NAN_CHANNEL_PLAN_0_SET_DURATION_2(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X1C, 16, 16, __value) +#define NAN_CHANNEL_PLAN_1_GET_CHANNEL_NUMBER_3(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X08, 0, 8) +#define NAN_CHANNEL_PLAN_1_SET_CHANNEL_NUMBER_3(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 0, 8, __value) +#define NAN_CHANNEL_PLAN_1_GET_UNPAUSE_MACID_3(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X08, 8, 8) +#define NAN_CHANNEL_PLAN_1_SET_UNPAUSE_MACID_3(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X08, 8, 8, __value) +#define NAN_CHANNEL_PLAN_1_GET_START_TIME_SLOT_3(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X0C, 0, 16) +#define NAN_CHANNEL_PLAN_1_SET_START_TIME_SLOT_3(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X0C, 0, 16, __value) +#define NAN_CHANNEL_PLAN_1_GET_DURATION_3(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X0C, 16, 16) +#define NAN_CHANNEL_PLAN_1_SET_DURATION_3(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X0C, 16, 16, __value) +#define NAN_CHANNEL_PLAN_1_GET_CHANNEL_NUMBER_4(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X10, 0, 8) +#define NAN_CHANNEL_PLAN_1_SET_CHANNEL_NUMBER_4(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X10, 0, 8, __value) +#define NAN_CHANNEL_PLAN_1_GET_UNPAUSE_MACID_4(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X10, 8, 8) +#define NAN_CHANNEL_PLAN_1_SET_UNPAUSE_MACID_4(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X10, 8, 8, __value) +#define NAN_CHANNEL_PLAN_1_GET_START_TIME_SLOT_4(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X14, 0, 16) +#define NAN_CHANNEL_PLAN_1_SET_START_TIME_SLOT_4(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X14, 0, 16, __value) +#define NAN_CHANNEL_PLAN_1_GET_DURATION_4(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X14, 16, 16) +#define NAN_CHANNEL_PLAN_1_SET_DURATION_4(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X14, 16, 16, __value) +#define NAN_CHANNEL_PLAN_1_GET_CHANNEL_NUMBER_5(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X18, 0, 8) +#define NAN_CHANNEL_PLAN_1_SET_CHANNEL_NUMBER_5(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X18, 0, 8, __value) +#define NAN_CHANNEL_PLAN_1_GET_UNPAUSE_MACID_5(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X18, 8, 8) +#define NAN_CHANNEL_PLAN_1_SET_UNPAUSE_MACID_5(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X18, 8, 8, __value) +#define NAN_CHANNEL_PLAN_1_GET_START_TIME_SLOT_5(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X1C, 0, 16) +#define NAN_CHANNEL_PLAN_1_SET_START_TIME_SLOT_5(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X1C, 0, 16, __value) +#define NAN_CHANNEL_PLAN_1_GET_DURATION_5(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X1C, 16, 16) +#define NAN_CHANNEL_PLAN_1_SET_DURATION_5(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X1C, 16, 16, __value) +#endif diff --git a/drivers/staging/rtlwifi/halmac/halmac_h2c_extra_info_nic.h b/drivers/staging/rtlwifi/halmac/halmac_h2c_extra_info_nic.h new file mode 100644 index 000000000000..5f23cba6d067 --- /dev/null +++ b/drivers/staging/rtlwifi/halmac/halmac_h2c_extra_info_nic.h @@ -0,0 +1,115 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef _HAL_H2CEXTRAINFO_H2C_C2H_NIC_H_ +#define _HAL_H2CEXTRAINFO_H2C_C2H_NIC_H_ +#define PHY_PARAMETER_INFO_GET_LENGTH(__extra_info) \ + LE_BITS_TO_4BYTE(__extra_info + 0X00, 0, 8) +#define PHY_PARAMETER_INFO_SET_LENGTH(__extra_info, __value) \ + SET_BITS_TO_LE_4BYTE(__extra_info + 0X00, 0, 8, __value) +#define PHY_PARAMETER_INFO_GET_IO_CMD(__extra_info) \ + LE_BITS_TO_4BYTE(__extra_info + 0X00, 8, 7) +#define PHY_PARAMETER_INFO_SET_IO_CMD(__extra_info, __value) \ + SET_BITS_TO_LE_4BYTE(__extra_info + 0X00, 8, 7, __value) +#define PHY_PARAMETER_INFO_GET_MSK_EN(__extra_info) \ + LE_BITS_TO_4BYTE(__extra_info + 0X00, 15, 1) +#define PHY_PARAMETER_INFO_SET_MSK_EN(__extra_info, __value) \ + SET_BITS_TO_LE_4BYTE(__extra_info + 0X00, 15, 1, __value) +#define PHY_PARAMETER_INFO_GET_LLT_PG_BNDY(__extra_info) \ + LE_BITS_TO_4BYTE(__extra_info + 0X00, 16, 8) +#define PHY_PARAMETER_INFO_SET_LLT_PG_BNDY(__extra_info, __value) \ + SET_BITS_TO_LE_4BYTE(__extra_info + 0X00, 16, 8, __value) +#define PHY_PARAMETER_INFO_GET_EFUSE_RSVDPAGE_LOC(__extra_info) \ + LE_BITS_TO_4BYTE(__extra_info + 0X00, 16, 8) +#define PHY_PARAMETER_INFO_SET_EFUSE_RSVDPAGE_LOC(__extra_info, __value) \ + SET_BITS_TO_LE_4BYTE(__extra_info + 0X00, 16, 8, __value) +#define PHY_PARAMETER_INFO_GET_EFUSE_PATCH_EN(__extra_info) \ + LE_BITS_TO_4BYTE(__extra_info + 0X00, 16, 8) +#define PHY_PARAMETER_INFO_SET_EFUSE_PATCH_EN(__extra_info, __value) \ + SET_BITS_TO_LE_4BYTE(__extra_info + 0X00, 16, 8, __value) +#define PHY_PARAMETER_INFO_GET_RF_ADDR(__extra_info) \ + LE_BITS_TO_4BYTE(__extra_info + 0X00, 16, 8) +#define PHY_PARAMETER_INFO_SET_RF_ADDR(__extra_info, __value) \ + SET_BITS_TO_LE_4BYTE(__extra_info + 0X00, 16, 8, __value) +#define PHY_PARAMETER_INFO_GET_IO_ADDR(__extra_info) \ + LE_BITS_TO_4BYTE(__extra_info + 0X00, 16, 16) +#define PHY_PARAMETER_INFO_SET_IO_ADDR(__extra_info, __value) \ + SET_BITS_TO_LE_4BYTE(__extra_info + 0X00, 16, 16, __value) +#define PHY_PARAMETER_INFO_GET_DELAY_VALUE(__extra_info) \ + LE_BITS_TO_4BYTE(__extra_info + 0X00, 16, 16) +#define PHY_PARAMETER_INFO_SET_DELAY_VALUE(__extra_info, __value) \ + SET_BITS_TO_LE_4BYTE(__extra_info + 0X00, 16, 16, __value) +#define PHY_PARAMETER_INFO_GET_RF_PATH(__extra_info) \ + LE_BITS_TO_4BYTE(__extra_info + 0X00, 24, 8) +#define PHY_PARAMETER_INFO_SET_RF_PATH(__extra_info, __value) \ + SET_BITS_TO_LE_4BYTE(__extra_info + 0X00, 24, 8, __value) +#define PHY_PARAMETER_INFO_GET_DATA(__extra_info) \ + LE_BITS_TO_4BYTE(__extra_info + 0X04, 0, 32) +#define PHY_PARAMETER_INFO_SET_DATA(__extra_info, __value) \ + SET_BITS_TO_LE_4BYTE(__extra_info + 0X04, 0, 32, __value) +#define PHY_PARAMETER_INFO_GET_MASK(__extra_info) \ + LE_BITS_TO_4BYTE(__extra_info + 0X08, 0, 32) +#define PHY_PARAMETER_INFO_SET_MASK(__extra_info, __value) \ + SET_BITS_TO_LE_4BYTE(__extra_info + 0X08, 0, 32, __value) +#define CHANNEL_INFO_GET_CHANNEL(__extra_info) \ + LE_BITS_TO_4BYTE(__extra_info + 0X00, 0, 8) +#define CHANNEL_INFO_SET_CHANNEL(__extra_info, __value) \ + SET_BITS_TO_LE_4BYTE(__extra_info + 0X00, 0, 8, __value) +#define CHANNEL_INFO_GET_PRI_CH_IDX(__extra_info) \ + LE_BITS_TO_4BYTE(__extra_info + 0X00, 8, 4) +#define CHANNEL_INFO_SET_PRI_CH_IDX(__extra_info, __value) \ + SET_BITS_TO_LE_4BYTE(__extra_info + 0X00, 8, 4, __value) +#define CHANNEL_INFO_GET_BANDWIDTH(__extra_info) \ + LE_BITS_TO_4BYTE(__extra_info + 0X00, 12, 4) +#define CHANNEL_INFO_SET_BANDWIDTH(__extra_info, __value) \ + SET_BITS_TO_LE_4BYTE(__extra_info + 0X00, 12, 4, __value) +#define CHANNEL_INFO_GET_TIMEOUT(__extra_info) \ + LE_BITS_TO_4BYTE(__extra_info + 0X00, 16, 8) +#define CHANNEL_INFO_SET_TIMEOUT(__extra_info, __value) \ + SET_BITS_TO_LE_4BYTE(__extra_info + 0X00, 16, 8, __value) +#define CHANNEL_INFO_GET_ACTION_ID(__extra_info) \ + LE_BITS_TO_4BYTE(__extra_info + 0X00, 24, 7) +#define CHANNEL_INFO_SET_ACTION_ID(__extra_info, __value) \ + SET_BITS_TO_LE_4BYTE(__extra_info + 0X00, 24, 7, __value) +#define CHANNEL_INFO_GET_CH_EXTRA_INFO(__extra_info) \ + LE_BITS_TO_4BYTE(__extra_info + 0X00, 31, 1) +#define CHANNEL_INFO_SET_CH_EXTRA_INFO(__extra_info, __value) \ + SET_BITS_TO_LE_4BYTE(__extra_info + 0X00, 31, 1, __value) +#define CH_EXTRA_INFO_GET_CH_EXTRA_INFO_ID(__extra_info) \ + LE_BITS_TO_4BYTE(__extra_info + 0X00, 0, 7) +#define CH_EXTRA_INFO_SET_CH_EXTRA_INFO_ID(__extra_info, __value) \ + SET_BITS_TO_LE_4BYTE(__extra_info + 0X00, 0, 7, __value) +#define CH_EXTRA_INFO_GET_CH_EXTRA_INFO(__extra_info) \ + LE_BITS_TO_4BYTE(__extra_info + 0X00, 7, 1) +#define CH_EXTRA_INFO_SET_CH_EXTRA_INFO(__extra_info, __value) \ + SET_BITS_TO_LE_4BYTE(__extra_info + 0X00, 7, 1, __value) +#define CH_EXTRA_INFO_GET_CH_EXTRA_INFO_SIZE(__extra_info) \ + LE_BITS_TO_4BYTE(__extra_info + 0X00, 8, 8) +#define CH_EXTRA_INFO_SET_CH_EXTRA_INFO_SIZE(__extra_info, __value) \ + SET_BITS_TO_LE_4BYTE(__extra_info + 0X00, 8, 8, __value) +#define CH_EXTRA_INFO_GET_CH_EXTRA_INFO_DATA(__extra_info) \ + LE_BITS_TO_4BYTE(__extra_info + 0X00, 16, 1) +#define CH_EXTRA_INFO_SET_CH_EXTRA_INFO_DATA(__extra_info, __value) \ + SET_BITS_TO_LE_4BYTE(__extra_info + 0X00, 16, 1, __value) +#endif diff --git a/drivers/staging/rtlwifi/halmac/halmac_intf_phy_cmd.h b/drivers/staging/rtlwifi/halmac/halmac_intf_phy_cmd.h new file mode 100644 index 000000000000..273d4c0e338a --- /dev/null +++ b/drivers/staging/rtlwifi/halmac/halmac_intf_phy_cmd.h @@ -0,0 +1,54 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef HALMAC_INTF_PHY_CMD +#define HALMAC_INTF_PHY_CMD + +/* Cut mask */ +enum halmac_intf_phy_cut { + HALMAC_INTF_PHY_CUT_TESTCHIP = BIT(0), + HALMAC_INTF_PHY_CUT_A = BIT(1), + HALMAC_INTF_PHY_CUT_B = BIT(2), + HALMAC_INTF_PHY_CUT_C = BIT(3), + HALMAC_INTF_PHY_CUT_D = BIT(4), + HALMAC_INTF_PHY_CUT_E = BIT(5), + HALMAC_INTF_PHY_CUT_F = BIT(6), + HALMAC_INTF_PHY_CUT_G = BIT(7), + HALMAC_INTF_PHY_CUT_ALL = 0x7FFF, +}; + +/* IP selection */ +enum halmac_ip_sel { + HALMAC_IP_SEL_INTF_PHY = 0, + HALMAC_IP_SEL_MAC = 1, + HALMAC_IP_SEL_PCIE_DBI = 2, + HALMAC_IP_SEL_UNDEFINE = 0x7FFF, +}; + +/* Platform mask */ +enum halmac_intf_phy_platform { + HALMAC_INTF_PHY_PLATFORM_ALL = 0x7FFF, +}; + +#endif diff --git a/drivers/staging/rtlwifi/halmac/halmac_original_c2h_nic.h b/drivers/staging/rtlwifi/halmac/halmac_original_c2h_nic.h new file mode 100644 index 000000000000..4331e2ae14c2 --- /dev/null +++ b/drivers/staging/rtlwifi/halmac/halmac_original_c2h_nic.h @@ -0,0 +1,403 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef _HAL_ORIGINALC2HFORMAT_H2C_C2H_NIC_H_ +#define _HAL_ORIGINALC2HFORMAT_H2C_C2H_NIC_H_ +#define CMD_ID_C2H 0X00 +#define CMD_ID_DBG 0X00 +#define CMD_ID_C2H_LB 0X01 +#define CMD_ID_C2H_SND_TXBF 0X02 +#define CMD_ID_C2H_CCX_RPT 0X03 +#define CMD_ID_C2H_AP_REQ_TXRPT 0X04 +#define CMD_ID_C2H_INITIAL_RATE_COLLECTION 0X05 +#define CMD_ID_C2H_RA_RPT 0X0C +#define CMD_ID_C2H_SPECIAL_STATISTICS 0X0D +#define CMD_ID_C2H_RA_PARA_RPT 0X0E +#define CMD_ID_C2H_CUR_CHANNEL 0X10 +#define CMD_ID_C2H_GPIO_WAKEUP 0X14 +#define C2H_GET_CMD_ID(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X00, 0, 8) +#define C2H_SET_CMD_ID(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X00, 0, 8, __value) +#define C2H_GET_SEQ(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X00, 8, 8) +#define C2H_SET_SEQ(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X00, 8, 8, __value) +#define DBG_GET_CMD_ID(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X00, 0, 8) +#define DBG_SET_CMD_ID(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X00, 0, 8, __value) +#define DBG_GET_SEQ(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X00, 8, 8) +#define DBG_SET_SEQ(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X00, 8, 8, __value) +#define DBG_GET_DBG_STR1(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X00, 16, 8) +#define DBG_SET_DBG_STR1(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X00, 16, 8, __value) +#define DBG_GET_DBG_STR2(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X00, 24, 8) +#define DBG_SET_DBG_STR2(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X00, 24, 8, __value) +#define DBG_GET_DBG_STR3(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X04, 0, 8) +#define DBG_SET_DBG_STR3(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X04, 0, 8, __value) +#define DBG_GET_DBG_STR4(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X04, 8, 8) +#define DBG_SET_DBG_STR4(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X04, 8, 8, __value) +#define DBG_GET_DBG_STR5(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X04, 16, 8) +#define DBG_SET_DBG_STR5(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X04, 16, 8, __value) +#define DBG_GET_DBG_STR6(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X04, 24, 8) +#define DBG_SET_DBG_STR6(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X04, 24, 8, __value) +#define DBG_GET_DBG_STR7(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X08, 0, 8) +#define DBG_SET_DBG_STR7(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X08, 0, 8, __value) +#define DBG_GET_DBG_STR8(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X08, 8, 8) +#define DBG_SET_DBG_STR8(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X08, 8, 8, __value) +#define DBG_GET_DBG_STR9(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X08, 16, 8) +#define DBG_SET_DBG_STR9(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X08, 16, 8, __value) +#define DBG_GET_DBG_STR10(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X08, 24, 8) +#define DBG_SET_DBG_STR10(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X08, 24, 8, __value) +#define DBG_GET_DBG_STR11(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X0C, 0, 8) +#define DBG_SET_DBG_STR11(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X0C, 0, 8, __value) +#define DBG_GET_DBG_STR12(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X0C, 8, 8) +#define DBG_SET_DBG_STR12(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X0C, 8, 8, __value) +#define DBG_GET_LEN(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X0C, 16, 8) +#define DBG_SET_LEN(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X0C, 16, 8, __value) +#define DBG_GET_TRIGGER(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X0C, 24, 8) +#define DBG_SET_TRIGGER(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X0C, 24, 8, __value) +#define C2H_LB_GET_CMD_ID(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X00, 0, 8) +#define C2H_LB_SET_CMD_ID(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X00, 0, 8, __value) +#define C2H_LB_GET_SEQ(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X00, 8, 8) +#define C2H_LB_SET_SEQ(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X00, 8, 8, __value) +#define C2H_LB_GET_PAYLOAD1(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X00, 16, 16) +#define C2H_LB_SET_PAYLOAD1(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X00, 16, 16, __value) +#define C2H_LB_GET_PAYLOAD2(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X04, 0, 32) +#define C2H_LB_SET_PAYLOAD2(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X04, 0, 32, __value) +#define C2H_LB_GET_LEN(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X0C, 16, 8) +#define C2H_LB_SET_LEN(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X0C, 16, 8, __value) +#define C2H_LB_GET_TRIGGER(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X0C, 24, 8) +#define C2H_LB_SET_TRIGGER(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X0C, 24, 8, __value) +#define C2H_SND_TXBF_GET_CMD_ID(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X00, 0, 8) +#define C2H_SND_TXBF_SET_CMD_ID(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X00, 0, 8, __value) +#define C2H_SND_TXBF_GET_SEQ(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X00, 8, 8) +#define C2H_SND_TXBF_SET_SEQ(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X00, 8, 8, __value) +#define C2H_SND_TXBF_GET_SND_RESULT(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X00, 16, 1) +#define C2H_SND_TXBF_SET_SND_RESULT(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X00, 16, 1, __value) +#define C2H_SND_TXBF_GET_LEN(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X0C, 16, 8) +#define C2H_SND_TXBF_SET_LEN(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X0C, 16, 8, __value) +#define C2H_SND_TXBF_GET_TRIGGER(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X0C, 24, 8) +#define C2H_SND_TXBF_SET_TRIGGER(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X0C, 24, 8, __value) +#define C2H_CCX_RPT_GET_CMD_ID(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X00, 0, 8) +#define C2H_CCX_RPT_SET_CMD_ID(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X00, 0, 8, __value) +#define C2H_CCX_RPT_GET_SEQ(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X00, 8, 8) +#define C2H_CCX_RPT_SET_SEQ(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X00, 8, 8, __value) +#define C2H_CCX_RPT_GET_QSEL(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X00, 16, 5) +#define C2H_CCX_RPT_SET_QSEL(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X00, 16, 5, __value) +#define C2H_CCX_RPT_GET_BMC(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X00, 21, 1) +#define C2H_CCX_RPT_SET_BMC(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X00, 21, 1, __value) +#define C2H_CCX_RPT_GET_LIFE_TIME_OVER(__c2h) \ + LE_BITS_TO_4BYTE(__c2h + 0X00, 22, 1) +#define C2H_CCX_RPT_SET_LIFE_TIME_OVER(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X00, 22, 1, __value) +#define C2H_CCX_RPT_GET_RETRY_OVER(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X00, 23, 1) +#define C2H_CCX_RPT_SET_RETRY_OVER(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X00, 23, 1, __value) +#define C2H_CCX_RPT_GET_MACID(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X00, 24, 8) +#define C2H_CCX_RPT_SET_MACID(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X00, 24, 8, __value) +#define C2H_CCX_RPT_GET_DATA_RETRY_CNT(__c2h) \ + LE_BITS_TO_4BYTE(__c2h + 0X04, 0, 6) +#define C2H_CCX_RPT_SET_DATA_RETRY_CNT(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X04, 0, 6, __value) +#define C2H_CCX_RPT_GET_QUEUE7_0(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X04, 8, 8) +#define C2H_CCX_RPT_SET_QUEUE7_0(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X04, 8, 8, __value) +#define C2H_CCX_RPT_GET_QUEUE15_8(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X04, 16, 8) +#define C2H_CCX_RPT_SET_QUEUE15_8(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X04, 16, 8, __value) +#define C2H_CCX_RPT_GET_FINAL_DATA_RATE(__c2h) \ + LE_BITS_TO_4BYTE(__c2h + 0X04, 24, 8) +#define C2H_CCX_RPT_SET_FINAL_DATA_RATE(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X04, 24, 8, __value) +#define C2H_CCX_RPT_GET_SW_DEFINE_0(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X08, 0, 8) +#define C2H_CCX_RPT_SET_SW_DEFINE_0(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X08, 0, 8, __value) +#define C2H_CCX_RPT_GET_SW_DEFINE_1(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X08, 8, 4) +#define C2H_CCX_RPT_SET_SW_DEFINE_1(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X08, 8, 4, __value) +#define C2H_CCX_RPT_GET_LEN(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X0C, 16, 8) +#define C2H_CCX_RPT_SET_LEN(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X0C, 16, 8, __value) +#define C2H_CCX_RPT_GET_TRIGGER(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X0C, 24, 8) +#define C2H_CCX_RPT_SET_TRIGGER(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X0C, 24, 8, __value) +#define C2H_AP_REQ_TXRPT_GET_CMD_ID(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X00, 0, 8) +#define C2H_AP_REQ_TXRPT_SET_CMD_ID(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X00, 0, 8, __value) +#define C2H_AP_REQ_TXRPT_GET_SEQ(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X00, 8, 8) +#define C2H_AP_REQ_TXRPT_SET_SEQ(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X00, 8, 8, __value) +#define C2H_AP_REQ_TXRPT_GET_STA1_MACID(__c2h) \ + LE_BITS_TO_4BYTE(__c2h + 0X00, 16, 8) +#define C2H_AP_REQ_TXRPT_SET_STA1_MACID(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X00, 16, 8, __value) +#define C2H_AP_REQ_TXRPT_GET_TX_OK1_0(__c2h) \ + LE_BITS_TO_4BYTE(__c2h + 0X00, 24, 8) +#define C2H_AP_REQ_TXRPT_SET_TX_OK1_0(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X00, 24, 8, __value) +#define C2H_AP_REQ_TXRPT_GET_TX_OK1_1(__c2h) \ + LE_BITS_TO_4BYTE(__c2h + 0X04, 0, 8) +#define C2H_AP_REQ_TXRPT_SET_TX_OK1_1(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X04, 0, 8, __value) +#define C2H_AP_REQ_TXRPT_GET_TX_FAIL1_0(__c2h) \ + LE_BITS_TO_4BYTE(__c2h + 0X04, 8, 8) +#define C2H_AP_REQ_TXRPT_SET_TX_FAIL1_0(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X04, 8, 8, __value) +#define C2H_AP_REQ_TXRPT_GET_TX_FAIL1_1(__c2h) \ + LE_BITS_TO_4BYTE(__c2h + 0X04, 16, 8) +#define C2H_AP_REQ_TXRPT_SET_TX_FAIL1_1(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X04, 16, 8, __value) +#define C2H_AP_REQ_TXRPT_GET_INITIAL_RATE1(__c2h) \ + LE_BITS_TO_4BYTE(__c2h + 0X04, 24, 8) +#define C2H_AP_REQ_TXRPT_SET_INITIAL_RATE1(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X04, 24, 8, __value) +#define C2H_AP_REQ_TXRPT_GET_STA2_MACID(__c2h) \ + LE_BITS_TO_4BYTE(__c2h + 0X08, 0, 8) +#define C2H_AP_REQ_TXRPT_SET_STA2_MACID(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X08, 0, 8, __value) +#define C2H_AP_REQ_TXRPT_GET_TX_OK2_0(__c2h) \ + LE_BITS_TO_4BYTE(__c2h + 0X08, 8, 8) +#define C2H_AP_REQ_TXRPT_SET_TX_OK2_0(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X08, 8, 8, __value) +#define C2H_AP_REQ_TXRPT_GET_TX_OK2_1(__c2h) \ + LE_BITS_TO_4BYTE(__c2h + 0X08, 16, 8) +#define C2H_AP_REQ_TXRPT_SET_TX_OK2_1(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X08, 16, 8, __value) +#define C2H_AP_REQ_TXRPT_GET_TX_FAIL2_0(__c2h) \ + LE_BITS_TO_4BYTE(__c2h + 0X08, 24, 8) +#define C2H_AP_REQ_TXRPT_SET_TX_FAIL2_0(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X08, 24, 8, __value) +#define C2H_AP_REQ_TXRPT_GET_TX_FAIL2_1(__c2h) \ + LE_BITS_TO_4BYTE(__c2h + 0X0C, 0, 8) +#define C2H_AP_REQ_TXRPT_SET_TX_FAIL2_1(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X0C, 0, 8, __value) +#define C2H_AP_REQ_TXRPT_GET_INITIAL_RATE2(__c2h) \ + LE_BITS_TO_4BYTE(__c2h + 0X0C, 8, 8) +#define C2H_AP_REQ_TXRPT_SET_INITIAL_RATE2(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X0C, 8, 8, __value) +#define C2H_AP_REQ_TXRPT_GET_LEN(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X0C, 16, 8) +#define C2H_AP_REQ_TXRPT_SET_LEN(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X0C, 16, 8, __value) +#define C2H_AP_REQ_TXRPT_GET_TRIGGER(__c2h) \ + LE_BITS_TO_4BYTE(__c2h + 0X0C, 24, 8) +#define C2H_AP_REQ_TXRPT_SET_TRIGGER(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X0C, 24, 8, __value) +#define C2H_INITIAL_RATE_COLLECTION_GET_CMD_ID(__c2h) \ + LE_BITS_TO_4BYTE(__c2h + 0X00, 0, 8) +#define C2H_INITIAL_RATE_COLLECTION_SET_CMD_ID(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X00, 0, 8, __value) +#define C2H_INITIAL_RATE_COLLECTION_GET_SEQ(__c2h) \ + LE_BITS_TO_4BYTE(__c2h + 0X00, 8, 8) +#define C2H_INITIAL_RATE_COLLECTION_SET_SEQ(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X00, 8, 8, __value) +#define C2H_INITIAL_RATE_COLLECTION_GET_TRYING_BITMAP(__c2h) \ + LE_BITS_TO_4BYTE(__c2h + 0X00, 16, 7) +#define C2H_INITIAL_RATE_COLLECTION_SET_TRYING_BITMAP(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X00, 16, 7, __value) +#define C2H_INITIAL_RATE_COLLECTION_GET_INITIAL_RATE1(__c2h) \ + LE_BITS_TO_4BYTE(__c2h + 0X00, 24, 8) +#define C2H_INITIAL_RATE_COLLECTION_SET_INITIAL_RATE1(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X00, 24, 8, __value) +#define C2H_INITIAL_RATE_COLLECTION_GET_INITIAL_RATE2(__c2h) \ + LE_BITS_TO_4BYTE(__c2h + 0X04, 0, 8) +#define C2H_INITIAL_RATE_COLLECTION_SET_INITIAL_RATE2(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X04, 0, 8, __value) +#define C2H_INITIAL_RATE_COLLECTION_GET_INITIAL_RATE3(__c2h) \ + LE_BITS_TO_4BYTE(__c2h + 0X04, 8, 8) +#define C2H_INITIAL_RATE_COLLECTION_SET_INITIAL_RATE3(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X04, 8, 8, __value) +#define C2H_INITIAL_RATE_COLLECTION_GET_INITIAL_RATE4(__c2h) \ + LE_BITS_TO_4BYTE(__c2h + 0X04, 16, 8) +#define C2H_INITIAL_RATE_COLLECTION_SET_INITIAL_RATE4(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X04, 16, 8, __value) +#define C2H_INITIAL_RATE_COLLECTION_GET_INITIAL_RATE5(__c2h) \ + LE_BITS_TO_4BYTE(__c2h + 0X04, 24, 8) +#define C2H_INITIAL_RATE_COLLECTION_SET_INITIAL_RATE5(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X04, 24, 8, __value) +#define C2H_INITIAL_RATE_COLLECTION_GET_INITIAL_RATE6(__c2h) \ + LE_BITS_TO_4BYTE(__c2h + 0X08, 0, 8) +#define C2H_INITIAL_RATE_COLLECTION_SET_INITIAL_RATE6(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X08, 0, 8, __value) +#define C2H_INITIAL_RATE_COLLECTION_GET_INITIAL_RATE7(__c2h) \ + LE_BITS_TO_4BYTE(__c2h + 0X08, 8, 8) +#define C2H_INITIAL_RATE_COLLECTION_SET_INITIAL_RATE7(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X08, 8, 8, __value) +#define C2H_INITIAL_RATE_COLLECTION_GET_LEN(__c2h) \ + LE_BITS_TO_4BYTE(__c2h + 0X0C, 16, 8) +#define C2H_INITIAL_RATE_COLLECTION_SET_LEN(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X0C, 16, 8, __value) +#define C2H_INITIAL_RATE_COLLECTION_GET_TRIGGER(__c2h) \ + LE_BITS_TO_4BYTE(__c2h + 0X0C, 24, 8) +#define C2H_INITIAL_RATE_COLLECTION_SET_TRIGGER(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X0C, 24, 8, __value) +#define C2H_RA_RPT_GET_CMD_ID(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X00, 0, 8) +#define C2H_RA_RPT_SET_CMD_ID(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X00, 0, 8, __value) +#define C2H_RA_RPT_GET_SEQ(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X00, 8, 8) +#define C2H_RA_RPT_SET_SEQ(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X00, 8, 8, __value) +#define C2H_RA_RPT_GET_RATE(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X00, 16, 8) +#define C2H_RA_RPT_SET_RATE(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X00, 16, 8, __value) +#define C2H_RA_RPT_GET_MACID(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X00, 24, 8) +#define C2H_RA_RPT_SET_MACID(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X00, 24, 8, __value) +#define C2H_RA_RPT_GET_USE_LDPC(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X04, 0, 1) +#define C2H_RA_RPT_SET_USE_LDPC(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X04, 0, 1, __value) +#define C2H_RA_RPT_GET_USE_TXBF(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X04, 1, 1) +#define C2H_RA_RPT_SET_USE_TXBF(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X04, 1, 1, __value) +#define C2H_RA_RPT_GET_COLLISION_STATE(__c2h) \ + LE_BITS_TO_4BYTE(__c2h + 0X04, 8, 8) +#define C2H_RA_RPT_SET_COLLISION_STATE(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X04, 8, 8, __value) +#define C2H_RA_RPT_GET_LEN(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X0C, 16, 8) +#define C2H_RA_RPT_SET_LEN(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X0C, 16, 8, __value) +#define C2H_RA_RPT_GET_TRIGGER(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X0C, 24, 8) +#define C2H_RA_RPT_SET_TRIGGER(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X0C, 24, 8, __value) +#define C2H_SPECIAL_STATISTICS_GET_CMD_ID(__c2h) \ + LE_BITS_TO_4BYTE(__c2h + 0X00, 0, 8) +#define C2H_SPECIAL_STATISTICS_SET_CMD_ID(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X00, 0, 8, __value) +#define C2H_SPECIAL_STATISTICS_GET_SEQ(__c2h) \ + LE_BITS_TO_4BYTE(__c2h + 0X00, 8, 8) +#define C2H_SPECIAL_STATISTICS_SET_SEQ(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X00, 8, 8, __value) +#define C2H_SPECIAL_STATISTICS_GET_STATISTICS_IDX(__c2h) \ + LE_BITS_TO_4BYTE(__c2h + 0X00, 16, 8) +#define C2H_SPECIAL_STATISTICS_SET_STATISTICS_IDX(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X00, 16, 8, __value) +#define C2H_SPECIAL_STATISTICS_GET_DATA0(__c2h) \ + LE_BITS_TO_4BYTE(__c2h + 0X00, 24, 8) +#define C2H_SPECIAL_STATISTICS_SET_DATA0(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X00, 24, 8, __value) +#define C2H_SPECIAL_STATISTICS_GET_DATA1(__c2h) \ + LE_BITS_TO_4BYTE(__c2h + 0X04, 0, 8) +#define C2H_SPECIAL_STATISTICS_SET_DATA1(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X04, 0, 8, __value) +#define C2H_SPECIAL_STATISTICS_GET_DATA2(__c2h) \ + LE_BITS_TO_4BYTE(__c2h + 0X04, 8, 8) +#define C2H_SPECIAL_STATISTICS_SET_DATA2(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X04, 8, 8, __value) +#define C2H_SPECIAL_STATISTICS_GET_DATA3(__c2h) \ + LE_BITS_TO_4BYTE(__c2h + 0X04, 16, 8) +#define C2H_SPECIAL_STATISTICS_SET_DATA3(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X04, 16, 8, __value) +#define C2H_SPECIAL_STATISTICS_GET_DATA4(__c2h) \ + LE_BITS_TO_4BYTE(__c2h + 0X04, 24, 8) +#define C2H_SPECIAL_STATISTICS_SET_DATA4(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X04, 24, 8, __value) +#define C2H_SPECIAL_STATISTICS_GET_DATA5(__c2h) \ + LE_BITS_TO_4BYTE(__c2h + 0X08, 0, 8) +#define C2H_SPECIAL_STATISTICS_SET_DATA5(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X08, 0, 8, __value) +#define C2H_SPECIAL_STATISTICS_GET_DATA6(__c2h) \ + LE_BITS_TO_4BYTE(__c2h + 0X08, 8, 8) +#define C2H_SPECIAL_STATISTICS_SET_DATA6(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X08, 8, 8, __value) +#define C2H_SPECIAL_STATISTICS_GET_DATA7(__c2h) \ + LE_BITS_TO_4BYTE(__c2h + 0X08, 16, 8) +#define C2H_SPECIAL_STATISTICS_SET_DATA7(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X08, 16, 8, __value) +#define C2H_SPECIAL_STATISTICS_GET_LEN(__c2h) \ + LE_BITS_TO_4BYTE(__c2h + 0X0C, 16, 8) +#define C2H_SPECIAL_STATISTICS_SET_LEN(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X0C, 16, 8, __value) +#define C2H_SPECIAL_STATISTICS_GET_TRIGGER(__c2h) \ + LE_BITS_TO_4BYTE(__c2h + 0X0C, 24, 8) +#define C2H_SPECIAL_STATISTICS_SET_TRIGGER(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X0C, 24, 8, __value) +#define C2H_RA_PARA_RPT_GET_CMD_ID(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X00, 0, 8) +#define C2H_RA_PARA_RPT_SET_CMD_ID(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X00, 0, 8, __value) +#define C2H_RA_PARA_RPT_GET_SEQ(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X00, 8, 8) +#define C2H_RA_PARA_RPT_SET_SEQ(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X00, 8, 8, __value) +#define C2H_RA_PARA_RPT_GET_LEN(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X0C, 16, 8) +#define C2H_RA_PARA_RPT_SET_LEN(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X0C, 16, 8, __value) +#define C2H_RA_PARA_RPT_GET_TRIGGER(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X0C, 24, 8) +#define C2H_RA_PARA_RPT_SET_TRIGGER(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X0C, 24, 8, __value) +#define C2H_CUR_CHANNEL_GET_CMD_ID(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X00, 0, 8) +#define C2H_CUR_CHANNEL_SET_CMD_ID(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X00, 0, 8, __value) +#define C2H_CUR_CHANNEL_GET_SEQ(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X00, 8, 8) +#define C2H_CUR_CHANNEL_SET_SEQ(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X00, 8, 8, __value) +#define C2H_CUR_CHANNEL_GET_CHANNEL_NUM(__c2h) \ + LE_BITS_TO_4BYTE(__c2h + 0X00, 16, 8) +#define C2H_CUR_CHANNEL_SET_CHANNEL_NUM(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X00, 16, 8, __value) +#define C2H_CUR_CHANNEL_GET_LEN(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X0C, 16, 8) +#define C2H_CUR_CHANNEL_SET_LEN(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X0C, 16, 8, __value) +#define C2H_CUR_CHANNEL_GET_TRIGGER(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X0C, 24, 8) +#define C2H_CUR_CHANNEL_SET_TRIGGER(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X0C, 24, 8, __value) +#define C2H_GPIO_WAKEUP_GET_CMD_ID(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X00, 0, 8) +#define C2H_GPIO_WAKEUP_SET_CMD_ID(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X00, 0, 8, __value) +#define C2H_GPIO_WAKEUP_GET_SEQ(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X00, 8, 8) +#define C2H_GPIO_WAKEUP_SET_SEQ(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X00, 8, 8, __value) +#define C2H_GPIO_WAKEUP_GET_LEN(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X0C, 16, 8) +#define C2H_GPIO_WAKEUP_SET_LEN(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X0C, 16, 8, __value) +#define C2H_GPIO_WAKEUP_GET_TRIGGER(__c2h) LE_BITS_TO_4BYTE(__c2h + 0X0C, 24, 8) +#define C2H_GPIO_WAKEUP_SET_TRIGGER(__c2h, __value) \ + SET_BITS_TO_LE_4BYTE(__c2h + 0X0C, 24, 8, __value) +#endif diff --git a/drivers/staging/rtlwifi/halmac/halmac_original_h2c_nic.h b/drivers/staging/rtlwifi/halmac/halmac_original_h2c_nic.h new file mode 100644 index 000000000000..db7aac4de843 --- /dev/null +++ b/drivers/staging/rtlwifi/halmac/halmac_original_h2c_nic.h @@ -0,0 +1,1011 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef _HAL_ORIGINALH2CFORMAT_H2C_C2H_NIC_H_ +#define _HAL_ORIGINALH2CFORMAT_H2C_C2H_NIC_H_ +#define CMD_ID_ORIGINAL_H2C 0X00 +#define CMD_ID_H2C2H_LB 0X0 +#define CMD_ID_D0_SCAN_OFFLOAD_CTRL 0X06 +#define CMD_ID_RSVD_PAGE 0X0 +#define CMD_ID_MEDIA_STATUS_RPT 0X01 +#define CMD_ID_KEEP_ALIVE 0X03 +#define CMD_ID_DISCONNECT_DECISION 0X04 +#define CMD_ID_AP_OFFLOAD 0X08 +#define CMD_ID_BCN_RSVDPAGE 0X09 +#define CMD_ID_PROBE_RSP_RSVDPAGE 0X0A +#define CMD_ID_SET_PWR_MODE 0X00 +#define CMD_ID_PS_TUNING_PARA 0X01 +#define CMD_ID_PS_TUNING_PARA_II 0X02 +#define CMD_ID_PS_LPS_PARA 0X03 +#define CMD_ID_P2P_PS_OFFLOAD 0X04 +#define CMD_ID_PS_SCAN_EN 0X05 +#define CMD_ID_SAP_PS 0X06 +#define CMD_ID_INACTIVE_PS 0X07 +#define CMD_ID_MACID_CFG 0X00 +#define CMD_ID_TXBF 0X01 +#define CMD_ID_RSSI_SETTING 0X02 +#define CMD_ID_AP_REQ_TXRPT 0X03 +#define CMD_ID_INIT_RATE_COLLECTION 0X04 +#define CMD_ID_IQK_OFFLOAD 0X05 +#define CMD_ID_MACID_CFG_3SS 0X06 +#define CMD_ID_RA_PARA_ADJUST 0X07 +#define CMD_ID_WWLAN 0X00 +#define CMD_ID_REMOTE_WAKE_CTRL 0X01 +#define CMD_ID_AOAC_GLOBAL_INFO 0X02 +#define CMD_ID_AOAC_RSVD_PAGE 0X03 +#define CMD_ID_AOAC_RSVD_PAGE2 0X04 +#define CMD_ID_D0_SCAN_OFFLOAD_INFO 0X05 +#define CMD_ID_CHANNEL_SWITCH_OFFLOAD 0X07 +#define CMD_ID_AOAC_RSVD_PAGE3 0X08 +#define CLASS_ORIGINAL_H2C 0X00 +#define CLASS_H2C2H_LB 0X07 +#define CLASS_D0_SCAN_OFFLOAD_CTRL 0X04 +#define CLASS_RSVD_PAGE 0X0 +#define CLASS_MEDIA_STATUS_RPT 0X0 +#define CLASS_KEEP_ALIVE 0X0 +#define CLASS_DISCONNECT_DECISION 0X0 +#define CLASS_AP_OFFLOAD 0X0 +#define CLASS_BCN_RSVDPAGE 0X0 +#define CLASS_PROBE_RSP_RSVDPAGE 0X0 +#define CLASS_SET_PWR_MODE 0X01 +#define CLASS_PS_TUNING_PARA 0X01 +#define CLASS_PS_TUNING_PARA_II 0X01 +#define CLASS_PS_LPS_PARA 0X01 +#define CLASS_P2P_PS_OFFLOAD 0X01 +#define CLASS_PS_SCAN_EN 0X1 +#define CLASS_SAP_PS 0X1 +#define CLASS_INACTIVE_PS 0X1 +#define CLASS_MACID_CFG 0X2 +#define CLASS_TXBF 0X2 +#define CLASS_RSSI_SETTING 0X2 +#define CLASS_AP_REQ_TXRPT 0X2 +#define CLASS_INIT_RATE_COLLECTION 0X2 +#define CLASS_IQK_OFFLOAD 0X2 +#define CLASS_MACID_CFG_3SS 0X2 +#define CLASS_RA_PARA_ADJUST 0X02 +#define CLASS_WWLAN 0X4 +#define CLASS_REMOTE_WAKE_CTRL 0X4 +#define CLASS_AOAC_GLOBAL_INFO 0X04 +#define CLASS_AOAC_RSVD_PAGE 0X04 +#define CLASS_AOAC_RSVD_PAGE2 0X04 +#define CLASS_D0_SCAN_OFFLOAD_INFO 0X04 +#define CLASS_CHANNEL_SWITCH_OFFLOAD 0X04 +#define CLASS_AOAC_RSVD_PAGE3 0X04 +#define ORIGINAL_H2C_GET_CMD_ID(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 0, 5) +#define ORIGINAL_H2C_SET_CMD_ID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 0, 5, __value) +#define ORIGINAL_H2C_GET_CLASS(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 5, 3) +#define ORIGINAL_H2C_SET_CLASS(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 5, 3, __value) +#define H2C2H_LB_GET_CMD_ID(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 0, 5) +#define H2C2H_LB_SET_CMD_ID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 0, 5, __value) +#define H2C2H_LB_GET_CLASS(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 5, 3) +#define H2C2H_LB_SET_CLASS(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 5, 3, __value) +#define H2C2H_LB_GET_SEQ(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 8, 8) +#define H2C2H_LB_SET_SEQ(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 8, 8, __value) +#define H2C2H_LB_GET_PAYLOAD1(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 16, 16) +#define H2C2H_LB_SET_PAYLOAD1(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 16, 16, __value) +#define H2C2H_LB_GET_PAYLOAD2(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X04, 0, 32) +#define H2C2H_LB_SET_PAYLOAD2(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 0, 32, __value) +#define D0_SCAN_OFFLOAD_CTRL_GET_CMD_ID(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 0, 5) +#define D0_SCAN_OFFLOAD_CTRL_SET_CMD_ID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 0, 5, __value) +#define D0_SCAN_OFFLOAD_CTRL_GET_CLASS(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 5, 3) +#define D0_SCAN_OFFLOAD_CTRL_SET_CLASS(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 5, 3, __value) +#define D0_SCAN_OFFLOAD_CTRL_GET_D0_SCAN_FUN_EN(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 8, 1) +#define D0_SCAN_OFFLOAD_CTRL_SET_D0_SCAN_FUN_EN(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 8, 1, __value) +#define D0_SCAN_OFFLOAD_CTRL_GET_RTD3FUN_EN(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 9, 1) +#define D0_SCAN_OFFLOAD_CTRL_SET_RTD3FUN_EN(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 9, 1, __value) +#define D0_SCAN_OFFLOAD_CTRL_GET_U3_SCAN_FUN_EN(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 10, 1) +#define D0_SCAN_OFFLOAD_CTRL_SET_U3_SCAN_FUN_EN(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 10, 1, __value) +#define D0_SCAN_OFFLOAD_CTRL_GET_NLO_FUN_EN(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 11, 1) +#define D0_SCAN_OFFLOAD_CTRL_SET_NLO_FUN_EN(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 11, 1, __value) +#define D0_SCAN_OFFLOAD_CTRL_GET_IPS_DEPENDENT(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 12, 1) +#define D0_SCAN_OFFLOAD_CTRL_SET_IPS_DEPENDENT(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 12, 1, __value) +#define D0_SCAN_OFFLOAD_CTRL_GET_LOC_PROBE_PACKET(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 16, 17) +#define D0_SCAN_OFFLOAD_CTRL_SET_LOC_PROBE_PACKET(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 16, 17, __value) +#define D0_SCAN_OFFLOAD_CTRL_GET_LOC_SCAN_INFO(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 24, 8) +#define D0_SCAN_OFFLOAD_CTRL_SET_LOC_SCAN_INFO(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 24, 8, __value) +#define D0_SCAN_OFFLOAD_CTRL_GET_LOC_SSID_INFO(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X04, 0, 8) +#define D0_SCAN_OFFLOAD_CTRL_SET_LOC_SSID_INFO(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 0, 8, __value) +#define RSVD_PAGE_GET_CMD_ID(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 0, 5) +#define RSVD_PAGE_SET_CMD_ID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 0, 5, __value) +#define RSVD_PAGE_GET_CLASS(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 5, 3) +#define RSVD_PAGE_SET_CLASS(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 5, 3, __value) +#define RSVD_PAGE_GET_LOC_PROBE_RSP(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 8, 8) +#define RSVD_PAGE_SET_LOC_PROBE_RSP(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 8, 8, __value) +#define RSVD_PAGE_GET_LOC_PS_POLL(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 16, 8) +#define RSVD_PAGE_SET_LOC_PS_POLL(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 16, 8, __value) +#define RSVD_PAGE_GET_LOC_NULL_DATA(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 24, 8) +#define RSVD_PAGE_SET_LOC_NULL_DATA(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 24, 8, __value) +#define RSVD_PAGE_GET_LOC_QOS_NULL(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X04, 0, 8) +#define RSVD_PAGE_SET_LOC_QOS_NULL(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 0, 8, __value) +#define RSVD_PAGE_GET_LOC_BT_QOS_NULL(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X04, 8, 8) +#define RSVD_PAGE_SET_LOC_BT_QOS_NULL(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 8, 8, __value) +#define RSVD_PAGE_GET_LOC_CTS2SELF(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X04, 16, 8) +#define RSVD_PAGE_SET_LOC_CTS2SELF(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 16, 8, __value) +#define RSVD_PAGE_GET_LOC_LTECOEX_QOSNULL(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X04, 24, 8) +#define RSVD_PAGE_SET_LOC_LTECOEX_QOSNULL(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 24, 8, __value) +#define MEDIA_STATUS_RPT_GET_CMD_ID(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 0, 5) +#define MEDIA_STATUS_RPT_SET_CMD_ID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 0, 5, __value) +#define MEDIA_STATUS_RPT_GET_CLASS(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 5, 3) +#define MEDIA_STATUS_RPT_SET_CLASS(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 5, 3, __value) +#define MEDIA_STATUS_RPT_GET_OP_MODE(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 8, 1) +#define MEDIA_STATUS_RPT_SET_OP_MODE(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 8, 1, __value) +#define MEDIA_STATUS_RPT_GET_MACID_IN(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 9, 1) +#define MEDIA_STATUS_RPT_SET_MACID_IN(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 9, 1, __value) +#define MEDIA_STATUS_RPT_GET_MACID(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 16, 8) +#define MEDIA_STATUS_RPT_SET_MACID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 16, 8, __value) +#define MEDIA_STATUS_RPT_GET_MACID_END(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 24, 8) +#define MEDIA_STATUS_RPT_SET_MACID_END(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 24, 8, __value) +#define KEEP_ALIVE_GET_CMD_ID(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 0, 5) +#define KEEP_ALIVE_SET_CMD_ID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 0, 5, __value) +#define KEEP_ALIVE_GET_CLASS(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 5, 3) +#define KEEP_ALIVE_SET_CLASS(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 5, 3, __value) +#define KEEP_ALIVE_GET_ENABLE(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 8, 1) +#define KEEP_ALIVE_SET_ENABLE(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 8, 1, __value) +#define KEEP_ALIVE_GET_ADOPT_USER_SETTING(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 9, 1) +#define KEEP_ALIVE_SET_ADOPT_USER_SETTING(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 9, 1, __value) +#define KEEP_ALIVE_GET_PKT_TYPE(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 10, 1) +#define KEEP_ALIVE_SET_PKT_TYPE(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 10, 1, __value) +#define KEEP_ALIVE_GET_KEEP_ALIVE_CHECK_PERIOD(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 16, 8) +#define KEEP_ALIVE_SET_KEEP_ALIVE_CHECK_PERIOD(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 16, 8, __value) +#define DISCONNECT_DECISION_GET_CMD_ID(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 0, 5) +#define DISCONNECT_DECISION_SET_CMD_ID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 0, 5, __value) +#define DISCONNECT_DECISION_GET_CLASS(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 5, 3) +#define DISCONNECT_DECISION_SET_CLASS(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 5, 3, __value) +#define DISCONNECT_DECISION_GET_ENABLE(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 8, 1) +#define DISCONNECT_DECISION_SET_ENABLE(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 8, 1, __value) +#define DISCONNECT_DECISION_GET_ADOPT_USER_SETTING(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 9, 1) +#define DISCONNECT_DECISION_SET_ADOPT_USER_SETTING(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 9, 1, __value) +#define DISCONNECT_DECISION_GET_TRY_OK_BCN_FAIL_COUNT_EN(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 10, 1) +#define DISCONNECT_DECISION_SET_TRY_OK_BCN_FAIL_COUNT_EN(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 10, 1, __value) +#define DISCONNECT_DECISION_GET_DISCONNECT_EN(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 11, 1) +#define DISCONNECT_DECISION_SET_DISCONNECT_EN(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 11, 1, __value) +#define DISCONNECT_DECISION_GET_DISCON_DECISION_CHECK_PERIOD(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 16, 8) +#define DISCONNECT_DECISION_SET_DISCON_DECISION_CHECK_PERIOD(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 16, 8, __value) +#define DISCONNECT_DECISION_GET_TRY_PKT_NUM(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 24, 8) +#define DISCONNECT_DECISION_SET_TRY_PKT_NUM(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 24, 8, __value) +#define DISCONNECT_DECISION_GET_TRY_OK_BCN_FAIL_COUNT_LIMIT(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X04, 0, 8) +#define DISCONNECT_DECISION_SET_TRY_OK_BCN_FAIL_COUNT_LIMIT(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 0, 8, __value) +#define AP_OFFLOAD_GET_CMD_ID(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 0, 5) +#define AP_OFFLOAD_SET_CMD_ID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 0, 5, __value) +#define AP_OFFLOAD_GET_CLASS(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 5, 3) +#define AP_OFFLOAD_SET_CLASS(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 5, 3, __value) +#define AP_OFFLOAD_GET_ON(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 8, 1) +#define AP_OFFLOAD_SET_ON(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 8, 1, __value) +#define AP_OFFLOAD_GET_CFG_MIFI_PLATFORM(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 9, 1) +#define AP_OFFLOAD_SET_CFG_MIFI_PLATFORM(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 9, 1, __value) +#define AP_OFFLOAD_GET_LINKED(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 10, 1) +#define AP_OFFLOAD_SET_LINKED(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 10, 1, __value) +#define AP_OFFLOAD_GET_EN_AUTO_WAKE(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 11, 1) +#define AP_OFFLOAD_SET_EN_AUTO_WAKE(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 11, 1, __value) +#define AP_OFFLOAD_GET_WAKE_FLAG(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 12, 1) +#define AP_OFFLOAD_SET_WAKE_FLAG(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 12, 1, __value) +#define AP_OFFLOAD_GET_HIDDEN_ROOT(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 16, 1) +#define AP_OFFLOAD_SET_HIDDEN_ROOT(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 16, 1, __value) +#define AP_OFFLOAD_GET_HIDDEN_VAP1(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 17, 1) +#define AP_OFFLOAD_SET_HIDDEN_VAP1(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 17, 1, __value) +#define AP_OFFLOAD_GET_HIDDEN_VAP2(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 18, 1) +#define AP_OFFLOAD_SET_HIDDEN_VAP2(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 18, 1, __value) +#define AP_OFFLOAD_GET_HIDDEN_VAP3(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 19, 1) +#define AP_OFFLOAD_SET_HIDDEN_VAP3(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 19, 1, __value) +#define AP_OFFLOAD_GET_HIDDEN_VAP4(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 20, 1) +#define AP_OFFLOAD_SET_HIDDEN_VAP4(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 20, 1, __value) +#define AP_OFFLOAD_GET_DENYANY_ROOT(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 24, 1) +#define AP_OFFLOAD_SET_DENYANY_ROOT(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 24, 1, __value) +#define AP_OFFLOAD_GET_DENYANY_VAP1(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 25, 1) +#define AP_OFFLOAD_SET_DENYANY_VAP1(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 25, 1, __value) +#define AP_OFFLOAD_GET_DENYANY_VAP2(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 26, 1) +#define AP_OFFLOAD_SET_DENYANY_VAP2(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 26, 1, __value) +#define AP_OFFLOAD_GET_DENYANY_VAP3(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 27, 1) +#define AP_OFFLOAD_SET_DENYANY_VAP3(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 27, 1, __value) +#define AP_OFFLOAD_GET_DENYANY_VAP4(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 28, 1) +#define AP_OFFLOAD_SET_DENYANY_VAP4(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 28, 1, __value) +#define AP_OFFLOAD_GET_WAIT_TBTT_CNT(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X04, 0, 8) +#define AP_OFFLOAD_SET_WAIT_TBTT_CNT(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 0, 8, __value) +#define AP_OFFLOAD_GET_WAKE_TIMEOUT(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X04, 8, 8) +#define AP_OFFLOAD_SET_WAKE_TIMEOUT(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 8, 8, __value) +#define AP_OFFLOAD_GET_LEN_IV_PAIR(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X04, 16, 8) +#define AP_OFFLOAD_SET_LEN_IV_PAIR(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 16, 8, __value) +#define AP_OFFLOAD_GET_LEN_IV_GRP(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X04, 24, 8) +#define AP_OFFLOAD_SET_LEN_IV_GRP(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 24, 8, __value) +#define BCN_RSVDPAGE_GET_CMD_ID(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 0, 5) +#define BCN_RSVDPAGE_SET_CMD_ID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 0, 5, __value) +#define BCN_RSVDPAGE_GET_CLASS(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 5, 3) +#define BCN_RSVDPAGE_SET_CLASS(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 5, 3, __value) +#define BCN_RSVDPAGE_GET_LOC_ROOT(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 8, 8) +#define BCN_RSVDPAGE_SET_LOC_ROOT(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 8, 8, __value) +#define BCN_RSVDPAGE_GET_LOC_VAP1(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 16, 8) +#define BCN_RSVDPAGE_SET_LOC_VAP1(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 16, 8, __value) +#define BCN_RSVDPAGE_GET_LOC_VAP2(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 24, 8) +#define BCN_RSVDPAGE_SET_LOC_VAP2(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 24, 8, __value) +#define BCN_RSVDPAGE_GET_LOC_VAP3(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X04, 0, 8) +#define BCN_RSVDPAGE_SET_LOC_VAP3(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 0, 8, __value) +#define BCN_RSVDPAGE_GET_LOC_VAP4(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X04, 8, 8) +#define BCN_RSVDPAGE_SET_LOC_VAP4(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 8, 8, __value) +#define PROBE_RSP_RSVDPAGE_GET_CMD_ID(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 0, 5) +#define PROBE_RSP_RSVDPAGE_SET_CMD_ID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 0, 5, __value) +#define PROBE_RSP_RSVDPAGE_GET_CLASS(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 5, 3) +#define PROBE_RSP_RSVDPAGE_SET_CLASS(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 5, 3, __value) +#define PROBE_RSP_RSVDPAGE_GET_LOC_ROOT(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 8, 8) +#define PROBE_RSP_RSVDPAGE_SET_LOC_ROOT(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 8, 8, __value) +#define PROBE_RSP_RSVDPAGE_GET_LOC_VAP1(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 16, 8) +#define PROBE_RSP_RSVDPAGE_SET_LOC_VAP1(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 16, 8, __value) +#define PROBE_RSP_RSVDPAGE_GET_LOC_VAP2(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 24, 8) +#define PROBE_RSP_RSVDPAGE_SET_LOC_VAP2(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 24, 8, __value) +#define PROBE_RSP_RSVDPAGE_GET_LOC_VAP3(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X04, 0, 8) +#define PROBE_RSP_RSVDPAGE_SET_LOC_VAP3(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 0, 8, __value) +#define PROBE_RSP_RSVDPAGE_GET_LOC_VAP4(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X04, 8, 8) +#define PROBE_RSP_RSVDPAGE_SET_LOC_VAP4(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 8, 8, __value) +#define SET_PWR_MODE_GET_CMD_ID(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 0, 5) +#define SET_PWR_MODE_SET_CMD_ID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 0, 5, __value) +#define SET_PWR_MODE_GET_CLASS(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 5, 3) +#define SET_PWR_MODE_SET_CLASS(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 5, 3, __value) +#define SET_PWR_MODE_GET_MODE(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 8, 7) +#define SET_PWR_MODE_SET_MODE(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 8, 7, __value) +#define SET_PWR_MODE_GET_CLK_REQUEST(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 15, 1) +#define SET_PWR_MODE_SET_CLK_REQUEST(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 15, 1, __value) +#define SET_PWR_MODE_GET_RLBM(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 16, 4) +#define SET_PWR_MODE_SET_RLBM(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 16, 4, __value) +#define SET_PWR_MODE_GET_SMART_PS(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 20, 4) +#define SET_PWR_MODE_SET_SMART_PS(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 20, 4, __value) +#define SET_PWR_MODE_GET_AWAKE_INTERVAL(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 24, 8) +#define SET_PWR_MODE_SET_AWAKE_INTERVAL(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 24, 8, __value) +#define SET_PWR_MODE_GET_B_ALL_QUEUE_UAPSD(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X04, 0, 1) +#define SET_PWR_MODE_SET_B_ALL_QUEUE_UAPSD(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 0, 1, __value) +#define SET_PWR_MODE_GET_BCN_EARLY_RPT(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X04, 2, 1) +#define SET_PWR_MODE_SET_BCN_EARLY_RPT(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 2, 1, __value) +#define SET_PWR_MODE_GET_PORT_ID(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X04, 5, 3) +#define SET_PWR_MODE_SET_PORT_ID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 5, 3, __value) +#define SET_PWR_MODE_GET_PWR_STATE(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X04, 8, 8) +#define SET_PWR_MODE_SET_PWR_STATE(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 8, 8, __value) +#define SET_PWR_MODE_GET_LOW_POWER_RX_BCN(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X04, 16, 1) +#define SET_PWR_MODE_SET_LOW_POWER_RX_BCN(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 16, 1, __value) +#define SET_PWR_MODE_GET_ANT_AUTO_SWITCH(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X04, 17, 1) +#define SET_PWR_MODE_SET_ANT_AUTO_SWITCH(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 17, 1, __value) +#define SET_PWR_MODE_GET_PS_ALLOW_BT_HIGH_PRIORITY(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X04, 18, 1) +#define SET_PWR_MODE_SET_PS_ALLOW_BT_HIGH_PRIORITY(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 18, 1, __value) +#define SET_PWR_MODE_GET_PROTECT_BCN(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X04, 19, 1) +#define SET_PWR_MODE_SET_PROTECT_BCN(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 19, 1, __value) +#define SET_PWR_MODE_GET_SILENCE_PERIOD(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X04, 20, 1) +#define SET_PWR_MODE_SET_SILENCE_PERIOD(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 20, 1, __value) +#define SET_PWR_MODE_GET_FAST_BT_CONNECT(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X04, 21, 1) +#define SET_PWR_MODE_SET_FAST_BT_CONNECT(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 21, 1, __value) +#define SET_PWR_MODE_GET_TWO_ANTENNA_EN(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X04, 22, 1) +#define SET_PWR_MODE_SET_TWO_ANTENNA_EN(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 22, 1, __value) +#define SET_PWR_MODE_GET_ADOPT_USER_SETTING(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X04, 24, 1) +#define SET_PWR_MODE_SET_ADOPT_USER_SETTING(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 24, 1, __value) +#define SET_PWR_MODE_GET_DRV_BCN_EARLY_SHIFT(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X04, 25, 3) +#define SET_PWR_MODE_SET_DRV_BCN_EARLY_SHIFT(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 25, 3, __value) +#define SET_PWR_MODE_GET_DRV_BCN_EARLY_SHIFT2(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X04, 28, 4) +#define SET_PWR_MODE_SET_DRV_BCN_EARLY_SHIFT2(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 28, 4, __value) +#define PS_TUNING_PARA_GET_CMD_ID(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 0, 5) +#define PS_TUNING_PARA_SET_CMD_ID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 0, 5, __value) +#define PS_TUNING_PARA_GET_CLASS(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 5, 3) +#define PS_TUNING_PARA_SET_CLASS(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 5, 3, __value) +#define PS_TUNING_PARA_GET_BCN_TO_LIMIT(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 8, 7) +#define PS_TUNING_PARA_SET_BCN_TO_LIMIT(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 8, 7, __value) +#define PS_TUNING_PARA_GET_DTIM_TIME_OUT(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 15, 1) +#define PS_TUNING_PARA_SET_DTIM_TIME_OUT(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 15, 1, __value) +#define PS_TUNING_PARA_GET_PS_TIME_OUT(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 16, 4) +#define PS_TUNING_PARA_SET_PS_TIME_OUT(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 16, 4, __value) +#define PS_TUNING_PARA_GET_ADOPT(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 24, 8) +#define PS_TUNING_PARA_SET_ADOPT(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 24, 8, __value) +#define PS_TUNING_PARA_II_GET_CMD_ID(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 0, 5) +#define PS_TUNING_PARA_II_SET_CMD_ID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 0, 5, __value) +#define PS_TUNING_PARA_II_GET_CLASS(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 5, 3) +#define PS_TUNING_PARA_II_SET_CLASS(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 5, 3, __value) +#define PS_TUNING_PARA_II_GET_BCN_TO_PERIOD(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 8, 7) +#define PS_TUNING_PARA_II_SET_BCN_TO_PERIOD(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 8, 7, __value) +#define PS_TUNING_PARA_II_GET_ADOPT(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 15, 1) +#define PS_TUNING_PARA_II_SET_ADOPT(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 15, 1, __value) +#define PS_TUNING_PARA_II_GET_DRV_EARLY_IVL(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 16, 8) +#define PS_TUNING_PARA_II_SET_DRV_EARLY_IVL(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 16, 8, __value) +#define PS_LPS_PARA_GET_CMD_ID(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 0, 5) +#define PS_LPS_PARA_SET_CMD_ID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 0, 5, __value) +#define PS_LPS_PARA_GET_CLASS(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 5, 3) +#define PS_LPS_PARA_SET_CLASS(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 5, 3, __value) +#define PS_LPS_PARA_GET_LPS_CONTROL(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 8, 8) +#define PS_LPS_PARA_SET_LPS_CONTROL(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 8, 8, __value) +#define P2P_PS_OFFLOAD_GET_CMD_ID(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 0, 5) +#define P2P_PS_OFFLOAD_SET_CMD_ID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 0, 5, __value) +#define P2P_PS_OFFLOAD_GET_CLASS(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 5, 3) +#define P2P_PS_OFFLOAD_SET_CLASS(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 5, 3, __value) +#define P2P_PS_OFFLOAD_GET_OFFLOAD_EN(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 8, 1) +#define P2P_PS_OFFLOAD_SET_OFFLOAD_EN(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 8, 1, __value) +#define P2P_PS_OFFLOAD_GET_ROLE(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 9, 1) +#define P2P_PS_OFFLOAD_SET_ROLE(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 9, 1, __value) +#define P2P_PS_OFFLOAD_GET_CTWINDOW_EN(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 10, 1) +#define P2P_PS_OFFLOAD_SET_CTWINDOW_EN(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 10, 1, __value) +#define P2P_PS_OFFLOAD_GET_NOA0_EN(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 11, 1) +#define P2P_PS_OFFLOAD_SET_NOA0_EN(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 11, 1, __value) +#define P2P_PS_OFFLOAD_GET_NOA1_EN(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 12, 1) +#define P2P_PS_OFFLOAD_SET_NOA1_EN(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 12, 1, __value) +#define P2P_PS_OFFLOAD_GET_ALL_STA_SLEEP(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 13, 1) +#define P2P_PS_OFFLOAD_SET_ALL_STA_SLEEP(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 13, 1, __value) +#define P2P_PS_OFFLOAD_GET_DISCOVERY(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 14, 1) +#define P2P_PS_OFFLOAD_SET_DISCOVERY(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 14, 1, __value) +#define PS_SCAN_EN_GET_CMD_ID(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 0, 5) +#define PS_SCAN_EN_SET_CMD_ID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 0, 5, __value) +#define PS_SCAN_EN_GET_CLASS(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 5, 3) +#define PS_SCAN_EN_SET_CLASS(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 5, 3, __value) +#define PS_SCAN_EN_GET_ENABLE(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 8, 1) +#define PS_SCAN_EN_SET_ENABLE(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 8, 1, __value) +#define SAP_PS_GET_CMD_ID(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 0, 5) +#define SAP_PS_SET_CMD_ID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 0, 5, __value) +#define SAP_PS_GET_CLASS(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 5, 3) +#define SAP_PS_SET_CLASS(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 5, 3, __value) +#define SAP_PS_GET_ENABLE(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 8, 1) +#define SAP_PS_SET_ENABLE(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 8, 1, __value) +#define SAP_PS_GET_EN_PS(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 9, 1) +#define SAP_PS_SET_EN_PS(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 9, 1, __value) +#define SAP_PS_GET_EN_LP_RX(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 10, 1) +#define SAP_PS_SET_EN_LP_RX(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 10, 1, __value) +#define SAP_PS_GET_MANUAL_32K(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 11, 1) +#define SAP_PS_SET_MANUAL_32K(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 11, 1, __value) +#define SAP_PS_GET_DURATION(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 16, 8) +#define SAP_PS_SET_DURATION(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 16, 8, __value) +#define INACTIVE_PS_GET_CMD_ID(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 0, 5) +#define INACTIVE_PS_SET_CMD_ID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 0, 5, __value) +#define INACTIVE_PS_GET_CLASS(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 5, 3) +#define INACTIVE_PS_SET_CLASS(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 5, 3, __value) +#define INACTIVE_PS_GET_ENABLE(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 8, 1) +#define INACTIVE_PS_SET_ENABLE(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 8, 1, __value) +#define INACTIVE_PS_GET_IGNORE_PS_CONDITION(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 9, 1) +#define INACTIVE_PS_SET_IGNORE_PS_CONDITION(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 9, 1, __value) +#define INACTIVE_PS_GET_FREQUENCY(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 16, 8) +#define INACTIVE_PS_SET_FREQUENCY(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 16, 8, __value) +#define INACTIVE_PS_GET_DURATION(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 24, 8) +#define INACTIVE_PS_SET_DURATION(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 24, 8, __value) +#define MACID_CFG_GET_CMD_ID(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 0, 5) +#define MACID_CFG_SET_CMD_ID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 0, 5, __value) +#define MACID_CFG_GET_CLASS(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 5, 3) +#define MACID_CFG_SET_CLASS(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 5, 3, __value) +#define MACID_CFG_GET_MAC_ID(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 8, 8) +#define MACID_CFG_SET_MAC_ID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 8, 8, __value) +#define MACID_CFG_GET_RATE_ID(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 16, 5) +#define MACID_CFG_SET_RATE_ID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 16, 5, __value) +#define MACID_CFG_GET_SGI(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 23, 1) +#define MACID_CFG_SET_SGI(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 23, 1, __value) +#define MACID_CFG_GET_BW(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 24, 2) +#define MACID_CFG_SET_BW(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 24, 2, __value) +#define MACID_CFG_GET_LDPC_CAP(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 26, 1) +#define MACID_CFG_SET_LDPC_CAP(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 26, 1, __value) +#define MACID_CFG_GET_NO_UPDATE(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 27, 1) +#define MACID_CFG_SET_NO_UPDATE(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 27, 1, __value) +#define MACID_CFG_GET_WHT_EN(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 28, 2) +#define MACID_CFG_SET_WHT_EN(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 28, 2, __value) +#define MACID_CFG_GET_DISPT(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 30, 1) +#define MACID_CFG_SET_DISPT(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 30, 1, __value) +#define MACID_CFG_GET_DISRA(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 31, 1) +#define MACID_CFG_SET_DISRA(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 31, 1, __value) +#define MACID_CFG_GET_RATE_MASK7_0(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X04, 0, 8) +#define MACID_CFG_SET_RATE_MASK7_0(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 0, 8, __value) +#define MACID_CFG_GET_RATE_MASK15_8(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X04, 8, 8) +#define MACID_CFG_SET_RATE_MASK15_8(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 8, 8, __value) +#define MACID_CFG_GET_RATE_MASK23_16(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X04, 16, 8) +#define MACID_CFG_SET_RATE_MASK23_16(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 16, 8, __value) +#define MACID_CFG_GET_RATE_MASK31_24(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X04, 24, 8) +#define MACID_CFG_SET_RATE_MASK31_24(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 24, 8, __value) +#define TXBF_GET_CMD_ID(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 0, 5) +#define TXBF_SET_CMD_ID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 0, 5, __value) +#define TXBF_GET_CLASS(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 5, 3) +#define TXBF_SET_CLASS(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 5, 3, __value) +#define TXBF_GET_NDPA0_HEAD_PAGE(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 8, 8) +#define TXBF_SET_NDPA0_HEAD_PAGE(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 8, 8, __value) +#define TXBF_GET_NDPA1_HEAD_PAGE(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 16, 8) +#define TXBF_SET_NDPA1_HEAD_PAGE(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 16, 8, __value) +#define TXBF_GET_PERIOD_0(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 24, 8) +#define TXBF_SET_PERIOD_0(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 24, 8, __value) +#define RSSI_SETTING_GET_CMD_ID(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 0, 5) +#define RSSI_SETTING_SET_CMD_ID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 0, 5, __value) +#define RSSI_SETTING_GET_CLASS(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 5, 3) +#define RSSI_SETTING_SET_CLASS(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 5, 3, __value) +#define RSSI_SETTING_GET_MAC_ID(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 8, 8) +#define RSSI_SETTING_SET_MAC_ID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 8, 8, __value) +#define RSSI_SETTING_GET_RSSI(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 24, 7) +#define RSSI_SETTING_SET_RSSI(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 24, 7, __value) +#define RSSI_SETTING_GET_RA_INFO(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X04, 0, 8) +#define RSSI_SETTING_SET_RA_INFO(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 0, 8, __value) +#define AP_REQ_TXRPT_GET_CMD_ID(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 0, 5) +#define AP_REQ_TXRPT_SET_CMD_ID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 0, 5, __value) +#define AP_REQ_TXRPT_GET_CLASS(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 5, 3) +#define AP_REQ_TXRPT_SET_CLASS(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 5, 3, __value) +#define AP_REQ_TXRPT_GET_STA1_MACID(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 8, 8) +#define AP_REQ_TXRPT_SET_STA1_MACID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 8, 8, __value) +#define AP_REQ_TXRPT_GET_STA2_MACID(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 16, 8) +#define AP_REQ_TXRPT_SET_STA2_MACID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 16, 8, __value) +#define AP_REQ_TXRPT_GET_RTY_OK_TOTAL(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 24, 1) +#define AP_REQ_TXRPT_SET_RTY_OK_TOTAL(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 24, 1, __value) +#define AP_REQ_TXRPT_GET_RTY_CNT_MACID(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 25, 1) +#define AP_REQ_TXRPT_SET_RTY_CNT_MACID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 25, 1, __value) +#define INIT_RATE_COLLECTION_GET_CMD_ID(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 0, 5) +#define INIT_RATE_COLLECTION_SET_CMD_ID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 0, 5, __value) +#define INIT_RATE_COLLECTION_GET_CLASS(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 5, 3) +#define INIT_RATE_COLLECTION_SET_CLASS(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 5, 3, __value) +#define INIT_RATE_COLLECTION_GET_STA1_MACID(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 8, 8) +#define INIT_RATE_COLLECTION_SET_STA1_MACID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 8, 8, __value) +#define INIT_RATE_COLLECTION_GET_STA2_MACID(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 16, 8) +#define INIT_RATE_COLLECTION_SET_STA2_MACID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 16, 8, __value) +#define INIT_RATE_COLLECTION_GET_STA3_MACID(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 24, 8) +#define INIT_RATE_COLLECTION_SET_STA3_MACID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 24, 8, __value) +#define INIT_RATE_COLLECTION_GET_STA4_MACID(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X04, 0, 8) +#define INIT_RATE_COLLECTION_SET_STA4_MACID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 0, 8, __value) +#define INIT_RATE_COLLECTION_GET_STA5_MACID(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X04, 8, 8) +#define INIT_RATE_COLLECTION_SET_STA5_MACID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 8, 8, __value) +#define INIT_RATE_COLLECTION_GET_STA6_MACID(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X04, 16, 8) +#define INIT_RATE_COLLECTION_SET_STA6_MACID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 16, 8, __value) +#define INIT_RATE_COLLECTION_GET_STA7_MACID(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X04, 24, 8) +#define INIT_RATE_COLLECTION_SET_STA7_MACID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 24, 8, __value) +#define IQK_OFFLOAD_GET_CMD_ID(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 0, 5) +#define IQK_OFFLOAD_SET_CMD_ID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 0, 5, __value) +#define IQK_OFFLOAD_GET_CLASS(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 5, 3) +#define IQK_OFFLOAD_SET_CLASS(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 5, 3, __value) +#define IQK_OFFLOAD_GET_CHANNEL(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 8, 8) +#define IQK_OFFLOAD_SET_CHANNEL(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 8, 8, __value) +#define IQK_OFFLOAD_GET_BWBAND(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 16, 8) +#define IQK_OFFLOAD_SET_BWBAND(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 16, 8, __value) +#define IQK_OFFLOAD_GET_EXTPALNA(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 24, 8) +#define IQK_OFFLOAD_SET_EXTPALNA(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 24, 8, __value) +#define MACID_CFG_3SS_GET_CMD_ID(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 0, 5) +#define MACID_CFG_3SS_SET_CMD_ID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 0, 5, __value) +#define MACID_CFG_3SS_GET_CLASS(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 5, 3) +#define MACID_CFG_3SS_SET_CLASS(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 5, 3, __value) +#define MACID_CFG_3SS_GET_MACID(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 8, 8) +#define MACID_CFG_3SS_SET_MACID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 8, 8, __value) +#define MACID_CFG_3SS_GET_RATE_MASK_39_32(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X04, 0, 8) +#define MACID_CFG_3SS_SET_RATE_MASK_39_32(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 0, 8, __value) +#define MACID_CFG_3SS_GET_RATE_MASK_47_40(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X04, 8, 8) +#define MACID_CFG_3SS_SET_RATE_MASK_47_40(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 8, 8, __value) +#define RA_PARA_ADJUST_GET_CMD_ID(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 0, 5) +#define RA_PARA_ADJUST_SET_CMD_ID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 0, 5, __value) +#define RA_PARA_ADJUST_GET_CLASS(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 5, 3) +#define RA_PARA_ADJUST_SET_CLASS(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 5, 3, __value) +#define RA_PARA_ADJUST_GET_MAC_ID(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 8, 8) +#define RA_PARA_ADJUST_SET_MAC_ID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 8, 8, __value) +#define RA_PARA_ADJUST_GET_PARAMETER_INDEX(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 16, 8) +#define RA_PARA_ADJUST_SET_PARAMETER_INDEX(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 16, 8, __value) +#define RA_PARA_ADJUST_GET_RATE_ID(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 24, 8) +#define RA_PARA_ADJUST_SET_RATE_ID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 24, 8, __value) +#define RA_PARA_ADJUST_GET_VALUE_BYTE0(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X04, 0, 8) +#define RA_PARA_ADJUST_SET_VALUE_BYTE0(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 0, 8, __value) +#define RA_PARA_ADJUST_GET_VALUE_BYTE1(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X04, 8, 8) +#define RA_PARA_ADJUST_SET_VALUE_BYTE1(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 8, 8, __value) +#define RA_PARA_ADJUST_GET_ASK_FW_FOR_FW_PARA(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X04, 16, 8) +#define RA_PARA_ADJUST_SET_ASK_FW_FOR_FW_PARA(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 16, 8, __value) +#define WWLAN_GET_CMD_ID(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 0, 5) +#define WWLAN_SET_CMD_ID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 0, 5, __value) +#define WWLAN_GET_CLASS(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 5, 3) +#define WWLAN_SET_CLASS(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 5, 3, __value) +#define WWLAN_GET_FUNC_EN(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 8, 1) +#define WWLAN_SET_FUNC_EN(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 8, 1, __value) +#define WWLAN_GET_PATTERM_MAT_EN(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 9, 1) +#define WWLAN_SET_PATTERM_MAT_EN(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 9, 1, __value) +#define WWLAN_GET_MAGIC_PKT_EN(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 10, 1) +#define WWLAN_SET_MAGIC_PKT_EN(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 10, 1, __value) +#define WWLAN_GET_UNICAST_WAKEUP_EN(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 11, 1) +#define WWLAN_SET_UNICAST_WAKEUP_EN(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 11, 1, __value) +#define WWLAN_GET_ALL_PKT_DROP(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 12, 1) +#define WWLAN_SET_ALL_PKT_DROP(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 12, 1, __value) +#define WWLAN_GET_GPIO_ACTIVE(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 13, 1) +#define WWLAN_SET_GPIO_ACTIVE(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 13, 1, __value) +#define WWLAN_GET_REKEY_WAKEUP_EN(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 14, 1) +#define WWLAN_SET_REKEY_WAKEUP_EN(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 14, 1, __value) +#define WWLAN_GET_DEAUTH_WAKEUP_EN(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 15, 1) +#define WWLAN_SET_DEAUTH_WAKEUP_EN(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 15, 1, __value) +#define WWLAN_GET_GPIO_NUM(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 16, 7) +#define WWLAN_SET_GPIO_NUM(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 16, 7, __value) +#define WWLAN_GET_DATAPIN_WAKEUP_EN(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 23, 1) +#define WWLAN_SET_DATAPIN_WAKEUP_EN(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 23, 1, __value) +#define WWLAN_GET_GPIO_DURATION(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 24, 8) +#define WWLAN_SET_GPIO_DURATION(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 24, 8, __value) +#define WWLAN_GET_GPIO_PLUS_EN(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X04, 0, 1) +#define WWLAN_SET_GPIO_PLUS_EN(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 0, 1, __value) +#define WWLAN_GET_GPIO_PULSE_COUNT(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X04, 1, 7) +#define WWLAN_SET_GPIO_PULSE_COUNT(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 1, 7, __value) +#define WWLAN_GET_DISABLE_UPHY(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X04, 8, 1) +#define WWLAN_SET_DISABLE_UPHY(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 8, 1, __value) +#define WWLAN_GET_HST2DEV_EN(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X04, 9, 1) +#define WWLAN_SET_HST2DEV_EN(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 9, 1, __value) +#define WWLAN_GET_GPIO_DURATION_MS(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X04, 10, 1) +#define WWLAN_SET_GPIO_DURATION_MS(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 10, 1, __value) +#define REMOTE_WAKE_CTRL_GET_CMD_ID(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 0, 5) +#define REMOTE_WAKE_CTRL_SET_CMD_ID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 0, 5, __value) +#define REMOTE_WAKE_CTRL_GET_CLASS(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 5, 3) +#define REMOTE_WAKE_CTRL_SET_CLASS(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 5, 3, __value) +#define REMOTE_WAKE_CTRL_GET_REMOTE_WAKE_CTRL_EN(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 8, 1) +#define REMOTE_WAKE_CTRL_SET_REMOTE_WAKE_CTRL_EN(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 8, 1, __value) +#define REMOTE_WAKE_CTRL_GET_ARP_EN(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 9, 1) +#define REMOTE_WAKE_CTRL_SET_ARP_EN(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 9, 1, __value) +#define REMOTE_WAKE_CTRL_GET_NDP_EN(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 10, 1) +#define REMOTE_WAKE_CTRL_SET_NDP_EN(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 10, 1, __value) +#define REMOTE_WAKE_CTRL_GET_GTK_EN(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 11, 1) +#define REMOTE_WAKE_CTRL_SET_GTK_EN(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 11, 1, __value) +#define REMOTE_WAKE_CTRL_GET_NLO_OFFLOAD_EN(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 12, 1) +#define REMOTE_WAKE_CTRL_SET_NLO_OFFLOAD_EN(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 12, 1, __value) +#define REMOTE_WAKE_CTRL_GET_REAL_WOW_V1_EN(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 13, 1) +#define REMOTE_WAKE_CTRL_SET_REAL_WOW_V1_EN(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 13, 1, __value) +#define REMOTE_WAKE_CTRL_GET_REAL_WOW_V2_EN(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 14, 1) +#define REMOTE_WAKE_CTRL_SET_REAL_WOW_V2_EN(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 14, 1, __value) +#define REMOTE_WAKE_CTRL_GET_FW_UNICAST(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 15, 1) +#define REMOTE_WAKE_CTRL_SET_FW_UNICAST(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 15, 1, __value) +#define REMOTE_WAKE_CTRL_GET_P2P_OFFLOAD_EN(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 16, 1) +#define REMOTE_WAKE_CTRL_SET_P2P_OFFLOAD_EN(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 16, 1, __value) +#define REMOTE_WAKE_CTRL_GET_RUNTIME_PM_EN(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 17, 1) +#define REMOTE_WAKE_CTRL_SET_RUNTIME_PM_EN(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 17, 1, __value) +#define REMOTE_WAKE_CTRL_GET_NET_BIOS_DROP_EN(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 18, 1) +#define REMOTE_WAKE_CTRL_SET_NET_BIOS_DROP_EN(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 18, 1, __value) +#define REMOTE_WAKE_CTRL_GET_ARP_ACTION(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 24, 1) +#define REMOTE_WAKE_CTRL_SET_ARP_ACTION(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 24, 1, __value) +#define REMOTE_WAKE_CTRL_GET_FW_PARSING_UNTIL_WAKEUP(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 28, 1) +#define REMOTE_WAKE_CTRL_SET_FW_PARSING_UNTIL_WAKEUP(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 28, 1, __value) +#define REMOTE_WAKE_CTRL_GET_FW_PARSING_AFTER_WAKEUP(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 29, 1) +#define REMOTE_WAKE_CTRL_SET_FW_PARSING_AFTER_WAKEUP(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 29, 1, __value) +#define AOAC_GLOBAL_INFO_GET_CMD_ID(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 0, 5) +#define AOAC_GLOBAL_INFO_SET_CMD_ID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 0, 5, __value) +#define AOAC_GLOBAL_INFO_GET_CLASS(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 5, 3) +#define AOAC_GLOBAL_INFO_SET_CLASS(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 5, 3, __value) +#define AOAC_GLOBAL_INFO_GET_PAIR_WISE_ENC_ALG(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 8, 8) +#define AOAC_GLOBAL_INFO_SET_PAIR_WISE_ENC_ALG(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 8, 8, __value) +#define AOAC_GLOBAL_INFO_GET_GROUP_ENC_ALG(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 16, 8) +#define AOAC_GLOBAL_INFO_SET_GROUP_ENC_ALG(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 16, 8, __value) +#define AOAC_RSVD_PAGE_GET_CMD_ID(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 0, 5) +#define AOAC_RSVD_PAGE_SET_CMD_ID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 0, 5, __value) +#define AOAC_RSVD_PAGE_GET_CLASS(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 5, 3) +#define AOAC_RSVD_PAGE_SET_CLASS(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 5, 3, __value) +#define AOAC_RSVD_PAGE_GET_LOC_REMOTE_CTRL_INFO(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 8, 8) +#define AOAC_RSVD_PAGE_SET_LOC_REMOTE_CTRL_INFO(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 8, 8, __value) +#define AOAC_RSVD_PAGE_GET_LOC_ARP_RESPONSE(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 16, 8) +#define AOAC_RSVD_PAGE_SET_LOC_ARP_RESPONSE(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 16, 8, __value) +#define AOAC_RSVD_PAGE_GET_LOC_NEIGHBOR_ADVERTISEMENT(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 24, 8) +#define AOAC_RSVD_PAGE_SET_LOC_NEIGHBOR_ADVERTISEMENT(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 24, 8, __value) +#define AOAC_RSVD_PAGE_GET_LOC_GTK_RSP(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X04, 0, 8) +#define AOAC_RSVD_PAGE_SET_LOC_GTK_RSP(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 0, 8, __value) +#define AOAC_RSVD_PAGE_GET_LOC_GTK_INFO(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X04, 8, 8) +#define AOAC_RSVD_PAGE_SET_LOC_GTK_INFO(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 8, 8, __value) +#define AOAC_RSVD_PAGE_GET_LOC_GTK_EXT_MEM(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X04, 16, 8) +#define AOAC_RSVD_PAGE_SET_LOC_GTK_EXT_MEM(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 16, 8, __value) +#define AOAC_RSVD_PAGE_GET_LOC_NDP_INFO(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X04, 24, 8) +#define AOAC_RSVD_PAGE_SET_LOC_NDP_INFO(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 24, 8, __value) +#define AOAC_RSVD_PAGE2_GET_CMD_ID(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 0, 5) +#define AOAC_RSVD_PAGE2_SET_CMD_ID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 0, 5, __value) +#define AOAC_RSVD_PAGE2_GET_CLASS(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 5, 3) +#define AOAC_RSVD_PAGE2_SET_CLASS(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 5, 3, __value) +#define AOAC_RSVD_PAGE2_GET_LOC_ROUTER_SOLICATION(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 8, 8) +#define AOAC_RSVD_PAGE2_SET_LOC_ROUTER_SOLICATION(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 8, 8, __value) +#define AOAC_RSVD_PAGE2_GET_LOC_BUBBLE_PACKET(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 16, 8) +#define AOAC_RSVD_PAGE2_SET_LOC_BUBBLE_PACKET(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 16, 8, __value) +#define AOAC_RSVD_PAGE2_GET_LOC_TEREDO_INFO(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 24, 8) +#define AOAC_RSVD_PAGE2_SET_LOC_TEREDO_INFO(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 24, 8, __value) +#define AOAC_RSVD_PAGE2_GET_LOC_REALWOW_INFO(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X04, 0, 8) +#define AOAC_RSVD_PAGE2_SET_LOC_REALWOW_INFO(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 0, 8, __value) +#define AOAC_RSVD_PAGE2_GET_LOC_KEEP_ALIVE_PKT(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X04, 8, 8) +#define AOAC_RSVD_PAGE2_SET_LOC_KEEP_ALIVE_PKT(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 8, 8, __value) +#define AOAC_RSVD_PAGE2_GET_LOC_ACK_PATTERN(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X04, 16, 8) +#define AOAC_RSVD_PAGE2_SET_LOC_ACK_PATTERN(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 16, 8, __value) +#define AOAC_RSVD_PAGE2_GET_LOC_WAKEUP_PATTERN(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X04, 24, 8) +#define AOAC_RSVD_PAGE2_SET_LOC_WAKEUP_PATTERN(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X04, 24, 8, __value) +#define D0_SCAN_OFFLOAD_INFO_GET_CMD_ID(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 0, 5) +#define D0_SCAN_OFFLOAD_INFO_SET_CMD_ID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 0, 5, __value) +#define D0_SCAN_OFFLOAD_INFO_GET_CLASS(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 5, 3) +#define D0_SCAN_OFFLOAD_INFO_SET_CLASS(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 5, 3, __value) +#define D0_SCAN_OFFLOAD_INFO_GET_LOC_CHANNEL_INFO(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 8, 8) +#define D0_SCAN_OFFLOAD_INFO_SET_LOC_CHANNEL_INFO(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 8, 8, __value) +#define CHANNEL_SWITCH_OFFLOAD_GET_CMD_ID(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 0, 5) +#define CHANNEL_SWITCH_OFFLOAD_SET_CMD_ID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 0, 5, __value) +#define CHANNEL_SWITCH_OFFLOAD_GET_CLASS(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 5, 3) +#define CHANNEL_SWITCH_OFFLOAD_SET_CLASS(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 5, 3, __value) +#define CHANNEL_SWITCH_OFFLOAD_GET_CHANNEL_NUM(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 8, 8) +#define CHANNEL_SWITCH_OFFLOAD_SET_CHANNEL_NUM(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 8, 8, __value) +#define CHANNEL_SWITCH_OFFLOAD_GET_EN_RFE(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 16, 8) +#define CHANNEL_SWITCH_OFFLOAD_SET_EN_RFE(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 16, 8, __value) +#define CHANNEL_SWITCH_OFFLOAD_GET_RFE_TYPE(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 24, 8) +#define CHANNEL_SWITCH_OFFLOAD_SET_RFE_TYPE(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 24, 8, __value) +#define AOAC_RSVD_PAGE3_GET_CMD_ID(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 0, 5) +#define AOAC_RSVD_PAGE3_SET_CMD_ID(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 0, 5, __value) +#define AOAC_RSVD_PAGE3_GET_CLASS(__h2c) LE_BITS_TO_4BYTE(__h2c + 0X00, 5, 3) +#define AOAC_RSVD_PAGE3_SET_CLASS(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 5, 3, __value) +#define AOAC_RSVD_PAGE3_GET_LOC_NLO_INFO(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 8, 8) +#define AOAC_RSVD_PAGE3_SET_LOC_NLO_INFO(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 8, 8, __value) +#define AOAC_RSVD_PAGE3_GET_LOC_AOAC_REPORT(__h2c) \ + LE_BITS_TO_4BYTE(__h2c + 0X00, 16, 8) +#define AOAC_RSVD_PAGE3_SET_LOC_AOAC_REPORT(__h2c, __value) \ + SET_BITS_TO_LE_4BYTE(__h2c + 0X00, 16, 8, __value) +#endif diff --git a/drivers/staging/rtlwifi/halmac/halmac_pcie_reg.h b/drivers/staging/rtlwifi/halmac/halmac_pcie_reg.h new file mode 100644 index 000000000000..41780676508e --- /dev/null +++ b/drivers/staging/rtlwifi/halmac/halmac_pcie_reg.h @@ -0,0 +1,28 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef __HALMAC_PCIE_REG_H__ +#define __HALMAC_PCIE_REG_H__ + +#endif /* __HALMAC_PCIE_REG_H__ */ diff --git a/drivers/staging/rtlwifi/halmac/halmac_pwr_seq_cmd.h b/drivers/staging/rtlwifi/halmac/halmac_pwr_seq_cmd.h new file mode 100644 index 000000000000..13a65a4754b0 --- /dev/null +++ b/drivers/staging/rtlwifi/halmac/halmac_pwr_seq_cmd.h @@ -0,0 +1,116 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef HALMAC_POWER_SEQUENCE_CMD +#define HALMAC_POWER_SEQUENCE_CMD + +#include "halmac_2_platform.h" +#include "halmac_type.h" + +#define HALMAC_POLLING_READY_TIMEOUT_COUNT 20000 + +/* The value of cmd : 4 bits */ + +/* offset : the read register offset + * msk : the mask of the read value + * value : N/A, left by 0 + * Note : dirver shall implement this function by read & msk + */ +#define HALMAC_PWR_CMD_READ 0x00 +/* + * offset: the read register offset + * msk: the mask of the write bits + * value: write value + * Note: driver shall implement this cmd by read & msk after write + */ +#define HALMAC_PWR_CMD_WRITE 0x01 +/* offset: the read register offset + * msk: the mask of the polled value + * value: the value to be polled, masked by the msd field. + * Note: driver shall implement this cmd by + * do{ + * if( (Read(offset) & msk) == (value & msk) ) + * break; + * } while(not timeout); + */ +#define HALMAC_PWR_CMD_POLLING 0x02 +/* offset: the value to delay + * msk: N/A + * value: the unit of delay, 0: us, 1: ms + */ +#define HALMAC_PWR_CMD_DELAY 0x03 +/* offset: N/A + * msk: N/A + * value: N/A + */ +#define HALMAC_PWR_CMD_END 0x04 + +/* The value of base : 4 bits */ + +/* define the base address of each block */ +#define HALMAC_PWR_BASEADDR_MAC 0x00 +#define HALMAC_PWR_BASEADDR_USB 0x01 +#define HALMAC_PWR_BASEADDR_PCIE 0x02 +#define HALMAC_PWR_BASEADDR_SDIO 0x03 + +/* The value of interface_msk : 4 bits */ +#define HALMAC_PWR_INTF_SDIO_MSK BIT(0) +#define HALMAC_PWR_INTF_USB_MSK BIT(1) +#define HALMAC_PWR_INTF_PCI_MSK BIT(2) +#define HALMAC_PWR_INTF_ALL_MSK (BIT(0) | BIT(1) | BIT(2) | BIT(3)) + +/* The value of fab_msk : 4 bits */ +#define HALMAC_PWR_FAB_TSMC_MSK BIT(0) +#define HALMAC_PWR_FAB_UMC_MSK BIT(1) +#define HALMAC_PWR_FAB_ALL_MSK (BIT(0) | BIT(1) | BIT(2) | BIT(3)) + +/* The value of cut_msk : 8 bits */ +#define HALMAC_PWR_CUT_TESTCHIP_MSK BIT(0) +#define HALMAC_PWR_CUT_A_MSK BIT(1) +#define HALMAC_PWR_CUT_B_MSK BIT(2) +#define HALMAC_PWR_CUT_C_MSK BIT(3) +#define HALMAC_PWR_CUT_D_MSK BIT(4) +#define HALMAC_PWR_CUT_E_MSK BIT(5) +#define HALMAC_PWR_CUT_F_MSK BIT(6) +#define HALMAC_PWR_CUT_G_MSK BIT(7) +#define HALMAC_PWR_CUT_ALL_MSK 0xFF + +enum halmac_pwrseq_cmd_delay_unit_ { + HALMAC_PWRSEQ_DELAY_US, + HALMAC_PWRSEQ_DELAY_MS, +}; + +/*Don't care endian issue, because element of pwer seq vector is fixed address*/ +struct halmac_wl_pwr_cfg_ { + u16 offset; + u8 cut_msk; + u8 fab_msk : 4; + u8 interface_msk : 4; + u8 base : 4; + u8 cmd : 4; + u8 msk; + u8 value; +}; + +#endif diff --git a/drivers/staging/rtlwifi/halmac/halmac_reg2.h b/drivers/staging/rtlwifi/halmac/halmac_reg2.h new file mode 100644 index 000000000000..bebf974ed949 --- /dev/null +++ b/drivers/staging/rtlwifi/halmac/halmac_reg2.h @@ -0,0 +1,1132 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef __HALMAC_COM_REG_H__ +#define __HALMAC_COM_REG_H__ +/*-------------------------Modification Log----------------------------------- + * For Page0, it is based on Combo_And_WL_Only_Page0_Reg.xls SVN524 + * The supported IC are 8723A, 8881A, 8723B, 8192E, 8881A + * 8812A and 8188E is not included in page0 register + * + * For other pages, it is based on MAC_Register.doc SVN502 + * Most IC is the same with 8812A + *-------------------------Modification Log----------------------------------- + */ + +/*--------------------------Include File--------------------------------------*/ +/*--------------------------Include File--------------------------------------*/ + +#define REG_SYS_ISO_CTRL 0x0000 + +#define REG_SDIO_TX_CTRL 0x10250000 + +#define REG_SYS_FUNC_EN 0x0002 +#define REG_SYS_PW_CTRL 0x0004 +#define REG_SYS_CLK_CTRL 0x0008 +#define REG_SYS_EEPROM_CTRL 0x000A +#define REG_EE_VPD 0x000C +#define REG_SYS_SWR_CTRL1 0x0010 +#define REG_SYS_SWR_CTRL2 0x0014 + +#define REG_SDIO_HIMR 0x10250014 + +#define REG_SYS_SWR_CTRL3 0x0018 + +#define REG_SDIO_HISR 0x10250018 + +#define REG_RSV_CTRL 0x001C + +#define REG_SDIO_RX_REQ_LEN 0x1025001C + +#define REG_RF_CTRL 0x001F + +#define REG_SDIO_FREE_TXPG_SEQ_V1 0x1025001F + +#define REG_AFE_LDO_CTRL 0x0020 + +#define REG_SDIO_FREE_TXPG 0x10250020 + +#define REG_AFE_CTRL1 0x0024 + +#define REG_SDIO_FREE_TXPG2 0x10250024 + +#define REG_AFE_CTRL2 0x0028 + +#define REG_SDIO_OQT_FREE_TXPG_V1 0x10250028 + +#define REG_AFE_CTRL3 0x002C +#define REG_EFUSE_CTRL 0x0030 + +#define REG_SDIO_HTSFR_INFO 0x10250030 + +#define REG_LDO_EFUSE_CTRL 0x0034 +#define REG_PWR_OPTION_CTRL 0x0038 + +#define REG_SDIO_HCPWM1_V2 0x10250038 +#define REG_SDIO_HCPWM2_V2 0x1025003A + +#define REG_CAL_TIMER 0x003C +#define REG_ACLK_MON 0x003E +#define REG_GPIO_MUXCFG 0x0040 + +#define REG_SDIO_INDIRECT_REG_CFG 0x10250040 + +#define REG_GPIO_PIN_CTRL 0x0044 + +#define REG_SDIO_INDIRECT_REG_DATA 0x10250044 + +#define REG_GPIO_INTM 0x0048 +#define REG_LED_CFG 0x004C +#define REG_FSIMR 0x0050 +#define REG_FSISR 0x0054 +#define REG_HSIMR 0x0058 +#define REG_HSISR 0x005C +#define REG_GPIO_EXT_CTRL 0x0060 + +#define REG_SDIO_H2C 0x10250060 + +#define REG_PAD_CTRL1 0x0064 + +#define REG_SDIO_C2H 0x10250064 + +#define REG_WL_BT_PWR_CTRL 0x0068 + +#define REG_SDM_DEBUG 0x006C + +#define REG_SYS_SDIO_CTRL 0x0070 + +#define REG_HCI_OPT_CTRL 0x0074 + +#define REG_AFE_CTRL4 0x0078 + +#define REG_LDO_SWR_CTRL 0x007C + +#define REG_MCUFW_CTRL 0x0080 + +#define REG_SDIO_HRPWM1 0x10250080 +#define REG_SDIO_HRPWM2 0x10250082 + +#define REG_MCU_TST_CFG 0x0084 + +#define REG_SDIO_HPS_CLKR 0x10250084 +#define REG_SDIO_BUS_CTRL 0x10250085 + +#define REG_SDIO_HSUS_CTRL 0x10250086 + +#define REG_HMEBOX_E0_E1 0x0088 + +#define REG_SDIO_RESPONSE_TIMER 0x10250088 + +#define REG_SDIO_CMD_CRC 0x1025008A + +#define REG_HMEBOX_E2_E3 0x008C +#define REG_WLLPS_CTRL 0x0090 + +#define REG_SDIO_HSISR 0x10250090 +#define REG_SDIO_HSIMR 0x10250091 + +#define REG_AFE_CTRL5 0x0094 + +#define REG_GPIO_DEBOUNCE_CTRL 0x0098 +#define REG_RPWM2 0x009C +#define REG_SYSON_FSM_MON 0x00A0 + +#define REG_AFE_CTRL6 0x00A4 + +#define REG_PMC_DBG_CTRL1 0x00A8 + +#define REG_AFE_CTRL7 0x00AC + +#define REG_HIMR0 0x00B0 +#define REG_HISR0 0x00B4 +#define REG_HIMR1 0x00B8 +#define REG_HISR1 0x00BC +#define REG_DBG_PORT_SEL 0x00C0 + +#define REG_SDIO_ERR_RPT 0x102500C0 +#define REG_SDIO_CMD_ERRCNT 0x102500C1 +#define REG_SDIO_DATA_ERRCNT 0x102500C2 + +#define REG_PAD_CTRL2 0x00C4 + +#define REG_SDIO_CMD_ERR_CONTENT 0x102500C4 + +#define REG_SDIO_CRC_ERR_IDX 0x102500C9 +#define REG_SDIO_DATA_CRC 0x102500CA +#define REG_SDIO_DATA_REPLY_TIME 0x102500CB + +#define REG_PMC_DBG_CTRL2 0x00CC +#define REG_BIST_CTRL 0x00D0 +#define REG_BIST_RPT 0x00D4 +#define REG_MEM_CTRL 0x00D8 + +#define REG_AFE_CTRL8 0x00DC + +#define REG_USB_SIE_INTF 0x00E0 +#define REG_PCIE_MIO_INTF 0x00E4 +#define REG_PCIE_MIO_INTD 0x00E8 + +#define REG_WLRF1 0x00EC + +#define REG_SYS_CFG1 0x00F0 +#define REG_SYS_STATUS1 0x00F4 +#define REG_SYS_STATUS2 0x00F8 +#define REG_SYS_CFG2 0x00FC +#define REG_CR 0x0100 + +#define REG_PKT_BUFF_ACCESS_CTRL 0x0106 + +#define REG_TSF_CLK_STATE 0x0108 +#define REG_TXDMA_PQ_MAP 0x010C +#define REG_TRXFF_BNDY 0x0114 + +#define REG_PTA_I2C_MBOX 0x0118 + +#define REG_RXFF_BNDY 0x011C + +#define REG_FE1IMR 0x0120 + +#define REG_FE1ISR 0x0124 + +#define REG_CPWM 0x012C +#define REG_FWIMR 0x0130 +#define REG_FWISR 0x0134 +#define REG_FTIMR 0x0138 +#define REG_FTISR 0x013C +#define REG_PKTBUF_DBG_CTRL 0x0140 +#define REG_PKTBUF_DBG_DATA_L 0x0144 +#define REG_PKTBUF_DBG_DATA_H 0x0148 +#define REG_CPWM2 0x014C +#define REG_TC0_CTRL 0x0150 +#define REG_TC1_CTRL 0x0154 +#define REG_TC2_CTRL 0x0158 +#define REG_TC3_CTRL 0x015C +#define REG_TC4_CTRL 0x0160 +#define REG_TCUNIT_BASE 0x0164 +#define REG_TC5_CTRL 0x0168 +#define REG_TC6_CTRL 0x016C +#define REG_MBIST_FAIL 0x0170 +#define REG_MBIST_START_PAUSE 0x0174 +#define REG_MBIST_DONE 0x0178 + +#define REG_MBIST_FAIL_NRML 0x017C + +#define REG_AES_DECRPT_DATA 0x0180 +#define REG_AES_DECRPT_CFG 0x0184 + +#define REG_TMETER 0x0190 +#define REG_OSC_32K_CTRL 0x0194 +#define REG_32K_CAL_REG1 0x0198 +#define REG_C2HEVT 0x01A0 + +#define REG_C2HEVT_1 0x01A4 +#define REG_C2HEVT_2 0x01A8 +#define REG_C2HEVT_3 0x01AC + +#define REG_SW_DEFINED_PAGE1 0x01B8 + +#define REG_MCUTST_I 0x01C0 +#define REG_MCUTST_II 0x01C4 +#define REG_FMETHR 0x01C8 +#define REG_HMETFR 0x01CC +#define REG_HMEBOX0 0x01D0 +#define REG_HMEBOX1 0x01D4 +#define REG_HMEBOX2 0x01D8 +#define REG_HMEBOX3 0x01DC +#define REG_LLT_INIT 0x01E0 + +#define REG_LLT_INIT_ADDR 0x01E4 + +#define REG_BB_ACCESS_CTRL 0x01E8 +#define REG_BB_ACCESS_DATA 0x01EC +#define REG_HMEBOX_E0 0x01F0 +#define REG_HMEBOX_E1 0x01F4 +#define REG_HMEBOX_E2 0x01F8 +#define REG_HMEBOX_E3 0x01FC + +#define REG_FIFOPAGE_CTRL_1 0x0200 + +#define REG_FIFOPAGE_CTRL_2 0x0204 + +#define REG_AUTO_LLT_V1 0x0208 + +#define REG_TXDMA_OFFSET_CHK 0x020C +#define REG_TXDMA_STATUS 0x0210 + +#define REG_TX_DMA_DBG 0x0214 + +#define REG_TQPNT1 0x0218 +#define REG_TQPNT2 0x021C + +#define REG_TQPNT3 0x0220 + +#define REG_TQPNT4 0x0224 + +#define REG_RQPN_CTRL_1 0x0228 +#define REG_RQPN_CTRL_2 0x022C +#define REG_FIFOPAGE_INFO_1 0x0230 +#define REG_FIFOPAGE_INFO_2 0x0234 +#define REG_FIFOPAGE_INFO_3 0x0238 +#define REG_FIFOPAGE_INFO_4 0x023C +#define REG_FIFOPAGE_INFO_5 0x0240 + +#define REG_H2C_HEAD 0x0244 +#define REG_H2C_TAIL 0x0248 +#define REG_H2C_READ_ADDR 0x024C +#define REG_H2C_WR_ADDR 0x0250 +#define REG_H2C_INFO 0x0254 + +#define REG_RXDMA_AGG_PG_TH 0x0280 +#define REG_RXPKT_NUM 0x0284 +#define REG_RXDMA_STATUS 0x0288 +#define REG_RXDMA_DPR 0x028C +#define REG_RXDMA_MODE 0x0290 +#define REG_C2H_PKT 0x0294 + +#define REG_FWFF_C2H 0x0298 +#define REG_FWFF_CTRL 0x029C +#define REG_FWFF_PKT_INFO 0x02A0 + +#define REG_PCIE_CTRL 0x0300 + +#define REG_INT_MIG 0x0304 +#define REG_BCNQ_TXBD_DESA 0x0308 +#define REG_MGQ_TXBD_DESA 0x0310 +#define REG_VOQ_TXBD_DESA 0x0318 +#define REG_VIQ_TXBD_DESA 0x0320 +#define REG_BEQ_TXBD_DESA 0x0328 +#define REG_BKQ_TXBD_DESA 0x0330 +#define REG_RXQ_RXBD_DESA 0x0338 +#define REG_HI0Q_TXBD_DESA 0x0340 +#define REG_HI1Q_TXBD_DESA 0x0348 +#define REG_HI2Q_TXBD_DESA 0x0350 +#define REG_HI3Q_TXBD_DESA 0x0358 +#define REG_HI4Q_TXBD_DESA 0x0360 +#define REG_HI5Q_TXBD_DESA 0x0368 +#define REG_HI6Q_TXBD_DESA 0x0370 +#define REG_HI7Q_TXBD_DESA 0x0378 +#define REG_MGQ_TXBD_NUM 0x0380 +#define REG_RX_RXBD_NUM 0x0382 +#define REG_VOQ_TXBD_NUM 0x0384 +#define REG_VIQ_TXBD_NUM 0x0386 +#define REG_BEQ_TXBD_NUM 0x0388 +#define REG_BKQ_TXBD_NUM 0x038A +#define REG_HI0Q_TXBD_NUM 0x038C +#define REG_HI1Q_TXBD_NUM 0x038E +#define REG_HI2Q_TXBD_NUM 0x0390 +#define REG_HI3Q_TXBD_NUM 0x0392 +#define REG_HI4Q_TXBD_NUM 0x0394 +#define REG_HI5Q_TXBD_NUM 0x0396 +#define REG_HI6Q_TXBD_NUM 0x0398 +#define REG_HI7Q_TXBD_NUM 0x039A +#define REG_TSFTIMER_HCI 0x039C +#define REG_BD_RWPTR_CLR 0x039C +#define REG_VOQ_TXBD_IDX 0x03A0 +#define REG_VIQ_TXBD_IDX 0x03A4 +#define REG_BEQ_TXBD_IDX 0x03A8 +#define REG_BKQ_TXBD_IDX 0x03AC +#define REG_MGQ_TXBD_IDX 0x03B0 +#define REG_RXQ_RXBD_IDX 0x03B4 +#define REG_HI0Q_TXBD_IDX 0x03B8 +#define REG_HI1Q_TXBD_IDX 0x03BC +#define REG_HI2Q_TXBD_IDX 0x03C0 +#define REG_HI3Q_TXBD_IDX 0x03C4 +#define REG_HI4Q_TXBD_IDX 0x03C8 +#define REG_HI5Q_TXBD_IDX 0x03CC +#define REG_HI6Q_TXBD_IDX 0x03D0 +#define REG_HI7Q_TXBD_IDX 0x03D4 + +#define REG_DBG_SEL_V1 0x03D8 + +#define REG_PCIE_HRPWM1_V1 0x03D9 + +#define REG_PCIE_HCPWM1_V1 0x03DA + +#define REG_PCIE_CTRL2 0x03DB + +#define REG_PCIE_HRPWM2_V1 0x03DC + +#define REG_PCIE_HCPWM2_V1 0x03DE + +#define REG_PCIE_H2C_MSG_V1 0x03E0 + +#define REG_PCIE_C2H_MSG_V1 0x03E4 + +#define REG_DBI_WDATA_V1 0x03E8 + +#define REG_DBI_RDATA_V1 0x03EC + +#define REG_DBI_FLAG_V1 0x03F0 + +#define REG_MDIO_V1 0x03F4 + +#define REG_PCIE_MIX_CFG 0x03F8 + +#define REG_HCI_MIX_CFG 0x03FC + +#define REG_Q0_INFO 0x0400 +#define REG_Q1_INFO 0x0404 +#define REG_Q2_INFO 0x0408 +#define REG_Q3_INFO 0x040C +#define REG_MGQ_INFO 0x0410 +#define REG_HIQ_INFO 0x0414 +#define REG_BCNQ_INFO 0x0418 +#define REG_TXPKT_EMPTY 0x041A +#define REG_CPU_MGQ_INFO 0x041C +#define REG_FWHW_TXQ_CTRL 0x0420 + +#define REG_DATAFB_SEL 0x0423 + +#define REG_BCNQ_BDNY_V1 0x0424 + +#define REG_LIFETIME_EN 0x0426 + +#define REG_SPEC_SIFS 0x0428 +#define REG_RETRY_LIMIT 0x042A +#define REG_TXBF_CTRL 0x042C +#define REG_DARFRC 0x0430 +#define REG_RARFRC 0x0438 +#define REG_RRSR 0x0440 +#define REG_ARFR0 0x0444 +#define REG_ARFR1_V1 0x044C +#define REG_CCK_CHECK 0x0454 + +#define REG_AMPDU_MAX_TIME_V1 0x0455 + +#define REG_BCNQ1_BDNY_V1 0x0456 + +#define REG_AMPDU_MAX_LENGTH 0x0458 +#define REG_ACQ_STOP 0x045C + +#define REG_NDPA_RATE 0x045D + +#define REG_TX_HANG_CTRL 0x045E +#define REG_NDPA_OPT_CTRL 0x045F + +#define REG_RD_RESP_PKT_TH 0x0463 +#define REG_CMDQ_INFO 0x0464 +#define REG_Q4_INFO 0x0468 +#define REG_Q5_INFO 0x046C +#define REG_Q6_INFO 0x0470 +#define REG_Q7_INFO 0x0474 + +#define REG_WMAC_LBK_BUF_HD_V1 0x0478 +#define REG_MGQ_BDNY_V1 0x047A + +#define REG_TXRPT_CTRL 0x047C +#define REG_INIRTS_RATE_SEL 0x0480 +#define REG_BASIC_CFEND_RATE 0x0481 +#define REG_STBC_CFEND_RATE 0x0482 +#define REG_DATA_SC 0x0483 +#define REG_MACID_SLEEP3 0x0484 +#define REG_MACID_SLEEP1 0x0488 +#define REG_ARFR2_V1 0x048C +#define REG_ARFR3_V1 0x0494 +#define REG_ARFR4 0x049C +#define REG_ARFR5 0x04A4 +#define REG_TXRPT_START_OFFSET 0x04AC + +#define REG_POWER_STAGE1 0x04B4 + +#define REG_POWER_STAGE2 0x04B8 + +#define REG_SW_AMPDU_BURST_MODE_CTRL 0x04BC +#define REG_PKT_LIFE_TIME 0x04C0 +#define REG_STBC_SETTING 0x04C4 +#define REG_STBC_SETTING2 0x04C5 +#define REG_QUEUE_CTRL 0x04C6 +#define REG_SINGLE_AMPDU_CTRL 0x04C7 +#define REG_PROT_MODE_CTRL 0x04C8 +#define REG_BAR_MODE_CTRL 0x04CC +#define REG_RA_TRY_RATE_AGG_LMT 0x04CF +#define REG_MACID_SLEEP2 0x04D0 +#define REG_MACID_SLEEP 0x04D4 + +#define REG_HW_SEQ0 0x04D8 +#define REG_HW_SEQ1 0x04DA +#define REG_HW_SEQ2 0x04DC +#define REG_HW_SEQ3 0x04DE + +#define REG_NULL_PKT_STATUS_V1 0x04E0 + +#define REG_PTCL_ERR_STATUS 0x04E2 + +#define REG_NULL_PKT_STATUS_EXTEND 0x04E3 + +#define REG_VIDEO_ENHANCEMENT_FUN 0x04E4 + +#define REG_BT_POLLUTE_PKT_CNT 0x04E8 +#define REG_PTCL_DBG 0x04EC + +#define REG_CPUMGQ_TIMER_CTRL2 0x04F4 + +#define REG_DUMMY_PAGE4_V1 0x04FC +#define REG_MOREDATA 0x04FE + +#define REG_EDCA_VO_PARAM 0x0500 +#define REG_EDCA_VI_PARAM 0x0504 +#define REG_EDCA_BE_PARAM 0x0508 +#define REG_EDCA_BK_PARAM 0x050C +#define REG_BCNTCFG 0x0510 +#define REG_PIFS 0x0512 +#define REG_RDG_PIFS 0x0513 +#define REG_SIFS 0x0514 +#define REG_TSFTR_SYN_OFFSET 0x0518 +#define REG_AGGR_BREAK_TIME 0x051A +#define REG_SLOT 0x051B +#define REG_TX_PTCL_CTRL 0x0520 +#define REG_TXPAUSE 0x0522 +#define REG_DIS_TXREQ_CLR 0x0523 +#define REG_RD_CTRL 0x0524 +#define REG_MBSSID_CTRL 0x0526 +#define REG_P2PPS_CTRL 0x0527 +#define REG_PKT_LIFETIME_CTRL 0x0528 +#define REG_P2PPS_SPEC_STATE 0x052B + +#define REG_BAR_TX_CTRL 0x0530 + +#define REG_QUEUE_INCOL_THR 0x0538 +#define REG_QUEUE_INCOL_EN 0x053C + +#define REG_TBTT_PROHIBIT 0x0540 +#define REG_P2PPS_STATE 0x0543 +#define REG_RD_NAV_NXT 0x0544 +#define REG_NAV_PROT_LEN 0x0546 + +#define REG_BCN_CTRL 0x0550 + +#define REG_BCN_CTRL_CLINT0 0x0551 + +#define REG_MBID_NUM 0x0552 +#define REG_DUAL_TSF_RST 0x0553 +#define REG_MBSSID_BCN_SPACE 0x0554 +#define REG_DRVERLYINT 0x0558 +#define REG_BCNDMATIM 0x0559 +#define REG_ATIMWND 0x055A +#define REG_USTIME_TSF 0x055C +#define REG_BCN_MAX_ERR 0x055D +#define REG_RXTSF_OFFSET_CCK 0x055E +#define REG_RXTSF_OFFSET_OFDM 0x055F +#define REG_TSFTR 0x0560 + +#define REG_FREERUN_CNT 0x0568 + +#define REG_ATIMWND1_V1 0x0570 + +#define REG_TBTT_PROHIBIT_INFRA 0x0571 + +#define REG_CTWND 0x0572 +#define REG_BCNIVLCUNT 0x0573 +#define REG_BCNDROPCTRL 0x0574 +#define REG_HGQ_TIMEOUT_PERIOD 0x0575 + +#define REG_TXCMD_TIMEOUT_PERIOD 0x0576 +#define REG_MISC_CTRL 0x0577 +#define REG_BCN_CTRL_CLINT1 0x0578 +#define REG_BCN_CTRL_CLINT2 0x0579 +#define REG_BCN_CTRL_CLINT3 0x057A + +#define REG_EXTEND_CTRL 0x057B + +#define REG_P2PPS1_SPEC_STATE 0x057C +#define REG_P2PPS1_STATE 0x057D +#define REG_P2PPS2_SPEC_STATE 0x057E +#define REG_P2PPS2_STATE 0x057F + +#define REG_PS_TIMER0 0x0580 + +#define REG_PS_TIMER1 0x0584 + +#define REG_PS_TIMER2 0x0588 + +#define REG_TBTT_CTN_AREA 0x058C +#define REG_FORCE_BCN_IFS 0x058E +#define REG_TXOP_MIN 0x0590 +#define REG_PRE_BKF_TIME 0x0592 +#define REG_CROSS_TXOP_CTRL 0x0593 + +#define REG_ATIMWND2 0x05A0 +#define REG_ATIMWND3 0x05A1 +#define REG_ATIMWND4 0x05A2 +#define REG_ATIMWND5 0x05A3 +#define REG_ATIMWND6 0x05A4 +#define REG_ATIMWND7 0x05A5 +#define REG_ATIMUGT 0x05A6 +#define REG_HIQ_NO_LMT_EN 0x05A7 +#define REG_DTIM_COUNTER_ROOT 0x05A8 +#define REG_DTIM_COUNTER_VAP1 0x05A9 +#define REG_DTIM_COUNTER_VAP2 0x05AA +#define REG_DTIM_COUNTER_VAP3 0x05AB +#define REG_DTIM_COUNTER_VAP4 0x05AC +#define REG_DTIM_COUNTER_VAP5 0x05AD +#define REG_DTIM_COUNTER_VAP6 0x05AE +#define REG_DTIM_COUNTER_VAP7 0x05AF +#define REG_DIS_ATIM 0x05B0 + +#define REG_EARLY_128US 0x05B1 +#define REG_P2PPS1_CTRL 0x05B2 +#define REG_P2PPS2_CTRL 0x05B3 +#define REG_TIMER0_SRC_SEL 0x05B4 +#define REG_NOA_UNIT_SEL 0x05B5 +#define REG_P2POFF_DIS_TXTIME 0x05B7 +#define REG_MBSSID_BCN_SPACE2 0x05B8 +#define REG_MBSSID_BCN_SPACE3 0x05BC + +#define REG_ACMHWCTRL 0x05C0 +#define REG_ACMRSTCTRL 0x05C1 +#define REG_ACMAVG 0x05C2 +#define REG_VO_ADMTIME 0x05C4 +#define REG_VI_ADMTIME 0x05C6 +#define REG_BE_ADMTIME 0x05C8 +#define REG_EDCA_RANDOM_GEN 0x05CC +#define REG_TXCMD_NOA_SEL 0x05CF +#define REG_NOA_PARAM 0x05E0 + +#define REG_P2P_RST 0x05F0 +#define REG_SCHEDULER_RST 0x05F1 + +#define REG_SCH_TXCMD 0x05F8 +#define REG_PAGE5_DUMMY 0x05FC +#define REG_WMAC_CR 0x0600 + +#define REG_WMAC_FWPKT_CR 0x0601 + +#define REG_BWOPMODE 0x0603 + +#define REG_TCR 0x0604 +#define REG_RCR 0x0608 +#define REG_RX_PKT_LIMIT 0x060C +#define REG_RX_DLK_TIME 0x060D +#define REG_RX_DRVINFO_SZ 0x060F +#define REG_MACID 0x0610 +#define REG_BSSID 0x0618 +#define REG_MAR 0x0620 +#define REG_MBIDCAMCFG_1 0x0628 +#define REG_MBIDCAMCFG_2 0x062C + +#define REG_WMAC_TCR_TSFT_OFS 0x0630 +#define REG_UDF_THSD 0x0632 +#define REG_ZLD_NUM 0x0633 + +#define REG_STMP_THSD 0x0634 +#define REG_WMAC_TXTIMEOUT 0x0635 +#define REG_MCU_TEST_2_V1 0x0636 + +#define REG_USTIME_EDCA 0x0638 + +#define REG_MAC_SPEC_SIFS 0x063A +#define REG_RESP_SIFS_CCK 0x063C +#define REG_RESP_SIFS_OFDM 0x063E +#define REG_ACKTO 0x0640 +#define REG_CTS2TO 0x0641 +#define REG_EIFS 0x0642 + +#define REG_NAV_CTRL 0x0650 +#define REG_BACAMCMD 0x0654 +#define REG_BACAMCONTENT 0x0658 +#define REG_LBDLY 0x0660 + +#define REG_WMAC_BACAM_RPMEN 0x0661 + +#define REG_TX_RX 0x0662 + +#define REG_WMAC_BITMAP_CTL 0x0663 + +#define REG_RXERR_RPT 0x0664 +#define REG_WMAC_TRXPTCL_CTL 0x0668 +#define REG_CAMCMD 0x0670 +#define REG_CAMWRITE 0x0674 +#define REG_CAMREAD 0x0678 +#define REG_CAMDBG 0x067C +#define REG_SECCFG 0x0680 + +#define REG_RXFILTER_CATEGORY_1 0x0682 +#define REG_RXFILTER_ACTION_1 0x0683 +#define REG_RXFILTER_CATEGORY_2 0x0684 +#define REG_RXFILTER_ACTION_2 0x0685 +#define REG_RXFILTER_CATEGORY_3 0x0686 +#define REG_RXFILTER_ACTION_3 0x0687 +#define REG_RXFLTMAP3 0x0688 +#define REG_RXFLTMAP4 0x068A +#define REG_RXFLTMAP5 0x068C +#define REG_RXFLTMAP6 0x068E + +#define REG_WOW_CTRL 0x0690 + +#define REG_NAN_RX_TSF_FILTER 0x0691 + +#define REG_PS_RX_INFO 0x0692 +#define REG_WMMPS_UAPSD_TID 0x0693 +#define REG_LPNAV_CTRL 0x0694 + +#define REG_WKFMCAM_CMD 0x0698 +#define REG_WKFMCAM_RWD 0x069C + +#define REG_RXFLTMAP0 0x06A0 +#define REG_RXFLTMAP1 0x06A2 +#define REG_RXFLTMAP 0x06A4 +#define REG_BCN_PSR_RPT 0x06A8 + +#define REG_FLC_RPC 0x06AC +#define REG_FLC_RPCT 0x06AD +#define REG_FLC_PTS 0x06AE +#define REG_FLC_TRPC 0x06AF + +#define REG_RXPKTMON_CTRL 0x06B0 + +#define REG_STATE_MON 0x06B4 + +#define REG_ERROR_MON 0x06B8 +#define REG_SEARCH_MACID 0x06BC + +#define REG_BT_COEX_TABLE 0x06C0 + +#define REG_RXCMD_0 0x06D0 +#define REG_RXCMD_1 0x06D4 + +#define REG_WMAC_RESP_TXINFO 0x06D8 + +#define REG_BBPSF_CTRL 0x06DC + +#define REG_P2P_RX_BCN_NOA 0x06E0 +#define REG_ASSOCIATED_BFMER0_INFO 0x06E4 +#define REG_ASSOCIATED_BFMER1_INFO 0x06EC +#define REG_TX_CSI_RPT_PARAM_BW20 0x06F4 +#define REG_TX_CSI_RPT_PARAM_BW40 0x06F8 +#define REG_TX_CSI_RPT_PARAM_BW80 0x06FC +#define REG_MACID1 0x0700 + +#define REG_BSSID1 0x0708 + +#define REG_BCN_PSR_RPT1 0x0710 +#define REG_ASSOCIATED_BFMEE_SEL 0x0714 +#define REG_SND_PTCL_CTRL 0x0718 +#define REG_RX_CSI_RPT_INFO 0x071C +#define REG_NS_ARP_CTRL 0x0720 +#define REG_NS_ARP_INFO 0x0724 + +#define REG_BEAMFORMING_INFO_NSARP_V1 0x0728 + +#define REG_BEAMFORMING_INFO_NSARP 0x072C + +#define REG_WMAC_RTX_CTX_SUBTYPE_CFG 0x0750 + +#define REG_WMAC_SWAES_CFG 0x0760 + +#define REG_BT_COEX_V2 0x0762 + +#define REG_BT_COEX 0x0764 + +#define REG_WLAN_ACT_MASK_CTRL 0x0768 + +#define REG_BT_COEX_ENHANCED_INTR_CTRL 0x076E + +#define REG_BT_ACT_STATISTICS 0x0770 + +#define REG_BT_STATISTICS_CONTROL_REGISTER 0x0778 + +#define REG_BT_STATUS_REPORT_REGISTER 0x077C + +#define REG_BT_INTERRUPT_CONTROL_REGISTER 0x0780 + +#define REG_WLAN_REPORT_TIME_OUT_CONTROL_REGISTER 0x0784 + +#define REG_BT_ISOLATION_TABLE_REGISTER_REGISTER 0x0785 + +#define REG_BT_INTERRUPT_STATUS_REGISTER 0x078F + +#define REG_BT_TDMA_TIME_REGISTER 0x0790 + +#define REG_BT_ACT_REGISTER 0x0794 + +#define REG_OBFF_CTRL_BASIC 0x0798 + +#define REG_OBFF_CTRL2_TIMER 0x079C + +#define REG_LTR_CTRL_BASIC 0x07A0 + +#define REG_LTR_CTRL2_TIMER_THRESHOLD 0x07A4 + +#define REG_LTR_IDLE_LATENCY_V1 0x07A8 +#define REG_LTR_ACTIVE_LATENCY_V1 0x07AC + +#define REG_ANTENNA_TRAINING_CONTROL_REGISTER 0x07B0 + +#define REG_WMAC_PKTCNT_RWD 0x07B8 +#define REG_WMAC_PKTCNT_CTRL 0x07BC + +#define REG_IQ_DUMP 0x07C0 + +#define REG_WMAC_FTM_CTL 0x07CC + +#define REG_WMAC_IQ_MDPK_FUNC 0x07CE + +#define REG_WMAC_OPTION_FUNCTION 0x07D0 + +#define REG_RX_FILTER_FUNCTION 0x07DA + +#define REG_NDP_SIG 0x07E0 +#define REG_TXCMD_INFO_FOR_RSP_PKT 0x07E4 + +#define REG_RTS_ADDRESS_0 0x07F0 + +#define REG_RTS_ADDRESS_1 0x07F8 + +#define REG__RPFM_MAP1 0x07FE + +#define REG_SYS_CFG3 0x1000 +#define REG_SYS_CFG4 0x1034 + +#define REG_SYS_CFG5 0x1070 + +#define REG_CPU_DMEM_CON 0x1080 + +#define REG_BOOT_REASON 0x1088 +#define REG_NFCPAD_CTRL 0x10A8 + +#define REG_HIMR2 0x10B0 +#define REG_HISR2 0x10B4 +#define REG_HIMR3 0x10B8 +#define REG_HISR3 0x10BC +#define REG_SW_MDIO 0x10C0 +#define REG_SW_FLUSH 0x10C4 + +#define REG_H2C_PKT_READADDR 0x10D0 +#define REG_H2C_PKT_WRITEADDR 0x10D4 + +#define REG_MEM_PWR_CRTL 0x10D8 + +#define REG_FW_DBG0 0x10E0 +#define REG_FW_DBG1 0x10E4 +#define REG_FW_DBG2 0x10E8 +#define REG_FW_DBG3 0x10EC +#define REG_FW_DBG4 0x10F0 +#define REG_FW_DBG5 0x10F4 +#define REG_FW_DBG6 0x10F8 +#define REG_FW_DBG7 0x10FC +#define REG_CR_EXT 0x1100 +#define REG_FWFF 0x1114 + +#define REG_RXFF_PTR_V1 0x1118 +#define REG_RXFF_WTR_V1 0x111C + +#define REG_FE2IMR 0x1120 +#define REG_FE2ISR 0x1124 +#define REG_FE3IMR 0x1128 +#define REG_FE3ISR 0x112C +#define REG_FE4IMR 0x1130 +#define REG_FE4ISR 0x1134 +#define REG_FT1IMR 0x1138 +#define REG_FT1ISR 0x113C +#define REG_SPWR0 0x1140 +#define REG_SPWR1 0x1144 +#define REG_SPWR2 0x1148 +#define REG_SPWR3 0x114C +#define REG_POWSEQ 0x1150 + +#define REG_TC7_CTRL_V1 0x1158 +#define REG_TC8_CTRL_V1 0x115C + +#define REG_FT2IMR 0x11E0 +#define REG_FT2ISR 0x11E4 + +#define REG_MSG2 0x11F0 +#define REG_MSG3 0x11F4 +#define REG_MSG4 0x11F8 +#define REG_MSG5 0x11FC +#define REG_DDMA_CH0SA 0x1200 +#define REG_DDMA_CH0DA 0x1204 +#define REG_DDMA_CH0CTRL 0x1208 +#define REG_DDMA_CH1SA 0x1210 +#define REG_DDMA_CH1DA 0x1214 +#define REG_DDMA_CH1CTRL 0x1218 +#define REG_DDMA_CH2SA 0x1220 +#define REG_DDMA_CH2DA 0x1224 +#define REG_DDMA_CH2CTRL 0x1228 +#define REG_DDMA_CH3SA 0x1230 +#define REG_DDMA_CH3DA 0x1234 +#define REG_DDMA_CH3CTRL 0x1238 +#define REG_DDMA_CH4SA 0x1240 +#define REG_DDMA_CH4DA 0x1244 +#define REG_DDMA_CH4CTRL 0x1248 +#define REG_DDMA_CH5SA 0x1250 +#define REG_DDMA_CH5DA 0x1254 + +#define REG_REG_DDMA_CH5CTRL 0x1258 + +#define REG_DDMA_INT_MSK 0x12E0 +#define REG_DDMA_CHSTATUS 0x12E8 +#define REG_DDMA_CHKSUM 0x12F0 +#define REG_DDMA_MONITOR 0x12FC + +#define REG_STC_INT_CS 0x1300 +#define REG_ST_INT_CFG 0x1304 +#define REG_CMU_DLY_CTRL 0x1310 +#define REG_CMU_DLY_CFG 0x1314 +#define REG_H2CQ_TXBD_DESA 0x1320 +#define REG_H2CQ_TXBD_NUM 0x1328 +#define REG_H2CQ_TXBD_IDX 0x132C +#define REG_H2CQ_CSR 0x1330 + +#define REG_CHANGE_PCIE_SPEED 0x1350 + +#define REG_OLD_DEHANG 0x13F4 + +#define REG_Q0_Q1_INFO 0x1400 +#define REG_Q2_Q3_INFO 0x1404 +#define REG_Q4_Q5_INFO 0x1408 +#define REG_Q6_Q7_INFO 0x140C +#define REG_MGQ_HIQ_INFO 0x1410 +#define REG_CMDQ_BCNQ_INFO 0x1414 +#define REG_USEREG_SETTING 0x1420 +#define REG_AESIV_SETTING 0x1424 +#define REG_BF0_TIME_SETTING 0x1428 +#define REG_BF1_TIME_SETTING 0x142C +#define REG_BF_TIMEOUT_EN 0x1430 +#define REG_MACID_RELEASE0 0x1434 +#define REG_MACID_RELEASE1 0x1438 +#define REG_MACID_RELEASE2 0x143C +#define REG_MACID_RELEASE3 0x1440 +#define REG_MACID_RELEASE_SETTING 0x1444 +#define REG_FAST_EDCA_VOVI_SETTING 0x1448 +#define REG_FAST_EDCA_BEBK_SETTING 0x144C +#define REG_MACID_DROP0 0x1450 +#define REG_MACID_DROP1 0x1454 +#define REG_MACID_DROP2 0x1458 +#define REG_MACID_DROP3 0x145C + +#define REG_R_MACID_RELEASE_SUCCESS_0 0x1460 +#define REG_R_MACID_RELEASE_SUCCESS_1 0x1464 +#define REG_R_MACID_RELEASE_SUCCESS_2 0x1468 +#define REG_R_MACID_RELEASE_SUCCESS_3 0x146C +#define REG_MGG_FIFO_CRTL 0x1470 +#define REG_MGG_FIFO_INT 0x1474 +#define REG_MGG_FIFO_LIFETIME 0x1478 +#define REG_R_MACID_RELEASE_SUCCESS_CLEAR_OFFSET 0x147C + +#define REG_MACID_SHCUT_OFFSET 0x1480 + +#define REG_MU_TX_CTL 0x14C0 +#define REG_MU_STA_GID_VLD 0x14C4 +#define REG_MU_STA_USER_POS_INFO 0x14C8 +#define REG_MU_TRX_DBG_CNT 0x14D0 + +#define REG_CPUMGQ_TX_TIMER 0x1500 +#define REG_PS_TIMER_A 0x1504 +#define REG_PS_TIMER_B 0x1508 +#define REG_PS_TIMER_C 0x150C +#define REG_PS_TIMER_ABC_CPUMGQ_TIMER_CRTL 0x1510 +#define REG_CPUMGQ_TX_TIMER_EARLY 0x1514 +#define REG_PS_TIMER_A_EARLY 0x1515 +#define REG_PS_TIMER_B_EARLY 0x1516 +#define REG_PS_TIMER_C_EARLY 0x1517 + +#define REG_BCN_PSR_RPT2 0x1600 +#define REG_BCN_PSR_RPT3 0x1604 +#define REG_BCN_PSR_RPT4 0x1608 +#define REG_A1_ADDR_MASK 0x160C +#define REG_MACID2 0x1620 +#define REG_BSSID2 0x1628 +#define REG_MACID3 0x1630 +#define REG_BSSID3 0x1638 +#define REG_MACID4 0x1640 +#define REG_BSSID4 0x1648 + +#define REG_NOA_REPORT 0x1650 +#define REG_PWRBIT_SETTING 0x1660 +#define REG_WMAC_MU_BF_OPTION 0x167C + +#define REG_WMAC_MU_ARB 0x167E +#define REG_WMAC_MU_OPTION 0x167F +#define REG_WMAC_MU_BF_CTL 0x1680 + +#define REG_WMAC_MU_BFRPT_PARA 0x1682 + +#define REG_WMAC_ASSOCIATED_MU_BFMEE2 0x1684 +#define REG_WMAC_ASSOCIATED_MU_BFMEE3 0x1686 +#define REG_WMAC_ASSOCIATED_MU_BFMEE4 0x1688 +#define REG_WMAC_ASSOCIATED_MU_BFMEE5 0x168A +#define REG_WMAC_ASSOCIATED_MU_BFMEE6 0x168C +#define REG_WMAC_ASSOCIATED_MU_BFMEE7 0x168E + +#define REG_TRANSMIT_ADDRSS_0 0x16A0 +#define REG_TRANSMIT_ADDRSS_1 0x16A8 +#define REG_TRANSMIT_ADDRSS_2 0x16B0 +#define REG_TRANSMIT_ADDRSS_3 0x16B8 +#define REG_TRANSMIT_ADDRSS_4 0x16C0 + +#define REG_WL2LTECOEX_INDIRECT_ACCESS_CTRL_V1 0x1700 +#define REG_WL2LTECOEX_INDIRECT_ACCESS_WRITE_DATA_V1 0x1704 +#define REG_WL2LTECOEX_INDIRECT_ACCESS_READ_DATA_V1 0x1708 + +/* ----------------------------------------------------- */ +/* */ +/* 0xFB00h ~ 0xFCFFh TX/RX packet buffer affress */ +/* */ +/* ----------------------------------------------------- */ +#define REG_RXPKTBUF_STARTADDR 0xFB00 +#define REG_TXPKTBUF_STARTADDR 0xFC00 + +/* ----------------------------------------------------- */ +/* */ +/* 0xFD00h ~ 0xFDFFh 8051 CPU Local REG */ +/* */ +/* ----------------------------------------------------- */ +#define REG_SYS_CTRL 0xFD00 +#define REG_PONSTS_RPT1 0xFD01 +#define REG_PONSTS_RPT2 0xFD02 +#define REG_PONSTS_RPT3 0xFD03 +#define REG_PONSTS_RPT4 0xFD04 /* 0x84 */ +#define REG_PONSTS_RPT5 0xFD05 /* 0x85 */ +#define REG_8051ERRFLAG 0xFD08 +#define REG_8051ERRFLAG_MASK 0xFD09 +#define REG_TXADDRH 0xFD10 /* Tx Packet High address */ +#define REG_RXADDRH 0xFD11 /* Rx Packet High address */ +#define REG_TXADDRH_EXT 0xFD12 /* 0xFD12[0] : for 8051 access txpktbuf + * high64k as external register + */ + +#define REG_U3_STATE 0xFD48 /* (Read only) + * [7:4] : usb3 changed last state. + * [3:0] : usb3 state + */ + +/* for MAILBOX */ +#define REG_OUTDATA0 0xFD50 +#define REG_OUTDATA1 0xFD54 +#define REG_OUTRDY 0xFD58 /* bit[0] : OutReady, + * bit[1] : OutEmptyIntEn + */ + +#define REG_INDATA0 0xFD60 +#define REG_INDATA1 0xFD64 +#define REG_INRDY 0xFD68 /* bit[0] : InReady, + * bit[1] : InRdyIntEn + */ + +/* MCU ERROR debug REG */ +#define REG_MCUERR_PCLSB 0xFD90 /* PC[7:0] */ +#define REG_MCUERR_PCMSB 0xFD91 /* PC[15:8] */ +#define REG_MCUERR_ACC 0xFD92 +#define REG_MCUERR_B 0xFD93 +#define REG_MCUERR_DPTRLSB 0xFD94 /* DPTR[7:0] */ +#define REG_MCUERR_DPTRMSB 0xFD95 /* DPTR[15:8] */ +#define REG_MCUERR_SP 0xFD96 /* SP[7:0] */ +#define REG_MCUERR_IE 0xFD97 /* IE[7:0] */ +#define REG_MCUERR_EIE 0xFD98 /* EIE[7:0] */ +#define REG_VERA_SIM 0xFD9F +/* 0xFD99~0xFD9F are reserved.. */ + +/* ----------------------------------------------------- */ +/* */ +/* 0xFE00h ~ 0xFEFFh USB Configuration */ +/* */ +/* ----------------------------------------------------- */ + +/* RTS5101 USB Register Definition */ +#define REG_USB_SETUP_DEC_INT 0xFE00 +#define REG_USB_DMACTL 0xFE01 +#define REG_USB_IRQSTAT0 0xFE02 +#define REG_USB_IRQSTAT1 0xFE03 +#define REG_USB_IRQEN0 0xFE04 +#define REG_USB_IRQEN1 0xFE05 +#define REG_USB_AUTOPTRL 0xFE06 +#define REG_USB_AUTOPTRH 0xFE07 +#define REG_USB_AUTODAT 0xFE08 + +#define REG_USB_SCRATCH0 0xFE09 +#define REG_USB_SCRATCH1 0xFE0A +#define REG_USB_SEEPROM 0xFE0B +#define REG_USB_GPIO0 0xFE0C +#define REG_USB_GPIO0DIR 0xFE0D +#define REG_USB_CLKSEL 0xFE0E +#define REG_USB_BOOTCTL 0xFE0F + +#define REG_USB_USBCTL 0xFE10 +#define REG_USB_USBSTAT 0xFE11 +#define REG_USB_DEVADDR 0xFE12 +#define REG_USB_USBTEST 0xFE13 +#define REG_USB_FNUM0 0xFE14 +#define REG_USB_FNUM1 0xFE15 + +#define REG_USB_EP_IDX 0xFE20 +#define REG_USB_EP_CFG 0xFE21 +#define REG_USB_EP_CTL 0xFE22 +#define REG_USB_EP_STAT 0xFE23 +#define REG_USB_EP_IRQ 0xFE24 +#define REG_USB_EP_IRQEN 0xFE25 +#define REG_USB_EP_MAXPKT0 0xFE26 +#define REG_USB_EP_MAXPKT1 0xFE27 +#define REG_USB_EP_DAT 0xFE28 +#define REG_USB_EP_BC0 0xFE29 +#define REG_USB_EP_BC1 0xFE2A +#define REG_USB_EP_TC0 0xFE2B +#define REG_USB_EP_TC1 0xFE2C +#define REG_USB_EP_TC2 0xFE2D +#define REG_USB_EP_CTL2 0xFE2E + +#define REG_USB_INFO 0xFE17 +#define REG_USB_SPECIAL_OPTION 0xFE55 +#define REG_USB_DMA_AGG_TO 0xFE5B +#define REG_USB_AGG_TO 0xFE5C +#define REG_USB_AGG_TH 0xFE5D + +#define REG_USB_VID 0xFE60 +#define REG_USB_PID 0xFE62 +#define REG_USB_OPT 0xFE64 +#define REG_USB_CONFIG 0xFE65 /* RX EP setting. + * 0xFE65 Bit[3:0] : RXQ, + * Bit[7:4] : INTQ + */ + /* TX EP setting. + * 0xFE66 Bit[3:0] : TXQ0, + * Bit[7:4] : TXQ1, + * 0xFE67 Bit[3:0] : TXQ2 + */ +#define REG_USB_PHY_PARA1 0xFE68 /* Bit[7:4]: XCVR_SEN (USB PHY 0xE2[7:4]), + * Bit[3:0]: XCVR_SH (USB PHY 0xE2[3:0]) + */ +#define REG_USB_PHY_PARA2 0xFE69 /* Bit[7:5]: XCVR_BG (USB PHY 0xE3[5:3]), + * Bit[4:2]: XCVR_DR (USB PHY 0xE3[2:0]), + * Bit[1]: SE0_LVL (USB PHY 0xE5[7]), + * Bit[0]: FORCE_XTL_ON (USB PHY 0xE5[1]) + */ +#define REG_USB_PHY_PARA3 0xFE6A /* Bit[7:5]: XCVR_SRC (USB PHY 0xE5[4:2]), + * Bit[4]: LATE_DLLEN (USB PHY 0xF0[4]), + * Bit[3]: HS_LP_MODE (USB PHY 0xF0[3]), + * Bit[2]: UTMI_POS_OUT (USB PHY 0xF1 [7]), + * Bit[1:0]: TX_DELAY (USB PHY 0xF1 [2:1]) + */ +#define REG_USB_PHY_PARA4 0xFE6B /* (USB PHY 0xE7[7:0]) */ +#define REG_USB_OPT2 0xFE6C +#define REG_USB_MAC_ADDR 0xFE70 /* 0xFE70~0xFE75 */ +#define REG_USB_MANUFACTURE_SETTING 0xFE80 /* 0xFE80~0xFE90 Max: 32 bytes*/ +#define REG_USB_PRODUCT_STRING 0xFEA0 /* 0xFEA0~0xFECF Max: 48 bytes*/ +#define REG_USB_SERIAL_NUMBER_STRING 0xFED0 /* 0xFED0~0xFEDF Max: 12 bytes*/ + +#define REG_USB_ALTERNATE_SETTING 0xFE4F +#define REG_USB_INT_BINTERVAL 0xFE6E +#define REG_USB_GPS_EP_CONFIG 0xFE6D + +#endif /* __HALMAC_COM_REG_H__ */ diff --git a/drivers/staging/rtlwifi/halmac/halmac_reg_8822b.h b/drivers/staging/rtlwifi/halmac/halmac_reg_8822b.h new file mode 100644 index 000000000000..4bc59b127412 --- /dev/null +++ b/drivers/staging/rtlwifi/halmac/halmac_reg_8822b.h @@ -0,0 +1,728 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef __INC_HALMAC_REG_8822B_H +#define __INC_HALMAC_REG_8822B_H + +#define REG_SYS_ISO_CTRL_8822B 0x0000 +#define REG_SYS_FUNC_EN_8822B 0x0002 +#define REG_SYS_PW_CTRL_8822B 0x0004 +#define REG_SYS_CLK_CTRL_8822B 0x0008 +#define REG_SYS_EEPROM_CTRL_8822B 0x000A +#define REG_EE_VPD_8822B 0x000C +#define REG_SYS_SWR_CTRL1_8822B 0x0010 +#define REG_SYS_SWR_CTRL2_8822B 0x0014 +#define REG_SYS_SWR_CTRL3_8822B 0x0018 +#define REG_RSV_CTRL_8822B 0x001C +#define REG_RF_CTRL_8822B 0x001F +#define REG_AFE_LDO_CTRL_8822B 0x0020 +#define REG_AFE_CTRL1_8822B 0x0024 +#define REG_AFE_CTRL2_8822B 0x0028 +#define REG_AFE_CTRL3_8822B 0x002C +#define REG_EFUSE_CTRL_8822B 0x0030 +#define REG_LDO_EFUSE_CTRL_8822B 0x0034 +#define REG_PWR_OPTION_CTRL_8822B 0x0038 +#define REG_CAL_TIMER_8822B 0x003C +#define REG_ACLK_MON_8822B 0x003E +#define REG_GPIO_MUXCFG_8822B 0x0040 +#define REG_GPIO_PIN_CTRL_8822B 0x0044 +#define REG_GPIO_INTM_8822B 0x0048 +#define REG_LED_CFG_8822B 0x004C +#define REG_FSIMR_8822B 0x0050 +#define REG_FSISR_8822B 0x0054 +#define REG_HSIMR_8822B 0x0058 +#define REG_HSISR_8822B 0x005C +#define REG_GPIO_EXT_CTRL_8822B 0x0060 +#define REG_PAD_CTRL1_8822B 0x0064 +#define REG_WL_BT_PWR_CTRL_8822B 0x0068 +#define REG_SDM_DEBUG_8822B 0x006C +#define REG_SYS_SDIO_CTRL_8822B 0x0070 +#define REG_HCI_OPT_CTRL_8822B 0x0074 +#define REG_AFE_CTRL4_8822B 0x0078 +#define REG_LDO_SWR_CTRL_8822B 0x007C +#define REG_MCUFW_CTRL_8822B 0x0080 +#define REG_MCU_TST_CFG_8822B 0x0084 +#define REG_HMEBOX_E0_E1_8822B 0x0088 +#define REG_HMEBOX_E2_E3_8822B 0x008C +#define REG_WLLPS_CTRL_8822B 0x0090 +#define REG_AFE_CTRL5_8822B 0x0094 +#define REG_GPIO_DEBOUNCE_CTRL_8822B 0x0098 +#define REG_RPWM2_8822B 0x009C +#define REG_SYSON_FSM_MON_8822B 0x00A0 +#define REG_AFE_CTRL6_8822B 0x00A4 +#define REG_PMC_DBG_CTRL1_8822B 0x00A8 +#define REG_AFE_CTRL7_8822B 0x00AC +#define REG_HIMR0_8822B 0x00B0 +#define REG_HISR0_8822B 0x00B4 +#define REG_HIMR1_8822B 0x00B8 +#define REG_HISR1_8822B 0x00BC +#define REG_DBG_PORT_SEL_8822B 0x00C0 +#define REG_PAD_CTRL2_8822B 0x00C4 +#define REG_PMC_DBG_CTRL2_8822B 0x00CC +#define REG_BIST_CTRL_8822B 0x00D0 +#define REG_BIST_RPT_8822B 0x00D4 +#define REG_MEM_CTRL_8822B 0x00D8 +#define REG_AFE_CTRL8_8822B 0x00DC +#define REG_USB_SIE_INTF_8822B 0x00E0 +#define REG_PCIE_MIO_INTF_8822B 0x00E4 +#define REG_PCIE_MIO_INTD_8822B 0x00E8 +#define REG_WLRF1_8822B 0x00EC +#define REG_SYS_CFG1_8822B 0x00F0 +#define REG_SYS_STATUS1_8822B 0x00F4 +#define REG_SYS_STATUS2_8822B 0x00F8 +#define REG_SYS_CFG2_8822B 0x00FC +#define REG_SYS_CFG3_8822B 0x1000 +#define REG_SYS_CFG4_8822B 0x1034 +#define REG_SYS_CFG5_8822B 0x1070 +#define REG_CPU_DMEM_CON_8822B 0x1080 +#define REG_BOOT_REASON_8822B 0x1088 +#define REG_NFCPAD_CTRL_8822B 0x10A8 +#define REG_HIMR2_8822B 0x10B0 +#define REG_HISR2_8822B 0x10B4 +#define REG_HIMR3_8822B 0x10B8 +#define REG_HISR3_8822B 0x10BC +#define REG_SW_MDIO_8822B 0x10C0 +#define REG_SW_FLUSH_8822B 0x10C4 +#define REG_H2C_PKT_READADDR_8822B 0x10D0 +#define REG_H2C_PKT_WRITEADDR_8822B 0x10D4 +#define REG_MEM_PWR_CRTL_8822B 0x10D8 +#define REG_FW_DBG0_8822B 0x10E0 +#define REG_FW_DBG1_8822B 0x10E4 +#define REG_FW_DBG2_8822B 0x10E8 +#define REG_FW_DBG3_8822B 0x10EC +#define REG_FW_DBG4_8822B 0x10F0 +#define REG_FW_DBG5_8822B 0x10F4 +#define REG_FW_DBG6_8822B 0x10F8 +#define REG_FW_DBG7_8822B 0x10FC +#define REG_CR_8822B 0x0100 +#define REG_PKT_BUFF_ACCESS_CTRL_8822B 0x0106 +#define REG_TSF_CLK_STATE_8822B 0x0108 +#define REG_TXDMA_PQ_MAP_8822B 0x010C +#define REG_TRXFF_BNDY_8822B 0x0114 +#define REG_PTA_I2C_MBOX_8822B 0x0118 +#define REG_RXFF_BNDY_8822B 0x011C +#define REG_FE1IMR_8822B 0x0120 +#define REG_FE1ISR_8822B 0x0124 +#define REG_CPWM_8822B 0x012C +#define REG_FWIMR_8822B 0x0130 +#define REG_FWISR_8822B 0x0134 +#define REG_FTIMR_8822B 0x0138 +#define REG_FTISR_8822B 0x013C +#define REG_PKTBUF_DBG_CTRL_8822B 0x0140 +#define REG_PKTBUF_DBG_DATA_L_8822B 0x0144 +#define REG_PKTBUF_DBG_DATA_H_8822B 0x0148 +#define REG_CPWM2_8822B 0x014C +#define REG_TC0_CTRL_8822B 0x0150 +#define REG_TC1_CTRL_8822B 0x0154 +#define REG_TC2_CTRL_8822B 0x0158 +#define REG_TC3_CTRL_8822B 0x015C +#define REG_TC4_CTRL_8822B 0x0160 +#define REG_TCUNIT_BASE_8822B 0x0164 +#define REG_TC5_CTRL_8822B 0x0168 +#define REG_TC6_CTRL_8822B 0x016C +#define REG_MBIST_FAIL_8822B 0x0170 +#define REG_MBIST_START_PAUSE_8822B 0x0174 +#define REG_MBIST_DONE_8822B 0x0178 +#define REG_MBIST_FAIL_NRML_8822B 0x017C +#define REG_AES_DECRPT_DATA_8822B 0x0180 +#define REG_AES_DECRPT_CFG_8822B 0x0184 +#define REG_TMETER_8822B 0x0190 +#define REG_OSC_32K_CTRL_8822B 0x0194 +#define REG_32K_CAL_REG1_8822B 0x0198 +#define REG_C2HEVT_8822B 0x01A0 +#define REG_SW_DEFINED_PAGE1_8822B 0x01B8 +#define REG_MCUTST_I_8822B 0x01C0 +#define REG_MCUTST_II_8822B 0x01C4 +#define REG_FMETHR_8822B 0x01C8 +#define REG_HMETFR_8822B 0x01CC +#define REG_HMEBOX0_8822B 0x01D0 +#define REG_HMEBOX1_8822B 0x01D4 +#define REG_HMEBOX2_8822B 0x01D8 +#define REG_HMEBOX3_8822B 0x01DC +#define REG_LLT_INIT_8822B 0x01E0 +#define REG_LLT_INIT_ADDR_8822B 0x01E4 +#define REG_BB_ACCESS_CTRL_8822B 0x01E8 +#define REG_BB_ACCESS_DATA_8822B 0x01EC +#define REG_HMEBOX_E0_8822B 0x01F0 +#define REG_HMEBOX_E1_8822B 0x01F4 +#define REG_HMEBOX_E2_8822B 0x01F8 +#define REG_HMEBOX_E3_8822B 0x01FC +#define REG_CR_EXT_8822B 0x1100 +#define REG_FWFF_8822B 0x1114 +#define REG_RXFF_PTR_V1_8822B 0x1118 +#define REG_RXFF_WTR_V1_8822B 0x111C +#define REG_FE2IMR_8822B 0x1120 +#define REG_FE2ISR_8822B 0x1124 +#define REG_FE3IMR_8822B 0x1128 +#define REG_FE3ISR_8822B 0x112C +#define REG_FE4IMR_8822B 0x1130 +#define REG_FE4ISR_8822B 0x1134 +#define REG_FT1IMR_8822B 0x1138 +#define REG_FT1ISR_8822B 0x113C +#define REG_SPWR0_8822B 0x1140 +#define REG_SPWR1_8822B 0x1144 +#define REG_SPWR2_8822B 0x1148 +#define REG_SPWR3_8822B 0x114C +#define REG_POWSEQ_8822B 0x1150 +#define REG_TC7_CTRL_V1_8822B 0x1158 +#define REG_TC8_CTRL_V1_8822B 0x115C +#define REG_FT2IMR_8822B 0x11E0 +#define REG_FT2ISR_8822B 0x11E4 +#define REG_MSG2_8822B 0x11F0 +#define REG_MSG3_8822B 0x11F4 +#define REG_MSG4_8822B 0x11F8 +#define REG_MSG5_8822B 0x11FC +#define REG_FIFOPAGE_CTRL_1_8822B 0x0200 +#define REG_FIFOPAGE_CTRL_2_8822B 0x0204 +#define REG_AUTO_LLT_V1_8822B 0x0208 +#define REG_TXDMA_OFFSET_CHK_8822B 0x020C +#define REG_TXDMA_STATUS_8822B 0x0210 +#define REG_TX_DMA_DBG_8822B 0x0214 +#define REG_TQPNT1_8822B 0x0218 +#define REG_TQPNT2_8822B 0x021C +#define REG_TQPNT3_8822B 0x0220 +#define REG_TQPNT4_8822B 0x0224 +#define REG_RQPN_CTRL_1_8822B 0x0228 +#define REG_RQPN_CTRL_2_8822B 0x022C +#define REG_FIFOPAGE_INFO_1_8822B 0x0230 +#define REG_FIFOPAGE_INFO_2_8822B 0x0234 +#define REG_FIFOPAGE_INFO_3_8822B 0x0238 +#define REG_FIFOPAGE_INFO_4_8822B 0x023C +#define REG_FIFOPAGE_INFO_5_8822B 0x0240 +#define REG_H2C_HEAD_8822B 0x0244 +#define REG_H2C_TAIL_8822B 0x0248 +#define REG_H2C_READ_ADDR_8822B 0x024C +#define REG_H2C_WR_ADDR_8822B 0x0250 +#define REG_H2C_INFO_8822B 0x0254 +#define REG_RXDMA_AGG_PG_TH_8822B 0x0280 +#define REG_RXPKT_NUM_8822B 0x0284 +#define REG_RXDMA_STATUS_8822B 0x0288 +#define REG_RXDMA_DPR_8822B 0x028C +#define REG_RXDMA_MODE_8822B 0x0290 +#define REG_C2H_PKT_8822B 0x0294 +#define REG_FWFF_C2H_8822B 0x0298 +#define REG_FWFF_CTRL_8822B 0x029C +#define REG_FWFF_PKT_INFO_8822B 0x02A0 +#define REG_DDMA_CH0SA_8822B 0x1200 +#define REG_DDMA_CH0DA_8822B 0x1204 +#define REG_DDMA_CH0CTRL_8822B 0x1208 +#define REG_DDMA_CH1SA_8822B 0x1210 +#define REG_DDMA_CH1DA_8822B 0x1214 +#define REG_DDMA_CH1CTRL_8822B 0x1218 +#define REG_DDMA_CH2SA_8822B 0x1220 +#define REG_DDMA_CH2DA_8822B 0x1224 +#define REG_DDMA_CH2CTRL_8822B 0x1228 +#define REG_DDMA_CH3SA_8822B 0x1230 +#define REG_DDMA_CH3DA_8822B 0x1234 +#define REG_DDMA_CH3CTRL_8822B 0x1238 +#define REG_DDMA_CH4SA_8822B 0x1240 +#define REG_DDMA_CH4DA_8822B 0x1244 +#define REG_DDMA_CH4CTRL_8822B 0x1248 +#define REG_DDMA_CH5SA_8822B 0x1250 +#define REG_DDMA_CH5DA_8822B 0x1254 +#define REG_REG_DDMA_CH5CTRL_8822B 0x1258 +#define REG_DDMA_INT_MSK_8822B 0x12E0 +#define REG_DDMA_CHSTATUS_8822B 0x12E8 +#define REG_DDMA_CHKSUM_8822B 0x12F0 +#define REG_DDMA_MONITOR_8822B 0x12FC +#define REG_PCIE_CTRL_8822B 0x0300 +#define REG_INT_MIG_8822B 0x0304 +#define REG_BCNQ_TXBD_DESA_8822B 0x0308 +#define REG_MGQ_TXBD_DESA_8822B 0x0310 +#define REG_VOQ_TXBD_DESA_8822B 0x0318 +#define REG_VIQ_TXBD_DESA_8822B 0x0320 +#define REG_BEQ_TXBD_DESA_8822B 0x0328 +#define REG_BKQ_TXBD_DESA_8822B 0x0330 +#define REG_RXQ_RXBD_DESA_8822B 0x0338 +#define REG_HI0Q_TXBD_DESA_8822B 0x0340 +#define REG_HI1Q_TXBD_DESA_8822B 0x0348 +#define REG_HI2Q_TXBD_DESA_8822B 0x0350 +#define REG_HI3Q_TXBD_DESA_8822B 0x0358 +#define REG_HI4Q_TXBD_DESA_8822B 0x0360 +#define REG_HI5Q_TXBD_DESA_8822B 0x0368 +#define REG_HI6Q_TXBD_DESA_8822B 0x0370 +#define REG_HI7Q_TXBD_DESA_8822B 0x0378 +#define REG_MGQ_TXBD_NUM_8822B 0x0380 +#define REG_RX_RXBD_NUM_8822B 0x0382 +#define REG_VOQ_TXBD_NUM_8822B 0x0384 +#define REG_VIQ_TXBD_NUM_8822B 0x0386 +#define REG_BEQ_TXBD_NUM_8822B 0x0388 +#define REG_BKQ_TXBD_NUM_8822B 0x038A +#define REG_HI0Q_TXBD_NUM_8822B 0x038C +#define REG_HI1Q_TXBD_NUM_8822B 0x038E +#define REG_HI2Q_TXBD_NUM_8822B 0x0390 +#define REG_HI3Q_TXBD_NUM_8822B 0x0392 +#define REG_HI4Q_TXBD_NUM_8822B 0x0394 +#define REG_HI5Q_TXBD_NUM_8822B 0x0396 +#define REG_HI6Q_TXBD_NUM_8822B 0x0398 +#define REG_HI7Q_TXBD_NUM_8822B 0x039A +#define REG_TSFTIMER_HCI_8822B 0x039C +#define REG_BD_RWPTR_CLR_8822B 0x039C +#define REG_VOQ_TXBD_IDX_8822B 0x03A0 +#define REG_VIQ_TXBD_IDX_8822B 0x03A4 +#define REG_BEQ_TXBD_IDX_8822B 0x03A8 +#define REG_BKQ_TXBD_IDX_8822B 0x03AC +#define REG_MGQ_TXBD_IDX_8822B 0x03B0 +#define REG_RXQ_RXBD_IDX_8822B 0x03B4 +#define REG_HI0Q_TXBD_IDX_8822B 0x03B8 +#define REG_HI1Q_TXBD_IDX_8822B 0x03BC +#define REG_HI2Q_TXBD_IDX_8822B 0x03C0 +#define REG_HI3Q_TXBD_IDX_8822B 0x03C4 +#define REG_HI4Q_TXBD_IDX_8822B 0x03C8 +#define REG_HI5Q_TXBD_IDX_8822B 0x03CC +#define REG_HI6Q_TXBD_IDX_8822B 0x03D0 +#define REG_HI7Q_TXBD_IDX_8822B 0x03D4 +#define REG_DBG_SEL_V1_8822B 0x03D8 +#define REG_PCIE_HRPWM1_V1_8822B 0x03D9 +#define REG_PCIE_HCPWM1_V1_8822B 0x03DA +#define REG_PCIE_CTRL2_8822B 0x03DB +#define REG_PCIE_HRPWM2_V1_8822B 0x03DC +#define REG_PCIE_HCPWM2_V1_8822B 0x03DE +#define REG_PCIE_H2C_MSG_V1_8822B 0x03E0 +#define REG_PCIE_C2H_MSG_V1_8822B 0x03E4 +#define REG_DBI_WDATA_V1_8822B 0x03E8 +#define REG_DBI_RDATA_V1_8822B 0x03EC +#define REG_DBI_FLAG_V1_8822B 0x03F0 +#define REG_MDIO_V1_8822B 0x03F4 +#define REG_PCIE_MIX_CFG_8822B 0x03F8 +#define REG_HCI_MIX_CFG_8822B 0x03FC +#define REG_STC_INT_CS_8822B 0x1300 +#define REG_ST_INT_CFG_8822B 0x1304 +#define REG_CMU_DLY_CTRL_8822B 0x1310 +#define REG_CMU_DLY_CFG_8822B 0x1314 +#define REG_H2CQ_TXBD_DESA_8822B 0x1320 +#define REG_H2CQ_TXBD_NUM_8822B 0x1328 +#define REG_H2CQ_TXBD_IDX_8822B 0x132C +#define REG_H2CQ_CSR_8822B 0x1330 +#define REG_CHANGE_PCIE_SPEED_8822B 0x1350 +#define REG_OLD_DEHANG_8822B 0x13F4 +#define REG_Q0_INFO_8822B 0x0400 +#define REG_Q1_INFO_8822B 0x0404 +#define REG_Q2_INFO_8822B 0x0408 +#define REG_Q3_INFO_8822B 0x040C +#define REG_MGQ_INFO_8822B 0x0410 +#define REG_HIQ_INFO_8822B 0x0414 +#define REG_BCNQ_INFO_8822B 0x0418 +#define REG_TXPKT_EMPTY_8822B 0x041A +#define REG_CPU_MGQ_INFO_8822B 0x041C +#define REG_FWHW_TXQ_CTRL_8822B 0x0420 +#define REG_DATAFB_SEL_8822B 0x0423 +#define REG_BCNQ_BDNY_V1_8822B 0x0424 +#define REG_LIFETIME_EN_8822B 0x0426 +#define REG_SPEC_SIFS_8822B 0x0428 +#define REG_RETRY_LIMIT_8822B 0x042A +#define REG_TXBF_CTRL_8822B 0x042C +#define REG_DARFRC_8822B 0x0430 +#define REG_RARFRC_8822B 0x0438 +#define REG_RRSR_8822B 0x0440 +#define REG_ARFR0_8822B 0x0444 +#define REG_ARFR1_V1_8822B 0x044C +#define REG_CCK_CHECK_8822B 0x0454 +#define REG_AMPDU_MAX_TIME_V1_8822B 0x0455 +#define REG_BCNQ1_BDNY_V1_8822B 0x0456 +#define REG_AMPDU_MAX_LENGTH_8822B 0x0458 +#define REG_ACQ_STOP_8822B 0x045C +#define REG_NDPA_RATE_8822B 0x045D +#define REG_TX_HANG_CTRL_8822B 0x045E +#define REG_NDPA_OPT_CTRL_8822B 0x045F +#define REG_RD_RESP_PKT_TH_8822B 0x0463 +#define REG_CMDQ_INFO_8822B 0x0464 +#define REG_Q4_INFO_8822B 0x0468 +#define REG_Q5_INFO_8822B 0x046C +#define REG_Q6_INFO_8822B 0x0470 +#define REG_Q7_INFO_8822B 0x0474 +#define REG_WMAC_LBK_BUF_HD_V1_8822B 0x0478 +#define REG_MGQ_BDNY_V1_8822B 0x047A +#define REG_TXRPT_CTRL_8822B 0x047C +#define REG_INIRTS_RATE_SEL_8822B 0x0480 +#define REG_BASIC_CFEND_RATE_8822B 0x0481 +#define REG_STBC_CFEND_RATE_8822B 0x0482 +#define REG_DATA_SC_8822B 0x0483 +#define REG_MACID_SLEEP3_8822B 0x0484 +#define REG_MACID_SLEEP1_8822B 0x0488 +#define REG_ARFR2_V1_8822B 0x048C +#define REG_ARFR3_V1_8822B 0x0494 +#define REG_ARFR4_8822B 0x049C +#define REG_ARFR5_8822B 0x04A4 +#define REG_TXRPT_START_OFFSET_8822B 0x04AC +#define REG_POWER_STAGE1_8822B 0x04B4 +#define REG_POWER_STAGE2_8822B 0x04B8 +#define REG_SW_AMPDU_BURST_MODE_CTRL_8822B 0x04BC +#define REG_PKT_LIFE_TIME_8822B 0x04C0 +#define REG_STBC_SETTING_8822B 0x04C4 +#define REG_STBC_SETTING2_8822B 0x04C5 +#define REG_QUEUE_CTRL_8822B 0x04C6 +#define REG_SINGLE_AMPDU_CTRL_8822B 0x04C7 +#define REG_PROT_MODE_CTRL_8822B 0x04C8 +#define REG_BAR_MODE_CTRL_8822B 0x04CC +#define REG_RA_TRY_RATE_AGG_LMT_8822B 0x04CF +#define REG_MACID_SLEEP2_8822B 0x04D0 +#define REG_MACID_SLEEP_8822B 0x04D4 +#define REG_HW_SEQ0_8822B 0x04D8 +#define REG_HW_SEQ1_8822B 0x04DA +#define REG_HW_SEQ2_8822B 0x04DC +#define REG_HW_SEQ3_8822B 0x04DE +#define REG_NULL_PKT_STATUS_V1_8822B 0x04E0 +#define REG_PTCL_ERR_STATUS_8822B 0x04E2 +#define REG_NULL_PKT_STATUS_EXTEND_8822B 0x04E3 +#define REG_VIDEO_ENHANCEMENT_FUN_8822B 0x04E4 +#define REG_BT_POLLUTE_PKT_CNT_8822B 0x04E8 +#define REG_PTCL_DBG_8822B 0x04EC +#define REG_CPUMGQ_TIMER_CTRL2_8822B 0x04F4 +#define REG_DUMMY_PAGE4_V1_8822B 0x04FC +#define REG_MOREDATA_8822B 0x04FE +#define REG_Q0_Q1_INFO_8822B 0x1400 +#define REG_Q2_Q3_INFO_8822B 0x1404 +#define REG_Q4_Q5_INFO_8822B 0x1408 +#define REG_Q6_Q7_INFO_8822B 0x140C +#define REG_MGQ_HIQ_INFO_8822B 0x1410 +#define REG_CMDQ_BCNQ_INFO_8822B 0x1414 +#define REG_USEREG_SETTING_8822B 0x1420 +#define REG_AESIV_SETTING_8822B 0x1424 +#define REG_BF0_TIME_SETTING_8822B 0x1428 +#define REG_BF1_TIME_SETTING_8822B 0x142C +#define REG_BF_TIMEOUT_EN_8822B 0x1430 +#define REG_MACID_RELEASE0_8822B 0x1434 +#define REG_MACID_RELEASE1_8822B 0x1438 +#define REG_MACID_RELEASE2_8822B 0x143C +#define REG_MACID_RELEASE3_8822B 0x1440 +#define REG_MACID_RELEASE_SETTING_8822B 0x1444 +#define REG_FAST_EDCA_VOVI_SETTING_8822B 0x1448 +#define REG_FAST_EDCA_BEBK_SETTING_8822B 0x144C +#define REG_MACID_DROP0_8822B 0x1450 +#define REG_MACID_DROP1_8822B 0x1454 +#define REG_MACID_DROP2_8822B 0x1458 +#define REG_MACID_DROP3_8822B 0x145C +#define REG_R_MACID_RELEASE_SUCCESS_0_8822B 0x1460 +#define REG_R_MACID_RELEASE_SUCCESS_1_8822B 0x1464 +#define REG_R_MACID_RELEASE_SUCCESS_2_8822B 0x1468 +#define REG_R_MACID_RELEASE_SUCCESS_3_8822B 0x146C +#define REG_MGG_FIFO_CRTL_8822B 0x1470 +#define REG_MGG_FIFO_INT_8822B 0x1474 +#define REG_MGG_FIFO_LIFETIME_8822B 0x1478 +#define REG_R_MACID_RELEASE_SUCCESS_CLEAR_OFFSET_8822B 0x147C +#define REG_MACID_SHCUT_OFFSET_8822B 0x1480 +#define REG_MU_TX_CTL_8822B 0x14C0 +#define REG_MU_STA_GID_VLD_8822B 0x14C4 +#define REG_MU_STA_USER_POS_INFO_8822B 0x14C8 +#define REG_MU_TRX_DBG_CNT_8822B 0x14D0 +#define REG_EDCA_VO_PARAM_8822B 0x0500 +#define REG_EDCA_VI_PARAM_8822B 0x0504 +#define REG_EDCA_BE_PARAM_8822B 0x0508 +#define REG_EDCA_BK_PARAM_8822B 0x050C +#define REG_BCNTCFG_8822B 0x0510 +#define REG_PIFS_8822B 0x0512 +#define REG_RDG_PIFS_8822B 0x0513 +#define REG_SIFS_8822B 0x0514 +#define REG_TSFTR_SYN_OFFSET_8822B 0x0518 +#define REG_AGGR_BREAK_TIME_8822B 0x051A +#define REG_SLOT_8822B 0x051B +#define REG_TX_PTCL_CTRL_8822B 0x0520 +#define REG_TXPAUSE_8822B 0x0522 +#define REG_DIS_TXREQ_CLR_8822B 0x0523 +#define REG_RD_CTRL_8822B 0x0524 +#define REG_MBSSID_CTRL_8822B 0x0526 +#define REG_P2PPS_CTRL_8822B 0x0527 +#define REG_PKT_LIFETIME_CTRL_8822B 0x0528 +#define REG_P2PPS_SPEC_STATE_8822B 0x052B +#define REG_BAR_TX_CTRL_8822B 0x0530 +#define REG_QUEUE_INCOL_THR_8822B 0x0538 +#define REG_QUEUE_INCOL_EN_8822B 0x053C +#define REG_TBTT_PROHIBIT_8822B 0x0540 +#define REG_P2PPS_STATE_8822B 0x0543 +#define REG_RD_NAV_NXT_8822B 0x0544 +#define REG_NAV_PROT_LEN_8822B 0x0546 +#define REG_BCN_CTRL_8822B 0x0550 +#define REG_BCN_CTRL_CLINT0_8822B 0x0551 +#define REG_MBID_NUM_8822B 0x0552 +#define REG_DUAL_TSF_RST_8822B 0x0553 +#define REG_MBSSID_BCN_SPACE_8822B 0x0554 +#define REG_DRVERLYINT_8822B 0x0558 +#define REG_BCNDMATIM_8822B 0x0559 +#define REG_ATIMWND_8822B 0x055A +#define REG_USTIME_TSF_8822B 0x055C +#define REG_BCN_MAX_ERR_8822B 0x055D +#define REG_RXTSF_OFFSET_CCK_8822B 0x055E +#define REG_RXTSF_OFFSET_OFDM_8822B 0x055F +#define REG_TSFTR_8822B 0x0560 +#define REG_FREERUN_CNT_8822B 0x0568 +#define REG_ATIMWND1_V1_8822B 0x0570 +#define REG_TBTT_PROHIBIT_INFRA_8822B 0x0571 +#define REG_CTWND_8822B 0x0572 +#define REG_BCNIVLCUNT_8822B 0x0573 +#define REG_BCNDROPCTRL_8822B 0x0574 +#define REG_HGQ_TIMEOUT_PERIOD_8822B 0x0575 +#define REG_TXCMD_TIMEOUT_PERIOD_8822B 0x0576 +#define REG_MISC_CTRL_8822B 0x0577 +#define REG_BCN_CTRL_CLINT1_8822B 0x0578 +#define REG_BCN_CTRL_CLINT2_8822B 0x0579 +#define REG_BCN_CTRL_CLINT3_8822B 0x057A +#define REG_EXTEND_CTRL_8822B 0x057B +#define REG_P2PPS1_SPEC_STATE_8822B 0x057C +#define REG_P2PPS1_STATE_8822B 0x057D +#define REG_P2PPS2_SPEC_STATE_8822B 0x057E +#define REG_P2PPS2_STATE_8822B 0x057F +#define REG_PS_TIMER0_8822B 0x0580 +#define REG_PS_TIMER1_8822B 0x0584 +#define REG_PS_TIMER2_8822B 0x0588 +#define REG_TBTT_CTN_AREA_8822B 0x058C +#define REG_FORCE_BCN_IFS_8822B 0x058E +#define REG_TXOP_MIN_8822B 0x0590 +#define REG_PRE_BKF_TIME_8822B 0x0592 +#define REG_CROSS_TXOP_CTRL_8822B 0x0593 +#define REG_ATIMWND2_8822B 0x05A0 +#define REG_ATIMWND3_8822B 0x05A1 +#define REG_ATIMWND4_8822B 0x05A2 +#define REG_ATIMWND5_8822B 0x05A3 +#define REG_ATIMWND6_8822B 0x05A4 +#define REG_ATIMWND7_8822B 0x05A5 +#define REG_ATIMUGT_8822B 0x05A6 +#define REG_HIQ_NO_LMT_EN_8822B 0x05A7 +#define REG_DTIM_COUNTER_ROOT_8822B 0x05A8 +#define REG_DTIM_COUNTER_VAP1_8822B 0x05A9 +#define REG_DTIM_COUNTER_VAP2_8822B 0x05AA +#define REG_DTIM_COUNTER_VAP3_8822B 0x05AB +#define REG_DTIM_COUNTER_VAP4_8822B 0x05AC +#define REG_DTIM_COUNTER_VAP5_8822B 0x05AD +#define REG_DTIM_COUNTER_VAP6_8822B 0x05AE +#define REG_DTIM_COUNTER_VAP7_8822B 0x05AF +#define REG_DIS_ATIM_8822B 0x05B0 +#define REG_EARLY_128US_8822B 0x05B1 +#define REG_P2PPS1_CTRL_8822B 0x05B2 +#define REG_P2PPS2_CTRL_8822B 0x05B3 +#define REG_TIMER0_SRC_SEL_8822B 0x05B4 +#define REG_NOA_UNIT_SEL_8822B 0x05B5 +#define REG_P2POFF_DIS_TXTIME_8822B 0x05B7 +#define REG_MBSSID_BCN_SPACE2_8822B 0x05B8 +#define REG_MBSSID_BCN_SPACE3_8822B 0x05BC +#define REG_ACMHWCTRL_8822B 0x05C0 +#define REG_ACMRSTCTRL_8822B 0x05C1 +#define REG_ACMAVG_8822B 0x05C2 +#define REG_VO_ADMTIME_8822B 0x05C4 +#define REG_VI_ADMTIME_8822B 0x05C6 +#define REG_BE_ADMTIME_8822B 0x05C8 +#define REG_EDCA_RANDOM_GEN_8822B 0x05CC +#define REG_TXCMD_NOA_SEL_8822B 0x05CF +#define REG_NOA_PARAM_8822B 0x05E0 +#define REG_P2P_RST_8822B 0x05F0 +#define REG_SCHEDULER_RST_8822B 0x05F1 +#define REG_SCH_TXCMD_8822B 0x05F8 +#define REG_PAGE5_DUMMY_8822B 0x05FC +#define REG_CPUMGQ_TX_TIMER_8822B 0x1500 +#define REG_PS_TIMER_A_8822B 0x1504 +#define REG_PS_TIMER_B_8822B 0x1508 +#define REG_PS_TIMER_C_8822B 0x150C +#define REG_PS_TIMER_ABC_CPUMGQ_TIMER_CRTL_8822B 0x1510 +#define REG_CPUMGQ_TX_TIMER_EARLY_8822B 0x1514 +#define REG_PS_TIMER_A_EARLY_8822B 0x1515 +#define REG_PS_TIMER_B_EARLY_8822B 0x1516 +#define REG_PS_TIMER_C_EARLY_8822B 0x1517 +#define REG_WMAC_CR_8822B 0x0600 +#define REG_WMAC_FWPKT_CR_8822B 0x0601 +#define REG_BWOPMODE_8822B 0x0603 +#define REG_TCR_8822B 0x0604 +#define REG_RCR_8822B 0x0608 +#define REG_RX_PKT_LIMIT_8822B 0x060C +#define REG_RX_DLK_TIME_8822B 0x060D +#define REG_RX_DRVINFO_SZ_8822B 0x060F +#define REG_MACID_8822B 0x0610 +#define REG_BSSID_8822B 0x0618 +#define REG_MAR_8822B 0x0620 +#define REG_MBIDCAMCFG_1_8822B 0x0628 +#define REG_MBIDCAMCFG_2_8822B 0x062C +#define REG_WMAC_TCR_TSFT_OFS_8822B 0x0630 +#define REG_UDF_THSD_8822B 0x0632 +#define REG_ZLD_NUM_8822B 0x0633 +#define REG_STMP_THSD_8822B 0x0634 +#define REG_WMAC_TXTIMEOUT_8822B 0x0635 +#define REG_MCU_TEST_2_V1_8822B 0x0636 +#define REG_USTIME_EDCA_8822B 0x0638 +#define REG_MAC_SPEC_SIFS_8822B 0x063A +#define REG_RESP_SIFS_CCK_8822B 0x063C +#define REG_RESP_SIFS_OFDM_8822B 0x063E +#define REG_ACKTO_8822B 0x0640 +#define REG_CTS2TO_8822B 0x0641 +#define REG_EIFS_8822B 0x0642 +#define REG_NAV_CTRL_8822B 0x0650 +#define REG_BACAMCMD_8822B 0x0654 +#define REG_BACAMCONTENT_8822B 0x0658 +#define REG_LBDLY_8822B 0x0660 +#define REG_WMAC_BACAM_RPMEN_8822B 0x0661 +#define REG_TX_RX_8822B 0x0662 +#define REG_WMAC_BITMAP_CTL_8822B 0x0663 +#define REG_RXERR_RPT_8822B 0x0664 +#define REG_WMAC_TRXPTCL_CTL_8822B 0x0668 +#define REG_CAMCMD_8822B 0x0670 +#define REG_CAMWRITE_8822B 0x0674 +#define REG_CAMREAD_8822B 0x0678 +#define REG_CAMDBG_8822B 0x067C +#define REG_SECCFG_8822B 0x0680 +#define REG_RXFILTER_CATEGORY_1_8822B 0x0682 +#define REG_RXFILTER_ACTION_1_8822B 0x0683 +#define REG_RXFILTER_CATEGORY_2_8822B 0x0684 +#define REG_RXFILTER_ACTION_2_8822B 0x0685 +#define REG_RXFILTER_CATEGORY_3_8822B 0x0686 +#define REG_RXFILTER_ACTION_3_8822B 0x0687 +#define REG_RXFLTMAP3_8822B 0x0688 +#define REG_RXFLTMAP4_8822B 0x068A +#define REG_RXFLTMAP5_8822B 0x068C +#define REG_RXFLTMAP6_8822B 0x068E +#define REG_WOW_CTRL_8822B 0x0690 +#define REG_NAN_RX_TSF_FILTER_8822B 0x0691 +#define REG_PS_RX_INFO_8822B 0x0692 +#define REG_WMMPS_UAPSD_TID_8822B 0x0693 +#define REG_LPNAV_CTRL_8822B 0x0694 +#define REG_WKFMCAM_CMD_8822B 0x0698 +#define REG_WKFMCAM_RWD_8822B 0x069C +#define REG_RXFLTMAP0_8822B 0x06A0 +#define REG_RXFLTMAP1_8822B 0x06A2 +#define REG_RXFLTMAP_8822B 0x06A4 +#define REG_BCN_PSR_RPT_8822B 0x06A8 +#define REG_FLC_RPC_8822B 0x06AC +#define REG_FLC_RPCT_8822B 0x06AD +#define REG_FLC_PTS_8822B 0x06AE +#define REG_FLC_TRPC_8822B 0x06AF +#define REG_RXPKTMON_CTRL_8822B 0x06B0 +#define REG_STATE_MON_8822B 0x06B4 +#define REG_ERROR_MON_8822B 0x06B8 +#define REG_SEARCH_MACID_8822B 0x06BC +#define REG_BT_COEX_TABLE_8822B 0x06C0 +#define REG_RXCMD_0_8822B 0x06D0 +#define REG_RXCMD_1_8822B 0x06D4 +#define REG_WMAC_RESP_TXINFO_8822B 0x06D8 +#define REG_BBPSF_CTRL_8822B 0x06DC +#define REG_P2P_RX_BCN_NOA_8822B 0x06E0 +#define REG_ASSOCIATED_BFMER0_INFO_8822B 0x06E4 +#define REG_ASSOCIATED_BFMER1_INFO_8822B 0x06EC +#define REG_TX_CSI_RPT_PARAM_BW20_8822B 0x06F4 +#define REG_TX_CSI_RPT_PARAM_BW40_8822B 0x06F8 +#define REG_TX_CSI_RPT_PARAM_BW80_8822B 0x06FC +#define REG_BCN_PSR_RPT2_8822B 0x1600 +#define REG_BCN_PSR_RPT3_8822B 0x1604 +#define REG_BCN_PSR_RPT4_8822B 0x1608 +#define REG_A1_ADDR_MASK_8822B 0x160C +#define REG_MACID2_8822B 0x1620 +#define REG_BSSID2_8822B 0x1628 +#define REG_MACID3_8822B 0x1630 +#define REG_BSSID3_8822B 0x1638 +#define REG_MACID4_8822B 0x1640 +#define REG_BSSID4_8822B 0x1648 +#define REG_NOA_REPORT_8822B 0x1650 +#define REG_PWRBIT_SETTING_8822B 0x1660 +#define REG_WMAC_MU_BF_OPTION_8822B 0x167C +#define REG_WMAC_MU_ARB_8822B 0x167E +#define REG_WMAC_MU_OPTION_8822B 0x167F +#define REG_WMAC_MU_BF_CTL_8822B 0x1680 +#define REG_WMAC_MU_BFRPT_PARA_8822B 0x1682 +#define REG_WMAC_ASSOCIATED_MU_BFMEE2_8822B 0x1684 +#define REG_WMAC_ASSOCIATED_MU_BFMEE3_8822B 0x1686 +#define REG_WMAC_ASSOCIATED_MU_BFMEE4_8822B 0x1688 +#define REG_WMAC_ASSOCIATED_MU_BFMEE5_8822B 0x168A +#define REG_WMAC_ASSOCIATED_MU_BFMEE6_8822B 0x168C +#define REG_WMAC_ASSOCIATED_MU_BFMEE7_8822B 0x168E +#define REG_TRANSMIT_ADDRSS_0_8822B 0x16A0 +#define REG_TRANSMIT_ADDRSS_1_8822B 0x16A8 +#define REG_TRANSMIT_ADDRSS_2_8822B 0x16B0 +#define REG_TRANSMIT_ADDRSS_3_8822B 0x16B8 +#define REG_TRANSMIT_ADDRSS_4_8822B 0x16C0 +#define REG_MACID1_8822B 0x0700 +#define REG_BSSID1_8822B 0x0708 +#define REG_BCN_PSR_RPT1_8822B 0x0710 +#define REG_ASSOCIATED_BFMEE_SEL_8822B 0x0714 +#define REG_SND_PTCL_CTRL_8822B 0x0718 +#define REG_RX_CSI_RPT_INFO_8822B 0x071C +#define REG_NS_ARP_CTRL_8822B 0x0720 +#define REG_NS_ARP_INFO_8822B 0x0724 +#define REG_BEAMFORMING_INFO_NSARP_V1_8822B 0x0728 +#define REG_BEAMFORMING_INFO_NSARP_8822B 0x072C +#define REG_WMAC_RTX_CTX_SUBTYPE_CFG_8822B 0x0750 +#define REG_WMAC_SWAES_CFG_8822B 0x0760 +#define REG_BT_COEX_V2_8822B 0x0762 +#define REG_BT_COEX_8822B 0x0764 +#define REG_WLAN_ACT_MASK_CTRL_8822B 0x0768 +#define REG_BT_COEX_ENHANCED_INTR_CTRL_8822B 0x076E +#define REG_BT_ACT_STATISTICS_8822B 0x0770 +#define REG_BT_STATISTICS_CONTROL_REGISTER_8822B 0x0778 +#define REG_BT_STATUS_REPORT_REGISTER_8822B 0x077C +#define REG_BT_INTERRUPT_CONTROL_REGISTER_8822B 0x0780 +#define REG_WLAN_REPORT_TIME_OUT_CONTROL_REGISTER_8822B 0x0784 +#define REG_BT_ISOLATION_TABLE_REGISTER_REGISTER_8822B 0x0785 +#define REG_BT_INTERRUPT_STATUS_REGISTER_8822B 0x078F +#define REG_BT_TDMA_TIME_REGISTER_8822B 0x0790 +#define REG_BT_ACT_REGISTER_8822B 0x0794 +#define REG_OBFF_CTRL_BASIC_8822B 0x0798 +#define REG_OBFF_CTRL2_TIMER_8822B 0x079C +#define REG_LTR_CTRL_BASIC_8822B 0x07A0 +#define REG_LTR_CTRL2_TIMER_THRESHOLD_8822B 0x07A4 +#define REG_LTR_IDLE_LATENCY_V1_8822B 0x07A8 +#define REG_LTR_ACTIVE_LATENCY_V1_8822B 0x07AC +#define REG_ANTENNA_TRAINING_CONTROL_REGISTER_8822B 0x07B0 +#define REG_WMAC_PKTCNT_RWD_8822B 0x07B8 +#define REG_WMAC_PKTCNT_CTRL_8822B 0x07BC +#define REG_IQ_DUMP_8822B 0x07C0 +#define REG_WMAC_FTM_CTL_8822B 0x07CC +#define REG_WMAC_IQ_MDPK_FUNC_8822B 0x07CE +#define REG_WMAC_OPTION_FUNCTION_8822B 0x07D0 +#define REG_RX_FILTER_FUNCTION_8822B 0x07DA +#define REG_NDP_SIG_8822B 0x07E0 +#define REG_TXCMD_INFO_FOR_RSP_PKT_8822B 0x07E4 +#define REG_RTS_ADDRESS_0_8822B 0x07F0 +#define REG_RTS_ADDRESS_1_8822B 0x07F8 +#define REG__RPFM_MAP1_8822B 0x07FE +#define REG_WL2LTECOEX_INDIRECT_ACCESS_CTRL_V1_8822B 0x1700 +#define REG_WL2LTECOEX_INDIRECT_ACCESS_WRITE_DATA_V1_8822B 0x1704 +#define REG_WL2LTECOEX_INDIRECT_ACCESS_READ_DATA_V1_8822B 0x1708 +#define REG_SDIO_TX_CTRL_8822B 0x10250000 +#define REG_SDIO_HIMR_8822B 0x10250014 +#define REG_SDIO_HISR_8822B 0x10250018 +#define REG_SDIO_RX_REQ_LEN_8822B 0x1025001C +#define REG_SDIO_FREE_TXPG_SEQ_V1_8822B 0x1025001F +#define REG_SDIO_FREE_TXPG_8822B 0x10250020 +#define REG_SDIO_FREE_TXPG2_8822B 0x10250024 +#define REG_SDIO_OQT_FREE_TXPG_V1_8822B 0x10250028 +#define REG_SDIO_HTSFR_INFO_8822B 0x10250030 +#define REG_SDIO_HCPWM1_V2_8822B 0x10250038 +#define REG_SDIO_HCPWM2_V2_8822B 0x1025003A +#define REG_SDIO_INDIRECT_REG_CFG_8822B 0x10250040 +#define REG_SDIO_INDIRECT_REG_DATA_8822B 0x10250044 +#define REG_SDIO_H2C_8822B 0x10250060 +#define REG_SDIO_C2H_8822B 0x10250064 +#define REG_SDIO_HRPWM1_8822B 0x10250080 +#define REG_SDIO_HRPWM2_8822B 0x10250082 +#define REG_SDIO_HPS_CLKR_8822B 0x10250084 +#define REG_SDIO_BUS_CTRL_8822B 0x10250085 +#define REG_SDIO_HSUS_CTRL_8822B 0x10250086 +#define REG_SDIO_RESPONSE_TIMER_8822B 0x10250088 +#define REG_SDIO_CMD_CRC_8822B 0x1025008A +#define REG_SDIO_HSISR_8822B 0x10250090 +#define REG_SDIO_HSIMR_8822B 0x10250091 +#define REG_SDIO_ERR_RPT_8822B 0x102500C0 +#define REG_SDIO_CMD_ERRCNT_8822B 0x102500C1 +#define REG_SDIO_DATA_ERRCNT_8822B 0x102500C2 +#define REG_SDIO_CMD_ERR_CONTENT_8822B 0x102500C4 +#define REG_SDIO_CRC_ERR_IDX_8822B 0x102500C9 +#define REG_SDIO_DATA_CRC_8822B 0x102500CA +#define REG_SDIO_DATA_REPLY_TIME_8822B 0x102500CB + +#endif diff --git a/drivers/staging/rtlwifi/halmac/halmac_rx_bd_chip.h b/drivers/staging/rtlwifi/halmac/halmac_rx_bd_chip.h new file mode 100644 index 000000000000..59ff1fecf73f --- /dev/null +++ b/drivers/staging/rtlwifi/halmac/halmac_rx_bd_chip.h @@ -0,0 +1,48 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef _HALMAC_RX_BD_CHIP_H_ +#define _HALMAC_RX_BD_CHIP_H_ + +/*TXBD_DW0*/ + +#define GET_RX_BD_RXFAIL_8822B(__rx_bd) GET_RX_BD_RXFAIL(__rx_bd) +#define GET_RX_BD_TOTALRXPKTSIZE_8822B(__rx_bd) \ + GET_RX_BD_TOTALRXPKTSIZE(__rx_bd) +#define GET_RX_BD_RXTAG_8822B(__rx_bd) GET_RX_BD_RXTAG(__rx_bd) +#define GET_RX_BD_FS_8822B(__rx_bd) GET_RX_BD_FS(__rx_bd) +#define GET_RX_BD_LS_8822B(__rx_bd) GET_RX_BD_LS(__rx_bd) +#define GET_RX_BD_RXBUFFSIZE_8822B(__rx_bd) GET_RX_BD_RXBUFFSIZE(__rx_bd) + +/*TXBD_DW1*/ + +#define GET_RX_BD_PHYSICAL_ADDR_LOW_8822B(__rx_bd) \ + GET_RX_BD_PHYSICAL_ADDR_LOW(__rx_bd) + +/*TXBD_DW2*/ + +#define GET_RX_BD_PHYSICAL_ADDR_HIGH_8822B(__rx_bd) \ + GET_RX_BD_PHYSICAL_ADDR_HIGH(__rx_bd) + +#endif diff --git a/drivers/staging/rtlwifi/halmac/halmac_rx_bd_nic.h b/drivers/staging/rtlwifi/halmac/halmac_rx_bd_nic.h new file mode 100644 index 000000000000..62817d808fbb --- /dev/null +++ b/drivers/staging/rtlwifi/halmac/halmac_rx_bd_nic.h @@ -0,0 +1,48 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef _HALMAC_RX_BD_NIC_H_ +#define _HALMAC_RX_BD_NIC_H_ + +/*TXBD_DW0*/ + +#define GET_RX_BD_RXFAIL(__rx_bd) LE_BITS_TO_4BYTE(__rx_bd + 0x00, 31, 1) +#define GET_RX_BD_TOTALRXPKTSIZE(__rx_bd) \ + LE_BITS_TO_4BYTE(__rx_bd + 0x00, 16, 13) +#define GET_RX_BD_RXTAG(__rx_bd) LE_BITS_TO_4BYTE(__rx_bd + 0x00, 16, 13) +#define GET_RX_BD_FS(__rx_bd) LE_BITS_TO_4BYTE(__rx_bd + 0x00, 15, 1) +#define GET_RX_BD_LS(__rx_bd) LE_BITS_TO_4BYTE(__rx_bd + 0x00, 14, 1) +#define GET_RX_BD_RXBUFFSIZE(__rx_bd) LE_BITS_TO_4BYTE(__rx_bd + 0x00, 0, 14) + +/*TXBD_DW1*/ + +#define GET_RX_BD_PHYSICAL_ADDR_LOW(__rx_bd) \ + LE_BITS_TO_4BYTE(__rx_bd + 0x04, 0, 32) + +/*TXBD_DW2*/ + +#define GET_RX_BD_PHYSICAL_ADDR_HIGH(__rx_bd) \ + LE_BITS_TO_4BYTE(__rx_bd + 0x08, 0, 32) + +#endif diff --git a/drivers/staging/rtlwifi/halmac/halmac_rx_desc_chip.h b/drivers/staging/rtlwifi/halmac/halmac_rx_desc_chip.h new file mode 100644 index 000000000000..442120a14839 --- /dev/null +++ b/drivers/staging/rtlwifi/halmac/halmac_rx_desc_chip.h @@ -0,0 +1,118 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef _HALMAC_RX_DESC_CHIP_H_ +#define _HALMAC_RX_DESC_CHIP_H_ + +/*RXDESC_WORD0*/ + +#define GET_RX_DESC_EOR_8822B(__rx_desc) GET_RX_DESC_EOR(__rx_desc) +#define GET_RX_DESC_PHYPKTIDC_8822B(__rx_desc) GET_RX_DESC_PHYPKTIDC(__rx_desc) +#define GET_RX_DESC_SWDEC_8822B(__rx_desc) GET_RX_DESC_SWDEC(__rx_desc) +#define GET_RX_DESC_PHYST_8822B(__rx_desc) GET_RX_DESC_PHYST(__rx_desc) +#define GET_RX_DESC_SHIFT_8822B(__rx_desc) GET_RX_DESC_SHIFT(__rx_desc) +#define GET_RX_DESC_QOS_8822B(__rx_desc) GET_RX_DESC_QOS(__rx_desc) +#define GET_RX_DESC_SECURITY_8822B(__rx_desc) GET_RX_DESC_SECURITY(__rx_desc) +#define GET_RX_DESC_DRV_INFO_SIZE_8822B(__rx_desc) \ + GET_RX_DESC_DRV_INFO_SIZE(__rx_desc) +#define GET_RX_DESC_ICV_ERR_8822B(__rx_desc) GET_RX_DESC_ICV_ERR(__rx_desc) +#define GET_RX_DESC_CRC32_8822B(__rx_desc) GET_RX_DESC_CRC32(__rx_desc) +#define GET_RX_DESC_PKT_LEN_8822B(__rx_desc) GET_RX_DESC_PKT_LEN(__rx_desc) + +/*RXDESC_WORD1*/ + +#define GET_RX_DESC_BC_8822B(__rx_desc) GET_RX_DESC_BC(__rx_desc) +#define GET_RX_DESC_MC_8822B(__rx_desc) GET_RX_DESC_MC(__rx_desc) +#define GET_RX_DESC_TY_PE_8822B(__rx_desc) GET_RX_DESC_TY_PE(__rx_desc) +#define GET_RX_DESC_MF_8822B(__rx_desc) GET_RX_DESC_MF(__rx_desc) +#define GET_RX_DESC_MD_8822B(__rx_desc) GET_RX_DESC_MD(__rx_desc) +#define GET_RX_DESC_PWR_8822B(__rx_desc) GET_RX_DESC_PWR(__rx_desc) +#define GET_RX_DESC_PAM_8822B(__rx_desc) GET_RX_DESC_PAM(__rx_desc) +#define GET_RX_DESC_CHK_VLD_8822B(__rx_desc) GET_RX_DESC_CHK_VLD(__rx_desc) +#define GET_RX_DESC_RX_IS_TCP_UDP_8822B(__rx_desc) \ + GET_RX_DESC_RX_IS_TCP_UDP(__rx_desc) +#define GET_RX_DESC_RX_IPV_8822B(__rx_desc) GET_RX_DESC_RX_IPV(__rx_desc) +#define GET_RX_DESC_CHKERR_8822B(__rx_desc) GET_RX_DESC_CHKERR(__rx_desc) +#define GET_RX_DESC_PAGGR_8822B(__rx_desc) GET_RX_DESC_PAGGR(__rx_desc) +#define GET_RX_DESC_RXID_MATCH_8822B(__rx_desc) \ + GET_RX_DESC_RXID_MATCH(__rx_desc) +#define GET_RX_DESC_AMSDU_8822B(__rx_desc) GET_RX_DESC_AMSDU(__rx_desc) +#define GET_RX_DESC_MACID_VLD_8822B(__rx_desc) GET_RX_DESC_MACID_VLD(__rx_desc) +#define GET_RX_DESC_TID_8822B(__rx_desc) GET_RX_DESC_TID(__rx_desc) +#define GET_RX_DESC_EXT_SECTYPE_8822B(__rx_desc) \ + GET_RX_DESC_EXT_SECTYPE(__rx_desc) +#define GET_RX_DESC_MACID_8822B(__rx_desc) GET_RX_DESC_MACID(__rx_desc) + +/*RXDESC_WORD2*/ + +#define GET_RX_DESC_FCS_OK_8822B(__rx_desc) GET_RX_DESC_FCS_OK(__rx_desc) +#define GET_RX_DESC_PPDU_CNT_8822B(__rx_desc) GET_RX_DESC_PPDU_CNT(__rx_desc) +#define GET_RX_DESC_C2H_8822B(__rx_desc) GET_RX_DESC_C2H(__rx_desc) +#define GET_RX_DESC_HWRSVD_8822B(__rx_desc) GET_RX_DESC_HWRSVD(__rx_desc) +#define GET_RX_DESC_WLANHD_IV_LEN_8822B(__rx_desc) \ + GET_RX_DESC_WLANHD_IV_LEN(__rx_desc) +#define GET_RX_DESC_RX_IS_QOS_8822B(__rx_desc) GET_RX_DESC_RX_IS_QOS(__rx_desc) +#define GET_RX_DESC_FRAG_8822B(__rx_desc) GET_RX_DESC_FRAG(__rx_desc) +#define GET_RX_DESC_SEQ_8822B(__rx_desc) GET_RX_DESC_SEQ(__rx_desc) + +/*RXDESC_WORD3*/ + +#define GET_RX_DESC_MAGIC_WAKE_8822B(__rx_desc) \ + GET_RX_DESC_MAGIC_WAKE(__rx_desc) +#define GET_RX_DESC_UNICAST_WAKE_8822B(__rx_desc) \ + GET_RX_DESC_UNICAST_WAKE(__rx_desc) +#define GET_RX_DESC_PATTERN_MATCH_8822B(__rx_desc) \ + GET_RX_DESC_PATTERN_MATCH(__rx_desc) +#define GET_RX_DESC_RXPAYLOAD_MATCH_8822B(__rx_desc) \ + GET_RX_DESC_RXPAYLOAD_MATCH(__rx_desc) +#define GET_RX_DESC_RXPAYLOAD_ID_8822B(__rx_desc) \ + GET_RX_DESC_RXPAYLOAD_ID(__rx_desc) +#define GET_RX_DESC_DMA_AGG_NUM_8822B(__rx_desc) \ + GET_RX_DESC_DMA_AGG_NUM(__rx_desc) +#define GET_RX_DESC_BSSID_FIT_1_0_8822B(__rx_desc) \ + GET_RX_DESC_BSSID_FIT_1_0(__rx_desc) +#define GET_RX_DESC_EOSP_8822B(__rx_desc) GET_RX_DESC_EOSP(__rx_desc) +#define GET_RX_DESC_HTC_8822B(__rx_desc) GET_RX_DESC_HTC(__rx_desc) +#define GET_RX_DESC_BSSID_FIT_4_2_8822B(__rx_desc) \ + GET_RX_DESC_BSSID_FIT_4_2(__rx_desc) +#define GET_RX_DESC_RX_RATE_8822B(__rx_desc) GET_RX_DESC_RX_RATE(__rx_desc) + +/*RXDESC_WORD4*/ + +#define GET_RX_DESC_A1_FIT_8822B(__rx_desc) GET_RX_DESC_A1_FIT(__rx_desc) +#define GET_RX_DESC_MACID_RPT_BUFF_8822B(__rx_desc) \ + GET_RX_DESC_MACID_RPT_BUFF(__rx_desc) +#define GET_RX_DESC_RX_PRE_NDP_VLD_8822B(__rx_desc) \ + GET_RX_DESC_RX_PRE_NDP_VLD(__rx_desc) +#define GET_RX_DESC_RX_SCRAMBLER_8822B(__rx_desc) \ + GET_RX_DESC_RX_SCRAMBLER(__rx_desc) +#define GET_RX_DESC_RX_EOF_8822B(__rx_desc) GET_RX_DESC_RX_EOF(__rx_desc) +#define GET_RX_DESC_PATTERN_IDX_8822B(__rx_desc) \ + GET_RX_DESC_PATTERN_IDX(__rx_desc) + +/*RXDESC_WORD5*/ + +#define GET_RX_DESC_TSFL_8822B(__rx_desc) GET_RX_DESC_TSFL(__rx_desc) + +#endif diff --git a/drivers/staging/rtlwifi/halmac/halmac_rx_desc_nic.h b/drivers/staging/rtlwifi/halmac/halmac_rx_desc_nic.h new file mode 100644 index 000000000000..8256c3605072 --- /dev/null +++ b/drivers/staging/rtlwifi/halmac/halmac_rx_desc_nic.h @@ -0,0 +1,133 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef _HALMAC_RX_DESC_NIC_H_ +#define _HALMAC_RX_DESC_NIC_H_ + +/*RXDESC_WORD0*/ + +#define GET_RX_DESC_EOR(__rx_desc) LE_BITS_TO_4BYTE(__rx_desc + 0x00, 30, 1) +#define GET_RX_DESC_PHYPKTIDC(__rx_desc) \ + LE_BITS_TO_4BYTE(__rx_desc + 0x00, 28, 1) +#define GET_RX_DESC_SWDEC(__rx_desc) LE_BITS_TO_4BYTE(__rx_desc + 0x00, 27, 1) +#define GET_RX_DESC_PHYST(__rx_desc) LE_BITS_TO_4BYTE(__rx_desc + 0x00, 26, 1) +#define GET_RX_DESC_SHIFT(__rx_desc) LE_BITS_TO_4BYTE(__rx_desc + 0x00, 24, 2) +#define GET_RX_DESC_QOS(__rx_desc) LE_BITS_TO_4BYTE(__rx_desc + 0x00, 23, 1) +#define GET_RX_DESC_SECURITY(__rx_desc) \ + LE_BITS_TO_4BYTE(__rx_desc + 0x00, 20, 3) +#define GET_RX_DESC_DRV_INFO_SIZE(__rx_desc) \ + LE_BITS_TO_4BYTE(__rx_desc + 0x00, 16, 4) +#define GET_RX_DESC_ICV_ERR(__rx_desc) LE_BITS_TO_4BYTE(__rx_desc + 0x00, 15, 1) +#define GET_RX_DESC_CRC32(__rx_desc) LE_BITS_TO_4BYTE(__rx_desc + 0x00, 14, 1) +#define GET_RX_DESC_PKT_LEN(__rx_desc) LE_BITS_TO_4BYTE(__rx_desc + 0x00, 0, 14) + +/*RXDESC_WORD1*/ + +#define GET_RX_DESC_BC(__rx_desc) LE_BITS_TO_4BYTE(__rx_desc + 0x04, 31, 1) +#define GET_RX_DESC_MC(__rx_desc) LE_BITS_TO_4BYTE(__rx_desc + 0x04, 30, 1) +#define GET_RX_DESC_TY_PE(__rx_desc) LE_BITS_TO_4BYTE(__rx_desc + 0x04, 28, 2) +#define GET_RX_DESC_MF(__rx_desc) LE_BITS_TO_4BYTE(__rx_desc + 0x04, 27, 1) +#define GET_RX_DESC_MD(__rx_desc) LE_BITS_TO_4BYTE(__rx_desc + 0x04, 26, 1) +#define GET_RX_DESC_PWR(__rx_desc) LE_BITS_TO_4BYTE(__rx_desc + 0x04, 25, 1) +#define GET_RX_DESC_PAM(__rx_desc) LE_BITS_TO_4BYTE(__rx_desc + 0x04, 24, 1) +#define GET_RX_DESC_CHK_VLD(__rx_desc) LE_BITS_TO_4BYTE(__rx_desc + 0x04, 23, 1) +#define GET_RX_DESC_RX_IS_TCP_UDP(__rx_desc) \ + LE_BITS_TO_4BYTE(__rx_desc + 0x04, 22, 1) +#define GET_RX_DESC_RX_IPV(__rx_desc) LE_BITS_TO_4BYTE(__rx_desc + 0x04, 21, 1) +#define GET_RX_DESC_CHKERR(__rx_desc) LE_BITS_TO_4BYTE(__rx_desc + 0x04, 20, 1) +#define GET_RX_DESC_PAGGR(__rx_desc) LE_BITS_TO_4BYTE(__rx_desc + 0x04, 15, 1) +#define GET_RX_DESC_RXID_MATCH(__rx_desc) \ + LE_BITS_TO_4BYTE(__rx_desc + 0x04, 14, 1) +#define GET_RX_DESC_AMSDU(__rx_desc) LE_BITS_TO_4BYTE(__rx_desc + 0x04, 13, 1) +#define GET_RX_DESC_MACID_VLD(__rx_desc) \ + LE_BITS_TO_4BYTE(__rx_desc + 0x04, 12, 1) +#define GET_RX_DESC_TID(__rx_desc) LE_BITS_TO_4BYTE(__rx_desc + 0x04, 8, 4) + +#define GET_RX_DESC_EXT_SECTYPE(__rx_desc) \ + LE_BITS_TO_4BYTE(__rx_desc + 0x04, 7, 1) + +#define GET_RX_DESC_MACID(__rx_desc) LE_BITS_TO_4BYTE(__rx_desc + 0x04, 0, 7) + +/*RXDESC_WORD2*/ + +#define GET_RX_DESC_FCS_OK(__rx_desc) LE_BITS_TO_4BYTE(__rx_desc + 0x08, 31, 1) + +#define GET_RX_DESC_PPDU_CNT(__rx_desc) \ + LE_BITS_TO_4BYTE(__rx_desc + 0x08, 29, 2) + +#define GET_RX_DESC_C2H(__rx_desc) LE_BITS_TO_4BYTE(__rx_desc + 0x08, 28, 1) +#define GET_RX_DESC_HWRSVD(__rx_desc) LE_BITS_TO_4BYTE(__rx_desc + 0x08, 24, 4) +#define GET_RX_DESC_WLANHD_IV_LEN(__rx_desc) \ + LE_BITS_TO_4BYTE(__rx_desc + 0x08, 18, 6) +#define GET_RX_DESC_RX_IS_QOS(__rx_desc) \ + LE_BITS_TO_4BYTE(__rx_desc + 0x08, 16, 1) +#define GET_RX_DESC_FRAG(__rx_desc) LE_BITS_TO_4BYTE(__rx_desc + 0x08, 12, 4) +#define GET_RX_DESC_SEQ(__rx_desc) LE_BITS_TO_4BYTE(__rx_desc + 0x08, 0, 12) + +/*RXDESC_WORD3*/ + +#define GET_RX_DESC_MAGIC_WAKE(__rx_desc) \ + LE_BITS_TO_4BYTE(__rx_desc + 0x0C, 31, 1) +#define GET_RX_DESC_UNICAST_WAKE(__rx_desc) \ + LE_BITS_TO_4BYTE(__rx_desc + 0x0C, 30, 1) +#define GET_RX_DESC_PATTERN_MATCH(__rx_desc) \ + LE_BITS_TO_4BYTE(__rx_desc + 0x0C, 29, 1) + +#define GET_RX_DESC_RXPAYLOAD_MATCH(__rx_desc) \ + LE_BITS_TO_4BYTE(__rx_desc + 0x0C, 28, 1) +#define GET_RX_DESC_RXPAYLOAD_ID(__rx_desc) \ + LE_BITS_TO_4BYTE(__rx_desc + 0x0C, 24, 4) + +#define GET_RX_DESC_DMA_AGG_NUM(__rx_desc) \ + LE_BITS_TO_4BYTE(__rx_desc + 0x0C, 16, 8) +#define GET_RX_DESC_BSSID_FIT_1_0(__rx_desc) \ + LE_BITS_TO_4BYTE(__rx_desc + 0x0C, 12, 2) +#define GET_RX_DESC_EOSP(__rx_desc) LE_BITS_TO_4BYTE(__rx_desc + 0x0C, 11, 1) +#define GET_RX_DESC_HTC(__rx_desc) LE_BITS_TO_4BYTE(__rx_desc + 0x0C, 10, 1) + +#define GET_RX_DESC_BSSID_FIT_4_2(__rx_desc) \ + LE_BITS_TO_4BYTE(__rx_desc + 0x0C, 7, 3) + +#define GET_RX_DESC_RX_RATE(__rx_desc) LE_BITS_TO_4BYTE(__rx_desc + 0x0C, 0, 7) + +/*RXDESC_WORD4*/ + +#define GET_RX_DESC_A1_FIT(__rx_desc) LE_BITS_TO_4BYTE(__rx_desc + 0x10, 24, 5) + +#define GET_RX_DESC_MACID_RPT_BUFF(__rx_desc) \ + LE_BITS_TO_4BYTE(__rx_desc + 0x10, 17, 7) +#define GET_RX_DESC_RX_PRE_NDP_VLD(__rx_desc) \ + LE_BITS_TO_4BYTE(__rx_desc + 0x10, 16, 1) +#define GET_RX_DESC_RX_SCRAMBLER(__rx_desc) \ + LE_BITS_TO_4BYTE(__rx_desc + 0x10, 9, 7) +#define GET_RX_DESC_RX_EOF(__rx_desc) LE_BITS_TO_4BYTE(__rx_desc + 0x10, 8, 1) + +#define GET_RX_DESC_PATTERN_IDX(__rx_desc) \ + LE_BITS_TO_4BYTE(__rx_desc + 0x10, 0, 8) + +/*RXDESC_WORD5*/ + +#define GET_RX_DESC_TSFL(__rx_desc) LE_BITS_TO_4BYTE(__rx_desc + 0x14, 0, 32) + +#endif diff --git a/drivers/staging/rtlwifi/halmac/halmac_sdio_reg.h b/drivers/staging/rtlwifi/halmac/halmac_sdio_reg.h new file mode 100644 index 000000000000..8967699e3784 --- /dev/null +++ b/drivers/staging/rtlwifi/halmac/halmac_sdio_reg.h @@ -0,0 +1,62 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef __HALMAC_SDIO_REG_H__ +#define __HALMAC_SDIO_REG_H__ + +/* SDIO CMD address mapping */ + +#define HALMAC_SDIO_4BYTE_LEN_MASK 0x1FFF +#define HALMAC_SDIO_LOCAL_MSK 0x0FFF +#define HALMAC_WLAN_MAC_REG_MSK 0xFFFF +#define HALMAC_WLAN_IOREG_MSK 0xFFFF + +/* Sdio address for SDIO Local Reg, TRX FIFO, MAC Reg */ +enum halmac_sdio_cmd_addr { + HALMAC_SDIO_CMD_ADDR_SDIO_REG = 0, + HALMAC_SDIO_CMD_ADDR_MAC_REG = 8, + HALMAC_SDIO_CMD_ADDR_TXFF_HIGH = 4, + HALMAC_SDIO_CMD_ADDR_TXFF_LOW = 6, + HALMAC_SDIO_CMD_ADDR_TXFF_NORMAL = 5, + HALMAC_SDIO_CMD_ADDR_TXFF_EXTRA = 7, + HALMAC_SDIO_CMD_ADDR_RXFF = 7, +}; + +/* IO Bus domain address mapping */ +#define SDIO_LOCAL_OFFSET 0x10250000 +#define WLAN_IOREG_OFFSET 0x10260000 +#define FW_FIFO_OFFSET 0x10270000 +#define TX_HIQ_OFFSET 0x10310000 +#define TX_MIQ_OFFSET 0x10320000 +#define TX_LOQ_OFFSET 0x10330000 +#define TX_EXQ_OFFSET 0x10350000 +#define RX_RXOFF_OFFSET 0x10340000 + +/* Get TX WLAN FIFO information in CMD53 addr */ +#define GET_WLAN_TXFF_DEVICE_ID(__cmd53_addr) \ + LE_BITS_TO_4BYTE((u32 *)__cmd53_addr, 13, 4) +#define GET_WLAN_TXFF_PKT_SIZE(__cmd53_addr) \ + (LE_BITS_TO_4BYTE((u32 *)__cmd53_addr, 0, 13) << 2) + +#endif /* __HALMAC_SDIO_REG_H__ */ diff --git a/drivers/staging/rtlwifi/halmac/halmac_tx_bd_chip.h b/drivers/staging/rtlwifi/halmac/halmac_tx_bd_chip.h new file mode 100644 index 000000000000..d5c9da247ca3 --- /dev/null +++ b/drivers/staging/rtlwifi/halmac/halmac_tx_bd_chip.h @@ -0,0 +1,118 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef _HALMAC_TX_BD_CHIP_H_ +#define _HALMAC_TX_BD_CHIP_H_ + +/*TXBD_DW0*/ + +#define SET_TX_BD_OWN_8822B(__tx_bd, __value) SET_TX_BD_OWN(__tx_bd, __value) +#define GET_TX_BD_OWN_8822B(__tx_bd) GET_TX_BD_OWN(__tx_bd) +#define SET_TX_BD_PSB_8822B(__tx_bd, __value) SET_TX_BD_PSB(__tx_bd, __value) +#define GET_TX_BD_PSB_8822B(__tx_bd) GET_TX_BD_PSB(__tx_bd) +#define SET_TX_BD_TX_BUFF_SIZE0_8822B(__tx_bd, __value) \ + SET_TX_BD_TX_BUFF_SIZE0(__tx_bd, __value) +#define GET_TX_BD_TX_BUFF_SIZE0_8822B(__tx_bd) GET_TX_BD_TX_BUFF_SIZE0(__tx_bd) + +/*TXBD_DW1*/ + +#define SET_TX_BD_PHYSICAL_ADDR0_LOW_8822B(__tx_bd, __value) \ + SET_TX_BD_PHYSICAL_ADDR0_LOW(__tx_bd, __value) +#define GET_TX_BD_PHYSICAL_ADDR0_LOW_8822B(__tx_bd) \ + GET_TX_BD_PHYSICAL_ADDR0_LOW(__tx_bd) + +/*TXBD_DW2*/ + +#define SET_TX_BD_PHYSICAL_ADDR0_HIGH_8822B(__tx_bd, __value) \ + SET_TX_BD_PHYSICAL_ADDR0_HIGH(__tx_bd, __value) +#define GET_TX_BD_PHYSICAL_ADDR0_HIGH_8822B(__tx_bd) \ + GET_TX_BD_PHYSICAL_ADDR0_HIGH(__tx_bd) + +/*TXBD_DW4*/ + +#define SET_TX_BD_A1_8822B(__tx_bd, __value) SET_TX_BD_A1(__tx_bd, __value) +#define GET_TX_BD_A1_8822B(__tx_bd) GET_TX_BD_A1(__tx_bd) +#define SET_TX_BD_TX_BUFF_SIZE1_8822B(__tx_bd, __value) \ + SET_TX_BD_TX_BUFF_SIZE1(__tx_bd, __value) +#define GET_TX_BD_TX_BUFF_SIZE1_8822B(__tx_bd) GET_TX_BD_TX_BUFF_SIZE1(__tx_bd) + +/*TXBD_DW5*/ + +#define SET_TX_BD_PHYSICAL_ADDR1_LOW_8822B(__tx_bd, __value) \ + SET_TX_BD_PHYSICAL_ADDR1_LOW(__tx_bd, __value) +#define GET_TX_BD_PHYSICAL_ADDR1_LOW_8822B(__tx_bd) \ + GET_TX_BD_PHYSICAL_ADDR1_LOW(__tx_bd) + +/*TXBD_DW6*/ + +#define SET_TX_BD_PHYSICAL_ADDR1_HIGH_8822B(__tx_bd, __value) \ + SET_TX_BD_PHYSICAL_ADDR1_HIGH(__tx_bd, __value) +#define GET_TX_BD_PHYSICAL_ADDR1_HIGH_8822B(__tx_bd) \ + GET_TX_BD_PHYSICAL_ADDR1_HIGH(__tx_bd) + +/*TXBD_DW8*/ + +#define SET_TX_BD_A2_8822B(__tx_bd, __value) SET_TX_BD_A2(__tx_bd, __value) +#define GET_TX_BD_A2_8822B(__tx_bd) GET_TX_BD_A2(__tx_bd) +#define SET_TX_BD_TX_BUFF_SIZE2_8822B(__tx_bd, __value) \ + SET_TX_BD_TX_BUFF_SIZE2(__tx_bd, __value) +#define GET_TX_BD_TX_BUFF_SIZE2_8822B(__tx_bd) GET_TX_BD_TX_BUFF_SIZE2(__tx_bd) + +/*TXBD_DW9*/ + +#define SET_TX_BD_PHYSICAL_ADDR2_LOW_8822B(__tx_bd, __value) \ + SET_TX_BD_PHYSICAL_ADDR2_LOW(__tx_bd, __value) +#define GET_TX_BD_PHYSICAL_ADDR2_LOW_8822B(__tx_bd) \ + GET_TX_BD_PHYSICAL_ADDR2_LOW(__tx_bd) + +/*TXBD_DW10*/ + +#define SET_TX_BD_PHYSICAL_ADDR2_HIGH_8822B(__tx_bd, __value) \ + SET_TX_BD_PHYSICAL_ADDR2_HIGH(__tx_bd, __value) +#define GET_TX_BD_PHYSICAL_ADDR2_HIGH_8822B(__tx_bd) \ + GET_TX_BD_PHYSICAL_ADDR2_HIGH(__tx_bd) + +/*TXBD_DW12*/ + +#define SET_TX_BD_A3_8822B(__tx_bd, __value) SET_TX_BD_A3(__tx_bd, __value) +#define GET_TX_BD_A3_8822B(__tx_bd) GET_TX_BD_A3(__tx_bd) +#define SET_TX_BD_TX_BUFF_SIZE3_8822B(__tx_bd, __value) \ + SET_TX_BD_TX_BUFF_SIZE3(__tx_bd, __value) +#define GET_TX_BD_TX_BUFF_SIZE3_8822B(__tx_bd) GET_TX_BD_TX_BUFF_SIZE3(__tx_bd) + +/*TXBD_DW13*/ + +#define SET_TX_BD_PHYSICAL_ADDR3_LOW_8822B(__tx_bd, __value) \ + SET_TX_BD_PHYSICAL_ADDR3_LOW(__tx_bd, __value) +#define GET_TX_BD_PHYSICAL_ADDR3_LOW_8822B(__tx_bd) \ + GET_TX_BD_PHYSICAL_ADDR3_LOW(__tx_bd) + +/*TXBD_DW14*/ + +#define SET_TX_BD_PHYSICAL_ADDR3_HIGH_8822B(__tx_bd, __value) \ + SET_TX_BD_PHYSICAL_ADDR3_HIGH(__tx_bd, __value) +#define GET_TX_BD_PHYSICAL_ADDR3_HIGH_8822B(__tx_bd) \ + GET_TX_BD_PHYSICAL_ADDR3_HIGH(__tx_bd) + +#endif diff --git a/drivers/staging/rtlwifi/halmac/halmac_tx_bd_nic.h b/drivers/staging/rtlwifi/halmac/halmac_tx_bd_nic.h new file mode 100644 index 000000000000..43c2261ab083 --- /dev/null +++ b/drivers/staging/rtlwifi/halmac/halmac_tx_bd_nic.h @@ -0,0 +1,123 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef _HALMAC_TX_BD_NIC_H_ +#define _HALMAC_TX_BD_NIC_H_ + +/*TXBD_DW0*/ + +#define SET_TX_BD_OWN(__tx_bd, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_bd + 0x00, 31, 1, __value) +#define GET_TX_BD_OWN(__tx_bd) LE_BITS_TO_4BYTE(__tx_bd + 0x00, 31, 1) +#define SET_TX_BD_PSB(__tx_bd, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_bd + 0x00, 16, 8, __value) +#define GET_TX_BD_PSB(__tx_bd) LE_BITS_TO_4BYTE(__tx_bd + 0x00, 16, 8) +#define SET_TX_BD_TX_BUFF_SIZE0(__tx_bd, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_bd + 0x00, 0, 16, __value) +#define GET_TX_BD_TX_BUFF_SIZE0(__tx_bd) LE_BITS_TO_4BYTE(__tx_bd + 0x00, 0, 16) + +/*TXBD_DW1*/ + +#define SET_TX_BD_PHYSICAL_ADDR0_LOW(__tx_bd, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_bd + 0x04, 0, 32, __value) +#define GET_TX_BD_PHYSICAL_ADDR0_LOW(__tx_bd) \ + LE_BITS_TO_4BYTE(__tx_bd + 0x04, 0, 32) + +/*TXBD_DW2*/ + +#define SET_TX_BD_PHYSICAL_ADDR0_HIGH(__tx_bd, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_bd + 0x08, 0, 32, __value) +#define GET_TX_BD_PHYSICAL_ADDR0_HIGH(__tx_bd) \ + LE_BITS_TO_4BYTE(__tx_bd + 0x08, 0, 32) + +/*TXBD_DW4*/ + +#define SET_TX_BD_A1(__tx_bd, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_bd + 0x10, 31, 1, __value) +#define GET_TX_BD_A1(__tx_bd) LE_BITS_TO_4BYTE(__tx_bd + 0x10, 31, 1) +#define SET_TX_BD_TX_BUFF_SIZE1(__tx_bd, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_bd + 0x10, 0, 16, __value) +#define GET_TX_BD_TX_BUFF_SIZE1(__tx_bd) LE_BITS_TO_4BYTE(__tx_bd + 0x10, 0, 16) + +/*TXBD_DW5*/ + +#define SET_TX_BD_PHYSICAL_ADDR1_LOW(__tx_bd, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_bd + 0x14, 0, 32, __value) +#define GET_TX_BD_PHYSICAL_ADDR1_LOW(__tx_bd) \ + LE_BITS_TO_4BYTE(__tx_bd + 0x14, 0, 32) + +/*TXBD_DW6*/ + +#define SET_TX_BD_PHYSICAL_ADDR1_HIGH(__tx_bd, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_bd + 0x18, 0, 32, __value) +#define GET_TX_BD_PHYSICAL_ADDR1_HIGH(__tx_bd) \ + LE_BITS_TO_4BYTE(__tx_bd + 0x18, 0, 32) + +/*TXBD_DW8*/ + +#define SET_TX_BD_A2(__tx_bd, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_bd + 0x20, 31, 1, __value) +#define GET_TX_BD_A2(__tx_bd) LE_BITS_TO_4BYTE(__tx_bd + 0x20, 31, 1) +#define SET_TX_BD_TX_BUFF_SIZE2(__tx_bd, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_bd + 0x20, 0, 16, __value) +#define GET_TX_BD_TX_BUFF_SIZE2(__tx_bd) LE_BITS_TO_4BYTE(__tx_bd + 0x20, 0, 16) + +/*TXBD_DW9*/ + +#define SET_TX_BD_PHYSICAL_ADDR2_LOW(__tx_bd, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_bd + 0x24, 0, 32, __value) +#define GET_TX_BD_PHYSICAL_ADDR2_LOW(__tx_bd) \ + LE_BITS_TO_4BYTE(__tx_bd + 0x24, 0, 32) + +/*TXBD_DW10*/ + +#define SET_TX_BD_PHYSICAL_ADDR2_HIGH(__tx_bd, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_bd + 0x28, 0, 32, __value) +#define GET_TX_BD_PHYSICAL_ADDR2_HIGH(__tx_bd) \ + LE_BITS_TO_4BYTE(__tx_bd + 0x28, 0, 32) + +/*TXBD_DW12*/ + +#define SET_TX_BD_A3(__tx_bd, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_bd + 0x30, 31, 1, __value) +#define GET_TX_BD_A3(__tx_bd) LE_BITS_TO_4BYTE(__tx_bd + 0x30, 31, 1) +#define SET_TX_BD_TX_BUFF_SIZE3(__tx_bd, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_bd + 0x30, 0, 16, __value) +#define GET_TX_BD_TX_BUFF_SIZE3(__tx_bd) LE_BITS_TO_4BYTE(__tx_bd + 0x30, 0, 16) + +/*TXBD_DW13*/ + +#define SET_TX_BD_PHYSICAL_ADDR3_LOW(__tx_bd, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_bd + 0x34, 0, 32, __value) +#define GET_TX_BD_PHYSICAL_ADDR3_LOW(__tx_bd) \ + LE_BITS_TO_4BYTE(__tx_bd + 0x34, 0, 32) + +/*TXBD_DW14*/ + +#define SET_TX_BD_PHYSICAL_ADDR3_HIGH(__tx_bd, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_bd + 0x38, 0, 32, __value) +#define GET_TX_BD_PHYSICAL_ADDR3_HIGH(__tx_bd) \ + LE_BITS_TO_4BYTE(__tx_bd + 0x38, 0, 32) + +#endif diff --git a/drivers/staging/rtlwifi/halmac/halmac_tx_desc_chip.h b/drivers/staging/rtlwifi/halmac/halmac_tx_desc_chip.h new file mode 100644 index 000000000000..fd1aa39c4bed --- /dev/null +++ b/drivers/staging/rtlwifi/halmac/halmac_tx_desc_chip.h @@ -0,0 +1,444 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef _HALMAC_TX_DESC_CHIP_H_ +#define _HALMAC_TX_DESC_CHIP_H_ + +/*TXDESC_WORD0*/ + +#define SET_TX_DESC_DISQSELSEQ_8822B(__tx_desc, __value) \ + SET_TX_DESC_DISQSELSEQ(__tx_desc, __value) +#define GET_TX_DESC_DISQSELSEQ_8822B(__tx_desc) \ + GET_TX_DESC_DISQSELSEQ(__tx_desc) +#define SET_TX_DESC_GF_8822B(__tx_desc, __value) \ + SET_TX_DESC_GF(__tx_desc, __value) +#define GET_TX_DESC_GF_8822B(__tx_desc) GET_TX_DESC_GF(__tx_desc) +#define SET_TX_DESC_NO_ACM_8822B(__tx_desc, __value) \ + SET_TX_DESC_NO_ACM(__tx_desc, __value) +#define GET_TX_DESC_NO_ACM_8822B(__tx_desc) GET_TX_DESC_NO_ACM(__tx_desc) +#define SET_TX_DESC_BCNPKT_TSF_CTRL_8822B(__tx_desc, __value) \ + SET_TX_DESC_BCNPKT_TSF_CTRL(__tx_desc, __value) +#define GET_TX_DESC_BCNPKT_TSF_CTRL_8822B(__tx_desc) \ + GET_TX_DESC_BCNPKT_TSF_CTRL(__tx_desc) +#define SET_TX_DESC_AMSDU_PAD_EN_8822B(__tx_desc, __value) \ + SET_TX_DESC_AMSDU_PAD_EN(__tx_desc, __value) +#define GET_TX_DESC_AMSDU_PAD_EN_8822B(__tx_desc) \ + GET_TX_DESC_AMSDU_PAD_EN(__tx_desc) +#define SET_TX_DESC_LS_8822B(__tx_desc, __value) \ + SET_TX_DESC_LS(__tx_desc, __value) +#define GET_TX_DESC_LS_8822B(__tx_desc) GET_TX_DESC_LS(__tx_desc) +#define SET_TX_DESC_HTC_8822B(__tx_desc, __value) \ + SET_TX_DESC_HTC(__tx_desc, __value) +#define GET_TX_DESC_HTC_8822B(__tx_desc) GET_TX_DESC_HTC(__tx_desc) +#define SET_TX_DESC_BMC_8822B(__tx_desc, __value) \ + SET_TX_DESC_BMC(__tx_desc, __value) +#define GET_TX_DESC_BMC_8822B(__tx_desc) GET_TX_DESC_BMC(__tx_desc) +#define SET_TX_DESC_OFFSET_8822B(__tx_desc, __value) \ + SET_TX_DESC_OFFSET(__tx_desc, __value) +#define GET_TX_DESC_OFFSET_8822B(__tx_desc) GET_TX_DESC_OFFSET(__tx_desc) +#define SET_TX_DESC_TXPKTSIZE_8822B(__tx_desc, __value) \ + SET_TX_DESC_TXPKTSIZE(__tx_desc, __value) +#define GET_TX_DESC_TXPKTSIZE_8822B(__tx_desc) GET_TX_DESC_TXPKTSIZE(__tx_desc) + +/*TXDESC_WORD1*/ + +#define SET_TX_DESC_MOREDATA_8822B(__tx_desc, __value) \ + SET_TX_DESC_MOREDATA(__tx_desc, __value) +#define GET_TX_DESC_MOREDATA_8822B(__tx_desc) GET_TX_DESC_MOREDATA(__tx_desc) +#define SET_TX_DESC_PKT_OFFSET_8822B(__tx_desc, __value) \ + SET_TX_DESC_PKT_OFFSET(__tx_desc, __value) +#define GET_TX_DESC_PKT_OFFSET_8822B(__tx_desc) \ + GET_TX_DESC_PKT_OFFSET(__tx_desc) +#define SET_TX_DESC_SEC_TYPE_8822B(__tx_desc, __value) \ + SET_TX_DESC_SEC_TYPE(__tx_desc, __value) +#define GET_TX_DESC_SEC_TYPE_8822B(__tx_desc) GET_TX_DESC_SEC_TYPE(__tx_desc) +#define SET_TX_DESC_EN_DESC_ID_8822B(__tx_desc, __value) \ + SET_TX_DESC_EN_DESC_ID(__tx_desc, __value) +#define GET_TX_DESC_EN_DESC_ID_8822B(__tx_desc) \ + GET_TX_DESC_EN_DESC_ID(__tx_desc) +#define SET_TX_DESC_RATE_ID_8822B(__tx_desc, __value) \ + SET_TX_DESC_RATE_ID(__tx_desc, __value) +#define GET_TX_DESC_RATE_ID_8822B(__tx_desc) GET_TX_DESC_RATE_ID(__tx_desc) +#define SET_TX_DESC_PIFS_8822B(__tx_desc, __value) \ + SET_TX_DESC_PIFS(__tx_desc, __value) +#define GET_TX_DESC_PIFS_8822B(__tx_desc) GET_TX_DESC_PIFS(__tx_desc) +#define SET_TX_DESC_LSIG_TXOP_EN_8822B(__tx_desc, __value) \ + SET_TX_DESC_LSIG_TXOP_EN(__tx_desc, __value) +#define GET_TX_DESC_LSIG_TXOP_EN_8822B(__tx_desc) \ + GET_TX_DESC_LSIG_TXOP_EN(__tx_desc) +#define SET_TX_DESC_RD_NAV_EXT_8822B(__tx_desc, __value) \ + SET_TX_DESC_RD_NAV_EXT(__tx_desc, __value) +#define GET_TX_DESC_RD_NAV_EXT_8822B(__tx_desc) \ + GET_TX_DESC_RD_NAV_EXT(__tx_desc) +#define SET_TX_DESC_QSEL_8822B(__tx_desc, __value) \ + SET_TX_DESC_QSEL(__tx_desc, __value) +#define GET_TX_DESC_QSEL_8822B(__tx_desc) GET_TX_DESC_QSEL(__tx_desc) +#define SET_TX_DESC_MACID_8822B(__tx_desc, __value) \ + SET_TX_DESC_MACID(__tx_desc, __value) +#define GET_TX_DESC_MACID_8822B(__tx_desc) GET_TX_DESC_MACID(__tx_desc) + +/*TXDESC_WORD2*/ + +#define SET_TX_DESC_HW_AES_IV_8822B(__tx_desc, __value) \ + SET_TX_DESC_HW_AES_IV(__tx_desc, __value) +#define GET_TX_DESC_HW_AES_IV_8822B(__tx_desc) GET_TX_DESC_HW_AES_IV(__tx_desc) +#define SET_TX_DESC_FTM_EN_8822B(__tx_desc, __value) \ + SET_TX_DESC_FTM_EN(__tx_desc, __value) +#define GET_TX_DESC_FTM_EN_8822B(__tx_desc) GET_TX_DESC_FTM_EN(__tx_desc) +#define SET_TX_DESC_G_ID_8822B(__tx_desc, __value) \ + SET_TX_DESC_G_ID(__tx_desc, __value) +#define GET_TX_DESC_G_ID_8822B(__tx_desc) GET_TX_DESC_G_ID(__tx_desc) +#define SET_TX_DESC_BT_NULL_8822B(__tx_desc, __value) \ + SET_TX_DESC_BT_NULL(__tx_desc, __value) +#define GET_TX_DESC_BT_NULL_8822B(__tx_desc) GET_TX_DESC_BT_NULL(__tx_desc) +#define SET_TX_DESC_AMPDU_DENSITY_8822B(__tx_desc, __value) \ + SET_TX_DESC_AMPDU_DENSITY(__tx_desc, __value) +#define GET_TX_DESC_AMPDU_DENSITY_8822B(__tx_desc) \ + GET_TX_DESC_AMPDU_DENSITY(__tx_desc) +#define SET_TX_DESC_SPE_RPT_8822B(__tx_desc, __value) \ + SET_TX_DESC_SPE_RPT(__tx_desc, __value) +#define GET_TX_DESC_SPE_RPT_8822B(__tx_desc) GET_TX_DESC_SPE_RPT(__tx_desc) +#define SET_TX_DESC_RAW_8822B(__tx_desc, __value) \ + SET_TX_DESC_RAW(__tx_desc, __value) +#define GET_TX_DESC_RAW_8822B(__tx_desc) GET_TX_DESC_RAW(__tx_desc) +#define SET_TX_DESC_MOREFRAG_8822B(__tx_desc, __value) \ + SET_TX_DESC_MOREFRAG(__tx_desc, __value) +#define GET_TX_DESC_MOREFRAG_8822B(__tx_desc) GET_TX_DESC_MOREFRAG(__tx_desc) +#define SET_TX_DESC_BK_8822B(__tx_desc, __value) \ + SET_TX_DESC_BK(__tx_desc, __value) +#define GET_TX_DESC_BK_8822B(__tx_desc) GET_TX_DESC_BK(__tx_desc) +#define SET_TX_DESC_NULL_1_8822B(__tx_desc, __value) \ + SET_TX_DESC_NULL_1(__tx_desc, __value) +#define GET_TX_DESC_NULL_1_8822B(__tx_desc) GET_TX_DESC_NULL_1(__tx_desc) +#define SET_TX_DESC_NULL_0_8822B(__tx_desc, __value) \ + SET_TX_DESC_NULL_0(__tx_desc, __value) +#define GET_TX_DESC_NULL_0_8822B(__tx_desc) GET_TX_DESC_NULL_0(__tx_desc) +#define SET_TX_DESC_RDG_EN_8822B(__tx_desc, __value) \ + SET_TX_DESC_RDG_EN(__tx_desc, __value) +#define GET_TX_DESC_RDG_EN_8822B(__tx_desc) GET_TX_DESC_RDG_EN(__tx_desc) +#define SET_TX_DESC_AGG_EN_8822B(__tx_desc, __value) \ + SET_TX_DESC_AGG_EN(__tx_desc, __value) +#define GET_TX_DESC_AGG_EN_8822B(__tx_desc) GET_TX_DESC_AGG_EN(__tx_desc) +#define SET_TX_DESC_CCA_RTS_8822B(__tx_desc, __value) \ + SET_TX_DESC_CCA_RTS(__tx_desc, __value) +#define GET_TX_DESC_CCA_RTS_8822B(__tx_desc) GET_TX_DESC_CCA_RTS(__tx_desc) +#define SET_TX_DESC_TRI_FRAME_8822B(__tx_desc, __value) \ + SET_TX_DESC_TRI_FRAME(__tx_desc, __value) +#define GET_TX_DESC_TRI_FRAME_8822B(__tx_desc) GET_TX_DESC_TRI_FRAME(__tx_desc) +#define SET_TX_DESC_P_AID_8822B(__tx_desc, __value) \ + SET_TX_DESC_P_AID(__tx_desc, __value) +#define GET_TX_DESC_P_AID_8822B(__tx_desc) GET_TX_DESC_P_AID(__tx_desc) + +/*TXDESC_WORD3*/ + +#define SET_TX_DESC_AMPDU_MAX_TIME_8822B(__tx_desc, __value) \ + SET_TX_DESC_AMPDU_MAX_TIME(__tx_desc, __value) +#define GET_TX_DESC_AMPDU_MAX_TIME_8822B(__tx_desc) \ + GET_TX_DESC_AMPDU_MAX_TIME(__tx_desc) +#define SET_TX_DESC_NDPA_8822B(__tx_desc, __value) \ + SET_TX_DESC_NDPA(__tx_desc, __value) +#define GET_TX_DESC_NDPA_8822B(__tx_desc) GET_TX_DESC_NDPA(__tx_desc) +#define SET_TX_DESC_MAX_AGG_NUM_8822B(__tx_desc, __value) \ + SET_TX_DESC_MAX_AGG_NUM(__tx_desc, __value) +#define GET_TX_DESC_MAX_AGG_NUM_8822B(__tx_desc) \ + GET_TX_DESC_MAX_AGG_NUM(__tx_desc) +#define SET_TX_DESC_USE_MAX_TIME_EN_8822B(__tx_desc, __value) \ + SET_TX_DESC_USE_MAX_TIME_EN(__tx_desc, __value) +#define GET_TX_DESC_USE_MAX_TIME_EN_8822B(__tx_desc) \ + GET_TX_DESC_USE_MAX_TIME_EN(__tx_desc) +#define SET_TX_DESC_NAVUSEHDR_8822B(__tx_desc, __value) \ + SET_TX_DESC_NAVUSEHDR(__tx_desc, __value) +#define GET_TX_DESC_NAVUSEHDR_8822B(__tx_desc) GET_TX_DESC_NAVUSEHDR(__tx_desc) +#define SET_TX_DESC_CHK_EN_8822B(__tx_desc, __value) \ + SET_TX_DESC_CHK_EN(__tx_desc, __value) +#define GET_TX_DESC_CHK_EN_8822B(__tx_desc) GET_TX_DESC_CHK_EN(__tx_desc) +#define SET_TX_DESC_HW_RTS_EN_8822B(__tx_desc, __value) \ + SET_TX_DESC_HW_RTS_EN(__tx_desc, __value) +#define GET_TX_DESC_HW_RTS_EN_8822B(__tx_desc) GET_TX_DESC_HW_RTS_EN(__tx_desc) +#define SET_TX_DESC_RTSEN_8822B(__tx_desc, __value) \ + SET_TX_DESC_RTSEN(__tx_desc, __value) +#define GET_TX_DESC_RTSEN_8822B(__tx_desc) GET_TX_DESC_RTSEN(__tx_desc) +#define SET_TX_DESC_CTS2SELF_8822B(__tx_desc, __value) \ + SET_TX_DESC_CTS2SELF(__tx_desc, __value) +#define GET_TX_DESC_CTS2SELF_8822B(__tx_desc) GET_TX_DESC_CTS2SELF(__tx_desc) +#define SET_TX_DESC_DISDATAFB_8822B(__tx_desc, __value) \ + SET_TX_DESC_DISDATAFB(__tx_desc, __value) +#define GET_TX_DESC_DISDATAFB_8822B(__tx_desc) GET_TX_DESC_DISDATAFB(__tx_desc) +#define SET_TX_DESC_DISRTSFB_8822B(__tx_desc, __value) \ + SET_TX_DESC_DISRTSFB(__tx_desc, __value) +#define GET_TX_DESC_DISRTSFB_8822B(__tx_desc) GET_TX_DESC_DISRTSFB(__tx_desc) +#define SET_TX_DESC_USE_RATE_8822B(__tx_desc, __value) \ + SET_TX_DESC_USE_RATE(__tx_desc, __value) +#define GET_TX_DESC_USE_RATE_8822B(__tx_desc) GET_TX_DESC_USE_RATE(__tx_desc) +#define SET_TX_DESC_HW_SSN_SEL_8822B(__tx_desc, __value) \ + SET_TX_DESC_HW_SSN_SEL(__tx_desc, __value) +#define GET_TX_DESC_HW_SSN_SEL_8822B(__tx_desc) \ + GET_TX_DESC_HW_SSN_SEL(__tx_desc) +#define SET_TX_DESC_WHEADER_LEN_8822B(__tx_desc, __value) \ + SET_TX_DESC_WHEADER_LEN(__tx_desc, __value) +#define GET_TX_DESC_WHEADER_LEN_8822B(__tx_desc) \ + GET_TX_DESC_WHEADER_LEN(__tx_desc) + +/*TXDESC_WORD4*/ + +#define SET_TX_DESC_PCTS_MASK_IDX_8822B(__tx_desc, __value) \ + SET_TX_DESC_PCTS_MASK_IDX(__tx_desc, __value) +#define GET_TX_DESC_PCTS_MASK_IDX_8822B(__tx_desc) \ + GET_TX_DESC_PCTS_MASK_IDX(__tx_desc) +#define SET_TX_DESC_PCTS_EN_8822B(__tx_desc, __value) \ + SET_TX_DESC_PCTS_EN(__tx_desc, __value) +#define GET_TX_DESC_PCTS_EN_8822B(__tx_desc) GET_TX_DESC_PCTS_EN(__tx_desc) +#define SET_TX_DESC_RTSRATE_8822B(__tx_desc, __value) \ + SET_TX_DESC_RTSRATE(__tx_desc, __value) +#define GET_TX_DESC_RTSRATE_8822B(__tx_desc) GET_TX_DESC_RTSRATE(__tx_desc) +#define SET_TX_DESC_RTS_DATA_RTY_LMT_8822B(__tx_desc, __value) \ + SET_TX_DESC_RTS_DATA_RTY_LMT(__tx_desc, __value) +#define GET_TX_DESC_RTS_DATA_RTY_LMT_8822B(__tx_desc) \ + GET_TX_DESC_RTS_DATA_RTY_LMT(__tx_desc) +#define SET_TX_DESC_RTY_LMT_EN_8822B(__tx_desc, __value) \ + SET_TX_DESC_RTY_LMT_EN(__tx_desc, __value) +#define GET_TX_DESC_RTY_LMT_EN_8822B(__tx_desc) \ + GET_TX_DESC_RTY_LMT_EN(__tx_desc) +#define SET_TX_DESC_RTS_RTY_LOWEST_RATE_8822B(__tx_desc, __value) \ + SET_TX_DESC_RTS_RTY_LOWEST_RATE(__tx_desc, __value) +#define GET_TX_DESC_RTS_RTY_LOWEST_RATE_8822B(__tx_desc) \ + GET_TX_DESC_RTS_RTY_LOWEST_RATE(__tx_desc) +#define SET_TX_DESC_DATA_RTY_LOWEST_RATE_8822B(__tx_desc, __value) \ + SET_TX_DESC_DATA_RTY_LOWEST_RATE(__tx_desc, __value) +#define GET_TX_DESC_DATA_RTY_LOWEST_RATE_8822B(__tx_desc) \ + GET_TX_DESC_DATA_RTY_LOWEST_RATE(__tx_desc) +#define SET_TX_DESC_TRY_RATE_8822B(__tx_desc, __value) \ + SET_TX_DESC_TRY_RATE(__tx_desc, __value) +#define GET_TX_DESC_TRY_RATE_8822B(__tx_desc) GET_TX_DESC_TRY_RATE(__tx_desc) +#define SET_TX_DESC_DATARATE_8822B(__tx_desc, __value) \ + SET_TX_DESC_DATARATE(__tx_desc, __value) +#define GET_TX_DESC_DATARATE_8822B(__tx_desc) GET_TX_DESC_DATARATE(__tx_desc) + +/*TXDESC_WORD5*/ + +#define SET_TX_DESC_POLLUTED_8822B(__tx_desc, __value) \ + SET_TX_DESC_POLLUTED(__tx_desc, __value) +#define GET_TX_DESC_POLLUTED_8822B(__tx_desc) GET_TX_DESC_POLLUTED(__tx_desc) +#define SET_TX_DESC_TXPWR_OFSET_8822B(__tx_desc, __value) \ + SET_TX_DESC_TXPWR_OFSET(__tx_desc, __value) +#define GET_TX_DESC_TXPWR_OFSET_8822B(__tx_desc) \ + GET_TX_DESC_TXPWR_OFSET(__tx_desc) +#define SET_TX_DESC_TX_ANT_8822B(__tx_desc, __value) \ + SET_TX_DESC_TX_ANT(__tx_desc, __value) +#define GET_TX_DESC_TX_ANT_8822B(__tx_desc) GET_TX_DESC_TX_ANT(__tx_desc) +#define SET_TX_DESC_PORT_ID_8822B(__tx_desc, __value) \ + SET_TX_DESC_PORT_ID(__tx_desc, __value) +#define GET_TX_DESC_PORT_ID_8822B(__tx_desc) GET_TX_DESC_PORT_ID(__tx_desc) +#define SET_TX_DESC_MULTIPLE_PORT_8822B(__tx_desc, __value) \ + SET_TX_DESC_MULTIPLE_PORT(__tx_desc, __value) +#define GET_TX_DESC_MULTIPLE_PORT_8822B(__tx_desc) \ + GET_TX_DESC_MULTIPLE_PORT(__tx_desc) +#define SET_TX_DESC_SIGNALING_TAPKT_EN_8822B(__tx_desc, __value) \ + SET_TX_DESC_SIGNALING_TAPKT_EN(__tx_desc, __value) +#define GET_TX_DESC_SIGNALING_TAPKT_EN_8822B(__tx_desc) \ + GET_TX_DESC_SIGNALING_TAPKT_EN(__tx_desc) +#define SET_TX_DESC_RTS_SC_8822B(__tx_desc, __value) \ + SET_TX_DESC_RTS_SC(__tx_desc, __value) +#define GET_TX_DESC_RTS_SC_8822B(__tx_desc) GET_TX_DESC_RTS_SC(__tx_desc) +#define SET_TX_DESC_RTS_SHORT_8822B(__tx_desc, __value) \ + SET_TX_DESC_RTS_SHORT(__tx_desc, __value) +#define GET_TX_DESC_RTS_SHORT_8822B(__tx_desc) GET_TX_DESC_RTS_SHORT(__tx_desc) +#define SET_TX_DESC_VCS_STBC_8822B(__tx_desc, __value) \ + SET_TX_DESC_VCS_STBC(__tx_desc, __value) +#define GET_TX_DESC_VCS_STBC_8822B(__tx_desc) GET_TX_DESC_VCS_STBC(__tx_desc) +#define SET_TX_DESC_DATA_STBC_8822B(__tx_desc, __value) \ + SET_TX_DESC_DATA_STBC(__tx_desc, __value) +#define GET_TX_DESC_DATA_STBC_8822B(__tx_desc) GET_TX_DESC_DATA_STBC(__tx_desc) +#define SET_TX_DESC_DATA_LDPC_8822B(__tx_desc, __value) \ + SET_TX_DESC_DATA_LDPC(__tx_desc, __value) +#define GET_TX_DESC_DATA_LDPC_8822B(__tx_desc) GET_TX_DESC_DATA_LDPC(__tx_desc) +#define SET_TX_DESC_DATA_BW_8822B(__tx_desc, __value) \ + SET_TX_DESC_DATA_BW(__tx_desc, __value) +#define GET_TX_DESC_DATA_BW_8822B(__tx_desc) GET_TX_DESC_DATA_BW(__tx_desc) +#define SET_TX_DESC_DATA_SHORT_8822B(__tx_desc, __value) \ + SET_TX_DESC_DATA_SHORT(__tx_desc, __value) +#define GET_TX_DESC_DATA_SHORT_8822B(__tx_desc) \ + GET_TX_DESC_DATA_SHORT(__tx_desc) +#define SET_TX_DESC_DATA_SC_8822B(__tx_desc, __value) \ + SET_TX_DESC_DATA_SC(__tx_desc, __value) +#define GET_TX_DESC_DATA_SC_8822B(__tx_desc) GET_TX_DESC_DATA_SC(__tx_desc) + +/*TXDESC_WORD6*/ + +#define SET_TX_DESC_ANTSEL_D_8822B(__tx_desc, __value) \ + SET_TX_DESC_ANTSEL_D(__tx_desc, __value) +#define GET_TX_DESC_ANTSEL_D_8822B(__tx_desc) GET_TX_DESC_ANTSEL_D(__tx_desc) +#define SET_TX_DESC_ANT_MAPD_8822B(__tx_desc, __value) \ + SET_TX_DESC_ANT_MAPD(__tx_desc, __value) +#define GET_TX_DESC_ANT_MAPD_8822B(__tx_desc) GET_TX_DESC_ANT_MAPD(__tx_desc) +#define SET_TX_DESC_ANT_MAPC_8822B(__tx_desc, __value) \ + SET_TX_DESC_ANT_MAPC(__tx_desc, __value) +#define GET_TX_DESC_ANT_MAPC_8822B(__tx_desc) GET_TX_DESC_ANT_MAPC(__tx_desc) +#define SET_TX_DESC_ANT_MAPB_8822B(__tx_desc, __value) \ + SET_TX_DESC_ANT_MAPB(__tx_desc, __value) +#define GET_TX_DESC_ANT_MAPB_8822B(__tx_desc) GET_TX_DESC_ANT_MAPB(__tx_desc) +#define SET_TX_DESC_ANT_MAPA_8822B(__tx_desc, __value) \ + SET_TX_DESC_ANT_MAPA(__tx_desc, __value) +#define GET_TX_DESC_ANT_MAPA_8822B(__tx_desc) GET_TX_DESC_ANT_MAPA(__tx_desc) +#define SET_TX_DESC_ANTSEL_C_8822B(__tx_desc, __value) \ + SET_TX_DESC_ANTSEL_C(__tx_desc, __value) +#define GET_TX_DESC_ANTSEL_C_8822B(__tx_desc) GET_TX_DESC_ANTSEL_C(__tx_desc) +#define SET_TX_DESC_ANTSEL_B_8822B(__tx_desc, __value) \ + SET_TX_DESC_ANTSEL_B(__tx_desc, __value) +#define GET_TX_DESC_ANTSEL_B_8822B(__tx_desc) GET_TX_DESC_ANTSEL_B(__tx_desc) +#define SET_TX_DESC_ANTSEL_A_8822B(__tx_desc, __value) \ + SET_TX_DESC_ANTSEL_A(__tx_desc, __value) +#define GET_TX_DESC_ANTSEL_A_8822B(__tx_desc) GET_TX_DESC_ANTSEL_A(__tx_desc) +#define SET_TX_DESC_MBSSID_8822B(__tx_desc, __value) \ + SET_TX_DESC_MBSSID(__tx_desc, __value) +#define GET_TX_DESC_MBSSID_8822B(__tx_desc) GET_TX_DESC_MBSSID(__tx_desc) +#define SET_TX_DESC_SW_DEFINE_8822B(__tx_desc, __value) \ + SET_TX_DESC_SW_DEFINE(__tx_desc, __value) +#define GET_TX_DESC_SW_DEFINE_8822B(__tx_desc) GET_TX_DESC_SW_DEFINE(__tx_desc) + +/*TXDESC_WORD7*/ + +#define SET_TX_DESC_DMA_TXAGG_NUM_8822B(__tx_desc, __value) \ + SET_TX_DESC_DMA_TXAGG_NUM(__tx_desc, __value) +#define GET_TX_DESC_DMA_TXAGG_NUM_8822B(__tx_desc) \ + GET_TX_DESC_DMA_TXAGG_NUM(__tx_desc) +#define SET_TX_DESC_FINAL_DATA_RATE_8822B(__tx_desc, __value) \ + SET_TX_DESC_FINAL_DATA_RATE(__tx_desc, __value) +#define GET_TX_DESC_FINAL_DATA_RATE_8822B(__tx_desc) \ + GET_TX_DESC_FINAL_DATA_RATE(__tx_desc) +#define SET_TX_DESC_NTX_MAP_8822B(__tx_desc, __value) \ + SET_TX_DESC_NTX_MAP(__tx_desc, __value) +#define GET_TX_DESC_NTX_MAP_8822B(__tx_desc) GET_TX_DESC_NTX_MAP(__tx_desc) +#define SET_TX_DESC_TX_BUFF_SIZE_8822B(__tx_desc, __value) \ + SET_TX_DESC_TX_BUFF_SIZE(__tx_desc, __value) +#define GET_TX_DESC_TX_BUFF_SIZE_8822B(__tx_desc) \ + GET_TX_DESC_TX_BUFF_SIZE(__tx_desc) +#define SET_TX_DESC_TXDESC_CHECKSUM_8822B(__tx_desc, __value) \ + SET_TX_DESC_TXDESC_CHECKSUM(__tx_desc, __value) +#define GET_TX_DESC_TXDESC_CHECKSUM_8822B(__tx_desc) \ + GET_TX_DESC_TXDESC_CHECKSUM(__tx_desc) +#define SET_TX_DESC_TIMESTAMP_8822B(__tx_desc, __value) \ + SET_TX_DESC_TIMESTAMP(__tx_desc, __value) +#define GET_TX_DESC_TIMESTAMP_8822B(__tx_desc) GET_TX_DESC_TIMESTAMP(__tx_desc) + +/*TXDESC_WORD8*/ + +#define SET_TX_DESC_TXWIFI_CP_8822B(__tx_desc, __value) \ + SET_TX_DESC_TXWIFI_CP(__tx_desc, __value) +#define GET_TX_DESC_TXWIFI_CP_8822B(__tx_desc) GET_TX_DESC_TXWIFI_CP(__tx_desc) +#define SET_TX_DESC_MAC_CP_8822B(__tx_desc, __value) \ + SET_TX_DESC_MAC_CP(__tx_desc, __value) +#define GET_TX_DESC_MAC_CP_8822B(__tx_desc) GET_TX_DESC_MAC_CP(__tx_desc) +#define SET_TX_DESC_STW_PKTRE_DIS_8822B(__tx_desc, __value) \ + SET_TX_DESC_STW_PKTRE_DIS(__tx_desc, __value) +#define GET_TX_DESC_STW_PKTRE_DIS_8822B(__tx_desc) \ + GET_TX_DESC_STW_PKTRE_DIS(__tx_desc) +#define SET_TX_DESC_STW_RB_DIS_8822B(__tx_desc, __value) \ + SET_TX_DESC_STW_RB_DIS(__tx_desc, __value) +#define GET_TX_DESC_STW_RB_DIS_8822B(__tx_desc) \ + GET_TX_DESC_STW_RB_DIS(__tx_desc) +#define SET_TX_DESC_STW_RATE_DIS_8822B(__tx_desc, __value) \ + SET_TX_DESC_STW_RATE_DIS(__tx_desc, __value) +#define GET_TX_DESC_STW_RATE_DIS_8822B(__tx_desc) \ + GET_TX_DESC_STW_RATE_DIS(__tx_desc) +#define SET_TX_DESC_STW_ANT_DIS_8822B(__tx_desc, __value) \ + SET_TX_DESC_STW_ANT_DIS(__tx_desc, __value) +#define GET_TX_DESC_STW_ANT_DIS_8822B(__tx_desc) \ + GET_TX_DESC_STW_ANT_DIS(__tx_desc) +#define SET_TX_DESC_STW_EN_8822B(__tx_desc, __value) \ + SET_TX_DESC_STW_EN(__tx_desc, __value) +#define GET_TX_DESC_STW_EN_8822B(__tx_desc) GET_TX_DESC_STW_EN(__tx_desc) +#define SET_TX_DESC_SMH_EN_8822B(__tx_desc, __value) \ + SET_TX_DESC_SMH_EN(__tx_desc, __value) +#define GET_TX_DESC_SMH_EN_8822B(__tx_desc) GET_TX_DESC_SMH_EN(__tx_desc) +#define SET_TX_DESC_TAILPAGE_L_8822B(__tx_desc, __value) \ + SET_TX_DESC_TAILPAGE_L(__tx_desc, __value) +#define GET_TX_DESC_TAILPAGE_L_8822B(__tx_desc) \ + GET_TX_DESC_TAILPAGE_L(__tx_desc) +#define SET_TX_DESC_SDIO_DMASEQ_8822B(__tx_desc, __value) \ + SET_TX_DESC_SDIO_DMASEQ(__tx_desc, __value) +#define GET_TX_DESC_SDIO_DMASEQ_8822B(__tx_desc) \ + GET_TX_DESC_SDIO_DMASEQ(__tx_desc) +#define SET_TX_DESC_NEXTHEADPAGE_L_8822B(__tx_desc, __value) \ + SET_TX_DESC_NEXTHEADPAGE_L(__tx_desc, __value) +#define GET_TX_DESC_NEXTHEADPAGE_L_8822B(__tx_desc) \ + GET_TX_DESC_NEXTHEADPAGE_L(__tx_desc) +#define SET_TX_DESC_EN_HWSEQ_8822B(__tx_desc, __value) \ + SET_TX_DESC_EN_HWSEQ(__tx_desc, __value) +#define GET_TX_DESC_EN_HWSEQ_8822B(__tx_desc) GET_TX_DESC_EN_HWSEQ(__tx_desc) +#define SET_TX_DESC_EN_HWEXSEQ_8822B(__tx_desc, __value) \ + SET_TX_DESC_EN_HWEXSEQ(__tx_desc, __value) +#define GET_TX_DESC_EN_HWEXSEQ_8822B(__tx_desc) \ + GET_TX_DESC_EN_HWEXSEQ(__tx_desc) +#define SET_TX_DESC_DATA_RC_8822B(__tx_desc, __value) \ + SET_TX_DESC_DATA_RC(__tx_desc, __value) +#define GET_TX_DESC_DATA_RC_8822B(__tx_desc) GET_TX_DESC_DATA_RC(__tx_desc) +#define SET_TX_DESC_BAR_RTY_TH_8822B(__tx_desc, __value) \ + SET_TX_DESC_BAR_RTY_TH(__tx_desc, __value) +#define GET_TX_DESC_BAR_RTY_TH_8822B(__tx_desc) \ + GET_TX_DESC_BAR_RTY_TH(__tx_desc) +#define SET_TX_DESC_RTS_RC_8822B(__tx_desc, __value) \ + SET_TX_DESC_RTS_RC(__tx_desc, __value) +#define GET_TX_DESC_RTS_RC_8822B(__tx_desc) GET_TX_DESC_RTS_RC(__tx_desc) + +/*TXDESC_WORD9*/ + +#define SET_TX_DESC_TAILPAGE_H_8822B(__tx_desc, __value) \ + SET_TX_DESC_TAILPAGE_H(__tx_desc, __value) +#define GET_TX_DESC_TAILPAGE_H_8822B(__tx_desc) \ + GET_TX_DESC_TAILPAGE_H(__tx_desc) +#define SET_TX_DESC_NEXTHEADPAGE_H_8822B(__tx_desc, __value) \ + SET_TX_DESC_NEXTHEADPAGE_H(__tx_desc, __value) +#define GET_TX_DESC_NEXTHEADPAGE_H_8822B(__tx_desc) \ + GET_TX_DESC_NEXTHEADPAGE_H(__tx_desc) +#define SET_TX_DESC_SW_SEQ_8822B(__tx_desc, __value) \ + SET_TX_DESC_SW_SEQ(__tx_desc, __value) +#define GET_TX_DESC_SW_SEQ_8822B(__tx_desc) GET_TX_DESC_SW_SEQ(__tx_desc) +#define SET_TX_DESC_TXBF_PATH_8822B(__tx_desc, __value) \ + SET_TX_DESC_TXBF_PATH(__tx_desc, __value) +#define GET_TX_DESC_TXBF_PATH_8822B(__tx_desc) GET_TX_DESC_TXBF_PATH(__tx_desc) +#define SET_TX_DESC_PADDING_LEN_8822B(__tx_desc, __value) \ + SET_TX_DESC_PADDING_LEN(__tx_desc, __value) +#define GET_TX_DESC_PADDING_LEN_8822B(__tx_desc) \ + GET_TX_DESC_PADDING_LEN(__tx_desc) +#define SET_TX_DESC_GROUP_BIT_IE_OFFSET_8822B(__tx_desc, __value) \ + SET_TX_DESC_GROUP_BIT_IE_OFFSET(__tx_desc, __value) +#define GET_TX_DESC_GROUP_BIT_IE_OFFSET_8822B(__tx_desc) \ + GET_TX_DESC_GROUP_BIT_IE_OFFSET(__tx_desc) + +/*WORD10*/ + +#define SET_TX_DESC_MU_DATARATE_8822B(__tx_desc, __value) \ + SET_TX_DESC_MU_DATARATE(__tx_desc, __value) +#define GET_TX_DESC_MU_DATARATE_8822B(__tx_desc) \ + GET_TX_DESC_MU_DATARATE(__tx_desc) +#define SET_TX_DESC_MU_RC_8822B(__tx_desc, __value) \ + SET_TX_DESC_MU_RC(__tx_desc, __value) +#define GET_TX_DESC_MU_RC_8822B(__tx_desc) GET_TX_DESC_MU_RC(__tx_desc) +#define SET_TX_DESC_SND_PKT_SEL_8822B(__tx_desc, __value) \ + SET_TX_DESC_SND_PKT_SEL(__tx_desc, __value) +#define GET_TX_DESC_SND_PKT_SEL_8822B(__tx_desc) \ + GET_TX_DESC_SND_PKT_SEL(__tx_desc) + +#endif diff --git a/drivers/staging/rtlwifi/halmac/halmac_tx_desc_nic.h b/drivers/staging/rtlwifi/halmac/halmac_tx_desc_nic.h new file mode 100644 index 000000000000..02177c5faddf --- /dev/null +++ b/drivers/staging/rtlwifi/halmac/halmac_tx_desc_nic.h @@ -0,0 +1,506 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef _HALMAC_TX_DESC_NIC_H_ +#define _HALMAC_TX_DESC_NIC_H_ + +/*TXDESC_WORD0*/ + +#define SET_TX_DESC_DISQSELSEQ(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x00, 31, 1, __value) +#define GET_TX_DESC_DISQSELSEQ(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x00, 31, 1) + +#define SET_TX_DESC_GF(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x00, 30, 1, __value) +#define GET_TX_DESC_GF(__tx_desc) LE_BITS_TO_4BYTE(__tx_desc + 0x00, 30, 1) +#define SET_TX_DESC_NO_ACM(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x00, 29, 1, __value) +#define GET_TX_DESC_NO_ACM(__tx_desc) LE_BITS_TO_4BYTE(__tx_desc + 0x00, 29, 1) + +#define SET_TX_DESC_BCNPKT_TSF_CTRL(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x00, 28, 1, __value) +#define GET_TX_DESC_BCNPKT_TSF_CTRL(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x00, 28, 1) + +#define SET_TX_DESC_AMSDU_PAD_EN(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x00, 27, 1, __value) +#define GET_TX_DESC_AMSDU_PAD_EN(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x00, 27, 1) + +#define SET_TX_DESC_LS(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x00, 26, 1, __value) +#define GET_TX_DESC_LS(__tx_desc) LE_BITS_TO_4BYTE(__tx_desc + 0x00, 26, 1) +#define SET_TX_DESC_HTC(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x00, 25, 1, __value) +#define GET_TX_DESC_HTC(__tx_desc) LE_BITS_TO_4BYTE(__tx_desc + 0x00, 25, 1) +#define SET_TX_DESC_BMC(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x00, 24, 1, __value) +#define GET_TX_DESC_BMC(__tx_desc) LE_BITS_TO_4BYTE(__tx_desc + 0x00, 24, 1) +#define SET_TX_DESC_OFFSET(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x00, 16, 8, __value) +#define GET_TX_DESC_OFFSET(__tx_desc) LE_BITS_TO_4BYTE(__tx_desc + 0x00, 16, 8) +#define SET_TX_DESC_TXPKTSIZE(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x00, 0, 16, __value) +#define GET_TX_DESC_TXPKTSIZE(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x00, 0, 16) + +/*TXDESC_WORD1*/ + +#define SET_TX_DESC_MOREDATA(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x04, 29, 1, __value) +#define GET_TX_DESC_MOREDATA(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x04, 29, 1) +#define SET_TX_DESC_PKT_OFFSET(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x04, 24, 5, __value) +#define GET_TX_DESC_PKT_OFFSET(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x04, 24, 5) +#define SET_TX_DESC_SEC_TYPE(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x04, 22, 2, __value) +#define GET_TX_DESC_SEC_TYPE(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x04, 22, 2) +#define SET_TX_DESC_EN_DESC_ID(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x04, 21, 1, __value) +#define GET_TX_DESC_EN_DESC_ID(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x04, 21, 1) +#define SET_TX_DESC_RATE_ID(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x04, 16, 5, __value) +#define GET_TX_DESC_RATE_ID(__tx_desc) LE_BITS_TO_4BYTE(__tx_desc + 0x04, 16, 5) +#define SET_TX_DESC_PIFS(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x04, 15, 1, __value) +#define GET_TX_DESC_PIFS(__tx_desc) LE_BITS_TO_4BYTE(__tx_desc + 0x04, 15, 1) +#define SET_TX_DESC_LSIG_TXOP_EN(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x04, 14, 1, __value) +#define GET_TX_DESC_LSIG_TXOP_EN(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x04, 14, 1) +#define SET_TX_DESC_RD_NAV_EXT(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x04, 13, 1, __value) +#define GET_TX_DESC_RD_NAV_EXT(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x04, 13, 1) +#define SET_TX_DESC_QSEL(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x04, 8, 5, __value) +#define GET_TX_DESC_QSEL(__tx_desc) LE_BITS_TO_4BYTE(__tx_desc + 0x04, 8, 5) +#define SET_TX_DESC_MACID(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x04, 0, 7, __value) +#define GET_TX_DESC_MACID(__tx_desc) LE_BITS_TO_4BYTE(__tx_desc + 0x04, 0, 7) + +/*TXDESC_WORD2*/ + +#define SET_TX_DESC_HW_AES_IV(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x08, 31, 1, __value) +#define GET_TX_DESC_HW_AES_IV(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x08, 31, 1) + +#define SET_TX_DESC_FTM_EN(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x08, 30, 1, __value) +#define GET_TX_DESC_FTM_EN(__tx_desc) LE_BITS_TO_4BYTE(__tx_desc + 0x08, 30, 1) + +#define SET_TX_DESC_G_ID(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x08, 24, 6, __value) +#define GET_TX_DESC_G_ID(__tx_desc) LE_BITS_TO_4BYTE(__tx_desc + 0x08, 24, 6) +#define SET_TX_DESC_BT_NULL(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x08, 23, 1, __value) +#define GET_TX_DESC_BT_NULL(__tx_desc) LE_BITS_TO_4BYTE(__tx_desc + 0x08, 23, 1) +#define SET_TX_DESC_AMPDU_DENSITY(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x08, 20, 3, __value) +#define GET_TX_DESC_AMPDU_DENSITY(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x08, 20, 3) +#ifdef SET_TX_DESC_SPE_RPT +#undef SET_TX_DESC_SPE_RPT +#endif +#define SET_TX_DESC_SPE_RPT(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x08, 19, 1, __value) +#define GET_TX_DESC_SPE_RPT(__tx_desc) LE_BITS_TO_4BYTE(__tx_desc + 0x08, 19, 1) +#define SET_TX_DESC_RAW(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x08, 18, 1, __value) +#define GET_TX_DESC_RAW(__tx_desc) LE_BITS_TO_4BYTE(__tx_desc + 0x08, 18, 1) +#define SET_TX_DESC_MOREFRAG(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x08, 17, 1, __value) +#define GET_TX_DESC_MOREFRAG(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x08, 17, 1) +#define SET_TX_DESC_BK(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x08, 16, 1, __value) +#define GET_TX_DESC_BK(__tx_desc) LE_BITS_TO_4BYTE(__tx_desc + 0x08, 16, 1) +#define SET_TX_DESC_NULL_1(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x08, 15, 1, __value) +#define GET_TX_DESC_NULL_1(__tx_desc) LE_BITS_TO_4BYTE(__tx_desc + 0x08, 15, 1) +#define SET_TX_DESC_NULL_0(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x08, 14, 1, __value) +#define GET_TX_DESC_NULL_0(__tx_desc) LE_BITS_TO_4BYTE(__tx_desc + 0x08, 14, 1) +#define SET_TX_DESC_RDG_EN(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x08, 13, 1, __value) +#define GET_TX_DESC_RDG_EN(__tx_desc) LE_BITS_TO_4BYTE(__tx_desc + 0x08, 13, 1) +#define SET_TX_DESC_AGG_EN(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x08, 12, 1, __value) +#define GET_TX_DESC_AGG_EN(__tx_desc) LE_BITS_TO_4BYTE(__tx_desc + 0x08, 12, 1) +#define SET_TX_DESC_CCA_RTS(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x08, 10, 2, __value) +#define GET_TX_DESC_CCA_RTS(__tx_desc) LE_BITS_TO_4BYTE(__tx_desc + 0x08, 10, 2) + +#define SET_TX_DESC_TRI_FRAME(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x08, 9, 1, __value) +#define GET_TX_DESC_TRI_FRAME(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x08, 9, 1) + +#define SET_TX_DESC_P_AID(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x08, 0, 9, __value) +#define GET_TX_DESC_P_AID(__tx_desc) LE_BITS_TO_4BYTE(__tx_desc + 0x08, 0, 9) + +/*TXDESC_WORD3*/ + +#define SET_TX_DESC_AMPDU_MAX_TIME(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x0C, 24, 8, __value) +#define GET_TX_DESC_AMPDU_MAX_TIME(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x0C, 24, 8) +#define SET_TX_DESC_NDPA(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x0C, 22, 2, __value) +#define GET_TX_DESC_NDPA(__tx_desc) LE_BITS_TO_4BYTE(__tx_desc + 0x0C, 22, 2) +#define SET_TX_DESC_MAX_AGG_NUM(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x0C, 17, 5, __value) +#define GET_TX_DESC_MAX_AGG_NUM(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x0C, 17, 5) +#define SET_TX_DESC_USE_MAX_TIME_EN(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x0C, 16, 1, __value) +#define GET_TX_DESC_USE_MAX_TIME_EN(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x0C, 16, 1) +#define SET_TX_DESC_NAVUSEHDR(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x0C, 15, 1, __value) +#define GET_TX_DESC_NAVUSEHDR(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x0C, 15, 1) + +#define SET_TX_DESC_CHK_EN(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x0C, 14, 1, __value) +#define GET_TX_DESC_CHK_EN(__tx_desc) LE_BITS_TO_4BYTE(__tx_desc + 0x0C, 14, 1) + +#define SET_TX_DESC_HW_RTS_EN(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x0C, 13, 1, __value) +#define GET_TX_DESC_HW_RTS_EN(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x0C, 13, 1) +#define SET_TX_DESC_RTSEN(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x0C, 12, 1, __value) +#define GET_TX_DESC_RTSEN(__tx_desc) LE_BITS_TO_4BYTE(__tx_desc + 0x0C, 12, 1) +#define SET_TX_DESC_CTS2SELF(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x0C, 11, 1, __value) +#define GET_TX_DESC_CTS2SELF(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x0C, 11, 1) +#define SET_TX_DESC_DISDATAFB(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x0C, 10, 1, __value) +#define GET_TX_DESC_DISDATAFB(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x0C, 10, 1) +#define SET_TX_DESC_DISRTSFB(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x0C, 9, 1, __value) +#define GET_TX_DESC_DISRTSFB(__tx_desc) LE_BITS_TO_4BYTE(__tx_desc + 0x0C, 9, 1) +#define SET_TX_DESC_USE_RATE(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x0C, 8, 1, __value) +#define GET_TX_DESC_USE_RATE(__tx_desc) LE_BITS_TO_4BYTE(__tx_desc + 0x0C, 8, 1) +#define SET_TX_DESC_HW_SSN_SEL(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x0C, 6, 2, __value) +#define GET_TX_DESC_HW_SSN_SEL(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x0C, 6, 2) + +#define SET_TX_DESC_WHEADER_LEN(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x0C, 0, 5, __value) +#define GET_TX_DESC_WHEADER_LEN(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x0C, 0, 5) + +/*TXDESC_WORD4*/ + +#define SET_TX_DESC_PCTS_MASK_IDX(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x10, 30, 2, __value) +#define GET_TX_DESC_PCTS_MASK_IDX(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x10, 30, 2) +#define SET_TX_DESC_PCTS_EN(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x10, 29, 1, __value) +#define GET_TX_DESC_PCTS_EN(__tx_desc) LE_BITS_TO_4BYTE(__tx_desc + 0x10, 29, 1) +#define SET_TX_DESC_RTSRATE(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x10, 24, 5, __value) +#define GET_TX_DESC_RTSRATE(__tx_desc) LE_BITS_TO_4BYTE(__tx_desc + 0x10, 24, 5) +#define SET_TX_DESC_RTS_DATA_RTY_LMT(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x10, 18, 6, __value) +#define GET_TX_DESC_RTS_DATA_RTY_LMT(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x10, 18, 6) +#define SET_TX_DESC_RTY_LMT_EN(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x10, 17, 1, __value) +#define GET_TX_DESC_RTY_LMT_EN(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x10, 17, 1) +#define SET_TX_DESC_RTS_RTY_LOWEST_RATE(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x10, 13, 4, __value) +#define GET_TX_DESC_RTS_RTY_LOWEST_RATE(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x10, 13, 4) +#define SET_TX_DESC_DATA_RTY_LOWEST_RATE(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x10, 8, 5, __value) +#define GET_TX_DESC_DATA_RTY_LOWEST_RATE(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x10, 8, 5) +#define SET_TX_DESC_TRY_RATE(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x10, 7, 1, __value) +#define GET_TX_DESC_TRY_RATE(__tx_desc) LE_BITS_TO_4BYTE(__tx_desc + 0x10, 7, 1) +#define SET_TX_DESC_DATARATE(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x10, 0, 7, __value) +#define GET_TX_DESC_DATARATE(__tx_desc) LE_BITS_TO_4BYTE(__tx_desc + 0x10, 0, 7) + +/*TXDESC_WORD5*/ + +#define SET_TX_DESC_POLLUTED(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x14, 31, 1, __value) +#define GET_TX_DESC_POLLUTED(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x14, 31, 1) + +#define SET_TX_DESC_TXPWR_OFSET(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x14, 28, 3, __value) +#define GET_TX_DESC_TXPWR_OFSET(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x14, 28, 3) +#define SET_TX_DESC_TX_ANT(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x14, 24, 4, __value) +#define GET_TX_DESC_TX_ANT(__tx_desc) LE_BITS_TO_4BYTE(__tx_desc + 0x14, 24, 4) +#define SET_TX_DESC_PORT_ID(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x14, 21, 3, __value) +#define GET_TX_DESC_PORT_ID(__tx_desc) LE_BITS_TO_4BYTE(__tx_desc + 0x14, 21, 3) + +#define SET_TX_DESC_MULTIPLE_PORT(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x14, 18, 3, __value) +#define GET_TX_DESC_MULTIPLE_PORT(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x14, 18, 3) + +#define SET_TX_DESC_SIGNALING_TAPKT_EN(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x14, 17, 1, __value) +#define GET_TX_DESC_SIGNALING_TAPKT_EN(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x14, 17, 1) + +#define SET_TX_DESC_RTS_SC(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x14, 13, 4, __value) +#define GET_TX_DESC_RTS_SC(__tx_desc) LE_BITS_TO_4BYTE(__tx_desc + 0x14, 13, 4) +#define SET_TX_DESC_RTS_SHORT(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x14, 12, 1, __value) +#define GET_TX_DESC_RTS_SHORT(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x14, 12, 1) + +#define SET_TX_DESC_VCS_STBC(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x14, 10, 2, __value) +#define GET_TX_DESC_VCS_STBC(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x14, 10, 2) + +#define SET_TX_DESC_DATA_STBC(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x14, 8, 2, __value) +#define GET_TX_DESC_DATA_STBC(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x14, 8, 2) + +#define SET_TX_DESC_DATA_LDPC(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x14, 7, 1, __value) +#define GET_TX_DESC_DATA_LDPC(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x14, 7, 1) + +#define SET_TX_DESC_DATA_BW(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x14, 5, 2, __value) +#define GET_TX_DESC_DATA_BW(__tx_desc) LE_BITS_TO_4BYTE(__tx_desc + 0x14, 5, 2) +#define SET_TX_DESC_DATA_SHORT(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x14, 4, 1, __value) +#define GET_TX_DESC_DATA_SHORT(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x14, 4, 1) +#define SET_TX_DESC_DATA_SC(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x14, 0, 4, __value) +#define GET_TX_DESC_DATA_SC(__tx_desc) LE_BITS_TO_4BYTE(__tx_desc + 0x14, 0, 4) + +/*TXDESC_WORD6*/ + +#define SET_TX_DESC_ANTSEL_D(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x18, 30, 2, __value) +#define GET_TX_DESC_ANTSEL_D(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x18, 30, 2) +#define SET_TX_DESC_ANT_MAPD(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x18, 28, 2, __value) +#define GET_TX_DESC_ANT_MAPD(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x18, 28, 2) +#define SET_TX_DESC_ANT_MAPC(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x18, 26, 2, __value) +#define GET_TX_DESC_ANT_MAPC(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x18, 26, 2) +#define SET_TX_DESC_ANT_MAPB(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x18, 24, 2, __value) +#define GET_TX_DESC_ANT_MAPB(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x18, 24, 2) +#define SET_TX_DESC_ANT_MAPA(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x18, 22, 2, __value) +#define GET_TX_DESC_ANT_MAPA(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x18, 22, 2) +#define SET_TX_DESC_ANTSEL_C(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x18, 20, 2, __value) +#define GET_TX_DESC_ANTSEL_C(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x18, 20, 2) +#define SET_TX_DESC_ANTSEL_B(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x18, 18, 2, __value) +#define GET_TX_DESC_ANTSEL_B(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x18, 18, 2) + +#define SET_TX_DESC_ANTSEL_A(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x18, 16, 2, __value) +#define GET_TX_DESC_ANTSEL_A(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x18, 16, 2) +#define SET_TX_DESC_MBSSID(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x18, 12, 4, __value) +#define GET_TX_DESC_MBSSID(__tx_desc) LE_BITS_TO_4BYTE(__tx_desc + 0x18, 12, 4) +#ifdef SET_TX_DESC_SW_DEFINE +#undef SET_TX_DESC_SW_DEFINE +#endif +#define SET_TX_DESC_SW_DEFINE(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x18, 0, 12, __value) +#define GET_TX_DESC_SW_DEFINE(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x18, 0, 12) + +/*TXDESC_WORD7*/ + +#define SET_TX_DESC_DMA_TXAGG_NUM(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x1C, 24, 8, __value) +#define GET_TX_DESC_DMA_TXAGG_NUM(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x1C, 24, 8) + +#define SET_TX_DESC_FINAL_DATA_RATE(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x1C, 24, 8, __value) +#define GET_TX_DESC_FINAL_DATA_RATE(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x1C, 24, 8) +#define SET_TX_DESC_NTX_MAP(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x1C, 20, 4, __value) +#define GET_TX_DESC_NTX_MAP(__tx_desc) LE_BITS_TO_4BYTE(__tx_desc + 0x1C, 20, 4) + +#define SET_TX_DESC_TX_BUFF_SIZE(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x1C, 0, 16, __value) +#define GET_TX_DESC_TX_BUFF_SIZE(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x1C, 0, 16) +#define SET_TX_DESC_TXDESC_CHECKSUM(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x1C, 0, 16, __value) +#define GET_TX_DESC_TXDESC_CHECKSUM(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x1C, 0, 16) +#define SET_TX_DESC_TIMESTAMP(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x1C, 0, 16, __value) +#define GET_TX_DESC_TIMESTAMP(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x1C, 0, 16) + +/*TXDESC_WORD8*/ + +#define SET_TX_DESC_TXWIFI_CP(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x20, 31, 1, __value) +#define GET_TX_DESC_TXWIFI_CP(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x20, 31, 1) +#define SET_TX_DESC_MAC_CP(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x20, 30, 1, __value) +#define GET_TX_DESC_MAC_CP(__tx_desc) LE_BITS_TO_4BYTE(__tx_desc + 0x20, 30, 1) +#define SET_TX_DESC_STW_PKTRE_DIS(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x20, 29, 1, __value) +#define GET_TX_DESC_STW_PKTRE_DIS(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x20, 29, 1) +#define SET_TX_DESC_STW_RB_DIS(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x20, 28, 1, __value) +#define GET_TX_DESC_STW_RB_DIS(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x20, 28, 1) +#define SET_TX_DESC_STW_RATE_DIS(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x20, 27, 1, __value) +#define GET_TX_DESC_STW_RATE_DIS(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x20, 27, 1) +#define SET_TX_DESC_STW_ANT_DIS(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x20, 26, 1, __value) +#define GET_TX_DESC_STW_ANT_DIS(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x20, 26, 1) +#define SET_TX_DESC_STW_EN(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x20, 25, 1, __value) +#define GET_TX_DESC_STW_EN(__tx_desc) LE_BITS_TO_4BYTE(__tx_desc + 0x20, 25, 1) +#define SET_TX_DESC_SMH_EN(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x20, 24, 1, __value) +#define GET_TX_DESC_SMH_EN(__tx_desc) LE_BITS_TO_4BYTE(__tx_desc + 0x20, 24, 1) + +#define SET_TX_DESC_TAILPAGE_L(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x20, 24, 8, __value) +#define GET_TX_DESC_TAILPAGE_L(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x20, 24, 8) + +#define SET_TX_DESC_SDIO_DMASEQ(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x20, 16, 8, __value) +#define GET_TX_DESC_SDIO_DMASEQ(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x20, 16, 8) + +#define SET_TX_DESC_NEXTHEADPAGE_L(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x20, 16, 8, __value) +#define GET_TX_DESC_NEXTHEADPAGE_L(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x20, 16, 8) +#define SET_TX_DESC_EN_HWSEQ(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x20, 15, 1, __value) +#define GET_TX_DESC_EN_HWSEQ(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x20, 15, 1) + +#define SET_TX_DESC_EN_HWEXSEQ(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x20, 14, 1, __value) +#define GET_TX_DESC_EN_HWEXSEQ(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x20, 14, 1) + +#define SET_TX_DESC_DATA_RC(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x20, 8, 6, __value) +#define GET_TX_DESC_DATA_RC(__tx_desc) LE_BITS_TO_4BYTE(__tx_desc + 0x20, 8, 6) +#define SET_TX_DESC_BAR_RTY_TH(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x20, 6, 2, __value) +#define GET_TX_DESC_BAR_RTY_TH(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x20, 6, 2) +#define SET_TX_DESC_RTS_RC(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x20, 0, 6, __value) +#define GET_TX_DESC_RTS_RC(__tx_desc) LE_BITS_TO_4BYTE(__tx_desc + 0x20, 0, 6) + +/*TXDESC_WORD9*/ + +#define SET_TX_DESC_TAILPAGE_H(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x24, 28, 4, __value) +#define GET_TX_DESC_TAILPAGE_H(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x24, 28, 4) +#define SET_TX_DESC_NEXTHEADPAGE_H(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x24, 24, 4, __value) +#define GET_TX_DESC_NEXTHEADPAGE_H(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x24, 24, 4) + +#define SET_TX_DESC_SW_SEQ(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x24, 12, 12, __value) +#define GET_TX_DESC_SW_SEQ(__tx_desc) LE_BITS_TO_4BYTE(__tx_desc + 0x24, 12, 12) +#define SET_TX_DESC_TXBF_PATH(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x24, 11, 1, __value) +#define GET_TX_DESC_TXBF_PATH(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x24, 11, 1) +#define SET_TX_DESC_PADDING_LEN(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x24, 0, 11, __value) +#define GET_TX_DESC_PADDING_LEN(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x24, 0, 11) +#define SET_TX_DESC_GROUP_BIT_IE_OFFSET(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x24, 0, 8, __value) +#define GET_TX_DESC_GROUP_BIT_IE_OFFSET(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x24, 0, 8) + +/*WORD10*/ + +#define SET_TX_DESC_MU_DATARATE(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x28, 8, 8, __value) +#define GET_TX_DESC_MU_DATARATE(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x28, 8, 8) +#define SET_TX_DESC_MU_RC(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x28, 4, 4, __value) +#define GET_TX_DESC_MU_RC(__tx_desc) LE_BITS_TO_4BYTE(__tx_desc + 0x28, 4, 4) +#define SET_TX_DESC_SND_PKT_SEL(__tx_desc, __value) \ + SET_BITS_TO_LE_4BYTE(__tx_desc + 0x28, 0, 2, __value) +#define GET_TX_DESC_SND_PKT_SEL(__tx_desc) \ + LE_BITS_TO_4BYTE(__tx_desc + 0x28, 0, 2) + +#endif diff --git a/drivers/staging/rtlwifi/halmac/halmac_type.h b/drivers/staging/rtlwifi/halmac/halmac_type.h new file mode 100644 index 000000000000..0bf842435080 --- /dev/null +++ b/drivers/staging/rtlwifi/halmac/halmac_type.h @@ -0,0 +1,1934 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef _HALMAC_TYPE_H_ +#define _HALMAC_TYPE_H_ + +#include "halmac_2_platform.h" +#include "halmac_fw_info.h" +#include "halmac_intf_phy_cmd.h" + +#define HALMAC_SCAN_CH_NUM_MAX 28 +#define HALMAC_BCN_IE_BMP_SIZE 24 /* ID0~ID191, 192/8=24 */ +#define HALMAC_PHY_PARAMETER_SIZE 12 +#define HALMAC_PHY_PARAMETER_MAX_NUM 128 +#define HALMAC_MAX_SSID_LEN 32 +#define HALMAC_SUPPORT_NLO_NUM 16 +#define HALMAC_SUPPORT_PROBE_REQ_NUM 8 +#define HALMC_DDMA_POLLING_COUNT 1000 +#define API_ARRAY_SIZE 32 + +/* platform api */ +#define PLATFORM_SDIO_CMD52_READ \ + halmac_adapter->halmac_platform_api->SDIO_CMD52_READ +#define PLATFORM_SDIO_CMD53_READ_8 \ + halmac_adapter->halmac_platform_api->SDIO_CMD53_READ_8 +#define PLATFORM_SDIO_CMD53_READ_16 \ + halmac_adapter->halmac_platform_api->SDIO_CMD53_READ_16 +#define PLATFORM_SDIO_CMD53_READ_32 \ + halmac_adapter->halmac_platform_api->SDIO_CMD53_READ_32 +#define PLATFORM_SDIO_CMD53_READ_N \ + halmac_adapter->halmac_platform_api->SDIO_CMD53_READ_N +#define PLATFORM_SDIO_CMD52_WRITE \ + halmac_adapter->halmac_platform_api->SDIO_CMD52_WRITE +#define PLATFORM_SDIO_CMD53_WRITE_8 \ + halmac_adapter->halmac_platform_api->SDIO_CMD53_WRITE_8 +#define PLATFORM_SDIO_CMD53_WRITE_16 \ + halmac_adapter->halmac_platform_api->SDIO_CMD53_WRITE_16 +#define PLATFORM_SDIO_CMD53_WRITE_32 \ + halmac_adapter->halmac_platform_api->SDIO_CMD53_WRITE_32 + +#define PLATFORM_REG_READ_8 halmac_adapter->halmac_platform_api->REG_READ_8 +#define PLATFORM_REG_READ_16 halmac_adapter->halmac_platform_api->REG_READ_16 +#define PLATFORM_REG_READ_32 halmac_adapter->halmac_platform_api->REG_READ_32 +#define PLATFORM_REG_WRITE_8 halmac_adapter->halmac_platform_api->REG_WRITE_8 +#define PLATFORM_REG_WRITE_16 halmac_adapter->halmac_platform_api->REG_WRITE_16 +#define PLATFORM_REG_WRITE_32 halmac_adapter->halmac_platform_api->REG_WRITE_32 + +#define PLATFORM_SEND_RSVD_PAGE \ + halmac_adapter->halmac_platform_api->SEND_RSVD_PAGE +#define PLATFORM_SEND_H2C_PKT halmac_adapter->halmac_platform_api->SEND_H2C_PKT + +#define PLATFORM_EVENT_INDICATION \ + halmac_adapter->halmac_platform_api->EVENT_INDICATION + +#define HALMAC_RT_TRACE(drv_adapter, comp, level, fmt, ...) \ + RT_TRACE(drv_adapter, COMP_HALMAC, level, fmt, ##__VA_ARGS__) + +#define HALMAC_REG_READ_8 halmac_api->halmac_reg_read_8 +#define HALMAC_REG_READ_16 halmac_api->halmac_reg_read_16 +#define HALMAC_REG_READ_32 halmac_api->halmac_reg_read_32 +#define HALMAC_REG_WRITE_8 halmac_api->halmac_reg_write_8 +#define HALMAC_REG_WRITE_16 halmac_api->halmac_reg_write_16 +#define HALMAC_REG_WRITE_32 halmac_api->halmac_reg_write_32 +#define HALMAC_REG_SDIO_CMD53_READ_N halmac_api->halmac_reg_sdio_cmd53_read_n + +/* Swap Little-endian <-> Big-endia*/ + +/*1->Little endian 0->Big endian*/ +#if HALMAC_SYSTEM_ENDIAN +#else +#endif + +#define HALMAC_ALIGN(x, a) HALMAC_ALIGN_MASK(x, (a) - 1) +#define HALMAC_ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask)) + +/* HALMAC API return status*/ +enum halmac_ret_status { + HALMAC_RET_SUCCESS = 0x00, + HALMAC_RET_SUCCESS_ENQUEUE = 0x01, + HALMAC_RET_PLATFORM_API_NULL = 0x02, + HALMAC_RET_EFUSE_SIZE_INCORRECT = 0x03, + HALMAC_RET_MALLOC_FAIL = 0x04, + HALMAC_RET_ADAPTER_INVALID = 0x05, + HALMAC_RET_ITF_INCORRECT = 0x06, + HALMAC_RET_DLFW_FAIL = 0x07, + HALMAC_RET_PORT_NOT_SUPPORT = 0x08, + HALMAC_RET_TRXMODE_NOT_SUPPORT = 0x09, + HALMAC_RET_INIT_LLT_FAIL = 0x0A, + HALMAC_RET_POWER_STATE_INVALID = 0x0B, + HALMAC_RET_H2C_ACK_NOT_RECEIVED = 0x0C, + HALMAC_RET_DL_RSVD_PAGE_FAIL = 0x0D, + HALMAC_RET_EFUSE_R_FAIL = 0x0E, + HALMAC_RET_EFUSE_W_FAIL = 0x0F, + HALMAC_RET_H2C_SW_RES_FAIL = 0x10, + HALMAC_RET_SEND_H2C_FAIL = 0x11, + HALMAC_RET_PARA_NOT_SUPPORT = 0x12, + HALMAC_RET_PLATFORM_API_INCORRECT = 0x13, + HALMAC_RET_ENDIAN_ERR = 0x14, + HALMAC_RET_FW_SIZE_ERR = 0x15, + HALMAC_RET_TRX_MODE_NOT_SUPPORT = 0x16, + HALMAC_RET_FAIL = 0x17, + HALMAC_RET_CHANGE_PS_FAIL = 0x18, + HALMAC_RET_CFG_PARA_FAIL = 0x19, + HALMAC_RET_UPDATE_PROBE_FAIL = 0x1A, + HALMAC_RET_SCAN_FAIL = 0x1B, + HALMAC_RET_STOP_SCAN_FAIL = 0x1C, + HALMAC_RET_BCN_PARSER_CMD_FAIL = 0x1D, + HALMAC_RET_POWER_ON_FAIL = 0x1E, + HALMAC_RET_POWER_OFF_FAIL = 0x1F, + HALMAC_RET_RX_AGG_MODE_FAIL = 0x20, + HALMAC_RET_DATA_BUF_NULL = 0x21, + HALMAC_RET_DATA_SIZE_INCORRECT = 0x22, + HALMAC_RET_QSEL_INCORRECT = 0x23, + HALMAC_RET_DMA_MAP_INCORRECT = 0x24, + HALMAC_RET_SEND_ORIGINAL_H2C_FAIL = 0x25, + HALMAC_RET_DDMA_FAIL = 0x26, + HALMAC_RET_FW_CHECKSUM_FAIL = 0x27, + HALMAC_RET_PWRSEQ_POLLING_FAIL = 0x28, + HALMAC_RET_PWRSEQ_CMD_INCORRECT = 0x29, + HALMAC_RET_WRITE_DATA_FAIL = 0x2A, + HALMAC_RET_DUMP_FIFOSIZE_INCORRECT = 0x2B, + HALMAC_RET_NULL_POINTER = 0x2C, + HALMAC_RET_PROBE_NOT_FOUND = 0x2D, + HALMAC_RET_FW_NO_MEMORY = 0x2E, + HALMAC_RET_H2C_STATUS_ERR = 0x2F, + HALMAC_RET_GET_H2C_SPACE_ERR = 0x30, + HALMAC_RET_H2C_SPACE_FULL = 0x31, + HALMAC_RET_DATAPACK_NO_FOUND = 0x32, + HALMAC_RET_CANNOT_FIND_H2C_RESOURCE = 0x33, + HALMAC_RET_TX_DMA_ERR = 0x34, + HALMAC_RET_RX_DMA_ERR = 0x35, + HALMAC_RET_CHIP_NOT_SUPPORT = 0x36, + HALMAC_RET_FREE_SPACE_NOT_ENOUGH = 0x37, + HALMAC_RET_CH_SW_SEQ_WRONG = 0x38, + HALMAC_RET_CH_SW_NO_BUF = 0x39, + HALMAC_RET_SW_CASE_NOT_SUPPORT = 0x3A, + HALMAC_RET_CONVERT_SDIO_OFFSET_FAIL = 0x3B, + HALMAC_RET_INVALID_SOUNDING_SETTING = 0x3C, + HALMAC_RET_GEN_INFO_NOT_SENT = 0x3D, + HALMAC_RET_STATE_INCORRECT = 0x3E, + HALMAC_RET_H2C_BUSY = 0x3F, + HALMAC_RET_INVALID_FEATURE_ID = 0x40, + HALMAC_RET_BUFFER_TOO_SMALL = 0x41, + HALMAC_RET_ZERO_LEN_RSVD_PACKET = 0x42, + HALMAC_RET_BUSY_STATE = 0x43, + HALMAC_RET_ERROR_STATE = 0x44, + HALMAC_RET_API_INVALID = 0x45, + HALMAC_RET_POLLING_BCN_VALID_FAIL = 0x46, + HALMAC_RET_SDIO_LEAVE_SUSPEND_FAIL = 0x47, + HALMAC_RET_EEPROM_PARSING_FAIL = 0x48, + HALMAC_RET_EFUSE_NOT_ENOUGH = 0x49, + HALMAC_RET_WRONG_ARGUMENT = 0x4A, + HALMAC_RET_NOT_SUPPORT = 0x4B, + HALMAC_RET_C2H_NOT_HANDLED = 0x4C, + HALMAC_RET_PARA_SENDING = 0x4D, + HALMAC_RET_CFG_DLFW_SIZE_FAIL = 0x4E, + HALMAC_RET_CFG_TXFIFO_PAGE_FAIL = 0x4F, + HALMAC_RET_SWITCH_CASE_ERROR = 0x50, + HALMAC_RET_EFUSE_BANK_INCORRECT = 0x51, + HALMAC_RET_SWITCH_EFUSE_BANK_FAIL = 0x52, + HALMAC_RET_USB_MODE_UNCHANGE = 0x53, + HALMAC_RET_NO_DLFW = 0x54, + HALMAC_RET_USB2_3_SWITCH_UNSUPPORT = 0x55, + HALMAC_RET_BIP_NO_SUPPORT = 0x56, + HALMAC_RET_ENTRY_INDEX_ERROR = 0x57, + HALMAC_RET_ENTRY_KEY_ID_ERROR = 0x58, + HALMAC_RET_DRV_DL_ERR = 0x59, + HALMAC_RET_OQT_NOT_ENOUGH = 0x5A, + HALMAC_RET_PWR_UNCHANGE = 0x5B, + HALMAC_RET_FW_NO_SUPPORT = 0x60, + HALMAC_RET_TXFIFO_NO_EMPTY = 0x61, +}; + +enum halmac_mac_clock_hw_def { + HALMAC_MAC_CLOCK_HW_DEF_80M = 0, + HALMAC_MAC_CLOCK_HW_DEF_40M = 1, + HALMAC_MAC_CLOCK_HW_DEF_20M = 2, +}; + +/* Rx aggregation parameters */ +enum halmac_normal_rxagg_th_to { + HALMAC_NORMAL_RXAGG_THRESHOLD = 0xFF, + HALMAC_NORMAL_RXAGG_TIMEOUT = 0x01, +}; + +enum halmac_loopback_rxagg_th_to { + HALMAC_LOOPBACK_RXAGG_THRESHOLD = 0xFF, + HALMAC_LOOPBACK_RXAGG_TIMEOUT = 0x01, +}; + +/* Chip ID*/ +enum halmac_chip_id { + HALMAC_CHIP_ID_8822B = 0, + HALMAC_CHIP_ID_8821C = 1, + HALMAC_CHIP_ID_8814B = 2, + HALMAC_CHIP_ID_8197F = 3, + HALMAC_CHIP_ID_UNDEFINE = 0x7F, +}; + +enum halmac_chip_id_hw_def { + HALMAC_CHIP_ID_HW_DEF_8723A = 0x01, + HALMAC_CHIP_ID_HW_DEF_8188E = 0x02, + HALMAC_CHIP_ID_HW_DEF_8881A = 0x03, + HALMAC_CHIP_ID_HW_DEF_8812A = 0x04, + HALMAC_CHIP_ID_HW_DEF_8821A = 0x05, + HALMAC_CHIP_ID_HW_DEF_8723B = 0x06, + HALMAC_CHIP_ID_HW_DEF_8192E = 0x07, + HALMAC_CHIP_ID_HW_DEF_8814A = 0x08, + HALMAC_CHIP_ID_HW_DEF_8821C = 0x09, + HALMAC_CHIP_ID_HW_DEF_8822B = 0x0A, + HALMAC_CHIP_ID_HW_DEF_8703B = 0x0B, + HALMAC_CHIP_ID_HW_DEF_8188F = 0x0C, + HALMAC_CHIP_ID_HW_DEF_8192F = 0x0D, + HALMAC_CHIP_ID_HW_DEF_8197F = 0x0E, + HALMAC_CHIP_ID_HW_DEF_8723D = 0x0F, + HALMAC_CHIP_ID_HW_DEF_8814B = 0x10, + HALMAC_CHIP_ID_HW_DEF_UNDEFINE = 0x7F, + HALMAC_CHIP_ID_HW_DEF_PS = 0xEA, +}; + +/* Chip Version*/ +enum halmac_chip_ver { + HALMAC_CHIP_VER_A_CUT = 0x00, + HALMAC_CHIP_VER_B_CUT = 0x01, + HALMAC_CHIP_VER_C_CUT = 0x02, + HALMAC_CHIP_VER_D_CUT = 0x03, + HALMAC_CHIP_VER_E_CUT = 0x04, + HALMAC_CHIP_VER_F_CUT = 0x05, + HALMAC_CHIP_VER_TEST = 0xFF, + HALMAC_CHIP_VER_UNDEFINE = 0x7FFF, +}; + +/* Network type select */ +enum halmac_network_type_select { + HALMAC_NETWORK_NO_LINK = 0, + HALMAC_NETWORK_ADHOC = 1, + HALMAC_NETWORK_INFRASTRUCTURE = 2, + HALMAC_NETWORK_AP = 3, + HALMAC_NETWORK_UNDEFINE = 0x7F, +}; + +/* Transfer mode select */ +enum halmac_trnsfer_mode_select { + HALMAC_TRNSFER_NORMAL = 0x0, + HALMAC_TRNSFER_LOOPBACK_DIRECT = 0xB, + HALMAC_TRNSFER_LOOPBACK_DELAY = 0x3, + HALMAC_TRNSFER_UNDEFINE = 0x7F, +}; + +/* Queue select */ +enum halmac_dma_mapping { + HALMAC_DMA_MAPPING_EXTRA = 0, + HALMAC_DMA_MAPPING_LOW = 1, + HALMAC_DMA_MAPPING_NORMAL = 2, + HALMAC_DMA_MAPPING_HIGH = 3, + HALMAC_DMA_MAPPING_UNDEFINE = 0x7F, +}; + +#define HALMAC_MAP2_HQ HALMAC_DMA_MAPPING_HIGH +#define HALMAC_MAP2_NQ HALMAC_DMA_MAPPING_NORMAL +#define HALMAC_MAP2_LQ HALMAC_DMA_MAPPING_LOW +#define HALMAC_MAP2_EXQ HALMAC_DMA_MAPPING_EXTRA +#define HALMAC_MAP2_UNDEF HALMAC_DMA_MAPPING_UNDEFINE + +/* TXDESC queue select TID */ +enum halmac_txdesc_queue_tid { + HALMAC_TXDESC_QSEL_TID0 = 0, + HALMAC_TXDESC_QSEL_TID1 = 1, + HALMAC_TXDESC_QSEL_TID2 = 2, + HALMAC_TXDESC_QSEL_TID3 = 3, + HALMAC_TXDESC_QSEL_TID4 = 4, + HALMAC_TXDESC_QSEL_TID5 = 5, + HALMAC_TXDESC_QSEL_TID6 = 6, + HALMAC_TXDESC_QSEL_TID7 = 7, + HALMAC_TXDESC_QSEL_TID8 = 8, + HALMAC_TXDESC_QSEL_TID9 = 9, + HALMAC_TXDESC_QSEL_TIDA = 10, + HALMAC_TXDESC_QSEL_TIDB = 11, + HALMAC_TXDESC_QSEL_TIDC = 12, + HALMAC_TXDESC_QSEL_TIDD = 13, + HALMAC_TXDESC_QSEL_TIDE = 14, + HALMAC_TXDESC_QSEL_TIDF = 15, + + HALMAC_TXDESC_QSEL_BEACON = 0x10, + HALMAC_TXDESC_QSEL_HIGH = 0x11, + HALMAC_TXDESC_QSEL_MGT = 0x12, + HALMAC_TXDESC_QSEL_H2C_CMD = 0x13, + + HALMAC_TXDESC_QSEL_UNDEFINE = 0x7F, +}; + +enum halmac_ptcl_queue { + HALMAC_PTCL_QUEUE_VO = 0x0, + HALMAC_PTCL_QUEUE_VI = 0x1, + HALMAC_PTCL_QUEUE_BE = 0x2, + HALMAC_PTCL_QUEUE_BK = 0x3, + HALMAC_PTCL_QUEUE_MG = 0x4, + HALMAC_PTCL_QUEUE_HI = 0x5, + HALMAC_PTCL_QUEUE_NUM = 0x6, + HALMAC_PTCL_QUEUE_UNDEFINE = 0x7F, +}; + +enum halmac_queue_select { + HALMAC_QUEUE_SELECT_VO = HALMAC_TXDESC_QSEL_TID6, + HALMAC_QUEUE_SELECT_VI = HALMAC_TXDESC_QSEL_TID4, + HALMAC_QUEUE_SELECT_BE = HALMAC_TXDESC_QSEL_TID0, + HALMAC_QUEUE_SELECT_BK = HALMAC_TXDESC_QSEL_TID1, + HALMAC_QUEUE_SELECT_VO_V2 = HALMAC_TXDESC_QSEL_TID7, + HALMAC_QUEUE_SELECT_VI_V2 = HALMAC_TXDESC_QSEL_TID5, + HALMAC_QUEUE_SELECT_BE_V2 = HALMAC_TXDESC_QSEL_TID3, + HALMAC_QUEUE_SELECT_BK_V2 = HALMAC_TXDESC_QSEL_TID2, + HALMAC_QUEUE_SELECT_BCN = HALMAC_TXDESC_QSEL_BEACON, + HALMAC_QUEUE_SELECT_HIGH = HALMAC_TXDESC_QSEL_HIGH, + HALMAC_QUEUE_SELECT_MGNT = HALMAC_TXDESC_QSEL_MGT, + HALMAC_QUEUE_SELECT_CMD = HALMAC_TXDESC_QSEL_H2C_CMD, + HALMAC_QUEUE_SELECT_UNDEFINE = 0x7F, +}; + +/* USB burst size */ +enum halmac_usb_burst_size { + HALMAC_USB_BURST_SIZE_3_0 = 0x0, + HALMAC_USB_BURST_SIZE_2_0_HSPEED = 0x1, + HALMAC_USB_BURST_SIZE_2_0_FSPEED = 0x2, + HALMAC_USB_BURST_SIZE_2_0_OTHERS = 0x3, + HALMAC_USB_BURST_SIZE_UNDEFINE = 0x7F, +}; + +/* HAL API function parameters*/ +enum halmac_interface { + HALMAC_INTERFACE_PCIE = 0x0, + HALMAC_INTERFACE_USB = 0x1, + HALMAC_INTERFACE_SDIO = 0x2, + HALMAC_INTERFACE_AXI = 0x3, + HALMAC_INTERFACE_UNDEFINE = 0x7F, +}; + +enum halmac_rx_agg_mode { + HALMAC_RX_AGG_MODE_NONE = 0x0, + HALMAC_RX_AGG_MODE_DMA = 0x1, + HALMAC_RX_AGG_MODE_USB = 0x2, + HALMAC_RX_AGG_MODE_UNDEFINE = 0x7F, +}; + +struct halmac_rxagg_th { + u8 drv_define; + u8 timeout; + u8 size; +}; + +struct halmac_rxagg_cfg { + enum halmac_rx_agg_mode mode; + struct halmac_rxagg_th threshold; +}; + +enum halmac_mac_power { + HALMAC_MAC_POWER_OFF = 0x0, + HALMAC_MAC_POWER_ON = 0x1, + HALMAC_MAC_POWER_UNDEFINE = 0x7F, +}; + +enum halmac_ps_state { + HALMAC_PS_STATE_ACT = 0x0, + HALMAC_PS_STATE_LPS = 0x1, + HALMAC_PS_STATE_IPS = 0x2, + HALMAC_PS_STATE_UNDEFINE = 0x7F, +}; + +enum halmac_trx_mode { + HALMAC_TRX_MODE_NORMAL = 0x0, + HALMAC_TRX_MODE_TRXSHARE = 0x1, + HALMAC_TRX_MODE_WMM = 0x2, + HALMAC_TRX_MODE_P2P = 0x3, + HALMAC_TRX_MODE_LOOPBACK = 0x4, + HALMAC_TRX_MODE_DELAY_LOOPBACK = 0x5, + HALMAC_TRX_MODE_MAX = 0x6, + HALMAC_TRX_MODE_WMM_LINUX = 0x7E, + HALMAC_TRX_MODE_UNDEFINE = 0x7F, +}; + +enum halmac_wireless_mode { + HALMAC_WIRELESS_MODE_B = 0x0, + HALMAC_WIRELESS_MODE_G = 0x1, + HALMAC_WIRELESS_MODE_N = 0x2, + HALMAC_WIRELESS_MODE_AC = 0x3, + HALMAC_WIRELESS_MODE_UNDEFINE = 0x7F, +}; + +enum halmac_bw { + HALMAC_BW_20 = 0x00, + HALMAC_BW_40 = 0x01, + HALMAC_BW_80 = 0x02, + HALMAC_BW_160 = 0x03, + HALMAC_BW_5 = 0x04, + HALMAC_BW_10 = 0x05, + HALMAC_BW_MAX = 0x06, + HALMAC_BW_UNDEFINE = 0x7F, +}; + +enum halmac_efuse_read_cfg { + HALMAC_EFUSE_R_AUTO = 0x00, + HALMAC_EFUSE_R_DRV = 0x01, + HALMAC_EFUSE_R_FW = 0x02, + HALMAC_EFUSE_R_UNDEFINE = 0x7F, +}; + +enum halmac_dlfw_mem { + HALMAC_DLFW_MEM_EMEM = 0x00, + HALMAC_DLFW_MEM_UNDEFINE = 0x7F, +}; + +struct halmac_tx_desc { + u32 dword0; + u32 dword1; + u32 dword2; + u32 dword3; + u32 dword4; + u32 dword5; + u32 dword6; + u32 dword7; + u32 dword8; + u32 dword9; + u32 dword10; + u32 dword11; +}; + +struct halmac_rx_desc { + u32 dword0; + u32 dword1; + u32 dword2; + u32 dword3; + u32 dword4; + u32 dword5; +}; + +struct halmac_fwlps_option { + u8 mode; + u8 clk_request; + u8 rlbm; + u8 smart_ps; + u8 awake_interval; + u8 all_queue_uapsd; + u8 pwr_state; + u8 low_pwr_rx_beacon; + u8 ant_auto_switch; + u8 ps_allow_bt_high_priority; + u8 protect_bcn; + u8 silence_period; + u8 fast_bt_connect; + u8 two_antenna_en; + u8 adopt_user_setting; + u8 drv_bcn_early_shift; + bool enter_32K; +}; + +struct halmac_fwips_option { + u8 adopt_user_setting; +}; + +struct halmac_wowlan_option { + u8 adopt_user_setting; +}; + +struct halmac_bcn_ie_info { + u8 func_en; + u8 size_th; + u8 timeout; + u8 ie_bmp[HALMAC_BCN_IE_BMP_SIZE]; +}; + +enum halmac_reg_type { + HALMAC_REG_TYPE_MAC = 0x0, + HALMAC_REG_TYPE_BB = 0x1, + HALMAC_REG_TYPE_RF = 0x2, + HALMAC_REG_TYPE_UNDEFINE = 0x7F, +}; + +enum halmac_parameter_cmd { + /* HALMAC_PARAMETER_CMD_LLT = 0x1, */ + /* HALMAC_PARAMETER_CMD_R_EFUSE = 0x2, */ + /* HALMAC_PARAMETER_CMD_EFUSE_PATCH = 0x3, */ + HALMAC_PARAMETER_CMD_MAC_W8 = 0x4, + HALMAC_PARAMETER_CMD_MAC_W16 = 0x5, + HALMAC_PARAMETER_CMD_MAC_W32 = 0x6, + HALMAC_PARAMETER_CMD_RF_W = 0x7, + HALMAC_PARAMETER_CMD_BB_W8 = 0x8, + HALMAC_PARAMETER_CMD_BB_W16 = 0x9, + HALMAC_PARAMETER_CMD_BB_W32 = 0XA, + HALMAC_PARAMETER_CMD_DELAY_US = 0X10, + HALMAC_PARAMETER_CMD_DELAY_MS = 0X11, + HALMAC_PARAMETER_CMD_END = 0XFF, +}; + +union halmac_parameter_content { + struct _MAC_REG_W { + u32 value; + u32 msk; + u16 offset; + u8 msk_en; + } MAC_REG_W; + struct _BB_REG_W { + u32 value; + u32 msk; + u16 offset; + u8 msk_en; + } BB_REG_W; + struct _RF_REG_W { + u32 value; + u32 msk; + u8 offset; + u8 msk_en; + u8 rf_path; + } RF_REG_W; + struct _DELAY_TIME { + u32 rsvd1; + u32 rsvd2; + u16 delay_time; + u8 rsvd3; + } DELAY_TIME; +}; + +struct halmac_phy_parameter_info { + enum halmac_parameter_cmd cmd_id; + union halmac_parameter_content content; +}; + +struct halmac_h2c_info { + u16 h2c_seq_num; /* H2C sequence number */ + u8 in_use; /* 0 : empty 1 : used */ + enum halmac_h2c_return_code status; +}; + +struct halmac_pg_efuse_info { + u8 *efuse_map; + u32 efuse_map_size; + u8 *efuse_mask; + u32 efuse_mask_size; +}; + +struct halmac_txagg_buff_info { + u8 *tx_agg_buf; + u8 *curr_pkt_buf; + u32 avai_buf_size; + u32 total_pkt_size; + u8 agg_num; +}; + +struct halmac_config_para_info { + u32 para_buf_size; /* Parameter buffer size */ + u8 *cfg_para_buf; /* Buffer for config parameter */ + u8 *para_buf_w; /* Write pointer of the parameter buffer */ + u32 para_num; /* Parameter numbers in parameter buffer */ + u32 avai_para_buf_size; /* Free size of parameter buffer */ + u32 offset_accumulation; + u32 value_accumulation; + enum halmac_data_type data_type; /*DataType which is passed to FW*/ + u8 datapack_segment; /*DataPack Segment, from segment0...*/ + bool full_fifo_mode; /* Used full tx fifo to save cfg parameter */ +}; + +struct halmac_hw_config_info { + u32 efuse_size; /* Record efuse size */ + u32 eeprom_size; /* Record eeprom size */ + u32 bt_efuse_size; /* Record BT efuse size */ + u32 tx_fifo_size; /* Record tx fifo size */ + u32 rx_fifo_size; /* Record rx fifo size */ + u8 txdesc_size; /* Record tx desc size */ + u8 rxdesc_size; /* Record rx desc size */ + u32 page_size; /* Record page size */ + u16 tx_align_size; + u8 page_size_2_power; + u8 cam_entry_num; /* Record CAM entry number */ +}; + +struct halmac_sdio_free_space { + u16 high_queue_number; /* Free space of HIQ */ + u16 normal_queue_number; /* Free space of MIDQ */ + u16 low_queue_number; /* Free space of LOWQ */ + u16 public_queue_number; /* Free space of PUBQ */ + u16 extra_queue_number; /* Free space of EXBQ */ + u8 ac_oqt_number; + u8 non_ac_oqt_number; + u8 ac_empty; +}; + +enum hal_fifo_sel { + HAL_FIFO_SEL_TX, + HAL_FIFO_SEL_RX, + HAL_FIFO_SEL_RSVD_PAGE, + HAL_FIFO_SEL_REPORT, + HAL_FIFO_SEL_LLT, +}; + +enum halmac_drv_info { + HALMAC_DRV_INFO_NONE, /* No information is appended in rx_pkt */ + HALMAC_DRV_INFO_PHY_STATUS, /* PHY status is appended after rx_desc */ + HALMAC_DRV_INFO_PHY_SNIFFER, /* PHY status and sniffer info appended */ + HALMAC_DRV_INFO_PHY_PLCP, /* PHY status and plcp header are appended */ + HALMAC_DRV_INFO_UNDEFINE, +}; + +struct halmac_bt_coex_cmd { + u8 element_id; + u8 op_code; + u8 op_code_ver; + u8 req_num; + u8 data0; + u8 data1; + u8 data2; + u8 data3; + u8 data4; +}; + +enum halmac_pri_ch_idx { + HALMAC_CH_IDX_UNDEFINE = 0, + HALMAC_CH_IDX_1 = 1, + HALMAC_CH_IDX_2 = 2, + HALMAC_CH_IDX_3 = 3, + HALMAC_CH_IDX_4 = 4, + HALMAC_CH_IDX_MAX = 5, +}; + +struct halmac_ch_info { + enum halmac_cs_action_id action_id; + enum halmac_bw bw; + enum halmac_pri_ch_idx pri_ch_idx; + u8 channel; + u8 timeout; + u8 extra_info; +}; + +struct halmac_ch_extra_info { + u8 extra_info; + enum halmac_cs_extra_action_id extra_action_id; + u8 extra_info_size; + u8 *extra_info_data; +}; + +enum halmac_cs_periodic_option { + HALMAC_CS_PERIODIC_NONE, + HALMAC_CS_PERIODIC_NORMAL, + HALMAC_CS_PERIODIC_2_PHASE, + HALMAC_CS_PERIODIC_SEAMLESS, +}; + +struct halmac_ch_switch_option { + enum halmac_bw dest_bw; + enum halmac_cs_periodic_option periodic_option; + enum halmac_pri_ch_idx dest_pri_ch_idx; + /* u32 tsf_high; */ + u32 tsf_low; + bool switch_en; + u8 dest_ch_en; + u8 absolute_time_en; + u8 dest_ch; + u8 normal_period; + u8 normal_cycle; + u8 phase_2_period; +}; + +struct halmac_fw_version { + u16 version; + u8 sub_version; + u8 sub_index; + u16 h2c_version; +}; + +enum halmac_rf_type { + HALMAC_RF_1T2R = 0, + HALMAC_RF_2T4R = 1, + HALMAC_RF_2T2R = 2, + HALMAC_RF_2T3R = 3, + HALMAC_RF_1T1R = 4, + HALMAC_RF_2T2R_GREEN = 5, + HALMAC_RF_3T3R = 6, + HALMAC_RF_3T4R = 7, + HALMAC_RF_4T4R = 8, + HALMAC_RF_MAX_TYPE = 0xF, +}; + +struct halmac_general_info { + u8 rfe_type; + enum halmac_rf_type rf_type; +}; + +struct halmac_pwr_tracking_para { + u8 enable; + u8 tx_pwr_index; + u8 pwr_tracking_offset_value; + u8 tssi_value; +}; + +struct halmac_pwr_tracking_option { + u8 type; + u8 bbswing_index; + struct halmac_pwr_tracking_para + pwr_tracking_para[4]; /* pathA, pathB, pathC, pathD */ +}; + +struct halmac_nlo_cfg { + u8 num_of_ssid; + u8 num_of_hidden_ap; + u8 rsvd[2]; + u32 pattern_check; + u32 rsvd1; + u32 rsvd2; + u8 ssid_len[HALMAC_SUPPORT_NLO_NUM]; + u8 chiper_type[HALMAC_SUPPORT_NLO_NUM]; + u8 rsvd3[HALMAC_SUPPORT_NLO_NUM]; + u8 loc_probe_req[HALMAC_SUPPORT_PROBE_REQ_NUM]; + u8 rsvd4[56]; + u8 ssid[HALMAC_SUPPORT_NLO_NUM][HALMAC_MAX_SSID_LEN]; +}; + +enum halmac_data_rate { + HALMAC_CCK1, + HALMAC_CCK2, + HALMAC_CCK5_5, + HALMAC_CCK11, + HALMAC_OFDM6, + HALMAC_OFDM9, + HALMAC_OFDM12, + HALMAC_OFDM18, + HALMAC_OFDM24, + HALMAC_OFDM36, + HALMAC_OFDM48, + HALMAC_OFDM54, + HALMAC_MCS0, + HALMAC_MCS1, + HALMAC_MCS2, + HALMAC_MCS3, + HALMAC_MCS4, + HALMAC_MCS5, + HALMAC_MCS6, + HALMAC_MCS7, + HALMAC_MCS8, + HALMAC_MCS9, + HALMAC_MCS10, + HALMAC_MCS11, + HALMAC_MCS12, + HALMAC_MCS13, + HALMAC_MCS14, + HALMAC_MCS15, + HALMAC_MCS16, + HALMAC_MCS17, + HALMAC_MCS18, + HALMAC_MCS19, + HALMAC_MCS20, + HALMAC_MCS21, + HALMAC_MCS22, + HALMAC_MCS23, + HALMAC_MCS24, + HALMAC_MCS25, + HALMAC_MCS26, + HALMAC_MCS27, + HALMAC_MCS28, + HALMAC_MCS29, + HALMAC_MCS30, + HALMAC_MCS31, + HALMAC_VHT_NSS1_MCS0, + HALMAC_VHT_NSS1_MCS1, + HALMAC_VHT_NSS1_MCS2, + HALMAC_VHT_NSS1_MCS3, + HALMAC_VHT_NSS1_MCS4, + HALMAC_VHT_NSS1_MCS5, + HALMAC_VHT_NSS1_MCS6, + HALMAC_VHT_NSS1_MCS7, + HALMAC_VHT_NSS1_MCS8, + HALMAC_VHT_NSS1_MCS9, + HALMAC_VHT_NSS2_MCS0, + HALMAC_VHT_NSS2_MCS1, + HALMAC_VHT_NSS2_MCS2, + HALMAC_VHT_NSS2_MCS3, + HALMAC_VHT_NSS2_MCS4, + HALMAC_VHT_NSS2_MCS5, + HALMAC_VHT_NSS2_MCS6, + HALMAC_VHT_NSS2_MCS7, + HALMAC_VHT_NSS2_MCS8, + HALMAC_VHT_NSS2_MCS9, + HALMAC_VHT_NSS3_MCS0, + HALMAC_VHT_NSS3_MCS1, + HALMAC_VHT_NSS3_MCS2, + HALMAC_VHT_NSS3_MCS3, + HALMAC_VHT_NSS3_MCS4, + HALMAC_VHT_NSS3_MCS5, + HALMAC_VHT_NSS3_MCS6, + HALMAC_VHT_NSS3_MCS7, + HALMAC_VHT_NSS3_MCS8, + HALMAC_VHT_NSS3_MCS9, + HALMAC_VHT_NSS4_MCS0, + HALMAC_VHT_NSS4_MCS1, + HALMAC_VHT_NSS4_MCS2, + HALMAC_VHT_NSS4_MCS3, + HALMAC_VHT_NSS4_MCS4, + HALMAC_VHT_NSS4_MCS5, + HALMAC_VHT_NSS4_MCS6, + HALMAC_VHT_NSS4_MCS7, + HALMAC_VHT_NSS4_MCS8, + HALMAC_VHT_NSS4_MCS9 +}; + +enum halmac_rf_path { + HALMAC_RF_PATH_A, + HALMAC_RF_PATH_B, + HALMAC_RF_PATH_C, + HALMAC_RF_PATH_D +}; + +enum halmac_snd_pkt_sel { + HALMAC_UNI_NDPA, + HALMAC_BMC_NDPA, + HALMAC_NON_FINAL_BFRPRPOLL, + HALMAC_FINAL_BFRPTPOLL, +}; + +enum hal_security_type { + HAL_SECURITY_TYPE_NONE = 0, + HAL_SECURITY_TYPE_WEP40 = 1, + HAL_SECURITY_TYPE_WEP104 = 2, + HAL_SECURITY_TYPE_TKIP = 3, + HAL_SECURITY_TYPE_AES128 = 4, + HAL_SECURITY_TYPE_WAPI = 5, + HAL_SECURITY_TYPE_AES256 = 6, + HAL_SECURITY_TYPE_GCMP128 = 7, + HAL_SECURITY_TYPE_GCMP256 = 8, + HAL_SECURITY_TYPE_GCMSMS4 = 9, + HAL_SECURITY_TYPE_BIP = 10, + HAL_SECURITY_TYPE_UNDEFINE = 0x7F, +}; + +enum hal_intf_phy { + HAL_INTF_PHY_USB2 = 0, + HAL_INTF_PHY_USB3 = 1, + HAL_INTF_PHY_PCIE_GEN1 = 2, + HAL_INTF_PHY_PCIE_GEN2 = 3, + HAL_INTF_PHY_UNDEFINE = 0x7F, +}; + +enum halmac_dbg_msg_info { + HALMAC_DBG_ERR, + HALMAC_DBG_WARN, + HALMAC_DBG_TRACE, +}; + +enum halmac_dbg_msg_type { + HALMAC_MSG_INIT, + HALMAC_MSG_EFUSE, + HALMAC_MSG_FW, + HALMAC_MSG_H2C, + HALMAC_MSG_PWR, + HALMAC_MSG_SND, + HALMAC_MSG_COMMON, + HALMAC_MSG_DBI, + HALMAC_MSG_MDIO, + HALMAC_MSG_USB +}; + +enum halmac_cmd_process_status { + HALMAC_CMD_PROCESS_IDLE = 0x01, /* Init status */ + HALMAC_CMD_PROCESS_SENDING = 0x02, /* Wait ack */ + HALMAC_CMD_PROCESS_RCVD = 0x03, /* Rcvd ack */ + HALMAC_CMD_PROCESS_DONE = 0x04, /* Event done */ + HALMAC_CMD_PROCESS_ERROR = 0x05, /* Return code error */ + HALMAC_CMD_PROCESS_UNDEFINE = 0x7F, +}; + +enum halmac_feature_id { + HALMAC_FEATURE_CFG_PARA, /* Support */ + HALMAC_FEATURE_DUMP_PHYSICAL_EFUSE, /* Support */ + HALMAC_FEATURE_DUMP_LOGICAL_EFUSE, /* Support */ + HALMAC_FEATURE_UPDATE_PACKET, /* Support */ + HALMAC_FEATURE_UPDATE_DATAPACK, + HALMAC_FEATURE_RUN_DATAPACK, + HALMAC_FEATURE_CHANNEL_SWITCH, /* Support */ + HALMAC_FEATURE_IQK, /* Support */ + HALMAC_FEATURE_POWER_TRACKING, /* Support */ + HALMAC_FEATURE_PSD, /* Support */ + HALMAC_FEATURE_ALL, /* Support, only for reset */ +}; + +enum halmac_drv_rsvd_pg_num { + HALMAC_RSVD_PG_NUM16, /* 2K */ + HALMAC_RSVD_PG_NUM24, /* 3K */ + HALMAC_RSVD_PG_NUM32, /* 4K */ +}; + +enum halmac_pcie_cfg { + HALMAC_PCIE_GEN1, + HALMAC_PCIE_GEN2, + HALMAC_PCIE_CFG_UNDEFINE, +}; + +enum halmac_portid { + HALMAC_PORTID0 = 0, + HALMAC_PORTID1 = 1, + HALMAC_PORTID2 = 2, + HALMAC_PORTID3 = 3, + HALMAC_PORTID4 = 4, + HALMAC_PORTIDMAX +}; + +struct halmac_p2pps { + /*DW0*/ + u8 offload_en : 1; + u8 role : 1; + u8 ctwindow_en : 1; + u8 noa_en : 1; + u8 noa_sel : 1; + u8 all_sta_sleep : 1; + u8 discovery : 1; + u8 rsvd2 : 1; + u8 p2p_port_id; + u8 p2p_group; + u8 p2p_macid; + + /*DW1*/ + u8 ctwindow_length; + u8 rsvd3; + u8 rsvd4; + u8 rsvd5; + + /*DW2*/ + u32 noa_duration_para; + + /*DW3*/ + u32 noa_interval_para; + + /*DW4*/ + u32 noa_start_time_para; + + /*DW5*/ + u32 noa_count_para; +}; + +/* Platform API setting */ +struct halmac_platform_api { + /* R/W register */ + u8 (*SDIO_CMD52_READ)(void *driver_adapter, u32 offset); + u8 (*SDIO_CMD53_READ_8)(void *driver_adapter, u32 offset); + u16 (*SDIO_CMD53_READ_16)(void *driver_adapter, u32 offset); + u32 (*SDIO_CMD53_READ_32)(void *driver_adapter, u32 offset); + u8 (*SDIO_CMD53_READ_N)(void *driver_adapter, u32 offset, u32 size, + u8 *data); + void (*SDIO_CMD52_WRITE)(void *driver_adapter, u32 offset, u8 value); + void (*SDIO_CMD53_WRITE_8)(void *driver_adapter, u32 offset, u8 value); + void (*SDIO_CMD53_WRITE_16)(void *driver_adapter, u32 offset, + u16 value); + void (*SDIO_CMD53_WRITE_32)(void *driver_adapter, u32 offset, + u32 value); + u8 (*REG_READ_8)(void *driver_adapter, u32 offset); + u16 (*REG_READ_16)(void *driver_adapter, u32 offset); + u32 (*REG_READ_32)(void *driver_adapter, u32 offset); + void (*REG_WRITE_8)(void *driver_adapter, u32 offset, u8 value); + void (*REG_WRITE_16)(void *driver_adapter, u32 offset, u16 value); + void (*REG_WRITE_32)(void *driver_adapter, u32 offset, u32 value); + + /* send buf to reserved page, the tx_desc is not included in buf, + * driver need to fill tx_desc with qsel = bcn + */ + bool (*SEND_RSVD_PAGE)(void *driver_adapter, u8 *buf, u32 size); + /* send buf to h2c queue, the tx_desc is not included in buf, + * driver need to fill tx_desc with qsel = h2c + */ + bool (*SEND_H2C_PKT)(void *driver_adapter, u8 *buf, u32 size); + + bool (*EVENT_INDICATION)(void *driver_adapter, + enum halmac_feature_id feature_id, + enum halmac_cmd_process_status process_status, + u8 *buf, u32 size); +}; + +/*1->Little endian 0->Big endian*/ +#if HALMAC_SYSTEM_ENDIAN + +#else + +#endif + +/* User can not use members in address_l_h, use address[6] is mandatory */ +union halmac_wlan_addr { + u8 address[6]; /* WLAN address (MACID, BSSID, Brodcast ID). + * address[0] is lowest, address[5] is highest + */ + struct { + union { + u32 address_low; + __le32 le_address_low; + u8 address_low_b[4]; + }; + union { + u16 address_high; + __le16 le_address_high; + u8 address_high_b[2]; + }; + } address_l_h; +}; + +enum halmac_snd_role { + HAL_BFER = 0, + HAL_BFEE = 1, +}; + +enum halmac_csi_seg_len { + HAL_CSI_SEG_4K = 0, + HAL_CSI_SEG_8K = 1, + HAL_CSI_SEG_11K = 2, +}; + +struct halmac_cfg_mumimo_para { + enum halmac_snd_role role; + bool sounding_sts[6]; + u16 grouping_bitmap; + bool mu_tx_en; + u32 given_gid_tab[2]; + u32 given_user_pos[4]; +}; + +struct halmac_su_bfer_init_para { + u8 userid; + u16 paid; + u16 csi_para; + union halmac_wlan_addr bfer_address; +}; + +struct halmac_mu_bfee_init_para { + u8 userid; + u16 paid; + u32 user_position_l; + u32 user_position_h; +}; + +struct halmac_mu_bfer_init_para { + u16 paid; + u16 csi_para; + u16 my_aid; + enum halmac_csi_seg_len csi_length_sel; + union halmac_wlan_addr bfer_address; +}; + +struct halmac_snd_info { + u16 paid; + u8 userid; + enum halmac_data_rate ndpa_rate; + u16 csi_para; + u16 my_aid; + enum halmac_data_rate csi_rate; + enum halmac_csi_seg_len csi_length_sel; + enum halmac_snd_role role; + union halmac_wlan_addr bfer_address; + enum halmac_bw bw; + u8 txbf_en; + struct halmac_su_bfer_init_para *su_bfer_init; + struct halmac_mu_bfer_init_para *mu_bfer_init; + struct halmac_mu_bfee_init_para *mu_bfee_init; +}; + +struct halmac_cs_info { + u8 *ch_info_buf; + u8 *ch_info_buf_w; + u8 extra_info_en; + u32 buf_size; /* buffer size */ + u32 avai_buf_size; /* buffer size */ + u32 total_size; + u32 accu_timeout; + u32 ch_num; +}; + +struct halmac_restore_info { + u32 mac_register; + u32 value; + u8 length; +}; + +struct halmac_event_trigger { + u32 physical_efuse_map : 1; + u32 logical_efuse_map : 1; + u32 rsvd1 : 28; +}; + +struct halmac_h2c_header_info { + u16 sub_cmd_id; + u16 content_size; + bool ack; +}; + +enum halmac_dlfw_state { + HALMAC_DLFW_NONE = 0, + HALMAC_DLFW_DONE = 1, + HALMAC_GEN_INFO_SENT = 2, + HALMAC_DLFW_UNDEFINED = 0x7F, +}; + +enum halmac_efuse_cmd_construct_state { + HALMAC_EFUSE_CMD_CONSTRUCT_IDLE = 0, + HALMAC_EFUSE_CMD_CONSTRUCT_BUSY = 1, + HALMAC_EFUSE_CMD_CONSTRUCT_H2C_SENT = 2, + HALMAC_EFUSE_CMD_CONSTRUCT_STATE_NUM = 3, + HALMAC_EFUSE_CMD_CONSTRUCT_UNDEFINED = 0x7F, +}; + +enum halmac_cfg_para_cmd_construct_state { + HALMAC_CFG_PARA_CMD_CONSTRUCT_IDLE = 0, + HALMAC_CFG_PARA_CMD_CONSTRUCT_CONSTRUCTING = 1, + HALMAC_CFG_PARA_CMD_CONSTRUCT_H2C_SENT = 2, + HALMAC_CFG_PARA_CMD_CONSTRUCT_NUM = 3, + HALMAC_CFG_PARA_CMD_CONSTRUCT_UNDEFINED = 0x7F, +}; + +enum halmac_scan_cmd_construct_state { + HALMAC_SCAN_CMD_CONSTRUCT_IDLE = 0, + HALMAC_SCAN_CMD_CONSTRUCT_BUFFER_CLEARED = 1, + HALMAC_SCAN_CMD_CONSTRUCT_CONSTRUCTING = 2, + HALMAC_SCAN_CMD_CONSTRUCT_H2C_SENT = 3, + HALMAC_SCAN_CMD_CONSTRUCT_STATE_NUM = 4, + HALMAC_SCAN_CMD_CONSTRUCT_UNDEFINED = 0x7F, +}; + +enum halmac_api_state { + HALMAC_API_STATE_INIT = 0, + HALMAC_API_STATE_HALT = 1, + HALMAC_API_STATE_UNDEFINED = 0x7F, +}; + +struct halmac_efuse_state_set { + enum halmac_efuse_cmd_construct_state efuse_cmd_construct_state; + enum halmac_cmd_process_status process_status; + u8 fw_return_code; + u16 seq_num; +}; + +struct halmac_cfg_para_state_set { + enum halmac_cfg_para_cmd_construct_state cfg_para_cmd_construct_state; + enum halmac_cmd_process_status process_status; + u8 fw_return_code; + u16 seq_num; +}; + +struct halmac_scan_state_set { + enum halmac_scan_cmd_construct_state scan_cmd_construct_state; + enum halmac_cmd_process_status process_status; + u8 fw_return_code; + u16 seq_num; +}; + +struct halmac_update_packet_state_set { + enum halmac_cmd_process_status process_status; + u8 fw_return_code; + u16 seq_num; +}; + +struct halmac_iqk_state_set { + enum halmac_cmd_process_status process_status; + u8 fw_return_code; + u16 seq_num; +}; + +struct halmac_power_tracking_state_set { + enum halmac_cmd_process_status process_status; + u8 fw_return_code; + u16 seq_num; +}; + +struct halmac_psd_state_set { + enum halmac_cmd_process_status process_status; + u16 data_size; + u16 segment_size; + u8 *data; + u8 fw_return_code; + u16 seq_num; +}; + +struct halmac_state { + struct halmac_efuse_state_set + efuse_state_set; /* State machine + cmd process status */ + struct halmac_cfg_para_state_set + cfg_para_state_set; /* State machine + cmd process status */ + struct halmac_scan_state_set + scan_state_set; /* State machine + cmd process status */ + struct halmac_update_packet_state_set + update_packet_set; /* cmd process status */ + struct halmac_iqk_state_set iqk_set; /* cmd process status */ + struct halmac_power_tracking_state_set + power_tracking_set; /* cmd process status */ + struct halmac_psd_state_set psd_set; /* cmd process status */ + enum halmac_api_state api_state; /* Halmac api state */ + enum halmac_mac_power mac_power; /* 0 : power off, 1 : power on*/ + enum halmac_ps_state ps_state; /* power saving state */ + enum halmac_dlfw_state dlfw_state; /* download FW state */ +}; + +struct halmac_ver { + u8 major_ver; + u8 prototype_ver; + u8 minor_ver; +}; + +enum halmac_api_id { + /*stuff, need to be the 1st*/ + HALMAC_API_STUFF = 0x0, + /*stuff, need to be the 1st*/ + HALMAC_API_MAC_POWER_SWITCH = 0x1, + HALMAC_API_DOWNLOAD_FIRMWARE = 0x2, + HALMAC_API_CFG_MAC_ADDR = 0x3, + HALMAC_API_CFG_BSSID = 0x4, + HALMAC_API_CFG_MULTICAST_ADDR = 0x5, + HALMAC_API_PRE_INIT_SYSTEM_CFG = 0x6, + HALMAC_API_INIT_SYSTEM_CFG = 0x7, + HALMAC_API_INIT_TRX_CFG = 0x8, + HALMAC_API_CFG_RX_AGGREGATION = 0x9, + HALMAC_API_INIT_PROTOCOL_CFG = 0xA, + HALMAC_API_INIT_EDCA_CFG = 0xB, + HALMAC_API_CFG_OPERATION_MODE = 0xC, + HALMAC_API_CFG_CH_BW = 0xD, + HALMAC_API_CFG_BW = 0xE, + HALMAC_API_INIT_WMAC_CFG = 0xF, + HALMAC_API_INIT_MAC_CFG = 0x10, + HALMAC_API_INIT_SDIO_CFG = 0x11, + HALMAC_API_INIT_USB_CFG = 0x12, + HALMAC_API_INIT_PCIE_CFG = 0x13, + HALMAC_API_INIT_INTERFACE_CFG = 0x14, + HALMAC_API_DEINIT_SDIO_CFG = 0x15, + HALMAC_API_DEINIT_USB_CFG = 0x16, + HALMAC_API_DEINIT_PCIE_CFG = 0x17, + HALMAC_API_DEINIT_INTERFACE_CFG = 0x18, + HALMAC_API_GET_EFUSE_SIZE = 0x19, + HALMAC_API_DUMP_EFUSE_MAP = 0x1A, + HALMAC_API_WRITE_EFUSE = 0x1B, + HALMAC_API_READ_EFUSE = 0x1C, + HALMAC_API_GET_LOGICAL_EFUSE_SIZE = 0x1D, + HALMAC_API_DUMP_LOGICAL_EFUSE_MAP = 0x1E, + HALMAC_API_WRITE_LOGICAL_EFUSE = 0x1F, + HALMAC_API_READ_LOGICAL_EFUSE = 0x20, + HALMAC_API_PG_EFUSE_BY_MAP = 0x21, + HALMAC_API_GET_C2H_INFO = 0x22, + HALMAC_API_CFG_FWLPS_OPTION = 0x23, + HALMAC_API_CFG_FWIPS_OPTION = 0x24, + HALMAC_API_ENTER_WOWLAN = 0x25, + HALMAC_API_LEAVE_WOWLAN = 0x26, + HALMAC_API_ENTER_PS = 0x27, + HALMAC_API_LEAVE_PS = 0x28, + HALMAC_API_H2C_LB = 0x29, + HALMAC_API_DEBUG = 0x2A, + HALMAC_API_CFG_PARAMETER = 0x2B, + HALMAC_API_UPDATE_PACKET = 0x2C, + HALMAC_API_BCN_IE_FILTER = 0x2D, + HALMAC_API_REG_READ_8 = 0x2E, + HALMAC_API_REG_WRITE_8 = 0x2F, + HALMAC_API_REG_READ_16 = 0x30, + HALMAC_API_REG_WRITE_16 = 0x31, + HALMAC_API_REG_READ_32 = 0x32, + HALMAC_API_REG_WRITE_32 = 0x33, + HALMAC_API_TX_ALLOWED_SDIO = 0x34, + HALMAC_API_SET_BULKOUT_NUM = 0x35, + HALMAC_API_GET_SDIO_TX_ADDR = 0x36, + HALMAC_API_GET_USB_BULKOUT_ID = 0x37, + HALMAC_API_TIMER_2S = 0x38, + HALMAC_API_FILL_TXDESC_CHECKSUM = 0x39, + HALMAC_API_SEND_ORIGINAL_H2C = 0x3A, + HALMAC_API_UPDATE_DATAPACK = 0x3B, + HALMAC_API_RUN_DATAPACK = 0x3C, + HALMAC_API_CFG_DRV_INFO = 0x3D, + HALMAC_API_SEND_BT_COEX = 0x3E, + HALMAC_API_VERIFY_PLATFORM_API = 0x3F, + HALMAC_API_GET_FIFO_SIZE = 0x40, + HALMAC_API_DUMP_FIFO = 0x41, + HALMAC_API_CFG_TXBF = 0x42, + HALMAC_API_CFG_MUMIMO = 0x43, + HALMAC_API_CFG_SOUNDING = 0x44, + HALMAC_API_DEL_SOUNDING = 0x45, + HALMAC_API_SU_BFER_ENTRY_INIT = 0x46, + HALMAC_API_SU_BFEE_ENTRY_INIT = 0x47, + HALMAC_API_MU_BFER_ENTRY_INIT = 0x48, + HALMAC_API_MU_BFEE_ENTRY_INIT = 0x49, + HALMAC_API_SU_BFER_ENTRY_DEL = 0x4A, + HALMAC_API_SU_BFEE_ENTRY_DEL = 0x4B, + HALMAC_API_MU_BFER_ENTRY_DEL = 0x4C, + HALMAC_API_MU_BFEE_ENTRY_DEL = 0x4D, + + HALMAC_API_ADD_CH_INFO = 0x4E, + HALMAC_API_ADD_EXTRA_CH_INFO = 0x4F, + HALMAC_API_CTRL_CH_SWITCH = 0x50, + HALMAC_API_CLEAR_CH_INFO = 0x51, + + HALMAC_API_SEND_GENERAL_INFO = 0x52, + HALMAC_API_START_IQK = 0x53, + HALMAC_API_CTRL_PWR_TRACKING = 0x54, + HALMAC_API_PSD = 0x55, + HALMAC_API_CFG_TX_AGG_ALIGN = 0x56, + + HALMAC_API_QUERY_STATE = 0x57, + HALMAC_API_RESET_FEATURE = 0x58, + HALMAC_API_CHECK_FW_STATUS = 0x59, + HALMAC_API_DUMP_FW_DMEM = 0x5A, + HALMAC_API_CFG_MAX_DL_SIZE = 0x5B, + + HALMAC_API_INIT_OBJ = 0x5C, + HALMAC_API_DEINIT_OBJ = 0x5D, + HALMAC_API_CFG_LA_MODE = 0x5E, + HALMAC_API_GET_HW_VALUE = 0x5F, + HALMAC_API_SET_HW_VALUE = 0x60, + HALMAC_API_CFG_DRV_RSVD_PG_NUM = 0x61, + HALMAC_API_SWITCH_EFUSE_BANK = 0x62, + HALMAC_API_WRITE_EFUSE_BT = 0x63, + HALMAC_API_DUMP_EFUSE_MAP_BT = 0x64, + HALMAC_API_DL_DRV_RSVD_PG = 0x65, + HALMAC_API_PCIE_SWITCH = 0x66, + HALMAC_API_PHY_CFG = 0x67, + HALMAC_API_CFG_RX_FIFO_EXPANDING_MODE = 0x68, + HALMAC_API_CFG_CSI_RATE = 0x69, + HALMAC_API_MAX +}; + +struct halmac_api_record { + enum halmac_api_id api_array[API_ARRAY_SIZE]; + u8 array_wptr; +}; + +enum halmac_la_mode { + HALMAC_LA_MODE_DISABLE = 0, + HALMAC_LA_MODE_PARTIAL = 1, + HALMAC_LA_MODE_FULL = 2, + HALMAC_LA_MODE_UNDEFINE = 0x7F, +}; + +enum halmac_rx_fifo_expanding_mode { + HALMAC_RX_FIFO_EXPANDING_MODE_DISABLE = 0, + HALMAC_RX_FIFO_EXPANDING_MODE_1_BLOCK = 1, + HALMAC_RX_FIFO_EXPANDING_MODE_2_BLOCK = 2, + HALMAC_RX_FIFO_EXPANDING_MODE_3_BLOCK = 3, + HALMAC_RX_FIFO_EXPANDING_MODE_UNDEFINE = 0x7F, +}; + +enum halmac_sdio_cmd53_4byte_mode { + HALMAC_SDIO_CMD53_4BYTE_MODE_DISABLE = 0, + HALMAC_SDIO_CMD53_4BYTE_MODE_RW = 1, + HALMAC_SDIO_CMD53_4BYTE_MODE_R = 2, + HALMAC_SDIO_CMD53_4BYTE_MODE_W = 3, + HALMAC_SDIO_CMD53_4BYTE_MODE_UNDEFINE = 0x7F, +}; + +enum halmac_usb_mode { + HALMAC_USB_MODE_U2 = 1, + HALMAC_USB_MODE_U3 = 2, +}; + +enum halmac_hw_id { + /* Get HW value */ + HALMAC_HW_RQPN_MAPPING = 0x00, + HALMAC_HW_EFUSE_SIZE = 0x01, + HALMAC_HW_EEPROM_SIZE = 0x02, + HALMAC_HW_BT_BANK_EFUSE_SIZE = 0x03, + HALMAC_HW_BT_BANK1_EFUSE_SIZE = 0x04, + HALMAC_HW_BT_BANK2_EFUSE_SIZE = 0x05, + HALMAC_HW_TXFIFO_SIZE = 0x06, + HALMAC_HW_RSVD_PG_BNDY = 0x07, + HALMAC_HW_CAM_ENTRY_NUM = 0x08, + HALMAC_HW_IC_VERSION = 0x09, + HALMAC_HW_PAGE_SIZE = 0x0A, + HALMAC_HW_TX_AGG_ALIGN_SIZE = 0x0B, + HALMAC_HW_RX_AGG_ALIGN_SIZE = 0x0C, + HALMAC_HW_DRV_INFO_SIZE = 0x0D, + HALMAC_HW_TXFF_ALLOCATION = 0x0E, + HALMAC_HW_RSVD_EFUSE_SIZE = 0x0F, + HALMAC_HW_FW_HDR_SIZE = 0x10, + HALMAC_HW_TX_DESC_SIZE = 0x11, + HALMAC_HW_RX_DESC_SIZE = 0x12, + HALMAC_HW_WLAN_EFUSE_AVAILABLE_SIZE = 0x13, + /* Set HW value */ + HALMAC_HW_USB_MODE = 0x60, + HALMAC_HW_SEQ_EN = 0x61, + HALMAC_HW_BANDWIDTH = 0x62, + HALMAC_HW_CHANNEL = 0x63, + HALMAC_HW_PRI_CHANNEL_IDX = 0x64, + HALMAC_HW_EN_BB_RF = 0x65, + HALMAC_HW_SDIO_TX_PAGE_THRESHOLD = 0x66, + HALMAC_HW_AMPDU_CONFIG = 0x67, + + HALMAC_HW_ID_UNDEFINE = 0x7F, +}; + +enum halmac_efuse_bank { + HALMAC_EFUSE_BANK_WIFI = 0, + HALMAC_EFUSE_BANK_BT = 1, + HALMAC_EFUSE_BANK_BT_1 = 2, + HALMAC_EFUSE_BANK_BT_2 = 3, + HALMAC_EFUSE_BANK_MAX, + HALMAC_EFUSE_BANK_UNDEFINE = 0X7F, +}; + +struct halmac_txff_allocation { + u16 tx_fifo_pg_num; + u16 rsvd_pg_num; + u16 rsvd_drv_pg_num; + u16 ac_q_pg_num; + u16 high_queue_pg_num; + u16 low_queue_pg_num; + u16 normal_queue_pg_num; + u16 extra_queue_pg_num; + u16 pub_queue_pg_num; + u16 rsvd_pg_bndy; + u16 rsvd_drv_pg_bndy; + u16 rsvd_h2c_extra_info_pg_bndy; + u16 rsvd_h2c_queue_pg_bndy; + u16 rsvd_cpu_instr_pg_bndy; + u16 rsvd_fw_txbuff_pg_bndy; + enum halmac_la_mode la_mode; + enum halmac_rx_fifo_expanding_mode rx_fifo_expanding_mode; +}; + +struct halmac_rqpn_map { + enum halmac_dma_mapping dma_map_vo; + enum halmac_dma_mapping dma_map_vi; + enum halmac_dma_mapping dma_map_be; + enum halmac_dma_mapping dma_map_bk; + enum halmac_dma_mapping dma_map_mg; + enum halmac_dma_mapping dma_map_hi; +}; + +struct halmac_security_setting { + u8 tx_encryption; + u8 rx_decryption; + u8 bip_enable; +}; + +struct halmac_cam_entry_info { + enum hal_security_type security_type; + u32 key[4]; + u32 key_ext[4]; + u8 mac_address[6]; + u8 unicast; + u8 key_id; + u8 valid; +}; + +struct halmac_cam_entry_format { + u16 key_id : 2; + u16 type : 3; + u16 mic : 1; + u16 grp : 1; + u16 spp_mode : 1; + u16 rpt_md : 1; + u16 ext_sectype : 1; + u16 mgnt : 1; + u16 rsvd1 : 4; + u16 valid : 1; + u8 mac_address[6]; + u32 key[4]; + u32 rsvd[2]; +}; + +struct halmac_tx_page_threshold_info { + u32 threshold; + enum halmac_dma_mapping dma_queue_sel; +}; + +struct halmac_ampdu_config { + u8 max_agg_num; +}; + +struct halmac_port_cfg { + u8 port0_sync_tsf; + u8 port1_sync_tsf; +}; + +struct halmac_rqpn_ { + enum halmac_trx_mode mode; + enum halmac_dma_mapping dma_map_vo; + enum halmac_dma_mapping dma_map_vi; + enum halmac_dma_mapping dma_map_be; + enum halmac_dma_mapping dma_map_bk; + enum halmac_dma_mapping dma_map_mg; + enum halmac_dma_mapping dma_map_hi; +}; + +struct halmac_pg_num_ { + enum halmac_trx_mode mode; + u16 hq_num; + u16 nq_num; + u16 lq_num; + u16 exq_num; + u16 gap_num; /*used for loopback mode*/ +}; + +struct halmac_intf_phy_para_ { + u16 offset; + u16 value; + u16 ip_sel; + u16 cut; + u16 plaform; +}; + +struct halmac_iqk_para_ { + u8 clear; + u8 segment_iqk; +}; + +/* Hal mac adapter */ +struct halmac_adapter { + /* Dma mapping of protocol queues */ + enum halmac_dma_mapping halmac_ptcl_queue[HALMAC_PTCL_QUEUE_NUM]; + /* low power state option */ + struct halmac_fwlps_option fwlps_option; + /* mac address information, suppot 2 ports */ + union halmac_wlan_addr hal_mac_addr[HALMAC_PORTIDMAX]; + /* bss address information, suppot 2 ports */ + union halmac_wlan_addr hal_bss_addr[HALMAC_PORTIDMAX]; + /* Protect h2c_packet_seq packet*/ + spinlock_t h2c_seq_lock; + /* Protect Efuse map memory of halmac_adapter */ + spinlock_t efuse_lock; + struct halmac_config_para_info config_para_info; + struct halmac_cs_info ch_sw_info; + struct halmac_event_trigger event_trigger; + /* HW related information */ + struct halmac_hw_config_info hw_config_info; + struct halmac_sdio_free_space sdio_free_space; + struct halmac_snd_info snd_info; + /* Backup HalAdapter address */ + void *hal_adapter_backup; + /* Driver or FW adapter address. Do not write this memory*/ + void *driver_adapter; + u8 *hal_efuse_map; + /* Record function pointer of halmac api */ + void *halmac_api; + /* Record function pointer of platform api */ + struct halmac_platform_api *halmac_platform_api; + /* Record efuse used memory */ + u32 efuse_end; + u32 h2c_buf_free_space; + u32 h2c_buff_size; + u32 max_download_size; + /* Chip ID, 8822B, 8821C... */ + enum halmac_chip_id chip_id; + /* A cut, B cut... */ + enum halmac_chip_ver chip_version; + struct halmac_fw_version fw_version; + struct halmac_state halmac_state; + /* Interface information, get from driver */ + enum halmac_interface halmac_interface; + /* Noraml, WMM, P2P, LoopBack... */ + enum halmac_trx_mode trx_mode; + struct halmac_txff_allocation txff_allocation; + u8 h2c_packet_seq; /* current h2c packet sequence number */ + u16 ack_h2c_packet_seq; /*the acked h2c packet sequence number */ + bool hal_efuse_map_valid; + u8 efuse_segment_size; + u8 rpwm_record; /* record rpwm value */ + bool low_clk; /*LPS 32K or IPS 32K*/ + u8 halmac_bulkout_num; /* USB bulkout num */ + struct halmac_api_record api_record; /* API record */ + bool gen_info_valid; + struct halmac_general_info general_info; + u8 drv_info_size; + enum halmac_sdio_cmd53_4byte_mode sdio_cmd53_4byte; +}; + +/* Function pointer of Hal mac API */ +struct halmac_api { + enum halmac_ret_status (*halmac_mac_power_switch)( + struct halmac_adapter *halmac_adapter, + enum halmac_mac_power halmac_power); + enum halmac_ret_status (*halmac_download_firmware)( + struct halmac_adapter *halmac_adapter, u8 *hamacl_fw, + u32 halmac_fw_size); + enum halmac_ret_status (*halmac_free_download_firmware)( + struct halmac_adapter *halmac_adapter, + enum halmac_dlfw_mem dlfw_mem, u8 *hamacl_fw, + u32 halmac_fw_size); + enum halmac_ret_status (*halmac_get_fw_version)( + struct halmac_adapter *halmac_adapter, + struct halmac_fw_version *fw_version); + enum halmac_ret_status (*halmac_cfg_mac_addr)( + struct halmac_adapter *halmac_adapter, u8 halmac_port, + union halmac_wlan_addr *hal_address); + enum halmac_ret_status (*halmac_cfg_bssid)( + struct halmac_adapter *halmac_adapter, u8 halmac_port, + union halmac_wlan_addr *hal_address); + enum halmac_ret_status (*halmac_cfg_multicast_addr)( + struct halmac_adapter *halmac_adapter, + union halmac_wlan_addr *hal_address); + enum halmac_ret_status (*halmac_pre_init_system_cfg)( + struct halmac_adapter *halmac_adapter); + enum halmac_ret_status (*halmac_init_system_cfg)( + struct halmac_adapter *halmac_adapter); + enum halmac_ret_status (*halmac_init_trx_cfg)( + struct halmac_adapter *halmac_adapter, + enum halmac_trx_mode mode); + enum halmac_ret_status (*halmac_init_h2c)( + struct halmac_adapter *halmac_adapter); + enum halmac_ret_status (*halmac_cfg_rx_aggregation)( + struct halmac_adapter *halmac_adapter, + struct halmac_rxagg_cfg *phalmac_rxagg_cfg); + enum halmac_ret_status (*halmac_init_protocol_cfg)( + struct halmac_adapter *halmac_adapter); + enum halmac_ret_status (*halmac_init_edca_cfg)( + struct halmac_adapter *halmac_adapter); + enum halmac_ret_status (*halmac_cfg_operation_mode)( + struct halmac_adapter *halmac_adapter, + enum halmac_wireless_mode wireless_mode); + enum halmac_ret_status (*halmac_cfg_ch_bw)( + struct halmac_adapter *halmac_adapter, u8 channel, + enum halmac_pri_ch_idx pri_ch_idx, enum halmac_bw bw); + enum halmac_ret_status (*halmac_cfg_bw)( + struct halmac_adapter *halmac_adapter, enum halmac_bw bw); + enum halmac_ret_status (*halmac_init_wmac_cfg)( + struct halmac_adapter *halmac_adapter); + enum halmac_ret_status (*halmac_init_mac_cfg)( + struct halmac_adapter *halmac_adapter, + enum halmac_trx_mode mode); + enum halmac_ret_status (*halmac_init_sdio_cfg)( + struct halmac_adapter *halmac_adapter); + enum halmac_ret_status (*halmac_init_usb_cfg)( + struct halmac_adapter *halmac_adapter); + enum halmac_ret_status (*halmac_init_pcie_cfg)( + struct halmac_adapter *halmac_adapter); + enum halmac_ret_status (*halmac_init_interface_cfg)( + struct halmac_adapter *halmac_adapter); + enum halmac_ret_status (*halmac_deinit_sdio_cfg)( + struct halmac_adapter *halmac_adapter); + enum halmac_ret_status (*halmac_deinit_usb_cfg)( + struct halmac_adapter *halmac_adapter); + enum halmac_ret_status (*halmac_deinit_pcie_cfg)( + struct halmac_adapter *halmac_adapter); + enum halmac_ret_status (*halmac_deinit_interface_cfg)( + struct halmac_adapter *halmac_adapter); + enum halmac_ret_status (*halmac_get_efuse_size)( + struct halmac_adapter *halmac_adapter, u32 *halmac_size); + enum halmac_ret_status (*halmac_get_efuse_available_size)( + struct halmac_adapter *halmac_adapter, u32 *halmac_size); + enum halmac_ret_status (*halmac_dump_efuse_map)( + struct halmac_adapter *halmac_adapter, + enum halmac_efuse_read_cfg cfg); + enum halmac_ret_status (*halmac_dump_efuse_map_bt)( + struct halmac_adapter *halmac_adapter, + enum halmac_efuse_bank halmac_efues_bank, u32 bt_efuse_map_size, + u8 *bt_efuse_map); + enum halmac_ret_status (*halmac_write_efuse)( + struct halmac_adapter *halmac_adapter, u32 halmac_offset, + u8 halmac_value); + enum halmac_ret_status (*halmac_read_efuse)( + struct halmac_adapter *halmac_adapter, u32 halmac_offset, + u8 *value); + enum halmac_ret_status (*halmac_switch_efuse_bank)( + struct halmac_adapter *halmac_adapter, + enum halmac_efuse_bank halmac_efues_bank); + enum halmac_ret_status (*halmac_write_efuse_bt)( + struct halmac_adapter *halmac_adapter, u32 halmac_offset, + u8 halmac_value, enum halmac_efuse_bank halmac_efues_bank); + enum halmac_ret_status (*halmac_get_logical_efuse_size)( + struct halmac_adapter *halmac_adapter, u32 *halmac_size); + enum halmac_ret_status (*halmac_dump_logical_efuse_map)( + struct halmac_adapter *halmac_adapter, + enum halmac_efuse_read_cfg cfg); + enum halmac_ret_status (*halmac_write_logical_efuse)( + struct halmac_adapter *halmac_adapter, u32 halmac_offset, + u8 halmac_value); + enum halmac_ret_status (*halmac_read_logical_efuse)( + struct halmac_adapter *halmac_adapter, u32 halmac_offset, + u8 *value); + enum halmac_ret_status (*halmac_pg_efuse_by_map)( + struct halmac_adapter *halmac_adapter, + struct halmac_pg_efuse_info *pg_efuse_info, + enum halmac_efuse_read_cfg cfg); + enum halmac_ret_status (*halmac_get_c2h_info)( + struct halmac_adapter *halmac_adapter, u8 *halmac_buf, + u32 halmac_size); + enum halmac_ret_status (*halmac_cfg_fwlps_option)( + struct halmac_adapter *halmac_adapter, + struct halmac_fwlps_option *lps_option); + enum halmac_ret_status (*halmac_cfg_fwips_option)( + struct halmac_adapter *halmac_adapter, + struct halmac_fwips_option *ips_option); + enum halmac_ret_status (*halmac_enter_wowlan)( + struct halmac_adapter *halmac_adapter, + struct halmac_wowlan_option *wowlan_option); + enum halmac_ret_status (*halmac_leave_wowlan)( + struct halmac_adapter *halmac_adapter); + enum halmac_ret_status (*halmac_enter_ps)( + struct halmac_adapter *halmac_adapter, + enum halmac_ps_state ps_state); + enum halmac_ret_status (*halmac_leave_ps)( + struct halmac_adapter *halmac_adapter); + enum halmac_ret_status (*halmac_h2c_lb)( + struct halmac_adapter *halmac_adapter); + enum halmac_ret_status (*halmac_debug)( + struct halmac_adapter *halmac_adapter); + enum halmac_ret_status (*halmac_cfg_parameter)( + struct halmac_adapter *halmac_adapter, + struct halmac_phy_parameter_info *para_info, u8 full_fifo); + enum halmac_ret_status (*halmac_update_packet)( + struct halmac_adapter *halmac_adapter, + enum halmac_packet_id pkt_id, u8 *pkt, u32 pkt_size); + enum halmac_ret_status (*halmac_bcn_ie_filter)( + struct halmac_adapter *halmac_adapter, + struct halmac_bcn_ie_info *bcn_ie_info); + u8 (*halmac_reg_read_8)(struct halmac_adapter *halmac_adapter, + u32 halmac_offset); + enum halmac_ret_status (*halmac_reg_write_8)( + struct halmac_adapter *halmac_adapter, u32 halmac_offset, + u8 halmac_data); + u16 (*halmac_reg_read_16)(struct halmac_adapter *halmac_adapter, + u32 halmac_offset); + enum halmac_ret_status (*halmac_reg_write_16)( + struct halmac_adapter *halmac_adapter, u32 halmac_offset, + u16 halmac_data); + u32 (*halmac_reg_read_32)(struct halmac_adapter *halmac_adapter, + u32 halmac_offset); + u32 (*halmac_reg_read_indirect_32)( + struct halmac_adapter *halmac_adapter, u32 halmac_offset); + u8 (*halmac_reg_sdio_cmd53_read_n)( + struct halmac_adapter *halmac_adapter, u32 halmac_offset, + u32 halmac_size, u8 *halmac_data); + enum halmac_ret_status (*halmac_reg_write_32)( + struct halmac_adapter *halmac_adapter, u32 halmac_offset, + u32 halmac_data); + enum halmac_ret_status (*halmac_tx_allowed_sdio)( + struct halmac_adapter *halmac_adapter, u8 *halmac_buf, + u32 halmac_size); + enum halmac_ret_status (*halmac_set_bulkout_num)( + struct halmac_adapter *halmac_adapter, u8 bulkout_num); + enum halmac_ret_status (*halmac_get_sdio_tx_addr)( + struct halmac_adapter *halmac_adapter, u8 *halmac_buf, + u32 halmac_size, u32 *pcmd53_addr); + enum halmac_ret_status (*halmac_get_usb_bulkout_id)( + struct halmac_adapter *halmac_adapter, u8 *halmac_buf, + u32 halmac_size, u8 *bulkout_id); + enum halmac_ret_status (*halmac_timer_2s)( + struct halmac_adapter *halmac_adapter); + enum halmac_ret_status (*halmac_fill_txdesc_checksum)( + struct halmac_adapter *halmac_adapter, u8 *cur_desc); + enum halmac_ret_status (*halmac_update_datapack)( + struct halmac_adapter *halmac_adapter, + enum halmac_data_type halmac_data_type, + struct halmac_phy_parameter_info *para_info); + enum halmac_ret_status (*halmac_run_datapack)( + struct halmac_adapter *halmac_adapter, + enum halmac_data_type halmac_data_type); + enum halmac_ret_status (*halmac_cfg_drv_info)( + struct halmac_adapter *halmac_adapter, + enum halmac_drv_info halmac_drv_info); + enum halmac_ret_status (*halmac_send_bt_coex)( + struct halmac_adapter *halmac_adapter, u8 *bt_buf, u32 bt_size, + u8 ack); + enum halmac_ret_status (*halmac_verify_platform_api)( + struct halmac_adapter *halmac_adapte); + u32 (*halmac_get_fifo_size)(struct halmac_adapter *halmac_adapter, + enum hal_fifo_sel halmac_fifo_sel); + enum halmac_ret_status (*halmac_dump_fifo)( + struct halmac_adapter *halmac_adapter, + enum hal_fifo_sel halmac_fifo_sel, u32 halmac_start_addr, + u32 halmac_fifo_dump_size, u8 *fifo_map); + enum halmac_ret_status (*halmac_cfg_txbf)( + struct halmac_adapter *halmac_adapter, u8 userid, + enum halmac_bw bw, u8 txbf_en); + enum halmac_ret_status (*halmac_cfg_mumimo)( + struct halmac_adapter *halmac_adapter, + struct halmac_cfg_mumimo_para *cfgmu); + enum halmac_ret_status (*halmac_cfg_sounding)( + struct halmac_adapter *halmac_adapter, + enum halmac_snd_role role, enum halmac_data_rate datarate); + enum halmac_ret_status (*halmac_del_sounding)( + struct halmac_adapter *halmac_adapter, + enum halmac_snd_role role); + enum halmac_ret_status (*halmac_su_bfer_entry_init)( + struct halmac_adapter *halmac_adapter, + struct halmac_su_bfer_init_para *su_bfer_init); + enum halmac_ret_status (*halmac_su_bfee_entry_init)( + struct halmac_adapter *halmac_adapter, u8 userid, u16 paid); + enum halmac_ret_status (*halmac_mu_bfer_entry_init)( + struct halmac_adapter *halmac_adapter, + struct halmac_mu_bfer_init_para *mu_bfer_init); + enum halmac_ret_status (*halmac_mu_bfee_entry_init)( + struct halmac_adapter *halmac_adapter, + struct halmac_mu_bfee_init_para *mu_bfee_init); + enum halmac_ret_status (*halmac_su_bfer_entry_del)( + struct halmac_adapter *halmac_adapter, u8 userid); + enum halmac_ret_status (*halmac_su_bfee_entry_del)( + struct halmac_adapter *halmac_adapter, u8 userid); + enum halmac_ret_status (*halmac_mu_bfer_entry_del)( + struct halmac_adapter *halmac_adapter); + enum halmac_ret_status (*halmac_mu_bfee_entry_del)( + struct halmac_adapter *halmac_adapter, u8 userid); + enum halmac_ret_status (*halmac_add_ch_info)( + struct halmac_adapter *halmac_adapter, + struct halmac_ch_info *ch_info); + enum halmac_ret_status (*halmac_add_extra_ch_info)( + struct halmac_adapter *halmac_adapter, + struct halmac_ch_extra_info *ch_extra_info); + enum halmac_ret_status (*halmac_ctrl_ch_switch)( + struct halmac_adapter *halmac_adapter, + struct halmac_ch_switch_option *cs_option); + enum halmac_ret_status (*halmac_p2pps)( + struct halmac_adapter *halmac_adapter, + struct halmac_p2pps *p2p_ps); + enum halmac_ret_status (*halmac_clear_ch_info)( + struct halmac_adapter *halmac_adapter); + enum halmac_ret_status (*halmac_send_general_info)( + struct halmac_adapter *halmac_adapter, + struct halmac_general_info *pg_general_info); + enum halmac_ret_status (*halmac_start_iqk)( + struct halmac_adapter *halmac_adapter, + struct halmac_iqk_para_ *iqk_para); + enum halmac_ret_status (*halmac_ctrl_pwr_tracking)( + struct halmac_adapter *halmac_adapter, + struct halmac_pwr_tracking_option *pwr_tracking_opt); + enum halmac_ret_status (*halmac_psd)( + struct halmac_adapter *halmac_adapter, u16 start_psd, + u16 end_psd); + enum halmac_ret_status (*halmac_cfg_tx_agg_align)( + struct halmac_adapter *halmac_adapter, u8 enable, + u16 align_size); + enum halmac_ret_status (*halmac_query_status)( + struct halmac_adapter *halmac_adapter, + enum halmac_feature_id feature_id, + enum halmac_cmd_process_status *process_status, u8 *data, + u32 *size); + enum halmac_ret_status (*halmac_reset_feature)( + struct halmac_adapter *halmac_adapter, + enum halmac_feature_id feature_id); + enum halmac_ret_status (*halmac_check_fw_status)( + struct halmac_adapter *halmac_adapter, bool *fw_status); + enum halmac_ret_status (*halmac_dump_fw_dmem)( + struct halmac_adapter *halmac_adapter, u8 *dmem, u32 *size); + enum halmac_ret_status (*halmac_cfg_max_dl_size)( + struct halmac_adapter *halmac_adapter, u32 size); + enum halmac_ret_status (*halmac_cfg_la_mode)( + struct halmac_adapter *halmac_adapter, + enum halmac_la_mode la_mode); + enum halmac_ret_status (*halmac_cfg_rx_fifo_expanding_mode)( + struct halmac_adapter *halmac_adapter, + enum halmac_rx_fifo_expanding_mode rx_fifo_expanding_mode); + enum halmac_ret_status (*halmac_config_security)( + struct halmac_adapter *halmac_adapter, + struct halmac_security_setting *sec_setting); + u8 (*halmac_get_used_cam_entry_num)( + struct halmac_adapter *halmac_adapter, + enum hal_security_type sec_type); + enum halmac_ret_status (*halmac_write_cam)( + struct halmac_adapter *halmac_adapter, u32 entry_index, + struct halmac_cam_entry_info *cam_entry_info); + enum halmac_ret_status (*halmac_read_cam_entry)( + struct halmac_adapter *halmac_adapter, u32 entry_index, + struct halmac_cam_entry_format *content); + enum halmac_ret_status (*halmac_clear_cam_entry)( + struct halmac_adapter *halmac_adapter, u32 entry_index); + enum halmac_ret_status (*halmac_get_hw_value)( + struct halmac_adapter *halmac_adapter, enum halmac_hw_id hw_id, + void *pvalue); + enum halmac_ret_status (*halmac_set_hw_value)( + struct halmac_adapter *halmac_adapter, enum halmac_hw_id hw_id, + void *pvalue); + enum halmac_ret_status (*halmac_cfg_drv_rsvd_pg_num)( + struct halmac_adapter *halmac_adapter, + enum halmac_drv_rsvd_pg_num pg_num); + enum halmac_ret_status (*halmac_get_chip_version)( + struct halmac_adapter *halmac_adapter, + struct halmac_ver *version); + enum halmac_ret_status (*halmac_chk_txdesc)( + struct halmac_adapter *halmac_adapter, u8 *halmac_buf, + u32 halmac_size); + enum halmac_ret_status (*halmac_dl_drv_rsvd_page)( + struct halmac_adapter *halmac_adapter, u8 pg_offset, + u8 *hal_buf, u32 size); + enum halmac_ret_status (*halmac_pcie_switch)( + struct halmac_adapter *halmac_adapter, + enum halmac_pcie_cfg pcie_cfg); + enum halmac_ret_status (*halmac_phy_cfg)( + struct halmac_adapter *halmac_adapter, + enum halmac_intf_phy_platform platform); + enum halmac_ret_status (*halmac_cfg_csi_rate)( + struct halmac_adapter *halmac_adapter, u8 rssi, u8 current_rate, + u8 fixrate_en, u8 *new_rate); + enum halmac_ret_status (*halmac_sdio_cmd53_4byte)( + struct halmac_adapter *halmac_adapter, + enum halmac_sdio_cmd53_4byte_mode cmd53_4byte_mode); + enum halmac_ret_status (*halmac_interface_integration_tuning)( + struct halmac_adapter *halmac_adapter); + enum halmac_ret_status (*halmac_txfifo_is_empty)( + struct halmac_adapter *halmac_adapter, u32 chk_num); +}; + +#define HALMAC_GET_API(phalmac_adapter) \ + ((struct halmac_api *)phalmac_adapter->halmac_api) + +static inline enum halmac_ret_status +halmac_adapter_validate(struct halmac_adapter *halmac_adapter) +{ + if ((!halmac_adapter) || + (halmac_adapter->hal_adapter_backup != halmac_adapter)) + return HALMAC_RET_ADAPTER_INVALID; + + return HALMAC_RET_SUCCESS; +} + +static inline enum halmac_ret_status +halmac_api_validate(struct halmac_adapter *halmac_adapter) +{ + if (halmac_adapter->halmac_state.api_state != HALMAC_API_STATE_INIT) + return HALMAC_RET_API_INVALID; + + return HALMAC_RET_SUCCESS; +} + +static inline enum halmac_ret_status +halmac_fw_validate(struct halmac_adapter *halmac_adapter) +{ + if (halmac_adapter->halmac_state.dlfw_state != HALMAC_DLFW_DONE && + halmac_adapter->halmac_state.dlfw_state != HALMAC_GEN_INFO_SENT) + return HALMAC_RET_NO_DLFW; + + return HALMAC_RET_SUCCESS; +} + +#endif diff --git a/drivers/staging/rtlwifi/halmac/halmac_usb_reg.h b/drivers/staging/rtlwifi/halmac/halmac_usb_reg.h new file mode 100644 index 000000000000..d6e721ea7463 --- /dev/null +++ b/drivers/staging/rtlwifi/halmac/halmac_usb_reg.h @@ -0,0 +1,28 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef __HALMAC_USB_REG_H__ +#define __HALMAC_USB_REG_H__ + +#endif /* __HALMAC_USB_REG_H__ */ diff --git a/drivers/staging/rtlwifi/halmac/rtl_halmac.c b/drivers/staging/rtlwifi/halmac/rtl_halmac.c new file mode 100644 index 000000000000..6448a8bfc14b --- /dev/null +++ b/drivers/staging/rtlwifi/halmac/rtl_halmac.c @@ -0,0 +1,1384 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include "halmac_api.h" +#include "rtl_halmac.h" +#include <linux/module.h> +#include <linux/vmalloc.h> + +#define DEFAULT_INDICATOR_TIMELMT msecs_to_jiffies(1000) /* ms */ +#define FIRMWARE_MAX_SIZE HALMAC_FW_SIZE_MAX_88XX + +static struct rtl_halmac_ops rtl_halmac_operation = { + .halmac_init_adapter = rtl_halmac_init_adapter, + .halmac_deinit_adapter = rtl_halmac_deinit_adapter, + .halmac_init_hal = rtl_halmac_init_hal, + .halmac_deinit_hal = rtl_halmac_deinit_hal, + .halmac_poweron = rtl_halmac_poweron, + .halmac_poweroff = rtl_halmac_poweroff, + + .halmac_phy_power_switch = rtl_halmac_phy_power_switch, + .halmac_set_mac_address = rtl_halmac_set_mac_address, + .halmac_set_bssid = rtl_halmac_set_bssid, + + .halmac_get_physical_efuse_size = rtl_halmac_get_physical_efuse_size, + .halmac_read_physical_efuse_map = rtl_halmac_read_physical_efuse_map, + .halmac_get_logical_efuse_size = rtl_halmac_get_logical_efuse_size, + .halmac_read_logical_efuse_map = rtl_halmac_read_logical_efuse_map, + + .halmac_set_bandwidth = rtl_halmac_set_bandwidth, + + .halmac_c2h_handle = rtl_halmac_c2h_handle, + + .halmac_chk_txdesc = rtl_halmac_chk_txdesc, +}; + +struct rtl_halmac_ops *rtl_halmac_get_ops_pointer(void) +{ + return &rtl_halmac_operation; +} +EXPORT_SYMBOL(rtl_halmac_get_ops_pointer); + +/* + * Driver API for HALMAC operations + */ + +static u8 _halmac_reg_read_8(void *p, u32 offset) +{ + struct rtl_priv *rtlpriv = (struct rtl_priv *)p; + + return rtl_read_byte(rtlpriv, offset); +} + +static u16 _halmac_reg_read_16(void *p, u32 offset) +{ + struct rtl_priv *rtlpriv = (struct rtl_priv *)p; + + return rtl_read_word(rtlpriv, offset); +} + +static u32 _halmac_reg_read_32(void *p, u32 offset) +{ + struct rtl_priv *rtlpriv = (struct rtl_priv *)p; + + return rtl_read_dword(rtlpriv, offset); +} + +static void _halmac_reg_write_8(void *p, u32 offset, u8 val) +{ + struct rtl_priv *rtlpriv = (struct rtl_priv *)p; + + rtl_write_byte(rtlpriv, offset, val); +} + +static void _halmac_reg_write_16(void *p, u32 offset, u16 val) +{ + struct rtl_priv *rtlpriv = (struct rtl_priv *)p; + + rtl_write_word(rtlpriv, offset, val); +} + +static void _halmac_reg_write_32(void *p, u32 offset, u32 val) +{ + struct rtl_priv *rtlpriv = (struct rtl_priv *)p; + + rtl_write_dword(rtlpriv, offset, val); +} + +static bool _halmac_write_data_rsvd_page(void *p, u8 *buf, u32 size) +{ + struct rtl_priv *rtlpriv = (struct rtl_priv *)p; + + if (rtlpriv->cfg->ops->halmac_cb_write_data_rsvd_page && + rtlpriv->cfg->ops->halmac_cb_write_data_rsvd_page(rtlpriv, buf, + size)) + return true; + + return false; +} + +static bool _halmac_write_data_h2c(void *p, u8 *buf, u32 size) +{ + struct rtl_priv *rtlpriv = (struct rtl_priv *)p; + + if (rtlpriv->cfg->ops->halmac_cb_write_data_h2c && + rtlpriv->cfg->ops->halmac_cb_write_data_h2c(rtlpriv, buf, size)) + return true; + + return false; +} + +static const char *const RTL_HALMAC_FEATURE_NAME[] = { + "HALMAC_FEATURE_CFG_PARA", + "HALMAC_FEATURE_DUMP_PHYSICAL_EFUSE", + "HALMAC_FEATURE_DUMP_LOGICAL_EFUSE", + "HALMAC_FEATURE_UPDATE_PACKET", + "HALMAC_FEATURE_UPDATE_DATAPACK", + "HALMAC_FEATURE_RUN_DATAPACK", + "HALMAC_FEATURE_CHANNEL_SWITCH", + "HALMAC_FEATURE_IQK", + "HALMAC_FEATURE_POWER_TRACKING", + "HALMAC_FEATURE_PSD", + "HALMAC_FEATURE_ALL"}; + +static inline bool is_valid_id_status(struct rtl_priv *rtlpriv, + enum halmac_feature_id id, + enum halmac_cmd_process_status status) +{ + switch (id) { + case HALMAC_FEATURE_CFG_PARA: + RT_TRACE(rtlpriv, COMP_HALMAC, DBG_LOUD, "%s: %s\n", __func__, + RTL_HALMAC_FEATURE_NAME[id]); + break; + case HALMAC_FEATURE_DUMP_PHYSICAL_EFUSE: + RT_TRACE(rtlpriv, COMP_HALMAC, DBG_LOUD, "%s: %s\n", __func__, + RTL_HALMAC_FEATURE_NAME[id]); + if (status != HALMAC_CMD_PROCESS_DONE) { + RT_TRACE(rtlpriv, COMP_HALMAC, DBG_LOUD, + "%s: <WARN> id(%d) unspecified status(%d)!\n", + __func__, id, status); + } + break; + case HALMAC_FEATURE_DUMP_LOGICAL_EFUSE: + RT_TRACE(rtlpriv, COMP_HALMAC, DBG_LOUD, "%s: %s\n", __func__, + RTL_HALMAC_FEATURE_NAME[id]); + if (status != HALMAC_CMD_PROCESS_DONE) { + RT_TRACE(rtlpriv, COMP_HALMAC, DBG_LOUD, + "%s: <WARN> id(%d) unspecified status(%d)!\n", + __func__, id, status); + } + break; + case HALMAC_FEATURE_UPDATE_PACKET: + RT_TRACE(rtlpriv, COMP_HALMAC, DBG_LOUD, "%s: %s\n", __func__, + RTL_HALMAC_FEATURE_NAME[id]); + break; + case HALMAC_FEATURE_UPDATE_DATAPACK: + RT_TRACE(rtlpriv, COMP_HALMAC, DBG_LOUD, "%s: %s\n", __func__, + RTL_HALMAC_FEATURE_NAME[id]); + break; + case HALMAC_FEATURE_RUN_DATAPACK: + RT_TRACE(rtlpriv, COMP_HALMAC, DBG_LOUD, "%s: %s\n", __func__, + RTL_HALMAC_FEATURE_NAME[id]); + break; + case HALMAC_FEATURE_CHANNEL_SWITCH: + RT_TRACE(rtlpriv, COMP_HALMAC, DBG_LOUD, "%s: %s\n", __func__, + RTL_HALMAC_FEATURE_NAME[id]); + break; + case HALMAC_FEATURE_IQK: + RT_TRACE(rtlpriv, COMP_HALMAC, DBG_LOUD, "%s: %s\n", __func__, + RTL_HALMAC_FEATURE_NAME[id]); + break; + case HALMAC_FEATURE_POWER_TRACKING: + RT_TRACE(rtlpriv, COMP_HALMAC, DBG_LOUD, "%s: %s\n", __func__, + RTL_HALMAC_FEATURE_NAME[id]); + break; + case HALMAC_FEATURE_PSD: + RT_TRACE(rtlpriv, COMP_HALMAC, DBG_LOUD, "%s: %s\n", __func__, + RTL_HALMAC_FEATURE_NAME[id]); + break; + case HALMAC_FEATURE_ALL: + RT_TRACE(rtlpriv, COMP_HALMAC, DBG_LOUD, "%s: %s\n", __func__, + RTL_HALMAC_FEATURE_NAME[id]); + break; + default: + RT_TRACE(rtlpriv, COMP_HALMAC, DBG_LOUD, + "%s: unknown feature id(%d)\n", __func__, id); + return false; + } + + return true; +} + +static int init_halmac_event_with_waittime(struct rtl_priv *rtlpriv, + enum halmac_feature_id id, u8 *buf, + u32 size, u32 time) +{ + struct completion *comp; + + if (!rtlpriv->halmac.indicator[id].comp) { + comp = kzalloc(sizeof(*comp), GFP_KERNEL); + if (!comp) + return -1; + } else { + RT_TRACE(rtlpriv, COMP_HALMAC, DBG_LOUD, + "%s: <WARN> id(%d) sctx is not NULL!!\n", __func__, + id); + comp = rtlpriv->halmac.indicator[id].comp; + rtlpriv->halmac.indicator[id].comp = NULL; + } + + init_completion(comp); + rtlpriv->halmac.indicator[id].wait_ms = time; + + rtlpriv->halmac.indicator[id].buffer = buf; + rtlpriv->halmac.indicator[id].buf_size = size; + rtlpriv->halmac.indicator[id].ret_size = 0; + rtlpriv->halmac.indicator[id].status = 0; + /* fill sctx at least to sure other variables are all ready! */ + rtlpriv->halmac.indicator[id].comp = comp; + + return 0; +} + +static inline int init_halmac_event(struct rtl_priv *rtlpriv, + enum halmac_feature_id id, u8 *buf, + u32 size) +{ + return init_halmac_event_with_waittime(rtlpriv, id, buf, size, + DEFAULT_INDICATOR_TIMELMT); +} + +static void free_halmac_event(struct rtl_priv *rtlpriv, + enum halmac_feature_id id) +{ + struct completion *comp; + + if (!rtlpriv->halmac.indicator[id].comp) + return; + + comp = rtlpriv->halmac.indicator[id].comp; + rtlpriv->halmac.indicator[id].comp = NULL; + kfree(comp); +} + +static int wait_halmac_event(struct rtl_priv *rtlpriv, + enum halmac_feature_id id) +{ + struct completion *comp; + int ret; + + comp = rtlpriv->halmac.indicator[id].comp; + if (!comp) + return -1; + + ret = wait_for_completion_timeout( + comp, rtlpriv->halmac.indicator[id].wait_ms); + free_halmac_event(rtlpriv, id); + if (ret > 0) + return 0; + + return -1; +} + +/* + * Return: + * Always return true, HALMAC don't care the return value. + */ +static bool +_halmac_event_indication(void *p, enum halmac_feature_id feature_id, + enum halmac_cmd_process_status process_status, u8 *buf, + u32 size) +{ + struct rtl_priv *rtlpriv; + struct rtl_halmac_indicator *tbl, *indicator; + struct completion *comp; + u32 cpsz; + bool ret; + + rtlpriv = (struct rtl_priv *)p; + tbl = rtlpriv->halmac.indicator; + + ret = is_valid_id_status(rtlpriv, feature_id, process_status); + if (!ret) + goto exit; + + indicator = &tbl[feature_id]; + indicator->status = process_status; + indicator->ret_size = size; + if (!indicator->comp) { + RT_TRACE(rtlpriv, COMP_HALMAC, DBG_LOUD, + "%s: No feature id(%d) waiting!!\n", __func__, + feature_id); + goto exit; + } + comp = indicator->comp; + + if (process_status == HALMAC_CMD_PROCESS_ERROR) { + RT_TRACE(rtlpriv, COMP_HALMAC, DBG_LOUD, + "%s: Something wrong id(%d)!!\n", __func__, + feature_id); + complete(comp); /* may provide error code */ + goto exit; + } + + if (size > indicator->buf_size) { + RT_TRACE( + rtlpriv, COMP_HALMAC, DBG_LOUD, + "%s: <WARN> id(%d) buffer is not enough(%d<%d), data will be truncated!\n", + __func__, feature_id, indicator->buf_size, size); + cpsz = indicator->buf_size; + } else { + cpsz = size; + } + + if (cpsz && indicator->buffer) + memcpy(indicator->buffer, buf, cpsz); + + complete(comp); + +exit: + return true; +} + +static struct halmac_platform_api rtl_halmac_platform_api = { + /* R/W register */ + .REG_READ_8 = _halmac_reg_read_8, + .REG_READ_16 = _halmac_reg_read_16, + .REG_READ_32 = _halmac_reg_read_32, + .REG_WRITE_8 = _halmac_reg_write_8, + .REG_WRITE_16 = _halmac_reg_write_16, + .REG_WRITE_32 = _halmac_reg_write_32, + + /* Write data */ + /* impletement in HAL-IC level */ + .SEND_RSVD_PAGE = _halmac_write_data_rsvd_page, + .SEND_H2C_PKT = _halmac_write_data_h2c, + + .EVENT_INDICATION = _halmac_event_indication, +}; + +static int init_priv(struct rtl_halmac *halmac) +{ + struct rtl_halmac_indicator *indicator; + u32 count, size; + + halmac->send_general_info = 0; + + count = HALMAC_FEATURE_ALL + 1; + size = sizeof(*indicator) * count; + indicator = kzalloc(size, GFP_KERNEL); + if (!indicator) + return -1; + halmac->indicator = indicator; + + return 0; +} + +static void deinit_priv(struct rtl_halmac *halmac) +{ + struct rtl_halmac_indicator *indicator; + + indicator = halmac->indicator; + halmac->indicator = NULL; + kfree(indicator); +} + +int rtl_halmac_init_adapter(struct rtl_priv *rtlpriv) +{ + struct halmac_adapter *halmac; + struct halmac_api *api; + enum halmac_interface intf; + enum halmac_ret_status status; + int err = 0; + struct halmac_platform_api *pf_api = &rtl_halmac_platform_api; + + halmac = rtlpriv_to_halmac(rtlpriv); + if (halmac) { + err = 0; + goto out; + } + + err = init_priv(&rtlpriv->halmac); + if (err) + goto out; + + intf = HALMAC_INTERFACE_PCIE; + status = halmac_init_adapter(rtlpriv, pf_api, intf, &halmac, &api); + if (status != HALMAC_RET_SUCCESS) { + RT_TRACE(rtlpriv, COMP_HALMAC, DBG_LOUD, + "%s: halmac_init_adapter fail!(status=%d)\n", __func__, + status); + err = -1; + goto out; + } + + rtlpriv->halmac.internal = halmac; + +out: + if (err) + rtl_halmac_deinit_adapter(rtlpriv); + + return err; +} + +int rtl_halmac_deinit_adapter(struct rtl_priv *rtlpriv) +{ + struct halmac_adapter *halmac; + enum halmac_ret_status status; + int err = 0; + + halmac = rtlpriv_to_halmac(rtlpriv); + if (!halmac) { + err = 0; + goto out; + } + + deinit_priv(&rtlpriv->halmac); + + halmac_halt_api(halmac); + + status = halmac_deinit_adapter(halmac); + rtlpriv->halmac.internal = NULL; + if (status != HALMAC_RET_SUCCESS) { + err = -1; + goto out; + } + +out: + return err; +} + +int rtl_halmac_poweron(struct rtl_priv *rtlpriv) +{ + struct halmac_adapter *halmac; + struct halmac_api *api; + enum halmac_ret_status status; + int err = -1; + + halmac = rtlpriv_to_halmac(rtlpriv); + if (!halmac) + goto out; + + api = HALMAC_GET_API(halmac); + + status = api->halmac_pre_init_system_cfg(halmac); + if (status != HALMAC_RET_SUCCESS) + goto out; + + status = api->halmac_mac_power_switch(halmac, HALMAC_MAC_POWER_ON); + if (status != HALMAC_RET_SUCCESS) + goto out; + + status = api->halmac_init_system_cfg(halmac); + if (status != HALMAC_RET_SUCCESS) + goto out; + + err = 0; +out: + return err; +} + +int rtl_halmac_poweroff(struct rtl_priv *rtlpriv) +{ + struct halmac_adapter *halmac; + struct halmac_api *api; + enum halmac_ret_status status; + int err = -1; + + halmac = rtlpriv_to_halmac(rtlpriv); + if (!halmac) + goto out; + + api = HALMAC_GET_API(halmac); + + status = api->halmac_mac_power_switch(halmac, HALMAC_MAC_POWER_OFF); + if (status != HALMAC_RET_SUCCESS) + goto out; + + err = 0; +out: + return err; +} + +/* + * Note: + * When this function return, the register REG_RCR may be changed. + */ +int rtl_halmac_config_rx_info(struct rtl_priv *rtlpriv, + enum halmac_drv_info info) +{ + struct halmac_adapter *halmac; + struct halmac_api *api; + enum halmac_ret_status status; + int err = -1; + + halmac = rtlpriv_to_halmac(rtlpriv); + api = HALMAC_GET_API(halmac); + + status = api->halmac_cfg_drv_info(halmac, info); + if (status != HALMAC_RET_SUCCESS) + goto out; + + err = 0; +out: + return err; +} + +static enum halmac_ret_status init_mac_flow(struct rtl_priv *rtlpriv) +{ + struct halmac_adapter *halmac; + struct halmac_api *api; + enum halmac_ret_status status; + u8 wifi_test = 0; + int err; + + halmac = rtlpriv_to_halmac(rtlpriv); + api = HALMAC_GET_API(halmac); + + if (wifi_test) + status = api->halmac_init_mac_cfg(halmac, HALMAC_TRX_MODE_WMM); + else + status = api->halmac_init_mac_cfg(halmac, + HALMAC_TRX_MODE_NORMAL); + if (status != HALMAC_RET_SUCCESS) + goto out; + + err = rtl_halmac_rx_agg_switch(rtlpriv, true); + if (err) + goto out; + + if (rtlpriv->cfg->maps[RTL_RC_VHT_RATE_1SS_MCS7]) + status = api->halmac_cfg_operation_mode( + halmac, HALMAC_WIRELESS_MODE_AC); + else if (rtlpriv->cfg->maps[RTL_RC_HT_RATEMCS7]) + status = api->halmac_cfg_operation_mode(halmac, + HALMAC_WIRELESS_MODE_N); + else if (rtlpriv->cfg->maps[RTL_RC_OFDM_RATE6M]) + status = api->halmac_cfg_operation_mode(halmac, + HALMAC_WIRELESS_MODE_G); + else + status = api->halmac_cfg_operation_mode(halmac, + HALMAC_WIRELESS_MODE_B); + if (status != HALMAC_RET_SUCCESS) + goto out; + +out: + return status; +} + +static inline enum halmac_rf_type _rf_type_drv2halmac(enum rf_type rf_drv) +{ + enum halmac_rf_type rf_mac; + + switch (rf_drv) { + case RF_1T2R: + rf_mac = HALMAC_RF_1T2R; + break; + case RF_2T2R: + rf_mac = HALMAC_RF_2T2R; + break; + case RF_1T1R: + rf_mac = HALMAC_RF_1T1R; + break; + case RF_2T2R_GREEN: + rf_mac = HALMAC_RF_2T2R_GREEN; + break; + default: + rf_mac = (enum halmac_rf_type)rf_drv; + break; + } + + return rf_mac; +} + +static int _send_general_info(struct rtl_priv *rtlpriv) +{ + struct halmac_adapter *halmac; + struct halmac_api *api; + struct halmac_general_info info; + enum halmac_ret_status status; + + halmac = rtlpriv_to_halmac(rtlpriv); + if (!halmac) + return -1; + api = HALMAC_GET_API(halmac); + + memset(&info, 0, sizeof(info)); + info.rfe_type = rtlpriv->rtlhal.rfe_type; + info.rf_type = _rf_type_drv2halmac(rtlpriv->phy.rf_type); + + status = api->halmac_send_general_info(halmac, &info); + switch (status) { + case HALMAC_RET_SUCCESS: + break; + case HALMAC_RET_NO_DLFW: + RT_TRACE(rtlpriv, COMP_HALMAC, DBG_WARNING, + "%s: halmac_send_general_info() fail because fw not dl!\n", + __func__); + /* fallthrough here */ + default: + return -1; + } + + return 0; +} + +/* + * Notices: + * Make sure + * 1. rtl_hal_get_hwreg(HW_VAR_RF_TYPE) + * 2. HAL_DATA_TYPE.rfe_type + * already ready for use before calling this function. + */ +static int _halmac_init_hal(struct rtl_priv *rtlpriv, u8 *fw, u32 fwsize) +{ + struct halmac_adapter *halmac; + struct halmac_api *api; + enum halmac_ret_status status; + bool ok; + bool fw_ok = false; + int err, err_ret = -1; + + halmac = rtlpriv_to_halmac(rtlpriv); + if (!halmac) + goto out; + api = HALMAC_GET_API(halmac); + + /* StatePowerOff */ + + /* SKIP: halmac_init_adapter (Already done before) */ + + /* halmac_pre_Init_system_cfg */ + /* halmac_mac_power_switch(on) */ + /* halmac_Init_system_cfg */ + err = rtl_halmac_poweron(rtlpriv); + if (err) + goto out; + + /* StatePowerOn */ + + /* DownloadFW */ + rtlpriv->halmac.send_general_info = 0; + if (fw && fwsize) { + err = rtl_halmac_dlfw(rtlpriv, fw, fwsize); + if (err) + goto out; + fw_ok = true; + } + + /* InitMACFlow */ + status = init_mac_flow(rtlpriv); + if (status != HALMAC_RET_SUCCESS) + goto out; + + /* halmac_send_general_info */ + if (fw_ok) { + rtlpriv->halmac.send_general_info = 0; + err = _send_general_info(rtlpriv); + if (err) + goto out; + } else { + rtlpriv->halmac.send_general_info = 1; + } + + /* Init Phy parameter-MAC */ + if (rtlpriv->cfg->ops->halmac_cb_init_mac_register) + ok = rtlpriv->cfg->ops->halmac_cb_init_mac_register(rtlpriv); + else + ok = false; + + if (!ok) + goto out; + + /* StateMacInitialized */ + + /* halmac_cfg_drv_info */ + err = rtl_halmac_config_rx_info(rtlpriv, HALMAC_DRV_INFO_PHY_STATUS); + if (err) + goto out; + + /* halmac_set_hw_value(HALMAC_HW_EN_BB_RF) */ + /* Init BB, RF */ + if (rtlpriv->cfg->ops->halmac_cb_init_bb_rf_register) + ok = rtlpriv->cfg->ops->halmac_cb_init_bb_rf_register(rtlpriv); + else + ok = false; + + if (!ok) + goto out; + + status = api->halmac_init_interface_cfg(halmac); + if (status != HALMAC_RET_SUCCESS) + goto out; + + /* SKIP: halmac_verify_platform_api */ + /* SKIP: halmac_h2c_lb */ + + /* StateRxIdle */ + + err_ret = 0; +out: + return err_ret; +} + +int rtl_halmac_init_hal(struct rtl_priv *rtlpriv) +{ + if (!rtlpriv->rtlhal.pfirmware || rtlpriv->rtlhal.fwsize == 0) + return -1; + + return _halmac_init_hal(rtlpriv, rtlpriv->rtlhal.pfirmware, + rtlpriv->rtlhal.fwsize); +} + +int rtl_halmac_deinit_hal(struct rtl_priv *rtlpriv) +{ + struct halmac_adapter *halmac; + struct halmac_api *api; + enum halmac_ret_status status; + int err = -1; + + halmac = rtlpriv_to_halmac(rtlpriv); + if (!halmac) + goto out; + api = HALMAC_GET_API(halmac); + + status = api->halmac_deinit_interface_cfg(halmac); + if (status != HALMAC_RET_SUCCESS) + goto out; + + /* rtw_hal_power_off(adapter); */ + status = api->halmac_mac_power_switch(halmac, HALMAC_MAC_POWER_OFF); + if (status != HALMAC_RET_SUCCESS) + goto out; + + err = 0; +out: + return err; +} + +int rtl_halmac_self_verify(struct rtl_priv *rtlpriv) +{ + struct halmac_adapter *mac; + struct halmac_api *api; + enum halmac_ret_status status; + int err = -1; + + mac = rtlpriv_to_halmac(rtlpriv); + api = HALMAC_GET_API(mac); + + status = api->halmac_verify_platform_api(mac); + if (status != HALMAC_RET_SUCCESS) + goto out; + + status = api->halmac_h2c_lb(mac); + if (status != HALMAC_RET_SUCCESS) + goto out; + + err = 0; +out: + return err; +} + +int rtl_halmac_dlfw(struct rtl_priv *rtlpriv, u8 *fw, u32 fwsize) +{ + struct halmac_adapter *mac; + struct halmac_api *api; + enum halmac_ret_status status; + struct halmac_fw_version fw_version; + int err = 0; + + mac = rtlpriv_to_halmac(rtlpriv); + api = HALMAC_GET_API(mac); + + if ((!fw) || (!fwsize)) + return -1; + + /* 1. Driver Stop Tx */ + /* ToDo */ + + /* 2. Driver Check Tx FIFO is empty */ + /* ToDo */ + + /* 3. Config MAX download size */ + api->halmac_cfg_max_dl_size(mac, 0x1000); + + /* 4. Download Firmware */ + mac->h2c_packet_seq = 0; + status = api->halmac_download_firmware(mac, fw, fwsize); + if (status != HALMAC_RET_SUCCESS) + return -1; + + status = api->halmac_get_fw_version(mac, &fw_version); + if (status == HALMAC_RET_SUCCESS) { + rtlpriv->rtlhal.fw_version = fw_version.version; + rtlpriv->rtlhal.fw_subversion = + (fw_version.sub_version << 8) | (fw_version.sub_index); + + RT_TRACE( + rtlpriv, COMP_HALMAC, DBG_DMESG, + "halmac report firmware version %04X.%04X\n", + rtlpriv->rtlhal.fw_version, + rtlpriv->rtlhal.fw_subversion); + } + + if (rtlpriv->halmac.send_general_info) { + rtlpriv->halmac.send_general_info = 0; + err = _send_general_info(rtlpriv); + } + + /* 5. Driver resume TX if needed */ + /* ToDo */ + + /* 6. Reset driver variables if needed */ + /*hal->LastHMEBoxNum = 0;*/ + + return err; +} + +/* + * Description: + * Power on/off BB/RF domain. + * + * Parameters: + * enable true/false for power on/off + * + * Return: + * 0 Success + * others Fail + */ +int rtl_halmac_phy_power_switch(struct rtl_priv *rtlpriv, u8 enable) +{ + struct halmac_adapter *halmac; + struct halmac_api *api; + enum halmac_ret_status status; + + halmac = rtlpriv_to_halmac(rtlpriv); + if (!halmac) + return -1; + api = HALMAC_GET_API(halmac); + + status = api->halmac_set_hw_value(halmac, HALMAC_HW_EN_BB_RF, &enable); + if (status != HALMAC_RET_SUCCESS) + return -1; + + return 0; +} + +static bool _is_fw_read_cmd_down(struct rtl_priv *rtlpriv, u8 msgbox_num) +{ + bool read_down = false; + int retry_cnts = 100; + u8 valid; + + RT_TRACE(rtlpriv, COMP_HALMAC, DBG_LOUD, + "%s, reg_1cc(%x), msg_box(%d)...\n", __func__, + rtl_read_byte(rtlpriv, REG_HMETFR), msgbox_num); + + do { + valid = rtl_read_byte(rtlpriv, REG_HMETFR) & BIT(msgbox_num); + if (valid == 0) + read_down = true; + else + schedule(); + } while ((!read_down) && (retry_cnts--)); + + return read_down; +} + +int rtl_halmac_send_h2c(struct rtl_priv *rtlpriv, u8 *h2c) +{ + u8 h2c_box_num = 0; + u32 msgbox_addr = 0; + u32 msgbox_ex_addr = 0; + __le32 h2c_cmd = 0; + __le32 h2c_cmd_ex = 0; + s32 ret = -1; + unsigned long flag = 0; + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + + if (!h2c) { + RT_TRACE(rtlpriv, COMP_HALMAC, DBG_LOUD, "%s: pbuf is NULL\n", + __func__); + return ret; + } + + spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag); + + /* pay attention to if race condition happened in H2C cmd setting */ + h2c_box_num = rtlhal->last_hmeboxnum; + + if (!_is_fw_read_cmd_down(rtlpriv, h2c_box_num)) { + RT_TRACE(rtlpriv, COMP_HALMAC, DBG_LOUD, + " fw read cmd failed...\n"); + goto exit; + } + + /* Write Ext command(byte 4 -7) */ + msgbox_ex_addr = REG_HMEBOX_E0 + (h2c_box_num * EX_MESSAGE_BOX_SIZE); + memcpy((u8 *)(&h2c_cmd_ex), h2c + 4, EX_MESSAGE_BOX_SIZE); + rtl_write_dword(rtlpriv, msgbox_ex_addr, le32_to_cpu(h2c_cmd_ex)); + + /* Write command (byte 0 -3 ) */ + msgbox_addr = REG_HMEBOX0 + (h2c_box_num * MESSAGE_BOX_SIZE); + memcpy((u8 *)(&h2c_cmd), h2c, 4); + rtl_write_dword(rtlpriv, msgbox_addr, le32_to_cpu(h2c_cmd)); + + /* update last msg box number */ + rtlhal->last_hmeboxnum = (h2c_box_num + 1) % MAX_H2C_BOX_NUMS; + ret = 0; + +exit: + spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag); + return ret; +} + +int rtl_halmac_c2h_handle(struct rtl_priv *rtlpriv, u8 *c2h, u32 size) +{ + struct halmac_adapter *mac; + struct halmac_api *api; + enum halmac_ret_status status; + + mac = rtlpriv_to_halmac(rtlpriv); + api = HALMAC_GET_API(mac); + + status = api->halmac_get_c2h_info(mac, c2h, size); + if (status != HALMAC_RET_SUCCESS) + return -1; + + return 0; +} + +int rtl_halmac_get_physical_efuse_size(struct rtl_priv *rtlpriv, u32 *size) +{ + struct halmac_adapter *mac; + struct halmac_api *api; + enum halmac_ret_status status; + u32 val; + + mac = rtlpriv_to_halmac(rtlpriv); + api = HALMAC_GET_API(mac); + + status = api->halmac_get_efuse_size(mac, &val); + if (status != HALMAC_RET_SUCCESS) + return -1; + + *size = val; + return 0; +} + +int rtl_halmac_read_physical_efuse_map(struct rtl_priv *rtlpriv, u8 *map, + u32 size) +{ + struct halmac_adapter *mac; + struct halmac_api *api; + enum halmac_ret_status status; + enum halmac_feature_id id; + int ret; + + mac = rtlpriv_to_halmac(rtlpriv); + api = HALMAC_GET_API(mac); + id = HALMAC_FEATURE_DUMP_PHYSICAL_EFUSE; + + ret = init_halmac_event(rtlpriv, id, map, size); + if (ret) + return -1; + + status = api->halmac_dump_efuse_map(mac, HALMAC_EFUSE_R_DRV); + if (status != HALMAC_RET_SUCCESS) { + free_halmac_event(rtlpriv, id); + return -1; + } + + ret = wait_halmac_event(rtlpriv, id); + if (ret) + return -1; + + return 0; +} + +int rtl_halmac_read_physical_efuse(struct rtl_priv *rtlpriv, u32 offset, + u32 cnt, u8 *data) +{ + struct halmac_adapter *mac; + struct halmac_api *api; + enum halmac_ret_status status; + u8 v; + u32 i; + + mac = rtlpriv_to_halmac(rtlpriv); + api = HALMAC_GET_API(mac); + + for (i = 0; i < cnt; i++) { + status = api->halmac_read_efuse(mac, offset + i, &v); + if (status != HALMAC_RET_SUCCESS) + return -1; + data[i] = v; + } + + return 0; +} + +int rtl_halmac_write_physical_efuse(struct rtl_priv *rtlpriv, u32 offset, + u32 cnt, u8 *data) +{ + struct halmac_adapter *mac; + struct halmac_api *api; + enum halmac_ret_status status; + u32 i; + + mac = rtlpriv_to_halmac(rtlpriv); + api = HALMAC_GET_API(mac); + + for (i = 0; i < cnt; i++) { + status = api->halmac_write_efuse(mac, offset + i, data[i]); + if (status != HALMAC_RET_SUCCESS) + return -1; + } + + return 0; +} + +int rtl_halmac_get_logical_efuse_size(struct rtl_priv *rtlpriv, u32 *size) +{ + struct halmac_adapter *mac; + struct halmac_api *api; + enum halmac_ret_status status; + u32 val; + + mac = rtlpriv_to_halmac(rtlpriv); + api = HALMAC_GET_API(mac); + + status = api->halmac_get_logical_efuse_size(mac, &val); + if (status != HALMAC_RET_SUCCESS) + return -1; + + *size = val; + return 0; +} + +int rtl_halmac_read_logical_efuse_map(struct rtl_priv *rtlpriv, u8 *map, + u32 size) +{ + struct halmac_adapter *mac; + struct halmac_api *api; + enum halmac_ret_status status; + enum halmac_feature_id id; + int ret; + + mac = rtlpriv_to_halmac(rtlpriv); + api = HALMAC_GET_API(mac); + id = HALMAC_FEATURE_DUMP_LOGICAL_EFUSE; + + ret = init_halmac_event(rtlpriv, id, map, size); + if (ret) + return -1; + + status = api->halmac_dump_logical_efuse_map(mac, HALMAC_EFUSE_R_AUTO); + if (status != HALMAC_RET_SUCCESS) { + free_halmac_event(rtlpriv, id); + return -1; + } + + ret = wait_halmac_event(rtlpriv, id); + if (ret) + return -1; + + return 0; +} + +int rtl_halmac_write_logical_efuse_map(struct rtl_priv *rtlpriv, u8 *map, + u32 size, u8 *maskmap, u32 masksize) +{ + struct halmac_adapter *mac; + struct halmac_api *api; + struct halmac_pg_efuse_info pginfo; + enum halmac_ret_status status; + + mac = rtlpriv_to_halmac(rtlpriv); + api = HALMAC_GET_API(mac); + + pginfo.efuse_map = map; + pginfo.efuse_map_size = size; + pginfo.efuse_mask = maskmap; + pginfo.efuse_mask_size = masksize; + + status = api->halmac_pg_efuse_by_map(mac, &pginfo, HALMAC_EFUSE_R_AUTO); + if (status != HALMAC_RET_SUCCESS) + return -1; + + return 0; +} + +int rtl_halmac_read_logical_efuse(struct rtl_priv *rtlpriv, u32 offset, u32 cnt, + u8 *data) +{ + struct halmac_adapter *mac; + struct halmac_api *api; + enum halmac_ret_status status; + u8 v; + u32 i; + + mac = rtlpriv_to_halmac(rtlpriv); + api = HALMAC_GET_API(mac); + + for (i = 0; i < cnt; i++) { + status = api->halmac_read_logical_efuse(mac, offset + i, &v); + if (status != HALMAC_RET_SUCCESS) + return -1; + data[i] = v; + } + + return 0; +} + +int rtl_halmac_write_logical_efuse(struct rtl_priv *rtlpriv, u32 offset, + u32 cnt, u8 *data) +{ + struct halmac_adapter *mac; + struct halmac_api *api; + enum halmac_ret_status status; + u32 i; + + mac = rtlpriv_to_halmac(rtlpriv); + api = HALMAC_GET_API(mac); + + for (i = 0; i < cnt; i++) { + status = api->halmac_write_logical_efuse(mac, offset + i, + data[i]); + if (status != HALMAC_RET_SUCCESS) + return -1; + } + + return 0; +} + +int rtl_halmac_set_mac_address(struct rtl_priv *rtlpriv, u8 hwport, u8 *addr) +{ + struct halmac_adapter *halmac; + struct halmac_api *api; + u8 port; + union halmac_wlan_addr hwa; + enum halmac_ret_status status; + int err = -1; + + halmac = rtlpriv_to_halmac(rtlpriv); + api = HALMAC_GET_API(halmac); + + port = hwport; + memset(&hwa, 0, sizeof(hwa)); + memcpy(hwa.address, addr, 6); + + status = api->halmac_cfg_mac_addr(halmac, port, &hwa); + if (status != HALMAC_RET_SUCCESS) + goto out; + + err = 0; +out: + return err; +} + +int rtl_halmac_set_bssid(struct rtl_priv *rtlpriv, u8 hwport, u8 *addr) +{ + struct halmac_adapter *halmac; + struct halmac_api *api; + u8 port; + union halmac_wlan_addr hwa; + enum halmac_ret_status status; + int err = -1; + + halmac = rtlpriv_to_halmac(rtlpriv); + api = HALMAC_GET_API(halmac); + port = hwport; + + memset(&hwa, 0, sizeof(union halmac_wlan_addr)); + memcpy(hwa.address, addr, 6); + status = api->halmac_cfg_bssid(halmac, port, &hwa); + if (status != HALMAC_RET_SUCCESS) + goto out; + + err = 0; +out: + return err; +} + +int rtl_halmac_set_bandwidth(struct rtl_priv *rtlpriv, u8 channel, + u8 pri_ch_idx, u8 bw) +{ + struct halmac_adapter *mac; + struct halmac_api *api; + enum halmac_ret_status status; + + mac = rtlpriv_to_halmac(rtlpriv); + api = HALMAC_GET_API(mac); + + status = api->halmac_cfg_ch_bw(mac, channel, pri_ch_idx, bw); + if (status != HALMAC_RET_SUCCESS) + return -1; + + return 0; +} + +int rtl_halmac_get_hw_value(struct rtl_priv *rtlpriv, enum halmac_hw_id hw_id, + void *pvalue) +{ + struct halmac_adapter *mac; + struct halmac_api *api; + enum halmac_ret_status status; + + mac = rtlpriv_to_halmac(rtlpriv); + api = HALMAC_GET_API(mac); + + status = api->halmac_get_hw_value(mac, hw_id, pvalue); + if (status != HALMAC_RET_SUCCESS) + return -1; + + return 0; +} + +int rtl_halmac_dump_fifo(struct rtl_priv *rtlpriv, + enum hal_fifo_sel halmac_fifo_sel) +{ + struct halmac_adapter *mac; + struct halmac_api *api; + enum halmac_ret_status status; + u8 *pfifo_map = NULL; + u32 fifo_size = 0; + s8 ret = 0; + + mac = rtlpriv_to_halmac(rtlpriv); + api = HALMAC_GET_API(mac); + + fifo_size = api->halmac_get_fifo_size(mac, halmac_fifo_sel); + if (fifo_size) + pfifo_map = vmalloc(fifo_size); + if (!pfifo_map) + return -1; + + status = api->halmac_dump_fifo(mac, halmac_fifo_sel, 0, fifo_size, + pfifo_map); + + if (status != HALMAC_RET_SUCCESS) { + ret = -1; + goto _exit; + } + +_exit: + if (pfifo_map) + vfree(pfifo_map); + return ret; +} + +int rtl_halmac_rx_agg_switch(struct rtl_priv *rtlpriv, bool enable) +{ + struct halmac_adapter *halmac; + struct halmac_api *api; + struct halmac_rxagg_cfg rxaggcfg; + enum halmac_ret_status status; + int err = -1; + + halmac = rtlpriv_to_halmac(rtlpriv); + api = HALMAC_GET_API(halmac); + memset((void *)&rxaggcfg, 0, sizeof(rxaggcfg)); + + if (enable) { + /* enable RX agg. */ + /* PCIE do nothing */ + } else { + /* disable RX agg. */ + rxaggcfg.mode = HALMAC_RX_AGG_MODE_NONE; + } + + status = api->halmac_cfg_rx_aggregation(halmac, &rxaggcfg); + if (status != HALMAC_RET_SUCCESS) + goto out; + + err = 0; +out: + return err; +} + +int rtl_halmac_get_wow_reason(struct rtl_priv *rtlpriv, u8 *reason) +{ + u8 val8; + int err = -1; + + val8 = rtl_read_byte(rtlpriv, 0x1C7); + if (val8 == 0xEA) + goto out; + + *reason = val8; + err = 0; +out: + return err; +} + +/* + * Description: + * Get RX driver info size. RX driver info is a small memory space between + * scriptor and RX payload. + * + * +-------------------------+ + * | RX descriptor | + * | usually 24 bytes | + * +-------------------------+ + * | RX driver info | + * | depends on driver cfg | + * +-------------------------+ + * | RX paylad | + * | | + * +-------------------------+ + * + * Parameter: + * d pointer to struct dvobj_priv of driver + * sz rx driver info size in bytes. + * + * Rteurn: + * 0 Success + * other Fail + */ +int rtl_halmac_get_drv_info_sz(struct rtl_priv *rtlpriv, u8 *sz) +{ + /* enum halmac_ret_status status; */ + u8 dw = 6; /* max number */ + + *sz = dw * 8; + return 0; +} + +int rtl_halmac_get_rsvd_drv_pg_bndy(struct rtl_priv *rtlpriv, u16 *drv_pg) +{ + enum halmac_ret_status status; + struct halmac_adapter *halmac = rtlpriv_to_halmac(rtlpriv); + struct halmac_api *api = HALMAC_GET_API(halmac); + + status = api->halmac_get_hw_value(halmac, HALMAC_HW_RSVD_PG_BNDY, + drv_pg); + if (status != HALMAC_RET_SUCCESS) + return -1; + + return 0; +} + +int rtl_halmac_chk_txdesc(struct rtl_priv *rtlpriv, u8 *txdesc, u32 size) +{ + struct halmac_adapter *mac; + struct halmac_api *api; + enum halmac_ret_status status; + + mac = rtlpriv_to_halmac(rtlpriv); + api = HALMAC_GET_API(mac); + + status = api->halmac_chk_txdesc(mac, txdesc, size); + + if (status != HALMAC_RET_SUCCESS) + return -1; + + return 0; +} + +MODULE_AUTHOR("Realtek WlanFAE <wlanfae@realtek.com>"); +MODULE_AUTHOR("Larry Finger <Larry.FInger@lwfinger.net>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Realtek 802.11n PCI wireless core"); diff --git a/drivers/staging/rtlwifi/halmac/rtl_halmac.h b/drivers/staging/rtlwifi/halmac/rtl_halmac.h new file mode 100644 index 000000000000..51a3684f30d8 --- /dev/null +++ b/drivers/staging/rtlwifi/halmac/rtl_halmac.h @@ -0,0 +1,94 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef _RTL_HALMAC_H_ +#define _RTL_HALMAC_H_ + +#include "halmac_api.h" + +#define rtlpriv_to_halmac(priv) \ + ((struct halmac_adapter *)((priv)->halmac.internal)) + +/* for H2C cmd */ +#define MAX_H2C_BOX_NUMS 4 +#define MESSAGE_BOX_SIZE 4 +#define EX_MESSAGE_BOX_SIZE 4 + +/* HALMAC API for Driver(HAL) */ +int rtl_halmac_init_adapter(struct rtl_priv *rtlpriv); +int rtl_halmac_deinit_adapter(struct rtl_priv *rtlpriv); +int rtl_halmac_poweron(struct rtl_priv *rtlpriv); +int rtl_halmac_poweroff(struct rtl_priv *rtlpriv); +int rtl_halmac_init_hal(struct rtl_priv *rtlpriv); +int rtl_halmac_init_hal_fw(struct rtl_priv *rtlpriv, u8 *fw, u32 fwsize); +int rtl_halmac_init_hal_fw_file(struct rtl_priv *rtlpriv, u8 *fwpath); +int rtl_halmac_deinit_hal(struct rtl_priv *rtlpriv); +int rtl_halmac_self_verify(struct rtl_priv *rtlpriv); +int rtl_halmac_dlfw(struct rtl_priv *rtlpriv, u8 *fw, u32 fwsize); +int rtl_halmac_dlfw_from_file(struct rtl_priv *rtlpriv, u8 *fwpath); +int rtl_halmac_phy_power_switch(struct rtl_priv *rtlpriv, u8 enable); +int rtl_halmac_send_h2c(struct rtl_priv *rtlpriv, u8 *h2c); +int rtl_halmac_c2h_handle(struct rtl_priv *rtlpriv, u8 *c2h, u32 size); + +int rtl_halmac_get_physical_efuse_size(struct rtl_priv *rtlpriv, u32 *size); +int rtl_halmac_read_physical_efuse_map(struct rtl_priv *rtlpriv, u8 *map, + u32 size); +int rtl_halmac_read_physical_efuse(struct rtl_priv *rtlpriv, u32 offset, + u32 cnt, u8 *data); +int rtl_halmac_write_physical_efuse(struct rtl_priv *rtlpriv, u32 offset, + u32 cnt, u8 *data); +int rtl_halmac_get_logical_efuse_size(struct rtl_priv *rtlpriv, u32 *size); +int rtl_halmac_read_logical_efuse_map(struct rtl_priv *rtlpriv, u8 *map, + u32 size); +int rtl_halmac_write_logical_efuse_map(struct rtl_priv *rtlpriv, u8 *map, + u32 size, u8 *maskmap, u32 masksize); +int rtl_halmac_read_logical_efuse(struct rtl_priv *rtlpriv, u32 offset, u32 cnt, + u8 *data); +int rtl_halmac_write_logical_efuse(struct rtl_priv *rtlpriv, u32 offset, + u32 cnt, u8 *data); + +int rtl_halmac_config_rx_info(struct rtl_priv *rtlpriv, enum halmac_drv_info); +int rtl_halmac_set_mac_address(struct rtl_priv *rtlpriv, u8 hwport, u8 *addr); +int rtl_halmac_set_bssid(struct rtl_priv *d, u8 hwport, u8 *addr); + +int rtl_halmac_set_bandwidth(struct rtl_priv *rtlpriv, u8 channel, + u8 pri_ch_idx, u8 bw); +int rtl_halmac_rx_agg_switch(struct rtl_priv *rtlpriv, bool enable); +int rtl_halmac_get_hw_value(struct rtl_priv *d, enum halmac_hw_id hw_id, + void *pvalue); +int rtl_halmac_dump_fifo(struct rtl_priv *rtlpriv, + enum hal_fifo_sel halmac_fifo_sel); + +int rtl_halmac_get_wow_reason(struct rtl_priv *rtlpriv, u8 *reason); +int rtl_halmac_get_drv_info_sz(struct rtl_priv *d, u8 *sz); + +int rtl_halmac_get_rsvd_drv_pg_bndy(struct rtl_priv *dvobj, u16 *drv_pg); +int rtl_halmac_download_rsvd_page(struct rtl_priv *dvobj, u8 pg_offset, + u8 *pbuf, u32 size); + +int rtl_halmac_chk_txdesc(struct rtl_priv *rtlpriv, u8 *txdesc, u32 size); + +struct rtl_halmac_ops *rtl_halmac_get_ops_pointer(void); + +#endif /* _RTL_HALMAC_H_ */ diff --git a/drivers/staging/rtlwifi/pci.c b/drivers/staging/rtlwifi/pci.c new file mode 100644 index 000000000000..4035b8835bd1 --- /dev/null +++ b/drivers/staging/rtlwifi/pci.c @@ -0,0 +1,2508 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include "wifi.h" +#include "core.h" +#include "pci.h" +#include "base.h" +#include "ps.h" +#include "efuse.h" +#include <linux/interrupt.h> +#include <linux/export.h> +#include <linux/kmemleak.h> +#include <linux/module.h> + +MODULE_AUTHOR("lizhaoming <chaoming_li@realsil.com.cn>"); +MODULE_AUTHOR("Realtek WlanFAE <wlanfae@realtek.com>"); +MODULE_AUTHOR("Larry Finger <Larry.FInger@lwfinger.net>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("PCI basic driver for rtlwifi"); + +static const u16 pcibridge_vendors[PCI_BRIDGE_VENDOR_MAX] = { + INTEL_VENDOR_ID, + ATI_VENDOR_ID, + AMD_VENDOR_ID, + SIS_VENDOR_ID +}; + +static const u8 ac_to_hwq[] = { + VO_QUEUE, + VI_QUEUE, + BE_QUEUE, + BK_QUEUE +}; + +static u8 _rtl_mac_to_hwqueue(struct ieee80211_hw *hw, + struct sk_buff *skb) +{ + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + __le16 fc = rtl_get_fc(skb); + u8 queue_index = skb_get_queue_mapping(skb); + struct ieee80211_hdr *hdr; + + if (unlikely(ieee80211_is_beacon(fc))) + return BEACON_QUEUE; + if (ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc)) + return MGNT_QUEUE; + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) + if (ieee80211_is_nullfunc(fc)) + return HIGH_QUEUE; + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8822BE) { + hdr = rtl_get_hdr(skb); + + if (is_multicast_ether_addr(hdr->addr1) || + is_broadcast_ether_addr(hdr->addr1)) + return HIGH_QUEUE; + } + + return ac_to_hwq[queue_index]; +} + +/* Update PCI dependent default settings*/ +static void _rtl_pci_update_default_setting(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + u8 pcibridge_vendor = pcipriv->ndis_adapter.pcibridge_vendor; + u8 init_aspm; + + ppsc->reg_rfps_level = 0; + ppsc->support_aspm = false; + + /*Update PCI ASPM setting */ + ppsc->const_amdpci_aspm = rtlpci->const_amdpci_aspm; + switch (rtlpci->const_pci_aspm) { + case 0: + /*No ASPM */ + break; + + case 1: + /*ASPM dynamically enabled/disable. */ + ppsc->reg_rfps_level |= RT_RF_LPS_LEVEL_ASPM; + break; + + case 2: + /*ASPM with Clock Req dynamically enabled/disable. */ + ppsc->reg_rfps_level |= (RT_RF_LPS_LEVEL_ASPM | + RT_RF_OFF_LEVL_CLK_REQ); + break; + + case 3: + /* Always enable ASPM and Clock Req + * from initialization to halt. + */ + ppsc->reg_rfps_level &= ~(RT_RF_LPS_LEVEL_ASPM); + ppsc->reg_rfps_level |= (RT_RF_PS_LEVEL_ALWAYS_ASPM | + RT_RF_OFF_LEVL_CLK_REQ); + break; + + case 4: + /* Always enable ASPM without Clock Req + * from initialization to halt. + */ + ppsc->reg_rfps_level &= ~(RT_RF_LPS_LEVEL_ASPM | + RT_RF_OFF_LEVL_CLK_REQ); + ppsc->reg_rfps_level |= RT_RF_PS_LEVEL_ALWAYS_ASPM; + break; + } + + ppsc->reg_rfps_level |= RT_RF_OFF_LEVL_HALT_NIC; + + /*Update Radio OFF setting */ + switch (rtlpci->const_hwsw_rfoff_d3) { + case 1: + if (ppsc->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM) + ppsc->reg_rfps_level |= RT_RF_OFF_LEVL_ASPM; + break; + + case 2: + if (ppsc->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM) + ppsc->reg_rfps_level |= RT_RF_OFF_LEVL_ASPM; + ppsc->reg_rfps_level |= RT_RF_OFF_LEVL_HALT_NIC; + break; + + case 3: + ppsc->reg_rfps_level |= RT_RF_OFF_LEVL_PCI_D3; + break; + } + + /*Set HW definition to determine if it supports ASPM. */ + switch (rtlpci->const_support_pciaspm) { + case 0:{ + /*Not support ASPM. */ + bool support_aspm = false; + + ppsc->support_aspm = support_aspm; + break; + } + case 1:{ + /*Support ASPM. */ + bool support_aspm = true; + bool support_backdoor = true; + + ppsc->support_aspm = support_aspm; + + /*if (priv->oem_id == RT_CID_TOSHIBA && + * !priv->ndis_adapter.amd_l1_patch) + * support_backdoor = false; + */ + + ppsc->support_backdoor = support_backdoor; + + break; + } + case 2: + /*ASPM value set by chipset. */ + if (pcibridge_vendor == PCI_BRIDGE_VENDOR_INTEL) { + bool support_aspm = true; + + ppsc->support_aspm = support_aspm; + } + break; + default: + pr_err("switch case %#x not processed\n", + rtlpci->const_support_pciaspm); + break; + } + + /* toshiba aspm issue, toshiba will set aspm selfly + * so we should not set aspm in driver + */ + pci_read_config_byte(rtlpci->pdev, 0x80, &init_aspm); + if (rtlpriv->rtlhal.hw_type == HARDWARE_TYPE_RTL8192SE && + init_aspm == 0x43) + ppsc->support_aspm = false; +} + +static bool _rtl_pci_platform_switch_device_pci_aspm( + struct ieee80211_hw *hw, + u8 value) +{ + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + + if (rtlhal->hw_type != HARDWARE_TYPE_RTL8192SE) + value |= 0x40; + + pci_write_config_byte(rtlpci->pdev, 0x80, value); + + return false; +} + +/*When we set 0x01 to enable clk request. Set 0x0 to disable clk req.*/ +static void _rtl_pci_switch_clk_req(struct ieee80211_hw *hw, u8 value) +{ + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + + pci_write_config_byte(rtlpci->pdev, 0x81, value); + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) + udelay(100); +} + +/*Disable RTL8192SE ASPM & Disable Pci Bridge ASPM*/ +static void rtl_pci_disable_aspm(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + u8 pcibridge_vendor = pcipriv->ndis_adapter.pcibridge_vendor; + u8 num4bytes = pcipriv->ndis_adapter.num4bytes; + /*Retrieve original configuration settings. */ + u8 linkctrl_reg = pcipriv->ndis_adapter.linkctrl_reg; + u16 pcibridge_linkctrlreg = pcipriv->ndis_adapter.pcibridge_linkctrlreg; + u16 aspmlevel = 0; + u8 tmp_u1b = 0; + + if (!ppsc->support_aspm) + return; + + if (pcibridge_vendor == PCI_BRIDGE_VENDOR_UNKNOWN) { + RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE, + "PCI(Bridge) UNKNOWN\n"); + + return; + } + + if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_CLK_REQ) { + RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_CLK_REQ); + _rtl_pci_switch_clk_req(hw, 0x0); + } + + /*for promising device will in L0 state after an I/O. */ + pci_read_config_byte(rtlpci->pdev, 0x80, &tmp_u1b); + + /*Set corresponding value. */ + aspmlevel |= BIT(0) | BIT(1); + linkctrl_reg &= ~aspmlevel; + pcibridge_linkctrlreg &= ~(BIT(0) | BIT(1)); + + _rtl_pci_platform_switch_device_pci_aspm(hw, linkctrl_reg); + udelay(50); + + /*4 Disable Pci Bridge ASPM */ + pci_write_config_byte(rtlpci->pdev, (num4bytes << 2), + pcibridge_linkctrlreg); + + udelay(50); +} + +/* + *Enable RTL8192SE ASPM & Enable Pci Bridge ASPM for + *power saving We should follow the sequence to enable + *RTL8192SE first then enable Pci Bridge ASPM + *or the system will show bluescreen. + */ +static void rtl_pci_enable_aspm(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + u8 pcibridge_vendor = pcipriv->ndis_adapter.pcibridge_vendor; + u8 num4bytes = pcipriv->ndis_adapter.num4bytes; + u16 aspmlevel; + u8 u_pcibridge_aspmsetting; + u8 u_device_aspmsetting; + + if (!ppsc->support_aspm) + return; + + if (pcibridge_vendor == PCI_BRIDGE_VENDOR_UNKNOWN) { + RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE, + "PCI(Bridge) UNKNOWN\n"); + return; + } + + /*4 Enable Pci Bridge ASPM */ + + u_pcibridge_aspmsetting = + pcipriv->ndis_adapter.pcibridge_linkctrlreg | + rtlpci->const_hostpci_aspm_setting; + + if (pcibridge_vendor == PCI_BRIDGE_VENDOR_INTEL) + u_pcibridge_aspmsetting &= ~BIT(0); + + pci_write_config_byte(rtlpci->pdev, (num4bytes << 2), + u_pcibridge_aspmsetting); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "PlatformEnableASPM(): Write reg[%x] = %x\n", + (pcipriv->ndis_adapter.pcibridge_pciehdr_offset + 0x10), + u_pcibridge_aspmsetting); + + udelay(50); + + /*Get ASPM level (with/without Clock Req) */ + aspmlevel = rtlpci->const_devicepci_aspm_setting; + u_device_aspmsetting = pcipriv->ndis_adapter.linkctrl_reg; + + /*_rtl_pci_platform_switch_device_pci_aspm(dev,*/ + /*(priv->ndis_adapter.linkctrl_reg | ASPMLevel)); */ + + u_device_aspmsetting |= aspmlevel; + + _rtl_pci_platform_switch_device_pci_aspm(hw, u_device_aspmsetting); + + if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_CLK_REQ) { + _rtl_pci_switch_clk_req(hw, (ppsc->reg_rfps_level & + RT_RF_OFF_LEVL_CLK_REQ) ? 1 : 0); + RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_CLK_REQ); + } + udelay(100); +} + +static bool rtl_pci_get_amd_l1_patch(struct ieee80211_hw *hw) +{ + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + + bool status = false; + u8 offset_e0; + unsigned int offset_e4; + + pci_write_config_byte(rtlpci->pdev, 0xe0, 0xa0); + + pci_read_config_byte(rtlpci->pdev, 0xe0, &offset_e0); + + if (offset_e0 == 0xA0) { + pci_read_config_dword(rtlpci->pdev, 0xe4, &offset_e4); + if (offset_e4 & BIT(23)) + status = true; + } + + return status; +} + +static bool rtl_pci_check_buddy_priv(struct ieee80211_hw *hw, + struct rtl_priv **buddy_priv) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + bool find_buddy_priv = false; + struct rtl_priv *tpriv; + struct rtl_pci_priv *tpcipriv = NULL; + + if (!list_empty(&rtlpriv->glb_var->glb_priv_list)) { + list_for_each_entry(tpriv, &rtlpriv->glb_var->glb_priv_list, + list) { + tpcipriv = (struct rtl_pci_priv *)tpriv->priv; + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "pcipriv->ndis_adapter.funcnumber %x\n", + pcipriv->ndis_adapter.funcnumber); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "tpcipriv->ndis_adapter.funcnumber %x\n", + tpcipriv->ndis_adapter.funcnumber); + + if ((pcipriv->ndis_adapter.busnumber == + tpcipriv->ndis_adapter.busnumber) && + (pcipriv->ndis_adapter.devnumber == + tpcipriv->ndis_adapter.devnumber) && + (pcipriv->ndis_adapter.funcnumber != + tpcipriv->ndis_adapter.funcnumber)) { + find_buddy_priv = true; + break; + } + } + } + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "find_buddy_priv %d\n", find_buddy_priv); + + if (find_buddy_priv) + *buddy_priv = tpriv; + + return find_buddy_priv; +} + +static void rtl_pci_get_linkcontrol_field(struct ieee80211_hw *hw) +{ + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(pcipriv); + u8 capabilityoffset = pcipriv->ndis_adapter.pcibridge_pciehdr_offset; + u8 linkctrl_reg; + u8 num4bbytes; + + num4bbytes = (capabilityoffset + 0x10) / 4; + + /*Read Link Control Register */ + pci_read_config_byte(rtlpci->pdev, (num4bbytes << 2), &linkctrl_reg); + + pcipriv->ndis_adapter.pcibridge_linkctrlreg = linkctrl_reg; +} + +static void rtl_pci_parse_configuration(struct pci_dev *pdev, + struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + + u8 tmp; + u16 linkctrl_reg; + + /*Link Control Register */ + pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &linkctrl_reg); + pcipriv->ndis_adapter.linkctrl_reg = (u8)linkctrl_reg; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Link Control Register =%x\n", + pcipriv->ndis_adapter.linkctrl_reg); + + pci_read_config_byte(pdev, 0x98, &tmp); + tmp |= BIT(4); + pci_write_config_byte(pdev, 0x98, tmp); + + tmp = 0x17; + pci_write_config_byte(pdev, 0x70f, tmp); +} + +static void rtl_pci_init_aspm(struct ieee80211_hw *hw) +{ + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + + _rtl_pci_update_default_setting(hw); + + if (ppsc->reg_rfps_level & RT_RF_PS_LEVEL_ALWAYS_ASPM) { + /*Always enable ASPM & Clock Req. */ + rtl_pci_enable_aspm(hw); + RT_SET_PS_LEVEL(ppsc, RT_RF_PS_LEVEL_ALWAYS_ASPM); + } +} + +static void _rtl_pci_io_handler_init(struct device *dev, + struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtlpriv->io.dev = dev; + + rtlpriv->io.write8_async = pci_write8_async; + rtlpriv->io.write16_async = pci_write16_async; + rtlpriv->io.write32_async = pci_write32_async; + + rtlpriv->io.read8_sync = pci_read8_sync; + rtlpriv->io.read16_sync = pci_read16_sync; + rtlpriv->io.read32_sync = pci_read32_sync; +} + +static bool _rtl_update_earlymode_info(struct ieee80211_hw *hw, + struct sk_buff *skb, + struct rtl_tcb_desc *tcb_desc, u8 tid) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct sk_buff *next_skb; + u8 additionlen = FCS_LEN; + + /* here open is 4, wep/tkip is 8, aes is 12*/ + if (info->control.hw_key) + additionlen += info->control.hw_key->icv_len; + + /* The most skb num is 6 */ + tcb_desc->empkt_num = 0; + spin_lock_bh(&rtlpriv->locks.waitq_lock); + skb_queue_walk(&rtlpriv->mac80211.skb_waitq[tid], next_skb) { + struct ieee80211_tx_info *next_info; + + next_info = IEEE80211_SKB_CB(next_skb); + if (next_info->flags & IEEE80211_TX_CTL_AMPDU) { + tcb_desc->empkt_len[tcb_desc->empkt_num] = + next_skb->len + additionlen; + tcb_desc->empkt_num++; + } else { + break; + } + + if (skb_queue_is_last(&rtlpriv->mac80211.skb_waitq[tid], + next_skb)) + break; + + if (tcb_desc->empkt_num >= rtlhal->max_earlymode_num) + break; + } + spin_unlock_bh(&rtlpriv->locks.waitq_lock); + + return true; +} + +/* just for early mode now */ +static void _rtl_pci_tx_chk_waitq(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct sk_buff *skb = NULL; + struct ieee80211_tx_info *info = NULL; + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + int tid; + + if (!rtlpriv->rtlhal.earlymode_enable) + return; + + if (rtlpriv->dm.supp_phymode_switch && + (rtlpriv->easy_concurrent_ctl.switch_in_process || + (rtlpriv->buddy_priv && + rtlpriv->buddy_priv->easy_concurrent_ctl.switch_in_process))) + return; + /* we just use em for BE/BK/VI/VO */ + for (tid = 7; tid >= 0; tid--) { + u8 hw_queue = ac_to_hwq[rtl_tid_to_ac(tid)]; + struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[hw_queue]; + + while (!mac->act_scanning && + rtlpriv->psc.rfpwr_state == ERFON) { + struct rtl_tcb_desc tcb_desc; + + memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc)); + spin_lock_bh(&rtlpriv->locks.waitq_lock); + if (!skb_queue_empty(&mac->skb_waitq[tid]) && + (ring->entries - skb_queue_len(&ring->queue) > + rtlhal->max_earlymode_num)) { + skb = skb_dequeue(&mac->skb_waitq[tid]); + } else { + spin_unlock_bh(&rtlpriv->locks.waitq_lock); + break; + } + spin_unlock_bh(&rtlpriv->locks.waitq_lock); + + /* Some macaddr can't do early mode. like + * multicast/broadcast/no_qos data + */ + info = IEEE80211_SKB_CB(skb); + if (info->flags & IEEE80211_TX_CTL_AMPDU) + _rtl_update_earlymode_info(hw, skb, + &tcb_desc, tid); + + rtlpriv->intf_ops->adapter_tx(hw, NULL, skb, &tcb_desc); + } + } +} + +static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + + struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[prio]; + + while (skb_queue_len(&ring->queue)) { + struct sk_buff *skb; + struct ieee80211_tx_info *info; + __le16 fc; + u8 tid; + u8 *entry; + + if (rtlpriv->use_new_trx_flow) + entry = (u8 *)(&ring->buffer_desc[ring->idx]); + else + entry = (u8 *)(&ring->desc[ring->idx]); + + if (!rtlpriv->cfg->ops->is_tx_desc_closed(hw, prio, ring->idx)) + return; + ring->idx = (ring->idx + 1) % ring->entries; + + skb = __skb_dequeue(&ring->queue); + pci_unmap_single(rtlpci->pdev, + rtlpriv->cfg->ops->get_desc(hw, (u8 *)entry, true, + HW_DESC_TXBUFF_ADDR), + skb->len, PCI_DMA_TODEVICE); + + /* remove early mode header */ + if (rtlpriv->rtlhal.earlymode_enable) + skb_pull(skb, EM_HDR_LEN); + + RT_TRACE(rtlpriv, (COMP_INTR | COMP_SEND), DBG_TRACE, + "new ring->idx:%d, free: skb_queue_len:%d, free: seq:%x\n", + ring->idx, + skb_queue_len(&ring->queue), + *(u16 *)(skb->data + 22)); + + if (prio == TXCMD_QUEUE) { + dev_kfree_skb(skb); + goto tx_status_ok; + } + + /* for sw LPS, just after NULL skb send out, we can + * sure AP knows we are sleeping, we should not let + * rf sleep + */ + fc = rtl_get_fc(skb); + if (ieee80211_is_nullfunc(fc)) { + if (ieee80211_has_pm(fc)) { + rtlpriv->mac80211.offchan_delay = true; + rtlpriv->psc.state_inap = true; + } else { + rtlpriv->psc.state_inap = false; + } + } + if (ieee80211_is_action(fc)) { + struct ieee80211_mgmt *action_frame = + (struct ieee80211_mgmt *)skb->data; + if (action_frame->u.action.u.ht_smps.action == + WLAN_HT_ACTION_SMPS) { + dev_kfree_skb(skb); + goto tx_status_ok; + } + } + + /* update tid tx pkt num */ + tid = rtl_get_tid(skb); + if (tid <= 7) + rtlpriv->link_info.tidtx_inperiod[tid]++; + + info = IEEE80211_SKB_CB(skb); + ieee80211_tx_info_clear_status(info); + + info->flags |= IEEE80211_TX_STAT_ACK; + /*info->status.rates[0].count = 1; */ + + ieee80211_tx_status_irqsafe(hw, skb); + + if ((ring->entries - skb_queue_len(&ring->queue)) <= 4) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_DMESG, + "more desc left, wake skb_queue@%d, ring->idx = %d, skb_queue_len = 0x%x\n", + prio, ring->idx, + skb_queue_len(&ring->queue)); + + ieee80211_wake_queue(hw, skb_get_queue_mapping (skb)); + } +tx_status_ok: + skb = NULL; + } + + if (((rtlpriv->link_info.num_rx_inperiod + + rtlpriv->link_info.num_tx_inperiod) > 8) || + (rtlpriv->link_info.num_rx_inperiod > 2)) + rtl_lps_leave(hw); +} + +static int _rtl_pci_init_one_rxdesc(struct ieee80211_hw *hw, + struct sk_buff *new_skb, u8 *entry, + int rxring_idx, int desc_idx) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + u32 bufferaddress; + u8 tmp_one = 1; + struct sk_buff *skb; + + if (likely(new_skb)) { + skb = new_skb; + goto remap; + } + skb = dev_alloc_skb(rtlpci->rxbuffersize); + if (!skb) + return 0; + +remap: + /* just set skb->cb to mapping addr for pci_unmap_single use */ + *((dma_addr_t *)skb->cb) = + pci_map_single(rtlpci->pdev, skb_tail_pointer(skb), + rtlpci->rxbuffersize, PCI_DMA_FROMDEVICE); + bufferaddress = *((dma_addr_t *)skb->cb); + if (pci_dma_mapping_error(rtlpci->pdev, bufferaddress)) + return 0; + rtlpci->rx_ring[rxring_idx].rx_buf[desc_idx] = skb; + if (rtlpriv->use_new_trx_flow) { + /* skb->cb may be 64 bit address */ + rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry, false, + HW_DESC_RX_PREPARE, + (u8 *)(dma_addr_t *)skb->cb); + } else { + rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry, false, + HW_DESC_RXBUFF_ADDR, + (u8 *)&bufferaddress); + rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry, false, + HW_DESC_RXPKT_LEN, + (u8 *)&rtlpci->rxbuffersize); + rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry, false, + HW_DESC_RXOWN, + (u8 *)&tmp_one); + } + return 1; +} + +/* inorder to receive 8K AMSDU we have set skb to + * 9100bytes in init rx ring, but if this packet is + * not a AMSDU, this large packet will be sent to + * TCP/IP directly, this cause big packet ping fail + * like: "ping -s 65507", so here we will realloc skb + * based on the true size of packet, Mac80211 + * Probably will do it better, but does not yet. + * + * Some platform will fail when alloc skb sometimes. + * in this condition, we will send the old skb to + * mac80211 directly, this will not cause any other + * issues, but only this packet will be lost by TCP/IP + */ +static void _rtl_pci_rx_to_mac80211(struct ieee80211_hw *hw, + struct sk_buff *skb, + struct ieee80211_rx_status rx_status) +{ + if (unlikely(!rtl_action_proc(hw, skb, false))) { + dev_kfree_skb_any(skb); + } else { + struct sk_buff *uskb = NULL; + + uskb = dev_alloc_skb(skb->len + 128); + if (likely(uskb)) { + memcpy(IEEE80211_SKB_RXCB(uskb), &rx_status, + sizeof(rx_status)); + skb_put_data(uskb, skb->data, skb->len); + dev_kfree_skb_any(skb); + ieee80211_rx_irqsafe(hw, uskb); + } else { + ieee80211_rx_irqsafe(hw, skb); + } + } +} + +/*hsisr interrupt handler*/ +static void _rtl_pci_hs_interrupt(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[MAC_HSISR], + rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[MAC_HSISR]) | + rtlpci->sys_irq_mask); +} + +static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + int rxring_idx = RTL_PCI_RX_MPDU_QUEUE; + struct ieee80211_rx_status rx_status = { 0 }; + unsigned int count = rtlpci->rxringcount; + u8 own; + u8 tmp_one; + bool unicast = false; + u8 hw_queue = 0; + unsigned int rx_remained_cnt = 0; + struct rtl_stats stats = { + .signal = 0, + .rate = 0, + }; + + /*RX NORMAL PKT */ + while (count--) { + struct ieee80211_hdr *hdr; + __le16 fc; + u16 len; + /*rx buffer descriptor */ + struct rtl_rx_buffer_desc *buffer_desc = NULL; + /*if use new trx flow, it means wifi info */ + struct rtl_rx_desc *pdesc = NULL; + /*rx pkt */ + struct sk_buff *skb = rtlpci->rx_ring[rxring_idx].rx_buf[ + rtlpci->rx_ring[rxring_idx].idx]; + struct sk_buff *new_skb; + + if (rtlpriv->use_new_trx_flow) { + if (rx_remained_cnt == 0) + rx_remained_cnt = + rtlpriv->cfg->ops->rx_desc_buff_remained_cnt(hw, + hw_queue); + if (rx_remained_cnt == 0) + return; + buffer_desc = &rtlpci->rx_ring[rxring_idx].buffer_desc[ + rtlpci->rx_ring[rxring_idx].idx]; + pdesc = (struct rtl_rx_desc *)skb->data; + } else { /* rx descriptor */ + pdesc = &rtlpci->rx_ring[rxring_idx].desc[ + rtlpci->rx_ring[rxring_idx].idx]; + + own = (u8)rtlpriv->cfg->ops->get_desc(hw, (u8 *)pdesc, + false, + HW_DESC_OWN); + if (own) /* wait data to be filled by hardware */ + return; + } + + /* Reaching this point means: data is filled already + * AAAAAAttention !!! + * We can NOT access 'skb' before 'pci_unmap_single' + */ + pci_unmap_single(rtlpci->pdev, *((dma_addr_t *)skb->cb), + rtlpci->rxbuffersize, PCI_DMA_FROMDEVICE); + + /* get a new skb - if fail, old one will be reused */ + new_skb = dev_alloc_skb(rtlpci->rxbuffersize); + if (unlikely(!new_skb)) + goto no_new; + memset(&rx_status, 0, sizeof(rx_status)); + rtlpriv->cfg->ops->query_rx_desc(hw, &stats, + &rx_status, (u8 *)pdesc, skb); + + if (rtlpriv->use_new_trx_flow) + rtlpriv->cfg->ops->rx_check_dma_ok(hw, + (u8 *)buffer_desc, + hw_queue); + + len = rtlpriv->cfg->ops->get_desc(hw, (u8 *)pdesc, false, + HW_DESC_RXPKT_LEN); + + if (skb->end - skb->tail > len) { + skb_put(skb, len); + if (rtlpriv->use_new_trx_flow) + skb_reserve(skb, stats.rx_drvinfo_size + + stats.rx_bufshift + 24); + else + skb_reserve(skb, stats.rx_drvinfo_size + + stats.rx_bufshift); + } else { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "skb->end - skb->tail = %d, len is %d\n", + skb->end - skb->tail, len); + dev_kfree_skb_any(skb); + goto new_trx_end; + } + /* handle command packet here */ + if (rtlpriv->cfg->ops->rx_command_packet && + rtlpriv->cfg->ops->rx_command_packet(hw, &stats, skb)) { + dev_kfree_skb_any(skb); + goto new_trx_end; + } + + /* + * NOTICE This can not be use for mac80211, + * this is done in mac80211 code, + * if done here sec DHCP will fail + * skb_trim(skb, skb->len - 4); + */ + + hdr = rtl_get_hdr(skb); + fc = rtl_get_fc(skb); + + if (!stats.crc && !stats.hwerror) { + memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, + sizeof(rx_status)); + + if (is_broadcast_ether_addr(hdr->addr1)) { + ;/*TODO*/ + } else if (is_multicast_ether_addr(hdr->addr1)) { + ;/*TODO*/ + } else { + unicast = true; + rtlpriv->stats.rxbytesunicast += skb->len; + } + rtl_is_special_data(hw, skb, false, true); + + if (ieee80211_is_data(fc)) { + rtlpriv->cfg->ops->led_control(hw, LED_CTL_RX); + if (unicast) + rtlpriv->link_info.num_rx_inperiod++; + } + + rtl_collect_scan_list(hw, skb); + + /* static bcn for roaming */ + rtl_beacon_statistic(hw, skb); + rtl_p2p_info(hw, (void *)skb->data, skb->len); + /* for sw lps */ + rtl_swlps_beacon(hw, (void *)skb->data, skb->len); + rtl_recognize_peer(hw, (void *)skb->data, skb->len); + if ((rtlpriv->mac80211.opmode == NL80211_IFTYPE_AP) && + (rtlpriv->rtlhal.current_bandtype == + BAND_ON_2_4G) && + (ieee80211_is_beacon(fc) || + ieee80211_is_probe_resp(fc))) { + dev_kfree_skb_any(skb); + } else { + rtl_check_beacon_key(hw, (void *)skb->data, + skb->len); + _rtl_pci_rx_to_mac80211(hw, skb, rx_status); + } + } else { + dev_kfree_skb_any(skb); + } +new_trx_end: + if (rtlpriv->use_new_trx_flow) { + rtlpci->rx_ring[hw_queue].next_rx_rp += 1; + rtlpci->rx_ring[hw_queue].next_rx_rp %= + RTL_PCI_MAX_RX_COUNT; + + rx_remained_cnt--; + rtl_write_word(rtlpriv, 0x3B4, + rtlpci->rx_ring[hw_queue].next_rx_rp); + } + if (((rtlpriv->link_info.num_rx_inperiod + + rtlpriv->link_info.num_tx_inperiod) > 8) || + (rtlpriv->link_info.num_rx_inperiod > 2)) + rtl_lps_leave(hw); + skb = new_skb; +no_new: + if (rtlpriv->use_new_trx_flow) { + _rtl_pci_init_one_rxdesc(hw, skb, (u8 *)buffer_desc, + rxring_idx, + rtlpci->rx_ring[rxring_idx].idx); + } else { + _rtl_pci_init_one_rxdesc(hw, skb, (u8 *)pdesc, + rxring_idx, + rtlpci->rx_ring[rxring_idx].idx); + if (rtlpci->rx_ring[rxring_idx].idx == + rtlpci->rxringcount - 1) + rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, + false, + HW_DESC_RXERO, + (u8 *)&tmp_one); + } + rtlpci->rx_ring[rxring_idx].idx = + (rtlpci->rx_ring[rxring_idx].idx + 1) % + rtlpci->rxringcount; + } +} + +static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id) +{ + struct ieee80211_hw *hw = dev_id; + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + unsigned long flags; + u32 inta = 0; + u32 intb = 0; + u32 intc = 0; + u32 intd = 0; + irqreturn_t ret = IRQ_HANDLED; + + if (rtlpci->irq_enabled == 0) + return ret; + + spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags); + rtlpriv->cfg->ops->disable_interrupt(hw); + + /*read ISR: 4/8bytes */ + rtlpriv->cfg->ops->interrupt_recognized(hw, &inta, &intb, &intc, &intd); + + /*Shared IRQ or HW disappeared */ + if (!inta || inta == 0xffff) + goto done; + + /*<1> beacon related */ + if (inta & rtlpriv->cfg->maps[RTL_IMR_TBDOK]) { + RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE, + "beacon ok interrupt!\n"); + } + + if (unlikely(inta & rtlpriv->cfg->maps[RTL_IMR_TBDER])) { + RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE, + "beacon err interrupt!\n"); + } + + if (inta & rtlpriv->cfg->maps[RTL_IMR_BDOK]) + RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE, "beacon interrupt!\n"); + + if (inta & rtlpriv->cfg->maps[RTL_IMR_BCNINT]) { + RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE, + "prepare beacon for interrupt!\n"); + tasklet_schedule(&rtlpriv->works.irq_prepare_bcn_tasklet); + } + + /*<2> Tx related */ + if (unlikely(intb & rtlpriv->cfg->maps[RTL_IMR_TXFOVW])) + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, "IMR_TXFOVW!\n"); + + if (inta & rtlpriv->cfg->maps[RTL_IMR_MGNTDOK]) { + RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE, + "Manage ok interrupt!\n"); + _rtl_pci_tx_isr(hw, MGNT_QUEUE); + } + + if (inta & rtlpriv->cfg->maps[RTL_IMR_HIGHDOK]) { + RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE, + "HIGH_QUEUE ok interrupt!\n"); + _rtl_pci_tx_isr(hw, HIGH_QUEUE); + } + + if (inta & rtlpriv->cfg->maps[RTL_IMR_BKDOK]) { + rtlpriv->link_info.num_tx_inperiod++; + + RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE, + "BK Tx OK interrupt!\n"); + _rtl_pci_tx_isr(hw, BK_QUEUE); + } + + if (inta & rtlpriv->cfg->maps[RTL_IMR_BEDOK]) { + rtlpriv->link_info.num_tx_inperiod++; + + RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE, + "BE TX OK interrupt!\n"); + _rtl_pci_tx_isr(hw, BE_QUEUE); + } + + if (inta & rtlpriv->cfg->maps[RTL_IMR_VIDOK]) { + rtlpriv->link_info.num_tx_inperiod++; + + RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE, + "VI TX OK interrupt!\n"); + _rtl_pci_tx_isr(hw, VI_QUEUE); + } + + if (inta & rtlpriv->cfg->maps[RTL_IMR_VODOK]) { + rtlpriv->link_info.num_tx_inperiod++; + + RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE, + "Vo TX OK interrupt!\n"); + _rtl_pci_tx_isr(hw, VO_QUEUE); + } + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8822BE) { + if (intd & rtlpriv->cfg->maps[RTL_IMR_H2CDOK]) { + rtlpriv->link_info.num_tx_inperiod++; + + RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE, + "H2C TX OK interrupt!\n"); + _rtl_pci_tx_isr(hw, H2C_QUEUE); + } + } + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) { + if (inta & rtlpriv->cfg->maps[RTL_IMR_COMDOK]) { + rtlpriv->link_info.num_tx_inperiod++; + + RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE, + "CMD TX OK interrupt!\n"); + _rtl_pci_tx_isr(hw, TXCMD_QUEUE); + } + } + + /*<3> Rx related */ + if (inta & rtlpriv->cfg->maps[RTL_IMR_ROK]) { + RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE, "Rx ok interrupt!\n"); + _rtl_pci_rx_interrupt(hw); + } + + if (unlikely(inta & rtlpriv->cfg->maps[RTL_IMR_RDU])) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "rx descriptor unavailable!\n"); + _rtl_pci_rx_interrupt(hw); + } + + if (unlikely(intb & rtlpriv->cfg->maps[RTL_IMR_RXFOVW])) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, "rx overflow !\n"); + _rtl_pci_rx_interrupt(hw); + } + + /*<4> fw related*/ + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723AE) { + if (inta & rtlpriv->cfg->maps[RTL_IMR_C2HCMD]) { + RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE, + "firmware interrupt!\n"); + queue_delayed_work(rtlpriv->works.rtl_wq, + &rtlpriv->works.fwevt_wq, 0); + } + } + + /*<5> hsisr related*/ + /* Only 8188EE & 8723BE Supported. + * If Other ICs Come in, System will corrupt, + * because maps[RTL_IMR_HSISR_IND] & maps[MAC_HSISR] + * are not initialized + */ + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8188EE || + rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) { + if (unlikely(inta & rtlpriv->cfg->maps[RTL_IMR_HSISR_IND])) { + RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE, + "hsisr interrupt!\n"); + _rtl_pci_hs_interrupt(hw); + } + } + + if (rtlpriv->rtlhal.earlymode_enable) + tasklet_schedule(&rtlpriv->works.irq_tasklet); + +done: + rtlpriv->cfg->ops->enable_interrupt(hw); + spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); + return ret; +} + +static void _rtl_pci_irq_tasklet(struct ieee80211_hw *hw) +{ + _rtl_pci_tx_chk_waitq(hw); +} + +static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl8192_tx_ring *ring = NULL; + struct ieee80211_hdr *hdr = NULL; + struct ieee80211_tx_info *info = NULL; + struct sk_buff *pskb = NULL; + struct rtl_tx_desc *pdesc = NULL; + struct rtl_tcb_desc tcb_desc; + /*This is for new trx flow*/ + struct rtl_tx_buffer_desc *pbuffer_desc = NULL; + u8 temp_one = 1; + u8 *entry; + + memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc)); + ring = &rtlpci->tx_ring[BEACON_QUEUE]; + pskb = __skb_dequeue(&ring->queue); + if (rtlpriv->use_new_trx_flow) + entry = (u8 *)(&ring->buffer_desc[ring->idx]); + else + entry = (u8 *)(&ring->desc[ring->idx]); + if (pskb) { + pci_unmap_single(rtlpci->pdev, + rtlpriv->cfg->ops->get_desc( + hw, (u8 *)entry, true, HW_DESC_TXBUFF_ADDR), + pskb->len, PCI_DMA_TODEVICE); + kfree_skb(pskb); + } + + /*NB: the beacon data buffer must be 32-bit aligned. */ + pskb = ieee80211_beacon_get(hw, mac->vif); + if (!pskb) + return; + hdr = rtl_get_hdr(pskb); + info = IEEE80211_SKB_CB(pskb); + pdesc = &ring->desc[0]; + if (rtlpriv->use_new_trx_flow) + pbuffer_desc = &ring->buffer_desc[0]; + + rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *)pdesc, + (u8 *)pbuffer_desc, info, NULL, pskb, + BEACON_QUEUE, &tcb_desc); + + __skb_queue_tail(&ring->queue, pskb); + + if (rtlpriv->use_new_trx_flow) { + temp_one = 4; + rtlpriv->cfg->ops->set_desc(hw, (u8 *)pbuffer_desc, true, + HW_DESC_OWN, (u8 *)&temp_one); + } else { + rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, true, HW_DESC_OWN, + &temp_one); + } +} + +static void _rtl_pci_init_trx_var(struct ieee80211_hw *hw) +{ + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + u8 i; + u16 desc_num; + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192EE) + desc_num = TX_DESC_NUM_92E; + else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8822BE) + desc_num = TX_DESC_NUM_8822B; + else + desc_num = RT_TXDESC_NUM; + + for (i = 0; i < RTL_PCI_MAX_TX_QUEUE_COUNT; i++) + rtlpci->txringcount[i] = desc_num; + + /* + *we just alloc 2 desc for beacon queue, + *because we just need first desc in hw beacon. + */ + rtlpci->txringcount[BEACON_QUEUE] = 2; + + /*BE queue need more descriptor for performance + *consideration or, No more tx desc will happen, + *and may cause mac80211 mem leakage. + */ + if (!rtl_priv(hw)->use_new_trx_flow) + rtlpci->txringcount[BE_QUEUE] = RT_TXDESC_NUM_BE_QUEUE; + + rtlpci->rxbuffersize = 9100; /*2048/1024; */ + rtlpci->rxringcount = RTL_PCI_MAX_RX_COUNT; /*64; */ +} + +static void _rtl_pci_init_struct(struct ieee80211_hw *hw, + struct pci_dev *pdev) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + + rtlpci->up_first_time = true; + rtlpci->being_init_adapter = false; + + rtlhal->hw = hw; + rtlpci->pdev = pdev; + + /*Tx/Rx related var */ + _rtl_pci_init_trx_var(hw); + + /*IBSS*/ + mac->beacon_interval = 100; + + /*AMPDU*/ + mac->min_space_cfg = 0; + mac->max_mss_density = 0; + /*set sane AMPDU defaults */ + mac->current_ampdu_density = 7; + mac->current_ampdu_factor = 3; + + /*Retry Limit*/ + mac->retry_short = 7; + mac->retry_long = 7; + + /*QOS*/ + rtlpci->acm_method = EACMWAY2_SW; + + /*task */ + tasklet_init(&rtlpriv->works.irq_tasklet, + (void (*)(unsigned long))_rtl_pci_irq_tasklet, + (unsigned long)hw); + tasklet_init(&rtlpriv->works.irq_prepare_bcn_tasklet, + (void (*)(unsigned long))_rtl_pci_prepare_bcn_tasklet, + (unsigned long)hw); + INIT_WORK(&rtlpriv->works.lps_change_work, + rtl_lps_change_work_callback); +} + +static int _rtl_pci_init_tx_ring(struct ieee80211_hw *hw, + unsigned int prio, unsigned int entries) +{ + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_tx_buffer_desc *buffer_desc; + struct rtl_tx_desc *desc; + dma_addr_t buffer_desc_dma, desc_dma; + u32 nextdescaddress; + int i; + + /* alloc tx buffer desc for new trx flow*/ + if (rtlpriv->use_new_trx_flow) { + buffer_desc = + pci_zalloc_consistent(rtlpci->pdev, + sizeof(*buffer_desc) * entries, + &buffer_desc_dma); + + if (!buffer_desc || (unsigned long)buffer_desc & 0xFF) { + pr_err("Cannot allocate TX ring (prio = %d)\n", + prio); + return -ENOMEM; + } + + rtlpci->tx_ring[prio].buffer_desc = buffer_desc; + rtlpci->tx_ring[prio].buffer_desc_dma = buffer_desc_dma; + + rtlpci->tx_ring[prio].cur_tx_rp = 0; + rtlpci->tx_ring[prio].cur_tx_wp = 0; + } + + /* alloc dma for this ring */ + desc = pci_zalloc_consistent(rtlpci->pdev, + sizeof(*desc) * entries, &desc_dma); + + if (!desc || (unsigned long)desc & 0xFF) { + pr_err("Cannot allocate TX ring (prio = %d)\n", prio); + return -ENOMEM; + } + + rtlpci->tx_ring[prio].desc = desc; + rtlpci->tx_ring[prio].dma = desc_dma; + + rtlpci->tx_ring[prio].idx = 0; + rtlpci->tx_ring[prio].entries = entries; + skb_queue_head_init(&rtlpci->tx_ring[prio].queue); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "queue:%d, ring_addr:%p\n", + prio, desc); + + /* init every desc in this ring */ + if (!rtlpriv->use_new_trx_flow) { + for (i = 0; i < entries; i++) { + nextdescaddress = (u32)desc_dma + + ((i + 1) % entries) * + sizeof(*desc); + + rtlpriv->cfg->ops->set_desc(hw, (u8 *)&desc[i], + true, + HW_DESC_TX_NEXTDESC_ADDR, + (u8 *)&nextdescaddress); + } + } + return 0; +} + +static int _rtl_pci_init_rx_ring(struct ieee80211_hw *hw, int rxring_idx) +{ + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_priv *rtlpriv = rtl_priv(hw); + int i; + + if (rtlpriv->use_new_trx_flow) { + struct rtl_rx_buffer_desc *entry = NULL; + /* alloc dma for this ring */ + rtlpci->rx_ring[rxring_idx].buffer_desc = + pci_zalloc_consistent(rtlpci->pdev, + sizeof(*rtlpci->rx_ring[rxring_idx].buffer_desc) * + rtlpci->rxringcount, + &rtlpci->rx_ring[rxring_idx].dma); + if (!rtlpci->rx_ring[rxring_idx].buffer_desc || + (ulong)rtlpci->rx_ring[rxring_idx].buffer_desc & 0xFF) { + pr_err("Cannot allocate RX ring\n"); + return -ENOMEM; + } + + /* init every desc in this ring */ + rtlpci->rx_ring[rxring_idx].idx = 0; + for (i = 0; i < rtlpci->rxringcount; i++) { + entry = &rtlpci->rx_ring[rxring_idx].buffer_desc[i]; + if (!_rtl_pci_init_one_rxdesc(hw, NULL, (u8 *)entry, + rxring_idx, i)) + return -ENOMEM; + } + } else { + struct rtl_rx_desc *entry = NULL; + u8 tmp_one = 1; + /* alloc dma for this ring */ + rtlpci->rx_ring[rxring_idx].desc = + pci_zalloc_consistent(rtlpci->pdev, + sizeof(*rtlpci->rx_ring[rxring_idx].desc) * + rtlpci->rxringcount, + &rtlpci->rx_ring[rxring_idx].dma); + if (!rtlpci->rx_ring[rxring_idx].desc || + (unsigned long)rtlpci->rx_ring[rxring_idx].desc & 0xFF) { + pr_err("Cannot allocate RX ring\n"); + return -ENOMEM; + } + + /* init every desc in this ring */ + rtlpci->rx_ring[rxring_idx].idx = 0; + + for (i = 0; i < rtlpci->rxringcount; i++) { + entry = &rtlpci->rx_ring[rxring_idx].desc[i]; + if (!_rtl_pci_init_one_rxdesc(hw, NULL, (u8 *)entry, + rxring_idx, i)) + return -ENOMEM; + } + + rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry, false, + HW_DESC_RXERO, &tmp_one); + } + return 0; +} + +static void _rtl_pci_free_tx_ring(struct ieee80211_hw *hw, + unsigned int prio) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[prio]; + + /* free every desc in this ring */ + while (skb_queue_len(&ring->queue)) { + u8 *entry; + struct sk_buff *skb = __skb_dequeue(&ring->queue); + + if (rtlpriv->use_new_trx_flow) + entry = (u8 *)(&ring->buffer_desc[ring->idx]); + else + entry = (u8 *)(&ring->desc[ring->idx]); + + pci_unmap_single(rtlpci->pdev, + rtlpriv->cfg->ops->get_desc(hw, (u8 *)entry, + true, + HW_DESC_TXBUFF_ADDR), + skb->len, PCI_DMA_TODEVICE); + kfree_skb(skb); + ring->idx = (ring->idx + 1) % ring->entries; + } + + /* free dma of this ring */ + pci_free_consistent(rtlpci->pdev, + sizeof(*ring->desc) * ring->entries, + ring->desc, ring->dma); + ring->desc = NULL; + if (rtlpriv->use_new_trx_flow) { + pci_free_consistent(rtlpci->pdev, + sizeof(*ring->buffer_desc) * ring->entries, + ring->buffer_desc, ring->buffer_desc_dma); + ring->buffer_desc = NULL; + } +} + +static void _rtl_pci_free_rx_ring(struct ieee80211_hw *hw, int rxring_idx) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + int i; + + /* free every desc in this ring */ + for (i = 0; i < rtlpci->rxringcount; i++) { + struct sk_buff *skb = rtlpci->rx_ring[rxring_idx].rx_buf[i]; + + if (!skb) + continue; + pci_unmap_single(rtlpci->pdev, *((dma_addr_t *)skb->cb), + rtlpci->rxbuffersize, PCI_DMA_FROMDEVICE); + kfree_skb(skb); + } + + /* free dma of this ring */ + if (rtlpriv->use_new_trx_flow) { + pci_free_consistent(rtlpci->pdev, + sizeof(*rtlpci->rx_ring[rxring_idx].buffer_desc) * + rtlpci->rxringcount, + rtlpci->rx_ring[rxring_idx].buffer_desc, + rtlpci->rx_ring[rxring_idx].dma); + rtlpci->rx_ring[rxring_idx].buffer_desc = NULL; + } else { + pci_free_consistent(rtlpci->pdev, + sizeof(*rtlpci->rx_ring[rxring_idx].desc) * + rtlpci->rxringcount, + rtlpci->rx_ring[rxring_idx].desc, + rtlpci->rx_ring[rxring_idx].dma); + rtlpci->rx_ring[rxring_idx].desc = NULL; + } +} + +static int _rtl_pci_init_trx_ring(struct ieee80211_hw *hw) +{ + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + int ret; + int i, rxring_idx; + + /* rxring_idx 0:RX_MPDU_QUEUE + * rxring_idx 1:RX_CMD_QUEUE + */ + for (rxring_idx = 0; rxring_idx < RTL_PCI_MAX_RX_QUEUE; rxring_idx++) { + ret = _rtl_pci_init_rx_ring(hw, rxring_idx); + if (ret) + return ret; + } + + for (i = 0; i < RTL_PCI_MAX_TX_QUEUE_COUNT; i++) { + ret = _rtl_pci_init_tx_ring(hw, i, rtlpci->txringcount[i]); + if (ret) + goto err_free_rings; + } + + return 0; + +err_free_rings: + for (rxring_idx = 0; rxring_idx < RTL_PCI_MAX_RX_QUEUE; rxring_idx++) + _rtl_pci_free_rx_ring(hw, rxring_idx); + + for (i = 0; i < RTL_PCI_MAX_TX_QUEUE_COUNT; i++) + if (rtlpci->tx_ring[i].desc || + rtlpci->tx_ring[i].buffer_desc) + _rtl_pci_free_tx_ring(hw, i); + + return 1; +} + +static int _rtl_pci_deinit_trx_ring(struct ieee80211_hw *hw) +{ + u32 i, rxring_idx; + + /*free rx rings */ + for (rxring_idx = 0; rxring_idx < RTL_PCI_MAX_RX_QUEUE; rxring_idx++) + _rtl_pci_free_rx_ring(hw, rxring_idx); + + /*free tx rings */ + for (i = 0; i < RTL_PCI_MAX_TX_QUEUE_COUNT; i++) + _rtl_pci_free_tx_ring(hw, i); + + return 0; +} + +int rtl_pci_reset_trx_ring(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + int i, rxring_idx; + unsigned long flags; + u8 tmp_one = 1; + u32 bufferaddress; + /* rxring_idx 0:RX_MPDU_QUEUE */ + /* rxring_idx 1:RX_CMD_QUEUE */ + for (rxring_idx = 0; rxring_idx < RTL_PCI_MAX_RX_QUEUE; rxring_idx++) { + /* force the rx_ring[RX_MPDU_QUEUE/ + * RX_CMD_QUEUE].idx to the first one + * new trx flow, do nothing + */ + if (!rtlpriv->use_new_trx_flow && + rtlpci->rx_ring[rxring_idx].desc) { + struct rtl_rx_desc *entry = NULL; + + rtlpci->rx_ring[rxring_idx].idx = 0; + for (i = 0; i < rtlpci->rxringcount; i++) { + entry = &rtlpci->rx_ring[rxring_idx].desc[i]; + bufferaddress = + rtlpriv->cfg->ops->get_desc(hw, (u8 *)entry, + false, HW_DESC_RXBUFF_ADDR); + memset((u8 *)entry, 0, + sizeof(*rtlpci->rx_ring + [rxring_idx].desc));/*clear one entry*/ + if (rtlpriv->use_new_trx_flow) { + /* This is deadcode */ + rtlpriv->cfg->ops->set_desc(hw, + (u8 *)entry, false, + HW_DESC_RX_PREPARE, + (u8 *)&bufferaddress); + } else { + rtlpriv->cfg->ops->set_desc(hw, + (u8 *)entry, false, + HW_DESC_RXBUFF_ADDR, + (u8 *)&bufferaddress); + rtlpriv->cfg->ops->set_desc(hw, + (u8 *)entry, false, + HW_DESC_RXPKT_LEN, + (u8 *)&rtlpci->rxbuffersize); + rtlpriv->cfg->ops->set_desc(hw, + (u8 *)entry, false, + HW_DESC_RXOWN, + (u8 *)&tmp_one); + } + } + rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry, false, + HW_DESC_RXERO, (u8 *)&tmp_one); + } + rtlpci->rx_ring[rxring_idx].idx = 0; + } + + /* + *after reset, release previous pending packet, + *and force the tx idx to the first one + */ + spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags); + for (i = 0; i < RTL_PCI_MAX_TX_QUEUE_COUNT; i++) { + if (rtlpci->tx_ring[i].desc || + rtlpci->tx_ring[i].buffer_desc) { + struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[i]; + + while (skb_queue_len(&ring->queue)) { + u8 *entry; + struct sk_buff *skb = + __skb_dequeue(&ring->queue); + if (rtlpriv->use_new_trx_flow) + entry = (u8 *)(&ring->buffer_desc + [ring->idx]); + else + entry = (u8 *)(&ring->desc[ring->idx]); + + pci_unmap_single(rtlpci->pdev, + rtlpriv->cfg->ops->get_desc(hw, (u8 *)entry, + true, HW_DESC_TXBUFF_ADDR), + skb->len, PCI_DMA_TODEVICE); + dev_kfree_skb_irq(skb); + ring->idx = (ring->idx + 1) % ring->entries; + } + + if (rtlpriv->use_new_trx_flow) { + rtlpci->tx_ring[i].cur_tx_rp = 0; + rtlpci->tx_ring[i].cur_tx_wp = 0; + } + + ring->idx = 0; + ring->entries = rtlpci->txringcount[i]; + } + } + spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); + + return 0; +} + +static bool rtl_pci_tx_chk_waitq_insert(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, + struct sk_buff *skb) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_sta_info *sta_entry = NULL; + u8 tid = rtl_get_tid(skb); + __le16 fc = rtl_get_fc(skb); + + if (!sta) + return false; + sta_entry = (struct rtl_sta_info *)sta->drv_priv; + + if (!rtlpriv->rtlhal.earlymode_enable) + return false; + if (ieee80211_is_nullfunc(fc)) + return false; + if (ieee80211_is_qos_nullfunc(fc)) + return false; + if (ieee80211_is_pspoll(fc)) + return false; + if (sta_entry->tids[tid].agg.agg_state != RTL_AGG_OPERATIONAL) + return false; + if (_rtl_mac_to_hwqueue(hw, skb) > VO_QUEUE) + return false; + if (tid > 7) + return false; + + /* maybe every tid should be checked */ + if (!rtlpriv->link_info.higher_busytxtraffic[tid]) + return false; + + spin_lock_bh(&rtlpriv->locks.waitq_lock); + skb_queue_tail(&rtlpriv->mac80211.skb_waitq[tid], skb); + spin_unlock_bh(&rtlpriv->locks.waitq_lock); + + return true; +} + +static int rtl_pci_tx(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, + struct sk_buff *skb, + struct rtl_tcb_desc *ptcb_desc) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_sta_info *sta_entry = NULL; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct rtl8192_tx_ring *ring; + struct rtl_tx_desc *pdesc; + struct rtl_tx_buffer_desc *ptx_bd_desc = NULL; + u16 idx; + u8 hw_queue = _rtl_mac_to_hwqueue(hw, skb); + unsigned long flags; + struct ieee80211_hdr *hdr = rtl_get_hdr(skb); + __le16 fc = rtl_get_fc(skb); + u8 *pda_addr = hdr->addr1; + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + /*ssn */ + u8 tid = 0; + u16 seq_number = 0; + u8 own; + u8 temp_one = 1; + + if (ieee80211_is_mgmt(fc)) + rtl_tx_mgmt_proc(hw, skb); + + if (rtlpriv->psc.sw_ps_enabled) { + if (ieee80211_is_data(fc) && !ieee80211_is_nullfunc(fc) && + !ieee80211_has_pm(fc)) + hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); + } + + rtl_action_proc(hw, skb, true); + + if (is_multicast_ether_addr(pda_addr)) + rtlpriv->stats.txbytesmulticast += skb->len; + else if (is_broadcast_ether_addr(pda_addr)) + rtlpriv->stats.txbytesbroadcast += skb->len; + else + rtlpriv->stats.txbytesunicast += skb->len; + + spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags); + ring = &rtlpci->tx_ring[hw_queue]; + if (hw_queue != BEACON_QUEUE) { + if (rtlpriv->use_new_trx_flow) + idx = ring->cur_tx_wp; + else + idx = (ring->idx + skb_queue_len(&ring->queue)) % + ring->entries; + } else { + idx = 0; + } + + pdesc = &ring->desc[idx]; + if (rtlpriv->use_new_trx_flow) { + ptx_bd_desc = &ring->buffer_desc[idx]; + } else { + own = (u8)rtlpriv->cfg->ops->get_desc(hw, (u8 *)pdesc, + true, HW_DESC_OWN); + + if ((own == 1) && (hw_queue != BEACON_QUEUE)) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "No more TX desc@%d, ring->idx = %d, idx = %d, skb_queue_len = 0x%x\n", + hw_queue, ring->idx, idx, + skb_queue_len(&ring->queue)); + + spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, + flags); + return skb->len; + } + } + + if (rtlpriv->cfg->ops->get_available_desc && + rtlpriv->cfg->ops->get_available_desc(hw, hw_queue) == 0) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "get_available_desc fail\n"); + spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); + return skb->len; + } + + if (ieee80211_is_data_qos(fc)) { + tid = rtl_get_tid(skb); + if (sta) { + sta_entry = (struct rtl_sta_info *)sta->drv_priv; + seq_number = (le16_to_cpu(hdr->seq_ctrl) & + IEEE80211_SCTL_SEQ) >> 4; + seq_number += 1; + + if (!ieee80211_has_morefrags(hdr->frame_control)) + sta_entry->tids[tid].seq_number = seq_number; + } + } + + if (ieee80211_is_data(fc)) + rtlpriv->cfg->ops->led_control(hw, LED_CTL_TX); + + rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *)pdesc, + (u8 *)ptx_bd_desc, info, sta, skb, hw_queue, ptcb_desc); + + __skb_queue_tail(&ring->queue, skb); + + if (rtlpriv->use_new_trx_flow) { + rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, true, + HW_DESC_OWN, &hw_queue); + } else { + rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, true, + HW_DESC_OWN, &temp_one); + } + + if ((ring->entries - skb_queue_len(&ring->queue)) < 2 && + hw_queue != BEACON_QUEUE) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD, + "less desc left, stop skb_queue@%d, ring->idx = %d, idx = %d, skb_queue_len = 0x%x\n", + hw_queue, ring->idx, idx, + skb_queue_len(&ring->queue)); + + ieee80211_stop_queue(hw, skb_get_queue_mapping(skb)); + } + + spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); + + rtlpriv->cfg->ops->tx_polling(hw, hw_queue); + + return 0; +} + +static void rtl_pci_flush(struct ieee80211_hw *hw, u32 queues, bool drop) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + u16 i = 0; + int queue_id; + struct rtl8192_tx_ring *ring; + + if (mac->skip_scan) + return; + + for (queue_id = RTL_PCI_MAX_TX_QUEUE_COUNT - 1; queue_id >= 0;) { + u32 queue_len; + + if (((queues >> queue_id) & 0x1) == 0) { + queue_id--; + continue; + } + ring = &pcipriv->dev.tx_ring[queue_id]; + queue_len = skb_queue_len(&ring->queue); + if (queue_len == 0 || queue_id == BEACON_QUEUE || + queue_id == TXCMD_QUEUE) { + queue_id--; + continue; + } else { + msleep(20); + i++; + } + + /* we just wait 1s for all queues */ + if (rtlpriv->psc.rfpwr_state == ERFOFF || + is_hal_stop(rtlhal) || i >= 200) + return; + } +} + +static void rtl_pci_deinit(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + + _rtl_pci_deinit_trx_ring(hw); + + synchronize_irq(rtlpci->pdev->irq); + tasklet_kill(&rtlpriv->works.irq_tasklet); + cancel_work_sync(&rtlpriv->works.lps_change_work); + + flush_workqueue(rtlpriv->works.rtl_wq); + destroy_workqueue(rtlpriv->works.rtl_wq); +} + +static int rtl_pci_init(struct ieee80211_hw *hw, struct pci_dev *pdev) +{ + int err; + + _rtl_pci_init_struct(hw, pdev); + + err = _rtl_pci_init_trx_ring(hw); + if (err) { + pr_err("tx ring initialization failed\n"); + return err; + } + + return 0; +} + +static int rtl_pci_start(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_mac *rtlmac = rtl_mac(rtl_priv(hw)); + + int err; + + rtl_pci_reset_trx_ring(hw); + + rtlpci->driver_is_goingto_unload = false; + if (rtlpriv->cfg->ops->get_btc_status && + rtlpriv->cfg->ops->get_btc_status()) { + rtlpriv->btcoexist.btc_info.ap_num = 36; + rtlpriv->btcoexist.btc_ops->btc_init_variables(rtlpriv); + rtlpriv->btcoexist.btc_ops->btc_init_hal_vars(rtlpriv); + } else if (rtlpriv->btcoexist.btc_ops) { + rtlpriv->btcoexist.btc_ops->btc_init_variables_wifi_only( + rtlpriv); + } + + err = rtlpriv->cfg->ops->hw_init(hw); + if (err) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "Failed to config hardware!\n"); + return err; + } + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RETRY_LIMIT, + &rtlmac->retry_long); + + rtlpriv->cfg->ops->enable_interrupt(hw); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "enable_interrupt OK\n"); + + rtl_init_rx_config(hw); + + /*should be after adapter start and interrupt enable. */ + set_hal_start(rtlhal); + + RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); + + rtlpci->up_first_time = false; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "%s OK\n", __func__); + return 0; +} + +static void rtl_pci_stop(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + unsigned long flags; + u8 rf_timeout = 0; + + if (rtlpriv->cfg->ops->get_btc_status()) + rtlpriv->btcoexist.btc_ops->btc_halt_notify(rtlpriv); + + if (rtlpriv->btcoexist.btc_ops) + rtlpriv->btcoexist.btc_ops->btc_deinit_variables(rtlpriv); + + /* + *should be before disable interrupt&adapter + *and will do it immediately. + */ + set_hal_stop(rtlhal); + + rtlpci->driver_is_goingto_unload = true; + rtlpriv->cfg->ops->disable_interrupt(hw); + cancel_work_sync(&rtlpriv->works.lps_change_work); + + spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flags); + while (ppsc->rfchange_inprogress) { + spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flags); + if (rf_timeout > 100) { + spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flags); + break; + } + mdelay(1); + rf_timeout++; + spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flags); + } + ppsc->rfchange_inprogress = true; + spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flags); + + rtlpriv->cfg->ops->hw_disable(hw); + /* some things are not needed if firmware not available */ + if (!rtlpriv->max_fw_size) + return; + rtlpriv->cfg->ops->led_control(hw, LED_CTL_POWER_OFF); + + spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flags); + ppsc->rfchange_inprogress = false; + spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flags); + + rtl_pci_enable_aspm(hw); +} + +static bool _rtl_pci_find_adapter(struct pci_dev *pdev, + struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct pci_dev *bridge_pdev = pdev->bus->self; + u16 venderid; + u16 deviceid; + u8 revisionid; + u16 irqline; + u8 tmp; + + pcipriv->ndis_adapter.pcibridge_vendor = PCI_BRIDGE_VENDOR_UNKNOWN; + venderid = pdev->vendor; + deviceid = pdev->device; + pci_read_config_byte(pdev, 0x8, &revisionid); + pci_read_config_word(pdev, 0x3C, &irqline); + + /* PCI ID 0x10ec:0x8192 occurs for both RTL8192E, which uses + * r8192e_pci, and RTL8192SE, which uses this driver. If the + * revision ID is RTL_PCI_REVISION_ID_8192PCIE (0x01), then + * the correct driver is r8192e_pci, thus this routine should + * return false. + */ + if (deviceid == RTL_PCI_8192SE_DID && + revisionid == RTL_PCI_REVISION_ID_8192PCIE) + return false; + + if (deviceid == RTL_PCI_8192_DID || + deviceid == RTL_PCI_0044_DID || + deviceid == RTL_PCI_0047_DID || + deviceid == RTL_PCI_8192SE_DID || + deviceid == RTL_PCI_8174_DID || + deviceid == RTL_PCI_8173_DID || + deviceid == RTL_PCI_8172_DID || + deviceid == RTL_PCI_8171_DID) { + switch (revisionid) { + case RTL_PCI_REVISION_ID_8192PCIE: + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "8192 PCI-E is found - vid/did=%x/%x\n", + venderid, deviceid); + rtlhal->hw_type = HARDWARE_TYPE_RTL8192E; + return false; + case RTL_PCI_REVISION_ID_8192SE: + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "8192SE is found - vid/did=%x/%x\n", + venderid, deviceid); + rtlhal->hw_type = HARDWARE_TYPE_RTL8192SE; + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "Err: Unknown device - vid/did=%x/%x\n", + venderid, deviceid); + rtlhal->hw_type = HARDWARE_TYPE_RTL8192SE; + break; + } + } else if (deviceid == RTL_PCI_8723AE_DID) { + rtlhal->hw_type = HARDWARE_TYPE_RTL8723AE; + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "8723AE PCI-E is found - vid/did=%x/%x\n", + venderid, deviceid); + } else if (deviceid == RTL_PCI_8192CET_DID || + deviceid == RTL_PCI_8192CE_DID || + deviceid == RTL_PCI_8191CE_DID || + deviceid == RTL_PCI_8188CE_DID) { + rtlhal->hw_type = HARDWARE_TYPE_RTL8192CE; + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "8192C PCI-E is found - vid/did=%x/%x\n", + venderid, deviceid); + } else if (deviceid == RTL_PCI_8192DE_DID || + deviceid == RTL_PCI_8192DE_DID2) { + rtlhal->hw_type = HARDWARE_TYPE_RTL8192DE; + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "8192D PCI-E is found - vid/did=%x/%x\n", + venderid, deviceid); + } else if (deviceid == RTL_PCI_8188EE_DID) { + rtlhal->hw_type = HARDWARE_TYPE_RTL8188EE; + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "Find adapter, Hardware type is 8188EE\n"); + } else if (deviceid == RTL_PCI_8723BE_DID) { + rtlhal->hw_type = HARDWARE_TYPE_RTL8723BE; + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "Find adapter, Hardware type is 8723BE\n"); + } else if (deviceid == RTL_PCI_8192EE_DID) { + rtlhal->hw_type = HARDWARE_TYPE_RTL8192EE; + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "Find adapter, Hardware type is 8192EE\n"); + } else if (deviceid == RTL_PCI_8821AE_DID) { + rtlhal->hw_type = HARDWARE_TYPE_RTL8821AE; + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "Find adapter, Hardware type is 8821AE\n"); + } else if (deviceid == RTL_PCI_8812AE_DID) { + rtlhal->hw_type = HARDWARE_TYPE_RTL8812AE; + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "Find adapter, Hardware type is 8812AE\n"); + } else if (deviceid == RTL_PCI_8822BE_DID) { + rtlhal->hw_type = HARDWARE_TYPE_RTL8822BE; + rtlhal->bandset = BAND_ON_BOTH; + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "Find adapter, Hardware type is 8822BE\n"); + } else { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "Err: Unknown device - vid/did=%x/%x\n", + venderid, deviceid); + + rtlhal->hw_type = RTL_DEFAULT_HARDWARE_TYPE; + } + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192DE) { + if (revisionid == 0 || revisionid == 1) { + if (revisionid == 0) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "Find 92DE MAC0\n"); + rtlhal->interfaceindex = 0; + } else if (revisionid == 1) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "Find 92DE MAC1\n"); + rtlhal->interfaceindex = 1; + } + } else { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "Unknown device - VendorID/DeviceID=%x/%x, Revision=%x\n", + venderid, deviceid, revisionid); + rtlhal->interfaceindex = 0; + } + } + + switch (rtlhal->hw_type) { + case HARDWARE_TYPE_RTL8192EE: + case HARDWARE_TYPE_RTL8822BE: + /* use new trx flow */ + rtlpriv->use_new_trx_flow = true; + break; + + default: + rtlpriv->use_new_trx_flow = false; + break; + } + + /*find bus info */ + pcipriv->ndis_adapter.busnumber = pdev->bus->number; + pcipriv->ndis_adapter.devnumber = PCI_SLOT(pdev->devfn); + pcipriv->ndis_adapter.funcnumber = PCI_FUNC(pdev->devfn); + + /*find bridge info */ + pcipriv->ndis_adapter.pcibridge_vendor = PCI_BRIDGE_VENDOR_UNKNOWN; + /* some ARM have no bridge_pdev and will crash here + * so we should check if bridge_pdev is NULL + */ + if (bridge_pdev) { + /*find bridge info if available */ + pcipriv->ndis_adapter.pcibridge_vendorid = bridge_pdev->vendor; + for (tmp = 0; tmp < PCI_BRIDGE_VENDOR_MAX; tmp++) { + if (bridge_pdev->vendor == pcibridge_vendors[tmp]) { + pcipriv->ndis_adapter.pcibridge_vendor = tmp; + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "Pci Bridge Vendor is found index: %d\n", + tmp); + break; + } + } + } + + if (pcipriv->ndis_adapter.pcibridge_vendor != + PCI_BRIDGE_VENDOR_UNKNOWN) { + pcipriv->ndis_adapter.pcibridge_busnum = + bridge_pdev->bus->number; + pcipriv->ndis_adapter.pcibridge_devnum = + PCI_SLOT(bridge_pdev->devfn); + pcipriv->ndis_adapter.pcibridge_funcnum = + PCI_FUNC(bridge_pdev->devfn); + pcipriv->ndis_adapter.pcibridge_pciehdr_offset = + pci_pcie_cap(bridge_pdev); + pcipriv->ndis_adapter.num4bytes = + (pcipriv->ndis_adapter.pcibridge_pciehdr_offset + 0x10) / 4; + + rtl_pci_get_linkcontrol_field(hw); + + if (pcipriv->ndis_adapter.pcibridge_vendor == + PCI_BRIDGE_VENDOR_AMD) { + pcipriv->ndis_adapter.amd_l1_patch = + rtl_pci_get_amd_l1_patch(hw); + } + } + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "pcidev busnumber:devnumber:funcnumber:vendor:link_ctl %d:%d:%d:%x:%x\n", + pcipriv->ndis_adapter.busnumber, + pcipriv->ndis_adapter.devnumber, + pcipriv->ndis_adapter.funcnumber, + pdev->vendor, pcipriv->ndis_adapter.linkctrl_reg); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "pci_bridge busnumber:devnumber:funcnumber:vendor:pcie_cap:link_ctl_reg:amd %d:%d:%d:%x:%x:%x:%x\n", + pcipriv->ndis_adapter.pcibridge_busnum, + pcipriv->ndis_adapter.pcibridge_devnum, + pcipriv->ndis_adapter.pcibridge_funcnum, + pcibridge_vendors[pcipriv->ndis_adapter.pcibridge_vendor], + pcipriv->ndis_adapter.pcibridge_pciehdr_offset, + pcipriv->ndis_adapter.pcibridge_linkctrlreg, + pcipriv->ndis_adapter.amd_l1_patch); + + rtl_pci_parse_configuration(pdev, hw); + list_add_tail(&rtlpriv->list, &rtlpriv->glb_var->glb_priv_list); + + return true; +} + +static int rtl_pci_intr_mode_msi(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(pcipriv); + int ret; + + ret = pci_enable_msi(rtlpci->pdev); + if (ret < 0) + return ret; + + ret = request_irq(rtlpci->pdev->irq, &_rtl_pci_interrupt, + IRQF_SHARED, KBUILD_MODNAME, hw); + if (ret < 0) { + pci_disable_msi(rtlpci->pdev); + return ret; + } + + rtlpci->using_msi = true; + + RT_TRACE(rtlpriv, COMP_INIT | COMP_INTR, DBG_DMESG, + "MSI Interrupt Mode!\n"); + return 0; +} + +static int rtl_pci_intr_mode_legacy(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(pcipriv); + int ret; + + ret = request_irq(rtlpci->pdev->irq, &_rtl_pci_interrupt, + IRQF_SHARED, KBUILD_MODNAME, hw); + if (ret < 0) + return ret; + + rtlpci->using_msi = false; + RT_TRACE(rtlpriv, COMP_INIT | COMP_INTR, DBG_DMESG, + "Pin-based Interrupt Mode!\n"); + return 0; +} + +static int rtl_pci_intr_mode_decide(struct ieee80211_hw *hw) +{ + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(pcipriv); + int ret; + + if (rtlpci->msi_support) { + ret = rtl_pci_intr_mode_msi(hw); + if (ret < 0) + ret = rtl_pci_intr_mode_legacy(hw); + } else { + ret = rtl_pci_intr_mode_legacy(hw); + } + return ret; +} + +static void platform_enable_dma64(struct pci_dev *pdev, bool dma64) +{ + u8 value; + + pci_read_config_byte(pdev, 0x719, &value); + + /* 0x719 Bit5 is DMA64 bit fetch. */ + if (dma64) + value |= BIT(5); + else + value &= ~BIT(5); + + pci_write_config_byte(pdev, 0x719, value); +} + +int rtl_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct ieee80211_hw *hw = NULL; + + struct rtl_priv *rtlpriv = NULL; + struct rtl_pci_priv *pcipriv = NULL; + struct rtl_pci *rtlpci; + unsigned long pmem_start, pmem_len, pmem_flags; + int err; + + err = rtl_core_module_init(); + if (err) + return err; + err = pci_enable_device(pdev); + if (err) { + WARN_ONCE(true, "%s : Cannot enable new PCI device\n", + pci_name(pdev)); + return err; + } + + if (((struct rtl_hal_cfg *)(id->driver_data))->mod_params->dma64 && + !pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) { + if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) { + WARN_ONCE(true, + "Unable to obtain 64bit DMA for consistent allocations\n"); + err = -ENOMEM; + goto fail1; + } + + platform_enable_dma64(pdev, true); + } else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) { + if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) { + WARN_ONCE(true, + "rtlwifi: Unable to obtain 32bit DMA for consistent allocations\n"); + err = -ENOMEM; + goto fail1; + } + + platform_enable_dma64(pdev, false); + } + + pci_set_master(pdev); + + hw = ieee80211_alloc_hw(sizeof(struct rtl_pci_priv) + + sizeof(struct rtl_priv), &rtl_ops); + if (!hw) { + WARN_ONCE(true, + "%s : ieee80211 alloc failed\n", pci_name(pdev)); + err = -ENOMEM; + goto fail1; + } + + SET_IEEE80211_DEV(hw, &pdev->dev); + pci_set_drvdata(pdev, hw); + + rtlpriv = hw->priv; + rtlpriv->hw = hw; + pcipriv = (void *)rtlpriv->priv; + pcipriv->dev.pdev = pdev; + init_completion(&rtlpriv->firmware_loading_complete); + /*proximity init here*/ + rtlpriv->proximity.proxim_on = false; + + pcipriv = (void *)rtlpriv->priv; + pcipriv->dev.pdev = pdev; + + /* init cfg & intf_ops */ + rtlpriv->rtlhal.interface = INTF_PCI; + rtlpriv->cfg = (struct rtl_hal_cfg *)(id->driver_data); + rtlpriv->intf_ops = &rtl_pci_ops; + rtlpriv->glb_var = &rtl_global_var; + + /* MEM map */ + err = pci_request_regions(pdev, KBUILD_MODNAME); + if (err) { + WARN_ONCE(true, "rtlwifi: Can't obtain PCI resources\n"); + goto fail1; + } + + pmem_start = pci_resource_start(pdev, rtlpriv->cfg->bar_id); + pmem_len = pci_resource_len(pdev, rtlpriv->cfg->bar_id); + pmem_flags = pci_resource_flags(pdev, rtlpriv->cfg->bar_id); + + /*shared mem start */ + rtlpriv->io.pci_mem_start = + (unsigned long)pci_iomap(pdev, + rtlpriv->cfg->bar_id, pmem_len); + if (rtlpriv->io.pci_mem_start == 0) { + WARN_ONCE(true, "rtlwifi: Can't map PCI mem\n"); + err = -ENOMEM; + goto fail2; + } + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "mem mapped space: start: 0x%08lx len:%08lx flags:%08lx, after map:0x%08lx\n", + pmem_start, pmem_len, pmem_flags, + rtlpriv->io.pci_mem_start); + + /* Disable Clk Request */ + pci_write_config_byte(pdev, 0x81, 0); + /* leave D3 mode */ + pci_write_config_byte(pdev, 0x44, 0); + pci_write_config_byte(pdev, 0x04, 0x06); + pci_write_config_byte(pdev, 0x04, 0x07); + + /* find adapter */ + if (!_rtl_pci_find_adapter(pdev, hw)) { + err = -ENODEV; + goto fail2; + } + + /* Init IO handler */ + _rtl_pci_io_handler_init(&pdev->dev, hw); + + /*like read eeprom and so on */ + rtlpriv->cfg->ops->read_eeprom_info(hw); + + if (rtlpriv->cfg->ops->init_sw_vars(hw)) { + pr_err("Can't init_sw_vars\n"); + err = -ENODEV; + goto fail3; + } + rtlpriv->cfg->ops->init_sw_leds(hw); + + /*aspm */ + rtl_pci_init_aspm(hw); + + /* Init mac80211 sw */ + err = rtl_init_core(hw); + if (err) { + pr_err("Can't allocate sw for mac80211\n"); + goto fail3; + } + + /* Init PCI sw */ + err = rtl_pci_init(hw, pdev); + if (err) { + pr_err("Failed to init PCI\n"); + goto fail3; + } + + err = ieee80211_register_hw(hw); + if (err) { + pr_err("Can't register mac80211 hw.\n"); + err = -ENODEV; + goto fail3; + } + rtlpriv->mac80211.mac80211_registered = 1; + + /* add for debug */ + rtl_debug_add_one(hw); + + /*init rfkill */ + rtl_init_rfkill(hw); /* Init PCI sw */ + + rtlpci = rtl_pcidev(pcipriv); + err = rtl_pci_intr_mode_decide(hw); + if (err) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "%s: failed to register IRQ handler\n", + wiphy_name(hw->wiphy)); + goto fail3; + } + rtlpci->irq_alloc = 1; + + set_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status); + return 0; + +fail3: + pci_set_drvdata(pdev, NULL); + rtl_deinit_core(hw); + +fail2: + if (rtlpriv->io.pci_mem_start != 0) + pci_iounmap(pdev, (void __iomem *)rtlpriv->io.pci_mem_start); + + pci_release_regions(pdev); + complete(&rtlpriv->firmware_loading_complete); + +fail1: + if (hw) + ieee80211_free_hw(hw); + pci_disable_device(pdev); + + return err; +} + +void rtl_pci_disconnect(struct pci_dev *pdev) +{ + struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(pcipriv); + struct rtl_mac *rtlmac = rtl_mac(rtlpriv); + + /* just in case driver is removed before firmware callback */ + wait_for_completion(&rtlpriv->firmware_loading_complete); + clear_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status); + + /* remove form debug */ + rtl_debug_remove_one(hw); + + /*ieee80211_unregister_hw will call ops_stop */ + if (rtlmac->mac80211_registered == 1) { + ieee80211_unregister_hw(hw); + rtlmac->mac80211_registered = 0; + } else { + rtl_deinit_deferred_work(hw); + rtlpriv->intf_ops->adapter_stop(hw); + } + rtlpriv->cfg->ops->disable_interrupt(hw); + + /*deinit rfkill */ + rtl_deinit_rfkill(hw); + + rtl_pci_deinit(hw); + rtl_deinit_core(hw); + rtlpriv->cfg->ops->deinit_sw_vars(hw); + + if (rtlpci->irq_alloc) { + free_irq(rtlpci->pdev->irq, hw); + rtlpci->irq_alloc = 0; + } + + if (rtlpci->using_msi) + pci_disable_msi(rtlpci->pdev); + + list_del(&rtlpriv->list); + if (rtlpriv->io.pci_mem_start != 0) { + pci_iounmap(pdev, (void __iomem *)rtlpriv->io.pci_mem_start); + pci_release_regions(pdev); + } + + pci_disable_device(pdev); + + rtl_pci_disable_aspm(hw); + + pci_set_drvdata(pdev, NULL); + + ieee80211_free_hw(hw); + rtl_core_module_exit(); +} + +#ifdef CONFIG_PM_SLEEP +/*************************************** + * kernel pci power state define: + * PCI_D0 ((pci_power_t __force) 0) + * PCI_D1 ((pci_power_t __force) 1) + * PCI_D2 ((pci_power_t __force) 2) + * PCI_D3hot ((pci_power_t __force) 3) + * PCI_D3cold ((pci_power_t __force) 4) + * PCI_UNKNOWN ((pci_power_t __force) 5) + + * This function is called when system + * goes into suspend state mac80211 will + * call rtl_mac_stop() from the mac80211 + * suspend function first, So there is + * no need to call hw_disable here. + ****************************************/ +int rtl_pci_suspend(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtlpriv->cfg->ops->hw_suspend(hw); + rtl_deinit_rfkill(hw); + + return 0; +} + +int rtl_pci_resume(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtlpriv->cfg->ops->hw_resume(hw); + rtl_init_rfkill(hw); + return 0; +} +#endif /* CONFIG_PM_SLEEP */ + +const struct rtl_intf_ops rtl_pci_ops = { + .read_efuse_byte = read_efuse_byte, + .adapter_start = rtl_pci_start, + .adapter_stop = rtl_pci_stop, + .check_buddy_priv = rtl_pci_check_buddy_priv, + .adapter_tx = rtl_pci_tx, + .flush = rtl_pci_flush, + .reset_trx_ring = rtl_pci_reset_trx_ring, + .waitq_insert = rtl_pci_tx_chk_waitq_insert, + + .disable_aspm = rtl_pci_disable_aspm, + .enable_aspm = rtl_pci_enable_aspm, +}; diff --git a/drivers/staging/rtlwifi/pci.h b/drivers/staging/rtlwifi/pci.h new file mode 100644 index 000000000000..3fb56c845a61 --- /dev/null +++ b/drivers/staging/rtlwifi/pci.h @@ -0,0 +1,329 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL_PCI_H__ +#define __RTL_PCI_H__ + +#include <linux/pci.h> +/* 1: MSDU packet queue, + * 2: Rx Command Queue + */ +#define RTL_PCI_RX_MPDU_QUEUE 0 +#define RTL_PCI_RX_CMD_QUEUE 1 +#define RTL_PCI_MAX_RX_QUEUE 2 + +#define RTL_PCI_MAX_RX_COUNT 512/*64*/ +#define RTL_PCI_MAX_TX_QUEUE_COUNT 9 + +#define RT_TXDESC_NUM 128 +#define TX_DESC_NUM_92E 512 +#define TX_DESC_NUM_8822B 512 +#define RT_TXDESC_NUM_BE_QUEUE 256 + +#define BK_QUEUE 0 +#define BE_QUEUE 1 +#define VI_QUEUE 2 +#define VO_QUEUE 3 +#define BEACON_QUEUE 4 +#define TXCMD_QUEUE 5 +#define MGNT_QUEUE 6 +#define HIGH_QUEUE 7 +#define HCCA_QUEUE 8 +#define H2C_QUEUE TXCMD_QUEUE /* In 8822B */ + +#define RTL_PCI_DEVICE(vend, dev, cfg) \ + .vendor = (vend), \ + .device = (dev), \ + .subvendor = PCI_ANY_ID, \ + .subdevice = PCI_ANY_ID,\ + .driver_data = (kernel_ulong_t)&(cfg) + +#define INTEL_VENDOR_ID 0x8086 +#define SIS_VENDOR_ID 0x1039 +#define ATI_VENDOR_ID 0x1002 +#define ATI_DEVICE_ID 0x7914 +#define AMD_VENDOR_ID 0x1022 + +#define PCI_MAX_BRIDGE_NUMBER 255 +#define PCI_MAX_DEVICES 32 +#define PCI_MAX_FUNCTION 8 + +#define PCI_CONF_ADDRESS 0x0CF8 /*PCI Configuration Space Address */ +#define PCI_CONF_DATA 0x0CFC /*PCI Configuration Space Data */ + +#define PCI_CLASS_BRIDGE_DEV 0x06 +#define PCI_SUBCLASS_BR_PCI_TO_PCI 0x04 +#define PCI_CAPABILITY_ID_PCI_EXPRESS 0x10 +#define PCI_CAP_ID_EXP 0x10 + +#define U1DONTCARE 0xFF +#define U2DONTCARE 0xFFFF +#define U4DONTCARE 0xFFFFFFFF + +#define RTL_PCI_8192_DID 0x8192 /*8192 PCI-E */ +#define RTL_PCI_8192SE_DID 0x8192 /*8192 SE */ +#define RTL_PCI_8174_DID 0x8174 /*8192 SE */ +#define RTL_PCI_8173_DID 0x8173 /*8191 SE Crab */ +#define RTL_PCI_8172_DID 0x8172 /*8191 SE RE */ +#define RTL_PCI_8171_DID 0x8171 /*8191 SE Unicron */ +#define RTL_PCI_8723AE_DID 0x8723 /*8723AE */ +#define RTL_PCI_0045_DID 0x0045 /*8190 PCI for Ceraga */ +#define RTL_PCI_0046_DID 0x0046 /*8190 Cardbus for Ceraga */ +#define RTL_PCI_0044_DID 0x0044 /*8192e PCIE for Ceraga */ +#define RTL_PCI_0047_DID 0x0047 /*8192e Express Card for Ceraga */ +#define RTL_PCI_700F_DID 0x700F +#define RTL_PCI_701F_DID 0x701F +#define RTL_PCI_DLINK_DID 0x3304 +#define RTL_PCI_8723AE_DID 0x8723 /*8723e */ +#define RTL_PCI_8192CET_DID 0x8191 /*8192ce */ +#define RTL_PCI_8192CE_DID 0x8178 /*8192ce */ +#define RTL_PCI_8191CE_DID 0x8177 /*8192ce */ +#define RTL_PCI_8188CE_DID 0x8176 /*8192ce */ +#define RTL_PCI_8192CU_DID 0x8191 /*8192ce */ +#define RTL_PCI_8192DE_DID 0x8193 /*8192de */ +#define RTL_PCI_8192DE_DID2 0x002B /*92DE*/ +#define RTL_PCI_8188EE_DID 0x8179 /*8188ee*/ +#define RTL_PCI_8723BE_DID 0xB723 /*8723be*/ +#define RTL_PCI_8192EE_DID 0x818B /*8192ee*/ +#define RTL_PCI_8821AE_DID 0x8821 /*8821ae*/ +#define RTL_PCI_8812AE_DID 0x8812 /*8812ae*/ +#define RTL_PCI_8822BE_DID 0xB822 /*8822be*/ + +/*8192 support 16 pages of IO registers*/ +#define RTL_MEM_MAPPED_IO_RANGE_8190PCI 0x1000 +#define RTL_MEM_MAPPED_IO_RANGE_8192PCIE 0x4000 +#define RTL_MEM_MAPPED_IO_RANGE_8192SE 0x4000 +#define RTL_MEM_MAPPED_IO_RANGE_8192CE 0x4000 +#define RTL_MEM_MAPPED_IO_RANGE_8192DE 0x4000 + +#define RTL_PCI_REVISION_ID_8190PCI 0x00 +#define RTL_PCI_REVISION_ID_8192PCIE 0x01 +#define RTL_PCI_REVISION_ID_8192SE 0x10 +#define RTL_PCI_REVISION_ID_8192CE 0x1 +#define RTL_PCI_REVISION_ID_8192DE 0x0 + +#define RTL_DEFAULT_HARDWARE_TYPE HARDWARE_TYPE_RTL8192CE + +enum pci_bridge_vendor { + PCI_BRIDGE_VENDOR_INTEL = 0x0, /*0b'0000,0001 */ + PCI_BRIDGE_VENDOR_ATI, /*0b'0000,0010*/ + PCI_BRIDGE_VENDOR_AMD, /*0b'0000,0100*/ + PCI_BRIDGE_VENDOR_SIS, /*0b'0000,1000*/ + PCI_BRIDGE_VENDOR_UNKNOWN, /*0b'0100,0000*/ + PCI_BRIDGE_VENDOR_MAX, +}; + +struct rtl_pci_capabilities_header { + u8 capability_id; + u8 next; +}; + +/* In new TRX flow, Buffer_desc is new concept + * But TX wifi info == TX descriptor in old flow + * RX wifi info == RX descriptor in old flow + */ +struct rtl_tx_buffer_desc { + u32 dword[4 * (1 << (BUFDESC_SEG_NUM + 1))]; +} __packed; + +struct rtl_tx_desc { + u32 dword[16]; +} __packed; + +struct rtl_rx_buffer_desc { /*rx buffer desc*/ + u32 dword[4]; +} __packed; + +struct rtl_rx_desc { /*old: rx desc new: rx wifi info*/ + u32 dword[8]; +} __packed; + +struct rtl_tx_cmd_desc { + u32 dword[16]; +} __packed; + +struct rtl8192_tx_ring { + struct rtl_tx_desc *desc; + dma_addr_t dma; + unsigned int idx; + unsigned int entries; + struct sk_buff_head queue; + /*add for new trx flow*/ + struct rtl_tx_buffer_desc *buffer_desc; /*tx buffer descriptor*/ + dma_addr_t buffer_desc_dma; /*tx bufferd desc dma memory*/ + u16 cur_tx_wp; /* current_tx_write_point */ + u16 cur_tx_rp; /* current_tx_read_point */ +}; + +struct rtl8192_rx_ring { + struct rtl_rx_desc *desc; + dma_addr_t dma; + unsigned int idx; + struct sk_buff *rx_buf[RTL_PCI_MAX_RX_COUNT]; + /*add for new trx flow*/ + struct rtl_rx_buffer_desc *buffer_desc; /*rx buffer descriptor*/ + u16 next_rx_rp; /* next_rx_read_point */ +}; + +struct rtl_pci { + struct pci_dev *pdev; + bool irq_enabled; + + bool driver_is_goingto_unload; + bool up_first_time; + bool first_init; + bool being_init_adapter; + bool init_ready; + + /*Tx */ + struct rtl8192_tx_ring tx_ring[RTL_PCI_MAX_TX_QUEUE_COUNT]; + int txringcount[RTL_PCI_MAX_TX_QUEUE_COUNT]; + u32 transmit_config; + + /*Rx */ + struct rtl8192_rx_ring rx_ring[RTL_PCI_MAX_RX_QUEUE]; + int rxringcount; + u16 rxbuffersize; + u32 receive_config; + + /*irq */ + u8 irq_alloc; + u32 irq_mask[4]; /* 0-1: normal, 2: unused, 3: h2c */ + u32 sys_irq_mask; + + /*Bcn control register setting */ + u32 reg_bcn_ctrl_val; + + /*ASPM*/ u8 const_pci_aspm; + u8 const_amdpci_aspm; + u8 const_hwsw_rfoff_d3; + u8 const_support_pciaspm; + /*pci-e bridge */ + u8 const_hostpci_aspm_setting; + /*pci-e device */ + u8 const_devicepci_aspm_setting; + /* If it supports ASPM, Offset[560h] = 0x40, + * otherwise Offset[560h] = 0x00. + */ + bool support_aspm; + bool support_backdoor; + + /*QOS & EDCA */ + enum acm_method acm_method; + + u16 shortretry_limit; + u16 longretry_limit; + + /* MSI support */ + bool msi_support; + bool using_msi; + /* interrupt clear before set */ + bool int_clear; +}; + +struct mp_adapter { + u8 linkctrl_reg; + + u8 busnumber; + u8 devnumber; + u8 funcnumber; + + u8 pcibridge_busnum; + u8 pcibridge_devnum; + u8 pcibridge_funcnum; + + u8 pcibridge_vendor; + u16 pcibridge_vendorid; + u16 pcibridge_deviceid; + + u8 num4bytes; + + u8 pcibridge_pciehdr_offset; + u8 pcibridge_linkctrlreg; + + bool amd_l1_patch; +}; + +struct rtl_pci_priv { + struct bt_coexist_info bt_coexist; + struct rtl_led_ctl ledctl; + struct rtl_pci dev; + struct mp_adapter ndis_adapter; +}; + +#define rtl_pcipriv(hw) (((struct rtl_pci_priv *)(rtl_priv(hw))->priv)) +#define rtl_pcidev(pcipriv) (&((pcipriv)->dev)) + +int rtl_pci_reset_trx_ring(struct ieee80211_hw *hw); + +extern const struct rtl_intf_ops rtl_pci_ops; + +int rtl_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id); +void rtl_pci_disconnect(struct pci_dev *pdev); +#ifdef CONFIG_PM_SLEEP +int rtl_pci_suspend(struct device *dev); +int rtl_pci_resume(struct device *dev); +#endif /* CONFIG_PM_SLEEP */ +static inline u8 pci_read8_sync(struct rtl_priv *rtlpriv, u32 addr) +{ + return readb((u8 __iomem *)rtlpriv->io.pci_mem_start + addr); +} + +static inline u16 pci_read16_sync(struct rtl_priv *rtlpriv, u32 addr) +{ + return readw((u8 __iomem *)rtlpriv->io.pci_mem_start + addr); +} + +static inline u32 pci_read32_sync(struct rtl_priv *rtlpriv, u32 addr) +{ + return readl((u8 __iomem *)rtlpriv->io.pci_mem_start + addr); +} + +static inline void pci_write8_async(struct rtl_priv *rtlpriv, u32 addr, u8 val) +{ + writeb(val, (u8 __iomem *)rtlpriv->io.pci_mem_start + addr); +} + +static inline void pci_write16_async(struct rtl_priv *rtlpriv, + u32 addr, u16 val) +{ + writew(val, (u8 __iomem *)rtlpriv->io.pci_mem_start + addr); +} + +static inline void pci_write32_async(struct rtl_priv *rtlpriv, + u32 addr, u32 val) +{ + writel(val, (u8 __iomem *)rtlpriv->io.pci_mem_start + addr); +} + +static inline u16 calc_fifo_space(u16 rp, u16 wp, u16 size) +{ + if (rp <= wp) + return size - 1 + rp - wp; + return rp - wp - 1; +} + +#endif diff --git a/drivers/staging/rtlwifi/phydm/halphyrf_ce.c b/drivers/staging/rtlwifi/phydm/halphyrf_ce.c new file mode 100644 index 000000000000..684e383201d6 --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/halphyrf_ce.c @@ -0,0 +1,965 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include "mp_precomp.h" +#include "phydm_precomp.h" + +#define CALCULATE_SWINGTALBE_OFFSET(_offset, _direction, _size, \ + _delta_thermal) \ + do { \ + for (_offset = 0; _offset < _size; _offset++) { \ + if (_delta_thermal < \ + thermal_threshold[_direction][_offset]) { \ + if (_offset != 0) \ + _offset--; \ + break; \ + } \ + } \ + if (_offset >= _size) \ + _offset = _size - 1; \ + } while (0) + +static inline void phydm_set_calibrate_info_up( + struct phy_dm_struct *dm, struct txpwrtrack_cfg *c, u8 delta, + struct dm_rf_calibration_struct *cali_info, + u8 *delta_swing_table_idx_tup_a, u8 *delta_swing_table_idx_tup_b, + u8 *delta_swing_table_idx_tup_c, u8 *delta_swing_table_idx_tup_d) +{ + u8 p = 0; + + for (p = ODM_RF_PATH_A; p < c->rf_path_count; p++) { + cali_info->delta_power_index_last[p] = + cali_info->delta_power_index + [p]; /*recording poer index offset*/ + switch (p) { + case ODM_RF_PATH_B: + ODM_RT_TRACE(dm, ODM_COMP_TX_PWR_TRACK, + "delta_swing_table_idx_tup_b[%d] = %d\n", + delta, delta_swing_table_idx_tup_b[delta]); + + cali_info->delta_power_index[p] = + delta_swing_table_idx_tup_b[delta]; + /*Record delta swing for mix mode pwr tracking*/ + cali_info->absolute_ofdm_swing_idx[p] = + delta_swing_table_idx_tup_b[delta]; + ODM_RT_TRACE( + dm, ODM_COMP_TX_PWR_TRACK, + "******Temp is higher and cali_info->absolute_ofdm_swing_idx[ODM_RF_PATH_B] = %d\n", + cali_info->absolute_ofdm_swing_idx[p]); + break; + + case ODM_RF_PATH_C: + ODM_RT_TRACE(dm, ODM_COMP_TX_PWR_TRACK, + "delta_swing_table_idx_tup_c[%d] = %d\n", + delta, delta_swing_table_idx_tup_c[delta]); + + cali_info->delta_power_index[p] = + delta_swing_table_idx_tup_c[delta]; + /*Record delta swing for mix mode pwr tracking*/ + cali_info->absolute_ofdm_swing_idx[p] = + delta_swing_table_idx_tup_c[delta]; + ODM_RT_TRACE( + dm, ODM_COMP_TX_PWR_TRACK, + "******Temp is higher and cali_info->absolute_ofdm_swing_idx[ODM_RF_PATH_C] = %d\n", + cali_info->absolute_ofdm_swing_idx[p]); + break; + + case ODM_RF_PATH_D: + ODM_RT_TRACE(dm, ODM_COMP_TX_PWR_TRACK, + "delta_swing_table_idx_tup_d[%d] = %d\n", + delta, delta_swing_table_idx_tup_d[delta]); + + cali_info->delta_power_index[p] = + delta_swing_table_idx_tup_d[delta]; + /*Record delta swing for mix mode pwr tracking*/ + cali_info->absolute_ofdm_swing_idx[p] = + delta_swing_table_idx_tup_d[delta]; + ODM_RT_TRACE( + dm, ODM_COMP_TX_PWR_TRACK, + "******Temp is higher and cali_info->absolute_ofdm_swing_idx[ODM_RF_PATH_D] = %d\n", + cali_info->absolute_ofdm_swing_idx[p]); + break; + + default: + ODM_RT_TRACE(dm, ODM_COMP_TX_PWR_TRACK, + "delta_swing_table_idx_tup_a[%d] = %d\n", + delta, delta_swing_table_idx_tup_a[delta]); + + cali_info->delta_power_index[p] = + delta_swing_table_idx_tup_a[delta]; + /*Record delta swing for mix mode pwr tracking*/ + cali_info->absolute_ofdm_swing_idx[p] = + delta_swing_table_idx_tup_a[delta]; + ODM_RT_TRACE( + dm, ODM_COMP_TX_PWR_TRACK, + "******Temp is higher and cali_info->absolute_ofdm_swing_idx[ODM_RF_PATH_A] = %d\n", + cali_info->absolute_ofdm_swing_idx[p]); + break; + } + } +} + +static inline void phydm_set_calibrate_info_down( + struct phy_dm_struct *dm, struct txpwrtrack_cfg *c, u8 delta, + struct dm_rf_calibration_struct *cali_info, + u8 *delta_swing_table_idx_tdown_a, u8 *delta_swing_table_idx_tdown_b, + u8 *delta_swing_table_idx_tdown_c, u8 *delta_swing_table_idx_tdown_d) +{ + u8 p = 0; + + for (p = ODM_RF_PATH_A; p < c->rf_path_count; p++) { + cali_info->delta_power_index_last[p] = + cali_info->delta_power_index + [p]; /*recording poer index offset*/ + + switch (p) { + case ODM_RF_PATH_B: + ODM_RT_TRACE(dm, ODM_COMP_TX_PWR_TRACK, + "delta_swing_table_idx_tdown_b[%d] = %d\n", + delta, + delta_swing_table_idx_tdown_b[delta]); + cali_info->delta_power_index[p] = + -1 * delta_swing_table_idx_tdown_b[delta]; + /*Record delta swing for mix mode pwr tracking*/ + cali_info->absolute_ofdm_swing_idx[p] = + -1 * delta_swing_table_idx_tdown_b[delta]; + ODM_RT_TRACE( + dm, ODM_COMP_TX_PWR_TRACK, + "******Temp is lower and cali_info->absolute_ofdm_swing_idx[ODM_RF_PATH_B] = %d\n", + cali_info->absolute_ofdm_swing_idx[p]); + break; + + case ODM_RF_PATH_C: + ODM_RT_TRACE(dm, ODM_COMP_TX_PWR_TRACK, + "delta_swing_table_idx_tdown_c[%d] = %d\n", + delta, + delta_swing_table_idx_tdown_c[delta]); + cali_info->delta_power_index[p] = + -1 * delta_swing_table_idx_tdown_c[delta]; + /*Record delta swing for mix mode pwr tracking*/ + cali_info->absolute_ofdm_swing_idx[p] = + -1 * delta_swing_table_idx_tdown_c[delta]; + ODM_RT_TRACE( + dm, ODM_COMP_TX_PWR_TRACK, + "******Temp is lower and cali_info->absolute_ofdm_swing_idx[ODM_RF_PATH_C] = %d\n", + cali_info->absolute_ofdm_swing_idx[p]); + break; + + case ODM_RF_PATH_D: + ODM_RT_TRACE(dm, ODM_COMP_TX_PWR_TRACK, + "delta_swing_table_idx_tdown_d[%d] = %d\n", + delta, + delta_swing_table_idx_tdown_d[delta]); + cali_info->delta_power_index[p] = + -1 * delta_swing_table_idx_tdown_d[delta]; + /*Record delta swing for mix mode pwr tracking*/ + cali_info->absolute_ofdm_swing_idx[p] = + -1 * delta_swing_table_idx_tdown_d[delta]; + ODM_RT_TRACE( + dm, ODM_COMP_TX_PWR_TRACK, + "******Temp is lower and cali_info->absolute_ofdm_swing_idx[ODM_RF_PATH_D] = %d\n", + cali_info->absolute_ofdm_swing_idx[p]); + break; + + default: + ODM_RT_TRACE(dm, ODM_COMP_TX_PWR_TRACK, + "delta_swing_table_idx_tdown_a[%d] = %d\n", + delta, + delta_swing_table_idx_tdown_a[delta]); + cali_info->delta_power_index[p] = + -1 * delta_swing_table_idx_tdown_a[delta]; + /*Record delta swing for mix mode pwr tracking*/ + cali_info->absolute_ofdm_swing_idx[p] = + -1 * delta_swing_table_idx_tdown_a[delta]; + ODM_RT_TRACE( + dm, ODM_COMP_TX_PWR_TRACK, + "******Temp is lower and cali_info->absolute_ofdm_swing_idx[ODM_RF_PATH_A] = %d\n", + cali_info->absolute_ofdm_swing_idx[p]); + break; + } + } +} + +static inline void phydm_odm_tx_power_set(struct phy_dm_struct *dm, + struct txpwrtrack_cfg *c, + u8 indexforchannel, u8 flag) +{ + u8 p = 0; + + if (dm->support_ic_type == ODM_RTL8188E || + dm->support_ic_type == ODM_RTL8192E || + dm->support_ic_type == ODM_RTL8821 || + dm->support_ic_type == ODM_RTL8812 || + dm->support_ic_type == ODM_RTL8723B || + dm->support_ic_type == ODM_RTL8814A || + dm->support_ic_type == ODM_RTL8703B || + dm->support_ic_type == ODM_RTL8188F || + dm->support_ic_type == ODM_RTL8822B || + dm->support_ic_type == ODM_RTL8723D || + dm->support_ic_type == ODM_RTL8821C || + dm->support_ic_type == ODM_RTL8710B) { /* JJ ADD 20161014 */ + + ODM_RT_TRACE( + dm, ODM_COMP_TX_PWR_TRACK, + "**********Enter POWER Tracking MIX_MODE**********\n"); + for (p = ODM_RF_PATH_A; p < c->rf_path_count; p++) { + if (flag == 0) + (*c->odm_tx_pwr_track_set_pwr)(dm, MIX_MODE, p, + 0); + else + (*c->odm_tx_pwr_track_set_pwr)(dm, MIX_MODE, p, + indexforchannel); + } + } else { + ODM_RT_TRACE( + dm, ODM_COMP_TX_PWR_TRACK, + "**********Enter POWER Tracking BBSWING_MODE**********\n"); + for (p = ODM_RF_PATH_A; p < c->rf_path_count; p++) + (*c->odm_tx_pwr_track_set_pwr)(dm, BBSWING, p, + indexforchannel); + } +} + +void configure_txpower_track(void *dm_void, struct txpwrtrack_cfg *config) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + + /* JJ ADD 20161014 */ + + if (dm->support_ic_type == ODM_RTL8822B) + configure_txpower_track_8822b(config); +} + +/* ********************************************************************** + * <20121113, Kordan> This function should be called when tx_agc changed. + * Otherwise the previous compensation is gone, because we record the + * delta of temperature between two TxPowerTracking watch dogs. + * + * NOTE: If Tx BB swing or Tx scaling is varified during run-time, still + * need to call this function. + * ***********************************************************************/ +void odm_clear_txpowertracking_state(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct rtl_priv *rtlpriv = (struct rtl_priv *)dm->adapter; + struct rtl_efuse *rtlefu = rtl_efuse(rtlpriv); + u8 p = 0; + struct dm_rf_calibration_struct *cali_info = &dm->rf_calibrate_info; + + cali_info->bb_swing_idx_cck_base = cali_info->default_cck_index; + cali_info->bb_swing_idx_cck = cali_info->default_cck_index; + dm->rf_calibrate_info.CCK_index = 0; + + for (p = ODM_RF_PATH_A; p < MAX_RF_PATH; ++p) { + cali_info->bb_swing_idx_ofdm_base[p] = + cali_info->default_ofdm_index; + cali_info->bb_swing_idx_ofdm[p] = cali_info->default_ofdm_index; + cali_info->OFDM_index[p] = cali_info->default_ofdm_index; + + cali_info->power_index_offset[p] = 0; + cali_info->delta_power_index[p] = 0; + cali_info->delta_power_index_last[p] = 0; + + cali_info->absolute_ofdm_swing_idx[p] = + 0; /* Initial Mix mode power tracking*/ + cali_info->remnant_ofdm_swing_idx[p] = 0; + cali_info->kfree_offset[p] = 0; + } + + cali_info->modify_tx_agc_flag_path_a = + false; /*Initial at Modify Tx Scaling mode*/ + cali_info->modify_tx_agc_flag_path_b = + false; /*Initial at Modify Tx Scaling mode*/ + cali_info->modify_tx_agc_flag_path_c = + false; /*Initial at Modify Tx Scaling mode*/ + cali_info->modify_tx_agc_flag_path_d = + false; /*Initial at Modify Tx Scaling mode*/ + cali_info->remnant_cck_swing_idx = 0; + cali_info->thermal_value = rtlefu->eeprom_thermalmeter; + + cali_info->modify_tx_agc_value_cck = 0; /* modify by Mingzhi.Guo */ + cali_info->modify_tx_agc_value_ofdm = 0; /* modify by Mingzhi.Guo */ +} + +void odm_txpowertracking_callback_thermal_meter(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct rtl_priv *rtlpriv = (struct rtl_priv *)dm->adapter; + struct rtl_efuse *rtlefu = rtl_efuse(rtlpriv); + void *adapter = dm->adapter; + + struct dm_rf_calibration_struct *cali_info = &dm->rf_calibrate_info; + + u8 thermal_value = 0, delta, delta_LCK, delta_IQK, p = 0, i = 0; + s8 diff_DPK[4]; /* use 'for..loop' to initialize */ + u8 thermal_value_avg_count = 0; + u32 thermal_value_avg = 0, regc80, regcd0, regcd4, regab4; + + /* OFDM BB Swing should be less than +3.0dB (required by Arthur) */ + u8 OFDM_min_index = 0; + /* get_right_chnl_place_for_iqk(hal_data->current_channel) */ + u8 indexforchannel = 0; + u8 power_tracking_type = 0; /* no specify type */ + u8 xtal_offset_eanble = 0; + + struct txpwrtrack_cfg c; + + /* 4 1. The following TWO tables decide the final index of + * OFDM/CCK swing table. + */ + u8 *delta_swing_table_idx_tup_a = NULL; + u8 *delta_swing_table_idx_tdown_a = NULL; + u8 *delta_swing_table_idx_tup_b = NULL; + u8 *delta_swing_table_idx_tdown_b = NULL; + /*for 8814 add by Yu Chen*/ + u8 *delta_swing_table_idx_tup_c = NULL; + u8 *delta_swing_table_idx_tdown_c = NULL; + u8 *delta_swing_table_idx_tup_d = NULL; + u8 *delta_swing_table_idx_tdown_d = NULL; + /*for Xtal Offset by James.Tung*/ + s8 *delta_swing_table_xtal_up = NULL; + s8 *delta_swing_table_xtal_down = NULL; + + /* 4 2. Initialization ( 7 steps in total ) */ + + configure_txpower_track(dm, &c); + + (*c.get_delta_swing_table)(dm, (u8 **)&delta_swing_table_idx_tup_a, + (u8 **)&delta_swing_table_idx_tdown_a, + (u8 **)&delta_swing_table_idx_tup_b, + (u8 **)&delta_swing_table_idx_tdown_b); + + if (dm->support_ic_type & ODM_RTL8814A) /*for 8814 path C & D*/ + (*c.get_delta_swing_table8814only)( + dm, (u8 **)&delta_swing_table_idx_tup_c, + (u8 **)&delta_swing_table_idx_tdown_c, + (u8 **)&delta_swing_table_idx_tup_d, + (u8 **)&delta_swing_table_idx_tdown_d); + /* JJ ADD 20161014 */ + if (dm->support_ic_type & + (ODM_RTL8703B | ODM_RTL8723D | ODM_RTL8710B)) /*for Xtal Offset*/ + (*c.get_delta_swing_xtal_table)( + dm, (s8 **)&delta_swing_table_xtal_up, + (s8 **)&delta_swing_table_xtal_down); + + cali_info->txpowertracking_callback_cnt++; /*cosa add for debug*/ + cali_info->is_txpowertracking_init = true; + + /*cali_info->txpowertrack_control = hal_data->txpowertrack_control; + *<Kordan> We should keep updating ctrl variable according to HalData. + *<Kordan> rf_calibrate_info.rega24 will be initialized when + *ODM HW configuring, but MP configures with para files. + */ + if (dm->mp_mode) + cali_info->rega24 = 0x090e1317; + + ODM_RT_TRACE( + dm, ODM_COMP_TX_PWR_TRACK, + "===>%s\n cali_info->bb_swing_idx_cck_base: %d, cali_info->bb_swing_idx_ofdm_base[A]: %d, cali_info->default_ofdm_index: %d\n", + __func__, cali_info->bb_swing_idx_cck_base, + cali_info->bb_swing_idx_ofdm_base[ODM_RF_PATH_A], + cali_info->default_ofdm_index); + + ODM_RT_TRACE( + dm, ODM_COMP_TX_PWR_TRACK, + "cali_info->txpowertrack_control=%d, rtlefu->eeprom_thermalmeter %d\n", + cali_info->txpowertrack_control, rtlefu->eeprom_thermalmeter); + + thermal_value = + (u8)odm_get_rf_reg(dm, ODM_RF_PATH_A, c.thermal_reg_addr, + 0xfc00); /* 0x42: RF Reg[15:10] 88E */ + + /*add log by zhao he, check c80/c94/c14/ca0 value*/ + if (dm->support_ic_type == ODM_RTL8723D) { + regc80 = odm_get_bb_reg(dm, 0xc80, MASKDWORD); + regcd0 = odm_get_bb_reg(dm, 0xcd0, MASKDWORD); + regcd4 = odm_get_bb_reg(dm, 0xcd4, MASKDWORD); + regab4 = odm_get_bb_reg(dm, 0xab4, 0x000007FF); + ODM_RT_TRACE( + dm, ODM_COMP_CALIBRATION, + "0xc80 = 0x%x 0xcd0 = 0x%x 0xcd4 = 0x%x 0xab4 = 0x%x\n", + regc80, regcd0, regcd4, regab4); + } + /* JJ ADD 20161014 */ + if (dm->support_ic_type == ODM_RTL8710B) { + regc80 = odm_get_bb_reg(dm, 0xc80, MASKDWORD); + regcd0 = odm_get_bb_reg(dm, 0xcd0, MASKDWORD); + regcd4 = odm_get_bb_reg(dm, 0xcd4, MASKDWORD); + regab4 = odm_get_bb_reg(dm, 0xab4, 0x000007FF); + ODM_RT_TRACE( + dm, ODM_COMP_CALIBRATION, + "0xc80 = 0x%x 0xcd0 = 0x%x 0xcd4 = 0x%x 0xab4 = 0x%x\n", + regc80, regcd0, regcd4, regab4); + } + + if (!cali_info->txpowertrack_control) + return; + + /*4 3. Initialize ThermalValues of rf_calibrate_info*/ + + if (cali_info->is_reloadtxpowerindex) + ODM_RT_TRACE(dm, ODM_COMP_TX_PWR_TRACK, + "reload ofdm index for band switch\n"); + + /*4 4. Calculate average thermal meter*/ + + cali_info->thermal_value_avg[cali_info->thermal_value_avg_index] = + thermal_value; + cali_info->thermal_value_avg_index++; + if (cali_info->thermal_value_avg_index == + c.average_thermal_num) /*Average times = c.average_thermal_num*/ + cali_info->thermal_value_avg_index = 0; + + for (i = 0; i < c.average_thermal_num; i++) { + if (cali_info->thermal_value_avg[i]) { + thermal_value_avg += cali_info->thermal_value_avg[i]; + thermal_value_avg_count++; + } + } + + if (thermal_value_avg_count) { + /* Calculate Average thermal_value after average enough times */ + thermal_value = + (u8)(thermal_value_avg / thermal_value_avg_count); + cali_info->thermal_value_delta = + thermal_value - rtlefu->eeprom_thermalmeter; + ODM_RT_TRACE( + dm, ODM_COMP_TX_PWR_TRACK, + "AVG Thermal Meter = 0x%X, EFUSE Thermal base = 0x%X\n", + thermal_value, rtlefu->eeprom_thermalmeter); + } + + /* 4 5. Calculate delta, delta_LCK, delta_IQK. */ + + /* "delta" is used to determine whether thermal value changes or not*/ + delta = (thermal_value > cali_info->thermal_value) ? + (thermal_value - cali_info->thermal_value) : + (cali_info->thermal_value - thermal_value); + delta_LCK = (thermal_value > cali_info->thermal_value_lck) ? + (thermal_value - cali_info->thermal_value_lck) : + (cali_info->thermal_value_lck - thermal_value); + delta_IQK = (thermal_value > cali_info->thermal_value_iqk) ? + (thermal_value - cali_info->thermal_value_iqk) : + (cali_info->thermal_value_iqk - thermal_value); + + if (cali_info->thermal_value_iqk == + 0xff) { /*no PG, use thermal value for IQK*/ + cali_info->thermal_value_iqk = thermal_value; + delta_IQK = + (thermal_value > cali_info->thermal_value_iqk) ? + (thermal_value - cali_info->thermal_value_iqk) : + (cali_info->thermal_value_iqk - thermal_value); + ODM_RT_TRACE(dm, ODM_COMP_TX_PWR_TRACK, + "no PG, use thermal_value for IQK\n"); + } + + for (p = ODM_RF_PATH_A; p < c.rf_path_count; p++) + diff_DPK[p] = (s8)thermal_value - (s8)cali_info->dpk_thermal[p]; + + /*4 6. If necessary, do LCK.*/ + + if (!(dm->support_ic_type & + ODM_RTL8821)) { /*no PG, do LCK at initial status*/ + if (cali_info->thermal_value_lck == 0xff) { + ODM_RT_TRACE(dm, ODM_COMP_TX_PWR_TRACK, + "no PG, do LCK\n"); + cali_info->thermal_value_lck = thermal_value; + + /*Use RTLCK, so close power tracking driver LCK*/ + if (!(dm->support_ic_type & ODM_RTL8814A) && + c.phy_lc_calibrate) + (*c.phy_lc_calibrate)(dm); + + delta_LCK = + (thermal_value > cali_info->thermal_value_lck) ? + (thermal_value - + cali_info->thermal_value_lck) : + (cali_info->thermal_value_lck - + thermal_value); + } + + ODM_RT_TRACE(dm, ODM_COMP_TX_PWR_TRACK, + "(delta, delta_LCK, delta_IQK) = (%d, %d, %d)\n", + delta, delta_LCK, delta_IQK); + + /*Delta temperature is equal to or larger than 20 centigrade.*/ + if (delta_LCK >= c.threshold_iqk) { + ODM_RT_TRACE(dm, ODM_COMP_TX_PWR_TRACK, + "delta_LCK(%d) >= threshold_iqk(%d)\n", + delta_LCK, c.threshold_iqk); + cali_info->thermal_value_lck = thermal_value; + + /*Use RTLCK, so close power tracking driver LCK*/ + if (!(dm->support_ic_type & ODM_RTL8814A) && + c.phy_lc_calibrate) + (*c.phy_lc_calibrate)(dm); + } + } + + /*3 7. If necessary, move the index of swing table to adjust Tx power.*/ + + if (delta > 0 && cali_info->txpowertrack_control) { + /* "delta" here is used to record the abs value of difference.*/ + delta = thermal_value > rtlefu->eeprom_thermalmeter ? + (thermal_value - rtlefu->eeprom_thermalmeter) : + (rtlefu->eeprom_thermalmeter - thermal_value); + if (delta >= TXPWR_TRACK_TABLE_SIZE) + delta = TXPWR_TRACK_TABLE_SIZE - 1; + + /*4 7.1 The Final Power index = BaseIndex + power_index_offset*/ + + if (thermal_value > rtlefu->eeprom_thermalmeter) { + phydm_set_calibrate_info_up( + dm, &c, delta, cali_info, + delta_swing_table_idx_tup_a, + delta_swing_table_idx_tup_b, + delta_swing_table_idx_tup_c, + delta_swing_table_idx_tup_d); + /* JJ ADD 20161014 */ + if (dm->support_ic_type & + (ODM_RTL8703B | ODM_RTL8723D | ODM_RTL8710B)) { + /*Save xtal_offset from Xtal table*/ + + /*recording last Xtal offset*/ + cali_info->xtal_offset_last = + cali_info->xtal_offset; + ODM_RT_TRACE( + dm, ODM_COMP_TX_PWR_TRACK, + "[Xtal] delta_swing_table_xtal_up[%d] = %d\n", + delta, + delta_swing_table_xtal_up[delta]); + cali_info->xtal_offset = + delta_swing_table_xtal_up[delta]; + xtal_offset_eanble = + (cali_info->xtal_offset_last == + cali_info->xtal_offset) ? + 0 : + 1; + } + + } else { + phydm_set_calibrate_info_down( + dm, &c, delta, cali_info, + delta_swing_table_idx_tdown_a, + delta_swing_table_idx_tdown_b, + delta_swing_table_idx_tdown_c, + delta_swing_table_idx_tdown_d); + /* JJ ADD 20161014 */ + if (dm->support_ic_type & + (ODM_RTL8703B | ODM_RTL8723D | ODM_RTL8710B)) { + /*Save xtal_offset from Xtal table*/ + + /*recording last Xtal offset*/ + cali_info->xtal_offset_last = + cali_info->xtal_offset; + ODM_RT_TRACE( + dm, ODM_COMP_TX_PWR_TRACK, + "[Xtal] delta_swing_table_xtal_down[%d] = %d\n", + delta, + delta_swing_table_xtal_down[delta]); + cali_info->xtal_offset = + delta_swing_table_xtal_down[delta]; + xtal_offset_eanble = + (cali_info->xtal_offset_last == + cali_info->xtal_offset) ? + 0 : + 1; + } + } + + for (p = ODM_RF_PATH_A; p < c.rf_path_count; p++) { + ODM_RT_TRACE( + dm, ODM_COMP_TX_PWR_TRACK, + "\n\n=========================== [path-%d] Calculating power_index_offset===========================\n", + p); + + if (cali_info->delta_power_index[p] == + cali_info->delta_power_index_last[p]) { + /* If Thermal value changes but lookup table + * value still the same + */ + cali_info->power_index_offset[p] = 0; + } else { + /*Power idx diff between 2 times Pwr Tracking*/ + cali_info->power_index_offset[p] = + cali_info->delta_power_index[p] - + cali_info->delta_power_index_last[p]; + } + + ODM_RT_TRACE( + dm, ODM_COMP_TX_PWR_TRACK, + "[path-%d] power_index_offset(%d) = delta_power_index(%d) - delta_power_index_last(%d)\n", + p, cali_info->power_index_offset[p], + cali_info->delta_power_index[p], + cali_info->delta_power_index_last[p]); + + cali_info->OFDM_index[p] = + cali_info->bb_swing_idx_ofdm_base[p] + + cali_info->power_index_offset[p]; + cali_info->CCK_index = + cali_info->bb_swing_idx_cck_base + + cali_info->power_index_offset[p]; + + cali_info->bb_swing_idx_cck = cali_info->CCK_index; + cali_info->bb_swing_idx_ofdm[p] = + cali_info->OFDM_index[p]; + + /*******Print BB Swing base and index Offset**********/ + + ODM_RT_TRACE( + dm, ODM_COMP_TX_PWR_TRACK, + "The 'CCK' final index(%d) = BaseIndex(%d) + power_index_offset(%d)\n", + cali_info->bb_swing_idx_cck, + cali_info->bb_swing_idx_cck_base, + cali_info->power_index_offset[p]); + ODM_RT_TRACE( + dm, ODM_COMP_TX_PWR_TRACK, + "The 'OFDM' final index(%d) = BaseIndex[%d](%d) + power_index_offset(%d)\n", + cali_info->bb_swing_idx_ofdm[p], p, + cali_info->bb_swing_idx_ofdm_base[p], + cali_info->power_index_offset[p]); + + /*4 7.1 Handle boundary conditions of index.*/ + + if (cali_info->OFDM_index[p] > + c.swing_table_size_ofdm - 1) + cali_info->OFDM_index[p] = + c.swing_table_size_ofdm - 1; + else if (cali_info->OFDM_index[p] <= OFDM_min_index) + cali_info->OFDM_index[p] = OFDM_min_index; + } + + ODM_RT_TRACE( + dm, ODM_COMP_TX_PWR_TRACK, + "\n\n========================================================================================================\n"); + + if (cali_info->CCK_index > c.swing_table_size_cck - 1) + cali_info->CCK_index = c.swing_table_size_cck - 1; + else if (cali_info->CCK_index <= 0) + cali_info->CCK_index = 0; + } else { + ODM_RT_TRACE( + dm, ODM_COMP_TX_PWR_TRACK, + "The thermal meter is unchanged or TxPowerTracking OFF(%d): thermal_value: %d, cali_info->thermal_value: %d\n", + cali_info->txpowertrack_control, thermal_value, + cali_info->thermal_value); + + for (p = ODM_RF_PATH_A; p < c.rf_path_count; p++) + cali_info->power_index_offset[p] = 0; + } + + /*Print Swing base & current*/ + ODM_RT_TRACE( + dm, ODM_COMP_TX_PWR_TRACK, + "TxPowerTracking: [CCK] Swing Current index: %d, Swing base index: %d\n", + cali_info->CCK_index, cali_info->bb_swing_idx_cck_base); + + for (p = ODM_RF_PATH_A; p < c.rf_path_count; p++) + ODM_RT_TRACE( + dm, ODM_COMP_TX_PWR_TRACK, + "TxPowerTracking: [OFDM] Swing Current index: %d, Swing base index[%d]: %d\n", + cali_info->OFDM_index[p], p, + cali_info->bb_swing_idx_ofdm_base[p]); + + if ((dm->support_ic_type & ODM_RTL8814A)) { + ODM_RT_TRACE(dm, ODM_COMP_TX_PWR_TRACK, + "power_tracking_type=%d\n", power_tracking_type); + + if (power_tracking_type == 0) { + ODM_RT_TRACE( + dm, ODM_COMP_TX_PWR_TRACK, + "**********Enter POWER Tracking MIX_MODE**********\n"); + for (p = ODM_RF_PATH_A; p < c.rf_path_count; p++) + (*c.odm_tx_pwr_track_set_pwr)(dm, MIX_MODE, p, + 0); + } else if (power_tracking_type == 1) { + ODM_RT_TRACE( + dm, ODM_COMP_TX_PWR_TRACK, + "**********Enter POWER Tracking MIX(2G) TSSI(5G) MODE**********\n"); + for (p = ODM_RF_PATH_A; p < c.rf_path_count; p++) + (*c.odm_tx_pwr_track_set_pwr)( + dm, MIX_2G_TSSI_5G_MODE, p, 0); + } else if (power_tracking_type == 2) { + ODM_RT_TRACE( + dm, ODM_COMP_TX_PWR_TRACK, + "**********Enter POWER Tracking MIX(5G) TSSI(2G)MODE**********\n"); + for (p = ODM_RF_PATH_A; p < c.rf_path_count; p++) + (*c.odm_tx_pwr_track_set_pwr)( + dm, MIX_5G_TSSI_2G_MODE, p, 0); + } else if (power_tracking_type == 3) { + ODM_RT_TRACE( + dm, ODM_COMP_TX_PWR_TRACK, + "**********Enter POWER Tracking TSSI MODE**********\n"); + for (p = ODM_RF_PATH_A; p < c.rf_path_count; p++) + (*c.odm_tx_pwr_track_set_pwr)(dm, TSSI_MODE, p, + 0); + } + /*Record last Power Tracking Thermal value*/ + cali_info->thermal_value = thermal_value; + + } else if ((cali_info->power_index_offset[ODM_RF_PATH_A] != 0 || + cali_info->power_index_offset[ODM_RF_PATH_B] != 0 || + cali_info->power_index_offset[ODM_RF_PATH_C] != 0 || + cali_info->power_index_offset[ODM_RF_PATH_D] != 0) && + cali_info->txpowertrack_control && + (rtlefu->eeprom_thermalmeter != 0xff)) { + /* 4 7.2 Configure the Swing Table to adjust Tx Power. */ + + /*Always true after Tx Power is adjusted by power tracking.*/ + cali_info->is_tx_power_changed = true; + /* 2012/04/23 MH According to Luke's suggestion, we can not + * write BB digital to increase TX power. Otherwise, EVM will + * be bad. + */ + /* 2012/04/25 MH Add for tx power tracking to set tx power in + * tx agc for 88E. + */ + if (thermal_value > cali_info->thermal_value) { + for (p = ODM_RF_PATH_A; p < c.rf_path_count; p++) { + /* print temperature increasing */ + ODM_RT_TRACE( + dm, ODM_COMP_TX_PWR_TRACK, + "Temperature Increasing(%d): delta_pi: %d, delta_t: %d, Now_t: %d, EFUSE_t: %d, Last_t: %d\n", + p, cali_info->power_index_offset[p], + delta, thermal_value, + rtlefu->eeprom_thermalmeter, + cali_info->thermal_value); + } + } else if (thermal_value < + cali_info->thermal_value) { /*Low temperature*/ + for (p = ODM_RF_PATH_A; p < c.rf_path_count; p++) { + /* print temperature decreasing */ + ODM_RT_TRACE( + dm, ODM_COMP_TX_PWR_TRACK, + "Temperature Decreasing(%d): delta_pi: %d, delta_t: %d, Now_t: %d, EFUSE_t: %d, Last_t: %d\n", + p, cali_info->power_index_offset[p], + delta, thermal_value, + rtlefu->eeprom_thermalmeter, + cali_info->thermal_value); + } + } + + if (thermal_value > rtlefu->eeprom_thermalmeter) { + ODM_RT_TRACE( + dm, ODM_COMP_TX_PWR_TRACK, + "Temperature(%d) higher than PG value(%d)\n", + thermal_value, rtlefu->eeprom_thermalmeter); + + phydm_odm_tx_power_set(dm, &c, indexforchannel, 0); + } else { + ODM_RT_TRACE( + dm, ODM_COMP_TX_PWR_TRACK, + "Temperature(%d) lower than PG value(%d)\n", + thermal_value, rtlefu->eeprom_thermalmeter); + phydm_odm_tx_power_set(dm, &c, indexforchannel, 1); + } + + /*Record last time Power Tracking result as base.*/ + cali_info->bb_swing_idx_cck_base = cali_info->bb_swing_idx_cck; + + for (p = ODM_RF_PATH_A; p < c.rf_path_count; p++) + cali_info->bb_swing_idx_ofdm_base[p] = + cali_info->bb_swing_idx_ofdm[p]; + + ODM_RT_TRACE( + dm, ODM_COMP_TX_PWR_TRACK, + "cali_info->thermal_value = %d thermal_value= %d\n", + cali_info->thermal_value, thermal_value); + + /*Record last Power Tracking Thermal value*/ + cali_info->thermal_value = thermal_value; + } + + if (dm->support_ic_type == ODM_RTL8703B || + dm->support_ic_type == ODM_RTL8723D || + dm->support_ic_type == ODM_RTL8710B) { /* JJ ADD 20161014 */ + + if (xtal_offset_eanble != 0 && + cali_info->txpowertrack_control && + (rtlefu->eeprom_thermalmeter != 0xff)) { + ODM_RT_TRACE( + dm, ODM_COMP_TX_PWR_TRACK, + "**********Enter Xtal Tracking**********\n"); + + if (thermal_value > rtlefu->eeprom_thermalmeter) { + ODM_RT_TRACE( + dm, ODM_COMP_TX_PWR_TRACK, + "Temperature(%d) higher than PG value(%d)\n", + thermal_value, + rtlefu->eeprom_thermalmeter); + (*c.odm_txxtaltrack_set_xtal)(dm); + } else { + ODM_RT_TRACE( + dm, ODM_COMP_TX_PWR_TRACK, + "Temperature(%d) lower than PG value(%d)\n", + thermal_value, + rtlefu->eeprom_thermalmeter); + (*c.odm_txxtaltrack_set_xtal)(dm); + } + } + ODM_RT_TRACE(dm, ODM_COMP_TX_PWR_TRACK, + "**********End Xtal Tracking**********\n"); + } + + if (!IS_HARDWARE_TYPE_8723B(adapter)) { + /* Delta temperature is equal to or larger than 20 centigrade + * (When threshold is 8). + */ + if (delta_IQK >= c.threshold_iqk) { + ODM_RT_TRACE(dm, ODM_COMP_TX_PWR_TRACK, + "delta_IQK(%d) >= threshold_iqk(%d)\n", + delta_IQK, c.threshold_iqk); + if (!cali_info->is_iqk_in_progress) + (*c.do_iqk)(dm, delta_IQK, thermal_value, 8); + } + } + if (cali_info->dpk_thermal[ODM_RF_PATH_A] != 0) { + if (diff_DPK[ODM_RF_PATH_A] >= c.threshold_dpk) { + odm_set_bb_reg(dm, 0x82c, BIT(31), 0x1); + odm_set_bb_reg( + dm, 0xcc4, + BIT(14) | BIT(13) | BIT(12) | BIT(11) | BIT(10), + (diff_DPK[ODM_RF_PATH_A] / c.threshold_dpk)); + odm_set_bb_reg(dm, 0x82c, BIT(31), 0x0); + } else if ((diff_DPK[ODM_RF_PATH_A] <= -1 * c.threshold_dpk)) { + s32 value = 0x20 + + (diff_DPK[ODM_RF_PATH_A] / c.threshold_dpk); + + odm_set_bb_reg(dm, 0x82c, BIT(31), 0x1); + odm_set_bb_reg(dm, 0xcc4, BIT(14) | BIT(13) | BIT(12) | + BIT(11) | BIT(10), + value); + odm_set_bb_reg(dm, 0x82c, BIT(31), 0x0); + } else { + odm_set_bb_reg(dm, 0x82c, BIT(31), 0x1); + odm_set_bb_reg(dm, 0xcc4, BIT(14) | BIT(13) | BIT(12) | + BIT(11) | BIT(10), + 0); + odm_set_bb_reg(dm, 0x82c, BIT(31), 0x0); + } + } + if (cali_info->dpk_thermal[ODM_RF_PATH_B] != 0) { + if (diff_DPK[ODM_RF_PATH_B] >= c.threshold_dpk) { + odm_set_bb_reg(dm, 0x82c, BIT(31), 0x1); + odm_set_bb_reg( + dm, 0xec4, + BIT(14) | BIT(13) | BIT(12) | BIT(11) | BIT(10), + (diff_DPK[ODM_RF_PATH_B] / c.threshold_dpk)); + odm_set_bb_reg(dm, 0x82c, BIT(31), 0x0); + } else if ((diff_DPK[ODM_RF_PATH_B] <= -1 * c.threshold_dpk)) { + s32 value = 0x20 + + (diff_DPK[ODM_RF_PATH_B] / c.threshold_dpk); + + odm_set_bb_reg(dm, 0x82c, BIT(31), 0x1); + odm_set_bb_reg(dm, 0xec4, BIT(14) | BIT(13) | BIT(12) | + BIT(11) | BIT(10), + value); + odm_set_bb_reg(dm, 0x82c, BIT(31), 0x0); + } else { + odm_set_bb_reg(dm, 0x82c, BIT(31), 0x1); + odm_set_bb_reg(dm, 0xec4, BIT(14) | BIT(13) | BIT(12) | + BIT(11) | BIT(10), + 0); + odm_set_bb_reg(dm, 0x82c, BIT(31), 0x0); + } + } + + ODM_RT_TRACE(dm, ODM_COMP_TX_PWR_TRACK, "<===%s\n", __func__); + + cali_info->tx_powercount = 0; +} + +/* 3============================================================ + * 3 IQ Calibration + * 3============================================================ + */ + +void odm_reset_iqk_result(void *dm_void) { return; } + +u8 odm_get_right_chnl_place_for_iqk(u8 chnl) +{ + u8 channel_all[ODM_TARGET_CHNL_NUM_2G_5G] = { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 14, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, + 56, 58, 60, 62, 64, 100, 102, 104, 106, 108, 110, 112, + 114, 116, 118, 120, 122, 124, 126, 128, 130, 132, 134, 136, + 138, 140, 149, 151, 153, 155, 157, 159, 161, 163, 165}; + u8 place = chnl; + + if (chnl > 14) { + for (place = 14; place < sizeof(channel_all); place++) { + if (channel_all[place] == chnl) + return place - 13; + } + } + return 0; +} + +static void odm_iq_calibrate(struct phy_dm_struct *dm) +{ + void *adapter = dm->adapter; + + if (IS_HARDWARE_TYPE_8812AU(adapter)) + return; + + if (dm->is_linked) { + if ((*dm->channel != dm->pre_channel) && + (!*dm->is_scan_in_process)) { + dm->pre_channel = *dm->channel; + dm->linked_interval = 0; + } + + if (dm->linked_interval < 3) + dm->linked_interval++; + + if (dm->linked_interval == 2) { + if (IS_HARDWARE_TYPE_8814A(adapter)) + ; + + else if (IS_HARDWARE_TYPE_8822B(adapter)) + phy_iq_calibrate_8822b(dm, false); + } + } else { + dm->linked_interval = 0; + } +} + +void phydm_rf_init(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + + odm_txpowertracking_init(dm); + + odm_clear_txpowertracking_state(dm); +} + +void phydm_rf_watchdog(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + + odm_txpowertracking_check(dm); + if (dm->support_ic_type & ODM_IC_11AC_SERIES) + odm_iq_calibrate(dm); +} diff --git a/drivers/staging/rtlwifi/phydm/halphyrf_ce.h b/drivers/staging/rtlwifi/phydm/halphyrf_ce.h new file mode 100644 index 000000000000..e5d6257efb2b --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/halphyrf_ce.h @@ -0,0 +1,85 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __HAL_PHY_RF_H__ +#define __HAL_PHY_RF_H__ + +#include "phydm_kfree.h" + +#include "rtl8822b/phydm_iqk_8822b.h" + +#include "phydm_powertracking_ce.h" + +enum spur_cal_method { PLL_RESET, AFE_PHASE_SEL }; + +enum pwrtrack_method { + BBSWING, + TXAGC, + MIX_MODE, + TSSI_MODE, + MIX_2G_TSSI_5G_MODE, + MIX_5G_TSSI_2G_MODE +}; + +typedef void (*func_set_pwr)(void *, enum pwrtrack_method, u8, u8); +typedef void (*func_iqk)(void *, u8, u8, u8); +typedef void (*func_lck)(void *); +typedef void (*func_swing)(void *, u8 **, u8 **, u8 **, u8 **); +typedef void (*func_swing8814only)(void *, u8 **, u8 **, u8 **, u8 **); +typedef void (*func_swing_xtal)(void *, s8 **, s8 **); +typedef void (*func_set_xtal)(void *); + +struct txpwrtrack_cfg { + u8 swing_table_size_cck; + u8 swing_table_size_ofdm; + u8 threshold_iqk; + u8 threshold_dpk; + u8 average_thermal_num; + u8 rf_path_count; + u32 thermal_reg_addr; + func_set_pwr odm_tx_pwr_track_set_pwr; + func_iqk do_iqk; + func_lck phy_lc_calibrate; + func_swing get_delta_swing_table; + func_swing8814only get_delta_swing_table8814only; + func_swing_xtal get_delta_swing_xtal_table; + func_set_xtal odm_txxtaltrack_set_xtal; +}; + +void configure_txpower_track(void *dm_void, struct txpwrtrack_cfg *config); + +void odm_clear_txpowertracking_state(void *dm_void); + +void odm_txpowertracking_callback_thermal_meter(void *dm); + +#define ODM_TARGET_CHNL_NUM_2G_5G 59 + +void odm_reset_iqk_result(void *dm_void); +u8 odm_get_right_chnl_place_for_iqk(u8 chnl); + +void phydm_rf_init(void *dm_void); +void phydm_rf_watchdog(void *dm_void); + +#endif /* #ifndef __HAL_PHY_RF_H__ */ diff --git a/drivers/staging/rtlwifi/phydm/mp_precomp.h b/drivers/staging/rtlwifi/phydm/mp_precomp.h new file mode 100644 index 000000000000..b313de511ed6 --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/mp_precomp.h @@ -0,0 +1,24 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ diff --git a/drivers/staging/rtlwifi/phydm/phydm.c b/drivers/staging/rtlwifi/phydm/phydm.c new file mode 100644 index 000000000000..37888c3087a4 --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/phydm.c @@ -0,0 +1,1986 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +/* ************************************************************ + * include files + * *************************************************************/ + +#include "mp_precomp.h" +#include "phydm_precomp.h" + +static const u16 db_invert_table[12][8] = { + {1, 1, 1, 2, 2, 2, 2, 3}, + {3, 3, 4, 4, 4, 5, 6, 6}, + {7, 8, 9, 10, 11, 13, 14, 16}, + {18, 20, 22, 25, 28, 32, 35, 40}, + {45, 50, 56, 63, 71, 79, 89, 100}, + {112, 126, 141, 158, 178, 200, 224, 251}, + {282, 316, 355, 398, 447, 501, 562, 631}, + {708, 794, 891, 1000, 1122, 1259, 1413, 1585}, + {1778, 1995, 2239, 2512, 2818, 3162, 3548, 3981}, + {4467, 5012, 5623, 6310, 7079, 7943, 8913, 10000}, + {11220, 12589, 14125, 15849, 17783, 19953, 22387, 25119}, + {28184, 31623, 35481, 39811, 44668, 50119, 56234, 65535}, +}; + +/* ************************************************************ + * Local Function predefine. + * *************************************************************/ + +/* START------------COMMON INFO RELATED--------------- */ + +static void odm_update_power_training_state(struct phy_dm_struct *dm); + +/* ************************************************************ + * 3 Export Interface + * *************************************************************/ + +/*Y = 10*log(X)*/ +s32 odm_pwdb_conversion(s32 X, u32 total_bit, u32 decimal_bit) +{ + s32 Y, integer = 0, decimal = 0; + u32 i; + + if (X == 0) + X = 1; /* log2(x), x can't be 0 */ + + for (i = (total_bit - 1); i > 0; i--) { + if (X & BIT(i)) { + integer = i; + if (i > 0) { + /* decimal is 0.5dB*3=1.5dB~=2dB */ + decimal = (X & BIT(i - 1)) ? 2 : 0; + } + break; + } + } + + Y = 3 * (integer - decimal_bit) + decimal; /* 10*log(x)=3*log2(x), */ + + return Y; +} + +s32 odm_sign_conversion(s32 value, u32 total_bit) +{ + if (value & BIT(total_bit - 1)) + value -= BIT(total_bit); + return value; +} + +void phydm_seq_sorting(void *dm_void, u32 *value, u32 *rank_idx, u32 *idx_out, + u8 seq_length) +{ + u8 i = 0, j = 0; + u32 tmp_a, tmp_b; + u32 tmp_idx_a, tmp_idx_b; + + for (i = 0; i < seq_length; i++) { + rank_idx[i] = i; + /**/ + } + + for (i = 0; i < (seq_length - 1); i++) { + for (j = 0; j < (seq_length - 1 - i); j++) { + tmp_a = value[j]; + tmp_b = value[j + 1]; + + tmp_idx_a = rank_idx[j]; + tmp_idx_b = rank_idx[j + 1]; + + if (tmp_a < tmp_b) { + value[j] = tmp_b; + value[j + 1] = tmp_a; + + rank_idx[j] = tmp_idx_b; + rank_idx[j + 1] = tmp_idx_a; + } + } + } + + for (i = 0; i < seq_length; i++) { + idx_out[rank_idx[i]] = i + 1; + /**/ + } +} + +void odm_init_mp_driver_status(struct phy_dm_struct *dm) +{ + dm->mp_mode = false; +} + +static void odm_update_mp_driver_status(struct phy_dm_struct *dm) +{ + /* Do nothing. */ +} + +static void phydm_init_trx_antenna_setting(struct phy_dm_struct *dm) +{ + /*#if (RTL8814A_SUPPORT == 1)*/ + + if (dm->support_ic_type & (ODM_RTL8814A)) { + u8 rx_ant = 0, tx_ant = 0; + + rx_ant = (u8)odm_get_bb_reg(dm, ODM_REG(BB_RX_PATH, dm), + ODM_BIT(BB_RX_PATH, dm)); + tx_ant = (u8)odm_get_bb_reg(dm, ODM_REG(BB_TX_PATH, dm), + ODM_BIT(BB_TX_PATH, dm)); + dm->tx_ant_status = (tx_ant & 0xf); + dm->rx_ant_status = (rx_ant & 0xf); + } else if (dm->support_ic_type & (ODM_RTL8723D | ODM_RTL8821C | + ODM_RTL8710B)) { /* JJ ADD 20161014 */ + dm->tx_ant_status = 0x1; + dm->rx_ant_status = 0x1; + } + /*#endif*/ +} + +static void phydm_traffic_load_decision(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + + /*---TP & Trafic-load calculation---*/ + + if (dm->last_tx_ok_cnt > *dm->num_tx_bytes_unicast) + dm->last_tx_ok_cnt = *dm->num_tx_bytes_unicast; + + if (dm->last_rx_ok_cnt > *dm->num_rx_bytes_unicast) + dm->last_rx_ok_cnt = *dm->num_rx_bytes_unicast; + + dm->cur_tx_ok_cnt = *dm->num_tx_bytes_unicast - dm->last_tx_ok_cnt; + dm->cur_rx_ok_cnt = *dm->num_rx_bytes_unicast - dm->last_rx_ok_cnt; + dm->last_tx_ok_cnt = *dm->num_tx_bytes_unicast; + dm->last_rx_ok_cnt = *dm->num_rx_bytes_unicast; + + dm->tx_tp = ((dm->tx_tp) >> 1) + + (u32)(((dm->cur_tx_ok_cnt) >> 18) >> + 1); /* <<3(8bit), >>20(10^6,M), >>1(2sec)*/ + dm->rx_tp = ((dm->rx_tp) >> 1) + + (u32)(((dm->cur_rx_ok_cnt) >> 18) >> + 1); /* <<3(8bit), >>20(10^6,M), >>1(2sec)*/ + dm->total_tp = dm->tx_tp + dm->rx_tp; + + dm->pre_traffic_load = dm->traffic_load; + + if (dm->cur_tx_ok_cnt > 1875000 || + dm->cur_rx_ok_cnt > + 1875000) { /* ( 1.875M * 8bit ) / 2sec= 7.5M bits /sec )*/ + + dm->traffic_load = TRAFFIC_HIGH; + /**/ + } else if ( + dm->cur_tx_ok_cnt > 500000 || + dm->cur_rx_ok_cnt > + 500000) { /*( 0.5M * 8bit ) / 2sec = 2M bits /sec )*/ + + dm->traffic_load = TRAFFIC_MID; + /**/ + } else if ( + dm->cur_tx_ok_cnt > 100000 || + dm->cur_rx_ok_cnt > + 100000) { /*( 0.1M * 8bit ) / 2sec = 0.4M bits /sec )*/ + + dm->traffic_load = TRAFFIC_LOW; + /**/ + } else { + dm->traffic_load = TRAFFIC_ULTRA_LOW; + /**/ + } +} + +static void phydm_config_ofdm_tx_path(struct phy_dm_struct *dm, u32 path) {} + +void phydm_config_ofdm_rx_path(struct phy_dm_struct *dm, u32 path) +{ + u8 ofdm_rx_path = 0; + + if (dm->support_ic_type & (ODM_RTL8192E)) { + } else if (dm->support_ic_type & (ODM_RTL8812 | ODM_RTL8822B)) { + if (path == PHYDM_A) { + ofdm_rx_path = 1; + /**/ + } else if (path == PHYDM_B) { + ofdm_rx_path = 2; + /**/ + } else if (path == PHYDM_AB) { + ofdm_rx_path = 3; + /**/ + } + + odm_set_bb_reg(dm, 0x808, MASKBYTE0, + ((ofdm_rx_path << 4) | ofdm_rx_path)); + } +} + +static void phydm_config_cck_rx_antenna_init(struct phy_dm_struct *dm) {} + +static void phydm_config_cck_rx_path(struct phy_dm_struct *dm, u8 path, + u8 path_div_en) +{ +} + +void phydm_config_trx_path(void *dm_void, u32 *const dm_value, u32 *_used, + char *output, u32 *_out_len) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + u32 used = *_used; + u32 out_len = *_out_len; + + /* CCK */ + if (dm_value[0] == 0) { + if (dm_value[1] == 1) { /*TX*/ + if (dm_value[2] == 1) + odm_set_bb_reg(dm, 0xa04, 0xf0000000, 0x8); + else if (dm_value[2] == 2) + odm_set_bb_reg(dm, 0xa04, 0xf0000000, 0x4); + else if (dm_value[2] == 3) + odm_set_bb_reg(dm, 0xa04, 0xf0000000, 0xc); + } else if (dm_value[1] == 2) { /*RX*/ + + phydm_config_cck_rx_antenna_init(dm); + + if (dm_value[2] == 1) + phydm_config_cck_rx_path(dm, PHYDM_A, + CCA_PATHDIV_DISABLE); + else if (dm_value[2] == 2) + phydm_config_cck_rx_path(dm, PHYDM_B, + CCA_PATHDIV_DISABLE); + else if (dm_value[2] == 3 && + dm_value[3] == 1) /*enable path diversity*/ + phydm_config_cck_rx_path(dm, PHYDM_AB, + CCA_PATHDIV_ENABLE); + else if (dm_value[2] == 3 && dm_value[3] != 1) + phydm_config_cck_rx_path(dm, PHYDM_B, + CCA_PATHDIV_DISABLE); + } + } + /* OFDM */ + else if (dm_value[0] == 1) { + if (dm_value[1] == 1) { /*TX*/ + phydm_config_ofdm_tx_path(dm, dm_value[2]); + /**/ + } else if (dm_value[1] == 2) { /*RX*/ + phydm_config_ofdm_rx_path(dm, dm_value[2]); + /**/ + } + } + + PHYDM_SNPRINTF( + output + used, out_len - used, + "PHYDM Set path [%s] [%s] = [%s%s%s%s]\n", + (dm_value[0] == 1) ? "OFDM" : "CCK", + (dm_value[1] == 1) ? "TX" : "RX", + (dm_value[2] & 0x1) ? "A" : "", (dm_value[2] & 0x2) ? "B" : "", + (dm_value[2] & 0x4) ? "C" : "", (dm_value[2] & 0x8) ? "D" : ""); +} + +static void phydm_init_cck_setting(struct phy_dm_struct *dm) +{ + dm->is_cck_high_power = (bool)odm_get_bb_reg( + dm, ODM_REG(CCK_RPT_FORMAT, dm), ODM_BIT(CCK_RPT_FORMAT, dm)); + + /* JJ ADD 20161014 */ + /* JJ ADD 20161014 */ + if (dm->support_ic_type & (ODM_RTL8723D | ODM_RTL8822B | ODM_RTL8197F | + ODM_RTL8821C | ODM_RTL8710B)) + dm->cck_new_agc = odm_get_bb_reg(dm, 0xa9c, BIT(17)) ? + true : + false; /*1: new agc 0: old agc*/ + else + dm->cck_new_agc = false; +} + +static void phydm_init_soft_ml_setting(struct phy_dm_struct *dm) +{ + if (!dm->mp_mode) { + if (dm->support_ic_type & ODM_RTL8822B) + odm_set_bb_reg(dm, 0x19a8, MASKDWORD, 0xc10a0000); + } +} + +static void phydm_init_hw_info_by_rfe(struct phy_dm_struct *dm) +{ + if (dm->support_ic_type & ODM_RTL8822B) + phydm_init_hw_info_by_rfe_type_8822b(dm); +} + +static void odm_common_info_self_init(struct phy_dm_struct *dm) +{ + phydm_init_cck_setting(dm); + dm->rf_path_rx_enable = (u8)odm_get_bb_reg(dm, ODM_REG(BB_RX_PATH, dm), + ODM_BIT(BB_RX_PATH, dm)); + odm_init_mp_driver_status(dm); + phydm_init_trx_antenna_setting(dm); + phydm_init_soft_ml_setting(dm); + + dm->phydm_period = PHYDM_WATCH_DOG_PERIOD; + dm->phydm_sys_up_time = 0; + + if (dm->support_ic_type & ODM_IC_1SS) + dm->num_rf_path = 1; + else if (dm->support_ic_type & ODM_IC_2SS) + dm->num_rf_path = 2; + else if (dm->support_ic_type & ODM_IC_3SS) + dm->num_rf_path = 3; + else if (dm->support_ic_type & ODM_IC_4SS) + dm->num_rf_path = 4; + + dm->tx_rate = 0xFF; + + dm->number_linked_client = 0; + dm->pre_number_linked_client = 0; + dm->number_active_client = 0; + dm->pre_number_active_client = 0; + + dm->last_tx_ok_cnt = 0; + dm->last_rx_ok_cnt = 0; + dm->tx_tp = 0; + dm->rx_tp = 0; + dm->total_tp = 0; + dm->traffic_load = TRAFFIC_LOW; + + dm->nbi_set_result = 0; + dm->is_init_hw_info_by_rfe = false; + dm->pre_dbg_priority = BB_DBGPORT_RELEASE; +} + +static void odm_common_info_self_update(struct phy_dm_struct *dm) +{ + u8 entry_cnt = 0, num_active_client = 0; + u32 i, one_entry_macid = 0; + struct rtl_sta_info *entry; + + /* THis variable cannot be used because it is wrong*/ + if (*dm->band_width == ODM_BW40M) { + if (*dm->sec_ch_offset == 1) + dm->control_channel = *dm->channel - 2; + else if (*dm->sec_ch_offset == 2) + dm->control_channel = *dm->channel + 2; + } else { + dm->control_channel = *dm->channel; + } + + for (i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++) { + entry = dm->odm_sta_info[i]; + if (IS_STA_VALID(entry)) { + entry_cnt++; + if (entry_cnt == 1) + one_entry_macid = i; + } + } + + if (entry_cnt == 1) { + dm->is_one_entry_only = true; + dm->one_entry_macid = one_entry_macid; + } else { + dm->is_one_entry_only = false; + } + + dm->pre_number_linked_client = dm->number_linked_client; + dm->pre_number_active_client = dm->number_active_client; + + dm->number_linked_client = entry_cnt; + dm->number_active_client = num_active_client; + + /* Update MP driver status*/ + odm_update_mp_driver_status(dm); + + /*Traffic load information update*/ + phydm_traffic_load_decision(dm); + + dm->phydm_sys_up_time += dm->phydm_period; +} + +static void odm_common_info_self_reset(struct phy_dm_struct *dm) +{ + dm->phy_dbg_info.num_qry_beacon_pkt = 0; +} + +void *phydm_get_structure(struct phy_dm_struct *dm, u8 structure_type) + +{ + void *p_struct = NULL; + + switch (structure_type) { + case PHYDM_FALSEALMCNT: + p_struct = &dm->false_alm_cnt; + break; + + case PHYDM_CFOTRACK: + p_struct = &dm->dm_cfo_track; + break; + + case PHYDM_ADAPTIVITY: + p_struct = &dm->adaptivity; + break; + + default: + break; + } + + return p_struct; +} + +static void odm_hw_setting(struct phy_dm_struct *dm) +{ + if (dm->support_ic_type & ODM_RTL8822B) + phydm_hwsetting_8822b(dm); +} + +static void phydm_supportability_init(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + u32 support_ability = 0; + + if (dm->support_ic_type != ODM_RTL8821C) + return; + + switch (dm->support_ic_type) { + /*---------------AC Series-------------------*/ + + case ODM_RTL8822B: + support_ability |= ODM_BB_DIG | ODM_BB_FA_CNT | ODM_BB_CCK_PD | + ODM_BB_CFO_TRACKING | ODM_BB_RATE_ADAPTIVE | + ODM_BB_RSSI_MONITOR | ODM_BB_RA_MASK | + ODM_RF_TX_PWR_TRACK; + break; + + default: + support_ability |= ODM_BB_DIG | ODM_BB_FA_CNT | ODM_BB_CCK_PD | + ODM_BB_CFO_TRACKING | ODM_BB_RATE_ADAPTIVE | + ODM_BB_RSSI_MONITOR | ODM_BB_RA_MASK | + ODM_RF_TX_PWR_TRACK; + + ODM_RT_TRACE(dm, ODM_COMP_UNCOND, + "[Warning] Supportability Init Warning !!!\n"); + break; + } + + if (*dm->enable_antdiv) + support_ability |= ODM_BB_ANT_DIV; + + if (*dm->enable_adaptivity) { + ODM_RT_TRACE(dm, ODM_COMP_INIT, + "ODM adaptivity is set to Enabled!!!\n"); + + support_ability |= ODM_BB_ADAPTIVITY; + + } else { + ODM_RT_TRACE(dm, ODM_COMP_INIT, + "ODM adaptivity is set to disnabled!!!\n"); + /**/ + } + + ODM_RT_TRACE(dm, ODM_COMP_INIT, "PHYDM support_ability = ((0x%x))\n", + support_ability); + odm_cmn_info_init(dm, ODM_CMNINFO_ABILITY, support_ability); +} + +/* + * 2011/09/21 MH Add to describe different team necessary resource allocate?? + */ +void odm_dm_init(struct phy_dm_struct *dm) +{ + phydm_supportability_init(dm); + odm_common_info_self_init(dm); + odm_dig_init(dm); + phydm_nhm_counter_statistics_init(dm); + phydm_adaptivity_init(dm); + phydm_ra_info_init(dm); + odm_rate_adaptive_mask_init(dm); + odm_cfo_tracking_init(dm); + odm_edca_turbo_init(dm); + odm_rssi_monitor_init(dm); + phydm_rf_init(dm); + odm_txpowertracking_init(dm); + + if (dm->support_ic_type & ODM_RTL8822B) + phydm_txcurrentcalibration(dm); + + odm_antenna_diversity_init(dm); + odm_auto_channel_select_init(dm); + odm_dynamic_tx_power_init(dm); + phydm_init_ra_info(dm); + adc_smp_init(dm); + + phydm_beamforming_init(dm); + + if (dm->support_ic_type & ODM_IC_11N_SERIES) { + /* 11n series */ + odm_dynamic_bb_power_saving_init(dm); + } + + phydm_psd_init(dm); +} + +void odm_dm_reset(struct phy_dm_struct *dm) +{ + struct dig_thres *dig_tab = &dm->dm_dig_table; + + odm_ant_div_reset(dm); + phydm_set_edcca_threshold_api(dm, dig_tab->cur_ig_value); +} + +void phydm_support_ability_debug(void *dm_void, u32 *const dm_value, u32 *_used, + char *output, u32 *_out_len) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + u32 pre_support_ability; + u32 used = *_used; + u32 out_len = *_out_len; + + pre_support_ability = dm->support_ability; + PHYDM_SNPRINTF(output + used, out_len - used, "\n%s\n", + "================================"); + if (dm_value[0] == 100) { + PHYDM_SNPRINTF(output + used, out_len - used, + "[Supportability] PhyDM Selection\n"); + PHYDM_SNPRINTF(output + used, out_len - used, "%s\n", + "================================"); + PHYDM_SNPRINTF( + output + used, out_len - used, "00. (( %s ))DIG\n", + ((dm->support_ability & ODM_BB_DIG) ? ("V") : ("."))); + PHYDM_SNPRINTF( + output + used, out_len - used, "01. (( %s ))RA_MASK\n", + ((dm->support_ability & ODM_BB_RA_MASK) ? ("V") : + ("."))); + PHYDM_SNPRINTF(output + used, out_len - used, + "02. (( %s ))DYNAMIC_TXPWR\n", + ((dm->support_ability & ODM_BB_DYNAMIC_TXPWR) ? + ("V") : + ("."))); + PHYDM_SNPRINTF(output + used, out_len - used, + "03. (( %s ))FA_CNT\n", + ((dm->support_ability & ODM_BB_FA_CNT) ? ("V") : + ("."))); + PHYDM_SNPRINTF(output + used, out_len - used, + "04. (( %s ))RSSI_MONITOR\n", + ((dm->support_ability & ODM_BB_RSSI_MONITOR) ? + ("V") : + ("."))); + PHYDM_SNPRINTF(output + used, out_len - used, + "05. (( %s ))CCK_PD\n", + ((dm->support_ability & ODM_BB_CCK_PD) ? ("V") : + ("."))); + PHYDM_SNPRINTF( + output + used, out_len - used, "06. (( %s ))ANT_DIV\n", + ((dm->support_ability & ODM_BB_ANT_DIV) ? ("V") : + ("."))); + PHYDM_SNPRINTF(output + used, out_len - used, + "08. (( %s ))PWR_TRAIN\n", + ((dm->support_ability & ODM_BB_PWR_TRAIN) ? + ("V") : + ("."))); + PHYDM_SNPRINTF(output + used, out_len - used, + "09. (( %s ))RATE_ADAPTIVE\n", + ((dm->support_ability & ODM_BB_RATE_ADAPTIVE) ? + ("V") : + ("."))); + PHYDM_SNPRINTF( + output + used, out_len - used, "10. (( %s ))PATH_DIV\n", + ((dm->support_ability & ODM_BB_PATH_DIV) ? ("V") : + ("."))); + PHYDM_SNPRINTF(output + used, out_len - used, + "13. (( %s ))ADAPTIVITY\n", + ((dm->support_ability & ODM_BB_ADAPTIVITY) ? + ("V") : + ("."))); + PHYDM_SNPRINTF(output + used, out_len - used, + "14. (( %s ))struct cfo_tracking\n", + ((dm->support_ability & ODM_BB_CFO_TRACKING) ? + ("V") : + ("."))); + PHYDM_SNPRINTF( + output + used, out_len - used, "15. (( %s ))NHM_CNT\n", + ((dm->support_ability & ODM_BB_NHM_CNT) ? ("V") : + ("."))); + PHYDM_SNPRINTF(output + used, out_len - used, + "16. (( %s ))PRIMARY_CCA\n", + ((dm->support_ability & ODM_BB_PRIMARY_CCA) ? + ("V") : + ("."))); + PHYDM_SNPRINTF( + output + used, out_len - used, "17. (( %s ))TXBF\n", + ((dm->support_ability & ODM_BB_TXBF) ? ("V") : ("."))); + PHYDM_SNPRINTF(output + used, out_len - used, + "18. (( %s ))DYNAMIC_ARFR\n", + ((dm->support_ability & ODM_BB_DYNAMIC_ARFR) ? + ("V") : + ("."))); + PHYDM_SNPRINTF(output + used, out_len - used, + "20. (( %s ))EDCA_TURBO\n", + ((dm->support_ability & ODM_MAC_EDCA_TURBO) ? + ("V") : + ("."))); + PHYDM_SNPRINTF(output + used, out_len - used, + "21. (( %s ))DYNAMIC_RX_PATH\n", + ((dm->support_ability & ODM_BB_DYNAMIC_RX_PATH) ? + ("V") : + ("."))); + PHYDM_SNPRINTF(output + used, out_len - used, + "24. (( %s ))TX_PWR_TRACK\n", + ((dm->support_ability & ODM_RF_TX_PWR_TRACK) ? + ("V") : + ("."))); + PHYDM_SNPRINTF(output + used, out_len - used, + "25. (( %s ))RX_GAIN_TRACK\n", + ((dm->support_ability & ODM_RF_RX_GAIN_TRACK) ? + ("V") : + ("."))); + PHYDM_SNPRINTF(output + used, out_len - used, + "26. (( %s ))RF_CALIBRATION\n", + ((dm->support_ability & ODM_RF_CALIBRATION) ? + ("V") : + ("."))); + PHYDM_SNPRINTF(output + used, out_len - used, "%s\n", + "================================"); + } else { + if (dm_value[1] == 1) { /* enable */ + dm->support_ability |= BIT(dm_value[0]); + } else if (dm_value[1] == 2) /* disable */ + dm->support_ability &= ~(BIT(dm_value[0])); + else { + PHYDM_SNPRINTF(output + used, out_len - used, "%s\n", + "[Warning!!!] 1:enable, 2:disable"); + } + } + PHYDM_SNPRINTF(output + used, out_len - used, + "pre-support_ability = 0x%x\n", pre_support_ability); + PHYDM_SNPRINTF(output + used, out_len - used, + "Curr-support_ability = 0x%x\n", dm->support_ability); + PHYDM_SNPRINTF(output + used, out_len - used, "%s\n", + "================================"); +} + +void phydm_watchdog_mp(struct phy_dm_struct *dm) {} +/* + * 2011/09/20 MH This is the entry pointer for all team to execute HW outsrc DM. + * You can not add any dummy function here, be care, you can only use DM struct + * to perform any new ODM_DM. + */ +void odm_dm_watchdog(struct phy_dm_struct *dm) +{ + odm_common_info_self_update(dm); + phydm_basic_dbg_message(dm); + odm_hw_setting(dm); + + odm_false_alarm_counter_statistics(dm); + phydm_noisy_detection(dm); + + odm_rssi_monitor_check(dm); + + if (*dm->is_power_saving) { + odm_dig_by_rssi_lps(dm); + phydm_adaptivity(dm); + odm_antenna_diversity( + dm); /*enable AntDiv in PS mode, request from SD4 Jeff*/ + ODM_RT_TRACE(dm, ODM_COMP_COMMON, + "DMWatchdog in power saving mode\n"); + return; + } + + phydm_check_adaptivity(dm); + odm_update_power_training_state(dm); + odm_DIG(dm); + phydm_adaptivity(dm); + odm_cck_packet_detection_thresh(dm); + + phydm_ra_info_watchdog(dm); + odm_edca_turbo_check(dm); + odm_cfo_tracking(dm); + odm_dynamic_tx_power(dm); + odm_antenna_diversity(dm); + + phydm_beamforming_watchdog(dm); + + phydm_rf_watchdog(dm); + + odm_dtc(dm); + + odm_common_info_self_reset(dm); +} + +/* + * Init /.. Fixed HW value. Only init time. + */ +void odm_cmn_info_init(struct phy_dm_struct *dm, enum odm_cmninfo cmn_info, + u32 value) +{ + /* This section is used for init value */ + switch (cmn_info) { + /* Fixed ODM value. */ + case ODM_CMNINFO_ABILITY: + dm->support_ability = (u32)value; + break; + + case ODM_CMNINFO_RF_TYPE: + dm->rf_type = (u8)value; + break; + + case ODM_CMNINFO_PLATFORM: + dm->support_platform = (u8)value; + break; + + case ODM_CMNINFO_INTERFACE: + dm->support_interface = (u8)value; + break; + + case ODM_CMNINFO_MP_TEST_CHIP: + dm->is_mp_chip = (u8)value; + break; + + case ODM_CMNINFO_IC_TYPE: + dm->support_ic_type = value; + break; + + case ODM_CMNINFO_CUT_VER: + dm->cut_version = (u8)value; + break; + + case ODM_CMNINFO_FAB_VER: + dm->fab_version = (u8)value; + break; + + case ODM_CMNINFO_RFE_TYPE: + dm->rfe_type = (u8)value; + phydm_init_hw_info_by_rfe(dm); + break; + + case ODM_CMNINFO_RF_ANTENNA_TYPE: + dm->ant_div_type = (u8)value; + break; + + case ODM_CMNINFO_WITH_EXT_ANTENNA_SWITCH: + dm->with_extenal_ant_switch = (u8)value; + break; + + case ODM_CMNINFO_BE_FIX_TX_ANT: + dm->dm_fat_table.b_fix_tx_ant = (u8)value; + break; + + case ODM_CMNINFO_BOARD_TYPE: + if (!dm->is_init_hw_info_by_rfe) + dm->board_type = (u8)value; + break; + + case ODM_CMNINFO_PACKAGE_TYPE: + if (!dm->is_init_hw_info_by_rfe) + dm->package_type = (u8)value; + break; + + case ODM_CMNINFO_EXT_LNA: + if (!dm->is_init_hw_info_by_rfe) + dm->ext_lna = (u8)value; + break; + + case ODM_CMNINFO_5G_EXT_LNA: + if (!dm->is_init_hw_info_by_rfe) + dm->ext_lna_5g = (u8)value; + break; + + case ODM_CMNINFO_EXT_PA: + if (!dm->is_init_hw_info_by_rfe) + dm->ext_pa = (u8)value; + break; + + case ODM_CMNINFO_5G_EXT_PA: + if (!dm->is_init_hw_info_by_rfe) + dm->ext_pa_5g = (u8)value; + break; + + case ODM_CMNINFO_GPA: + if (!dm->is_init_hw_info_by_rfe) + dm->type_gpa = (u16)value; + break; + + case ODM_CMNINFO_APA: + if (!dm->is_init_hw_info_by_rfe) + dm->type_apa = (u16)value; + break; + + case ODM_CMNINFO_GLNA: + if (!dm->is_init_hw_info_by_rfe) + dm->type_glna = (u16)value; + break; + + case ODM_CMNINFO_ALNA: + if (!dm->is_init_hw_info_by_rfe) + dm->type_alna = (u16)value; + break; + + case ODM_CMNINFO_EXT_TRSW: + if (!dm->is_init_hw_info_by_rfe) + dm->ext_trsw = (u8)value; + break; + case ODM_CMNINFO_EXT_LNA_GAIN: + dm->ext_lna_gain = (u8)value; + break; + case ODM_CMNINFO_PATCH_ID: + dm->patch_id = (u8)value; + break; + case ODM_CMNINFO_BINHCT_TEST: + dm->is_in_hct_test = (bool)value; + break; + case ODM_CMNINFO_BWIFI_TEST: + dm->wifi_test = (u8)value; + break; + case ODM_CMNINFO_SMART_CONCURRENT: + dm->is_dual_mac_smart_concurrent = (bool)value; + break; + case ODM_CMNINFO_DOMAIN_CODE_2G: + dm->odm_regulation_2_4g = (u8)value; + break; + case ODM_CMNINFO_DOMAIN_CODE_5G: + dm->odm_regulation_5g = (u8)value; + break; + case ODM_CMNINFO_CONFIG_BB_RF: + dm->config_bbrf = (bool)value; + break; + case ODM_CMNINFO_IQKFWOFFLOAD: + dm->iqk_fw_offload = (u8)value; + break; + case ODM_CMNINFO_IQKPAOFF: + dm->rf_calibrate_info.is_iqk_pa_off = (bool)value; + break; + case ODM_CMNINFO_REGRFKFREEENABLE: + dm->rf_calibrate_info.reg_rf_kfree_enable = (u8)value; + break; + case ODM_CMNINFO_RFKFREEENABLE: + dm->rf_calibrate_info.rf_kfree_enable = (u8)value; + break; + case ODM_CMNINFO_NORMAL_RX_PATH_CHANGE: + dm->normal_rx_path = (u8)value; + break; + case ODM_CMNINFO_EFUSE0X3D8: + dm->efuse0x3d8 = (u8)value; + break; + case ODM_CMNINFO_EFUSE0X3D7: + dm->efuse0x3d7 = (u8)value; + break; + /* To remove the compiler warning, must add an empty default statement + * to handle the other values. + */ + default: + /* do nothing */ + break; + } +} + +void odm_cmn_info_hook(struct phy_dm_struct *dm, enum odm_cmninfo cmn_info, + void *value) +{ + /* */ + /* Hook call by reference pointer. */ + /* */ + switch (cmn_info) { + /* */ + /* Dynamic call by reference pointer. */ + /* */ + case ODM_CMNINFO_MAC_PHY_MODE: + dm->mac_phy_mode = (u8 *)value; + break; + + case ODM_CMNINFO_TX_UNI: + dm->num_tx_bytes_unicast = (u64 *)value; + break; + + case ODM_CMNINFO_RX_UNI: + dm->num_rx_bytes_unicast = (u64 *)value; + break; + + case ODM_CMNINFO_WM_MODE: + dm->wireless_mode = (u8 *)value; + break; + + case ODM_CMNINFO_BAND: + dm->band_type = (u8 *)value; + break; + + case ODM_CMNINFO_SEC_CHNL_OFFSET: + dm->sec_ch_offset = (u8 *)value; + break; + + case ODM_CMNINFO_SEC_MODE: + dm->security = (u8 *)value; + break; + + case ODM_CMNINFO_BW: + dm->band_width = (u8 *)value; + break; + + case ODM_CMNINFO_CHNL: + dm->channel = (u8 *)value; + break; + + case ODM_CMNINFO_DMSP_GET_VALUE: + dm->is_get_value_from_other_mac = (bool *)value; + break; + + case ODM_CMNINFO_BUDDY_ADAPTOR: + dm->buddy_adapter = (void **)value; + break; + + case ODM_CMNINFO_DMSP_IS_MASTER: + dm->is_master_of_dmsp = (bool *)value; + break; + + case ODM_CMNINFO_SCAN: + dm->is_scan_in_process = (bool *)value; + break; + + case ODM_CMNINFO_POWER_SAVING: + dm->is_power_saving = (bool *)value; + break; + + case ODM_CMNINFO_ONE_PATH_CCA: + dm->one_path_cca = (u8 *)value; + break; + + case ODM_CMNINFO_DRV_STOP: + dm->is_driver_stopped = (bool *)value; + break; + + case ODM_CMNINFO_PNP_IN: + dm->is_driver_is_going_to_pnp_set_power_sleep = (bool *)value; + break; + + case ODM_CMNINFO_INIT_ON: + dm->pinit_adpt_in_progress = (bool *)value; + break; + + case ODM_CMNINFO_ANT_TEST: + dm->antenna_test = (u8 *)value; + break; + + case ODM_CMNINFO_NET_CLOSED: + dm->is_net_closed = (bool *)value; + break; + + case ODM_CMNINFO_FORCED_RATE: + dm->forced_data_rate = (u16 *)value; + break; + case ODM_CMNINFO_ANT_DIV: + dm->enable_antdiv = (u8 *)value; + break; + case ODM_CMNINFO_ADAPTIVITY: + dm->enable_adaptivity = (u8 *)value; + break; + case ODM_CMNINFO_FORCED_IGI_LB: + dm->pu1_forced_igi_lb = (u8 *)value; + break; + + case ODM_CMNINFO_P2P_LINK: + dm->dm_dig_table.is_p2p_in_process = (u8 *)value; + break; + + case ODM_CMNINFO_IS1ANTENNA: + dm->is_1_antenna = (bool *)value; + break; + + case ODM_CMNINFO_RFDEFAULTPATH: + dm->rf_default_path = (u8 *)value; + break; + + case ODM_CMNINFO_FCS_MODE: + dm->is_fcs_mode_enable = (bool *)value; + break; + /*add by YuChen for beamforming PhyDM*/ + case ODM_CMNINFO_HUBUSBMODE: + dm->hub_usb_mode = (u8 *)value; + break; + case ODM_CMNINFO_FWDWRSVDPAGEINPROGRESS: + dm->is_fw_dw_rsvd_page_in_progress = (bool *)value; + break; + case ODM_CMNINFO_TX_TP: + dm->current_tx_tp = (u32 *)value; + break; + case ODM_CMNINFO_RX_TP: + dm->current_rx_tp = (u32 *)value; + break; + case ODM_CMNINFO_SOUNDING_SEQ: + dm->sounding_seq = (u8 *)value; + break; + case ODM_CMNINFO_FORCE_TX_ANT_BY_TXDESC: + dm->dm_fat_table.p_force_tx_ant_by_desc = (u8 *)value; + break; + case ODM_CMNINFO_SET_S0S1_DEFAULT_ANTENNA: + dm->dm_fat_table.p_default_s0_s1 = (u8 *)value; + break; + + default: + /*do nothing*/ + break; + } +} + +void odm_cmn_info_ptr_array_hook(struct phy_dm_struct *dm, + enum odm_cmninfo cmn_info, u16 index, + void *value) +{ + /*Hook call by reference pointer.*/ + switch (cmn_info) { + /*Dynamic call by reference pointer. */ + case ODM_CMNINFO_STA_STATUS: + dm->odm_sta_info[index] = (struct rtl_sta_info *)value; + + if (IS_STA_VALID(dm->odm_sta_info[index])) + dm->platform2phydm_macid_table[index] = index; + + break; + /* To remove the compiler warning, must add an empty default statement + * to handle the other values. + */ + default: + /* do nothing */ + break; + } +} + +/* + * Update band/CHannel/.. The values are dynamic but non-per-packet. + */ +void odm_cmn_info_update(struct phy_dm_struct *dm, u32 cmn_info, u64 value) +{ + /* This init variable may be changed in run time. */ + switch (cmn_info) { + case ODM_CMNINFO_LINK_IN_PROGRESS: + dm->is_link_in_process = (bool)value; + break; + + case ODM_CMNINFO_ABILITY: + dm->support_ability = (u32)value; + break; + + case ODM_CMNINFO_RF_TYPE: + dm->rf_type = (u8)value; + break; + + case ODM_CMNINFO_WIFI_DIRECT: + dm->is_wifi_direct = (bool)value; + break; + + case ODM_CMNINFO_WIFI_DISPLAY: + dm->is_wifi_display = (bool)value; + break; + + case ODM_CMNINFO_LINK: + dm->is_linked = (bool)value; + break; + + case ODM_CMNINFO_CMW500LINK: + dm->is_linkedcmw500 = (bool)value; + break; + + case ODM_CMNINFO_LPSPG: + dm->is_in_lps_pg = (bool)value; + break; + + case ODM_CMNINFO_STATION_STATE: + dm->bsta_state = (bool)value; + break; + + case ODM_CMNINFO_RSSI_MIN: + dm->rssi_min = (u8)value; + break; + + case ODM_CMNINFO_DBG_COMP: + dm->debug_components = (u32)value; + break; + + case ODM_CMNINFO_DBG_LEVEL: + dm->debug_level = (u32)value; + break; + case ODM_CMNINFO_RA_THRESHOLD_HIGH: + dm->rate_adaptive.high_rssi_thresh = (u8)value; + break; + + case ODM_CMNINFO_RA_THRESHOLD_LOW: + dm->rate_adaptive.low_rssi_thresh = (u8)value; + break; + /* The following is for BT HS mode and BT coexist mechanism. */ + case ODM_CMNINFO_BT_ENABLED: + dm->is_bt_enabled = (bool)value; + break; + + case ODM_CMNINFO_BT_HS_CONNECT_PROCESS: + dm->is_bt_connect_process = (bool)value; + break; + + case ODM_CMNINFO_BT_HS_RSSI: + dm->bt_hs_rssi = (u8)value; + break; + + case ODM_CMNINFO_BT_OPERATION: + dm->is_bt_hs_operation = (bool)value; + break; + + case ODM_CMNINFO_BT_LIMITED_DIG: + dm->is_bt_limited_dig = (bool)value; + break; + + case ODM_CMNINFO_BT_DIG: + dm->bt_hs_dig_val = (u8)value; + break; + + case ODM_CMNINFO_BT_BUSY: + dm->is_bt_busy = (bool)value; + break; + + case ODM_CMNINFO_BT_DISABLE_EDCA: + dm->is_bt_disable_edca_turbo = (bool)value; + break; + + case ODM_CMNINFO_AP_TOTAL_NUM: + dm->ap_total_num = (u8)value; + break; + + case ODM_CMNINFO_POWER_TRAINING: + dm->is_disable_power_training = (bool)value; + break; + + default: + /* do nothing */ + break; + } +} + +u32 phydm_cmn_info_query(struct phy_dm_struct *dm, + enum phydm_info_query info_type) +{ + struct false_alarm_stat *false_alm_cnt = + (struct false_alarm_stat *)phydm_get_structure( + dm, PHYDM_FALSEALMCNT); + + switch (info_type) { + case PHYDM_INFO_FA_OFDM: + return false_alm_cnt->cnt_ofdm_fail; + + case PHYDM_INFO_FA_CCK: + return false_alm_cnt->cnt_cck_fail; + + case PHYDM_INFO_FA_TOTAL: + return false_alm_cnt->cnt_all; + + case PHYDM_INFO_CCA_OFDM: + return false_alm_cnt->cnt_ofdm_cca; + + case PHYDM_INFO_CCA_CCK: + return false_alm_cnt->cnt_cck_cca; + + case PHYDM_INFO_CCA_ALL: + return false_alm_cnt->cnt_cca_all; + + case PHYDM_INFO_CRC32_OK_VHT: + return false_alm_cnt->cnt_vht_crc32_ok; + + case PHYDM_INFO_CRC32_OK_HT: + return false_alm_cnt->cnt_ht_crc32_ok; + + case PHYDM_INFO_CRC32_OK_LEGACY: + return false_alm_cnt->cnt_ofdm_crc32_ok; + + case PHYDM_INFO_CRC32_OK_CCK: + return false_alm_cnt->cnt_cck_crc32_ok; + + case PHYDM_INFO_CRC32_ERROR_VHT: + return false_alm_cnt->cnt_vht_crc32_error; + + case PHYDM_INFO_CRC32_ERROR_HT: + return false_alm_cnt->cnt_ht_crc32_error; + + case PHYDM_INFO_CRC32_ERROR_LEGACY: + return false_alm_cnt->cnt_ofdm_crc32_error; + + case PHYDM_INFO_CRC32_ERROR_CCK: + return false_alm_cnt->cnt_cck_crc32_error; + + case PHYDM_INFO_EDCCA_FLAG: + return false_alm_cnt->edcca_flag; + + case PHYDM_INFO_OFDM_ENABLE: + return false_alm_cnt->ofdm_block_enable; + + case PHYDM_INFO_CCK_ENABLE: + return false_alm_cnt->cck_block_enable; + + case PHYDM_INFO_DBG_PORT_0: + return false_alm_cnt->dbg_port0; + + default: + return 0xffffffff; + } +} + +void odm_init_all_timers(struct phy_dm_struct *dm) {} + +void odm_cancel_all_timers(struct phy_dm_struct *dm) {} + +void odm_release_all_timers(struct phy_dm_struct *dm) {} + +/* 3============================================================ + * 3 Tx Power Tracking + * 3============================================================ + */ + +/* need to ODM CE Platform + * move to here for ANT detection mechanism using + */ + +u32 odm_convert_to_db(u32 value) +{ + u8 i; + u8 j; + u32 dB; + + value = value & 0xFFFF; + + for (i = 0; i < 12; i++) { + if (value <= db_invert_table[i][7]) + break; + } + + if (i >= 12) + return 96; /* maximum 96 dB */ + + for (j = 0; j < 8; j++) { + if (value <= db_invert_table[i][j]) + break; + } + + dB = (i << 3) + j + 1; + + return dB; +} + +u32 odm_convert_to_linear(u32 value) +{ + u8 i; + u8 j; + u32 linear; + + /* 1dB~96dB */ + + value = value & 0xFF; + + i = (u8)((value - 1) >> 3); + j = (u8)(value - 1) - (i << 3); + + linear = db_invert_table[i][j]; + + return linear; +} + +/* + * ODM multi-port consideration, added by Roger, 2013.10.01. + */ +void odm_asoc_entry_init(struct phy_dm_struct *dm) {} + +/* Justin: According to the current RRSI to adjust Response Frame TX power */ +void odm_dtc(struct phy_dm_struct *dm) {} + +static void odm_update_power_training_state(struct phy_dm_struct *dm) +{ + struct false_alarm_stat *false_alm_cnt = + (struct false_alarm_stat *)phydm_get_structure( + dm, PHYDM_FALSEALMCNT); + struct dig_thres *dig_tab = &dm->dm_dig_table; + u32 score = 0; + + if (!(dm->support_ability & ODM_BB_PWR_TRAIN)) + return; + + ODM_RT_TRACE(dm, ODM_COMP_RA_MASK, "%s()============>\n", __func__); + dm->is_change_state = false; + + /* Debug command */ + if (dm->force_power_training_state) { + if (dm->force_power_training_state == 1 && + !dm->is_disable_power_training) { + dm->is_change_state = true; + dm->is_disable_power_training = true; + } else if (dm->force_power_training_state == 2 && + dm->is_disable_power_training) { + dm->is_change_state = true; + dm->is_disable_power_training = false; + } + + dm->PT_score = 0; + dm->phy_dbg_info.num_qry_phy_status_ofdm = 0; + dm->phy_dbg_info.num_qry_phy_status_cck = 0; + ODM_RT_TRACE(dm, ODM_COMP_RA_MASK, + "%s(): force_power_training_state = %d\n", + __func__, dm->force_power_training_state); + return; + } + + if (!dm->is_linked) + return; + + /* First connect */ + if ((dm->is_linked) && !dig_tab->is_media_connect_0) { + dm->PT_score = 0; + dm->is_change_state = true; + dm->phy_dbg_info.num_qry_phy_status_ofdm = 0; + dm->phy_dbg_info.num_qry_phy_status_cck = 0; + ODM_RT_TRACE(dm, ODM_COMP_RA_MASK, "%s(): First Connect\n", + __func__); + return; + } + + /* Compute score */ + if (dm->nhm_cnt_0 >= 215) { + score = 2; + } else if (dm->nhm_cnt_0 >= 190) { + score = 1; /* unknown state */ + } else { + u32 rx_pkt_cnt; + + rx_pkt_cnt = (u32)(dm->phy_dbg_info.num_qry_phy_status_ofdm) + + (u32)(dm->phy_dbg_info.num_qry_phy_status_cck); + + if ((false_alm_cnt->cnt_cca_all > 31 && rx_pkt_cnt > 31) && + (false_alm_cnt->cnt_cca_all >= rx_pkt_cnt)) { + if ((rx_pkt_cnt + (rx_pkt_cnt >> 1)) <= + false_alm_cnt->cnt_cca_all) + score = 0; + else if ((rx_pkt_cnt + (rx_pkt_cnt >> 2)) <= + false_alm_cnt->cnt_cca_all) + score = 1; + else + score = 2; + } + ODM_RT_TRACE(dm, ODM_COMP_RA_MASK, + "%s(): rx_pkt_cnt = %d, cnt_cca_all = %d\n", + __func__, rx_pkt_cnt, false_alm_cnt->cnt_cca_all); + } + ODM_RT_TRACE( + dm, ODM_COMP_RA_MASK, + "%s(): num_qry_phy_status_ofdm = %d, num_qry_phy_status_cck = %d\n", + __func__, (u32)(dm->phy_dbg_info.num_qry_phy_status_ofdm), + (u32)(dm->phy_dbg_info.num_qry_phy_status_cck)); + ODM_RT_TRACE(dm, ODM_COMP_RA_MASK, "%s(): nhm_cnt_0 = %d, score = %d\n", + __func__, dm->nhm_cnt_0, score); + + /* smoothing */ + dm->PT_score = (score << 4) + (dm->PT_score >> 1) + (dm->PT_score >> 2); + score = (dm->PT_score + 32) >> 6; + ODM_RT_TRACE(dm, ODM_COMP_RA_MASK, + "%s(): PT_score = %d, score after smoothing = %d\n", + __func__, dm->PT_score, score); + + /* mode decision */ + if (score == 2) { + if (dm->is_disable_power_training) { + dm->is_change_state = true; + dm->is_disable_power_training = false; + ODM_RT_TRACE(dm, ODM_COMP_RA_MASK, + "%s(): Change state\n", __func__); + } + ODM_RT_TRACE(dm, ODM_COMP_RA_MASK, + "%s(): Enable Power Training\n", __func__); + } else if (score == 0) { + if (!dm->is_disable_power_training) { + dm->is_change_state = true; + dm->is_disable_power_training = true; + ODM_RT_TRACE(dm, ODM_COMP_RA_MASK, + "%s(): Change state\n", __func__); + } + ODM_RT_TRACE(dm, ODM_COMP_RA_MASK, + "%s(): Disable Power Training\n", __func__); + } + + dm->phy_dbg_info.num_qry_phy_status_ofdm = 0; + dm->phy_dbg_info.num_qry_phy_status_cck = 0; +} + +/*===========================================================*/ +/* The following is for compile only*/ +/*===========================================================*/ +/*#define TARGET_CHNL_NUM_2G_5G 59*/ +/*===========================================================*/ + +void phydm_noisy_detection(struct phy_dm_struct *dm) +{ + u32 total_fa_cnt, total_cca_cnt; + u32 score = 0, i, score_smooth; + + total_cca_cnt = dm->false_alm_cnt.cnt_cca_all; + total_fa_cnt = dm->false_alm_cnt.cnt_all; + + for (i = 0; i <= 16; i++) { + if (total_fa_cnt * 16 >= total_cca_cnt * (16 - i)) { + score = 16 - i; + break; + } + } + + /* noisy_decision_smooth = noisy_decision_smooth>>1 + (score<<3)>>1; */ + dm->noisy_decision_smooth = + (dm->noisy_decision_smooth >> 1) + (score << 2); + + /* Round the noisy_decision_smooth: +"3" comes from (2^3)/2-1 */ + score_smooth = (total_cca_cnt >= 300) ? + ((dm->noisy_decision_smooth + 3) >> 3) : + 0; + + dm->noisy_decision = (score_smooth >= 3) ? 1 : 0; + ODM_RT_TRACE( + dm, ODM_COMP_NOISY_DETECT, + "[NoisyDetection] total_cca_cnt=%d, total_fa_cnt=%d, noisy_decision_smooth=%d, score=%d, score_smooth=%d, dm->noisy_decision=%d\n", + total_cca_cnt, total_fa_cnt, dm->noisy_decision_smooth, score, + score_smooth, dm->noisy_decision); +} + +void phydm_set_ext_switch(void *dm_void, u32 *const dm_value, u32 *_used, + char *output, u32 *_out_len) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + u32 ext_ant_switch = dm_value[0]; + + if (dm->support_ic_type & (ODM_RTL8821 | ODM_RTL8881A)) { + /*Output Pin Settings*/ + odm_set_mac_reg(dm, 0x4C, BIT(23), + 0); /*select DPDT_P and DPDT_N as output pin*/ + odm_set_mac_reg(dm, 0x4C, BIT(24), 1); /*by WLAN control*/ + + odm_set_bb_reg(dm, 0xCB4, 0xF, 7); /*DPDT_P = 1b'0*/ + odm_set_bb_reg(dm, 0xCB4, 0xF0, 7); /*DPDT_N = 1b'0*/ + + if (ext_ant_switch == MAIN_ANT) { + odm_set_bb_reg(dm, 0xCB4, (BIT(29) | BIT(28)), 1); + ODM_RT_TRACE( + dm, ODM_COMP_API, + "***8821A set ant switch = 2b'01 (Main)\n"); + } else if (ext_ant_switch == AUX_ANT) { + odm_set_bb_reg(dm, 0xCB4, BIT(29) | BIT(28), 2); + ODM_RT_TRACE(dm, ODM_COMP_API, + "***8821A set ant switch = 2b'10 (Aux)\n"); + } + } +} + +static void phydm_csi_mask_enable(void *dm_void, u32 enable) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + u32 reg_value = 0; + + reg_value = (enable == CSI_MASK_ENABLE) ? 1 : 0; + + if (dm->support_ic_type & ODM_IC_11N_SERIES) { + odm_set_bb_reg(dm, 0xD2C, BIT(28), reg_value); + ODM_RT_TRACE(dm, ODM_COMP_API, + "Enable CSI Mask: Reg 0xD2C[28] = ((0x%x))\n", + reg_value); + + } else if (dm->support_ic_type & ODM_IC_11AC_SERIES) { + odm_set_bb_reg(dm, 0x874, BIT(0), reg_value); + ODM_RT_TRACE(dm, ODM_COMP_API, + "Enable CSI Mask: Reg 0x874[0] = ((0x%x))\n", + reg_value); + } +} + +static void phydm_clean_all_csi_mask(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + + if (dm->support_ic_type & ODM_IC_11N_SERIES) { + odm_set_bb_reg(dm, 0xD40, MASKDWORD, 0); + odm_set_bb_reg(dm, 0xD44, MASKDWORD, 0); + odm_set_bb_reg(dm, 0xD48, MASKDWORD, 0); + odm_set_bb_reg(dm, 0xD4c, MASKDWORD, 0); + + } else if (dm->support_ic_type & ODM_IC_11AC_SERIES) { + odm_set_bb_reg(dm, 0x880, MASKDWORD, 0); + odm_set_bb_reg(dm, 0x884, MASKDWORD, 0); + odm_set_bb_reg(dm, 0x888, MASKDWORD, 0); + odm_set_bb_reg(dm, 0x88c, MASKDWORD, 0); + odm_set_bb_reg(dm, 0x890, MASKDWORD, 0); + odm_set_bb_reg(dm, 0x894, MASKDWORD, 0); + odm_set_bb_reg(dm, 0x898, MASKDWORD, 0); + odm_set_bb_reg(dm, 0x89c, MASKDWORD, 0); + } +} + +static void phydm_set_csi_mask_reg(void *dm_void, u32 tone_idx_tmp, + u8 tone_direction) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + u8 byte_offset, bit_offset; + u32 target_reg; + u8 reg_tmp_value; + u32 tone_num = 64; + u32 tone_num_shift = 0; + u32 csi_mask_reg_p = 0, csi_mask_reg_n = 0; + + /* calculate real tone idx*/ + if ((tone_idx_tmp % 10) >= 5) + tone_idx_tmp += 10; + + tone_idx_tmp = (tone_idx_tmp / 10); + + if (dm->support_ic_type & ODM_IC_11N_SERIES) { + tone_num = 64; + csi_mask_reg_p = 0xD40; + csi_mask_reg_n = 0xD48; + + } else if (dm->support_ic_type & ODM_IC_11AC_SERIES) { + tone_num = 128; + csi_mask_reg_p = 0x880; + csi_mask_reg_n = 0x890; + } + + if (tone_direction == FREQ_POSITIVE) { + if (tone_idx_tmp >= (tone_num - 1)) + tone_idx_tmp = (tone_num - 1); + + byte_offset = (u8)(tone_idx_tmp >> 3); + bit_offset = (u8)(tone_idx_tmp & 0x7); + target_reg = csi_mask_reg_p + byte_offset; + + } else { + tone_num_shift = tone_num; + + if (tone_idx_tmp >= tone_num) + tone_idx_tmp = tone_num; + + tone_idx_tmp = tone_num - tone_idx_tmp; + + byte_offset = (u8)(tone_idx_tmp >> 3); + bit_offset = (u8)(tone_idx_tmp & 0x7); + target_reg = csi_mask_reg_n + byte_offset; + } + + reg_tmp_value = odm_read_1byte(dm, target_reg); + ODM_RT_TRACE(dm, ODM_COMP_API, + "Pre Mask tone idx[%d]: Reg0x%x = ((0x%x))\n", + (tone_idx_tmp + tone_num_shift), target_reg, + reg_tmp_value); + reg_tmp_value |= BIT(bit_offset); + odm_write_1byte(dm, target_reg, reg_tmp_value); + ODM_RT_TRACE(dm, ODM_COMP_API, + "New Mask tone idx[%d]: Reg0x%x = ((0x%x))\n", + (tone_idx_tmp + tone_num_shift), target_reg, + reg_tmp_value); +} + +static void phydm_set_nbi_reg(void *dm_void, u32 tone_idx_tmp, u32 bw) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + u32 nbi_table_128[NBI_TABLE_SIZE_128] = { + 25, 55, 85, 115, 135, 155, 185, 205, 225, 245, + /*1~10*/ /*tone_idx X 10*/ + 265, 285, 305, 335, 355, 375, 395, 415, 435, 455, /*11~20*/ + 485, 505, 525, 555, 585, 615, 635}; /*21~27*/ + + u32 nbi_table_256[NBI_TABLE_SIZE_256] = { + 25, 55, 85, 115, 135, 155, 175, 195, 225, + 245, /*1~10*/ + 265, 285, 305, 325, 345, 365, 385, 405, 425, + 445, /*11~20*/ + 465, 485, 505, 525, 545, 565, 585, 605, 625, + 645, /*21~30*/ + 665, 695, 715, 735, 755, 775, 795, 815, 835, + 855, /*31~40*/ + 875, 895, 915, 935, 955, 975, 995, 1015, 1035, + 1055, /*41~50*/ + 1085, 1105, 1125, 1145, 1175, 1195, 1225, 1255, 1275}; /*51~59*/ + + u32 reg_idx = 0; + u32 i; + u8 nbi_table_idx = FFT_128_TYPE; + + if (dm->support_ic_type & ODM_IC_11N_SERIES) { + nbi_table_idx = FFT_128_TYPE; + } else if (dm->support_ic_type & ODM_IC_11AC_1_SERIES) { + nbi_table_idx = FFT_256_TYPE; + } else if (dm->support_ic_type & ODM_IC_11AC_2_SERIES) { + if (bw == 80) + nbi_table_idx = FFT_256_TYPE; + else /*20M, 40M*/ + nbi_table_idx = FFT_128_TYPE; + } + + if (nbi_table_idx == FFT_128_TYPE) { + for (i = 0; i < NBI_TABLE_SIZE_128; i++) { + if (tone_idx_tmp < nbi_table_128[i]) { + reg_idx = i + 1; + break; + } + } + + } else if (nbi_table_idx == FFT_256_TYPE) { + for (i = 0; i < NBI_TABLE_SIZE_256; i++) { + if (tone_idx_tmp < nbi_table_256[i]) { + reg_idx = i + 1; + break; + } + } + } + + if (dm->support_ic_type & ODM_IC_11N_SERIES) { + odm_set_bb_reg(dm, 0xc40, 0x1f000000, reg_idx); + ODM_RT_TRACE(dm, ODM_COMP_API, + "Set tone idx: Reg0xC40[28:24] = ((0x%x))\n", + reg_idx); + /**/ + } else { + odm_set_bb_reg(dm, 0x87c, 0xfc000, reg_idx); + ODM_RT_TRACE(dm, ODM_COMP_API, + "Set tone idx: Reg0x87C[19:14] = ((0x%x))\n", + reg_idx); + /**/ + } +} + +static void phydm_nbi_enable(void *dm_void, u32 enable) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + u32 reg_value = 0; + + reg_value = (enable == NBI_ENABLE) ? 1 : 0; + + if (dm->support_ic_type & ODM_IC_11N_SERIES) { + odm_set_bb_reg(dm, 0xc40, BIT(9), reg_value); + ODM_RT_TRACE(dm, ODM_COMP_API, + "Enable NBI Reg0xC40[9] = ((0x%x))\n", reg_value); + + } else if (dm->support_ic_type & ODM_IC_11AC_SERIES) { + odm_set_bb_reg(dm, 0x87c, BIT(13), reg_value); + ODM_RT_TRACE(dm, ODM_COMP_API, + "Enable NBI Reg0x87C[13] = ((0x%x))\n", reg_value); + } +} + +static u8 phydm_calculate_fc(void *dm_void, u32 channel, u32 bw, u32 second_ch, + u32 *fc_in) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + u32 fc = *fc_in; + u32 start_ch_per_40m[NUM_START_CH_40M + 1] = { + 36, 44, 52, 60, 100, 108, 116, 124, + 132, 140, 149, 157, 165, 173, 173 + 8, + }; + u32 start_ch_per_80m[NUM_START_CH_80M + 1] = { + 36, 52, 100, 116, 132, 149, 165, 165 + 16, + }; + u32 *start_ch = &start_ch_per_40m[0]; + u32 num_start_channel = NUM_START_CH_40M; + u32 channel_offset = 0; + u32 i; + + /*2.4G*/ + if (channel <= 14 && channel > 0) { + if (bw == 80) + return SET_ERROR; + + fc = 2412 + (channel - 1) * 5; + + if (bw == 40 && (second_ch == PHYDM_ABOVE)) { + if (channel >= 10) { + ODM_RT_TRACE( + dm, ODM_COMP_API, + "CH = ((%d)), Scnd_CH = ((%d)) Error setting\n", + channel, second_ch); + return SET_ERROR; + } + fc += 10; + } else if (bw == 40 && (second_ch == PHYDM_BELOW)) { + if (channel <= 2) { + ODM_RT_TRACE( + dm, ODM_COMP_API, + "CH = ((%d)), Scnd_CH = ((%d)) Error setting\n", + channel, second_ch); + return SET_ERROR; + } + fc -= 10; + } + } + /*5G*/ + else if (channel >= 36 && channel <= 177) { + if (bw == 20) { + fc = 5180 + (channel - 36) * 5; + *fc_in = fc; + return SET_SUCCESS; + } + + if (bw == 40) { + num_start_channel = NUM_START_CH_40M; + start_ch = &start_ch_per_40m[0]; + channel_offset = CH_OFFSET_40M; + } else if (bw == 80) { + num_start_channel = NUM_START_CH_80M; + start_ch = &start_ch_per_80m[0]; + channel_offset = CH_OFFSET_80M; + } + + for (i = 0; i < num_start_channel; i++) { + if (channel < start_ch[i + 1]) { + channel = start_ch[i] + channel_offset; + break; + } + } + + ODM_RT_TRACE(dm, ODM_COMP_API, "Mod_CH = ((%d))\n", channel); + + fc = 5180 + (channel - 36) * 5; + + } else { + ODM_RT_TRACE(dm, ODM_COMP_API, "CH = ((%d)) Error setting\n", + channel); + return SET_ERROR; + } + + *fc_in = fc; + + return SET_SUCCESS; +} + +static u8 phydm_calculate_intf_distance(void *dm_void, u32 bw, u32 fc, + u32 f_interference, + u32 *tone_idx_tmp_in) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + u32 bw_up, bw_low; + u32 int_distance; + u32 tone_idx_tmp; + u8 set_result = SET_NO_NEED; + + bw_up = fc + bw / 2; + bw_low = fc - bw / 2; + + ODM_RT_TRACE(dm, ODM_COMP_API, + "[f_l, fc, fh] = [ %d, %d, %d ], f_int = ((%d))\n", bw_low, + fc, bw_up, f_interference); + + if ((f_interference >= bw_low) && (f_interference <= bw_up)) { + int_distance = (fc >= f_interference) ? (fc - f_interference) : + (f_interference - fc); + tone_idx_tmp = + (int_distance << 5); /* =10*(int_distance /0.3125) */ + ODM_RT_TRACE( + dm, ODM_COMP_API, + "int_distance = ((%d MHz)) Mhz, tone_idx_tmp = ((%d.%d))\n", + int_distance, (tone_idx_tmp / 10), (tone_idx_tmp % 10)); + *tone_idx_tmp_in = tone_idx_tmp; + set_result = SET_SUCCESS; + } + + return set_result; +} + +static u8 phydm_csi_mask_setting(void *dm_void, u32 enable, u32 channel, u32 bw, + u32 f_interference, u32 second_ch) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + u32 fc; + u8 tone_direction; + u32 tone_idx_tmp; + u8 set_result = SET_SUCCESS; + + if (enable == CSI_MASK_DISABLE) { + set_result = SET_SUCCESS; + phydm_clean_all_csi_mask(dm); + + } else { + ODM_RT_TRACE( + dm, ODM_COMP_API, + "[Set CSI MASK_] CH = ((%d)), BW = ((%d)), f_intf = ((%d)), Scnd_CH = ((%s))\n", + channel, bw, f_interference, + (((bw == 20) || (channel > 14)) ? + "Don't care" : + (second_ch == PHYDM_ABOVE) ? "H" : "L")); + + /*calculate fc*/ + if (phydm_calculate_fc(dm, channel, bw, second_ch, &fc) == + SET_ERROR) { + set_result = SET_ERROR; + } else { + /*calculate interference distance*/ + if (phydm_calculate_intf_distance( + dm, bw, fc, f_interference, + &tone_idx_tmp) == SET_SUCCESS) { + tone_direction = (f_interference >= fc) ? + FREQ_POSITIVE : + FREQ_NEGATIVE; + phydm_set_csi_mask_reg(dm, tone_idx_tmp, + tone_direction); + set_result = SET_SUCCESS; + } else { + set_result = SET_NO_NEED; + } + } + } + + if (set_result == SET_SUCCESS) + phydm_csi_mask_enable(dm, enable); + else + phydm_csi_mask_enable(dm, CSI_MASK_DISABLE); + + return set_result; +} + +u8 phydm_nbi_setting(void *dm_void, u32 enable, u32 channel, u32 bw, + u32 f_interference, u32 second_ch) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + u32 fc; + u32 tone_idx_tmp; + u8 set_result = SET_SUCCESS; + + if (enable == NBI_DISABLE) { + set_result = SET_SUCCESS; + } else { + ODM_RT_TRACE( + dm, ODM_COMP_API, + "[Set NBI] CH = ((%d)), BW = ((%d)), f_intf = ((%d)), Scnd_CH = ((%s))\n", + channel, bw, f_interference, + (((second_ch == PHYDM_DONT_CARE) || (bw == 20) || + (channel > 14)) ? + "Don't care" : + (second_ch == PHYDM_ABOVE) ? "H" : "L")); + + /*calculate fc*/ + if (phydm_calculate_fc(dm, channel, bw, second_ch, &fc) == + SET_ERROR) { + set_result = SET_ERROR; + } else { + /*calculate interference distance*/ + if (phydm_calculate_intf_distance( + dm, bw, fc, f_interference, + &tone_idx_tmp) == SET_SUCCESS) { + phydm_set_nbi_reg(dm, tone_idx_tmp, bw); + set_result = SET_SUCCESS; + } else { + set_result = SET_NO_NEED; + } + } + } + + if (set_result == SET_SUCCESS) + phydm_nbi_enable(dm, enable); + else + phydm_nbi_enable(dm, NBI_DISABLE); + + return set_result; +} + +void phydm_api_debug(void *dm_void, u32 function_map, u32 *const dm_value, + u32 *_used, char *output, u32 *_out_len) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + u32 used = *_used; + u32 out_len = *_out_len; + u32 channel = dm_value[1]; + u32 bw = dm_value[2]; + u32 f_interference = dm_value[3]; + u32 second_ch = dm_value[4]; + u8 set_result = 0; + + /*PHYDM_API_NBI*/ + /*--------------------------------------------------------------------*/ + if (function_map == PHYDM_API_NBI) { + if (dm_value[0] == 100) { + PHYDM_SNPRINTF( + output + used, out_len - used, + "[HELP-NBI] EN(on=1, off=2) CH BW(20/40/80) f_intf(Mhz) Scnd_CH(L=1, H=2)\n"); + return; + + } else if (dm_value[0] == NBI_ENABLE) { + PHYDM_SNPRINTF( + output + used, out_len - used, + "[Enable NBI] CH = ((%d)), BW = ((%d)), f_intf = ((%d)), Scnd_CH = ((%s))\n", + channel, bw, f_interference, + ((second_ch == PHYDM_DONT_CARE) || (bw == 20) || + (channel > 14)) ? + "Don't care" : + ((second_ch == PHYDM_ABOVE) ? "H" : + "L")); + set_result = + phydm_nbi_setting(dm, NBI_ENABLE, channel, bw, + f_interference, second_ch); + + } else if (dm_value[0] == NBI_DISABLE) { + PHYDM_SNPRINTF(output + used, out_len - used, + "[Disable NBI]\n"); + set_result = + phydm_nbi_setting(dm, NBI_DISABLE, channel, bw, + f_interference, second_ch); + + } else { + set_result = SET_ERROR; + } + + PHYDM_SNPRINTF( + output + used, out_len - used, "[NBI set result: %s]\n", + (set_result == SET_SUCCESS) ? + "Success" : + ((set_result == SET_NO_NEED) ? "No need" : + "Error")); + } + + /*PHYDM_CSI_MASK*/ + /*--------------------------------------------------------------------*/ + else if (function_map == PHYDM_API_CSI_MASK) { + if (dm_value[0] == 100) { + PHYDM_SNPRINTF( + output + used, out_len - used, + "[HELP-CSI MASK] EN(on=1, off=2) CH BW(20/40/80) f_intf(Mhz) Scnd_CH(L=1, H=2)\n"); + return; + + } else if (dm_value[0] == CSI_MASK_ENABLE) { + PHYDM_SNPRINTF( + output + used, out_len - used, + "[Enable CSI MASK] CH = ((%d)), BW = ((%d)), f_intf = ((%d)), Scnd_CH = ((%s))\n", + channel, bw, f_interference, + (channel > 14) ? + "Don't care" : + (((second_ch == PHYDM_DONT_CARE) || + (bw == 20) || (channel > 14)) ? + "H" : + "L")); + set_result = phydm_csi_mask_setting( + dm, CSI_MASK_ENABLE, channel, bw, + f_interference, second_ch); + + } else if (dm_value[0] == CSI_MASK_DISABLE) { + PHYDM_SNPRINTF(output + used, out_len - used, + "[Disable CSI MASK]\n"); + set_result = phydm_csi_mask_setting( + dm, CSI_MASK_DISABLE, channel, bw, + f_interference, second_ch); + + } else { + set_result = SET_ERROR; + } + + PHYDM_SNPRINTF(output + used, out_len - used, + "[CSI MASK set result: %s]\n", + (set_result == SET_SUCCESS) ? + "Success" : + ((set_result == SET_NO_NEED) ? + "No need" : + "Error")); + } +} diff --git a/drivers/staging/rtlwifi/phydm/phydm.h b/drivers/staging/rtlwifi/phydm/phydm.h new file mode 100644 index 000000000000..5812ff427ead --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/phydm.h @@ -0,0 +1,946 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __HALDMOUTSRC_H__ +#define __HALDMOUTSRC_H__ + +/*============================================================*/ +/*include files*/ +/*============================================================*/ +#include "phydm_pre_define.h" +#include "phydm_dig.h" +#include "phydm_edcaturbocheck.h" +#include "phydm_antdiv.h" +#include "phydm_dynamicbbpowersaving.h" +#include "phydm_rainfo.h" +#include "phydm_dynamictxpower.h" +#include "phydm_cfotracking.h" +#include "phydm_acs.h" +#include "phydm_adaptivity.h" +#include "phydm_iqk.h" +#include "phydm_dfs.h" +#include "phydm_ccx.h" +#include "txbf/phydm_hal_txbf_api.h" + +#include "phydm_adc_sampling.h" +#include "phydm_dynamic_rx_path.h" +#include "phydm_psd.h" + +#include "phydm_beamforming.h" + +#include "phydm_noisemonitor.h" +#include "halphyrf_ce.h" + +/*============================================================*/ +/*Definition */ +/*============================================================*/ + +/* Traffic load decision */ +#define TRAFFIC_ULTRA_LOW 1 +#define TRAFFIC_LOW 2 +#define TRAFFIC_MID 3 +#define TRAFFIC_HIGH 4 + +#define NONE 0 + +/*NBI API------------------------------------*/ +#define NBI_ENABLE 1 +#define NBI_DISABLE 2 + +#define NBI_TABLE_SIZE_128 27 +#define NBI_TABLE_SIZE_256 59 + +#define NUM_START_CH_80M 7 +#define NUM_START_CH_40M 14 + +#define CH_OFFSET_40M 2 +#define CH_OFFSET_80M 6 + +/*CSI MASK API------------------------------------*/ +#define CSI_MASK_ENABLE 1 +#define CSI_MASK_DISABLE 2 + +/*------------------------------------------------*/ + +#define FFT_128_TYPE 1 +#define FFT_256_TYPE 2 + +#define SET_SUCCESS 1 +#define SET_ERROR 2 +#define SET_NO_NEED 3 + +#define FREQ_POSITIVE 1 +#define FREQ_NEGATIVE 2 + +#define PHYDM_WATCH_DOG_PERIOD 2 + +/*============================================================*/ +/*structure and define*/ +/*============================================================*/ + +/*2011/09/20 MH Add for AP/ADSLpseudo DM structuer requirement.*/ +/*We need to remove to other position???*/ + +struct rtl8192cd_priv { + u8 temp; +}; + +struct dyn_primary_cca { + u8 pri_cca_flag; + u8 intf_flag; + u8 intf_type; + u8 dup_rts_flag; + u8 monitor_flag; + u8 ch_offset; + u8 mf_state; +}; + +#define dm_type_by_fw 0 +#define dm_type_by_driver 1 + +/*Declare for common info*/ + +#define IQK_THRESHOLD 8 +#define DPK_THRESHOLD 4 + +struct dm_phy_status_info { + /* */ + /* Be care, if you want to add any element please insert between */ + /* rx_pwdb_all & signal_strength. */ + /* */ + u8 rx_pwdb_all; + u8 signal_quality; /* in 0-100 index. */ + s8 rx_mimo_signal_quality[4]; /* per-path's EVM translate to 0~100% */ + u8 rx_mimo_evm_dbm[4]; /* per-path's original EVM (dbm) */ + u8 rx_mimo_signal_strength[4]; /* in 0~100 index */ + s16 cfo_short[4]; /* per-path's cfo_short */ + s16 cfo_tail[4]; /* per-path's cfo_tail */ + s8 rx_power; /* in dBm Translate from PWdB */ + s8 recv_signal_power; /* Real power in dBm for this packet, + * no beautification and aggregation. + * Keep this raw info to be used for the other + * procedures. + */ + u8 bt_rx_rssi_percentage; + u8 signal_strength; /* in 0-100 index. */ + s8 rx_pwr[4]; /* per-path's pwdb */ + s8 rx_snr[4]; /* per-path's SNR */ + /* s8 BB_Backup[13]; backup reg. */ + u8 rx_count : 2; /* RX path counter---*/ + u8 band_width : 2; + u8 rxsc : 4; /* sub-channel---*/ + u8 bt_coex_pwr_adjust; + u8 channel; /* channel number---*/ + bool is_mu_packet; /* is MU packet or not---*/ + bool is_beamformed; /* BF packet---*/ +}; + +struct dm_per_pkt_info { + u8 data_rate; + u8 station_id; + bool is_packet_match_bssid; + bool is_packet_to_self; + bool is_packet_beacon; + bool is_to_self; + u8 ppdu_cnt; +}; + +struct odm_phy_dbg_info { + /*ODM Write,debug info*/ + s8 rx_snr_db[4]; + u32 num_qry_phy_status; + u32 num_qry_phy_status_cck; + u32 num_qry_phy_status_ofdm; + u32 num_qry_mu_pkt; + u32 num_qry_bf_pkt; + u32 num_qry_mu_vht_pkt[40]; + u32 num_qry_vht_pkt[40]; + bool is_ldpc_pkt; + bool is_stbc_pkt; + u8 num_of_ppdu[4]; + u8 gid_num[4]; + u8 num_qry_beacon_pkt; + /* Others */ + s32 rx_evm[4]; +}; + +/*2011/20/20 MH For MP driver RT_WLAN_STA = struct rtl_sta_info*/ +/*Please declare below ODM relative info in your STA info structure.*/ + +struct odm_sta_info { + /*Driver Write*/ + bool is_used; /*record the sta status link or not?*/ + u8 iot_peer; /*Enum value. HT_IOT_PEER_E*/ + + /*ODM Write*/ + /*PHY_STATUS_INFO*/ + u8 rssi_path[4]; + u8 rssi_ave; + u8 RXEVM[4]; + u8 RXSNR[4]; +}; + +enum odm_cmninfo { + /*Fixed value*/ + /*-----------HOOK BEFORE REG INIT-----------*/ + ODM_CMNINFO_PLATFORM = 0, + ODM_CMNINFO_ABILITY, + ODM_CMNINFO_INTERFACE, + ODM_CMNINFO_MP_TEST_CHIP, + ODM_CMNINFO_IC_TYPE, + ODM_CMNINFO_CUT_VER, + ODM_CMNINFO_FAB_VER, + ODM_CMNINFO_RF_TYPE, + ODM_CMNINFO_RFE_TYPE, + ODM_CMNINFO_BOARD_TYPE, + ODM_CMNINFO_PACKAGE_TYPE, + ODM_CMNINFO_EXT_LNA, + ODM_CMNINFO_5G_EXT_LNA, + ODM_CMNINFO_EXT_PA, + ODM_CMNINFO_5G_EXT_PA, + ODM_CMNINFO_GPA, + ODM_CMNINFO_APA, + ODM_CMNINFO_GLNA, + ODM_CMNINFO_ALNA, + ODM_CMNINFO_EXT_TRSW, + ODM_CMNINFO_DPK_EN, + ODM_CMNINFO_EXT_LNA_GAIN, + ODM_CMNINFO_PATCH_ID, + ODM_CMNINFO_BINHCT_TEST, + ODM_CMNINFO_BWIFI_TEST, + ODM_CMNINFO_SMART_CONCURRENT, + ODM_CMNINFO_CONFIG_BB_RF, + ODM_CMNINFO_DOMAIN_CODE_2G, + ODM_CMNINFO_DOMAIN_CODE_5G, + ODM_CMNINFO_IQKFWOFFLOAD, + ODM_CMNINFO_IQKPAOFF, + ODM_CMNINFO_HUBUSBMODE, + ODM_CMNINFO_FWDWRSVDPAGEINPROGRESS, + ODM_CMNINFO_TX_TP, + ODM_CMNINFO_RX_TP, + ODM_CMNINFO_SOUNDING_SEQ, + ODM_CMNINFO_REGRFKFREEENABLE, + ODM_CMNINFO_RFKFREEENABLE, + ODM_CMNINFO_NORMAL_RX_PATH_CHANGE, + ODM_CMNINFO_EFUSE0X3D8, + ODM_CMNINFO_EFUSE0X3D7, + /*-----------HOOK BEFORE REG INIT-----------*/ + + /*Dynamic value:*/ + + /*--------- POINTER REFERENCE-----------*/ + ODM_CMNINFO_MAC_PHY_MODE, + ODM_CMNINFO_TX_UNI, + ODM_CMNINFO_RX_UNI, + ODM_CMNINFO_WM_MODE, + ODM_CMNINFO_BAND, + ODM_CMNINFO_SEC_CHNL_OFFSET, + ODM_CMNINFO_SEC_MODE, + ODM_CMNINFO_BW, + ODM_CMNINFO_CHNL, + ODM_CMNINFO_FORCED_RATE, + ODM_CMNINFO_ANT_DIV, + ODM_CMNINFO_ADAPTIVITY, + ODM_CMNINFO_DMSP_GET_VALUE, + ODM_CMNINFO_BUDDY_ADAPTOR, + ODM_CMNINFO_DMSP_IS_MASTER, + ODM_CMNINFO_SCAN, + ODM_CMNINFO_POWER_SAVING, + ODM_CMNINFO_ONE_PATH_CCA, + ODM_CMNINFO_DRV_STOP, + ODM_CMNINFO_PNP_IN, + ODM_CMNINFO_INIT_ON, + ODM_CMNINFO_ANT_TEST, + ODM_CMNINFO_NET_CLOSED, + ODM_CMNINFO_FORCED_IGI_LB, + ODM_CMNINFO_P2P_LINK, + ODM_CMNINFO_FCS_MODE, + ODM_CMNINFO_IS1ANTENNA, + ODM_CMNINFO_RFDEFAULTPATH, + ODM_CMNINFO_DFS_MASTER_ENABLE, + ODM_CMNINFO_FORCE_TX_ANT_BY_TXDESC, + ODM_CMNINFO_SET_S0S1_DEFAULT_ANTENNA, + /*--------- POINTER REFERENCE-----------*/ + + /*------------CALL BY VALUE-------------*/ + ODM_CMNINFO_WIFI_DIRECT, + ODM_CMNINFO_WIFI_DISPLAY, + ODM_CMNINFO_LINK_IN_PROGRESS, + ODM_CMNINFO_LINK, + ODM_CMNINFO_CMW500LINK, + ODM_CMNINFO_LPSPG, + ODM_CMNINFO_STATION_STATE, + ODM_CMNINFO_RSSI_MIN, + ODM_CMNINFO_DBG_COMP, + ODM_CMNINFO_DBG_LEVEL, + ODM_CMNINFO_RA_THRESHOLD_HIGH, + ODM_CMNINFO_RA_THRESHOLD_LOW, + ODM_CMNINFO_RF_ANTENNA_TYPE, + ODM_CMNINFO_WITH_EXT_ANTENNA_SWITCH, + ODM_CMNINFO_BE_FIX_TX_ANT, + ODM_CMNINFO_BT_ENABLED, + ODM_CMNINFO_BT_HS_CONNECT_PROCESS, + ODM_CMNINFO_BT_HS_RSSI, + ODM_CMNINFO_BT_OPERATION, + ODM_CMNINFO_BT_LIMITED_DIG, + ODM_CMNINFO_BT_DIG, + ODM_CMNINFO_BT_BUSY, + ODM_CMNINFO_BT_DISABLE_EDCA, + ODM_CMNINFO_AP_TOTAL_NUM, + ODM_CMNINFO_POWER_TRAINING, + ODM_CMNINFO_DFS_REGION_DOMAIN, + /*------------CALL BY VALUE-------------*/ + + /*Dynamic ptr array hook itms.*/ + ODM_CMNINFO_STA_STATUS, + ODM_CMNINFO_MAX, + +}; + +enum phydm_info_query { + PHYDM_INFO_FA_OFDM, + PHYDM_INFO_FA_CCK, + PHYDM_INFO_FA_TOTAL, + PHYDM_INFO_CCA_OFDM, + PHYDM_INFO_CCA_CCK, + PHYDM_INFO_CCA_ALL, + PHYDM_INFO_CRC32_OK_VHT, + PHYDM_INFO_CRC32_OK_HT, + PHYDM_INFO_CRC32_OK_LEGACY, + PHYDM_INFO_CRC32_OK_CCK, + PHYDM_INFO_CRC32_ERROR_VHT, + PHYDM_INFO_CRC32_ERROR_HT, + PHYDM_INFO_CRC32_ERROR_LEGACY, + PHYDM_INFO_CRC32_ERROR_CCK, + PHYDM_INFO_EDCCA_FLAG, + PHYDM_INFO_OFDM_ENABLE, + PHYDM_INFO_CCK_ENABLE, + PHYDM_INFO_DBG_PORT_0 +}; + +enum phydm_api { + PHYDM_API_NBI = 1, + PHYDM_API_CSI_MASK, + +}; + +/*2011/10/20 MH Define ODM support ability. ODM_CMNINFO_ABILITY*/ +enum odm_ability { + /*BB ODM section BIT 0-19*/ + ODM_BB_DIG = BIT(0), + ODM_BB_RA_MASK = BIT(1), + ODM_BB_DYNAMIC_TXPWR = BIT(2), + ODM_BB_FA_CNT = BIT(3), + ODM_BB_RSSI_MONITOR = BIT(4), + ODM_BB_CCK_PD = BIT(5), + ODM_BB_ANT_DIV = BIT(6), + ODM_BB_PWR_TRAIN = BIT(8), + ODM_BB_RATE_ADAPTIVE = BIT(9), + ODM_BB_PATH_DIV = BIT(10), + ODM_BB_ADAPTIVITY = BIT(13), + ODM_BB_CFO_TRACKING = BIT(14), + ODM_BB_NHM_CNT = BIT(15), + ODM_BB_PRIMARY_CCA = BIT(16), + ODM_BB_TXBF = BIT(17), + ODM_BB_DYNAMIC_ARFR = BIT(18), + + ODM_MAC_EDCA_TURBO = BIT(20), + ODM_BB_DYNAMIC_RX_PATH = BIT(21), + + /*RF ODM section BIT 24-31*/ + ODM_RF_TX_PWR_TRACK = BIT(24), + ODM_RF_RX_GAIN_TRACK = BIT(25), + ODM_RF_CALIBRATION = BIT(26), + +}; + +/*ODM_CMNINFO_ONE_PATH_CCA*/ +enum odm_cca_path { + ODM_CCA_2R = 0, + ODM_CCA_1R_A = 1, + ODM_CCA_1R_B = 2, +}; + +enum cca_pathdiv_en { + CCA_PATHDIV_DISABLE = 0, + CCA_PATHDIV_ENABLE = 1, + +}; + +enum phy_reg_pg_type { + PHY_REG_PG_RELATIVE_VALUE = 0, + PHY_REG_PG_EXACT_VALUE = 1 +}; + +/*2011/09/22 MH Copy from SD4 defined structure. + *We use to support PHY DM integration. + */ + +struct phy_dm_struct { + /*Add for different team use temporarily*/ + void *adapter; /*For CE/NIC team*/ + struct rtl8192cd_priv *priv; /*For AP/ADSL team*/ + /*When you use adapter or priv pointer, + *you must make sure the pointer is ready. + */ + bool odm_ready; + + struct rtl8192cd_priv fake_priv; + + enum phy_reg_pg_type phy_reg_pg_value_type; + u8 phy_reg_pg_version; + + u32 debug_components; + u32 fw_debug_components; + u32 debug_level; + + u32 num_qry_phy_status_all; /*CCK + OFDM*/ + u32 last_num_qry_phy_status_all; + u32 rx_pwdb_ave; + bool MPDIG_2G; /*off MPDIG*/ + u8 times_2g; + bool is_init_hw_info_by_rfe; + + /*------ ODM HANDLE, DRIVER NEEDS NOT TO HOOK------*/ + bool is_cck_high_power; + u8 rf_path_rx_enable; + u8 control_channel; + /*------ ODM HANDLE, DRIVER NEEDS NOT TO HOOK------*/ + + /* 1 COMMON INFORMATION */ + + /*Init value*/ + /*-----------HOOK BEFORE REG INIT-----------*/ + /*ODM Platform info AP/ADSL/CE/MP = 1/2/3/4*/ + u8 support_platform; + /* ODM Platform info WIN/AP/CE = 1/2/3 */ + u8 normal_rx_path; + /*ODM Support Ability DIG/RATR/TX_PWR_TRACK/ ... = 1/2/3/...*/ + u32 support_ability; + /*ODM PCIE/USB/SDIO = 1/2/3*/ + u8 support_interface; + /*ODM composite or independent. Bit oriented/ 92C+92D+ .... or + *any other type = 1/2/3/... + */ + u32 support_ic_type; + /*cut version TestChip/A-cut/B-cut... = 0/1/2/3/...*/ + u8 cut_version; + /*Fab version TSMC/UMC = 0/1*/ + u8 fab_version; + /*RF type 4T4R/3T3R/2T2R/1T2R/1T1R/...*/ + u8 rf_type; + u8 rfe_type; + /*Board type Normal/HighPower/MiniCard/SLIM/Combo/... = 0/1/2/3/4/...*/ + /*Enable Function DPK OFF/ON = 0/1*/ + u8 dpk_en; + u8 board_type; + u8 package_type; + u16 type_glna; + u16 type_gpa; + u16 type_alna; + u16 type_apa; + /*with external LNA NO/Yes = 0/1*/ + u8 ext_lna; /*2G*/ + u8 ext_lna_5g; /*5G*/ + /*with external PA NO/Yes = 0/1*/ + u8 ext_pa; /*2G*/ + u8 ext_pa_5g; /*5G*/ + /*with Efuse number*/ + u8 efuse0x3d7; + u8 efuse0x3d8; + /*with external TRSW NO/Yes = 0/1*/ + u8 ext_trsw; + u8 ext_lna_gain; /*2G*/ + u8 patch_id; /*Customer ID*/ + bool is_in_hct_test; + u8 wifi_test; + + bool is_dual_mac_smart_concurrent; + u32 bk_support_ability; + u8 ant_div_type; + u8 with_extenal_ant_switch; + bool config_bbrf; + u8 odm_regulation_2_4g; + u8 odm_regulation_5g; + u8 iqk_fw_offload; + bool cck_new_agc; + u8 phydm_period; + u32 phydm_sys_up_time; + u8 num_rf_path; + /*-----------HOOK BEFORE REG INIT-----------*/ + + /*Dynamic value*/ + + /*--------- POINTER REFERENCE-----------*/ + + u8 u1_byte_temp; + bool BOOLEAN_temp; + void *PADAPTER_temp; + + /*MAC PHY mode SMSP/DMSP/DMDP = 0/1/2*/ + u8 *mac_phy_mode; + /*TX Unicast byte count*/ + u64 *num_tx_bytes_unicast; + /*RX Unicast byte count*/ + u64 *num_rx_bytes_unicast; + /*Wireless mode B/G/A/N = BIT0/BIT1/BIT2/BIT3*/ + u8 *wireless_mode; + /*Frequence band 2.4G/5G = 0/1*/ + u8 *band_type; + /*Secondary channel offset don't_care/below/above = 0/1/2*/ + u8 *sec_ch_offset; + /*security mode Open/WEP/AES/TKIP = 0/1/2/3*/ + u8 *security; + /*BW info 20M/40M/80M = 0/1/2*/ + u8 *band_width; + /*Central channel location Ch1/Ch2/....*/ + u8 *channel; /*central channel number*/ + bool dpk_done; + /*Common info for 92D DMSP*/ + + bool *is_get_value_from_other_mac; + void **buddy_adapter; + bool *is_master_of_dmsp; /* MAC0: master, MAC1: slave */ + /*Common info for status*/ + bool *is_scan_in_process; + bool *is_power_saving; + /*CCA path 2-path/path-A/path-B = 0/1/2; using enum odm_cca_path.*/ + u8 *one_path_cca; + u8 *antenna_test; + bool *is_net_closed; + u8 *pu1_forced_igi_lb; + bool *is_fcs_mode_enable; + /*--------- For 8723B IQK-----------*/ + bool *is_1_antenna; + u8 *rf_default_path; + /* 0:S1, 1:S0 */ + + /*--------- POINTER REFERENCE-----------*/ + u16 *forced_data_rate; + u8 *enable_antdiv; + u8 *enable_adaptivity; + u8 *hub_usb_mode; + bool *is_fw_dw_rsvd_page_in_progress; + u32 *current_tx_tp; + u32 *current_rx_tp; + u8 *sounding_seq; + /*------------CALL BY VALUE-------------*/ + bool is_link_in_process; + bool is_wifi_direct; + bool is_wifi_display; + bool is_linked; + bool is_linkedcmw500; + bool is_in_lps_pg; + bool bsta_state; + u8 rssi_min; + u8 interface_index; /*Add for 92D dual MAC: 0--Mac0 1--Mac1*/ + bool is_mp_chip; + bool is_one_entry_only; + bool mp_mode; + u32 one_entry_macid; + u8 pre_number_linked_client; + u8 number_linked_client; + u8 pre_number_active_client; + u8 number_active_client; + /*Common info for BTDM*/ + bool is_bt_enabled; /*BT is enabled*/ + bool is_bt_connect_process; /*BT HS is under connection progress.*/ + u8 bt_hs_rssi; /*BT HS mode wifi rssi value.*/ + bool is_bt_hs_operation; /*BT HS mode is under progress*/ + u8 bt_hs_dig_val; /*use BT rssi to decide the DIG value*/ + bool is_bt_disable_edca_turbo; /*Under some condition, don't enable*/ + bool is_bt_busy; /*BT is busy.*/ + bool is_bt_limited_dig; /*BT is busy.*/ + bool is_disable_phy_api; + /*------------CALL BY VALUE-------------*/ + u8 rssi_a; + u8 rssi_b; + u8 rssi_c; + u8 rssi_d; + u64 rssi_trsw; + u64 rssi_trsw_h; + u64 rssi_trsw_l; + u64 rssi_trsw_iso; + u8 tx_ant_status; + u8 rx_ant_status; + u8 cck_lna_idx; + u8 cck_vga_idx; + u8 curr_station_id; + u8 ofdm_agc_idx[4]; + + u8 rx_rate; + bool is_noisy_state; + u8 tx_rate; + u8 linked_interval; + u8 pre_channel; + u32 txagc_offset_value_a; + bool is_txagc_offset_positive_a; + u32 txagc_offset_value_b; + bool is_txagc_offset_positive_b; + u32 tx_tp; + u32 rx_tp; + u32 total_tp; + u64 cur_tx_ok_cnt; + u64 cur_rx_ok_cnt; + u64 last_tx_ok_cnt; + u64 last_rx_ok_cnt; + u32 bb_swing_offset_a; + bool is_bb_swing_offset_positive_a; + u32 bb_swing_offset_b; + bool is_bb_swing_offset_positive_b; + u8 igi_lower_bound; + u8 igi_upper_bound; + u8 antdiv_rssi; + u8 fat_comb_a; + u8 fat_comb_b; + u8 antdiv_intvl; + u8 ant_type; + u8 pre_ant_type; + u8 antdiv_period; + u8 evm_antdiv_period; + u8 antdiv_select; + u8 path_select; + u8 antdiv_evm_en; + u8 bdc_holdstate; + u8 ndpa_period; + bool h2c_rarpt_connect; + bool cck_agc_report_type; + + u8 dm_dig_max_TH; + u8 dm_dig_min_TH; + u8 print_agc; + u8 traffic_load; + u8 pre_traffic_load; + /*8821C Antenna BTG/WLG/WLA Select*/ + u8 current_rf_set_8821c; + u8 default_rf_set_8821c; + /*For Adaptivtiy*/ + u16 nhm_cnt_0; + u16 nhm_cnt_1; + s8 TH_L2H_default; + s8 th_edcca_hl_diff_default; + s8 th_l2h_ini; + s8 th_edcca_hl_diff; + s8 th_l2h_ini_mode2; + s8 th_edcca_hl_diff_mode2; + bool carrier_sense_enable; + u8 adaptivity_igi_upper; + bool adaptivity_flag; + u8 dc_backoff; + bool adaptivity_enable; + u8 ap_total_num; + bool edcca_enable; + u8 pre_dbg_priority; + struct adaptivity_statistics adaptivity; + /*For Adaptivtiy*/ + u8 last_usb_hub; + u8 tx_bf_data_rate; + + u8 nbi_set_result; + + u8 c2h_cmd_start; + u8 fw_debug_trace[60]; + u8 pre_c2h_seq; + bool fw_buff_is_enpty; + u32 data_frame_num; + + /*for noise detection*/ + bool noisy_decision; /*b_noisy*/ + bool pre_b_noisy; + u32 noisy_decision_smooth; + bool is_disable_dym_ecs; + + struct odm_noise_monitor noise_level; + /*Define STA info.*/ + /*odm_sta_info*/ + /*2012/01/12 MH For MP, + *we need to reduce one array pointer for default port.?? + */ + struct rtl_sta_info *odm_sta_info[ODM_ASSOCIATE_ENTRY_NUM]; + u16 platform2phydm_macid_table[ODM_ASSOCIATE_ENTRY_NUM]; + /* platform_macid_table[platform_macid] = phydm_macid */ + s32 accumulate_pwdb[ODM_ASSOCIATE_ENTRY_NUM]; + + /*2012/02/14 MH Add to share 88E ra with other SW team.*/ + /*We need to colelct all support abilit to a proper area.*/ + + bool ra_support88e; + + struct odm_phy_dbg_info phy_dbg_info; + + /*ODM Structure*/ + struct fast_antenna_training dm_fat_table; + struct dig_thres dm_dig_table; + struct dyn_pwr_saving dm_ps_table; + struct dyn_primary_cca dm_pri_cca; + struct ra_table dm_ra_table; + struct false_alarm_stat false_alm_cnt; + struct false_alarm_stat flase_alm_cnt_buddy_adapter; + struct sw_antenna_switch dm_swat_table; + struct cfo_tracking dm_cfo_track; + struct acs_info dm_acs; + struct ccx_info dm_ccx_info; + struct psd_info dm_psd_table; + + struct rt_adcsmp adcsmp; + + struct dm_iqk_info IQK_info; + + struct edca_turbo dm_edca_table; + u32 WMMEDCA_BE; + + bool *is_driver_stopped; + bool *is_driver_is_going_to_pnp_set_power_sleep; + bool *pinit_adpt_in_progress; + + /*PSD*/ + bool is_user_assign_level; + u8 RSSI_BT; /*come from BT*/ + bool is_psd_in_process; + bool is_psd_active; + bool is_dm_initial_gain_enable; + + /*MPT DIG*/ + struct timer_list mpt_dig_timer; + + /*for rate adaptive, in fact, 88c/92c fw will handle this*/ + u8 is_use_ra_mask; + + /* for dynamic SoML control */ + bool bsomlenabled; + + struct odm_rate_adaptive rate_adaptive; + struct dm_rf_calibration_struct rf_calibrate_info; + u32 n_iqk_cnt; + u32 n_iqk_ok_cnt; + u32 n_iqk_fail_cnt; + + /*Power Training*/ + u8 force_power_training_state; + bool is_change_state; + u32 PT_score; + u64 ofdm_rx_cnt; + u64 cck_rx_cnt; + bool is_disable_power_training; + u8 dynamic_tx_high_power_lvl; + u8 last_dtp_lvl; + u32 tx_agc_ofdm_18_6; + u8 rx_pkt_type; + + /*ODM relative time.*/ + struct timer_list path_div_switch_timer; + /*2011.09.27 add for path Diversity*/ + struct timer_list cck_path_diversity_timer; + struct timer_list fast_ant_training_timer; + struct timer_list sbdcnt_timer; + + /*ODM relative workitem.*/ +}; + +enum phydm_structure_type { + PHYDM_FALSEALMCNT, + PHYDM_CFOTRACK, + PHYDM_ADAPTIVITY, + PHYDM_ROMINFO, + +}; + +enum odm_rf_content { + odm_radioa_txt = 0x1000, + odm_radiob_txt = 0x1001, + odm_radioc_txt = 0x1002, + odm_radiod_txt = 0x1003 +}; + +enum odm_bb_config_type { + CONFIG_BB_PHY_REG, + CONFIG_BB_AGC_TAB, + CONFIG_BB_AGC_TAB_2G, + CONFIG_BB_AGC_TAB_5G, + CONFIG_BB_PHY_REG_PG, + CONFIG_BB_PHY_REG_MP, + CONFIG_BB_AGC_TAB_DIFF, +}; + +enum odm_rf_config_type { + CONFIG_RF_RADIO, + CONFIG_RF_TXPWR_LMT, +}; + +enum odm_fw_config_type { + CONFIG_FW_NIC, + CONFIG_FW_NIC_2, + CONFIG_FW_AP, + CONFIG_FW_AP_2, + CONFIG_FW_MP, + CONFIG_FW_WOWLAN, + CONFIG_FW_WOWLAN_2, + CONFIG_FW_AP_WOWLAN, + CONFIG_FW_BT, +}; + +/*status code*/ +enum rt_status { + RT_STATUS_SUCCESS, + RT_STATUS_FAILURE, + RT_STATUS_PENDING, + RT_STATUS_RESOURCE, + RT_STATUS_INVALID_CONTEXT, + RT_STATUS_INVALID_PARAMETER, + RT_STATUS_NOT_SUPPORT, + RT_STATUS_OS_API_FAILED, +}; + +/*===========================================================*/ +/*AGC RX High Power mode*/ +/*===========================================================*/ +#define lna_low_gain_1 0x64 +#define lna_low_gain_2 0x5A +#define lna_low_gain_3 0x58 + +#define FA_RXHP_TH1 5000 +#define FA_RXHP_TH2 1500 +#define FA_RXHP_TH3 800 +#define FA_RXHP_TH4 600 +#define FA_RXHP_TH5 500 + +enum dm_1r_cca { + CCA_1R = 0, + CCA_2R = 1, + CCA_MAX = 2, +}; + +enum dm_rf { + rf_save = 0, + rf_normal = 1, + RF_MAX = 2, +}; + +/*check Sta pointer valid or not*/ + +#define IS_STA_VALID(sta) (sta) + +u32 odm_convert_to_db(u32 value); + +u32 odm_convert_to_linear(u32 value); + +s32 odm_pwdb_conversion(s32 X, u32 total_bit, u32 decimal_bit); + +s32 odm_sign_conversion(s32 value, u32 total_bit); + +void odm_init_mp_driver_status(struct phy_dm_struct *dm); + +void phydm_txcurrentcalibration(struct phy_dm_struct *dm); + +void phydm_seq_sorting(void *dm_void, u32 *value, u32 *rank_idx, u32 *idx_out, + u8 seq_length); + +void odm_dm_init(struct phy_dm_struct *dm); + +void odm_dm_reset(struct phy_dm_struct *dm); + +void phydm_support_ability_debug(void *dm_void, u32 *const dm_value, u32 *_used, + char *output, u32 *_out_len); + +void phydm_config_ofdm_rx_path(struct phy_dm_struct *dm, u32 path); + +void phydm_config_trx_path(void *dm_void, u32 *const dm_value, u32 *_used, + char *output, u32 *_out_len); + +void odm_dm_watchdog(struct phy_dm_struct *dm); + +void phydm_watchdog_mp(struct phy_dm_struct *dm); + +void odm_cmn_info_init(struct phy_dm_struct *dm, enum odm_cmninfo cmn_info, + u32 value); + +void odm_cmn_info_hook(struct phy_dm_struct *dm, enum odm_cmninfo cmn_info, + void *value); + +void odm_cmn_info_ptr_array_hook(struct phy_dm_struct *dm, + enum odm_cmninfo cmn_info, u16 index, + void *value); + +void odm_cmn_info_update(struct phy_dm_struct *dm, u32 cmn_info, u64 value); + +u32 phydm_cmn_info_query(struct phy_dm_struct *dm, + enum phydm_info_query info_type); + +void odm_init_all_timers(struct phy_dm_struct *dm); + +void odm_cancel_all_timers(struct phy_dm_struct *dm); + +void odm_release_all_timers(struct phy_dm_struct *dm); + +void odm_asoc_entry_init(struct phy_dm_struct *dm); + +void *phydm_get_structure(struct phy_dm_struct *dm, u8 structure_type); + +/*===========================================================*/ +/* The following is for compile only*/ +/*===========================================================*/ + +#define IS_HARDWARE_TYPE_8188E(_adapter) false +#define IS_HARDWARE_TYPE_8188F(_adapter) false +#define IS_HARDWARE_TYPE_8703B(_adapter) false +#define IS_HARDWARE_TYPE_8723D(_adapter) false +#define IS_HARDWARE_TYPE_8821C(_adapter) false +#define IS_HARDWARE_TYPE_8812AU(_adapter) false +#define IS_HARDWARE_TYPE_8814A(_adapter) false +#define IS_HARDWARE_TYPE_8814AU(_adapter) false +#define IS_HARDWARE_TYPE_8814AE(_adapter) false +#define IS_HARDWARE_TYPE_8814AS(_adapter) false +#define IS_HARDWARE_TYPE_8723BU(_adapter) false +#define IS_HARDWARE_TYPE_8822BU(_adapter) false +#define IS_HARDWARE_TYPE_8822BS(_adapter) false +#define IS_HARDWARE_TYPE_JAGUAR(_adapter) \ + (IS_HARDWARE_TYPE_8812(_adapter) || IS_HARDWARE_TYPE_8821(_adapter)) +#define IS_HARDWARE_TYPE_8723AE(_adapter) false +#define IS_HARDWARE_TYPE_8192C(_adapter) false +#define IS_HARDWARE_TYPE_8192D(_adapter) false +#define RF_T_METER_92D 0x42 + +#define GET_RX_STATUS_DESC_RX_MCS(__prx_status_desc) \ + LE_BITS_TO_1BYTE(__prx_status_desc + 12, 0, 6) + +#define REG_CONFIG_RAM64X16 0xb2c + +#define TARGET_CHNL_NUM_2G_5G 59 + +/* *********************************************************** */ + +void odm_dtc(struct phy_dm_struct *dm); + +void phydm_noisy_detection(struct phy_dm_struct *dm); + +void phydm_set_ext_switch(void *dm_void, u32 *const dm_value, u32 *_used, + char *output, u32 *_out_len); + +void phydm_api_debug(void *dm_void, u32 function_map, u32 *const dm_value, + u32 *_used, char *output, u32 *_out_len); + +u8 phydm_nbi_setting(void *dm_void, u32 enable, u32 channel, u32 bw, + u32 f_interference, u32 second_ch); +#endif /* __HALDMOUTSRC_H__ */ diff --git a/drivers/staging/rtlwifi/phydm/phydm_acs.c b/drivers/staging/rtlwifi/phydm/phydm_acs.c new file mode 100644 index 000000000000..eae5a0a24b9b --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/phydm_acs.c @@ -0,0 +1,200 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +/* ************************************************************ + * include files + * *************************************************************/ +#include "mp_precomp.h" +#include "phydm_precomp.h" + +u8 odm_get_auto_channel_select_result(void *dm_void, u8 band) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct acs_info *acs = &dm->dm_acs; + u8 result; + + if (band == ODM_BAND_2_4G) { + ODM_RT_TRACE( + dm, ODM_COMP_ACS, + "[struct acs_info] %s(): clean_channel_2g(%d)\n", + __func__, acs->clean_channel_2g); + result = (u8)acs->clean_channel_2g; + } else { + ODM_RT_TRACE( + dm, ODM_COMP_ACS, + "[struct acs_info] %s(): clean_channel_5g(%d)\n", + __func__, acs->clean_channel_5g); + result = (u8)acs->clean_channel_5g; + } + + return result; +} + +static void odm_auto_channel_select_setting(void *dm_void, bool is_enable) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + u16 period = 0x2710; /* 40ms in default */ + u16 nhm_type = 0x7; + + ODM_RT_TRACE(dm, ODM_COMP_ACS, "%s()=========>\n", __func__); + + if (is_enable) { + /* 20 ms */ + period = 0x1388; + nhm_type = 0x1; + } + + if (dm->support_ic_type & ODM_IC_11AC_SERIES) { + /* PHY parameters initialize for ac series */ + + /* 0x990[31:16]=0x2710 + * Time duration for NHM unit: 4us, 0x2710=40ms + */ + odm_write_2byte(dm, ODM_REG_CCX_PERIOD_11AC + 2, period); + } else if (dm->support_ic_type & ODM_IC_11N_SERIES) { + /* PHY parameters initialize for n series */ + + /* 0x894[31:16]=0x2710 + * Time duration for NHM unit: 4us, 0x2710=40ms + */ + odm_write_2byte(dm, ODM_REG_CCX_PERIOD_11N + 2, period); + } +} + +void odm_auto_channel_select_init(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct acs_info *acs = &dm->dm_acs; + u8 i; + + if (!(dm->support_ability & ODM_BB_NHM_CNT)) + return; + + if (acs->is_force_acs_result) + return; + + ODM_RT_TRACE(dm, ODM_COMP_ACS, "%s()=========>\n", __func__); + + acs->clean_channel_2g = 1; + acs->clean_channel_5g = 36; + + for (i = 0; i < ODM_MAX_CHANNEL_2G; ++i) { + acs->channel_info_2g[0][i] = 0; + acs->channel_info_2g[1][i] = 0; + } + + if (dm->support_ic_type & ODM_IC_11AC_SERIES) { + for (i = 0; i < ODM_MAX_CHANNEL_5G; ++i) { + acs->channel_info_5g[0][i] = 0; + acs->channel_info_5g[1][i] = 0; + } + } +} + +void odm_auto_channel_select_reset(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct acs_info *acs = &dm->dm_acs; + + if (!(dm->support_ability & ODM_BB_NHM_CNT)) + return; + + if (acs->is_force_acs_result) + return; + + ODM_RT_TRACE(dm, ODM_COMP_ACS, "%s()=========>\n", __func__); + + odm_auto_channel_select_setting(dm, true); /* for 20ms measurement */ + phydm_nhm_counter_statistics_reset(dm); +} + +void odm_auto_channel_select(void *dm_void, u8 channel) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct acs_info *acs = &dm->dm_acs; + u8 channel_idx = 0, search_idx = 0; + u16 max_score = 0; + + if (!(dm->support_ability & ODM_BB_NHM_CNT)) { + ODM_RT_TRACE( + dm, ODM_COMP_DIG, + "%s(): Return: support_ability ODM_BB_NHM_CNT is disabled\n", + __func__); + return; + } + + if (acs->is_force_acs_result) { + ODM_RT_TRACE( + dm, ODM_COMP_DIG, + "%s(): Force 2G clean channel = %d, 5G clean channel = %d\n", + __func__, acs->clean_channel_2g, acs->clean_channel_5g); + return; + } + + ODM_RT_TRACE(dm, ODM_COMP_ACS, "%s(): channel = %d=========>\n", + __func__, channel); + + phydm_get_nhm_counter_statistics(dm); + odm_auto_channel_select_setting(dm, false); + + if (channel >= 1 && channel <= 14) { + channel_idx = channel - 1; + acs->channel_info_2g[1][channel_idx]++; + + if (acs->channel_info_2g[1][channel_idx] >= 2) + acs->channel_info_2g[0][channel_idx] = + (acs->channel_info_2g[0][channel_idx] >> 1) + + (acs->channel_info_2g[0][channel_idx] >> 2) + + (dm->nhm_cnt_0 >> 2); + else + acs->channel_info_2g[0][channel_idx] = dm->nhm_cnt_0; + + ODM_RT_TRACE(dm, ODM_COMP_ACS, "%s(): nhm_cnt_0 = %d\n", + __func__, dm->nhm_cnt_0); + ODM_RT_TRACE( + dm, ODM_COMP_ACS, + "%s(): Channel_Info[0][%d] = %d, Channel_Info[1][%d] = %d\n", + __func__, channel_idx, + acs->channel_info_2g[0][channel_idx], channel_idx, + acs->channel_info_2g[1][channel_idx]); + + for (search_idx = 0; search_idx < ODM_MAX_CHANNEL_2G; + search_idx++) { + if (acs->channel_info_2g[1][search_idx] != 0 && + acs->channel_info_2g[0][search_idx] >= max_score) { + max_score = acs->channel_info_2g[0][search_idx]; + acs->clean_channel_2g = search_idx + 1; + } + } + ODM_RT_TRACE( + dm, ODM_COMP_ACS, + "(1)%s(): 2G: clean_channel_2g = %d, max_score = %d\n", + __func__, acs->clean_channel_2g, max_score); + + } else if (channel >= 36) { + /* Need to do */ + acs->clean_channel_5g = channel; + } +} diff --git a/drivers/staging/rtlwifi/phydm/phydm_acs.h b/drivers/staging/rtlwifi/phydm/phydm_acs.h new file mode 100644 index 000000000000..51d72b72bd6f --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/phydm_acs.h @@ -0,0 +1,57 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __PHYDMACS_H__ +#define __PHYDMACS_H__ + +#define ACS_VERSION "1.1" /*20150729 by YuChen*/ +#define CLM_VERSION "1.0" + +#define ODM_MAX_CHANNEL_2G 14 +#define ODM_MAX_CHANNEL_5G 24 + +/* For phydm_auto_channel_select_setting_ap() */ +#define STORE_DEFAULT_NHM_SETTING 0 +#define RESTORE_DEFAULT_NHM_SETTING 1 +#define ACS_NHM_SETTING 2 + +struct acs_info { + bool is_force_acs_result; + u8 clean_channel_2g; + u8 clean_channel_5g; + /* channel_info[1]: channel score, channel_info[2]:channel_scan_times */ + u16 channel_info_2g[2][ODM_MAX_CHANNEL_2G]; + u16 channel_info_5g[2][ODM_MAX_CHANNEL_5G]; +}; + +void odm_auto_channel_select_init(void *dm_void); + +void odm_auto_channel_select_reset(void *dm_void); + +void odm_auto_channel_select(void *dm_void, u8 channel); + +u8 odm_get_auto_channel_select_result(void *dm_void, u8 band); + +#endif /* #ifndef __PHYDMACS_H__ */ diff --git a/drivers/staging/rtlwifi/phydm/phydm_adaptivity.c b/drivers/staging/rtlwifi/phydm/phydm_adaptivity.c new file mode 100644 index 000000000000..4f9e267409f6 --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/phydm_adaptivity.c @@ -0,0 +1,941 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +/* ************************************************************ + * include files + * *************************************************************/ +#include "mp_precomp.h" +#include "phydm_precomp.h" + +void phydm_check_adaptivity(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct adaptivity_statistics *adaptivity = + (struct adaptivity_statistics *)phydm_get_structure( + dm, PHYDM_ADAPTIVITY); + + if (dm->support_ability & ODM_BB_ADAPTIVITY) { + if (adaptivity->dynamic_link_adaptivity || + adaptivity->acs_for_adaptivity) { + if (dm->is_linked && !adaptivity->is_check) { + phydm_nhm_counter_statistics(dm); + phydm_check_environment(dm); + } else if (!dm->is_linked) { + adaptivity->is_check = false; + } + } else { + dm->adaptivity_enable = true; + + if (dm->support_ic_type & (ODM_IC_11AC_GAIN_IDX_EDCCA | + ODM_IC_11N_GAIN_IDX_EDCCA)) + dm->adaptivity_flag = false; + else + dm->adaptivity_flag = true; + } + } else { + dm->adaptivity_enable = false; + dm->adaptivity_flag = false; + } +} + +void phydm_nhm_counter_statistics_init(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + + if (dm->support_ic_type & ODM_IC_11N_SERIES) { + /*PHY parameters initialize for n series*/ + + /*0x894[31:16]=0x0xC350 + *Time duration for NHM unit: us, 0xc350=200ms + */ + odm_write_2byte(dm, ODM_REG_CCX_PERIOD_11N + 2, 0xC350); + /*0x890[31:16]=0xffff th_9, th_10*/ + odm_write_2byte(dm, ODM_REG_NHM_TH9_TH10_11N + 2, 0xffff); + /*0x898=0xffffff52 th_3, th_2, th_1, th_0*/ + odm_write_4byte(dm, ODM_REG_NHM_TH3_TO_TH0_11N, 0xffffff50); + /*0x89c=0xffffffff th_7, th_6, th_5, th_4*/ + odm_write_4byte(dm, ODM_REG_NHM_TH7_TO_TH4_11N, 0xffffffff); + /*0xe28[7:0]=0xff th_8*/ + odm_set_bb_reg(dm, ODM_REG_FPGA0_IQK_11N, MASKBYTE0, 0xff); + /*0x890[10:8]=1 ignoreCCA ignore PHYTXON enable CCX*/ + odm_set_bb_reg(dm, ODM_REG_NHM_TH9_TH10_11N, + BIT(10) | BIT(9) | BIT(8), 0x1); + /*0xc0c[7]=1 max power among all RX ants*/ + odm_set_bb_reg(dm, ODM_REG_OFDM_FA_RSTC_11N, BIT(7), 0x1); + } else if (dm->support_ic_type & ODM_IC_11AC_SERIES) { + /*PHY parameters initialize for ac series*/ + + odm_write_2byte(dm, ODM_REG_CCX_PERIOD_11AC + 2, 0xC350); + /*0x994[31:16]=0xffff th_9, th_10*/ + odm_write_2byte(dm, ODM_REG_NHM_TH9_TH10_11AC + 2, 0xffff); + /*0x998=0xffffff52 th_3, th_2, th_1, th_0*/ + odm_write_4byte(dm, ODM_REG_NHM_TH3_TO_TH0_11AC, 0xffffff50); + /*0x99c=0xffffffff th_7, th_6, th_5, th_4*/ + odm_write_4byte(dm, ODM_REG_NHM_TH7_TO_TH4_11AC, 0xffffffff); + /*0x9a0[7:0]=0xff th_8*/ + odm_set_bb_reg(dm, ODM_REG_NHM_TH8_11AC, MASKBYTE0, 0xff); + /*0x994[10:8]=1 ignoreCCA ignore PHYTXON enable CCX*/ + odm_set_bb_reg(dm, ODM_REG_NHM_TH9_TH10_11AC, + BIT(8) | BIT(9) | BIT(10), 0x1); + /*0x9e8[7]=1 max power among all RX ants*/ + odm_set_bb_reg(dm, ODM_REG_NHM_9E8_11AC, BIT(0), 0x1); + } +} + +void phydm_nhm_counter_statistics(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + + if (!(dm->support_ability & ODM_BB_NHM_CNT)) + return; + + /*Get NHM report*/ + phydm_get_nhm_counter_statistics(dm); + + /*Reset NHM counter*/ + phydm_nhm_counter_statistics_reset(dm); +} + +void phydm_get_nhm_counter_statistics(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + u32 value32 = 0; + + if (dm->support_ic_type & ODM_IC_11AC_SERIES) + value32 = odm_get_bb_reg(dm, ODM_REG_NHM_CNT_11AC, MASKDWORD); + else if (dm->support_ic_type & ODM_IC_11N_SERIES) + value32 = odm_get_bb_reg(dm, ODM_REG_NHM_CNT_11N, MASKDWORD); + + dm->nhm_cnt_0 = (u8)(value32 & MASKBYTE0); + dm->nhm_cnt_1 = (u8)((value32 & MASKBYTE1) >> 8); +} + +void phydm_nhm_counter_statistics_reset(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + + if (dm->support_ic_type & ODM_IC_11N_SERIES) { + odm_set_bb_reg(dm, ODM_REG_NHM_TH9_TH10_11N, BIT(1), 0); + odm_set_bb_reg(dm, ODM_REG_NHM_TH9_TH10_11N, BIT(1), 1); + } else if (dm->support_ic_type & ODM_IC_11AC_SERIES) { + odm_set_bb_reg(dm, ODM_REG_NHM_TH9_TH10_11AC, BIT(1), 0); + odm_set_bb_reg(dm, ODM_REG_NHM_TH9_TH10_11AC, BIT(1), 1); + } +} + +void phydm_set_edcca_threshold(void *dm_void, s8 H2L, s8 L2H) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + + if (dm->support_ic_type & ODM_IC_11N_SERIES) + odm_set_bb_reg(dm, REG_OFDM_0_ECCA_THRESHOLD, + MASKBYTE2 | MASKBYTE0, + (u32)((u8)L2H | (u8)H2L << 16)); + else if (dm->support_ic_type & ODM_IC_11AC_SERIES) + odm_set_bb_reg(dm, REG_FPGA0_XB_LSSI_READ_BACK, MASKLWORD, + (u16)((u8)L2H | (u8)H2L << 8)); +} + +static void phydm_set_lna(void *dm_void, enum phydm_set_lna type) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + + if (dm->support_ic_type & (ODM_RTL8188E | ODM_RTL8192E)) { + if (type == phydm_disable_lna) { + odm_set_rf_reg(dm, ODM_RF_PATH_A, 0xef, 0x80000, 0x1); + odm_set_rf_reg(dm, ODM_RF_PATH_A, 0x30, 0xfffff, + 0x18000); /*select Rx mode*/ + odm_set_rf_reg(dm, ODM_RF_PATH_A, 0x31, 0xfffff, + 0x0000f); + odm_set_rf_reg(dm, ODM_RF_PATH_A, 0x32, 0xfffff, + 0x37f82); /*disable LNA*/ + odm_set_rf_reg(dm, ODM_RF_PATH_A, 0xef, 0x80000, 0x0); + if (dm->rf_type > ODM_1T1R) { + odm_set_rf_reg(dm, ODM_RF_PATH_B, 0xef, 0x80000, + 0x1); + odm_set_rf_reg(dm, ODM_RF_PATH_B, 0x30, 0xfffff, + 0x18000); + odm_set_rf_reg(dm, ODM_RF_PATH_B, 0x31, 0xfffff, + 0x0000f); + odm_set_rf_reg(dm, ODM_RF_PATH_B, 0x32, 0xfffff, + 0x37f82); + odm_set_rf_reg(dm, ODM_RF_PATH_B, 0xef, 0x80000, + 0x0); + } + } else if (type == phydm_enable_lna) { + odm_set_rf_reg(dm, ODM_RF_PATH_A, 0xef, 0x80000, 0x1); + odm_set_rf_reg(dm, ODM_RF_PATH_A, 0x30, 0xfffff, + 0x18000); /*select Rx mode*/ + odm_set_rf_reg(dm, ODM_RF_PATH_A, 0x31, 0xfffff, + 0x0000f); + odm_set_rf_reg(dm, ODM_RF_PATH_A, 0x32, 0xfffff, + 0x77f82); /*back to normal*/ + odm_set_rf_reg(dm, ODM_RF_PATH_A, 0xef, 0x80000, 0x0); + if (dm->rf_type > ODM_1T1R) { + odm_set_rf_reg(dm, ODM_RF_PATH_B, 0xef, 0x80000, + 0x1); + odm_set_rf_reg(dm, ODM_RF_PATH_B, 0x30, 0xfffff, + 0x18000); + odm_set_rf_reg(dm, ODM_RF_PATH_B, 0x31, 0xfffff, + 0x0000f); + odm_set_rf_reg(dm, ODM_RF_PATH_B, 0x32, 0xfffff, + 0x77f82); + odm_set_rf_reg(dm, ODM_RF_PATH_B, 0xef, 0x80000, + 0x0); + } + } + } else if (dm->support_ic_type & ODM_RTL8723B) { + if (type == phydm_disable_lna) { + /*S0*/ + odm_set_rf_reg(dm, ODM_RF_PATH_A, 0xef, 0x80000, 0x1); + odm_set_rf_reg(dm, ODM_RF_PATH_A, 0x30, 0xfffff, + 0x18000); /*select Rx mode*/ + odm_set_rf_reg(dm, ODM_RF_PATH_A, 0x31, 0xfffff, + 0x0001f); + odm_set_rf_reg(dm, ODM_RF_PATH_A, 0x32, 0xfffff, + 0xe6137); /*disable LNA*/ + odm_set_rf_reg(dm, ODM_RF_PATH_A, 0xef, 0x80000, 0x0); + /*S1*/ + odm_set_rf_reg(dm, ODM_RF_PATH_A, 0xed, 0x00020, 0x1); + odm_set_rf_reg( + dm, ODM_RF_PATH_A, 0x43, 0xfffff, + 0x3008d); /*select Rx mode and disable LNA*/ + odm_set_rf_reg(dm, ODM_RF_PATH_A, 0xed, 0x00020, 0x0); + } else if (type == phydm_enable_lna) { + /*S0*/ + odm_set_rf_reg(dm, ODM_RF_PATH_A, 0xef, 0x80000, 0x1); + odm_set_rf_reg(dm, ODM_RF_PATH_A, 0x30, 0xfffff, + 0x18000); /*select Rx mode*/ + odm_set_rf_reg(dm, ODM_RF_PATH_A, 0x31, 0xfffff, + 0x0001f); + odm_set_rf_reg(dm, ODM_RF_PATH_A, 0x32, 0xfffff, + 0xe6177); /*disable LNA*/ + odm_set_rf_reg(dm, ODM_RF_PATH_A, 0xef, 0x80000, 0x0); + /*S1*/ + odm_set_rf_reg(dm, ODM_RF_PATH_A, 0xed, 0x00020, 0x1); + odm_set_rf_reg( + dm, ODM_RF_PATH_A, 0x43, 0xfffff, + 0x300bd); /*select Rx mode and disable LNA*/ + odm_set_rf_reg(dm, ODM_RF_PATH_A, 0xed, 0x00020, 0x0); + } + + } else if (dm->support_ic_type & ODM_RTL8812) { + if (type == phydm_disable_lna) { + odm_set_rf_reg(dm, ODM_RF_PATH_A, 0xef, 0x80000, 0x1); + odm_set_rf_reg(dm, ODM_RF_PATH_A, 0x30, 0xfffff, + 0x18000); /*select Rx mode*/ + odm_set_rf_reg(dm, ODM_RF_PATH_A, 0x31, 0xfffff, + 0x3f7ff); + odm_set_rf_reg(dm, ODM_RF_PATH_A, 0x32, 0xfffff, + 0xc22bf); /*disable LNA*/ + odm_set_rf_reg(dm, ODM_RF_PATH_A, 0xef, 0x80000, 0x0); + if (dm->rf_type > ODM_1T1R) { + odm_set_rf_reg(dm, ODM_RF_PATH_B, 0xef, 0x80000, + 0x1); + odm_set_rf_reg(dm, ODM_RF_PATH_B, 0x30, 0xfffff, + 0x18000); /*select Rx mode*/ + odm_set_rf_reg(dm, ODM_RF_PATH_B, 0x31, 0xfffff, + 0x3f7ff); + odm_set_rf_reg(dm, ODM_RF_PATH_B, 0x32, 0xfffff, + 0xc22bf); /*disable LNA*/ + odm_set_rf_reg(dm, ODM_RF_PATH_B, 0xef, 0x80000, + 0x0); + } + } else if (type == phydm_enable_lna) { + odm_set_rf_reg(dm, ODM_RF_PATH_A, 0xef, 0x80000, 0x1); + odm_set_rf_reg(dm, ODM_RF_PATH_A, 0x30, 0xfffff, + 0x18000); /*select Rx mode*/ + odm_set_rf_reg(dm, ODM_RF_PATH_A, 0x31, 0xfffff, + 0x3f7ff); + odm_set_rf_reg(dm, ODM_RF_PATH_A, 0x32, 0xfffff, + 0xc26bf); /*disable LNA*/ + odm_set_rf_reg(dm, ODM_RF_PATH_A, 0xef, 0x80000, 0x0); + if (dm->rf_type > ODM_1T1R) { + odm_set_rf_reg(dm, ODM_RF_PATH_B, 0xef, 0x80000, + 0x1); + odm_set_rf_reg(dm, ODM_RF_PATH_B, 0x30, 0xfffff, + 0x18000); /*select Rx mode*/ + odm_set_rf_reg(dm, ODM_RF_PATH_B, 0x31, 0xfffff, + 0x3f7ff); + odm_set_rf_reg(dm, ODM_RF_PATH_B, 0x32, 0xfffff, + 0xc26bf); /*disable LNA*/ + odm_set_rf_reg(dm, ODM_RF_PATH_B, 0xef, 0x80000, + 0x0); + } + } + } else if (dm->support_ic_type & (ODM_RTL8821 | ODM_RTL8881A)) { + if (type == phydm_disable_lna) { + odm_set_rf_reg(dm, ODM_RF_PATH_A, 0xef, 0x80000, 0x1); + odm_set_rf_reg(dm, ODM_RF_PATH_A, 0x30, 0xfffff, + 0x18000); /*select Rx mode*/ + odm_set_rf_reg(dm, ODM_RF_PATH_A, 0x31, 0xfffff, + 0x0002f); + odm_set_rf_reg(dm, ODM_RF_PATH_A, 0x32, 0xfffff, + 0xfb09b); /*disable LNA*/ + odm_set_rf_reg(dm, ODM_RF_PATH_A, 0xef, 0x80000, 0x0); + } else if (type == phydm_enable_lna) { + odm_set_rf_reg(dm, ODM_RF_PATH_A, 0xef, 0x80000, 0x1); + odm_set_rf_reg(dm, ODM_RF_PATH_A, 0x30, 0xfffff, + 0x18000); /*select Rx mode*/ + odm_set_rf_reg(dm, ODM_RF_PATH_A, 0x31, 0xfffff, + 0x0002f); + odm_set_rf_reg(dm, ODM_RF_PATH_A, 0x32, 0xfffff, + 0xfb0bb); /*disable LNA*/ + odm_set_rf_reg(dm, ODM_RF_PATH_A, 0xef, 0x80000, 0x0); + } + } +} + +void phydm_set_trx_mux(void *dm_void, enum phydm_trx_mux_type tx_mode, + enum phydm_trx_mux_type rx_mode) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + + if (dm->support_ic_type & ODM_IC_11N_SERIES) { + /*set TXmod to standby mode to remove outside noise affect*/ + odm_set_bb_reg(dm, ODM_REG_CCK_RPT_FORMAT_11N, + BIT(3) | BIT(2) | BIT(1), tx_mode); + /*set RXmod to standby mode to remove outside noise affect*/ + odm_set_bb_reg(dm, ODM_REG_CCK_RPT_FORMAT_11N, + BIT(22) | BIT(21) | BIT(20), rx_mode); + if (dm->rf_type > ODM_1T1R) { + /*set TXmod to standby mode to rm outside noise affect*/ + odm_set_bb_reg(dm, ODM_REG_CCK_RPT_FORMAT_11N_B, + BIT(3) | BIT(2) | BIT(1), tx_mode); + /*set RXmod to standby mode to rm outside noise affect*/ + odm_set_bb_reg(dm, ODM_REG_CCK_RPT_FORMAT_11N_B, + BIT(22) | BIT(21) | BIT(20), rx_mode); + } + } else if (dm->support_ic_type & ODM_IC_11AC_SERIES) { + /*set TXmod to standby mode to remove outside noise affect*/ + odm_set_bb_reg(dm, ODM_REG_TRMUX_11AC, + BIT(11) | BIT(10) | BIT(9) | BIT(8), tx_mode); + /*set RXmod to standby mode to remove outside noise affect*/ + odm_set_bb_reg(dm, ODM_REG_TRMUX_11AC, + BIT(7) | BIT(6) | BIT(5) | BIT(4), rx_mode); + if (dm->rf_type > ODM_1T1R) { + /*set TXmod to standby mode to rm outside noise affect*/ + odm_set_bb_reg(dm, ODM_REG_TRMUX_11AC_B, + BIT(11) | BIT(10) | BIT(9) | BIT(8), + tx_mode); + /*set RXmod to standby mode to rm outside noise affect*/ + odm_set_bb_reg(dm, ODM_REG_TRMUX_11AC_B, + BIT(7) | BIT(6) | BIT(5) | BIT(4), + rx_mode); + } + } +} + +void phydm_mac_edcca_state(void *dm_void, enum phydm_mac_edcca_type state) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + + if (state == phydm_ignore_edcca) { + /*ignore EDCCA reg520[15]=1*/ + odm_set_mac_reg(dm, REG_TX_PTCL_CTRL, BIT(15), 1); + } else { /*don't set MAC ignore EDCCA signal*/ + /*don't ignore EDCCA reg520[15]=0*/ + odm_set_mac_reg(dm, REG_TX_PTCL_CTRL, BIT(15), 0); + } + ODM_RT_TRACE(dm, PHYDM_COMP_ADAPTIVITY, "EDCCA enable state = %d\n", + state); +} + +bool phydm_cal_nhm_cnt(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + u16 base = 0; + + base = dm->nhm_cnt_0 + dm->nhm_cnt_1; + + if (base != 0) { + dm->nhm_cnt_0 = ((dm->nhm_cnt_0) << 8) / base; + dm->nhm_cnt_1 = ((dm->nhm_cnt_1) << 8) / base; + } + if ((dm->nhm_cnt_0 - dm->nhm_cnt_1) >= 100) + return true; /*clean environment*/ + else + return false; /*noisy environment*/ +} + +void phydm_check_environment(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct adaptivity_statistics *adaptivity = + (struct adaptivity_statistics *)phydm_get_structure( + dm, PHYDM_ADAPTIVITY); + bool is_clean_environment = false; + + if (adaptivity->is_first_link) { + if (dm->support_ic_type & + (ODM_IC_11AC_GAIN_IDX_EDCCA | ODM_IC_11N_GAIN_IDX_EDCCA)) + dm->adaptivity_flag = false; + else + dm->adaptivity_flag = true; + + adaptivity->is_first_link = false; + return; + } + + if (adaptivity->nhm_wait < 3) { /*Start enter NHM after 4 nhm_wait*/ + adaptivity->nhm_wait++; + phydm_nhm_counter_statistics(dm); + return; + } + + phydm_nhm_counter_statistics(dm); + is_clean_environment = phydm_cal_nhm_cnt(dm); + + if (is_clean_environment) { + dm->th_l2h_ini = + adaptivity->th_l2h_ini_backup; /*adaptivity mode*/ + dm->th_edcca_hl_diff = adaptivity->th_edcca_hl_diff_backup; + + dm->adaptivity_enable = true; + + if (dm->support_ic_type & + (ODM_IC_11AC_GAIN_IDX_EDCCA | ODM_IC_11N_GAIN_IDX_EDCCA)) + dm->adaptivity_flag = false; + else + dm->adaptivity_flag = true; + } else { + if (!adaptivity->acs_for_adaptivity) { + dm->th_l2h_ini = dm->th_l2h_ini_mode2; /*mode2*/ + dm->th_edcca_hl_diff = dm->th_edcca_hl_diff_mode2; + + dm->adaptivity_flag = false; + dm->adaptivity_enable = false; + } + } + + adaptivity->nhm_wait = 0; + adaptivity->is_first_link = true; + adaptivity->is_check = true; +} + +void phydm_search_pwdb_lower_bound(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct adaptivity_statistics *adaptivity = + (struct adaptivity_statistics *)phydm_get_structure( + dm, PHYDM_ADAPTIVITY); + u32 value32 = 0, reg_value32 = 0; + u8 cnt, try_count = 0; + u8 tx_edcca1 = 0, tx_edcca0 = 0; + bool is_adjust = true; + s8 th_l2h_dmc, th_h2l_dmc, igi_target = 0x32; + s8 diff; + u8 IGI = adaptivity->igi_base + 30 + (u8)dm->th_l2h_ini - + (u8)dm->th_edcca_hl_diff; + + if (dm->support_ic_type & (ODM_RTL8723B | ODM_RTL8188E | ODM_RTL8192E | + ODM_RTL8812 | ODM_RTL8821 | ODM_RTL8881A)) { + phydm_set_lna(dm, phydm_disable_lna); + } else { + phydm_set_trx_mux(dm, phydm_standby_mode, phydm_standby_mode); + odm_pause_dig(dm, PHYDM_PAUSE, PHYDM_PAUSE_LEVEL_0, 0x7e); + } + + diff = igi_target - (s8)IGI; + th_l2h_dmc = dm->th_l2h_ini + diff; + if (th_l2h_dmc > 10) + th_l2h_dmc = 10; + th_h2l_dmc = th_l2h_dmc - dm->th_edcca_hl_diff; + + phydm_set_edcca_threshold(dm, th_h2l_dmc, th_l2h_dmc); + ODM_delay_ms(30); + + while (is_adjust) { + if (dm->support_ic_type & ODM_IC_11N_SERIES) { + odm_set_bb_reg(dm, ODM_REG_DBG_RPT_11N, MASKDWORD, 0x0); + reg_value32 = + odm_get_bb_reg(dm, ODM_REG_RPT_11N, MASKDWORD); + } else if (dm->support_ic_type & ODM_IC_11AC_SERIES) { + odm_set_bb_reg(dm, ODM_REG_DBG_RPT_11AC, MASKDWORD, + 0x0); + reg_value32 = + odm_get_bb_reg(dm, ODM_REG_RPT_11AC, MASKDWORD); + } + while (reg_value32 & BIT(3) && try_count < 3) { + ODM_delay_ms(3); + try_count = try_count + 1; + if (dm->support_ic_type & ODM_IC_11N_SERIES) + reg_value32 = odm_get_bb_reg( + dm, ODM_REG_RPT_11N, MASKDWORD); + else if (dm->support_ic_type & ODM_IC_11AC_SERIES) + reg_value32 = odm_get_bb_reg( + dm, ODM_REG_RPT_11AC, MASKDWORD); + } + try_count = 0; + + for (cnt = 0; cnt < 20; cnt++) { + if (dm->support_ic_type & ODM_IC_11N_SERIES) { + odm_set_bb_reg(dm, ODM_REG_DBG_RPT_11N, + MASKDWORD, 0x208); + value32 = odm_get_bb_reg(dm, ODM_REG_RPT_11N, + MASKDWORD); + } else if (dm->support_ic_type & ODM_IC_11AC_SERIES) { + odm_set_bb_reg(dm, ODM_REG_DBG_RPT_11AC, + MASKDWORD, 0x209); + value32 = odm_get_bb_reg(dm, ODM_REG_RPT_11AC, + MASKDWORD); + } + if (value32 & BIT(30) && + (dm->support_ic_type & + (ODM_RTL8723B | ODM_RTL8188E))) + tx_edcca1 = tx_edcca1 + 1; + else if (value32 & BIT(29)) + tx_edcca1 = tx_edcca1 + 1; + else + tx_edcca0 = tx_edcca0 + 1; + } + + if (tx_edcca1 > 1) { + IGI = IGI - 1; + th_l2h_dmc = th_l2h_dmc + 1; + if (th_l2h_dmc > 10) + th_l2h_dmc = 10; + th_h2l_dmc = th_l2h_dmc - dm->th_edcca_hl_diff; + + phydm_set_edcca_threshold(dm, th_h2l_dmc, th_l2h_dmc); + if (th_l2h_dmc == 10) { + is_adjust = false; + adaptivity->h2l_lb = th_h2l_dmc; + adaptivity->l2h_lb = th_l2h_dmc; + dm->adaptivity_igi_upper = IGI; + } + + tx_edcca1 = 0; + tx_edcca0 = 0; + + } else { + is_adjust = false; + adaptivity->h2l_lb = th_h2l_dmc; + adaptivity->l2h_lb = th_l2h_dmc; + dm->adaptivity_igi_upper = IGI; + tx_edcca1 = 0; + tx_edcca0 = 0; + } + } + + dm->adaptivity_igi_upper = dm->adaptivity_igi_upper - dm->dc_backoff; + adaptivity->h2l_lb = adaptivity->h2l_lb + dm->dc_backoff; + adaptivity->l2h_lb = adaptivity->l2h_lb + dm->dc_backoff; + + if (dm->support_ic_type & (ODM_RTL8723B | ODM_RTL8188E | ODM_RTL8192E | + ODM_RTL8812 | ODM_RTL8821 | ODM_RTL8881A)) { + phydm_set_lna(dm, phydm_enable_lna); + } else { + phydm_set_trx_mux(dm, phydm_tx_mode, phydm_rx_mode); + odm_pause_dig(dm, PHYDM_RESUME, PHYDM_PAUSE_LEVEL_0, NONE); + } + + phydm_set_edcca_threshold(dm, 0x7f, 0x7f); /*resume to no link state*/ +} + +static bool phydm_re_search_condition(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + u8 adaptivity_igi_upper; + u8 count = 0; + + adaptivity_igi_upper = dm->adaptivity_igi_upper + dm->dc_backoff; + + if (adaptivity_igi_upper <= 0x26 && count < 3) { + count = count + 1; + return true; + } + + return false; +} + +void phydm_adaptivity_info_init(void *dm_void, enum phydm_adapinfo cmn_info, + u32 value) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct adaptivity_statistics *adaptivity = + (struct adaptivity_statistics *)phydm_get_structure( + dm, PHYDM_ADAPTIVITY); + + switch (cmn_info) { + case PHYDM_ADAPINFO_CARRIER_SENSE_ENABLE: + dm->carrier_sense_enable = (bool)value; + break; + + case PHYDM_ADAPINFO_DCBACKOFF: + dm->dc_backoff = (u8)value; + break; + + case PHYDM_ADAPINFO_DYNAMICLINKADAPTIVITY: + adaptivity->dynamic_link_adaptivity = (bool)value; + break; + + case PHYDM_ADAPINFO_TH_L2H_INI: + dm->th_l2h_ini = (s8)value; + break; + + case PHYDM_ADAPINFO_TH_EDCCA_HL_DIFF: + dm->th_edcca_hl_diff = (s8)value; + break; + + case PHYDM_ADAPINFO_AP_NUM_TH: + adaptivity->ap_num_th = (u8)value; + break; + + default: + break; + } +} + +void phydm_adaptivity_init(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct adaptivity_statistics *adaptivity = + (struct adaptivity_statistics *)phydm_get_structure( + dm, PHYDM_ADAPTIVITY); + s8 igi_target = 0x32; + + if (!dm->carrier_sense_enable) { + if (dm->th_l2h_ini == 0) + dm->th_l2h_ini = 0xf5; + } else { + dm->th_l2h_ini = 0xa; + } + + if (dm->th_edcca_hl_diff == 0) + dm->th_edcca_hl_diff = 7; + if (dm->wifi_test || dm->mp_mode) { + /*even no adaptivity, we still enable EDCCA, AP use mib ctrl*/ + dm->edcca_enable = false; + } else { + dm->edcca_enable = true; + } + + dm->adaptivity_igi_upper = 0; + dm->adaptivity_enable = + false; /*use this flag to decide enable or disable*/ + + dm->th_l2h_ini_mode2 = 20; + dm->th_edcca_hl_diff_mode2 = 8; + adaptivity->th_l2h_ini_backup = dm->th_l2h_ini; + adaptivity->th_edcca_hl_diff_backup = dm->th_edcca_hl_diff; + + adaptivity->igi_base = 0x32; + adaptivity->igi_target = 0x1c; + adaptivity->h2l_lb = 0; + adaptivity->l2h_lb = 0; + adaptivity->nhm_wait = 0; + adaptivity->is_check = false; + adaptivity->is_first_link = true; + adaptivity->adajust_igi_level = 0; + adaptivity->is_stop_edcca = false; + adaptivity->backup_h2l = 0; + adaptivity->backup_l2h = 0; + + phydm_mac_edcca_state(dm, phydm_dont_ignore_edcca); + + /*Search pwdB lower bound*/ + if (dm->support_ic_type & ODM_IC_11N_SERIES) + odm_set_bb_reg(dm, ODM_REG_DBG_RPT_11N, MASKDWORD, 0x208); + else if (dm->support_ic_type & ODM_IC_11AC_SERIES) + odm_set_bb_reg(dm, ODM_REG_DBG_RPT_11AC, MASKDWORD, 0x209); + + if (dm->support_ic_type & ODM_IC_11N_GAIN_IDX_EDCCA) { + if (dm->support_ic_type & ODM_RTL8197F) { + /*set to page B1*/ + odm_set_bb_reg(dm, ODM_REG_PAGE_B1_97F, BIT(30), 0x1); + /*0:rx_dfir, 1: dcnf_out, 2 :rx_iq, 3: rx_nbi_nf_out*/ + odm_set_bb_reg(dm, ODM_REG_EDCCA_DCNF_97F, + BIT(27) | BIT(26), 0x1); + odm_set_bb_reg(dm, ODM_REG_PAGE_B1_97F, BIT(30), 0x0); + } else { + /*0:rx_dfir, 1: dcnf_out, 2 :rx_iq, 3: rx_nbi_nf_out*/ + odm_set_bb_reg(dm, ODM_REG_EDCCA_DCNF_11N, + BIT(21) | BIT(20), 0x1); + } + } + /*8814a no need to find pwdB lower bound, maybe*/ + if (dm->support_ic_type & ODM_IC_11AC_GAIN_IDX_EDCCA) { + /*0:rx_dfir, 1: dcnf_out, 2 :rx_iq, 3: rx_nbi_nf_out*/ + odm_set_bb_reg(dm, ODM_REG_ACBB_EDCCA_ENHANCE, + BIT(29) | BIT(28), 0x1); + } + + if (!(dm->support_ic_type & + (ODM_IC_11AC_GAIN_IDX_EDCCA | ODM_IC_11N_GAIN_IDX_EDCCA))) { + phydm_search_pwdb_lower_bound(dm); + if (phydm_re_search_condition(dm)) + phydm_search_pwdb_lower_bound(dm); + } + + /*we need to consider PwdB upper bound for 8814 later IC*/ + adaptivity->adajust_igi_level = + (u8)((dm->th_l2h_ini + igi_target) - pwdb_upper_bound + + dfir_loss); /*IGI = L2H - PwdB - dfir_loss*/ + + ODM_RT_TRACE( + dm, PHYDM_COMP_ADAPTIVITY, + "th_l2h_ini = 0x%x, th_edcca_hl_diff = 0x%x, adaptivity->adajust_igi_level = 0x%x\n", + dm->th_l2h_ini, dm->th_edcca_hl_diff, + adaptivity->adajust_igi_level); + + /*Check this later on Windows*/ + /*phydm_set_edcca_threshold_api(dm, dig_tab->cur_ig_value);*/ +} + +void phydm_adaptivity(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct dig_thres *dig_tab = &dm->dm_dig_table; + u8 IGI = dig_tab->cur_ig_value; + s8 th_l2h_dmc, th_h2l_dmc; + s8 diff = 0, igi_target; + struct adaptivity_statistics *adaptivity = + (struct adaptivity_statistics *)phydm_get_structure( + dm, PHYDM_ADAPTIVITY); + + if (!dm->edcca_enable || adaptivity->is_stop_edcca) { + ODM_RT_TRACE(dm, PHYDM_COMP_ADAPTIVITY, "Disable EDCCA!!!\n"); + return; + } + + if (!(dm->support_ability & ODM_BB_ADAPTIVITY)) { + ODM_RT_TRACE(dm, PHYDM_COMP_ADAPTIVITY, + "adaptivity disable, enable EDCCA mode!!!\n"); + dm->th_l2h_ini = dm->th_l2h_ini_mode2; + dm->th_edcca_hl_diff = dm->th_edcca_hl_diff_mode2; + } + + ODM_RT_TRACE(dm, PHYDM_COMP_ADAPTIVITY, "%s() =====>\n", __func__); + ODM_RT_TRACE(dm, PHYDM_COMP_ADAPTIVITY, + "igi_base=0x%x, th_l2h_ini = %d, th_edcca_hl_diff = %d\n", + adaptivity->igi_base, dm->th_l2h_ini, + dm->th_edcca_hl_diff); + if (dm->support_ic_type & ODM_IC_11AC_SERIES) { + /*fix AC series when enable EDCCA hang issue*/ + odm_set_bb_reg(dm, 0x800, BIT(10), 1); /*ADC_mask disable*/ + odm_set_bb_reg(dm, 0x800, BIT(10), 0); /*ADC_mask enable*/ + } + if (*dm->band_width == ODM_BW20M) /*CHANNEL_WIDTH_20*/ + igi_target = adaptivity->igi_base; + else if (*dm->band_width == ODM_BW40M) + igi_target = adaptivity->igi_base + 2; + else if (*dm->band_width == ODM_BW80M) + igi_target = adaptivity->igi_base + 2; + else + igi_target = adaptivity->igi_base; + adaptivity->igi_target = (u8)igi_target; + + ODM_RT_TRACE( + dm, PHYDM_COMP_ADAPTIVITY, + "band_width=%s, igi_target=0x%x, dynamic_link_adaptivity = %d, acs_for_adaptivity = %d\n", + (*dm->band_width == ODM_BW80M) ? + "80M" : + ((*dm->band_width == ODM_BW40M) ? "40M" : "20M"), + igi_target, adaptivity->dynamic_link_adaptivity, + adaptivity->acs_for_adaptivity); + ODM_RT_TRACE( + dm, PHYDM_COMP_ADAPTIVITY, + "rssi_min = %d, adaptivity->adajust_igi_level= 0x%x, adaptivity_flag = %d, adaptivity_enable = %d\n", + dm->rssi_min, adaptivity->adajust_igi_level, + dm->adaptivity_flag, dm->adaptivity_enable); + + if (adaptivity->dynamic_link_adaptivity && (!dm->is_linked) && + !dm->adaptivity_enable) { + phydm_set_edcca_threshold(dm, 0x7f, 0x7f); + ODM_RT_TRACE( + dm, PHYDM_COMP_ADAPTIVITY, + "In DynamicLink mode(noisy) and No link, Turn off EDCCA!!\n"); + return; + } + + if (dm->support_ic_type & + (ODM_IC_11AC_GAIN_IDX_EDCCA | ODM_IC_11N_GAIN_IDX_EDCCA)) { + if ((adaptivity->adajust_igi_level > IGI) && + dm->adaptivity_enable) + diff = adaptivity->adajust_igi_level - IGI; + + th_l2h_dmc = dm->th_l2h_ini - diff + igi_target; + th_h2l_dmc = th_l2h_dmc - dm->th_edcca_hl_diff; + } else { + diff = igi_target - (s8)IGI; + th_l2h_dmc = dm->th_l2h_ini + diff; + if (th_l2h_dmc > 10 && dm->adaptivity_enable) + th_l2h_dmc = 10; + + th_h2l_dmc = th_l2h_dmc - dm->th_edcca_hl_diff; + + /*replace lower bound to prevent EDCCA always equal 1*/ + if (th_h2l_dmc < adaptivity->h2l_lb) + th_h2l_dmc = adaptivity->h2l_lb; + if (th_l2h_dmc < adaptivity->l2h_lb) + th_l2h_dmc = adaptivity->l2h_lb; + } + ODM_RT_TRACE(dm, PHYDM_COMP_ADAPTIVITY, + "IGI=0x%x, th_l2h_dmc = %d, th_h2l_dmc = %d\n", IGI, + th_l2h_dmc, th_h2l_dmc); + ODM_RT_TRACE( + dm, PHYDM_COMP_ADAPTIVITY, + "adaptivity_igi_upper=0x%x, h2l_lb = 0x%x, l2h_lb = 0x%x\n", + dm->adaptivity_igi_upper, adaptivity->h2l_lb, + adaptivity->l2h_lb); + + phydm_set_edcca_threshold(dm, th_h2l_dmc, th_l2h_dmc); + + if (dm->adaptivity_enable) + odm_set_mac_reg(dm, REG_RD_CTRL, BIT(11), 1); +} + +/*This is for solving USB can't Tx problem due to USB3.0 interference in 2.4G*/ +void phydm_pause_edcca(void *dm_void, bool is_pasue_edcca) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct adaptivity_statistics *adaptivity = + (struct adaptivity_statistics *)phydm_get_structure( + dm, PHYDM_ADAPTIVITY); + struct dig_thres *dig_tab = &dm->dm_dig_table; + u8 IGI = dig_tab->cur_ig_value; + s8 diff = 0; + + if (is_pasue_edcca) { + adaptivity->is_stop_edcca = true; + + if (dm->support_ic_type & + (ODM_IC_11AC_GAIN_IDX_EDCCA | ODM_IC_11N_GAIN_IDX_EDCCA)) { + if (adaptivity->adajust_igi_level > IGI) + diff = adaptivity->adajust_igi_level - IGI; + + adaptivity->backup_l2h = + dm->th_l2h_ini - diff + adaptivity->igi_target; + adaptivity->backup_h2l = + adaptivity->backup_l2h - dm->th_edcca_hl_diff; + } else { + diff = adaptivity->igi_target - (s8)IGI; + adaptivity->backup_l2h = dm->th_l2h_ini + diff; + if (adaptivity->backup_l2h > 10) + adaptivity->backup_l2h = 10; + + adaptivity->backup_h2l = + adaptivity->backup_l2h - dm->th_edcca_hl_diff; + + /*replace lower bound to prevent EDCCA always equal 1*/ + if (adaptivity->backup_h2l < adaptivity->h2l_lb) + adaptivity->backup_h2l = adaptivity->h2l_lb; + if (adaptivity->backup_l2h < adaptivity->l2h_lb) + adaptivity->backup_l2h = adaptivity->l2h_lb; + } + ODM_RT_TRACE( + dm, PHYDM_COMP_ADAPTIVITY, + "pauseEDCCA : L2Hbak = 0x%x, H2Lbak = 0x%x, IGI = 0x%x\n", + adaptivity->backup_l2h, adaptivity->backup_h2l, IGI); + + /*Disable EDCCA*/ + phydm_pause_edcca_work_item_callback(dm); + + } else { + adaptivity->is_stop_edcca = false; + ODM_RT_TRACE( + dm, PHYDM_COMP_ADAPTIVITY, + "resumeEDCCA : L2Hbak = 0x%x, H2Lbak = 0x%x, IGI = 0x%x\n", + adaptivity->backup_l2h, adaptivity->backup_h2l, IGI); + /*Resume EDCCA*/ + phydm_resume_edcca_work_item_callback(dm); + } +} + +void phydm_pause_edcca_work_item_callback(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + + if (dm->support_ic_type & ODM_IC_11N_SERIES) + odm_set_bb_reg(dm, REG_OFDM_0_ECCA_THRESHOLD, + MASKBYTE2 | MASKBYTE0, (u32)(0x7f | 0x7f << 16)); + else if (dm->support_ic_type & ODM_IC_11AC_SERIES) + odm_set_bb_reg(dm, REG_FPGA0_XB_LSSI_READ_BACK, MASKLWORD, + (u16)(0x7f | 0x7f << 8)); +} + +void phydm_resume_edcca_work_item_callback(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct adaptivity_statistics *adaptivity = + (struct adaptivity_statistics *)phydm_get_structure( + dm, PHYDM_ADAPTIVITY); + + if (dm->support_ic_type & ODM_IC_11N_SERIES) + odm_set_bb_reg(dm, REG_OFDM_0_ECCA_THRESHOLD, + MASKBYTE2 | MASKBYTE0, + (u32)((u8)adaptivity->backup_l2h | + (u8)adaptivity->backup_h2l << 16)); + else if (dm->support_ic_type & ODM_IC_11AC_SERIES) + odm_set_bb_reg(dm, REG_FPGA0_XB_LSSI_READ_BACK, MASKLWORD, + (u16)((u8)adaptivity->backup_l2h | + (u8)adaptivity->backup_h2l << 8)); +} + +void phydm_set_edcca_threshold_api(void *dm_void, u8 IGI) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct adaptivity_statistics *adaptivity = + (struct adaptivity_statistics *)phydm_get_structure( + dm, PHYDM_ADAPTIVITY); + s8 th_l2h_dmc, th_h2l_dmc; + s8 diff = 0, igi_target = 0x32; + + if (dm->support_ability & ODM_BB_ADAPTIVITY) { + if (dm->support_ic_type & + (ODM_IC_11AC_GAIN_IDX_EDCCA | ODM_IC_11N_GAIN_IDX_EDCCA)) { + if (adaptivity->adajust_igi_level > IGI) + diff = adaptivity->adajust_igi_level - IGI; + + th_l2h_dmc = dm->th_l2h_ini - diff + igi_target; + th_h2l_dmc = th_l2h_dmc - dm->th_edcca_hl_diff; + } else { + diff = igi_target - (s8)IGI; + th_l2h_dmc = dm->th_l2h_ini + diff; + if (th_l2h_dmc > 10) + th_l2h_dmc = 10; + + th_h2l_dmc = th_l2h_dmc - dm->th_edcca_hl_diff; + + /*replace lower bound to prevent EDCCA always equal 1*/ + if (th_h2l_dmc < adaptivity->h2l_lb) + th_h2l_dmc = adaptivity->h2l_lb; + if (th_l2h_dmc < adaptivity->l2h_lb) + th_l2h_dmc = adaptivity->l2h_lb; + } + ODM_RT_TRACE( + dm, PHYDM_COMP_ADAPTIVITY, + "API :IGI=0x%x, th_l2h_dmc = %d, th_h2l_dmc = %d\n", + IGI, th_l2h_dmc, th_h2l_dmc); + ODM_RT_TRACE( + dm, PHYDM_COMP_ADAPTIVITY, + "API :adaptivity_igi_upper=0x%x, h2l_lb = 0x%x, l2h_lb = 0x%x\n", + dm->adaptivity_igi_upper, adaptivity->h2l_lb, + adaptivity->l2h_lb); + + phydm_set_edcca_threshold(dm, th_h2l_dmc, th_l2h_dmc); + } +} diff --git a/drivers/staging/rtlwifi/phydm/phydm_adaptivity.h b/drivers/staging/rtlwifi/phydm/phydm_adaptivity.h new file mode 100644 index 000000000000..fdb39b4f9df2 --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/phydm_adaptivity.h @@ -0,0 +1,119 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __PHYDMADAPTIVITY_H__ +#define __PHYDMADAPTIVITY_H__ + +/*20160902 changed by Kevin, refine method for searching pwdb lower bound*/ +#define ADAPTIVITY_VERSION "9.3.5" + +#define pwdb_upper_bound 7 +#define dfir_loss 5 + +enum phydm_adapinfo { + PHYDM_ADAPINFO_CARRIER_SENSE_ENABLE = 0, + PHYDM_ADAPINFO_DCBACKOFF, + PHYDM_ADAPINFO_DYNAMICLINKADAPTIVITY, + PHYDM_ADAPINFO_TH_L2H_INI, + PHYDM_ADAPINFO_TH_EDCCA_HL_DIFF, + PHYDM_ADAPINFO_AP_NUM_TH + +}; + +enum phydm_set_lna { + phydm_disable_lna = 0, + phydm_enable_lna = 1, +}; + +enum phydm_trx_mux_type { + phydm_shutdown = 0, + phydm_standby_mode = 1, + phydm_tx_mode = 2, + phydm_rx_mode = 3 +}; + +enum phydm_mac_edcca_type { + phydm_ignore_edcca = 0, + phydm_dont_ignore_edcca = 1 +}; + +struct adaptivity_statistics { + s8 th_l2h_ini_backup; + s8 th_edcca_hl_diff_backup; + s8 igi_base; + u8 igi_target; + u8 nhm_wait; + s8 h2l_lb; + s8 l2h_lb; + bool is_first_link; + bool is_check; + bool dynamic_link_adaptivity; + u8 ap_num_th; + u8 adajust_igi_level; + bool acs_for_adaptivity; + s8 backup_l2h; + s8 backup_h2l; + bool is_stop_edcca; +}; + +void phydm_pause_edcca(void *dm_void, bool is_pasue_edcca); + +void phydm_check_adaptivity(void *dm_void); + +void phydm_check_environment(void *dm_void); + +void phydm_nhm_counter_statistics_init(void *dm_void); + +void phydm_nhm_counter_statistics(void *dm_void); + +void phydm_nhm_counter_statistics_reset(void *dm_void); + +void phydm_get_nhm_counter_statistics(void *dm_void); + +void phydm_mac_edcca_state(void *dm_void, enum phydm_mac_edcca_type state); + +void phydm_set_edcca_threshold(void *dm_void, s8 H2L, s8 L2H); + +void phydm_set_trx_mux(void *dm_void, enum phydm_trx_mux_type tx_mode, + enum phydm_trx_mux_type rx_mode); + +bool phydm_cal_nhm_cnt(void *dm_void); + +void phydm_search_pwdb_lower_bound(void *dm_void); + +void phydm_adaptivity_info_init(void *dm_void, enum phydm_adapinfo cmn_info, + u32 value); + +void phydm_adaptivity_init(void *dm_void); + +void phydm_adaptivity(void *dm_void); + +void phydm_set_edcca_threshold_api(void *dm_void, u8 IGI); + +void phydm_pause_edcca_work_item_callback(void *dm_void); + +void phydm_resume_edcca_work_item_callback(void *dm_void); + +#endif diff --git a/drivers/staging/rtlwifi/phydm/phydm_adc_sampling.c b/drivers/staging/rtlwifi/phydm/phydm_adc_sampling.c new file mode 100644 index 000000000000..158dd5d05de4 --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/phydm_adc_sampling.c @@ -0,0 +1,628 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#include "mp_precomp.h" +#include "phydm_precomp.h" + +static bool phydm_la_buffer_allocate(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct rt_adcsmp *adc_smp = &dm->adcsmp; + struct rt_adcsmp_string *adc_smp_buf = &adc_smp->adc_smp_buf; + bool ret = false; + + ODM_RT_TRACE(dm, ODM_COMP_UNCOND, "[LA mode BufferAllocate]\n"); + + if (adc_smp_buf->length == 0) { + odm_allocate_memory(dm, (void **)&adc_smp_buf->octet, + adc_smp_buf->buffer_size); + if (!adc_smp_buf->octet) { + ret = false; + } else { + adc_smp_buf->length = adc_smp_buf->buffer_size; + ret = true; + } + } + + return ret; +} + +static void phydm_la_get_tx_pkt_buf(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct rt_adcsmp *adc_smp = &dm->adcsmp; + struct rt_adcsmp_string *adc_smp_buf = &adc_smp->adc_smp_buf; + u32 i = 0, value32, data_l = 0, data_h = 0; + u32 addr, finish_addr; + u32 end_addr = (adc_smp_buf->start_pos + adc_smp_buf->buffer_size) - + 1; /*end_addr = 0x3ffff;*/ + bool is_round_up; + static u32 page = 0xFF; + u32 smp_cnt = 0, smp_number = 0, addr_8byte = 0; + + odm_memory_set(dm, adc_smp_buf->octet, 0, adc_smp_buf->length); + odm_write_1byte(dm, 0x0106, 0x69); + + ODM_RT_TRACE(dm, ODM_COMP_UNCOND, "GetTxPktBuf\n"); + + value32 = odm_read_4byte(dm, 0x7c0); + is_round_up = (bool)((value32 & BIT(31)) >> 31); + /*Reg7C0[30:16]: finish addr (unit: 8byte)*/ + finish_addr = (value32 & 0x7FFF0000) >> 16; + + if (is_round_up) { + addr = (finish_addr + 1) << 3; + ODM_RT_TRACE( + dm, ODM_COMP_UNCOND, + "is_round_up = ((%d)), finish_addr=((0x%x)), 0x7c0=((0x%x))\n", + is_round_up, finish_addr, value32); + /*Byte to 64Byte*/ + smp_number = ((adc_smp_buf->buffer_size) >> 3); + } else { + addr = adc_smp_buf->start_pos; + + addr_8byte = addr >> 3; + if (addr_8byte > finish_addr) + smp_number = addr_8byte - finish_addr; + else + smp_number = finish_addr - addr_8byte; + + ODM_RT_TRACE( + dm, ODM_COMP_UNCOND, + "is_round_up = ((%d)), finish_addr=((0x%x * 8Byte)), Start_Addr = ((0x%x * 8Byte)), smp_number = ((%d))\n", + is_round_up, finish_addr, addr_8byte, smp_number); + } + + if (dm->support_ic_type & ODM_RTL8197F) { + /*64K byte*/ + for (addr = 0x0, i = 0; addr < end_addr; addr += 8, i += 2) { + if ((addr & 0xfff) == 0) + odm_set_bb_reg(dm, 0x0140, MASKLWORD, + 0x780 + (addr >> 12)); + data_l = odm_get_bb_reg(dm, 0x8000 + (addr & 0xfff), + MASKDWORD); + data_h = odm_get_bb_reg(dm, 0x8000 + (addr & 0xfff) + 4, + MASKDWORD); + + ODM_RT_TRACE(dm, ODM_COMP_UNCOND, "%08x%08x\n", data_h, + data_l); + } + } else { + while (addr != (finish_addr << 3)) { + if (page != (addr >> 12)) { + /*Reg140=0x780+(addr>>12), + *addr=0x30~0x3F, total 16 pages + */ + page = (addr >> 12); + } + odm_set_bb_reg(dm, 0x0140, MASKLWORD, 0x780 + page); + + /*pDataL = 0x8000+(addr&0xfff);*/ + data_l = odm_get_bb_reg(dm, 0x8000 + (addr & 0xfff), + MASKDWORD); + data_h = odm_get_bb_reg(dm, 0x8000 + (addr & 0xfff) + 4, + MASKDWORD); + + adc_smp_buf->octet[i] = data_h; + adc_smp_buf->octet[i + 1] = data_l; + + ODM_RT_TRACE(dm, ODM_COMP_UNCOND, "%08x%08x\n", data_h, + data_l); + + i = i + 2; + + if ((addr + 8) >= end_addr) + addr = adc_smp_buf->start_pos; + else + addr = addr + 8; + + smp_cnt++; + if (smp_cnt >= (smp_number - 1)) + break; + } + ODM_RT_TRACE(dm, ODM_COMP_UNCOND, "smp_cnt = ((%d))\n", + smp_cnt); + } +} + +static void phydm_la_mode_set_mac_iq_dump(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct rt_adcsmp *adc_smp = &dm->adcsmp; + u32 reg_value; + + odm_write_1byte(dm, 0x7c0, 0); /*clear all 0x7c0*/ + odm_set_mac_reg(dm, 0x7c0, BIT(0), 1); /*Enable LA mode HW block*/ + + if (adc_smp->la_trig_mode == PHYDM_MAC_TRIG) { + adc_smp->is_bb_trigger = 0; + odm_set_mac_reg(dm, 0x7c0, BIT(2), + 1); /*polling bit for MAC mode*/ + odm_set_mac_reg( + dm, 0x7c0, BIT(4) | BIT(3), + adc_smp->la_trigger_edge); /*trigger mode for MAC*/ + + ODM_RT_TRACE( + dm, ODM_COMP_UNCOND, + "[MAC_trig] ref_mask = ((0x%x)), ref_value = ((0x%x)), dbg_port = ((0x%x))\n", + adc_smp->la_mac_ref_mask, adc_smp->la_trig_sig_sel, + adc_smp->la_dbg_port); + /*[Set MAC Debug Port]*/ + odm_set_mac_reg(dm, 0xF4, BIT(16), 1); + odm_set_mac_reg(dm, 0x38, 0xff0000, adc_smp->la_dbg_port); + odm_set_mac_reg(dm, 0x7c4, MASKDWORD, adc_smp->la_mac_ref_mask); + odm_set_mac_reg(dm, 0x7c8, MASKDWORD, adc_smp->la_trig_sig_sel); + + } else { + adc_smp->is_bb_trigger = 1; + odm_set_mac_reg(dm, 0x7c0, BIT(1), + 1); /*polling bit for BB ADC mode*/ + + if (adc_smp->la_trig_mode == PHYDM_ADC_MAC_TRIG) { + odm_set_mac_reg( + dm, 0x7c0, BIT(3), + 1); /*polling bit for MAC trigger event*/ + odm_set_mac_reg(dm, 0x7c0, BIT(7) | BIT(6), + adc_smp->la_trig_sig_sel); + + if (adc_smp->la_trig_sig_sel == ADCSMP_TRIG_REG) + odm_set_mac_reg( + dm, 0x7c0, BIT(5), + 1); /* manual trigger 0x7C0[5] = 0->1*/ + } + } + + reg_value = odm_get_bb_reg(dm, 0x7c0, 0xff); + ODM_RT_TRACE(dm, ODM_COMP_UNCOND, + "4. [Set MAC IQ dump] 0x7c0[7:0] = ((0x%x))\n", reg_value); +} + +static void phydm_la_mode_set_dma_type(void *dm_void, u8 la_dma_type) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + + ODM_RT_TRACE(dm, ODM_COMP_UNCOND, + "2. [LA mode DMA setting] Dma_type = ((%d))\n", + la_dma_type); + + if (dm->support_ic_type & ODM_N_ANTDIV_SUPPORT) + odm_set_bb_reg(dm, 0x9a0, 0xf00, la_dma_type); /*0x9A0[11:8]*/ + else + odm_set_bb_reg(dm, odm_adc_trigger_jaguar2, 0xf00, + la_dma_type); /*0x95C[11:8]*/ +} + +static void phydm_adc_smp_start(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct rt_adcsmp *adc_smp = &dm->adcsmp; + u8 tmp_u1b; + u8 while_cnt = 0; + u8 polling_ok = false, target_polling_bit; + + phydm_la_mode_bb_setting(dm); + phydm_la_mode_set_dma_type(dm, adc_smp->la_dma_type); + phydm_la_mode_set_trigger_time(dm, adc_smp->la_trigger_time); + + if (dm->support_ic_type & ODM_RTL8197F) { + odm_set_bb_reg(dm, 0xd00, BIT(26), 0x1); + } else { /*for 8814A and 8822B?*/ + odm_write_1byte(dm, 0x198c, 0x7); + odm_write_1byte(dm, 0x8b4, 0x80); + /* odm_set_bb_reg(dm, 0x8b4, BIT(7), 1); */ + } + + phydm_la_mode_set_mac_iq_dump(dm); + /* return; */ + + target_polling_bit = (adc_smp->is_bb_trigger) ? BIT(1) : BIT(2); + do { /*Poll time always use 100ms, when it exceed 2s, break while loop*/ + tmp_u1b = odm_read_1byte(dm, 0x7c0); + + if (adc_smp->adc_smp_state != ADCSMP_STATE_SET) { + ODM_RT_TRACE( + dm, ODM_COMP_UNCOND, + "[state Error] adc_smp_state != ADCSMP_STATE_SET\n"); + break; + + } else if (tmp_u1b & target_polling_bit) { + ODM_delay_ms(100); + while_cnt = while_cnt + 1; + continue; + } else { + ODM_RT_TRACE(dm, ODM_COMP_UNCOND, + "[LA Query OK] polling_bit=((0x%x))\n", + target_polling_bit); + polling_ok = true; + if (dm->support_ic_type & ODM_RTL8197F) + odm_set_bb_reg(dm, 0x7c0, BIT(0), 0x0); + break; + } + } while (while_cnt < 20); + + if (adc_smp->adc_smp_state == ADCSMP_STATE_SET) { + if (polling_ok) + phydm_la_get_tx_pkt_buf(dm); + else + ODM_RT_TRACE(dm, ODM_COMP_UNCOND, + "[Polling timeout]\n"); + } + + if (adc_smp->adc_smp_state == ADCSMP_STATE_SET) + adc_smp->adc_smp_state = ADCSMP_STATE_QUERY; + + ODM_RT_TRACE(dm, ODM_COMP_UNCOND, + "[LA mode] LA_pattern_count = ((%d))\n", + adc_smp->la_count); + + adc_smp_stop(dm); + + if (adc_smp->la_count == 0) { + ODM_RT_TRACE(dm, ODM_COMP_UNCOND, + "LA Dump finished ---------->\n\n\n"); + /**/ + } else { + adc_smp->la_count--; + ODM_RT_TRACE(dm, ODM_COMP_UNCOND, + "LA Dump more ---------->\n\n\n"); + adc_smp_set(dm, adc_smp->la_trig_mode, adc_smp->la_trig_sig_sel, + adc_smp->la_dma_type, adc_smp->la_trigger_time, 0); + } +} + +void adc_smp_set(void *dm_void, u8 trig_mode, u32 trig_sig_sel, + u8 dma_data_sig_sel, u32 trigger_time, u16 polling_time) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + bool is_set_success = true; + struct rt_adcsmp *adc_smp = &dm->adcsmp; + + adc_smp->la_trig_mode = trig_mode; + adc_smp->la_trig_sig_sel = trig_sig_sel; + adc_smp->la_dma_type = dma_data_sig_sel; + adc_smp->la_trigger_time = trigger_time; + + if (adc_smp->adc_smp_state != ADCSMP_STATE_IDLE) + is_set_success = false; + else if (adc_smp->adc_smp_buf.length == 0) + is_set_success = phydm_la_buffer_allocate(dm); + + if (is_set_success) { + adc_smp->adc_smp_state = ADCSMP_STATE_SET; + + ODM_RT_TRACE(dm, ODM_COMP_UNCOND, + "[LA Set Success] LA_State=((%d))\n", + adc_smp->adc_smp_state); + + phydm_adc_smp_start(dm); + } else { + ODM_RT_TRACE(dm, ODM_COMP_UNCOND, + "[LA Set Fail] LA_State=((%d))\n", + adc_smp->adc_smp_state); + } +} + +void adc_smp_query(void *dm_void, void *output, u32 out_len, u32 *pused) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct rt_adcsmp *adc_smp = &dm->adcsmp; + struct rt_adcsmp_string *adc_smp_buf = &adc_smp->adc_smp_buf; + u32 used = *pused; + u32 i; + + ODM_RT_TRACE(dm, ODM_COMP_UNCOND, "%s adc_smp_state %d", __func__, + adc_smp->adc_smp_state); + + for (i = 0; i < (adc_smp_buf->length >> 2) - 2; i += 2) { + PHYDM_SNPRINTF(output + used, out_len - used, "%08x%08x\n", + adc_smp_buf->octet[i], + adc_smp_buf->octet[i + 1]); + } + + PHYDM_SNPRINTF(output + used, out_len - used, "\n"); + *pused = used; +} + +s32 adc_smp_get_sample_counts(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct rt_adcsmp *adc_smp = &dm->adcsmp; + struct rt_adcsmp_string *adc_smp_buf = &adc_smp->adc_smp_buf; + + return (adc_smp_buf->length >> 2) - 2; +} + +s32 adc_smp_query_single_data(void *dm_void, void *output, u32 out_len, + u32 index) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct rt_adcsmp *adc_smp = &dm->adcsmp; + struct rt_adcsmp_string *adc_smp_buf = &adc_smp->adc_smp_buf; + u32 used = 0; + + if (adc_smp->adc_smp_state != ADCSMP_STATE_QUERY) { + PHYDM_SNPRINTF(output + used, out_len - used, + "Error: la data is not ready yet ...\n"); + return -1; + } + + if (index < ((adc_smp_buf->length >> 2) - 2)) { + PHYDM_SNPRINTF(output + used, out_len - used, "%08x%08x\n", + adc_smp_buf->octet[index], + adc_smp_buf->octet[index + 1]); + } + return 0; +} + +void adc_smp_stop(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct rt_adcsmp *adc_smp = &dm->adcsmp; + + adc_smp->adc_smp_state = ADCSMP_STATE_IDLE; + ODM_RT_TRACE(dm, ODM_COMP_UNCOND, "[LA_Stop] LA_state = ((%d))\n", + adc_smp->adc_smp_state); +} + +void adc_smp_init(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct rt_adcsmp *adc_smp = &dm->adcsmp; + struct rt_adcsmp_string *adc_smp_buf = &adc_smp->adc_smp_buf; + + adc_smp->adc_smp_state = ADCSMP_STATE_IDLE; + + if (dm->support_ic_type & ODM_RTL8814A) { + adc_smp_buf->start_pos = 0x30000; + adc_smp_buf->buffer_size = 0x10000; + } else if (dm->support_ic_type & ODM_RTL8822B) { + adc_smp_buf->start_pos = 0x20000; + adc_smp_buf->buffer_size = 0x20000; + } else if (dm->support_ic_type & ODM_RTL8197F) { + adc_smp_buf->start_pos = 0x00000; + adc_smp_buf->buffer_size = 0x10000; + } else if (dm->support_ic_type & ODM_RTL8821C) { + adc_smp_buf->start_pos = 0x8000; + adc_smp_buf->buffer_size = 0x8000; + } +} + +void adc_smp_de_init(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct rt_adcsmp *adc_smp = &dm->adcsmp; + struct rt_adcsmp_string *adc_smp_buf = &adc_smp->adc_smp_buf; + + adc_smp_stop(dm); + + if (adc_smp_buf->length != 0x0) { + odm_free_memory(dm, adc_smp_buf->octet, adc_smp_buf->length); + adc_smp_buf->length = 0x0; + } +} + +void phydm_la_mode_bb_setting(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct rt_adcsmp *adc_smp = &dm->adcsmp; + + u8 trig_mode = adc_smp->la_trig_mode; + u32 trig_sig_sel = adc_smp->la_trig_sig_sel; + u32 dbg_port = adc_smp->la_dbg_port; + u8 is_trigger_edge = adc_smp->la_trigger_edge; + u8 sampling_rate = adc_smp->la_smp_rate; + + ODM_RT_TRACE( + dm, ODM_COMP_UNCOND, + "1. [LA mode bb_setting] trig_mode = ((%d)), dbg_port = ((0x%x)), Trig_Edge = ((%d)), smp_rate = ((%d)), Trig_Sel = ((0x%x))\n", + trig_mode, dbg_port, is_trigger_edge, sampling_rate, + trig_sig_sel); + + if (trig_mode == PHYDM_MAC_TRIG) + trig_sig_sel = 0; /*ignore this setting*/ + + if (dm->support_ic_type & ODM_IC_11AC_SERIES) { + if (trig_mode == PHYDM_ADC_RF0_TRIG) { + /*DBGOUT_RFC_a[31:0]*/ + odm_set_bb_reg(dm, 0x8f8, + BIT(25) | BIT(24) | BIT(23) | BIT(22), + 9); + } else if (trig_mode == PHYDM_ADC_RF1_TRIG) { + /*DBGOUT_RFC_b[31:0]*/ + odm_set_bb_reg(dm, 0x8f8, + BIT(25) | BIT(24) | BIT(23) | BIT(22), + 8); + } else { + odm_set_bb_reg(dm, 0x8f8, + BIT(25) | BIT(24) | BIT(23) | BIT(22), + 0); + } + /* + * (0:) '{ofdm_dbg[31:0]}' + * (1:) '{cca,crc32_fail,dbg_ofdm[29:0]}' + * (2:) '{vbon,crc32_fail,dbg_ofdm[29:0]}' + * (3:) '{cca,crc32_ok,dbg_ofdm[29:0]}' + * (4:) '{vbon,crc32_ok,dbg_ofdm[29:0]}' + * (5:) '{dbg_iqk_anta}' + * (6:) '{cca,ofdm_crc_ok,dbg_dp_anta[29:0]}' + * (7:) '{dbg_iqk_antb}' + * (8:) '{DBGOUT_RFC_b[31:0]}' + * (9:) '{DBGOUT_RFC_a[31:0]}' + * (a:) '{dbg_ofdm}' + * (b:) '{dbg_cck}' + */ + + /*disable dbg clk gating*/ + odm_set_bb_reg(dm, 0x198C, BIT(2) | BIT(1) | BIT(0), 7); + + /*0x95C[4:0], BB debug port bit*/ + odm_set_bb_reg(dm, 0x95C, 0x1f, trig_sig_sel); + odm_set_bb_reg(dm, 0x8FC, MASKDWORD, dbg_port); + /*0: posedge, 1: negedge*/ + odm_set_bb_reg(dm, 0x95C, BIT(31), is_trigger_edge); + odm_set_bb_reg(dm, 0x95c, 0xe0, sampling_rate); + /* (0:) '80MHz' + * (1:) '40MHz' + * (2:) '20MHz' + * (3:) '10MHz' + * (4:) '5MHz' + * (5:) '2.5MHz' + * (6:) '1.25MHz' + * (7:) '160MHz (for BW160 ic)' + */ + } else { + /*0x9A0[4:0], BB debug port bit*/ + odm_set_bb_reg(dm, 0x9a0, 0x1f, trig_sig_sel); + odm_set_bb_reg(dm, 0x908, MASKDWORD, dbg_port); + /*0: posedge, 1: negedge*/ + odm_set_bb_reg(dm, 0x9A0, BIT(31), is_trigger_edge); + odm_set_bb_reg(dm, 0x9A0, 0xe0, sampling_rate); + /* (0:) '80MHz' + * (1:) '40MHz' + * (2:) '20MHz' + * (3:) '10MHz' + * (4:) '5MHz' + * (5:) '2.5MHz' + * (6:) '1.25MHz' + * (7:) '160MHz (for BW160 ic)' + */ + } +} + +void phydm_la_mode_set_trigger_time(void *dm_void, u32 trigger_time_mu_sec) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + u8 trigger_time_unit_num; + u32 time_unit = 0; + + if (trigger_time_mu_sec < 128) + time_unit = 0; /*unit: 1mu sec*/ + else if (trigger_time_mu_sec < 256) + time_unit = 1; /*unit: 2mu sec*/ + else if (trigger_time_mu_sec < 512) + time_unit = 2; /*unit: 4mu sec*/ + else if (trigger_time_mu_sec < 1024) + time_unit = 3; /*unit: 8mu sec*/ + else if (trigger_time_mu_sec < 2048) + time_unit = 4; /*unit: 16mu sec*/ + else if (trigger_time_mu_sec < 4096) + time_unit = 5; /*unit: 32mu sec*/ + else if (trigger_time_mu_sec < 8192) + time_unit = 6; /*unit: 64mu sec*/ + + trigger_time_unit_num = (u8)(trigger_time_mu_sec >> time_unit); + + ODM_RT_TRACE( + dm, ODM_COMP_UNCOND, + "3. [Set Trigger Time] Trig_Time = ((%d)) * unit = ((2^%d us))\n", + trigger_time_unit_num, time_unit); + + odm_set_mac_reg(dm, 0x7cc, BIT(20) | BIT(19) | BIT(18), time_unit); + odm_set_mac_reg(dm, 0x7c0, 0x7f00, (trigger_time_unit_num & 0x7f)); +} + +void phydm_lamode_trigger_setting(void *dm_void, char input[][16], u32 *_used, + char *output, u32 *_out_len, u32 input_num) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct rt_adcsmp *adc_smp = &dm->adcsmp; + u8 trig_mode, dma_data_sig_sel; + u32 trig_sig_sel; + bool is_enable_la_mode; + u32 trigger_time_mu_sec; + char help[] = "-h"; + u32 var1[10] = {0}; + u32 used = *_used; + u32 out_len = *_out_len; + + if (dm->support_ic_type & PHYDM_IC_SUPPORT_LA_MODE) { + PHYDM_SSCANF(input[1], DCMD_DECIMAL, &var1[0]); + is_enable_la_mode = (bool)var1[0]; + /*dbg_print("echo cmd input_num = %d\n", input_num);*/ + + if ((strcmp(input[1], help) == 0)) { + PHYDM_SNPRINTF( + output + used, out_len - used, + "{En} {0:BB,1:BB_MAC,2:RF0,3:RF1,4:MAC}\n {BB:dbg_port[bit],BB_MAC:0-ok/1-fail/2-cca,MAC:ref} {DMA type} {TrigTime}\n {polling_time/ref_mask} {dbg_port} {0:P_Edge, 1:N_Edge} {SpRate:0-80M,1-40M,2-20M} {Capture num}\n"); + /**/ + } else if ((is_enable_la_mode == 1)) { + PHYDM_SSCANF(input[2], DCMD_DECIMAL, &var1[1]); + + trig_mode = (u8)var1[1]; + + if (trig_mode == PHYDM_MAC_TRIG) + PHYDM_SSCANF(input[3], DCMD_HEX, &var1[2]); + else + PHYDM_SSCANF(input[3], DCMD_DECIMAL, &var1[2]); + trig_sig_sel = var1[2]; + + PHYDM_SSCANF(input[4], DCMD_DECIMAL, &var1[3]); + PHYDM_SSCANF(input[5], DCMD_DECIMAL, &var1[4]); + PHYDM_SSCANF(input[6], DCMD_HEX, &var1[5]); + PHYDM_SSCANF(input[7], DCMD_HEX, &var1[6]); + PHYDM_SSCANF(input[8], DCMD_DECIMAL, &var1[7]); + PHYDM_SSCANF(input[9], DCMD_DECIMAL, &var1[8]); + PHYDM_SSCANF(input[10], DCMD_DECIMAL, &var1[9]); + + dma_data_sig_sel = (u8)var1[3]; + trigger_time_mu_sec = var1[4]; /*unit: us*/ + + adc_smp->la_mac_ref_mask = var1[5]; + adc_smp->la_dbg_port = var1[6]; + adc_smp->la_trigger_edge = (u8)var1[7]; + adc_smp->la_smp_rate = (u8)(var1[8] & 0x7); + adc_smp->la_count = var1[9]; + + ODM_RT_TRACE( + dm, ODM_COMP_UNCOND, + "echo lamode %d %d %d %d %d %d %x %d %d %d\n", + var1[0], var1[1], var1[2], var1[3], var1[4], + var1[5], var1[6], var1[7], var1[8], var1[9]); + + PHYDM_SNPRINTF( + output + used, out_len - used, + "a.En= ((1)), b.mode = ((%d)), c.Trig_Sel = ((0x%x)), d.Dma_type = ((%d))\n", + trig_mode, trig_sig_sel, dma_data_sig_sel); + PHYDM_SNPRINTF( + output + used, out_len - used, + "e.Trig_Time = ((%dus)), f.mac_ref_mask = ((0x%x)), g.dbg_port = ((0x%x))\n", + trigger_time_mu_sec, adc_smp->la_mac_ref_mask, + adc_smp->la_dbg_port); + PHYDM_SNPRINTF( + output + used, out_len - used, + "h.Trig_edge = ((%d)), i.smp rate = ((%d MHz)), j.Cap_num = ((%d))\n", + adc_smp->la_trigger_edge, + (80 >> adc_smp->la_smp_rate), + adc_smp->la_count); + + adc_smp_set(dm, trig_mode, trig_sig_sel, + dma_data_sig_sel, trigger_time_mu_sec, 0); + + } else { + adc_smp_stop(dm); + PHYDM_SNPRINTF(output + used, out_len - used, + "Disable LA mode\n"); + } + } +} diff --git a/drivers/staging/rtlwifi/phydm/phydm_adc_sampling.h b/drivers/staging/rtlwifi/phydm/phydm_adc_sampling.h new file mode 100644 index 000000000000..460931489be3 --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/phydm_adc_sampling.h @@ -0,0 +1,96 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef __INC_ADCSMP_H +#define __INC_ADCSMP_H + +#define DYNAMIC_LA_MODE "1.0" /*2016.07.15 Dino */ + +struct rt_adcsmp_string { + u32 *octet; + u32 length; + u32 buffer_size; + u32 start_pos; +}; + +enum rt_adcsmp_trig_sel { + PHYDM_ADC_BB_TRIG = 0, + PHYDM_ADC_MAC_TRIG = 1, + PHYDM_ADC_RF0_TRIG = 2, + PHYDM_ADC_RF1_TRIG = 3, + PHYDM_MAC_TRIG = 4 +}; + +enum rt_adcsmp_trig_sig_sel { + ADCSMP_TRIG_CRCOK = 0, + ADCSMP_TRIG_CRCFAIL = 1, + ADCSMP_TRIG_CCA = 2, + ADCSMP_TRIG_REG = 3 +}; + +enum rt_adcsmp_state { + ADCSMP_STATE_IDLE = 0, + ADCSMP_STATE_SET = 1, + ADCSMP_STATE_QUERY = 2 +}; + +struct rt_adcsmp { + struct rt_adcsmp_string adc_smp_buf; + enum rt_adcsmp_state adc_smp_state; + u8 la_trig_mode; + u32 la_trig_sig_sel; + u8 la_dma_type; + u32 la_trigger_time; + u32 la_mac_ref_mask; + u32 la_dbg_port; + u8 la_trigger_edge; + u8 la_smp_rate; + u32 la_count; + u8 is_bb_trigger; + u8 la_work_item_index; +}; + +void adc_smp_set(void *dm_void, u8 trig_mode, u32 trig_sig_sel, + u8 dma_data_sig_sel, u32 trigger_time, u16 polling_time); + +void adc_smp_query(void *dm_void, void *output, u32 out_len, u32 *pused); + +s32 adc_smp_get_sample_counts(void *dm_void); + +s32 adc_smp_query_single_data(void *dm_void, void *output, u32 out_len, + u32 index); + +void adc_smp_stop(void *dm_void); + +void adc_smp_init(void *dm_void); + +void adc_smp_de_init(void *dm_void); + +void phydm_la_mode_bb_setting(void *dm_void); + +void phydm_la_mode_set_trigger_time(void *dm_void, u32 trigger_time_mu_sec); + +void phydm_lamode_trigger_setting(void *dm_void, char input[][16], u32 *_used, + char *output, u32 *_out_len, u32 input_num); +#endif diff --git a/drivers/staging/rtlwifi/phydm/phydm_antdiv.c b/drivers/staging/rtlwifi/phydm/phydm_antdiv.c new file mode 100644 index 000000000000..39d3c6947556 --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/phydm_antdiv.c @@ -0,0 +1,83 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +/* ************************************************************ + * include files + * *************************************************************/ + +#include "mp_precomp.h" +#include "phydm_precomp.h" + +/* ****************************************************** + * when antenna test utility is on or some testing need to disable antenna + * diversity, call this function to disable all ODM related mechanisms which + * will switch antenna. + * *******************************************************/ +void odm_stop_antenna_switch_dm(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + + /* disable ODM antenna diversity */ + dm->support_ability &= ~ODM_BB_ANT_DIV; + ODM_RT_TRACE(dm, ODM_COMP_ANT_DIV, "STOP Antenna Diversity\n"); +} + +void phydm_enable_antenna_diversity(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + + dm->support_ability |= ODM_BB_ANT_DIV; + ODM_RT_TRACE(dm, ODM_COMP_ANT_DIV, + "AntDiv is enabled & Re-Init AntDiv\n"); + odm_antenna_diversity_init(dm); +} + +void odm_set_ant_config(void *dm_void, u8 ant_setting /* 0=A, 1=B, 2=C, .... */ + ) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + + if (dm->support_ic_type == ODM_RTL8723B) { + if (ant_setting == 0) /* ant A*/ + odm_set_bb_reg(dm, 0x948, MASKDWORD, 0x00000000); + else if (ant_setting == 1) + odm_set_bb_reg(dm, 0x948, MASKDWORD, 0x00000280); + } else if (dm->support_ic_type == ODM_RTL8723D) { + if (ant_setting == 0) /* ant A*/ + odm_set_bb_reg(dm, 0x948, MASKLWORD, 0x0000); + else if (ant_setting == 1) + odm_set_bb_reg(dm, 0x948, MASKLWORD, 0x0280); + } +} + +/* ****************************************************** */ + +void odm_sw_ant_div_rest_after_link(void *dm_void) {} + +void odm_ant_div_reset(void *dm_void) {} + +void odm_antenna_diversity_init(void *dm_void) {} + +void odm_antenna_diversity(void *dm_void) {} diff --git a/drivers/staging/rtlwifi/phydm/phydm_antdiv.h b/drivers/staging/rtlwifi/phydm/phydm_antdiv.h new file mode 100644 index 000000000000..ebbff2f56c5e --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/phydm_antdiv.h @@ -0,0 +1,301 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __PHYDMANTDIV_H__ +#define __PHYDMANTDIV_H__ + +/* 2.0 2014.11.04 + * 2.1 2015.01.13 Dino + * 2.2 2015.01.16 Dino + * 3.1 2015.07.29 YuChen, remove 92c 92d 8723a + * 3.2 2015.08.11 Stanley, disable antenna diversity when BT is enable for 8723B + * 3.3 2015.08.12 Stanley. 8723B does not need to check the antenna is control + * by BT, because antenna diversity only works when BT is disable + * or radio off + * 3.4 2015.08.28 Dino 1.Add 8821A Smart Antenna 2. Add 8188F SW S0S1 Antenna + * Diversity + * 3.5 2015.10.07 Stanley Always check antenna detection result from BT-coex. + * for 8723B, not from PHYDM + * 3.6 2015.11.16 Stanley + * 3.7 2015.11.20 Dino Add SmartAnt FAT Patch + * 3.8 2015.12.21 Dino, Add SmartAnt dynamic training packet num + * 3.9 2016.01.05 Dino, Add SmartAnt cmd for converting single & two smtant, and + * add cmd for adjust truth table + */ +#define ANTDIV_VERSION "3.9" + +/* 1 ============================================================ + * 1 Definition + * 1 ============================================================ + */ + +#define ANTDIV_INIT 0xff +#define MAIN_ANT 1 /*ant A or ant Main or S1*/ +#define AUX_ANT 2 /*AntB or ant Aux or S0*/ +#define MAX_ANT 3 /* 3 for AP using*/ + +#define ANT1_2G 0 /* = ANT2_5G for 8723D BTG S1 RX S0S1 diversity for 8723D, + * TX fixed at S1 + */ +#define ANT2_2G 1 /* = ANT1_5G for 8723D BTG S0 RX S0S1 diversity for 8723D, + * TX fixed at S1 + */ +/*smart antenna*/ +#define SUPPORT_RF_PATH_NUM 4 +#define SUPPORT_BEAM_PATTERN_NUM 4 +#define NUM_ANTENNA_8821A 2 + +#define SUPPORT_BEAM_SET_PATTERN_NUM 8 + +#define NO_FIX_TX_ANT 0 +#define FIX_TX_AT_MAIN 1 +#define FIX_AUX_AT_MAIN 2 + +/* Antenna Diversty Control type */ +#define ODM_AUTO_ANT 0 +#define ODM_FIX_MAIN_ANT 1 +#define ODM_FIX_AUX_ANT 2 + +#define ODM_N_ANTDIV_SUPPORT \ + (ODM_RTL8188E | ODM_RTL8192E | ODM_RTL8723B | ODM_RTL8188F | \ + ODM_RTL8723D | ODM_RTL8195A) +#define ODM_AC_ANTDIV_SUPPORT \ + (ODM_RTL8821 | ODM_RTL8881A | ODM_RTL8812 | ODM_RTL8821C | \ + ODM_RTL8822B | ODM_RTL8814B) +#define ODM_ANTDIV_SUPPORT (ODM_N_ANTDIV_SUPPORT | ODM_AC_ANTDIV_SUPPORT) +#define ODM_SMART_ANT_SUPPORT (ODM_RTL8188E | ODM_RTL8192E) +#define ODM_HL_SMART_ANT_TYPE1_SUPPORT (ODM_RTL8821 | ODM_RTL8822B) + +#define ODM_ANTDIV_2G_SUPPORT_IC \ + (ODM_RTL8188E | ODM_RTL8192E | ODM_RTL8723B | ODM_RTL8881A | \ + ODM_RTL8188F | ODM_RTL8723D) +#define ODM_ANTDIV_5G_SUPPORT_IC \ + (ODM_RTL8821 | ODM_RTL8881A | ODM_RTL8812 | ODM_RTL8821C) + +#define ODM_EVM_ENHANCE_ANTDIV_SUPPORT_IC (ODM_RTL8192E) + +#define ODM_ANTDIV_2G BIT(0) +#define ODM_ANTDIV_5G BIT(1) + +#define ANTDIV_ON 1 +#define ANTDIV_OFF 0 + +#define FAT_ON 1 +#define FAT_OFF 0 + +#define TX_BY_DESC 1 +#define TX_BY_REG 0 + +#define RSSI_METHOD 0 +#define EVM_METHOD 1 +#define CRC32_METHOD 2 + +#define INIT_ANTDIV_TIMMER 0 +#define CANCEL_ANTDIV_TIMMER 1 +#define RELEASE_ANTDIV_TIMMER 2 + +#define CRC32_FAIL 1 +#define CRC32_OK 0 + +#define evm_rssi_th_high 25 +#define evm_rssi_th_low 20 + +#define NORMAL_STATE_MIAN 1 +#define NORMAL_STATE_AUX 2 +#define TRAINING_STATE 3 + +#define FORCE_RSSI_DIFF 10 + +#define CSI_ON 1 +#define CSI_OFF 0 + +#define DIVON_CSIOFF 1 +#define DIVOFF_CSION 2 + +#define BDC_DIV_TRAIN_STATE 0 +#define bdc_bfer_train_state 1 +#define BDC_DECISION_STATE 2 +#define BDC_BF_HOLD_STATE 3 +#define BDC_DIV_HOLD_STATE 4 + +#define BDC_MODE_1 1 +#define BDC_MODE_2 2 +#define BDC_MODE_3 3 +#define BDC_MODE_4 4 +#define BDC_MODE_NULL 0xff + +/*SW S0S1 antenna diversity*/ +#define SWAW_STEP_INIT 0xff +#define SWAW_STEP_PEEK 0 +#define SWAW_STEP_DETERMINE 1 + +#define RSSI_CHECK_RESET_PERIOD 10 +#define RSSI_CHECK_THRESHOLD 50 + +/*Hong Lin Smart antenna*/ +#define HL_SMTANT_2WIRE_DATA_LEN 24 + +/* 1 ============================================================ + * 1 structure + * 1 ============================================================ + */ + +struct sw_antenna_switch { + u8 double_chk_flag; /*If current antenna RSSI > "RSSI_CHECK_THRESHOLD", + *than check this antenna again + */ + u8 try_flag; + s32 pre_rssi; + u8 cur_antenna; + u8 pre_antenna; + u8 rssi_trying; + u8 reset_idx; + u8 train_time; + u8 train_time_flag; /*base on RSSI difference between two antennas*/ + struct timer_list phydm_sw_antenna_switch_timer; + u32 pkt_cnt_sw_ant_div_by_ctrl_frame; + bool is_sw_ant_div_by_ctrl_frame; + + /* AntDect (Before link Antenna Switch check) need to be moved*/ + u16 single_ant_counter; + u16 dual_ant_counter; + u16 aux_fail_detec_counter; + u16 retry_counter; + u8 swas_no_link_state; + u32 swas_no_link_bk_reg948; + bool ANTA_ON; /*To indicate ant A is or not*/ + bool ANTB_ON; /*To indicate ant B is on or not*/ + bool pre_aux_fail_detec; + bool rssi_ant_dect_result; + u8 ant_5g; + u8 ant_2g; +}; + +struct fast_antenna_training { + u8 bssid[6]; + u8 antsel_rx_keep_0; + u8 antsel_rx_keep_1; + u8 antsel_rx_keep_2; + u8 antsel_rx_keep_3; + u32 ant_sum_rssi[7]; + u32 ant_rssi_cnt[7]; + u32 ant_ave_rssi[7]; + u8 fat_state; + u32 train_idx; + u8 antsel_a[ODM_ASSOCIATE_ENTRY_NUM]; + u8 antsel_b[ODM_ASSOCIATE_ENTRY_NUM]; + u8 antsel_c[ODM_ASSOCIATE_ENTRY_NUM]; + u16 main_ant_sum[ODM_ASSOCIATE_ENTRY_NUM]; + u16 aux_ant_sum[ODM_ASSOCIATE_ENTRY_NUM]; + u16 main_ant_cnt[ODM_ASSOCIATE_ENTRY_NUM]; + u16 aux_ant_cnt[ODM_ASSOCIATE_ENTRY_NUM]; + u16 main_ant_sum_cck[ODM_ASSOCIATE_ENTRY_NUM]; + u16 aux_ant_sum_cck[ODM_ASSOCIATE_ENTRY_NUM]; + u16 main_ant_cnt_cck[ODM_ASSOCIATE_ENTRY_NUM]; + u16 aux_ant_cnt_cck[ODM_ASSOCIATE_ENTRY_NUM]; + u8 rx_idle_ant; + u8 ant_div_on_off; + bool is_become_linked; + u32 min_max_rssi; + u8 idx_ant_div_counter_2g; + u8 idx_ant_div_counter_5g; + u8 ant_div_2g_5g; + + u32 cck_ctrl_frame_cnt_main; + u32 cck_ctrl_frame_cnt_aux; + u32 ofdm_ctrl_frame_cnt_main; + u32 ofdm_ctrl_frame_cnt_aux; + u32 main_ant_ctrl_frame_sum; + u32 aux_ant_ctrl_frame_sum; + u32 main_ant_ctrl_frame_cnt; + u32 aux_ant_ctrl_frame_cnt; + u8 b_fix_tx_ant; + bool fix_ant_bfee; + bool enable_ctrl_frame_antdiv; + bool use_ctrl_frame_antdiv; + u8 hw_antsw_occur; + u8 *p_force_tx_ant_by_desc; + u8 force_tx_ant_by_desc; /*A temp value, will hook to driver team's + *outer parameter later + */ + u8 *p_default_s0_s1; + u8 default_s0_s1; +}; + +/* 1 ============================================================ + * 1 enumeration + * 1 ============================================================ + */ + +/*Fast antenna training*/ +enum fat_state { + FAT_BEFORE_LINK_STATE = 0, + FAT_PREPARE_STATE = 1, + FAT_TRAINING_STATE = 2, + FAT_DECISION_STATE = 3 +}; + +enum ant_div_type { + NO_ANTDIV = 0xFF, + CG_TRX_HW_ANTDIV = 0x01, + CGCS_RX_HW_ANTDIV = 0x02, + FIXED_HW_ANTDIV = 0x03, + CG_TRX_SMART_ANTDIV = 0x04, + CGCS_RX_SW_ANTDIV = 0x05, + /*8723B intrnal switch S0 S1*/ + S0S1_SW_ANTDIV = 0x06, + /*TRX S0S1 diversity for 8723D*/ + S0S1_TRX_HW_ANTDIV = 0x07, + /*Hong-Lin Smart antenna use for 8821AE which is a 2 ant. entitys, and + *each ant. is equipped with 4 antenna patterns + */ + HL_SW_SMART_ANT_TYPE1 = 0x10, + /*Hong-Bo Smart antenna use for 8822B which is a 2 ant. entitys*/ + HL_SW_SMART_ANT_TYPE2 = 0x11, +}; + +/* 1 ============================================================ + * 1 function prototype + * 1 ============================================================ + */ + +void odm_stop_antenna_switch_dm(void *dm_void); + +void phydm_enable_antenna_diversity(void *dm_void); + +void odm_set_ant_config(void *dm_void, u8 ant_setting /* 0=A, 1=B, 2=C, .... */ + ); + +#define sw_ant_div_rest_after_link odm_sw_ant_div_rest_after_link + +void odm_sw_ant_div_rest_after_link(void *dm_void); + +void odm_ant_div_reset(void *dm_void); + +void odm_antenna_diversity_init(void *dm_void); + +void odm_antenna_diversity(void *dm_void); + +#endif /*#ifndef __ODMANTDIV_H__*/ diff --git a/drivers/staging/rtlwifi/phydm/phydm_beamforming.h b/drivers/staging/rtlwifi/phydm/phydm_beamforming.h new file mode 100644 index 000000000000..adc04ba4e218 --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/phydm_beamforming.h @@ -0,0 +1,48 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef __INC_PHYDM_BEAMFORMING_H +#define __INC_PHYDM_BEAMFORMING_H + +/*Beamforming Related*/ +#include "txbf/halcomtxbf.h" +#include "txbf/haltxbfjaguar.h" +#include "txbf/haltxbf8822b.h" +#include "txbf/haltxbfinterface.h" + +#define beamforming_gid_paid(adapter, tcb) +#define phydm_acting_determine(dm, type) false +#define beamforming_enter(dm, sta_idx) +#define beamforming_leave(dm, RA) +#define beamforming_end_fw(dm) +#define beamforming_control_v1(dm, RA, AID, mode, BW, rate) true +#define beamforming_control_v2(dm, idx, mode, BW, period) true +#define phydm_beamforming_end_sw(dm, _status) +#define beamforming_timer_callback(dm) +#define phydm_beamforming_init(dm) +#define phydm_beamforming_control_v2(dm, _idx, _mode, _BW, _period) false +#define beamforming_watchdog(dm) +#define phydm_beamforming_watchdog(dm) + +#endif diff --git a/drivers/staging/rtlwifi/phydm/phydm_ccx.c b/drivers/staging/rtlwifi/phydm/phydm_ccx.c new file mode 100644 index 000000000000..2e0dc68757dc --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/phydm_ccx.c @@ -0,0 +1,457 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#include "mp_precomp.h" +#include "phydm_precomp.h" + +/*Set NHM period, threshold, disable ignore cca or not, + *disable ignore txon or not + */ +void phydm_nhm_setting(void *dm_void, u8 nhm_setting) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct ccx_info *ccx_info = &dm->dm_ccx_info; + + if (dm->support_ic_type & ODM_IC_11AC_SERIES) { + if (nhm_setting == SET_NHM_SETTING) { + /*Set inexclude_cca, inexclude_txon*/ + odm_set_bb_reg(dm, ODM_REG_NHM_TH9_TH10_11AC, BIT(9), + ccx_info->nhm_inexclude_cca); + odm_set_bb_reg(dm, ODM_REG_NHM_TH9_TH10_11AC, BIT(10), + ccx_info->nhm_inexclude_txon); + + /*Set NHM period*/ + odm_set_bb_reg(dm, ODM_REG_CCX_PERIOD_11AC, MASKHWORD, + ccx_info->NHM_period); + + /*Set NHM threshold*/ + odm_set_bb_reg(dm, ODM_REG_NHM_TH3_TO_TH0_11AC, + MASKBYTE0, ccx_info->NHM_th[0]); + odm_set_bb_reg(dm, ODM_REG_NHM_TH3_TO_TH0_11AC, + MASKBYTE1, ccx_info->NHM_th[1]); + odm_set_bb_reg(dm, ODM_REG_NHM_TH3_TO_TH0_11AC, + MASKBYTE2, ccx_info->NHM_th[2]); + odm_set_bb_reg(dm, ODM_REG_NHM_TH3_TO_TH0_11AC, + MASKBYTE3, ccx_info->NHM_th[3]); + odm_set_bb_reg(dm, ODM_REG_NHM_TH7_TO_TH4_11AC, + MASKBYTE0, ccx_info->NHM_th[4]); + odm_set_bb_reg(dm, ODM_REG_NHM_TH7_TO_TH4_11AC, + MASKBYTE1, ccx_info->NHM_th[5]); + odm_set_bb_reg(dm, ODM_REG_NHM_TH7_TO_TH4_11AC, + MASKBYTE2, ccx_info->NHM_th[6]); + odm_set_bb_reg(dm, ODM_REG_NHM_TH7_TO_TH4_11AC, + MASKBYTE3, ccx_info->NHM_th[7]); + odm_set_bb_reg(dm, ODM_REG_NHM_TH8_11AC, MASKBYTE0, + ccx_info->NHM_th[8]); + odm_set_bb_reg(dm, ODM_REG_NHM_TH9_TH10_11AC, MASKBYTE2, + ccx_info->NHM_th[9]); + odm_set_bb_reg(dm, ODM_REG_NHM_TH9_TH10_11AC, MASKBYTE3, + ccx_info->NHM_th[10]); + + /*CCX EN*/ + odm_set_bb_reg(dm, ODM_REG_NHM_TH9_TH10_11AC, BIT(8), + CCX_EN); + } else if (nhm_setting == STORE_NHM_SETTING) { + /*Store prev. disable_ignore_cca, disable_ignore_txon*/ + ccx_info->NHM_inexclude_cca_restore = + (enum nhm_inexclude_cca)odm_get_bb_reg( + dm, ODM_REG_NHM_TH9_TH10_11AC, BIT(9)); + ccx_info->NHM_inexclude_txon_restore = + (enum nhm_inexclude_txon)odm_get_bb_reg( + dm, ODM_REG_NHM_TH9_TH10_11AC, BIT(10)); + + /*Store pervious NHM period*/ + ccx_info->NHM_period_restore = (u16)odm_get_bb_reg( + dm, ODM_REG_CCX_PERIOD_11AC, MASKHWORD); + + /*Store NHM threshold*/ + ccx_info->NHM_th_restore[0] = (u8)odm_get_bb_reg( + dm, ODM_REG_NHM_TH3_TO_TH0_11AC, MASKBYTE0); + ccx_info->NHM_th_restore[1] = (u8)odm_get_bb_reg( + dm, ODM_REG_NHM_TH3_TO_TH0_11AC, MASKBYTE1); + ccx_info->NHM_th_restore[2] = (u8)odm_get_bb_reg( + dm, ODM_REG_NHM_TH3_TO_TH0_11AC, MASKBYTE2); + ccx_info->NHM_th_restore[3] = (u8)odm_get_bb_reg( + dm, ODM_REG_NHM_TH3_TO_TH0_11AC, MASKBYTE3); + ccx_info->NHM_th_restore[4] = (u8)odm_get_bb_reg( + dm, ODM_REG_NHM_TH7_TO_TH4_11AC, MASKBYTE0); + ccx_info->NHM_th_restore[5] = (u8)odm_get_bb_reg( + dm, ODM_REG_NHM_TH7_TO_TH4_11AC, MASKBYTE1); + ccx_info->NHM_th_restore[6] = (u8)odm_get_bb_reg( + dm, ODM_REG_NHM_TH7_TO_TH4_11AC, MASKBYTE2); + ccx_info->NHM_th_restore[7] = (u8)odm_get_bb_reg( + dm, ODM_REG_NHM_TH7_TO_TH4_11AC, MASKBYTE3); + ccx_info->NHM_th_restore[8] = (u8)odm_get_bb_reg( + dm, ODM_REG_NHM_TH8_11AC, MASKBYTE0); + ccx_info->NHM_th_restore[9] = (u8)odm_get_bb_reg( + dm, ODM_REG_NHM_TH9_TH10_11AC, MASKBYTE2); + ccx_info->NHM_th_restore[10] = (u8)odm_get_bb_reg( + dm, ODM_REG_NHM_TH9_TH10_11AC, MASKBYTE3); + } else if (nhm_setting == RESTORE_NHM_SETTING) { + /*Set disable_ignore_cca, disable_ignore_txon*/ + odm_set_bb_reg(dm, ODM_REG_NHM_TH9_TH10_11AC, BIT(9), + ccx_info->NHM_inexclude_cca_restore); + odm_set_bb_reg(dm, ODM_REG_NHM_TH9_TH10_11AC, BIT(10), + ccx_info->NHM_inexclude_txon_restore); + + /*Set NHM period*/ + odm_set_bb_reg(dm, ODM_REG_CCX_PERIOD_11AC, MASKHWORD, + ccx_info->NHM_period); + + /*Set NHM threshold*/ + odm_set_bb_reg(dm, ODM_REG_NHM_TH3_TO_TH0_11AC, + MASKBYTE0, ccx_info->NHM_th_restore[0]); + odm_set_bb_reg(dm, ODM_REG_NHM_TH3_TO_TH0_11AC, + MASKBYTE1, ccx_info->NHM_th_restore[1]); + odm_set_bb_reg(dm, ODM_REG_NHM_TH3_TO_TH0_11AC, + MASKBYTE2, ccx_info->NHM_th_restore[2]); + odm_set_bb_reg(dm, ODM_REG_NHM_TH3_TO_TH0_11AC, + MASKBYTE3, ccx_info->NHM_th_restore[3]); + odm_set_bb_reg(dm, ODM_REG_NHM_TH7_TO_TH4_11AC, + MASKBYTE0, ccx_info->NHM_th_restore[4]); + odm_set_bb_reg(dm, ODM_REG_NHM_TH7_TO_TH4_11AC, + MASKBYTE1, ccx_info->NHM_th_restore[5]); + odm_set_bb_reg(dm, ODM_REG_NHM_TH7_TO_TH4_11AC, + MASKBYTE2, ccx_info->NHM_th_restore[6]); + odm_set_bb_reg(dm, ODM_REG_NHM_TH7_TO_TH4_11AC, + MASKBYTE3, ccx_info->NHM_th_restore[7]); + odm_set_bb_reg(dm, ODM_REG_NHM_TH8_11AC, MASKBYTE0, + ccx_info->NHM_th_restore[8]); + odm_set_bb_reg(dm, ODM_REG_NHM_TH9_TH10_11AC, MASKBYTE2, + ccx_info->NHM_th_restore[9]); + odm_set_bb_reg(dm, ODM_REG_NHM_TH9_TH10_11AC, MASKBYTE3, + ccx_info->NHM_th_restore[10]); + } else { + return; + } + } + + else if (dm->support_ic_type & ODM_IC_11N_SERIES) { + if (nhm_setting == SET_NHM_SETTING) { + /*Set disable_ignore_cca, disable_ignore_txon*/ + odm_set_bb_reg(dm, ODM_REG_NHM_TH9_TH10_11N, BIT(9), + ccx_info->nhm_inexclude_cca); + odm_set_bb_reg(dm, ODM_REG_NHM_TH9_TH10_11N, BIT(10), + ccx_info->nhm_inexclude_txon); + + /*Set NHM period*/ + odm_set_bb_reg(dm, ODM_REG_CCX_PERIOD_11N, MASKHWORD, + ccx_info->NHM_period); + + /*Set NHM threshold*/ + odm_set_bb_reg(dm, ODM_REG_NHM_TH3_TO_TH0_11N, + MASKBYTE0, ccx_info->NHM_th[0]); + odm_set_bb_reg(dm, ODM_REG_NHM_TH3_TO_TH0_11N, + MASKBYTE1, ccx_info->NHM_th[1]); + odm_set_bb_reg(dm, ODM_REG_NHM_TH3_TO_TH0_11N, + MASKBYTE2, ccx_info->NHM_th[2]); + odm_set_bb_reg(dm, ODM_REG_NHM_TH3_TO_TH0_11N, + MASKBYTE3, ccx_info->NHM_th[3]); + odm_set_bb_reg(dm, ODM_REG_NHM_TH7_TO_TH4_11N, + MASKBYTE0, ccx_info->NHM_th[4]); + odm_set_bb_reg(dm, ODM_REG_NHM_TH7_TO_TH4_11N, + MASKBYTE1, ccx_info->NHM_th[5]); + odm_set_bb_reg(dm, ODM_REG_NHM_TH7_TO_TH4_11N, + MASKBYTE2, ccx_info->NHM_th[6]); + odm_set_bb_reg(dm, ODM_REG_NHM_TH7_TO_TH4_11N, + MASKBYTE3, ccx_info->NHM_th[7]); + odm_set_bb_reg(dm, ODM_REG_NHM_TH8_11N, MASKBYTE0, + ccx_info->NHM_th[8]); + odm_set_bb_reg(dm, ODM_REG_NHM_TH9_TH10_11N, MASKBYTE2, + ccx_info->NHM_th[9]); + odm_set_bb_reg(dm, ODM_REG_NHM_TH9_TH10_11N, MASKBYTE3, + ccx_info->NHM_th[10]); + + /*CCX EN*/ + odm_set_bb_reg(dm, ODM_REG_NHM_TH9_TH10_11N, BIT(8), + CCX_EN); + } else if (nhm_setting == STORE_NHM_SETTING) { + /*Store prev. disable_ignore_cca, disable_ignore_txon*/ + ccx_info->NHM_inexclude_cca_restore = + (enum nhm_inexclude_cca)odm_get_bb_reg( + dm, ODM_REG_NHM_TH9_TH10_11N, BIT(9)); + ccx_info->NHM_inexclude_txon_restore = + (enum nhm_inexclude_txon)odm_get_bb_reg( + dm, ODM_REG_NHM_TH9_TH10_11N, BIT(10)); + + /*Store pervious NHM period*/ + ccx_info->NHM_period_restore = (u16)odm_get_bb_reg( + dm, ODM_REG_CCX_PERIOD_11N, MASKHWORD); + + /*Store NHM threshold*/ + ccx_info->NHM_th_restore[0] = (u8)odm_get_bb_reg( + dm, ODM_REG_NHM_TH3_TO_TH0_11N, MASKBYTE0); + ccx_info->NHM_th_restore[1] = (u8)odm_get_bb_reg( + dm, ODM_REG_NHM_TH3_TO_TH0_11N, MASKBYTE1); + ccx_info->NHM_th_restore[2] = (u8)odm_get_bb_reg( + dm, ODM_REG_NHM_TH3_TO_TH0_11N, MASKBYTE2); + ccx_info->NHM_th_restore[3] = (u8)odm_get_bb_reg( + dm, ODM_REG_NHM_TH3_TO_TH0_11N, MASKBYTE3); + ccx_info->NHM_th_restore[4] = (u8)odm_get_bb_reg( + dm, ODM_REG_NHM_TH7_TO_TH4_11N, MASKBYTE0); + ccx_info->NHM_th_restore[5] = (u8)odm_get_bb_reg( + dm, ODM_REG_NHM_TH7_TO_TH4_11N, MASKBYTE1); + ccx_info->NHM_th_restore[6] = (u8)odm_get_bb_reg( + dm, ODM_REG_NHM_TH7_TO_TH4_11N, MASKBYTE2); + ccx_info->NHM_th_restore[7] = (u8)odm_get_bb_reg( + dm, ODM_REG_NHM_TH7_TO_TH4_11N, MASKBYTE3); + ccx_info->NHM_th_restore[8] = (u8)odm_get_bb_reg( + dm, ODM_REG_NHM_TH8_11N, MASKBYTE0); + ccx_info->NHM_th_restore[9] = (u8)odm_get_bb_reg( + dm, ODM_REG_NHM_TH9_TH10_11N, MASKBYTE2); + ccx_info->NHM_th_restore[10] = (u8)odm_get_bb_reg( + dm, ODM_REG_NHM_TH9_TH10_11N, MASKBYTE3); + } else if (nhm_setting == RESTORE_NHM_SETTING) { + /*Set disable_ignore_cca, disable_ignore_txon*/ + odm_set_bb_reg(dm, ODM_REG_NHM_TH9_TH10_11N, BIT(9), + ccx_info->NHM_inexclude_cca_restore); + odm_set_bb_reg(dm, ODM_REG_NHM_TH9_TH10_11N, BIT(10), + ccx_info->NHM_inexclude_txon_restore); + + /*Set NHM period*/ + odm_set_bb_reg(dm, ODM_REG_CCX_PERIOD_11N, MASKHWORD, + ccx_info->NHM_period_restore); + + /*Set NHM threshold*/ + odm_set_bb_reg(dm, ODM_REG_NHM_TH3_TO_TH0_11N, + MASKBYTE0, ccx_info->NHM_th_restore[0]); + odm_set_bb_reg(dm, ODM_REG_NHM_TH3_TO_TH0_11N, + MASKBYTE1, ccx_info->NHM_th_restore[1]); + odm_set_bb_reg(dm, ODM_REG_NHM_TH3_TO_TH0_11N, + MASKBYTE2, ccx_info->NHM_th_restore[2]); + odm_set_bb_reg(dm, ODM_REG_NHM_TH3_TO_TH0_11N, + MASKBYTE3, ccx_info->NHM_th_restore[3]); + odm_set_bb_reg(dm, ODM_REG_NHM_TH7_TO_TH4_11N, + MASKBYTE0, ccx_info->NHM_th_restore[4]); + odm_set_bb_reg(dm, ODM_REG_NHM_TH7_TO_TH4_11N, + MASKBYTE1, ccx_info->NHM_th_restore[5]); + odm_set_bb_reg(dm, ODM_REG_NHM_TH7_TO_TH4_11N, + MASKBYTE2, ccx_info->NHM_th_restore[6]); + odm_set_bb_reg(dm, ODM_REG_NHM_TH7_TO_TH4_11N, + MASKBYTE3, ccx_info->NHM_th_restore[7]); + odm_set_bb_reg(dm, ODM_REG_NHM_TH8_11N, MASKBYTE0, + ccx_info->NHM_th_restore[8]); + odm_set_bb_reg(dm, ODM_REG_NHM_TH9_TH10_11N, MASKBYTE2, + ccx_info->NHM_th_restore[9]); + odm_set_bb_reg(dm, ODM_REG_NHM_TH9_TH10_11N, MASKBYTE3, + ccx_info->NHM_th_restore[10]); + } else { + return; + } + } +} + +void phydm_nhm_trigger(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + + if (dm->support_ic_type & ODM_IC_11AC_SERIES) { + /*Trigger NHM*/ + odm_set_bb_reg(dm, ODM_REG_NHM_TH9_TH10_11AC, BIT(1), 0); + odm_set_bb_reg(dm, ODM_REG_NHM_TH9_TH10_11AC, BIT(1), 1); + } else if (dm->support_ic_type & ODM_IC_11N_SERIES) { + /*Trigger NHM*/ + odm_set_bb_reg(dm, ODM_REG_NHM_TH9_TH10_11N, BIT(1), 0); + odm_set_bb_reg(dm, ODM_REG_NHM_TH9_TH10_11N, BIT(1), 1); + } +} + +void phydm_get_nhm_result(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + u32 value32; + struct ccx_info *ccx_info = &dm->dm_ccx_info; + + if (dm->support_ic_type & ODM_IC_11AC_SERIES) { + value32 = odm_read_4byte(dm, ODM_REG_NHM_CNT_11AC); + ccx_info->NHM_result[0] = (u8)(value32 & MASKBYTE0); + ccx_info->NHM_result[1] = (u8)((value32 & MASKBYTE1) >> 8); + ccx_info->NHM_result[2] = (u8)((value32 & MASKBYTE2) >> 16); + ccx_info->NHM_result[3] = (u8)((value32 & MASKBYTE3) >> 24); + + value32 = odm_read_4byte(dm, ODM_REG_NHM_CNT7_TO_CNT4_11AC); + ccx_info->NHM_result[4] = (u8)(value32 & MASKBYTE0); + ccx_info->NHM_result[5] = (u8)((value32 & MASKBYTE1) >> 8); + ccx_info->NHM_result[6] = (u8)((value32 & MASKBYTE2) >> 16); + ccx_info->NHM_result[7] = (u8)((value32 & MASKBYTE3) >> 24); + + value32 = odm_read_4byte(dm, ODM_REG_NHM_CNT11_TO_CNT8_11AC); + ccx_info->NHM_result[8] = (u8)(value32 & MASKBYTE0); + ccx_info->NHM_result[9] = (u8)((value32 & MASKBYTE1) >> 8); + ccx_info->NHM_result[10] = (u8)((value32 & MASKBYTE2) >> 16); + ccx_info->NHM_result[11] = (u8)((value32 & MASKBYTE3) >> 24); + + /*Get NHM duration*/ + value32 = odm_read_4byte(dm, ODM_REG_NHM_DUR_READY_11AC); + ccx_info->NHM_duration = (u16)(value32 & MASKLWORD); + } + + else if (dm->support_ic_type & ODM_IC_11N_SERIES) { + value32 = odm_read_4byte(dm, ODM_REG_NHM_CNT_11N); + ccx_info->NHM_result[0] = (u8)(value32 & MASKBYTE0); + ccx_info->NHM_result[1] = (u8)((value32 & MASKBYTE1) >> 8); + ccx_info->NHM_result[2] = (u8)((value32 & MASKBYTE2) >> 16); + ccx_info->NHM_result[3] = (u8)((value32 & MASKBYTE3) >> 24); + + value32 = odm_read_4byte(dm, ODM_REG_NHM_CNT7_TO_CNT4_11N); + ccx_info->NHM_result[4] = (u8)(value32 & MASKBYTE0); + ccx_info->NHM_result[5] = (u8)((value32 & MASKBYTE1) >> 8); + ccx_info->NHM_result[6] = (u8)((value32 & MASKBYTE2) >> 16); + ccx_info->NHM_result[7] = (u8)((value32 & MASKBYTE3) >> 24); + + value32 = odm_read_4byte(dm, ODM_REG_NHM_CNT9_TO_CNT8_11N); + ccx_info->NHM_result[8] = (u8)((value32 & MASKBYTE2) >> 16); + ccx_info->NHM_result[9] = (u8)((value32 & MASKBYTE3) >> 24); + + value32 = odm_read_4byte(dm, ODM_REG_NHM_CNT10_TO_CNT11_11N); + ccx_info->NHM_result[10] = (u8)((value32 & MASKBYTE2) >> 16); + ccx_info->NHM_result[11] = (u8)((value32 & MASKBYTE3) >> 24); + + /*Get NHM duration*/ + value32 = odm_read_4byte(dm, ODM_REG_NHM_CNT10_TO_CNT11_11N); + ccx_info->NHM_duration = (u16)(value32 & MASKLWORD); + } +} + +bool phydm_check_nhm_ready(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + u32 value32 = 0; + u8 i; + bool ret = false; + + if (dm->support_ic_type & ODM_IC_11AC_SERIES) { + value32 = + odm_get_bb_reg(dm, ODM_REG_CLM_RESULT_11AC, MASKDWORD); + + for (i = 0; i < 200; i++) { + ODM_delay_ms(1); + if (odm_get_bb_reg(dm, ODM_REG_NHM_DUR_READY_11AC, + BIT(17))) { + ret = 1; + break; + } + } + } + + else if (dm->support_ic_type & ODM_IC_11N_SERIES) { + value32 = odm_get_bb_reg(dm, ODM_REG_CLM_READY_11N, MASKDWORD); + + for (i = 0; i < 200; i++) { + ODM_delay_ms(1); + if (odm_get_bb_reg(dm, ODM_REG_NHM_DUR_READY_11AC, + BIT(17))) { + ret = 1; + break; + } + } + } + return ret; +} + +void phydm_clm_setting(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct ccx_info *ccx_info = &dm->dm_ccx_info; + + if (dm->support_ic_type & ODM_IC_11AC_SERIES) { + odm_set_bb_reg(dm, ODM_REG_CCX_PERIOD_11AC, MASKLWORD, + ccx_info->CLM_period); /*4us sample 1 time*/ + odm_set_bb_reg(dm, ODM_REG_CLM_11AC, BIT(8), + 0x1); /*Enable CCX for CLM*/ + + } else if (dm->support_ic_type & ODM_IC_11N_SERIES) { + odm_set_bb_reg(dm, ODM_REG_CCX_PERIOD_11N, MASKLWORD, + ccx_info->CLM_period); /*4us sample 1 time*/ + odm_set_bb_reg(dm, ODM_REG_CLM_11N, BIT(8), + 0x1); /*Enable CCX for CLM*/ + } + + ODM_RT_TRACE(dm, ODM_COMP_CCX, "[%s] : CLM period = %dus\n", __func__, + ccx_info->CLM_period * 4); +} + +void phydm_clm_trigger(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + + if (dm->support_ic_type & ODM_IC_11AC_SERIES) { + odm_set_bb_reg(dm, ODM_REG_CLM_11AC, BIT(0), + 0x0); /*Trigger CLM*/ + odm_set_bb_reg(dm, ODM_REG_CLM_11AC, BIT(0), 0x1); + } else if (dm->support_ic_type & ODM_IC_11N_SERIES) { + odm_set_bb_reg(dm, ODM_REG_CLM_11N, BIT(0), + 0x0); /*Trigger CLM*/ + odm_set_bb_reg(dm, ODM_REG_CLM_11N, BIT(0), 0x1); + } +} + +bool phydm_check_cl_mready(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + u32 value32 = 0; + bool ret = false; + + if (dm->support_ic_type & ODM_IC_11AC_SERIES) + value32 = odm_get_bb_reg( + dm, ODM_REG_CLM_RESULT_11AC, + MASKDWORD); /*make sure CLM calc is ready*/ + else if (dm->support_ic_type & ODM_IC_11N_SERIES) + value32 = odm_get_bb_reg( + dm, ODM_REG_CLM_READY_11N, + MASKDWORD); /*make sure CLM calc is ready*/ + + if ((dm->support_ic_type & ODM_IC_11AC_SERIES) && (value32 & BIT(16))) + ret = true; + else if ((dm->support_ic_type & ODM_IC_11N_SERIES) && + (value32 & BIT(16))) + ret = true; + else + ret = false; + + ODM_RT_TRACE(dm, ODM_COMP_CCX, "[%s] : CLM ready = %d\n", __func__, + ret); + + return ret; +} + +void phydm_get_cl_mresult(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct ccx_info *ccx_info = &dm->dm_ccx_info; + + u32 value32 = 0; + + if (dm->support_ic_type & ODM_IC_11AC_SERIES) + value32 = odm_get_bb_reg(dm, ODM_REG_CLM_RESULT_11AC, + MASKDWORD); /*read CLM calc result*/ + else if (dm->support_ic_type & ODM_IC_11N_SERIES) + value32 = odm_get_bb_reg(dm, ODM_REG_CLM_RESULT_11N, + MASKDWORD); /*read CLM calc result*/ + + ccx_info->CLM_result = (u16)(value32 & MASKLWORD); + + ODM_RT_TRACE(dm, ODM_COMP_CCX, "[%s] : CLM result = %dus\n", __func__, + ccx_info->CLM_result * 4); +} diff --git a/drivers/staging/rtlwifi/phydm/phydm_ccx.h b/drivers/staging/rtlwifi/phydm/phydm_ccx.h new file mode 100644 index 000000000000..a3517f4642f9 --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/phydm_ccx.h @@ -0,0 +1,83 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef __PHYDMCCX_H__ +#define __PHYDMCCX_H__ + +#define CCX_EN 1 + +#define SET_NHM_SETTING 0 +#define STORE_NHM_SETTING 1 +#define RESTORE_NHM_SETTING 2 + +enum nhm_inexclude_cca { NHM_EXCLUDE_CCA, NHM_INCLUDE_CCA }; + +enum nhm_inexclude_txon { NHM_EXCLUDE_TXON, NHM_INCLUDE_TXON }; + +struct ccx_info { + /*Settings*/ + u8 NHM_th[11]; + u16 NHM_period; /* 4us per unit */ + u16 CLM_period; /* 4us per unit */ + enum nhm_inexclude_txon nhm_inexclude_txon; + enum nhm_inexclude_cca nhm_inexclude_cca; + + /*Previous Settings*/ + u8 NHM_th_restore[11]; + u16 NHM_period_restore; /* 4us per unit */ + u16 CLM_period_restore; /* 4us per unit */ + enum nhm_inexclude_txon NHM_inexclude_txon_restore; + enum nhm_inexclude_cca NHM_inexclude_cca_restore; + + /*Report*/ + u8 NHM_result[12]; + u16 NHM_duration; + u16 CLM_result; + + bool echo_NHM_en; + bool echo_CLM_en; + u8 echo_IGI; +}; + +/*NHM*/ + +void phydm_nhm_setting(void *dm_void, u8 nhm_setting); + +void phydm_nhm_trigger(void *dm_void); + +void phydm_get_nhm_result(void *dm_void); + +bool phydm_check_nhm_ready(void *dm_void); + +/*CLM*/ + +void phydm_clm_setting(void *dm_void); + +void phydm_clm_trigger(void *dm_void); + +bool phydm_check_cl_mready(void *dm_void); + +void phydm_get_cl_mresult(void *dm_void); + +#endif diff --git a/drivers/staging/rtlwifi/phydm/phydm_cfotracking.c b/drivers/staging/rtlwifi/phydm/phydm_cfotracking.c new file mode 100644 index 000000000000..2ec8444f31a7 --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/phydm_cfotracking.c @@ -0,0 +1,343 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#include "mp_precomp.h" +#include "phydm_precomp.h" + +static void odm_set_crystal_cap(void *dm_void, u8 crystal_cap) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct cfo_tracking *cfo_track = + (struct cfo_tracking *)phydm_get_structure(dm, PHYDM_CFOTRACK); + + if (cfo_track->crystal_cap == crystal_cap) + return; + + cfo_track->crystal_cap = crystal_cap; + + if (dm->support_ic_type & (ODM_RTL8188E | ODM_RTL8188F)) { + /* write 0x24[22:17] = 0x24[16:11] = crystal_cap */ + crystal_cap = crystal_cap & 0x3F; + odm_set_bb_reg(dm, REG_AFE_XTAL_CTRL, 0x007ff800, + (crystal_cap | (crystal_cap << 6))); + } else if (dm->support_ic_type & ODM_RTL8812) { + /* write 0x2C[30:25] = 0x2C[24:19] = crystal_cap */ + crystal_cap = crystal_cap & 0x3F; + odm_set_bb_reg(dm, REG_MAC_PHY_CTRL, 0x7FF80000, + (crystal_cap | (crystal_cap << 6))); + } else if ((dm->support_ic_type & (ODM_RTL8703B | ODM_RTL8723B | + ODM_RTL8192E | ODM_RTL8821))) { + /* 0x2C[23:18] = 0x2C[17:12] = crystal_cap */ + crystal_cap = crystal_cap & 0x3F; + odm_set_bb_reg(dm, REG_MAC_PHY_CTRL, 0x00FFF000, + (crystal_cap | (crystal_cap << 6))); + } else if (dm->support_ic_type & ODM_RTL8814A) { + /* write 0x2C[26:21] = 0x2C[20:15] = crystal_cap */ + crystal_cap = crystal_cap & 0x3F; + odm_set_bb_reg(dm, REG_MAC_PHY_CTRL, 0x07FF8000, + (crystal_cap | (crystal_cap << 6))); + } else if (dm->support_ic_type & (ODM_RTL8822B | ODM_RTL8821C)) { + /* write 0x24[30:25] = 0x28[6:1] = crystal_cap */ + crystal_cap = crystal_cap & 0x3F; + odm_set_bb_reg(dm, REG_AFE_XTAL_CTRL, 0x7e000000, crystal_cap); + odm_set_bb_reg(dm, REG_AFE_PLL_CTRL, 0x7e, crystal_cap); + } else { + ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING, + "%s(): Use default setting.\n", __func__); + odm_set_bb_reg(dm, REG_MAC_PHY_CTRL, 0xFFF000, + (crystal_cap | (crystal_cap << 6))); + } + + ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING, "%s(): crystal_cap = 0x%x\n", + __func__, crystal_cap); + + /* JJ modified 20161115 */ +} + +static u8 odm_get_default_crytaltal_cap(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + u8 crystal_cap = 0x20; + + struct rtl_priv *rtlpriv = (struct rtl_priv *)dm->adapter; + struct rtl_efuse *rtlefuse = rtl_efuse(rtlpriv); + + crystal_cap = rtlefuse->crystalcap; + + crystal_cap = crystal_cap & 0x3f; + + return crystal_cap; +} + +static void odm_set_atc_status(void *dm_void, bool atc_status) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct cfo_tracking *cfo_track = + (struct cfo_tracking *)phydm_get_structure(dm, PHYDM_CFOTRACK); + + if (cfo_track->is_atc_status == atc_status) + return; + + odm_set_bb_reg(dm, ODM_REG(BB_ATC, dm), ODM_BIT(BB_ATC, dm), + atc_status); + cfo_track->is_atc_status = atc_status; +} + +static bool odm_get_atc_status(void *dm_void) +{ + bool atc_status; + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + + atc_status = (bool)odm_get_bb_reg(dm, ODM_REG(BB_ATC, dm), + ODM_BIT(BB_ATC, dm)); + return atc_status; +} + +void odm_cfo_tracking_reset(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct cfo_tracking *cfo_track = + (struct cfo_tracking *)phydm_get_structure(dm, PHYDM_CFOTRACK); + + cfo_track->def_x_cap = odm_get_default_crytaltal_cap(dm); + cfo_track->is_adjust = true; + + if (cfo_track->crystal_cap > cfo_track->def_x_cap) { + odm_set_crystal_cap(dm, cfo_track->crystal_cap - 1); + ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING, + "%s(): approch default value (0x%x)\n", __func__, + cfo_track->crystal_cap); + } else if (cfo_track->crystal_cap < cfo_track->def_x_cap) { + odm_set_crystal_cap(dm, cfo_track->crystal_cap + 1); + ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING, + "%s(): approch default value (0x%x)\n", __func__, + cfo_track->crystal_cap); + } + + odm_set_atc_status(dm, true); +} + +void odm_cfo_tracking_init(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct cfo_tracking *cfo_track = + (struct cfo_tracking *)phydm_get_structure(dm, PHYDM_CFOTRACK); + + cfo_track->crystal_cap = odm_get_default_crytaltal_cap(dm); + cfo_track->def_x_cap = cfo_track->crystal_cap; + cfo_track->is_atc_status = odm_get_atc_status(dm); + cfo_track->is_adjust = true; + ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING, "%s()=========>\n", __func__); + ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING, + "%s(): is_atc_status = %d, crystal_cap = 0x%x\n", __func__, + cfo_track->is_atc_status, cfo_track->def_x_cap); + + /* Crystal cap. control by WiFi */ + if (dm->support_ic_type & ODM_RTL8822B) + odm_set_bb_reg(dm, 0x10, 0x40, 0x1); +} + +void odm_cfo_tracking(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct cfo_tracking *cfo_track = + (struct cfo_tracking *)phydm_get_structure(dm, PHYDM_CFOTRACK); + s32 cfo_ave = 0; + u32 cfo_rpt_sum, cfo_khz_avg[4] = {0}; + s32 cfo_ave_diff; + s8 crystal_cap = cfo_track->crystal_cap; + u8 adjust_xtal = 1, i, valid_path_cnt = 0; + + /* 4 Support ability */ + if (!(dm->support_ability & ODM_BB_CFO_TRACKING)) { + ODM_RT_TRACE( + dm, ODM_COMP_CFO_TRACKING, + "%s(): Return: support_ability ODM_BB_CFO_TRACKING is disabled\n", + __func__); + return; + } + + ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING, "%s()=========>\n", __func__); + + if (!dm->is_linked || !dm->is_one_entry_only) { + /* 4 No link or more than one entry */ + odm_cfo_tracking_reset(dm); + ODM_RT_TRACE( + dm, ODM_COMP_CFO_TRACKING, + "%s(): Reset: is_linked = %d, is_one_entry_only = %d\n", + __func__, dm->is_linked, dm->is_one_entry_only); + } else { + /* 3 1. CFO Tracking */ + /* 4 1.1 No new packet */ + if (cfo_track->packet_count == cfo_track->packet_count_pre) { + ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING, + "%s(): packet counter doesn't change\n", + __func__); + return; + } + cfo_track->packet_count_pre = cfo_track->packet_count; + + /* 4 1.2 Calculate CFO */ + for (i = 0; i < dm->num_rf_path; i++) { + if (cfo_track->CFO_cnt[i] == 0) + continue; + + valid_path_cnt++; + cfo_rpt_sum = + (u32)((cfo_track->CFO_tail[i] < 0) ? + (0 - cfo_track->CFO_tail[i]) : + cfo_track->CFO_tail[i]); + cfo_khz_avg[i] = CFO_HW_RPT_2_MHZ(cfo_rpt_sum) / + cfo_track->CFO_cnt[i]; + + ODM_RT_TRACE( + dm, ODM_COMP_CFO_TRACKING, + "[path %d] cfo_rpt_sum = (( %d )), CFO_cnt = (( %d )) , CFO_avg= (( %s%d )) kHz\n", + i, cfo_rpt_sum, cfo_track->CFO_cnt[i], + ((cfo_track->CFO_tail[i] < 0) ? "-" : " "), + cfo_khz_avg[i]); + } + + for (i = 0; i < valid_path_cnt; i++) { + if (cfo_track->CFO_tail[i] < 0) { + /* */ + cfo_ave += (0 - (s32)cfo_khz_avg[i]); + } else { + cfo_ave += (s32)cfo_khz_avg[i]; + } + } + + if (valid_path_cnt >= 2) + cfo_ave = cfo_ave / valid_path_cnt; + + ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING, + "valid_path_cnt = ((%d)), cfo_ave = ((%d kHz))\n", + valid_path_cnt, cfo_ave); + + /*reset counter*/ + for (i = 0; i < dm->num_rf_path; i++) { + cfo_track->CFO_tail[i] = 0; + cfo_track->CFO_cnt[i] = 0; + } + + /* 4 1.3 Avoid abnormal large CFO */ + cfo_ave_diff = (cfo_track->CFO_ave_pre >= cfo_ave) ? + (cfo_track->CFO_ave_pre - cfo_ave) : + (cfo_ave - cfo_track->CFO_ave_pre); + if (cfo_ave_diff > 20 && cfo_track->large_cfo_hit == 0 && + !cfo_track->is_adjust) { + ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING, + "%s(): first large CFO hit\n", __func__); + cfo_track->large_cfo_hit = 1; + return; + } + + cfo_track->large_cfo_hit = 0; + cfo_track->CFO_ave_pre = cfo_ave; + + /* 4 1.4 Dynamic Xtal threshold */ + if (!cfo_track->is_adjust) { + if (cfo_ave > CFO_TH_XTAL_HIGH || + cfo_ave < (-CFO_TH_XTAL_HIGH)) + cfo_track->is_adjust = true; + } else { + if (cfo_ave < CFO_TH_XTAL_LOW && + cfo_ave > (-CFO_TH_XTAL_LOW)) + cfo_track->is_adjust = false; + } + + /* 4 1.5 BT case: Disable CFO tracking */ + if (dm->is_bt_enabled) { + cfo_track->is_adjust = false; + odm_set_crystal_cap(dm, cfo_track->def_x_cap); + ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING, + "%s(): Disable CFO tracking for BT!!\n", + __func__); + } + + /* 4 1.7 Adjust Crystal Cap. */ + if (cfo_track->is_adjust) { + if (cfo_ave > CFO_TH_XTAL_LOW) + crystal_cap = crystal_cap + adjust_xtal; + else if (cfo_ave < (-CFO_TH_XTAL_LOW)) + crystal_cap = crystal_cap - adjust_xtal; + + if (crystal_cap > 0x3f) + crystal_cap = 0x3f; + else if (crystal_cap < 0) + crystal_cap = 0; + + odm_set_crystal_cap(dm, (u8)crystal_cap); + } + ODM_RT_TRACE( + dm, ODM_COMP_CFO_TRACKING, + "%s(): Crystal cap = 0x%x, Default Crystal cap = 0x%x\n", + __func__, cfo_track->crystal_cap, cfo_track->def_x_cap); + + if (dm->support_ic_type & ODM_IC_11AC_SERIES) + return; + + /* 3 2. Dynamic ATC switch */ + if (cfo_ave < CFO_TH_ATC && cfo_ave > -CFO_TH_ATC) { + odm_set_atc_status(dm, false); + ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING, + "%s(): Disable ATC!!\n", __func__); + } else { + odm_set_atc_status(dm, true); + ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING, + "%s(): Enable ATC!!\n", __func__); + } + } +} + +void odm_parsing_cfo(void *dm_void, void *pktinfo_void, s8 *pcfotail, u8 num_ss) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct dm_per_pkt_info *pktinfo = + (struct dm_per_pkt_info *)pktinfo_void; + struct cfo_tracking *cfo_track = + (struct cfo_tracking *)phydm_get_structure(dm, PHYDM_CFOTRACK); + u8 i; + + if (!(dm->support_ability & ODM_BB_CFO_TRACKING)) + return; + + if (pktinfo->is_packet_match_bssid) { + if (num_ss > dm->num_rf_path) /*For fool proof*/ + num_ss = dm->num_rf_path; + + /* 3 Update CFO report for path-A & path-B */ + /* Only paht-A and path-B have CFO tail and short CFO */ + for (i = 0; i < num_ss; i++) { + cfo_track->CFO_tail[i] += pcfotail[i]; + cfo_track->CFO_cnt[i]++; + } + + /* 3 Update packet counter */ + if (cfo_track->packet_count == 0xffffffff) + cfo_track->packet_count = 0; + else + cfo_track->packet_count++; + } +} diff --git a/drivers/staging/rtlwifi/phydm/phydm_cfotracking.h b/drivers/staging/rtlwifi/phydm/phydm_cfotracking.h new file mode 100644 index 000000000000..e8436a31019d --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/phydm_cfotracking.h @@ -0,0 +1,60 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __PHYDMCFOTRACK_H__ +#define __PHYDMCFOTRACK_H__ + +#define CFO_TRACKING_VERSION "1.4" /*2015.10.01 Stanley, Modify for 8822B*/ + +#define CFO_TH_XTAL_HIGH 20 /* kHz */ +#define CFO_TH_XTAL_LOW 10 /* kHz */ +#define CFO_TH_ATC 80 /* kHz */ + +struct cfo_tracking { + bool is_atc_status; + bool large_cfo_hit; + bool is_adjust; + u8 crystal_cap; + u8 def_x_cap; + s32 CFO_tail[4]; + u32 CFO_cnt[4]; + s32 CFO_ave_pre; + u32 packet_count; + u32 packet_count_pre; + + bool is_force_xtal_cap; + bool is_reset; +}; + +void odm_cfo_tracking_reset(void *dm_void); + +void odm_cfo_tracking_init(void *dm_void); + +void odm_cfo_tracking(void *dm_void); + +void odm_parsing_cfo(void *dm_void, void *pktinfo_void, s8 *pcfotail, + u8 num_ss); + +#endif diff --git a/drivers/staging/rtlwifi/phydm/phydm_debug.c b/drivers/staging/rtlwifi/phydm/phydm_debug.c new file mode 100644 index 000000000000..a5f90afdae9b --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/phydm_debug.c @@ -0,0 +1,2910 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +/* ************************************************************ + * include files + * *************************************************************/ + +#include "mp_precomp.h" +#include "phydm_precomp.h" + +bool phydm_api_set_txagc(struct phy_dm_struct *, u32, enum odm_rf_radio_path, + u8, bool); +static inline void phydm_check_dmval_txagc(struct phy_dm_struct *dm, u32 used, + u32 out_len, u32 *const dm_value, + char *output) +{ + if ((u8)dm_value[2] != 0xff) { + if (phydm_api_set_txagc(dm, dm_value[3], + (enum odm_rf_radio_path)dm_value[1], + (u8)dm_value[2], true)) + PHYDM_SNPRINTF(output + used, out_len - used, + " %s%d %s%x%s%x\n", "Write path-", + dm_value[1], "rate index-0x", + dm_value[2], " = 0x", dm_value[3]); + else + PHYDM_SNPRINTF(output + used, out_len - used, + " %s%d %s%x%s\n", "Write path-", + (dm_value[1] & 0x1), "rate index-0x", + (dm_value[2] & 0x7f), " fail"); + } else { + u8 i; + u32 power_index; + bool status = true; + + power_index = (dm_value[3] & 0x3f); + + if (dm->support_ic_type & (ODM_RTL8822B | ODM_RTL8821C)) { + power_index = (power_index << 24) | + (power_index << 16) | (power_index << 8) | + (power_index); + for (i = 0; i < ODM_RATEVHTSS2MCS9; i += 4) + status = (status & + phydm_api_set_txagc( + dm, power_index, + (enum odm_rf_radio_path) + dm_value[1], + i, false)); + } else if (dm->support_ic_type & ODM_RTL8197F) { + for (i = 0; i <= ODM_RATEMCS15; i++) + status = (status & + phydm_api_set_txagc( + dm, power_index, + (enum odm_rf_radio_path) + dm_value[1], + i, false)); + } + + if (status) + PHYDM_SNPRINTF(output + used, out_len - used, + " %s%d %s%x\n", + "Write all TXAGC of path-", dm_value[1], + " = 0x", dm_value[3]); + else + PHYDM_SNPRINTF(output + used, out_len - used, + " %s%d %s\n", + "Write all TXAGC of path-", dm_value[1], + " fail"); + } +} + +static inline void phydm_print_nhm_trigger(char *output, u32 used, u32 out_len, + struct ccx_info *ccx_info) +{ + int i; + + for (i = 0; i <= 10; i++) { + if (i == 5) + PHYDM_SNPRINTF( + output + used, out_len - used, + "\r\n NHM_th[%d] = 0x%x, echo_IGI = 0x%x", i, + ccx_info->NHM_th[i], ccx_info->echo_IGI); + else if (i == 10) + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n NHM_th[%d] = 0x%x\n", i, + ccx_info->NHM_th[i]); + else + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n NHM_th[%d] = 0x%x", i, + ccx_info->NHM_th[i]); + } +} + +static inline void phydm_print_nhm_result(char *output, u32 used, u32 out_len, + struct ccx_info *ccx_info) +{ + int i; + + for (i = 0; i <= 11; i++) { + if (i == 5) + PHYDM_SNPRINTF( + output + used, out_len - used, + "\r\n nhm_result[%d] = %d, echo_IGI = 0x%x", i, + ccx_info->NHM_result[i], ccx_info->echo_IGI); + else if (i == 11) + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n nhm_result[%d] = %d\n", i, + ccx_info->NHM_result[i]); + else + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n nhm_result[%d] = %d", i, + ccx_info->NHM_result[i]); + } +} + +static inline void phydm_print_csi(struct phy_dm_struct *dm, u32 used, + u32 out_len, char *output) +{ + int index, ptr; + u32 dword_h, dword_l; + + for (index = 0; index < 80; index++) { + ptr = index + 256; + + if (ptr > 311) + ptr -= 312; + + odm_set_bb_reg(dm, 0x1910, 0x03FF0000, ptr); /*Select Address*/ + dword_h = odm_get_bb_reg(dm, 0xF74, MASKDWORD); + dword_l = odm_get_bb_reg(dm, 0xF5C, MASKDWORD); + + if (index % 2 == 0) + PHYDM_SNPRINTF( + output + used, out_len - used, + "%02x %02x %02x %02x %02x %02x %02x %02x\n", + dword_l & MASKBYTE0, (dword_l & MASKBYTE1) >> 8, + (dword_l & MASKBYTE2) >> 16, + (dword_l & MASKBYTE3) >> 24, + dword_h & MASKBYTE0, (dword_h & MASKBYTE1) >> 8, + (dword_h & MASKBYTE2) >> 16, + (dword_h & MASKBYTE3) >> 24); + else + PHYDM_SNPRINTF( + output + used, out_len - used, + "%02x %02x %02x %02x %02x %02x %02x %02x\n", + dword_l & MASKBYTE0, (dword_l & MASKBYTE1) >> 8, + (dword_l & MASKBYTE2) >> 16, + (dword_l & MASKBYTE3) >> 24, + dword_h & MASKBYTE0, (dword_h & MASKBYTE1) >> 8, + (dword_h & MASKBYTE2) >> 16, + (dword_h & MASKBYTE3) >> 24); + } +} + +void phydm_init_debug_setting(struct phy_dm_struct *dm) +{ + dm->debug_level = ODM_DBG_TRACE; + + dm->fw_debug_components = 0; + dm->debug_components = + + 0; + + dm->fw_buff_is_enpty = true; + dm->pre_c2h_seq = 0; +} + +u8 phydm_set_bb_dbg_port(void *dm_void, u8 curr_dbg_priority, u32 debug_port) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + u8 dbg_port_result = false; + + if (curr_dbg_priority > dm->pre_dbg_priority) { + if (dm->support_ic_type & ODM_IC_11AC_SERIES) { + odm_set_bb_reg(dm, 0x8fc, MASKDWORD, debug_port); + /**/ + } else /*if (dm->support_ic_type & ODM_IC_11N_SERIES)*/ { + odm_set_bb_reg(dm, 0x908, MASKDWORD, debug_port); + /**/ + } + ODM_RT_TRACE( + dm, ODM_COMP_API, + "DbgPort set success, Reg((0x%x)), Cur_priority=((%d)), Pre_priority=((%d))\n", + debug_port, curr_dbg_priority, dm->pre_dbg_priority); + dm->pre_dbg_priority = curr_dbg_priority; + dbg_port_result = true; + } + + return dbg_port_result; +} + +void phydm_release_bb_dbg_port(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + + dm->pre_dbg_priority = BB_DBGPORT_RELEASE; + ODM_RT_TRACE(dm, ODM_COMP_API, "Release BB dbg_port\n"); +} + +u32 phydm_get_bb_dbg_port_value(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + u32 dbg_port_value = 0; + + if (dm->support_ic_type & ODM_IC_11AC_SERIES) { + dbg_port_value = odm_get_bb_reg(dm, 0xfa0, MASKDWORD); + /**/ + } else /*if (dm->support_ic_type & ODM_IC_11N_SERIES)*/ { + dbg_port_value = odm_get_bb_reg(dm, 0xdf4, MASKDWORD); + /**/ + } + ODM_RT_TRACE(dm, ODM_COMP_API, "dbg_port_value = 0x%x\n", + dbg_port_value); + return dbg_port_value; +} + +static void phydm_bb_rx_hang_info(void *dm_void, u32 *_used, char *output, + u32 *_out_len) +{ + u32 value32 = 0; + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + u32 used = *_used; + u32 out_len = *_out_len; + + if (dm->support_ic_type & ODM_IC_11N_SERIES) + return; + + value32 = odm_get_bb_reg(dm, 0xF80, MASKDWORD); + PHYDM_SNPRINTF(output + used, out_len - used, "\r\n %-35s = 0x%x", + "rptreg of sc/bw/ht/...", value32); + + if (dm->support_ic_type & ODM_RTL8822B) + odm_set_bb_reg(dm, 0x198c, BIT(2) | BIT(1) | BIT(0), 7); + + /* dbg_port = basic state machine */ + { + odm_set_bb_reg(dm, ODM_REG_DBG_RPT_11AC, MASKDWORD, 0x000); + value32 = odm_get_bb_reg(dm, ODM_REG_DBG_RPT_11AC, MASKDWORD); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n %-35s = 0x%x", "0x8fc", value32); + + value32 = odm_get_bb_reg(dm, ODM_REG_RPT_11AC, MASKDWORD); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n %-35s = 0x%x", "basic state machine", + value32); + } + + /* dbg_port = state machine */ + { + odm_set_bb_reg(dm, ODM_REG_DBG_RPT_11AC, MASKDWORD, 0x007); + value32 = odm_get_bb_reg(dm, ODM_REG_DBG_RPT_11AC, MASKDWORD); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n %-35s = 0x%x", "0x8fc", value32); + + value32 = odm_get_bb_reg(dm, ODM_REG_RPT_11AC, MASKDWORD); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n %-35s = 0x%x", "state machine", value32); + } + + /* dbg_port = CCA-related*/ + { + odm_set_bb_reg(dm, ODM_REG_DBG_RPT_11AC, MASKDWORD, 0x204); + value32 = odm_get_bb_reg(dm, ODM_REG_DBG_RPT_11AC, MASKDWORD); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n %-35s = 0x%x", "0x8fc", value32); + + value32 = odm_get_bb_reg(dm, ODM_REG_RPT_11AC, MASKDWORD); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n %-35s = 0x%x", "CCA-related", value32); + } + + /* dbg_port = edcca/rxd*/ + { + odm_set_bb_reg(dm, ODM_REG_DBG_RPT_11AC, MASKDWORD, 0x278); + value32 = odm_get_bb_reg(dm, ODM_REG_DBG_RPT_11AC, MASKDWORD); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n %-35s = 0x%x", "0x8fc", value32); + + value32 = odm_get_bb_reg(dm, ODM_REG_RPT_11AC, MASKDWORD); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n %-35s = 0x%x", "edcca/rxd", value32); + } + + /* dbg_port = rx_state/mux_state/ADC_MASK_OFDM*/ + { + odm_set_bb_reg(dm, ODM_REG_DBG_RPT_11AC, MASKDWORD, 0x290); + value32 = odm_get_bb_reg(dm, ODM_REG_DBG_RPT_11AC, MASKDWORD); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n %-35s = 0x%x", "0x8fc", value32); + + value32 = odm_get_bb_reg(dm, ODM_REG_RPT_11AC, MASKDWORD); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n %-35s = 0x%x", + "rx_state/mux_state/ADC_MASK_OFDM", value32); + } + + /* dbg_port = bf-related*/ + { + odm_set_bb_reg(dm, ODM_REG_DBG_RPT_11AC, MASKDWORD, 0x2B2); + value32 = odm_get_bb_reg(dm, ODM_REG_DBG_RPT_11AC, MASKDWORD); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n %-35s = 0x%x", "0x8fc", value32); + + value32 = odm_get_bb_reg(dm, ODM_REG_RPT_11AC, MASKDWORD); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n %-35s = 0x%x", "bf-related", value32); + } + + /* dbg_port = bf-related*/ + { + odm_set_bb_reg(dm, ODM_REG_DBG_RPT_11AC, MASKDWORD, 0x2B8); + value32 = odm_get_bb_reg(dm, ODM_REG_DBG_RPT_11AC, MASKDWORD); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n %-35s = 0x%x", "0x8fc", value32); + + value32 = odm_get_bb_reg(dm, ODM_REG_RPT_11AC, MASKDWORD); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n %-35s = 0x%x", "bf-related", value32); + } + + /* dbg_port = txon/rxd*/ + { + odm_set_bb_reg(dm, ODM_REG_DBG_RPT_11AC, MASKDWORD, 0xA03); + value32 = odm_get_bb_reg(dm, ODM_REG_DBG_RPT_11AC, MASKDWORD); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n %-35s = 0x%x", "0x8fc", value32); + + value32 = odm_get_bb_reg(dm, ODM_REG_RPT_11AC, MASKDWORD); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n %-35s = 0x%x", "txon/rxd", value32); + } + + /* dbg_port = l_rate/l_length*/ + { + odm_set_bb_reg(dm, ODM_REG_DBG_RPT_11AC, MASKDWORD, 0xA0B); + value32 = odm_get_bb_reg(dm, ODM_REG_DBG_RPT_11AC, MASKDWORD); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n %-35s = 0x%x", "0x8fc", value32); + + value32 = odm_get_bb_reg(dm, ODM_REG_RPT_11AC, MASKDWORD); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n %-35s = 0x%x", "l_rate/l_length", value32); + } + + /* dbg_port = rxd/rxd_hit*/ + { + odm_set_bb_reg(dm, ODM_REG_DBG_RPT_11AC, MASKDWORD, 0xA0D); + value32 = odm_get_bb_reg(dm, ODM_REG_DBG_RPT_11AC, MASKDWORD); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n %-35s = 0x%x", "0x8fc", value32); + + value32 = odm_get_bb_reg(dm, ODM_REG_RPT_11AC, MASKDWORD); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n %-35s = 0x%x", "rxd/rxd_hit", value32); + } + + /* dbg_port = dis_cca*/ + { + odm_set_bb_reg(dm, ODM_REG_DBG_RPT_11AC, MASKDWORD, 0xAA0); + value32 = odm_get_bb_reg(dm, ODM_REG_DBG_RPT_11AC, MASKDWORD); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n %-35s = 0x%x", "0x8fc", value32); + + value32 = odm_get_bb_reg(dm, ODM_REG_RPT_11AC, MASKDWORD); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n %-35s = 0x%x", "dis_cca", value32); + } + + /* dbg_port = tx*/ + { + odm_set_bb_reg(dm, ODM_REG_DBG_RPT_11AC, MASKDWORD, 0xAB0); + value32 = odm_get_bb_reg(dm, ODM_REG_DBG_RPT_11AC, MASKDWORD); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n %-35s = 0x%x", "0x8fc", value32); + + value32 = odm_get_bb_reg(dm, ODM_REG_RPT_11AC, MASKDWORD); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n %-35s = 0x%x", "tx", value32); + } + + /* dbg_port = rx plcp*/ + { + odm_set_bb_reg(dm, ODM_REG_DBG_RPT_11AC, MASKDWORD, 0xAD0); + value32 = odm_get_bb_reg(dm, ODM_REG_DBG_RPT_11AC, MASKDWORD); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n %-35s = 0x%x", "0x8fc", value32); + + value32 = odm_get_bb_reg(dm, ODM_REG_RPT_11AC, MASKDWORD); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n %-35s = 0x%x", "rx plcp", value32); + + odm_set_bb_reg(dm, ODM_REG_DBG_RPT_11AC, MASKDWORD, 0xAD1); + value32 = odm_get_bb_reg(dm, ODM_REG_DBG_RPT_11AC, MASKDWORD); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n %-35s = 0x%x", "0x8fc", value32); + + value32 = odm_get_bb_reg(dm, ODM_REG_RPT_11AC, MASKDWORD); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n %-35s = 0x%x", "rx plcp", value32); + + odm_set_bb_reg(dm, ODM_REG_DBG_RPT_11AC, MASKDWORD, 0xAD2); + value32 = odm_get_bb_reg(dm, ODM_REG_DBG_RPT_11AC, MASKDWORD); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n %-35s = 0x%x", "0x8fc", value32); + + value32 = odm_get_bb_reg(dm, ODM_REG_RPT_11AC, MASKDWORD); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n %-35s = 0x%x", "rx plcp", value32); + + odm_set_bb_reg(dm, ODM_REG_DBG_RPT_11AC, MASKDWORD, 0xAD3); + value32 = odm_get_bb_reg(dm, ODM_REG_DBG_RPT_11AC, MASKDWORD); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n %-35s = 0x%x", "0x8fc", value32); + + value32 = odm_get_bb_reg(dm, ODM_REG_RPT_11AC, MASKDWORD); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n %-35s = 0x%x", "rx plcp", value32); + } +} + +static void phydm_bb_debug_info_n_series(void *dm_void, u32 *_used, + char *output, u32 *_out_len) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + u32 used = *_used; + u32 out_len = *_out_len; + + u32 value32 = 0, value32_1 = 0; + u8 rf_gain_a = 0, rf_gain_b = 0, rf_gain_c = 0, rf_gain_d = 0; + u8 rx_snr_a = 0, rx_snr_b = 0, rx_snr_c = 0, rx_snr_d = 0; + + s8 rxevm_0 = 0, rxevm_1 = 0; + s32 short_cfo_a = 0, short_cfo_b = 0, long_cfo_a = 0, long_cfo_b = 0; + s32 scfo_a = 0, scfo_b = 0, avg_cfo_a = 0, avg_cfo_b = 0; + s32 cfo_end_a = 0, cfo_end_b = 0, acq_cfo_a = 0, acq_cfo_b = 0; + + PHYDM_SNPRINTF(output + used, out_len - used, "\r\n %-35s\n", + "BB Report Info"); + + /*AGC result*/ + value32 = odm_get_bb_reg(dm, 0xdd0, MASKDWORD); + rf_gain_a = (u8)(value32 & 0x3f); + rf_gain_a = rf_gain_a << 1; + + rf_gain_b = (u8)((value32 >> 8) & 0x3f); + rf_gain_b = rf_gain_b << 1; + + rf_gain_c = (u8)((value32 >> 16) & 0x3f); + rf_gain_c = rf_gain_c << 1; + + rf_gain_d = (u8)((value32 >> 24) & 0x3f); + rf_gain_d = rf_gain_d << 1; + + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n %-35s = %d / %d / %d / %d", + "OFDM RX RF Gain(A/B/C/D)", rf_gain_a, rf_gain_b, + rf_gain_c, rf_gain_d); + + /*SNR report*/ + value32 = odm_get_bb_reg(dm, 0xdd4, MASKDWORD); + rx_snr_a = (u8)(value32 & 0xff); + rx_snr_a = rx_snr_a >> 1; + + rx_snr_b = (u8)((value32 >> 8) & 0xff); + rx_snr_b = rx_snr_b >> 1; + + rx_snr_c = (u8)((value32 >> 16) & 0xff); + rx_snr_c = rx_snr_c >> 1; + + rx_snr_d = (u8)((value32 >> 24) & 0xff); + rx_snr_d = rx_snr_d >> 1; + + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n %-35s = %d / %d / %d / %d", "RXSNR(A/B/C/D, dB)", + rx_snr_a, rx_snr_b, rx_snr_c, rx_snr_d); + + /* PostFFT related info*/ + value32 = odm_get_bb_reg(dm, 0xdd8, MASKDWORD); + + rxevm_0 = (s8)((value32 & MASKBYTE2) >> 16); + rxevm_0 /= 2; + if (rxevm_0 < -63) + rxevm_0 = 0; + + rxevm_1 = (s8)((value32 & MASKBYTE3) >> 24); + rxevm_1 /= 2; + if (rxevm_1 < -63) + rxevm_1 = 0; + + PHYDM_SNPRINTF(output + used, out_len - used, "\r\n %-35s = %d / %d", + "RXEVM (1ss/2ss)", rxevm_0, rxevm_1); + + /*CFO Report Info*/ + odm_set_bb_reg(dm, 0xd00, BIT(26), 1); + + /*Short CFO*/ + value32 = odm_get_bb_reg(dm, 0xdac, MASKDWORD); + value32_1 = odm_get_bb_reg(dm, 0xdb0, MASKDWORD); + + short_cfo_b = (s32)(value32 & 0xfff); /*S(12,11)*/ + short_cfo_a = (s32)((value32 & 0x0fff0000) >> 16); + + long_cfo_b = (s32)(value32_1 & 0x1fff); /*S(13,12)*/ + long_cfo_a = (s32)((value32_1 & 0x1fff0000) >> 16); + + /*SFO 2's to dec*/ + if (short_cfo_a > 2047) + short_cfo_a = short_cfo_a - 4096; + if (short_cfo_b > 2047) + short_cfo_b = short_cfo_b - 4096; + + short_cfo_a = (short_cfo_a * 312500) / 2048; + short_cfo_b = (short_cfo_b * 312500) / 2048; + + /*LFO 2's to dec*/ + + if (long_cfo_a > 4095) + long_cfo_a = long_cfo_a - 8192; + + if (long_cfo_b > 4095) + long_cfo_b = long_cfo_b - 8192; + + long_cfo_a = long_cfo_a * 312500 / 4096; + long_cfo_b = long_cfo_b * 312500 / 4096; + + PHYDM_SNPRINTF(output + used, out_len - used, "\r\n %-35s", + "CFO Report Info"); + PHYDM_SNPRINTF(output + used, out_len - used, "\r\n %-35s = %d / %d", + "Short CFO(Hz) <A/B>", short_cfo_a, short_cfo_b); + PHYDM_SNPRINTF(output + used, out_len - used, "\r\n %-35s = %d / %d", + "Long CFO(Hz) <A/B>", long_cfo_a, long_cfo_b); + + /*SCFO*/ + value32 = odm_get_bb_reg(dm, 0xdb8, MASKDWORD); + value32_1 = odm_get_bb_reg(dm, 0xdb4, MASKDWORD); + + scfo_b = (s32)(value32 & 0x7ff); /*S(11,10)*/ + scfo_a = (s32)((value32 & 0x07ff0000) >> 16); + + if (scfo_a > 1023) + scfo_a = scfo_a - 2048; + + if (scfo_b > 1023) + scfo_b = scfo_b - 2048; + + scfo_a = scfo_a * 312500 / 1024; + scfo_b = scfo_b * 312500 / 1024; + + avg_cfo_b = (s32)(value32_1 & 0x1fff); /*S(13,12)*/ + avg_cfo_a = (s32)((value32_1 & 0x1fff0000) >> 16); + + if (avg_cfo_a > 4095) + avg_cfo_a = avg_cfo_a - 8192; + + if (avg_cfo_b > 4095) + avg_cfo_b = avg_cfo_b - 8192; + + avg_cfo_a = avg_cfo_a * 312500 / 4096; + avg_cfo_b = avg_cfo_b * 312500 / 4096; + + PHYDM_SNPRINTF(output + used, out_len - used, "\r\n %-35s = %d / %d", + "value SCFO(Hz) <A/B>", scfo_a, scfo_b); + PHYDM_SNPRINTF(output + used, out_len - used, "\r\n %-35s = %d / %d", + "Avg CFO(Hz) <A/B>", avg_cfo_a, avg_cfo_b); + + value32 = odm_get_bb_reg(dm, 0xdbc, MASKDWORD); + value32_1 = odm_get_bb_reg(dm, 0xde0, MASKDWORD); + + cfo_end_b = (s32)(value32 & 0x1fff); /*S(13,12)*/ + cfo_end_a = (s32)((value32 & 0x1fff0000) >> 16); + + if (cfo_end_a > 4095) + cfo_end_a = cfo_end_a - 8192; + + if (cfo_end_b > 4095) + cfo_end_b = cfo_end_b - 8192; + + cfo_end_a = cfo_end_a * 312500 / 4096; + cfo_end_b = cfo_end_b * 312500 / 4096; + + acq_cfo_b = (s32)(value32_1 & 0x1fff); /*S(13,12)*/ + acq_cfo_a = (s32)((value32_1 & 0x1fff0000) >> 16); + + if (acq_cfo_a > 4095) + acq_cfo_a = acq_cfo_a - 8192; + + if (acq_cfo_b > 4095) + acq_cfo_b = acq_cfo_b - 8192; + + acq_cfo_a = acq_cfo_a * 312500 / 4096; + acq_cfo_b = acq_cfo_b * 312500 / 4096; + + PHYDM_SNPRINTF(output + used, out_len - used, "\r\n %-35s = %d / %d", + "End CFO(Hz) <A/B>", cfo_end_a, cfo_end_b); + PHYDM_SNPRINTF(output + used, out_len - used, "\r\n %-35s = %d / %d", + "ACQ CFO(Hz) <A/B>", acq_cfo_a, acq_cfo_b); +} + +static void phydm_bb_debug_info(void *dm_void, u32 *_used, char *output, + u32 *_out_len) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + u32 used = *_used; + u32 out_len = *_out_len; + + char *tmp_string = NULL; + + u8 rx_ht_bw, rx_vht_bw, rxsc, rx_ht, rx_bw; + static u8 v_rx_bw; + u32 value32, value32_1, value32_2, value32_3; + s32 sfo_a, sfo_b, sfo_c, sfo_d; + s32 lfo_a, lfo_b, lfo_c, lfo_d; + static u8 MCSS, tail, parity, rsv, vrsv, idx, smooth, htsound, agg, + stbc, vstbc, fec, fecext, sgi, sgiext, htltf, vgid, v_nsts, + vtxops, vrsv2, vbrsv, bf, vbcrc; + static u16 h_length, htcrc8, length; + static u16 vpaid; + static u16 v_length, vhtcrc8, v_mcss, v_tail, vb_tail; + static u8 hmcss, hrx_bw; + + u8 pwdb; + s8 rxevm_0, rxevm_1, rxevm_2; + u8 rf_gain_path_a, rf_gain_path_b, rf_gain_path_c, rf_gain_path_d; + u8 rx_snr_path_a, rx_snr_path_b, rx_snr_path_c, rx_snr_path_d; + s32 sig_power; + + const char *L_rate[8] = {"6M", "9M", "12M", "18M", + "24M", "36M", "48M", "54M"}; + + if (dm->support_ic_type & ODM_IC_11N_SERIES) { + phydm_bb_debug_info_n_series(dm, &used, output, &out_len); + return; + } + + PHYDM_SNPRINTF(output + used, out_len - used, "\r\n %-35s\n", + "BB Report Info"); + + /*BW & mode Detection*/ + + value32 = odm_get_bb_reg(dm, 0xf80, MASKDWORD); + value32_2 = value32; + rx_ht_bw = (u8)(value32 & 0x1); + rx_vht_bw = (u8)((value32 >> 1) & 0x3); + rxsc = (u8)(value32 & 0x78); + value32_1 = (value32 & 0x180) >> 7; + rx_ht = (u8)(value32_1); + + rx_bw = 0; + + if (rx_ht == 2) { + if (rx_vht_bw == 0) + tmp_string = "20M"; + else if (rx_vht_bw == 1) + tmp_string = "40M"; + else + tmp_string = "80M"; + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n %-35s %s %s", "mode", "VHT", tmp_string); + rx_bw = rx_vht_bw; + } else if (rx_ht == 1) { + if (rx_ht_bw == 0) + tmp_string = "20M"; + else if (rx_ht_bw == 1) + tmp_string = "40M"; + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n %-35s %s %s", "mode", "HT", tmp_string); + rx_bw = rx_ht_bw; + } else { + PHYDM_SNPRINTF(output + used, out_len - used, "\r\n %-35s %s", + "mode", "Legacy"); + } + if (rx_ht != 0) { + if (rxsc == 0) + tmp_string = "duplicate/full bw"; + else if (rxsc == 1) + tmp_string = "usc20-1"; + else if (rxsc == 2) + tmp_string = "lsc20-1"; + else if (rxsc == 3) + tmp_string = "usc20-2"; + else if (rxsc == 4) + tmp_string = "lsc20-2"; + else if (rxsc == 9) + tmp_string = "usc40"; + else if (rxsc == 10) + tmp_string = "lsc40"; + PHYDM_SNPRINTF(output + used, out_len - used, " %-35s", + tmp_string); + } + + /* RX signal power and AGC related info*/ + + value32 = odm_get_bb_reg(dm, 0xF90, MASKDWORD); + pwdb = (u8)((value32 & MASKBYTE1) >> 8); + pwdb = pwdb >> 1; + sig_power = -110 + pwdb; + PHYDM_SNPRINTF(output + used, out_len - used, "\r\n %-35s = %d", + "OFDM RX Signal Power(dB)", sig_power); + + value32 = odm_get_bb_reg(dm, 0xd14, MASKDWORD); + rx_snr_path_a = (u8)(value32 & 0xFF) >> 1; + rf_gain_path_a = (s8)((value32 & MASKBYTE1) >> 8); + rf_gain_path_a *= 2; + value32 = odm_get_bb_reg(dm, 0xd54, MASKDWORD); + rx_snr_path_b = (u8)(value32 & 0xFF) >> 1; + rf_gain_path_b = (s8)((value32 & MASKBYTE1) >> 8); + rf_gain_path_b *= 2; + value32 = odm_get_bb_reg(dm, 0xd94, MASKDWORD); + rx_snr_path_c = (u8)(value32 & 0xFF) >> 1; + rf_gain_path_c = (s8)((value32 & MASKBYTE1) >> 8); + rf_gain_path_c *= 2; + value32 = odm_get_bb_reg(dm, 0xdd4, MASKDWORD); + rx_snr_path_d = (u8)(value32 & 0xFF) >> 1; + rf_gain_path_d = (s8)((value32 & MASKBYTE1) >> 8); + rf_gain_path_d *= 2; + + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n %-35s = %d / %d / %d / %d", + "OFDM RX RF Gain(A/B/C/D)", rf_gain_path_a, + rf_gain_path_b, rf_gain_path_c, rf_gain_path_d); + + /* RX counter related info*/ + + value32 = odm_get_bb_reg(dm, 0xF08, MASKDWORD); + PHYDM_SNPRINTF(output + used, out_len - used, "\r\n %-35s = %d", + "OFDM CCA counter", ((value32 & 0xFFFF0000) >> 16)); + + value32 = odm_get_bb_reg(dm, 0xFD0, MASKDWORD); + PHYDM_SNPRINTF(output + used, out_len - used, "\r\n %-35s = %d", + "OFDM SBD Fail counter", value32 & 0xFFFF); + + value32 = odm_get_bb_reg(dm, 0xFC4, MASKDWORD); + PHYDM_SNPRINTF(output + used, out_len - used, "\r\n %-35s = %d / %d", + "VHT SIGA/SIGB CRC8 Fail counter", value32 & 0xFFFF, + ((value32 & 0xFFFF0000) >> 16)); + + value32 = odm_get_bb_reg(dm, 0xFCC, MASKDWORD); + PHYDM_SNPRINTF(output + used, out_len - used, "\r\n %-35s = %d", + "CCK CCA counter", value32 & 0xFFFF); + + value32 = odm_get_bb_reg(dm, 0xFBC, MASKDWORD); + PHYDM_SNPRINTF(output + used, out_len - used, "\r\n %-35s = %d / %d", + "LSIG (parity Fail/rate Illegal) counter", + value32 & 0xFFFF, ((value32 & 0xFFFF0000) >> 16)); + + value32_1 = odm_get_bb_reg(dm, 0xFC8, MASKDWORD); + value32_2 = odm_get_bb_reg(dm, 0xFC0, MASKDWORD); + PHYDM_SNPRINTF(output + used, out_len - used, "\r\n %-35s = %d / %d", + "HT/VHT MCS NOT SUPPORT counter", + ((value32_2 & 0xFFFF0000) >> 16), value32_1 & 0xFFFF); + + /* PostFFT related info*/ + value32 = odm_get_bb_reg(dm, 0xF8c, MASKDWORD); + rxevm_0 = (s8)((value32 & MASKBYTE2) >> 16); + rxevm_0 /= 2; + if (rxevm_0 < -63) + rxevm_0 = 0; + + rxevm_1 = (s8)((value32 & MASKBYTE3) >> 24); + rxevm_1 /= 2; + value32 = odm_get_bb_reg(dm, 0xF88, MASKDWORD); + rxevm_2 = (s8)((value32 & MASKBYTE2) >> 16); + rxevm_2 /= 2; + + if (rxevm_1 < -63) + rxevm_1 = 0; + if (rxevm_2 < -63) + rxevm_2 = 0; + + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n %-35s = %d / %d / %d", "RXEVM (1ss/2ss/3ss)", + rxevm_0, rxevm_1, rxevm_2); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n %-35s = %d / %d / %d / %d", "RXSNR(A/B/C/D, dB)", + rx_snr_path_a, rx_snr_path_b, rx_snr_path_c, + rx_snr_path_d); + + value32 = odm_get_bb_reg(dm, 0xF8C, MASKDWORD); + PHYDM_SNPRINTF(output + used, out_len - used, "\r\n %-35s = %d / %d", + "CSI_1st /CSI_2nd", value32 & 0xFFFF, + ((value32 & 0xFFFF0000) >> 16)); + + /*BW & mode Detection*/ + + /*Reset Page F counter*/ + odm_set_bb_reg(dm, 0xB58, BIT(0), 1); + odm_set_bb_reg(dm, 0xB58, BIT(0), 0); + + /*CFO Report Info*/ + /*Short CFO*/ + value32 = odm_get_bb_reg(dm, 0xd0c, MASKDWORD); + value32_1 = odm_get_bb_reg(dm, 0xd4c, MASKDWORD); + value32_2 = odm_get_bb_reg(dm, 0xd8c, MASKDWORD); + value32_3 = odm_get_bb_reg(dm, 0xdcc, MASKDWORD); + + sfo_a = (s32)(value32 & 0xfff); + sfo_b = (s32)(value32_1 & 0xfff); + sfo_c = (s32)(value32_2 & 0xfff); + sfo_d = (s32)(value32_3 & 0xfff); + + lfo_a = (s32)(value32 >> 16); + lfo_b = (s32)(value32_1 >> 16); + lfo_c = (s32)(value32_2 >> 16); + lfo_d = (s32)(value32_3 >> 16); + + /*SFO 2's to dec*/ + if (sfo_a > 2047) + sfo_a = sfo_a - 4096; + sfo_a = (sfo_a * 312500) / 2048; + if (sfo_b > 2047) + sfo_b = sfo_b - 4096; + sfo_b = (sfo_b * 312500) / 2048; + if (sfo_c > 2047) + sfo_c = sfo_c - 4096; + sfo_c = (sfo_c * 312500) / 2048; + if (sfo_d > 2047) + sfo_d = sfo_d - 4096; + sfo_d = (sfo_d * 312500) / 2048; + + /*LFO 2's to dec*/ + + if (lfo_a > 4095) + lfo_a = lfo_a - 8192; + + if (lfo_b > 4095) + lfo_b = lfo_b - 8192; + + if (lfo_c > 4095) + lfo_c = lfo_c - 8192; + + if (lfo_d > 4095) + lfo_d = lfo_d - 8192; + lfo_a = lfo_a * 312500 / 4096; + lfo_b = lfo_b * 312500 / 4096; + lfo_c = lfo_c * 312500 / 4096; + lfo_d = lfo_d * 312500 / 4096; + PHYDM_SNPRINTF(output + used, out_len - used, "\r\n %-35s", + "CFO Report Info"); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n %-35s = %d / %d / %d /%d", + "Short CFO(Hz) <A/B/C/D>", sfo_a, sfo_b, sfo_c, sfo_d); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n %-35s = %d / %d / %d /%d", + "Long CFO(Hz) <A/B/C/D>", lfo_a, lfo_b, lfo_c, lfo_d); + + /*SCFO*/ + value32 = odm_get_bb_reg(dm, 0xd10, MASKDWORD); + value32_1 = odm_get_bb_reg(dm, 0xd50, MASKDWORD); + value32_2 = odm_get_bb_reg(dm, 0xd90, MASKDWORD); + value32_3 = odm_get_bb_reg(dm, 0xdd0, MASKDWORD); + + sfo_a = (s32)(value32 & 0x7ff); + sfo_b = (s32)(value32_1 & 0x7ff); + sfo_c = (s32)(value32_2 & 0x7ff); + sfo_d = (s32)(value32_3 & 0x7ff); + + if (sfo_a > 1023) + sfo_a = sfo_a - 2048; + + if (sfo_b > 2047) + sfo_b = sfo_b - 4096; + + if (sfo_c > 2047) + sfo_c = sfo_c - 4096; + + if (sfo_d > 2047) + sfo_d = sfo_d - 4096; + + sfo_a = sfo_a * 312500 / 1024; + sfo_b = sfo_b * 312500 / 1024; + sfo_c = sfo_c * 312500 / 1024; + sfo_d = sfo_d * 312500 / 1024; + + lfo_a = (s32)(value32 >> 16); + lfo_b = (s32)(value32_1 >> 16); + lfo_c = (s32)(value32_2 >> 16); + lfo_d = (s32)(value32_3 >> 16); + + if (lfo_a > 4095) + lfo_a = lfo_a - 8192; + + if (lfo_b > 4095) + lfo_b = lfo_b - 8192; + + if (lfo_c > 4095) + lfo_c = lfo_c - 8192; + + if (lfo_d > 4095) + lfo_d = lfo_d - 8192; + lfo_a = lfo_a * 312500 / 4096; + lfo_b = lfo_b * 312500 / 4096; + lfo_c = lfo_c * 312500 / 4096; + lfo_d = lfo_d * 312500 / 4096; + + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n %-35s = %d / %d / %d /%d", + "value SCFO(Hz) <A/B/C/D>", sfo_a, sfo_b, sfo_c, sfo_d); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n %-35s = %d / %d / %d /%d", "ACQ CFO(Hz) <A/B/C/D>", + lfo_a, lfo_b, lfo_c, lfo_d); + + value32 = odm_get_bb_reg(dm, 0xd14, MASKDWORD); + value32_1 = odm_get_bb_reg(dm, 0xd54, MASKDWORD); + value32_2 = odm_get_bb_reg(dm, 0xd94, MASKDWORD); + value32_3 = odm_get_bb_reg(dm, 0xdd4, MASKDWORD); + + lfo_a = (s32)(value32 >> 16); + lfo_b = (s32)(value32_1 >> 16); + lfo_c = (s32)(value32_2 >> 16); + lfo_d = (s32)(value32_3 >> 16); + + if (lfo_a > 4095) + lfo_a = lfo_a - 8192; + + if (lfo_b > 4095) + lfo_b = lfo_b - 8192; + + if (lfo_c > 4095) + lfo_c = lfo_c - 8192; + + if (lfo_d > 4095) + lfo_d = lfo_d - 8192; + + lfo_a = lfo_a * 312500 / 4096; + lfo_b = lfo_b * 312500 / 4096; + lfo_c = lfo_c * 312500 / 4096; + lfo_d = lfo_d * 312500 / 4096; + + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n %-35s = %d / %d / %d /%d", "End CFO(Hz) <A/B/C/D>", + lfo_a, lfo_b, lfo_c, lfo_d); + + value32 = odm_get_bb_reg(dm, 0xf20, MASKDWORD); /*L SIG*/ + + tail = (u8)((value32 & 0xfc0000) >> 16); + parity = (u8)((value32 & 0x20000) >> 16); + length = (u16)((value32 & 0x1ffe00) >> 8); + rsv = (u8)(value32 & 0x10); + MCSS = (u8)(value32 & 0x0f); + + switch (MCSS) { + case 0x0b: + idx = 0; + break; + case 0x0f: + idx = 1; + break; + case 0x0a: + idx = 2; + break; + case 0x0e: + idx = 3; + break; + case 0x09: + idx = 4; + break; + case 0x08: + idx = 5; + break; + case 0x0c: + idx = 6; + break; + default: + idx = 6; + break; + } + + PHYDM_SNPRINTF(output + used, out_len - used, "\r\n %-35s", "L-SIG"); + PHYDM_SNPRINTF(output + used, out_len - used, "\r\n %-35s : %s", "rate", + L_rate[idx]); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n %-35s = %x / %x / %x", "Rsv/length/parity", rsv, + rx_bw, length); + + value32 = odm_get_bb_reg(dm, 0xf2c, MASKDWORD); /*HT SIG*/ + if (rx_ht == 1) { + hmcss = (u8)(value32 & 0x7F); + hrx_bw = (u8)(value32 & 0x80); + h_length = (u16)((value32 >> 8) & 0xffff); + } + PHYDM_SNPRINTF(output + used, out_len - used, "\r\n %-35s", "HT-SIG1"); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n %-35s = %x / %x / %x", "MCS/BW/length", hmcss, + hrx_bw, h_length); + + value32 = odm_get_bb_reg(dm, 0xf30, MASKDWORD); /*HT SIG*/ + + if (rx_ht == 1) { + smooth = (u8)(value32 & 0x01); + htsound = (u8)(value32 & 0x02); + rsv = (u8)(value32 & 0x04); + agg = (u8)(value32 & 0x08); + stbc = (u8)(value32 & 0x30); + fec = (u8)(value32 & 0x40); + sgi = (u8)(value32 & 0x80); + htltf = (u8)((value32 & 0x300) >> 8); + htcrc8 = (u16)((value32 & 0x3fc00) >> 8); + tail = (u8)((value32 & 0xfc0000) >> 16); + } + PHYDM_SNPRINTF(output + used, out_len - used, "\r\n %-35s", "HT-SIG2"); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n %-35s = %x / %x / %x / %x / %x / %x", + "Smooth/NoSound/Rsv/Aggregate/STBC/LDPC", smooth, + htsound, rsv, agg, stbc, fec); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n %-35s = %x / %x / %x / %x", + "SGI/E-HT-LTFs/CRC/tail", sgi, htltf, htcrc8, tail); + + value32 = odm_get_bb_reg(dm, 0xf2c, MASKDWORD); /*VHT SIG A1*/ + if (rx_ht == 2) { + /* value32 = odm_get_bb_reg(dm, 0xf2c,MASKDWORD);*/ + v_rx_bw = (u8)(value32 & 0x03); + vrsv = (u8)(value32 & 0x04); + vstbc = (u8)(value32 & 0x08); + vgid = (u8)((value32 & 0x3f0) >> 4); + v_nsts = (u8)(((value32 & 0x1c00) >> 8) + 1); + vpaid = (u16)(value32 & 0x3fe); + vtxops = (u8)((value32 & 0x400000) >> 20); + vrsv2 = (u8)((value32 & 0x800000) >> 20); + } + PHYDM_SNPRINTF(output + used, out_len - used, "\r\n %-35s", + "VHT-SIG-A1"); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n %-35s = %x / %x / %x / %x / %x / %x / %x / %x", + "BW/Rsv1/STBC/GID/Nsts/PAID/TXOPPS/Rsv2", v_rx_bw, vrsv, + vstbc, vgid, v_nsts, vpaid, vtxops, vrsv2); + + value32 = odm_get_bb_reg(dm, 0xf30, MASKDWORD); /*VHT SIG*/ + + if (rx_ht == 2) { + /*value32 = odm_get_bb_reg(dm, 0xf30,MASKDWORD); */ /*VHT SIG*/ + + /* sgi=(u8)(value32&0x01); */ + sgiext = (u8)(value32 & 0x03); + /* fec = (u8)(value32&0x04); */ + fecext = (u8)(value32 & 0x0C); + + v_mcss = (u8)(value32 & 0xf0); + bf = (u8)((value32 & 0x100) >> 8); + vrsv = (u8)((value32 & 0x200) >> 8); + vhtcrc8 = (u16)((value32 & 0x3fc00) >> 8); + v_tail = (u8)((value32 & 0xfc0000) >> 16); + } + PHYDM_SNPRINTF(output + used, out_len - used, "\r\n %-35s", + "VHT-SIG-A2"); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n %-35s = %x / %x / %x / %x / %x / %x / %x", + "SGI/FEC/MCS/BF/Rsv/CRC/tail", sgiext, fecext, v_mcss, + bf, vrsv, vhtcrc8, v_tail); + + value32 = odm_get_bb_reg(dm, 0xf34, MASKDWORD); /*VHT SIG*/ + { + v_length = (u16)(value32 & 0x1fffff); + vbrsv = (u8)((value32 & 0x600000) >> 20); + vb_tail = (u16)((value32 & 0x1f800000) >> 20); + vbcrc = (u8)((value32 & 0x80000000) >> 28); + } + PHYDM_SNPRINTF(output + used, out_len - used, "\r\n %-35s", + "VHT-SIG-B"); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n %-35s = %x / %x / %x / %x", "length/Rsv/tail/CRC", + v_length, vbrsv, vb_tail, vbcrc); + + /*for Condition number*/ + if (dm->support_ic_type & ODM_RTL8822B) { + s32 condition_num = 0; + char *factor = NULL; + + /*enable report condition number*/ + odm_set_bb_reg(dm, 0x1988, BIT(22), 0x1); + + condition_num = odm_get_bb_reg(dm, 0xf84, MASKDWORD); + condition_num = (condition_num & 0x3ffff) >> 4; + + if (*dm->band_width == ODM_BW80M) { + factor = "256/234"; + } else if (*dm->band_width == ODM_BW40M) { + factor = "128/108"; + } else if (*dm->band_width == ODM_BW20M) { + if (rx_ht == 2 || rx_ht == 1) + factor = "64/52"; /*HT or VHT*/ + else + factor = "64/48"; /*legacy*/ + } + + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n %-35s = %d (factor = %s)", + "Condition number", condition_num, factor); + } +} + +void phydm_basic_dbg_message(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct false_alarm_stat *false_alm_cnt = + (struct false_alarm_stat *)phydm_get_structure( + dm, PHYDM_FALSEALMCNT); + struct cfo_tracking *cfo_track = + (struct cfo_tracking *)phydm_get_structure(dm, PHYDM_CFOTRACK); + struct dig_thres *dig_tab = &dm->dm_dig_table; + struct ra_table *ra_tab = &dm->dm_ra_table; + u16 macid, phydm_macid, client_cnt = 0; + struct rtl_sta_info *entry; + s32 tmp_val = 0; + u8 tmp_val_u1 = 0; + + ODM_RT_TRACE(dm, ODM_COMP_COMMON, + "[PHYDM Common MSG] System up time: ((%d sec))----->\n", + dm->phydm_sys_up_time); + + if (dm->is_linked) { + ODM_RT_TRACE(dm, ODM_COMP_COMMON, + "ID=%d, BW=((%d)), CH=((%d))\n", + dm->curr_station_id, 20 << *dm->band_width, + *dm->channel); + + /*Print RX rate*/ + if (dm->rx_rate <= ODM_RATE11M) + ODM_RT_TRACE( + dm, ODM_COMP_COMMON, + "[CCK AGC Report] LNA_idx = 0x%x, VGA_idx = 0x%x\n", + dm->cck_lna_idx, dm->cck_vga_idx); + else + ODM_RT_TRACE( + dm, ODM_COMP_COMMON, + "[OFDM AGC Report] { 0x%x, 0x%x, 0x%x, 0x%x }\n", + dm->ofdm_agc_idx[0], dm->ofdm_agc_idx[1], + dm->ofdm_agc_idx[2], dm->ofdm_agc_idx[3]); + + ODM_RT_TRACE(dm, ODM_COMP_COMMON, + "RSSI: { %d, %d, %d, %d }, rx_rate:", + (dm->rssi_a == 0xff) ? 0 : dm->rssi_a, + (dm->rssi_b == 0xff) ? 0 : dm->rssi_b, + (dm->rssi_c == 0xff) ? 0 : dm->rssi_c, + (dm->rssi_d == 0xff) ? 0 : dm->rssi_d); + + phydm_print_rate(dm, dm->rx_rate, ODM_COMP_COMMON); + + /*Print TX rate*/ + for (macid = 0; macid < ODM_ASSOCIATE_ENTRY_NUM; macid++) { + entry = dm->odm_sta_info[macid]; + if (!IS_STA_VALID(entry)) + continue; + + phydm_macid = (dm->platform2phydm_macid_table[macid]); + ODM_RT_TRACE(dm, ODM_COMP_COMMON, "TXRate [%d]:", + macid); + phydm_print_rate(dm, ra_tab->link_tx_rate[macid], + ODM_COMP_COMMON); + + client_cnt++; + + if (client_cnt == dm->number_linked_client) + break; + } + + ODM_RT_TRACE( + dm, ODM_COMP_COMMON, + "TP { TX, RX, total} = {%d, %d, %d }Mbps, traffic_load = (%d))\n", + dm->tx_tp, dm->rx_tp, dm->total_tp, dm->traffic_load); + + tmp_val_u1 = + (cfo_track->crystal_cap > cfo_track->def_x_cap) ? + (cfo_track->crystal_cap - + cfo_track->def_x_cap) : + (cfo_track->def_x_cap - cfo_track->crystal_cap); + ODM_RT_TRACE( + dm, ODM_COMP_COMMON, + "CFO_avg = ((%d kHz)) , CrystalCap_tracking = ((%s%d))\n", + cfo_track->CFO_ave_pre, + ((cfo_track->crystal_cap > cfo_track->def_x_cap) ? "+" : + "-"), + tmp_val_u1); + + /* Condition number */ + if (dm->support_ic_type == ODM_RTL8822B) { + tmp_val = phydm_get_condition_number_8822B(dm); + ODM_RT_TRACE(dm, ODM_COMP_COMMON, + "Condition number = ((%d))\n", tmp_val); + } + + /*STBC or LDPC pkt*/ + ODM_RT_TRACE(dm, ODM_COMP_COMMON, "LDPC = %s, STBC = %s\n", + (dm->phy_dbg_info.is_ldpc_pkt) ? "Y" : "N", + (dm->phy_dbg_info.is_stbc_pkt) ? "Y" : "N"); + } else { + ODM_RT_TRACE(dm, ODM_COMP_COMMON, "No Link !!!\n"); + } + + ODM_RT_TRACE(dm, ODM_COMP_COMMON, + "[CCA Cnt] {CCK, OFDM, Total} = {%d, %d, %d}\n", + false_alm_cnt->cnt_cck_cca, false_alm_cnt->cnt_ofdm_cca, + false_alm_cnt->cnt_cca_all); + + ODM_RT_TRACE(dm, ODM_COMP_COMMON, + "[FA Cnt] {CCK, OFDM, Total} = {%d, %d, %d}\n", + false_alm_cnt->cnt_cck_fail, false_alm_cnt->cnt_ofdm_fail, + false_alm_cnt->cnt_all); + + if (dm->support_ic_type & ODM_IC_11N_SERIES) + ODM_RT_TRACE( + dm, ODM_COMP_COMMON, + "[OFDM FA Detail] Parity_Fail = (( %d )), Rate_Illegal = (( %d )), CRC8_fail = (( %d )), Mcs_fail = (( %d )), Fast_Fsync = (( %d )), SB_Search_fail = (( %d ))\n", + false_alm_cnt->cnt_parity_fail, + false_alm_cnt->cnt_rate_illegal, + false_alm_cnt->cnt_crc8_fail, + false_alm_cnt->cnt_mcs_fail, + false_alm_cnt->cnt_fast_fsync, + false_alm_cnt->cnt_sb_search_fail); + + ODM_RT_TRACE( + dm, ODM_COMP_COMMON, + "is_linked = %d, Num_client = %d, rssi_min = %d, current_igi = 0x%x, bNoisy=%d\n\n", + dm->is_linked, dm->number_linked_client, dm->rssi_min, + dig_tab->cur_ig_value, dm->noisy_decision); +} + +void phydm_basic_profile(void *dm_void, u32 *_used, char *output, u32 *_out_len) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + char *cut = NULL; + char *ic_type = NULL; + u32 used = *_used; + u32 out_len = *_out_len; + u32 date = 0; + char *commit_by = NULL; + u32 release_ver = 0; + + PHYDM_SNPRINTF(output + used, out_len - used, "%-35s\n", + "% Basic Profile %"); + + if (dm->support_ic_type == ODM_RTL8188E) { + } else if (dm->support_ic_type == ODM_RTL8822B) { + ic_type = "RTL8822B"; + date = RELEASE_DATE_8822B; + commit_by = COMMIT_BY_8822B; + release_ver = RELEASE_VERSION_8822B; + } + + /* JJ ADD 20161014 */ + + PHYDM_SNPRINTF(output + used, out_len - used, + " %-35s: %s (MP Chip: %s)\n", "IC type", ic_type, + dm->is_mp_chip ? "Yes" : "No"); + + if (dm->cut_version == ODM_CUT_A) + cut = "A"; + else if (dm->cut_version == ODM_CUT_B) + cut = "B"; + else if (dm->cut_version == ODM_CUT_C) + cut = "C"; + else if (dm->cut_version == ODM_CUT_D) + cut = "D"; + else if (dm->cut_version == ODM_CUT_E) + cut = "E"; + else if (dm->cut_version == ODM_CUT_F) + cut = "F"; + else if (dm->cut_version == ODM_CUT_I) + cut = "I"; + PHYDM_SNPRINTF(output + used, out_len - used, " %-35s: %s\n", + "cut version", cut); + PHYDM_SNPRINTF(output + used, out_len - used, " %-35s: %d\n", + "PHY Parameter version", odm_get_hw_img_version(dm)); + PHYDM_SNPRINTF(output + used, out_len - used, " %-35s: %d\n", + "PHY Parameter Commit date", date); + PHYDM_SNPRINTF(output + used, out_len - used, " %-35s: %s\n", + "PHY Parameter Commit by", commit_by); + PHYDM_SNPRINTF(output + used, out_len - used, " %-35s: %d\n", + "PHY Parameter Release version", release_ver); + + { + struct rtl_priv *rtlpriv = (struct rtl_priv *)dm->adapter; + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + + PHYDM_SNPRINTF(output + used, out_len - used, + " %-35s: %d (Subversion: %d)\n", "FW version", + rtlhal->fw_version, rtlhal->fw_subversion); + } + /* 1 PHY DM version List */ + PHYDM_SNPRINTF(output + used, out_len - used, "%-35s\n", + "% PHYDM version %"); + PHYDM_SNPRINTF(output + used, out_len - used, " %-35s: %s\n", + "Code base", PHYDM_CODE_BASE); + PHYDM_SNPRINTF(output + used, out_len - used, " %-35s: %s\n", + "Release Date", PHYDM_RELEASE_DATE); + PHYDM_SNPRINTF(output + used, out_len - used, " %-35s: %s\n", + "adaptivity", ADAPTIVITY_VERSION); + PHYDM_SNPRINTF(output + used, out_len - used, " %-35s: %s\n", "DIG", + DIG_VERSION); + PHYDM_SNPRINTF(output + used, out_len - used, " %-35s: %s\n", + "Dynamic BB PowerSaving", DYNAMIC_BBPWRSAV_VERSION); + PHYDM_SNPRINTF(output + used, out_len - used, " %-35s: %s\n", + "CFO Tracking", CFO_TRACKING_VERSION); + PHYDM_SNPRINTF(output + used, out_len - used, " %-35s: %s\n", + "Antenna Diversity", ANTDIV_VERSION); + PHYDM_SNPRINTF(output + used, out_len - used, " %-35s: %s\n", + "Power Tracking", POWRTRACKING_VERSION); + PHYDM_SNPRINTF(output + used, out_len - used, " %-35s: %s\n", + "Dynamic TxPower", DYNAMIC_TXPWR_VERSION); + PHYDM_SNPRINTF(output + used, out_len - used, " %-35s: %s\n", + "RA Info", RAINFO_VERSION); + PHYDM_SNPRINTF(output + used, out_len - used, " %-35s: %s\n", + "Auto channel Selection", ACS_VERSION); + PHYDM_SNPRINTF(output + used, out_len - used, " %-35s: %s\n", + "EDCA Turbo", EDCATURBO_VERSION); + PHYDM_SNPRINTF(output + used, out_len - used, " %-35s: %s\n", + "LA mode", DYNAMIC_LA_MODE); + PHYDM_SNPRINTF(output + used, out_len - used, " %-35s: %s\n", + "Dynamic RX path", DYNAMIC_RX_PATH_VERSION); + + if (dm->support_ic_type & ODM_RTL8822B) + PHYDM_SNPRINTF(output + used, out_len - used, " %-35s: %s\n", + "PHY config 8822B", PHY_CONFIG_VERSION_8822B); + + *_used = used; + *_out_len = out_len; +} + +void phydm_fw_trace_en_h2c(void *dm_void, bool enable, u32 fw_debug_component, + u32 monitor_mode, u32 macid) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + u8 h2c_parameter[7] = {0}; + u8 cmd_length; + + if (dm->support_ic_type & PHYDM_IC_3081_SERIES) { + h2c_parameter[0] = enable; + h2c_parameter[1] = (u8)(fw_debug_component & MASKBYTE0); + h2c_parameter[2] = (u8)((fw_debug_component & MASKBYTE1) >> 8); + h2c_parameter[3] = (u8)((fw_debug_component & MASKBYTE2) >> 16); + h2c_parameter[4] = (u8)((fw_debug_component & MASKBYTE3) >> 24); + h2c_parameter[5] = (u8)monitor_mode; + h2c_parameter[6] = (u8)macid; + cmd_length = 7; + + } else { + h2c_parameter[0] = enable; + h2c_parameter[1] = (u8)monitor_mode; + h2c_parameter[2] = (u8)macid; + cmd_length = 3; + } + + ODM_RT_TRACE(dm, ODM_FW_DEBUG_TRACE, "---->\n"); + if (monitor_mode == 0) + ODM_RT_TRACE(dm, ODM_FW_DEBUG_TRACE, + "[H2C] FW_debug_en: (( %d ))\n", enable); + else + ODM_RT_TRACE( + dm, ODM_FW_DEBUG_TRACE, + "[H2C] FW_debug_en: (( %d )), mode: (( %d )), macid: (( %d ))\n", + enable, monitor_mode, macid); + odm_fill_h2c_cmd(dm, PHYDM_H2C_FW_TRACE_EN, cmd_length, h2c_parameter); +} + +bool phydm_api_set_txagc(struct phy_dm_struct *dm, u32 power_index, + enum odm_rf_radio_path path, u8 hw_rate, + bool is_single_rate) +{ + bool ret = false; + + if (dm->support_ic_type & (ODM_RTL8822B | ODM_RTL8821C)) { + if (is_single_rate) { + if (dm->support_ic_type == ODM_RTL8822B) + ret = phydm_write_txagc_1byte_8822b( + dm, power_index, path, hw_rate); + + } else { + if (dm->support_ic_type == ODM_RTL8822B) + ret = config_phydm_write_txagc_8822b( + dm, power_index, path, hw_rate); + } + } + + return ret; +} + +static u8 phydm_api_get_txagc(struct phy_dm_struct *dm, + enum odm_rf_radio_path path, u8 hw_rate) +{ + u8 ret = 0; + + if (dm->support_ic_type & ODM_RTL8822B) + ret = config_phydm_read_txagc_8822b(dm, path, hw_rate); + + return ret; +} + +static bool phydm_api_switch_bw_channel(struct phy_dm_struct *dm, u8 central_ch, + u8 primary_ch_idx, + enum odm_bw bandwidth) +{ + bool ret = false; + + if (dm->support_ic_type & ODM_RTL8822B) + ret = config_phydm_switch_channel_bw_8822b( + dm, central_ch, primary_ch_idx, bandwidth); + + return ret; +} + +bool phydm_api_trx_mode(struct phy_dm_struct *dm, enum odm_rf_path tx_path, + enum odm_rf_path rx_path, bool is_tx2_path) +{ + bool ret = false; + + if (dm->support_ic_type & ODM_RTL8822B) + ret = config_phydm_trx_mode_8822b(dm, tx_path, rx_path, + is_tx2_path); + + return ret; +} + +static void phydm_get_per_path_txagc(void *dm_void, u8 path, u32 *_used, + char *output, u32 *_out_len) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + u8 rate_idx; + u8 txagc; + u32 used = *_used; + u32 out_len = *_out_len; + + if (((dm->support_ic_type & (ODM_RTL8822B | ODM_RTL8197F)) && + (path <= ODM_RF_PATH_B)) || + ((dm->support_ic_type & (ODM_RTL8821C)) && + (path <= ODM_RF_PATH_A))) { + for (rate_idx = 0; rate_idx <= 0x53; rate_idx++) { + if (rate_idx == ODM_RATE1M) + PHYDM_SNPRINTF(output + used, out_len - used, + " %-35s\n", "CCK====>"); + else if (rate_idx == ODM_RATE6M) + PHYDM_SNPRINTF(output + used, out_len - used, + "\n %-35s\n", "OFDM====>"); + else if (rate_idx == ODM_RATEMCS0) + PHYDM_SNPRINTF(output + used, out_len - used, + "\n %-35s\n", "HT 1ss====>"); + else if (rate_idx == ODM_RATEMCS8) + PHYDM_SNPRINTF(output + used, out_len - used, + "\n %-35s\n", "HT 2ss====>"); + else if (rate_idx == ODM_RATEMCS16) + PHYDM_SNPRINTF(output + used, out_len - used, + "\n %-35s\n", "HT 3ss====>"); + else if (rate_idx == ODM_RATEMCS24) + PHYDM_SNPRINTF(output + used, out_len - used, + "\n %-35s\n", "HT 4ss====>"); + else if (rate_idx == ODM_RATEVHTSS1MCS0) + PHYDM_SNPRINTF(output + used, out_len - used, + "\n %-35s\n", "VHT 1ss====>"); + else if (rate_idx == ODM_RATEVHTSS2MCS0) + PHYDM_SNPRINTF(output + used, out_len - used, + "\n %-35s\n", "VHT 2ss====>"); + else if (rate_idx == ODM_RATEVHTSS3MCS0) + PHYDM_SNPRINTF(output + used, out_len - used, + "\n %-35s\n", "VHT 3ss====>"); + else if (rate_idx == ODM_RATEVHTSS4MCS0) + PHYDM_SNPRINTF(output + used, out_len - used, + "\n %-35s\n", "VHT 4ss====>"); + + txagc = phydm_api_get_txagc( + dm, (enum odm_rf_radio_path)path, rate_idx); + if (config_phydm_read_txagc_check(txagc)) + PHYDM_SNPRINTF(output + used, out_len - used, + " 0x%02x ", txagc); + else + PHYDM_SNPRINTF(output + used, out_len - used, + " 0x%s ", "xx"); + } + } +} + +static void phydm_get_txagc(void *dm_void, u32 *_used, char *output, + u32 *_out_len) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + u32 used = *_used; + u32 out_len = *_out_len; + + /* path-A */ + PHYDM_SNPRINTF(output + used, out_len - used, "%-35s\n", + "path-A===================="); + phydm_get_per_path_txagc(dm, ODM_RF_PATH_A, _used, output, _out_len); + + /* path-B */ + PHYDM_SNPRINTF(output + used, out_len - used, "\n%-35s\n", + "path-B===================="); + phydm_get_per_path_txagc(dm, ODM_RF_PATH_B, _used, output, _out_len); + + /* path-C */ + PHYDM_SNPRINTF(output + used, out_len - used, "\n%-35s\n", + "path-C===================="); + phydm_get_per_path_txagc(dm, ODM_RF_PATH_C, _used, output, _out_len); + + /* path-D */ + PHYDM_SNPRINTF(output + used, out_len - used, "\n%-35s\n", + "path-D===================="); + phydm_get_per_path_txagc(dm, ODM_RF_PATH_D, _used, output, _out_len); +} + +static void phydm_set_txagc(void *dm_void, u32 *const dm_value, u32 *_used, + char *output, u32 *_out_len) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + u32 used = *_used; + u32 out_len = *_out_len; + + /*dm_value[1] = path*/ + /*dm_value[2] = hw_rate*/ + /*dm_value[3] = power_index*/ + + if (dm->support_ic_type & + (ODM_RTL8822B | ODM_RTL8197F | ODM_RTL8821C)) { + if (dm_value[1] <= 1) { + phydm_check_dmval_txagc(dm, used, out_len, dm_value, + output); + } else { + PHYDM_SNPRINTF(output + used, out_len - used, + " %s%d %s%x%s\n", "Write path-", + (dm_value[1] & 0x1), "rate index-0x", + (dm_value[2] & 0x7f), " fail"); + } + } +} + +static void phydm_debug_trace(void *dm_void, u32 *const dm_value, u32 *_used, + char *output, u32 *_out_len) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + u32 pre_debug_components, one = 1; + u32 used = *_used; + u32 out_len = *_out_len; + + pre_debug_components = dm->debug_components; + + PHYDM_SNPRINTF(output + used, out_len - used, "\n%s\n", + "================================"); + if (dm_value[0] == 100) { + PHYDM_SNPRINTF(output + used, out_len - used, "%s\n", + "[Debug Message] PhyDM Selection"); + PHYDM_SNPRINTF(output + used, out_len - used, "%s\n", + "================================"); + PHYDM_SNPRINTF(output + used, out_len - used, + "00. (( %s ))DIG\n", + ((dm->debug_components & ODM_COMP_DIG) ? ("V") : + ("."))); + PHYDM_SNPRINTF( + output + used, out_len - used, "01. (( %s ))RA_MASK\n", + ((dm->debug_components & ODM_COMP_RA_MASK) ? ("V") : + ("."))); + PHYDM_SNPRINTF( + output + used, out_len - used, + "02. (( %s ))DYNAMIC_TXPWR\n", + ((dm->debug_components & ODM_COMP_DYNAMIC_TXPWR) ? + ("V") : + ("."))); + PHYDM_SNPRINTF( + output + used, out_len - used, "03. (( %s ))FA_CNT\n", + ((dm->debug_components & ODM_COMP_FA_CNT) ? ("V") : + ("."))); + PHYDM_SNPRINTF(output + used, out_len - used, + "04. (( %s ))RSSI_MONITOR\n", + ((dm->debug_components & ODM_COMP_RSSI_MONITOR) ? + ("V") : + ("."))); + PHYDM_SNPRINTF( + output + used, out_len - used, "05. (( %s ))SNIFFER\n", + ((dm->debug_components & ODM_COMP_SNIFFER) ? ("V") : + ("."))); + PHYDM_SNPRINTF( + output + used, out_len - used, "06. (( %s ))ANT_DIV\n", + ((dm->debug_components & ODM_COMP_ANT_DIV) ? ("V") : + ("."))); + PHYDM_SNPRINTF(output + used, out_len - used, + "07. (( %s ))DFS\n", + ((dm->debug_components & ODM_COMP_DFS) ? ("V") : + ("."))); + PHYDM_SNPRINTF(output + used, out_len - used, + "08. (( %s ))NOISY_DETECT\n", + ((dm->debug_components & ODM_COMP_NOISY_DETECT) ? + ("V") : + ("."))); + PHYDM_SNPRINTF( + output + used, out_len - used, + "09. (( %s ))RATE_ADAPTIVE\n", + ((dm->debug_components & ODM_COMP_RATE_ADAPTIVE) ? + ("V") : + ("."))); + PHYDM_SNPRINTF( + output + used, out_len - used, "10. (( %s ))PATH_DIV\n", + ((dm->debug_components & ODM_COMP_PATH_DIV) ? ("V") : + ("."))); + PHYDM_SNPRINTF( + output + used, out_len - used, + "12. (( %s ))DYNAMIC_PRICCA\n", + ((dm->debug_components & ODM_COMP_DYNAMIC_PRICCA) ? + ("V") : + ("."))); + PHYDM_SNPRINTF( + output + used, out_len - used, "14. (( %s ))MP\n", + ((dm->debug_components & ODM_COMP_MP) ? ("V") : ("."))); + PHYDM_SNPRINTF(output + used, out_len - used, + "15. (( %s ))struct cfo_tracking\n", + ((dm->debug_components & ODM_COMP_CFO_TRACKING) ? + ("V") : + ("."))); + PHYDM_SNPRINTF(output + used, out_len - used, + "16. (( %s ))struct acs_info\n", + ((dm->debug_components & ODM_COMP_ACS) ? ("V") : + ("."))); + PHYDM_SNPRINTF(output + used, out_len - used, + "17. (( %s ))ADAPTIVITY\n", + ((dm->debug_components & PHYDM_COMP_ADAPTIVITY) ? + ("V") : + ("."))); + PHYDM_SNPRINTF( + output + used, out_len - used, "18. (( %s ))RA_DBG\n", + ((dm->debug_components & PHYDM_COMP_RA_DBG) ? ("V") : + ("."))); + PHYDM_SNPRINTF( + output + used, out_len - used, "19. (( %s ))TXBF\n", + ((dm->debug_components & PHYDM_COMP_TXBF) ? ("V") : + ("."))); + PHYDM_SNPRINTF(output + used, out_len - used, + "20. (( %s ))EDCA_TURBO\n", + ((dm->debug_components & ODM_COMP_EDCA_TURBO) ? + ("V") : + ("."))); + PHYDM_SNPRINTF(output + used, out_len - used, + "22. (( %s ))FW_DEBUG_TRACE\n", + ((dm->debug_components & ODM_FW_DEBUG_TRACE) ? + ("V") : + ("."))); + + PHYDM_SNPRINTF(output + used, out_len - used, + "24. (( %s ))TX_PWR_TRACK\n", + ((dm->debug_components & ODM_COMP_TX_PWR_TRACK) ? + ("V") : + ("."))); + PHYDM_SNPRINTF(output + used, out_len - used, + "26. (( %s ))CALIBRATION\n", + ((dm->debug_components & ODM_COMP_CALIBRATION) ? + ("V") : + ("."))); + PHYDM_SNPRINTF(output + used, out_len - used, + "28. (( %s ))PHY_CONFIG\n", + ((dm->debug_components & ODM_PHY_CONFIG) ? + ("V") : + ("."))); + PHYDM_SNPRINTF( + output + used, out_len - used, "29. (( %s ))INIT\n", + ((dm->debug_components & ODM_COMP_INIT) ? ("V") : + ("."))); + PHYDM_SNPRINTF( + output + used, out_len - used, "30. (( %s ))COMMON\n", + ((dm->debug_components & ODM_COMP_COMMON) ? ("V") : + ("."))); + PHYDM_SNPRINTF(output + used, out_len - used, + "31. (( %s ))API\n", + ((dm->debug_components & ODM_COMP_API) ? ("V") : + ("."))); + PHYDM_SNPRINTF(output + used, out_len - used, "%s\n", + "================================"); + + } else if (dm_value[0] == 101) { + dm->debug_components = 0; + PHYDM_SNPRINTF(output + used, out_len - used, "%s\n", + "Disable all debug components"); + } else { + if (dm_value[1] == 1) /*enable*/ + dm->debug_components |= (one << dm_value[0]); + else if (dm_value[1] == 2) /*disable*/ + dm->debug_components &= ~(one << dm_value[0]); + else + PHYDM_SNPRINTF(output + used, out_len - used, "%s\n", + "[Warning!!!] 1:enable, 2:disable"); + } + PHYDM_SNPRINTF(output + used, out_len - used, + "pre-DbgComponents = 0x%x\n", pre_debug_components); + PHYDM_SNPRINTF(output + used, out_len - used, + "Curr-DbgComponents = 0x%x\n", dm->debug_components); + PHYDM_SNPRINTF(output + used, out_len - used, "%s\n", + "================================"); +} + +static void phydm_fw_debug_trace(void *dm_void, u32 *const dm_value, u32 *_used, + char *output, u32 *_out_len) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + u32 pre_fw_debug_components, one = 1; + u32 used = *_used; + u32 out_len = *_out_len; + + pre_fw_debug_components = dm->fw_debug_components; + + PHYDM_SNPRINTF(output + used, out_len - used, "\n%s\n", + "================================"); + if (dm_value[0] == 100) { + PHYDM_SNPRINTF(output + used, out_len - used, "%s\n", + "[FW Debug Component]"); + PHYDM_SNPRINTF(output + used, out_len - used, "%s\n", + "================================"); + PHYDM_SNPRINTF( + output + used, out_len - used, "00. (( %s ))RA\n", + ((dm->fw_debug_components & PHYDM_FW_COMP_RA) ? ("V") : + ("."))); + + if (dm->support_ic_type & PHYDM_IC_3081_SERIES) { + PHYDM_SNPRINTF( + output + used, out_len - used, + "01. (( %s ))MU\n", + ((dm->fw_debug_components & PHYDM_FW_COMP_MU) ? + ("V") : + ("."))); + PHYDM_SNPRINTF(output + used, out_len - used, + "02. (( %s ))path Div\n", + ((dm->fw_debug_components & + PHYDM_FW_COMP_PHY_CONFIG) ? + ("V") : + ("."))); + PHYDM_SNPRINTF(output + used, out_len - used, + "03. (( %s ))Phy Config\n", + ((dm->fw_debug_components & + PHYDM_FW_COMP_PHY_CONFIG) ? + ("V") : + ("."))); + } + PHYDM_SNPRINTF(output + used, out_len - used, "%s\n", + "================================"); + + } else { + if (dm_value[0] == 101) { + dm->fw_debug_components = 0; + PHYDM_SNPRINTF(output + used, out_len - used, "%s\n", + "Clear all fw debug components"); + } else { + if (dm_value[1] == 1) /*enable*/ + dm->fw_debug_components |= (one << dm_value[0]); + else if (dm_value[1] == 2) /*disable*/ + dm->fw_debug_components &= + ~(one << dm_value[0]); + else + PHYDM_SNPRINTF( + output + used, out_len - used, "%s\n", + "[Warning!!!] 1:enable, 2:disable"); + } + + if (dm->fw_debug_components == 0) { + dm->debug_components &= ~ODM_FW_DEBUG_TRACE; + phydm_fw_trace_en_h2c( + dm, false, dm->fw_debug_components, dm_value[2], + dm_value[3]); /*H2C to enable C2H Msg*/ + } else { + dm->debug_components |= ODM_FW_DEBUG_TRACE; + phydm_fw_trace_en_h2c( + dm, true, dm->fw_debug_components, dm_value[2], + dm_value[3]); /*H2C to enable C2H Msg*/ + } + } +} + +static void phydm_dump_bb_reg(void *dm_void, u32 *_used, char *output, + u32 *_out_len) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + u32 addr = 0; + u32 used = *_used; + u32 out_len = *_out_len; + + /* For Nseries IC we only need to dump page8 to pageF using 3 digits*/ + for (addr = 0x800; addr < 0xfff; addr += 4) { + if (dm->support_ic_type & ODM_IC_11N_SERIES) + PHYDM_VAST_INFO_SNPRINTF( + output + used, out_len - used, + "0x%03x 0x%08x\n", addr, + odm_get_bb_reg(dm, addr, MASKDWORD)); + else + PHYDM_VAST_INFO_SNPRINTF( + output + used, out_len - used, + "0x%04x 0x%08x\n", addr, + odm_get_bb_reg(dm, addr, MASKDWORD)); + } + + if (dm->support_ic_type & + (ODM_RTL8822B | ODM_RTL8814A | ODM_RTL8821C)) { + if (dm->rf_type > ODM_2T2R) { + for (addr = 0x1800; addr < 0x18ff; addr += 4) + PHYDM_VAST_INFO_SNPRINTF( + output + used, out_len - used, + "0x%04x 0x%08x\n", addr, + odm_get_bb_reg(dm, addr, MASKDWORD)); + } + + if (dm->rf_type > ODM_3T3R) { + for (addr = 0x1a00; addr < 0x1aff; addr += 4) + PHYDM_VAST_INFO_SNPRINTF( + output + used, out_len - used, + "0x%04x 0x%08x\n", addr, + odm_get_bb_reg(dm, addr, MASKDWORD)); + } + + for (addr = 0x1900; addr < 0x19ff; addr += 4) + PHYDM_VAST_INFO_SNPRINTF( + output + used, out_len - used, + "0x%04x 0x%08x\n", addr, + odm_get_bb_reg(dm, addr, MASKDWORD)); + + for (addr = 0x1c00; addr < 0x1cff; addr += 4) + PHYDM_VAST_INFO_SNPRINTF( + output + used, out_len - used, + "0x%04x 0x%08x\n", addr, + odm_get_bb_reg(dm, addr, MASKDWORD)); + + for (addr = 0x1f00; addr < 0x1fff; addr += 4) + PHYDM_VAST_INFO_SNPRINTF( + output + used, out_len - used, + "0x%04x 0x%08x\n", addr, + odm_get_bb_reg(dm, addr, MASKDWORD)); + } +} + +static void phydm_dump_all_reg(void *dm_void, u32 *_used, char *output, + u32 *_out_len) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + u32 addr = 0; + u32 used = *_used; + u32 out_len = *_out_len; + + /* dump MAC register */ + PHYDM_VAST_INFO_SNPRINTF(output + used, out_len - used, + "MAC==========\n"); + for (addr = 0; addr < 0x7ff; addr += 4) + PHYDM_VAST_INFO_SNPRINTF(output + used, out_len - used, + "0x%04x 0x%08x\n", addr, + odm_get_bb_reg(dm, addr, MASKDWORD)); + + for (addr = 0x1000; addr < 0x17ff; addr += 4) + PHYDM_VAST_INFO_SNPRINTF(output + used, out_len - used, + "0x%04x 0x%08x\n", addr, + odm_get_bb_reg(dm, addr, MASKDWORD)); + + /* dump BB register */ + PHYDM_VAST_INFO_SNPRINTF(output + used, out_len - used, + "BB==========\n"); + phydm_dump_bb_reg(dm, &used, output, &out_len); + + /* dump RF register */ + PHYDM_VAST_INFO_SNPRINTF(output + used, out_len - used, + "RF-A==========\n"); + for (addr = 0; addr < 0xFF; addr++) + PHYDM_VAST_INFO_SNPRINTF(output + used, out_len - used, + "0x%02x 0x%05x\n", addr, + odm_get_rf_reg(dm, ODM_RF_PATH_A, addr, + RFREGOFFSETMASK)); + + if (dm->rf_type > ODM_1T1R) { + PHYDM_VAST_INFO_SNPRINTF(output + used, out_len - used, + "RF-B==========\n"); + for (addr = 0; addr < 0xFF; addr++) + PHYDM_VAST_INFO_SNPRINTF( + output + used, out_len - used, + "0x%02x 0x%05x\n", addr, + odm_get_rf_reg(dm, ODM_RF_PATH_B, addr, + RFREGOFFSETMASK)); + } + + if (dm->rf_type > ODM_2T2R) { + PHYDM_VAST_INFO_SNPRINTF(output + used, out_len - used, + "RF-C==========\n"); + for (addr = 0; addr < 0xFF; addr++) + PHYDM_VAST_INFO_SNPRINTF( + output + used, out_len - used, + "0x%02x 0x%05x\n", addr, + odm_get_rf_reg(dm, ODM_RF_PATH_C, addr, + RFREGOFFSETMASK)); + } + + if (dm->rf_type > ODM_3T3R) { + PHYDM_VAST_INFO_SNPRINTF(output + used, out_len - used, + "RF-D==========\n"); + for (addr = 0; addr < 0xFF; addr++) + PHYDM_VAST_INFO_SNPRINTF( + output + used, out_len - used, + "0x%02x 0x%05x\n", addr, + odm_get_rf_reg(dm, ODM_RF_PATH_D, addr, + RFREGOFFSETMASK)); + } +} + +static void phydm_enable_big_jump(struct phy_dm_struct *dm, bool state) +{ + struct dig_thres *dig_tab = &dm->dm_dig_table; + + if (!state) { + dm->dm_dig_table.enable_adjust_big_jump = false; + odm_set_bb_reg(dm, 0x8c8, 0xfe, + ((dig_tab->big_jump_step3 << 5) | + (dig_tab->big_jump_step2 << 3) | + dig_tab->big_jump_step1)); + } else { + dm->dm_dig_table.enable_adjust_big_jump = true; + } +} + +static void phydm_show_rx_rate(struct phy_dm_struct *dm, u32 *_used, + char *output, u32 *_out_len) +{ + u32 used = *_used; + u32 out_len = *_out_len; + + PHYDM_SNPRINTF(output + used, out_len - used, + "=====Rx SU rate Statistics=====\n"); + PHYDM_SNPRINTF( + output + used, out_len - used, + "1SS MCS0 = %d, 1SS MCS1 = %d, 1SS MCS2 = %d, 1SS MCS 3 = %d\n", + dm->phy_dbg_info.num_qry_vht_pkt[0], + dm->phy_dbg_info.num_qry_vht_pkt[1], + dm->phy_dbg_info.num_qry_vht_pkt[2], + dm->phy_dbg_info.num_qry_vht_pkt[3]); + PHYDM_SNPRINTF( + output + used, out_len - used, + "1SS MCS4 = %d, 1SS MCS5 = %d, 1SS MCS6 = %d, 1SS MCS 7 = %d\n", + dm->phy_dbg_info.num_qry_vht_pkt[4], + dm->phy_dbg_info.num_qry_vht_pkt[5], + dm->phy_dbg_info.num_qry_vht_pkt[6], + dm->phy_dbg_info.num_qry_vht_pkt[7]); + PHYDM_SNPRINTF(output + used, out_len - used, + "1SS MCS8 = %d, 1SS MCS9 = %d\n", + dm->phy_dbg_info.num_qry_vht_pkt[8], + dm->phy_dbg_info.num_qry_vht_pkt[9]); + PHYDM_SNPRINTF( + output + used, out_len - used, + "2SS MCS0 = %d, 2SS MCS1 = %d, 2SS MCS2 = %d, 2SS MCS 3 = %d\n", + dm->phy_dbg_info.num_qry_vht_pkt[10], + dm->phy_dbg_info.num_qry_vht_pkt[11], + dm->phy_dbg_info.num_qry_vht_pkt[12], + dm->phy_dbg_info.num_qry_vht_pkt[13]); + PHYDM_SNPRINTF( + output + used, out_len - used, + "2SS MCS4 = %d, 2SS MCS5 = %d, 2SS MCS6 = %d, 2SS MCS 7 = %d\n", + dm->phy_dbg_info.num_qry_vht_pkt[14], + dm->phy_dbg_info.num_qry_vht_pkt[15], + dm->phy_dbg_info.num_qry_vht_pkt[16], + dm->phy_dbg_info.num_qry_vht_pkt[17]); + PHYDM_SNPRINTF(output + used, out_len - used, + "2SS MCS8 = %d, 2SS MCS9 = %d\n", + dm->phy_dbg_info.num_qry_vht_pkt[18], + dm->phy_dbg_info.num_qry_vht_pkt[19]); + + PHYDM_SNPRINTF(output + used, out_len - used, + "=====Rx MU rate Statistics=====\n"); + PHYDM_SNPRINTF( + output + used, out_len - used, + "1SS MCS0 = %d, 1SS MCS1 = %d, 1SS MCS2 = %d, 1SS MCS 3 = %d\n", + dm->phy_dbg_info.num_qry_mu_vht_pkt[0], + dm->phy_dbg_info.num_qry_mu_vht_pkt[1], + dm->phy_dbg_info.num_qry_mu_vht_pkt[2], + dm->phy_dbg_info.num_qry_mu_vht_pkt[3]); + PHYDM_SNPRINTF( + output + used, out_len - used, + "1SS MCS4 = %d, 1SS MCS5 = %d, 1SS MCS6 = %d, 1SS MCS 7 = %d\n", + dm->phy_dbg_info.num_qry_mu_vht_pkt[4], + dm->phy_dbg_info.num_qry_mu_vht_pkt[5], + dm->phy_dbg_info.num_qry_mu_vht_pkt[6], + dm->phy_dbg_info.num_qry_mu_vht_pkt[7]); + PHYDM_SNPRINTF(output + used, out_len - used, + "1SS MCS8 = %d, 1SS MCS9 = %d\n", + dm->phy_dbg_info.num_qry_mu_vht_pkt[8], + dm->phy_dbg_info.num_qry_mu_vht_pkt[9]); + PHYDM_SNPRINTF( + output + used, out_len - used, + "2SS MCS0 = %d, 2SS MCS1 = %d, 2SS MCS2 = %d, 2SS MCS 3 = %d\n", + dm->phy_dbg_info.num_qry_mu_vht_pkt[10], + dm->phy_dbg_info.num_qry_mu_vht_pkt[11], + dm->phy_dbg_info.num_qry_mu_vht_pkt[12], + dm->phy_dbg_info.num_qry_mu_vht_pkt[13]); + PHYDM_SNPRINTF( + output + used, out_len - used, + "2SS MCS4 = %d, 2SS MCS5 = %d, 2SS MCS6 = %d, 2SS MCS 7 = %d\n", + dm->phy_dbg_info.num_qry_mu_vht_pkt[14], + dm->phy_dbg_info.num_qry_mu_vht_pkt[15], + dm->phy_dbg_info.num_qry_mu_vht_pkt[16], + dm->phy_dbg_info.num_qry_mu_vht_pkt[17]); + PHYDM_SNPRINTF(output + used, out_len - used, + "2SS MCS8 = %d, 2SS MCS9 = %d\n", + dm->phy_dbg_info.num_qry_mu_vht_pkt[18], + dm->phy_dbg_info.num_qry_mu_vht_pkt[19]); +} + +struct phydm_command { + char name[16]; + u8 id; +}; + +enum PHYDM_CMD_ID { + PHYDM_HELP, + PHYDM_DEMO, + PHYDM_RA, + PHYDM_PROFILE, + PHYDM_ANTDIV, + PHYDM_PATHDIV, + PHYDM_DEBUG, + PHYDM_FW_DEBUG, + PHYDM_SUPPORT_ABILITY, + PHYDM_GET_TXAGC, + PHYDM_SET_TXAGC, + PHYDM_SMART_ANT, + PHYDM_API, + PHYDM_TRX_PATH, + PHYDM_LA_MODE, + PHYDM_DUMP_REG, + PHYDM_MU_MIMO, + PHYDM_HANG, + PHYDM_BIG_JUMP, + PHYDM_SHOW_RXRATE, + PHYDM_NBI_EN, + PHYDM_CSI_MASK_EN, + PHYDM_DFS, + PHYDM_IQK, + PHYDM_NHM, + PHYDM_CLM, + PHYDM_BB_INFO, + PHYDM_TXBF, + PHYDM_PAUSE_DIG_EN, + PHYDM_H2C, + PHYDM_ANT_SWITCH, + PHYDM_DYNAMIC_RA_PATH, + PHYDM_PSD, + PHYDM_DEBUG_PORT +}; + +static struct phydm_command phy_dm_ary[] = { + {"-h", PHYDM_HELP}, /*do not move this element to other position*/ + {"demo", PHYDM_DEMO}, /*do not move this element to other position*/ + {"ra", PHYDM_RA}, + {"profile", PHYDM_PROFILE}, + {"antdiv", PHYDM_ANTDIV}, + {"pathdiv", PHYDM_PATHDIV}, + {"dbg", PHYDM_DEBUG}, + {"fw_dbg", PHYDM_FW_DEBUG}, + {"ability", PHYDM_SUPPORT_ABILITY}, + {"get_txagc", PHYDM_GET_TXAGC}, + {"set_txagc", PHYDM_SET_TXAGC}, + {"smtant", PHYDM_SMART_ANT}, + {"api", PHYDM_API}, + {"trxpath", PHYDM_TRX_PATH}, + {"lamode", PHYDM_LA_MODE}, + {"dumpreg", PHYDM_DUMP_REG}, + {"mu", PHYDM_MU_MIMO}, + {"hang", PHYDM_HANG}, + {"bigjump", PHYDM_BIG_JUMP}, + {"rxrate", PHYDM_SHOW_RXRATE}, + {"nbi", PHYDM_NBI_EN}, + {"csi_mask", PHYDM_CSI_MASK_EN}, + {"dfs", PHYDM_DFS}, + {"iqk", PHYDM_IQK}, + {"nhm", PHYDM_NHM}, + {"clm", PHYDM_CLM}, + {"bbinfo", PHYDM_BB_INFO}, + {"txbf", PHYDM_TXBF}, + {"pause_dig", PHYDM_PAUSE_DIG_EN}, + {"h2c", PHYDM_H2C}, + {"ant_switch", PHYDM_ANT_SWITCH}, + {"drp", PHYDM_DYNAMIC_RA_PATH}, + {"psd", PHYDM_PSD}, + {"dbgport", PHYDM_DEBUG_PORT}, +}; + +void phydm_cmd_parser(struct phy_dm_struct *dm, char input[][MAX_ARGV], + u32 input_num, u8 flag, char *output, u32 out_len) +{ + u32 used = 0; + u8 id = 0; + int var1[10] = {0}; + int i, input_idx = 0, phydm_ary_size; + char help[] = "-h"; + + bool is_enable_dbg_mode; + u8 central_ch, primary_ch_idx, bandwidth; + + if (flag == 0) { + PHYDM_SNPRINTF(output + used, out_len - used, + "GET, nothing to print\n"); + return; + } + + PHYDM_SNPRINTF(output + used, out_len - used, "\n"); + + /* Parsing Cmd ID */ + if (input_num) { + phydm_ary_size = + sizeof(phy_dm_ary) / sizeof(struct phydm_command); + for (i = 0; i < phydm_ary_size; i++) { + if (strcmp(phy_dm_ary[i].name, input[0]) == 0) { + id = phy_dm_ary[i].id; + break; + } + } + if (i == phydm_ary_size) { + PHYDM_SNPRINTF(output + used, out_len - used, + "SET, command not found!\n"); + return; + } + } + + switch (id) { + case PHYDM_HELP: { + PHYDM_SNPRINTF(output + used, out_len - used, "BB cmd ==>\n"); + for (i = 0; i < phydm_ary_size - 2; i++) { + PHYDM_SNPRINTF(output + used, out_len - used, + " %-5d: %s\n", i, + phy_dm_ary[i + 2].name); + /**/ + } + } break; + + case PHYDM_DEMO: { /*echo demo 10 0x3a z abcde >cmd*/ + u32 directory = 0; + + char char_temp; + + PHYDM_SSCANF(input[1], DCMD_DECIMAL, &directory); + PHYDM_SNPRINTF(output + used, out_len - used, + "Decimal value = %d\n", directory); + PHYDM_SSCANF(input[2], DCMD_HEX, &directory); + PHYDM_SNPRINTF(output + used, out_len - used, + "Hex value = 0x%x\n", directory); + PHYDM_SSCANF(input[3], DCMD_CHAR, &char_temp); + PHYDM_SNPRINTF(output + used, out_len - used, "Char = %c\n", + char_temp); + PHYDM_SNPRINTF(output + used, out_len - used, "String = %s\n", + input[4]); + } break; + + case PHYDM_RA: + + for (i = 0; i < 5; i++) { + if (input[i + 1]) { + PHYDM_SSCANF(input[i + 1], DCMD_DECIMAL, + &var1[i]); + + input_idx++; + } + } + + if (input_idx >= 1) { + phydm_RA_debug_PCR(dm, (u32 *)var1, &used, output, + &out_len); + } + + break; + + case PHYDM_ANTDIV: + + for (i = 0; i < 5; i++) { + if (input[i + 1]) { + PHYDM_SSCANF(input[i + 1], DCMD_HEX, &var1[i]); + + input_idx++; + } + } + + break; + + case PHYDM_PATHDIV: + + for (i = 0; i < 5; i++) { + if (input[i + 1]) { + PHYDM_SSCANF(input[i + 1], DCMD_HEX, &var1[i]); + + input_idx++; + } + } + + break; + + case PHYDM_DEBUG: + + for (i = 0; i < 5; i++) { + if (input[i + 1]) { + PHYDM_SSCANF(input[i + 1], DCMD_DECIMAL, + &var1[i]); + + input_idx++; + } + } + + if (input_idx >= 1) { + phydm_debug_trace(dm, (u32 *)var1, &used, output, + &out_len); + } + + break; + + case PHYDM_FW_DEBUG: + + for (i = 0; i < 5; i++) { + if (input[i + 1]) { + PHYDM_SSCANF(input[i + 1], DCMD_DECIMAL, + &var1[i]); + input_idx++; + } + } + + if (input_idx >= 1) + phydm_fw_debug_trace(dm, (u32 *)var1, &used, output, + &out_len); + + break; + + case PHYDM_SUPPORT_ABILITY: + + for (i = 0; i < 5; i++) { + if (input[i + 1]) { + PHYDM_SSCANF(input[i + 1], DCMD_DECIMAL, + &var1[i]); + + input_idx++; + } + } + + if (input_idx >= 1) { + phydm_support_ability_debug(dm, (u32 *)var1, &used, + output, &out_len); + } + + break; + + case PHYDM_SMART_ANT: + + for (i = 0; i < 5; i++) { + if (input[i + 1]) { + PHYDM_SSCANF(input[i + 1], DCMD_HEX, &var1[i]); + input_idx++; + } + } + + break; + + case PHYDM_API: + if (!(dm->support_ic_type & + (ODM_RTL8822B | ODM_RTL8197F | ODM_RTL8821C))) { + PHYDM_SNPRINTF( + output + used, out_len - used, + "This IC doesn't support PHYDM API function\n"); + } + + for (i = 0; i < 4; i++) { + if (input[i + 1]) + PHYDM_SSCANF(input[i + 1], DCMD_DECIMAL, + &var1[i]); + } + + is_enable_dbg_mode = (bool)var1[0]; + central_ch = (u8)var1[1]; + primary_ch_idx = (u8)var1[2]; + bandwidth = (enum odm_bw)var1[3]; + + if (is_enable_dbg_mode) { + dm->is_disable_phy_api = false; + phydm_api_switch_bw_channel(dm, central_ch, + primary_ch_idx, + (enum odm_bw)bandwidth); + dm->is_disable_phy_api = true; + PHYDM_SNPRINTF( + output + used, out_len - used, + "central_ch = %d, primary_ch_idx = %d, bandwidth = %d\n", + central_ch, primary_ch_idx, bandwidth); + } else { + dm->is_disable_phy_api = false; + PHYDM_SNPRINTF(output + used, out_len - used, + "Disable API debug mode\n"); + } + break; + + case PHYDM_PROFILE: /*echo profile, >cmd*/ + phydm_basic_profile(dm, &used, output, &out_len); + break; + + case PHYDM_GET_TXAGC: + phydm_get_txagc(dm, &used, output, &out_len); + break; + + case PHYDM_SET_TXAGC: { + bool is_enable_dbg_mode; + + for (i = 0; i < 5; i++) { + if (input[i + 1]) { + PHYDM_SSCANF(input[i + 1], DCMD_HEX, &var1[i]); + input_idx++; + } + } + + if ((strcmp(input[1], help) == 0)) { + PHYDM_SNPRINTF( + output + used, out_len - used, + "{En} {pathA~D(0~3)} {rate_idx(Hex), All_rate:0xff} {txagc_idx (Hex)}\n"); + /**/ + + } else { + is_enable_dbg_mode = (bool)var1[0]; + if (is_enable_dbg_mode) { + dm->is_disable_phy_api = false; + phydm_set_txagc(dm, (u32 *)var1, &used, output, + &out_len); + dm->is_disable_phy_api = true; + } else { + dm->is_disable_phy_api = false; + PHYDM_SNPRINTF(output + used, out_len - used, + "Disable API debug mode\n"); + } + } + } break; + + case PHYDM_TRX_PATH: + + for (i = 0; i < 4; i++) { + if (input[i + 1]) + PHYDM_SSCANF(input[i + 1], DCMD_DECIMAL, + &var1[i]); + } + if (dm->support_ic_type & (ODM_RTL8822B | ODM_RTL8197F)) { + u8 tx_path, rx_path; + bool is_enable_dbg_mode, is_tx2_path; + + is_enable_dbg_mode = (bool)var1[0]; + tx_path = (u8)var1[1]; + rx_path = (u8)var1[2]; + is_tx2_path = (bool)var1[3]; + + if (is_enable_dbg_mode) { + dm->is_disable_phy_api = false; + phydm_api_trx_mode( + dm, (enum odm_rf_path)tx_path, + (enum odm_rf_path)rx_path, is_tx2_path); + dm->is_disable_phy_api = true; + PHYDM_SNPRINTF( + output + used, out_len - used, + "tx_path = 0x%x, rx_path = 0x%x, is_tx2_path = %d\n", + tx_path, rx_path, is_tx2_path); + } else { + dm->is_disable_phy_api = false; + PHYDM_SNPRINTF(output + used, out_len - used, + "Disable API debug mode\n"); + } + } else { + phydm_config_trx_path(dm, (u32 *)var1, &used, output, + &out_len); + } + break; + + case PHYDM_LA_MODE: + + dm->support_ability &= ~(ODM_BB_FA_CNT); + phydm_lamode_trigger_setting(dm, &input[0], &used, output, + &out_len, input_num); + dm->support_ability |= ODM_BB_FA_CNT; + + break; + + case PHYDM_DUMP_REG: { + u8 type = 0; + + if (input[1]) { + PHYDM_SSCANF(input[1], DCMD_DECIMAL, &var1[0]); + type = (u8)var1[0]; + } + + if (type == 0) + phydm_dump_bb_reg(dm, &used, output, &out_len); + else if (type == 1) + phydm_dump_all_reg(dm, &used, output, &out_len); + } break; + + case PHYDM_MU_MIMO: + + if (input[1]) + PHYDM_SSCANF(input[1], DCMD_DECIMAL, &var1[0]); + else + var1[0] = 0; + + if (var1[0] == 1) { + PHYDM_SNPRINTF(output + used, out_len - used, + "Get MU BFee CSI\n"); + odm_set_bb_reg(dm, 0x9e8, BIT(17) | BIT(16), + 2); /*Read BFee*/ + odm_set_bb_reg(dm, 0x1910, BIT(15), + 1); /*Select BFee's CSI report*/ + odm_set_bb_reg(dm, 0x19b8, BIT(6), + 1); /*set as CSI report*/ + odm_set_bb_reg(dm, 0x19a8, 0xFFFF, + 0xFFFF); /*disable gated_clk*/ + phydm_print_csi(dm, used, out_len, output); + + } else if (var1[0] == 2) { + PHYDM_SSCANF(input[2], DCMD_DECIMAL, &var1[1]); + PHYDM_SNPRINTF(output + used, out_len - used, + "Get MU BFer's STA%d CSI\n", var1[1]); + odm_set_bb_reg(dm, 0x9e8, BIT(24), 0); /*Read BFer*/ + odm_set_bb_reg(dm, 0x9e8, BIT(25), + 1); /*enable Read/Write RAM*/ + odm_set_bb_reg(dm, 0x9e8, BIT(30) | BIT(29) | BIT(28), + var1[1]); /*read which STA's CSI report*/ + odm_set_bb_reg(dm, 0x1910, BIT(15), + 0); /*select BFer's CSI*/ + odm_set_bb_reg(dm, 0x19e0, 0x00003FC0, + 0xFF); /*disable gated_clk*/ + phydm_print_csi(dm, used, out_len, output); + } + break; + + case PHYDM_BIG_JUMP: { + if (input[1]) { + PHYDM_SSCANF(input[1], DCMD_DECIMAL, &var1[0]); + phydm_enable_big_jump(dm, (bool)(var1[0])); + } else { + PHYDM_SNPRINTF(output + used, out_len - used, + "unknown command!\n"); + } + break; + } + + case PHYDM_HANG: + phydm_bb_rx_hang_info(dm, &used, output, &out_len); + break; + + case PHYDM_SHOW_RXRATE: { + u8 rate_idx; + + if (input[1]) + PHYDM_SSCANF(input[1], DCMD_DECIMAL, &var1[0]); + + if (var1[0] == 1) { + phydm_show_rx_rate(dm, &used, output, &out_len); + } else { + PHYDM_SNPRINTF(output + used, out_len - used, + "Reset Rx rate counter\n"); + + for (rate_idx = 0; rate_idx < 40; rate_idx++) { + dm->phy_dbg_info.num_qry_vht_pkt[rate_idx] = 0; + dm->phy_dbg_info.num_qry_mu_vht_pkt[rate_idx] = + 0; + } + } + } break; + + case PHYDM_NBI_EN: + + for (i = 0; i < 5; i++) { + if (input[i + 1]) { + PHYDM_SSCANF(input[i + 1], DCMD_DECIMAL, + &var1[i]); + input_idx++; + } + } + + if (input_idx >= 1) { + phydm_api_debug(dm, PHYDM_API_NBI, (u32 *)var1, &used, + output, &out_len); + /**/ + } + + break; + + case PHYDM_CSI_MASK_EN: + + for (i = 0; i < 5; i++) { + if (input[i + 1]) { + PHYDM_SSCANF(input[i + 1], DCMD_DECIMAL, + &var1[i]); + input_idx++; + } + } + + if (input_idx >= 1) { + phydm_api_debug(dm, PHYDM_API_CSI_MASK, (u32 *)var1, + &used, output, &out_len); + /**/ + } + + break; + + case PHYDM_DFS: + break; + + case PHYDM_IQK: + break; + + case PHYDM_NHM: { + u8 target_rssi; + u16 nhm_period = 0xC350; /* 200ms */ + u8 IGI; + struct ccx_info *ccx_info = &dm->dm_ccx_info; + + PHYDM_SSCANF(input[1], DCMD_DECIMAL, &var1[0]); + + if (input_num == 1) { + ccx_info->echo_NHM_en = false; + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n Trigger NHM: echo nhm 1\n"); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r (Exclude CCA)\n"); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r Trigger NHM: echo nhm 2\n"); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r (Include CCA)\n"); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r Get NHM results: echo nhm 3\n"); + + return; + } + + /* NMH trigger */ + if ((var1[0] <= 2) && (var1[0] != 0)) { + ccx_info->echo_NHM_en = true; + ccx_info->echo_IGI = + (u8)odm_get_bb_reg(dm, 0xC50, MASKBYTE0); + + target_rssi = ccx_info->echo_IGI - 10; + + ccx_info->NHM_th[0] = (target_rssi - 15 + 10) * 2; + + for (i = 1; i <= 10; i++) + ccx_info->NHM_th[i] = + ccx_info->NHM_th[0] + 6 * i; + + /* 4 1. store previous NHM setting */ + phydm_nhm_setting(dm, STORE_NHM_SETTING); + + /* 4 2. Set NHM period, 0x990[31:16]=0xC350, + * Time duration for NHM unit: 4us, 0xC350=200ms + */ + ccx_info->NHM_period = nhm_period; + + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n Monitor NHM for %d us", + nhm_period * 4); + + /* 4 3. Set NHM inexclude_txon, inexclude_cca, ccx_en */ + + ccx_info->nhm_inexclude_cca = (var1[0] == 1) ? + NHM_EXCLUDE_CCA : + NHM_INCLUDE_CCA; + ccx_info->nhm_inexclude_txon = NHM_EXCLUDE_TXON; + + phydm_nhm_setting(dm, SET_NHM_SETTING); + phydm_print_nhm_trigger(output, used, out_len, + ccx_info); + + /* 4 4. Trigger NHM */ + phydm_nhm_trigger(dm); + } + + /*Get NHM results*/ + else if (var1[0] == 3) { + IGI = (u8)odm_get_bb_reg(dm, 0xC50, MASKBYTE0); + + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n Cur_IGI = 0x%x", IGI); + + phydm_get_nhm_result(dm); + + /* 4 Resotre NHM setting */ + phydm_nhm_setting(dm, RESTORE_NHM_SETTING); + phydm_print_nhm_result(output, used, out_len, ccx_info); + + ccx_info->echo_NHM_en = false; + } else { + ccx_info->echo_NHM_en = false; + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n Trigger NHM: echo nhm 1\n"); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r (Exclude CCA)\n"); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r Trigger NHM: echo nhm 2\n"); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r (Include CCA)\n"); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r Get NHM results: echo nhm 3\n"); + + return; + } + } break; + + case PHYDM_CLM: { + struct ccx_info *ccx_info = &dm->dm_ccx_info; + + PHYDM_SSCANF(input[1], DCMD_DECIMAL, &var1[0]); + + if (input_num == 1) { + ccx_info->echo_CLM_en = false; + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n Trigger CLM: echo clm 1\n"); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r Get CLM results: echo clm 2\n"); + return; + } + + /* Set & trigger CLM */ + if (var1[0] == 1) { + ccx_info->echo_CLM_en = true; + ccx_info->CLM_period = 0xC350; /*100ms*/ + phydm_clm_setting(dm); + phydm_clm_trigger(dm); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n Monitor CLM for 200ms\n"); + } + + /* Get CLM results */ + else if (var1[0] == 2) { + ccx_info->echo_CLM_en = false; + phydm_get_cl_mresult(dm); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n CLM_result = %d us\n", + ccx_info->CLM_result * 4); + + } else { + ccx_info->echo_CLM_en = false; + PHYDM_SNPRINTF(output + used, out_len - used, + "\n\r Error command !\n"); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r Trigger CLM: echo clm 1\n"); + PHYDM_SNPRINTF(output + used, out_len - used, + "\r Get CLM results: echo clm 2\n"); + } + } break; + + case PHYDM_BB_INFO: { + s32 value32 = 0; + + phydm_bb_debug_info(dm, &used, output, &out_len); + + if (dm->support_ic_type & ODM_RTL8822B && input[1]) { + PHYDM_SSCANF(input[1], DCMD_DECIMAL, &var1[0]); + odm_set_bb_reg(dm, 0x1988, 0x003fff00, var1[0]); + value32 = odm_get_bb_reg(dm, 0xf84, MASKDWORD); + value32 = (value32 & 0xff000000) >> 24; + PHYDM_SNPRINTF( + output + used, out_len - used, + "\r\n %-35s = condition num = %d, subcarriers = %d\n", + "Over condition num subcarrier", var1[0], + value32); + odm_set_bb_reg(dm, 0x1988, BIT(22), + 0x0); /*disable report condition number*/ + } + } break; + + case PHYDM_TXBF: { + PHYDM_SNPRINTF(output + used, out_len - used, + "\r\n no TxBF !!\n"); + } break; + + case PHYDM_PAUSE_DIG_EN: + + for (i = 0; i < 5; i++) { + if (input[i + 1]) { + PHYDM_SSCANF(input[i + 1], DCMD_HEX, &var1[i]); + input_idx++; + } + } + + if (input_idx >= 1) { + if (var1[0] == 0) { + odm_pause_dig(dm, PHYDM_PAUSE, + PHYDM_PAUSE_LEVEL_7, (u8)var1[1]); + PHYDM_SNPRINTF(output + used, out_len - used, + "Set IGI_value = ((%x))\n", + var1[1]); + } else if (var1[0] == 1) { + odm_pause_dig(dm, PHYDM_RESUME, + PHYDM_PAUSE_LEVEL_7, (u8)var1[1]); + PHYDM_SNPRINTF(output + used, out_len - used, + "Resume IGI_value\n"); + } else { + PHYDM_SNPRINTF( + output + used, out_len - used, + "echo (1:pause, 2resume) (IGI_value)\n"); + } + } + break; + case PHYDM_H2C: + + for (i = 0; i < 8; i++) { + if (input[i + 1]) { + PHYDM_SSCANF(input[i + 1], DCMD_HEX, &var1[i]); + input_idx++; + } + } + + if (input_idx >= 1) + phydm_h2C_debug(dm, (u32 *)var1, &used, output, + &out_len); + + break; + + case PHYDM_ANT_SWITCH: + + for (i = 0; i < 8; i++) { + if (input[i + 1]) { + PHYDM_SSCANF(input[i + 1], DCMD_DECIMAL, + &var1[i]); + input_idx++; + } + } + + if (input_idx >= 1) { + PHYDM_SNPRINTF(output + used, out_len - used, + "Not Support IC"); + } + + break; + + case PHYDM_DYNAMIC_RA_PATH: + + PHYDM_SNPRINTF(output + used, out_len - used, "Not Support IC"); + + break; + + case PHYDM_PSD: + + phydm_psd_debug(dm, &input[0], &used, output, &out_len, + input_num); + + break; + + case PHYDM_DEBUG_PORT: { + u32 dbg_port_value; + + PHYDM_SSCANF(input[1], DCMD_HEX, &var1[0]); + + if (phydm_set_bb_dbg_port(dm, BB_DBGPORT_PRIORITY_3, + var1[0])) { /*set debug port to 0x0*/ + + dbg_port_value = phydm_get_bb_dbg_port_value(dm); + phydm_release_bb_dbg_port(dm); + + PHYDM_SNPRINTF(output + used, out_len - used, + "Debug Port[0x%x] = ((0x%x))\n", var1[1], + dbg_port_value); + } + } break; + + default: + PHYDM_SNPRINTF(output + used, out_len - used, + "SET, unknown command!\n"); + break; + } +} + +s32 phydm_cmd(struct phy_dm_struct *dm, char *input, u32 in_len, u8 flag, + char *output, u32 out_len) +{ + char *token; + u32 argc = 0; + char argv[MAX_ARGC][MAX_ARGV]; + + do { + token = strsep(&input, ", "); + if (token) { + strcpy(argv[argc], token); + argc++; + } else { + break; + } + } while (argc < MAX_ARGC); + + if (argc == 1) + argv[0][strlen(argv[0]) - 1] = '\0'; + + phydm_cmd_parser(dm, argv, argc, flag, output, out_len); + + return 0; +} + +void phydm_fw_trace_handler(void *dm_void, u8 *cmd_buf, u8 cmd_len) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + + /*u8 debug_trace_11byte[60];*/ + u8 freg_num, c2h_seq, buf_0 = 0; + + if (!(dm->support_ic_type & PHYDM_IC_3081_SERIES)) + return; + + if (cmd_len > 12) + return; + + buf_0 = cmd_buf[0]; + freg_num = (buf_0 & 0xf); + c2h_seq = (buf_0 & 0xf0) >> 4; + + if ((c2h_seq != dm->pre_c2h_seq) && !dm->fw_buff_is_enpty) { + dm->fw_debug_trace[dm->c2h_cmd_start] = '\0'; + ODM_RT_TRACE(dm, ODM_FW_DEBUG_TRACE, + "[FW Dbg Queue Overflow] %s\n", + dm->fw_debug_trace); + dm->c2h_cmd_start = 0; + } + + if ((cmd_len - 1) > (60 - dm->c2h_cmd_start)) { + dm->fw_debug_trace[dm->c2h_cmd_start] = '\0'; + ODM_RT_TRACE(dm, ODM_FW_DEBUG_TRACE, + "[FW Dbg Queue error: wrong C2H length] %s\n", + dm->fw_debug_trace); + dm->c2h_cmd_start = 0; + return; + } + + strncpy((char *)&dm->fw_debug_trace[dm->c2h_cmd_start], + (char *)&cmd_buf[1], (cmd_len - 1)); + dm->c2h_cmd_start += (cmd_len - 1); + dm->fw_buff_is_enpty = false; + + if (freg_num == 0 || dm->c2h_cmd_start >= 60) { + if (dm->c2h_cmd_start < 60) + dm->fw_debug_trace[dm->c2h_cmd_start] = '\0'; + else + dm->fw_debug_trace[59] = '\0'; + + ODM_RT_TRACE(dm, ODM_FW_DEBUG_TRACE, "[FW DBG Msg] %s\n", + dm->fw_debug_trace); + /*dbg_print("[FW DBG Msg] %s\n", dm->fw_debug_trace);*/ + dm->c2h_cmd_start = 0; + dm->fw_buff_is_enpty = true; + } + + dm->pre_c2h_seq = c2h_seq; +} + +void phydm_fw_trace_handler_code(void *dm_void, u8 *buffer, u8 cmd_len) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + u8 function = buffer[0]; + u8 dbg_num = buffer[1]; + u16 content_0 = (((u16)buffer[3]) << 8) | ((u16)buffer[2]); + u16 content_1 = (((u16)buffer[5]) << 8) | ((u16)buffer[4]); + u16 content_2 = (((u16)buffer[7]) << 8) | ((u16)buffer[6]); + u16 content_3 = (((u16)buffer[9]) << 8) | ((u16)buffer[8]); + u16 content_4 = (((u16)buffer[11]) << 8) | ((u16)buffer[10]); + + if (cmd_len > 12) + ODM_RT_TRACE(dm, ODM_FW_DEBUG_TRACE, + "[FW Msg] Invalid cmd length (( %d )) >12\n", + cmd_len); + + /*--------------------------------------------*/ + ODM_RT_TRACE(dm, ODM_FW_DEBUG_TRACE, + "[FW][general][%d, %d, %d] = {%d, %d, %d, %d}\n", function, + dbg_num, content_0, content_1, content_2, content_3, + content_4); + /*--------------------------------------------*/ +} + +void phydm_fw_trace_handler_8051(void *dm_void, u8 *buffer, u8 cmd_len) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + + int i = 0; + u8 extend_c2h_sub_id = 0, extend_c2h_dbg_len = 0, + extend_c2h_dbg_seq = 0; + u8 fw_debug_trace[128]; + u8 *extend_c2h_dbg_content = NULL; + + if (cmd_len > 127) + return; + + extend_c2h_sub_id = buffer[0]; + extend_c2h_dbg_len = buffer[1]; + extend_c2h_dbg_content = buffer + 2; /*DbgSeq+DbgContent for show HEX*/ + +go_backfor_aggre_dbg_pkt: + i = 0; + extend_c2h_dbg_seq = buffer[2]; + extend_c2h_dbg_content = buffer + 3; + + for (;; i++) { + fw_debug_trace[i] = extend_c2h_dbg_content[i]; + if (extend_c2h_dbg_content[i + 1] == '\0') { + fw_debug_trace[i + 1] = '\0'; + ODM_RT_TRACE(dm, ODM_FW_DEBUG_TRACE, "[FW DBG Msg] %s", + &fw_debug_trace[0]); + break; + } else if (extend_c2h_dbg_content[i] == '\n') { + fw_debug_trace[i + 1] = '\0'; + ODM_RT_TRACE(dm, ODM_FW_DEBUG_TRACE, "[FW DBG Msg] %s", + &fw_debug_trace[0]); + buffer = extend_c2h_dbg_content + i + 3; + goto go_backfor_aggre_dbg_pkt; + } + } +} diff --git a/drivers/staging/rtlwifi/phydm/phydm_debug.h b/drivers/staging/rtlwifi/phydm/phydm_debug.h new file mode 100644 index 000000000000..f442f7c19595 --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/phydm_debug.h @@ -0,0 +1,175 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __ODM_DBG_H__ +#define __ODM_DBG_H__ + +/*#define DEBUG_VERSION "1.1"*/ /*2015.07.29 YuChen*/ +/*#define DEBUG_VERSION "1.2"*/ /*2015.08.28 Dino*/ +#define DEBUG_VERSION "1.3" /*2016.04.28 YuChen*/ +#define ODM_DBG_TRACE 5 + +/*FW DBG MSG*/ +#define RATE_DECISION BIT(0) +#define INIT_RA_TABLE BIT(1) +#define RATE_UP BIT(2) +#define RATE_DOWN BIT(3) +#define TRY_DONE BIT(4) +#define RA_H2C BIT(5) +#define F_RATE_AP_RPT BIT(7) + +/* ----------------------------------------------------------------------------- + * Define the tracing components + * + * ----------------------------------------------------------------------------- + */ +/*BB FW Functions*/ +#define PHYDM_FW_COMP_RA BIT(0) +#define PHYDM_FW_COMP_MU BIT(1) +#define PHYDM_FW_COMP_PATH_DIV BIT(2) +#define PHYDM_FW_COMP_PHY_CONFIG BIT(3) + +/*BB Driver Functions*/ +#define ODM_COMP_DIG BIT(0) +#define ODM_COMP_RA_MASK BIT(1) +#define ODM_COMP_DYNAMIC_TXPWR BIT(2) +#define ODM_COMP_FA_CNT BIT(3) +#define ODM_COMP_RSSI_MONITOR BIT(4) +#define ODM_COMP_SNIFFER BIT(5) +#define ODM_COMP_ANT_DIV BIT(6) +#define ODM_COMP_DFS BIT(7) +#define ODM_COMP_NOISY_DETECT BIT(8) +#define ODM_COMP_RATE_ADAPTIVE BIT(9) +#define ODM_COMP_PATH_DIV BIT(10) +#define ODM_COMP_CCX BIT(11) + +#define ODM_COMP_DYNAMIC_PRICCA BIT(12) +/*BIT13 TBD*/ +#define ODM_COMP_MP BIT(14) +#define ODM_COMP_CFO_TRACKING BIT(15) +#define ODM_COMP_ACS BIT(16) +#define PHYDM_COMP_ADAPTIVITY BIT(17) +#define PHYDM_COMP_RA_DBG BIT(18) +#define PHYDM_COMP_TXBF BIT(19) +/* MAC Functions */ +#define ODM_COMP_EDCA_TURBO BIT(20) +#define ODM_COMP_DYNAMIC_RX_PATH BIT(21) +#define ODM_FW_DEBUG_TRACE BIT(22) +/* RF Functions */ +/*BIT23 TBD*/ +#define ODM_COMP_TX_PWR_TRACK BIT(24) +/*BIT25 TBD*/ +#define ODM_COMP_CALIBRATION BIT(26) +/* Common Functions */ +/*BIT27 TBD*/ +#define ODM_PHY_CONFIG BIT(28) +#define ODM_COMP_INIT BIT(29) +#define ODM_COMP_COMMON BIT(30) +#define ODM_COMP_API BIT(31) + +#define ODM_COMP_UNCOND 0xFFFFFFFF + +/*------------------------Export Marco Definition---------------------------*/ + +#define config_phydm_read_txagc_check(data) (data != INVALID_TXAGC_DATA) + +#define ODM_RT_TRACE(dm, comp, fmt, ...) \ + do { \ + if (((comp) & dm->debug_components) || \ + ((comp) == ODM_COMP_UNCOND)) \ + RT_TRACE(dm->adapter, COMP_PHYDM, DBG_DMESG, fmt, \ + ##__VA_ARGS__); \ + } while (0) + +#define BB_DBGPORT_PRIORITY_3 3 /*Debug function (the highest priority)*/ +#define BB_DBGPORT_PRIORITY_2 2 /*Check hang function & Strong function*/ +#define BB_DBGPORT_PRIORITY_1 1 /*Watch dog function*/ +#define BB_DBGPORT_RELEASE 0 /*Init value (the lowest priority)*/ + +void phydm_init_debug_setting(struct phy_dm_struct *dm); + +u8 phydm_set_bb_dbg_port(void *dm_void, u8 curr_dbg_priority, u32 debug_port); + +void phydm_release_bb_dbg_port(void *dm_void); + +u32 phydm_get_bb_dbg_port_value(void *dm_void); + +void phydm_basic_dbg_message(void *dm_void); + +#define PHYDM_DBGPRINT 0 +#define MAX_ARGC 20 +#define MAX_ARGV 16 +#define DCMD_DECIMAL "%d" +#define DCMD_CHAR "%c" +#define DCMD_HEX "%x" + +#define PHYDM_SSCANF(x, y, z) \ + do { \ + if (sscanf(x, y, z) != 1) \ + ODM_RT_TRACE(dm, ODM_COMP_UNCOND, \ + "%s:%d sscanf fail!", __func__, \ + __LINE__); \ + } while (0) + +#define PHYDM_VAST_INFO_SNPRINTF(msg, ...) \ + do { \ + snprintf(msg, ##__VA_ARGS__); \ + ODM_RT_TRACE(dm, ODM_COMP_UNCOND, output); \ + } while (0) + +#if (PHYDM_DBGPRINT == 1) +#define PHYDM_SNPRINTF(msg, ...) \ + do { \ + snprintf(msg, ##__VA_ARGS__); \ + ODM_RT_TRACE(dm, ODM_COMP_UNCOND, output); \ + } while (0) +#else +#define PHYDM_SNPRINTF(msg, ...) \ + do { \ + if (out_len > used) \ + used += snprintf(msg, ##__VA_ARGS__); \ + } while (0) +#endif + +void phydm_basic_profile(void *dm_void, u32 *_used, char *output, + u32 *_out_len); +s32 phydm_cmd(struct phy_dm_struct *dm, char *input, u32 in_len, u8 flag, + char *output, u32 out_len); +void phydm_cmd_parser(struct phy_dm_struct *dm, char input[][16], u32 input_num, + u8 flag, char *output, u32 out_len); + +bool phydm_api_trx_mode(struct phy_dm_struct *dm, enum odm_rf_path tx_path, + enum odm_rf_path rx_path, bool is_tx2_path); + +void phydm_fw_trace_en_h2c(void *dm_void, bool enable, u32 fw_debug_component, + u32 monitor_mode, u32 macid); + +void phydm_fw_trace_handler(void *dm_void, u8 *cmd_buf, u8 cmd_len); + +void phydm_fw_trace_handler_code(void *dm_void, u8 *buffer, u8 cmd_len); + +void phydm_fw_trace_handler_8051(void *dm_void, u8 *cmd_buf, u8 cmd_len); + +#endif /* __ODM_DBG_H__ */ diff --git a/drivers/staging/rtlwifi/phydm/phydm_dfs.h b/drivers/staging/rtlwifi/phydm/phydm_dfs.h new file mode 100644 index 000000000000..59a1d08cf381 --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/phydm_dfs.h @@ -0,0 +1,59 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __PHYDM_DFS_H__ +#define __PHYDM_DFS_H__ + +#define DFS_VERSION "0.0" + +/* ============================================================ + * Definition + * ============================================================ + */ + +/* ============================================================ + * 1 structure + * ============================================================ + */ + +/* ============================================================ + * enumeration + * ============================================================ + */ + +enum phydm_dfs_region_domain { + PHYDM_DFS_DOMAIN_UNKNOWN = 0, + PHYDM_DFS_DOMAIN_FCC = 1, + PHYDM_DFS_DOMAIN_MKK = 2, + PHYDM_DFS_DOMAIN_ETSI = 3, +}; + +/* ============================================================ + * function prototype + * ============================================================ + */ +#define phydm_dfs_master_enabled(dm) false + +#endif /*#ifndef __PHYDM_DFS_H__ */ diff --git a/drivers/staging/rtlwifi/phydm/phydm_dig.c b/drivers/staging/rtlwifi/phydm/phydm_dig.c new file mode 100644 index 000000000000..31a4f3fcad19 --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/phydm_dig.c @@ -0,0 +1,1535 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +/* ************************************************************ + * include files + * *************************************************************/ +#include "mp_precomp.h" +#include "phydm_precomp.h" + +static int get_igi_for_diff(int); + +static inline void phydm_check_ap_write_dig(struct phy_dm_struct *dm, + u8 current_igi) +{ + switch (*dm->one_path_cca) { + case ODM_CCA_2R: + odm_set_bb_reg(dm, ODM_REG(IGI_A, dm), ODM_BIT(IGI, dm), + current_igi); + + if (dm->rf_type > ODM_1T1R) + odm_set_bb_reg(dm, ODM_REG(IGI_B, dm), ODM_BIT(IGI, dm), + current_igi); + break; + case ODM_CCA_1R_A: + odm_set_bb_reg(dm, ODM_REG(IGI_A, dm), ODM_BIT(IGI, dm), + current_igi); + if (dm->rf_type != ODM_1T1R) + odm_set_bb_reg(dm, ODM_REG(IGI_B, dm), ODM_BIT(IGI, dm), + get_igi_for_diff(current_igi)); + break; + case ODM_CCA_1R_B: + odm_set_bb_reg(dm, ODM_REG(IGI_B, dm), ODM_BIT(IGI, dm), + get_igi_for_diff(current_igi)); + if (dm->rf_type != ODM_1T1R) + odm_set_bb_reg(dm, ODM_REG(IGI_A, dm), ODM_BIT(IGI, dm), + current_igi); + break; + } +} + +static inline u8 phydm_get_current_igi(u8 dig_max_of_min, u8 rssi_min, + u8 current_igi) +{ + if (rssi_min < dig_max_of_min) { + if (current_igi < rssi_min) + return rssi_min; + } else { + if (current_igi < dig_max_of_min) + return dig_max_of_min; + } + return current_igi; +} + +void odm_change_dynamic_init_gain_thresh(void *dm_void, u32 dm_type, + u32 dm_value) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct dig_thres *dig_tab = &dm->dm_dig_table; + + if (dm_type == DIG_TYPE_THRESH_HIGH) { + dig_tab->rssi_high_thresh = dm_value; + } else if (dm_type == DIG_TYPE_THRESH_LOW) { + dig_tab->rssi_low_thresh = dm_value; + } else if (dm_type == DIG_TYPE_ENABLE) { + dig_tab->dig_enable_flag = true; + } else if (dm_type == DIG_TYPE_DISABLE) { + dig_tab->dig_enable_flag = false; + } else if (dm_type == DIG_TYPE_BACKOFF) { + if (dm_value > 30) + dm_value = 30; + dig_tab->backoff_val = (u8)dm_value; + } else if (dm_type == DIG_TYPE_RX_GAIN_MIN) { + if (dm_value == 0) + dm_value = 0x1; + dig_tab->rx_gain_range_min = (u8)dm_value; + } else if (dm_type == DIG_TYPE_RX_GAIN_MAX) { + if (dm_value > 0x50) + dm_value = 0x50; + dig_tab->rx_gain_range_max = (u8)dm_value; + } +} /* dm_change_dynamic_init_gain_thresh */ + +static int get_igi_for_diff(int value_IGI) +{ +#define ONERCCA_LOW_TH 0x30 +#define ONERCCA_LOW_DIFF 8 + + if (value_IGI < ONERCCA_LOW_TH) { + if ((ONERCCA_LOW_TH - value_IGI) < ONERCCA_LOW_DIFF) + return ONERCCA_LOW_TH; + else + return value_IGI + ONERCCA_LOW_DIFF; + } + + return value_IGI; +} + +static void odm_fa_threshold_check(void *dm_void, bool is_dfs_band, + bool is_performance, u32 rx_tp, u32 tx_tp, + u32 *dm_FA_thres) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + + if (dm->is_linked && (is_performance || is_dfs_band)) { + /*For NIC*/ + dm_FA_thres[0] = DM_DIG_FA_TH0; + dm_FA_thres[1] = DM_DIG_FA_TH1; + dm_FA_thres[2] = DM_DIG_FA_TH2; + } else { + if (is_dfs_band) { + /* For DFS band and no link */ + dm_FA_thres[0] = 250; + dm_FA_thres[1] = 1000; + dm_FA_thres[2] = 2000; + } else { + dm_FA_thres[0] = 2000; + dm_FA_thres[1] = 4000; + dm_FA_thres[2] = 5000; + } + } +} + +static u8 odm_forbidden_igi_check(void *dm_void, u8 dig_dynamic_min, + u8 current_igi) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct dig_thres *dig_tab = &dm->dm_dig_table; + struct false_alarm_stat *fa_cnt = + (struct false_alarm_stat *)phydm_get_structure( + dm, PHYDM_FALSEALMCNT); + u8 rx_gain_range_min = dig_tab->rx_gain_range_min; + + if (dig_tab->large_fa_timeout) { + if (--dig_tab->large_fa_timeout == 0) + dig_tab->large_fa_hit = 0; + } + + if (fa_cnt->cnt_all > 10000) { + ODM_RT_TRACE(dm, ODM_COMP_DIG, + "%s(): Abnormally false alarm case.\n", __func__); + + if (dig_tab->large_fa_hit != 3) + dig_tab->large_fa_hit++; + + if (dig_tab->forbidden_igi < current_igi) { + dig_tab->forbidden_igi = current_igi; + dig_tab->large_fa_hit = 1; + dig_tab->large_fa_timeout = LARGE_FA_TIMEOUT; + } + + if (dig_tab->large_fa_hit >= 3) { + if ((dig_tab->forbidden_igi + 2) > + dig_tab->rx_gain_range_max) + rx_gain_range_min = dig_tab->rx_gain_range_max; + else + rx_gain_range_min = + (dig_tab->forbidden_igi + 2); + dig_tab->recover_cnt = 1800; + ODM_RT_TRACE( + dm, ODM_COMP_DIG, + "%s(): Abnormally false alarm case: recover_cnt = %d\n", + __func__, dig_tab->recover_cnt); + } + } + + else if (fa_cnt->cnt_all > 2000) { + ODM_RT_TRACE(dm, ODM_COMP_DIG, + "Abnormally false alarm case.\n"); + ODM_RT_TRACE( + dm, ODM_COMP_DIG, + "cnt_all=%d, cnt_all_pre=%d, current_igi=0x%x, pre_ig_value=0x%x\n", + fa_cnt->cnt_all, fa_cnt->cnt_all_pre, current_igi, + dig_tab->pre_ig_value); + + /* fa_cnt->cnt_all = 1.1875*fa_cnt->cnt_all_pre */ + if ((fa_cnt->cnt_all > + (fa_cnt->cnt_all_pre + (fa_cnt->cnt_all_pre >> 3) + + (fa_cnt->cnt_all_pre >> 4))) && + (current_igi < dig_tab->pre_ig_value)) { + if (dig_tab->large_fa_hit != 3) + dig_tab->large_fa_hit++; + + if (dig_tab->forbidden_igi < current_igi) { + ODM_RT_TRACE( + dm, ODM_COMP_DIG, + "Updating forbidden_igi by current_igi, forbidden_igi=0x%x, current_igi=0x%x\n", + dig_tab->forbidden_igi, current_igi); + + dig_tab->forbidden_igi = current_igi; + dig_tab->large_fa_hit = 1; + dig_tab->large_fa_timeout = LARGE_FA_TIMEOUT; + } + } + + if (dig_tab->large_fa_hit >= 3) { + ODM_RT_TRACE( + dm, ODM_COMP_DIG, + "FaHit is greater than 3, rx_gain_range_max=0x%x, rx_gain_range_min=0x%x, forbidden_igi=0x%x\n", + dig_tab->rx_gain_range_max, rx_gain_range_min, + dig_tab->forbidden_igi); + + if ((dig_tab->forbidden_igi + 1) > + dig_tab->rx_gain_range_max) + rx_gain_range_min = dig_tab->rx_gain_range_max; + else + rx_gain_range_min = + (dig_tab->forbidden_igi + 1); + + dig_tab->recover_cnt = 1200; + ODM_RT_TRACE( + dm, ODM_COMP_DIG, + "Abnormally false alarm case: recover_cnt = %d, rx_gain_range_min = 0x%x\n", + dig_tab->recover_cnt, rx_gain_range_min); + } + } else { + if (dig_tab->recover_cnt != 0) { + dig_tab->recover_cnt--; + ODM_RT_TRACE(dm, ODM_COMP_DIG, + "%s(): Normal Case: recover_cnt = %d\n", + __func__, dig_tab->recover_cnt); + return rx_gain_range_min; + } + + if (dig_tab->large_fa_hit >= 3) { + dig_tab->large_fa_hit = 0; + return rx_gain_range_min; + } + + if ((dig_tab->forbidden_igi - 2) < + dig_dynamic_min) { /* DM_DIG_MIN) */ + dig_tab->forbidden_igi = + dig_dynamic_min; /* DM_DIG_MIN; */ + rx_gain_range_min = dig_dynamic_min; /* DM_DIG_MIN; */ + ODM_RT_TRACE(dm, ODM_COMP_DIG, + "%s(): Normal Case: At Lower Bound\n", + __func__); + } else { + if (dig_tab->large_fa_hit == 0) { + dig_tab->forbidden_igi -= 2; + rx_gain_range_min = + (dig_tab->forbidden_igi + 2); + ODM_RT_TRACE( + dm, ODM_COMP_DIG, + "%s(): Normal Case: Approach Lower Bound\n", + __func__); + } + } + } + + return rx_gain_range_min; +} + +static void phydm_set_big_jump_step(void *dm_void, u8 current_igi) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct dig_thres *dig_tab = &dm->dm_dig_table; + u8 step1[8] = {24, 30, 40, 50, 60, 70, 80, 90}; + u8 i; + + if (dig_tab->enable_adjust_big_jump == 0) + return; + + for (i = 0; i <= dig_tab->big_jump_step1; i++) { + if ((current_igi + step1[i]) > + dig_tab->big_jump_lmt[dig_tab->agc_table_idx]) { + if (i != 0) + i = i - 1; + break; + } else if (i == dig_tab->big_jump_step1) { + break; + } + } + if (dm->support_ic_type & ODM_RTL8822B) + odm_set_bb_reg(dm, 0x8c8, 0xe, i); + else if (dm->support_ic_type & ODM_RTL8197F) + odm_set_bb_reg(dm, ODM_REG_BB_AGC_SET_2_11N, 0xe, i); + + ODM_RT_TRACE(dm, ODM_COMP_DIG, + "%s(): bigjump = %d (ori = 0x%x), LMT=0x%x\n", __func__, i, + dig_tab->big_jump_step1, + dig_tab->big_jump_lmt[dig_tab->agc_table_idx]); +} + +void odm_write_dig(void *dm_void, u8 current_igi) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct dig_thres *dig_tab = &dm->dm_dig_table; + + if (dig_tab->is_stop_dig) { + ODM_RT_TRACE(dm, ODM_COMP_DIG, "%s(): Stop Writing IGI\n", + __func__); + return; + } + + ODM_RT_TRACE(dm, ODM_COMP_DIG, + "%s(): ODM_REG(IGI_A,dm)=0x%x, ODM_BIT(IGI,dm)=0x%x\n", + __func__, ODM_REG(IGI_A, dm), ODM_BIT(IGI, dm)); + + /* 1 Check initial gain by upper bound */ + if ((!dig_tab->is_psd_in_progress) && dm->is_linked) { + if (current_igi > dig_tab->rx_gain_range_max) { + ODM_RT_TRACE( + dm, ODM_COMP_DIG, + "%s(): current_igi(0x%02x) is larger than upper bound !!\n", + __func__, current_igi); + current_igi = dig_tab->rx_gain_range_max; + } + if (dm->support_ability & ODM_BB_ADAPTIVITY && + dm->adaptivity_flag) { + if (current_igi > dm->adaptivity_igi_upper) + current_igi = dm->adaptivity_igi_upper; + + ODM_RT_TRACE( + dm, ODM_COMP_DIG, + "%s(): adaptivity case: Force upper bound to 0x%x !!!!!!\n", + __func__, current_igi); + } + } + + if (dig_tab->cur_ig_value != current_igi) { + /* Modify big jump step for 8822B and 8197F */ + if (dm->support_ic_type & (ODM_RTL8822B | ODM_RTL8197F)) + phydm_set_big_jump_step(dm, current_igi); + + /* Set IGI value of CCK for new CCK AGC */ + if (dm->cck_new_agc) { + if (dm->support_ic_type & ODM_IC_PHY_STATUE_NEW_TYPE) + odm_set_bb_reg(dm, 0xa0c, 0x00003f00, + (current_igi >> 1)); + } + + /*Add by YuChen for USB IO too slow issue*/ + if ((dm->support_ability & ODM_BB_ADAPTIVITY) && + (current_igi > dig_tab->cur_ig_value)) { + dig_tab->cur_ig_value = current_igi; + phydm_adaptivity(dm); + } + + /* 1 Set IGI value */ + if (dm->support_platform & (ODM_WIN | ODM_CE)) { + odm_set_bb_reg(dm, ODM_REG(IGI_A, dm), ODM_BIT(IGI, dm), + current_igi); + + if (dm->rf_type > ODM_1T1R) + odm_set_bb_reg(dm, ODM_REG(IGI_B, dm), + ODM_BIT(IGI, dm), current_igi); + + } else if (dm->support_platform & (ODM_AP)) { + phydm_check_ap_write_dig(dm, current_igi); + } + + dig_tab->cur_ig_value = current_igi; + } + + ODM_RT_TRACE(dm, ODM_COMP_DIG, "%s(): current_igi(0x%02x).\n", __func__, + current_igi); +} + +void odm_pause_dig(void *dm_void, enum phydm_pause_type pause_type, + enum phydm_pause_level pause_level, u8 igi_value) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct dig_thres *dig_tab = &dm->dm_dig_table; + s8 max_level; + + ODM_RT_TRACE(dm, ODM_COMP_DIG, "%s()=========> level = %d\n", __func__, + pause_level); + + if ((dig_tab->pause_dig_level == 0) && + (!(dm->support_ability & ODM_BB_DIG) || + !(dm->support_ability & ODM_BB_FA_CNT))) { + ODM_RT_TRACE( + dm, ODM_COMP_DIG, + "%s(): Return: support_ability DIG or FA is disabled !!\n", + __func__); + return; + } + + if (pause_level > DM_DIG_MAX_PAUSE_TYPE) { + ODM_RT_TRACE(dm, ODM_COMP_DIG, + "%s(): Return: Wrong pause level !!\n", __func__); + return; + } + + ODM_RT_TRACE(dm, ODM_COMP_DIG, + "%s(): pause level = 0x%x, Current value = 0x%x\n", + __func__, dig_tab->pause_dig_level, igi_value); + ODM_RT_TRACE( + dm, ODM_COMP_DIG, + "%s(): pause value = 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", + __func__, dig_tab->pause_dig_value[7], + dig_tab->pause_dig_value[6], dig_tab->pause_dig_value[5], + dig_tab->pause_dig_value[4], dig_tab->pause_dig_value[3], + dig_tab->pause_dig_value[2], dig_tab->pause_dig_value[1], + dig_tab->pause_dig_value[0]); + + switch (pause_type) { + /* Pause DIG */ + case PHYDM_PAUSE: { + /* Disable DIG */ + odm_cmn_info_update(dm, ODM_CMNINFO_ABILITY, + dm->support_ability & (~ODM_BB_DIG)); + ODM_RT_TRACE(dm, ODM_COMP_DIG, "%s(): Pause DIG !!\n", + __func__); + + /* Backup IGI value */ + if (dig_tab->pause_dig_level == 0) { + dig_tab->igi_backup = dig_tab->cur_ig_value; + ODM_RT_TRACE( + dm, ODM_COMP_DIG, + "%s(): Backup IGI = 0x%x, new IGI = 0x%x\n", + __func__, dig_tab->igi_backup, igi_value); + } + + /* Record IGI value */ + dig_tab->pause_dig_value[pause_level] = igi_value; + + /* Update pause level */ + dig_tab->pause_dig_level = + (dig_tab->pause_dig_level | BIT(pause_level)); + + /* Write new IGI value */ + if (BIT(pause_level + 1) > dig_tab->pause_dig_level) { + odm_write_dig(dm, igi_value); + ODM_RT_TRACE(dm, ODM_COMP_DIG, + "%s(): IGI of higher level = 0x%x\n", + __func__, igi_value); + } + break; + } + /* Resume DIG */ + case PHYDM_RESUME: { + /* check if the level is illegal or not */ + if ((dig_tab->pause_dig_level & (BIT(pause_level))) != 0) { + dig_tab->pause_dig_level = dig_tab->pause_dig_level & + (~(BIT(pause_level))); + dig_tab->pause_dig_value[pause_level] = 0; + ODM_RT_TRACE(dm, ODM_COMP_DIG, "%s(): Resume DIG !!\n", + __func__); + } else { + ODM_RT_TRACE(dm, ODM_COMP_DIG, + "%s(): Wrong resume level !!\n", __func__); + break; + } + + /* Resume DIG */ + if (dig_tab->pause_dig_level == 0) { + /* Write backup IGI value */ + odm_write_dig(dm, dig_tab->igi_backup); + dig_tab->is_ignore_dig = true; + ODM_RT_TRACE(dm, ODM_COMP_DIG, + "%s(): Write original IGI = 0x%x\n", + __func__, dig_tab->igi_backup); + + /* Enable DIG */ + odm_cmn_info_update(dm, ODM_CMNINFO_ABILITY, + dm->support_ability | ODM_BB_DIG); + break; + } + + if (BIT(pause_level) <= dig_tab->pause_dig_level) + break; + + /* Calculate the maximum level now */ + for (max_level = (pause_level - 1); max_level >= 0; + max_level--) { + if ((dig_tab->pause_dig_level & BIT(max_level)) > 0) + break; + } + + /* write IGI of lower level */ + odm_write_dig(dm, dig_tab->pause_dig_value[max_level]); + ODM_RT_TRACE(dm, ODM_COMP_DIG, + "%s(): Write IGI (0x%x) of level (%d)\n", __func__, + dig_tab->pause_dig_value[max_level], max_level); + break; + } + default: + ODM_RT_TRACE(dm, ODM_COMP_DIG, "%s(): Wrong type !!\n", + __func__); + break; + } + + ODM_RT_TRACE(dm, ODM_COMP_DIG, + "%s(): pause level = 0x%x, Current value = 0x%x\n", + __func__, dig_tab->pause_dig_level, igi_value); + ODM_RT_TRACE( + dm, ODM_COMP_DIG, + "%s(): pause value = 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", + __func__, dig_tab->pause_dig_value[7], + dig_tab->pause_dig_value[6], dig_tab->pause_dig_value[5], + dig_tab->pause_dig_value[4], dig_tab->pause_dig_value[3], + dig_tab->pause_dig_value[2], dig_tab->pause_dig_value[1], + dig_tab->pause_dig_value[0]); +} + +static bool odm_dig_abort(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct dig_thres *dig_tab = &dm->dm_dig_table; + + /* support_ability */ + if (!(dm->support_ability & ODM_BB_FA_CNT)) { + ODM_RT_TRACE( + dm, ODM_COMP_DIG, + "%s(): Return: support_ability ODM_BB_FA_CNT is disabled\n", + __func__); + return true; + } + + /* support_ability */ + if (!(dm->support_ability & ODM_BB_DIG)) { + ODM_RT_TRACE( + dm, ODM_COMP_DIG, + "%s(): Return: support_ability ODM_BB_DIG is disabled\n", + __func__); + return true; + } + + /* ScanInProcess */ + if (*dm->is_scan_in_process) { + ODM_RT_TRACE(dm, ODM_COMP_DIG, + "%s(): Return: In Scan Progress\n", __func__); + return true; + } + + if (dig_tab->is_ignore_dig) { + dig_tab->is_ignore_dig = false; + ODM_RT_TRACE(dm, ODM_COMP_DIG, "%s(): Return: Ignore DIG\n", + __func__); + return true; + } + + /* add by Neil Chen to avoid PSD is processing */ + if (!dm->is_dm_initial_gain_enable) { + ODM_RT_TRACE(dm, ODM_COMP_DIG, + "%s(): Return: PSD is Processing\n", __func__); + return true; + } + + return false; +} + +void odm_dig_init(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct dig_thres *dig_tab = &dm->dm_dig_table; + u32 ret_value; + u8 i; + + dig_tab->is_stop_dig = false; + dig_tab->is_ignore_dig = false; + dig_tab->is_psd_in_progress = false; + dig_tab->cur_ig_value = + (u8)odm_get_bb_reg(dm, ODM_REG(IGI_A, dm), ODM_BIT(IGI, dm)); + dig_tab->pre_ig_value = 0; + dig_tab->rssi_low_thresh = DM_DIG_THRESH_LOW; + dig_tab->rssi_high_thresh = DM_DIG_THRESH_HIGH; + dig_tab->fa_low_thresh = DM_FALSEALARM_THRESH_LOW; + dig_tab->fa_high_thresh = DM_FALSEALARM_THRESH_HIGH; + dig_tab->backoff_val = DM_DIG_BACKOFF_DEFAULT; + dig_tab->backoff_val_range_max = DM_DIG_BACKOFF_MAX; + dig_tab->backoff_val_range_min = DM_DIG_BACKOFF_MIN; + dig_tab->pre_cck_cca_thres = 0xFF; + dig_tab->cur_cck_cca_thres = 0x83; + dig_tab->forbidden_igi = DM_DIG_MIN_NIC; + dig_tab->large_fa_hit = 0; + dig_tab->large_fa_timeout = 0; + dig_tab->recover_cnt = 0; + dig_tab->is_media_connect_0 = false; + dig_tab->is_media_connect_1 = false; + + /*To initialize dm->is_dm_initial_gain_enable==false to avoid DIG err*/ + dm->is_dm_initial_gain_enable = true; + + dig_tab->dig_dynamic_min_0 = DM_DIG_MIN_NIC; + dig_tab->dig_dynamic_min_1 = DM_DIG_MIN_NIC; + + /* To Initi BT30 IGI */ + dig_tab->bt30_cur_igi = 0x32; + + odm_memory_set(dm, dig_tab->pause_dig_value, 0, + (DM_DIG_MAX_PAUSE_TYPE + 1)); + dig_tab->pause_dig_level = 0; + odm_memory_set(dm, dig_tab->pause_cckpd_value, 0, + (DM_DIG_MAX_PAUSE_TYPE + 1)); + dig_tab->pause_cckpd_level = 0; + + if (dm->board_type & (ODM_BOARD_EXT_PA | ODM_BOARD_EXT_LNA)) { + dig_tab->rx_gain_range_max = DM_DIG_MAX_NIC; + dig_tab->rx_gain_range_min = DM_DIG_MIN_NIC; + } else { + dig_tab->rx_gain_range_max = DM_DIG_MAX_NIC; + dig_tab->rx_gain_range_min = DM_DIG_MIN_NIC; + } + + dig_tab->enable_adjust_big_jump = 1; + if (dm->support_ic_type & ODM_RTL8822B) { + ret_value = odm_get_bb_reg(dm, 0x8c8, MASKLWORD); + dig_tab->big_jump_step1 = (u8)(ret_value & 0xe) >> 1; + dig_tab->big_jump_step2 = (u8)(ret_value & 0x30) >> 4; + dig_tab->big_jump_step3 = (u8)(ret_value & 0xc0) >> 6; + + } else if (dm->support_ic_type & ODM_RTL8197F) { + ret_value = + odm_get_bb_reg(dm, ODM_REG_BB_AGC_SET_2_11N, MASKLWORD); + dig_tab->big_jump_step1 = (u8)(ret_value & 0xe) >> 1; + dig_tab->big_jump_step2 = (u8)(ret_value & 0x30) >> 4; + dig_tab->big_jump_step3 = (u8)(ret_value & 0xc0) >> 6; + } + if (dm->support_ic_type & (ODM_RTL8822B | ODM_RTL8197F)) { + for (i = 0; i < sizeof(dig_tab->big_jump_lmt); i++) { + if (dig_tab->big_jump_lmt[i] == 0) + dig_tab->big_jump_lmt[i] = + 0x64; /* Set -10dBm as default value */ + } + } +} + +void odm_DIG(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + + /* Common parameters */ + struct dig_thres *dig_tab = &dm->dm_dig_table; + struct false_alarm_stat *fa_cnt = + (struct false_alarm_stat *)phydm_get_structure( + dm, PHYDM_FALSEALMCNT); + bool first_connect, first_dis_connect; + u8 dig_max_of_min, dig_dynamic_min; + u8 dm_dig_max, dm_dig_min; + u8 current_igi = dig_tab->cur_ig_value; + u8 offset; + u32 dm_FA_thres[3]; + u32 tx_tp = 0, rx_tp = 0; + bool is_dfs_band = false; + bool is_performance = true, is_first_tp_target = false, + is_first_coverage = false; + + if (odm_dig_abort(dm)) + return; + + ODM_RT_TRACE(dm, ODM_COMP_DIG, "DIG Start===>\n"); + + /* 1 Update status */ + { + dig_dynamic_min = dig_tab->dig_dynamic_min_0; + first_connect = (dm->is_linked) && !dig_tab->is_media_connect_0; + first_dis_connect = + (!dm->is_linked) && dig_tab->is_media_connect_0; + } + + /* 1 Boundary Decision */ + { + /* 2 For WIN\CE */ + if (dm->support_ic_type >= ODM_RTL8188E) + dm_dig_max = 0x5A; + else + dm_dig_max = DM_DIG_MAX_NIC; + + if (dm->support_ic_type != ODM_RTL8821) + dm_dig_min = DM_DIG_MIN_NIC; + else + dm_dig_min = 0x1C; + + dig_max_of_min = DM_DIG_MAX_AP; + + /* Modify lower bound for DFS band */ + if ((((*dm->channel >= 52) && (*dm->channel <= 64)) || + ((*dm->channel >= 100) && (*dm->channel <= 140))) && + phydm_dfs_master_enabled(dm)) { + is_dfs_band = true; + if (*dm->band_width == ODM_BW20M) + dm_dig_min = DM_DIG_MIN_AP_DFS + 2; + else + dm_dig_min = DM_DIG_MIN_AP_DFS; + ODM_RT_TRACE(dm, ODM_COMP_DIG, + "DIG: ====== In DFS band ======\n"); + } + } + ODM_RT_TRACE(dm, ODM_COMP_DIG, + "DIG: Absolutly upper bound = 0x%x, lower bound = 0x%x\n", + dm_dig_max, dm_dig_min); + + if (dm->pu1_forced_igi_lb && (*dm->pu1_forced_igi_lb > 0)) { + ODM_RT_TRACE(dm, ODM_COMP_DIG, "DIG: Force IGI lb to: 0x%02x\n", + *dm->pu1_forced_igi_lb); + dm_dig_min = *dm->pu1_forced_igi_lb; + dm_dig_max = (dm_dig_min <= dm_dig_max) ? (dm_dig_max) : + (dm_dig_min + 1); + } + + /* 1 Adjust boundary by RSSI */ + if (dm->is_linked && is_performance) { + /* 2 Modify DIG upper bound */ + /* 4 Modify DIG upper bound for 92E, 8723A\B, 8821 & 8812 BT */ + if ((dm->support_ic_type & (ODM_RTL8192E | ODM_RTL8723B | + ODM_RTL8812 | ODM_RTL8821)) && + (dm->is_bt_limited_dig == 1)) { + offset = 10; + ODM_RT_TRACE( + dm, ODM_COMP_DIG, + "DIG: Coex. case: Force upper bound to RSSI + %d\n", + offset); + } else { + offset = 15; + } + + if ((dm->rssi_min + offset) > dm_dig_max) + dig_tab->rx_gain_range_max = dm_dig_max; + else if ((dm->rssi_min + offset) < dm_dig_min) + dig_tab->rx_gain_range_max = dm_dig_min; + else + dig_tab->rx_gain_range_max = dm->rssi_min + offset; + + /* 2 Modify DIG lower bound */ + /* if(dm->is_one_entry_only) */ + { + if (dm->rssi_min < dm_dig_min) + dig_dynamic_min = dm_dig_min; + else if (dm->rssi_min > dig_max_of_min) + dig_dynamic_min = dig_max_of_min; + else + dig_dynamic_min = dm->rssi_min; + + if (is_dfs_band) { + dig_dynamic_min = dm_dig_min; + ODM_RT_TRACE( + dm, ODM_COMP_DIG, + "DIG: DFS band: Force lower bound to 0x%x after link\n", + dm_dig_min); + } + } + } else { + if (is_performance && is_dfs_band) { + dig_tab->rx_gain_range_max = 0x28; + ODM_RT_TRACE( + dm, ODM_COMP_DIG, + "DIG: DFS band: Force upper bound to 0x%x before link\n", + dig_tab->rx_gain_range_max); + } else { + if (is_performance) + dig_tab->rx_gain_range_max = DM_DIG_MAX_OF_MIN; + else + dig_tab->rx_gain_range_max = dm_dig_max; + } + dig_dynamic_min = dm_dig_min; + } + + /* 1 Force Lower Bound for AntDiv */ + if (dm->is_linked && !dm->is_one_entry_only && + (dm->support_ic_type & ODM_ANTDIV_SUPPORT) && + (dm->support_ability & ODM_BB_ANT_DIV)) { + if (dm->ant_div_type == CG_TRX_HW_ANTDIV || + dm->ant_div_type == CG_TRX_SMART_ANTDIV) { + if (dig_tab->ant_div_rssi_max > dig_max_of_min) + dig_dynamic_min = dig_max_of_min; + else + dig_dynamic_min = (u8)dig_tab->ant_div_rssi_max; + ODM_RT_TRACE( + dm, ODM_COMP_DIG, + "DIG: AntDiv case: Force lower bound to 0x%x\n", + dig_dynamic_min); + ODM_RT_TRACE(dm, ODM_COMP_DIG, + "DIG: AntDiv case: rssi_max = 0x%x\n", + dig_tab->ant_div_rssi_max); + } + } + ODM_RT_TRACE( + dm, ODM_COMP_DIG, + "DIG: Adjust boundary by RSSI Upper bound = 0x%x, Lower bound = 0x%x\n", + dig_tab->rx_gain_range_max, dig_dynamic_min); + ODM_RT_TRACE( + dm, ODM_COMP_DIG, + "DIG: Link status: is_linked = %d, RSSI = %d, bFirstConnect = %d, bFirsrDisConnect = %d\n", + dm->is_linked, dm->rssi_min, first_connect, first_dis_connect); + + /* 1 Modify DIG lower bound, deal with abnormal case */ + /* 2 Abnormal false alarm case */ + if (is_dfs_band) { + dig_tab->rx_gain_range_min = dig_dynamic_min; + } else { + if (!dm->is_linked) { + dig_tab->rx_gain_range_min = dig_dynamic_min; + + if (first_dis_connect) + dig_tab->forbidden_igi = dig_dynamic_min; + } else { + dig_tab->rx_gain_range_min = odm_forbidden_igi_check( + dm, dig_dynamic_min, current_igi); + } + } + + /* 2 Abnormal # beacon case */ + if (dm->is_linked && !first_connect) { + ODM_RT_TRACE(dm, ODM_COMP_DIG, "Beacon Num (%d)\n", + dm->phy_dbg_info.num_qry_beacon_pkt); + if ((dm->phy_dbg_info.num_qry_beacon_pkt < 5) && + (dm->bsta_state)) { + dig_tab->rx_gain_range_min = 0x1c; + ODM_RT_TRACE( + dm, ODM_COMP_DIG, + "DIG: Abnrormal #beacon (%d) case in STA mode: Force lower bound to 0x%x\n", + dm->phy_dbg_info.num_qry_beacon_pkt, + dig_tab->rx_gain_range_min); + } + } + + /* 2 Abnormal lower bound case */ + if (dig_tab->rx_gain_range_min > dig_tab->rx_gain_range_max) { + dig_tab->rx_gain_range_min = dig_tab->rx_gain_range_max; + ODM_RT_TRACE( + dm, ODM_COMP_DIG, + "DIG: Abnrormal lower bound case: Force lower bound to 0x%x\n", + dig_tab->rx_gain_range_min); + } + + /* 1 False alarm threshold decision */ + odm_fa_threshold_check(dm, is_dfs_band, is_performance, rx_tp, tx_tp, + dm_FA_thres); + ODM_RT_TRACE(dm, ODM_COMP_DIG, + "DIG: False alarm threshold = %d, %d, %d\n", + dm_FA_thres[0], dm_FA_thres[1], dm_FA_thres[2]); + + /* 1 Adjust initial gain by false alarm */ + if (dm->is_linked && is_performance) { + /* 2 After link */ + ODM_RT_TRACE(dm, ODM_COMP_DIG, "DIG: Adjust IGI after link\n"); + + if (is_first_tp_target || (first_connect && is_performance)) { + dig_tab->large_fa_hit = 0; + + if (is_dfs_band) { + u8 rssi = dm->rssi_min; + + current_igi = + (dm->rssi_min > 0x28) ? 0x28 : rssi; + ODM_RT_TRACE( + dm, ODM_COMP_DIG, + "DIG: DFS band: One-shot to 0x28 upmost\n"); + } else { + current_igi = phydm_get_current_igi( + dig_max_of_min, dm->rssi_min, + current_igi); + } + + ODM_RT_TRACE( + dm, ODM_COMP_DIG, + "DIG: First connect case: IGI does on-shot to 0x%x\n", + current_igi); + + } else { + if (fa_cnt->cnt_all > dm_FA_thres[2]) + current_igi = current_igi + 4; + else if (fa_cnt->cnt_all > dm_FA_thres[1]) + current_igi = current_igi + 2; + else if (fa_cnt->cnt_all < dm_FA_thres[0]) + current_igi = current_igi - 2; + + /* 4 Abnormal # beacon case */ + if ((dm->phy_dbg_info.num_qry_beacon_pkt < 5) && + (fa_cnt->cnt_all < DM_DIG_FA_TH1) && + (dm->bsta_state)) { + current_igi = dig_tab->rx_gain_range_min; + ODM_RT_TRACE( + dm, ODM_COMP_DIG, + "DIG: Abnormal #beacon (%d) case: IGI does one-shot to 0x%x\n", + dm->phy_dbg_info.num_qry_beacon_pkt, + current_igi); + } + } + } else { + /* 2 Before link */ + ODM_RT_TRACE(dm, ODM_COMP_DIG, "DIG: Adjust IGI before link\n"); + + if (first_dis_connect || is_first_coverage) { + current_igi = dm_dig_min; + ODM_RT_TRACE( + dm, ODM_COMP_DIG, + "DIG: First disconnect case: IGI does on-shot to lower bound\n"); + } else { + if (fa_cnt->cnt_all > dm_FA_thres[2]) + current_igi = current_igi + 4; + else if (fa_cnt->cnt_all > dm_FA_thres[1]) + current_igi = current_igi + 2; + else if (fa_cnt->cnt_all < dm_FA_thres[0]) + current_igi = current_igi - 2; + } + } + + /* 1 Check initial gain by upper/lower bound */ + if (current_igi < dig_tab->rx_gain_range_min) + current_igi = dig_tab->rx_gain_range_min; + + if (current_igi > dig_tab->rx_gain_range_max) + current_igi = dig_tab->rx_gain_range_max; + + ODM_RT_TRACE(dm, ODM_COMP_DIG, "DIG: cur_ig_value=0x%x, TotalFA = %d\n", + current_igi, fa_cnt->cnt_all); + + /* 1 Update status */ + if (dm->is_bt_hs_operation) { + if (dm->is_linked) { + if (dig_tab->bt30_cur_igi > (current_igi)) + odm_write_dig(dm, current_igi); + else + odm_write_dig(dm, dig_tab->bt30_cur_igi); + + dig_tab->is_media_connect_0 = dm->is_linked; + dig_tab->dig_dynamic_min_0 = dig_dynamic_min; + } else { + if (dm->is_link_in_process) + odm_write_dig(dm, 0x1c); + else if (dm->is_bt_connect_process) + odm_write_dig(dm, 0x28); + else + odm_write_dig(dm, dig_tab->bt30_cur_igi); + } + } else { /* BT is not using */ + odm_write_dig(dm, current_igi); + dig_tab->is_media_connect_0 = dm->is_linked; + dig_tab->dig_dynamic_min_0 = dig_dynamic_min; + } + ODM_RT_TRACE(dm, ODM_COMP_DIG, "DIG end\n"); +} + +void odm_dig_by_rssi_lps(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct false_alarm_stat *fa_cnt = + (struct false_alarm_stat *)phydm_get_structure( + dm, PHYDM_FALSEALMCNT); + + u8 rssi_lower = DM_DIG_MIN_NIC; /* 0x1E or 0x1C */ + u8 current_igi = dm->rssi_min; + + if (odm_dig_abort(dm)) + return; + + current_igi = current_igi + RSSI_OFFSET_DIG; + + ODM_RT_TRACE(dm, ODM_COMP_DIG, "%s()==>\n", __func__); + + /* Using FW PS mode to make IGI */ + /* Adjust by FA in LPS MODE */ + if (fa_cnt->cnt_all > DM_DIG_FA_TH2_LPS) + current_igi = current_igi + 4; + else if (fa_cnt->cnt_all > DM_DIG_FA_TH1_LPS) + current_igi = current_igi + 2; + else if (fa_cnt->cnt_all < DM_DIG_FA_TH0_LPS) + current_igi = current_igi - 2; + + /* Lower bound checking */ + + /* RSSI Lower bound check */ + if ((dm->rssi_min - 10) > DM_DIG_MIN_NIC) + rssi_lower = (dm->rssi_min - 10); + else + rssi_lower = DM_DIG_MIN_NIC; + + /* Upper and Lower Bound checking */ + if (current_igi > DM_DIG_MAX_NIC) + current_igi = DM_DIG_MAX_NIC; + else if (current_igi < rssi_lower) + current_igi = rssi_lower; + + ODM_RT_TRACE(dm, ODM_COMP_DIG, "%s(): fa_cnt->cnt_all = %d\n", __func__, + fa_cnt->cnt_all); + ODM_RT_TRACE(dm, ODM_COMP_DIG, "%s(): dm->rssi_min = %d\n", __func__, + dm->rssi_min); + ODM_RT_TRACE(dm, ODM_COMP_DIG, "%s(): current_igi = 0x%x\n", __func__, + current_igi); + + odm_write_dig( + dm, + current_igi); /* odm_write_dig(dm, dig_tab->cur_ig_value); */ +} + +/* 3============================================================ + * 3 FASLE ALARM CHECK + * 3============================================================ + */ + +void odm_false_alarm_counter_statistics(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct false_alarm_stat *false_alm_cnt = + (struct false_alarm_stat *)phydm_get_structure( + dm, PHYDM_FALSEALMCNT); + struct rt_adcsmp *adc_smp = &dm->adcsmp; + u32 ret_value; + + if (!(dm->support_ability & ODM_BB_FA_CNT)) + return; + + ODM_RT_TRACE(dm, ODM_COMP_FA_CNT, "%s()======>\n", __func__); + + if (dm->support_ic_type & ODM_IC_11N_SERIES) { + /* hold ofdm counter */ + odm_set_bb_reg(dm, ODM_REG_OFDM_FA_HOLDC_11N, BIT(31), + 1); /* hold page C counter */ + odm_set_bb_reg(dm, ODM_REG_OFDM_FA_RSTD_11N, BIT(31), + 1); /* hold page D counter */ + + ret_value = odm_get_bb_reg(dm, ODM_REG_OFDM_FA_TYPE1_11N, + MASKDWORD); + false_alm_cnt->cnt_fast_fsync = (ret_value & 0xffff); + false_alm_cnt->cnt_sb_search_fail = + ((ret_value & 0xffff0000) >> 16); + + ret_value = odm_get_bb_reg(dm, ODM_REG_OFDM_FA_TYPE2_11N, + MASKDWORD); + false_alm_cnt->cnt_ofdm_cca = (ret_value & 0xffff); + false_alm_cnt->cnt_parity_fail = + ((ret_value & 0xffff0000) >> 16); + + ret_value = odm_get_bb_reg(dm, ODM_REG_OFDM_FA_TYPE3_11N, + MASKDWORD); + false_alm_cnt->cnt_rate_illegal = (ret_value & 0xffff); + false_alm_cnt->cnt_crc8_fail = ((ret_value & 0xffff0000) >> 16); + + ret_value = odm_get_bb_reg(dm, ODM_REG_OFDM_FA_TYPE4_11N, + MASKDWORD); + false_alm_cnt->cnt_mcs_fail = (ret_value & 0xffff); + + false_alm_cnt->cnt_ofdm_fail = + false_alm_cnt->cnt_parity_fail + + false_alm_cnt->cnt_rate_illegal + + false_alm_cnt->cnt_crc8_fail + + false_alm_cnt->cnt_mcs_fail + + false_alm_cnt->cnt_fast_fsync + + false_alm_cnt->cnt_sb_search_fail; + + /* read CCK CRC32 counter */ + false_alm_cnt->cnt_cck_crc32_error = odm_get_bb_reg( + dm, ODM_REG_CCK_CRC32_ERROR_CNT_11N, MASKDWORD); + false_alm_cnt->cnt_cck_crc32_ok = odm_get_bb_reg( + dm, ODM_REG_CCK_CRC32_OK_CNT_11N, MASKDWORD); + + /* read OFDM CRC32 counter */ + ret_value = odm_get_bb_reg(dm, ODM_REG_OFDM_CRC32_CNT_11N, + MASKDWORD); + false_alm_cnt->cnt_ofdm_crc32_error = + (ret_value & 0xffff0000) >> 16; + false_alm_cnt->cnt_ofdm_crc32_ok = ret_value & 0xffff; + + /* read HT CRC32 counter */ + ret_value = + odm_get_bb_reg(dm, ODM_REG_HT_CRC32_CNT_11N, MASKDWORD); + false_alm_cnt->cnt_ht_crc32_error = + (ret_value & 0xffff0000) >> 16; + false_alm_cnt->cnt_ht_crc32_ok = ret_value & 0xffff; + + /* read VHT CRC32 counter */ + false_alm_cnt->cnt_vht_crc32_error = 0; + false_alm_cnt->cnt_vht_crc32_ok = 0; + + { + /* hold cck counter */ + odm_set_bb_reg(dm, ODM_REG_CCK_FA_RST_11N, BIT(12), 1); + odm_set_bb_reg(dm, ODM_REG_CCK_FA_RST_11N, BIT(14), 1); + + ret_value = odm_get_bb_reg(dm, ODM_REG_CCK_FA_LSB_11N, + MASKBYTE0); + false_alm_cnt->cnt_cck_fail = ret_value; + + ret_value = odm_get_bb_reg(dm, ODM_REG_CCK_FA_MSB_11N, + MASKBYTE3); + false_alm_cnt->cnt_cck_fail += (ret_value & 0xff) << 8; + + ret_value = odm_get_bb_reg(dm, ODM_REG_CCK_CCA_CNT_11N, + MASKDWORD); + false_alm_cnt->cnt_cck_cca = + ((ret_value & 0xFF) << 8) | + ((ret_value & 0xFF00) >> 8); + } + + false_alm_cnt->cnt_all_pre = false_alm_cnt->cnt_all; + + false_alm_cnt->cnt_all = (false_alm_cnt->cnt_fast_fsync + + false_alm_cnt->cnt_sb_search_fail + + false_alm_cnt->cnt_parity_fail + + false_alm_cnt->cnt_rate_illegal + + false_alm_cnt->cnt_crc8_fail + + false_alm_cnt->cnt_mcs_fail + + false_alm_cnt->cnt_cck_fail); + + false_alm_cnt->cnt_cca_all = false_alm_cnt->cnt_ofdm_cca + + false_alm_cnt->cnt_cck_cca; + + if (dm->support_ic_type >= ODM_RTL8188E) { + /*reset false alarm counter registers*/ + odm_set_bb_reg(dm, ODM_REG_OFDM_FA_RSTC_11N, BIT(31), + 1); + odm_set_bb_reg(dm, ODM_REG_OFDM_FA_RSTC_11N, BIT(31), + 0); + odm_set_bb_reg(dm, ODM_REG_OFDM_FA_RSTD_11N, BIT(27), + 1); + odm_set_bb_reg(dm, ODM_REG_OFDM_FA_RSTD_11N, BIT(27), + 0); + + /*update ofdm counter*/ + odm_set_bb_reg(dm, ODM_REG_OFDM_FA_HOLDC_11N, BIT(31), + 0); /*update page C counter*/ + odm_set_bb_reg(dm, ODM_REG_OFDM_FA_RSTD_11N, BIT(31), + 0); /*update page D counter*/ + + /*reset CCK CCA counter*/ + odm_set_bb_reg(dm, ODM_REG_CCK_FA_RST_11N, + BIT(13) | BIT(12), 0); + odm_set_bb_reg(dm, ODM_REG_CCK_FA_RST_11N, + BIT(13) | BIT(12), 2); + + /*reset CCK FA counter*/ + odm_set_bb_reg(dm, ODM_REG_CCK_FA_RST_11N, + BIT(15) | BIT(14), 0); + odm_set_bb_reg(dm, ODM_REG_CCK_FA_RST_11N, + BIT(15) | BIT(14), 2); + + /*reset CRC32 counter*/ + odm_set_bb_reg(dm, ODM_REG_PAGE_F_RST_11N, BIT(16), 1); + odm_set_bb_reg(dm, ODM_REG_PAGE_F_RST_11N, BIT(16), 0); + } + + /* Get debug port 0 */ + odm_set_bb_reg(dm, ODM_REG_DBG_RPT_11N, MASKDWORD, 0x0); + false_alm_cnt->dbg_port0 = + odm_get_bb_reg(dm, ODM_REG_RPT_11N, MASKDWORD); + + /* Get EDCCA flag */ + odm_set_bb_reg(dm, ODM_REG_DBG_RPT_11N, MASKDWORD, 0x208); + false_alm_cnt->edcca_flag = + (bool)odm_get_bb_reg(dm, ODM_REG_RPT_11N, BIT(30)); + + ODM_RT_TRACE( + dm, ODM_COMP_FA_CNT, + "[OFDM FA Detail] Parity_Fail = (( %d )), Rate_Illegal = (( %d )), CRC8_fail = (( %d )), Mcs_fail = (( %d )), Fast_Fsync = (( %d )), SB_Search_fail = (( %d ))\n", + false_alm_cnt->cnt_parity_fail, + false_alm_cnt->cnt_rate_illegal, + false_alm_cnt->cnt_crc8_fail, + false_alm_cnt->cnt_mcs_fail, + false_alm_cnt->cnt_fast_fsync, + false_alm_cnt->cnt_sb_search_fail); + } + + if (dm->support_ic_type & ODM_IC_11AC_SERIES) { + u32 cck_enable; + + /* read OFDM FA counter */ + false_alm_cnt->cnt_ofdm_fail = + odm_get_bb_reg(dm, ODM_REG_OFDM_FA_11AC, MASKLWORD); + + /* Read CCK FA counter */ + false_alm_cnt->cnt_cck_fail = + odm_get_bb_reg(dm, ODM_REG_CCK_FA_11AC, MASKLWORD); + + /* read CCK/OFDM CCA counter */ + ret_value = + odm_get_bb_reg(dm, ODM_REG_CCK_CCA_CNT_11AC, MASKDWORD); + false_alm_cnt->cnt_ofdm_cca = (ret_value & 0xffff0000) >> 16; + false_alm_cnt->cnt_cck_cca = ret_value & 0xffff; + + /* read CCK CRC32 counter */ + ret_value = odm_get_bb_reg(dm, ODM_REG_CCK_CRC32_CNT_11AC, + MASKDWORD); + false_alm_cnt->cnt_cck_crc32_error = + (ret_value & 0xffff0000) >> 16; + false_alm_cnt->cnt_cck_crc32_ok = ret_value & 0xffff; + + /* read OFDM CRC32 counter */ + ret_value = odm_get_bb_reg(dm, ODM_REG_OFDM_CRC32_CNT_11AC, + MASKDWORD); + false_alm_cnt->cnt_ofdm_crc32_error = + (ret_value & 0xffff0000) >> 16; + false_alm_cnt->cnt_ofdm_crc32_ok = ret_value & 0xffff; + + /* read HT CRC32 counter */ + ret_value = odm_get_bb_reg(dm, ODM_REG_HT_CRC32_CNT_11AC, + MASKDWORD); + false_alm_cnt->cnt_ht_crc32_error = + (ret_value & 0xffff0000) >> 16; + false_alm_cnt->cnt_ht_crc32_ok = ret_value & 0xffff; + + /* read VHT CRC32 counter */ + ret_value = odm_get_bb_reg(dm, ODM_REG_VHT_CRC32_CNT_11AC, + MASKDWORD); + false_alm_cnt->cnt_vht_crc32_error = + (ret_value & 0xffff0000) >> 16; + false_alm_cnt->cnt_vht_crc32_ok = ret_value & 0xffff; + + /* reset OFDM FA counter */ + odm_set_bb_reg(dm, ODM_REG_OFDM_FA_RST_11AC, BIT(17), 1); + odm_set_bb_reg(dm, ODM_REG_OFDM_FA_RST_11AC, BIT(17), 0); + + /* reset CCK FA counter */ + odm_set_bb_reg(dm, ODM_REG_CCK_FA_RST_11AC, BIT(15), 0); + odm_set_bb_reg(dm, ODM_REG_CCK_FA_RST_11AC, BIT(15), 1); + + /* reset CCA counter */ + odm_set_bb_reg(dm, ODM_REG_RST_RPT_11AC, BIT(0), 1); + odm_set_bb_reg(dm, ODM_REG_RST_RPT_11AC, BIT(0), 0); + + cck_enable = + odm_get_bb_reg(dm, ODM_REG_BB_RX_PATH_11AC, BIT(28)); + if (cck_enable) { /* if(*dm->band_type == ODM_BAND_2_4G) */ + false_alm_cnt->cnt_all = false_alm_cnt->cnt_ofdm_fail + + false_alm_cnt->cnt_cck_fail; + false_alm_cnt->cnt_cca_all = + false_alm_cnt->cnt_cck_cca + + false_alm_cnt->cnt_ofdm_cca; + } else { + false_alm_cnt->cnt_all = false_alm_cnt->cnt_ofdm_fail; + false_alm_cnt->cnt_cca_all = + false_alm_cnt->cnt_ofdm_cca; + } + + if (adc_smp->adc_smp_state == ADCSMP_STATE_IDLE) { + if (phydm_set_bb_dbg_port( + dm, BB_DBGPORT_PRIORITY_1, + 0x0)) { /*set debug port to 0x0*/ + false_alm_cnt->dbg_port0 = + phydm_get_bb_dbg_port_value(dm); + phydm_release_bb_dbg_port(dm); + } + + if (phydm_set_bb_dbg_port( + dm, BB_DBGPORT_PRIORITY_1, + 0x209)) { /*set debug port to 0x0*/ + false_alm_cnt->edcca_flag = + (bool)((phydm_get_bb_dbg_port_value( + dm) & + BIT(30)) >> + 30); + phydm_release_bb_dbg_port(dm); + } + } + } + + false_alm_cnt->cnt_crc32_error_all = + false_alm_cnt->cnt_vht_crc32_error + + false_alm_cnt->cnt_ht_crc32_error + + false_alm_cnt->cnt_ofdm_crc32_error + + false_alm_cnt->cnt_cck_crc32_error; + false_alm_cnt->cnt_crc32_ok_all = false_alm_cnt->cnt_vht_crc32_ok + + false_alm_cnt->cnt_ht_crc32_ok + + false_alm_cnt->cnt_ofdm_crc32_ok + + false_alm_cnt->cnt_cck_crc32_ok; + + ODM_RT_TRACE(dm, ODM_COMP_FA_CNT, + "[CCA Cnt] {CCK, OFDM, Total} = {%d, %d, %d}\n", + false_alm_cnt->cnt_cck_cca, false_alm_cnt->cnt_ofdm_cca, + false_alm_cnt->cnt_cca_all); + + ODM_RT_TRACE(dm, ODM_COMP_FA_CNT, + "[FA Cnt] {CCK, OFDM, Total} = {%d, %d, %d}\n", + false_alm_cnt->cnt_cck_fail, false_alm_cnt->cnt_ofdm_fail, + false_alm_cnt->cnt_all); + + ODM_RT_TRACE(dm, ODM_COMP_FA_CNT, + "[CCK] CRC32 {error, ok}= {%d, %d}\n", + false_alm_cnt->cnt_cck_crc32_error, + false_alm_cnt->cnt_cck_crc32_ok); + ODM_RT_TRACE(dm, ODM_COMP_FA_CNT, "[OFDM]CRC32 {error, ok}= {%d, %d}\n", + false_alm_cnt->cnt_ofdm_crc32_error, + false_alm_cnt->cnt_ofdm_crc32_ok); + ODM_RT_TRACE(dm, ODM_COMP_FA_CNT, + "[ HT ] CRC32 {error, ok}= {%d, %d}\n", + false_alm_cnt->cnt_ht_crc32_error, + false_alm_cnt->cnt_ht_crc32_ok); + ODM_RT_TRACE(dm, ODM_COMP_FA_CNT, + "[VHT] CRC32 {error, ok}= {%d, %d}\n", + false_alm_cnt->cnt_vht_crc32_error, + false_alm_cnt->cnt_vht_crc32_ok); + ODM_RT_TRACE(dm, ODM_COMP_FA_CNT, + "[VHT] CRC32 {error, ok}= {%d, %d}\n", + false_alm_cnt->cnt_crc32_error_all, + false_alm_cnt->cnt_crc32_ok_all); + ODM_RT_TRACE(dm, ODM_COMP_FA_CNT, + "FA_Cnt: Dbg port 0x0 = 0x%x, EDCCA = %d\n\n", + false_alm_cnt->dbg_port0, false_alm_cnt->edcca_flag); +} + +/* 3============================================================ + * 3 CCK Packet Detect threshold + * 3============================================================ + */ + +void odm_pause_cck_packet_detection(void *dm_void, + enum phydm_pause_type pause_type, + enum phydm_pause_level pause_level, + u8 cck_pd_threshold) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct dig_thres *dig_tab = &dm->dm_dig_table; + s8 max_level; + + ODM_RT_TRACE(dm, ODM_COMP_DIG, "%s()=========> level = %d\n", __func__, + pause_level); + + if ((dig_tab->pause_cckpd_level == 0) && + (!(dm->support_ability & ODM_BB_CCK_PD) || + !(dm->support_ability & ODM_BB_FA_CNT))) { + ODM_RT_TRACE( + dm, ODM_COMP_DIG, + "Return: support_ability ODM_BB_CCK_PD or ODM_BB_FA_CNT is disabled\n"); + return; + } + + if (pause_level > DM_DIG_MAX_PAUSE_TYPE) { + ODM_RT_TRACE(dm, ODM_COMP_DIG, + "%s(): Return: Wrong pause level !!\n", __func__); + return; + } + + ODM_RT_TRACE(dm, ODM_COMP_DIG, + "%s(): pause level = 0x%x, Current value = 0x%x\n", + __func__, dig_tab->pause_cckpd_level, cck_pd_threshold); + ODM_RT_TRACE( + dm, ODM_COMP_DIG, + "%s(): pause value = 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", + __func__, dig_tab->pause_cckpd_value[7], + dig_tab->pause_cckpd_value[6], dig_tab->pause_cckpd_value[5], + dig_tab->pause_cckpd_value[4], dig_tab->pause_cckpd_value[3], + dig_tab->pause_cckpd_value[2], dig_tab->pause_cckpd_value[1], + dig_tab->pause_cckpd_value[0]); + + switch (pause_type) { + /* Pause CCK Packet Detection threshold */ + case PHYDM_PAUSE: { + /* Disable CCK PD */ + odm_cmn_info_update(dm, ODM_CMNINFO_ABILITY, + dm->support_ability & (~ODM_BB_CCK_PD)); + ODM_RT_TRACE(dm, ODM_COMP_DIG, + "%s(): Pause CCK packet detection threshold !!\n", + __func__); + + /*Backup original CCK PD threshold decided by CCK PD mechanism*/ + if (dig_tab->pause_cckpd_level == 0) { + dig_tab->cck_pd_backup = dig_tab->cur_cck_cca_thres; + ODM_RT_TRACE( + dm, ODM_COMP_DIG, + "%s(): Backup CCKPD = 0x%x, new CCKPD = 0x%x\n", + __func__, dig_tab->cck_pd_backup, + cck_pd_threshold); + } + + /* Update pause level */ + dig_tab->pause_cckpd_level = + (dig_tab->pause_cckpd_level | BIT(pause_level)); + + /* Record CCK PD threshold */ + dig_tab->pause_cckpd_value[pause_level] = cck_pd_threshold; + + /* Write new CCK PD threshold */ + if (BIT(pause_level + 1) > dig_tab->pause_cckpd_level) { + odm_write_cck_cca_thres(dm, cck_pd_threshold); + ODM_RT_TRACE(dm, ODM_COMP_DIG, + "%s(): CCKPD of higher level = 0x%x\n", + __func__, cck_pd_threshold); + } + break; + } + /* Resume CCK Packet Detection threshold */ + case PHYDM_RESUME: { + /* check if the level is illegal or not */ + if ((dig_tab->pause_cckpd_level & (BIT(pause_level))) != 0) { + dig_tab->pause_cckpd_level = + dig_tab->pause_cckpd_level & + (~(BIT(pause_level))); + dig_tab->pause_cckpd_value[pause_level] = 0; + ODM_RT_TRACE(dm, ODM_COMP_DIG, + "%s(): Resume CCK PD !!\n", __func__); + } else { + ODM_RT_TRACE(dm, ODM_COMP_DIG, + "%s(): Wrong resume level !!\n", __func__); + break; + } + + /* Resume DIG */ + if (dig_tab->pause_cckpd_level == 0) { + /* Write backup IGI value */ + odm_write_cck_cca_thres(dm, dig_tab->cck_pd_backup); + /* dig_tab->is_ignore_dig = true; */ + ODM_RT_TRACE(dm, ODM_COMP_DIG, + "%s(): Write original CCKPD = 0x%x\n", + __func__, dig_tab->cck_pd_backup); + + /* Enable DIG */ + odm_cmn_info_update(dm, ODM_CMNINFO_ABILITY, + dm->support_ability | + ODM_BB_CCK_PD); + break; + } + + if (BIT(pause_level) <= dig_tab->pause_cckpd_level) + break; + + /* Calculate the maximum level now */ + for (max_level = (pause_level - 1); max_level >= 0; + max_level--) { + if ((dig_tab->pause_cckpd_level & BIT(max_level)) > 0) + break; + } + + /* write CCKPD of lower level */ + odm_write_cck_cca_thres(dm, + dig_tab->pause_cckpd_value[max_level]); + ODM_RT_TRACE(dm, ODM_COMP_DIG, + "%s(): Write CCKPD (0x%x) of level (%d)\n", + __func__, dig_tab->pause_cckpd_value[max_level], + max_level); + break; + } + default: + ODM_RT_TRACE(dm, ODM_COMP_DIG, "%s(): Wrong type !!\n", + __func__); + break; + } + + ODM_RT_TRACE(dm, ODM_COMP_DIG, + "%s(): pause level = 0x%x, Current value = 0x%x\n", + __func__, dig_tab->pause_cckpd_level, cck_pd_threshold); + ODM_RT_TRACE( + dm, ODM_COMP_DIG, + "%s(): pause value = 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", + __func__, dig_tab->pause_cckpd_value[7], + dig_tab->pause_cckpd_value[6], dig_tab->pause_cckpd_value[5], + dig_tab->pause_cckpd_value[4], dig_tab->pause_cckpd_value[3], + dig_tab->pause_cckpd_value[2], dig_tab->pause_cckpd_value[1], + dig_tab->pause_cckpd_value[0]); +} + +void odm_cck_packet_detection_thresh(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct dig_thres *dig_tab = &dm->dm_dig_table; + struct false_alarm_stat *false_alm_cnt = + (struct false_alarm_stat *)phydm_get_structure( + dm, PHYDM_FALSEALMCNT); + u8 cur_cck_cca_thres = dig_tab->cur_cck_cca_thres, rssi_thd = 35; + + if ((!(dm->support_ability & ODM_BB_CCK_PD)) || + (!(dm->support_ability & ODM_BB_FA_CNT))) { + ODM_RT_TRACE(dm, ODM_COMP_DIG, "CCK_PD: return==========\n"); + return; + } + + if (dm->ext_lna) + return; + + ODM_RT_TRACE(dm, ODM_COMP_DIG, "CCK_PD: ==========>\n"); + + if (dig_tab->cck_fa_ma == 0xffffffff) + dig_tab->cck_fa_ma = false_alm_cnt->cnt_cck_fail; + else + dig_tab->cck_fa_ma = + ((dig_tab->cck_fa_ma << 1) + dig_tab->cck_fa_ma + + false_alm_cnt->cnt_cck_fail) >> + 2; + + ODM_RT_TRACE(dm, ODM_COMP_DIG, "CCK_PD: CCK FA moving average = %d\n", + dig_tab->cck_fa_ma); + + if (dm->is_linked) { + if (dm->rssi_min > rssi_thd) { + cur_cck_cca_thres = 0xcd; + } else if (dm->rssi_min > 20) { + if (dig_tab->cck_fa_ma > + ((DM_DIG_FA_TH1 >> 1) + (DM_DIG_FA_TH1 >> 3))) + cur_cck_cca_thres = 0xcd; + else if (dig_tab->cck_fa_ma < (DM_DIG_FA_TH0 >> 1)) + cur_cck_cca_thres = 0x83; + } else if (dm->rssi_min > 7) { + cur_cck_cca_thres = 0x83; + } else { + cur_cck_cca_thres = 0x40; + } + + } else { + if (dig_tab->cck_fa_ma > 0x400) + cur_cck_cca_thres = 0x83; + else if (dig_tab->cck_fa_ma < 0x200) + cur_cck_cca_thres = 0x40; + } + + { + odm_write_cck_cca_thres(dm, cur_cck_cca_thres); + } + + ODM_RT_TRACE(dm, ODM_COMP_DIG, "CCK_PD: cck_cca_th=((0x%x))\n\n", + cur_cck_cca_thres); +} + +void odm_write_cck_cca_thres(void *dm_void, u8 cur_cck_cca_thres) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct dig_thres *dig_tab = &dm->dm_dig_table; + + if (dig_tab->cur_cck_cca_thres != + cur_cck_cca_thres) { /* modify by Guo.Mingzhi 2012-01-03 */ + odm_write_1byte(dm, ODM_REG(CCK_CCA, dm), cur_cck_cca_thres); + dig_tab->cck_fa_ma = 0xffffffff; + } + dig_tab->pre_cck_cca_thres = dig_tab->cur_cck_cca_thres; + dig_tab->cur_cck_cca_thres = cur_cck_cca_thres; +} + +bool phydm_dig_go_up_check(void *dm_void) +{ + bool ret = true; + + return ret; +} diff --git a/drivers/staging/rtlwifi/phydm/phydm_dig.h b/drivers/staging/rtlwifi/phydm/phydm_dig.h new file mode 100644 index 000000000000..af70aaec3b19 --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/phydm_dig.h @@ -0,0 +1,241 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __PHYDMDIG_H__ +#define __PHYDMDIG_H__ + +#define DIG_VERSION "1.32" /* 2016.09.02 YuChen. add CCK PD for 8197F*/ + +/* Pause DIG & CCKPD */ +#define DM_DIG_MAX_PAUSE_TYPE 0x7 + +enum dig_goupcheck_level { + DIG_GOUPCHECK_LEVEL_0, + DIG_GOUPCHECK_LEVEL_1, + DIG_GOUPCHECK_LEVEL_2 + +}; + +struct dig_thres { + bool is_stop_dig; /* for debug */ + bool is_ignore_dig; + bool is_psd_in_progress; + + u8 dig_enable_flag; + u8 dig_ext_port_stage; + + int rssi_low_thresh; + int rssi_high_thresh; + + u32 fa_low_thresh; + u32 fa_high_thresh; + + u8 cur_sta_connect_state; + u8 pre_sta_connect_state; + u8 cur_multi_sta_connect_state; + + u8 pre_ig_value; + u8 cur_ig_value; + u8 backup_ig_value; /* MP DIG */ + u8 bt30_cur_igi; + u8 igi_backup; + + s8 backoff_val; + s8 backoff_val_range_max; + s8 backoff_val_range_min; + u8 rx_gain_range_max; + u8 rx_gain_range_min; + u8 rssi_val_min; + + u8 pre_cck_cca_thres; + u8 cur_cck_cca_thres; + u8 pre_cck_pd_state; + u8 cur_cck_pd_state; + u8 cck_pd_backup; + u8 pause_cckpd_level; + u8 pause_cckpd_value[DM_DIG_MAX_PAUSE_TYPE + 1]; + + u8 large_fa_hit; + u8 large_fa_timeout; /*if (large_fa_hit), monitor "large_fa_timeout" + *sec, if timeout, large_fa_hit=0 + */ + u8 forbidden_igi; + u32 recover_cnt; + + u8 dig_dynamic_min_0; + u8 dig_dynamic_min_1; + bool is_media_connect_0; + bool is_media_connect_1; + + u32 ant_div_rssi_max; + u32 rssi_max; + + u8 *is_p2p_in_process; + + u8 pause_dig_level; + u8 pause_dig_value[DM_DIG_MAX_PAUSE_TYPE + 1]; + + u32 cck_fa_ma; + enum dig_goupcheck_level dig_go_up_check_level; + u8 aaa_default; + + u8 rf_gain_idx; + u8 agc_table_idx; + u8 big_jump_lmt[16]; + u8 enable_adjust_big_jump : 1; + u8 big_jump_step1 : 3; + u8 big_jump_step2 : 2; + u8 big_jump_step3 : 2; +}; + +struct false_alarm_stat { + u32 cnt_parity_fail; + u32 cnt_rate_illegal; + u32 cnt_crc8_fail; + u32 cnt_mcs_fail; + u32 cnt_ofdm_fail; + u32 cnt_ofdm_fail_pre; /* For RTL8881A */ + u32 cnt_cck_fail; + u32 cnt_all; + u32 cnt_all_pre; + u32 cnt_fast_fsync; + u32 cnt_sb_search_fail; + u32 cnt_ofdm_cca; + u32 cnt_cck_cca; + u32 cnt_cca_all; + u32 cnt_bw_usc; /* Gary */ + u32 cnt_bw_lsc; /* Gary */ + u32 cnt_cck_crc32_error; + u32 cnt_cck_crc32_ok; + u32 cnt_ofdm_crc32_error; + u32 cnt_ofdm_crc32_ok; + u32 cnt_ht_crc32_error; + u32 cnt_ht_crc32_ok; + u32 cnt_vht_crc32_error; + u32 cnt_vht_crc32_ok; + u32 cnt_crc32_error_all; + u32 cnt_crc32_ok_all; + bool cck_block_enable; + bool ofdm_block_enable; + u32 dbg_port0; + bool edcca_flag; +}; + +enum dm_dig_op { + DIG_TYPE_THRESH_HIGH = 0, + DIG_TYPE_THRESH_LOW = 1, + DIG_TYPE_BACKOFF = 2, + DIG_TYPE_RX_GAIN_MIN = 3, + DIG_TYPE_RX_GAIN_MAX = 4, + DIG_TYPE_ENABLE = 5, + DIG_TYPE_DISABLE = 6, + DIG_OP_TYPE_MAX +}; + +enum phydm_pause_type { PHYDM_PAUSE = BIT(0), PHYDM_RESUME = BIT(1) }; + +enum phydm_pause_level { + /* number of pause level can't exceed DM_DIG_MAX_PAUSE_TYPE */ + PHYDM_PAUSE_LEVEL_0 = 0, + PHYDM_PAUSE_LEVEL_1 = 1, + PHYDM_PAUSE_LEVEL_2 = 2, + PHYDM_PAUSE_LEVEL_3 = 3, + PHYDM_PAUSE_LEVEL_4 = 4, + PHYDM_PAUSE_LEVEL_5 = 5, + PHYDM_PAUSE_LEVEL_6 = 6, + PHYDM_PAUSE_LEVEL_7 = DM_DIG_MAX_PAUSE_TYPE /* maximum level */ +}; + +#define DM_DIG_THRESH_HIGH 40 +#define DM_DIG_THRESH_LOW 35 + +#define DM_FALSEALARM_THRESH_LOW 400 +#define DM_FALSEALARM_THRESH_HIGH 1000 + +#define DM_DIG_MAX_NIC 0x3e +#define DM_DIG_MIN_NIC 0x20 +#define DM_DIG_MAX_OF_MIN_NIC 0x3e + +#define DM_DIG_MAX_AP 0x3e +#define DM_DIG_MIN_AP 0x20 +#define DM_DIG_MAX_OF_MIN 0x2A /* 0x32 */ +#define DM_DIG_MIN_AP_DFS 0x20 + +#define DM_DIG_MAX_NIC_HP 0x46 +#define DM_DIG_MIN_NIC_HP 0x2e + +#define DM_DIG_MAX_AP_HP 0x42 +#define DM_DIG_MIN_AP_HP 0x30 + +/* vivi 92c&92d has different definition, 20110504 + * this is for 92c + */ +#define DM_DIG_FA_TH0 0x200 /* 0x20 */ + +#define DM_DIG_FA_TH1 0x300 +#define DM_DIG_FA_TH2 0x400 +/* this is for 92d */ +#define DM_DIG_FA_TH0_92D 0x100 +#define DM_DIG_FA_TH1_92D 0x400 +#define DM_DIG_FA_TH2_92D 0x600 + +#define DM_DIG_BACKOFF_MAX 12 +#define DM_DIG_BACKOFF_MIN -4 +#define DM_DIG_BACKOFF_DEFAULT 10 + +#define DM_DIG_FA_TH0_LPS 4 /* -> 4 in lps */ +#define DM_DIG_FA_TH1_LPS 15 /* -> 15 lps */ +#define DM_DIG_FA_TH2_LPS 30 /* -> 30 lps */ +#define RSSI_OFFSET_DIG 0x05 +#define LARGE_FA_TIMEOUT 60 + +void odm_change_dynamic_init_gain_thresh(void *dm_void, u32 dm_type, + u32 dm_value); + +void odm_write_dig(void *dm_void, u8 current_igi); + +void odm_pause_dig(void *dm_void, enum phydm_pause_type pause_type, + enum phydm_pause_level pause_level, u8 igi_value); + +void odm_dig_init(void *dm_void); + +void odm_DIG(void *dm_void); + +void odm_dig_by_rssi_lps(void *dm_void); + +void odm_false_alarm_counter_statistics(void *dm_void); + +void odm_pause_cck_packet_detection(void *dm_void, + enum phydm_pause_type pause_type, + enum phydm_pause_level pause_level, + u8 cck_pd_threshold); + +void odm_cck_packet_detection_thresh(void *dm_void); + +void odm_write_cck_cca_thres(void *dm_void, u8 cur_cck_cca_thres); + +bool phydm_dig_go_up_check(void *dm_void); + +#endif diff --git a/drivers/staging/rtlwifi/phydm/phydm_dynamic_rx_path.h b/drivers/staging/rtlwifi/phydm/phydm_dynamic_rx_path.h new file mode 100644 index 000000000000..9f3cb2468c02 --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/phydm_dynamic_rx_path.h @@ -0,0 +1,37 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __PHYDMDYMICRXPATH_H__ +#define __PHYDMDYMICRXPATH_H__ + +#define DYNAMIC_RX_PATH_VERSION "1.0" /*2016.07.15 Dino */ + +#define DRP_RSSI_TH 35 + +#define INIT_DRP_TIMMER 0 +#define CANCEL_DRP_TIMMER 1 +#define RELEASE_DRP_TIMMER 2 + +#endif diff --git a/drivers/staging/rtlwifi/phydm/phydm_dynamicbbpowersaving.c b/drivers/staging/rtlwifi/phydm/phydm_dynamicbbpowersaving.c new file mode 100644 index 000000000000..7661c499aeb1 --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/phydm_dynamicbbpowersaving.c @@ -0,0 +1,129 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +/* ************************************************************ + * include files + * *************************************************************/ +#include "mp_precomp.h" +#include "phydm_precomp.h" + +static inline void phydm_update_rf_state(struct phy_dm_struct *dm, + struct dyn_pwr_saving *dm_ps_table, + int _rssi_up_bound, + int _rssi_low_bound, + int _is_force_in_normal) +{ + if (_is_force_in_normal) { + dm_ps_table->cur_rf_state = rf_normal; + return; + } + + if (dm->rssi_min == 0xFF) { + dm_ps_table->cur_rf_state = RF_MAX; + return; + } + + if (dm_ps_table->pre_rf_state == rf_normal) { + if (dm->rssi_min >= _rssi_up_bound) + dm_ps_table->cur_rf_state = rf_save; + else + dm_ps_table->cur_rf_state = rf_normal; + } else { + if (dm->rssi_min <= _rssi_low_bound) + dm_ps_table->cur_rf_state = rf_normal; + else + dm_ps_table->cur_rf_state = rf_save; + } +} + +void odm_dynamic_bb_power_saving_init(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct dyn_pwr_saving *dm_ps_table = &dm->dm_ps_table; + + dm_ps_table->pre_cca_state = CCA_MAX; + dm_ps_table->cur_cca_state = CCA_MAX; + dm_ps_table->pre_rf_state = RF_MAX; + dm_ps_table->cur_rf_state = RF_MAX; + dm_ps_table->rssi_val_min = 0; + dm_ps_table->initialize = 0; +} + +void odm_rf_saving(void *dm_void, u8 is_force_in_normal) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct dyn_pwr_saving *dm_ps_table = &dm->dm_ps_table; + u8 rssi_up_bound = 30; + u8 rssi_low_bound = 25; + + if (dm->patch_id == 40) { /* RT_CID_819x_FUNAI_TV */ + rssi_up_bound = 50; + rssi_low_bound = 45; + } + if (dm_ps_table->initialize == 0) { + dm_ps_table->reg874 = + (odm_get_bb_reg(dm, 0x874, MASKDWORD) & 0x1CC000) >> 14; + dm_ps_table->regc70 = + (odm_get_bb_reg(dm, 0xc70, MASKDWORD) & BIT(3)) >> 3; + dm_ps_table->reg85c = + (odm_get_bb_reg(dm, 0x85c, MASKDWORD) & 0xFF000000) >> + 24; + dm_ps_table->rega74 = + (odm_get_bb_reg(dm, 0xa74, MASKDWORD) & 0xF000) >> 12; + /* Reg818 = phy_query_bb_reg(adapter, 0x818, MASKDWORD); */ + dm_ps_table->initialize = 1; + } + + phydm_update_rf_state(dm, dm_ps_table, rssi_up_bound, rssi_low_bound, + is_force_in_normal); + + if (dm_ps_table->pre_rf_state != dm_ps_table->cur_rf_state) { + if (dm_ps_table->cur_rf_state == rf_save) { + odm_set_bb_reg(dm, 0x874, 0x1C0000, + 0x2); /* reg874[20:18]=3'b010 */ + odm_set_bb_reg(dm, 0xc70, BIT(3), + 0); /* regc70[3]=1'b0 */ + odm_set_bb_reg(dm, 0x85c, 0xFF000000, + 0x63); /* reg85c[31:24]=0x63 */ + odm_set_bb_reg(dm, 0x874, 0xC000, + 0x2); /* reg874[15:14]=2'b10 */ + odm_set_bb_reg(dm, 0xa74, 0xF000, + 0x3); /* RegA75[7:4]=0x3 */ + odm_set_bb_reg(dm, 0x818, BIT(28), + 0x0); /* Reg818[28]=1'b0 */ + odm_set_bb_reg(dm, 0x818, BIT(28), + 0x1); /* Reg818[28]=1'b1 */ + } else { + odm_set_bb_reg(dm, 0x874, 0x1CC000, + dm_ps_table->reg874); + odm_set_bb_reg(dm, 0xc70, BIT(3), dm_ps_table->regc70); + odm_set_bb_reg(dm, 0x85c, 0xFF000000, + dm_ps_table->reg85c); + odm_set_bb_reg(dm, 0xa74, 0xF000, dm_ps_table->rega74); + odm_set_bb_reg(dm, 0x818, BIT(28), 0x0); + } + dm_ps_table->pre_rf_state = dm_ps_table->cur_rf_state; + } +} diff --git a/drivers/staging/rtlwifi/phydm/phydm_dynamicbbpowersaving.h b/drivers/staging/rtlwifi/phydm/phydm_dynamicbbpowersaving.h new file mode 100644 index 000000000000..e7394c475395 --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/phydm_dynamicbbpowersaving.h @@ -0,0 +1,50 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __PHYDMDYNAMICBBPOWERSAVING_H__ +#define __PHYDMDYNAMICBBPOWERSAVING_H__ + +#define DYNAMIC_BBPWRSAV_VERSION "1.1" + +struct dyn_pwr_saving { + u8 pre_cca_state; + u8 cur_cca_state; + + u8 pre_rf_state; + u8 cur_rf_state; + + int rssi_val_min; + + u8 initialize; + u32 reg874, regc70, reg85c, rega74; +}; + +#define dm_rf_saving odm_rf_saving + +void odm_rf_saving(void *dm_void, u8 is_force_in_normal); + +void odm_dynamic_bb_power_saving_init(void *dm_void); + +#endif diff --git a/drivers/staging/rtlwifi/phydm/phydm_dynamictxpower.c b/drivers/staging/rtlwifi/phydm/phydm_dynamictxpower.c new file mode 100644 index 000000000000..ebb43342b80b --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/phydm_dynamictxpower.c @@ -0,0 +1,102 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +/* ************************************************************ + * include files + * *************************************************************/ +#include "mp_precomp.h" +#include "phydm_precomp.h" + +void odm_dynamic_tx_power_init(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + + dm->last_dtp_lvl = tx_high_pwr_level_normal; + dm->dynamic_tx_high_power_lvl = tx_high_pwr_level_normal; + dm->tx_agc_ofdm_18_6 = + odm_get_bb_reg(dm, 0xC24, MASKDWORD); /*TXAGC {18M 12M 9M 6M}*/ +} + +void odm_dynamic_tx_power_save_power_index(void *dm_void) {} + +void odm_dynamic_tx_power_restore_power_index(void *dm_void) {} + +void odm_dynamic_tx_power_write_power_index(void *dm_void, u8 value) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + u8 index; + u32 power_index_reg[6] = {0xc90, 0xc91, 0xc92, 0xc98, 0xc99, 0xc9a}; + + for (index = 0; index < 6; index++) + odm_write_1byte(dm, power_index_reg[index], value); +} + +static void odm_dynamic_tx_power_nic_ce(void *dm_void) {} + +void odm_dynamic_tx_power(void *dm_void) +{ + /* */ + /* For AP/ADSL use struct rtl8192cd_priv* */ + /* For CE/NIC use struct void* */ + /* */ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + + if (!(dm->support_ability & ODM_BB_DYNAMIC_TXPWR)) + return; + /* 2011/09/29 MH In HW integration first stage, we provide 4 different + * handle to operate at the same time. + * In the stage2/3, we need to prive universal interface and merge all + * HW dynamic mechanism. + */ + switch (dm->support_platform) { + case ODM_WIN: + odm_dynamic_tx_power_nic(dm); + break; + case ODM_CE: + odm_dynamic_tx_power_nic_ce(dm); + break; + case ODM_AP: + odm_dynamic_tx_power_ap(dm); + break; + default: + break; + } +} + +void odm_dynamic_tx_power_nic(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + + if (!(dm->support_ability & ODM_BB_DYNAMIC_TXPWR)) + return; +} + +void odm_dynamic_tx_power_ap(void *dm_void + + ) +{ +} + +void odm_dynamic_tx_power_8821(void *dm_void, u8 *desc, u8 mac_id) {} diff --git a/drivers/staging/rtlwifi/phydm/phydm_dynamictxpower.h b/drivers/staging/rtlwifi/phydm/phydm_dynamictxpower.h new file mode 100644 index 000000000000..10bad1209db2 --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/phydm_dynamictxpower.h @@ -0,0 +1,64 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __PHYDMDYNAMICTXPOWER_H__ +#define __PHYDMDYNAMICTXPOWER_H__ + +/*#define DYNAMIC_TXPWR_VERSION "1.0"*/ +/*#define DYNAMIC_TXPWR_VERSION "1.3" */ /*2015.08.26, Add 8814 Dynamic TX pwr*/ +#define DYNAMIC_TXPWR_VERSION "1.4" /*2015.11.06,Add CE 8821A Dynamic TX pwr*/ + +#define TX_POWER_NEAR_FIELD_THRESH_LVL2 74 +#define TX_POWER_NEAR_FIELD_THRESH_LVL1 60 + +#define tx_high_pwr_level_normal 0 +#define tx_high_pwr_level_level1 1 +#define tx_high_pwr_level_level2 2 + +#define tx_high_pwr_level_bt1 3 +#define tx_high_pwr_level_bt2 4 +#define tx_high_pwr_level_15 5 +#define tx_high_pwr_level_35 6 +#define tx_high_pwr_level_50 7 +#define tx_high_pwr_level_70 8 +#define tx_high_pwr_level_100 9 + +void odm_dynamic_tx_power_init(void *dm_void); + +void odm_dynamic_tx_power_restore_power_index(void *dm_void); + +void odm_dynamic_tx_power_nic(void *dm_void); + +void odm_dynamic_tx_power_save_power_index(void *dm_void); + +void odm_dynamic_tx_power_write_power_index(void *dm_void, u8 value); + +void odm_dynamic_tx_power_8821(void *dm_void, u8 *desc, u8 mac_id); + +void odm_dynamic_tx_power(void *dm_void); + +void odm_dynamic_tx_power_ap(void *dm_void); + +#endif diff --git a/drivers/staging/rtlwifi/phydm/phydm_edcaturbocheck.c b/drivers/staging/rtlwifi/phydm/phydm_edcaturbocheck.c new file mode 100644 index 000000000000..753a9b9834e4 --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/phydm_edcaturbocheck.c @@ -0,0 +1,139 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +/* ************************************************************ + * include files + * *************************************************************/ +#include "mp_precomp.h" +#include "phydm_precomp.h" + +void odm_edca_turbo_init(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + + dm->dm_edca_table.is_current_turbo_edca = false; + dm->dm_edca_table.is_cur_rdl_state = false; + + ODM_RT_TRACE(dm, ODM_COMP_EDCA_TURBO, "Orginial VO PARAM: 0x%x\n", + odm_read_4byte(dm, ODM_EDCA_VO_PARAM)); + ODM_RT_TRACE(dm, ODM_COMP_EDCA_TURBO, "Orginial VI PARAM: 0x%x\n", + odm_read_4byte(dm, ODM_EDCA_VI_PARAM)); + ODM_RT_TRACE(dm, ODM_COMP_EDCA_TURBO, "Orginial BE PARAM: 0x%x\n", + odm_read_4byte(dm, ODM_EDCA_BE_PARAM)); + ODM_RT_TRACE(dm, ODM_COMP_EDCA_TURBO, "Orginial BK PARAM: 0x%x\n", + odm_read_4byte(dm, ODM_EDCA_BK_PARAM)); + +} /* ODM_InitEdcaTurbo */ + +void odm_edca_turbo_check(void *dm_void) +{ + /* For AP/ADSL use struct rtl8192cd_priv* */ + /* For CE/NIC use struct void* */ + + /* 2011/09/29 MH In HW integration first stage, we provide 4 different + * handle to operate at the same time. + * In the stage2/3, we need to prive universal interface and merge all + * HW dynamic mechanism. + */ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + + ODM_RT_TRACE(dm, ODM_COMP_EDCA_TURBO, + "%s========================>\n", __func__); + + if (!(dm->support_ability & ODM_MAC_EDCA_TURBO)) + return; + + switch (dm->support_platform) { + case ODM_WIN: + + break; + + case ODM_CE: + odm_edca_turbo_check_ce(dm); + break; + } + ODM_RT_TRACE(dm, ODM_COMP_EDCA_TURBO, + "<========================%s\n", __func__); + +} /* odm_CheckEdcaTurbo */ + +void odm_edca_turbo_check_ce(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct rtl_priv *rtlpriv = (struct rtl_priv *)dm->adapter; + u64 cur_txok_cnt = 0; + u64 cur_rxok_cnt = 0; + u32 edca_be_ul = 0x5ea42b; + u32 edca_be_dl = 0x5ea42b; + u32 edca_be = 0x5ea42b; + bool is_cur_rdlstate; + bool edca_turbo_on = false; + + if (dm->wifi_test) + return; + + if (!dm->is_linked) { + rtlpriv->dm.is_any_nonbepkts = false; + return; + } + + if (rtlpriv->dm.dbginfo.num_non_be_pkt > 0x100) + rtlpriv->dm.is_any_nonbepkts = true; + rtlpriv->dm.dbginfo.num_non_be_pkt = 0; + + cur_txok_cnt = rtlpriv->stats.txbytesunicast_inperiod; + cur_rxok_cnt = rtlpriv->stats.rxbytesunicast_inperiod; + + /*b_bias_on_rx = false;*/ + edca_turbo_on = ((!rtlpriv->dm.is_any_nonbepkts) && + (!rtlpriv->dm.disable_framebursting)) ? + true : + false; + + if (rtlpriv->mac80211.mode == WIRELESS_MODE_B) + goto label_exit; + + if (edca_turbo_on) { + is_cur_rdlstate = + (cur_rxok_cnt > cur_txok_cnt * 4) ? true : false; + + edca_be = is_cur_rdlstate ? edca_be_dl : edca_be_ul; + rtl_write_dword(rtlpriv, REG_EDCA_BE_PARAM_8822B, edca_be); + rtlpriv->dm.is_cur_rdlstate = is_cur_rdlstate; + rtlpriv->dm.current_turbo_edca = true; + } else { + if (rtlpriv->dm.current_turbo_edca) { + u8 tmp = AC0_BE; + + rtlpriv->cfg->ops->set_hw_reg(rtlpriv->hw, + HW_VAR_AC_PARAM, + (u8 *)(&tmp)); + rtlpriv->dm.current_turbo_edca = false; + } + } + +label_exit: + rtlpriv->dm.is_any_nonbepkts = false; +} diff --git a/drivers/staging/rtlwifi/phydm/phydm_edcaturbocheck.h b/drivers/staging/rtlwifi/phydm/phydm_edcaturbocheck.h new file mode 100644 index 000000000000..5845b108a001 --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/phydm_edcaturbocheck.h @@ -0,0 +1,44 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __PHYDMEDCATURBOCHECK_H__ +#define __PHYDMEDCATURBOCHECK_H__ + +/*#define EDCATURBO_VERSION "2.1"*/ +#define EDCATURBO_VERSION "2.3" /*2015.07.29 by YuChen*/ + +struct edca_turbo { + bool is_current_turbo_edca; + bool is_cur_rdl_state; + + u32 prv_traffic_idx; /* edca turbo */ +}; + +void odm_edca_turbo_check(void *dm_void); +void odm_edca_turbo_init(void *dm_void); + +void odm_edca_turbo_check_ce(void *dm_void); + +#endif diff --git a/drivers/staging/rtlwifi/phydm/phydm_features.h b/drivers/staging/rtlwifi/phydm/phydm_features.h new file mode 100644 index 000000000000..37f6f0cd7235 --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/phydm_features.h @@ -0,0 +1,33 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __PHYDM_FEATURES_H__ +#define __PHYDM_FEATURES + +/*phydm debyg report & tools*/ + +/*Antenna Diversity*/ + +#endif diff --git a/drivers/staging/rtlwifi/phydm/phydm_hwconfig.c b/drivers/staging/rtlwifi/phydm/phydm_hwconfig.c new file mode 100644 index 000000000000..0a1f11a926e4 --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/phydm_hwconfig.c @@ -0,0 +1,1928 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +/* ************************************************************ + * include files + * *************************************************************/ + +#include "mp_precomp.h" +#include "phydm_precomp.h" + +#define READ_AND_CONFIG_MP(ic, txt) (odm_read_and_config_mp_##ic##txt(dm)) +#define READ_AND_CONFIG_TC(ic, txt) (odm_read_and_config_tc_##ic##txt(dm)) + +#define READ_AND_CONFIG READ_AND_CONFIG_MP + +#define READ_FIRMWARE_MP(ic, txt) \ + (odm_read_firmware_mp_##ic##txt(dm, p_firmware, size)) +#define READ_FIRMWARE_TC(ic, txt) \ + (odm_read_firmware_tc_##ic##txt(dm, p_firmware, size)) + +#define READ_FIRMWARE READ_FIRMWARE_MP + +#define GET_VERSION_MP(ic, txt) (odm_get_version_mp_##ic##txt()) +#define GET_VERSION_TC(ic, txt) (odm_get_version_tc_##ic##txt()) + +#define GET_VERSION(ic, txt) GET_VERSION_MP(ic, txt) + +static u32 phydm_process_rssi_pwdb(struct phy_dm_struct *dm, + struct rtl_sta_info *entry, + struct dm_per_pkt_info *pktinfo, + u32 undecorated_smoothed_ofdm, + u32 undecorated_smoothed_cck) +{ + u32 weighting = 0, undecorated_smoothed_pwdb; + /* 2011.07.28 LukeLee: modified to prevent unstable CCK RSSI */ + + if (entry->rssi_stat.ofdm_pkt == + 64) { /* speed up when all packets are OFDM*/ + undecorated_smoothed_pwdb = undecorated_smoothed_ofdm; + ODM_RT_TRACE(dm, ODM_COMP_RSSI_MONITOR, + "PWDB_0[%d] = (( %d ))\n", pktinfo->station_id, + undecorated_smoothed_cck); + } else { + if (entry->rssi_stat.valid_bit < 64) + entry->rssi_stat.valid_bit++; + + if (entry->rssi_stat.valid_bit == 64) { + weighting = ((entry->rssi_stat.ofdm_pkt) > 4) ? + 64 : + (entry->rssi_stat.ofdm_pkt << 4); + undecorated_smoothed_pwdb = + (weighting * undecorated_smoothed_ofdm + + (64 - weighting) * undecorated_smoothed_cck) >> + 6; + ODM_RT_TRACE(dm, ODM_COMP_RSSI_MONITOR, + "PWDB_1[%d] = (( %d )), W = (( %d ))\n", + pktinfo->station_id, + undecorated_smoothed_cck, weighting); + } else { + if (entry->rssi_stat.valid_bit != 0) + undecorated_smoothed_pwdb = + (entry->rssi_stat.ofdm_pkt * + undecorated_smoothed_ofdm + + (entry->rssi_stat.valid_bit - + entry->rssi_stat.ofdm_pkt) * + undecorated_smoothed_cck) / + entry->rssi_stat.valid_bit; + else + undecorated_smoothed_pwdb = 0; + + ODM_RT_TRACE( + dm, ODM_COMP_RSSI_MONITOR, + "PWDB_2[%d] = (( %d )), ofdm_pkt = (( %d )), Valid_Bit = (( %d ))\n", + pktinfo->station_id, undecorated_smoothed_cck, + entry->rssi_stat.ofdm_pkt, + entry->rssi_stat.valid_bit); + } + } + + return undecorated_smoothed_pwdb; +} + +static u32 phydm_process_rssi_cck(struct phy_dm_struct *dm, + struct dm_phy_status_info *phy_info, + struct rtl_sta_info *entry, + u32 undecorated_smoothed_cck) +{ + u32 rssi_ave; + u8 i; + + rssi_ave = phy_info->rx_pwdb_all; + dm->rssi_a = (u8)phy_info->rx_pwdb_all; + dm->rssi_b = 0xFF; + dm->rssi_c = 0xFF; + dm->rssi_d = 0xFF; + + if (entry->rssi_stat.cck_pkt <= 63) + entry->rssi_stat.cck_pkt++; + + /* 1 Process CCK RSSI */ + if (undecorated_smoothed_cck <= 0) { /* initialize */ + undecorated_smoothed_cck = phy_info->rx_pwdb_all; + entry->rssi_stat.cck_sum_power = + (u16)phy_info->rx_pwdb_all; /*reset*/ + entry->rssi_stat.cck_pkt = 1; /*reset*/ + ODM_RT_TRACE(dm, ODM_COMP_RSSI_MONITOR, "CCK_INIT: (( %d ))\n", + undecorated_smoothed_cck); + } else if (entry->rssi_stat.cck_pkt <= CCK_RSSI_INIT_COUNT) { + entry->rssi_stat.cck_sum_power = + entry->rssi_stat.cck_sum_power + + (u16)phy_info->rx_pwdb_all; + undecorated_smoothed_cck = entry->rssi_stat.cck_sum_power / + entry->rssi_stat.cck_pkt; + + ODM_RT_TRACE( + dm, ODM_COMP_RSSI_MONITOR, + "CCK_0: (( %d )), SumPow = (( %d )), cck_pkt = (( %d ))\n", + undecorated_smoothed_cck, + entry->rssi_stat.cck_sum_power, + entry->rssi_stat.cck_pkt); + } else { + if (phy_info->rx_pwdb_all > (u32)undecorated_smoothed_cck) { + undecorated_smoothed_cck = + (((undecorated_smoothed_cck) * + (RX_SMOOTH_FACTOR - 1)) + + (phy_info->rx_pwdb_all)) / + (RX_SMOOTH_FACTOR); + undecorated_smoothed_cck = undecorated_smoothed_cck + 1; + ODM_RT_TRACE(dm, ODM_COMP_RSSI_MONITOR, + "CCK_1: (( %d ))\n", + undecorated_smoothed_cck); + } else { + undecorated_smoothed_cck = + (((undecorated_smoothed_cck) * + (RX_SMOOTH_FACTOR - 1)) + + (phy_info->rx_pwdb_all)) / + (RX_SMOOTH_FACTOR); + ODM_RT_TRACE(dm, ODM_COMP_RSSI_MONITOR, + "CCK_2: (( %d ))\n", + undecorated_smoothed_cck); + } + } + + i = 63; + entry->rssi_stat.ofdm_pkt -= + (u8)((entry->rssi_stat.packet_map >> i) & BIT(0)); + entry->rssi_stat.packet_map = entry->rssi_stat.packet_map << 1; + return undecorated_smoothed_cck; +} + +static u32 phydm_process_rssi_ofdm(struct phy_dm_struct *dm, + struct dm_phy_status_info *phy_info, + struct rtl_sta_info *entry, + u32 undecorated_smoothed_ofdm) +{ + u32 rssi_ave; + u8 rssi_max, rssi_min, i; + + if (dm->support_ic_type & (ODM_RTL8814A | ODM_RTL8822B)) { + u8 rx_count = 0; + u32 rssi_linear = 0; + + if (dm->rx_ant_status & ODM_RF_A) { + dm->rssi_a = phy_info->rx_mimo_signal_strength + [ODM_RF_PATH_A]; + rx_count++; + rssi_linear += odm_convert_to_linear( + phy_info->rx_mimo_signal_strength + [ODM_RF_PATH_A]); + } else { + dm->rssi_a = 0; + } + + if (dm->rx_ant_status & ODM_RF_B) { + dm->rssi_b = phy_info->rx_mimo_signal_strength + [ODM_RF_PATH_B]; + rx_count++; + rssi_linear += odm_convert_to_linear( + phy_info->rx_mimo_signal_strength + [ODM_RF_PATH_B]); + } else { + dm->rssi_b = 0; + } + + if (dm->rx_ant_status & ODM_RF_C) { + dm->rssi_c = phy_info->rx_mimo_signal_strength + [ODM_RF_PATH_C]; + rx_count++; + rssi_linear += odm_convert_to_linear( + phy_info->rx_mimo_signal_strength + [ODM_RF_PATH_C]); + } else { + dm->rssi_c = 0; + } + + if (dm->rx_ant_status & ODM_RF_D) { + dm->rssi_d = phy_info->rx_mimo_signal_strength + [ODM_RF_PATH_D]; + rx_count++; + rssi_linear += odm_convert_to_linear( + phy_info->rx_mimo_signal_strength + [ODM_RF_PATH_D]); + } else { + dm->rssi_d = 0; + } + + /* Calculate average RSSI */ + switch (rx_count) { + case 2: + rssi_linear = (rssi_linear >> 1); + break; + case 3: + /* rssi_linear/3 ~ rssi_linear*11/32 */ + rssi_linear = ((rssi_linear) + (rssi_linear << 1) + + (rssi_linear << 3)) >> + 5; + break; + case 4: + rssi_linear = (rssi_linear >> 2); + break; + } + + rssi_ave = odm_convert_to_db(rssi_linear); + } else { + if (phy_info->rx_mimo_signal_strength[ODM_RF_PATH_B] == 0) { + rssi_ave = phy_info->rx_mimo_signal_strength + [ODM_RF_PATH_A]; + dm->rssi_a = phy_info->rx_mimo_signal_strength + [ODM_RF_PATH_A]; + dm->rssi_b = 0; + } else { + dm->rssi_a = phy_info->rx_mimo_signal_strength + [ODM_RF_PATH_A]; + dm->rssi_b = phy_info->rx_mimo_signal_strength + [ODM_RF_PATH_B]; + + if (phy_info->rx_mimo_signal_strength[ODM_RF_PATH_A] > + phy_info->rx_mimo_signal_strength[ODM_RF_PATH_B]) { + rssi_max = phy_info->rx_mimo_signal_strength + [ODM_RF_PATH_A]; + rssi_min = phy_info->rx_mimo_signal_strength + [ODM_RF_PATH_B]; + } else { + rssi_max = phy_info->rx_mimo_signal_strength + [ODM_RF_PATH_B]; + rssi_min = phy_info->rx_mimo_signal_strength + [ODM_RF_PATH_A]; + } + if ((rssi_max - rssi_min) < 3) + rssi_ave = rssi_max; + else if ((rssi_max - rssi_min) < 6) + rssi_ave = rssi_max - 1; + else if ((rssi_max - rssi_min) < 10) + rssi_ave = rssi_max - 2; + else + rssi_ave = rssi_max - 3; + } + } + + /* 1 Process OFDM RSSI */ + if (undecorated_smoothed_ofdm <= 0) { /* initialize */ + undecorated_smoothed_ofdm = phy_info->rx_pwdb_all; + ODM_RT_TRACE(dm, ODM_COMP_RSSI_MONITOR, "OFDM_INIT: (( %d ))\n", + undecorated_smoothed_ofdm); + } else { + if (phy_info->rx_pwdb_all > (u32)undecorated_smoothed_ofdm) { + undecorated_smoothed_ofdm = + (((undecorated_smoothed_ofdm) * + (RX_SMOOTH_FACTOR - 1)) + + (rssi_ave)) / + (RX_SMOOTH_FACTOR); + undecorated_smoothed_ofdm = + undecorated_smoothed_ofdm + 1; + ODM_RT_TRACE(dm, ODM_COMP_RSSI_MONITOR, + "OFDM_1: (( %d ))\n", + undecorated_smoothed_ofdm); + } else { + undecorated_smoothed_ofdm = + (((undecorated_smoothed_ofdm) * + (RX_SMOOTH_FACTOR - 1)) + + (rssi_ave)) / + (RX_SMOOTH_FACTOR); + ODM_RT_TRACE(dm, ODM_COMP_RSSI_MONITOR, + "OFDM_2: (( %d ))\n", + undecorated_smoothed_ofdm); + } + } + + if (entry->rssi_stat.ofdm_pkt != 64) { + i = 63; + entry->rssi_stat.ofdm_pkt -= + (u8)(((entry->rssi_stat.packet_map >> i) & BIT(0)) - 1); + } + + entry->rssi_stat.packet_map = + (entry->rssi_stat.packet_map << 1) | BIT(0); + return undecorated_smoothed_ofdm; +} + +static u8 odm_evm_db_to_percentage(s8); +static u8 odm_evm_dbm_jaguar_series(s8); + +static inline u32 phydm_get_rssi_average(struct phy_dm_struct *dm, + struct dm_phy_status_info *phy_info) +{ + u8 rssi_max = 0, rssi_min = 0; + + dm->rssi_a = phy_info->rx_mimo_signal_strength[ODM_RF_PATH_A]; + dm->rssi_b = phy_info->rx_mimo_signal_strength[ODM_RF_PATH_B]; + + if (phy_info->rx_mimo_signal_strength[ODM_RF_PATH_A] > + phy_info->rx_mimo_signal_strength[ODM_RF_PATH_B]) { + rssi_max = phy_info->rx_mimo_signal_strength[ODM_RF_PATH_A]; + rssi_min = phy_info->rx_mimo_signal_strength[ODM_RF_PATH_B]; + } else { + rssi_max = phy_info->rx_mimo_signal_strength[ODM_RF_PATH_B]; + rssi_min = phy_info->rx_mimo_signal_strength[ODM_RF_PATH_A]; + } + if ((rssi_max - rssi_min) < 3) + return rssi_max; + else if ((rssi_max - rssi_min) < 6) + return rssi_max - 1; + else if ((rssi_max - rssi_min) < 10) + return rssi_max - 2; + else + return rssi_max - 3; +} + +static inline u8 phydm_get_evm_dbm(u8 i, u8 EVM, + struct phy_status_rpt_8812 *phy_sta_rpt, + struct dm_phy_status_info *phy_info) +{ + if (i < ODM_RF_PATH_C) + return odm_evm_dbm_jaguar_series(phy_sta_rpt->rxevm[i]); + else + return odm_evm_dbm_jaguar_series(phy_sta_rpt->rxevm_cd[i - 2]); + /*RT_DISP(FRX, RX_PHY_SQ, ("RXRATE=%x RXEVM=%x EVM=%s%d\n",*/ + /*pktinfo->data_rate, phy_sta_rpt->rxevm[i], "%", EVM));*/ +} + +static inline u8 phydm_get_odm_evm(u8 i, struct dm_per_pkt_info *pktinfo, + struct phy_status_rpt_8812 *phy_sta_rpt) +{ + u8 evm = 0; + + if (pktinfo->data_rate >= ODM_RATE6M && + pktinfo->data_rate <= ODM_RATE54M) { + if (i == ODM_RF_PATH_A) { + evm = odm_evm_db_to_percentage( + (phy_sta_rpt->sigevm)); /*dbm*/ + evm += 20; + if (evm > 100) + evm = 100; + } + } else { + if (i < ODM_RF_PATH_C) { + if (phy_sta_rpt->rxevm[i] == -128) + phy_sta_rpt->rxevm[i] = -25; + evm = odm_evm_db_to_percentage( + (phy_sta_rpt->rxevm[i])); /*dbm*/ + } else { + if (phy_sta_rpt->rxevm_cd[i - 2] == -128) + phy_sta_rpt->rxevm_cd[i - 2] = -25; + evm = odm_evm_db_to_percentage( + (phy_sta_rpt->rxevm_cd[i - 2])); /*dbm*/ + } + } + + return evm; +} + +static inline s8 phydm_get_rx_pwr(u8 LNA_idx, u8 VGA_idx, u8 cck_highpwr) +{ + switch (LNA_idx) { + case 7: + if (VGA_idx <= 27) + return -100 + 2 * (27 - VGA_idx); /*VGA_idx = 27~2*/ + else + return -100; + break; + case 6: + return -48 + 2 * (2 - VGA_idx); /*VGA_idx = 2~0*/ + case 5: + return -42 + 2 * (7 - VGA_idx); /*VGA_idx = 7~5*/ + case 4: + return -36 + 2 * (7 - VGA_idx); /*VGA_idx = 7~4*/ + case 3: + return -24 + 2 * (7 - VGA_idx); /*VGA_idx = 7~0*/ + case 2: + if (cck_highpwr) + return -12 + 2 * (5 - VGA_idx); /*VGA_idx = 5~0*/ + else + return -6 + 2 * (5 - VGA_idx); + break; + case 1: + return 8 - 2 * VGA_idx; + case 0: + return 14 - 2 * VGA_idx; + default: + break; + } + return 0; +} + +static inline u8 phydm_adjust_pwdb(u8 cck_highpwr, u8 pwdb_all) +{ + if (!cck_highpwr) { + if (pwdb_all >= 80) + return ((pwdb_all - 80) << 1) + ((pwdb_all - 80) >> 1) + + 80; + else if ((pwdb_all <= 78) && (pwdb_all >= 20)) + return pwdb_all + 3; + if (pwdb_all > 100) + return 100; + } + return pwdb_all; +} + +static inline u8 +phydm_get_signal_quality_8812(struct dm_phy_status_info *phy_info, + struct phy_dm_struct *dm, + struct phy_status_rpt_8812 *phy_sta_rpt) +{ + u8 sq_rpt; + + if (phy_info->rx_pwdb_all > 40 && !dm->is_in_hct_test) + return 100; + + sq_rpt = phy_sta_rpt->pwdb_all; + + if (sq_rpt > 64) + return 0; + else if (sq_rpt < 20) + return 100; + else + return ((64 - sq_rpt) * 100) / 44; +} + +static inline u8 +phydm_get_signal_quality_8192(struct dm_phy_status_info *phy_info, + struct phy_dm_struct *dm, + struct phy_status_rpt_8192cd *phy_sta_rpt) +{ + u8 sq_rpt; + + if (phy_info->rx_pwdb_all > 40 && !dm->is_in_hct_test) + return 100; + + sq_rpt = phy_sta_rpt->cck_sig_qual_ofdm_pwdb_all; + + if (sq_rpt > 64) + return 0; + else if (sq_rpt < 20) + return 100; + else + return ((64 - sq_rpt) * 100) / 44; +} + +static u8 odm_query_rx_pwr_percentage(s8 ant_power) +{ + if ((ant_power <= -100) || (ant_power >= 20)) + return 0; + else if (ant_power >= 0) + return 100; + else + return 100 + ant_power; +} + +/* + * 2012/01/12 MH MOve some signal strength smooth method to MP HAL layer. + * IF other SW team do not support the feature, remove this section.?? + */ + +s32 odm_signal_scale_mapping(struct phy_dm_struct *dm, s32 curr_sig) +{ + { + return curr_sig; + } +} + +static u8 odm_sq_process_patch_rt_cid_819x_lenovo(struct phy_dm_struct *dm, + u8 is_cck_rate, u8 pwdb_all, + u8 path, u8 RSSI) +{ + u8 sq = 0; + return sq; +} + +static u8 odm_evm_db_to_percentage(s8 value) +{ + /* -33dB~0dB to 0%~99% */ + s8 ret_val; + + ret_val = value; + ret_val /= 2; + + if (ret_val >= 0) + ret_val = 0; + + if (ret_val <= -33) + ret_val = -33; + + ret_val = 0 - ret_val; + ret_val *= 3; + + if (ret_val == 99) + ret_val = 100; + + return (u8)ret_val; +} + +static u8 odm_evm_dbm_jaguar_series(s8 value) +{ + s8 ret_val = value; + + /* -33dB~0dB to 33dB ~ 0dB */ + if (ret_val == -128) + ret_val = 127; + else if (ret_val < 0) + ret_val = 0 - ret_val; + + ret_val = ret_val >> 1; + return (u8)ret_val; +} + +static s16 odm_cfo(s8 value) +{ + s16 ret_val; + + if (value < 0) { + ret_val = 0 - value; + ret_val = (ret_val << 1) + (ret_val >> 1); /* *2.5~=312.5/2^7 */ + ret_val = + ret_val | BIT(12); /* set bit12 as 1 for negative cfo */ + } else { + ret_val = value; + ret_val = (ret_val << 1) + (ret_val >> 1); /* *2.5~=312.5/2^7 */ + } + return ret_val; +} + +static u8 phydm_rate_to_num_ss(struct phy_dm_struct *dm, u8 data_rate) +{ + u8 num_ss = 1; + + if (data_rate <= ODM_RATE54M) + num_ss = 1; + else if (data_rate <= ODM_RATEMCS31) + num_ss = ((data_rate - ODM_RATEMCS0) >> 3) + 1; + else if (data_rate <= ODM_RATEVHTSS1MCS9) + num_ss = 1; + else if (data_rate <= ODM_RATEVHTSS2MCS9) + num_ss = 2; + else if (data_rate <= ODM_RATEVHTSS3MCS9) + num_ss = 3; + else if (data_rate <= ODM_RATEVHTSS4MCS9) + num_ss = 4; + + return num_ss; +} + +static void odm_rx_phy_status92c_series_parsing( + struct phy_dm_struct *dm, struct dm_phy_status_info *phy_info, + u8 *phy_status, struct dm_per_pkt_info *pktinfo) +{ + u8 i, max_spatial_stream; + s8 rx_pwr[4], rx_pwr_all = 0; + u8 EVM, pwdb_all = 0, pwdb_all_bt; + u8 RSSI, total_rssi = 0; + bool is_cck_rate = false; + u8 rf_rx_num = 0; + u8 LNA_idx = 0; + u8 VGA_idx = 0; + u8 cck_agc_rpt; + u8 num_ss; + struct phy_status_rpt_8192cd *phy_sta_rpt = + (struct phy_status_rpt_8192cd *)phy_status; + + is_cck_rate = (pktinfo->data_rate <= ODM_RATE11M) ? true : false; + + if (pktinfo->is_to_self) + dm->curr_station_id = pktinfo->station_id; + + phy_info->rx_mimo_signal_quality[ODM_RF_PATH_A] = -1; + phy_info->rx_mimo_signal_quality[ODM_RF_PATH_B] = -1; + + if (is_cck_rate) { + dm->phy_dbg_info.num_qry_phy_status_cck++; + cck_agc_rpt = phy_sta_rpt->cck_agc_rpt_ofdm_cfosho_a; + + if (dm->support_ic_type & (ODM_RTL8703B)) { + } else { /*3 bit LNA*/ + + LNA_idx = ((cck_agc_rpt & 0xE0) >> 5); + VGA_idx = (cck_agc_rpt & 0x1F); + } + + ODM_RT_TRACE( + dm, ODM_COMP_RSSI_MONITOR, + "ext_lna_gain (( %d )), LNA_idx: (( 0x%x )), VGA_idx: (( 0x%x )), rx_pwr_all: (( %d ))\n", + dm->ext_lna_gain, LNA_idx, VGA_idx, rx_pwr_all); + + if (dm->board_type & ODM_BOARD_EXT_LNA) + rx_pwr_all -= dm->ext_lna_gain; + + pwdb_all = odm_query_rx_pwr_percentage(rx_pwr_all); + + if (pktinfo->is_to_self) { + dm->cck_lna_idx = LNA_idx; + dm->cck_vga_idx = VGA_idx; + } + phy_info->rx_pwdb_all = pwdb_all; + + phy_info->bt_rx_rssi_percentage = pwdb_all; + phy_info->recv_signal_power = rx_pwr_all; + /* (3) Get Signal Quality (EVM) */ + { + u8 sq; + + sq = phydm_get_signal_quality_8192(phy_info, dm, + phy_sta_rpt); + phy_info->signal_quality = sq; + phy_info->rx_mimo_signal_quality[ODM_RF_PATH_A] = sq; + phy_info->rx_mimo_signal_quality[ODM_RF_PATH_B] = -1; + } + + for (i = ODM_RF_PATH_A; i < ODM_RF_PATH_MAX; i++) { + if (i == 0) + phy_info->rx_mimo_signal_strength[0] = pwdb_all; + else + phy_info->rx_mimo_signal_strength[1] = 0; + } + } else { /* 2 is OFDM rate */ + dm->phy_dbg_info.num_qry_phy_status_ofdm++; + + /* */ + /* (1)Get RSSI for HT rate */ + /* */ + + for (i = ODM_RF_PATH_A; i < ODM_RF_PATH_MAX; i++) { + /* 2008/01/30 MH we will judge RF RX path now. */ + if (dm->rf_path_rx_enable & BIT(i)) + rf_rx_num++; + /* else */ + /* continue; */ + + rx_pwr[i] = + ((phy_sta_rpt->path_agc[i].gain & 0x3F) * 2) - + 110; + + if (pktinfo->is_to_self) { + dm->ofdm_agc_idx[i] = + (phy_sta_rpt->path_agc[i].gain & 0x3F); + /**/ + } + + phy_info->rx_pwr[i] = rx_pwr[i]; + + /* Translate DBM to percentage. */ + RSSI = odm_query_rx_pwr_percentage(rx_pwr[i]); + total_rssi += RSSI; + + phy_info->rx_mimo_signal_strength[i] = (u8)RSSI; + + /* Get Rx snr value in DB */ + dm->phy_dbg_info.rx_snr_db[i] = + (s32)(phy_sta_rpt->path_rxsnr[i] / 2); + phy_info->rx_snr[i] = dm->phy_dbg_info.rx_snr_db[i]; + + /* Record Signal Strength for next packet */ + /* if(pktinfo->is_packet_match_bssid) */ + { + } + } + + /* */ + /* (2)PWDB, Average PWDB calcuated by hardware (for RA) */ + /* */ + rx_pwr_all = (((phy_sta_rpt->cck_sig_qual_ofdm_pwdb_all) >> 1) & + 0x7f) - + 110; + + pwdb_all = odm_query_rx_pwr_percentage(rx_pwr_all); + pwdb_all_bt = pwdb_all; + + phy_info->rx_pwdb_all = pwdb_all; + phy_info->bt_rx_rssi_percentage = pwdb_all_bt; + phy_info->rx_power = rx_pwr_all; + phy_info->recv_signal_power = rx_pwr_all; + + if ((dm->support_platform == ODM_WIN) && (dm->patch_id == 19)) { + /* do nothing */ + } else if ((dm->support_platform == ODM_WIN) && + (dm->patch_id == 25)) { + /* do nothing */ + } else { /* mgnt_info->customer_id != RT_CID_819X_LENOVO */ + /* */ + /* (3)EVM of HT rate */ + /* */ + if (pktinfo->data_rate >= ODM_RATEMCS8 && + pktinfo->data_rate <= ODM_RATEMCS15) { + /* both spatial stream make sense */ + max_spatial_stream = 2; + } else { + /* only spatial stream 1 makes sense */ + max_spatial_stream = 1; + } + + for (i = 0; i < max_spatial_stream; i++) { + /*Don't use shift operation like "rx_evmX >>= 1" + *because the compilor of free build environment + *fill most significant bit to "zero" when doing + *shifting operation which may change a negative + *value to positive one, then the dbm value + *(which is supposed to be negative) is not + *correct anymore. + */ + EVM = odm_evm_db_to_percentage( + (phy_sta_rpt + ->stream_rxevm[i])); /* dbm */ + + /* Fill value in RFD, Get the first spatial + * stream only + */ + if (i == ODM_RF_PATH_A) + phy_info->signal_quality = + (u8)(EVM & 0xff); + phy_info->rx_mimo_signal_quality[i] = + (u8)(EVM & 0xff); + } + } + + num_ss = phydm_rate_to_num_ss(dm, pktinfo->data_rate); + odm_parsing_cfo(dm, pktinfo, phy_sta_rpt->path_cfotail, num_ss); + } + /* UI BSS List signal strength(in percentage), make it good looking, + * from 0~100. + */ + /* It is assigned to the BSS List in GetValueFromBeaconOrProbeRsp(). */ + if (is_cck_rate) { + phy_info->signal_strength = (u8)( + odm_signal_scale_mapping(dm, pwdb_all)); /*pwdb_all;*/ + } else { + if (rf_rx_num != 0) { + phy_info->signal_strength = + (u8)(odm_signal_scale_mapping(dm, total_rssi /= + rf_rx_num)); + } + } + + /* For 92C/92D HW (Hybrid) Antenna Diversity */ +} + +static void +odm_rx_phy_bw_jaguar_series_parsing(struct dm_phy_status_info *phy_info, + struct dm_per_pkt_info *pktinfo, + struct phy_status_rpt_8812 *phy_sta_rpt) +{ + if (pktinfo->data_rate <= ODM_RATE54M) { + switch (phy_sta_rpt->r_RFMOD) { + case 1: + if (phy_sta_rpt->sub_chnl == 0) + phy_info->band_width = 1; + else + phy_info->band_width = 0; + break; + + case 2: + if (phy_sta_rpt->sub_chnl == 0) + phy_info->band_width = 2; + else if (phy_sta_rpt->sub_chnl == 9 || + phy_sta_rpt->sub_chnl == 10) + phy_info->band_width = 1; + else + phy_info->band_width = 0; + break; + + default: + case 0: + phy_info->band_width = 0; + break; + } + } +} + +static void odm_rx_phy_status_jaguar_series_parsing( + struct phy_dm_struct *dm, struct dm_phy_status_info *phy_info, + u8 *phy_status, struct dm_per_pkt_info *pktinfo) +{ + u8 i, max_spatial_stream; + s8 rx_pwr[4], rx_pwr_all = 0; + u8 EVM = 0, evm_dbm, pwdb_all = 0, pwdb_all_bt; + u8 RSSI, avg_rssi = 0, best_rssi = 0, second_rssi = 0; + u8 is_cck_rate = 0; + u8 rf_rx_num = 0; + u8 cck_highpwr = 0; + u8 LNA_idx, VGA_idx; + struct phy_status_rpt_8812 *phy_sta_rpt = + (struct phy_status_rpt_8812 *)phy_status; + struct fast_antenna_training *fat_tab = &dm->dm_fat_table; + u8 num_ss; + + odm_rx_phy_bw_jaguar_series_parsing(phy_info, pktinfo, phy_sta_rpt); + + if (pktinfo->data_rate <= ODM_RATE11M) + is_cck_rate = true; + else + is_cck_rate = false; + + if (pktinfo->is_to_self) + dm->curr_station_id = pktinfo->station_id; + else + dm->curr_station_id = 0xff; + + phy_info->rx_mimo_signal_quality[ODM_RF_PATH_A] = -1; + phy_info->rx_mimo_signal_quality[ODM_RF_PATH_B] = -1; + phy_info->rx_mimo_signal_quality[ODM_RF_PATH_C] = -1; + phy_info->rx_mimo_signal_quality[ODM_RF_PATH_D] = -1; + + if (is_cck_rate) { + u8 cck_agc_rpt; + + dm->phy_dbg_info.num_qry_phy_status_cck++; + + /*(1)Hardware does not provide RSSI for CCK*/ + /*(2)PWDB, Average PWDB calculated by hardware (for RA)*/ + + cck_highpwr = dm->is_cck_high_power; + + cck_agc_rpt = phy_sta_rpt->cfosho[0]; + LNA_idx = ((cck_agc_rpt & 0xE0) >> 5); + VGA_idx = (cck_agc_rpt & 0x1F); + + if (dm->support_ic_type == ODM_RTL8812) { + rx_pwr_all = + phydm_get_rx_pwr(LNA_idx, VGA_idx, cck_highpwr); + rx_pwr_all += 6; + pwdb_all = odm_query_rx_pwr_percentage(rx_pwr_all); + pwdb_all = phydm_adjust_pwdb(cck_highpwr, pwdb_all); + + } else if (dm->support_ic_type & (ODM_RTL8821 | ODM_RTL8881A)) { + s8 pout = -6; + + switch (LNA_idx) { + case 5: + rx_pwr_all = pout - 32 - (2 * VGA_idx); + break; + case 4: + rx_pwr_all = pout - 24 - (2 * VGA_idx); + break; + case 2: + rx_pwr_all = pout - 11 - (2 * VGA_idx); + break; + case 1: + rx_pwr_all = pout + 5 - (2 * VGA_idx); + break; + case 0: + rx_pwr_all = pout + 21 - (2 * VGA_idx); + break; + } + pwdb_all = odm_query_rx_pwr_percentage(rx_pwr_all); + } else if (dm->support_ic_type == ODM_RTL8814A || + dm->support_ic_type == ODM_RTL8822B) { + s8 pout = -6; + + switch (LNA_idx) { + /*CCK only use LNA: 2, 3, 5, 7*/ + case 7: + rx_pwr_all = pout - 32 - (2 * VGA_idx); + break; + case 5: + rx_pwr_all = pout - 22 - (2 * VGA_idx); + break; + case 3: + rx_pwr_all = pout - 2 - (2 * VGA_idx); + break; + case 2: + rx_pwr_all = pout + 5 - (2 * VGA_idx); + break; + default: + break; + } + pwdb_all = odm_query_rx_pwr_percentage(rx_pwr_all); + } + + dm->cck_lna_idx = LNA_idx; + dm->cck_vga_idx = VGA_idx; + phy_info->rx_pwdb_all = pwdb_all; + phy_info->bt_rx_rssi_percentage = pwdb_all; + phy_info->recv_signal_power = rx_pwr_all; + /*(3) Get Signal Quality (EVM)*/ + { + u8 sq; + + if ((dm->support_platform == ODM_WIN) && + (dm->patch_id == RT_CID_819X_LENOVO)) + sq = odm_sq_process_patch_rt_cid_819x_lenovo( + dm, is_cck_rate, pwdb_all, 0, 0); + else + sq = phydm_get_signal_quality_8812(phy_info, dm, + phy_sta_rpt); + + phy_info->signal_quality = sq; + phy_info->rx_mimo_signal_quality[ODM_RF_PATH_A] = sq; + } + + for (i = ODM_RF_PATH_A; i < ODM_RF_PATH_MAX_JAGUAR; i++) { + if (i == 0) + phy_info->rx_mimo_signal_strength[0] = pwdb_all; + else + phy_info->rx_mimo_signal_strength[i] = 0; + } + } else { + /*is OFDM rate*/ + fat_tab->hw_antsw_occur = phy_sta_rpt->hw_antsw_occur; + + dm->phy_dbg_info.num_qry_phy_status_ofdm++; + + /*(1)Get RSSI for OFDM rate*/ + + for (i = ODM_RF_PATH_A; i < ODM_RF_PATH_MAX_JAGUAR; i++) { + /*2008/01/30 MH we will judge RF RX path now.*/ + if (dm->rf_path_rx_enable & BIT(i)) + rf_rx_num++; + /*2012.05.25 LukeLee: Testchip AGC report is wrong, + *it should be restored back to old formula in MP chip + */ + if (i < ODM_RF_PATH_C) + rx_pwr[i] = (phy_sta_rpt->gain_trsw[i] & 0x7F) - + 110; + else + rx_pwr[i] = (phy_sta_rpt->gain_trsw_cd[i - 2] & + 0x7F) - + 110; + + phy_info->rx_pwr[i] = rx_pwr[i]; + + /* Translate DBM to percentage. */ + RSSI = odm_query_rx_pwr_percentage(rx_pwr[i]); + + /*total_rssi += RSSI;*/ + /*Get the best two RSSI*/ + if (RSSI > best_rssi && RSSI > second_rssi) { + second_rssi = best_rssi; + best_rssi = RSSI; + } else if (RSSI > second_rssi && RSSI <= best_rssi) { + second_rssi = RSSI; + } + + phy_info->rx_mimo_signal_strength[i] = (u8)RSSI; + + /*Get Rx snr value in DB*/ + if (i < ODM_RF_PATH_C) + phy_info->rx_snr[i] = + dm->phy_dbg_info.rx_snr_db[i] = + phy_sta_rpt->rxsnr[i] / 2; + else if (dm->support_ic_type & + (ODM_RTL8814A | ODM_RTL8822B)) + phy_info->rx_snr[i] = dm->phy_dbg_info + .rx_snr_db[i] = + phy_sta_rpt->csi_current[i - 2] / 2; + + /*(2) CFO_short & CFO_tail*/ + if (i < ODM_RF_PATH_C) { + phy_info->cfo_short[i] = + odm_cfo((phy_sta_rpt->cfosho[i])); + phy_info->cfo_tail[i] = + odm_cfo((phy_sta_rpt->cfotail[i])); + } + } + + /*(3)PWDB, Average PWDB calculated by hardware (for RA)*/ + + /*2012.05.25 LukeLee: Testchip AGC report is wrong, it should be + *restored back to old formula in MP chip + */ + if ((dm->support_ic_type & + (ODM_RTL8812 | ODM_RTL8821 | ODM_RTL8881A)) && + (!dm->is_mp_chip)) + rx_pwr_all = (phy_sta_rpt->pwdb_all & 0x7f) - 110; + else + rx_pwr_all = (((phy_sta_rpt->pwdb_all) >> 1) & 0x7f) - + 110; /*OLD FORMULA*/ + + pwdb_all = odm_query_rx_pwr_percentage(rx_pwr_all); + pwdb_all_bt = pwdb_all; + + phy_info->rx_pwdb_all = pwdb_all; + phy_info->bt_rx_rssi_percentage = pwdb_all_bt; + phy_info->rx_power = rx_pwr_all; + phy_info->recv_signal_power = rx_pwr_all; + + if ((dm->support_platform == ODM_WIN) && (dm->patch_id == 19)) { + /*do nothing*/ + } else { + /*mgnt_info->customer_id != RT_CID_819X_LENOVO*/ + + /*(4)EVM of OFDM rate*/ + + if ((pktinfo->data_rate >= ODM_RATEMCS8) && + (pktinfo->data_rate <= ODM_RATEMCS15)) + max_spatial_stream = 2; + else if ((pktinfo->data_rate >= ODM_RATEVHTSS2MCS0) && + (pktinfo->data_rate <= ODM_RATEVHTSS2MCS9)) + max_spatial_stream = 2; + else if ((pktinfo->data_rate >= ODM_RATEMCS16) && + (pktinfo->data_rate <= ODM_RATEMCS23)) + max_spatial_stream = 3; + else if ((pktinfo->data_rate >= ODM_RATEVHTSS3MCS0) && + (pktinfo->data_rate <= ODM_RATEVHTSS3MCS9)) + max_spatial_stream = 3; + else + max_spatial_stream = 1; + + for (i = 0; i < max_spatial_stream; i++) { + /*Don't use shift operation like "rx_evmX >>= 1" + *because the compilor of free build environment + *fill most significant bit to "zero" when doing + *shifting operation which may change a negative + *value to positive one, then the dbm value + *(which is supposed to be negative) is not + *correct anymore. + */ + + EVM = phydm_get_odm_evm(i, pktinfo, + phy_sta_rpt); + evm_dbm = phydm_get_evm_dbm(i, EVM, phy_sta_rpt, + phy_info); + phy_info->rx_mimo_signal_quality[i] = EVM; + phy_info->rx_mimo_evm_dbm[i] = evm_dbm; + } + } + + num_ss = phydm_rate_to_num_ss(dm, pktinfo->data_rate); + odm_parsing_cfo(dm, pktinfo, phy_sta_rpt->cfotail, num_ss); + } + + /*UI BSS List signal strength(in percentage), make it good looking, + *from 0~100. + */ + /*It is assigned to the BSS List in GetValueFromBeaconOrProbeRsp().*/ + if (is_cck_rate) { + phy_info->signal_strength = (u8)( + odm_signal_scale_mapping(dm, pwdb_all)); /*pwdb_all;*/ + } else { + if (rf_rx_num != 0) { + /* 2015/01 Sean, use the best two RSSI only, + * suggested by Ynlin and ChenYu. + */ + if (rf_rx_num == 1) + avg_rssi = best_rssi; + else + avg_rssi = (best_rssi + second_rssi) / 2; + phy_info->signal_strength = + (u8)(odm_signal_scale_mapping(dm, avg_rssi)); + } + } + dm->rx_pwdb_ave = dm->rx_pwdb_ave + phy_info->rx_pwdb_all; + + dm->dm_fat_table.antsel_rx_keep_0 = phy_sta_rpt->antidx_anta; + dm->dm_fat_table.antsel_rx_keep_1 = phy_sta_rpt->antidx_antb; + dm->dm_fat_table.antsel_rx_keep_2 = phy_sta_rpt->antidx_antc; + dm->dm_fat_table.antsel_rx_keep_3 = phy_sta_rpt->antidx_antd; +} + +void phydm_reset_rssi_for_dm(struct phy_dm_struct *dm, u8 station_id) +{ + struct rtl_sta_info *entry; + + entry = dm->odm_sta_info[station_id]; + + if (!IS_STA_VALID(entry)) + return; + + ODM_RT_TRACE(dm, ODM_COMP_RSSI_MONITOR, + "Reset RSSI for macid = (( %d ))\n", station_id); + + entry->rssi_stat.undecorated_smoothed_cck = -1; + entry->rssi_stat.undecorated_smoothed_ofdm = -1; + entry->rssi_stat.undecorated_smoothed_pwdb = -1; + entry->rssi_stat.ofdm_pkt = 0; + entry->rssi_stat.cck_pkt = 0; + entry->rssi_stat.cck_sum_power = 0; + entry->rssi_stat.is_send_rssi = RA_RSSI_STATE_INIT; + entry->rssi_stat.packet_map = 0; + entry->rssi_stat.valid_bit = 0; +} + +void odm_init_rssi_for_dm(struct phy_dm_struct *dm) {} + +static void odm_process_rssi_for_dm(struct phy_dm_struct *dm, + struct dm_phy_status_info *phy_info, + struct dm_per_pkt_info *pktinfo) +{ + s32 undecorated_smoothed_pwdb, undecorated_smoothed_cck, + undecorated_smoothed_ofdm; + u8 is_cck_rate = 0; + u8 send_rssi_2_fw = 0; + struct rtl_sta_info *entry; + + if (pktinfo->station_id >= ODM_ASSOCIATE_ENTRY_NUM) + return; + + /* 2012/05/30 MH/Luke.Lee Add some description */ + /* In windows driver: AP/IBSS mode STA */ + entry = dm->odm_sta_info[pktinfo->station_id]; + + if (!IS_STA_VALID(entry)) + return; + + { + if ((!pktinfo->is_packet_match_bssid)) /*data frame only*/ + return; + } + + if (pktinfo->is_packet_beacon) + dm->phy_dbg_info.num_qry_beacon_pkt++; + + is_cck_rate = (pktinfo->data_rate <= ODM_RATE11M) ? true : false; + dm->rx_rate = pktinfo->data_rate; + + /* --------------Statistic for antenna/path diversity---------------- */ + + /* -----------------Smart Antenna Debug Message------------------ */ + + undecorated_smoothed_cck = entry->rssi_stat.undecorated_smoothed_cck; + undecorated_smoothed_ofdm = entry->rssi_stat.undecorated_smoothed_ofdm; + undecorated_smoothed_pwdb = entry->rssi_stat.undecorated_smoothed_pwdb; + + if (pktinfo->is_packet_to_self || pktinfo->is_packet_beacon) { + if (!is_cck_rate) /* ofdm rate */ + undecorated_smoothed_ofdm = phydm_process_rssi_ofdm( + dm, phy_info, entry, undecorated_smoothed_ofdm); + else + undecorated_smoothed_cck = phydm_process_rssi_cck( + dm, phy_info, entry, undecorated_smoothed_cck); + + undecorated_smoothed_pwdb = phydm_process_rssi_pwdb( + dm, entry, pktinfo, undecorated_smoothed_ofdm, + undecorated_smoothed_cck); + + if ((entry->rssi_stat.ofdm_pkt >= 1 || + entry->rssi_stat.cck_pkt >= 5) && + (entry->rssi_stat.is_send_rssi == RA_RSSI_STATE_INIT)) { + send_rssi_2_fw = 1; + entry->rssi_stat.is_send_rssi = RA_RSSI_STATE_SEND; + } + + entry->rssi_stat.undecorated_smoothed_cck = + undecorated_smoothed_cck; + entry->rssi_stat.undecorated_smoothed_ofdm = + undecorated_smoothed_ofdm; + entry->rssi_stat.undecorated_smoothed_pwdb = + undecorated_smoothed_pwdb; + + if (send_rssi_2_fw) { /* Trigger init rate by RSSI */ + + if (entry->rssi_stat.ofdm_pkt != 0) + entry->rssi_stat.undecorated_smoothed_pwdb = + undecorated_smoothed_ofdm; + + ODM_RT_TRACE( + dm, ODM_COMP_RSSI_MONITOR, + "[Send to FW] PWDB = (( %d )), ofdm_pkt = (( %d )), cck_pkt = (( %d ))\n", + undecorated_smoothed_pwdb, + entry->rssi_stat.ofdm_pkt, + entry->rssi_stat.cck_pkt); + } + } +} + +/* + * Endianness before calling this API + */ +static void odm_phy_status_query_92c_series(struct phy_dm_struct *dm, + struct dm_phy_status_info *phy_info, + u8 *phy_status, + struct dm_per_pkt_info *pktinfo) +{ + odm_rx_phy_status92c_series_parsing(dm, phy_info, phy_status, pktinfo); + odm_process_rssi_for_dm(dm, phy_info, pktinfo); +} + +/* + * Endianness before calling this API + */ + +static void odm_phy_status_query_jaguar_series( + struct phy_dm_struct *dm, struct dm_phy_status_info *phy_info, + u8 *phy_status, struct dm_per_pkt_info *pktinfo) +{ + odm_rx_phy_status_jaguar_series_parsing(dm, phy_info, phy_status, + pktinfo); + odm_process_rssi_for_dm(dm, phy_info, pktinfo); +} + +void odm_phy_status_query(struct phy_dm_struct *dm, + struct dm_phy_status_info *phy_info, u8 *phy_status, + struct dm_per_pkt_info *pktinfo) +{ + if (dm->support_ic_type & ODM_IC_PHY_STATUE_NEW_TYPE) { + phydm_rx_phy_status_new_type(dm, phy_status, pktinfo, phy_info); + return; + } + + if (dm->support_ic_type & ODM_IC_11AC_SERIES) + odm_phy_status_query_jaguar_series(dm, phy_info, phy_status, + pktinfo); + + if (dm->support_ic_type & ODM_IC_11N_SERIES) + odm_phy_status_query_92c_series(dm, phy_info, phy_status, + pktinfo); +} + +/* For future use. */ +void odm_mac_status_query(struct phy_dm_struct *dm, u8 *mac_status, u8 mac_id, + bool is_packet_match_bssid, bool is_packet_to_self, + bool is_packet_beacon) +{ + /* 2011/10/19 Driver team will handle in the future. */ +} + +/* + * If you want to add a new IC, Please follow below template and generate + * a new one. + */ + +enum hal_status +odm_config_rf_with_header_file(struct phy_dm_struct *dm, + enum odm_rf_config_type config_type, + enum odm_rf_radio_path e_rf_path) +{ + ODM_RT_TRACE(dm, ODM_COMP_INIT, + "===>%s (%s)\n", __func__, + (dm->is_mp_chip) ? "MPChip" : "TestChip"); + ODM_RT_TRACE( + dm, ODM_COMP_INIT, + "dm->support_platform: 0x%X, dm->support_interface: 0x%X, dm->board_type: 0x%X\n", + dm->support_platform, dm->support_interface, dm->board_type); + + /* 1 AP doesn't use PHYDM power tracking table in these ICs */ + /* JJ ADD 20161014 */ + + /* 1 All platforms support */ + if (dm->support_ic_type == ODM_RTL8822B) { + if (config_type == CONFIG_RF_RADIO) { + if (e_rf_path == ODM_RF_PATH_A) + READ_AND_CONFIG_MP(8822b, _radioa); + else if (e_rf_path == ODM_RF_PATH_B) + READ_AND_CONFIG_MP(8822b, _radiob); + } else if (config_type == CONFIG_RF_TXPWR_LMT) { + if (dm->rfe_type == 5) + READ_AND_CONFIG_MP(8822b, _txpwr_lmt_type5); + else + READ_AND_CONFIG_MP(8822b, _txpwr_lmt); + } + } + + return HAL_STATUS_SUCCESS; +} + +enum hal_status +odm_config_rf_with_tx_pwr_track_header_file(struct phy_dm_struct *dm) +{ + ODM_RT_TRACE(dm, ODM_COMP_INIT, + "===>%s (%s)\n", __func__, + (dm->is_mp_chip) ? "MPChip" : "TestChip"); + ODM_RT_TRACE( + dm, ODM_COMP_INIT, + "dm->support_platform: 0x%X, dm->support_interface: 0x%X, dm->board_type: 0x%X\n", + dm->support_platform, dm->support_interface, dm->board_type); + + /* 1 AP doesn't use PHYDM power tracking table in these ICs */ + /* JJ ADD 20161014 */ + + /* 1 All platforms support */ + + if (dm->support_ic_type == ODM_RTL8822B) { + if (dm->rfe_type == 0) + READ_AND_CONFIG_MP(8822b, _txpowertrack_type0); + else if (dm->rfe_type == 1) + READ_AND_CONFIG_MP(8822b, _txpowertrack_type1); + else if (dm->rfe_type == 2) + READ_AND_CONFIG_MP(8822b, _txpowertrack_type2); + else if ((dm->rfe_type == 3) || (dm->rfe_type == 5)) + READ_AND_CONFIG_MP(8822b, _txpowertrack_type3_type5); + else if (dm->rfe_type == 4) + READ_AND_CONFIG_MP(8822b, _txpowertrack_type4); + else if (dm->rfe_type == 6) + READ_AND_CONFIG_MP(8822b, _txpowertrack_type6); + else if (dm->rfe_type == 7) + READ_AND_CONFIG_MP(8822b, _txpowertrack_type7); + else if (dm->rfe_type == 8) + READ_AND_CONFIG_MP(8822b, _txpowertrack_type8); + else if (dm->rfe_type == 9) + READ_AND_CONFIG_MP(8822b, _txpowertrack_type9); + else + READ_AND_CONFIG_MP(8822b, _txpowertrack); + } + + return HAL_STATUS_SUCCESS; +} + +enum hal_status +odm_config_bb_with_header_file(struct phy_dm_struct *dm, + enum odm_bb_config_type config_type) +{ + /* 1 AP doesn't use PHYDM initialization in these ICs */ + /* JJ ADD 20161014 */ + + /* 1 All platforms support */ + if (dm->support_ic_type == ODM_RTL8822B) { + if (config_type == CONFIG_BB_PHY_REG) + READ_AND_CONFIG_MP(8822b, _phy_reg); + else if (config_type == CONFIG_BB_AGC_TAB) + READ_AND_CONFIG_MP(8822b, _agc_tab); + else if (config_type == CONFIG_BB_PHY_REG_PG) + READ_AND_CONFIG_MP(8822b, _phy_reg_pg); + /*else if (config_type == CONFIG_BB_PHY_REG_MP)*/ + /*READ_AND_CONFIG_MP(8822b, _phy_reg_mp);*/ + } + + return HAL_STATUS_SUCCESS; +} + +enum hal_status odm_config_mac_with_header_file(struct phy_dm_struct *dm) +{ + ODM_RT_TRACE(dm, ODM_COMP_INIT, + "===>%s (%s)\n", __func__, + (dm->is_mp_chip) ? "MPChip" : "TestChip"); + ODM_RT_TRACE( + dm, ODM_COMP_INIT, + "dm->support_platform: 0x%X, dm->support_interface: 0x%X, dm->board_type: 0x%X\n", + dm->support_platform, dm->support_interface, dm->board_type); + + /* 1 AP doesn't use PHYDM initialization in these ICs */ + /* JJ ADD 20161014 */ + + /* 1 All platforms support */ + if (dm->support_ic_type == ODM_RTL8822B) + READ_AND_CONFIG_MP(8822b, _mac_reg); + + return HAL_STATUS_SUCCESS; +} + +enum hal_status +odm_config_fw_with_header_file(struct phy_dm_struct *dm, + enum odm_fw_config_type config_type, + u8 *p_firmware, u32 *size) +{ + return HAL_STATUS_SUCCESS; +} + +u32 odm_get_hw_img_version(struct phy_dm_struct *dm) +{ + u32 version = 0; + + /* 1 AP doesn't use PHYDM initialization in these ICs */ + /* JJ ADD 20161014 */ + + /*1 All platforms support*/ + if (dm->support_ic_type == ODM_RTL8822B) + version = GET_VERSION_MP(8822b, _mac_reg); + + return version; +} + +/* For 8822B only!! need to move to FW finally */ +/*==============================================*/ + +bool phydm_query_is_mu_api(struct phy_dm_struct *phydm, u8 ppdu_idx, + u8 *p_data_rate, u8 *p_gid) +{ + u8 data_rate = 0, gid = 0; + bool is_mu = false; + + data_rate = phydm->phy_dbg_info.num_of_ppdu[ppdu_idx]; + gid = phydm->phy_dbg_info.gid_num[ppdu_idx]; + + if (data_rate & BIT(7)) { + is_mu = true; + data_rate = data_rate & ~(BIT(7)); + } else { + is_mu = false; + } + + *p_data_rate = data_rate; + *p_gid = gid; + + return is_mu; +} + +static void phydm_rx_statistic_cal(struct phy_dm_struct *phydm, u8 *phy_status, + struct dm_per_pkt_info *pktinfo) +{ + struct phy_status_rpt_jaguar2_type1 *phy_sta_rpt = + (struct phy_status_rpt_jaguar2_type1 *)phy_status; + u8 date_rate = pktinfo->data_rate & ~(BIT(7)); + + if ((phy_sta_rpt->gid != 0) && (phy_sta_rpt->gid != 63)) { + if (date_rate >= ODM_RATEVHTSS1MCS0) { + phydm->phy_dbg_info + .num_qry_mu_vht_pkt[date_rate - 0x2C]++; + phydm->phy_dbg_info.num_of_ppdu[pktinfo->ppdu_cnt] = + date_rate | BIT(7); + phydm->phy_dbg_info.gid_num[pktinfo->ppdu_cnt] = + phy_sta_rpt->gid; + } + + } else { + if (date_rate >= ODM_RATEVHTSS1MCS0) { + phydm->phy_dbg_info.num_qry_vht_pkt[date_rate - 0x2C]++; + phydm->phy_dbg_info.num_of_ppdu[pktinfo->ppdu_cnt] = + date_rate; + phydm->phy_dbg_info.gid_num[pktinfo->ppdu_cnt] = + phy_sta_rpt->gid; + } + } +} + +static void phydm_reset_phy_info(struct phy_dm_struct *phydm, + struct dm_phy_status_info *phy_info) +{ + phy_info->rx_pwdb_all = 0; + phy_info->signal_quality = 0; + phy_info->band_width = 0; + phy_info->rx_count = 0; + odm_memory_set(phydm, phy_info->rx_mimo_signal_quality, 0, 4); + odm_memory_set(phydm, phy_info->rx_mimo_signal_strength, 0, 4); + odm_memory_set(phydm, phy_info->rx_snr, 0, 4); + + phy_info->rx_power = -110; + phy_info->recv_signal_power = -110; + phy_info->bt_rx_rssi_percentage = 0; + phy_info->signal_strength = 0; + phy_info->bt_coex_pwr_adjust = 0; + phy_info->channel = 0; + phy_info->is_mu_packet = 0; + phy_info->is_beamformed = 0; + phy_info->rxsc = 0; + odm_memory_set(phydm, phy_info->rx_pwr, -110, 4); + odm_memory_set(phydm, phy_info->rx_mimo_evm_dbm, 0, 4); + odm_memory_set(phydm, phy_info->cfo_short, 0, 8); + odm_memory_set(phydm, phy_info->cfo_tail, 0, 8); +} + +static void phydm_set_per_path_phy_info(u8 rx_path, s8 rx_pwr, s8 rx_evm, + s8 cfo_tail, s8 rx_snr, + struct dm_phy_status_info *phy_info) +{ + u8 evm_dbm = 0; + u8 evm_percentage = 0; + + /* SNR is S(8,1), EVM is S(8,1), CFO is S(8,7) */ + + if (rx_evm < 0) { + /* Calculate EVM in dBm */ + evm_dbm = ((u8)(0 - rx_evm) >> 1); + + /* Calculate EVM in percentage */ + if (evm_dbm >= 33) + evm_percentage = 100; + else + evm_percentage = (evm_dbm << 1) + (evm_dbm); + } + + phy_info->rx_pwr[rx_path] = rx_pwr; + phy_info->rx_mimo_evm_dbm[rx_path] = evm_dbm; + + /* CFO = CFO_tail * 312.5 / 2^7 ~= CFO tail * 39/512 (kHz)*/ + phy_info->cfo_tail[rx_path] = cfo_tail; + phy_info->cfo_tail[rx_path] = ((phy_info->cfo_tail[rx_path] << 5) + + (phy_info->cfo_tail[rx_path] << 2) + + (phy_info->cfo_tail[rx_path] << 1) + + (phy_info->cfo_tail[rx_path])) >> + 9; + + phy_info->rx_mimo_signal_strength[rx_path] = + odm_query_rx_pwr_percentage(rx_pwr); + phy_info->rx_mimo_signal_quality[rx_path] = evm_percentage; + phy_info->rx_snr[rx_path] = rx_snr >> 1; +} + +static void phydm_set_common_phy_info(s8 rx_power, u8 channel, + bool is_beamformed, bool is_mu_packet, + u8 bandwidth, u8 signal_quality, u8 rxsc, + struct dm_phy_status_info *phy_info) +{ + phy_info->rx_power = rx_power; /* RSSI in dB */ + phy_info->recv_signal_power = rx_power; /* RSSI in dB */ + phy_info->channel = channel; /* channel number */ + phy_info->is_beamformed = is_beamformed; /* apply BF */ + phy_info->is_mu_packet = is_mu_packet; /* MU packet */ + phy_info->rxsc = rxsc; + phy_info->rx_pwdb_all = + odm_query_rx_pwr_percentage(rx_power); /* RSSI in percentage */ + phy_info->signal_quality = signal_quality; /* signal quality */ + phy_info->band_width = bandwidth; /* bandwidth */ +} + +static void phydm_get_rx_phy_status_type0(struct phy_dm_struct *dm, + u8 *phy_status, + struct dm_per_pkt_info *pktinfo, + struct dm_phy_status_info *phy_info) +{ + /* type 0 is used for cck packet */ + + struct phy_status_rpt_jaguar2_type0 *phy_sta_rpt = + (struct phy_status_rpt_jaguar2_type0 *)phy_status; + u8 sq = 0; + s8 rx_power = phy_sta_rpt->pwdb - 110; + + /* JJ ADD 20161014 */ + + /* Calculate Signal Quality*/ + if (pktinfo->is_packet_match_bssid) { + if (phy_sta_rpt->signal_quality >= 64) { + sq = 0; + } else if (phy_sta_rpt->signal_quality <= 20) { + sq = 100; + } else { + /* mapping to 2~99% */ + sq = 64 - phy_sta_rpt->signal_quality; + sq = ((sq << 3) + sq) >> 2; + } + } + + /* Modify CCK PWDB if old AGC */ + if (!dm->cck_new_agc) { + u8 lna_idx, vga_idx; + + lna_idx = ((phy_sta_rpt->lna_h << 3) | phy_sta_rpt->lna_l); + vga_idx = phy_sta_rpt->vga; + + /* JJ ADD 20161014 */ + + /* Need to do !! */ + /*if (dm->support_ic_type & ODM_RTL8822B) */ + /*rx_power = odm_CCKRSSI_8822B(LNA_idx, VGA_idx);*/ + } + + /* Update CCK packet counter */ + dm->phy_dbg_info.num_qry_phy_status_cck++; + + /*CCK no STBC and LDPC*/ + dm->phy_dbg_info.is_ldpc_pkt = false; + dm->phy_dbg_info.is_stbc_pkt = false; + + /* Update Common information */ + phydm_set_common_phy_info(rx_power, phy_sta_rpt->channel, false, false, + ODM_BW20M, sq, phy_sta_rpt->rxsc, phy_info); + + /* Update CCK pwdb */ + /* Update per-path information */ + phydm_set_per_path_phy_info(ODM_RF_PATH_A, rx_power, 0, 0, 0, phy_info); + + dm->dm_fat_table.antsel_rx_keep_0 = phy_sta_rpt->antidx_a; + dm->dm_fat_table.antsel_rx_keep_1 = phy_sta_rpt->antidx_b; + dm->dm_fat_table.antsel_rx_keep_2 = phy_sta_rpt->antidx_c; + dm->dm_fat_table.antsel_rx_keep_3 = phy_sta_rpt->antidx_d; +} + +static void phydm_get_rx_phy_status_type1(struct phy_dm_struct *dm, + u8 *phy_status, + struct dm_per_pkt_info *pktinfo, + struct dm_phy_status_info *phy_info) +{ + /* type 1 is used for ofdm packet */ + + struct phy_status_rpt_jaguar2_type1 *phy_sta_rpt = + (struct phy_status_rpt_jaguar2_type1 *)phy_status; + s8 rx_pwr_db = -120; + u8 i, rxsc, bw = ODM_BW20M, rx_count = 0; + bool is_mu; + u8 num_ss; + + /* Update OFDM packet counter */ + dm->phy_dbg_info.num_qry_phy_status_ofdm++; + + /* Update per-path information */ + for (i = ODM_RF_PATH_A; i < ODM_RF_PATH_MAX_JAGUAR; i++) { + if (dm->rx_ant_status & BIT(i)) { + s8 rx_path_pwr_db; + + /* RX path counter */ + rx_count++; + + /* Update per-path information + * (RSSI_dB RSSI_percentage EVM SNR CFO sq) + */ + /* EVM report is reported by stream, not path */ + rx_path_pwr_db = phy_sta_rpt->pwdb[i] - + 110; /* per-path pwdb in dB domain */ + phydm_set_per_path_phy_info( + i, rx_path_pwr_db, + phy_sta_rpt->rxevm[rx_count - 1], + phy_sta_rpt->cfo_tail[i], phy_sta_rpt->rxsnr[i], + phy_info); + + /* search maximum pwdb */ + if (rx_path_pwr_db > rx_pwr_db) + rx_pwr_db = rx_path_pwr_db; + } + } + + /* mapping RX counter from 1~4 to 0~3 */ + if (rx_count > 0) + phy_info->rx_count = rx_count - 1; + + /* Check if MU packet or not */ + if ((phy_sta_rpt->gid != 0) && (phy_sta_rpt->gid != 63)) { + is_mu = true; + dm->phy_dbg_info.num_qry_mu_pkt++; + } else { + is_mu = false; + } + + /* count BF packet */ + dm->phy_dbg_info.num_qry_bf_pkt = + dm->phy_dbg_info.num_qry_bf_pkt + phy_sta_rpt->beamformed; + + /*STBC or LDPC pkt*/ + dm->phy_dbg_info.is_ldpc_pkt = phy_sta_rpt->ldpc; + dm->phy_dbg_info.is_stbc_pkt = phy_sta_rpt->stbc; + + /* Check sub-channel */ + if ((pktinfo->data_rate > ODM_RATE11M) && + (pktinfo->data_rate < ODM_RATEMCS0)) + rxsc = phy_sta_rpt->l_rxsc; + else + rxsc = phy_sta_rpt->ht_rxsc; + + /* Check RX bandwidth */ + if (dm->support_ic_type & ODM_RTL8822B) { + if ((rxsc >= 1) && (rxsc <= 8)) + bw = ODM_BW20M; + else if ((rxsc >= 9) && (rxsc <= 12)) + bw = ODM_BW40M; + else if (rxsc >= 13) + bw = ODM_BW80M; + else + bw = phy_sta_rpt->rf_mode; + } else if (dm->support_ic_type & (ODM_RTL8197F | ODM_RTL8723D | + ODM_RTL8710B)) { /* JJ ADD 20161014 */ + if (phy_sta_rpt->rf_mode == 0) + bw = ODM_BW20M; + else if ((rxsc == 1) || (rxsc == 2)) + bw = ODM_BW20M; + else + bw = ODM_BW40M; + } + + /* Update packet information */ + phydm_set_common_phy_info( + rx_pwr_db, phy_sta_rpt->channel, (bool)phy_sta_rpt->beamformed, + is_mu, bw, odm_evm_db_to_percentage(phy_sta_rpt->rxevm[0]), + rxsc, phy_info); + + num_ss = phydm_rate_to_num_ss(dm, pktinfo->data_rate); + + odm_parsing_cfo(dm, pktinfo, phy_sta_rpt->cfo_tail, num_ss); + dm->dm_fat_table.antsel_rx_keep_0 = phy_sta_rpt->antidx_a; + dm->dm_fat_table.antsel_rx_keep_1 = phy_sta_rpt->antidx_b; + dm->dm_fat_table.antsel_rx_keep_2 = phy_sta_rpt->antidx_c; + dm->dm_fat_table.antsel_rx_keep_3 = phy_sta_rpt->antidx_d; + + if (pktinfo->is_packet_match_bssid) { + /* */ + phydm_rx_statistic_cal(dm, phy_status, pktinfo); + } +} + +static void phydm_get_rx_phy_status_type2(struct phy_dm_struct *dm, + u8 *phy_status, + struct dm_per_pkt_info *pktinfo, + struct dm_phy_status_info *phy_info) +{ + struct phy_status_rpt_jaguar2_type2 *phy_sta_rpt = + (struct phy_status_rpt_jaguar2_type2 *)phy_status; + s8 rx_pwr_db = -120; + u8 i, rxsc, bw = ODM_BW20M, rx_count = 0; + + /* Update OFDM packet counter */ + dm->phy_dbg_info.num_qry_phy_status_ofdm++; + + /* Update per-path information */ + for (i = ODM_RF_PATH_A; i < ODM_RF_PATH_MAX_JAGUAR; i++) { + if (dm->rx_ant_status & BIT(i)) { + s8 rx_path_pwr_db; + + /* RX path counter */ + rx_count++; + + /* Update per-path information + * (RSSI_dB RSSI_percentage EVM SNR CFO sq) + */ + rx_path_pwr_db = phy_sta_rpt->pwdb[i] - + 110; /* per-path pwdb in dB domain */ + + phydm_set_per_path_phy_info(i, rx_path_pwr_db, 0, 0, 0, + phy_info); + + /* search maximum pwdb */ + if (rx_path_pwr_db > rx_pwr_db) + rx_pwr_db = rx_path_pwr_db; + } + } + + /* mapping RX counter from 1~4 to 0~3 */ + if (rx_count > 0) + phy_info->rx_count = rx_count - 1; + + /* Check RX sub-channel */ + if ((pktinfo->data_rate > ODM_RATE11M) && + (pktinfo->data_rate < ODM_RATEMCS0)) + rxsc = phy_sta_rpt->l_rxsc; + else + rxsc = phy_sta_rpt->ht_rxsc; + + /*STBC or LDPC pkt*/ + dm->phy_dbg_info.is_ldpc_pkt = phy_sta_rpt->ldpc; + dm->phy_dbg_info.is_stbc_pkt = phy_sta_rpt->stbc; + + /* Check RX bandwidth */ + /* the BW information of sc=0 is useless, because there is + * no information of RF mode + */ + + if (dm->support_ic_type & ODM_RTL8822B) { + if ((rxsc >= 1) && (rxsc <= 8)) + bw = ODM_BW20M; + else if ((rxsc >= 9) && (rxsc <= 12)) + bw = ODM_BW40M; + else if (rxsc >= 13) + bw = ODM_BW80M; + else + bw = ODM_BW20M; + } else if (dm->support_ic_type & (ODM_RTL8197F | ODM_RTL8723D | + ODM_RTL8710B)) { /* JJ ADD 20161014 */ + if (rxsc == 3) + bw = ODM_BW40M; + else if ((rxsc == 1) || (rxsc == 2)) + bw = ODM_BW20M; + else + bw = ODM_BW20M; + } + + /* Update packet information */ + phydm_set_common_phy_info(rx_pwr_db, phy_sta_rpt->channel, + (bool)phy_sta_rpt->beamformed, false, bw, 0, + rxsc, phy_info); +} + +static void +phydm_process_rssi_for_dm_new_type(struct phy_dm_struct *dm, + struct dm_phy_status_info *phy_info, + struct dm_per_pkt_info *pktinfo) +{ + s32 undecorated_smoothed_pwdb, accumulate_pwdb; + u32 rssi_ave; + u8 i; + struct rtl_sta_info *entry; + u8 scaling_factor = 4; + + if (pktinfo->station_id >= ODM_ASSOCIATE_ENTRY_NUM) + return; + + entry = dm->odm_sta_info[pktinfo->station_id]; + + if (!IS_STA_VALID(entry)) + return; + + if ((!pktinfo->is_packet_match_bssid)) /*data frame only*/ + return; + + if (pktinfo->is_packet_beacon) + dm->phy_dbg_info.num_qry_beacon_pkt++; + + if (pktinfo->is_packet_to_self || pktinfo->is_packet_beacon) { + u32 rssi_linear = 0; + + dm->rx_rate = pktinfo->data_rate; + undecorated_smoothed_pwdb = + entry->rssi_stat.undecorated_smoothed_pwdb; + accumulate_pwdb = dm->accumulate_pwdb[pktinfo->station_id]; + dm->rssi_a = phy_info->rx_mimo_signal_strength[ODM_RF_PATH_A]; + dm->rssi_b = phy_info->rx_mimo_signal_strength[ODM_RF_PATH_B]; + dm->rssi_c = phy_info->rx_mimo_signal_strength[ODM_RF_PATH_C]; + dm->rssi_d = phy_info->rx_mimo_signal_strength[ODM_RF_PATH_D]; + + for (i = ODM_RF_PATH_A; i < ODM_RF_PATH_MAX_JAGUAR; i++) { + if (phy_info->rx_mimo_signal_strength[i] != 0) + rssi_linear += odm_convert_to_linear( + phy_info->rx_mimo_signal_strength[i]); + } + + switch (phy_info->rx_count + 1) { + case 2: + rssi_linear = (rssi_linear >> 1); + break; + case 3: + /* rssi_linear/3 ~ rssi_linear*11/32 */ + rssi_linear = ((rssi_linear) + (rssi_linear << 1) + + (rssi_linear << 3)) >> + 5; + break; + case 4: + rssi_linear = (rssi_linear >> 2); + break; + } + rssi_ave = odm_convert_to_db(rssi_linear); + + if (undecorated_smoothed_pwdb <= 0) { + accumulate_pwdb = + (phy_info->rx_pwdb_all << scaling_factor); + undecorated_smoothed_pwdb = phy_info->rx_pwdb_all; + } else { + accumulate_pwdb = accumulate_pwdb - + (accumulate_pwdb >> scaling_factor) + + rssi_ave; + undecorated_smoothed_pwdb = + (accumulate_pwdb + + (1 << (scaling_factor - 1))) >> + scaling_factor; + } + + entry->rssi_stat.undecorated_smoothed_pwdb = + undecorated_smoothed_pwdb; + dm->accumulate_pwdb[pktinfo->station_id] = accumulate_pwdb; + } +} + +void phydm_rx_phy_status_new_type(struct phy_dm_struct *phydm, u8 *phy_status, + struct dm_per_pkt_info *pktinfo, + struct dm_phy_status_info *phy_info) +{ + u8 phy_status_type = (*phy_status & 0xf); + + /* Memory reset */ + phydm_reset_phy_info(phydm, phy_info); + + /* Phy status parsing */ + switch (phy_status_type) { + case 0: { + phydm_get_rx_phy_status_type0(phydm, phy_status, pktinfo, + phy_info); + break; + } + case 1: { + phydm_get_rx_phy_status_type1(phydm, phy_status, pktinfo, + phy_info); + break; + } + case 2: { + phydm_get_rx_phy_status_type2(phydm, phy_status, pktinfo, + phy_info); + break; + } + default: + return; + } + + /* Update signal strength to UI, and phy_info->rx_pwdb_all is the + * maximum RSSI of all path + */ + phy_info->signal_strength = + (u8)(odm_signal_scale_mapping(phydm, phy_info->rx_pwdb_all)); + + /* Calculate average RSSI and smoothed RSSI */ + phydm_process_rssi_for_dm_new_type(phydm, phy_info, pktinfo); +} + +u32 query_phydm_trx_capability(struct phy_dm_struct *dm) +{ + u32 value32 = 0xFFFFFFFF; + + return value32; +} + +u32 query_phydm_stbc_capability(struct phy_dm_struct *dm) +{ + u32 value32 = 0xFFFFFFFF; + + return value32; +} + +u32 query_phydm_ldpc_capability(struct phy_dm_struct *dm) +{ + u32 value32 = 0xFFFFFFFF; + + return value32; +} + +u32 query_phydm_txbf_parameters(struct phy_dm_struct *dm) +{ + u32 value32 = 0xFFFFFFFF; + + return value32; +} + +u32 query_phydm_txbf_capability(struct phy_dm_struct *dm) +{ + u32 value32 = 0xFFFFFFFF; + + return value32; +} diff --git a/drivers/staging/rtlwifi/phydm/phydm_hwconfig.h b/drivers/staging/rtlwifi/phydm/phydm_hwconfig.h new file mode 100644 index 000000000000..ec94c61df2b9 --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/phydm_hwconfig.h @@ -0,0 +1,510 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __HALHWOUTSRC_H__ +#define __HALHWOUTSRC_H__ + +/*--------------------------Define -------------------------------------------*/ +#define CCK_RSSI_INIT_COUNT 5 + +#define RA_RSSI_STATE_INIT 0 +#define RA_RSSI_STATE_SEND 1 +#define RA_RSSI_STATE_HOLD 2 + +#define CFO_HW_RPT_2_MHZ(val) ((val << 1) + (val >> 1)) +/* ((X* 3125) / 10)>>7 = (X*10)>>2 = X*2.5 = X<<1 + X>>1 */ + +#define AGC_DIFF_CONFIG_MP(ic, band) \ + (odm_read_and_config_mp_##ic##_agc_tab_diff( \ + dm, array_mp_##ic##_agc_tab_diff_##band, \ + sizeof(array_mp_##ic##_agc_tab_diff_##band) / sizeof(u32))) +#define AGC_DIFF_CONFIG_TC(ic, band) \ + (odm_read_and_config_tc_##ic##_agc_tab_diff( \ + dm, array_tc_##ic##_agc_tab_diff_##band, \ + sizeof(array_tc_##ic##_agc_tab_diff_##band) / sizeof(u32))) + +#define AGC_DIFF_CONFIG(ic, band) \ + do { \ + if (dm->is_mp_chip) \ + AGC_DIFF_CONFIG_MP(ic, band); \ + else \ + AGC_DIFF_CONFIG_TC(ic, band); \ + } while (0) + +/* ************************************************************ + * structure and define + * *************************************************************/ + +struct phy_rx_agc_info { +#if (ODM_ENDIAN_TYPE == ODM_ENDIAN_LITTLE) + u8 gain : 7, trsw : 1; +#else + u8 trsw : 1, gain : 7; +#endif +}; + +struct phy_status_rpt_8192cd { + struct phy_rx_agc_info path_agc[2]; + u8 ch_corr[2]; + u8 cck_sig_qual_ofdm_pwdb_all; + u8 cck_agc_rpt_ofdm_cfosho_a; + u8 cck_rpt_b_ofdm_cfosho_b; + u8 rsvd_1; /*ch_corr_msb;*/ + u8 noise_power_db_msb; + s8 path_cfotail[2]; + u8 pcts_mask[2]; + s8 stream_rxevm[2]; + u8 path_rxsnr[2]; + u8 noise_power_db_lsb; + u8 rsvd_2[3]; + u8 stream_csi[2]; + u8 stream_target_csi[2]; + s8 sig_evm; + u8 rsvd_3; + +#if (ODM_ENDIAN_TYPE == ODM_ENDIAN_LITTLE) + u8 antsel_rx_keep_2 : 1; /*ex_intf_flg:1;*/ + u8 sgi_en : 1; + u8 rxsc : 2; + u8 idle_long : 1; + u8 r_ant_train_en : 1; + u8 ant_sel_b : 1; + u8 ant_sel : 1; +#else /*_BIG_ENDIAN_ */ + u8 ant_sel : 1; + u8 ant_sel_b : 1; + u8 r_ant_train_en : 1; + u8 idle_long : 1; + u8 rxsc : 2; + u8 sgi_en : 1; + u8 antsel_rx_keep_2 : 1; /*ex_intf_flg:1;*/ +#endif +}; + +struct phy_status_rpt_8812 { + /* DWORD 0*/ + u8 gain_trsw[2]; /*path-A and path-B {TRSW, gain[6:0] }*/ + u8 chl_num_LSB; /*channel number[7:0]*/ +#if (ODM_ENDIAN_TYPE == ODM_ENDIAN_LITTLE) + u8 chl_num_MSB : 2; /*channel number[9:8]*/ + u8 sub_chnl : 4; /*sub-channel location[3:0]*/ + u8 r_RFMOD : 2; /*RF mode[1:0]*/ +#else /*_BIG_ENDIAN_ */ + u8 r_RFMOD : 2; + u8 sub_chnl : 4; + u8 chl_num_MSB : 2; +#endif + + /* DWORD 1*/ + u8 pwdb_all; /*CCK signal quality / OFDM pwdb all*/ + s8 cfosho[2]; /*DW1 byte 1 DW1 byte2 */ +/*CCK AGC report and CCK_BB_Power / OFDM path-A and path-B short CFO*/ +#if (ODM_ENDIAN_TYPE == ODM_ENDIAN_LITTLE) + /*this should be checked again + *because the definition of 8812 and 8814 is different + */ + u8 resvd_0 : 6; + u8 bt_RF_ch_MSB : 2; /*8812A:2'b0, 8814A: bt rf channel keep[7:6]*/ +#else /*_BIG_ENDIAN_*/ + u8 bt_RF_ch_MSB : 2; + u8 resvd_0 : 6; +#endif + +/* DWORD 2*/ +#if (ODM_ENDIAN_TYPE == ODM_ENDIAN_LITTLE) + u8 ant_div_sw_a : 1; /*8812A: ant_div_sw_a, 8814A: 1'b0*/ + u8 ant_div_sw_b : 1; /*8812A: ant_div_sw_b, 8814A: 1'b0*/ + u8 bt_RF_ch_LSB : 6; /*8812A: 6'b0, 8814A: bt rf channel keep[5:0]*/ +#else /*_BIG_ENDIAN_ */ + u8 bt_RF_ch_LSB : 6; + u8 ant_div_sw_b : 1; + u8 ant_div_sw_a : 1; +#endif + s8 cfotail[2]; /*DW2 byte 1 DW2 byte 2 path-A and path-B CFO tail*/ + u8 PCTS_MSK_RPT_0; /*PCTS mask report[7:0]*/ + u8 PCTS_MSK_RPT_1; /*PCTS mask report[15:8]*/ + + /* DWORD 3*/ + s8 rxevm[2]; /*DW3 byte 1 DW3 byte 2 stream 1 and stream 2 RX EVM*/ + s8 rxsnr[2]; /*DW3 byte 3 DW4 byte 0 path-A and path-B RX SNR*/ + + /* DWORD 4*/ + u8 PCTS_MSK_RPT_2; /*PCTS mask report[23:16]*/ +#if (ODM_ENDIAN_TYPE == ODM_ENDIAN_LITTLE) + u8 PCTS_MSK_RPT_3 : 6; /*PCTS mask report[29:24]*/ + u8 pcts_rpt_valid : 1; /*pcts_rpt_valid*/ + u8 resvd_1 : 1; /*1'b0*/ +#else /*_BIG_ENDIAN_*/ + u8 resvd_1 : 1; + u8 pcts_rpt_valid : 1; + u8 PCTS_MSK_RPT_3 : 6; +#endif + s8 rxevm_cd[2]; /*DW 4 byte 3 DW5 byte 0 */ + /* 8812A: 16'b0, 8814A: stream 3 and stream 4 RX EVM*/ + + /* DWORD 5*/ + u8 csi_current[2]; /*DW5 byte 1 DW5 byte 2 */ + /* 8812A: stream 1 and 2 CSI, 8814A: path-C and path-D RX SNR*/ + u8 gain_trsw_cd[2]; /*DW5 byte 3 DW6 byte 0 */ + /* path-C and path-D {TRSW, gain[6:0] }*/ + + /* DWORD 6*/ + s8 sigevm; /*signal field EVM*/ +#if (ODM_ENDIAN_TYPE == ODM_ENDIAN_LITTLE) + u8 antidx_antc : 3; /*8812A: 3'b0 8814A: antidx_antc[2:0]*/ + u8 antidx_antd : 3; /*8812A: 3'b0 8814A: antidx_antd[2:0]*/ + u8 dpdt_ctrl_keep : 1; /*8812A: 1'b0 8814A: dpdt_ctrl_keep*/ + u8 GNT_BT_keep : 1; /*8812A: 1'b0 8814A: GNT_BT_keep*/ +#else /*_BIG_ENDIAN_*/ + u8 GNT_BT_keep : 1; + u8 dpdt_ctrl_keep : 1; + u8 antidx_antd : 3; + u8 antidx_antc : 3; +#endif +#if (ODM_ENDIAN_TYPE == ODM_ENDIAN_LITTLE) + u8 antidx_anta : 3; /*antidx_anta[2:0]*/ + u8 antidx_antb : 3; /*antidx_antb[2:0]*/ + u8 hw_antsw_occur : 2; /*1'b0*/ +#else /*_BIG_ENDIAN_*/ + u8 hw_antsw_occur : 2; + u8 antidx_antb : 3; + u8 antidx_anta : 3; +#endif +}; + +void phydm_reset_rssi_for_dm(struct phy_dm_struct *dm, u8 station_id); + +void odm_init_rssi_for_dm(struct phy_dm_struct *dm); + +void odm_phy_status_query(struct phy_dm_struct *dm, + struct dm_phy_status_info *phy_info, u8 *phy_status, + struct dm_per_pkt_info *pktinfo); + +void odm_mac_status_query(struct phy_dm_struct *dm, u8 *mac_status, u8 mac_id, + bool is_packet_match_bssid, bool is_packet_to_self, + bool is_packet_beacon); + +enum hal_status +odm_config_rf_with_tx_pwr_track_header_file(struct phy_dm_struct *dm); + +enum hal_status +odm_config_rf_with_header_file(struct phy_dm_struct *dm, + enum odm_rf_config_type config_type, + enum odm_rf_radio_path e_rf_path); + +enum hal_status +odm_config_bb_with_header_file(struct phy_dm_struct *dm, + enum odm_bb_config_type config_type); + +enum hal_status odm_config_mac_with_header_file(struct phy_dm_struct *dm); + +enum hal_status +odm_config_fw_with_header_file(struct phy_dm_struct *dm, + enum odm_fw_config_type config_type, + u8 *p_firmware, u32 *size); + +u32 odm_get_hw_img_version(struct phy_dm_struct *dm); + +s32 odm_signal_scale_mapping(struct phy_dm_struct *dm, s32 curr_sig); + +/*For 8822B only!! need to move to FW finally */ +/*==============================================*/ +void phydm_rx_phy_status_new_type(struct phy_dm_struct *phydm, u8 *phy_status, + struct dm_per_pkt_info *pktinfo, + struct dm_phy_status_info *phy_info); + +bool phydm_query_is_mu_api(struct phy_dm_struct *phydm, u8 ppdu_idx, + u8 *p_data_rate, u8 *p_gid); + +struct phy_status_rpt_jaguar2_type0 { + /* DW0 */ + u8 page_num; + u8 pwdb; +#if (ODM_ENDIAN_TYPE == ODM_ENDIAN_LITTLE) + u8 gain : 6; + u8 rsvd_0 : 1; + u8 trsw : 1; +#else + u8 trsw : 1; + u8 rsvd_0 : 1; + u8 gain : 6; +#endif + u8 rsvd_1; + + /* DW1 */ + u8 rsvd_2; +#if (ODM_ENDIAN_TYPE == ODM_ENDIAN_LITTLE) + u8 rxsc : 4; + u8 agc_table : 4; +#else + u8 agc_table : 4; + u8 rxsc : 4; +#endif + u8 channel; + u8 band; + + /* DW2 */ + u16 length; +#if (ODM_ENDIAN_TYPE == ODM_ENDIAN_LITTLE) + u8 antidx_a : 3; + u8 antidx_b : 3; + u8 rsvd_3 : 2; + u8 antidx_c : 3; + u8 antidx_d : 3; + u8 rsvd_4 : 2; +#else + u8 rsvd_3 : 2; + u8 antidx_b : 3; + u8 antidx_a : 3; + u8 rsvd_4 : 2; + u8 antidx_d : 3; + u8 antidx_c : 3; +#endif + + /* DW3 */ + u8 signal_quality; +#if (ODM_ENDIAN_TYPE == ODM_ENDIAN_LITTLE) + u8 vga : 5; + u8 lna_l : 3; + u8 bb_power : 6; + u8 rsvd_9 : 1; + u8 lna_h : 1; +#else + u8 lna_l : 3; + u8 vga : 5; + u8 lna_h : 1; + u8 rsvd_9 : 1; + u8 bb_power : 6; +#endif + u8 rsvd_5; + + /* DW4 */ + u32 rsvd_6; + + /* DW5 */ + u32 rsvd_7; + + /* DW6 */ + u32 rsvd_8; +}; + +struct phy_status_rpt_jaguar2_type1 { + /* DW0 and DW1 */ + u8 page_num; + u8 pwdb[4]; +#if (ODM_ENDIAN_TYPE == ODM_ENDIAN_LITTLE) + u8 l_rxsc : 4; + u8 ht_rxsc : 4; +#else + u8 ht_rxsc : 4; + u8 l_rxsc : 4; +#endif + u8 channel; +#if (ODM_ENDIAN_TYPE == ODM_ENDIAN_LITTLE) + u8 band : 2; + u8 rsvd_0 : 1; + u8 hw_antsw_occu : 1; + u8 gnt_bt : 1; + u8 ldpc : 1; + u8 stbc : 1; + u8 beamformed : 1; +#else + u8 beamformed : 1; + u8 stbc : 1; + u8 ldpc : 1; + u8 gnt_bt : 1; + u8 hw_antsw_occu : 1; + u8 rsvd_0 : 1; + u8 band : 2; +#endif + + /* DW2 */ + u16 lsig_length; +#if (ODM_ENDIAN_TYPE == ODM_ENDIAN_LITTLE) + u8 antidx_a : 3; + u8 antidx_b : 3; + u8 rsvd_1 : 2; + u8 antidx_c : 3; + u8 antidx_d : 3; + u8 rsvd_2 : 2; +#else + u8 rsvd_1 : 2; + u8 antidx_b : 3; + u8 antidx_a : 3; + u8 rsvd_2 : 2; + u8 antidx_d : 3; + u8 antidx_c : 3; +#endif + + /* DW3 */ + u8 paid; +#if (ODM_ENDIAN_TYPE == ODM_ENDIAN_LITTLE) + u8 paid_msb : 1; + u8 gid : 6; + u8 rsvd_3 : 1; +#else + u8 rsvd_3 : 1; + u8 gid : 6; + u8 paid_msb : 1; +#endif + u8 intf_pos; +#if (ODM_ENDIAN_TYPE == ODM_ENDIAN_LITTLE) + u8 intf_pos_msb : 1; + u8 rsvd_4 : 2; + u8 nb_intf_flag : 1; + u8 rf_mode : 2; + u8 rsvd_5 : 2; +#else + u8 rsvd_5 : 2; + u8 rf_mode : 2; + u8 nb_intf_flag : 1; + u8 rsvd_4 : 2; + u8 intf_pos_msb : 1; +#endif + + /* DW4 */ + s8 rxevm[4]; /* s(8,1) */ + + /* DW5 */ + s8 cfo_tail[4]; /* s(8,7) */ + + /* DW6 */ + s8 rxsnr[4]; /* s(8,1) */ +}; + +struct phy_status_rpt_jaguar2_type2 { + /* DW0 ane DW1 */ + u8 page_num; + u8 pwdb[4]; +#if (ODM_ENDIAN_TYPE == ODM_ENDIAN_LITTLE) + u8 l_rxsc : 4; + u8 ht_rxsc : 4; +#else + u8 ht_rxsc : 4; + u8 l_rxsc : 4; +#endif + u8 channel; +#if (ODM_ENDIAN_TYPE == ODM_ENDIAN_LITTLE) + u8 band : 2; + u8 rsvd_0 : 1; + u8 hw_antsw_occu : 1; + u8 gnt_bt : 1; + u8 ldpc : 1; + u8 stbc : 1; + u8 beamformed : 1; +#else + u8 beamformed : 1; + u8 stbc : 1; + u8 ldpc : 1; + u8 gnt_bt : 1; + u8 hw_antsw_occu : 1; + u8 rsvd_0 : 1; + u8 band : 2; +#endif + +/* DW2 */ +#if (ODM_ENDIAN_TYPE == ODM_ENDIAN_LITTLE) + u8 shift_l_map : 6; + u8 rsvd_1 : 2; +#else + u8 rsvd_1 : 2; + u8 shift_l_map : 6; +#endif + u8 cnt_pw2cca; +#if (ODM_ENDIAN_TYPE == ODM_ENDIAN_LITTLE) + u8 agc_table_a : 4; + u8 agc_table_b : 4; + u8 agc_table_c : 4; + u8 agc_table_d : 4; +#else + u8 agc_table_b : 4; + u8 agc_table_a : 4; + u8 agc_table_d : 4; + u8 agc_table_c : 4; +#endif + + /* DW3 ~ DW6*/ + u8 cnt_cca2agc_rdy; +#if (ODM_ENDIAN_TYPE == ODM_ENDIAN_LITTLE) + u8 gain_a : 6; + u8 rsvd_2 : 1; + u8 trsw_a : 1; + u8 gain_b : 6; + u8 rsvd_3 : 1; + u8 trsw_b : 1; + u8 gain_c : 6; + u8 rsvd_4 : 1; + u8 trsw_c : 1; + u8 gain_d : 6; + u8 rsvd_5 : 1; + u8 trsw_d : 1; + u8 aagc_step_a : 2; + u8 aagc_step_b : 2; + u8 aagc_step_c : 2; + u8 aagc_step_d : 2; +#else + u8 trsw_a : 1; + u8 rsvd_2 : 1; + u8 gain_a : 6; + u8 trsw_b : 1; + u8 rsvd_3 : 1; + u8 gain_b : 6; + u8 trsw_c : 1; + u8 rsvd_4 : 1; + u8 gain_c : 6; + u8 trsw_d : 1; + u8 rsvd_5 : 1; + u8 gain_d : 6; + u8 aagc_step_d : 2; + u8 aagc_step_c : 2; + u8 aagc_step_b : 2; + u8 aagc_step_a : 2; +#endif + u8 ht_aagc_gain[4]; + u8 dagc_gain[4]; +#if (ODM_ENDIAN_TYPE == ODM_ENDIAN_LITTLE) + u8 counter : 6; + u8 rsvd_6 : 2; + u8 syn_count : 5; + u8 rsvd_7 : 3; +#else + u8 rsvd_6 : 2; + u8 counter : 6; + u8 rsvd_7 : 3; + u8 syn_count : 5; +#endif +}; + +u32 query_phydm_trx_capability(struct phy_dm_struct *dm); + +u32 query_phydm_stbc_capability(struct phy_dm_struct *dm); + +u32 query_phydm_ldpc_capability(struct phy_dm_struct *dm); + +u32 query_phydm_txbf_parameters(struct phy_dm_struct *dm); + +u32 query_phydm_txbf_capability(struct phy_dm_struct *dm); + +#endif /*#ifndef __HALHWOUTSRC_H__*/ diff --git a/drivers/staging/rtlwifi/phydm/phydm_interface.c b/drivers/staging/rtlwifi/phydm/phydm_interface.c new file mode 100644 index 000000000000..102576a46c04 --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/phydm_interface.c @@ -0,0 +1,341 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +/* ************************************************************ + * include files + * *************************************************************/ + +#include "mp_precomp.h" +#include "phydm_precomp.h" + +/* + * ODM IO Relative API. + */ + +u8 odm_read_1byte(struct phy_dm_struct *dm, u32 reg_addr) +{ + struct rtl_priv *rtlpriv = (struct rtl_priv *)dm->adapter; + + return rtl_read_byte(rtlpriv, reg_addr); +} + +u16 odm_read_2byte(struct phy_dm_struct *dm, u32 reg_addr) +{ + struct rtl_priv *rtlpriv = (struct rtl_priv *)dm->adapter; + + return rtl_read_word(rtlpriv, reg_addr); +} + +u32 odm_read_4byte(struct phy_dm_struct *dm, u32 reg_addr) +{ + struct rtl_priv *rtlpriv = (struct rtl_priv *)dm->adapter; + + return rtl_read_dword(rtlpriv, reg_addr); +} + +void odm_write_1byte(struct phy_dm_struct *dm, u32 reg_addr, u8 data) +{ + struct rtl_priv *rtlpriv = (struct rtl_priv *)dm->adapter; + + rtl_write_byte(rtlpriv, reg_addr, data); +} + +void odm_write_2byte(struct phy_dm_struct *dm, u32 reg_addr, u16 data) +{ + struct rtl_priv *rtlpriv = (struct rtl_priv *)dm->adapter; + + rtl_write_word(rtlpriv, reg_addr, data); +} + +void odm_write_4byte(struct phy_dm_struct *dm, u32 reg_addr, u32 data) +{ + struct rtl_priv *rtlpriv = (struct rtl_priv *)dm->adapter; + + rtl_write_dword(rtlpriv, reg_addr, data); +} + +void odm_set_mac_reg(struct phy_dm_struct *dm, u32 reg_addr, u32 bit_mask, + u32 data) +{ + struct rtl_priv *rtlpriv = (struct rtl_priv *)dm->adapter; + + rtl_set_bbreg(rtlpriv->hw, reg_addr, bit_mask, data); +} + +u32 odm_get_mac_reg(struct phy_dm_struct *dm, u32 reg_addr, u32 bit_mask) +{ + struct rtl_priv *rtlpriv = (struct rtl_priv *)dm->adapter; + + return rtl_get_bbreg(rtlpriv->hw, reg_addr, bit_mask); +} + +void odm_set_bb_reg(struct phy_dm_struct *dm, u32 reg_addr, u32 bit_mask, + u32 data) +{ + struct rtl_priv *rtlpriv = (struct rtl_priv *)dm->adapter; + + rtl_set_bbreg(rtlpriv->hw, reg_addr, bit_mask, data); +} + +u32 odm_get_bb_reg(struct phy_dm_struct *dm, u32 reg_addr, u32 bit_mask) +{ + struct rtl_priv *rtlpriv = (struct rtl_priv *)dm->adapter; + + return rtl_get_bbreg(rtlpriv->hw, reg_addr, bit_mask); +} + +void odm_set_rf_reg(struct phy_dm_struct *dm, enum odm_rf_radio_path e_rf_path, + u32 reg_addr, u32 bit_mask, u32 data) +{ + struct rtl_priv *rtlpriv = (struct rtl_priv *)dm->adapter; + + rtl_set_rfreg(rtlpriv->hw, (enum radio_path)e_rf_path, reg_addr, + bit_mask, data); +} + +u32 odm_get_rf_reg(struct phy_dm_struct *dm, enum odm_rf_radio_path e_rf_path, + u32 reg_addr, u32 bit_mask) +{ + struct rtl_priv *rtlpriv = (struct rtl_priv *)dm->adapter; + + return rtl_get_rfreg(rtlpriv->hw, (enum radio_path)e_rf_path, reg_addr, + bit_mask); +} + +/* + * ODM Memory relative API. + */ +void odm_allocate_memory(struct phy_dm_struct *dm, void **ptr, u32 length) +{ + *ptr = kmalloc(length, GFP_ATOMIC); +} + +/* length could be ignored, used to detect memory leakage. */ +void odm_free_memory(struct phy_dm_struct *dm, void *ptr, u32 length) +{ + kfree(ptr); +} + +void odm_move_memory(struct phy_dm_struct *dm, void *p_dest, void *src, + u32 length) +{ + memcpy(p_dest, src, length); +} + +void odm_memory_set(struct phy_dm_struct *dm, void *pbuf, s8 value, u32 length) +{ + memset(pbuf, value, length); +} + +s32 odm_compare_memory(struct phy_dm_struct *dm, void *p_buf1, void *buf2, + u32 length) +{ + return memcmp(p_buf1, buf2, length); +} + +/* + * ODM MISC relative API. + */ +void odm_acquire_spin_lock(struct phy_dm_struct *dm, enum rt_spinlock_type type) +{ +} + +void odm_release_spin_lock(struct phy_dm_struct *dm, enum rt_spinlock_type type) +{ +} + +/* + * ODM Timer relative API. + */ +void odm_stall_execution(u32 us_delay) { udelay(us_delay); } + +void ODM_delay_ms(u32 ms) { mdelay(ms); } + +void ODM_delay_us(u32 us) { udelay(us); } + +void ODM_sleep_ms(u32 ms) { msleep(ms); } + +void ODM_sleep_us(u32 us) { usleep_range(us, us + 1); } + +void odm_set_timer(struct phy_dm_struct *dm, struct timer_list *timer, + u32 ms_delay) +{ + mod_timer(timer, jiffies + msecs_to_jiffies(ms_delay)); +} + +void odm_initialize_timer(struct phy_dm_struct *dm, struct timer_list *timer, + void *call_back_func, void *context, + const char *sz_id) +{ + init_timer(timer); + timer->function = call_back_func; + timer->data = (unsigned long)dm; + /*mod_timer(timer, jiffies+RTL_MILISECONDS_TO_JIFFIES(10)); */ +} + +void odm_cancel_timer(struct phy_dm_struct *dm, struct timer_list *timer) +{ + del_timer(timer); +} + +void odm_release_timer(struct phy_dm_struct *dm, struct timer_list *timer) {} + +static u8 phydm_trans_h2c_id(struct phy_dm_struct *dm, u8 phydm_h2c_id) +{ + u8 platform_h2c_id = phydm_h2c_id; + + switch (phydm_h2c_id) { + /* 1 [0] */ + case ODM_H2C_RSSI_REPORT: + + break; + + /* 1 [3] */ + case ODM_H2C_WIFI_CALIBRATION: + + break; + + /* 1 [4] */ + case ODM_H2C_IQ_CALIBRATION: + + break; + /* 1 [5] */ + case ODM_H2C_RA_PARA_ADJUST: + + break; + + /* 1 [6] */ + case PHYDM_H2C_DYNAMIC_TX_PATH: + + break; + + /* [7]*/ + case PHYDM_H2C_FW_TRACE_EN: + + platform_h2c_id = 0x49; + + break; + + case PHYDM_H2C_TXBF: + break; + + case PHYDM_H2C_MU: + platform_h2c_id = 0x4a; /*H2C_MU*/ + break; + + default: + platform_h2c_id = phydm_h2c_id; + break; + } + + return platform_h2c_id; +} + +/*ODM FW relative API.*/ + +void odm_fill_h2c_cmd(struct phy_dm_struct *dm, u8 phydm_h2c_id, u32 cmd_len, + u8 *cmd_buffer) +{ + struct rtl_priv *rtlpriv = (struct rtl_priv *)dm->adapter; + u8 platform_h2c_id; + + platform_h2c_id = phydm_trans_h2c_id(dm, phydm_h2c_id); + + ODM_RT_TRACE(dm, PHYDM_COMP_RA_DBG, + "[H2C] platform_h2c_id = ((0x%x))\n", platform_h2c_id); + + rtlpriv->cfg->ops->fill_h2c_cmd(rtlpriv->hw, platform_h2c_id, cmd_len, + cmd_buffer); +} + +u8 phydm_c2H_content_parsing(void *dm_void, u8 c2h_cmd_id, u8 c2h_cmd_len, + u8 *tmp_buf) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + u8 extend_c2h_sub_id = 0; + u8 find_c2h_cmd = true; + + switch (c2h_cmd_id) { + case PHYDM_C2H_DBG: + phydm_fw_trace_handler(dm, tmp_buf, c2h_cmd_len); + break; + + case PHYDM_C2H_RA_RPT: + phydm_c2h_ra_report_handler(dm, tmp_buf, c2h_cmd_len); + break; + + case PHYDM_C2H_RA_PARA_RPT: + odm_c2h_ra_para_report_handler(dm, tmp_buf, c2h_cmd_len); + break; + + case PHYDM_C2H_DYNAMIC_TX_PATH_RPT: + break; + + case PHYDM_C2H_IQK_FINISH: + break; + + case PHYDM_C2H_DBG_CODE: + phydm_fw_trace_handler_code(dm, tmp_buf, c2h_cmd_len); + break; + + case PHYDM_C2H_EXTEND: + extend_c2h_sub_id = tmp_buf[0]; + if (extend_c2h_sub_id == PHYDM_EXTEND_C2H_DBG_PRINT) + phydm_fw_trace_handler_8051(dm, tmp_buf, c2h_cmd_len); + + break; + + default: + find_c2h_cmd = false; + break; + } + + return find_c2h_cmd; +} + +u64 odm_get_current_time(struct phy_dm_struct *dm) { return jiffies; } + +u64 odm_get_progressing_time(struct phy_dm_struct *dm, u64 start_time) +{ + return jiffies_to_msecs(jiffies - (u32)start_time); +} + +void odm_set_tx_power_index_by_rate_section(struct phy_dm_struct *dm, + u8 rf_path, u8 channel, + u8 rate_section) +{ + void *adapter = dm->adapter; + + phy_set_tx_power_index_by_rs(adapter, channel, rf_path, rate_section); +} + +u8 odm_get_tx_power_index(struct phy_dm_struct *dm, u8 rf_path, u8 tx_rate, + u8 band_width, u8 channel) +{ + void *adapter = dm->adapter; + + return phy_get_tx_power_index(adapter, (enum odm_rf_radio_path)rf_path, + tx_rate, band_width, channel); +} diff --git a/drivers/staging/rtlwifi/phydm/phydm_interface.h b/drivers/staging/rtlwifi/phydm/phydm_interface.h new file mode 100644 index 000000000000..d315c79c962a --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/phydm_interface.h @@ -0,0 +1,205 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __ODM_INTERFACE_H__ +#define __ODM_INTERFACE_H__ + +#define INTERFACE_VERSION "1.1" /*2015.07.29 YuChen*/ + +/* + * =========== Constant/Structure/Enum/... Define + */ + +/* + * =========== Macro Define + */ + +#define _reg_all(_name) ODM_##_name +#define _reg_ic(_name, _ic) ODM_##_name##_ic +#define _bit_all(_name) BIT_##_name +#define _bit_ic(_name, _ic) BIT_##_name##_ic + +/* _cat: implemented by Token-Pasting Operator. */ + +/*=================================== + * + * #define ODM_REG_DIG_11N 0xC50 + * #define ODM_REG_DIG_11AC 0xDDD + * + * ODM_REG(DIG,_pdm_odm) + * =================================== + */ + +#define _reg_11N(_name) ODM_REG_##_name##_11N +#define _reg_11AC(_name) ODM_REG_##_name##_11AC +#define _bit_11N(_name) ODM_BIT_##_name##_11N +#define _bit_11AC(_name) ODM_BIT_##_name##_11AC + +#define _cat(_name, _ic_type, _func) \ + (((_ic_type) & ODM_IC_11N_SERIES) ? _func##_11N(_name) : \ + _func##_11AC(_name)) + +/* _name: name of register or bit. + * Example: "ODM_REG(R_A_AGC_CORE1, dm)" + * gets "ODM_R_A_AGC_CORE1" or "ODM_R_A_AGC_CORE1_8192C", + * depends on support_ic_type. + */ +#define ODM_REG(_name, _pdm_odm) _cat(_name, _pdm_odm->support_ic_type, _reg) +#define ODM_BIT(_name, _pdm_odm) _cat(_name, _pdm_odm->support_ic_type, _bit) +enum phydm_h2c_cmd { + PHYDM_H2C_TXBF = 0x41, + ODM_H2C_RSSI_REPORT = 0x42, + ODM_H2C_IQ_CALIBRATION = 0x45, + ODM_H2C_RA_PARA_ADJUST = 0x47, + PHYDM_H2C_DYNAMIC_TX_PATH = 0x48, + PHYDM_H2C_FW_TRACE_EN = 0x49, + ODM_H2C_WIFI_CALIBRATION = 0x6d, + PHYDM_H2C_MU = 0x4a, + ODM_MAX_H2CCMD +}; + +enum phydm_c2h_evt { + PHYDM_C2H_DBG = 0, + PHYDM_C2H_LB = 1, + PHYDM_C2H_XBF = 2, + PHYDM_C2H_TX_REPORT = 3, + PHYDM_C2H_INFO = 9, + PHYDM_C2H_BT_MP = 11, + PHYDM_C2H_RA_RPT = 12, + PHYDM_C2H_RA_PARA_RPT = 14, + PHYDM_C2H_DYNAMIC_TX_PATH_RPT = 15, + PHYDM_C2H_IQK_FINISH = 17, /*0x11*/ + PHYDM_C2H_DBG_CODE = 0xFE, + PHYDM_C2H_EXTEND = 0xFF, +}; + +enum phydm_extend_c2h_evt { + PHYDM_EXTEND_C2H_DBG_PRINT = 0 + +}; + +/* + * =========== Extern Variable ??? It should be forbidden. + */ + +/* + * =========== EXtern Function Prototype + */ + +u8 odm_read_1byte(struct phy_dm_struct *dm, u32 reg_addr); + +u16 odm_read_2byte(struct phy_dm_struct *dm, u32 reg_addr); + +u32 odm_read_4byte(struct phy_dm_struct *dm, u32 reg_addr); + +void odm_write_1byte(struct phy_dm_struct *dm, u32 reg_addr, u8 data); + +void odm_write_2byte(struct phy_dm_struct *dm, u32 reg_addr, u16 data); + +void odm_write_4byte(struct phy_dm_struct *dm, u32 reg_addr, u32 data); + +void odm_set_mac_reg(struct phy_dm_struct *dm, u32 reg_addr, u32 bit_mask, + u32 data); + +u32 odm_get_mac_reg(struct phy_dm_struct *dm, u32 reg_addr, u32 bit_mask); + +void odm_set_bb_reg(struct phy_dm_struct *dm, u32 reg_addr, u32 bit_mask, + u32 data); + +u32 odm_get_bb_reg(struct phy_dm_struct *dm, u32 reg_addr, u32 bit_mask); + +void odm_set_rf_reg(struct phy_dm_struct *dm, enum odm_rf_radio_path e_rf_path, + u32 reg_addr, u32 bit_mask, u32 data); + +u32 odm_get_rf_reg(struct phy_dm_struct *dm, enum odm_rf_radio_path e_rf_path, + u32 reg_addr, u32 bit_mask); + +/* + * Memory Relative Function. + */ +void odm_allocate_memory(struct phy_dm_struct *dm, void **ptr, u32 length); +void odm_free_memory(struct phy_dm_struct *dm, void *ptr, u32 length); + +void odm_move_memory(struct phy_dm_struct *dm, void *p_dest, void *src, + u32 length); + +s32 odm_compare_memory(struct phy_dm_struct *dm, void *p_buf1, void *buf2, + u32 length); + +void odm_memory_set(struct phy_dm_struct *dm, void *pbuf, s8 value, u32 length); + +/* + * ODM MISC-spin lock relative API. + */ +void odm_acquire_spin_lock(struct phy_dm_struct *dm, + enum rt_spinlock_type type); + +void odm_release_spin_lock(struct phy_dm_struct *dm, + enum rt_spinlock_type type); + +/* + * ODM Timer relative API. + */ +void odm_stall_execution(u32 us_delay); + +void ODM_delay_ms(u32 ms); + +void ODM_delay_us(u32 us); + +void ODM_sleep_ms(u32 ms); + +void ODM_sleep_us(u32 us); + +void odm_set_timer(struct phy_dm_struct *dm, struct timer_list *timer, + u32 ms_delay); + +void odm_initialize_timer(struct phy_dm_struct *dm, struct timer_list *timer, + void *call_back_func, void *context, + const char *sz_id); + +void odm_cancel_timer(struct phy_dm_struct *dm, struct timer_list *timer); + +void odm_release_timer(struct phy_dm_struct *dm, struct timer_list *timer); + +/* + * ODM FW relative API. + */ +void odm_fill_h2c_cmd(struct phy_dm_struct *dm, u8 element_id, u32 cmd_len, + u8 *cmd_buffer); + +u8 phydm_c2H_content_parsing(void *dm_void, u8 c2h_cmd_id, u8 c2h_cmd_len, + u8 *tmp_buf); + +u64 odm_get_current_time(struct phy_dm_struct *dm); +u64 odm_get_progressing_time(struct phy_dm_struct *dm, u64 start_time); + +void odm_set_tx_power_index_by_rate_section(struct phy_dm_struct *dm, + u8 rf_path, u8 channel, + u8 rate_section); + +u8 odm_get_tx_power_index(struct phy_dm_struct *dm, u8 rf_path, u8 tx_rate, + u8 band_width, u8 channel); + +#endif /* __ODM_INTERFACE_H__ */ diff --git a/drivers/staging/rtlwifi/phydm/phydm_iqk.h b/drivers/staging/rtlwifi/phydm/phydm_iqk.h new file mode 100644 index 000000000000..0d45bf099aeb --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/phydm_iqk.h @@ -0,0 +1,76 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __PHYDMIQK_H__ +#define __PHYDMIQK_H__ + +/*--------------------------Define Parameters-------------------------------*/ +#define LOK_delay 1 +#define WBIQK_delay 10 +#define TX_IQK 0 +#define RX_IQK 1 +#define TXIQK 0 +#define RXIQK1 1 +#define RXIQK2 2 +#define GSRXK1 0 +#define GSRXK2 1 +#define kcount_limit_80m 2 +#define kcount_limit_others 4 +#define rxiqk_gs_limit 4 + +#define NUM 4 +/*----------------------End Define Parameters-------------------------------*/ + +struct dm_iqk_info { + bool lok_fail[NUM]; + bool iqk_fail[2][NUM]; + u32 iqc_matrix[2][NUM]; + u8 iqk_times; + u32 rf_reg18; + u32 lna_idx; + u8 rxiqk_step; + u8 tmp1bcc; + u8 kcount; + + u32 iqk_channel[2]; + bool iqk_fail_report[2][4][2]; /*channel/path/TRX(TX:0, RX:1) */ + u32 iqk_cfir_real[2][4][2] + [8]; /*channel / path / TRX(TX:0, RX:1) / CFIR_real*/ + u32 iqk_cfir_imag[2][4][2] + [8]; /*channel / path / TRX(TX:0, RX:1) / CFIR_imag*/ + u8 retry_count[2][4][3]; /* channel / path / (TXK:0, RXK1:1, RXK2:2) */ + u8 gs_retry_count[2][4][2]; /* channel / path / (GSRXK1:0, GSRXK2:1) */ + u8 rxiqk_fail_code[2][4]; /* channel / path + * 0:SRXK1 fail, 1:RXK1 fail 2:RXK2 fail + */ + u32 lok_idac[2][4]; /*channel / path*/ + u16 rxiqk_agc[2][4]; /*channel / path*/ + u32 bypass_iqk[2][4]; /*channel / 0xc94/0xe94*/ + u32 tmp_gntwl; + bool is_btg; + bool isbnd; +}; + +#endif diff --git a/drivers/staging/rtlwifi/phydm/phydm_kfree.c b/drivers/staging/rtlwifi/phydm/phydm_kfree.c new file mode 100644 index 000000000000..5f3582341806 --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/phydm_kfree.c @@ -0,0 +1,228 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +/*============================================================*/ +/*include files*/ +/*============================================================*/ +#include "mp_precomp.h" +#include "phydm_precomp.h" + +/*<YuChen, 150720> Add for KFree Feature Requested by RF David.*/ +/*This is a phydm API*/ + +static void phydm_set_kfree_to_rf_8814a(void *dm_void, u8 e_rf_path, u8 data) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct dm_rf_calibration_struct *cali_info = &dm->rf_calibrate_info; + bool is_odd; + + if ((data % 2) != 0) { /*odd->positive*/ + data = data - 1; + odm_set_rf_reg(dm, e_rf_path, REG_RF_TX_GAIN_OFFSET, BIT(19), + 1); + is_odd = true; + } else { /*even->negative*/ + odm_set_rf_reg(dm, e_rf_path, REG_RF_TX_GAIN_OFFSET, BIT(19), + 0); + is_odd = false; + } + ODM_RT_TRACE(dm, ODM_COMP_MP, "%s(): RF_0x55[19]= %d\n", __func__, + is_odd); + switch (data) { + case 0: + odm_set_rf_reg(dm, e_rf_path, REG_RF_TX_GAIN_OFFSET, BIT(14), + 0); + odm_set_rf_reg(dm, e_rf_path, REG_RF_TX_GAIN_OFFSET, + BIT(17) | BIT(16) | BIT(15), 0); + cali_info->kfree_offset[e_rf_path] = 0; + break; + case 2: + odm_set_rf_reg(dm, e_rf_path, REG_RF_TX_GAIN_OFFSET, BIT(14), + 1); + odm_set_rf_reg(dm, e_rf_path, REG_RF_TX_GAIN_OFFSET, + BIT(17) | BIT(16) | BIT(15), 0); + cali_info->kfree_offset[e_rf_path] = 0; + break; + case 4: + odm_set_rf_reg(dm, e_rf_path, REG_RF_TX_GAIN_OFFSET, BIT(14), + 0); + odm_set_rf_reg(dm, e_rf_path, REG_RF_TX_GAIN_OFFSET, + BIT(17) | BIT(16) | BIT(15), 1); + cali_info->kfree_offset[e_rf_path] = 1; + break; + case 6: + odm_set_rf_reg(dm, e_rf_path, REG_RF_TX_GAIN_OFFSET, BIT(14), + 1); + odm_set_rf_reg(dm, e_rf_path, REG_RF_TX_GAIN_OFFSET, + BIT(17) | BIT(16) | BIT(15), 1); + cali_info->kfree_offset[e_rf_path] = 1; + break; + case 8: + odm_set_rf_reg(dm, e_rf_path, REG_RF_TX_GAIN_OFFSET, BIT(14), + 0); + odm_set_rf_reg(dm, e_rf_path, REG_RF_TX_GAIN_OFFSET, + BIT(17) | BIT(16) | BIT(15), 2); + cali_info->kfree_offset[e_rf_path] = 2; + break; + case 10: + odm_set_rf_reg(dm, e_rf_path, REG_RF_TX_GAIN_OFFSET, BIT(14), + 1); + odm_set_rf_reg(dm, e_rf_path, REG_RF_TX_GAIN_OFFSET, + BIT(17) | BIT(16) | BIT(15), 2); + cali_info->kfree_offset[e_rf_path] = 2; + break; + case 12: + odm_set_rf_reg(dm, e_rf_path, REG_RF_TX_GAIN_OFFSET, BIT(14), + 0); + odm_set_rf_reg(dm, e_rf_path, REG_RF_TX_GAIN_OFFSET, + BIT(17) | BIT(16) | BIT(15), 3); + cali_info->kfree_offset[e_rf_path] = 3; + break; + case 14: + odm_set_rf_reg(dm, e_rf_path, REG_RF_TX_GAIN_OFFSET, BIT(14), + 1); + odm_set_rf_reg(dm, e_rf_path, REG_RF_TX_GAIN_OFFSET, + BIT(17) | BIT(16) | BIT(15), 3); + cali_info->kfree_offset[e_rf_path] = 3; + break; + case 16: + odm_set_rf_reg(dm, e_rf_path, REG_RF_TX_GAIN_OFFSET, BIT(14), + 0); + odm_set_rf_reg(dm, e_rf_path, REG_RF_TX_GAIN_OFFSET, + BIT(17) | BIT(16) | BIT(15), 4); + cali_info->kfree_offset[e_rf_path] = 4; + break; + case 18: + odm_set_rf_reg(dm, e_rf_path, REG_RF_TX_GAIN_OFFSET, BIT(14), + 1); + odm_set_rf_reg(dm, e_rf_path, REG_RF_TX_GAIN_OFFSET, + BIT(17) | BIT(16) | BIT(15), 4); + cali_info->kfree_offset[e_rf_path] = 4; + break; + case 20: + odm_set_rf_reg(dm, e_rf_path, REG_RF_TX_GAIN_OFFSET, BIT(14), + 0); + odm_set_rf_reg(dm, e_rf_path, REG_RF_TX_GAIN_OFFSET, + BIT(17) | BIT(16) | BIT(15), 5); + cali_info->kfree_offset[e_rf_path] = 5; + break; + + default: + break; + } + + if (!is_odd) { + /*that means Kfree offset is negative, we need to record it.*/ + cali_info->kfree_offset[e_rf_path] = + (-1) * cali_info->kfree_offset[e_rf_path]; + ODM_RT_TRACE(dm, ODM_COMP_MP, "%s(): kfree_offset = %d\n", + __func__, cali_info->kfree_offset[e_rf_path]); + } else { + ODM_RT_TRACE(dm, ODM_COMP_MP, "%s(): kfree_offset = %d\n", + __func__, cali_info->kfree_offset[e_rf_path]); + } +} + +static void phydm_set_kfree_to_rf(void *dm_void, u8 e_rf_path, u8 data) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + + if (dm->support_ic_type & ODM_RTL8814A) + phydm_set_kfree_to_rf_8814a(dm, e_rf_path, data); +} + +void phydm_config_kfree(void *dm_void, u8 channel_to_sw, u8 *kfree_table) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct dm_rf_calibration_struct *cali_info = &dm->rf_calibrate_info; + u8 rfpath = 0, max_rf_path = 0; + u8 channel_idx = 0; + + if (dm->support_ic_type & ODM_RTL8814A) + max_rf_path = 4; /*0~3*/ + else if (dm->support_ic_type & + (ODM_RTL8812 | ODM_RTL8192E | ODM_RTL8822B)) + max_rf_path = 2; /*0~1*/ + else + max_rf_path = 1; + + ODM_RT_TRACE(dm, ODM_COMP_MP, "===>%s()\n", __func__); + + if (cali_info->reg_rf_kfree_enable == 2) { + ODM_RT_TRACE(dm, ODM_COMP_MP, + "%s(): reg_rf_kfree_enable == 2, Disable\n", + __func__); + return; + } + + if (cali_info->reg_rf_kfree_enable != 1 && + cali_info->reg_rf_kfree_enable != 0) { + ODM_RT_TRACE(dm, ODM_COMP_MP, "<===%s()\n", __func__); + return; + } + + ODM_RT_TRACE(dm, ODM_COMP_MP, "%s(): reg_rf_kfree_enable == true\n", + __func__); + /*Make sure the targetval is defined*/ + if (((cali_info->reg_rf_kfree_enable == 1) && + (kfree_table[0] != 0xFF)) || + cali_info->rf_kfree_enable) { + /*if kfree_table[0] == 0xff, means no Kfree*/ + if (*dm->band_type == ODM_BAND_2_4G) { + if (channel_to_sw <= 14 && channel_to_sw >= 1) + channel_idx = PHYDM_2G; + } else if (*dm->band_type == ODM_BAND_5G) { + if (channel_to_sw >= 36 && channel_to_sw <= 48) + channel_idx = PHYDM_5GLB1; + if (channel_to_sw >= 52 && channel_to_sw <= 64) + channel_idx = PHYDM_5GLB2; + if (channel_to_sw >= 100 && channel_to_sw <= 120) + channel_idx = PHYDM_5GMB1; + if (channel_to_sw >= 124 && channel_to_sw <= 144) + channel_idx = PHYDM_5GMB2; + if (channel_to_sw >= 149 && channel_to_sw <= 177) + channel_idx = PHYDM_5GHB; + } + + for (rfpath = ODM_RF_PATH_A; rfpath < max_rf_path; rfpath++) { + ODM_RT_TRACE(dm, ODM_COMP_MP, "%s(): PATH_%d: %#x\n", + __func__, rfpath, + kfree_table[channel_idx * max_rf_path + + rfpath]); + phydm_set_kfree_to_rf( + dm, rfpath, + kfree_table[channel_idx * max_rf_path + + rfpath]); + } + } else { + ODM_RT_TRACE( + dm, ODM_COMP_MP, + "%s(): targetval not defined, Don't execute KFree Process.\n", + __func__); + return; + } + + ODM_RT_TRACE(dm, ODM_COMP_MP, "<===%s()\n", __func__); +} diff --git a/drivers/staging/rtlwifi/phydm/phydm_kfree.h b/drivers/staging/rtlwifi/phydm/phydm_kfree.h new file mode 100644 index 000000000000..1ee60059afc1 --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/phydm_kfree.h @@ -0,0 +1,42 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __PHYDMKFREE_H__ +#define __PHYDKFREE_H__ + +#define KFREE_VERSION "1.0" + +enum phydm_kfree_channeltosw { + PHYDM_2G = 0, + PHYDM_5GLB1 = 1, + PHYDM_5GLB2 = 2, + PHYDM_5GMB1 = 3, + PHYDM_5GMB2 = 4, + PHYDM_5GHB = 5, +}; + +void phydm_config_kfree(void *dm_void, u8 channel_to_sw, u8 *kfree_table); + +#endif diff --git a/drivers/staging/rtlwifi/phydm/phydm_noisemonitor.c b/drivers/staging/rtlwifi/phydm/phydm_noisemonitor.c new file mode 100644 index 000000000000..8d79a5add1b4 --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/phydm_noisemonitor.c @@ -0,0 +1,330 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +/* ************************************************************ + * include files + * *************************************************************/ +#include "mp_precomp.h" +#include "phydm_precomp.h" +#include "phydm_noisemonitor.h" + +/* ************************************************* + * This function is for inband noise test utility only + * To obtain the inband noise level(dbm), do the following. + * 1. disable DIG and Power Saving + * 2. Set initial gain = 0x1a + * 3. Stop updating idle time pwer report (for driver read) + * - 0x80c[25] + * + * **************************************************/ + +#define VALID_MIN -35 +#define VALID_MAX 10 +#define VALID_CNT 5 + +static inline void phydm_set_noise_data_sum(struct noise_level *noise_data, + u8 max_rf_path) +{ + u8 rf_path; + + for (rf_path = ODM_RF_PATH_A; rf_path < max_rf_path; rf_path++) { + if (noise_data->valid_cnt[rf_path]) + noise_data->sum[rf_path] /= + noise_data->valid_cnt[rf_path]; + else + noise_data->sum[rf_path] = 0; + } +} + +static s16 odm_inband_noise_monitor_n_series(struct phy_dm_struct *dm, + u8 is_pause_dig, u8 igi_value, + u32 max_time) +{ + u32 tmp4b; + u8 max_rf_path = 0, rf_path; + u8 reg_c50, reg_c58, valid_done = 0; + struct noise_level noise_data; + u64 start = 0, func_start = 0, func_end = 0; + + func_start = odm_get_current_time(dm); + dm->noise_level.noise_all = 0; + + if ((dm->rf_type == ODM_1T2R) || (dm->rf_type == ODM_2T2R)) + max_rf_path = 2; + else + max_rf_path = 1; + + ODM_RT_TRACE(dm, ODM_COMP_COMMON, "%s() ==>\n", __func__); + + odm_memory_set(dm, &noise_data, 0, sizeof(struct noise_level)); + + /* */ + /* step 1. Disable DIG && Set initial gain. */ + /* */ + + if (is_pause_dig) + odm_pause_dig(dm, PHYDM_PAUSE, PHYDM_PAUSE_LEVEL_1, igi_value); + /* */ + /* step 2. Disable all power save for read registers */ + /* */ + /* dcmd_DebugControlPowerSave(adapter, PSDisable); */ + + /* */ + /* step 3. Get noise power level */ + /* */ + start = odm_get_current_time(dm); + while (1) { + /* Stop updating idle time pwer report (for driver read) */ + odm_set_bb_reg(dm, REG_FPGA0_TX_GAIN_STAGE, BIT(25), 1); + + /* Read Noise Floor Report */ + tmp4b = odm_get_bb_reg(dm, 0x8f8, MASKDWORD); + ODM_RT_TRACE(dm, ODM_COMP_COMMON, + "Noise Floor Report (0x8f8) = 0x%08x\n", tmp4b); + + /* update idle time pwer report per 5us */ + odm_set_bb_reg(dm, REG_FPGA0_TX_GAIN_STAGE, BIT(25), 0); + + noise_data.value[ODM_RF_PATH_A] = (u8)(tmp4b & 0xff); + noise_data.value[ODM_RF_PATH_B] = (u8)((tmp4b & 0xff00) >> 8); + + ODM_RT_TRACE(dm, ODM_COMP_COMMON, + "value_a = 0x%x(%d), value_b = 0x%x(%d)\n", + noise_data.value[ODM_RF_PATH_A], + noise_data.value[ODM_RF_PATH_A], + noise_data.value[ODM_RF_PATH_B], + noise_data.value[ODM_RF_PATH_B]); + + for (rf_path = ODM_RF_PATH_A; rf_path < max_rf_path; + rf_path++) { + noise_data.sval[rf_path] = + (s8)noise_data.value[rf_path]; + noise_data.sval[rf_path] /= 2; + } + + ODM_RT_TRACE(dm, ODM_COMP_COMMON, "sval_a = %d, sval_b = %d\n", + noise_data.sval[ODM_RF_PATH_A], + noise_data.sval[ODM_RF_PATH_B]); + + for (rf_path = ODM_RF_PATH_A; rf_path < max_rf_path; + rf_path++) { + if (!(noise_data.valid_cnt[rf_path] < VALID_CNT) || + !(noise_data.sval[rf_path] < VALID_MAX && + noise_data.sval[rf_path] >= VALID_MIN)) { + continue; + } + + noise_data.valid_cnt[rf_path]++; + noise_data.sum[rf_path] += noise_data.sval[rf_path]; + ODM_RT_TRACE(dm, ODM_COMP_COMMON, + "rf_path:%d Valid sval = %d\n", rf_path, + noise_data.sval[rf_path]); + ODM_RT_TRACE(dm, ODM_COMP_COMMON, "Sum of sval = %d,\n", + noise_data.sum[rf_path]); + if (noise_data.valid_cnt[rf_path] == VALID_CNT) { + valid_done++; + ODM_RT_TRACE( + dm, ODM_COMP_COMMON, + "After divided, rf_path:%d,sum = %d\n", + rf_path, noise_data.sum[rf_path]); + } + } + + if ((valid_done == max_rf_path) || + (odm_get_progressing_time(dm, start) > max_time)) { + phydm_set_noise_data_sum(&noise_data, max_rf_path); + break; + } + } + reg_c50 = (u8)odm_get_bb_reg(dm, REG_OFDM_0_XA_AGC_CORE1, MASKBYTE0); + reg_c50 &= ~BIT(7); + ODM_RT_TRACE(dm, ODM_COMP_COMMON, "0x%x = 0x%02x(%d)\n", + REG_OFDM_0_XA_AGC_CORE1, reg_c50, reg_c50); + dm->noise_level.noise[ODM_RF_PATH_A] = + (u8)(-110 + reg_c50 + noise_data.sum[ODM_RF_PATH_A]); + dm->noise_level.noise_all += dm->noise_level.noise[ODM_RF_PATH_A]; + + if (max_rf_path == 2) { + reg_c58 = (u8)odm_get_bb_reg(dm, REG_OFDM_0_XB_AGC_CORE1, + MASKBYTE0); + reg_c58 &= ~BIT(7); + ODM_RT_TRACE(dm, ODM_COMP_COMMON, "0x%x = 0x%02x(%d)\n", + REG_OFDM_0_XB_AGC_CORE1, reg_c58, reg_c58); + dm->noise_level.noise[ODM_RF_PATH_B] = + (u8)(-110 + reg_c58 + noise_data.sum[ODM_RF_PATH_B]); + dm->noise_level.noise_all += + dm->noise_level.noise[ODM_RF_PATH_B]; + } + dm->noise_level.noise_all /= max_rf_path; + + ODM_RT_TRACE(dm, ODM_COMP_COMMON, "noise_a = %d, noise_b = %d\n", + dm->noise_level.noise[ODM_RF_PATH_A], + dm->noise_level.noise[ODM_RF_PATH_B]); + + /* */ + /* step 4. Recover the Dig */ + /* */ + if (is_pause_dig) + odm_pause_dig(dm, PHYDM_RESUME, PHYDM_PAUSE_LEVEL_1, igi_value); + func_end = odm_get_progressing_time(dm, func_start); + + ODM_RT_TRACE(dm, ODM_COMP_COMMON, "%s() <==\n", __func__); + return dm->noise_level.noise_all; +} + +static s16 odm_inband_noise_monitor_ac_series(struct phy_dm_struct *dm, + u8 is_pause_dig, u8 igi_value, + u32 max_time) +{ + s32 rxi_buf_anta, rxq_buf_anta; /*rxi_buf_antb, rxq_buf_antb;*/ + s32 value32, pwdb_A = 0, sval, noise, sum; + bool pd_flag; + u8 valid_cnt; + u64 start = 0, func_start = 0, func_end = 0; + + if (!(dm->support_ic_type & (ODM_RTL8812 | ODM_RTL8821 | ODM_RTL8814A))) + return 0; + + func_start = odm_get_current_time(dm); + dm->noise_level.noise_all = 0; + + ODM_RT_TRACE(dm, ODM_COMP_COMMON, "%s() ==>\n", __func__); + + /* step 1. Disable DIG && Set initial gain. */ + if (is_pause_dig) + odm_pause_dig(dm, PHYDM_PAUSE, PHYDM_PAUSE_LEVEL_1, igi_value); + + /* step 2. Disable all power save for read registers */ + /*dcmd_DebugControlPowerSave(adapter, PSDisable); */ + + /* step 3. Get noise power level */ + start = odm_get_current_time(dm); + + /* reset counters */ + sum = 0; + valid_cnt = 0; + + /* step 3. Get noise power level */ + while (1) { + /*Set IGI=0x1C */ + odm_write_dig(dm, 0x1C); + /*stop CK320&CK88 */ + odm_set_bb_reg(dm, 0x8B4, BIT(6), 1); + /*Read path-A */ + odm_set_bb_reg(dm, 0x8FC, MASKDWORD, 0x200); /*set debug port*/ + value32 = odm_get_bb_reg(dm, 0xFA0, + MASKDWORD); /*read debug port*/ + + rxi_buf_anta = (value32 & 0xFFC00) >> + 10; /*rxi_buf_anta=RegFA0[19:10]*/ + rxq_buf_anta = value32 & 0x3FF; /*rxq_buf_anta=RegFA0[19:10]*/ + + pd_flag = (bool)((value32 & BIT(31)) >> 31); + + /*Not in packet detection period or Tx state */ + if ((!pd_flag) || (rxi_buf_anta != 0x200)) { + /*sign conversion*/ + rxi_buf_anta = odm_sign_conversion(rxi_buf_anta, 10); + rxq_buf_anta = odm_sign_conversion(rxq_buf_anta, 10); + + pwdb_A = odm_pwdb_conversion( + rxi_buf_anta * rxi_buf_anta + + rxq_buf_anta * rxq_buf_anta, + 20, 18); /*S(10,9)*S(10,9)=S(20,18)*/ + + ODM_RT_TRACE( + dm, ODM_COMP_COMMON, + "pwdb_A= %d dB, rxi_buf_anta= 0x%x, rxq_buf_anta= 0x%x\n", + pwdb_A, rxi_buf_anta & 0x3FF, + rxq_buf_anta & 0x3FF); + } + /*Start CK320&CK88*/ + odm_set_bb_reg(dm, 0x8B4, BIT(6), 0); + /*BB Reset*/ + odm_write_1byte(dm, 0x02, odm_read_1byte(dm, 0x02) & (~BIT(0))); + odm_write_1byte(dm, 0x02, odm_read_1byte(dm, 0x02) | BIT(0)); + /*PMAC Reset*/ + odm_write_1byte(dm, 0xB03, + odm_read_1byte(dm, 0xB03) & (~BIT(0))); + odm_write_1byte(dm, 0xB03, odm_read_1byte(dm, 0xB03) | BIT(0)); + /*CCK Reset*/ + if (odm_read_1byte(dm, 0x80B) & BIT(4)) { + odm_write_1byte(dm, 0x80B, + odm_read_1byte(dm, 0x80B) & (~BIT(4))); + odm_write_1byte(dm, 0x80B, + odm_read_1byte(dm, 0x80B) | BIT(4)); + } + + sval = pwdb_A; + + if ((sval < 0 && sval >= -27) && (valid_cnt < VALID_CNT)) { + valid_cnt++; + sum += sval; + ODM_RT_TRACE(dm, ODM_COMP_COMMON, "Valid sval = %d\n", + sval); + ODM_RT_TRACE(dm, ODM_COMP_COMMON, "Sum of sval = %d,\n", + sum); + if ((valid_cnt >= VALID_CNT) || + (odm_get_progressing_time(dm, start) > max_time)) { + sum /= VALID_CNT; + ODM_RT_TRACE(dm, ODM_COMP_COMMON, + "After divided, sum = %d\n", sum); + break; + } + } + } + + /*ADC backoff is 12dB,*/ + /*Ptarget=0x1C-110=-82dBm*/ + noise = sum + 12 + 0x1C - 110; + + /*Offset*/ + noise = noise - 3; + ODM_RT_TRACE(dm, ODM_COMP_COMMON, "noise = %d\n", noise); + dm->noise_level.noise_all = (s16)noise; + + /* step 4. Recover the Dig*/ + if (is_pause_dig) + odm_pause_dig(dm, PHYDM_RESUME, PHYDM_PAUSE_LEVEL_1, igi_value); + + func_end = odm_get_progressing_time(dm, func_start); + + ODM_RT_TRACE(dm, ODM_COMP_COMMON, "%s() <==\n", __func__); + + return dm->noise_level.noise_all; +} + +s16 odm_inband_noise_monitor(void *dm_void, u8 is_pause_dig, u8 igi_value, + u32 max_time) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + + if (dm->support_ic_type & ODM_IC_11AC_SERIES) + return odm_inband_noise_monitor_ac_series(dm, is_pause_dig, + igi_value, max_time); + else + return odm_inband_noise_monitor_n_series(dm, is_pause_dig, + igi_value, max_time); +} diff --git a/drivers/staging/rtlwifi/phydm/phydm_noisemonitor.h b/drivers/staging/rtlwifi/phydm/phydm_noisemonitor.h new file mode 100644 index 000000000000..a711b7954985 --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/phydm_noisemonitor.h @@ -0,0 +1,46 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef __ODMNOISEMONITOR_H__ +#define __ODMNOISEMONITOR_H__ + +#define ODM_MAX_CHANNEL_NUM 38 /* 14+24 */ +struct noise_level { + u8 value[MAX_RF_PATH]; + s8 sval[MAX_RF_PATH]; + + s32 sum[MAX_RF_PATH]; + u8 valid[MAX_RF_PATH]; + u8 valid_cnt[MAX_RF_PATH]; +}; + +struct odm_noise_monitor { + s8 noise[MAX_RF_PATH]; + s16 noise_all; +}; + +s16 odm_inband_noise_monitor(void *dm_void, u8 is_pause_dig, u8 igi_value, + u32 max_time); + +#endif diff --git a/drivers/staging/rtlwifi/phydm/phydm_powertracking_ce.c b/drivers/staging/rtlwifi/phydm/phydm_powertracking_ce.c new file mode 100644 index 000000000000..48e73eb1622b --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/phydm_powertracking_ce.c @@ -0,0 +1,644 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +/*============================================================ */ +/* include files */ +/*============================================================ */ +#include "mp_precomp.h" +#include "phydm_precomp.h" + +/* ************************************************************ + * Global var + * *************************************************************/ + +u32 ofdm_swing_table[OFDM_TABLE_SIZE] = { + 0x7f8001fe, /* 0, +6.0dB */ + 0x788001e2, /* 1, +5.5dB */ + 0x71c001c7, /* 2, +5.0dB*/ + 0x6b8001ae, /* 3, +4.5dB*/ + 0x65400195, /* 4, +4.0dB*/ + 0x5fc0017f, /* 5, +3.5dB*/ + 0x5a400169, /* 6, +3.0dB*/ + 0x55400155, /* 7, +2.5dB*/ + 0x50800142, /* 8, +2.0dB*/ + 0x4c000130, /* 9, +1.5dB*/ + 0x47c0011f, /* 10, +1.0dB*/ + 0x43c0010f, /* 11, +0.5dB*/ + 0x40000100, /* 12, +0dB*/ + 0x3c8000f2, /* 13, -0.5dB*/ + 0x390000e4, /* 14, -1.0dB*/ + 0x35c000d7, /* 15, -1.5dB*/ + 0x32c000cb, /* 16, -2.0dB*/ + 0x300000c0, /* 17, -2.5dB*/ + 0x2d4000b5, /* 18, -3.0dB*/ + 0x2ac000ab, /* 19, -3.5dB*/ + 0x288000a2, /* 20, -4.0dB*/ + 0x26000098, /* 21, -4.5dB*/ + 0x24000090, /* 22, -5.0dB*/ + 0x22000088, /* 23, -5.5dB*/ + 0x20000080, /* 24, -6.0dB*/ + 0x1e400079, /* 25, -6.5dB*/ + 0x1c800072, /* 26, -7.0dB*/ + 0x1b00006c, /* 27. -7.5dB*/ + 0x19800066, /* 28, -8.0dB*/ + 0x18000060, /* 29, -8.5dB*/ + 0x16c0005b, /* 30, -9.0dB*/ + 0x15800056, /* 31, -9.5dB*/ + 0x14400051, /* 32, -10.0dB*/ + 0x1300004c, /* 33, -10.5dB*/ + 0x12000048, /* 34, -11.0dB*/ + 0x11000044, /* 35, -11.5dB*/ + 0x10000040, /* 36, -12.0dB*/ +}; + +u8 cck_swing_table_ch1_ch13[CCK_TABLE_SIZE][8] = { + {0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04}, /* 0, +0dB */ + {0x33, 0x32, 0x2b, 0x23, 0x1a, 0x11, 0x08, 0x04}, /* 1, -0.5dB */ + {0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03}, /* 2, -1.0dB*/ + {0x2d, 0x2d, 0x27, 0x1f, 0x18, 0x0f, 0x08, 0x03}, /* 3, -1.5dB*/ + {0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03}, /* 4, -2.0dB */ + {0x28, 0x28, 0x22, 0x1c, 0x15, 0x0d, 0x07, 0x03}, /* 5, -2.5dB*/ + {0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03}, /* 6, -3.0dB*/ + {0x24, 0x23, 0x1f, 0x19, 0x13, 0x0c, 0x06, 0x03}, /* 7, -3.5dB*/ + {0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02}, /* 8, -4.0dB */ + {0x20, 0x20, 0x1b, 0x16, 0x11, 0x08, 0x05, 0x02}, /* 9, -4.5dB*/ + {0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02}, /* 10, -5.0dB */ + {0x1d, 0x1c, 0x18, 0x14, 0x0f, 0x0a, 0x05, 0x02}, /* 11, -5.5dB*/ + {0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, + 0x02}, /* 12, -6.0dB <== default */ + {0x1a, 0x19, 0x16, 0x12, 0x0d, 0x09, 0x04, 0x02}, /* 13, -6.5dB*/ + {0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02}, /* 14, -7.0dB */ + {0x17, 0x16, 0x13, 0x10, 0x0c, 0x08, 0x04, 0x02}, /* 15, -7.5dB*/ + {0x16, 0x15, 0x12, 0x0f, 0x0b, 0x07, 0x04, 0x01}, /* 16, -8.0dB */ + {0x14, 0x14, 0x11, 0x0e, 0x0b, 0x07, 0x03, 0x02}, /* 17, -8.5dB*/ + {0x13, 0x13, 0x10, 0x0d, 0x0a, 0x06, 0x03, 0x01}, /* 18, -9.0dB */ + {0x12, 0x12, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, /* 19, -9.5dB*/ + {0x11, 0x11, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, /* 20, -10.0dB*/ + {0x10, 0x10, 0x0e, 0x0b, 0x08, 0x05, 0x03, 0x01}, /* 21, -10.5dB*/ + {0x0f, 0x0f, 0x0d, 0x0b, 0x08, 0x05, 0x03, 0x01}, /* 22, -11.0dB*/ + {0x0e, 0x0e, 0x0c, 0x0a, 0x08, 0x05, 0x02, 0x01}, /* 23, -11.5dB*/ + {0x0d, 0x0d, 0x0c, 0x0a, 0x07, 0x05, 0x02, 0x01}, /* 24, -12.0dB*/ + {0x0d, 0x0c, 0x0b, 0x09, 0x07, 0x04, 0x02, 0x01}, /* 25, -12.5dB*/ + {0x0c, 0x0c, 0x0a, 0x09, 0x06, 0x04, 0x02, 0x01}, /* 26, -13.0dB*/ + {0x0b, 0x0b, 0x0a, 0x08, 0x06, 0x04, 0x02, 0x01}, /* 27, -13.5dB*/ + {0x0b, 0x0a, 0x09, 0x08, 0x06, 0x04, 0x02, 0x01}, /* 28, -14.0dB*/ + {0x0a, 0x0a, 0x09, 0x07, 0x05, 0x03, 0x02, 0x01}, /* 29, -14.5dB*/ + {0x0a, 0x09, 0x08, 0x07, 0x05, 0x03, 0x02, 0x01}, /* 30, -15.0dB*/ + {0x09, 0x09, 0x08, 0x06, 0x05, 0x03, 0x01, 0x01}, /* 31, -15.5dB*/ + {0x09, 0x08, 0x07, 0x06, 0x04, 0x03, 0x01, 0x01} /* 32, -16.0dB*/ +}; + +u8 cck_swing_table_ch14[CCK_TABLE_SIZE][8] = { + {0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00}, /* 0, +0dB */ + {0x33, 0x32, 0x2b, 0x19, 0x00, 0x00, 0x00, 0x00}, /* 1, -0.5dB */ + {0x30, 0x2f, 0x29, 0x18, 0x00, 0x00, 0x00, 0x00}, /* 2, -1.0dB */ + {0x2d, 0x2d, 0x17, 0x17, 0x00, 0x00, 0x00, 0x00}, /* 3, -1.5dB*/ + {0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00}, /* 4, -2.0dB */ + {0x28, 0x28, 0x24, 0x14, 0x00, 0x00, 0x00, 0x00}, /* 5, -2.5dB*/ + {0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00}, /* 6, -3.0dB */ + {0x24, 0x23, 0x1f, 0x12, 0x00, 0x00, 0x00, 0x00}, /* 7, -3.5dB */ + {0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00}, /* 8, -4.0dB */ + {0x20, 0x20, 0x1b, 0x10, 0x00, 0x00, 0x00, 0x00}, /* 9, -4.5dB*/ + {0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00}, /* 10, -5.0dB */ + {0x1d, 0x1c, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00}, /* 11, -5.5dB*/ + {0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, + 0x00}, /* 12, -6.0dB <== default*/ + {0x1a, 0x19, 0x16, 0x0d, 0x00, 0x00, 0x00, 0x00}, /* 13, -6.5dB */ + {0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00}, /* 14, -7.0dB */ + {0x17, 0x16, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x00}, /* 15, -7.5dB*/ + {0x16, 0x15, 0x12, 0x0b, 0x00, 0x00, 0x00, 0x00}, /* 16, -8.0dB */ + {0x14, 0x14, 0x11, 0x0a, 0x00, 0x00, 0x00, 0x00}, /* 17, -8.5dB*/ + {0x13, 0x13, 0x10, 0x0a, 0x00, 0x00, 0x00, 0x00}, /* 18, -9.0dB */ + {0x12, 0x12, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, /* 19, -9.5dB*/ + {0x11, 0x11, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, /* 20, -10.0dB*/ + {0x10, 0x10, 0x0e, 0x08, 0x00, 0x00, 0x00, 0x00}, /* 21, -10.5dB*/ + {0x0f, 0x0f, 0x0d, 0x08, 0x00, 0x00, 0x00, 0x00}, /* 22, -11.0dB*/ + {0x0e, 0x0e, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, /* 23, -11.5dB*/ + {0x0d, 0x0d, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, /* 24, -12.0dB*/ + {0x0d, 0x0c, 0x0b, 0x06, 0x00, 0x00, 0x00, 0x00}, /* 25, -12.5dB*/ + {0x0c, 0x0c, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, /* 26, -13.0dB*/ + {0x0b, 0x0b, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, /* 27, -13.5dB*/ + {0x0b, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 28, -14.0dB*/ + {0x0a, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 29, -14.5dB*/ + {0x0a, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 30, -15.0dB*/ + {0x09, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 31, -15.5dB*/ + {0x09, 0x08, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00} /* 32, -16.0dB*/ +}; + +u32 ofdm_swing_table_new[OFDM_TABLE_SIZE] = { + 0x0b40002d, /* 0, -15.0dB */ + 0x0c000030, /* 1, -14.5dB*/ + 0x0cc00033, /* 2, -14.0dB*/ + 0x0d800036, /* 3, -13.5dB*/ + 0x0e400039, /* 4, -13.0dB */ + 0x0f00003c, /* 5, -12.5dB*/ + 0x10000040, /* 6, -12.0dB*/ + 0x11000044, /* 7, -11.5dB*/ + 0x12000048, /* 8, -11.0dB*/ + 0x1300004c, /* 9, -10.5dB*/ + 0x14400051, /* 10, -10.0dB*/ + 0x15800056, /* 11, -9.5dB*/ + 0x16c0005b, /* 12, -9.0dB*/ + 0x18000060, /* 13, -8.5dB*/ + 0x19800066, /* 14, -8.0dB*/ + 0x1b00006c, /* 15, -7.5dB*/ + 0x1c800072, /* 16, -7.0dB*/ + 0x1e400079, /* 17, -6.5dB*/ + 0x20000080, /* 18, -6.0dB*/ + 0x22000088, /* 19, -5.5dB*/ + 0x24000090, /* 20, -5.0dB*/ + 0x26000098, /* 21, -4.5dB*/ + 0x288000a2, /* 22, -4.0dB*/ + 0x2ac000ab, /* 23, -3.5dB*/ + 0x2d4000b5, /* 24, -3.0dB*/ + 0x300000c0, /* 25, -2.5dB*/ + 0x32c000cb, /* 26, -2.0dB*/ + 0x35c000d7, /* 27, -1.5dB*/ + 0x390000e4, /* 28, -1.0dB*/ + 0x3c8000f2, /* 29, -0.5dB*/ + 0x40000100, /* 30, +0dB*/ + 0x43c0010f, /* 31, +0.5dB*/ + 0x47c0011f, /* 32, +1.0dB*/ + 0x4c000130, /* 33, +1.5dB*/ + 0x50800142, /* 34, +2.0dB*/ + 0x55400155, /* 35, +2.5dB*/ + 0x5a400169, /* 36, +3.0dB*/ + 0x5fc0017f, /* 37, +3.5dB*/ + 0x65400195, /* 38, +4.0dB*/ + 0x6b8001ae, /* 39, +4.5dB*/ + 0x71c001c7, /* 40, +5.0dB*/ + 0x788001e2, /* 41, +5.5dB*/ + 0x7f8001fe /* 42, +6.0dB*/ +}; + +u8 cck_swing_table_ch1_ch14_88f[CCK_TABLE_SIZE_88F][16] = { + {0x44, 0x42, 0x3C, 0x33, 0x28, 0x1C, 0x13, 0x0B, 0x05, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-16dB*/ + {0x48, 0x46, 0x3F, 0x36, 0x2A, 0x1E, 0x14, 0x0B, 0x05, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-15.5dB*/ + {0x4D, 0x4A, 0x43, 0x39, 0x2C, 0x20, 0x15, 0x0C, 0x06, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-15dB*/ + {0x51, 0x4F, 0x47, 0x3C, 0x2F, 0x22, 0x16, 0x0D, 0x06, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-14.5dB*/ + {0x56, 0x53, 0x4B, 0x40, 0x32, 0x24, 0x17, 0x0E, 0x06, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-14dB*/ + {0x5B, 0x58, 0x50, 0x43, 0x35, 0x26, 0x19, 0x0E, 0x07, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-13.5dB*/ + {0x60, 0x5D, 0x54, 0x47, 0x38, 0x28, 0x1A, 0x0F, 0x07, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-13dB*/ + {0x66, 0x63, 0x59, 0x4C, 0x3B, 0x2B, 0x1C, 0x10, 0x08, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-12.5dB*/ + {0x6C, 0x69, 0x5F, 0x50, 0x3F, 0x2D, 0x1E, 0x11, 0x08, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-12dB*/ + {0x73, 0x6F, 0x64, 0x55, 0x42, 0x30, 0x1F, 0x12, 0x08, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-11.5dB*/ + {0x79, 0x76, 0x6A, 0x5A, 0x46, 0x33, 0x21, 0x13, 0x09, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-11dB*/ + {0x81, 0x7C, 0x71, 0x5F, 0x4A, 0x36, 0x23, 0x14, 0x0A, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-10.5dB*/ + {0x88, 0x84, 0x77, 0x65, 0x4F, 0x39, 0x25, 0x15, 0x0A, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-10dB*/ + {0x90, 0x8C, 0x7E, 0x6B, 0x54, 0x3C, 0x27, 0x17, 0x0B, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-9.5dB*/ + {0x99, 0x94, 0x86, 0x71, 0x58, 0x40, 0x2A, 0x18, 0x0B, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-9dB*/ + {0xA2, 0x9D, 0x8E, 0x78, 0x5E, 0x43, 0x2C, 0x19, 0x0C, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-8.5dB*/ + {0xAC, 0xA6, 0x96, 0x7F, 0x63, 0x47, 0x2F, 0x1B, 0x0D, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-8dB*/ + {0xB6, 0xB0, 0x9F, 0x87, 0x69, 0x4C, 0x32, 0x1D, 0x0D, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-7.5dB*/ + {0xC1, 0xBA, 0xA8, 0x8F, 0x6F, 0x50, 0x35, 0x1E, 0x0E, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-7dB*/ + {0xCC, 0xC5, 0xB2, 0x97, 0x76, 0x55, 0x38, 0x20, 0x0F, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-6.5dB*/ + {0xD8, 0xD1, 0xBD, 0xA0, 0x7D, 0x5A, 0x3B, 0x22, 0x10, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00} /*-6dB*/ +}; + +u8 cck_swing_table_ch1_ch13_88f[CCK_TABLE_SIZE_88F][16] = { + {0x44, 0x42, 0x3C, 0x33, 0x28, 0x1C, 0x13, 0x0B, 0x05, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-16dB*/ + {0x48, 0x46, 0x3F, 0x36, 0x2A, 0x1E, 0x14, 0x0B, 0x05, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-15.5dB*/ + {0x4D, 0x4A, 0x43, 0x39, 0x2C, 0x20, 0x15, 0x0C, 0x06, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-15dB*/ + {0x51, 0x4F, 0x47, 0x3C, 0x2F, 0x22, 0x16, 0x0D, 0x06, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-14.5dB*/ + {0x56, 0x53, 0x4B, 0x40, 0x32, 0x24, 0x17, 0x0E, 0x06, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-14dB*/ + {0x5B, 0x58, 0x50, 0x43, 0x35, 0x26, 0x19, 0x0E, 0x07, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-13.5dB*/ + {0x60, 0x5D, 0x54, 0x47, 0x38, 0x28, 0x1A, 0x0F, 0x07, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-13dB*/ + {0x66, 0x63, 0x59, 0x4C, 0x3B, 0x2B, 0x1C, 0x10, 0x08, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-12.5dB*/ + {0x6C, 0x69, 0x5F, 0x50, 0x3F, 0x2D, 0x1E, 0x11, 0x08, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-12dB*/ + {0x73, 0x6F, 0x64, 0x55, 0x42, 0x30, 0x1F, 0x12, 0x08, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-11.5dB*/ + {0x79, 0x76, 0x6A, 0x5A, 0x46, 0x33, 0x21, 0x13, 0x09, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-11dB*/ + {0x81, 0x7C, 0x71, 0x5F, 0x4A, 0x36, 0x23, 0x14, 0x0A, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-10.5dB*/ + {0x88, 0x84, 0x77, 0x65, 0x4F, 0x39, 0x25, 0x15, 0x0A, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-10dB*/ + {0x90, 0x8C, 0x7E, 0x6B, 0x54, 0x3C, 0x27, 0x17, 0x0B, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-9.5dB*/ + {0x99, 0x94, 0x86, 0x71, 0x58, 0x40, 0x2A, 0x18, 0x0B, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-9dB*/ + {0xA2, 0x9D, 0x8E, 0x78, 0x5E, 0x43, 0x2C, 0x19, 0x0C, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-8.5dB*/ + {0xAC, 0xA6, 0x96, 0x7F, 0x63, 0x47, 0x2F, 0x1B, 0x0D, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-8dB*/ + {0xB6, 0xB0, 0x9F, 0x87, 0x69, 0x4C, 0x32, 0x1D, 0x0D, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-7.5dB*/ + {0xC1, 0xBA, 0xA8, 0x8F, 0x6F, 0x50, 0x35, 0x1E, 0x0E, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-7dB*/ + {0xCC, 0xC5, 0xB2, 0x97, 0x76, 0x55, 0x38, 0x20, 0x0F, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-6.5dB*/ + {0xD8, 0xD1, 0xBD, 0xA0, 0x7D, 0x5A, 0x3B, 0x22, 0x10, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00} /*-6dB*/ +}; + +u8 cck_swing_table_ch14_88f[CCK_TABLE_SIZE_88F][16] = { + {0x44, 0x42, 0x3C, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-16dB*/ + {0x48, 0x46, 0x3F, 0x2A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-15.5dB*/ + {0x4D, 0x4A, 0x43, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-15dB*/ + {0x51, 0x4F, 0x47, 0x2F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-14.5dB*/ + {0x56, 0x53, 0x4B, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-14dB*/ + {0x5B, 0x58, 0x50, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-13.5dB*/ + {0x60, 0x5D, 0x54, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-13dB*/ + {0x66, 0x63, 0x59, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-12.5dB*/ + {0x6C, 0x69, 0x5F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-12dB*/ + {0x73, 0x6F, 0x64, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-11.5dB*/ + {0x79, 0x76, 0x6A, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-11dB*/ + {0x81, 0x7C, 0x71, 0x4A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-10.5dB*/ + {0x88, 0x84, 0x77, 0x4F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-10dB*/ + {0x90, 0x8C, 0x7E, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-9.5dB*/ + {0x99, 0x94, 0x86, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-9dB*/ + {0xA2, 0x9D, 0x8E, 0x5E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-8.5dB*/ + {0xAC, 0xA6, 0x96, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-8dB*/ + {0xB6, 0xB0, 0x9F, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-7.5dB*/ + {0xC1, 0xBA, 0xA8, 0x6F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-7dB*/ + {0xCC, 0xC5, 0xB2, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, /*-6.5dB*/ + {0xD8, 0xD1, 0xBD, 0x7D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00} /*-6dB*/ +}; + +u8 cck_swing_table_ch1_ch13_new[CCK_TABLE_SIZE][8] = { + {0x09, 0x08, 0x07, 0x06, 0x04, 0x03, 0x01, 0x01}, /* 0, -16.0dB*/ + {0x09, 0x09, 0x08, 0x06, 0x05, 0x03, 0x01, 0x01}, /* 1, -15.5dB*/ + {0x0a, 0x09, 0x08, 0x07, 0x05, 0x03, 0x02, 0x01}, /* 2, -15.0dB*/ + {0x0a, 0x0a, 0x09, 0x07, 0x05, 0x03, 0x02, 0x01}, /* 3, -14.5dB*/ + {0x0b, 0x0a, 0x09, 0x08, 0x06, 0x04, 0x02, 0x01}, /* 4, -14.0dB*/ + {0x0b, 0x0b, 0x0a, 0x08, 0x06, 0x04, 0x02, 0x01}, /* 5, -13.5dB*/ + {0x0c, 0x0c, 0x0a, 0x09, 0x06, 0x04, 0x02, 0x01}, /* 6, -13.0dB*/ + {0x0d, 0x0c, 0x0b, 0x09, 0x07, 0x04, 0x02, 0x01}, /* 7, -12.5dB*/ + {0x0d, 0x0d, 0x0c, 0x0a, 0x07, 0x05, 0x02, 0x01}, /* 8, -12.0dB*/ + {0x0e, 0x0e, 0x0c, 0x0a, 0x08, 0x05, 0x02, 0x01}, /* 9, -11.5dB*/ + {0x0f, 0x0f, 0x0d, 0x0b, 0x08, 0x05, 0x03, 0x01}, /* 10, -11.0dB*/ + {0x10, 0x10, 0x0e, 0x0b, 0x08, 0x05, 0x03, 0x01}, /* 11, -10.5dB*/ + {0x11, 0x11, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, /* 12, -10.0dB*/ + {0x12, 0x12, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, /* 13, -9.5dB*/ + {0x13, 0x13, 0x10, 0x0d, 0x0a, 0x06, 0x03, 0x01}, /* 14, -9.0dB */ + {0x14, 0x14, 0x11, 0x0e, 0x0b, 0x07, 0x03, 0x02}, /* 15, -8.5dB*/ + {0x16, 0x15, 0x12, 0x0f, 0x0b, 0x07, 0x04, 0x01}, /* 16, -8.0dB */ + {0x17, 0x16, 0x13, 0x10, 0x0c, 0x08, 0x04, 0x02}, /* 17, -7.5dB*/ + {0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02}, /* 18, -7.0dB */ + {0x1a, 0x19, 0x16, 0x12, 0x0d, 0x09, 0x04, 0x02}, /* 19, -6.5dB*/ + {0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02}, /*20, -6.0dB */ + {0x1d, 0x1c, 0x18, 0x14, 0x0f, 0x0a, 0x05, 0x02}, /* 21, -5.5dB*/ + {0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02}, /* 22, -5.0dB */ + {0x20, 0x20, 0x1b, 0x16, 0x11, 0x08, 0x05, 0x02}, /* 23, -4.5dB*/ + {0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02}, /* 24, -4.0dB */ + {0x24, 0x23, 0x1f, 0x19, 0x13, 0x0c, 0x06, 0x03}, /* 25, -3.5dB*/ + {0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03}, /* 26, -3.0dB*/ + {0x28, 0x28, 0x22, 0x1c, 0x15, 0x0d, 0x07, 0x03}, /* 27, -2.5dB*/ + {0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03}, /* 28, -2.0dB */ + {0x2d, 0x2d, 0x27, 0x1f, 0x18, 0x0f, 0x08, 0x03}, /* 29, -1.5dB*/ + {0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03}, /* 30, -1.0dB*/ + {0x33, 0x32, 0x2b, 0x23, 0x1a, 0x11, 0x08, 0x04}, /* 31, -0.5dB*/ + {0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04} /* 32, +0dB*/ +}; + +u8 cck_swing_table_ch14_new[CCK_TABLE_SIZE][8] = { + {0x09, 0x08, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00}, /* 0, -16.0dB*/ + {0x09, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 1, -15.5dB*/ + {0x0a, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 2, -15.0dB*/ + {0x0a, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 3, -14.5dB*/ + {0x0b, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 4, -14.0dB*/ + {0x0b, 0x0b, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, /*5, -13.5dB*/ + {0x0c, 0x0c, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, /* 6, -13.0dB*/ + {0x0d, 0x0c, 0x0b, 0x06, 0x00, 0x00, 0x00, 0x00}, /* 7, -12.5dB*/ + {0x0d, 0x0d, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, /* 8, -12.0dB*/ + {0x0e, 0x0e, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, /* 9, -11.5dB*/ + {0x0f, 0x0f, 0x0d, 0x08, 0x00, 0x00, 0x00, 0x00}, /* 10, -11.0dB*/ + {0x10, 0x10, 0x0e, 0x08, 0x00, 0x00, 0x00, 0x00}, /*11, -10.5dB*/ + {0x11, 0x11, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, /* 12, -10.0dB*/ + {0x12, 0x12, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, /* 13, -9.5dB*/ + {0x13, 0x13, 0x10, 0x0a, 0x00, 0x00, 0x00, 0x00}, /*14, -9.0dB */ + {0x14, 0x14, 0x11, 0x0a, 0x00, 0x00, 0x00, 0x00}, /* 15, -8.5dB*/ + {0x16, 0x15, 0x12, 0x0b, 0x00, 0x00, 0x00, 0x00}, /* 16, -8.0dB */ + {0x17, 0x16, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x00}, /* 17, -7.5dB*/ + {0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00}, /* 18, -7.0dB */ + {0x1a, 0x19, 0x16, 0x0d, 0x00, 0x00, 0x00, 0x00}, /* 19, -6.5dB */ + {0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00}, /* 20, -6.0dB */ + {0x1d, 0x1c, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00}, /* 21, -5.5dB*/ + {0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00}, /* 22, -5.0dB */ + {0x20, 0x20, 0x1b, 0x10, 0x00, 0x00, 0x00, 0x00}, /*23, -4.5dB*/ + {0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00}, /* 24, -4.0dB */ + {0x24, 0x23, 0x1f, 0x12, 0x00, 0x00, 0x00, 0x00}, /* 25, -3.5dB */ + {0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00}, /* 26, -3.0dB */ + {0x28, 0x28, 0x24, 0x14, 0x00, 0x00, 0x00, 0x00}, /*27, -2.5dB*/ + {0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00}, /* 28, -2.0dB */ + {0x2d, 0x2d, 0x17, 0x17, 0x00, 0x00, 0x00, 0x00}, /*29, -1.5dB*/ + {0x30, 0x2f, 0x29, 0x18, 0x00, 0x00, 0x00, 0x00}, /* 30, -1.0dB */ + {0x33, 0x32, 0x2b, 0x19, 0x00, 0x00, 0x00, 0x00}, /* 31, -0.5dB */ + {0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00} /* 32, +0dB */ +}; + +u32 cck_swing_table_ch1_ch14_8723d[CCK_TABLE_SIZE_8723D] = { + 0x0CD, /*0 , -20dB*/ + 0x0D9, 0x0E6, 0x0F3, 0x102, 0x111, 0x121, 0x132, 0x144, 0x158, 0x16C, + 0x182, 0x198, 0x1B1, 0x1CA, 0x1E5, 0x202, 0x221, 0x241, 0x263, 0x287, + 0x2AE, 0x2D6, 0x301, 0x32F, 0x35F, 0x392, 0x3C9, 0x402, 0x43F, 0x47F, + 0x4C3, 0x50C, 0x558, 0x5A9, 0x5FF, 0x65A, 0x6BA, 0x720, 0x78C, 0x7FF, +}; + +/* JJ ADD 20161014 */ +u32 cck_swing_table_ch1_ch14_8710b[CCK_TABLE_SIZE_8710B] = { + 0x0CD, /*0 , -20dB*/ + 0x0D9, 0x0E6, 0x0F3, 0x102, 0x111, 0x121, 0x132, 0x144, 0x158, 0x16C, + 0x182, 0x198, 0x1B1, 0x1CA, 0x1E5, 0x202, 0x221, 0x241, 0x263, 0x287, + 0x2AE, 0x2D6, 0x301, 0x32F, 0x35F, 0x392, 0x3C9, 0x402, 0x43F, 0x47F, + 0x4C3, 0x50C, 0x558, 0x5A9, 0x5FF, 0x65A, 0x6BA, 0x720, 0x78C, 0x7FF, +}; + +u32 tx_scaling_table_jaguar[TXSCALE_TABLE_SIZE] = { + 0x081, /* 0, -12.0dB*/ + 0x088, /* 1, -11.5dB*/ + 0x090, /* 2, -11.0dB*/ + 0x099, /* 3, -10.5dB*/ + 0x0A2, /* 4, -10.0dB*/ + 0x0AC, /* 5, -9.5dB*/ + 0x0B6, /* 6, -9.0dB*/ + 0x0C0, /*7, -8.5dB*/ + 0x0CC, /* 8, -8.0dB*/ + 0x0D8, /* 9, -7.5dB*/ + 0x0E5, /* 10, -7.0dB*/ + 0x0F2, /* 11, -6.5dB*/ + 0x101, /* 12, -6.0dB*/ + 0x110, /* 13, -5.5dB*/ + 0x120, /* 14, -5.0dB*/ + 0x131, /* 15, -4.5dB*/ + 0x143, /* 16, -4.0dB*/ + 0x156, /* 17, -3.5dB*/ + 0x16A, /* 18, -3.0dB*/ + 0x180, /* 19, -2.5dB*/ + 0x197, /* 20, -2.0dB*/ + 0x1AF, /* 21, -1.5dB*/ + 0x1C8, /* 22, -1.0dB*/ + 0x1E3, /* 23, -0.5dB*/ + 0x200, /* 24, +0 dB*/ + 0x21E, /* 25, +0.5dB*/ + 0x23E, /* 26, +1.0dB*/ + 0x261, /* 27, +1.5dB*/ + 0x285, /* 28, +2.0dB*/ + 0x2AB, /* 29, +2.5dB*/ + 0x2D3, /*30, +3.0dB*/ + 0x2FE, /* 31, +3.5dB*/ + 0x32B, /* 32, +4.0dB*/ + 0x35C, /* 33, +4.5dB*/ + 0x38E, /* 34, +5.0dB*/ + 0x3C4, /* 35, +5.5dB*/ + 0x3FE /* 36, +6.0dB */ +}; + +void odm_txpowertracking_init(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + + odm_txpowertracking_thermal_meter_init(dm); +} + +static u8 get_swing_index(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + u8 i = 0; + u32 bb_swing; + u32 swing_table_size; + u32 *swing_table; + + if (dm->support_ic_type == ODM_RTL8188E || + dm->support_ic_type == ODM_RTL8723B || + dm->support_ic_type == ODM_RTL8192E || + dm->support_ic_type == ODM_RTL8188F || + dm->support_ic_type == ODM_RTL8703B) { + bb_swing = odm_get_bb_reg(dm, REG_OFDM_0_XA_TX_IQ_IMBALANCE, + 0xFFC00000); + + swing_table = ofdm_swing_table_new; + swing_table_size = OFDM_TABLE_SIZE; + } else { + { + bb_swing = 0; + swing_table = ofdm_swing_table; + swing_table_size = OFDM_TABLE_SIZE; + } + } + + for (i = 0; i < swing_table_size; ++i) { + u32 table_value = swing_table[i]; + + if (table_value >= 0x100000) + table_value >>= 22; + if (bb_swing == table_value) + break; + } + return i; +} + +void odm_txpowertracking_thermal_meter_init(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + u8 default_swing_index = get_swing_index(dm); + u8 p = 0; + struct dm_rf_calibration_struct *cali_info = &dm->rf_calibrate_info; + struct rtl_priv *rtlpriv = (struct rtl_priv *)dm->adapter; + struct rtl_efuse *rtlefu = rtl_efuse(rtlpriv); + + cali_info->is_txpowertracking = true; + cali_info->tx_powercount = 0; + cali_info->is_txpowertracking_init = false; + + if (!dm->mp_mode) + cali_info->txpowertrack_control = true; + else + cali_info->txpowertrack_control = false; + + if (!dm->mp_mode) + cali_info->txpowertrack_control = true; + + ODM_RT_TRACE(dm, ODM_COMP_CALIBRATION, "dm txpowertrack_control = %d\n", + cali_info->txpowertrack_control); + + /* dm->rf_calibrate_info.txpowertrack_control = true; */ + cali_info->thermal_value = rtlefu->eeprom_thermalmeter; + cali_info->thermal_value_iqk = rtlefu->eeprom_thermalmeter; + cali_info->thermal_value_lck = rtlefu->eeprom_thermalmeter; + + if (!cali_info->default_bb_swing_index_flag) { + /*The index of "0 dB" in SwingTable.*/ + if (dm->support_ic_type == ODM_RTL8188E || + dm->support_ic_type == ODM_RTL8723B || + dm->support_ic_type == ODM_RTL8192E || + dm->support_ic_type == ODM_RTL8703B) { + cali_info->default_ofdm_index = + (default_swing_index >= OFDM_TABLE_SIZE) ? + 30 : + default_swing_index; + cali_info->default_cck_index = 20; + } else if (dm->support_ic_type == + ODM_RTL8188F) { /*add by Mingzhi.Guo 2015-03-23*/ + cali_info->default_ofdm_index = 28; /*OFDM: -1dB*/ + cali_info->default_cck_index = 20; /*CCK:-6dB*/ + } else if (dm->support_ic_type == + ODM_RTL8723D) { /*add by zhaohe 2015-10-27*/ + cali_info->default_ofdm_index = 28; /*OFDM: -1dB*/ + cali_info->default_cck_index = 28; /*CCK: -6dB*/ + } else if (dm->support_ic_type == + ODM_RTL8710B) { /* JJ ADD 20161014 */ + cali_info->default_ofdm_index = 28; /*OFDM: -1dB*/ + cali_info->default_cck_index = 28; /*CCK: -6dB*/ + } else { + cali_info->default_ofdm_index = + (default_swing_index >= TXSCALE_TABLE_SIZE) ? + 24 : + default_swing_index; + cali_info->default_cck_index = 24; + } + cali_info->default_bb_swing_index_flag = true; + } + + cali_info->bb_swing_idx_cck_base = cali_info->default_cck_index; + cali_info->CCK_index = cali_info->default_cck_index; + + for (p = ODM_RF_PATH_A; p < MAX_RF_PATH; ++p) { + cali_info->bb_swing_idx_ofdm_base[p] = + cali_info->default_ofdm_index; + cali_info->OFDM_index[p] = cali_info->default_ofdm_index; + cali_info->delta_power_index[p] = 0; + cali_info->delta_power_index_last[p] = 0; + cali_info->power_index_offset[p] = 0; + } + cali_info->modify_tx_agc_value_ofdm = 0; + cali_info->modify_tx_agc_value_cck = 0; +} + +void odm_txpowertracking_check(void *dm_void) +{ + /* 2011/09/29 MH In HW integration first stage, we provide 4 different + * handle to operate at the same time. + * In the stage2/3, we need to prive universal interface and merge all + * HW dynamic mechanism. + */ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + + switch (dm->support_platform) { + case ODM_WIN: + odm_txpowertracking_check_mp(dm); + break; + + case ODM_CE: + odm_txpowertracking_check_ce(dm); + break; + + case ODM_AP: + odm_txpowertracking_check_ap(dm); + break; + + default: + break; + } +} + +void odm_txpowertracking_check_ce(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + void *adapter = dm->adapter; + + if (!(dm->support_ability & ODM_RF_TX_PWR_TRACK)) + return; + + if (!dm->rf_calibrate_info.tm_trigger) { + if (IS_HARDWARE_TYPE_8188E(adapter) || + IS_HARDWARE_TYPE_8188F(adapter) || + IS_HARDWARE_TYPE_8192E(adapter) || + IS_HARDWARE_TYPE_8723B(adapter) || + IS_HARDWARE_TYPE_JAGUAR(adapter) || + IS_HARDWARE_TYPE_8814A(adapter) || + IS_HARDWARE_TYPE_8703B(adapter) || + IS_HARDWARE_TYPE_8723D(adapter) || + IS_HARDWARE_TYPE_8822B(adapter) || + IS_HARDWARE_TYPE_8821C(adapter) || + (dm->support_ic_type == ODM_RTL8710B)) /* JJ ADD 20161014 */ + odm_set_rf_reg(dm, ODM_RF_PATH_A, RF_T_METER_NEW, + (BIT(17) | BIT(16)), 0x03); + else + odm_set_rf_reg(dm, ODM_RF_PATH_A, RF_T_METER_OLD, + RFREGOFFSETMASK, 0x60); + + dm->rf_calibrate_info.tm_trigger = 1; + return; + } + + odm_txpowertracking_callback_thermal_meter(dm); + dm->rf_calibrate_info.tm_trigger = 0; +} + +void odm_txpowertracking_check_mp(void *dm_void) {} + +void odm_txpowertracking_check_ap(void *dm_void) {} diff --git a/drivers/staging/rtlwifi/phydm/phydm_powertracking_ce.h b/drivers/staging/rtlwifi/phydm/phydm_powertracking_ce.h new file mode 100644 index 000000000000..757d7720d931 --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/phydm_powertracking_ce.h @@ -0,0 +1,293 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __PHYDMPOWERTRACKING_H__ +#define __PHYDMPOWERTRACKING_H__ + +#define POWRTRACKING_VERSION "1.1" + +#define DPK_DELTA_MAPPING_NUM 13 +#define index_mapping_HP_NUM 15 +#define OFDM_TABLE_SIZE 43 +#define CCK_TABLE_SIZE 33 +#define CCK_TABLE_SIZE_88F 21 +#define TXSCALE_TABLE_SIZE 37 +#define CCK_TABLE_SIZE_8723D 41 +/* JJ ADD 20161014 */ +#define CCK_TABLE_SIZE_8710B 41 + +#define TXPWR_TRACK_TABLE_SIZE 30 +#define DELTA_SWINGIDX_SIZE 30 +#define DELTA_SWINTSSI_SIZE 61 +#define BAND_NUM 4 + +#define AVG_THERMAL_NUM 8 +#define HP_THERMAL_NUM 8 +#define IQK_MAC_REG_NUM 4 +#define IQK_ADDA_REG_NUM 16 +#define IQK_BB_REG_NUM_MAX 10 + +#define IQK_BB_REG_NUM 9 + +#define iqk_matrix_reg_num 8 + +extern u32 ofdm_swing_table[OFDM_TABLE_SIZE]; +extern u8 cck_swing_table_ch1_ch13[CCK_TABLE_SIZE][8]; +extern u8 cck_swing_table_ch14[CCK_TABLE_SIZE][8]; + +extern u32 ofdm_swing_table_new[OFDM_TABLE_SIZE]; +extern u8 cck_swing_table_ch1_ch13_new[CCK_TABLE_SIZE][8]; +extern u8 cck_swing_table_ch14_new[CCK_TABLE_SIZE][8]; +extern u8 cck_swing_table_ch1_ch14_88f[CCK_TABLE_SIZE_88F][16]; +extern u8 cck_swing_table_ch1_ch13_88f[CCK_TABLE_SIZE_88F][16]; +extern u8 cck_swing_table_ch14_88f[CCK_TABLE_SIZE_88F][16]; +extern u32 cck_swing_table_ch1_ch14_8723d[CCK_TABLE_SIZE_8723D]; +/* JJ ADD 20161014 */ +extern u32 cck_swing_table_ch1_ch14_8710b[CCK_TABLE_SIZE_8710B]; + +extern u32 tx_scaling_table_jaguar[TXSCALE_TABLE_SIZE]; + +/* <20121018, Kordan> In case fail to read TxPowerTrack.txt, + * we use the table of 88E as the default table. + */ + +#define dm_check_txpowertracking odm_txpowertracking_check + +struct iqk_matrix_regs_setting { + bool is_iqk_done; + s32 value[3][iqk_matrix_reg_num]; + bool is_bw_iqk_result_saved[3]; +}; + +struct dm_rf_calibration_struct { + /* for tx power tracking */ + + u32 rega24; /* for TempCCK */ + s32 rege94; + s32 rege9c; + s32 regeb4; + s32 regebc; + + u8 tx_powercount; + bool is_txpowertracking_init; + bool is_txpowertracking; + /* for mp mode, turn off txpwrtracking as default */ + u8 txpowertrack_control; + u8 tm_trigger; + u8 internal_pa_5g[2]; /* pathA / pathB */ + + u8 thermal_meter + [2]; /* thermal_meter, index 0 for RFIC0, and 1 for RFIC1 */ + u8 thermal_value; + u8 thermal_value_lck; + u8 thermal_value_iqk; + s8 thermal_value_delta; /* delta of thermal_value and efuse thermal */ + u8 thermal_value_dpk; + u8 thermal_value_avg[AVG_THERMAL_NUM]; + u8 thermal_value_avg_index; + u8 thermal_value_rx_gain; + u8 thermal_value_crystal; + u8 thermal_value_dpk_store; + u8 thermal_value_dpk_track; + bool txpowertracking_in_progress; + + bool is_reloadtxpowerindex; + u8 is_rf_pi_enable; + u32 txpowertracking_callback_cnt; /* cosa add for debug */ + + /* ---------------------- Tx power Tracking ------------------------- */ + u8 is_cck_in_ch14; + u8 CCK_index; + u8 OFDM_index[MAX_RF_PATH]; + s8 power_index_offset[MAX_RF_PATH]; + s8 delta_power_index[MAX_RF_PATH]; + s8 delta_power_index_last[MAX_RF_PATH]; + bool is_tx_power_changed; + s8 xtal_offset; + s8 xtal_offset_last; + + u8 thermal_value_hp[HP_THERMAL_NUM]; + u8 thermal_value_hp_index; + struct iqk_matrix_regs_setting + iqk_matrix_reg_setting[IQK_MATRIX_SETTINGS_NUM]; + u8 delta_lck; + s8 bb_swing_diff_2g, bb_swing_diff_5g; /* Unit: dB */ + u8 delta_swing_table_idx_2g_cck_a_p[DELTA_SWINGIDX_SIZE]; + u8 delta_swing_table_idx_2g_cck_a_n[DELTA_SWINGIDX_SIZE]; + u8 delta_swing_table_idx_2g_cck_b_p[DELTA_SWINGIDX_SIZE]; + u8 delta_swing_table_idx_2g_cck_b_n[DELTA_SWINGIDX_SIZE]; + u8 delta_swing_table_idx_2g_cck_c_p[DELTA_SWINGIDX_SIZE]; + u8 delta_swing_table_idx_2g_cck_c_n[DELTA_SWINGIDX_SIZE]; + u8 delta_swing_table_idx_2g_cck_d_p[DELTA_SWINGIDX_SIZE]; + u8 delta_swing_table_idx_2g_cck_d_n[DELTA_SWINGIDX_SIZE]; + u8 delta_swing_table_idx_2ga_p[DELTA_SWINGIDX_SIZE]; + u8 delta_swing_table_idx_2ga_n[DELTA_SWINGIDX_SIZE]; + u8 delta_swing_table_idx_2gb_p[DELTA_SWINGIDX_SIZE]; + u8 delta_swing_table_idx_2gb_n[DELTA_SWINGIDX_SIZE]; + u8 delta_swing_table_idx_2gc_p[DELTA_SWINGIDX_SIZE]; + u8 delta_swing_table_idx_2gc_n[DELTA_SWINGIDX_SIZE]; + u8 delta_swing_table_idx_2gd_p[DELTA_SWINGIDX_SIZE]; + u8 delta_swing_table_idx_2gd_n[DELTA_SWINGIDX_SIZE]; + u8 delta_swing_table_idx_5ga_p[BAND_NUM][DELTA_SWINGIDX_SIZE]; + u8 delta_swing_table_idx_5ga_n[BAND_NUM][DELTA_SWINGIDX_SIZE]; + u8 delta_swing_table_idx_5gb_p[BAND_NUM][DELTA_SWINGIDX_SIZE]; + u8 delta_swing_table_idx_5gb_n[BAND_NUM][DELTA_SWINGIDX_SIZE]; + u8 delta_swing_table_idx_5gc_p[BAND_NUM][DELTA_SWINGIDX_SIZE]; + u8 delta_swing_table_idx_5gc_n[BAND_NUM][DELTA_SWINGIDX_SIZE]; + u8 delta_swing_table_idx_5gd_p[BAND_NUM][DELTA_SWINGIDX_SIZE]; + u8 delta_swing_table_idx_5gd_n[BAND_NUM][DELTA_SWINGIDX_SIZE]; + u8 delta_swing_tssi_table_2g_cck_a[DELTA_SWINTSSI_SIZE]; + u8 delta_swing_tssi_table_2g_cck_b[DELTA_SWINTSSI_SIZE]; + u8 delta_swing_tssi_table_2g_cck_c[DELTA_SWINTSSI_SIZE]; + u8 delta_swing_tssi_table_2g_cck_d[DELTA_SWINTSSI_SIZE]; + u8 delta_swing_tssi_table_2ga[DELTA_SWINTSSI_SIZE]; + u8 delta_swing_tssi_table_2gb[DELTA_SWINTSSI_SIZE]; + u8 delta_swing_tssi_table_2gc[DELTA_SWINTSSI_SIZE]; + u8 delta_swing_tssi_table_2gd[DELTA_SWINTSSI_SIZE]; + u8 delta_swing_tssi_table_5ga[BAND_NUM][DELTA_SWINTSSI_SIZE]; + u8 delta_swing_tssi_table_5gb[BAND_NUM][DELTA_SWINTSSI_SIZE]; + u8 delta_swing_tssi_table_5gc[BAND_NUM][DELTA_SWINTSSI_SIZE]; + u8 delta_swing_tssi_table_5gd[BAND_NUM][DELTA_SWINTSSI_SIZE]; + s8 delta_swing_table_xtal_p[DELTA_SWINGIDX_SIZE]; + s8 delta_swing_table_xtal_n[DELTA_SWINGIDX_SIZE]; + u8 delta_swing_table_idx_2ga_p_8188e[DELTA_SWINGIDX_SIZE]; + u8 delta_swing_table_idx_2ga_n_8188e[DELTA_SWINGIDX_SIZE]; + + u8 bb_swing_idx_ofdm[MAX_RF_PATH]; + u8 bb_swing_idx_ofdm_current; + u8 bb_swing_idx_ofdm_base[MAX_RF_PATH]; + bool default_bb_swing_index_flag; + bool bb_swing_flag_ofdm; + u8 bb_swing_idx_cck; + u8 bb_swing_idx_cck_current; + u8 bb_swing_idx_cck_base; + u8 default_ofdm_index; + u8 default_cck_index; + bool bb_swing_flag_cck; + + s8 absolute_ofdm_swing_idx[MAX_RF_PATH]; + s8 remnant_ofdm_swing_idx[MAX_RF_PATH]; + s8 absolute_cck_swing_idx[MAX_RF_PATH]; + s8 remnant_cck_swing_idx; + s8 modify_tx_agc_value; /*Remnat compensate value at tx_agc */ + bool modify_tx_agc_flag_path_a; + bool modify_tx_agc_flag_path_b; + bool modify_tx_agc_flag_path_c; + bool modify_tx_agc_flag_path_d; + bool modify_tx_agc_flag_path_a_cck; + + s8 kfree_offset[MAX_RF_PATH]; + + /* ------------------------------------------------------------------ */ + + /* for IQK */ + u32 regc04; + u32 reg874; + u32 regc08; + u32 regb68; + u32 regb6c; + u32 reg870; + u32 reg860; + u32 reg864; + + bool is_iqk_initialized; + bool is_lck_in_progress; + bool is_antenna_detected; + bool is_need_iqk; + bool is_iqk_in_progress; + bool is_iqk_pa_off; + u8 delta_iqk; + u32 ADDA_backup[IQK_ADDA_REG_NUM]; + u32 IQK_MAC_backup[IQK_MAC_REG_NUM]; + u32 IQK_BB_backup_recover[9]; + /* { {S1: 0xc94, 0xc80, 0xc4c} , {S0: 0xc9c, 0xc88, 0xc4c}} */ + u32 IQK_BB_backup[IQK_BB_REG_NUM]; + u32 tx_iqc_8723b[2][3][2]; + /* { {S1: 0xc14, 0xca0} , {S0: 0xc14, 0xca0}} */ + u32 rx_iqc_8723b[2][2][2]; + /* { {S1: 0xc94, 0xc80, 0xc4c} , {S0: 0xc9c, 0xc88, 0xc4c}}*/ + u32 tx_iqc_8703b[3][2]; + /* { {S1: 0xc14, 0xca0} , {S0: 0xc14, 0xca0}}*/ + u32 rx_iqc_8703b[2][2]; + /* { {S1: 0xc94, 0xc80, 0xc4c} , {S0: 0xc9c, 0xc88, 0xc4c}}*/ + u32 tx_iqc_8723d[2][3][2]; + /* { {S1: 0xc14, 0xca0} , {S0: 0xc14, 0xca0}}*/ + u32 rx_iqc_8723d[2][2][2]; + /* JJ ADD 20161014 */ + /* { {S1: 0xc94, 0xc80, 0xc4c} , {S0: 0xc9c, 0xc88, 0xc4c}}*/ + u32 tx_iqc_8710b[2][3][2]; + /* { {S1: 0xc14, 0xca0} , {S0: 0xc14, 0xca0}}*/ + u32 rx_iqc_8710b[2][2][2]; + + u8 iqk_step; + u8 kcount; + u8 retry_count[4][2]; /* [4]: path ABCD, [2] TXK, RXK */ + bool is_mp_mode; + + /* <James> IQK time measurement */ + u64 iqk_start_time; + u64 iqk_progressing_time; + u64 iqk_total_progressing_time; + + u32 lok_result; + + /* for APK */ + u32 ap_koutput[2][2]; /* path A/B; output1_1a/output1_2a */ + u8 is_ap_kdone; + u8 is_apk_thermal_meter_ignore; + + /* DPK */ + bool is_dpk_fail; + u8 is_dp_done; + u8 is_dp_path_aok; + u8 is_dp_path_bok; + + u32 tx_lok[2]; + u32 dpk_tx_agc; + s32 dpk_gain; + u32 dpk_thermal[4]; + s8 modify_tx_agc_value_ofdm; + s8 modify_tx_agc_value_cck; + + /*Add by Yuchen for Kfree Phydm*/ + u8 reg_rf_kfree_enable; /*for registry*/ + u8 rf_kfree_enable; /*for efuse enable check*/ +}; + +void odm_txpowertracking_check(void *dm_void); + +void odm_txpowertracking_init(void *dm_void); + +void odm_txpowertracking_check_ap(void *dm_void); + +void odm_txpowertracking_thermal_meter_init(void *dm_void); + +void odm_txpowertracking_init(void *dm_void); + +void odm_txpowertracking_check_mp(void *dm_void); + +void odm_txpowertracking_check_ce(void *dm_void); + +#endif diff --git a/drivers/staging/rtlwifi/phydm/phydm_pre_define.h b/drivers/staging/rtlwifi/phydm/phydm_pre_define.h new file mode 100644 index 000000000000..6c301fe87b3d --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/phydm_pre_define.h @@ -0,0 +1,613 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __PHYDMPREDEFINE_H__ +#define __PHYDMPREDEFINE_H__ + +/* 1 ============================================================ + * 1 Definition + * 1 ============================================================ + */ + +#define PHYDM_CODE_BASE "PHYDM_TRUNK" +#define PHYDM_RELEASE_DATE "00000000" + +/* Max path of IC */ +#define MAX_PATH_NUM_8188E 1 +#define MAX_PATH_NUM_8192E 2 +#define MAX_PATH_NUM_8723B 1 +#define MAX_PATH_NUM_8812A 2 +#define MAX_PATH_NUM_8821A 1 +#define MAX_PATH_NUM_8814A 4 +#define MAX_PATH_NUM_8822B 2 +#define MAX_PATH_NUM_8821B 2 +#define MAX_PATH_NUM_8703B 1 +#define MAX_PATH_NUM_8188F 1 +#define MAX_PATH_NUM_8723D 1 +#define MAX_PATH_NUM_8197F 2 +#define MAX_PATH_NUM_8821C 1 +/* JJ ADD 20161014 */ +#define MAX_PATH_NUM_8710B 1 + +/* Max RF path */ +#define ODM_RF_PATH_MAX 2 +#define ODM_RF_PATH_MAX_JAGUAR 4 + +/*Bit define path*/ +#define PHYDM_A BIT(0) +#define PHYDM_B BIT(1) +#define PHYDM_C BIT(2) +#define PHYDM_D BIT(3) +#define PHYDM_AB (BIT(0) | BIT(1)) +#define PHYDM_AC (BIT(0) | BIT(2)) +#define PHYDM_AD (BIT(0) | BIT(3)) +#define PHYDM_BC (BIT(1) | BIT(2)) +#define PHYDM_BD (BIT(1) | BIT(3)) +#define PHYDM_CD (BIT(2) | BIT(3)) +#define PHYDM_ABC (BIT(0) | BIT(1) | BIT(2)) +#define PHYDM_ABD (BIT(0) | BIT(1) | BIT(3)) +#define PHYDM_ACD (BIT(0) | BIT(2) | BIT(3)) +#define PHYDM_BCD (BIT(1) | BIT(2) | BIT(3)) +#define PHYDM_ABCD (BIT(0) | BIT(1) | BIT(2) | BIT(3)) + +/* number of entry */ +/* defined in wifi.h (32+1) */ +#define ODM_ASSOCIATE_ENTRY_NUM ASSOCIATE_ENTRY_NUM + +#define RX_SMOOTH_FACTOR 20 + +/* -----MGN rate--------------------------------- */ + +enum ODM_MGN_RATE { + ODM_MGN_1M = 0x02, + ODM_MGN_2M = 0x04, + ODM_MGN_5_5M = 0x0B, + ODM_MGN_6M = 0x0C, + ODM_MGN_9M = 0x12, + ODM_MGN_11M = 0x16, + ODM_MGN_12M = 0x18, + ODM_MGN_18M = 0x24, + ODM_MGN_24M = 0x30, + ODM_MGN_36M = 0x48, + ODM_MGN_48M = 0x60, + ODM_MGN_54M = 0x6C, + ODM_MGN_MCS32 = 0x7F, + ODM_MGN_MCS0, + ODM_MGN_MCS1, + ODM_MGN_MCS2, + ODM_MGN_MCS3, + ODM_MGN_MCS4, + ODM_MGN_MCS5, + ODM_MGN_MCS6, + ODM_MGN_MCS7, + ODM_MGN_MCS8, + ODM_MGN_MCS9, + ODM_MGN_MCS10, + ODM_MGN_MCS11, + ODM_MGN_MCS12, + ODM_MGN_MCS13, + ODM_MGN_MCS14, + ODM_MGN_MCS15, + ODM_MGN_MCS16, + ODM_MGN_MCS17, + ODM_MGN_MCS18, + ODM_MGN_MCS19, + ODM_MGN_MCS20, + ODM_MGN_MCS21, + ODM_MGN_MCS22, + ODM_MGN_MCS23, + ODM_MGN_MCS24, + ODM_MGN_MCS25, + ODM_MGN_MCS26, + ODM_MGN_MCS27, + ODM_MGN_MCS28, + ODM_MGN_MCS29, + ODM_MGN_MCS30, + ODM_MGN_MCS31, + ODM_MGN_VHT1SS_MCS0, + ODM_MGN_VHT1SS_MCS1, + ODM_MGN_VHT1SS_MCS2, + ODM_MGN_VHT1SS_MCS3, + ODM_MGN_VHT1SS_MCS4, + ODM_MGN_VHT1SS_MCS5, + ODM_MGN_VHT1SS_MCS6, + ODM_MGN_VHT1SS_MCS7, + ODM_MGN_VHT1SS_MCS8, + ODM_MGN_VHT1SS_MCS9, + ODM_MGN_VHT2SS_MCS0, + ODM_MGN_VHT2SS_MCS1, + ODM_MGN_VHT2SS_MCS2, + ODM_MGN_VHT2SS_MCS3, + ODM_MGN_VHT2SS_MCS4, + ODM_MGN_VHT2SS_MCS5, + ODM_MGN_VHT2SS_MCS6, + ODM_MGN_VHT2SS_MCS7, + ODM_MGN_VHT2SS_MCS8, + ODM_MGN_VHT2SS_MCS9, + ODM_MGN_VHT3SS_MCS0, + ODM_MGN_VHT3SS_MCS1, + ODM_MGN_VHT3SS_MCS2, + ODM_MGN_VHT3SS_MCS3, + ODM_MGN_VHT3SS_MCS4, + ODM_MGN_VHT3SS_MCS5, + ODM_MGN_VHT3SS_MCS6, + ODM_MGN_VHT3SS_MCS7, + ODM_MGN_VHT3SS_MCS8, + ODM_MGN_VHT3SS_MCS9, + ODM_MGN_VHT4SS_MCS0, + ODM_MGN_VHT4SS_MCS1, + ODM_MGN_VHT4SS_MCS2, + ODM_MGN_VHT4SS_MCS3, + ODM_MGN_VHT4SS_MCS4, + ODM_MGN_VHT4SS_MCS5, + ODM_MGN_VHT4SS_MCS6, + ODM_MGN_VHT4SS_MCS7, + ODM_MGN_VHT4SS_MCS8, + ODM_MGN_VHT4SS_MCS9, + ODM_MGN_UNKNOWN +}; + +#define ODM_MGN_MCS0_SG 0xc0 +#define ODM_MGN_MCS1_SG 0xc1 +#define ODM_MGN_MCS2_SG 0xc2 +#define ODM_MGN_MCS3_SG 0xc3 +#define ODM_MGN_MCS4_SG 0xc4 +#define ODM_MGN_MCS5_SG 0xc5 +#define ODM_MGN_MCS6_SG 0xc6 +#define ODM_MGN_MCS7_SG 0xc7 +#define ODM_MGN_MCS8_SG 0xc8 +#define ODM_MGN_MCS9_SG 0xc9 +#define ODM_MGN_MCS10_SG 0xca +#define ODM_MGN_MCS11_SG 0xcb +#define ODM_MGN_MCS12_SG 0xcc +#define ODM_MGN_MCS13_SG 0xcd +#define ODM_MGN_MCS14_SG 0xce +#define ODM_MGN_MCS15_SG 0xcf + +/* -----DESC rate--------------------------------- */ + +#define ODM_RATEMCS15_SG 0x1c +#define ODM_RATEMCS32 0x20 + +/* CCK Rates, TxHT = 0 */ +#define ODM_RATE1M 0x00 +#define ODM_RATE2M 0x01 +#define ODM_RATE5_5M 0x02 +#define ODM_RATE11M 0x03 +/* OFDM Rates, TxHT = 0 */ +#define ODM_RATE6M 0x04 +#define ODM_RATE9M 0x05 +#define ODM_RATE12M 0x06 +#define ODM_RATE18M 0x07 +#define ODM_RATE24M 0x08 +#define ODM_RATE36M 0x09 +#define ODM_RATE48M 0x0A +#define ODM_RATE54M 0x0B +/* MCS Rates, TxHT = 1 */ +#define ODM_RATEMCS0 0x0C +#define ODM_RATEMCS1 0x0D +#define ODM_RATEMCS2 0x0E +#define ODM_RATEMCS3 0x0F +#define ODM_RATEMCS4 0x10 +#define ODM_RATEMCS5 0x11 +#define ODM_RATEMCS6 0x12 +#define ODM_RATEMCS7 0x13 +#define ODM_RATEMCS8 0x14 +#define ODM_RATEMCS9 0x15 +#define ODM_RATEMCS10 0x16 +#define ODM_RATEMCS11 0x17 +#define ODM_RATEMCS12 0x18 +#define ODM_RATEMCS13 0x19 +#define ODM_RATEMCS14 0x1A +#define ODM_RATEMCS15 0x1B +#define ODM_RATEMCS16 0x1C +#define ODM_RATEMCS17 0x1D +#define ODM_RATEMCS18 0x1E +#define ODM_RATEMCS19 0x1F +#define ODM_RATEMCS20 0x20 +#define ODM_RATEMCS21 0x21 +#define ODM_RATEMCS22 0x22 +#define ODM_RATEMCS23 0x23 +#define ODM_RATEMCS24 0x24 +#define ODM_RATEMCS25 0x25 +#define ODM_RATEMCS26 0x26 +#define ODM_RATEMCS27 0x27 +#define ODM_RATEMCS28 0x28 +#define ODM_RATEMCS29 0x29 +#define ODM_RATEMCS30 0x2A +#define ODM_RATEMCS31 0x2B +#define ODM_RATEVHTSS1MCS0 0x2C +#define ODM_RATEVHTSS1MCS1 0x2D +#define ODM_RATEVHTSS1MCS2 0x2E +#define ODM_RATEVHTSS1MCS3 0x2F +#define ODM_RATEVHTSS1MCS4 0x30 +#define ODM_RATEVHTSS1MCS5 0x31 +#define ODM_RATEVHTSS1MCS6 0x32 +#define ODM_RATEVHTSS1MCS7 0x33 +#define ODM_RATEVHTSS1MCS8 0x34 +#define ODM_RATEVHTSS1MCS9 0x35 +#define ODM_RATEVHTSS2MCS0 0x36 +#define ODM_RATEVHTSS2MCS1 0x37 +#define ODM_RATEVHTSS2MCS2 0x38 +#define ODM_RATEVHTSS2MCS3 0x39 +#define ODM_RATEVHTSS2MCS4 0x3A +#define ODM_RATEVHTSS2MCS5 0x3B +#define ODM_RATEVHTSS2MCS6 0x3C +#define ODM_RATEVHTSS2MCS7 0x3D +#define ODM_RATEVHTSS2MCS8 0x3E +#define ODM_RATEVHTSS2MCS9 0x3F +#define ODM_RATEVHTSS3MCS0 0x40 +#define ODM_RATEVHTSS3MCS1 0x41 +#define ODM_RATEVHTSS3MCS2 0x42 +#define ODM_RATEVHTSS3MCS3 0x43 +#define ODM_RATEVHTSS3MCS4 0x44 +#define ODM_RATEVHTSS3MCS5 0x45 +#define ODM_RATEVHTSS3MCS6 0x46 +#define ODM_RATEVHTSS3MCS7 0x47 +#define ODM_RATEVHTSS3MCS8 0x48 +#define ODM_RATEVHTSS3MCS9 0x49 +#define ODM_RATEVHTSS4MCS0 0x4A +#define ODM_RATEVHTSS4MCS1 0x4B +#define ODM_RATEVHTSS4MCS2 0x4C +#define ODM_RATEVHTSS4MCS3 0x4D +#define ODM_RATEVHTSS4MCS4 0x4E +#define ODM_RATEVHTSS4MCS5 0x4F +#define ODM_RATEVHTSS4MCS6 0x50 +#define ODM_RATEVHTSS4MCS7 0x51 +#define ODM_RATEVHTSS4MCS8 0x52 +#define ODM_RATEVHTSS4MCS9 0x53 + +#define ODM_NUM_RATE_IDX (ODM_RATEVHTSS4MCS9 + 1) + +/* 1 ============================================================ + * 1 enumeration + * 1 ============================================================ + */ + +/* ODM_CMNINFO_INTERFACE */ +enum odm_interface { + ODM_ITRF_PCIE = 0x1, + ODM_ITRF_USB = 0x2, + ODM_ITRF_SDIO = 0x4, + ODM_ITRF_ALL = 0x7, +}; + +/* ODM_CMNINFO_IC_TYPE */ +enum odm_ic_type { + ODM_RTL8188E = BIT(0), + ODM_RTL8812 = BIT(1), + ODM_RTL8821 = BIT(2), + ODM_RTL8192E = BIT(3), + ODM_RTL8723B = BIT(4), + ODM_RTL8814A = BIT(5), + ODM_RTL8881A = BIT(6), + ODM_RTL8822B = BIT(7), + ODM_RTL8703B = BIT(8), + ODM_RTL8195A = BIT(9), + ODM_RTL8188F = BIT(10), + ODM_RTL8723D = BIT(11), + ODM_RTL8197F = BIT(12), + ODM_RTL8821C = BIT(13), + ODM_RTL8814B = BIT(14), + ODM_RTL8198F = BIT(15), + /* JJ ADD 20161014 */ + ODM_RTL8710B = BIT(16), +}; + +/* JJ ADD 20161014 */ +#define ODM_IC_1SS \ + (ODM_RTL8188E | ODM_RTL8188F | ODM_RTL8723B | ODM_RTL8703B | \ + ODM_RTL8723D | ODM_RTL8881A | ODM_RTL8821 | ODM_RTL8821C | \ + ODM_RTL8195A | ODM_RTL8710B) +#define ODM_IC_2SS (ODM_RTL8192E | ODM_RTL8197F | ODM_RTL8812 | ODM_RTL8822B) +#define ODM_IC_3SS (ODM_RTL8814A) +#define ODM_IC_4SS (ODM_RTL8814B | ODM_RTL8198F) + +/* JJ ADD 20161014 */ +#define ODM_IC_11N_SERIES \ + (ODM_RTL8188E | ODM_RTL8192E | ODM_RTL8723B | ODM_RTL8703B | \ + ODM_RTL8188F | ODM_RTL8723D | ODM_RTL8197F | ODM_RTL8710B) +#define ODM_IC_11AC_SERIES \ + (ODM_RTL8812 | ODM_RTL8821 | ODM_RTL8814A | ODM_RTL8881A | \ + ODM_RTL8822B | ODM_RTL8821C) +#define ODM_IC_11AC_1_SERIES (ODM_RTL8812 | ODM_RTL8821 | ODM_RTL8881A) +#define ODM_IC_11AC_2_SERIES (ODM_RTL8814A | ODM_RTL8822B | ODM_RTL8821C) +#define ODM_IC_TXBF_SUPPORT \ + (ODM_RTL8192E | ODM_RTL8812 | ODM_RTL8821 | ODM_RTL8814A | \ + ODM_RTL8881A | ODM_RTL8822B | ODM_RTL8197F | ODM_RTL8821C) +#define ODM_IC_11N_GAIN_IDX_EDCCA \ + (ODM_RTL8195A | ODM_RTL8703B | ODM_RTL8188F | ODM_RTL8723D | \ + ODM_RTL8197F | ODM_RTL8710B) +#define ODM_IC_11AC_GAIN_IDX_EDCCA (ODM_RTL8814A | ODM_RTL8822B | ODM_RTL8821C) +#define ODM_IC_PHY_STATUE_NEW_TYPE \ + (ODM_RTL8197F | ODM_RTL8822B | ODM_RTL8723D | ODM_RTL8821C | \ + ODM_RTL8710B) + +#define PHYDM_IC_8051_SERIES \ + (ODM_RTL8881A | ODM_RTL8812 | ODM_RTL8821 | ODM_RTL8188E | \ + ODM_RTL8192E | ODM_RTL8723B | ODM_RTL8703B | ODM_RTL8188F) +#define PHYDM_IC_3081_SERIES \ + (ODM_RTL8814A | ODM_RTL8822B | ODM_RTL8197F | ODM_RTL8821C) + +#define PHYDM_IC_SUPPORT_LA_MODE \ + (ODM_RTL8814A | ODM_RTL8822B | ODM_RTL8197F | ODM_RTL8821C) + +/* JJ ADD 20161014 */ + +/* ODM_CMNINFO_CUT_VER */ +enum odm_cut_version { + ODM_CUT_A = 0, + ODM_CUT_B = 1, + ODM_CUT_C = 2, + ODM_CUT_D = 3, + ODM_CUT_E = 4, + ODM_CUT_F = 5, + + ODM_CUT_I = 8, + ODM_CUT_J = 9, + ODM_CUT_K = 10, + ODM_CUT_TEST = 15, +}; + +/* ODM_CMNINFO_FAB_VER */ +enum odm_fab { + ODM_TSMC = 0, + ODM_UMC = 1, +}; + +/* ODM_CMNINFO_RF_TYPE + * + * For example 1T2R (A+AB = BIT(0)|BIT(4)|BIT(5)) + */ +enum odm_rf_path { + ODM_RF_A = BIT(0), + ODM_RF_B = BIT(1), + ODM_RF_C = BIT(2), + ODM_RF_D = BIT(3), +}; + +enum odm_rf_tx_num { + ODM_1T = 1, + ODM_2T = 2, + ODM_3T = 3, + ODM_4T = 4, +}; + +enum odm_rf_type { + ODM_1T1R, + ODM_1T2R, + ODM_2T2R, + ODM_2T2R_GREEN, + ODM_2T3R, + ODM_2T4R, + ODM_3T3R, + ODM_3T4R, + ODM_4T4R, + ODM_XTXR +}; + +enum odm_mac_phy_mode { + ODM_SMSP = 0, + ODM_DMSP = 1, + ODM_DMDP = 2, +}; + +enum odm_bt_coexist { + ODM_BT_BUSY = 1, + ODM_BT_ON = 2, + ODM_BT_OFF = 3, + ODM_BT_NONE = 4, +}; + +/* ODM_CMNINFO_OP_MODE */ +enum odm_operation_mode { + ODM_NO_LINK = BIT(0), + ODM_LINK = BIT(1), + ODM_SCAN = BIT(2), + ODM_POWERSAVE = BIT(3), + ODM_AP_MODE = BIT(4), + ODM_CLIENT_MODE = BIT(5), + ODM_AD_HOC = BIT(6), + ODM_WIFI_DIRECT = BIT(7), + ODM_WIFI_DISPLAY = BIT(8), +}; + +/* ODM_CMNINFO_WM_MODE */ +enum odm_wireless_mode { + ODM_WM_UNKNOWN = 0x0, + ODM_WM_B = BIT(0), + ODM_WM_G = BIT(1), + ODM_WM_A = BIT(2), + ODM_WM_N24G = BIT(3), + ODM_WM_N5G = BIT(4), + ODM_WM_AUTO = BIT(5), + ODM_WM_AC = BIT(6), +}; + +/* ODM_CMNINFO_BAND */ +enum odm_band_type { + ODM_BAND_2_4G = 0, + ODM_BAND_5G, + ODM_BAND_ON_BOTH, + ODM_BANDMAX +}; + +/* ODM_CMNINFO_SEC_CHNL_OFFSET */ +enum phydm_sec_chnl_offset { + PHYDM_DONT_CARE = 0, + PHYDM_BELOW = 1, + PHYDM_ABOVE = 2 +}; + +/* ODM_CMNINFO_SEC_MODE */ +enum odm_security { + ODM_SEC_OPEN = 0, + ODM_SEC_WEP40 = 1, + ODM_SEC_TKIP = 2, + ODM_SEC_RESERVE = 3, + ODM_SEC_AESCCMP = 4, + ODM_SEC_WEP104 = 5, + ODM_WEP_WPA_MIXED = 6, /* WEP + WPA */ + ODM_SEC_SMS4 = 7, +}; + +/* ODM_CMNINFO_BW */ +enum odm_bw { + ODM_BW20M = 0, + ODM_BW40M = 1, + ODM_BW80M = 2, + ODM_BW160M = 3, + ODM_BW5M = 4, + ODM_BW10M = 5, + ODM_BW_MAX = 6 +}; + +/* ODM_CMNINFO_CHNL */ + +/* ODM_CMNINFO_BOARD_TYPE */ +enum odm_board_type { + ODM_BOARD_DEFAULT = 0, /* The DEFAULT case. */ + ODM_BOARD_MINICARD = BIT(0), /* 0 = non-mini card, 1= mini card. */ + ODM_BOARD_SLIM = BIT(1), /* 0 = non-slim card, 1 = slim card */ + ODM_BOARD_BT = BIT(2), /* 0 = without BT card, 1 = with BT */ + ODM_BOARD_EXT_PA = + BIT(3), /* 0 = no 2G ext-PA, 1 = existing 2G ext-PA */ + ODM_BOARD_EXT_LNA = + BIT(4), /* 0 = no 2G ext-LNA, 1 = existing 2G ext-LNA */ + ODM_BOARD_EXT_TRSW = + BIT(5), /* 0 = no ext-TRSW, 1 = existing ext-TRSW */ + ODM_BOARD_EXT_PA_5G = + BIT(6), /* 0 = no 5G ext-PA, 1 = existing 5G ext-PA */ + ODM_BOARD_EXT_LNA_5G = + BIT(7), /* 0 = no 5G ext-LNA, 1 = existing 5G ext-LNA */ +}; + +enum odm_package_type { + ODM_PACKAGE_DEFAULT = 0, + ODM_PACKAGE_QFN68 = BIT(0), + ODM_PACKAGE_TFBGA90 = BIT(1), + ODM_PACKAGE_TFBGA79 = BIT(2), +}; + +enum odm_type_gpa { + TYPE_GPA0 = 0x0000, + TYPE_GPA1 = 0x0055, + TYPE_GPA2 = 0x00AA, + TYPE_GPA3 = 0x00FF, + TYPE_GPA4 = 0x5500, + TYPE_GPA5 = 0x5555, + TYPE_GPA6 = 0x55AA, + TYPE_GPA7 = 0x55FF, + TYPE_GPA8 = 0xAA00, + TYPE_GPA9 = 0xAA55, + TYPE_GPA10 = 0xAAAA, + TYPE_GPA11 = 0xAAFF, + TYPE_GPA12 = 0xFF00, + TYPE_GPA13 = 0xFF55, + TYPE_GPA14 = 0xFFAA, + TYPE_GPA15 = 0xFFFF, +}; + +enum odm_type_apa { + TYPE_APA0 = 0x0000, + TYPE_APA1 = 0x0055, + TYPE_APA2 = 0x00AA, + TYPE_APA3 = 0x00FF, + TYPE_APA4 = 0x5500, + TYPE_APA5 = 0x5555, + TYPE_APA6 = 0x55AA, + TYPE_APA7 = 0x55FF, + TYPE_APA8 = 0xAA00, + TYPE_APA9 = 0xAA55, + TYPE_APA10 = 0xAAAA, + TYPE_APA11 = 0xAAFF, + TYPE_APA12 = 0xFF00, + TYPE_APA13 = 0xFF55, + TYPE_APA14 = 0xFFAA, + TYPE_APA15 = 0xFFFF, +}; + +enum odm_type_glna { + TYPE_GLNA0 = 0x0000, + TYPE_GLNA1 = 0x0055, + TYPE_GLNA2 = 0x00AA, + TYPE_GLNA3 = 0x00FF, + TYPE_GLNA4 = 0x5500, + TYPE_GLNA5 = 0x5555, + TYPE_GLNA6 = 0x55AA, + TYPE_GLNA7 = 0x55FF, + TYPE_GLNA8 = 0xAA00, + TYPE_GLNA9 = 0xAA55, + TYPE_GLNA10 = 0xAAAA, + TYPE_GLNA11 = 0xAAFF, + TYPE_GLNA12 = 0xFF00, + TYPE_GLNA13 = 0xFF55, + TYPE_GLNA14 = 0xFFAA, + TYPE_GLNA15 = 0xFFFF, +}; + +enum odm_type_alna { + TYPE_ALNA0 = 0x0000, + TYPE_ALNA1 = 0x0055, + TYPE_ALNA2 = 0x00AA, + TYPE_ALNA3 = 0x00FF, + TYPE_ALNA4 = 0x5500, + TYPE_ALNA5 = 0x5555, + TYPE_ALNA6 = 0x55AA, + TYPE_ALNA7 = 0x55FF, + TYPE_ALNA8 = 0xAA00, + TYPE_ALNA9 = 0xAA55, + TYPE_ALNA10 = 0xAAAA, + TYPE_ALNA11 = 0xAAFF, + TYPE_ALNA12 = 0xFF00, + TYPE_ALNA13 = 0xFF55, + TYPE_ALNA14 = 0xFFAA, + TYPE_ALNA15 = 0xFFFF, +}; + +enum odm_rf_radio_path { + ODM_RF_PATH_A = 0, /* Radio path A */ + ODM_RF_PATH_B = 1, /* Radio path B */ + ODM_RF_PATH_C = 2, /* Radio path C */ + ODM_RF_PATH_D = 3, /* Radio path D */ + ODM_RF_PATH_AB, + ODM_RF_PATH_AC, + ODM_RF_PATH_AD, + ODM_RF_PATH_BC, + ODM_RF_PATH_BD, + ODM_RF_PATH_CD, + ODM_RF_PATH_ABC, + ODM_RF_PATH_ACD, + ODM_RF_PATH_BCD, + ODM_RF_PATH_ABCD, + /* ODM_RF_PATH_MAX, */ /* Max RF number 90 support */ +}; + +enum odm_parameter_init { + ODM_PRE_SETTING = 0, + ODM_POST_SETTING = 1, +}; + +#endif diff --git a/drivers/staging/rtlwifi/phydm/phydm_precomp.h b/drivers/staging/rtlwifi/phydm/phydm_precomp.h new file mode 100644 index 000000000000..bada15c4d2d8 --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/phydm_precomp.h @@ -0,0 +1,85 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __ODM_PRECOMP_H__ +#define __ODM_PRECOMP_H__ + +#include "phydm_types.h" + +/* 2 Config Flags and Structs - defined by each ODM type */ + +#include "../wifi.h" +#include "rtl_phydm.h" + +/* 2 OutSrc Header Files */ + +#include "phydm.h" +#include "phydm_hwconfig.h" +#include "phydm_debug.h" +#include "phydm_regdefine11ac.h" +#include "phydm_regdefine11n.h" +#include "phydm_interface.h" +#include "phydm_reg.h" + +#include "phydm_adc_sampling.h" + +/* JJ ADD 20161014 */ + +#include "../halmac/halmac_reg2.h" + +#define LDPC_HT_ENABLE_RX BIT(0) +#define LDPC_HT_ENABLE_TX BIT(1) +#define LDPC_HT_TEST_TX_ENABLE BIT(2) +#define LDPC_HT_CAP_TX BIT(3) + +#define STBC_HT_ENABLE_RX BIT(0) +#define STBC_HT_ENABLE_TX BIT(1) +#define STBC_HT_TEST_TX_ENABLE BIT(2) +#define STBC_HT_CAP_TX BIT(3) + +#define LDPC_VHT_ENABLE_RX BIT(0) +#define LDPC_VHT_ENABLE_TX BIT(1) +#define LDPC_VHT_TEST_TX_ENABLE BIT(2) +#define LDPC_VHT_CAP_TX BIT(3) + +#define STBC_VHT_ENABLE_RX BIT(0) +#define STBC_VHT_ENABLE_TX BIT(1) +#define STBC_VHT_TEST_TX_ENABLE BIT(2) +#define STBC_VHT_CAP_TX BIT(3) + +#include "rtl8822b/halhwimg8822b_mac.h" +#include "rtl8822b/halhwimg8822b_rf.h" +#include "rtl8822b/halhwimg8822b_bb.h" +#include "rtl8822b/phydm_regconfig8822b.h" +#include "rtl8822b/halphyrf_8822b.h" +#include "rtl8822b/phydm_rtl8822b.h" +#include "rtl8822b/phydm_hal_api8822b.h" +#include "rtl8822b/version_rtl8822b.h" + +#include "../halmac/halmac_reg_8822b.h" + +/* JJ ADD 20161014 */ + +#endif /* __ODM_PRECOMP_H__ */ diff --git a/drivers/staging/rtlwifi/phydm/phydm_psd.c b/drivers/staging/rtlwifi/phydm/phydm_psd.c new file mode 100644 index 000000000000..48f8776bc8f9 --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/phydm_psd.c @@ -0,0 +1,422 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +/*============================================================ + * include files + *============================================================ + */ +#include "mp_precomp.h" +#include "phydm_precomp.h" + +u32 phydm_get_psd_data(void *dm_void, u32 psd_tone_idx, u32 igi) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct psd_info *dm_psd_table = &dm->dm_psd_table; + u32 psd_report = 0; + + odm_set_bb_reg(dm, dm_psd_table->psd_reg, 0x3ff, psd_tone_idx); + + odm_set_bb_reg(dm, dm_psd_table->psd_reg, BIT(22), + 1); /*PSD trigger start*/ + ODM_delay_us(10); + odm_set_bb_reg(dm, dm_psd_table->psd_reg, BIT(22), + 0); /*PSD trigger stop*/ + + psd_report = odm_get_bb_reg(dm, dm_psd_table->psd_report_reg, 0xffff); + psd_report = odm_convert_to_db(psd_report) + igi; + + return psd_report; +} + +static u8 phydm_psd_stop_trx(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + u32 i; + u8 trx_idle_success = false; + u32 dbg_port_value = 0; + + /*[Stop TRX]----------------------------------------------------------*/ + if (!phydm_set_bb_dbg_port(dm, BB_DBGPORT_PRIORITY_3, + 0x0)) /*set debug port to 0x0*/ + return STOP_TRX_FAIL; + + for (i = 0; i < 10000; i++) { + dbg_port_value = phydm_get_bb_dbg_port_value(dm); + if ((dbg_port_value & (BIT(17) | BIT(3))) == + 0) /* PHYTXON && CCA_all */ { + ODM_RT_TRACE(dm, ODM_COMP_API, + "PSD wait for ((%d)) times\n", i); + + trx_idle_success = true; + break; + } + } + + if (trx_idle_success) { + /*pause all TX queue*/ + odm_set_bb_reg(dm, 0x520, 0xff0000, 0xff); + + if (dm->support_ic_type & ODM_IC_11AC_SERIES) { + /*disable CCK block*/ + odm_set_bb_reg(dm, 0x808, BIT(28), 0); + /*disable OFDM RX CCA*/ + odm_set_bb_reg(dm, 0x838, BIT(1), 1); + } else { + /*TBD*/ + /* disable whole CCK block */ + odm_set_bb_reg(dm, 0x800, BIT(24), 0); + /*[ Set IQK Matrix = 0 ] equivalent to [ Turn off CCA]*/ + odm_set_bb_reg(dm, 0xC14, MASKDWORD, 0x0); + } + + } else { + return STOP_TRX_FAIL; + } + + phydm_release_bb_dbg_port(dm); + + return STOP_TRX_SUCCESS; +} + +static u8 psd_result_cali_tone_8821[7] = {21, 28, 33, 93, 98, 105, 127}; +static u8 psd_result_cali_val_8821[7] = {67, 69, 71, 72, 71, 69, 67}; + +void phydm_psd(void *dm_void, u32 igi, u16 start_point, u16 stop_point) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct psd_info *dm_psd_table = &dm->dm_psd_table; + u32 i = 0, mod_tone_idx; + u32 t = 0; + u16 fft_max_half_bw; + u32 psd_igi_a_reg; + u32 psd_igi_b_reg; + u16 psd_fc_channel = dm_psd_table->psd_fc_channel; + u8 ag_rf_mode_reg = 0; + u8 rf_reg18_9_8 = 0; + u32 psd_result_tmp = 0; + u8 psd_result = 0; + u8 psd_result_cali_tone[7] = {0}; + u8 psd_result_cali_val[7] = {0}; + u8 noise_table_idx = 0; + + if (dm->support_ic_type == ODM_RTL8821) { + odm_move_memory(dm, psd_result_cali_tone, + psd_result_cali_tone_8821, 7); + odm_move_memory(dm, psd_result_cali_val, + psd_result_cali_val_8821, 7); + } + + dm_psd_table->psd_in_progress = 1; + + /*[Stop DIG]*/ + dm->support_ability &= ~(ODM_BB_DIG); + dm->support_ability &= ~(ODM_BB_FA_CNT); + + ODM_RT_TRACE(dm, ODM_COMP_API, "PSD Start =>\n"); + + if (dm->support_ic_type & ODM_IC_11AC_SERIES) { + psd_igi_a_reg = 0xc50; + psd_igi_b_reg = 0xe50; + } else { + psd_igi_a_reg = 0xc50; + psd_igi_b_reg = 0xc58; + } + + /*[back up IGI]*/ + dm_psd_table->initial_gain_backup = + odm_get_bb_reg(dm, psd_igi_a_reg, 0xff); + odm_set_bb_reg(dm, psd_igi_a_reg, 0xff, + 0x6e); /*IGI target at 0dBm & make it can't CCA*/ + odm_set_bb_reg(dm, psd_igi_b_reg, 0xff, + 0x6e); /*IGI target at 0dBm & make it can't CCA*/ + ODM_delay_us(10); + + if (phydm_psd_stop_trx(dm) == STOP_TRX_FAIL) { + ODM_RT_TRACE(dm, ODM_COMP_API, "STOP_TRX_FAIL\n"); + return; + } + + /*[Set IGI]*/ + odm_set_bb_reg(dm, psd_igi_a_reg, 0xff, igi); + odm_set_bb_reg(dm, psd_igi_b_reg, 0xff, igi); + + /*[Backup RF Reg]*/ + dm_psd_table->rf_0x18_bkp = + odm_get_rf_reg(dm, ODM_RF_PATH_A, 0x18, RFREGOFFSETMASK); + + if (psd_fc_channel > 14) { + rf_reg18_9_8 = 1; + + if (psd_fc_channel >= 36 && psd_fc_channel <= 64) + ag_rf_mode_reg = 0x1; + else if (psd_fc_channel >= 100 && psd_fc_channel <= 140) + ag_rf_mode_reg = 0x3; + else if (psd_fc_channel > 140) + ag_rf_mode_reg = 0x5; + } + + /* Set RF fc*/ + odm_set_rf_reg(dm, ODM_RF_PATH_A, 0x18, 0xff, psd_fc_channel); + odm_set_rf_reg(dm, ODM_RF_PATH_A, 0x18, 0x300, rf_reg18_9_8); + /*2b'11: 20MHz, 2b'10: 40MHz, 2b'01: 80MHz */ + odm_set_rf_reg(dm, ODM_RF_PATH_A, 0x18, 0xc00, + dm_psd_table->psd_bw_rf_reg); + /* Set RF ag fc mode*/ + odm_set_rf_reg(dm, ODM_RF_PATH_A, 0x18, 0xf0000, ag_rf_mode_reg); + + ODM_RT_TRACE(dm, ODM_COMP_API, "0xc50=((0x%x))\n", + odm_get_bb_reg(dm, 0xc50, MASKDWORD)); + ODM_RT_TRACE(dm, ODM_COMP_API, "RF0x18=((0x%x))\n", + odm_get_rf_reg(dm, ODM_RF_PATH_A, 0x18, RFREGOFFSETMASK)); + + /*[Stop 3-wires]*/ + if (dm->support_ic_type & ODM_IC_11AC_SERIES) { + odm_set_bb_reg(dm, 0xc00, 0xf, 0x4); /* hardware 3-wire off */ + odm_set_bb_reg(dm, 0xe00, 0xf, 0x4); /* hardware 3-wire off */ + } else { + odm_set_bb_reg(dm, 0x88c, 0xf00000, + 0xf); /* 3 wire Disable 88c[23:20]=0xf */ + } + ODM_delay_us(10); + + if (stop_point > (dm_psd_table->fft_smp_point - 1)) + stop_point = (dm_psd_table->fft_smp_point - 1); + + if (start_point > (dm_psd_table->fft_smp_point - 1)) + start_point = (dm_psd_table->fft_smp_point - 1); + + if (start_point > stop_point) + stop_point = start_point; + + if (stop_point > 127) /* limit of psd_result[128] */ + stop_point = 127; + + for (i = start_point; i <= stop_point; i++) { + fft_max_half_bw = (dm_psd_table->fft_smp_point) >> 1; + + if (i < fft_max_half_bw) + mod_tone_idx = i + fft_max_half_bw; + else + mod_tone_idx = i - fft_max_half_bw; + + psd_result_tmp = 0; + for (t = 0; t < dm_psd_table->sw_avg_time; t++) + psd_result_tmp += + phydm_get_psd_data(dm, mod_tone_idx, igi); + psd_result = + (u8)((psd_result_tmp / dm_psd_table->sw_avg_time)) - + dm_psd_table->psd_pwr_common_offset; + + if (dm_psd_table->fft_smp_point == 128 && + (dm_psd_table->noise_k_en)) { + if (i > psd_result_cali_tone[noise_table_idx]) + noise_table_idx++; + + if (noise_table_idx > 6) + noise_table_idx = 6; + + if (psd_result >= psd_result_cali_val[noise_table_idx]) + psd_result = + psd_result - + psd_result_cali_val[noise_table_idx]; + else + psd_result = 0; + + dm_psd_table->psd_result[i] = psd_result; + } + + ODM_RT_TRACE(dm, ODM_COMP_API, "[%d] N_cali = %d, PSD = %d\n", + mod_tone_idx, psd_result_cali_val[noise_table_idx], + psd_result); + } + + /*[Start 3-wires]*/ + if (dm->support_ic_type & ODM_IC_11AC_SERIES) { + odm_set_bb_reg(dm, 0xc00, 0xf, 0x7); /* hardware 3-wire on */ + odm_set_bb_reg(dm, 0xe00, 0xf, 0x7); /* hardware 3-wire on */ + } else { + odm_set_bb_reg(dm, 0x88c, 0xf00000, + 0x0); /* 3 wire enable 88c[23:20]=0x0 */ + } + ODM_delay_us(10); + + /*[Revert Reg]*/ + odm_set_bb_reg(dm, 0x520, 0xff0000, 0x0); /*start all TX queue*/ + odm_set_bb_reg(dm, 0x808, BIT(28), 1); /*enable CCK block*/ + odm_set_bb_reg(dm, 0x838, BIT(1), 0); /*enable OFDM RX CCA*/ + + odm_set_bb_reg(dm, psd_igi_a_reg, 0xff, + dm_psd_table->initial_gain_backup); + odm_set_bb_reg(dm, psd_igi_b_reg, 0xff, + dm_psd_table->initial_gain_backup); + + odm_set_rf_reg(dm, ODM_RF_PATH_A, 0x18, RFREGOFFSETMASK, + dm_psd_table->rf_0x18_bkp); + + ODM_RT_TRACE(dm, ODM_COMP_API, "PSD finished\n\n"); + + dm->support_ability |= ODM_BB_DIG; + dm->support_ability |= ODM_BB_FA_CNT; + dm_psd_table->psd_in_progress = 0; +} + +void phydm_psd_para_setting(void *dm_void, u8 sw_avg_time, u8 hw_avg_time, + u8 i_q_setting, u16 fft_smp_point, u8 ant_sel, + u8 psd_input, u8 channel, u8 noise_k_en) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct psd_info *dm_psd_table = &dm->dm_psd_table; + u8 fft_smp_point_idx = 0; + + dm_psd_table->fft_smp_point = fft_smp_point; + + if (sw_avg_time == 0) + sw_avg_time = 1; + + dm_psd_table->sw_avg_time = sw_avg_time; + dm_psd_table->psd_fc_channel = channel; + dm_psd_table->noise_k_en = noise_k_en; + + if (fft_smp_point == 128) + fft_smp_point_idx = 0; + else if (fft_smp_point == 256) + fft_smp_point_idx = 1; + else if (fft_smp_point == 512) + fft_smp_point_idx = 2; + else if (fft_smp_point == 1024) + fft_smp_point_idx = 3; + + if (dm->support_ic_type & ODM_IC_11AC_SERIES) { + odm_set_bb_reg(dm, 0x910, BIT(11) | BIT(10), i_q_setting); + odm_set_bb_reg(dm, 0x910, BIT(13) | BIT(12), hw_avg_time); + odm_set_bb_reg(dm, 0x910, BIT(15) | BIT(14), fft_smp_point_idx); + odm_set_bb_reg(dm, 0x910, BIT(17) | BIT(16), ant_sel); + odm_set_bb_reg(dm, 0x910, BIT(23), psd_input); + } + + /*bw = (*dm->band_width); //ODM_BW20M */ + /*channel = *(dm->channel);*/ +} + +void phydm_psd_init(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct psd_info *dm_psd_table = &dm->dm_psd_table; + + ODM_RT_TRACE(dm, ODM_COMP_API, "PSD para init\n"); + + dm_psd_table->psd_in_progress = false; + + if (dm->support_ic_type & ODM_IC_11AC_SERIES) { + dm_psd_table->psd_reg = 0x910; + dm_psd_table->psd_report_reg = 0xF44; + + if (ODM_IC_11AC_2_SERIES) + dm_psd_table->psd_bw_rf_reg = + 1; /*2b'11: 20MHz, 2b'10: 40MHz, 2b'01: 80MHz */ + else + dm_psd_table->psd_bw_rf_reg = + 2; /*2b'11: 20MHz, 2b'10: 40MHz, 2b'01: 80MHz */ + + } else { + dm_psd_table->psd_reg = 0x808; + dm_psd_table->psd_report_reg = 0x8B4; + dm_psd_table->psd_bw_rf_reg = + 2; /*2b'11: 20MHz, 2b'10: 40MHz, 2b'01: 80MHz */ + } + + if (dm->support_ic_type == ODM_RTL8812) + dm_psd_table->psd_pwr_common_offset = 0; + else if (dm->support_ic_type == ODM_RTL8821) + dm_psd_table->psd_pwr_common_offset = 0; + else + dm_psd_table->psd_pwr_common_offset = 0; + + phydm_psd_para_setting(dm, 1, 2, 3, 128, 0, 0, 7, 0); + /*phydm_psd(dm, 0x3c, 0, 127);*/ /* target at -50dBm */ +} + +void phydm_psd_debug(void *dm_void, char input[][16], u32 *_used, char *output, + u32 *_out_len, u32 input_num) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + char help[] = "-h"; + u32 var1[10] = {0}; + u32 used = *_used; + u32 out_len = *_out_len; + u8 i; + + if ((strcmp(input[1], help) == 0)) { + PHYDM_SNPRINTF( + output + used, out_len - used, + "{0} {sw_avg} {hw_avg 0:3} {1:I,2:Q,3:IQ} {fft_point: 128*(1:4)} {path_sel 0~3} {0:ADC, 1:RXIQC} {CH} {noise_k}\n"); + PHYDM_SNPRINTF(output + used, out_len - used, + "{1} {IGI(hex)} {start_point} {stop_point}\n"); + return; + } + + PHYDM_SSCANF(input[1], DCMD_DECIMAL, &var1[0]); + + if (var1[0] == 0) { + for (i = 1; i < 10; i++) { + if (input[i + 1]) + PHYDM_SSCANF(input[i + 1], DCMD_DECIMAL, + &var1[i]); + } + + PHYDM_SNPRINTF( + output + used, out_len - used, + "sw_avg_time=((%d)), hw_avg_time=((%d)), IQ=((%d)), fft=((%d)), path=((%d)), input =((%d)) ch=((%d)), noise_k=((%d))\n", + var1[1], var1[2], var1[3], var1[4], var1[5], var1[6], + (u8)var1[7], (u8)var1[8]); + phydm_psd_para_setting(dm, (u8)var1[1], (u8)var1[2], + (u8)var1[3], (u16)var1[4], (u8)var1[5], + (u8)var1[6], (u8)var1[7], (u8)var1[8]); + + } else if (var1[0] == 1) { + PHYDM_SSCANF(input[2], DCMD_HEX, &var1[1]); + PHYDM_SSCANF(input[3], DCMD_DECIMAL, &var1[2]); + PHYDM_SSCANF(input[4], DCMD_DECIMAL, &var1[3]); + PHYDM_SNPRINTF( + output + used, out_len - used, + "IGI=((0x%x)), start_point=((%d)), stop_point=((%d))\n", + var1[1], var1[2], var1[3]); + dm->debug_components |= ODM_COMP_API; + phydm_psd(dm, var1[1], (u16)var1[2], (u16)var1[3]); + dm->debug_components &= (~ODM_COMP_API); + } +} + +u8 phydm_get_psd_result_table(void *dm_void, int index) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct psd_info *dm_psd_table = &dm->dm_psd_table; + u8 temp_result = 0; + + if (index < 128) + temp_result = dm_psd_table->psd_result[index]; + + return temp_result; +} diff --git a/drivers/staging/rtlwifi/phydm/phydm_psd.h b/drivers/staging/rtlwifi/phydm/phydm_psd.h new file mode 100644 index 000000000000..aeb70751d80b --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/phydm_psd.h @@ -0,0 +1,67 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __PHYDMPSD_H__ +#define __PHYDMPSD_H__ + +/*#define PSD_VERSION "1.0"*/ /*2016.09.22 Dino*/ +#define PSD_VERSION "1.1" /*2016.10.07 Dino, Add Option for PSD Tone index + *Selection + */ + +#define STOP_TRX_SUCCESS 1 +#define STOP_TRX_FAIL 0 + +struct psd_info { + u8 psd_in_progress; + u32 psd_reg; + u32 psd_report_reg; + u8 psd_pwr_common_offset; + u16 sw_avg_time; + u16 fft_smp_point; + u32 initial_gain_backup; + u32 rf_0x18_bkp; + u16 psd_fc_channel; + u32 psd_bw_rf_reg; + u8 psd_result[128]; + u8 noise_k_en; +}; + +u32 phydm_get_psd_data(void *dm_void, u32 psd_tone_idx, u32 igi); + +void phydm_psd_debug(void *dm_void, char input[][16], u32 *_used, char *output, + u32 *_out_len, u32 input_num); + +void phydm_psd(void *dm_void, u32 igi, u16 start_point, u16 stop_point); + +void phydm_psd_para_setting(void *dm_void, u8 sw_avg_time, u8 hw_avg_time, + u8 i_q_setting, u16 fft_smp_point, u8 ant_sel, + u8 psd_input, u8 channel, u8 noise_k_en); + +void phydm_psd_init(void *dm_void); + +u8 phydm_get_psd_result_table(void *dm_void, int index); + +#endif diff --git a/drivers/staging/rtlwifi/phydm/phydm_rainfo.c b/drivers/staging/rtlwifi/phydm/phydm_rainfo.c new file mode 100644 index 000000000000..8c08c76d4eda --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/phydm_rainfo.c @@ -0,0 +1,1208 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +/* ************************************************************ + * include files + * *************************************************************/ +#include "mp_precomp.h" +#include "phydm_precomp.h" + +void phydm_h2C_debug(void *dm_void, u32 *const dm_value, u32 *_used, + char *output, u32 *_out_len) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + u8 h2c_parameter[H2C_MAX_LENGTH] = {0}; + u8 phydm_h2c_id = (u8)dm_value[0]; + u8 i; + u32 used = *_used; + u32 out_len = *_out_len; + + PHYDM_SNPRINTF(output + used, out_len - used, + "Phydm Send H2C_ID (( 0x%x))\n", phydm_h2c_id); + for (i = 0; i < H2C_MAX_LENGTH; i++) { + h2c_parameter[i] = (u8)dm_value[i + 1]; + PHYDM_SNPRINTF(output + used, out_len - used, + "H2C: Byte[%d] = ((0x%x))\n", i, + h2c_parameter[i]); + } + + odm_fill_h2c_cmd(dm, phydm_h2c_id, H2C_MAX_LENGTH, h2c_parameter); +} + +void phydm_RA_debug_PCR(void *dm_void, u32 *const dm_value, u32 *_used, + char *output, u32 *_out_len) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct ra_table *ra_tab = &dm->dm_ra_table; + u32 used = *_used; + u32 out_len = *_out_len; + + if (dm_value[0] == 100) { + PHYDM_SNPRINTF( + output + used, out_len - used, + "[Get] PCR RA_threshold_offset = (( %s%d ))\n", + ((ra_tab->RA_threshold_offset == 0) ? + " " : + ((ra_tab->RA_offset_direction) ? "+" : "-")), + ra_tab->RA_threshold_offset); + /**/ + } else if (dm_value[0] == 0) { + ra_tab->RA_offset_direction = 0; + ra_tab->RA_threshold_offset = (u8)dm_value[1]; + PHYDM_SNPRINTF(output + used, out_len - used, + "[Set] PCR RA_threshold_offset = (( -%d ))\n", + ra_tab->RA_threshold_offset); + } else if (dm_value[0] == 1) { + ra_tab->RA_offset_direction = 1; + ra_tab->RA_threshold_offset = (u8)dm_value[1]; + PHYDM_SNPRINTF(output + used, out_len - used, + "[Set] PCR RA_threshold_offset = (( +%d ))\n", + ra_tab->RA_threshold_offset); + } else { + PHYDM_SNPRINTF(output + used, out_len - used, "[Set] Error\n"); + /**/ + } +} + +void odm_c2h_ra_para_report_handler(void *dm_void, u8 *cmd_buf, u8 cmd_len) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + + u8 para_idx = cmd_buf[0]; /*Retry Penalty, NH, NL*/ + u8 i; + + ODM_RT_TRACE(dm, PHYDM_COMP_RA_DBG, + "[ From FW C2H RA Para ] cmd_buf[0]= (( %d ))\n", + cmd_buf[0]); + + if (para_idx == RADBG_DEBUG_MONITOR1) { + ODM_RT_TRACE(dm, ODM_FW_DEBUG_TRACE, + "-------------------------------\n"); + if (dm->support_ic_type & PHYDM_IC_3081_SERIES) { + ODM_RT_TRACE(dm, ODM_FW_DEBUG_TRACE, "%5s %d\n", + "RSSI =", cmd_buf[1]); + ODM_RT_TRACE(dm, ODM_FW_DEBUG_TRACE, "%5s 0x%x\n", + "rate =", cmd_buf[2] & 0x7f); + ODM_RT_TRACE(dm, ODM_FW_DEBUG_TRACE, "%5s %d\n", + "SGI =", (cmd_buf[2] & 0x80) >> 7); + ODM_RT_TRACE(dm, ODM_FW_DEBUG_TRACE, "%5s %d\n", + "BW =", cmd_buf[3]); + ODM_RT_TRACE(dm, ODM_FW_DEBUG_TRACE, "%5s %d\n", + "BW_max =", cmd_buf[4]); + ODM_RT_TRACE(dm, ODM_FW_DEBUG_TRACE, "%5s 0x%x\n", + "multi_rate0 =", cmd_buf[5]); + ODM_RT_TRACE(dm, ODM_FW_DEBUG_TRACE, "%5s 0x%x\n", + "multi_rate1 =", cmd_buf[6]); + ODM_RT_TRACE(dm, ODM_FW_DEBUG_TRACE, "%5s %d\n", + "DISRA =", cmd_buf[7]); + ODM_RT_TRACE(dm, ODM_FW_DEBUG_TRACE, "%5s %d\n", + "VHT_EN =", cmd_buf[8]); + ODM_RT_TRACE(dm, ODM_FW_DEBUG_TRACE, "%5s %d\n", + "SGI_support =", cmd_buf[9]); + ODM_RT_TRACE(dm, ODM_FW_DEBUG_TRACE, "%5s %d\n", + "try_ness =", cmd_buf[10]); + ODM_RT_TRACE(dm, ODM_FW_DEBUG_TRACE, "%5s 0x%x\n", + "pre_rate =", cmd_buf[11]); + } else { + ODM_RT_TRACE(dm, ODM_FW_DEBUG_TRACE, "%5s %d\n", + "RSSI =", cmd_buf[1]); + ODM_RT_TRACE(dm, ODM_FW_DEBUG_TRACE, "%5s %x\n", + "BW =", cmd_buf[2]); + ODM_RT_TRACE(dm, ODM_FW_DEBUG_TRACE, "%5s %d\n", + "DISRA =", cmd_buf[3]); + ODM_RT_TRACE(dm, ODM_FW_DEBUG_TRACE, "%5s %d\n", + "VHT_EN =", cmd_buf[4]); + ODM_RT_TRACE(dm, ODM_FW_DEBUG_TRACE, "%5s %d\n", + "Hightest rate =", cmd_buf[5]); + ODM_RT_TRACE(dm, ODM_FW_DEBUG_TRACE, "%5s 0x%x\n", + "Lowest rate =", cmd_buf[6]); + ODM_RT_TRACE(dm, ODM_FW_DEBUG_TRACE, "%5s 0x%x\n", + "SGI_support =", cmd_buf[7]); + ODM_RT_TRACE(dm, ODM_FW_DEBUG_TRACE, "%5s %d\n", + "Rate_ID =", cmd_buf[8]); + ; + } + ODM_RT_TRACE(dm, ODM_FW_DEBUG_TRACE, + "-------------------------------\n"); + } else if (para_idx == RADBG_DEBUG_MONITOR2) { + ODM_RT_TRACE(dm, ODM_FW_DEBUG_TRACE, + "-------------------------------\n"); + if (dm->support_ic_type & PHYDM_IC_3081_SERIES) { + ODM_RT_TRACE(dm, ODM_FW_DEBUG_TRACE, "%5s %d\n", + "rate_id =", cmd_buf[1]); + ODM_RT_TRACE(dm, ODM_FW_DEBUG_TRACE, "%5s 0x%x\n", + "highest_rate =", cmd_buf[2]); + ODM_RT_TRACE(dm, ODM_FW_DEBUG_TRACE, "%5s 0x%x\n", + "lowest_rate =", cmd_buf[3]); + + for (i = 4; i <= 11; i++) + ODM_RT_TRACE(dm, ODM_FW_DEBUG_TRACE, + "RAMASK = 0x%x\n", cmd_buf[i]); + } else { + ODM_RT_TRACE(dm, ODM_FW_DEBUG_TRACE, + "%5s %x%x %x%x %x%x %x%x\n", + "RA Mask:", cmd_buf[8], cmd_buf[7], + cmd_buf[6], cmd_buf[5], cmd_buf[4], + cmd_buf[3], cmd_buf[2], cmd_buf[1]); + } + ODM_RT_TRACE(dm, ODM_FW_DEBUG_TRACE, + "-------------------------------\n"); + } else if (para_idx == RADBG_DEBUG_MONITOR3) { + for (i = 0; i < (cmd_len - 1); i++) + ODM_RT_TRACE(dm, ODM_FW_DEBUG_TRACE, + "content[%d] = %d\n", i, cmd_buf[1 + i]); + } else if (para_idx == RADBG_DEBUG_MONITOR4) { + ODM_RT_TRACE(dm, ODM_FW_DEBUG_TRACE, "%5s {%d.%d}\n", + "RA version =", cmd_buf[1], cmd_buf[2]); + } else if (para_idx == RADBG_DEBUG_MONITOR5) { + ODM_RT_TRACE(dm, ODM_FW_DEBUG_TRACE, "%5s 0x%x\n", + "Current rate =", cmd_buf[1]); + ODM_RT_TRACE(dm, ODM_FW_DEBUG_TRACE, "%5s %d\n", + "Retry ratio =", cmd_buf[2]); + ODM_RT_TRACE(dm, ODM_FW_DEBUG_TRACE, "%5s %d\n", + "rate down ratio =", cmd_buf[3]); + ODM_RT_TRACE(dm, ODM_FW_DEBUG_TRACE, "%5s 0x%x\n", + "highest rate =", cmd_buf[4]); + ODM_RT_TRACE(dm, ODM_FW_DEBUG_TRACE, "%5s {0x%x 0x%x}\n", + "Muti-try =", cmd_buf[5], cmd_buf[6]); + ODM_RT_TRACE(dm, ODM_FW_DEBUG_TRACE, "%5s 0x%x%x%x%x%x\n", + "RA mask =", cmd_buf[11], cmd_buf[10], cmd_buf[9], + cmd_buf[8], cmd_buf[7]); + } +} + +void phydm_ra_dynamic_retry_count(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + + if (!(dm->support_ability & ODM_BB_DYNAMIC_ARFR)) + return; + + if (dm->pre_b_noisy != dm->noisy_decision) { + if (dm->noisy_decision) { + ODM_RT_TRACE(dm, ODM_COMP_RATE_ADAPTIVE, + "->Noisy Env. RA fallback value\n"); + odm_set_mac_reg(dm, 0x430, MASKDWORD, 0x0); + odm_set_mac_reg(dm, 0x434, MASKDWORD, 0x04030201); + } else { + ODM_RT_TRACE(dm, ODM_COMP_RATE_ADAPTIVE, + "->Clean Env. RA fallback value\n"); + odm_set_mac_reg(dm, 0x430, MASKDWORD, 0x01000000); + odm_set_mac_reg(dm, 0x434, MASKDWORD, 0x06050402); + } + dm->pre_b_noisy = dm->noisy_decision; + } +} + +void phydm_ra_dynamic_retry_limit(void *dm_void) {} + +void phydm_print_rate(void *dm_void, u8 rate, u32 dbg_component) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + u8 legacy_table[12] = {1, 2, 5, 11, 6, 9, 12, 18, 24, 36, 48, 54}; + u8 rate_idx = rate & 0x7f; /*remove bit7 SGI*/ + u8 vht_en = (rate_idx >= ODM_RATEVHTSS1MCS0) ? 1 : 0; + u8 b_sgi = (rate & 0x80) >> 7; + + ODM_RT_TRACE(dm, dbg_component, "( %s%s%s%s%d%s%s)\n", + ((rate_idx >= ODM_RATEVHTSS1MCS0) && + (rate_idx <= ODM_RATEVHTSS1MCS9)) ? + "VHT 1ss " : + "", + ((rate_idx >= ODM_RATEVHTSS2MCS0) && + (rate_idx <= ODM_RATEVHTSS2MCS9)) ? + "VHT 2ss " : + "", + ((rate_idx >= ODM_RATEVHTSS3MCS0) && + (rate_idx <= ODM_RATEVHTSS3MCS9)) ? + "VHT 3ss " : + "", + (rate_idx >= ODM_RATEMCS0) ? "MCS " : "", + (vht_en) ? ((rate_idx - ODM_RATEVHTSS1MCS0) % 10) : + ((rate_idx >= ODM_RATEMCS0) ? + (rate_idx - ODM_RATEMCS0) : + ((rate_idx <= ODM_RATE54M) ? + legacy_table[rate_idx] : + 0)), + (b_sgi) ? "-S" : " ", + (rate_idx >= ODM_RATEMCS0) ? "" : "M"); +} + +void phydm_c2h_ra_report_handler(void *dm_void, u8 *cmd_buf, u8 cmd_len) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct ra_table *ra_tab = &dm->dm_ra_table; + u8 macid = cmd_buf[1]; + u8 rate = cmd_buf[0]; + u8 rate_idx = rate & 0x7f; /*remove bit7 SGI*/ + u8 rate_order; + + if (cmd_len >= 4) { + if (cmd_buf[3] == 0) { + ODM_RT_TRACE(dm, ODM_COMP_RATE_ADAPTIVE, + "TX Init-rate Update[%d]:", macid); + /**/ + } else if (cmd_buf[3] == 0xff) { + ODM_RT_TRACE(dm, ODM_COMP_RATE_ADAPTIVE, + "FW Level: Fix rate[%d]:", macid); + /**/ + } else if (cmd_buf[3] == 1) { + ODM_RT_TRACE(dm, ODM_COMP_RATE_ADAPTIVE, + "Try Success[%d]:", macid); + /**/ + } else if (cmd_buf[3] == 2) { + ODM_RT_TRACE(dm, ODM_COMP_RATE_ADAPTIVE, + "Try Fail & Try Again[%d]:", macid); + /**/ + } else if (cmd_buf[3] == 3) { + ODM_RT_TRACE(dm, ODM_COMP_RATE_ADAPTIVE, + "rate Back[%d]:", macid); + /**/ + } else if (cmd_buf[3] == 4) { + ODM_RT_TRACE(dm, ODM_COMP_RATE_ADAPTIVE, + "start rate by RSSI[%d]:", macid); + /**/ + } else if (cmd_buf[3] == 5) { + ODM_RT_TRACE(dm, ODM_COMP_RATE_ADAPTIVE, + "Try rate[%d]:", macid); + /**/ + } + } else { + ODM_RT_TRACE(dm, ODM_COMP_RATE_ADAPTIVE, "Tx rate Update[%d]:", + macid); + /**/ + } + + phydm_print_rate(dm, rate, ODM_COMP_RATE_ADAPTIVE); + + ra_tab->link_tx_rate[macid] = rate; + + /*trigger power training*/ + + rate_order = phydm_rate_order_compute(dm, rate_idx); + + if ((dm->is_one_entry_only) || + ((rate_order > ra_tab->highest_client_tx_order) && + (ra_tab->power_tracking_flag == 1))) { + phydm_update_pwr_track(dm, rate_idx); + ra_tab->power_tracking_flag = 0; + } + + /*trigger dynamic rate ID*/ +} + +void odm_rssi_monitor_init(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct ra_table *ra_tab = &dm->dm_ra_table; + + ra_tab->firstconnect = false; +} + +void odm_ra_post_action_on_assoc(void *dm_void) {} + +void phydm_init_ra_info(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + + if (dm->support_ic_type == ODM_RTL8822B) { + u32 ret_value; + + ret_value = odm_get_bb_reg(dm, 0x4c8, MASKBYTE2); + odm_set_bb_reg(dm, 0x4cc, MASKBYTE3, (ret_value - 1)); + } +} + +void phydm_modify_RA_PCR_threshold(void *dm_void, u8 RA_offset_direction, + u8 RA_threshold_offset + + ) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct ra_table *ra_tab = &dm->dm_ra_table; + + ra_tab->RA_offset_direction = RA_offset_direction; + ra_tab->RA_threshold_offset = RA_threshold_offset; + ODM_RT_TRACE(dm, ODM_COMP_RA_MASK, + "Set RA_threshold_offset = (( %s%d ))\n", + ((RA_threshold_offset == 0) ? + " " : + ((RA_offset_direction) ? "+" : "-")), + RA_threshold_offset); +} + +static void odm_rssi_monitor_check_mp(void *dm_void) {} + +static void odm_rssi_monitor_check_ce(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct ra_table *ra_tab = &dm->dm_ra_table; + struct rtl_priv *rtlpriv = (struct rtl_priv *)dm->adapter; + struct rtl_mac *mac = rtl_mac(rtlpriv); + struct rtl_sta_info *entry; + int i; + int tmp_entry_min_pwdb = 0xff; + unsigned long cur_tx_ok_cnt = 0, cur_rx_ok_cnt = 0; + u8 UL_DL_STATE = 0, STBC_TX = 0, tx_bf_en = 0; + u8 h2c_parameter[H2C_0X42_LENGTH] = {0}; + u8 cmdlen = H2C_0X42_LENGTH; + u8 macid = 0; + + if (!dm->is_linked) + return; + + for (i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++) { + entry = (struct rtl_sta_info *)dm->odm_sta_info[i]; + if (!IS_STA_VALID(entry)) + continue; + + if (is_multicast_ether_addr(entry->mac_addr) || + is_broadcast_ether_addr(entry->mac_addr)) + continue; + + if (entry->rssi_stat.undecorated_smoothed_pwdb == (-1)) + continue; + + /* calculate min_pwdb */ + if (entry->rssi_stat.undecorated_smoothed_pwdb < + tmp_entry_min_pwdb) + tmp_entry_min_pwdb = + entry->rssi_stat.undecorated_smoothed_pwdb; + + /* report RSSI */ + cur_tx_ok_cnt = rtlpriv->stats.txbytesunicast_inperiod; + cur_rx_ok_cnt = rtlpriv->stats.rxbytesunicast_inperiod; + + if (cur_rx_ok_cnt > (cur_tx_ok_cnt * 6)) + UL_DL_STATE = 1; + else + UL_DL_STATE = 0; + + if (mac->opmode == NL80211_IFTYPE_AP || + mac->opmode == NL80211_IFTYPE_ADHOC) { + struct ieee80211_sta *sta = container_of( + (void *)entry, struct ieee80211_sta, drv_priv); + macid = sta->aid + 1; + } + + h2c_parameter[0] = macid; + h2c_parameter[2] = + entry->rssi_stat.undecorated_smoothed_pwdb & 0x7F; + + if (UL_DL_STATE) + h2c_parameter[3] |= RAINFO_BE_RX_STATE; + + if (tx_bf_en) + h2c_parameter[3] |= RAINFO_BF_STATE; + if (STBC_TX) + h2c_parameter[3] |= RAINFO_STBC_STATE; + if (dm->noisy_decision) + h2c_parameter[3] |= RAINFO_NOISY_STATE; + + if (entry->rssi_stat.is_send_rssi == RA_RSSI_STATE_SEND) { + h2c_parameter[3] |= RAINFO_INIT_RSSI_RATE_STATE; + entry->rssi_stat.is_send_rssi = RA_RSSI_STATE_HOLD; + } + + h2c_parameter[4] = (ra_tab->RA_threshold_offset & 0x7f) | + (ra_tab->RA_offset_direction << 7); + + odm_fill_h2c_cmd(dm, ODM_H2C_RSSI_REPORT, cmdlen, + h2c_parameter); + } + + if (tmp_entry_min_pwdb != 0xff) + dm->rssi_min = tmp_entry_min_pwdb; +} + +static void odm_rssi_monitor_check_ap(void *dm_void) {} + +void odm_rssi_monitor_check(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + + if (!(dm->support_ability & ODM_BB_RSSI_MONITOR)) + return; + + switch (dm->support_platform) { + case ODM_WIN: + odm_rssi_monitor_check_mp(dm); + break; + + case ODM_CE: + odm_rssi_monitor_check_ce(dm); + break; + + case ODM_AP: + odm_rssi_monitor_check_ap(dm); + break; + + default: + break; + } +} + +void odm_rate_adaptive_mask_init(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct odm_rate_adaptive *odm_ra = &dm->rate_adaptive; + + odm_ra->type = dm_type_by_driver; + if (odm_ra->type == dm_type_by_driver) + dm->is_use_ra_mask = true; + else + dm->is_use_ra_mask = false; + + odm_ra->ratr_state = DM_RATR_STA_INIT; + + odm_ra->ldpc_thres = 35; + odm_ra->is_use_ldpc = false; + + odm_ra->high_rssi_thresh = 50; + odm_ra->low_rssi_thresh = 20; +} + +/*----------------------------------------------------------------------------- + * Function: odm_refresh_rate_adaptive_mask() + * + * Overview: Update rate table mask according to rssi + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 05/27/2009 hpfan Create version 0. + * + *--------------------------------------------------------------------------- + */ +void odm_refresh_rate_adaptive_mask(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct ra_table *ra_tab = &dm->dm_ra_table; + + if (!dm->is_linked) + return; + + if (!(dm->support_ability & ODM_BB_RA_MASK)) { + ODM_RT_TRACE(dm, ODM_COMP_RA_MASK, + "%s(): Return cos not supported\n", __func__); + return; + } + + ra_tab->force_update_ra_mask_count++; + /* 2011/09/29 MH In HW integration first stage, we provide 4 different + * handle to operate at the same time. + * In the stage2/3, we need to prive universal interface and merge all + * HW dynamic mechanism. + */ + switch (dm->support_platform) { + case ODM_WIN: + odm_refresh_rate_adaptive_mask_mp(dm); + break; + + case ODM_CE: + odm_refresh_rate_adaptive_mask_ce(dm); + break; + + case ODM_AP: + odm_refresh_rate_adaptive_mask_apadsl(dm); + break; + } +} + +static u8 phydm_trans_platform_bw(void *dm_void, u8 BW) +{ + if (BW == HT_CHANNEL_WIDTH_20) + BW = PHYDM_BW_20; + + else if (BW == HT_CHANNEL_WIDTH_20_40) + BW = PHYDM_BW_40; + + else if (BW == HT_CHANNEL_WIDTH_80) + BW = PHYDM_BW_80; + + return BW; +} + +static u8 phydm_trans_platform_rf_type(void *dm_void, u8 rf_type) +{ + if (rf_type == RF_1T2R) + rf_type = PHYDM_RF_1T2R; + + else if (rf_type == RF_2T4R) + rf_type = PHYDM_RF_2T4R; + + else if (rf_type == RF_2T2R) + rf_type = PHYDM_RF_2T2R; + + else if (rf_type == RF_1T1R) + rf_type = PHYDM_RF_1T1R; + + else if (rf_type == RF_2T2R_GREEN) + rf_type = PHYDM_RF_2T2R_GREEN; + + else if (rf_type == RF_3T3R) + rf_type = PHYDM_RF_3T3R; + + else if (rf_type == RF_4T4R) + rf_type = PHYDM_RF_4T4R; + + else if (rf_type == RF_2T3R) + rf_type = PHYDM_RF_1T2R; + + else if (rf_type == RF_3T4R) + rf_type = PHYDM_RF_3T4R; + + return rf_type; +} + +static u32 phydm_trans_platform_wireless_mode(void *dm_void, u32 wireless_mode) +{ + return wireless_mode; +} + +u8 phydm_vht_en_mapping(void *dm_void, u32 wireless_mode) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + u8 vht_en_out = 0; + + if ((wireless_mode == PHYDM_WIRELESS_MODE_AC_5G) || + (wireless_mode == PHYDM_WIRELESS_MODE_AC_24G) || + (wireless_mode == PHYDM_WIRELESS_MODE_AC_ONLY)) { + vht_en_out = 1; + /**/ + } + + ODM_RT_TRACE(dm, ODM_COMP_RA_MASK, + "wireless_mode= (( 0x%x )), VHT_EN= (( %d ))\n", + wireless_mode, vht_en_out); + return vht_en_out; +} + +u8 phydm_rate_id_mapping(void *dm_void, u32 wireless_mode, u8 rf_type, u8 bw) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + u8 rate_id_idx = 0; + u8 phydm_BW; + u8 phydm_rf_type; + + phydm_BW = phydm_trans_platform_bw(dm, bw); + phydm_rf_type = phydm_trans_platform_rf_type(dm, rf_type); + wireless_mode = phydm_trans_platform_wireless_mode(dm, wireless_mode); + + ODM_RT_TRACE( + dm, ODM_COMP_RA_MASK, + "wireless_mode= (( 0x%x )), rf_type = (( 0x%x )), BW = (( 0x%x ))\n", + wireless_mode, phydm_rf_type, phydm_BW); + + switch (wireless_mode) { + case PHYDM_WIRELESS_MODE_N_24G: { + if (phydm_BW == PHYDM_BW_40) { + if (phydm_rf_type == PHYDM_RF_1T1R) + rate_id_idx = PHYDM_BGN_40M_1SS; + else if (phydm_rf_type == PHYDM_RF_2T2R) + rate_id_idx = PHYDM_BGN_40M_2SS; + else + rate_id_idx = PHYDM_ARFR5_N_3SS; + + } else { + if (phydm_rf_type == PHYDM_RF_1T1R) + rate_id_idx = PHYDM_BGN_20M_1SS; + else if (phydm_rf_type == PHYDM_RF_2T2R) + rate_id_idx = PHYDM_BGN_20M_2SS; + else + rate_id_idx = PHYDM_ARFR5_N_3SS; + } + } break; + + case PHYDM_WIRELESS_MODE_N_5G: { + if (phydm_rf_type == PHYDM_RF_1T1R) + rate_id_idx = PHYDM_GN_N1SS; + else if (phydm_rf_type == PHYDM_RF_2T2R) + rate_id_idx = PHYDM_GN_N2SS; + else + rate_id_idx = PHYDM_ARFR5_N_3SS; + } + + break; + + case PHYDM_WIRELESS_MODE_G: + rate_id_idx = PHYDM_BG; + break; + + case PHYDM_WIRELESS_MODE_A: + rate_id_idx = PHYDM_G; + break; + + case PHYDM_WIRELESS_MODE_B: + rate_id_idx = PHYDM_B_20M; + break; + + case PHYDM_WIRELESS_MODE_AC_5G: + case PHYDM_WIRELESS_MODE_AC_ONLY: { + if (phydm_rf_type == PHYDM_RF_1T1R) + rate_id_idx = PHYDM_ARFR1_AC_1SS; + else if (phydm_rf_type == PHYDM_RF_2T2R) + rate_id_idx = PHYDM_ARFR0_AC_2SS; + else + rate_id_idx = PHYDM_ARFR4_AC_3SS; + } break; + + case PHYDM_WIRELESS_MODE_AC_24G: { + /*Becareful to set "Lowest rate" while using PHYDM_ARFR4_AC_3SS + *in 2.4G/5G + */ + if (phydm_BW >= PHYDM_BW_80) { + if (phydm_rf_type == PHYDM_RF_1T1R) + rate_id_idx = PHYDM_ARFR1_AC_1SS; + else if (phydm_rf_type == PHYDM_RF_2T2R) + rate_id_idx = PHYDM_ARFR0_AC_2SS; + else + rate_id_idx = PHYDM_ARFR4_AC_3SS; + } else { + if (phydm_rf_type == PHYDM_RF_1T1R) + rate_id_idx = PHYDM_ARFR2_AC_2G_1SS; + else if (phydm_rf_type == PHYDM_RF_2T2R) + rate_id_idx = PHYDM_ARFR3_AC_2G_2SS; + else + rate_id_idx = PHYDM_ARFR4_AC_3SS; + } + } break; + + default: + rate_id_idx = 0; + break; + } + + ODM_RT_TRACE(dm, ODM_COMP_RA_MASK, "RA rate ID = (( 0x%x ))\n", + rate_id_idx); + + return rate_id_idx; +} + +void phydm_update_hal_ra_mask(void *dm_void, u32 wireless_mode, u8 rf_type, + u8 BW, u8 mimo_ps_enable, u8 disable_cck_rate, + u32 *ratr_bitmap_msb_in, u32 *ratr_bitmap_lsb_in, + u8 tx_rate_level) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + u8 phydm_rf_type; + u8 phydm_BW; + u32 ratr_bitmap = *ratr_bitmap_lsb_in, + ratr_bitmap_msb = *ratr_bitmap_msb_in; + + wireless_mode = phydm_trans_platform_wireless_mode(dm, wireless_mode); + + phydm_rf_type = phydm_trans_platform_rf_type(dm, rf_type); + phydm_BW = phydm_trans_platform_bw(dm, BW); + + ODM_RT_TRACE(dm, ODM_COMP_RA_MASK, + "Platfoem original RA Mask = (( 0x %x | %x ))\n", + ratr_bitmap_msb, ratr_bitmap); + + switch (wireless_mode) { + case PHYDM_WIRELESS_MODE_B: { + ratr_bitmap &= 0x0000000f; + } break; + + case PHYDM_WIRELESS_MODE_G: { + ratr_bitmap &= 0x00000ff5; + } break; + + case PHYDM_WIRELESS_MODE_A: { + ratr_bitmap &= 0x00000ff0; + } break; + + case PHYDM_WIRELESS_MODE_N_24G: + case PHYDM_WIRELESS_MODE_N_5G: { + if (mimo_ps_enable) + phydm_rf_type = PHYDM_RF_1T1R; + + if (phydm_rf_type == PHYDM_RF_1T1R) { + if (phydm_BW == PHYDM_BW_40) + ratr_bitmap &= 0x000ff015; + else + ratr_bitmap &= 0x000ff005; + } else if (phydm_rf_type == PHYDM_RF_2T2R || + phydm_rf_type == PHYDM_RF_2T4R || + phydm_rf_type == PHYDM_RF_2T3R) { + if (phydm_BW == PHYDM_BW_40) + ratr_bitmap &= 0x0ffff015; + else + ratr_bitmap &= 0x0ffff005; + } else { /*3T*/ + + ratr_bitmap &= 0xfffff015; + ratr_bitmap_msb &= 0xf; + } + } break; + + case PHYDM_WIRELESS_MODE_AC_24G: { + if (phydm_rf_type == PHYDM_RF_1T1R) { + ratr_bitmap &= 0x003ff015; + } else if (phydm_rf_type == PHYDM_RF_2T2R || + phydm_rf_type == PHYDM_RF_2T4R || + phydm_rf_type == PHYDM_RF_2T3R) { + ratr_bitmap &= 0xfffff015; + } else { /*3T*/ + + ratr_bitmap &= 0xfffff010; + ratr_bitmap_msb &= 0x3ff; + } + + if (phydm_BW == + PHYDM_BW_20) { /* AC 20MHz doesn't support MCS9 */ + ratr_bitmap &= 0x7fdfffff; + ratr_bitmap_msb &= 0x1ff; + } + } break; + + case PHYDM_WIRELESS_MODE_AC_5G: { + if (phydm_rf_type == PHYDM_RF_1T1R) { + ratr_bitmap &= 0x003ff010; + } else if (phydm_rf_type == PHYDM_RF_2T2R || + phydm_rf_type == PHYDM_RF_2T4R || + phydm_rf_type == PHYDM_RF_2T3R) { + ratr_bitmap &= 0xfffff010; + } else { /*3T*/ + + ratr_bitmap &= 0xfffff010; + ratr_bitmap_msb &= 0x3ff; + } + + if (phydm_BW == + PHYDM_BW_20) { /* AC 20MHz doesn't support MCS9 */ + ratr_bitmap &= 0x7fdfffff; + ratr_bitmap_msb &= 0x1ff; + } + } break; + + default: + break; + } + + if (wireless_mode != PHYDM_WIRELESS_MODE_B) { + if (tx_rate_level == 0) + ratr_bitmap &= 0xffffffff; + else if (tx_rate_level == 1) + ratr_bitmap &= 0xfffffff0; + else if (tx_rate_level == 2) + ratr_bitmap &= 0xffffefe0; + else if (tx_rate_level == 3) + ratr_bitmap &= 0xffffcfc0; + else if (tx_rate_level == 4) + ratr_bitmap &= 0xffff8f80; + else if (tx_rate_level >= 5) + ratr_bitmap &= 0xffff0f00; + } + + if (disable_cck_rate) + ratr_bitmap &= 0xfffffff0; + + ODM_RT_TRACE( + dm, ODM_COMP_RA_MASK, + "wireless_mode= (( 0x%x )), rf_type = (( 0x%x )), BW = (( 0x%x )), MimoPs_en = (( %d )), tx_rate_level= (( 0x%x ))\n", + wireless_mode, phydm_rf_type, phydm_BW, mimo_ps_enable, + tx_rate_level); + + *ratr_bitmap_lsb_in = ratr_bitmap; + *ratr_bitmap_msb_in = ratr_bitmap_msb; + ODM_RT_TRACE(dm, ODM_COMP_RA_MASK, + "Phydm modified RA Mask = (( 0x %x | %x ))\n", + *ratr_bitmap_msb_in, *ratr_bitmap_lsb_in); +} + +u8 phydm_RA_level_decision(void *dm_void, u32 rssi, u8 ratr_state) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + u8 ra_rate_floor_table[RA_FLOOR_TABLE_SIZE] = { + 20, 34, 38, 42, + 46, 50, 100}; /*MCS0 ~ MCS4 , VHT1SS MCS0 ~ MCS4 , G 6M~24M*/ + u8 new_ratr_state = 0; + u8 i; + + ODM_RT_TRACE( + dm, ODM_COMP_RA_MASK, + "curr RA level = ((%d)), Rate_floor_table ori [ %d , %d, %d , %d, %d, %d]\n", + ratr_state, ra_rate_floor_table[0], ra_rate_floor_table[1], + ra_rate_floor_table[2], ra_rate_floor_table[3], + ra_rate_floor_table[4], ra_rate_floor_table[5]); + + for (i = 0; i < RA_FLOOR_TABLE_SIZE; i++) { + if (i >= (ratr_state)) + ra_rate_floor_table[i] += RA_FLOOR_UP_GAP; + } + + ODM_RT_TRACE( + dm, ODM_COMP_RA_MASK, + "RSSI = ((%d)), Rate_floor_table_mod [ %d , %d, %d , %d, %d, %d]\n", + rssi, ra_rate_floor_table[0], ra_rate_floor_table[1], + ra_rate_floor_table[2], ra_rate_floor_table[3], + ra_rate_floor_table[4], ra_rate_floor_table[5]); + + for (i = 0; i < RA_FLOOR_TABLE_SIZE; i++) { + if (rssi < ra_rate_floor_table[i]) { + new_ratr_state = i; + break; + } + } + + return new_ratr_state; +} + +void odm_refresh_rate_adaptive_mask_mp(void *dm_void) {} + +void odm_refresh_rate_adaptive_mask_ce(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct ra_table *ra_tab = &dm->dm_ra_table; + void *adapter = dm->adapter; + u32 i; + struct rtl_sta_info *entry; + u8 ratr_state_new; + + if (!dm->is_use_ra_mask) { + ODM_RT_TRACE( + dm, ODM_COMP_RA_MASK, + "<---- %s(): driver does not control rate adaptive mask\n", + __func__); + return; + } + + for (i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++) { + entry = dm->odm_sta_info[i]; + + if (!IS_STA_VALID(entry)) + continue; + + if (is_multicast_ether_addr(entry->mac_addr)) + continue; + else if (is_broadcast_ether_addr(entry->mac_addr)) + continue; + + ratr_state_new = phydm_RA_level_decision( + dm, entry->rssi_stat.undecorated_smoothed_pwdb, + entry->rssi_level); + + if ((entry->rssi_level != ratr_state_new) || + (ra_tab->force_update_ra_mask_count >= + FORCED_UPDATE_RAMASK_PERIOD)) { + ra_tab->force_update_ra_mask_count = 0; + ODM_RT_TRACE( + dm, ODM_COMP_RA_MASK, + "Update Tx RA Level: ((%x)) -> ((%x)), RSSI = ((%d))\n", + entry->rssi_level, ratr_state_new, + entry->rssi_stat.undecorated_smoothed_pwdb); + + entry->rssi_level = ratr_state_new; + rtl_hal_update_ra_mask(adapter, entry, + entry->rssi_level); + } else { + ODM_RT_TRACE(dm, ODM_COMP_RA_MASK, + "Stay in RA level = (( %d ))\n\n", + ratr_state_new); + /**/ + } + } +} + +void odm_refresh_rate_adaptive_mask_apadsl(void *dm_void) {} + +void odm_refresh_basic_rate_mask(void *dm_void) {} + +u8 phydm_rate_order_compute(void *dm_void, u8 rate_idx) +{ + u8 rate_order = 0; + + if (rate_idx >= ODM_RATEVHTSS4MCS0) { + rate_idx -= ODM_RATEVHTSS4MCS0; + /**/ + } else if (rate_idx >= ODM_RATEVHTSS3MCS0) { + rate_idx -= ODM_RATEVHTSS3MCS0; + /**/ + } else if (rate_idx >= ODM_RATEVHTSS2MCS0) { + rate_idx -= ODM_RATEVHTSS2MCS0; + /**/ + } else if (rate_idx >= ODM_RATEVHTSS1MCS0) { + rate_idx -= ODM_RATEVHTSS1MCS0; + /**/ + } else if (rate_idx >= ODM_RATEMCS24) { + rate_idx -= ODM_RATEMCS24; + /**/ + } else if (rate_idx >= ODM_RATEMCS16) { + rate_idx -= ODM_RATEMCS16; + /**/ + } else if (rate_idx >= ODM_RATEMCS8) { + rate_idx -= ODM_RATEMCS8; + /**/ + } + rate_order = rate_idx; + + return rate_order; +} + +static void phydm_ra_common_info_update(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct ra_table *ra_tab = &dm->dm_ra_table; + u16 macid; + u8 rate_order_tmp; + u8 cnt = 0; + + ra_tab->highest_client_tx_order = 0; + ra_tab->power_tracking_flag = 1; + + if (dm->number_linked_client != 0) { + for (macid = 0; macid < ODM_ASSOCIATE_ENTRY_NUM; macid++) { + rate_order_tmp = phydm_rate_order_compute( + dm, ((ra_tab->link_tx_rate[macid]) & 0x7f)); + + if (rate_order_tmp >= + (ra_tab->highest_client_tx_order)) { + ra_tab->highest_client_tx_order = + rate_order_tmp; + ra_tab->highest_client_tx_rate_order = macid; + } + + cnt++; + + if (cnt == dm->number_linked_client) + break; + } + ODM_RT_TRACE( + dm, ODM_COMP_RATE_ADAPTIVE, + "MACID[%d], Highest Tx order Update for power traking: %d\n", + (ra_tab->highest_client_tx_rate_order), + (ra_tab->highest_client_tx_order)); + } +} + +void phydm_ra_info_watchdog(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + + phydm_ra_common_info_update(dm); + phydm_ra_dynamic_retry_limit(dm); + phydm_ra_dynamic_retry_count(dm); + odm_refresh_rate_adaptive_mask(dm); + odm_refresh_basic_rate_mask(dm); +} + +void phydm_ra_info_init(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct ra_table *ra_tab = &dm->dm_ra_table; + + ra_tab->highest_client_tx_rate_order = 0; + ra_tab->highest_client_tx_order = 0; + ra_tab->RA_threshold_offset = 0; + ra_tab->RA_offset_direction = 0; +} + +u8 odm_find_rts_rate(void *dm_void, u8 tx_rate, bool is_erp_protect) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + u8 rts_ini_rate = ODM_RATE6M; + + if (is_erp_protect) { /* use CCK rate as RTS*/ + rts_ini_rate = ODM_RATE1M; + } else { + switch (tx_rate) { + case ODM_RATEVHTSS3MCS9: + case ODM_RATEVHTSS3MCS8: + case ODM_RATEVHTSS3MCS7: + case ODM_RATEVHTSS3MCS6: + case ODM_RATEVHTSS3MCS5: + case ODM_RATEVHTSS3MCS4: + case ODM_RATEVHTSS3MCS3: + case ODM_RATEVHTSS2MCS9: + case ODM_RATEVHTSS2MCS8: + case ODM_RATEVHTSS2MCS7: + case ODM_RATEVHTSS2MCS6: + case ODM_RATEVHTSS2MCS5: + case ODM_RATEVHTSS2MCS4: + case ODM_RATEVHTSS2MCS3: + case ODM_RATEVHTSS1MCS9: + case ODM_RATEVHTSS1MCS8: + case ODM_RATEVHTSS1MCS7: + case ODM_RATEVHTSS1MCS6: + case ODM_RATEVHTSS1MCS5: + case ODM_RATEVHTSS1MCS4: + case ODM_RATEVHTSS1MCS3: + case ODM_RATEMCS15: + case ODM_RATEMCS14: + case ODM_RATEMCS13: + case ODM_RATEMCS12: + case ODM_RATEMCS11: + case ODM_RATEMCS7: + case ODM_RATEMCS6: + case ODM_RATEMCS5: + case ODM_RATEMCS4: + case ODM_RATEMCS3: + case ODM_RATE54M: + case ODM_RATE48M: + case ODM_RATE36M: + case ODM_RATE24M: + rts_ini_rate = ODM_RATE24M; + break; + case ODM_RATEVHTSS3MCS2: + case ODM_RATEVHTSS3MCS1: + case ODM_RATEVHTSS2MCS2: + case ODM_RATEVHTSS2MCS1: + case ODM_RATEVHTSS1MCS2: + case ODM_RATEVHTSS1MCS1: + case ODM_RATEMCS10: + case ODM_RATEMCS9: + case ODM_RATEMCS2: + case ODM_RATEMCS1: + case ODM_RATE18M: + case ODM_RATE12M: + rts_ini_rate = ODM_RATE12M; + break; + case ODM_RATEVHTSS3MCS0: + case ODM_RATEVHTSS2MCS0: + case ODM_RATEVHTSS1MCS0: + case ODM_RATEMCS8: + case ODM_RATEMCS0: + case ODM_RATE9M: + case ODM_RATE6M: + rts_ini_rate = ODM_RATE6M; + break; + case ODM_RATE11M: + case ODM_RATE5_5M: + case ODM_RATE2M: + case ODM_RATE1M: + rts_ini_rate = ODM_RATE1M; + break; + default: + rts_ini_rate = ODM_RATE6M; + break; + } + } + + if (*dm->band_type == 1) { + if (rts_ini_rate < ODM_RATE6M) + rts_ini_rate = ODM_RATE6M; + } + return rts_ini_rate; +} + +static void odm_set_ra_dm_arfb_by_noisy(struct phy_dm_struct *dm) {} + +void odm_update_noisy_state(void *dm_void, bool is_noisy_state_from_c2h) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + + /* JJ ADD 20161014 */ + if (dm->support_ic_type == ODM_RTL8821 || + dm->support_ic_type == ODM_RTL8812 || + dm->support_ic_type == ODM_RTL8723B || + dm->support_ic_type == ODM_RTL8192E || + dm->support_ic_type == ODM_RTL8188E || + dm->support_ic_type == ODM_RTL8723D || + dm->support_ic_type == ODM_RTL8710B) + dm->is_noisy_state = is_noisy_state_from_c2h; + odm_set_ra_dm_arfb_by_noisy(dm); +}; + +void phydm_update_pwr_track(void *dm_void, u8 rate) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + + ODM_RT_TRACE(dm, ODM_COMP_TX_PWR_TRACK, "Pwr Track Get rate=0x%x\n", + rate); + + dm->tx_rate = rate; +} + +/* RA_MASK_PHYDMLIZE, will delete it later*/ + +bool odm_ra_state_check(void *dm_void, s32 rssi, bool is_force_update, + u8 *ra_tr_state) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct odm_rate_adaptive *ra = &dm->rate_adaptive; + const u8 go_up_gap = 5; + u8 high_rssi_thresh_for_ra = ra->high_rssi_thresh; + u8 low_rssi_thresh_for_ra = ra->low_rssi_thresh; + u8 ratr_state; + + ODM_RT_TRACE(dm, ODM_COMP_RA_MASK, + "RSSI= (( %d )), Current_RSSI_level = (( %d ))\n", rssi, + *ra_tr_state); + ODM_RT_TRACE(dm, ODM_COMP_RA_MASK, + "[Ori RA RSSI Thresh] High= (( %d )), Low = (( %d ))\n", + high_rssi_thresh_for_ra, low_rssi_thresh_for_ra); + /* threshold Adjustment: + * when RSSI state trends to go up one or two levels, make sure RSSI is + * high enough. Here go_up_gap is added to solve the boundary's level + * alternation issue. + */ + + switch (*ra_tr_state) { + case DM_RATR_STA_INIT: + case DM_RATR_STA_HIGH: + break; + + case DM_RATR_STA_MIDDLE: + high_rssi_thresh_for_ra += go_up_gap; + break; + + case DM_RATR_STA_LOW: + high_rssi_thresh_for_ra += go_up_gap; + low_rssi_thresh_for_ra += go_up_gap; + break; + + default: + WARN_ONCE(true, "wrong rssi level setting %d !", *ra_tr_state); + break; + } + + /* Decide ratr_state by RSSI.*/ + if (rssi > high_rssi_thresh_for_ra) + ratr_state = DM_RATR_STA_HIGH; + else if (rssi > low_rssi_thresh_for_ra) + ratr_state = DM_RATR_STA_MIDDLE; + + else + ratr_state = DM_RATR_STA_LOW; + ODM_RT_TRACE(dm, ODM_COMP_RA_MASK, + "[Mod RA RSSI Thresh] High= (( %d )), Low = (( %d ))\n", + high_rssi_thresh_for_ra, low_rssi_thresh_for_ra); + + if (*ra_tr_state != ratr_state || is_force_update) { + ODM_RT_TRACE(dm, ODM_COMP_RA_MASK, + "[RSSI Level Update] %d->%d\n", *ra_tr_state, + ratr_state); + *ra_tr_state = ratr_state; + return true; + } + + return false; +} diff --git a/drivers/staging/rtlwifi/phydm/phydm_rainfo.h b/drivers/staging/rtlwifi/phydm/phydm_rainfo.h new file mode 100644 index 000000000000..c14ed9bda0af --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/phydm_rainfo.h @@ -0,0 +1,269 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __PHYDMRAINFO_H__ +#define __PHYDMRAINFO_H__ + +/*#define RAINFO_VERSION "2.0"*/ /*2014.11.04*/ +/*#define RAINFO_VERSION "3.0"*/ /*2015.01.13 Dino*/ +/*#define RAINFO_VERSION "3.1"*/ /*2015.01.14 Dino*/ +/*#define RAINFO_VERSION "3.3"*/ /*2015.07.29 YuChen*/ +/*#define RAINFO_VERSION "3.4"*/ /*2015.12.15 Stanley*/ +/*#define RAINFO_VERSION "4.0"*/ /*2016.03.24 Dino, Add more RA mask + *state and Phydm-lize partial ra mask + *function + */ +/*#define RAINFO_VERSION "4.1"*/ /*2016.04.20 Dino, Add new function to + *adjust PCR RA threshold + */ +/*#define RAINFO_VERSION "4.2"*/ /*2016.05.17 Dino, Add H2C debug cmd */ +#define RAINFO_VERSION "4.3" /*2016.07.11 Dino, Fix RA hang in CCK 1M problem*/ + +#define FORCED_UPDATE_RAMASK_PERIOD 5 + +#define H2C_0X42_LENGTH 5 +#define H2C_MAX_LENGTH 7 + +#define RA_FLOOR_UP_GAP 3 +#define RA_FLOOR_TABLE_SIZE 7 + +#define ACTIVE_TP_THRESHOLD 150 +#define RA_RETRY_DESCEND_NUM 2 +#define RA_RETRY_LIMIT_LOW 4 +#define RA_RETRY_LIMIT_HIGH 32 + +#define RAINFO_BE_RX_STATE BIT(0) /* 1:RX */ /* ULDL */ +#define RAINFO_STBC_STATE BIT(1) +/* #define RAINFO_LDPC_STATE BIT2 */ +#define RAINFO_NOISY_STATE BIT(2) /* set by Noisy_Detection */ +#define RAINFO_SHURTCUT_STATE BIT(3) +#define RAINFO_SHURTCUT_FLAG BIT(4) +#define RAINFO_INIT_RSSI_RATE_STATE BIT(5) +#define RAINFO_BF_STATE BIT(6) +#define RAINFO_BE_TX_STATE BIT(7) /* 1:TX */ + +#define RA_MASK_CCK 0xf +#define RA_MASK_OFDM 0xff0 +#define RA_MASK_HT1SS 0xff000 +#define RA_MASK_HT2SS 0xff00000 +/*#define RA_MASK_MCS3SS */ +#define RA_MASK_HT4SS 0xff0 +#define RA_MASK_VHT1SS 0x3ff000 +#define RA_MASK_VHT2SS 0xffc00000 + +#define RA_FIRST_MACID 0 + +#define ap_init_rate_adaptive_state odm_rate_adaptive_state_ap_init + +#define DM_RATR_STA_INIT 0 +#define DM_RATR_STA_HIGH 1 +#define DM_RATR_STA_MIDDLE 2 +#define DM_RATR_STA_LOW 3 +#define DM_RATR_STA_ULTRA_LOW 4 + +enum phydm_ra_arfr_num { + ARFR_0_RATE_ID = 0x9, + ARFR_1_RATE_ID = 0xa, + ARFR_2_RATE_ID = 0xb, + ARFR_3_RATE_ID = 0xc, + ARFR_4_RATE_ID = 0xd, + ARFR_5_RATE_ID = 0xe +}; + +enum phydm_ra_dbg_para { + RADBG_PCR_TH_OFFSET = 0, + RADBG_RTY_PENALTY = 1, + RADBG_N_HIGH = 2, + RADBG_N_LOW = 3, + RADBG_TRATE_UP_TABLE = 4, + RADBG_TRATE_DOWN_TABLE = 5, + RADBG_TRYING_NECESSARY = 6, + RADBG_TDROPING_NECESSARY = 7, + RADBG_RATE_UP_RTY_RATIO = 8, + RADBG_RATE_DOWN_RTY_RATIO = 9, /* u8 */ + + RADBG_DEBUG_MONITOR1 = 0xc, + RADBG_DEBUG_MONITOR2 = 0xd, + RADBG_DEBUG_MONITOR3 = 0xe, + RADBG_DEBUG_MONITOR4 = 0xf, + RADBG_DEBUG_MONITOR5 = 0x10, + NUM_RA_PARA +}; + +enum phydm_wireless_mode { + PHYDM_WIRELESS_MODE_UNKNOWN = 0x00, + PHYDM_WIRELESS_MODE_A = 0x01, + PHYDM_WIRELESS_MODE_B = 0x02, + PHYDM_WIRELESS_MODE_G = 0x04, + PHYDM_WIRELESS_MODE_AUTO = 0x08, + PHYDM_WIRELESS_MODE_N_24G = 0x10, + PHYDM_WIRELESS_MODE_N_5G = 0x20, + PHYDM_WIRELESS_MODE_AC_5G = 0x40, + PHYDM_WIRELESS_MODE_AC_24G = 0x80, + PHYDM_WIRELESS_MODE_AC_ONLY = 0x100, + PHYDM_WIRELESS_MODE_MAX = 0x800, + PHYDM_WIRELESS_MODE_ALL = 0xFFFF +}; + +enum phydm_rateid_idx { + PHYDM_BGN_40M_2SS = 0, + PHYDM_BGN_40M_1SS = 1, + PHYDM_BGN_20M_2SS = 2, + PHYDM_BGN_20M_1SS = 3, + PHYDM_GN_N2SS = 4, + PHYDM_GN_N1SS = 5, + PHYDM_BG = 6, + PHYDM_G = 7, + PHYDM_B_20M = 8, + PHYDM_ARFR0_AC_2SS = 9, + PHYDM_ARFR1_AC_1SS = 10, + PHYDM_ARFR2_AC_2G_1SS = 11, + PHYDM_ARFR3_AC_2G_2SS = 12, + PHYDM_ARFR4_AC_3SS = 13, + PHYDM_ARFR5_N_3SS = 14 +}; + +enum phydm_rf_type_def { + PHYDM_RF_1T1R = 0, + PHYDM_RF_1T2R, + PHYDM_RF_2T2R, + PHYDM_RF_2T2R_GREEN, + PHYDM_RF_2T3R, + PHYDM_RF_2T4R, + PHYDM_RF_3T3R, + PHYDM_RF_3T4R, + PHYDM_RF_4T4R, + PHYDM_RF_MAX_TYPE +}; + +enum phydm_bw { + PHYDM_BW_20 = 0, + PHYDM_BW_40, + PHYDM_BW_80, + PHYDM_BW_80_80, + PHYDM_BW_160, + PHYDM_BW_10, + PHYDM_BW_5 +}; + +struct ra_table { + u8 firstconnect; + + u8 link_tx_rate[ODM_ASSOCIATE_ENTRY_NUM]; + u8 highest_client_tx_order; + u16 highest_client_tx_rate_order; + u8 power_tracking_flag; + u8 RA_threshold_offset; + u8 RA_offset_direction; + u8 force_update_ra_mask_count; +}; + +struct odm_rate_adaptive { + /* dm_type_by_fw/dm_type_by_driver */ + u8 type; + /* if RSSI > high_rssi_thresh => ratr_state is DM_RATR_STA_HIGH */ + u8 high_rssi_thresh; + /* if RSSI <= low_rssi_thresh => ratr_state is DM_RATR_STA_LOW */ + u8 low_rssi_thresh; + /* Cur RSSI level, DM_RATR_STA_HIGH/DM_RATR_STA_MIDDLE/DM_RATR_STA_LOW*/ + u8 ratr_state; + + /* if RSSI > ldpc_thres => switch from LPDC to BCC */ + u8 ldpc_thres; + bool is_lower_rts_rate; + + bool is_use_ldpc; +}; + +void phydm_h2C_debug(void *dm_void, u32 *const dm_value, u32 *_used, + char *output, u32 *_out_len); + +void phydm_RA_debug_PCR(void *dm_void, u32 *const dm_value, u32 *_used, + char *output, u32 *_out_len); + +void odm_c2h_ra_para_report_handler(void *dm_void, u8 *cmd_buf, u8 cmd_len); + +void odm_ra_para_adjust(void *dm_void); + +void phydm_ra_dynamic_retry_count(void *dm_void); + +void phydm_ra_dynamic_retry_limit(void *dm_void); + +void phydm_ra_dynamic_rate_id_on_assoc(void *dm_void, u8 wireless_mode, + u8 init_rate_id); + +void phydm_print_rate(void *dm_void, u8 rate, u32 dbg_component); + +void phydm_c2h_ra_report_handler(void *dm_void, u8 *cmd_buf, u8 cmd_len); + +u8 phydm_rate_order_compute(void *dm_void, u8 rate_idx); + +void phydm_ra_info_watchdog(void *dm_void); + +void phydm_ra_info_init(void *dm_void); + +void odm_rssi_monitor_init(void *dm_void); + +void phydm_modify_RA_PCR_threshold(void *dm_void, u8 RA_offset_direction, + u8 RA_threshold_offset); + +void odm_rssi_monitor_check(void *dm_void); + +void phydm_init_ra_info(void *dm_void); + +u8 phydm_vht_en_mapping(void *dm_void, u32 wireless_mode); + +u8 phydm_rate_id_mapping(void *dm_void, u32 wireless_mode, u8 rf_type, u8 bw); + +void phydm_update_hal_ra_mask(void *dm_void, u32 wireless_mode, u8 rf_type, + u8 BW, u8 mimo_ps_enable, u8 disable_cck_rate, + u32 *ratr_bitmap_msb_in, u32 *ratr_bitmap_in, + u8 tx_rate_level); + +void odm_rate_adaptive_mask_init(void *dm_void); + +void odm_refresh_rate_adaptive_mask(void *dm_void); + +void odm_refresh_rate_adaptive_mask_mp(void *dm_void); + +void odm_refresh_rate_adaptive_mask_ce(void *dm_void); + +void odm_refresh_rate_adaptive_mask_apadsl(void *dm_void); + +u8 phydm_RA_level_decision(void *dm_void, u32 rssi, u8 ratr_state); + +bool odm_ra_state_check(void *dm_void, s32 RSSI, bool is_force_update, + u8 *ra_tr_state); + +void odm_refresh_basic_rate_mask(void *dm_void); +void odm_ra_post_action_on_assoc(void *dm); + +u8 odm_find_rts_rate(void *dm_void, u8 tx_rate, bool is_erp_protect); + +void odm_update_noisy_state(void *dm_void, bool is_noisy_state_from_c2h); + +void phydm_update_pwr_track(void *dm_void, u8 rate); + +#endif /*#ifndef __ODMRAINFO_H__*/ diff --git a/drivers/staging/rtlwifi/phydm/phydm_reg.h b/drivers/staging/rtlwifi/phydm/phydm_reg.h new file mode 100644 index 000000000000..d9d878e4c925 --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/phydm_reg.h @@ -0,0 +1,151 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +/* ************************************************************ + * File Name: odm_reg.h + * + * Description: + * + * This file is for general register definition. + * + * + * *************************************************************/ +#ifndef __HAL_ODM_REG_H__ +#define __HAL_ODM_REG_H__ + +/* + * Register Definition + */ + +/* MAC REG */ +#define ODM_BB_RESET 0x002 +#define ODM_DUMMY 0x4fe +#define RF_T_METER_OLD 0x24 +#define RF_T_METER_NEW 0x42 + +#define ODM_EDCA_VO_PARAM 0x500 +#define ODM_EDCA_VI_PARAM 0x504 +#define ODM_EDCA_BE_PARAM 0x508 +#define ODM_EDCA_BK_PARAM 0x50C +#define ODM_TXPAUSE 0x522 + +/* LTE_COEX */ +#define REG_LTECOEX_CTRL 0x07C0 +#define REG_LTECOEX_WRITE_DATA 0x07C4 +#define REG_LTECOEX_READ_DATA 0x07C8 +#define REG_LTECOEX_PATH_CONTROL 0x70 + +/* BB REG */ +#define ODM_FPGA_PHY0_PAGE8 0x800 +#define ODM_PSD_SETTING 0x808 +#define ODM_AFE_SETTING 0x818 +#define ODM_TXAGC_B_6_18 0x830 +#define ODM_TXAGC_B_24_54 0x834 +#define ODM_TXAGC_B_MCS32_5 0x838 +#define ODM_TXAGC_B_MCS0_MCS3 0x83c +#define ODM_TXAGC_B_MCS4_MCS7 0x848 +#define ODM_TXAGC_B_MCS8_MCS11 0x84c +#define ODM_ANALOG_REGISTER 0x85c +#define ODM_RF_INTERFACE_OUTPUT 0x860 +#define ODM_TXAGC_B_MCS12_MCS15 0x868 +#define ODM_TXAGC_B_11_A_2_11 0x86c +#define ODM_AD_DA_LSB_MASK 0x874 +#define ODM_ENABLE_3_WIRE 0x88c +#define ODM_PSD_REPORT 0x8b4 +#define ODM_R_ANT_SELECT 0x90c +#define ODM_CCK_ANT_SELECT 0xa07 +#define ODM_CCK_PD_THRESH 0xa0a +#define ODM_CCK_RF_REG1 0xa11 +#define ODM_CCK_MATCH_FILTER 0xa20 +#define ODM_CCK_RAKE_MAC 0xa2e +#define ODM_CCK_CNT_RESET 0xa2d +#define ODM_CCK_TX_DIVERSITY 0xa2f +#define ODM_CCK_FA_CNT_MSB 0xa5b +#define ODM_CCK_FA_CNT_LSB 0xa5c +#define ODM_CCK_NEW_FUNCTION 0xa75 +#define ODM_OFDM_PHY0_PAGE_C 0xc00 +#define ODM_OFDM_RX_ANT 0xc04 +#define ODM_R_A_RXIQI 0xc14 +#define ODM_R_A_AGC_CORE1 0xc50 +#define ODM_R_A_AGC_CORE2 0xc54 +#define ODM_R_B_AGC_CORE1 0xc58 +#define ODM_R_AGC_PAR 0xc70 +#define ODM_R_HTSTF_AGC_PAR 0xc7c +#define ODM_TX_PWR_TRAINING_A 0xc90 +#define ODM_TX_PWR_TRAINING_B 0xc98 +#define ODM_OFDM_FA_CNT1 0xcf0 +#define ODM_OFDM_PHY0_PAGE_D 0xd00 +#define ODM_OFDM_FA_CNT2 0xda0 +#define ODM_OFDM_FA_CNT3 0xda4 +#define ODM_OFDM_FA_CNT4 0xda8 +#define ODM_TXAGC_A_6_18 0xe00 +#define ODM_TXAGC_A_24_54 0xe04 +#define ODM_TXAGC_A_1_MCS32 0xe08 +#define ODM_TXAGC_A_MCS0_MCS3 0xe10 +#define ODM_TXAGC_A_MCS4_MCS7 0xe14 +#define ODM_TXAGC_A_MCS8_MCS11 0xe18 +#define ODM_TXAGC_A_MCS12_MCS15 0xe1c + +/* RF REG */ +#define ODM_GAIN_SETTING 0x00 +#define ODM_CHANNEL 0x18 +#define ODM_RF_T_METER 0x24 +#define ODM_RF_T_METER_92D 0x42 +#define ODM_RF_T_METER_88E 0x42 +#define ODM_RF_T_METER_92E 0x42 +#define ODM_RF_T_METER_8812 0x42 +#define REG_RF_TX_GAIN_OFFSET 0x55 + +/* ant Detect Reg */ +#define ODM_DPDT 0x300 + +/* PSD Init */ +#define ODM_PSDREG 0x808 + +/* 92D path Div */ +#define PATHDIV_REG 0xB30 +#define PATHDIV_TRI 0xBA0 + +/* + * Bitmap Definition + */ + +#define BIT_FA_RESET BIT(0) + +#define REG_OFDM_0_XA_TX_IQ_IMBALANCE 0xC80 +#define REG_OFDM_0_ECCA_THRESHOLD 0xC4C +#define REG_FPGA0_XB_LSSI_READ_BACK 0x8A4 +#define REG_FPGA0_TX_GAIN_STAGE 0x80C +#define REG_OFDM_0_XA_AGC_CORE1 0xC50 +#define REG_OFDM_0_XB_AGC_CORE1 0xC58 +#define REG_A_TX_SCALE_JAGUAR 0xC1C +#define REG_B_TX_SCALE_JAGUAR 0xE1C + +#define REG_AFE_XTAL_CTRL 0x0024 +#define REG_AFE_PLL_CTRL 0x0028 +#define REG_MAC_PHY_CTRL 0x002C + +#define RF_CHNLBW 0x18 + +#endif diff --git a/drivers/staging/rtlwifi/phydm/phydm_regdefine11ac.h b/drivers/staging/rtlwifi/phydm/phydm_regdefine11ac.h new file mode 100644 index 000000000000..28d48415ac99 --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/phydm_regdefine11ac.h @@ -0,0 +1,94 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __ODM_REGDEFINE11AC_H__ +#define __ODM_REGDEFINE11AC_H__ + +/* 2 RF REG LIST */ + +/* 2 BB REG LIST */ +/* PAGE 8 */ +#define ODM_REG_CCK_RPT_FORMAT_11AC 0x804 +#define ODM_REG_BB_RX_PATH_11AC 0x808 +#define ODM_REG_BB_TX_PATH_11AC 0x80c +#define ODM_REG_BB_ATC_11AC 0x860 +#define ODM_REG_EDCCA_POWER_CAL 0x8dc +#define ODM_REG_DBG_RPT_11AC 0x8fc +/* PAGE 9 */ +#define ODM_REG_EDCCA_DOWN_OPT 0x900 +#define ODM_REG_ACBB_EDCCA_ENHANCE 0x944 +#define odm_adc_trigger_jaguar2 0x95C /*ADC sample mode*/ +#define ODM_REG_OFDM_FA_RST_11AC 0x9A4 +#define ODM_REG_CCX_PERIOD_11AC 0x990 +#define ODM_REG_NHM_TH9_TH10_11AC 0x994 +#define ODM_REG_CLM_11AC 0x994 +#define ODM_REG_NHM_TH3_TO_TH0_11AC 0x998 +#define ODM_REG_NHM_TH7_TO_TH4_11AC 0x99c +#define ODM_REG_NHM_TH8_11AC 0x9a0 +#define ODM_REG_NHM_9E8_11AC 0x9e8 +#define ODM_REG_CSI_CONTENT_VALUE 0x9b4 +/* PAGE A */ +#define ODM_REG_CCK_CCA_11AC 0xA0A +#define ODM_REG_CCK_FA_RST_11AC 0xA2C +#define ODM_REG_CCK_FA_11AC 0xA5C +/* PAGE B */ +#define ODM_REG_RST_RPT_11AC 0xB58 +/* PAGE C */ +#define ODM_REG_TRMUX_11AC 0xC08 +#define ODM_REG_IGI_A_11AC 0xC50 +/* PAGE E */ +#define ODM_REG_IGI_B_11AC 0xE50 +#define ODM_REG_TRMUX_11AC_B 0xE08 +/* PAGE F */ +#define ODM_REG_CCK_CRC32_CNT_11AC 0xF04 +#define ODM_REG_CCK_CCA_CNT_11AC 0xF08 +#define ODM_REG_VHT_CRC32_CNT_11AC 0xF0c +#define ODM_REG_HT_CRC32_CNT_11AC 0xF10 +#define ODM_REG_OFDM_CRC32_CNT_11AC 0xF14 +#define ODM_REG_OFDM_FA_11AC 0xF48 +#define ODM_REG_RPT_11AC 0xfa0 +#define ODM_REG_CLM_RESULT_11AC 0xfa4 +#define ODM_REG_NHM_CNT_11AC 0xfa8 +#define ODM_REG_NHM_DUR_READY_11AC 0xfb4 + +#define ODM_REG_NHM_CNT7_TO_CNT4_11AC 0xfac +#define ODM_REG_NHM_CNT11_TO_CNT8_11AC 0xfb0 +#define ODM_REG_OFDM_FA_TYPE2_11AC 0xFD0 +/* PAGE 18 */ +#define ODM_REG_IGI_C_11AC 0x1850 +/* PAGE 1A */ +#define ODM_REG_IGI_D_11AC 0x1A50 + +/* 2 MAC REG LIST */ +#define ODM_REG_RESP_TX_11AC 0x6D8 + +/* DIG Related */ +#define ODM_BIT_IGI_11AC 0xFFFFFFFF +#define ODM_BIT_CCK_RPT_FORMAT_11AC BIT(16) +#define ODM_BIT_BB_RX_PATH_11AC 0xF +#define ODM_BIT_BB_TX_PATH_11AC 0xF +#define ODM_BIT_BB_ATC_11AC BIT(14) + +#endif diff --git a/drivers/staging/rtlwifi/phydm/phydm_regdefine11n.h b/drivers/staging/rtlwifi/phydm/phydm_regdefine11n.h new file mode 100644 index 000000000000..0b6581c50ab3 --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/phydm_regdefine11n.h @@ -0,0 +1,213 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __ODM_REGDEFINE11N_H__ +#define __ODM_REGDEFINE11N_H__ + +/* 2 RF REG LIST */ +#define ODM_REG_RF_MODE_11N 0x00 +#define ODM_REG_RF_0B_11N 0x0B +#define ODM_REG_CHNBW_11N 0x18 +#define ODM_REG_T_METER_11N 0x24 +#define ODM_REG_RF_25_11N 0x25 +#define ODM_REG_RF_26_11N 0x26 +#define ODM_REG_RF_27_11N 0x27 +#define ODM_REG_RF_2B_11N 0x2B +#define ODM_REG_RF_2C_11N 0x2C +#define ODM_REG_RXRF_A3_11N 0x3C +#define ODM_REG_T_METER_92D_11N 0x42 +#define ODM_REG_T_METER_88E_11N 0x42 + +/* 2 BB REG LIST */ +/* PAGE 8 */ +#define ODM_REG_BB_CTRL_11N 0x800 +#define ODM_REG_RF_PIN_11N 0x804 +#define ODM_REG_PSD_CTRL_11N 0x808 +#define ODM_REG_TX_ANT_CTRL_11N 0x80C +#define ODM_REG_BB_PWR_SAV5_11N 0x818 +#define ODM_REG_CCK_RPT_FORMAT_11N 0x824 +#define ODM_REG_CCK_RPT_FORMAT_11N_B 0x82C +#define ODM_REG_RX_DEFAULT_A_11N 0x858 +#define ODM_REG_RX_DEFAULT_B_11N 0x85A +#define ODM_REG_BB_PWR_SAV3_11N 0x85C +#define ODM_REG_ANTSEL_CTRL_11N 0x860 +#define ODM_REG_RX_ANT_CTRL_11N 0x864 +#define ODM_REG_PIN_CTRL_11N 0x870 +#define ODM_REG_BB_PWR_SAV1_11N 0x874 +#define ODM_REG_ANTSEL_PATH_11N 0x878 +#define ODM_REG_BB_3WIRE_11N 0x88C +#define ODM_REG_SC_CNT_11N 0x8C4 +#define ODM_REG_PSD_DATA_11N 0x8B4 +#define ODM_REG_CCX_PERIOD_11N 0x894 +#define ODM_REG_NHM_TH9_TH10_11N 0x890 +#define ODM_REG_CLM_11N 0x890 +#define ODM_REG_NHM_TH3_TO_TH0_11N 0x898 +#define ODM_REG_NHM_TH7_TO_TH4_11N 0x89c +#define ODM_REG_NHM_TH8_11N 0xe28 +#define ODM_REG_CLM_READY_11N 0x8b4 +#define ODM_REG_CLM_RESULT_11N 0x8d0 +#define ODM_REG_NHM_CNT_11N 0x8d8 + +/* For struct acs_info, Jeffery, 2014-12-26 */ +#define ODM_REG_NHM_CNT7_TO_CNT4_11N 0x8dc +#define ODM_REG_NHM_CNT9_TO_CNT8_11N 0x8d0 +#define ODM_REG_NHM_CNT10_TO_CNT11_11N 0x8d4 + +/* PAGE 9 */ +#define ODM_REG_BB_CTRL_PAGE9_11N 0x900 +#define ODM_REG_DBG_RPT_11N 0x908 +#define ODM_REG_BB_TX_PATH_11N 0x90c +#define ODM_REG_ANT_MAPPING1_11N 0x914 +#define ODM_REG_ANT_MAPPING2_11N 0x918 +#define ODM_REG_EDCCA_DOWN_OPT_11N 0x948 +#define ODM_REG_RX_DFIR_MOD_97F 0x948 + +/* PAGE A */ +#define ODM_REG_CCK_ANTDIV_PARA1_11N 0xA00 +#define ODM_REG_CCK_ANT_SEL_11N 0xA04 +#define ODM_REG_CCK_CCA_11N 0xA0A +#define ODM_REG_CCK_ANTDIV_PARA2_11N 0xA0C +#define ODM_REG_CCK_ANTDIV_PARA3_11N 0xA10 +#define ODM_REG_CCK_ANTDIV_PARA4_11N 0xA14 +#define ODM_REG_CCK_FILTER_PARA1_11N 0xA22 +#define ODM_REG_CCK_FILTER_PARA2_11N 0xA23 +#define ODM_REG_CCK_FILTER_PARA3_11N 0xA24 +#define ODM_REG_CCK_FILTER_PARA4_11N 0xA25 +#define ODM_REG_CCK_FILTER_PARA5_11N 0xA26 +#define ODM_REG_CCK_FILTER_PARA6_11N 0xA27 +#define ODM_REG_CCK_FILTER_PARA7_11N 0xA28 +#define ODM_REG_CCK_FILTER_PARA8_11N 0xA29 +#define ODM_REG_CCK_FA_RST_11N 0xA2C +#define ODM_REG_CCK_FA_MSB_11N 0xA58 +#define ODM_REG_CCK_FA_LSB_11N 0xA5C +#define ODM_REG_CCK_CCA_CNT_11N 0xA60 +#define ODM_REG_BB_PWR_SAV4_11N 0xA74 +/* PAGE B */ +#define ODM_REG_LNA_SWITCH_11N 0xB2C +#define ODM_REG_PATH_SWITCH_11N 0xB30 +#define ODM_REG_RSSI_CTRL_11N 0xB38 +#define ODM_REG_CONFIG_ANTA_11N 0xB68 +#define ODM_REG_RSSI_BT_11N 0xB9C +#define ODM_REG_RXCK_RFMOD 0xBB0 +#define ODM_REG_EDCCA_DCNF_97F 0xBC0 + +/* PAGE C */ +#define ODM_REG_OFDM_FA_HOLDC_11N 0xC00 +#define ODM_REG_BB_RX_PATH_11N 0xC04 +#define ODM_REG_TRMUX_11N 0xC08 +#define ODM_REG_OFDM_FA_RSTC_11N 0xC0C +#define ODM_REG_DOWNSAM_FACTOR_11N 0xC10 +#define ODM_REG_RXIQI_MATRIX_11N 0xC14 +#define ODM_REG_TXIQK_MATRIX_LSB1_11N 0xC4C +#define ODM_REG_IGI_A_11N 0xC50 +#define ODM_REG_ANTDIV_PARA2_11N 0xC54 +#define ODM_REG_IGI_B_11N 0xC58 +#define ODM_REG_ANTDIV_PARA3_11N 0xC5C +#define ODM_REG_L1SBD_PD_CH_11N 0XC6C +#define ODM_REG_BB_PWR_SAV2_11N 0xC70 +#define ODM_REG_BB_AGC_SET_2_11N 0xc74 +#define ODM_REG_RX_OFF_11N 0xC7C +#define ODM_REG_TXIQK_MATRIXA_11N 0xC80 +#define ODM_REG_TXIQK_MATRIXB_11N 0xC88 +#define ODM_REG_TXIQK_MATRIXA_LSB2_11N 0xC94 +#define ODM_REG_TXIQK_MATRIXB_LSB2_11N 0xC9C +#define ODM_REG_RXIQK_MATRIX_LSB_11N 0xCA0 +#define ODM_REG_ANTDIV_PARA1_11N 0xCA4 +#define ODM_REG_SMALL_BANDWIDTH_11N 0xCE4 +#define ODM_REG_OFDM_FA_TYPE1_11N 0xCF0 +/* PAGE D */ +#define ODM_REG_OFDM_FA_RSTD_11N 0xD00 +#define ODM_REG_BB_RX_ANT_11N 0xD04 +#define ODM_REG_BB_ATC_11N 0xD2C +#define ODM_REG_OFDM_FA_TYPE2_11N 0xDA0 +#define ODM_REG_OFDM_FA_TYPE3_11N 0xDA4 +#define ODM_REG_OFDM_FA_TYPE4_11N 0xDA8 +#define ODM_REG_RPT_11N 0xDF4 +/* PAGE E */ +#define ODM_REG_TXAGC_A_6_18_11N 0xE00 +#define ODM_REG_TXAGC_A_24_54_11N 0xE04 +#define ODM_REG_TXAGC_A_1_MCS32_11N 0xE08 +#define ODM_REG_TXAGC_A_MCS0_3_11N 0xE10 +#define ODM_REG_TXAGC_A_MCS4_7_11N 0xE14 +#define ODM_REG_TXAGC_A_MCS8_11_11N 0xE18 +#define ODM_REG_TXAGC_A_MCS12_15_11N 0xE1C +#define ODM_REG_EDCCA_DCNF_11N 0xE24 +#define ODM_REG_TAP_UPD_97F 0xE24 +#define ODM_REG_FPGA0_IQK_11N 0xE28 +#define ODM_REG_PAGE_B1_97F 0xE28 +#define ODM_REG_TXIQK_TONE_A_11N 0xE30 +#define ODM_REG_RXIQK_TONE_A_11N 0xE34 +#define ODM_REG_TXIQK_PI_A_11N 0xE38 +#define ODM_REG_RXIQK_PI_A_11N 0xE3C +#define ODM_REG_TXIQK_11N 0xE40 +#define ODM_REG_RXIQK_11N 0xE44 +#define ODM_REG_IQK_AGC_PTS_11N 0xE48 +#define ODM_REG_IQK_AGC_RSP_11N 0xE4C +#define ODM_REG_BLUETOOTH_11N 0xE6C +#define ODM_REG_RX_WAIT_CCA_11N 0xE70 +#define ODM_REG_TX_CCK_RFON_11N 0xE74 +#define ODM_REG_TX_CCK_BBON_11N 0xE78 +#define ODM_REG_OFDM_RFON_11N 0xE7C +#define ODM_REG_OFDM_BBON_11N 0xE80 +#define ODM_REG_TX2RX_11N 0xE84 +#define ODM_REG_TX2TX_11N 0xE88 +#define ODM_REG_RX_CCK_11N 0xE8C +#define ODM_REG_RX_OFDM_11N 0xED0 +#define ODM_REG_RX_WAIT_RIFS_11N 0xED4 +#define ODM_REG_RX2RX_11N 0xED8 +#define ODM_REG_STANDBY_11N 0xEDC +#define ODM_REG_SLEEP_11N 0xEE0 +#define ODM_REG_PMPD_ANAEN_11N 0xEEC +/* PAGE F */ +#define ODM_REG_PAGE_F_RST_11N 0xF14 +#define ODM_REG_IGI_C_11N 0xF84 +#define ODM_REG_IGI_D_11N 0xF88 +#define ODM_REG_CCK_CRC32_ERROR_CNT_11N 0xF84 +#define ODM_REG_CCK_CRC32_OK_CNT_11N 0xF88 +#define ODM_REG_HT_CRC32_CNT_11N 0xF90 +#define ODM_REG_OFDM_CRC32_CNT_11N 0xF94 + +/* 2 MAC REG LIST */ +#define ODM_REG_BB_RST_11N 0x02 +#define ODM_REG_ANTSEL_PIN_11N 0x4C +#define ODM_REG_EARLY_MODE_11N 0x4D0 +#define ODM_REG_RSSI_MONITOR_11N 0x4FE +#define ODM_REG_EDCA_VO_11N 0x500 +#define ODM_REG_EDCA_VI_11N 0x504 +#define ODM_REG_EDCA_BE_11N 0x508 +#define ODM_REG_EDCA_BK_11N 0x50C +#define ODM_REG_TXPAUSE_11N 0x522 +#define ODM_REG_RESP_TX_11N 0x6D8 +#define ODM_REG_ANT_TRAIN_PARA1_11N 0x7b0 +#define ODM_REG_ANT_TRAIN_PARA2_11N 0x7b4 + +/* DIG Related */ +#define ODM_BIT_IGI_11N 0x0000007F +#define ODM_BIT_CCK_RPT_FORMAT_11N BIT(9) +#define ODM_BIT_BB_RX_PATH_11N 0xF +#define ODM_BIT_BB_TX_PATH_11N 0xF +#define ODM_BIT_BB_ATC_11N BIT(11) + +#endif diff --git a/drivers/staging/rtlwifi/phydm/phydm_types.h b/drivers/staging/rtlwifi/phydm/phydm_types.h new file mode 100644 index 000000000000..a34ebe876528 --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/phydm_types.h @@ -0,0 +1,130 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef __ODM_TYPES_H__ +#define __ODM_TYPES_H__ + +/*Define Different SW team support*/ +#define ODM_AP 0x01 /*BIT0*/ +#define ODM_CE 0x04 /*BIT2*/ +#define ODM_WIN 0x08 /*BIT3*/ +#define ODM_ADSL 0x10 /*BIT4*/ +#define ODM_IOT 0x20 /*BIT5*/ + +/*Deifne HW endian support*/ +#define ODM_ENDIAN_BIG 0 +#define ODM_ENDIAN_LITTLE 1 + +#define GET_PDM_ODM(__padapter) \ + ((struct phy_dm_struct *)(&(GET_HAL_DATA(__padapter))->odmpriv)) + +enum hal_status { + HAL_STATUS_SUCCESS, + HAL_STATUS_FAILURE, +}; + +/* + * Declare for ODM spin lock definition temporarily fro compile pass. + */ +enum rt_spinlock_type { + RT_TX_SPINLOCK = 1, + RT_RX_SPINLOCK = 2, + RT_RM_SPINLOCK = 3, + RT_CAM_SPINLOCK = 4, + RT_SCAN_SPINLOCK = 5, + RT_LOG_SPINLOCK = 7, + RT_BW_SPINLOCK = 8, + RT_CHNLOP_SPINLOCK = 9, + RT_RF_OPERATE_SPINLOCK = 10, + RT_INITIAL_SPINLOCK = 11, + RT_RF_STATE_SPINLOCK = + 12, /* For RF state. Added by Bruce, 2007-10-30. */ + /* Shall we define Ndis 6.2 SpinLock Here ? */ + RT_PORT_SPINLOCK = 16, + RT_VNIC_SPINLOCK = 17, + RT_HVL_SPINLOCK = 18, + RT_H2C_SPINLOCK = 20, /* For H2C cmd. Added by tynli. 2009.11.09. */ + + rt_bt_data_spinlock = 25, + + RT_WAPI_OPTION_SPINLOCK = 26, + RT_WAPI_RX_SPINLOCK = 27, + + /* add for 92D CCK control issue */ + RT_CCK_PAGEA_SPINLOCK = 28, + RT_BUFFER_SPINLOCK = 29, + RT_CHANNEL_AND_BANDWIDTH_SPINLOCK = 30, + RT_GEN_TEMP_BUF_SPINLOCK = 31, + RT_AWB_SPINLOCK = 32, + RT_FW_PS_SPINLOCK = 33, + RT_HW_TIMER_SPIN_LOCK = 34, + RT_MPT_WI_SPINLOCK = 35, + RT_P2P_SPIN_LOCK = 36, /* Protect P2P context */ + RT_DBG_SPIN_LOCK = 37, + RT_IQK_SPINLOCK = 38, + RT_PENDED_OID_SPINLOCK = 39, + RT_CHNLLIST_SPINLOCK = 40, + RT_INDIC_SPINLOCK = 41, /* protect indication */ + RT_RFD_SPINLOCK = 42, + RT_SYNC_IO_CNT_SPINLOCK = 43, + RT_LAST_SPINLOCK, +}; + +#include <asm/byteorder.h> + +#if defined(__LITTLE_ENDIAN) +#define ODM_ENDIAN_TYPE ODM_ENDIAN_LITTLE +#elif defined(__BIG_ENDIAN) +#define ODM_ENDIAN_TYPE ODM_ENDIAN_BIG +#else +#error +#endif + +#define COND_ELSE 2 +#define COND_ENDIF 3 + +#define MASKBYTE0 0xff +#define MASKBYTE1 0xff00 +#define MASKBYTE2 0xff0000 +#define MASKBYTE3 0xff000000 +#define MASKHWORD 0xffff0000 +#define MASKLWORD 0x0000ffff +#define MASKDWORD 0xffffffff +#define MASK7BITS 0x7f +#define MASK12BITS 0xfff +#define MASKH4BITS 0xf0000000 +#define MASK20BITS 0xfffff +#define MASKOFDM_D 0xffc00000 +#define MASKCCK 0x3f3f3f3f +#define RFREGOFFSETMASK 0xfffff +#define MASKH3BYTES 0xffffff00 +#define MASKL3BYTES 0x00ffffff +#define MASKBYTE2HIGHNIBBLE 0x00f00000 +#define MASKBYTE3LOWNIBBLE 0x0f000000 +#define MASKL3BYTES 0x00ffffff +#define RFREGOFFSETMASK 0xfffff + +#include "phydm_features.h" + +#endif /* __ODM_TYPES_H__ */ diff --git a/drivers/staging/rtlwifi/phydm/rtl8822b/halhwimg8822b_bb.c b/drivers/staging/rtlwifi/phydm/rtl8822b/halhwimg8822b_bb.c new file mode 100644 index 000000000000..4e7946019fcb --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/rtl8822b/halhwimg8822b_bb.c @@ -0,0 +1,1969 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +/*Image2HeaderVersion: 3.2*/ +#include "../mp_precomp.h" +#include "../phydm_precomp.h" + +static bool check_positive(struct phy_dm_struct *dm, const u32 condition1, + const u32 condition2, const u32 condition3, + const u32 condition4) +{ + u8 _board_type = ((dm->board_type & BIT(4)) >> 4) << 0 | /* _GLNA*/ + ((dm->board_type & BIT(3)) >> 3) << 1 | /* _GPA*/ + ((dm->board_type & BIT(7)) >> 7) << 2 | /* _ALNA*/ + ((dm->board_type & BIT(6)) >> 6) << 3 | /* _APA */ + ((dm->board_type & BIT(2)) >> 2) << 4; /* _BT*/ + + u32 cond1 = condition1, cond2 = condition2, cond3 = condition3, + cond4 = condition4; + + u8 cut_version_for_para = + (dm->cut_version == ODM_CUT_A) ? 14 : dm->cut_version; + u8 pkg_type_for_para = (dm->package_type == 0) ? 14 : dm->package_type; + + u32 driver1 = cut_version_for_para << 24 | + (dm->support_interface & 0xF0) << 16 | + dm->support_platform << 16 | pkg_type_for_para << 12 | + (dm->support_interface & 0x0F) << 8 | _board_type; + + u32 driver2 = (dm->type_glna & 0xFF) << 0 | (dm->type_gpa & 0xFF) << 8 | + (dm->type_alna & 0xFF) << 16 | + (dm->type_apa & 0xFF) << 24; + + u32 driver3 = 0; + + u32 driver4 = (dm->type_glna & 0xFF00) >> 8 | (dm->type_gpa & 0xFF00) | + (dm->type_alna & 0xFF00) << 8 | + (dm->type_apa & 0xFF00) << 16; + + ODM_RT_TRACE( + dm, ODM_COMP_INIT, + "===> %s (cond1, cond2, cond3, cond4) = (0x%X 0x%X 0x%X 0x%X)\n", + __func__, cond1, cond2, cond3, cond4); + ODM_RT_TRACE( + dm, ODM_COMP_INIT, + "===> %s (driver1, driver2, driver3, driver4) = (0x%X 0x%X 0x%X 0x%X)\n", + __func__, driver1, driver2, driver3, driver4); + + ODM_RT_TRACE(dm, ODM_COMP_INIT, + " (Platform, Interface) = (0x%X, 0x%X)\n", + dm->support_platform, dm->support_interface); + ODM_RT_TRACE(dm, ODM_COMP_INIT, + " (Board, Package) = (0x%X, 0x%X)\n", + dm->board_type, dm->package_type); + + /*============== value Defined Check ===============*/ + /*QFN type [15:12] and cut version [27:24] need to do value check*/ + + if (((cond1 & 0x0000F000) != 0) && + ((cond1 & 0x0000F000) != (driver1 & 0x0000F000))) + return false; + if (((cond1 & 0x0F000000) != 0) && + ((cond1 & 0x0F000000) != (driver1 & 0x0F000000))) + return false; + + /*=============== Bit Defined Check ================*/ + /* We don't care [31:28] */ + + cond1 &= 0x00FF0FFF; + driver1 &= 0x00FF0FFF; + + if ((cond1 & driver1) == cond1) { + u32 bit_mask = 0; + + if ((cond1 & 0x0F) == 0) /* board_type is DONTCARE*/ + return true; + + if ((cond1 & BIT(0)) != 0) /*GLNA*/ + bit_mask |= 0x000000FF; + if ((cond1 & BIT(1)) != 0) /*GPA*/ + bit_mask |= 0x0000FF00; + if ((cond1 & BIT(2)) != 0) /*ALNA*/ + bit_mask |= 0x00FF0000; + if ((cond1 & BIT(3)) != 0) /*APA*/ + bit_mask |= 0xFF000000; + + if (((cond2 & bit_mask) == (driver2 & bit_mask)) && + ((cond4 & bit_mask) == + (driver4 & + bit_mask))) /* board_type of each RF path is matched*/ + return true; + else + return false; + } else { + return false; + } +} + +/****************************************************************************** + * agc_tab.TXT + ******************************************************************************/ + +static u32 array_mp_8822b_agc_tab[] = { + 0x8000100f, 0x0a0a0a0a, 0x40000000, 0x00000000, 0x81C, 0xFF000003, + 0x81C, 0xF5000003, 0x81C, 0xF4020003, 0x81C, 0xF3040003, + 0x81C, 0xF2060003, 0x81C, 0xF1080003, 0x81C, 0xF00A0003, + 0x81C, 0xEF0C0003, 0x81C, 0xEE0E0003, 0x81C, 0xED100003, + 0x81C, 0xEC120003, 0x81C, 0xEB140003, 0x81C, 0xEA160003, + 0x81C, 0xE9180003, 0x81C, 0xE81A0003, 0x81C, 0xE71C0003, + 0x81C, 0xE61E0003, 0x81C, 0xE5200003, 0x81C, 0xE4220003, + 0x81C, 0xE3240003, 0x81C, 0xE2260003, 0x81C, 0xE1280003, + 0x81C, 0xE02A0003, 0x81C, 0xC32C0003, 0x81C, 0xC22E0003, + 0x81C, 0xC1300003, 0x81C, 0xC0320003, 0x81C, 0xA4340003, + 0x81C, 0xA3360003, 0x81C, 0xA2380003, 0x81C, 0xA13A0003, + 0x81C, 0xA03C0003, 0x81C, 0x823E0003, 0x81C, 0x81400003, + 0x81C, 0x80420003, 0x81C, 0x64440003, 0x81C, 0x63460003, + 0x81C, 0x62480003, 0x81C, 0x614A0003, 0x81C, 0x604C0003, + 0x81C, 0x454E0003, 0x81C, 0x44500003, 0x81C, 0x43520003, + 0x81C, 0x42540003, 0x81C, 0x41560003, 0x81C, 0x40580003, + 0x81C, 0x055A0003, 0x81C, 0x045C0003, 0x81C, 0x035E0003, + 0x81C, 0x02600003, 0x81C, 0x01620003, 0x81C, 0x00640003, + 0x81C, 0x00660003, 0x81C, 0x00680003, 0x81C, 0x006A0003, + 0x81C, 0x006C0003, 0x81C, 0x006E0003, 0x81C, 0x00700003, + 0x81C, 0x00720003, 0x81C, 0x00740003, 0x81C, 0x00760003, + 0x81C, 0x00780003, 0x81C, 0x007A0003, 0x81C, 0x007C0003, + 0x81C, 0x007E0003, 0x9000100f, 0x05050505, 0x40000000, 0x00000000, + 0x81C, 0xFF000003, 0x81C, 0xF5000003, 0x81C, 0xF4020003, + 0x81C, 0xF3040003, 0x81C, 0xF2060003, 0x81C, 0xF1080003, + 0x81C, 0xF00A0003, 0x81C, 0xEF0C0003, 0x81C, 0xEE0E0003, + 0x81C, 0xED100003, 0x81C, 0xEC120003, 0x81C, 0xEB140003, + 0x81C, 0xEA160003, 0x81C, 0xE9180003, 0x81C, 0xE81A0003, + 0x81C, 0xE71C0003, 0x81C, 0xE61E0003, 0x81C, 0xE5200003, + 0x81C, 0xE4220003, 0x81C, 0xE3240003, 0x81C, 0xE2260003, + 0x81C, 0xE1280003, 0x81C, 0xE02A0003, 0x81C, 0xC32C0003, + 0x81C, 0xC22E0003, 0x81C, 0xC1300003, 0x81C, 0xC0320003, + 0x81C, 0xA4340003, 0x81C, 0xA3360003, 0x81C, 0xA2380003, + 0x81C, 0xA13A0003, 0x81C, 0xA03C0003, 0x81C, 0x823E0003, + 0x81C, 0x81400003, 0x81C, 0x80420003, 0x81C, 0x64440003, + 0x81C, 0x63460003, 0x81C, 0x62480003, 0x81C, 0x614A0003, + 0x81C, 0x604C0003, 0x81C, 0x454E0003, 0x81C, 0x44500003, + 0x81C, 0x43520003, 0x81C, 0x42540003, 0x81C, 0x41560003, + 0x81C, 0x40580003, 0x81C, 0x055A0003, 0x81C, 0x045C0003, + 0x81C, 0x035E0003, 0x81C, 0x02600003, 0x81C, 0x01620003, + 0x81C, 0x00640003, 0x81C, 0x00660003, 0x81C, 0x00680003, + 0x81C, 0x006A0003, 0x81C, 0x006C0003, 0x81C, 0x006E0003, + 0x81C, 0x00700003, 0x81C, 0x00720003, 0x81C, 0x00740003, + 0x81C, 0x00760003, 0x81C, 0x00780003, 0x81C, 0x007A0003, + 0x81C, 0x007C0003, 0x81C, 0x007E0003, 0x9000100f, 0x00000000, + 0x40000000, 0x00000000, 0x81C, 0xFF000003, 0x81C, 0xF5000003, + 0x81C, 0xF4020003, 0x81C, 0xF3040003, 0x81C, 0xF2060003, + 0x81C, 0xF1080003, 0x81C, 0xF00A0003, 0x81C, 0xEF0C0003, + 0x81C, 0xEE0E0003, 0x81C, 0xED100003, 0x81C, 0xEC120003, + 0x81C, 0xEB140003, 0x81C, 0xEA160003, 0x81C, 0xE9180003, + 0x81C, 0xE81A0003, 0x81C, 0xE71C0003, 0x81C, 0xE61E0003, + 0x81C, 0xE5200003, 0x81C, 0xE4220003, 0x81C, 0xE3240003, + 0x81C, 0xE2260003, 0x81C, 0xE1280003, 0x81C, 0xE02A0003, + 0x81C, 0xC32C0003, 0x81C, 0xC22E0003, 0x81C, 0xC1300003, + 0x81C, 0xC0320003, 0x81C, 0xA4340003, 0x81C, 0xA3360003, + 0x81C, 0xA2380003, 0x81C, 0xA13A0003, 0x81C, 0xA03C0003, + 0x81C, 0x823E0003, 0x81C, 0x81400003, 0x81C, 0x80420003, + 0x81C, 0x64440003, 0x81C, 0x63460003, 0x81C, 0x62480003, + 0x81C, 0x614A0003, 0x81C, 0x604C0003, 0x81C, 0x454E0003, + 0x81C, 0x44500003, 0x81C, 0x43520003, 0x81C, 0x42540003, + 0x81C, 0x41560003, 0x81C, 0x40580003, 0x81C, 0x055A0003, + 0x81C, 0x045C0003, 0x81C, 0x035E0003, 0x81C, 0x02600003, + 0x81C, 0x01620003, 0x81C, 0x00640003, 0x81C, 0x00660003, + 0x81C, 0x00680003, 0x81C, 0x006A0003, 0x81C, 0x006C0003, + 0x81C, 0x006E0003, 0x81C, 0x00700003, 0x81C, 0x00720003, + 0x81C, 0x00740003, 0x81C, 0x00760003, 0x81C, 0x00780003, + 0x81C, 0x007A0003, 0x81C, 0x007C0003, 0x81C, 0x007E0003, + 0x9000200f, 0x00000000, 0x40000000, 0x00000000, 0x81C, 0xFF000003, + 0x81C, 0xF5000003, 0x81C, 0xF4020003, 0x81C, 0xF3040003, + 0x81C, 0xF2060003, 0x81C, 0xF1080003, 0x81C, 0xF00A0003, + 0x81C, 0xEF0C0003, 0x81C, 0xEE0E0003, 0x81C, 0xED100003, + 0x81C, 0xEC120003, 0x81C, 0xEB140003, 0x81C, 0xEA160003, + 0x81C, 0xE9180003, 0x81C, 0xE81A0003, 0x81C, 0xE71C0003, + 0x81C, 0xE61E0003, 0x81C, 0xE5200003, 0x81C, 0xE4220003, + 0x81C, 0xE3240003, 0x81C, 0xE2260003, 0x81C, 0xE1280003, + 0x81C, 0xE02A0003, 0x81C, 0xC32C0003, 0x81C, 0xC22E0003, + 0x81C, 0xC1300003, 0x81C, 0xC0320003, 0x81C, 0xA4340003, + 0x81C, 0xA3360003, 0x81C, 0xA2380003, 0x81C, 0xA13A0003, + 0x81C, 0xA03C0003, 0x81C, 0x823E0003, 0x81C, 0x81400003, + 0x81C, 0x80420003, 0x81C, 0x64440003, 0x81C, 0x63460003, + 0x81C, 0x62480003, 0x81C, 0x614A0003, 0x81C, 0x604C0003, + 0x81C, 0x454E0003, 0x81C, 0x44500003, 0x81C, 0x43520003, + 0x81C, 0x42540003, 0x81C, 0x41560003, 0x81C, 0x40580003, + 0x81C, 0x055A0003, 0x81C, 0x045C0003, 0x81C, 0x035E0003, + 0x81C, 0x02600003, 0x81C, 0x01620003, 0x81C, 0x00640003, + 0x81C, 0x00660003, 0x81C, 0x00680003, 0x81C, 0x006A0003, + 0x81C, 0x006C0003, 0x81C, 0x006E0003, 0x81C, 0x00700003, + 0x81C, 0x00720003, 0x81C, 0x00740003, 0x81C, 0x00760003, + 0x81C, 0x00780003, 0x81C, 0x007A0003, 0x81C, 0x007C0003, + 0x81C, 0x007E0003, 0x9000200c, 0x00000000, 0x40000000, 0x00000000, + 0x81C, 0xFF000003, 0x81C, 0xFD000003, 0x81C, 0xFC020003, + 0x81C, 0xFB040003, 0x81C, 0xFA060003, 0x81C, 0xF9080003, + 0x81C, 0xF80A0003, 0x81C, 0xF70C0003, 0x81C, 0xF60E0003, + 0x81C, 0xF5100003, 0x81C, 0xF4120003, 0x81C, 0xF3140003, + 0x81C, 0xF2160003, 0x81C, 0xF1180003, 0x81C, 0xF01A0003, + 0x81C, 0xEF1C0003, 0x81C, 0xEE1E0003, 0x81C, 0xED200003, + 0x81C, 0xEC220003, 0x81C, 0xEB240003, 0x81C, 0xEA260003, + 0x81C, 0xE9280003, 0x81C, 0xE82A0003, 0x81C, 0xE72C0003, + 0x81C, 0xE62E0003, 0x81C, 0xE5300003, 0x81C, 0xC8320003, + 0x81C, 0xC7340003, 0x81C, 0xC6360003, 0x81C, 0xC5380003, + 0x81C, 0xC43A0003, 0x81C, 0xC33C0003, 0x81C, 0xC23E0003, + 0x81C, 0xC1400003, 0x81C, 0xC0420003, 0x81C, 0xA5440003, + 0x81C, 0xA4460003, 0x81C, 0xA3480003, 0x81C, 0xA24A0003, + 0x81C, 0xA14C0003, 0x81C, 0x834E0003, 0x81C, 0x82500003, + 0x81C, 0x81520003, 0x81C, 0x80540003, 0x81C, 0x65560003, + 0x81C, 0x64580003, 0x81C, 0x635A0003, 0x81C, 0x625C0003, + 0x81C, 0x435E0003, 0x81C, 0x42600003, 0x81C, 0x41620003, + 0x81C, 0x40640003, 0x81C, 0x06660003, 0x81C, 0x05680003, + 0x81C, 0x046A0003, 0x81C, 0x036C0003, 0x81C, 0x026E0003, + 0x81C, 0x01700003, 0x81C, 0x00720003, 0x81C, 0x00740003, + 0x81C, 0x00760003, 0x81C, 0x00780003, 0x81C, 0x007A0003, + 0x81C, 0x007C0003, 0x81C, 0x007E0003, 0x90012100, 0x00000000, + 0x40000000, 0x00000000, 0x81C, 0xFF000003, 0x81C, 0xFE000003, + 0x81C, 0xFD020003, 0x81C, 0xFC040003, 0x81C, 0xFB060003, + 0x81C, 0xFA080003, 0x81C, 0xF90A0003, 0x81C, 0xF80C0003, + 0x81C, 0xF70E0003, 0x81C, 0xF6100003, 0x81C, 0xF5120003, + 0x81C, 0xF4140003, 0x81C, 0xF3160003, 0x81C, 0xF2180003, + 0x81C, 0xF11A0003, 0x81C, 0xF01C0003, 0x81C, 0xEF1E0003, + 0x81C, 0xEE200003, 0x81C, 0xED220003, 0x81C, 0xEC240003, + 0x81C, 0xEB260003, 0x81C, 0xEA280003, 0x81C, 0xE92A0003, + 0x81C, 0xE82C0003, 0x81C, 0xE72E0003, 0x81C, 0xE6300003, + 0x81C, 0xE5320003, 0x81C, 0xC8340003, 0x81C, 0xC7360003, + 0x81C, 0xC6380003, 0x81C, 0xC53A0003, 0x81C, 0xC43C0003, + 0x81C, 0xC33E0003, 0x81C, 0xC2400003, 0x81C, 0xC1420003, + 0x81C, 0xC0440003, 0x81C, 0xA3460003, 0x81C, 0xA2480003, + 0x81C, 0xA14A0003, 0x81C, 0xA04C0003, 0x81C, 0x824E0003, + 0x81C, 0x81500003, 0x81C, 0x80520003, 0x81C, 0x64540003, + 0x81C, 0x63560003, 0x81C, 0x62580003, 0x81C, 0x445A0003, + 0x81C, 0x435C0003, 0x81C, 0x425E0003, 0x81C, 0x41600003, + 0x81C, 0x40620003, 0x81C, 0x05640003, 0x81C, 0x04660003, + 0x81C, 0x03680003, 0x81C, 0x026A0003, 0x81C, 0x016C0003, + 0x81C, 0x006E0003, 0x81C, 0x00700003, 0x81C, 0x00720003, + 0x81C, 0x00740003, 0x81C, 0x00760003, 0x81C, 0x00780003, + 0x81C, 0x007A0003, 0x81C, 0x007C0003, 0x81C, 0x007E0003, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, 0x81C, 0xFF000003, + 0x81C, 0xF5000003, 0x81C, 0xF4020003, 0x81C, 0xF3040003, + 0x81C, 0xF2060003, 0x81C, 0xF1080003, 0x81C, 0xF00A0003, + 0x81C, 0xEF0C0003, 0x81C, 0xEE0E0003, 0x81C, 0xED100003, + 0x81C, 0xEC120003, 0x81C, 0xEB140003, 0x81C, 0xEA160003, + 0x81C, 0xE9180003, 0x81C, 0xE81A0003, 0x81C, 0xE71C0003, + 0x81C, 0xE61E0003, 0x81C, 0xE5200003, 0x81C, 0xE4220003, + 0x81C, 0xE3240003, 0x81C, 0xE2260003, 0x81C, 0xE1280003, + 0x81C, 0xE02A0003, 0x81C, 0xC32C0003, 0x81C, 0xC22E0003, + 0x81C, 0xC1300003, 0x81C, 0xC0320003, 0x81C, 0xA4340003, + 0x81C, 0xA3360003, 0x81C, 0xA2380003, 0x81C, 0xA13A0003, + 0x81C, 0xA03C0003, 0x81C, 0x823E0003, 0x81C, 0x81400003, + 0x81C, 0x80420003, 0x81C, 0x64440003, 0x81C, 0x63460003, + 0x81C, 0x62480003, 0x81C, 0x614A0003, 0x81C, 0x604C0003, + 0x81C, 0x454E0003, 0x81C, 0x44500003, 0x81C, 0x43520003, + 0x81C, 0x42540003, 0x81C, 0x41560003, 0x81C, 0x40580003, + 0x81C, 0x055A0003, 0x81C, 0x045C0003, 0x81C, 0x035E0003, + 0x81C, 0x02600003, 0x81C, 0x01620003, 0x81C, 0x00640003, + 0x81C, 0x00660003, 0x81C, 0x00680003, 0x81C, 0x006A0003, + 0x81C, 0x006C0003, 0x81C, 0x006E0003, 0x81C, 0x00700003, + 0x81C, 0x00720003, 0x81C, 0x00740003, 0x81C, 0x00760003, + 0x81C, 0x00780003, 0x81C, 0x007A0003, 0x81C, 0x007C0003, + 0x81C, 0x007E0003, 0x90011000, 0x00000000, 0x40000000, 0x00000000, + 0x81C, 0xFF000003, 0x81C, 0xFE000003, 0x81C, 0xFD020003, + 0x81C, 0xFC040003, 0x81C, 0xFB060003, 0x81C, 0xFA080003, + 0x81C, 0xF90A0003, 0x81C, 0xF80C0003, 0x81C, 0xF70E0003, + 0x81C, 0xF6100003, 0x81C, 0xF5120003, 0x81C, 0xF4140003, + 0x81C, 0xF3160003, 0x81C, 0xF2180003, 0x81C, 0xF11A0003, + 0x81C, 0xF01C0003, 0x81C, 0xEF1E0003, 0x81C, 0xEE200003, + 0x81C, 0xED220003, 0x81C, 0xEC240003, 0x81C, 0xEB260003, + 0x81C, 0xEA280003, 0x81C, 0xE92A0003, 0x81C, 0xE82C0003, + 0x81C, 0xE72E0003, 0x81C, 0xE6300003, 0x81C, 0xE5320003, + 0x81C, 0xC8340003, 0x81C, 0xC7360003, 0x81C, 0xC6380003, + 0x81C, 0xC53A0003, 0x81C, 0xC43C0003, 0x81C, 0xC33E0003, + 0x81C, 0xC2400003, 0x81C, 0xC1420003, 0x81C, 0xC0440003, + 0x81C, 0xA3460003, 0x81C, 0xA2480003, 0x81C, 0xA14A0003, + 0x81C, 0xA04C0003, 0x81C, 0x824E0003, 0x81C, 0x81500003, + 0x81C, 0x80520003, 0x81C, 0x64540003, 0x81C, 0x63560003, + 0x81C, 0x62580003, 0x81C, 0x445A0003, 0x81C, 0x435C0003, + 0x81C, 0x425E0003, 0x81C, 0x41600003, 0x81C, 0x40620003, + 0x81C, 0x05640003, 0x81C, 0x04660003, 0x81C, 0x03680003, + 0x81C, 0x026A0003, 0x81C, 0x016C0003, 0x81C, 0x006E0003, + 0x81C, 0x00700003, 0x81C, 0x00720003, 0x81C, 0x00740003, + 0x81C, 0x00760003, 0x81C, 0x00780003, 0x81C, 0x007A0003, + 0x81C, 0x007C0003, 0x81C, 0x007E0003, 0x90002100, 0x00000000, + 0x40000000, 0x00000000, 0x81C, 0xFF000003, 0x81C, 0xFD000003, + 0x81C, 0xFC020003, 0x81C, 0xFB040003, 0x81C, 0xFA060003, + 0x81C, 0xF9080003, 0x81C, 0xF80A0003, 0x81C, 0xF70C0003, + 0x81C, 0xF60E0003, 0x81C, 0xF5100003, 0x81C, 0xF4120003, + 0x81C, 0xF3140003, 0x81C, 0xF2160003, 0x81C, 0xF1180003, + 0x81C, 0xF01A0003, 0x81C, 0xEF1C0003, 0x81C, 0xEE1E0003, + 0x81C, 0xED200003, 0x81C, 0xEC220003, 0x81C, 0xEB240003, + 0x81C, 0xEA260003, 0x81C, 0xE9280003, 0x81C, 0xE82A0003, + 0x81C, 0xE72C0003, 0x81C, 0xE62E0003, 0x81C, 0xE5300003, + 0x81C, 0xC8320003, 0x81C, 0xC7340003, 0x81C, 0xC6360003, + 0x81C, 0xC5380003, 0x81C, 0xC43A0003, 0x81C, 0xC33C0003, + 0x81C, 0xC23E0003, 0x81C, 0xC1400003, 0x81C, 0xC0420003, + 0x81C, 0xA5440003, 0x81C, 0xA4460003, 0x81C, 0xA3480003, + 0x81C, 0xA24A0003, 0x81C, 0xA14C0003, 0x81C, 0x834E0003, + 0x81C, 0x82500003, 0x81C, 0x81520003, 0x81C, 0x80540003, + 0x81C, 0x65560003, 0x81C, 0x64580003, 0x81C, 0x635A0003, + 0x81C, 0x625C0003, 0x81C, 0x435E0003, 0x81C, 0x42600003, + 0x81C, 0x41620003, 0x81C, 0x40640003, 0x81C, 0x06660003, + 0x81C, 0x05680003, 0x81C, 0x046A0003, 0x81C, 0x036C0003, + 0x81C, 0x026E0003, 0x81C, 0x01700003, 0x81C, 0x00720003, + 0x81C, 0x00740003, 0x81C, 0x00760003, 0x81C, 0x00780003, + 0x81C, 0x007A0003, 0x81C, 0x007C0003, 0x81C, 0x007E0003, + 0x90002000, 0x00000000, 0x40000000, 0x00000000, 0x81C, 0xFF000003, + 0x81C, 0xFD000003, 0x81C, 0xFC020003, 0x81C, 0xFB040003, + 0x81C, 0xFA060003, 0x81C, 0xF9080003, 0x81C, 0xF80A0003, + 0x81C, 0xF70C0003, 0x81C, 0xF60E0003, 0x81C, 0xF5100003, + 0x81C, 0xF4120003, 0x81C, 0xF3140003, 0x81C, 0xF2160003, + 0x81C, 0xF1180003, 0x81C, 0xF01A0003, 0x81C, 0xEF1C0003, + 0x81C, 0xEE1E0003, 0x81C, 0xED200003, 0x81C, 0xEC220003, + 0x81C, 0xEB240003, 0x81C, 0xEA260003, 0x81C, 0xE9280003, + 0x81C, 0xE82A0003, 0x81C, 0xE72C0003, 0x81C, 0xE62E0003, + 0x81C, 0xE5300003, 0x81C, 0xC8320003, 0x81C, 0xC7340003, + 0x81C, 0xC6360003, 0x81C, 0xC5380003, 0x81C, 0xC43A0003, + 0x81C, 0xC33C0003, 0x81C, 0xC23E0003, 0x81C, 0xC1400003, + 0x81C, 0xC0420003, 0x81C, 0xA5440003, 0x81C, 0xA4460003, + 0x81C, 0xA3480003, 0x81C, 0xA24A0003, 0x81C, 0xA14C0003, + 0x81C, 0x834E0003, 0x81C, 0x82500003, 0x81C, 0x81520003, + 0x81C, 0x80540003, 0x81C, 0x65560003, 0x81C, 0x64580003, + 0x81C, 0x635A0003, 0x81C, 0x625C0003, 0x81C, 0x435E0003, + 0x81C, 0x42600003, 0x81C, 0x41620003, 0x81C, 0x40640003, + 0x81C, 0x06660003, 0x81C, 0x05680003, 0x81C, 0x046A0003, + 0x81C, 0x036C0003, 0x81C, 0x026E0003, 0x81C, 0x01700003, + 0x81C, 0x00720003, 0x81C, 0x00740003, 0x81C, 0x00760003, + 0x81C, 0x00780003, 0x81C, 0x007A0003, 0x81C, 0x007C0003, + 0x81C, 0x007E0003, 0xA0000000, 0x00000000, 0x81C, 0xFF000003, + 0x81C, 0xFE000003, 0x81C, 0xFD020003, 0x81C, 0xFC040003, + 0x81C, 0xFB060003, 0x81C, 0xFA080003, 0x81C, 0xF90A0003, + 0x81C, 0xF80C0003, 0x81C, 0xF70E0003, 0x81C, 0xF6100003, + 0x81C, 0xF5120003, 0x81C, 0xF4140003, 0x81C, 0xF3160003, + 0x81C, 0xF2180003, 0x81C, 0xF11A0003, 0x81C, 0xF01C0003, + 0x81C, 0xEF1E0003, 0x81C, 0xEE200003, 0x81C, 0xED220003, + 0x81C, 0xEC240003, 0x81C, 0xEB260003, 0x81C, 0xEA280003, + 0x81C, 0xE92A0003, 0x81C, 0xE82C0003, 0x81C, 0xE72E0003, + 0x81C, 0xE6300003, 0x81C, 0xE5320003, 0x81C, 0xC8340003, + 0x81C, 0xC7360003, 0x81C, 0xC6380003, 0x81C, 0xC53A0003, + 0x81C, 0xC43C0003, 0x81C, 0xC33E0003, 0x81C, 0xC2400003, + 0x81C, 0xC1420003, 0x81C, 0xC0440003, 0x81C, 0xA3460003, + 0x81C, 0xA2480003, 0x81C, 0xA14A0003, 0x81C, 0xA04C0003, + 0x81C, 0x824E0003, 0x81C, 0x81500003, 0x81C, 0x80520003, + 0x81C, 0x64540003, 0x81C, 0x63560003, 0x81C, 0x62580003, + 0x81C, 0x445A0003, 0x81C, 0x435C0003, 0x81C, 0x425E0003, + 0x81C, 0x41600003, 0x81C, 0x40620003, 0x81C, 0x05640003, + 0x81C, 0x04660003, 0x81C, 0x03680003, 0x81C, 0x026A0003, + 0x81C, 0x016C0003, 0x81C, 0x006E0003, 0x81C, 0x00700003, + 0x81C, 0x00720003, 0x81C, 0x00740003, 0x81C, 0x00760003, + 0x81C, 0x00780003, 0x81C, 0x007A0003, 0x81C, 0x007C0003, + 0x81C, 0x007E0003, 0xB0000000, 0x00000000, 0x8000100f, 0x0a0a0a0a, + 0x40000000, 0x00000000, 0x81C, 0xF8000103, 0x81C, 0xF7020103, + 0x81C, 0xF6040103, 0x81C, 0xF5060103, 0x81C, 0xF4080103, + 0x81C, 0xF30A0103, 0x81C, 0xF20C0103, 0x81C, 0xF10E0103, + 0x81C, 0xF0100103, 0x81C, 0xEF120103, 0x81C, 0xEE140103, + 0x81C, 0xED160103, 0x81C, 0xEC180103, 0x81C, 0xEB1A0103, + 0x81C, 0xEA1C0103, 0x81C, 0xE91E0103, 0x81C, 0xE8200103, + 0x81C, 0xE7220103, 0x81C, 0xE6240103, 0x81C, 0xE5260103, + 0x81C, 0xE4280103, 0x81C, 0xE32A0103, 0x81C, 0xE22C0103, + 0x81C, 0xC32E0103, 0x81C, 0xC2300103, 0x81C, 0xC1320103, + 0x81C, 0xA3340103, 0x81C, 0xA2360103, 0x81C, 0xA1380103, + 0x81C, 0xA03A0103, 0x81C, 0x823C0103, 0x81C, 0x813E0103, + 0x81C, 0x80400103, 0x81C, 0x64420103, 0x81C, 0x63440103, + 0x81C, 0x62460103, 0x81C, 0x61480103, 0x81C, 0x434A0103, + 0x81C, 0x424C0103, 0x81C, 0x414E0103, 0x81C, 0x40500103, + 0x81C, 0x22520103, 0x81C, 0x21540103, 0x81C, 0x20560103, + 0x81C, 0x04580103, 0x81C, 0x035A0103, 0x81C, 0x025C0103, + 0x81C, 0x015E0103, 0x81C, 0x00600103, 0x81C, 0x00620103, + 0x81C, 0x00640103, 0x81C, 0x00660103, 0x81C, 0x00680103, + 0x81C, 0x006A0103, 0x81C, 0x006C0103, 0x81C, 0x006E0103, + 0x81C, 0x00700103, 0x81C, 0x00720103, 0x81C, 0x00740103, + 0x81C, 0x00760103, 0x81C, 0x00780103, 0x81C, 0x007A0103, + 0x81C, 0x007C0103, 0x81C, 0x007E0103, 0x9000100f, 0x05050505, + 0x40000000, 0x00000000, 0x81C, 0xFA000103, 0x81C, 0xF9020103, + 0x81C, 0xF8040103, 0x81C, 0xF7060103, 0x81C, 0xF6080103, + 0x81C, 0xF50A0103, 0x81C, 0xF40C0103, 0x81C, 0xF30E0103, + 0x81C, 0xF2100103, 0x81C, 0xF1120103, 0x81C, 0xF0140103, + 0x81C, 0xEF160103, 0x81C, 0xEE180103, 0x81C, 0xED1A0103, + 0x81C, 0xEC1C0103, 0x81C, 0xEB1E0103, 0x81C, 0xEA200103, + 0x81C, 0xE9220103, 0x81C, 0xE8240103, 0x81C, 0xE7260103, + 0x81C, 0xE6280103, 0x81C, 0xE52A0103, 0x81C, 0xC42C0103, + 0x81C, 0xC32E0103, 0x81C, 0xC2300103, 0x81C, 0xC1320103, + 0x81C, 0xA4340103, 0x81C, 0xA3360103, 0x81C, 0xA2380103, + 0x81C, 0xA13A0103, 0x81C, 0x833C0103, 0x81C, 0x823E0103, + 0x81C, 0x81400103, 0x81C, 0x63420103, 0x81C, 0x62440103, + 0x81C, 0x61460103, 0x81C, 0x60480103, 0x81C, 0x424A0103, + 0x81C, 0x414C0103, 0x81C, 0x404E0103, 0x81C, 0x22500103, + 0x81C, 0x21520103, 0x81C, 0x20540103, 0x81C, 0x03560103, + 0x81C, 0x02580103, 0x81C, 0x015A0103, 0x81C, 0x005C0103, + 0x81C, 0x005E0103, 0x81C, 0x00600103, 0x81C, 0x00620103, + 0x81C, 0x00640103, 0x81C, 0x00660103, 0x81C, 0x00680103, + 0x81C, 0x006A0103, 0x81C, 0x006C0103, 0x81C, 0x006E0103, + 0x81C, 0x00700103, 0x81C, 0x00720103, 0x81C, 0x00740103, + 0x81C, 0x00760103, 0x81C, 0x00780103, 0x81C, 0x007A0103, + 0x81C, 0x007C0103, 0x81C, 0x007E0103, 0x9000100f, 0x00000000, + 0x40000000, 0x00000000, 0x81C, 0xF8000103, 0x81C, 0xF7020103, + 0x81C, 0xF6040103, 0x81C, 0xF5060103, 0x81C, 0xF4080103, + 0x81C, 0xF30A0103, 0x81C, 0xF20C0103, 0x81C, 0xF10E0103, + 0x81C, 0xF0100103, 0x81C, 0xEF120103, 0x81C, 0xEE140103, + 0x81C, 0xED160103, 0x81C, 0xEC180103, 0x81C, 0xEB1A0103, + 0x81C, 0xEA1C0103, 0x81C, 0xE91E0103, 0x81C, 0xE8200103, + 0x81C, 0xE7220103, 0x81C, 0xE6240103, 0x81C, 0xE5260103, + 0x81C, 0xE4280103, 0x81C, 0xE32A0103, 0x81C, 0xC32C0103, + 0x81C, 0xC22E0103, 0x81C, 0xC1300103, 0x81C, 0xC0320103, + 0x81C, 0xA3340103, 0x81C, 0xA2360103, 0x81C, 0xA1380103, + 0x81C, 0xA03A0103, 0x81C, 0x823C0103, 0x81C, 0x813E0103, + 0x81C, 0x80400103, 0x81C, 0x63420103, 0x81C, 0x62440103, + 0x81C, 0x61460103, 0x81C, 0x60480103, 0x81C, 0x424A0103, + 0x81C, 0x414C0103, 0x81C, 0x404E0103, 0x81C, 0x06500103, + 0x81C, 0x05520103, 0x81C, 0x04540103, 0x81C, 0x03560103, + 0x81C, 0x02580103, 0x81C, 0x015A0103, 0x81C, 0x005C0103, + 0x81C, 0x005E0103, 0x81C, 0x00600103, 0x81C, 0x00620103, + 0x81C, 0x00640103, 0x81C, 0x00660103, 0x81C, 0x00680103, + 0x81C, 0x006A0103, 0x81C, 0x006C0103, 0x81C, 0x006E0103, + 0x81C, 0x00700103, 0x81C, 0x00720103, 0x81C, 0x00740103, + 0x81C, 0x00760103, 0x81C, 0x00780103, 0x81C, 0x007A0103, + 0x81C, 0x007C0103, 0x81C, 0x007E0103, 0x9000200f, 0x00000000, + 0x40000000, 0x00000000, 0x81C, 0xF8000103, 0x81C, 0xF7020103, + 0x81C, 0xF6040103, 0x81C, 0xF5060103, 0x81C, 0xF4080103, + 0x81C, 0xF30A0103, 0x81C, 0xF20C0103, 0x81C, 0xF10E0103, + 0x81C, 0xF0100103, 0x81C, 0xEF120103, 0x81C, 0xEE140103, + 0x81C, 0xED160103, 0x81C, 0xEC180103, 0x81C, 0xEB1A0103, + 0x81C, 0xEA1C0103, 0x81C, 0xE91E0103, 0x81C, 0xE8200103, + 0x81C, 0xE7220103, 0x81C, 0xE6240103, 0x81C, 0xE5260103, + 0x81C, 0xE4280103, 0x81C, 0xE32A0103, 0x81C, 0xC32C0103, + 0x81C, 0xC22E0103, 0x81C, 0xC1300103, 0x81C, 0xC0320103, + 0x81C, 0xA3340103, 0x81C, 0xA2360103, 0x81C, 0xA1380103, + 0x81C, 0xA03A0103, 0x81C, 0x823C0103, 0x81C, 0x813E0103, + 0x81C, 0x80400103, 0x81C, 0x63420103, 0x81C, 0x62440103, + 0x81C, 0x61460103, 0x81C, 0x60480103, 0x81C, 0x424A0103, + 0x81C, 0x414C0103, 0x81C, 0x404E0103, 0x81C, 0x22500103, + 0x81C, 0x21520103, 0x81C, 0x20540103, 0x81C, 0x03560103, + 0x81C, 0x02580103, 0x81C, 0x015A0103, 0x81C, 0x005C0103, + 0x81C, 0x005E0103, 0x81C, 0x00600103, 0x81C, 0x00620103, + 0x81C, 0x00640103, 0x81C, 0x00660103, 0x81C, 0x00680103, + 0x81C, 0x006A0103, 0x81C, 0x006C0103, 0x81C, 0x006E0103, + 0x81C, 0x00700103, 0x81C, 0x00720103, 0x81C, 0x00740103, + 0x81C, 0x00760103, 0x81C, 0x00780103, 0x81C, 0x007A0103, + 0x81C, 0x007C0103, 0x81C, 0x007E0103, 0x9000200c, 0x00000000, + 0x40000000, 0x00000000, 0x81C, 0xF8000103, 0x81C, 0xF7020103, + 0x81C, 0xF6040103, 0x81C, 0xF5060103, 0x81C, 0xF4080103, + 0x81C, 0xF30A0103, 0x81C, 0xF20C0103, 0x81C, 0xF10E0103, + 0x81C, 0xF0100103, 0x81C, 0xEF120103, 0x81C, 0xEE140103, + 0x81C, 0xED160103, 0x81C, 0xEC180103, 0x81C, 0xEB1A0103, + 0x81C, 0xEA1C0103, 0x81C, 0xE91E0103, 0x81C, 0xE8200103, + 0x81C, 0xE7220103, 0x81C, 0xE6240103, 0x81C, 0xE5260103, + 0x81C, 0xE4280103, 0x81C, 0xE32A0103, 0x81C, 0xC32C0103, + 0x81C, 0xC22E0103, 0x81C, 0xC1300103, 0x81C, 0xC0320103, + 0x81C, 0xA3340103, 0x81C, 0xA2360103, 0x81C, 0xA1380103, + 0x81C, 0xA03A0103, 0x81C, 0x823C0103, 0x81C, 0x813E0103, + 0x81C, 0x80400103, 0x81C, 0x63420103, 0x81C, 0x62440103, + 0x81C, 0x61460103, 0x81C, 0x60480103, 0x81C, 0x424A0103, + 0x81C, 0x414C0103, 0x81C, 0x404E0103, 0x81C, 0x22500103, + 0x81C, 0x21520103, 0x81C, 0x20540103, 0x81C, 0x03560103, + 0x81C, 0x02580103, 0x81C, 0x015A0103, 0x81C, 0x005C0103, + 0x81C, 0x005E0103, 0x81C, 0x00600103, 0x81C, 0x00620103, + 0x81C, 0x00640103, 0x81C, 0x00660103, 0x81C, 0x00680103, + 0x81C, 0x006A0103, 0x81C, 0x006C0103, 0x81C, 0x006E0103, + 0x81C, 0x00700103, 0x81C, 0x00720103, 0x81C, 0x00740103, + 0x81C, 0x00760103, 0x81C, 0x00780103, 0x81C, 0x007A0103, + 0x81C, 0x007C0103, 0x81C, 0x007E0103, 0x90012100, 0x00000000, + 0x40000000, 0x00000000, 0x81C, 0xFD000103, 0x81C, 0xFC020103, + 0x81C, 0xFB040103, 0x81C, 0xFA060103, 0x81C, 0xF9080103, + 0x81C, 0xF80A0103, 0x81C, 0xF70C0103, 0x81C, 0xF60E0103, + 0x81C, 0xF5100103, 0x81C, 0xF4120103, 0x81C, 0xF3140103, + 0x81C, 0xF2160103, 0x81C, 0xF1180103, 0x81C, 0xF01A0103, + 0x81C, 0xEF1C0103, 0x81C, 0xEE1E0103, 0x81C, 0xED200103, + 0x81C, 0xEC220103, 0x81C, 0xEB240103, 0x81C, 0xEA260103, + 0x81C, 0xE9280103, 0x81C, 0xE82A0103, 0x81C, 0xE72C0103, + 0x81C, 0xE62E0103, 0x81C, 0xE5300103, 0x81C, 0xE4320103, + 0x81C, 0xE3340103, 0x81C, 0xC6360103, 0x81C, 0xC5380103, + 0x81C, 0xC43A0103, 0x81C, 0xC33C0103, 0x81C, 0xC23E0103, + 0x81C, 0xA5400103, 0x81C, 0xA4420103, 0x81C, 0xA3440103, + 0x81C, 0xA2460103, 0x81C, 0xA1480103, 0x81C, 0x834A0103, + 0x81C, 0x824C0103, 0x81C, 0x814E0103, 0x81C, 0x63500103, + 0x81C, 0x62520103, 0x81C, 0x61540103, 0x81C, 0x43560103, + 0x81C, 0x42580103, 0x81C, 0x245A0103, 0x81C, 0x235C0103, + 0x81C, 0x225E0103, 0x81C, 0x21600103, 0x81C, 0x04620103, + 0x81C, 0x03640103, 0x81C, 0x02660103, 0x81C, 0x01680103, + 0x81C, 0x006A0103, 0x81C, 0x006C0103, 0x81C, 0x006E0103, + 0x81C, 0x00700103, 0x81C, 0x00720103, 0x81C, 0x00740103, + 0x81C, 0x00760103, 0x81C, 0x00780103, 0x81C, 0x007A0103, + 0x81C, 0x007C0103, 0x81C, 0x007E0103, 0x90001004, 0x00000000, + 0x40000000, 0x00000000, 0x81C, 0xF8000103, 0x81C, 0xF7020103, + 0x81C, 0xF6040103, 0x81C, 0xF5060103, 0x81C, 0xF4080103, + 0x81C, 0xF30A0103, 0x81C, 0xF20C0103, 0x81C, 0xF10E0103, + 0x81C, 0xF0100103, 0x81C, 0xEF120103, 0x81C, 0xEE140103, + 0x81C, 0xED160103, 0x81C, 0xEC180103, 0x81C, 0xEB1A0103, + 0x81C, 0xEA1C0103, 0x81C, 0xE91E0103, 0x81C, 0xE8200103, + 0x81C, 0xE7220103, 0x81C, 0xE6240103, 0x81C, 0xE5260103, + 0x81C, 0xE4280103, 0x81C, 0xE32A0103, 0x81C, 0xE22C0103, + 0x81C, 0xC32E0103, 0x81C, 0xC2300103, 0x81C, 0xC1320103, + 0x81C, 0xA3340103, 0x81C, 0xA2360103, 0x81C, 0xA1380103, + 0x81C, 0xA03A0103, 0x81C, 0x823C0103, 0x81C, 0x813E0103, + 0x81C, 0x80400103, 0x81C, 0x64420103, 0x81C, 0x63440103, + 0x81C, 0x62460103, 0x81C, 0x61480103, 0x81C, 0x434A0103, + 0x81C, 0x424C0103, 0x81C, 0x414E0103, 0x81C, 0x40500103, + 0x81C, 0x22520103, 0x81C, 0x21540103, 0x81C, 0x20560103, + 0x81C, 0x04580103, 0x81C, 0x035A0103, 0x81C, 0x025C0103, + 0x81C, 0x015E0103, 0x81C, 0x00600103, 0x81C, 0x00620103, + 0x81C, 0x00640103, 0x81C, 0x00660103, 0x81C, 0x00680103, + 0x81C, 0x006A0103, 0x81C, 0x006C0103, 0x81C, 0x006E0103, + 0x81C, 0x00700103, 0x81C, 0x00720103, 0x81C, 0x00740103, + 0x81C, 0x00760103, 0x81C, 0x00780103, 0x81C, 0x007A0103, + 0x81C, 0x007C0103, 0x81C, 0x007E0103, 0x90011000, 0x00000000, + 0x40000000, 0x00000000, 0x81C, 0xFD000103, 0x81C, 0xFC020103, + 0x81C, 0xFB040103, 0x81C, 0xFA060103, 0x81C, 0xF9080103, + 0x81C, 0xF80A0103, 0x81C, 0xF70C0103, 0x81C, 0xF60E0103, + 0x81C, 0xF5100103, 0x81C, 0xF4120103, 0x81C, 0xF3140103, + 0x81C, 0xF2160103, 0x81C, 0xF1180103, 0x81C, 0xF01A0103, + 0x81C, 0xEE1C0103, 0x81C, 0xED1E0103, 0x81C, 0xEC200103, + 0x81C, 0xEB220103, 0x81C, 0xEA240103, 0x81C, 0xE9260103, + 0x81C, 0xE8280103, 0x81C, 0xE72A0103, 0x81C, 0xE62C0103, + 0x81C, 0xE52E0103, 0x81C, 0xE4300103, 0x81C, 0xE3320103, + 0x81C, 0xE2340103, 0x81C, 0xC5360103, 0x81C, 0xC4380103, + 0x81C, 0xC33A0103, 0x81C, 0xC23C0103, 0x81C, 0xA53E0103, + 0x81C, 0xA4400103, 0x81C, 0xA3420103, 0x81C, 0xA2440103, + 0x81C, 0xA1460103, 0x81C, 0x83480103, 0x81C, 0x824A0103, + 0x81C, 0x814C0103, 0x81C, 0x804E0103, 0x81C, 0x63500103, + 0x81C, 0x62520103, 0x81C, 0x61540103, 0x81C, 0x43560103, + 0x81C, 0x42580103, 0x81C, 0x415A0103, 0x81C, 0x405C0103, + 0x81C, 0x225E0103, 0x81C, 0x21600103, 0x81C, 0x20620103, + 0x81C, 0x03640103, 0x81C, 0x02660103, 0x81C, 0x01680103, + 0x81C, 0x006A0103, 0x81C, 0x006C0103, 0x81C, 0x006E0103, + 0x81C, 0x00700103, 0x81C, 0x00720103, 0x81C, 0x00740103, + 0x81C, 0x00760103, 0x81C, 0x00780103, 0x81C, 0x007A0103, + 0x81C, 0x007C0103, 0x81C, 0x007E0103, 0x90002100, 0x00000000, + 0x40000000, 0x00000000, 0x81C, 0xFD000103, 0x81C, 0xFC020103, + 0x81C, 0xFB040103, 0x81C, 0xFA060103, 0x81C, 0xF9080103, + 0x81C, 0xF80A0103, 0x81C, 0xF70C0103, 0x81C, 0xF60E0103, + 0x81C, 0xF5100103, 0x81C, 0xF4120103, 0x81C, 0xF3140103, + 0x81C, 0xF2160103, 0x81C, 0xF1180103, 0x81C, 0xF01A0103, + 0x81C, 0xEF1C0103, 0x81C, 0xEE1E0103, 0x81C, 0xED200103, + 0x81C, 0xEC220103, 0x81C, 0xEB240103, 0x81C, 0xEA260103, + 0x81C, 0xE9280103, 0x81C, 0xE82A0103, 0x81C, 0xE72C0103, + 0x81C, 0xE62E0103, 0x81C, 0xE5300103, 0x81C, 0xE4320103, + 0x81C, 0xE3340103, 0x81C, 0xE2360103, 0x81C, 0xC5380103, + 0x81C, 0xC43A0103, 0x81C, 0xC33C0103, 0x81C, 0xC23E0103, + 0x81C, 0xA5400103, 0x81C, 0xA4420103, 0x81C, 0xA3440103, + 0x81C, 0xA2460103, 0x81C, 0xA1480103, 0x81C, 0x834A0103, + 0x81C, 0x824C0103, 0x81C, 0x814E0103, 0x81C, 0x64500103, + 0x81C, 0x63520103, 0x81C, 0x62540103, 0x81C, 0x61560103, + 0x81C, 0x42580103, 0x81C, 0x415A0103, 0x81C, 0x405C0103, + 0x81C, 0x065E0103, 0x81C, 0x05600103, 0x81C, 0x04620103, + 0x81C, 0x03640103, 0x81C, 0x02660103, 0x81C, 0x01680103, + 0x81C, 0x006A0103, 0x81C, 0x006C0103, 0x81C, 0x006E0103, + 0x81C, 0x00700103, 0x81C, 0x00720103, 0x81C, 0x00740103, + 0x81C, 0x00760103, 0x81C, 0x00780103, 0x81C, 0x007A0103, + 0x81C, 0x007C0103, 0x81C, 0x007E0103, 0x90002000, 0x00000000, + 0x40000000, 0x00000000, 0x81C, 0xFE000103, 0x81C, 0xFD020103, + 0x81C, 0xFC040103, 0x81C, 0xFB060103, 0x81C, 0xFA080103, + 0x81C, 0xF90A0103, 0x81C, 0xF80C0103, 0x81C, 0xF70E0103, + 0x81C, 0xF6100103, 0x81C, 0xF5120103, 0x81C, 0xF4140103, + 0x81C, 0xF3160103, 0x81C, 0xF2180103, 0x81C, 0xF11A0103, + 0x81C, 0xF01C0103, 0x81C, 0xEF1E0103, 0x81C, 0xEE200103, + 0x81C, 0xED220103, 0x81C, 0xEC240103, 0x81C, 0xEB260103, + 0x81C, 0xEA280103, 0x81C, 0xE92A0103, 0x81C, 0xE82C0103, + 0x81C, 0xE72E0103, 0x81C, 0xE6300103, 0x81C, 0xE5320103, + 0x81C, 0xE4340103, 0x81C, 0xE3360103, 0x81C, 0xC6380103, + 0x81C, 0xC53A0103, 0x81C, 0xC43C0103, 0x81C, 0xC33E0103, + 0x81C, 0xA5400103, 0x81C, 0xA4420103, 0x81C, 0xA3440103, + 0x81C, 0xA2460103, 0x81C, 0xA1480103, 0x81C, 0xA04A0103, + 0x81C, 0x824C0103, 0x81C, 0x814E0103, 0x81C, 0x80500103, + 0x81C, 0x64520103, 0x81C, 0x63540103, 0x81C, 0x62560103, + 0x81C, 0x61580103, 0x81C, 0x605A0103, 0x81C, 0x235C0103, + 0x81C, 0x225E0103, 0x81C, 0x21600103, 0x81C, 0x20620103, + 0x81C, 0x03640103, 0x81C, 0x02660103, 0x81C, 0x01680103, + 0x81C, 0x006A0103, 0x81C, 0x006C0103, 0x81C, 0x006E0103, + 0x81C, 0x00700103, 0x81C, 0x00720103, 0x81C, 0x00740103, + 0x81C, 0x00760103, 0x81C, 0x00780103, 0x81C, 0x007A0103, + 0x81C, 0x007C0103, 0x81C, 0x007E0103, 0xA0000000, 0x00000000, + 0x81C, 0xFE000103, 0x81C, 0xFD020103, 0x81C, 0xFC040103, + 0x81C, 0xFB060103, 0x81C, 0xFA080103, 0x81C, 0xF90A0103, + 0x81C, 0xF80C0103, 0x81C, 0xF70E0103, 0x81C, 0xF6100103, + 0x81C, 0xF5120103, 0x81C, 0xF4140103, 0x81C, 0xF3160103, + 0x81C, 0xF2180103, 0x81C, 0xF11A0103, 0x81C, 0xF01C0103, + 0x81C, 0xEF1E0103, 0x81C, 0xEE200103, 0x81C, 0xED220103, + 0x81C, 0xEC240103, 0x81C, 0xEB260103, 0x81C, 0xEA280103, + 0x81C, 0xE92A0103, 0x81C, 0xE82C0103, 0x81C, 0xE72E0103, + 0x81C, 0xE6300103, 0x81C, 0xE5320103, 0x81C, 0xE4340103, + 0x81C, 0xE3360103, 0x81C, 0xC6380103, 0x81C, 0xC53A0103, + 0x81C, 0xC43C0103, 0x81C, 0xC33E0103, 0x81C, 0xA5400103, + 0x81C, 0xA4420103, 0x81C, 0xA3440103, 0x81C, 0xA2460103, + 0x81C, 0xA1480103, 0x81C, 0xA04A0103, 0x81C, 0x824C0103, + 0x81C, 0x814E0103, 0x81C, 0x80500103, 0x81C, 0x64520103, + 0x81C, 0x63540103, 0x81C, 0x62560103, 0x81C, 0x61580103, + 0x81C, 0x605A0103, 0x81C, 0x235C0103, 0x81C, 0x225E0103, + 0x81C, 0x21600103, 0x81C, 0x20620103, 0x81C, 0x03640103, + 0x81C, 0x02660103, 0x81C, 0x01680103, 0x81C, 0x006A0103, + 0x81C, 0x006C0103, 0x81C, 0x006E0103, 0x81C, 0x00700103, + 0x81C, 0x00720103, 0x81C, 0x00740103, 0x81C, 0x00760103, + 0x81C, 0x00780103, 0x81C, 0x007A0103, 0x81C, 0x007C0103, + 0x81C, 0x007E0103, 0xB0000000, 0x00000000, 0x8000100f, 0x0a0a0a0a, + 0x40000000, 0x00000000, 0x81C, 0xF8000203, 0x81C, 0xF7020203, + 0x81C, 0xF6040203, 0x81C, 0xF5060203, 0x81C, 0xF4080203, + 0x81C, 0xF30A0203, 0x81C, 0xF20C0203, 0x81C, 0xF10E0203, + 0x81C, 0xF0100203, 0x81C, 0xEF120203, 0x81C, 0xEE140203, + 0x81C, 0xED160203, 0x81C, 0xEC180203, 0x81C, 0xEB1A0203, + 0x81C, 0xEA1C0203, 0x81C, 0xE91E0203, 0x81C, 0xE8200203, + 0x81C, 0xE7220203, 0x81C, 0xE6240203, 0x81C, 0xE5260203, + 0x81C, 0xE4280203, 0x81C, 0xE32A0203, 0x81C, 0xC42C0203, + 0x81C, 0xC32E0203, 0x81C, 0xC2300203, 0x81C, 0xC1320203, + 0x81C, 0xA3340203, 0x81C, 0xA2360203, 0x81C, 0xA1380203, + 0x81C, 0xA03A0203, 0x81C, 0x823C0203, 0x81C, 0x813E0203, + 0x81C, 0x80400203, 0x81C, 0x65420203, 0x81C, 0x64440203, + 0x81C, 0x63460203, 0x81C, 0x62480203, 0x81C, 0x614A0203, + 0x81C, 0x424C0203, 0x81C, 0x414E0203, 0x81C, 0x40500203, + 0x81C, 0x22520203, 0x81C, 0x21540203, 0x81C, 0x20560203, + 0x81C, 0x04580203, 0x81C, 0x035A0203, 0x81C, 0x025C0203, + 0x81C, 0x015E0203, 0x81C, 0x00600203, 0x81C, 0x00620203, + 0x81C, 0x00640203, 0x81C, 0x00660203, 0x81C, 0x00680203, + 0x81C, 0x006A0203, 0x81C, 0x006C0203, 0x81C, 0x006E0203, + 0x81C, 0x00700203, 0x81C, 0x00720203, 0x81C, 0x00740203, + 0x81C, 0x00760203, 0x81C, 0x00780203, 0x81C, 0x007A0203, + 0x81C, 0x007C0203, 0x81C, 0x007E0203, 0x9000100f, 0x05050505, + 0x40000000, 0x00000000, 0x81C, 0xF9000203, 0x81C, 0xF8020203, + 0x81C, 0xF7040203, 0x81C, 0xF6060203, 0x81C, 0xF5080203, + 0x81C, 0xF40A0203, 0x81C, 0xF30C0203, 0x81C, 0xF20E0203, + 0x81C, 0xF1100203, 0x81C, 0xF0120203, 0x81C, 0xEF140203, + 0x81C, 0xEE160203, 0x81C, 0xED180203, 0x81C, 0xEC1A0203, + 0x81C, 0xEB1C0203, 0x81C, 0xEA1E0203, 0x81C, 0xE9200203, + 0x81C, 0xE8220203, 0x81C, 0xE7240203, 0x81C, 0xE6260203, + 0x81C, 0xE5280203, 0x81C, 0xC42A0203, 0x81C, 0xC32C0203, + 0x81C, 0xC22E0203, 0x81C, 0xC1300203, 0x81C, 0xC0320203, + 0x81C, 0xA3340203, 0x81C, 0xA2360203, 0x81C, 0xA1380203, + 0x81C, 0xA03A0203, 0x81C, 0x823C0203, 0x81C, 0x813E0203, + 0x81C, 0x80400203, 0x81C, 0x64420203, 0x81C, 0x63440203, + 0x81C, 0x62460203, 0x81C, 0x61480203, 0x81C, 0x604A0203, + 0x81C, 0x414C0203, 0x81C, 0x404E0203, 0x81C, 0x22500203, + 0x81C, 0x21520203, 0x81C, 0x20540203, 0x81C, 0x03560203, + 0x81C, 0x02580203, 0x81C, 0x015A0203, 0x81C, 0x005C0203, + 0x81C, 0x005E0203, 0x81C, 0x00600203, 0x81C, 0x00620203, + 0x81C, 0x00640203, 0x81C, 0x00660203, 0x81C, 0x00680203, + 0x81C, 0x006A0203, 0x81C, 0x006C0203, 0x81C, 0x006E0203, + 0x81C, 0x00700203, 0x81C, 0x00720203, 0x81C, 0x00740203, + 0x81C, 0x00760203, 0x81C, 0x00780203, 0x81C, 0x007A0203, + 0x81C, 0x007C0203, 0x81C, 0x007E0203, 0x9000100f, 0x00000000, + 0x40000000, 0x00000000, 0x81C, 0xF7000203, 0x81C, 0xF6020203, + 0x81C, 0xF5040203, 0x81C, 0xF4060203, 0x81C, 0xF3080203, + 0x81C, 0xF20A0203, 0x81C, 0xF10C0203, 0x81C, 0xF00E0203, + 0x81C, 0xEF100203, 0x81C, 0xEE120203, 0x81C, 0xED140203, + 0x81C, 0xEC160203, 0x81C, 0xEB180203, 0x81C, 0xEA1A0203, + 0x81C, 0xE91C0203, 0x81C, 0xE81E0203, 0x81C, 0xE7200203, + 0x81C, 0xE6220203, 0x81C, 0xE5240203, 0x81C, 0xE4260203, + 0x81C, 0xE3280203, 0x81C, 0xC42A0203, 0x81C, 0xC32C0203, + 0x81C, 0xC22E0203, 0x81C, 0xC1300203, 0x81C, 0xC0320203, + 0x81C, 0xA3340203, 0x81C, 0xA2360203, 0x81C, 0xA1380203, + 0x81C, 0xA03A0203, 0x81C, 0x823C0203, 0x81C, 0x813E0203, + 0x81C, 0x80400203, 0x81C, 0x63420203, 0x81C, 0x62440203, + 0x81C, 0x61460203, 0x81C, 0x60480203, 0x81C, 0x424A0203, + 0x81C, 0x414C0203, 0x81C, 0x404E0203, 0x81C, 0x06500203, + 0x81C, 0x05520203, 0x81C, 0x04540203, 0x81C, 0x03560203, + 0x81C, 0x02580203, 0x81C, 0x015A0203, 0x81C, 0x005C0203, + 0x81C, 0x005E0203, 0x81C, 0x00600203, 0x81C, 0x00620203, + 0x81C, 0x00640203, 0x81C, 0x00660203, 0x81C, 0x00680203, + 0x81C, 0x006A0203, 0x81C, 0x006C0203, 0x81C, 0x006E0203, + 0x81C, 0x00700203, 0x81C, 0x00720203, 0x81C, 0x00740203, + 0x81C, 0x00760203, 0x81C, 0x00780203, 0x81C, 0x007A0203, + 0x81C, 0x007C0203, 0x81C, 0x007E0203, 0x9000200f, 0x00000000, + 0x40000000, 0x00000000, 0x81C, 0xF7000203, 0x81C, 0xF6020203, + 0x81C, 0xF5040203, 0x81C, 0xF4060203, 0x81C, 0xF3080203, + 0x81C, 0xF20A0203, 0x81C, 0xF10C0203, 0x81C, 0xF00E0203, + 0x81C, 0xEF100203, 0x81C, 0xEE120203, 0x81C, 0xED140203, + 0x81C, 0xEC160203, 0x81C, 0xEB180203, 0x81C, 0xEA1A0203, + 0x81C, 0xE91C0203, 0x81C, 0xE81E0203, 0x81C, 0xE7200203, + 0x81C, 0xE6220203, 0x81C, 0xE5240203, 0x81C, 0xE4260203, + 0x81C, 0xE3280203, 0x81C, 0xC42A0203, 0x81C, 0xC32C0203, + 0x81C, 0xC22E0203, 0x81C, 0xC1300203, 0x81C, 0xC0320203, + 0x81C, 0xA3340203, 0x81C, 0xA2360203, 0x81C, 0xA1380203, + 0x81C, 0xA03A0203, 0x81C, 0x823C0203, 0x81C, 0x813E0203, + 0x81C, 0x80400203, 0x81C, 0x64420203, 0x81C, 0x63440203, + 0x81C, 0x62460203, 0x81C, 0x61480203, 0x81C, 0x604A0203, + 0x81C, 0x414C0203, 0x81C, 0x404E0203, 0x81C, 0x22500203, + 0x81C, 0x21520203, 0x81C, 0x20540203, 0x81C, 0x03560203, + 0x81C, 0x02580203, 0x81C, 0x015A0203, 0x81C, 0x005C0203, + 0x81C, 0x005E0203, 0x81C, 0x00600203, 0x81C, 0x00620203, + 0x81C, 0x00640203, 0x81C, 0x00660203, 0x81C, 0x00680203, + 0x81C, 0x006A0203, 0x81C, 0x006C0203, 0x81C, 0x006E0203, + 0x81C, 0x00700203, 0x81C, 0x00720203, 0x81C, 0x00740203, + 0x81C, 0x00760203, 0x81C, 0x00780203, 0x81C, 0x007A0203, + 0x81C, 0x007C0203, 0x81C, 0x007E0203, 0x9000200c, 0x00000000, + 0x40000000, 0x00000000, 0x81C, 0xF7000203, 0x81C, 0xF6020203, + 0x81C, 0xF5040203, 0x81C, 0xF4060203, 0x81C, 0xF3080203, + 0x81C, 0xF20A0203, 0x81C, 0xF10C0203, 0x81C, 0xF00E0203, + 0x81C, 0xEF100203, 0x81C, 0xEE120203, 0x81C, 0xED140203, + 0x81C, 0xEC160203, 0x81C, 0xEB180203, 0x81C, 0xEA1A0203, + 0x81C, 0xE91C0203, 0x81C, 0xE81E0203, 0x81C, 0xE7200203, + 0x81C, 0xE6220203, 0x81C, 0xE5240203, 0x81C, 0xE4260203, + 0x81C, 0xE3280203, 0x81C, 0xC42A0203, 0x81C, 0xC32C0203, + 0x81C, 0xC22E0203, 0x81C, 0xC1300203, 0x81C, 0xC0320203, + 0x81C, 0xA3340203, 0x81C, 0xA2360203, 0x81C, 0xA1380203, + 0x81C, 0xA03A0203, 0x81C, 0x823C0203, 0x81C, 0x813E0203, + 0x81C, 0x80400203, 0x81C, 0x64420203, 0x81C, 0x63440203, + 0x81C, 0x62460203, 0x81C, 0x61480203, 0x81C, 0x604A0203, + 0x81C, 0x414C0203, 0x81C, 0x404E0203, 0x81C, 0x22500203, + 0x81C, 0x21520203, 0x81C, 0x20540203, 0x81C, 0x03560203, + 0x81C, 0x02580203, 0x81C, 0x015A0203, 0x81C, 0x005C0203, + 0x81C, 0x005E0203, 0x81C, 0x00600203, 0x81C, 0x00620203, + 0x81C, 0x00640203, 0x81C, 0x00660203, 0x81C, 0x00680203, + 0x81C, 0x006A0203, 0x81C, 0x006C0203, 0x81C, 0x006E0203, + 0x81C, 0x00700203, 0x81C, 0x00720203, 0x81C, 0x00740203, + 0x81C, 0x00760203, 0x81C, 0x00780203, 0x81C, 0x007A0203, + 0x81C, 0x007C0203, 0x81C, 0x007E0203, 0x90012100, 0x00000000, + 0x40000000, 0x00000000, 0x81C, 0xFB000203, 0x81C, 0xFA020203, + 0x81C, 0xF9040203, 0x81C, 0xF8060203, 0x81C, 0xF7080203, + 0x81C, 0xF60A0203, 0x81C, 0xF50C0203, 0x81C, 0xF40E0203, + 0x81C, 0xF3100203, 0x81C, 0xF2120203, 0x81C, 0xF1140203, + 0x81C, 0xF0160203, 0x81C, 0xEF180203, 0x81C, 0xEE1A0203, + 0x81C, 0xED1C0203, 0x81C, 0xEC1E0203, 0x81C, 0xEB200203, + 0x81C, 0xEA220203, 0x81C, 0xE9240203, 0x81C, 0xE8260203, + 0x81C, 0xE7280203, 0x81C, 0xE62A0203, 0x81C, 0xE52C0203, + 0x81C, 0xE42E0203, 0x81C, 0xE3300203, 0x81C, 0xE2320203, + 0x81C, 0xC6340203, 0x81C, 0xC5360203, 0x81C, 0xC4380203, + 0x81C, 0xC33A0203, 0x81C, 0xC23C0203, 0x81C, 0xC13E0203, + 0x81C, 0xC0400203, 0x81C, 0xA3420203, 0x81C, 0xA2440203, + 0x81C, 0xA1460203, 0x81C, 0xA0480203, 0x81C, 0x824A0203, + 0x81C, 0x814C0203, 0x81C, 0x804E0203, 0x81C, 0x63500203, + 0x81C, 0x62520203, 0x81C, 0x61540203, 0x81C, 0x60560203, + 0x81C, 0x24580203, 0x81C, 0x235A0203, 0x81C, 0x225C0203, + 0x81C, 0x215E0203, 0x81C, 0x20600203, 0x81C, 0x03620203, + 0x81C, 0x02640203, 0x81C, 0x01660203, 0x81C, 0x00680203, + 0x81C, 0x006A0203, 0x81C, 0x006C0203, 0x81C, 0x006E0203, + 0x81C, 0x00700203, 0x81C, 0x00720203, 0x81C, 0x00740203, + 0x81C, 0x00760203, 0x81C, 0x00780203, 0x81C, 0x007A0203, + 0x81C, 0x007C0203, 0x81C, 0x007E0203, 0x90001004, 0x00000000, + 0x40000000, 0x00000000, 0x81C, 0xF8000203, 0x81C, 0xF7020203, + 0x81C, 0xF6040203, 0x81C, 0xF5060203, 0x81C, 0xF4080203, + 0x81C, 0xF30A0203, 0x81C, 0xF20C0203, 0x81C, 0xF10E0203, + 0x81C, 0xF0100203, 0x81C, 0xEF120203, 0x81C, 0xEE140203, + 0x81C, 0xED160203, 0x81C, 0xEC180203, 0x81C, 0xEB1A0203, + 0x81C, 0xEA1C0203, 0x81C, 0xE91E0203, 0x81C, 0xE8200203, + 0x81C, 0xE7220203, 0x81C, 0xE6240203, 0x81C, 0xE5260203, + 0x81C, 0xE4280203, 0x81C, 0xE32A0203, 0x81C, 0xC42C0203, + 0x81C, 0xC32E0203, 0x81C, 0xC2300203, 0x81C, 0xC1320203, + 0x81C, 0xA3340203, 0x81C, 0xA2360203, 0x81C, 0xA1380203, + 0x81C, 0xA03A0203, 0x81C, 0x823C0203, 0x81C, 0x813E0203, + 0x81C, 0x80400203, 0x81C, 0x65420203, 0x81C, 0x64440203, + 0x81C, 0x63460203, 0x81C, 0x62480203, 0x81C, 0x614A0203, + 0x81C, 0x424C0203, 0x81C, 0x414E0203, 0x81C, 0x40500203, + 0x81C, 0x22520203, 0x81C, 0x21540203, 0x81C, 0x20560203, + 0x81C, 0x04580203, 0x81C, 0x035A0203, 0x81C, 0x025C0203, + 0x81C, 0x015E0203, 0x81C, 0x00600203, 0x81C, 0x00620203, + 0x81C, 0x00640203, 0x81C, 0x00660203, 0x81C, 0x00680203, + 0x81C, 0x006A0203, 0x81C, 0x006C0203, 0x81C, 0x006E0203, + 0x81C, 0x00700203, 0x81C, 0x00720203, 0x81C, 0x00740203, + 0x81C, 0x00760203, 0x81C, 0x00780203, 0x81C, 0x007A0203, + 0x81C, 0x007C0203, 0x81C, 0x007E0203, 0x90011000, 0x00000000, + 0x40000000, 0x00000000, 0x81C, 0xFC000203, 0x81C, 0xFB020203, + 0x81C, 0xFA040203, 0x81C, 0xF9060203, 0x81C, 0xF8080203, + 0x81C, 0xF70A0203, 0x81C, 0xF60C0203, 0x81C, 0xF50E0203, + 0x81C, 0xF4100203, 0x81C, 0xF3120203, 0x81C, 0xF2140203, + 0x81C, 0xF1160203, 0x81C, 0xF0180203, 0x81C, 0xEE1A0203, + 0x81C, 0xED1C0203, 0x81C, 0xEC1E0203, 0x81C, 0xEB200203, + 0x81C, 0xEA220203, 0x81C, 0xE9240203, 0x81C, 0xE8260203, + 0x81C, 0xE7280203, 0x81C, 0xE62A0203, 0x81C, 0xE52C0203, + 0x81C, 0xE42E0203, 0x81C, 0xE3300203, 0x81C, 0xE2320203, + 0x81C, 0xC6340203, 0x81C, 0xC5360203, 0x81C, 0xC4380203, + 0x81C, 0xC33A0203, 0x81C, 0xA63C0203, 0x81C, 0xA53E0203, + 0x81C, 0xA4400203, 0x81C, 0xA3420203, 0x81C, 0xA2440203, + 0x81C, 0xA1460203, 0x81C, 0x83480203, 0x81C, 0x824A0203, + 0x81C, 0x814C0203, 0x81C, 0x804E0203, 0x81C, 0x63500203, + 0x81C, 0x62520203, 0x81C, 0x61540203, 0x81C, 0x42560203, + 0x81C, 0x41580203, 0x81C, 0x405A0203, 0x81C, 0x225C0203, + 0x81C, 0x215E0203, 0x81C, 0x20600203, 0x81C, 0x04620203, + 0x81C, 0x03640203, 0x81C, 0x02660203, 0x81C, 0x01680203, + 0x81C, 0x006A0203, 0x81C, 0x006C0203, 0x81C, 0x006E0203, + 0x81C, 0x00700203, 0x81C, 0x00720203, 0x81C, 0x00740203, + 0x81C, 0x00760203, 0x81C, 0x00780203, 0x81C, 0x007A0203, + 0x81C, 0x007C0203, 0x81C, 0x007E0203, 0x90002100, 0x00000000, + 0x40000000, 0x00000000, 0x81C, 0xFC000203, 0x81C, 0xFB020203, + 0x81C, 0xFA040203, 0x81C, 0xF9060203, 0x81C, 0xF8080203, + 0x81C, 0xF70A0203, 0x81C, 0xF60C0203, 0x81C, 0xF50E0203, + 0x81C, 0xF4100203, 0x81C, 0xF3120203, 0x81C, 0xF2140203, + 0x81C, 0xF1160203, 0x81C, 0xF0180203, 0x81C, 0xEF1A0203, + 0x81C, 0xEE1C0203, 0x81C, 0xED1E0203, 0x81C, 0xEC200203, + 0x81C, 0xEB220203, 0x81C, 0xEA240203, 0x81C, 0xE9260203, + 0x81C, 0xE8280203, 0x81C, 0xE72A0203, 0x81C, 0xE62C0203, + 0x81C, 0xE52E0203, 0x81C, 0xE4300203, 0x81C, 0xE3320203, + 0x81C, 0xE2340203, 0x81C, 0xE1360203, 0x81C, 0xC5380203, + 0x81C, 0xC43A0203, 0x81C, 0xC33C0203, 0x81C, 0xC23E0203, + 0x81C, 0xC1400203, 0x81C, 0xA3420203, 0x81C, 0xA2440203, + 0x81C, 0xA1460203, 0x81C, 0xA0480203, 0x81C, 0x834A0203, + 0x81C, 0x824C0203, 0x81C, 0x814E0203, 0x81C, 0x64500203, + 0x81C, 0x63520203, 0x81C, 0x62540203, 0x81C, 0x61560203, + 0x81C, 0x25580203, 0x81C, 0x245A0203, 0x81C, 0x235C0203, + 0x81C, 0x225E0203, 0x81C, 0x21600203, 0x81C, 0x04620203, + 0x81C, 0x03640203, 0x81C, 0x02660203, 0x81C, 0x01680203, + 0x81C, 0x006A0203, 0x81C, 0x006C0203, 0x81C, 0x006E0203, + 0x81C, 0x00700203, 0x81C, 0x00720203, 0x81C, 0x00740203, + 0x81C, 0x00760203, 0x81C, 0x00780203, 0x81C, 0x007A0203, + 0x81C, 0x007C0203, 0x81C, 0x007E0203, 0x90002000, 0x00000000, + 0x40000000, 0x00000000, 0x81C, 0xFC000203, 0x81C, 0xFB020203, + 0x81C, 0xFA040203, 0x81C, 0xF9060203, 0x81C, 0xF8080203, + 0x81C, 0xF70A0203, 0x81C, 0xF60C0203, 0x81C, 0xF50E0203, + 0x81C, 0xF4100203, 0x81C, 0xF3120203, 0x81C, 0xF2140203, + 0x81C, 0xF1160203, 0x81C, 0xF0180203, 0x81C, 0xEF1A0203, + 0x81C, 0xEE1C0203, 0x81C, 0xED1E0203, 0x81C, 0xEC200203, + 0x81C, 0xEB220203, 0x81C, 0xEA240203, 0x81C, 0xE9260203, + 0x81C, 0xE8280203, 0x81C, 0xE72A0203, 0x81C, 0xE62C0203, + 0x81C, 0xE52E0203, 0x81C, 0xE4300203, 0x81C, 0xE3320203, + 0x81C, 0xE2340203, 0x81C, 0xC6360203, 0x81C, 0xC5380203, + 0x81C, 0xC43A0203, 0x81C, 0xC33C0203, 0x81C, 0xA63E0203, + 0x81C, 0xA5400203, 0x81C, 0xA4420203, 0x81C, 0xA3440203, + 0x81C, 0xA2460203, 0x81C, 0xA1480203, 0x81C, 0x834A0203, + 0x81C, 0x824C0203, 0x81C, 0x814E0203, 0x81C, 0x64500203, + 0x81C, 0x63520203, 0x81C, 0x62540203, 0x81C, 0x61560203, + 0x81C, 0x60580203, 0x81C, 0x405A0203, 0x81C, 0x215C0203, + 0x81C, 0x205E0203, 0x81C, 0x03600203, 0x81C, 0x02620203, + 0x81C, 0x01640203, 0x81C, 0x00660203, 0x81C, 0x00680203, + 0x81C, 0x006A0203, 0x81C, 0x006C0203, 0x81C, 0x006E0203, + 0x81C, 0x00700203, 0x81C, 0x00720203, 0x81C, 0x00740203, + 0x81C, 0x00760203, 0x81C, 0x00780203, 0x81C, 0x007A0203, + 0x81C, 0x007C0203, 0x81C, 0x007E0203, 0xA0000000, 0x00000000, + 0x81C, 0xFD000203, 0x81C, 0xFC020203, 0x81C, 0xFB040203, + 0x81C, 0xFA060203, 0x81C, 0xF9080203, 0x81C, 0xF80A0203, + 0x81C, 0xF70C0203, 0x81C, 0xF60E0203, 0x81C, 0xF5100203, + 0x81C, 0xF4120203, 0x81C, 0xF3140203, 0x81C, 0xF2160203, + 0x81C, 0xF1180203, 0x81C, 0xF01A0203, 0x81C, 0xEF1C0203, + 0x81C, 0xEE1E0203, 0x81C, 0xED200203, 0x81C, 0xEC220203, + 0x81C, 0xEB240203, 0x81C, 0xEA260203, 0x81C, 0xE9280203, + 0x81C, 0xE82A0203, 0x81C, 0xE72C0203, 0x81C, 0xE62E0203, + 0x81C, 0xE5300203, 0x81C, 0xE4320203, 0x81C, 0xE3340203, + 0x81C, 0xC6360203, 0x81C, 0xC5380203, 0x81C, 0xC43A0203, + 0x81C, 0xC33C0203, 0x81C, 0xA63E0203, 0x81C, 0xA5400203, + 0x81C, 0xA4420203, 0x81C, 0xA3440203, 0x81C, 0xA2460203, + 0x81C, 0xA1480203, 0x81C, 0x834A0203, 0x81C, 0x824C0203, + 0x81C, 0x814E0203, 0x81C, 0x64500203, 0x81C, 0x63520203, + 0x81C, 0x62540203, 0x81C, 0x61560203, 0x81C, 0x60580203, + 0x81C, 0x235A0203, 0x81C, 0x225C0203, 0x81C, 0x215E0203, + 0x81C, 0x20600203, 0x81C, 0x03620203, 0x81C, 0x02640203, + 0x81C, 0x01660203, 0x81C, 0x00680203, 0x81C, 0x006A0203, + 0x81C, 0x006C0203, 0x81C, 0x006E0203, 0x81C, 0x00700203, + 0x81C, 0x00720203, 0x81C, 0x00740203, 0x81C, 0x00760203, + 0x81C, 0x00780203, 0x81C, 0x007A0203, 0x81C, 0x007C0203, + 0x81C, 0x007E0203, 0xB0000000, 0x00000000, 0x8000100f, 0x0a0a0a0a, + 0x40000000, 0x00000000, 0x81C, 0xF8000303, 0x81C, 0xF7020303, + 0x81C, 0xF6040303, 0x81C, 0xF5060303, 0x81C, 0xF4080303, + 0x81C, 0xF30A0303, 0x81C, 0xF20C0303, 0x81C, 0xF10E0303, + 0x81C, 0xF0100303, 0x81C, 0xEF120303, 0x81C, 0xEE140303, + 0x81C, 0xED160303, 0x81C, 0xEC180303, 0x81C, 0xEB1A0303, + 0x81C, 0xEA1C0303, 0x81C, 0xE91E0303, 0x81C, 0xCA200303, + 0x81C, 0xC9220303, 0x81C, 0xC8240303, 0x81C, 0xC7260303, + 0x81C, 0xC6280303, 0x81C, 0xC52A0303, 0x81C, 0xC42C0303, + 0x81C, 0xC32E0303, 0x81C, 0xC2300303, 0x81C, 0xC1320303, + 0x81C, 0xA3340303, 0x81C, 0xA2360303, 0x81C, 0xA1380303, + 0x81C, 0xA03A0303, 0x81C, 0x823C0303, 0x81C, 0x813E0303, + 0x81C, 0x80400303, 0x81C, 0x65420303, 0x81C, 0x64440303, + 0x81C, 0x63460303, 0x81C, 0x62480303, 0x81C, 0x614A0303, + 0x81C, 0x424C0303, 0x81C, 0x414E0303, 0x81C, 0x40500303, + 0x81C, 0x22520303, 0x81C, 0x21540303, 0x81C, 0x20560303, + 0x81C, 0x04580303, 0x81C, 0x035A0303, 0x81C, 0x025C0303, + 0x81C, 0x015E0303, 0x81C, 0x00600303, 0x81C, 0x00620303, + 0x81C, 0x00640303, 0x81C, 0x00660303, 0x81C, 0x00680303, + 0x81C, 0x006A0303, 0x81C, 0x006C0303, 0x81C, 0x006E0303, + 0x81C, 0x00700303, 0x81C, 0x00720303, 0x81C, 0x00740303, + 0x81C, 0x00760303, 0x81C, 0x00780303, 0x81C, 0x007A0303, + 0x81C, 0x007C0303, 0x81C, 0x007E0303, 0x9000100f, 0x05050505, + 0x40000000, 0x00000000, 0x81C, 0xF9000303, 0x81C, 0xF8020303, + 0x81C, 0xF7040303, 0x81C, 0xF6060303, 0x81C, 0xF5080303, + 0x81C, 0xF40A0303, 0x81C, 0xF30C0303, 0x81C, 0xF20E0303, + 0x81C, 0xF1100303, 0x81C, 0xF0120303, 0x81C, 0xEF140303, + 0x81C, 0xEE160303, 0x81C, 0xED180303, 0x81C, 0xEC1A0303, + 0x81C, 0xEB1C0303, 0x81C, 0xEA1E0303, 0x81C, 0xC9200303, + 0x81C, 0xC8220303, 0x81C, 0xC7240303, 0x81C, 0xC6260303, + 0x81C, 0xC5280303, 0x81C, 0xC42A0303, 0x81C, 0xC32C0303, + 0x81C, 0xC22E0303, 0x81C, 0xC1300303, 0x81C, 0xC0320303, + 0x81C, 0xA3340303, 0x81C, 0xA2360303, 0x81C, 0xA1380303, + 0x81C, 0xA03A0303, 0x81C, 0x823C0303, 0x81C, 0x813E0303, + 0x81C, 0x80400303, 0x81C, 0x64420303, 0x81C, 0x63440303, + 0x81C, 0x62460303, 0x81C, 0x61480303, 0x81C, 0x604A0303, + 0x81C, 0x414C0303, 0x81C, 0x404E0303, 0x81C, 0x22500303, + 0x81C, 0x21520303, 0x81C, 0x20540303, 0x81C, 0x03560303, + 0x81C, 0x02580303, 0x81C, 0x015A0303, 0x81C, 0x005C0303, + 0x81C, 0x005E0303, 0x81C, 0x00600303, 0x81C, 0x00620303, + 0x81C, 0x00640303, 0x81C, 0x00660303, 0x81C, 0x00680303, + 0x81C, 0x006A0303, 0x81C, 0x006C0303, 0x81C, 0x006E0303, + 0x81C, 0x00700303, 0x81C, 0x00720303, 0x81C, 0x00740303, + 0x81C, 0x00760303, 0x81C, 0x00780303, 0x81C, 0x007A0303, + 0x81C, 0x007C0303, 0x81C, 0x007E0303, 0x9000100f, 0x00000000, + 0x40000000, 0x00000000, 0x81C, 0xF7000303, 0x81C, 0xF6020303, + 0x81C, 0xF5040303, 0x81C, 0xF4060303, 0x81C, 0xF3080303, + 0x81C, 0xF20A0303, 0x81C, 0xF10C0303, 0x81C, 0xF00E0303, + 0x81C, 0xEF100303, 0x81C, 0xEE120303, 0x81C, 0xED140303, + 0x81C, 0xEC160303, 0x81C, 0xEB180303, 0x81C, 0xEA1A0303, + 0x81C, 0xE91C0303, 0x81C, 0xCA1E0303, 0x81C, 0xC9200303, + 0x81C, 0xC8220303, 0x81C, 0xC7240303, 0x81C, 0xC6260303, + 0x81C, 0xC5280303, 0x81C, 0xC42A0303, 0x81C, 0xC32C0303, + 0x81C, 0xC22E0303, 0x81C, 0xC1300303, 0x81C, 0xA4320303, + 0x81C, 0xA3340303, 0x81C, 0xA2360303, 0x81C, 0xA1380303, + 0x81C, 0xA03A0303, 0x81C, 0x823C0303, 0x81C, 0x813E0303, + 0x81C, 0x80400303, 0x81C, 0x64420303, 0x81C, 0x63440303, + 0x81C, 0x62460303, 0x81C, 0x61480303, 0x81C, 0x604A0303, + 0x81C, 0x414C0303, 0x81C, 0x404E0303, 0x81C, 0x06500303, + 0x81C, 0x05520303, 0x81C, 0x04540303, 0x81C, 0x03560303, + 0x81C, 0x02580303, 0x81C, 0x015A0303, 0x81C, 0x005C0303, + 0x81C, 0x005E0303, 0x81C, 0x00600303, 0x81C, 0x00620303, + 0x81C, 0x00640303, 0x81C, 0x00660303, 0x81C, 0x00680303, + 0x81C, 0x006A0303, 0x81C, 0x006C0303, 0x81C, 0x006E0303, + 0x81C, 0x00700303, 0x81C, 0x00720303, 0x81C, 0x00740303, + 0x81C, 0x00760303, 0x81C, 0x00780303, 0x81C, 0x007A0303, + 0x81C, 0x007C0303, 0x81C, 0x007E0303, 0x9000200f, 0x00000000, + 0x40000000, 0x00000000, 0x81C, 0xF7000303, 0x81C, 0xF6020303, + 0x81C, 0xF5040303, 0x81C, 0xF4060303, 0x81C, 0xF3080303, + 0x81C, 0xF20A0303, 0x81C, 0xF10C0303, 0x81C, 0xF00E0303, + 0x81C, 0xEF100303, 0x81C, 0xEE120303, 0x81C, 0xED140303, + 0x81C, 0xEC160303, 0x81C, 0xEB180303, 0x81C, 0xEA1A0303, + 0x81C, 0xE91C0303, 0x81C, 0xCA1E0303, 0x81C, 0xC9200303, + 0x81C, 0xC8220303, 0x81C, 0xC7240303, 0x81C, 0xC6260303, + 0x81C, 0xC5280303, 0x81C, 0xC42A0303, 0x81C, 0xC32C0303, + 0x81C, 0xC22E0303, 0x81C, 0xC1300303, 0x81C, 0xA4320303, + 0x81C, 0xA3340303, 0x81C, 0xA2360303, 0x81C, 0xA1380303, + 0x81C, 0xA03A0303, 0x81C, 0x823C0303, 0x81C, 0x813E0303, + 0x81C, 0x80400303, 0x81C, 0x64420303, 0x81C, 0x63440303, + 0x81C, 0x62460303, 0x81C, 0x61480303, 0x81C, 0x604A0303, + 0x81C, 0x414C0303, 0x81C, 0x404E0303, 0x81C, 0x22500303, + 0x81C, 0x21520303, 0x81C, 0x20540303, 0x81C, 0x03560303, + 0x81C, 0x02580303, 0x81C, 0x015A0303, 0x81C, 0x005C0303, + 0x81C, 0x005E0303, 0x81C, 0x00600303, 0x81C, 0x00620303, + 0x81C, 0x00640303, 0x81C, 0x00660303, 0x81C, 0x00680303, + 0x81C, 0x006A0303, 0x81C, 0x006C0303, 0x81C, 0x006E0303, + 0x81C, 0x00700303, 0x81C, 0x00720303, 0x81C, 0x00740303, + 0x81C, 0x00760303, 0x81C, 0x00780303, 0x81C, 0x007A0303, + 0x81C, 0x007C0303, 0x81C, 0x007E0303, 0x9000200c, 0x00000000, + 0x40000000, 0x00000000, 0x81C, 0xF7000303, 0x81C, 0xF6020303, + 0x81C, 0xF5040303, 0x81C, 0xF4060303, 0x81C, 0xF3080303, + 0x81C, 0xF20A0303, 0x81C, 0xF10C0303, 0x81C, 0xF00E0303, + 0x81C, 0xEF100303, 0x81C, 0xEE120303, 0x81C, 0xED140303, + 0x81C, 0xEC160303, 0x81C, 0xEB180303, 0x81C, 0xEA1A0303, + 0x81C, 0xE91C0303, 0x81C, 0xCA1E0303, 0x81C, 0xC9200303, + 0x81C, 0xC8220303, 0x81C, 0xC7240303, 0x81C, 0xC6260303, + 0x81C, 0xC5280303, 0x81C, 0xC42A0303, 0x81C, 0xC32C0303, + 0x81C, 0xC22E0303, 0x81C, 0xC1300303, 0x81C, 0xA4320303, + 0x81C, 0xA3340303, 0x81C, 0xA2360303, 0x81C, 0xA1380303, + 0x81C, 0xA03A0303, 0x81C, 0x823C0303, 0x81C, 0x813E0303, + 0x81C, 0x80400303, 0x81C, 0x64420303, 0x81C, 0x63440303, + 0x81C, 0x62460303, 0x81C, 0x61480303, 0x81C, 0x604A0303, + 0x81C, 0x414C0303, 0x81C, 0x404E0303, 0x81C, 0x22500303, + 0x81C, 0x21520303, 0x81C, 0x20540303, 0x81C, 0x03560303, + 0x81C, 0x02580303, 0x81C, 0x015A0303, 0x81C, 0x005C0303, + 0x81C, 0x005E0303, 0x81C, 0x00600303, 0x81C, 0x00620303, + 0x81C, 0x00640303, 0x81C, 0x00660303, 0x81C, 0x00680303, + 0x81C, 0x006A0303, 0x81C, 0x006C0303, 0x81C, 0x006E0303, + 0x81C, 0x00700303, 0x81C, 0x00720303, 0x81C, 0x00740303, + 0x81C, 0x00760303, 0x81C, 0x00780303, 0x81C, 0x007A0303, + 0x81C, 0x007C0303, 0x81C, 0x007E0303, 0x90012100, 0x00000000, + 0x40000000, 0x00000000, 0x81C, 0xFB000303, 0x81C, 0xFA020303, + 0x81C, 0xF9040303, 0x81C, 0xF8060303, 0x81C, 0xF7080303, + 0x81C, 0xF60A0303, 0x81C, 0xF50C0303, 0x81C, 0xF40E0303, + 0x81C, 0xF3100303, 0x81C, 0xF2120303, 0x81C, 0xF1140303, + 0x81C, 0xF0160303, 0x81C, 0xEF180303, 0x81C, 0xEE1A0303, + 0x81C, 0xED1C0303, 0x81C, 0xEC1E0303, 0x81C, 0xEB200303, + 0x81C, 0xEA220303, 0x81C, 0xE9240303, 0x81C, 0xE8260303, + 0x81C, 0xE7280303, 0x81C, 0xE62A0303, 0x81C, 0xE52C0303, + 0x81C, 0xE42E0303, 0x81C, 0xE3300303, 0x81C, 0xE2320303, + 0x81C, 0xC6340303, 0x81C, 0xC5360303, 0x81C, 0xC4380303, + 0x81C, 0xC33A0303, 0x81C, 0xC23C0303, 0x81C, 0xC13E0303, + 0x81C, 0xA4400303, 0x81C, 0xA3420303, 0x81C, 0xA2440303, + 0x81C, 0xA1460303, 0x81C, 0x83480303, 0x81C, 0x824A0303, + 0x81C, 0x814C0303, 0x81C, 0x804E0303, 0x81C, 0x63500303, + 0x81C, 0x62520303, 0x81C, 0x43540303, 0x81C, 0x42560303, + 0x81C, 0x41580303, 0x81C, 0x235A0303, 0x81C, 0x225C0303, + 0x81C, 0x215E0303, 0x81C, 0x20600303, 0x81C, 0x04620303, + 0x81C, 0x03640303, 0x81C, 0x02660303, 0x81C, 0x01680303, + 0x81C, 0x006A0303, 0x81C, 0x006C0303, 0x81C, 0x006E0303, + 0x81C, 0x00700303, 0x81C, 0x00720303, 0x81C, 0x00740303, + 0x81C, 0x00760303, 0x81C, 0x00780303, 0x81C, 0x007A0303, + 0x81C, 0x007C0303, 0x81C, 0x007E0303, 0x90001004, 0x00000000, + 0x40000000, 0x00000000, 0x81C, 0xF8000303, 0x81C, 0xF7020303, + 0x81C, 0xF6040303, 0x81C, 0xF5060303, 0x81C, 0xF4080303, + 0x81C, 0xF30A0303, 0x81C, 0xF20C0303, 0x81C, 0xF10E0303, + 0x81C, 0xF0100303, 0x81C, 0xEF120303, 0x81C, 0xEE140303, + 0x81C, 0xED160303, 0x81C, 0xEC180303, 0x81C, 0xEB1A0303, + 0x81C, 0xEA1C0303, 0x81C, 0xE91E0303, 0x81C, 0xCA200303, + 0x81C, 0xC9220303, 0x81C, 0xC8240303, 0x81C, 0xC7260303, + 0x81C, 0xC6280303, 0x81C, 0xC52A0303, 0x81C, 0xC42C0303, + 0x81C, 0xC32E0303, 0x81C, 0xC2300303, 0x81C, 0xC1320303, + 0x81C, 0xA3340303, 0x81C, 0xA2360303, 0x81C, 0xA1380303, + 0x81C, 0xA03A0303, 0x81C, 0x823C0303, 0x81C, 0x813E0303, + 0x81C, 0x80400303, 0x81C, 0x65420303, 0x81C, 0x64440303, + 0x81C, 0x63460303, 0x81C, 0x62480303, 0x81C, 0x614A0303, + 0x81C, 0x424C0303, 0x81C, 0x414E0303, 0x81C, 0x40500303, + 0x81C, 0x22520303, 0x81C, 0x21540303, 0x81C, 0x20560303, + 0x81C, 0x04580303, 0x81C, 0x035A0303, 0x81C, 0x025C0303, + 0x81C, 0x015E0303, 0x81C, 0x00600303, 0x81C, 0x00620303, + 0x81C, 0x00640303, 0x81C, 0x00660303, 0x81C, 0x00680303, + 0x81C, 0x006A0303, 0x81C, 0x006C0303, 0x81C, 0x006E0303, + 0x81C, 0x00700303, 0x81C, 0x00720303, 0x81C, 0x00740303, + 0x81C, 0x00760303, 0x81C, 0x00780303, 0x81C, 0x007A0303, + 0x81C, 0x007C0303, 0x81C, 0x007E0303, 0x90011000, 0x00000000, + 0x40000000, 0x00000000, 0x81C, 0xFB000303, 0x81C, 0xFA020303, + 0x81C, 0xF9040303, 0x81C, 0xF8060303, 0x81C, 0xF7080303, + 0x81C, 0xF60A0303, 0x81C, 0xF50C0303, 0x81C, 0xF40E0303, + 0x81C, 0xF3100303, 0x81C, 0xF2120303, 0x81C, 0xF1140303, + 0x81C, 0xF0160303, 0x81C, 0xEE180303, 0x81C, 0xED1A0303, + 0x81C, 0xEC1C0303, 0x81C, 0xEB1E0303, 0x81C, 0xEA200303, + 0x81C, 0xE9220303, 0x81C, 0xE8240303, 0x81C, 0xE7260303, + 0x81C, 0xE6280303, 0x81C, 0xE52A0303, 0x81C, 0xE42C0303, + 0x81C, 0xE32E0303, 0x81C, 0xE2300303, 0x81C, 0xE1320303, + 0x81C, 0xC6340303, 0x81C, 0xC5360303, 0x81C, 0xC4380303, + 0x81C, 0xC33A0303, 0x81C, 0xA63C0303, 0x81C, 0xA53E0303, + 0x81C, 0xA4400303, 0x81C, 0xA3420303, 0x81C, 0xA2440303, + 0x81C, 0xA1460303, 0x81C, 0x83480303, 0x81C, 0x824A0303, + 0x81C, 0x814C0303, 0x81C, 0x804E0303, 0x81C, 0x63500303, + 0x81C, 0x62520303, 0x81C, 0x61540303, 0x81C, 0x42560303, + 0x81C, 0x41580303, 0x81C, 0x405A0303, 0x81C, 0x225C0303, + 0x81C, 0x215E0303, 0x81C, 0x20600303, 0x81C, 0x04620303, + 0x81C, 0x03640303, 0x81C, 0x02660303, 0x81C, 0x01680303, + 0x81C, 0x006A0303, 0x81C, 0x006C0303, 0x81C, 0x006E0303, + 0x81C, 0x00700303, 0x81C, 0x00720303, 0x81C, 0x00740303, + 0x81C, 0x00760303, 0x81C, 0x00780303, 0x81C, 0x007A0303, + 0x81C, 0x007C0303, 0x81C, 0x007E0303, 0x90002100, 0x00000000, + 0x40000000, 0x00000000, 0x81C, 0xFB000303, 0x81C, 0xFA020303, + 0x81C, 0xF9040303, 0x81C, 0xF8060303, 0x81C, 0xF7080303, + 0x81C, 0xF60A0303, 0x81C, 0xF50C0303, 0x81C, 0xF40E0303, + 0x81C, 0xF3100303, 0x81C, 0xF2120303, 0x81C, 0xF1140303, + 0x81C, 0xF0160303, 0x81C, 0xEF180303, 0x81C, 0xEE1A0303, + 0x81C, 0xED1C0303, 0x81C, 0xEC1E0303, 0x81C, 0xEB200303, + 0x81C, 0xEA220303, 0x81C, 0xE9240303, 0x81C, 0xE8260303, + 0x81C, 0xE7280303, 0x81C, 0xE62A0303, 0x81C, 0xE52C0303, + 0x81C, 0xE42E0303, 0x81C, 0xE3300303, 0x81C, 0xE2320303, + 0x81C, 0xE1340303, 0x81C, 0xC5360303, 0x81C, 0xC4380303, + 0x81C, 0xC33A0303, 0x81C, 0xC23C0303, 0x81C, 0xC13E0303, + 0x81C, 0xA4400303, 0x81C, 0xA3420303, 0x81C, 0xA2440303, + 0x81C, 0xA1460303, 0x81C, 0x83480303, 0x81C, 0x824A0303, + 0x81C, 0x814C0303, 0x81C, 0x804E0303, 0x81C, 0x64500303, + 0x81C, 0x63520303, 0x81C, 0x62540303, 0x81C, 0x61560303, + 0x81C, 0x60580303, 0x81C, 0x235A0303, 0x81C, 0x225C0303, + 0x81C, 0x215E0303, 0x81C, 0x20600303, 0x81C, 0x04620303, + 0x81C, 0x03640303, 0x81C, 0x02660303, 0x81C, 0x01680303, + 0x81C, 0x006A0303, 0x81C, 0x006C0303, 0x81C, 0x006E0303, + 0x81C, 0x00700303, 0x81C, 0x00720303, 0x81C, 0x00740303, + 0x81C, 0x00760303, 0x81C, 0x00780303, 0x81C, 0x007A0303, + 0x81C, 0x007C0303, 0x81C, 0x007E0303, 0x90002000, 0x00000000, + 0x40000000, 0x00000000, 0x81C, 0xFC000303, 0x81C, 0xFB020303, + 0x81C, 0xFA040303, 0x81C, 0xF9060303, 0x81C, 0xF8080303, + 0x81C, 0xF70A0303, 0x81C, 0xF60C0303, 0x81C, 0xF50E0303, + 0x81C, 0xF4100303, 0x81C, 0xF3120303, 0x81C, 0xF2140303, + 0x81C, 0xF1160303, 0x81C, 0xF0180303, 0x81C, 0xEF1A0303, + 0x81C, 0xEE1C0303, 0x81C, 0xED1E0303, 0x81C, 0xEC200303, + 0x81C, 0xEB220303, 0x81C, 0xEA240303, 0x81C, 0xE9260303, + 0x81C, 0xE8280303, 0x81C, 0xE72A0303, 0x81C, 0xE62C0303, + 0x81C, 0xE52E0303, 0x81C, 0xE4300303, 0x81C, 0xE3320303, + 0x81C, 0xE2340303, 0x81C, 0xC6360303, 0x81C, 0xC5380303, + 0x81C, 0xC43A0303, 0x81C, 0xC33C0303, 0x81C, 0xA63E0303, + 0x81C, 0xA5400303, 0x81C, 0xA4420303, 0x81C, 0xA3440303, + 0x81C, 0xA2460303, 0x81C, 0x84480303, 0x81C, 0x834A0303, + 0x81C, 0x824C0303, 0x81C, 0x814E0303, 0x81C, 0x80500303, + 0x81C, 0x63520303, 0x81C, 0x62540303, 0x81C, 0x61560303, + 0x81C, 0x60580303, 0x81C, 0x225A0303, 0x81C, 0x055C0303, + 0x81C, 0x045E0303, 0x81C, 0x03600303, 0x81C, 0x02620303, + 0x81C, 0x01640303, 0x81C, 0x00660303, 0x81C, 0x00680303, + 0x81C, 0x006A0303, 0x81C, 0x006C0303, 0x81C, 0x006E0303, + 0x81C, 0x00700303, 0x81C, 0x00720303, 0x81C, 0x00740303, + 0x81C, 0x00760303, 0x81C, 0x00780303, 0x81C, 0x007A0303, + 0x81C, 0x007C0303, 0x81C, 0x007E0303, 0xA0000000, 0x00000000, + 0x81C, 0xFC000303, 0x81C, 0xFB020303, 0x81C, 0xFA040303, + 0x81C, 0xF9060303, 0x81C, 0xF8080303, 0x81C, 0xF70A0303, + 0x81C, 0xF60C0303, 0x81C, 0xF50E0303, 0x81C, 0xF4100303, + 0x81C, 0xF3120303, 0x81C, 0xF2140303, 0x81C, 0xF1160303, + 0x81C, 0xF0180303, 0x81C, 0xEF1A0303, 0x81C, 0xEE1C0303, + 0x81C, 0xED1E0303, 0x81C, 0xEC200303, 0x81C, 0xEB220303, + 0x81C, 0xEA240303, 0x81C, 0xE9260303, 0x81C, 0xE8280303, + 0x81C, 0xE72A0303, 0x81C, 0xE62C0303, 0x81C, 0xE52E0303, + 0x81C, 0xE4300303, 0x81C, 0xE3320303, 0x81C, 0xE2340303, + 0x81C, 0xC6360303, 0x81C, 0xC5380303, 0x81C, 0xC43A0303, + 0x81C, 0xC33C0303, 0x81C, 0xA63E0303, 0x81C, 0xA5400303, + 0x81C, 0xA4420303, 0x81C, 0xA3440303, 0x81C, 0xA2460303, + 0x81C, 0x84480303, 0x81C, 0x834A0303, 0x81C, 0x824C0303, + 0x81C, 0x814E0303, 0x81C, 0x80500303, 0x81C, 0x63520303, + 0x81C, 0x62540303, 0x81C, 0x61560303, 0x81C, 0x60580303, + 0x81C, 0x235A0303, 0x81C, 0x225C0303, 0x81C, 0x215E0303, + 0x81C, 0x20600303, 0x81C, 0x03620303, 0x81C, 0x02640303, + 0x81C, 0x01660303, 0x81C, 0x00680303, 0x81C, 0x006A0303, + 0x81C, 0x006C0303, 0x81C, 0x006E0303, 0x81C, 0x00700303, + 0x81C, 0x00720303, 0x81C, 0x00740303, 0x81C, 0x00760303, + 0x81C, 0x00780303, 0x81C, 0x007A0303, 0x81C, 0x007C0303, + 0x81C, 0x007E0303, 0xB0000000, 0x00000000, 0x8000100f, 0x0a0a0a0a, + 0x40000000, 0x00000000, 0x81C, 0xFF000403, 0x81C, 0xF5000403, + 0x81C, 0xF4020403, 0x81C, 0xF3040403, 0x81C, 0xF2060403, + 0x81C, 0xF1080403, 0x81C, 0xF00A0403, 0x81C, 0xEF0C0403, + 0x81C, 0xEE0E0403, 0x81C, 0xED100403, 0x81C, 0xEC120403, + 0x81C, 0xEB140403, 0x81C, 0xEA160403, 0x81C, 0xE9180403, + 0x81C, 0xE81A0403, 0x81C, 0xE71C0403, 0x81C, 0xE61E0403, + 0x81C, 0xE5200403, 0x81C, 0xE4220403, 0x81C, 0xE3240403, + 0x81C, 0xE2260403, 0x81C, 0xE1280403, 0x81C, 0xE02A0403, + 0x81C, 0xC32C0403, 0x81C, 0xC22E0403, 0x81C, 0xC1300403, + 0x81C, 0xC0320403, 0x81C, 0xA4340403, 0x81C, 0xA3360403, + 0x81C, 0xA2380403, 0x81C, 0xA13A0403, 0x81C, 0xA03C0403, + 0x81C, 0x823E0403, 0x81C, 0x81400403, 0x81C, 0x80420403, + 0x81C, 0x64440403, 0x81C, 0x63460403, 0x81C, 0x62480403, + 0x81C, 0x614A0403, 0x81C, 0x604C0403, 0x81C, 0x454E0403, + 0x81C, 0x44500403, 0x81C, 0x43520403, 0x81C, 0x42540403, + 0x81C, 0x41560403, 0x81C, 0x40580403, 0x81C, 0x055A0403, + 0x81C, 0x045C0403, 0x81C, 0x035E0403, 0x81C, 0x02600403, + 0x81C, 0x01620403, 0x81C, 0x00640403, 0x81C, 0x00660403, + 0x81C, 0x00680403, 0x81C, 0x006A0403, 0x81C, 0x006C0403, + 0x81C, 0x006E0403, 0x81C, 0x00700403, 0x81C, 0x00720403, + 0x81C, 0x00740403, 0x81C, 0x00760403, 0x81C, 0x00780403, + 0x81C, 0x007A0403, 0x81C, 0x007C0403, 0x81C, 0x007E0403, + 0x9000100f, 0x05050505, 0x40000000, 0x00000000, 0x81C, 0xFF000403, + 0x81C, 0xF5000403, 0x81C, 0xF4020403, 0x81C, 0xF3040403, + 0x81C, 0xF2060403, 0x81C, 0xF1080403, 0x81C, 0xF00A0403, + 0x81C, 0xEF0C0403, 0x81C, 0xEE0E0403, 0x81C, 0xED100403, + 0x81C, 0xEC120403, 0x81C, 0xEB140403, 0x81C, 0xEA160403, + 0x81C, 0xE9180403, 0x81C, 0xE81A0403, 0x81C, 0xE71C0403, + 0x81C, 0xE61E0403, 0x81C, 0xE5200403, 0x81C, 0xE4220403, + 0x81C, 0xE3240403, 0x81C, 0xE2260403, 0x81C, 0xE1280403, + 0x81C, 0xE02A0403, 0x81C, 0xC32C0403, 0x81C, 0xC22E0403, + 0x81C, 0xC1300403, 0x81C, 0xC0320403, 0x81C, 0xA4340403, + 0x81C, 0xA3360403, 0x81C, 0xA2380403, 0x81C, 0xA13A0403, + 0x81C, 0xA03C0403, 0x81C, 0x823E0403, 0x81C, 0x81400403, + 0x81C, 0x80420403, 0x81C, 0x64440403, 0x81C, 0x63460403, + 0x81C, 0x62480403, 0x81C, 0x614A0403, 0x81C, 0x604C0403, + 0x81C, 0x454E0403, 0x81C, 0x44500403, 0x81C, 0x43520403, + 0x81C, 0x42540403, 0x81C, 0x41560403, 0x81C, 0x40580403, + 0x81C, 0x055A0403, 0x81C, 0x045C0403, 0x81C, 0x035E0403, + 0x81C, 0x02600403, 0x81C, 0x01620403, 0x81C, 0x00640403, + 0x81C, 0x00660403, 0x81C, 0x00680403, 0x81C, 0x006A0403, + 0x81C, 0x006C0403, 0x81C, 0x006E0403, 0x81C, 0x00700403, + 0x81C, 0x00720403, 0x81C, 0x00740403, 0x81C, 0x00760403, + 0x81C, 0x00780403, 0x81C, 0x007A0403, 0x81C, 0x007C0403, + 0x81C, 0x007E0403, 0x9000100f, 0x00000000, 0x40000000, 0x00000000, + 0x81C, 0xFF000403, 0x81C, 0xF5000403, 0x81C, 0xF4020403, + 0x81C, 0xF3040403, 0x81C, 0xF2060403, 0x81C, 0xF1080403, + 0x81C, 0xF00A0403, 0x81C, 0xEF0C0403, 0x81C, 0xEE0E0403, + 0x81C, 0xED100403, 0x81C, 0xEC120403, 0x81C, 0xEB140403, + 0x81C, 0xEA160403, 0x81C, 0xE9180403, 0x81C, 0xE81A0403, + 0x81C, 0xE71C0403, 0x81C, 0xE61E0403, 0x81C, 0xE5200403, + 0x81C, 0xE4220403, 0x81C, 0xE3240403, 0x81C, 0xE2260403, + 0x81C, 0xE1280403, 0x81C, 0xE02A0403, 0x81C, 0xC32C0403, + 0x81C, 0xC22E0403, 0x81C, 0xC1300403, 0x81C, 0xC0320403, + 0x81C, 0xA4340403, 0x81C, 0xA3360403, 0x81C, 0xA2380403, + 0x81C, 0xA13A0403, 0x81C, 0xA03C0403, 0x81C, 0x823E0403, + 0x81C, 0x81400403, 0x81C, 0x80420403, 0x81C, 0x64440403, + 0x81C, 0x63460403, 0x81C, 0x62480403, 0x81C, 0x614A0403, + 0x81C, 0x604C0403, 0x81C, 0x454E0403, 0x81C, 0x44500403, + 0x81C, 0x43520403, 0x81C, 0x42540403, 0x81C, 0x41560403, + 0x81C, 0x40580403, 0x81C, 0x055A0403, 0x81C, 0x045C0403, + 0x81C, 0x035E0403, 0x81C, 0x02600403, 0x81C, 0x01620403, + 0x81C, 0x00640403, 0x81C, 0x00660403, 0x81C, 0x00680403, + 0x81C, 0x006A0403, 0x81C, 0x006C0403, 0x81C, 0x006E0403, + 0x81C, 0x00700403, 0x81C, 0x00720403, 0x81C, 0x00740403, + 0x81C, 0x00760403, 0x81C, 0x00780403, 0x81C, 0x007A0403, + 0x81C, 0x007C0403, 0x81C, 0x007E0403, 0x9000200f, 0x00000000, + 0x40000000, 0x00000000, 0x81C, 0xFF000403, 0x81C, 0xF5000403, + 0x81C, 0xF4020403, 0x81C, 0xF3040403, 0x81C, 0xF2060403, + 0x81C, 0xF1080403, 0x81C, 0xF00A0403, 0x81C, 0xEF0C0403, + 0x81C, 0xEE0E0403, 0x81C, 0xED100403, 0x81C, 0xEC120403, + 0x81C, 0xEB140403, 0x81C, 0xEA160403, 0x81C, 0xE9180403, + 0x81C, 0xE81A0403, 0x81C, 0xE71C0403, 0x81C, 0xE61E0403, + 0x81C, 0xE5200403, 0x81C, 0xE4220403, 0x81C, 0xE3240403, + 0x81C, 0xE2260403, 0x81C, 0xE1280403, 0x81C, 0xE02A0403, + 0x81C, 0xC32C0403, 0x81C, 0xC22E0403, 0x81C, 0xC1300403, + 0x81C, 0xC0320403, 0x81C, 0xA4340403, 0x81C, 0xA3360403, + 0x81C, 0xA2380403, 0x81C, 0xA13A0403, 0x81C, 0xA03C0403, + 0x81C, 0x823E0403, 0x81C, 0x81400403, 0x81C, 0x80420403, + 0x81C, 0x64440403, 0x81C, 0x63460403, 0x81C, 0x62480403, + 0x81C, 0x614A0403, 0x81C, 0x604C0403, 0x81C, 0x454E0403, + 0x81C, 0x44500403, 0x81C, 0x43520403, 0x81C, 0x42540403, + 0x81C, 0x41560403, 0x81C, 0x40580403, 0x81C, 0x055A0403, + 0x81C, 0x045C0403, 0x81C, 0x035E0403, 0x81C, 0x02600403, + 0x81C, 0x01620403, 0x81C, 0x00640403, 0x81C, 0x00660403, + 0x81C, 0x00680403, 0x81C, 0x006A0403, 0x81C, 0x006C0403, + 0x81C, 0x006E0403, 0x81C, 0x00700403, 0x81C, 0x00720403, + 0x81C, 0x00740403, 0x81C, 0x00760403, 0x81C, 0x00780403, + 0x81C, 0x007A0403, 0x81C, 0x007C0403, 0x81C, 0x007E0403, + 0x9000200c, 0x00000000, 0x40000000, 0x00000000, 0x81C, 0xFF000403, + 0x81C, 0xFF000403, 0x81C, 0xFF020403, 0x81C, 0xFE040403, + 0x81C, 0xFD060403, 0x81C, 0xFC080403, 0x81C, 0xFB0A0403, + 0x81C, 0xFA0C0403, 0x81C, 0xF90E0403, 0x81C, 0xF8100403, + 0x81C, 0xF7120403, 0x81C, 0xF6140403, 0x81C, 0xF5160403, + 0x81C, 0xF4180403, 0x81C, 0xF31A0403, 0x81C, 0xF21C0403, + 0x81C, 0xD51E0403, 0x81C, 0xD4200403, 0x81C, 0xD3220403, + 0x81C, 0xD2240403, 0x81C, 0xB6260403, 0x81C, 0xB5280403, + 0x81C, 0xB42A0403, 0x81C, 0xB32C0403, 0x81C, 0xB22E0403, + 0x81C, 0xB1300403, 0x81C, 0xB0320403, 0x81C, 0xAF340403, + 0x81C, 0xAE360403, 0x81C, 0xAD380403, 0x81C, 0xAC3A0403, + 0x81C, 0xAB3C0403, 0x81C, 0xAA3E0403, 0x81C, 0xA9400403, + 0x81C, 0xA8420403, 0x81C, 0xA7440403, 0x81C, 0xA6460403, + 0x81C, 0xA5480403, 0x81C, 0xA44A0403, 0x81C, 0xA34C0403, + 0x81C, 0x854E0403, 0x81C, 0x84500403, 0x81C, 0x83520403, + 0x81C, 0x82540403, 0x81C, 0x81560403, 0x81C, 0x80580403, + 0x81C, 0x485A0403, 0x81C, 0x475C0403, 0x81C, 0x465E0403, + 0x81C, 0x45600403, 0x81C, 0x44620403, 0x81C, 0x0A640403, + 0x81C, 0x09660403, 0x81C, 0x08680403, 0x81C, 0x076A0403, + 0x81C, 0x066C0403, 0x81C, 0x056E0403, 0x81C, 0x04700403, + 0x81C, 0x03720403, 0x81C, 0x02740403, 0x81C, 0x01760403, + 0x81C, 0x00780403, 0x81C, 0x007A0403, 0x81C, 0x007C0403, + 0x81C, 0x007E0403, 0x90012100, 0x00000000, 0x40000000, 0x00000000, + 0x81C, 0xFF000403, 0x81C, 0xFF000403, 0x81C, 0xFF020403, + 0x81C, 0xFE040403, 0x81C, 0xFD060403, 0x81C, 0xFC080403, + 0x81C, 0xFB0A0403, 0x81C, 0xFA0C0403, 0x81C, 0xF90E0403, + 0x81C, 0xF8100403, 0x81C, 0xF7120403, 0x81C, 0xF6140403, + 0x81C, 0xF5160403, 0x81C, 0xF4180403, 0x81C, 0xF31A0403, + 0x81C, 0xF21C0403, 0x81C, 0xD51E0403, 0x81C, 0xD4200403, + 0x81C, 0xD3220403, 0x81C, 0xD2240403, 0x81C, 0xB6260403, + 0x81C, 0xB5280403, 0x81C, 0xB42A0403, 0x81C, 0xB32C0403, + 0x81C, 0xB22E0403, 0x81C, 0xB1300403, 0x81C, 0xB0320403, + 0x81C, 0xAF340403, 0x81C, 0xAE360403, 0x81C, 0xAD380403, + 0x81C, 0xAC3A0403, 0x81C, 0xAB3C0403, 0x81C, 0xAA3E0403, + 0x81C, 0xA9400403, 0x81C, 0xA8420403, 0x81C, 0xA7440403, + 0x81C, 0xA6460403, 0x81C, 0xA5480403, 0x81C, 0xA44A0403, + 0x81C, 0xA34C0403, 0x81C, 0x854E0403, 0x81C, 0x84500403, + 0x81C, 0x83520403, 0x81C, 0x82540403, 0x81C, 0x81560403, + 0x81C, 0x80580403, 0x81C, 0x485A0403, 0x81C, 0x475C0403, + 0x81C, 0x465E0403, 0x81C, 0x45600403, 0x81C, 0x44620403, + 0x81C, 0x0A640403, 0x81C, 0x09660403, 0x81C, 0x08680403, + 0x81C, 0x076A0403, 0x81C, 0x066C0403, 0x81C, 0x056E0403, + 0x81C, 0x04700403, 0x81C, 0x03720403, 0x81C, 0x02740403, + 0x81C, 0x01760403, 0x81C, 0x00780403, 0x81C, 0x007A0403, + 0x81C, 0x007C0403, 0x81C, 0x007E0403, 0x90001004, 0x00000000, + 0x40000000, 0x00000000, 0x81C, 0xFF000403, 0x81C, 0xF5000403, + 0x81C, 0xF4020403, 0x81C, 0xF3040403, 0x81C, 0xF2060403, + 0x81C, 0xF1080403, 0x81C, 0xF00A0403, 0x81C, 0xEF0C0403, + 0x81C, 0xEE0E0403, 0x81C, 0xED100403, 0x81C, 0xEC120403, + 0x81C, 0xEB140403, 0x81C, 0xEA160403, 0x81C, 0xE9180403, + 0x81C, 0xE81A0403, 0x81C, 0xE71C0403, 0x81C, 0xE61E0403, + 0x81C, 0xE5200403, 0x81C, 0xE4220403, 0x81C, 0xE3240403, + 0x81C, 0xE2260403, 0x81C, 0xE1280403, 0x81C, 0xE02A0403, + 0x81C, 0xC32C0403, 0x81C, 0xC22E0403, 0x81C, 0xC1300403, + 0x81C, 0xC0320403, 0x81C, 0xA4340403, 0x81C, 0xA3360403, + 0x81C, 0xA2380403, 0x81C, 0xA13A0403, 0x81C, 0xA03C0403, + 0x81C, 0x823E0403, 0x81C, 0x81400403, 0x81C, 0x80420403, + 0x81C, 0x64440403, 0x81C, 0x63460403, 0x81C, 0x62480403, + 0x81C, 0x614A0403, 0x81C, 0x604C0403, 0x81C, 0x454E0403, + 0x81C, 0x44500403, 0x81C, 0x43520403, 0x81C, 0x42540403, + 0x81C, 0x41560403, 0x81C, 0x40580403, 0x81C, 0x055A0403, + 0x81C, 0x045C0403, 0x81C, 0x035E0403, 0x81C, 0x02600403, + 0x81C, 0x01620403, 0x81C, 0x00640403, 0x81C, 0x00660403, + 0x81C, 0x00680403, 0x81C, 0x006A0403, 0x81C, 0x006C0403, + 0x81C, 0x006E0403, 0x81C, 0x00700403, 0x81C, 0x00720403, + 0x81C, 0x00740403, 0x81C, 0x00760403, 0x81C, 0x00780403, + 0x81C, 0x007A0403, 0x81C, 0x007C0403, 0x81C, 0x007E0403, + 0x90011000, 0x00000000, 0x40000000, 0x00000000, 0x81C, 0xFF000403, + 0x81C, 0xFF000403, 0x81C, 0xFF020403, 0x81C, 0xFE040403, + 0x81C, 0xFD060403, 0x81C, 0xFC080403, 0x81C, 0xFB0A0403, + 0x81C, 0xFA0C0403, 0x81C, 0xF90E0403, 0x81C, 0xF8100403, + 0x81C, 0xF7120403, 0x81C, 0xF6140403, 0x81C, 0xF5160403, + 0x81C, 0xF4180403, 0x81C, 0xF31A0403, 0x81C, 0xF21C0403, + 0x81C, 0xD51E0403, 0x81C, 0xD4200403, 0x81C, 0xD3220403, + 0x81C, 0xD2240403, 0x81C, 0xB6260403, 0x81C, 0xB5280403, + 0x81C, 0xB42A0403, 0x81C, 0xB32C0403, 0x81C, 0xB22E0403, + 0x81C, 0xB1300403, 0x81C, 0xB0320403, 0x81C, 0xAF340403, + 0x81C, 0xAE360403, 0x81C, 0xAD380403, 0x81C, 0xAC3A0403, + 0x81C, 0xAB3C0403, 0x81C, 0xAA3E0403, 0x81C, 0xA9400403, + 0x81C, 0xA8420403, 0x81C, 0xA7440403, 0x81C, 0xA6460403, + 0x81C, 0xA5480403, 0x81C, 0xA44A0403, 0x81C, 0xA34C0403, + 0x81C, 0x854E0403, 0x81C, 0x84500403, 0x81C, 0x83520403, + 0x81C, 0x82540403, 0x81C, 0x81560403, 0x81C, 0x80580403, + 0x81C, 0x485A0403, 0x81C, 0x475C0403, 0x81C, 0x465E0403, + 0x81C, 0x45600403, 0x81C, 0x44620403, 0x81C, 0x0A640403, + 0x81C, 0x09660403, 0x81C, 0x08680403, 0x81C, 0x076A0403, + 0x81C, 0x066C0403, 0x81C, 0x056E0403, 0x81C, 0x04700403, + 0x81C, 0x03720403, 0x81C, 0x02740403, 0x81C, 0x01760403, + 0x81C, 0x00780403, 0x81C, 0x007A0403, 0x81C, 0x007C0403, + 0x81C, 0x007E0403, 0x90002100, 0x00000000, 0x40000000, 0x00000000, + 0x81C, 0xFF000403, 0x81C, 0xFF000403, 0x81C, 0xFF020403, + 0x81C, 0xFE040403, 0x81C, 0xFD060403, 0x81C, 0xFC080403, + 0x81C, 0xFB0A0403, 0x81C, 0xFA0C0403, 0x81C, 0xF90E0403, + 0x81C, 0xF8100403, 0x81C, 0xF7120403, 0x81C, 0xF6140403, + 0x81C, 0xF5160403, 0x81C, 0xF4180403, 0x81C, 0xF31A0403, + 0x81C, 0xF21C0403, 0x81C, 0xD51E0403, 0x81C, 0xD4200403, + 0x81C, 0xD3220403, 0x81C, 0xD2240403, 0x81C, 0xB6260403, + 0x81C, 0xB5280403, 0x81C, 0xB42A0403, 0x81C, 0xB32C0403, + 0x81C, 0xB22E0403, 0x81C, 0xB1300403, 0x81C, 0xB0320403, + 0x81C, 0xAF340403, 0x81C, 0xAE360403, 0x81C, 0xAD380403, + 0x81C, 0xAC3A0403, 0x81C, 0xAB3C0403, 0x81C, 0xAA3E0403, + 0x81C, 0xA9400403, 0x81C, 0xA8420403, 0x81C, 0xA7440403, + 0x81C, 0xA6460403, 0x81C, 0xA5480403, 0x81C, 0xA44A0403, + 0x81C, 0xA34C0403, 0x81C, 0x854E0403, 0x81C, 0x84500403, + 0x81C, 0x83520403, 0x81C, 0x82540403, 0x81C, 0x81560403, + 0x81C, 0x80580403, 0x81C, 0x485A0403, 0x81C, 0x475C0403, + 0x81C, 0x465E0403, 0x81C, 0x45600403, 0x81C, 0x44620403, + 0x81C, 0x0A640403, 0x81C, 0x09660403, 0x81C, 0x08680403, + 0x81C, 0x076A0403, 0x81C, 0x066C0403, 0x81C, 0x056E0403, + 0x81C, 0x04700403, 0x81C, 0x03720403, 0x81C, 0x02740403, + 0x81C, 0x01760403, 0x81C, 0x00780403, 0x81C, 0x007A0403, + 0x81C, 0x007C0403, 0x81C, 0x007E0403, 0x90002000, 0x00000000, + 0x40000000, 0x00000000, 0x81C, 0xFF000403, 0x81C, 0xFF000403, + 0x81C, 0xFF020403, 0x81C, 0xFE040403, 0x81C, 0xFD060403, + 0x81C, 0xFC080403, 0x81C, 0xFB0A0403, 0x81C, 0xFA0C0403, + 0x81C, 0xF90E0403, 0x81C, 0xF8100403, 0x81C, 0xF7120403, + 0x81C, 0xF6140403, 0x81C, 0xF5160403, 0x81C, 0xF4180403, + 0x81C, 0xF31A0403, 0x81C, 0xF21C0403, 0x81C, 0xD51E0403, + 0x81C, 0xD4200403, 0x81C, 0xD3220403, 0x81C, 0xD2240403, + 0x81C, 0xB6260403, 0x81C, 0xB5280403, 0x81C, 0xB42A0403, + 0x81C, 0xB32C0403, 0x81C, 0xB22E0403, 0x81C, 0xB1300403, + 0x81C, 0xB0320403, 0x81C, 0xAF340403, 0x81C, 0xAE360403, + 0x81C, 0xAD380403, 0x81C, 0xAC3A0403, 0x81C, 0xAB3C0403, + 0x81C, 0xAA3E0403, 0x81C, 0xA9400403, 0x81C, 0xA8420403, + 0x81C, 0xA7440403, 0x81C, 0xA6460403, 0x81C, 0xA5480403, + 0x81C, 0xA44A0403, 0x81C, 0xA34C0403, 0x81C, 0x854E0403, + 0x81C, 0x84500403, 0x81C, 0x83520403, 0x81C, 0x82540403, + 0x81C, 0x81560403, 0x81C, 0x80580403, 0x81C, 0x485A0403, + 0x81C, 0x475C0403, 0x81C, 0x465E0403, 0x81C, 0x45600403, + 0x81C, 0x44620403, 0x81C, 0x0A640403, 0x81C, 0x09660403, + 0x81C, 0x08680403, 0x81C, 0x076A0403, 0x81C, 0x066C0403, + 0x81C, 0x056E0403, 0x81C, 0x04700403, 0x81C, 0x03720403, + 0x81C, 0x02740403, 0x81C, 0x01760403, 0x81C, 0x00780403, + 0x81C, 0x007A0403, 0x81C, 0x007C0403, 0x81C, 0x007E0403, + 0xA0000000, 0x00000000, 0x81C, 0xFF000403, 0x81C, 0xFF000403, + 0x81C, 0xFF020403, 0x81C, 0xFE040403, 0x81C, 0xFD060403, + 0x81C, 0xFC080403, 0x81C, 0xFB0A0403, 0x81C, 0xFA0C0403, + 0x81C, 0xF90E0403, 0x81C, 0xF8100403, 0x81C, 0xF7120403, + 0x81C, 0xF6140403, 0x81C, 0xF5160403, 0x81C, 0xF4180403, + 0x81C, 0xF31A0403, 0x81C, 0xF21C0403, 0x81C, 0xD51E0403, + 0x81C, 0xD4200403, 0x81C, 0xD3220403, 0x81C, 0xD2240403, + 0x81C, 0xB6260403, 0x81C, 0xB5280403, 0x81C, 0xB42A0403, + 0x81C, 0xB32C0403, 0x81C, 0xB22E0403, 0x81C, 0xB1300403, + 0x81C, 0xB0320403, 0x81C, 0xAF340403, 0x81C, 0xAE360403, + 0x81C, 0xAD380403, 0x81C, 0xAC3A0403, 0x81C, 0xAB3C0403, + 0x81C, 0xAA3E0403, 0x81C, 0xA9400403, 0x81C, 0xA8420403, + 0x81C, 0xA7440403, 0x81C, 0xA6460403, 0x81C, 0xA5480403, + 0x81C, 0xA44A0403, 0x81C, 0xA34C0403, 0x81C, 0x854E0403, + 0x81C, 0x84500403, 0x81C, 0x83520403, 0x81C, 0x82540403, + 0x81C, 0x81560403, 0x81C, 0x80580403, 0x81C, 0x485A0403, + 0x81C, 0x475C0403, 0x81C, 0x465E0403, 0x81C, 0x45600403, + 0x81C, 0x44620403, 0x81C, 0x0A640403, 0x81C, 0x09660403, + 0x81C, 0x08680403, 0x81C, 0x076A0403, 0x81C, 0x066C0403, + 0x81C, 0x056E0403, 0x81C, 0x04700403, 0x81C, 0x03720403, + 0x81C, 0x02740403, 0x81C, 0x01760403, 0x81C, 0x00780403, + 0x81C, 0x007A0403, 0x81C, 0x007C0403, 0x81C, 0x007E0403, + 0xB0000000, 0x00000000, 0xC50, 0x00000022, 0xC50, 0x00000020, + 0xE50, 0x00000022, 0xE50, 0x00000020, + +}; + +void odm_read_and_config_mp_8822b_agc_tab(struct phy_dm_struct *dm) +{ + u32 i = 0; + u8 c_cond; + bool is_matched = true, is_skipped = false; + u32 array_len = sizeof(array_mp_8822b_agc_tab) / sizeof(u32); + u32 *array = array_mp_8822b_agc_tab; + + u32 v1 = 0, v2 = 0, pre_v1 = 0, pre_v2 = 0; + + ODM_RT_TRACE(dm, ODM_COMP_INIT, + "===> %s\n", __func__); + + for (; (i + 1) < array_len; i = i + 2) { + v1 = array[i]; + v2 = array[i + 1]; + + if (v1 & BIT(31)) { /* positive condition*/ + c_cond = (u8)((v1 & (BIT(29) | BIT(28))) >> 28); + if (c_cond == COND_ENDIF) { /*end*/ + is_matched = true; + is_skipped = false; + ODM_RT_TRACE(dm, ODM_COMP_INIT, "ENDIF\n"); + } else if (c_cond == COND_ELSE) { /*else*/ + is_matched = is_skipped ? false : true; + ODM_RT_TRACE(dm, ODM_COMP_INIT, "ELSE\n"); + } else { /*if , else if*/ + pre_v1 = v1; + pre_v2 = v2; + ODM_RT_TRACE(dm, ODM_COMP_INIT, + "IF or ELSE IF\n"); + } + } else if (v1 & BIT(30)) { /*negative condition*/ + if (is_skipped) { + is_matched = false; + continue; + } + + if (check_positive(dm, pre_v1, pre_v2, v1, v2)) { + is_matched = true; + is_skipped = true; + } else { + is_matched = false; + is_skipped = false; + } + } else if (is_matched) { + odm_config_bb_agc_8822b(dm, v1, MASKDWORD, v2); + } + } +} + +u32 odm_get_version_mp_8822b_agc_tab(void) { return 67; } + +/****************************************************************************** + * phy_reg.TXT + ******************************************************************************/ + +static u32 array_mp_8822b_phy_reg[] = { + 0x800, 0x9020D010, 0x804, 0x800181A0, 0x808, 0x0E028233, + 0x80C, 0x10000013, 0x810, 0x21101263, 0x814, 0x020C3D10, + 0x818, 0x84A10385, 0x81C, 0x1E1E081F, 0x820, 0x0001AAAA, + 0x824, 0x00030FE0, 0x828, 0x0000CCCC, 0x82C, 0x75CB7010, + 0x830, 0x79A0EA2A, 0x834, 0x072E6986, 0x838, 0x87766441, + 0x83C, 0x9194B2B6, 0x840, 0x171740E0, 0x844, 0x4D3D7CDB, + 0x848, 0x4AD0408B, 0x84C, 0x6AFBF7A5, 0x850, 0x28A74706, + 0x854, 0x0001520C, 0x858, 0x4060C000, 0x85C, 0x74010160, + 0x860, 0x68A7C321, 0x864, 0x79F27432, 0x868, 0x8CA7A314, + 0x86C, 0x778C2878, 0x870, 0x77777777, 0x874, 0x27612C2E, + 0x878, 0xC0003152, 0x87C, 0x5C8FC000, 0x880, 0x00000000, + 0x884, 0x00000000, 0x888, 0x00000000, 0x88C, 0x00000000, + 0x890, 0x00000000, 0x894, 0x00000000, 0x898, 0x00000000, + 0x89C, 0x00000000, 0x8A0, 0x00000013, 0x8A4, 0x7F7F7F7F, + 0x8A8, 0x2202033E, 0x8AC, 0xF00F000A, 0x8B0, 0x00000600, + 0x8B4, 0x000FC080, 0x8B8, 0xEC0057F7, 0x8BC, 0xACB520A3, + 0x8C0, 0xFFE04020, 0x8C4, 0x47C00000, 0x8C8, 0x000251A5, + 0x8CC, 0x08108000, 0x8D0, 0x0000B800, 0x8D4, 0x860308A0, + 0x8D8, 0x21095612, 0x8DC, 0x00000000, 0x8E0, 0x32D16777, + 0x8E4, 0x4C098935, 0x8E8, 0xFFFFC42C, 0x8EC, 0x99999999, + 0x8F0, 0x00009999, 0x8F4, 0x00D80FA1, 0x8F8, 0x40000080, + 0x8FC, 0x00000130, 0x900, 0x00800000, 0x904, 0x00000000, + 0x908, 0x00000000, 0x90C, 0xD3000000, 0x910, 0x0000FC00, + 0x914, 0xC6380000, 0x918, 0x1C1028C0, 0x91C, 0x64B11A1C, + 0x920, 0xE0767233, 0x924, 0x855A2500, 0x928, 0x4AB0E4E4, + 0x92C, 0xFFFEB200, 0x930, 0xFFFFFFFE, 0x934, 0x001FFFFF, + 0x938, 0x00008480, 0x93C, 0xE41C0642, 0x940, 0x0E470430, + 0x944, 0x00000000, 0x948, 0xAC000000, 0x94C, 0x10000083, + 0x950, 0x32010080, 0x954, 0x84510080, 0x958, 0x00000001, + 0x95C, 0x04248000, 0x960, 0x00000000, 0x964, 0x00000000, + 0x968, 0x00000000, 0x96C, 0x00000000, 0x970, 0x00001FFF, + 0x974, 0x44000FFF, 0x978, 0x00000000, 0x97C, 0x00000000, + 0x980, 0x00000000, 0x984, 0x00000000, 0x988, 0x00000000, + 0x98C, 0x23440000, 0x990, 0x27100000, 0x994, 0xFFFF0100, + 0x998, 0xFFFFFF5C, 0x99C, 0xFFFFFFFF, 0x9A0, 0x000000FF, + 0x9A4, 0x80000088, 0x9A8, 0x0C2F0000, 0x9AC, 0x01560000, + 0x9B0, 0x70000000, 0x9B4, 0x00000000, 0x9B8, 0x00000000, + 0x9BC, 0x00000000, 0x9C0, 0x00000000, 0x9C4, 0x00000000, + 0x9C8, 0x00000000, 0x9CC, 0x00000000, 0x9D0, 0x00000000, + 0x9D4, 0x00000000, 0x9D8, 0x00000000, 0x9DC, 0x00000000, + 0x9E0, 0x00000000, 0x9E4, 0x02000402, 0x9E8, 0x000022D4, + 0x9EC, 0x00000000, 0x9F0, 0x00010080, 0x9F4, 0x00000000, + 0x9F8, 0x00000000, 0x9FC, 0xEFFFF7F7, 0xA00, 0x00D047C8, + 0xA04, 0x81FF800C, 0xA08, 0x8C838300, 0xA0C, 0x2E20100F, + 0xA10, 0x9500BB78, 0xA14, 0x1114D028, 0xA18, 0x00881117, + 0xA1C, 0x89140F00, 0xA20, 0x84880000, 0xA24, 0x384F6577, + 0xA28, 0x00001525, 0xA2C, 0x00920000, 0xA70, 0x101FFF00, + 0xA74, 0x00000148, 0xA78, 0x00000900, 0xA7C, 0x225B0606, + 0xA80, 0x218675B2, 0xA84, 0x80208C00, 0xA88, 0x040C0000, + 0xA8C, 0x12345678, 0xA90, 0xABCDEF00, 0xA94, 0x001B1B89, + 0xA98, 0x030A0000, 0xA9C, 0x00060000, 0xAA0, 0x00000000, + 0xAA4, 0x0004000F, 0xAA8, 0x00000200, 0xB00, 0xE1000440, + 0xB04, 0x00800000, 0xB08, 0xFF02030B, 0xB0C, 0x01EAA406, + 0xB10, 0x00030690, 0xB14, 0x006000FA, 0xB18, 0x00000002, + 0xB1C, 0x00000002, 0xB20, 0x4B00001F, 0xB24, 0x4E8E3E40, + 0xB28, 0x03020100, 0xB2C, 0x07060504, 0xB30, 0x0B0A0908, + 0xB34, 0x0F0E0D0C, 0xB38, 0x13121110, 0xB3C, 0x0000003A, + 0xB40, 0x00000000, 0xB44, 0x80000000, 0xB48, 0x3F0000FA, + 0xB4C, 0x88C80020, 0xB50, 0x00000000, 0xB54, 0x00004241, + 0xB58, 0xE0008208, 0xB5C, 0x41EFFFF9, 0xB60, 0x00000000, + 0xB64, 0x00200063, 0xB68, 0x0000003A, 0xB6C, 0x00000102, + 0xB70, 0x4E6D1870, 0xB74, 0x03020100, 0xB78, 0x07060504, + 0xB7C, 0x0B0A0908, 0xB80, 0x0F0E0D0C, 0xB84, 0x13121110, + 0xB88, 0x00000000, 0xB8C, 0x00000000, 0xC00, 0x00000007, + 0xC04, 0x00000020, 0xC08, 0x60403231, 0xC0C, 0x00012345, + 0xC10, 0x00000100, 0xC14, 0x01000000, 0xC18, 0x00000000, + 0xC1C, 0x40040053, 0xC20, 0x40020103, 0xC24, 0x00000000, + 0xC28, 0x00000000, 0xC2C, 0x00000000, 0xC30, 0x00000000, + 0xC34, 0x00000000, 0xC38, 0x00000000, 0xC3C, 0x00000000, + 0xC40, 0x00000000, 0xC44, 0x00000000, 0xC48, 0x00000000, + 0xC4C, 0x00000000, 0xC50, 0x00000020, 0xC54, 0x00000000, + 0xC58, 0xD8020402, 0xC5C, 0xDE000120, 0xC68, 0x5979993F, + 0xC6C, 0x0000122A, 0xC70, 0x99795979, 0xC74, 0x99795979, + 0xC78, 0x99799979, 0xC7C, 0x99791979, 0xC80, 0x19791979, + 0xC84, 0x19791979, 0xC88, 0x00000000, 0xC8C, 0x07000000, + 0xC94, 0x01000100, 0xC98, 0x201C8000, 0xC9C, 0x00000000, + 0xCA0, 0x0000A555, 0xCA4, 0x08040201, 0xCA8, 0x80402010, + 0xCAC, 0x00000000, 0xCB0, 0x77777777, 0xCB4, 0x00007777, + 0xCB8, 0x00000000, 0xCBC, 0x00000000, 0xCC0, 0x00000000, + 0xCC4, 0x00000000, 0xCC8, 0x00000000, 0xCCC, 0x00000000, + 0xCD0, 0x00000000, 0xCD4, 0x00000000, 0xCD8, 0x00000000, + 0xCDC, 0x00000000, 0xCE0, 0x00000000, 0xCE4, 0x00000000, + 0xCE8, 0x00000000, 0xCEC, 0x00000000, 0xE00, 0x00000007, + 0xE04, 0x00000020, 0xE08, 0x60403231, 0xE0C, 0x00012345, + 0xE10, 0x00000100, 0xE14, 0x01000000, 0xE18, 0x00000000, + 0xE1C, 0x40040053, 0xE20, 0x40020103, 0xE24, 0x00000000, + 0xE28, 0x00000000, 0xE2C, 0x00000000, 0xE30, 0x00000000, + 0xE34, 0x00000000, 0xE38, 0x00000000, 0xE3C, 0x00000000, + 0xE40, 0x00000000, 0xE44, 0x00000000, 0xE48, 0x00000000, + 0xE4C, 0x00000000, 0xE50, 0x00000020, 0xE54, 0x00000000, + 0xE58, 0xD8020402, 0xE5C, 0xDE000120, 0xE68, 0x5979993F, + 0xE6C, 0x0000122A, 0xE70, 0x99795979, 0xE74, 0x99795979, + 0xE78, 0x99799979, 0xE7C, 0x99791979, 0xE80, 0x19791979, + 0xE84, 0x19791979, 0xE88, 0x00000000, 0xE8C, 0x07000000, + 0xE94, 0x01000100, 0xE98, 0x201C8000, 0xE9C, 0x00000000, + 0xEA0, 0x0000A555, 0xEA4, 0x08040201, 0xEA8, 0x80402010, + 0xEAC, 0x00000000, 0xEB0, 0x77777777, 0xEB4, 0x00007777, + 0xEB8, 0x00000000, 0xEBC, 0x00000000, 0xEC0, 0x00000000, + 0xEC4, 0x00000000, 0xEC8, 0x00000000, 0xECC, 0x00000000, + 0xED0, 0x00000000, 0xED4, 0x00000000, 0xED8, 0x00000000, + 0xEDC, 0x00000000, 0xEE0, 0x00000000, 0xEE4, 0x00000000, + 0xEE8, 0x00000000, 0xEEC, 0x00000000, 0x1900, 0x00000000, + 0x1904, 0x00238000, 0x1908, 0x00000000, 0x190C, 0x00000000, + 0x1910, 0x00000000, 0x1914, 0x00000000, 0x1918, 0x00000000, + 0x191C, 0x00000000, 0x1920, 0x00000000, 0x1924, 0x00000000, + 0x1928, 0x00000000, 0x192C, 0x00000000, 0x1930, 0x00000000, + 0x1934, 0x00000000, 0x1938, 0x00000000, 0x193C, 0x00000000, + 0x1940, 0x00000000, 0x1944, 0x00000000, 0x1948, 0x00000000, + 0x194C, 0x00000000, 0x1950, 0x00000000, 0x1954, 0x00000000, + 0x1958, 0x00000000, 0x195C, 0x00000000, 0x1960, 0x00000000, + 0x1964, 0x00000000, 0x1968, 0x00000000, 0x196C, 0x00000000, + 0x1970, 0x00000000, 0x1974, 0x00000000, 0x1978, 0x00000000, + 0x197C, 0x00000000, 0x1980, 0x00000000, 0x1984, 0x03000000, + 0x1988, 0x21401E88, 0x198C, 0x00004000, 0x1990, 0x00000000, + 0x1994, 0x00000000, 0x1998, 0x00000053, 0x199C, 0x00000000, + 0x19A0, 0x00000000, 0x19A4, 0x00000000, 0x19A8, 0x00000000, + 0x19AC, 0x0E47E47F, 0x19B0, 0x00000000, 0x19B4, 0x0E47E47F, + 0x19B8, 0x00000000, 0x19BC, 0x00000000, 0x19C0, 0x00000000, + 0x19C4, 0x00000000, 0x19C8, 0x00000000, 0x19CC, 0x00000000, + 0x19D0, 0x00000000, 0x19D4, 0xAAAAAAAA, 0x19D8, 0x00000AAA, + 0x19DC, 0x133E0F37, 0x19E0, 0x00000000, 0x19E4, 0x00000000, + 0x19E8, 0x00000000, 0x19EC, 0x00000000, 0x19F0, 0x00000000, + 0x19F4, 0x00000000, 0x19F8, 0x01A00000, 0x19FC, 0x00000000, + 0x1C00, 0x00000100, 0x1C04, 0x01000000, 0x1C08, 0x00000100, + 0x1C0C, 0x01000000, 0x1C10, 0x00000100, 0x1C14, 0x01000000, + 0x1C18, 0x00000100, 0x1C1C, 0x01000000, 0x1C20, 0x00000100, + 0x1C24, 0x01000000, 0x1C28, 0x00000100, 0x1C2C, 0x01000000, + 0x1C30, 0x00000100, 0x1C34, 0x01000000, 0x1C38, 0x00000000, + 0x1C3C, 0x00000000, 0x1C40, 0x000C0100, 0x1C44, 0x000000F3, + 0x1C48, 0x1A8249A8, 0x1C4C, 0x1461C826, 0x1C50, 0x0001469E, + 0x1C54, 0x58D158D1, 0x1C58, 0x04490088, 0x1C5C, 0x04004400, + 0x1C60, 0x00000000, 0x1C64, 0x04004400, 0x1C68, 0x00000100, + 0x1C6C, 0x01000000, 0x1C70, 0x00000100, 0x1C74, 0x01000000, + 0x1C78, 0x00000000, 0x1C7C, 0x00000010, 0x1C80, 0x5FFF5FFF, + 0x1C84, 0x5FFF5FFF, 0x1C88, 0x5FFF5FFF, 0x1C8C, 0x5FFF5FFF, + 0x1C90, 0x5FFF5FFF, 0x1C94, 0x5FFF5FFF, 0x1C98, 0x5FFF5FFF, + 0x1C9C, 0x5FFF5FFF, 0x1CA0, 0x00000100, 0x1CA4, 0x01000000, + 0x1CA8, 0x00000100, 0x1CAC, 0x5FFF5FFF, 0x1CB0, 0x00000100, + 0x1CB4, 0x01000000, 0x1CB8, 0x00000000, 0x1CBC, 0x00000000, + 0x1CC0, 0x00000100, 0x1CC4, 0x01000000, 0x1CC8, 0x00000100, + 0x1CCC, 0x01000000, 0x1CD0, 0x00000100, 0x1CD4, 0x01000000, + 0x1CD8, 0x00000100, 0x1CDC, 0x01000000, 0x1CE0, 0x00000100, + 0x1CE4, 0x01000000, 0x1CE8, 0x00000100, 0x1CEC, 0x01000000, + 0x1CF0, 0x00000100, 0x1CF4, 0x01000000, 0x1CF8, 0x00000000, + 0x1CFC, 0x00000000, 0xC60, 0x70038040, 0xC60, 0x70038040, + 0xC60, 0x70146040, 0xC60, 0x70246040, 0xC60, 0x70346040, + 0xC60, 0x70446040, 0xC60, 0x70532040, 0xC60, 0x70646040, + 0xC60, 0x70738040, 0xC60, 0x70838040, 0xC60, 0x70938040, + 0xC60, 0x70A38040, 0xC60, 0x70B36040, 0xC60, 0x70C06040, + 0xC60, 0x70D06040, 0xC60, 0x70E76040, 0xC60, 0x70F06040, + 0xE60, 0x70038040, 0xE60, 0x70038040, 0xE60, 0x70146040, + 0xE60, 0x70246040, 0xE60, 0x70346040, 0xE60, 0x70446040, + 0xE60, 0x70532040, 0xE60, 0x70646040, 0xE60, 0x70738040, + 0xE60, 0x70838040, 0xE60, 0x70938040, 0xE60, 0x70A38040, + 0xE60, 0x70B36040, 0xE60, 0x70C06040, 0xE60, 0x70D06040, + 0xE60, 0x70E76040, 0xE60, 0x70F06040, 0xC64, 0x00800000, + 0xC64, 0x08800001, 0xC64, 0x00800002, 0xC64, 0x00800003, + 0xC64, 0x00800004, 0xC64, 0x00800005, 0xC64, 0x00800006, + 0xC64, 0x08800007, 0xC64, 0x00004000, 0xE64, 0x00800000, + 0xE64, 0x08800001, 0xE64, 0x00800002, 0xE64, 0x00800003, + 0xE64, 0x00800004, 0xE64, 0x00800005, 0xE64, 0x00800006, + 0xE64, 0x08800007, 0xE64, 0x00004000, 0x1B00, 0xF8000008, + 0x1B00, 0xF80A7008, 0x1B00, 0xF8015008, 0x1B00, 0xF8000008, + 0x1B04, 0xE24629D2, 0x1B08, 0x00000080, 0x1B0C, 0x00000000, + 0x1B10, 0x00010C00, 0x1B14, 0x00000000, 0x1B18, 0x00292903, + 0x1B1C, 0xA2193C32, 0x1B20, 0x01840008, 0x1B24, 0x01860008, + 0x1B28, 0x80060300, 0x1B2C, 0x00000003, 0x1B30, 0x20000000, + 0x1B34, 0x00000800, 0x1B3C, 0x20000000, 0x1BC0, 0x01000000, + 0x1BCC, 0x00000000, 0x1B00, 0xF800000A, 0x1B1C, 0xA2193C32, + 0x1B20, 0x01840008, 0x1B24, 0x01860008, 0x1B28, 0x80060300, + 0x1B2C, 0x00000003, 0x1B30, 0x20000000, 0x1B34, 0x00000800, + 0x1B3C, 0x20000000, 0x1BC0, 0x01000000, 0x1BCC, 0x00000000, + 0x1B00, 0xF8000000, 0x1B80, 0x00000007, 0x1B80, 0x090A0005, + 0x1B80, 0x090A0007, 0x1B80, 0x0FFE0015, 0x1B80, 0x0FFE0017, + 0x1B80, 0x00220025, 0x1B80, 0x00220027, 0x1B80, 0x00040035, + 0x1B80, 0x00040037, 0x1B80, 0x05C00045, 0x1B80, 0x05C00047, + 0x1B80, 0x00070055, 0x1B80, 0x00070057, 0x1B80, 0x64000065, + 0x1B80, 0x64000067, 0x1B80, 0x00020075, 0x1B80, 0x00020077, + 0x1B80, 0x00080085, 0x1B80, 0x00080087, 0x1B80, 0x80000095, + 0x1B80, 0x80000097, 0x1B80, 0x090800A5, 0x1B80, 0x090800A7, + 0x1B80, 0x0F0200B5, 0x1B80, 0x0F0200B7, 0x1B80, 0x002200C5, + 0x1B80, 0x002200C7, 0x1B80, 0x000400D5, 0x1B80, 0x000400D7, + 0x1B80, 0x05C000E5, 0x1B80, 0x05C000E7, 0x1B80, 0x000700F5, + 0x1B80, 0x000700F7, 0x1B80, 0x64020105, 0x1B80, 0x64020107, + 0x1B80, 0x00020115, 0x1B80, 0x00020117, 0x1B80, 0x00040125, + 0x1B80, 0x00040127, 0x1B80, 0x4A000135, 0x1B80, 0x4A000137, + 0x1B80, 0x4B040145, 0x1B80, 0x4B040147, 0x1B80, 0x85030155, + 0x1B80, 0x85030157, 0x1B80, 0x40090165, 0x1B80, 0x40090167, + 0x1B80, 0xE0210175, 0x1B80, 0xE0210177, 0x1B80, 0x4B050185, + 0x1B80, 0x4B050187, 0x1B80, 0x86030195, 0x1B80, 0x86030197, + 0x1B80, 0x400B01A5, 0x1B80, 0x400B01A7, 0x1B80, 0xE02101B5, + 0x1B80, 0xE02101B7, 0x1B80, 0x4B0001C5, 0x1B80, 0x4B0001C7, + 0x1B80, 0x000701D5, 0x1B80, 0x000701D7, 0x1B80, 0x4C0001E5, + 0x1B80, 0x4C0001E7, 0x1B80, 0x000401F5, 0x1B80, 0x000401F7, + 0x1B80, 0x30000205, 0x1B80, 0x30000207, 0x1B80, 0xFE000215, + 0x1B80, 0xFE000217, 0x1B80, 0xFF000225, 0x1B80, 0xFF000227, + 0x1B80, 0xE1750235, 0x1B80, 0xE1750237, 0x1B80, 0xF00D0245, + 0x1B80, 0xF00D0247, 0x1B80, 0xF10D0255, 0x1B80, 0xF10D0257, + 0x1B80, 0xF20D0265, 0x1B80, 0xF20D0267, 0x1B80, 0xF30D0275, + 0x1B80, 0xF30D0277, 0x1B80, 0xF40D0285, 0x1B80, 0xF40D0287, + 0x1B80, 0xF50D0295, 0x1B80, 0xF50D0297, 0x1B80, 0xF60D02A5, + 0x1B80, 0xF60D02A7, 0x1B80, 0xF70D02B5, 0x1B80, 0xF70D02B7, + 0x1B80, 0xF80D02C5, 0x1B80, 0xF80D02C7, 0x1B80, 0xF90D02D5, + 0x1B80, 0xF90D02D7, 0x1B80, 0xFA0D02E5, 0x1B80, 0xFA0D02E7, + 0x1B80, 0xFB0D02F5, 0x1B80, 0xFB0D02F7, 0x1B80, 0x00010305, + 0x1B80, 0x00010307, 0x1B80, 0x303D0315, 0x1B80, 0x303D0317, + 0x1B80, 0x30550325, 0x1B80, 0x30550327, 0x1B80, 0x30A00335, + 0x1B80, 0x30A00337, 0x1B80, 0x30A30345, 0x1B80, 0x30A30347, + 0x1B80, 0x30570355, 0x1B80, 0x30570357, 0x1B80, 0x30620365, + 0x1B80, 0x30620367, 0x1B80, 0x306D0375, 0x1B80, 0x306D0377, + 0x1B80, 0x30AD0385, 0x1B80, 0x30AD0387, 0x1B80, 0x30A70395, + 0x1B80, 0x30A70397, 0x1B80, 0x30BB03A5, 0x1B80, 0x30BB03A7, + 0x1B80, 0x30C603B5, 0x1B80, 0x30C603B7, 0x1B80, 0x30D103C5, + 0x1B80, 0x30D103C7, 0x1B80, 0xE11403D5, 0x1B80, 0xE11403D7, + 0x1B80, 0x4D0403E5, 0x1B80, 0x4D0403E7, 0x1B80, 0x208003F5, + 0x1B80, 0x208003F7, 0x1B80, 0x00000405, 0x1B80, 0x00000407, + 0x1B80, 0x4D000415, 0x1B80, 0x4D000417, 0x1B80, 0x55070425, + 0x1B80, 0x55070427, 0x1B80, 0xE10C0435, 0x1B80, 0xE10C0437, + 0x1B80, 0xE10C0445, 0x1B80, 0xE10C0447, 0x1B80, 0x4D040455, + 0x1B80, 0x4D040457, 0x1B80, 0x20880465, 0x1B80, 0x20880467, + 0x1B80, 0x02000475, 0x1B80, 0x02000477, 0x1B80, 0x4D000485, + 0x1B80, 0x4D000487, 0x1B80, 0x550F0495, 0x1B80, 0x550F0497, + 0x1B80, 0xE10C04A5, 0x1B80, 0xE10C04A7, 0x1B80, 0x4F0204B5, + 0x1B80, 0x4F0204B7, 0x1B80, 0x4E0004C5, 0x1B80, 0x4E0004C7, + 0x1B80, 0x530204D5, 0x1B80, 0x530204D7, 0x1B80, 0x520104E5, + 0x1B80, 0x520104E7, 0x1B80, 0xE11004F5, 0x1B80, 0xE11004F7, + 0x1B80, 0x4D080505, 0x1B80, 0x4D080507, 0x1B80, 0x57100515, + 0x1B80, 0x57100517, 0x1B80, 0x57000525, 0x1B80, 0x57000527, + 0x1B80, 0x4D000535, 0x1B80, 0x4D000537, 0x1B80, 0x00010545, + 0x1B80, 0x00010547, 0x1B80, 0xE1140555, 0x1B80, 0xE1140557, + 0x1B80, 0x00010565, 0x1B80, 0x00010567, 0x1B80, 0x30770575, + 0x1B80, 0x30770577, 0x1B80, 0x00230585, 0x1B80, 0x00230587, + 0x1B80, 0xE1680595, 0x1B80, 0xE1680597, 0x1B80, 0x000205A5, + 0x1B80, 0x000205A7, 0x1B80, 0x54E905B5, 0x1B80, 0x54E905B7, + 0x1B80, 0x0BA605C5, 0x1B80, 0x0BA605C7, 0x1B80, 0x002305D5, + 0x1B80, 0x002305D7, 0x1B80, 0xE16805E5, 0x1B80, 0xE16805E7, + 0x1B80, 0x000205F5, 0x1B80, 0x000205F7, 0x1B80, 0x4D300605, + 0x1B80, 0x4D300607, 0x1B80, 0x30900615, 0x1B80, 0x30900617, + 0x1B80, 0x30730625, 0x1B80, 0x30730627, 0x1B80, 0x00220635, + 0x1B80, 0x00220637, 0x1B80, 0xE1680645, 0x1B80, 0xE1680647, + 0x1B80, 0x00020655, 0x1B80, 0x00020657, 0x1B80, 0x54E80665, + 0x1B80, 0x54E80667, 0x1B80, 0x0BA60675, 0x1B80, 0x0BA60677, + 0x1B80, 0x00220685, 0x1B80, 0x00220687, 0x1B80, 0xE1680695, + 0x1B80, 0xE1680697, 0x1B80, 0x000206A5, 0x1B80, 0x000206A7, + 0x1B80, 0x4D3006B5, 0x1B80, 0x4D3006B7, 0x1B80, 0x309006C5, + 0x1B80, 0x309006C7, 0x1B80, 0x63F106D5, 0x1B80, 0x63F106D7, + 0x1B80, 0xE11406E5, 0x1B80, 0xE11406E7, 0x1B80, 0xE16806F5, + 0x1B80, 0xE16806F7, 0x1B80, 0x63F40705, 0x1B80, 0x63F40707, + 0x1B80, 0xE1140715, 0x1B80, 0xE1140717, 0x1B80, 0xE1680725, + 0x1B80, 0xE1680727, 0x1B80, 0x0BA80735, 0x1B80, 0x0BA80737, + 0x1B80, 0x63F80745, 0x1B80, 0x63F80747, 0x1B80, 0xE1140755, + 0x1B80, 0xE1140757, 0x1B80, 0xE1680765, 0x1B80, 0xE1680767, + 0x1B80, 0x0BA90775, 0x1B80, 0x0BA90777, 0x1B80, 0x63FC0785, + 0x1B80, 0x63FC0787, 0x1B80, 0xE1140795, 0x1B80, 0xE1140797, + 0x1B80, 0xE16807A5, 0x1B80, 0xE16807A7, 0x1B80, 0x63FF07B5, + 0x1B80, 0x63FF07B7, 0x1B80, 0xE11407C5, 0x1B80, 0xE11407C7, + 0x1B80, 0xE16807D5, 0x1B80, 0xE16807D7, 0x1B80, 0x630007E5, + 0x1B80, 0x630007E7, 0x1B80, 0xE11407F5, 0x1B80, 0xE11407F7, + 0x1B80, 0xE1680805, 0x1B80, 0xE1680807, 0x1B80, 0x63030815, + 0x1B80, 0x63030817, 0x1B80, 0xE1140825, 0x1B80, 0xE1140827, + 0x1B80, 0xE1680835, 0x1B80, 0xE1680837, 0x1B80, 0xF4D40845, + 0x1B80, 0xF4D40847, 0x1B80, 0x63070855, 0x1B80, 0x63070857, + 0x1B80, 0xE1140865, 0x1B80, 0xE1140867, 0x1B80, 0xE1680875, + 0x1B80, 0xE1680877, 0x1B80, 0xF5DB0885, 0x1B80, 0xF5DB0887, + 0x1B80, 0x630B0895, 0x1B80, 0x630B0897, 0x1B80, 0xE11408A5, + 0x1B80, 0xE11408A7, 0x1B80, 0xE16808B5, 0x1B80, 0xE16808B7, + 0x1B80, 0x630E08C5, 0x1B80, 0x630E08C7, 0x1B80, 0xE11408D5, + 0x1B80, 0xE11408D7, 0x1B80, 0xE16808E5, 0x1B80, 0xE16808E7, + 0x1B80, 0x4D3008F5, 0x1B80, 0x4D3008F7, 0x1B80, 0x55010905, + 0x1B80, 0x55010907, 0x1B80, 0x57040915, 0x1B80, 0x57040917, + 0x1B80, 0x57000925, 0x1B80, 0x57000927, 0x1B80, 0x96000935, + 0x1B80, 0x96000937, 0x1B80, 0x57080945, 0x1B80, 0x57080947, + 0x1B80, 0x57000955, 0x1B80, 0x57000957, 0x1B80, 0x95000965, + 0x1B80, 0x95000967, 0x1B80, 0x4D000975, 0x1B80, 0x4D000977, + 0x1B80, 0x6C070985, 0x1B80, 0x6C070987, 0x1B80, 0x7B200995, + 0x1B80, 0x7B200997, 0x1B80, 0x7A0009A5, 0x1B80, 0x7A0009A7, + 0x1B80, 0x790009B5, 0x1B80, 0x790009B7, 0x1B80, 0x7F2009C5, + 0x1B80, 0x7F2009C7, 0x1B80, 0x7E0009D5, 0x1B80, 0x7E0009D7, + 0x1B80, 0x7D0009E5, 0x1B80, 0x7D0009E7, 0x1B80, 0x000109F5, + 0x1B80, 0x000109F7, 0x1B80, 0x62850A05, 0x1B80, 0x62850A07, + 0x1B80, 0xE1140A15, 0x1B80, 0xE1140A17, 0x1B80, 0x00010A25, + 0x1B80, 0x00010A27, 0x1B80, 0x5C320A35, 0x1B80, 0x5C320A37, + 0x1B80, 0xE1640A45, 0x1B80, 0xE1640A47, 0x1B80, 0xE1420A55, + 0x1B80, 0xE1420A57, 0x1B80, 0x00010A65, 0x1B80, 0x00010A67, + 0x1B80, 0x5C320A75, 0x1B80, 0x5C320A77, 0x1B80, 0x63F40A85, + 0x1B80, 0x63F40A87, 0x1B80, 0x62850A95, 0x1B80, 0x62850A97, + 0x1B80, 0x0BB00AA5, 0x1B80, 0x0BB00AA7, 0x1B80, 0xE1140AB5, + 0x1B80, 0xE1140AB7, 0x1B80, 0xE1680AC5, 0x1B80, 0xE1680AC7, + 0x1B80, 0x5C320AD5, 0x1B80, 0x5C320AD7, 0x1B80, 0x63FC0AE5, + 0x1B80, 0x63FC0AE7, 0x1B80, 0x62850AF5, 0x1B80, 0x62850AF7, + 0x1B80, 0x0BB10B05, 0x1B80, 0x0BB10B07, 0x1B80, 0xE1140B15, + 0x1B80, 0xE1140B17, 0x1B80, 0xE1680B25, 0x1B80, 0xE1680B27, + 0x1B80, 0x63030B35, 0x1B80, 0x63030B37, 0x1B80, 0xE1140B45, + 0x1B80, 0xE1140B47, 0x1B80, 0xE1680B55, 0x1B80, 0xE1680B57, + 0x1B80, 0xF7040B65, 0x1B80, 0xF7040B67, 0x1B80, 0x630B0B75, + 0x1B80, 0x630B0B77, 0x1B80, 0xE1140B85, 0x1B80, 0xE1140B87, + 0x1B80, 0xE1680B95, 0x1B80, 0xE1680B97, 0x1B80, 0x00010BA5, + 0x1B80, 0x00010BA7, 0x1B80, 0x30DF0BB5, 0x1B80, 0x30DF0BB7, + 0x1B80, 0x00230BC5, 0x1B80, 0x00230BC7, 0x1B80, 0xE16D0BD5, + 0x1B80, 0xE16D0BD7, 0x1B80, 0x00020BE5, 0x1B80, 0x00020BE7, + 0x1B80, 0x54E90BF5, 0x1B80, 0x54E90BF7, 0x1B80, 0x0BA60C05, + 0x1B80, 0x0BA60C07, 0x1B80, 0x00230C15, 0x1B80, 0x00230C17, + 0x1B80, 0xE16D0C25, 0x1B80, 0xE16D0C27, 0x1B80, 0x00020C35, + 0x1B80, 0x00020C37, 0x1B80, 0x4D100C45, 0x1B80, 0x4D100C47, + 0x1B80, 0x30900C55, 0x1B80, 0x30900C57, 0x1B80, 0x30D90C65, + 0x1B80, 0x30D90C67, 0x1B80, 0x00220C75, 0x1B80, 0x00220C77, + 0x1B80, 0xE16D0C85, 0x1B80, 0xE16D0C87, 0x1B80, 0x00020C95, + 0x1B80, 0x00020C97, 0x1B80, 0x54E80CA5, 0x1B80, 0x54E80CA7, + 0x1B80, 0x0BA60CB5, 0x1B80, 0x0BA60CB7, 0x1B80, 0x00220CC5, + 0x1B80, 0x00220CC7, 0x1B80, 0xE16D0CD5, 0x1B80, 0xE16D0CD7, + 0x1B80, 0x00020CE5, 0x1B80, 0x00020CE7, 0x1B80, 0x4D100CF5, + 0x1B80, 0x4D100CF7, 0x1B80, 0x30900D05, 0x1B80, 0x30900D07, + 0x1B80, 0x5C320D15, 0x1B80, 0x5C320D17, 0x1B80, 0x54F00D25, + 0x1B80, 0x54F00D27, 0x1B80, 0x67F10D35, 0x1B80, 0x67F10D37, + 0x1B80, 0xE1420D45, 0x1B80, 0xE1420D47, 0x1B80, 0xE16D0D55, + 0x1B80, 0xE16D0D57, 0x1B80, 0x67F40D65, 0x1B80, 0x67F40D67, + 0x1B80, 0xE1420D75, 0x1B80, 0xE1420D77, 0x1B80, 0xE16D0D85, + 0x1B80, 0xE16D0D87, 0x1B80, 0x5C320D95, 0x1B80, 0x5C320D97, + 0x1B80, 0x54F10DA5, 0x1B80, 0x54F10DA7, 0x1B80, 0x0BA80DB5, + 0x1B80, 0x0BA80DB7, 0x1B80, 0x67F80DC5, 0x1B80, 0x67F80DC7, + 0x1B80, 0xE1420DD5, 0x1B80, 0xE1420DD7, 0x1B80, 0xE16D0DE5, + 0x1B80, 0xE16D0DE7, 0x1B80, 0x5C320DF5, 0x1B80, 0x5C320DF7, + 0x1B80, 0x54F10E05, 0x1B80, 0x54F10E07, 0x1B80, 0x0BA90E15, + 0x1B80, 0x0BA90E17, 0x1B80, 0x67FC0E25, 0x1B80, 0x67FC0E27, + 0x1B80, 0xE1420E35, 0x1B80, 0xE1420E37, 0x1B80, 0xE16D0E45, + 0x1B80, 0xE16D0E47, 0x1B80, 0x67FF0E55, 0x1B80, 0x67FF0E57, + 0x1B80, 0xE1420E65, 0x1B80, 0xE1420E67, 0x1B80, 0xE16D0E75, + 0x1B80, 0xE16D0E77, 0x1B80, 0x5C320E85, 0x1B80, 0x5C320E87, + 0x1B80, 0x54F20E95, 0x1B80, 0x54F20E97, 0x1B80, 0x67000EA5, + 0x1B80, 0x67000EA7, 0x1B80, 0xE1420EB5, 0x1B80, 0xE1420EB7, + 0x1B80, 0xE16D0EC5, 0x1B80, 0xE16D0EC7, 0x1B80, 0x67030ED5, + 0x1B80, 0x67030ED7, 0x1B80, 0xE1420EE5, 0x1B80, 0xE1420EE7, + 0x1B80, 0xE16D0EF5, 0x1B80, 0xE16D0EF7, 0x1B80, 0xF9CC0F05, + 0x1B80, 0xF9CC0F07, 0x1B80, 0x67070F15, 0x1B80, 0x67070F17, + 0x1B80, 0xE1420F25, 0x1B80, 0xE1420F27, 0x1B80, 0xE16D0F35, + 0x1B80, 0xE16D0F37, 0x1B80, 0xFAD30F45, 0x1B80, 0xFAD30F47, + 0x1B80, 0x5C320F55, 0x1B80, 0x5C320F57, 0x1B80, 0x54F30F65, + 0x1B80, 0x54F30F67, 0x1B80, 0x670B0F75, 0x1B80, 0x670B0F77, + 0x1B80, 0xE1420F85, 0x1B80, 0xE1420F87, 0x1B80, 0xE16D0F95, + 0x1B80, 0xE16D0F97, 0x1B80, 0x670E0FA5, 0x1B80, 0x670E0FA7, + 0x1B80, 0xE1420FB5, 0x1B80, 0xE1420FB7, 0x1B80, 0xE16D0FC5, + 0x1B80, 0xE16D0FC7, 0x1B80, 0x4D100FD5, 0x1B80, 0x4D100FD7, + 0x1B80, 0x30900FE5, 0x1B80, 0x30900FE7, 0x1B80, 0x00010FF5, + 0x1B80, 0x00010FF7, 0x1B80, 0x7B241005, 0x1B80, 0x7B241007, + 0x1B80, 0x7A401015, 0x1B80, 0x7A401017, 0x1B80, 0x79001025, + 0x1B80, 0x79001027, 0x1B80, 0x55031035, 0x1B80, 0x55031037, + 0x1B80, 0x310C1045, 0x1B80, 0x310C1047, 0x1B80, 0x7B1C1055, + 0x1B80, 0x7B1C1057, 0x1B80, 0x7A401065, 0x1B80, 0x7A401067, + 0x1B80, 0x550B1075, 0x1B80, 0x550B1077, 0x1B80, 0x310C1085, + 0x1B80, 0x310C1087, 0x1B80, 0x7B201095, 0x1B80, 0x7B201097, + 0x1B80, 0x7A0010A5, 0x1B80, 0x7A0010A7, 0x1B80, 0x551310B5, + 0x1B80, 0x551310B7, 0x1B80, 0x740110C5, 0x1B80, 0x740110C7, + 0x1B80, 0x740010D5, 0x1B80, 0x740010D7, 0x1B80, 0x8E0010E5, + 0x1B80, 0x8E0010E7, 0x1B80, 0x000110F5, 0x1B80, 0x000110F7, + 0x1B80, 0x57021105, 0x1B80, 0x57021107, 0x1B80, 0x57001115, + 0x1B80, 0x57001117, 0x1B80, 0x97001125, 0x1B80, 0x97001127, + 0x1B80, 0x00011135, 0x1B80, 0x00011137, 0x1B80, 0x4F781145, + 0x1B80, 0x4F781147, 0x1B80, 0x53881155, 0x1B80, 0x53881157, + 0x1B80, 0xE1221165, 0x1B80, 0xE1221167, 0x1B80, 0x54801175, + 0x1B80, 0x54801177, 0x1B80, 0x54001185, 0x1B80, 0x54001187, + 0x1B80, 0xE1221195, 0x1B80, 0xE1221197, 0x1B80, 0x548111A5, + 0x1B80, 0x548111A7, 0x1B80, 0x540011B5, 0x1B80, 0x540011B7, + 0x1B80, 0xE12211C5, 0x1B80, 0xE12211C7, 0x1B80, 0x548211D5, + 0x1B80, 0x548211D7, 0x1B80, 0x540011E5, 0x1B80, 0x540011E7, + 0x1B80, 0xE12D11F5, 0x1B80, 0xE12D11F7, 0x1B80, 0xBF1D1205, + 0x1B80, 0xBF1D1207, 0x1B80, 0x301D1215, 0x1B80, 0x301D1217, + 0x1B80, 0xE1001225, 0x1B80, 0xE1001227, 0x1B80, 0xE1051235, + 0x1B80, 0xE1051237, 0x1B80, 0xE1091245, 0x1B80, 0xE1091247, + 0x1B80, 0xE1101255, 0x1B80, 0xE1101257, 0x1B80, 0xE1641265, + 0x1B80, 0xE1641267, 0x1B80, 0x55131275, 0x1B80, 0x55131277, + 0x1B80, 0xE10C1285, 0x1B80, 0xE10C1287, 0x1B80, 0x55151295, + 0x1B80, 0x55151297, 0x1B80, 0xE11012A5, 0x1B80, 0xE11012A7, + 0x1B80, 0xE16412B5, 0x1B80, 0xE16412B7, 0x1B80, 0x000112C5, + 0x1B80, 0x000112C7, 0x1B80, 0x54BF12D5, 0x1B80, 0x54BF12D7, + 0x1B80, 0x54C012E5, 0x1B80, 0x54C012E7, 0x1B80, 0x54A312F5, + 0x1B80, 0x54A312F7, 0x1B80, 0x54C11305, 0x1B80, 0x54C11307, + 0x1B80, 0x54A41315, 0x1B80, 0x54A41317, 0x1B80, 0x4C181325, + 0x1B80, 0x4C181327, 0x1B80, 0xBF071335, 0x1B80, 0xBF071337, + 0x1B80, 0x54C21345, 0x1B80, 0x54C21347, 0x1B80, 0x54A41355, + 0x1B80, 0x54A41357, 0x1B80, 0xBF041365, 0x1B80, 0xBF041367, + 0x1B80, 0x54C11375, 0x1B80, 0x54C11377, 0x1B80, 0x54A31385, + 0x1B80, 0x54A31387, 0x1B80, 0xBF011395, 0x1B80, 0xBF011397, + 0x1B80, 0xE17213A5, 0x1B80, 0xE17213A7, 0x1B80, 0x54DF13B5, + 0x1B80, 0x54DF13B7, 0x1B80, 0x000113C5, 0x1B80, 0x000113C7, + 0x1B80, 0x54BF13D5, 0x1B80, 0x54BF13D7, 0x1B80, 0x54E513E5, + 0x1B80, 0x54E513E7, 0x1B80, 0x050A13F5, 0x1B80, 0x050A13F7, + 0x1B80, 0x54DF1405, 0x1B80, 0x54DF1407, 0x1B80, 0x00011415, + 0x1B80, 0x00011417, 0x1B80, 0x7F201425, 0x1B80, 0x7F201427, + 0x1B80, 0x7E001435, 0x1B80, 0x7E001437, 0x1B80, 0x7D001445, + 0x1B80, 0x7D001447, 0x1B80, 0x55011455, 0x1B80, 0x55011457, + 0x1B80, 0x5C311465, 0x1B80, 0x5C311467, 0x1B80, 0xE10C1475, + 0x1B80, 0xE10C1477, 0x1B80, 0xE1101485, 0x1B80, 0xE1101487, + 0x1B80, 0x54801495, 0x1B80, 0x54801497, 0x1B80, 0x540014A5, + 0x1B80, 0x540014A7, 0x1B80, 0xE10C14B5, 0x1B80, 0xE10C14B7, + 0x1B80, 0xE11014C5, 0x1B80, 0xE11014C7, 0x1B80, 0x548114D5, + 0x1B80, 0x548114D7, 0x1B80, 0x540014E5, 0x1B80, 0x540014E7, + 0x1B80, 0xE10C14F5, 0x1B80, 0xE10C14F7, 0x1B80, 0xE1101505, + 0x1B80, 0xE1101507, 0x1B80, 0x54821515, 0x1B80, 0x54821517, + 0x1B80, 0x54001525, 0x1B80, 0x54001527, 0x1B80, 0xE12D1535, + 0x1B80, 0xE12D1537, 0x1B80, 0xBFE91545, 0x1B80, 0xBFE91547, + 0x1B80, 0x301D1555, 0x1B80, 0x301D1557, 0x1B80, 0x00231565, + 0x1B80, 0x00231567, 0x1B80, 0x7B201575, 0x1B80, 0x7B201577, + 0x1B80, 0x7A001585, 0x1B80, 0x7A001587, 0x1B80, 0x79001595, + 0x1B80, 0x79001597, 0x1B80, 0xE16815A5, 0x1B80, 0xE16815A7, + 0x1B80, 0x000215B5, 0x1B80, 0x000215B7, 0x1B80, 0x000115C5, + 0x1B80, 0x000115C7, 0x1B80, 0x002215D5, 0x1B80, 0x002215D7, + 0x1B80, 0x7B2015E5, 0x1B80, 0x7B2015E7, 0x1B80, 0x7A0015F5, + 0x1B80, 0x7A0015F7, 0x1B80, 0x79001605, 0x1B80, 0x79001607, + 0x1B80, 0xE1681615, 0x1B80, 0xE1681617, 0x1B80, 0x00021625, + 0x1B80, 0x00021627, 0x1B80, 0x00011635, 0x1B80, 0x00011637, + 0x1B80, 0x549F1645, 0x1B80, 0x549F1647, 0x1B80, 0x54FF1655, + 0x1B80, 0x54FF1657, 0x1B80, 0x54001665, 0x1B80, 0x54001667, + 0x1B80, 0x00011675, 0x1B80, 0x00011677, 0x1B80, 0x5C311685, + 0x1B80, 0x5C311687, 0x1B80, 0x07141695, 0x1B80, 0x07141697, + 0x1B80, 0x540016A5, 0x1B80, 0x540016A7, 0x1B80, 0x5C3216B5, + 0x1B80, 0x5C3216B7, 0x1B80, 0x000116C5, 0x1B80, 0x000116C7, + 0x1B80, 0x5C3216D5, 0x1B80, 0x5C3216D7, 0x1B80, 0x071416E5, + 0x1B80, 0x071416E7, 0x1B80, 0x540016F5, 0x1B80, 0x540016F7, + 0x1B80, 0x5C311705, 0x1B80, 0x5C311707, 0x1B80, 0x00011715, + 0x1B80, 0x00011717, 0x1B80, 0x4C981725, 0x1B80, 0x4C981727, + 0x1B80, 0x4C181735, 0x1B80, 0x4C181737, 0x1B80, 0x00011745, + 0x1B80, 0x00011747, 0x1B80, 0x5C321755, 0x1B80, 0x5C321757, + 0x1B80, 0x62841765, 0x1B80, 0x62841767, 0x1B80, 0x66861775, + 0x1B80, 0x66861777, 0x1B80, 0x6C031785, 0x1B80, 0x6C031787, + 0x1B80, 0x7B201795, 0x1B80, 0x7B201797, 0x1B80, 0x7A0017A5, + 0x1B80, 0x7A0017A7, 0x1B80, 0x790017B5, 0x1B80, 0x790017B7, + 0x1B80, 0x7F2017C5, 0x1B80, 0x7F2017C7, 0x1B80, 0x7E0017D5, + 0x1B80, 0x7E0017D7, 0x1B80, 0x7D0017E5, 0x1B80, 0x7D0017E7, + 0x1B80, 0x090117F5, 0x1B80, 0x090117F7, 0x1B80, 0x0C011805, + 0x1B80, 0x0C011807, 0x1B80, 0x0BA61815, 0x1B80, 0x0BA61817, + 0x1B80, 0x00011825, 0x1B80, 0x00011827, 0x1B80, 0x00000006, + 0x1B80, 0x00000002, + +}; + +void odm_read_and_config_mp_8822b_phy_reg(struct phy_dm_struct *dm) +{ + u32 i = 0; + u8 c_cond; + bool is_matched = true, is_skipped = false; + u32 array_len = sizeof(array_mp_8822b_phy_reg) / sizeof(u32); + u32 *array = array_mp_8822b_phy_reg; + + u32 v1 = 0, v2 = 0, pre_v1 = 0, pre_v2 = 0; + + ODM_RT_TRACE(dm, ODM_COMP_INIT, + "===> %s\n", __func__); + + for (; (i + 1) < array_len; i = i + 2) { + v1 = array[i]; + v2 = array[i + 1]; + + if (v1 & BIT(31)) { /* positive condition*/ + c_cond = (u8)((v1 & (BIT(29) | BIT(28))) >> 28); + if (c_cond == COND_ENDIF) { /*end*/ + is_matched = true; + is_skipped = false; + ODM_RT_TRACE(dm, ODM_COMP_INIT, "ENDIF\n"); + } else if (c_cond == COND_ELSE) { /*else*/ + is_matched = is_skipped ? false : true; + ODM_RT_TRACE(dm, ODM_COMP_INIT, "ELSE\n"); + } else { /*if , else if*/ + pre_v1 = v1; + pre_v2 = v2; + ODM_RT_TRACE(dm, ODM_COMP_INIT, + "IF or ELSE IF\n"); + } + } else if (v1 & BIT(30)) { /*negative condition*/ + if (is_skipped) { + is_matched = false; + continue; + } + + if (check_positive(dm, pre_v1, pre_v2, v1, v2)) { + is_matched = true; + is_skipped = true; + } else { + is_matched = false; + is_skipped = false; + } + } else if (is_matched) { + odm_config_bb_phy_8822b(dm, v1, MASKDWORD, v2); + } + } +} + +u32 odm_get_version_mp_8822b_phy_reg(void) { return 67; } + +/****************************************************************************** + * phy_reg_pg.TXT + ******************************************************************************/ + +static u32 array_mp_8822b_phy_reg_pg[] = { + 0, 0, 0, 0x00000c20, 0xffffffff, 0x32343638, + 0, 0, 0, 0x00000c24, 0xffffffff, 0x36384042, + 0, 0, 0, 0x00000c28, 0xffffffff, 0x28303234, + 0, 0, 0, 0x00000c2c, 0xffffffff, 0x34363840, + 0, 0, 0, 0x00000c30, 0xffffffff, 0x26283032, + 0, 0, 1, 0x00000c34, 0xffffffff, 0x34363840, + 0, 0, 1, 0x00000c38, 0xffffffff, 0x26283032, + 0, 0, 0, 0x00000c3c, 0xffffffff, 0x34363840, + 0, 0, 0, 0x00000c40, 0xffffffff, 0x26283032, + 0, 0, 0, 0x00000c44, 0xffffffff, 0x38402224, + 0, 0, 1, 0x00000c48, 0xffffffff, 0x30323436, + 0, 0, 1, 0x00000c4c, 0xffffffff, 0x22242628, + 0, 1, 0, 0x00000e20, 0xffffffff, 0x32343638, + 0, 1, 0, 0x00000e24, 0xffffffff, 0x36384042, + 0, 1, 0, 0x00000e28, 0xffffffff, 0x28303234, + 0, 1, 0, 0x00000e2c, 0xffffffff, 0x34363840, + 0, 1, 0, 0x00000e30, 0xffffffff, 0x26283032, + 0, 1, 1, 0x00000e34, 0xffffffff, 0x34363840, + 0, 1, 1, 0x00000e38, 0xffffffff, 0x26283032, + 0, 1, 0, 0x00000e3c, 0xffffffff, 0x34363840, + 0, 1, 0, 0x00000e40, 0xffffffff, 0x26283032, + 0, 1, 0, 0x00000e44, 0xffffffff, 0x38402224, + 0, 1, 1, 0x00000e48, 0xffffffff, 0x30323436, + 0, 1, 1, 0x00000e4c, 0xffffffff, 0x22242628, + 1, 0, 0, 0x00000c24, 0xffffffff, 0x34363840, + 1, 0, 0, 0x00000c28, 0xffffffff, 0x26283032, + 1, 0, 0, 0x00000c2c, 0xffffffff, 0x32343638, + 1, 0, 0, 0x00000c30, 0xffffffff, 0x24262830, + 1, 0, 1, 0x00000c34, 0xffffffff, 0x32343638, + 1, 0, 1, 0x00000c38, 0xffffffff, 0x24262830, + 1, 0, 0, 0x00000c3c, 0xffffffff, 0x32343638, + 1, 0, 0, 0x00000c40, 0xffffffff, 0x24262830, + 1, 0, 0, 0x00000c44, 0xffffffff, 0x36382022, + 1, 0, 1, 0x00000c48, 0xffffffff, 0x28303234, + 1, 0, 1, 0x00000c4c, 0xffffffff, 0x20222426, + 1, 1, 0, 0x00000e24, 0xffffffff, 0x34363840, + 1, 1, 0, 0x00000e28, 0xffffffff, 0x26283032, + 1, 1, 0, 0x00000e2c, 0xffffffff, 0x32343638, + 1, 1, 0, 0x00000e30, 0xffffffff, 0x24262830, + 1, 1, 1, 0x00000e34, 0xffffffff, 0x32343638, + 1, 1, 1, 0x00000e38, 0xffffffff, 0x24262830, + 1, 1, 0, 0x00000e3c, 0xffffffff, 0x32343638, + 1, 1, 0, 0x00000e40, 0xffffffff, 0x24262830, + 1, 1, 0, 0x00000e44, 0xffffffff, 0x36382022, + 1, 1, 1, 0x00000e48, 0xffffffff, 0x28303234, + 1, 1, 1, 0x00000e4c, 0xffffffff, 0x20222426, +}; + +void odm_read_and_config_mp_8822b_phy_reg_pg(struct phy_dm_struct *dm) +{ + u32 i = 0; + u32 array_len = sizeof(array_mp_8822b_phy_reg_pg) / sizeof(u32); + u32 *array = array_mp_8822b_phy_reg_pg; + + ODM_RT_TRACE(dm, ODM_COMP_INIT, + "===> %s\n", __func__); + + dm->phy_reg_pg_version = 1; + dm->phy_reg_pg_value_type = PHY_REG_PG_EXACT_VALUE; + + for (i = 0; i < array_len; i += 6) { + u32 v1 = array[i]; + u32 v2 = array[i + 1]; + u32 v3 = array[i + 2]; + u32 v4 = array[i + 3]; + u32 v5 = array[i + 4]; + u32 v6 = array[i + 5]; + + odm_config_bb_phy_reg_pg_8822b(dm, v1, v2, v3, v4, v5, v6); + } +} diff --git a/drivers/staging/rtlwifi/phydm/rtl8822b/halhwimg8822b_bb.h b/drivers/staging/rtlwifi/phydm/rtl8822b/halhwimg8822b_bb.h new file mode 100644 index 000000000000..53431998b47e --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/rtl8822b/halhwimg8822b_bb.h @@ -0,0 +1,54 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +/*Image2HeaderVersion: 3.2*/ +#ifndef __INC_MP_BB_HW_IMG_8822B_H +#define __INC_MP_BB_HW_IMG_8822B_H + +/****************************************************************************** + * agc_tab.TXT + ******************************************************************************/ + +void odm_read_and_config_mp_8822b_agc_tab(/* tc: Test Chip, mp: mp Chip*/ + struct phy_dm_struct *dm); +u32 odm_get_version_mp_8822b_agc_tab(void); + +/****************************************************************************** + * phy_reg.TXT + ******************************************************************************/ + +void odm_read_and_config_mp_8822b_phy_reg(/* tc: Test Chip, mp: mp Chip*/ + struct phy_dm_struct *dm); +u32 odm_get_version_mp_8822b_phy_reg(void); + +/****************************************************************************** + * phy_reg_pg.TXT + ******************************************************************************/ + +void odm_read_and_config_mp_8822b_phy_reg_pg(/* tc: Test Chip, mp: mp Chip*/ + struct phy_dm_struct *dm); +u32 odm_get_version_mp_8822b_phy_reg_pg(void); + +#endif diff --git a/drivers/staging/rtlwifi/phydm/rtl8822b/halhwimg8822b_mac.c b/drivers/staging/rtlwifi/phydm/rtl8822b/halhwimg8822b_mac.c new file mode 100644 index 000000000000..1a9daed2e609 --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/rtl8822b/halhwimg8822b_mac.c @@ -0,0 +1,222 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +/*Image2HeaderVersion: 3.2*/ +#include "../mp_precomp.h" +#include "../phydm_precomp.h" + +static bool check_positive(struct phy_dm_struct *dm, const u32 condition1, + const u32 condition2, const u32 condition3, + const u32 condition4) +{ + u8 _board_type = ((dm->board_type & BIT(4)) >> 4) << 0 | /* _GLNA*/ + ((dm->board_type & BIT(3)) >> 3) << 1 | /* _GPA*/ + ((dm->board_type & BIT(7)) >> 7) << 2 | /* _ALNA*/ + ((dm->board_type & BIT(6)) >> 6) << 3 | /* _APA */ + ((dm->board_type & BIT(2)) >> 2) << 4; /* _BT*/ + + u32 cond1 = condition1, cond2 = condition2, cond3 = condition3, + cond4 = condition4; + + u8 cut_version_for_para = + (dm->cut_version == ODM_CUT_A) ? 14 : dm->cut_version; + u8 pkg_type_for_para = (dm->package_type == 0) ? 14 : dm->package_type; + + u32 driver1 = cut_version_for_para << 24 | + (dm->support_interface & 0xF0) << 16 | + dm->support_platform << 16 | pkg_type_for_para << 12 | + (dm->support_interface & 0x0F) << 8 | _board_type; + + u32 driver2 = (dm->type_glna & 0xFF) << 0 | (dm->type_gpa & 0xFF) << 8 | + (dm->type_alna & 0xFF) << 16 | + (dm->type_apa & 0xFF) << 24; + + u32 driver3 = 0; + + u32 driver4 = (dm->type_glna & 0xFF00) >> 8 | (dm->type_gpa & 0xFF00) | + (dm->type_alna & 0xFF00) << 8 | + (dm->type_apa & 0xFF00) << 16; + + ODM_RT_TRACE( + dm, ODM_COMP_INIT, + "===> %s (cond1, cond2, cond3, cond4) = (0x%X 0x%X 0x%X 0x%X)\n", + __func__, cond1, cond2, cond3, cond4); + ODM_RT_TRACE( + dm, ODM_COMP_INIT, + "===> %s (driver1, driver2, driver3, driver4) = (0x%X 0x%X 0x%X 0x%X)\n", + __func__, driver1, driver2, driver3, driver4); + + ODM_RT_TRACE(dm, ODM_COMP_INIT, + " (Platform, Interface) = (0x%X, 0x%X)\n", + dm->support_platform, dm->support_interface); + ODM_RT_TRACE(dm, ODM_COMP_INIT, + " (Board, Package) = (0x%X, 0x%X)\n", + dm->board_type, dm->package_type); + + /*============== value Defined Check ===============*/ + /*QFN type [15:12] and cut version [27:24] need to do value check*/ + + if (((cond1 & 0x0000F000) != 0) && + ((cond1 & 0x0000F000) != (driver1 & 0x0000F000))) + return false; + if (((cond1 & 0x0F000000) != 0) && + ((cond1 & 0x0F000000) != (driver1 & 0x0F000000))) + return false; + + /*=============== Bit Defined Check ================*/ + /* We don't care [31:28] */ + + cond1 &= 0x00FF0FFF; + driver1 &= 0x00FF0FFF; + + if ((cond1 & driver1) == cond1) { + u32 bit_mask = 0; + + if ((cond1 & 0x0F) == 0) /* board_type is DONTCARE*/ + return true; + + if ((cond1 & BIT(0)) != 0) /*GLNA*/ + bit_mask |= 0x000000FF; + if ((cond1 & BIT(1)) != 0) /*GPA*/ + bit_mask |= 0x0000FF00; + if ((cond1 & BIT(2)) != 0) /*ALNA*/ + bit_mask |= 0x00FF0000; + if ((cond1 & BIT(3)) != 0) /*APA*/ + bit_mask |= 0xFF000000; + + if (((cond2 & bit_mask) == (driver2 & bit_mask)) && + ((cond4 & bit_mask) == + (driver4 & + bit_mask))) /* board_type of each RF path is matched*/ + return true; + else + return false; + } else { + return false; + } +} + +/****************************************************************************** + * mac_reg.TXT + ******************************************************************************/ + +static u32 array_mp_8822b_mac_reg[] = { + 0x029, 0x000000F9, 0x420, 0x00000080, 0x421, 0x0000000F, + 0x428, 0x0000000A, 0x429, 0x00000010, 0x430, 0x00000000, + 0x431, 0x00000000, 0x432, 0x00000000, 0x433, 0x00000001, + 0x434, 0x00000004, 0x435, 0x00000005, 0x436, 0x00000007, + 0x437, 0x00000008, 0x43C, 0x00000004, 0x43D, 0x00000005, + 0x43E, 0x00000007, 0x43F, 0x00000008, 0x440, 0x0000005D, + 0x441, 0x00000001, 0x442, 0x00000000, 0x444, 0x00000010, + 0x445, 0x000000F0, 0x446, 0x00000001, 0x447, 0x000000FE, + 0x448, 0x00000000, 0x449, 0x00000000, 0x44A, 0x00000000, + 0x44B, 0x00000040, 0x44C, 0x00000010, 0x44D, 0x000000F0, + 0x44E, 0x0000003F, 0x44F, 0x00000000, 0x450, 0x00000000, + 0x451, 0x00000000, 0x452, 0x00000000, 0x453, 0x00000040, + 0x455, 0x00000070, 0x45E, 0x00000004, 0x49C, 0x00000010, + 0x49D, 0x000000F0, 0x49E, 0x00000000, 0x49F, 0x00000006, + 0x4A0, 0x000000E0, 0x4A1, 0x00000003, 0x4A2, 0x00000000, + 0x4A3, 0x00000040, 0x4A4, 0x00000015, 0x4A5, 0x000000F0, + 0x4A6, 0x00000000, 0x4A7, 0x00000006, 0x4A8, 0x000000E0, + 0x4A9, 0x00000000, 0x4AA, 0x00000000, 0x4AB, 0x00000000, + 0x7DA, 0x00000008, 0x1448, 0x00000006, 0x144A, 0x00000006, + 0x144C, 0x00000006, 0x144E, 0x00000006, 0x4C8, 0x000000FF, + 0x4C9, 0x00000008, 0x4CA, 0x00000020, 0x4CB, 0x00000020, + 0x4CC, 0x000000FF, 0x4CD, 0x000000FF, 0x4CE, 0x00000001, + 0x4CF, 0x00000008, 0x500, 0x00000026, 0x501, 0x000000A2, + 0x502, 0x0000002F, 0x503, 0x00000000, 0x504, 0x00000028, + 0x505, 0x000000A3, 0x506, 0x0000005E, 0x507, 0x00000000, + 0x508, 0x0000002B, 0x509, 0x000000A4, 0x50A, 0x0000005E, + 0x50B, 0x00000000, 0x50C, 0x0000004F, 0x50D, 0x000000A4, + 0x50E, 0x00000000, 0x50F, 0x00000000, 0x512, 0x0000001C, + 0x514, 0x0000000A, 0x516, 0x0000000A, 0x521, 0x0000002F, + 0x525, 0x0000004F, 0x551, 0x00000010, 0x559, 0x00000002, + 0x55C, 0x00000050, 0x55D, 0x000000FF, 0x577, 0x0000000B, + 0x5BE, 0x00000064, 0x605, 0x00000030, 0x608, 0x0000000E, + 0x609, 0x00000022, 0x60C, 0x00000018, 0x6A0, 0x000000FF, + 0x6A1, 0x000000FF, 0x6A2, 0x000000FF, 0x6A3, 0x000000FF, + 0x6A4, 0x000000FF, 0x6A5, 0x000000FF, 0x6DE, 0x00000084, + 0x620, 0x000000FF, 0x621, 0x000000FF, 0x622, 0x000000FF, + 0x623, 0x000000FF, 0x624, 0x000000FF, 0x625, 0x000000FF, + 0x626, 0x000000FF, 0x627, 0x000000FF, 0x638, 0x00000050, + 0x63C, 0x0000000A, 0x63D, 0x0000000A, 0x63E, 0x0000000E, + 0x63F, 0x0000000E, 0x640, 0x00000040, 0x642, 0x00000040, + 0x643, 0x00000000, 0x652, 0x000000C8, 0x66E, 0x00000005, + 0x718, 0x00000040, 0x7D4, 0x00000098, + +}; + +void odm_read_and_config_mp_8822b_mac_reg(struct phy_dm_struct *dm) +{ + u32 i = 0; + u8 c_cond; + bool is_matched = true, is_skipped = false; + u32 array_len = sizeof(array_mp_8822b_mac_reg) / sizeof(u32); + u32 *array = array_mp_8822b_mac_reg; + + u32 v1 = 0, v2 = 0, pre_v1 = 0, pre_v2 = 0; + + ODM_RT_TRACE(dm, ODM_COMP_INIT, + "===> %s\n", __func__); + + for (; (i + 1) < array_len; i = i + 2) { + v1 = array[i]; + v2 = array[i + 1]; + + if (v1 & BIT(31)) { /* positive condition*/ + c_cond = (u8)((v1 & (BIT(29) | BIT(28))) >> 28); + if (c_cond == COND_ENDIF) { /*end*/ + is_matched = true; + is_skipped = false; + ODM_RT_TRACE(dm, ODM_COMP_INIT, "ENDIF\n"); + } else if (c_cond == COND_ELSE) { /*else*/ + is_matched = is_skipped ? false : true; + ODM_RT_TRACE(dm, ODM_COMP_INIT, "ELSE\n"); + } else { /*if , else if*/ + pre_v1 = v1; + pre_v2 = v2; + ODM_RT_TRACE(dm, ODM_COMP_INIT, + "IF or ELSE IF\n"); + } + } else if (v1 & BIT(30)) { /*negative condition*/ + if (is_skipped) { + is_matched = false; + continue; + } + + if (check_positive(dm, pre_v1, pre_v2, v1, v2)) { + is_matched = true; + is_skipped = true; + } else { + is_matched = false; + is_skipped = false; + } + } else if (is_matched) { + odm_config_mac_8822b(dm, v1, (u8)v2); + } + } +} + +u32 odm_get_version_mp_8822b_mac_reg(void) { return 67; } diff --git a/drivers/staging/rtlwifi/phydm/rtl8822b/halhwimg8822b_mac.h b/drivers/staging/rtlwifi/phydm/rtl8822b/halhwimg8822b_mac.h new file mode 100644 index 000000000000..d02fdd7a4a53 --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/rtl8822b/halhwimg8822b_mac.h @@ -0,0 +1,38 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +/*Image2HeaderVersion: 3.2*/ +#ifndef __INC_MP_MAC_HW_IMG_8822B_H +#define __INC_MP_MAC_HW_IMG_8822B_H + +/****************************************************************************** + * mac_reg.TXT + ******************************************************************************/ + +void odm_read_and_config_mp_8822b_mac_reg(/* tc: Test Chip, mp: mp Chip*/ + struct phy_dm_struct *dm); +u32 odm_get_version_mp_8822b_mac_reg(void); + +#endif diff --git a/drivers/staging/rtlwifi/phydm/rtl8822b/halhwimg8822b_rf.c b/drivers/staging/rtlwifi/phydm/rtl8822b/halhwimg8822b_rf.c new file mode 100644 index 000000000000..84cdc0644207 --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/rtl8822b/halhwimg8822b_rf.c @@ -0,0 +1,4744 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +/*Image2HeaderVersion: 3.2*/ +#include "../mp_precomp.h" +#include "../phydm_precomp.h" + +static bool check_positive(struct phy_dm_struct *dm, const u32 condition1, + const u32 condition2, const u32 condition3, + const u32 condition4) +{ + u8 _board_type = ((dm->board_type & BIT(4)) >> 4) << 0 | /* _GLNA*/ + ((dm->board_type & BIT(3)) >> 3) << 1 | /* _GPA*/ + ((dm->board_type & BIT(7)) >> 7) << 2 | /* _ALNA*/ + ((dm->board_type & BIT(6)) >> 6) << 3 | /* _APA */ + ((dm->board_type & BIT(2)) >> 2) << 4; /* _BT*/ + + u32 cond1 = condition1, cond2 = condition2, cond3 = condition3, + cond4 = condition4; + + u8 cut_version_for_para = + (dm->cut_version == ODM_CUT_A) ? 14 : dm->cut_version; + u8 pkg_type_for_para = (dm->package_type == 0) ? 14 : dm->package_type; + + u32 driver1 = cut_version_for_para << 24 | + (dm->support_interface & 0xF0) << 16 | + dm->support_platform << 16 | pkg_type_for_para << 12 | + (dm->support_interface & 0x0F) << 8 | _board_type; + + u32 driver2 = (dm->type_glna & 0xFF) << 0 | (dm->type_gpa & 0xFF) << 8 | + (dm->type_alna & 0xFF) << 16 | + (dm->type_apa & 0xFF) << 24; + + u32 driver3 = 0; + + u32 driver4 = (dm->type_glna & 0xFF00) >> 8 | (dm->type_gpa & 0xFF00) | + (dm->type_alna & 0xFF00) << 8 | + (dm->type_apa & 0xFF00) << 16; + + ODM_RT_TRACE( + dm, ODM_COMP_INIT, + "===> %s (cond1, cond2, cond3, cond4) = (0x%X 0x%X 0x%X 0x%X)\n", + __func__, cond1, cond2, cond3, cond4); + ODM_RT_TRACE( + dm, ODM_COMP_INIT, + "===> %s (driver1, driver2, driver3, driver4) = (0x%X 0x%X 0x%X 0x%X)\n", + __func__, driver1, driver2, driver3, driver4); + + ODM_RT_TRACE(dm, ODM_COMP_INIT, + " (Platform, Interface) = (0x%X, 0x%X)\n", + dm->support_platform, dm->support_interface); + ODM_RT_TRACE(dm, ODM_COMP_INIT, + " (Board, Package) = (0x%X, 0x%X)\n", + dm->board_type, dm->package_type); + + /*============== value Defined Check ===============*/ + /*QFN type [15:12] and cut version [27:24] need to do value check*/ + + if (((cond1 & 0x0000F000) != 0) && + ((cond1 & 0x0000F000) != (driver1 & 0x0000F000))) + return false; + if (((cond1 & 0x0F000000) != 0) && + ((cond1 & 0x0F000000) != (driver1 & 0x0F000000))) + return false; + + /*=============== Bit Defined Check ================*/ + /* We don't care [31:28] */ + + cond1 &= 0x00FF0FFF; + driver1 &= 0x00FF0FFF; + + if ((cond1 & driver1) == cond1) { + u32 bit_mask = 0; + + if ((cond1 & 0x0F) == 0) /* board_type is DONTCARE*/ + return true; + + if ((cond1 & BIT(0)) != 0) /*GLNA*/ + bit_mask |= 0x000000FF; + if ((cond1 & BIT(1)) != 0) /*GPA*/ + bit_mask |= 0x0000FF00; + if ((cond1 & BIT(2)) != 0) /*ALNA*/ + bit_mask |= 0x00FF0000; + if ((cond1 & BIT(3)) != 0) /*APA*/ + bit_mask |= 0xFF000000; + + if (((cond2 & bit_mask) == (driver2 & bit_mask)) && + ((cond4 & bit_mask) == + (driver4 & + bit_mask))) /* board_type of each RF path is matched*/ + return true; + else + return false; + } else { + return false; + } +} + +/****************************************************************************** + * radioa.TXT + ******************************************************************************/ + +static u32 array_mp_8822b_radioa[] = { + 0x000, 0x00030000, 0x8300100f, 0x0a0a0a0a, 0x40000000, 0x00000000, + 0x001, 0x0004002D, 0x9300100f, 0x05050505, 0x40000000, 0x00000000, + 0x001, 0x0004002D, 0x9300100f, 0x00000000, 0x40000000, 0x00000000, + 0x001, 0x0004002D, 0x9300200f, 0x00000000, 0x40000000, 0x00000000, + 0x001, 0x0004002D, 0x9000100f, 0x0a0a0a0a, 0x40000000, 0x00000000, + 0x001, 0x0004002D, 0x9000100f, 0x05050505, 0x40000000, 0x00000000, + 0x001, 0x0004002D, 0x9000100f, 0x00000000, 0x40000000, 0x00000000, + 0x001, 0x0004002D, 0x9000200f, 0x00000000, 0x40000000, 0x00000000, + 0x001, 0x0004002D, 0x9300200c, 0x00000000, 0x40000000, 0x00000000, + 0x001, 0x00040029, 0x93012100, 0x00000000, 0x40000000, 0x00000000, + 0x001, 0x00040029, 0x93002100, 0x00000000, 0x40000000, 0x00000000, + 0x001, 0x00040029, 0x9000200c, 0x00000000, 0x40000000, 0x00000000, + 0x001, 0x00040029, 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x001, 0x00040029, 0x93002000, 0x00000000, 0x40000000, 0x00000000, + 0x001, 0x00040029, 0x90002100, 0x00000000, 0x40000000, 0x00000000, + 0x001, 0x00040029, 0x90002000, 0x00000000, 0x40000000, 0x00000000, + 0x001, 0x00040029, 0xA0000000, 0x00000000, 0x001, 0x00040029, + 0xB0000000, 0x00000000, 0x018, 0x00010D24, 0x0EF, 0x00080000, + 0x033, 0x00000002, 0x03E, 0x0000003F, 0x03F, 0x000C0F4E, + 0x033, 0x00000001, 0x03E, 0x00000034, 0x03F, 0x0004080E, + 0x0EF, 0x00080000, 0x0DF, 0x00002449, 0x033, 0x00000024, + 0x03E, 0x0000003F, 0x03F, 0x00060FDE, 0x0EF, 0x00000000, + 0x0EF, 0x00080000, 0x033, 0x00000025, 0x03E, 0x00000037, + 0x03F, 0x0007EFCE, 0x0EF, 0x00000000, 0x0EF, 0x00080000, + 0x033, 0x00000026, 0x03E, 0x00000037, 0x03F, 0x000DEFCE, + 0x0EF, 0x00000000, 0x07F, 0x00000000, 0x8300100f, 0x0a0a0a0a, + 0x40000000, 0x00000000, 0x0B0, 0x000FF0F8, 0x9300100f, 0x05050505, + 0x40000000, 0x00000000, 0x0B0, 0x000FF0F8, 0x9300100f, 0x00000000, + 0x40000000, 0x00000000, 0x0B0, 0x000FF0F8, 0x9300200f, 0x00000000, + 0x40000000, 0x00000000, 0x0B0, 0x000FB0F8, 0x9000100f, 0x0a0a0a0a, + 0x40000000, 0x00000000, 0x0B0, 0x000FF0F8, 0x9000100f, 0x05050505, + 0x40000000, 0x00000000, 0x0B0, 0x000FF0F8, 0x9000100f, 0x00000000, + 0x40000000, 0x00000000, 0x0B0, 0x000FF0F8, 0x9000200f, 0x00000000, + 0x40000000, 0x00000000, 0x0B0, 0x000FB0F8, 0x9300200c, 0x00000000, + 0x40000000, 0x00000000, 0x0B0, 0x000FB0F8, 0x93012100, 0x00000000, + 0x40000000, 0x00000000, 0x0B0, 0x000FB0F8, 0x93002100, 0x00000000, + 0x40000000, 0x00000000, 0x0B0, 0x000FB0F8, 0x93011000, 0x00000000, + 0x40000000, 0x00000000, 0x0B0, 0x000FF0F8, 0x9000200c, 0x00000000, + 0x40000000, 0x00000000, 0x0B0, 0x000FB0F8, 0x90001004, 0x00000000, + 0x40000000, 0x00000000, 0x0B0, 0x000FF0F8, 0x93002000, 0x00000000, + 0x40000000, 0x00000000, 0x0B0, 0x000FB0F8, 0x93001000, 0x00000000, + 0x40000000, 0x00000000, 0x0B0, 0x000FF0F8, 0x90002100, 0x00000000, + 0x40000000, 0x00000000, 0x0B0, 0x000FB0F8, 0x90002000, 0x00000000, + 0x40000000, 0x00000000, 0x0B0, 0x000FB0F8, 0xA0000000, 0x00000000, + 0x0B0, 0x000FF0F8, 0xB0000000, 0x00000000, 0x0B1, 0x0007DBE4, + 0x0B2, 0x000225D1, 0x8300100f, 0x0a0a0a0a, 0x40000000, 0x00000000, + 0x0B3, 0x000FC760, 0x9300100f, 0x05050505, 0x40000000, 0x00000000, + 0x0B3, 0x000FC760, 0x9300100f, 0x00000000, 0x40000000, 0x00000000, + 0x0B3, 0x000FC760, 0x9300200f, 0x00000000, 0x40000000, 0x00000000, + 0x0B3, 0x000FC760, 0x9000100f, 0x0a0a0a0a, 0x40000000, 0x00000000, + 0x0B3, 0x000FC760, 0x9000100f, 0x05050505, 0x40000000, 0x00000000, + 0x0B3, 0x000FC760, 0x9000100f, 0x00000000, 0x40000000, 0x00000000, + 0x0B3, 0x000FC760, 0x9000200f, 0x00000000, 0x40000000, 0x00000000, + 0x0B3, 0x000FC760, 0x9300200c, 0x00000000, 0x40000000, 0x00000000, + 0x0B3, 0x000FC760, 0x93012100, 0x00000000, 0x40000000, 0x00000000, + 0x0B3, 0x000FC760, 0x93002100, 0x00000000, 0x40000000, 0x00000000, + 0x0B3, 0x0007C330, 0xA0000000, 0x00000000, 0x0B3, 0x000FC760, + 0xB0000000, 0x00000000, 0x0B4, 0x00099DD0, 0x0B5, 0x000400FC, + 0x0B6, 0x000187F0, 0x0B7, 0x00030018, 0x0B8, 0x00080800, + 0x0B9, 0x00000000, 0x0BA, 0x00008000, 0x0BB, 0x00000000, + 0x0BC, 0x00040030, 0x0BD, 0x00000000, 0x0BE, 0x00000000, + 0x0BF, 0x00000000, 0x0C0, 0x00000000, 0x0C1, 0x00000000, + 0x0C2, 0x00000000, 0x0C3, 0x00000000, 0x0C4, 0x00002402, + 0x0C5, 0x00000009, 0x0C6, 0x00040299, 0x0C7, 0x00055555, + 0x0C8, 0x0000C16C, 0x0C9, 0x0001C140, 0x0CA, 0x00000000, + 0x0CB, 0x00000000, 0x0CC, 0x00000000, 0x0CD, 0x00000000, + 0x0CE, 0x00090C00, 0x0CF, 0x0006D200, 0x0DF, 0x00000009, + 0x018, 0x00010524, 0x089, 0x00000207, 0x8300100f, 0x0a0a0a0a, + 0x40000000, 0x00000000, 0x08A, 0x000FF186, 0x9300100f, 0x05050505, + 0x40000000, 0x00000000, 0x08A, 0x000FE186, 0x9300100f, 0x00000000, + 0x40000000, 0x00000000, 0x08A, 0x000FF186, 0x9300200f, 0x00000000, + 0x40000000, 0x00000000, 0x08A, 0x000FF186, 0x9000100f, 0x0a0a0a0a, + 0x40000000, 0x00000000, 0x08A, 0x000FF186, 0x9000100f, 0x05050505, + 0x40000000, 0x00000000, 0x08A, 0x000FE186, 0x9000100f, 0x00000000, + 0x40000000, 0x00000000, 0x08A, 0x000FF186, 0x9000200f, 0x00000000, + 0x40000000, 0x00000000, 0x08A, 0x000FF186, 0x9300200c, 0x00000000, + 0x40000000, 0x00000000, 0x08A, 0x000FF186, 0x93012100, 0x00000000, + 0x40000000, 0x00000000, 0x08A, 0x000FF186, 0x93002100, 0x00000000, + 0x40000000, 0x00000000, 0x08A, 0x000FE186, 0xA0000000, 0x00000000, + 0x08A, 0x000FF186, 0xB0000000, 0x00000000, 0x08B, 0x00061E3C, + 0x08C, 0x000112C7, 0x08D, 0x000F4988, 0x08E, 0x00064D40, + 0x0EF, 0x00020000, 0x033, 0x00000007, 0x8300100f, 0x0a0a0a0a, + 0x40000000, 0x00000000, 0x03E, 0x00004040, 0x9300100f, 0x05050505, + 0x40000000, 0x00000000, 0x03E, 0x00004080, 0x9300100f, 0x00000000, + 0x40000000, 0x00000000, 0x03E, 0x00004040, 0x9300200f, 0x00000000, + 0x40000000, 0x00000000, 0x03E, 0x00004040, 0x9000100f, 0x0a0a0a0a, + 0x40000000, 0x00000000, 0x03E, 0x00004040, 0x9000100f, 0x05050505, + 0x40000000, 0x00000000, 0x03E, 0x00004040, 0x9000100f, 0x00000000, + 0x40000000, 0x00000000, 0x03E, 0x00004040, 0x9000200f, 0x00000000, + 0x40000000, 0x00000000, 0x03E, 0x00004040, 0x9300200c, 0x00000000, + 0x40000000, 0x00000000, 0x03E, 0x00004040, 0x93012100, 0x00000000, + 0x40000000, 0x00000000, 0x03E, 0x00004000, 0x93002100, 0x00000000, + 0x40000000, 0x00000000, 0x03E, 0x00004000, 0x93011000, 0x00000000, + 0x40000000, 0x00000000, 0x03E, 0x00004000, 0x9000200c, 0x00000000, + 0x40000000, 0x00000000, 0x03E, 0x00004040, 0x90001004, 0x00000000, + 0x40000000, 0x00000000, 0x03E, 0x00004040, 0xA0000000, 0x00000000, + 0x03E, 0x00004000, 0xB0000000, 0x00000000, 0x8300100f, 0x0a0a0a0a, + 0x40000000, 0x00000000, 0x03F, 0x000C3186, 0x9300100f, 0x05050505, + 0x40000000, 0x00000000, 0x03F, 0x000C3186, 0x9300100f, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x000C3186, 0x9300200f, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x000C3186, 0x9000100f, 0x0a0a0a0a, + 0x40000000, 0x00000000, 0x03F, 0x000C3186, 0x9000100f, 0x05050505, + 0x40000000, 0x00000000, 0x03F, 0x000C3186, 0x9000100f, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x000C3186, 0x9000200f, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x000C3186, 0x9300200c, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x000C3186, 0x93012100, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x000C3186, 0x93002100, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x000DFF86, 0x93011000, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x000C3186, 0x9000200c, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x000C3186, 0x90001004, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x000C3186, 0x93002000, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x000C0006, 0x93001000, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x000C3186, 0xA0000000, 0x00000000, + 0x03F, 0x000C3186, 0xB0000000, 0x00000000, 0x033, 0x00000006, + 0x8300100f, 0x0a0a0a0a, 0x40000000, 0x00000000, 0x03E, 0x00004080, + 0x9300100f, 0x05050505, 0x40000000, 0x00000000, 0x03E, 0x00004080, + 0x9300100f, 0x00000000, 0x40000000, 0x00000000, 0x03E, 0x00004080, + 0x9300200f, 0x00000000, 0x40000000, 0x00000000, 0x03E, 0x00004080, + 0x9000100f, 0x0a0a0a0a, 0x40000000, 0x00000000, 0x03E, 0x00004080, + 0x9000100f, 0x05050505, 0x40000000, 0x00000000, 0x03E, 0x00004040, + 0xA0000000, 0x00000000, 0x03E, 0x00004080, 0xB0000000, 0x00000000, + 0x03F, 0x000C3186, 0x033, 0x00000005, 0x8300100f, 0x0a0a0a0a, + 0x40000000, 0x00000000, 0x03E, 0x000040C8, 0x9300100f, 0x05050505, + 0x40000000, 0x00000000, 0x03E, 0x000040C8, 0x9300100f, 0x00000000, + 0x40000000, 0x00000000, 0x03E, 0x000040C8, 0x9300200f, 0x00000000, + 0x40000000, 0x00000000, 0x03E, 0x000040C8, 0x9000100f, 0x0a0a0a0a, + 0x40000000, 0x00000000, 0x03E, 0x000040C8, 0x9000100f, 0x05050505, + 0x40000000, 0x00000000, 0x03E, 0x00004084, 0xA0000000, 0x00000000, + 0x03E, 0x000040C8, 0xB0000000, 0x00000000, 0x03F, 0x000C3186, + 0x033, 0x00000004, 0x8300100f, 0x0a0a0a0a, 0x40000000, 0x00000000, + 0x03E, 0x00004190, 0x9300100f, 0x05050505, 0x40000000, 0x00000000, + 0x03E, 0x00004190, 0x9300100f, 0x00000000, 0x40000000, 0x00000000, + 0x03E, 0x00004190, 0x9300200f, 0x00000000, 0x40000000, 0x00000000, + 0x03E, 0x00004190, 0x9000100f, 0x0a0a0a0a, 0x40000000, 0x00000000, + 0x03E, 0x00004190, 0x9000100f, 0x05050505, 0x40000000, 0x00000000, + 0x03E, 0x00004108, 0xA0000000, 0x00000000, 0x03E, 0x00004190, + 0xB0000000, 0x00000000, 0x03F, 0x000C3186, 0x033, 0x00000003, + 0x8300100f, 0x0a0a0a0a, 0x40000000, 0x00000000, 0x03E, 0x00004998, + 0x9300100f, 0x05050505, 0x40000000, 0x00000000, 0x03E, 0x00004998, + 0x9300100f, 0x00000000, 0x40000000, 0x00000000, 0x03E, 0x00004998, + 0x9300200f, 0x00000000, 0x40000000, 0x00000000, 0x03E, 0x00004998, + 0x9000100f, 0x0a0a0a0a, 0x40000000, 0x00000000, 0x03E, 0x00004998, + 0x9000100f, 0x05050505, 0x40000000, 0x00000000, 0x03E, 0x0000490C, + 0xA0000000, 0x00000000, 0x03E, 0x00004998, 0xB0000000, 0x00000000, + 0x03F, 0x000C3186, 0x033, 0x00000002, 0x8300100f, 0x0a0a0a0a, + 0x40000000, 0x00000000, 0x03E, 0x00005840, 0x9300100f, 0x05050505, + 0x40000000, 0x00000000, 0x03E, 0x00005840, 0x9300100f, 0x00000000, + 0x40000000, 0x00000000, 0x03E, 0x00005840, 0x9300200f, 0x00000000, + 0x40000000, 0x00000000, 0x03E, 0x00005840, 0x9000100f, 0x0a0a0a0a, + 0x40000000, 0x00000000, 0x03E, 0x00005840, 0x9000100f, 0x05050505, + 0x40000000, 0x00000000, 0x03E, 0x00005E00, 0xA0000000, 0x00000000, + 0x03E, 0x00005840, 0xB0000000, 0x00000000, 0x03F, 0x000C3186, + 0x033, 0x00000001, 0x8300100f, 0x0a0a0a0a, 0x40000000, 0x00000000, + 0x03E, 0x000058C2, 0x9300100f, 0x05050505, 0x40000000, 0x00000000, + 0x03E, 0x000058C2, 0x9300100f, 0x00000000, 0x40000000, 0x00000000, + 0x03E, 0x000058C2, 0x9300200f, 0x00000000, 0x40000000, 0x00000000, + 0x03E, 0x000058C2, 0x9000100f, 0x0a0a0a0a, 0x40000000, 0x00000000, + 0x03E, 0x000058C2, 0x9000100f, 0x05050505, 0x40000000, 0x00000000, + 0x03E, 0x00005862, 0xA0000000, 0x00000000, 0x03E, 0x000058C2, + 0xB0000000, 0x00000000, 0x03F, 0x000C3186, 0x033, 0x00000000, + 0x8300100f, 0x0a0a0a0a, 0x40000000, 0x00000000, 0x03E, 0x00005930, + 0x9300100f, 0x05050505, 0x40000000, 0x00000000, 0x03E, 0x00005930, + 0x9300100f, 0x00000000, 0x40000000, 0x00000000, 0x03E, 0x00005930, + 0x9300200f, 0x00000000, 0x40000000, 0x00000000, 0x03E, 0x00005930, + 0x9000100f, 0x0a0a0a0a, 0x40000000, 0x00000000, 0x03E, 0x00005930, + 0x9000100f, 0x05050505, 0x40000000, 0x00000000, 0x03E, 0x00005948, + 0xA0000000, 0x00000000, 0x03E, 0x00005930, 0xB0000000, 0x00000000, + 0x03F, 0x000C3186, 0x033, 0x0000000F, 0x8300100f, 0x0a0a0a0a, + 0x40000000, 0x00000000, 0x03E, 0x00004040, 0x9300100f, 0x05050505, + 0x40000000, 0x00000000, 0x03E, 0x00004080, 0x9300100f, 0x00000000, + 0x40000000, 0x00000000, 0x03E, 0x00004040, 0x9300200f, 0x00000000, + 0x40000000, 0x00000000, 0x03E, 0x00004040, 0x9000100f, 0x0a0a0a0a, + 0x40000000, 0x00000000, 0x03E, 0x00004040, 0x9000100f, 0x05050505, + 0x40000000, 0x00000000, 0x03E, 0x00004080, 0x9000100f, 0x00000000, + 0x40000000, 0x00000000, 0x03E, 0x00004040, 0x9000200f, 0x00000000, + 0x40000000, 0x00000000, 0x03E, 0x00004040, 0x9300200c, 0x00000000, + 0x40000000, 0x00000000, 0x03E, 0x00004040, 0x93012100, 0x00000000, + 0x40000000, 0x00000000, 0x03E, 0x00004000, 0x93002100, 0x00000000, + 0x40000000, 0x00000000, 0x03E, 0x00004000, 0x93011000, 0x00000000, + 0x40000000, 0x00000000, 0x03E, 0x00004000, 0x9000200c, 0x00000000, + 0x40000000, 0x00000000, 0x03E, 0x00004040, 0x90001004, 0x00000000, + 0x40000000, 0x00000000, 0x03E, 0x00004040, 0xA0000000, 0x00000000, + 0x03E, 0x00004000, 0xB0000000, 0x00000000, 0x8300100f, 0x0a0a0a0a, + 0x40000000, 0x00000000, 0x03F, 0x000C3186, 0x9300100f, 0x05050505, + 0x40000000, 0x00000000, 0x03F, 0x000C3186, 0x9300100f, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x000C3186, 0x9300200f, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x000C3186, 0x9000100f, 0x0a0a0a0a, + 0x40000000, 0x00000000, 0x03F, 0x000C3186, 0x9000100f, 0x05050505, + 0x40000000, 0x00000000, 0x03F, 0x000C3186, 0x9000100f, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x000C3186, 0x9000200f, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x000C3186, 0x9300200c, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x000C3186, 0x93012100, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x000DFF86, 0x93002100, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x000DFF86, 0x93011000, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x000C3186, 0x9000200c, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x000C3186, 0x90001004, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x000C3186, 0x93002000, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x000C0006, 0x93001000, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x000C3186, 0xA0000000, 0x00000000, + 0x03F, 0x000C3186, 0xB0000000, 0x00000000, 0x033, 0x0000000E, + 0x03E, 0x00004080, 0x03F, 0x000C3186, 0x033, 0x0000000D, + 0x03E, 0x000040C8, 0x03F, 0x000C3186, 0x033, 0x0000000C, + 0x03E, 0x00004190, 0x03F, 0x000C3186, 0x033, 0x0000000B, + 0x03E, 0x00004998, 0x03F, 0x000C3186, 0x033, 0x0000000A, + 0x03E, 0x00005840, 0x03F, 0x000C3186, 0x033, 0x00000009, + 0x03E, 0x000058C2, 0x03F, 0x000C3186, 0x033, 0x00000008, + 0x03E, 0x00005930, 0x03F, 0x000C3186, 0x033, 0x00000017, + 0x8300100f, 0x0a0a0a0a, 0x40000000, 0x00000000, 0x03E, 0x00004040, + 0x9300100f, 0x05050505, 0x40000000, 0x00000000, 0x03E, 0x00004080, + 0x9300100f, 0x00000000, 0x40000000, 0x00000000, 0x03E, 0x00004040, + 0x9300200f, 0x00000000, 0x40000000, 0x00000000, 0x03E, 0x00004040, + 0x9000100f, 0x0a0a0a0a, 0x40000000, 0x00000000, 0x03E, 0x00004040, + 0x9000100f, 0x05050505, 0x40000000, 0x00000000, 0x03E, 0x00004080, + 0x9000100f, 0x00000000, 0x40000000, 0x00000000, 0x03E, 0x00004040, + 0x9000200f, 0x00000000, 0x40000000, 0x00000000, 0x03E, 0x00004040, + 0x9300200c, 0x00000000, 0x40000000, 0x00000000, 0x03E, 0x00004040, + 0x93012100, 0x00000000, 0x40000000, 0x00000000, 0x03E, 0x00004000, + 0x93002100, 0x00000000, 0x40000000, 0x00000000, 0x03E, 0x00004000, + 0x93011000, 0x00000000, 0x40000000, 0x00000000, 0x03E, 0x00004000, + 0x9000200c, 0x00000000, 0x40000000, 0x00000000, 0x03E, 0x00004040, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, 0x03E, 0x00004040, + 0xA0000000, 0x00000000, 0x03E, 0x00004000, 0xB0000000, 0x00000000, + 0x8300100f, 0x0a0a0a0a, 0x40000000, 0x00000000, 0x03F, 0x000C3186, + 0x9300100f, 0x05050505, 0x40000000, 0x00000000, 0x03F, 0x000C3186, + 0x9300100f, 0x00000000, 0x40000000, 0x00000000, 0x03F, 0x000C3186, + 0x9300200f, 0x00000000, 0x40000000, 0x00000000, 0x03F, 0x000C3186, + 0x9000100f, 0x0a0a0a0a, 0x40000000, 0x00000000, 0x03F, 0x000C3186, + 0x9000100f, 0x05050505, 0x40000000, 0x00000000, 0x03F, 0x000C3186, + 0x9000100f, 0x00000000, 0x40000000, 0x00000000, 0x03F, 0x000C3186, + 0x9000200f, 0x00000000, 0x40000000, 0x00000000, 0x03F, 0x000C3186, + 0x9300200c, 0x00000000, 0x40000000, 0x00000000, 0x03F, 0x000C3186, + 0x93012100, 0x00000000, 0x40000000, 0x00000000, 0x03F, 0x000C3186, + 0x93002100, 0x00000000, 0x40000000, 0x00000000, 0x03F, 0x000C3186, + 0x93011000, 0x00000000, 0x40000000, 0x00000000, 0x03F, 0x000C3186, + 0x9000200c, 0x00000000, 0x40000000, 0x00000000, 0x03F, 0x000C3186, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, 0x03F, 0x000C3186, + 0x93002000, 0x00000000, 0x40000000, 0x00000000, 0x03F, 0x000C0006, + 0x93001000, 0x00000000, 0x40000000, 0x00000000, 0x03F, 0x000C3186, + 0xA0000000, 0x00000000, 0x03F, 0x000C3186, 0xB0000000, 0x00000000, + 0x033, 0x00000016, 0x03E, 0x00004080, 0x03F, 0x000C3186, + 0x033, 0x00000015, 0x03E, 0x000040C8, 0x03F, 0x000C3186, + 0x033, 0x00000014, 0x03E, 0x00004190, 0x03F, 0x000C3186, + 0x033, 0x00000013, 0x03E, 0x00004998, 0x03F, 0x000C3186, + 0x033, 0x00000012, 0x03E, 0x00005840, 0x03F, 0x000C3186, + 0x033, 0x00000011, 0x03E, 0x000058C2, 0x03F, 0x000C3186, + 0x033, 0x00000010, 0x03E, 0x00005930, 0x03F, 0x000C3186, + 0x0EF, 0x00000000, 0x0EF, 0x00004000, 0x033, 0x00000000, + 0x03F, 0x0000000A, 0x033, 0x00000001, 0x8300100f, 0x0a0a0a0a, + 0x40000000, 0x00000000, 0x03F, 0x00000000, 0x9300100f, 0x05050505, + 0x40000000, 0x00000000, 0x03F, 0x00000000, 0x9300100f, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x00000000, 0x9300200f, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x00000000, 0x9000100f, 0x0a0a0a0a, + 0x40000000, 0x00000000, 0x03F, 0x00000000, 0x9000100f, 0x05050505, + 0x40000000, 0x00000000, 0x03F, 0x00000000, 0x9000100f, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x00000000, 0x9000200f, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x00000000, 0x9300200c, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x00000000, 0x93012100, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x00000005, 0x93002100, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x00000006, 0x93011000, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x00000005, 0x9000200c, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x00000000, 0x90001004, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x00000000, 0x93002000, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x00000000, 0x93001000, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x00000005, 0x90002100, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x00000000, 0x90002000, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x00000000, 0xA0000000, 0x00000000, + 0x03F, 0x00000005, 0xB0000000, 0x00000000, 0x033, 0x00000002, + 0x03F, 0x00000000, 0x0EF, 0x00000000, 0x018, 0x00000401, + 0x084, 0x00001209, 0x086, 0x000001A0, 0x8300100f, 0x0a0a0a0a, + 0x40000000, 0x00000000, 0x087, 0x00068080, 0x9300100f, 0x05050505, + 0x40000000, 0x00000000, 0x087, 0x00068080, 0x9300100f, 0x00000000, + 0x40000000, 0x00000000, 0x087, 0x00068080, 0x9300200f, 0x00000000, + 0x40000000, 0x00000000, 0x087, 0x00068080, 0x9000100f, 0x0a0a0a0a, + 0x40000000, 0x00000000, 0x087, 0x00068080, 0x9000100f, 0x05050505, + 0x40000000, 0x00000000, 0x087, 0x00068080, 0x9000100f, 0x00000000, + 0x40000000, 0x00000000, 0x087, 0x00068080, 0x9000200f, 0x00000000, + 0x40000000, 0x00000000, 0x087, 0x00068080, 0xA0000000, 0x00000000, + 0x087, 0x000E8180, 0xB0000000, 0x00000000, 0x088, 0x00070020, + 0x0DE, 0x00000010, 0x0EF, 0x00008000, 0x033, 0x0000000F, + 0x03F, 0x0000003C, 0x033, 0x0000000E, 0x03F, 0x00000038, + 0x033, 0x0000000D, 0x03F, 0x00000030, 0x033, 0x0000000C, + 0x03F, 0x00000028, 0x033, 0x0000000B, 0x03F, 0x00000020, + 0x033, 0x0000000A, 0x03F, 0x00000018, 0x033, 0x00000009, + 0x03F, 0x00000010, 0x033, 0x00000008, 0x03F, 0x00000008, + 0x033, 0x00000007, 0x03F, 0x0000003C, 0x033, 0x00000006, + 0x03F, 0x00000038, 0x033, 0x00000005, 0x03F, 0x00000030, + 0x033, 0x00000004, 0x03F, 0x00000028, 0x033, 0x00000003, + 0x03F, 0x00000020, 0x033, 0x00000002, 0x03F, 0x00000018, + 0x033, 0x00000001, 0x03F, 0x00000010, 0x033, 0x00000000, + 0x03F, 0x00000008, 0x0EF, 0x00000000, 0x0B8, 0x00080A00, + 0x0B0, 0x000FF0FA, 0x0FE, 0x00000000, 0x0CA, 0x00080000, + 0x0C9, 0x0001C141, 0x0FE, 0x00000000, 0x0B0, 0x000FF0F8, + 0x018, 0x00018D24, 0xFFE, 0x00000000, 0xFFE, 0x00000000, + 0xFFE, 0x00000000, 0xFFE, 0x00000000, 0x018, 0x00010D24, + 0x01B, 0x00075A40, 0x0EE, 0x00000002, 0x033, 0x00000000, + 0x03F, 0x00000004, 0x033, 0x00000001, 0x03F, 0x00000004, + 0x033, 0x00000002, 0x03F, 0x00000004, 0x033, 0x00000003, + 0x03F, 0x00000004, 0x033, 0x00000004, 0x03F, 0x00000004, + 0x033, 0x00000005, 0x03F, 0x00000006, 0x033, 0x00000006, + 0x03F, 0x00000002, 0x033, 0x00000007, 0x03F, 0x00000000, + 0x0EE, 0x00000000, 0x8300100f, 0x0a0a0a0a, 0x40000000, 0x00000000, + 0x061, 0x0005D4A0, 0x062, 0x0000D203, 0x063, 0x00000062, + 0x9300100f, 0x05050505, 0x40000000, 0x00000000, 0x061, 0x0005D4A0, + 0x062, 0x0000D203, 0x063, 0x00000062, 0x9300100f, 0x00000000, + 0x40000000, 0x00000000, 0x061, 0x0005D4A0, 0x062, 0x0000D203, + 0x063, 0x00000062, 0x9300200f, 0x00000000, 0x40000000, 0x00000000, + 0x061, 0x0005D2A1, 0x062, 0x0000D3A2, 0x063, 0x00000062, + 0x9000100f, 0x0a0a0a0a, 0x40000000, 0x00000000, 0x061, 0x0005D4A0, + 0x062, 0x0000D203, 0x063, 0x00000062, 0x9000100f, 0x05050505, + 0x40000000, 0x00000000, 0x061, 0x0005D4A0, 0x062, 0x0000D203, + 0x063, 0x00000062, 0x9000100f, 0x00000000, 0x40000000, 0x00000000, + 0x061, 0x0005D4A0, 0x062, 0x0000D203, 0x063, 0x00000062, + 0x9000200f, 0x00000000, 0x40000000, 0x00000000, 0x061, 0x0005D2A1, + 0x062, 0x0000D3A2, 0x063, 0x00000062, 0x9300200c, 0x00000000, + 0x40000000, 0x00000000, 0x061, 0x0005D2A1, 0x062, 0x0000D3A2, + 0x063, 0x00000062, 0x93012100, 0x00000000, 0x40000000, 0x00000000, + 0x061, 0x0005D301, 0x062, 0x0000D303, 0x063, 0x00000002, + 0x93002100, 0x00000000, 0x40000000, 0x00000000, 0x061, 0x0005D301, + 0x062, 0x0000D303, 0x063, 0x00000002, 0x93011000, 0x00000000, + 0x40000000, 0x00000000, 0x061, 0x0005D3D1, 0x062, 0x0000D3A2, + 0x063, 0x00000002, 0x9000200c, 0x00000000, 0x40000000, 0x00000000, + 0x061, 0x0005D2A1, 0x062, 0x0000D3A2, 0x063, 0x00000062, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, 0x061, 0x0005D3D1, + 0x062, 0x0000D3A2, 0x063, 0x00000002, 0x93002000, 0x00000000, + 0x40000000, 0x00000000, 0x061, 0x0005D301, 0x062, 0x0000D303, + 0x063, 0x00000002, 0x93001000, 0x00000000, 0x40000000, 0x00000000, + 0x061, 0x0005D3D1, 0x062, 0x0000D3A2, 0x063, 0x00000002, + 0x90002100, 0x00000000, 0x40000000, 0x00000000, 0x061, 0x0005D301, + 0x062, 0x0000D303, 0x063, 0x00000002, 0x90002000, 0x00000000, + 0x40000000, 0x00000000, 0x061, 0x0005D301, 0x062, 0x0000D303, + 0x063, 0x00000002, 0xA0000000, 0x00000000, 0x061, 0x0005D3D0, + 0x062, 0x0000D303, 0x063, 0x00000002, 0xB0000000, 0x00000000, + 0x8300100f, 0x0a0a0a0a, 0x40000000, 0x00000000, 0x0EF, 0x00000200, + 0x030, 0x000004A3, 0x030, 0x000014A3, 0x030, 0x000024A3, + 0x030, 0x000034A3, 0x030, 0x000044A3, 0x030, 0x000054A3, + 0x030, 0x000064A3, 0x030, 0x000074A3, 0x030, 0x000084A3, + 0x030, 0x000094A3, 0x030, 0x0000A4A3, 0x030, 0x0000B4A3, + 0x0EF, 0x00000000, 0x9300100f, 0x05050505, 0x40000000, 0x00000000, + 0x0EF, 0x00000200, 0x030, 0x000004A3, 0x030, 0x000014A3, + 0x030, 0x000024A3, 0x030, 0x000034A3, 0x030, 0x000044A3, + 0x030, 0x000054A3, 0x030, 0x000064A3, 0x030, 0x000074A3, + 0x030, 0x000084A3, 0x030, 0x000094A3, 0x030, 0x0000A4A3, + 0x030, 0x0000B4A3, 0x0EF, 0x00000000, 0x9300100f, 0x00000000, + 0x40000000, 0x00000000, 0x0EF, 0x00000200, 0x030, 0x000004A3, + 0x030, 0x000014A3, 0x030, 0x000024A3, 0x030, 0x000034A3, + 0x030, 0x000044A3, 0x030, 0x000054A3, 0x030, 0x000064A3, + 0x030, 0x000074A3, 0x030, 0x000084A3, 0x030, 0x000094A3, + 0x030, 0x0000A4A3, 0x030, 0x0000B4A3, 0x0EF, 0x00000000, + 0x9300200f, 0x00000000, 0x40000000, 0x00000000, 0x0EF, 0x00000200, + 0x030, 0x000002A6, 0x030, 0x000012A6, 0x030, 0x000022A6, + 0x030, 0x000032A6, 0x030, 0x000042A6, 0x030, 0x000052A6, + 0x030, 0x000062A6, 0x030, 0x000072A6, 0x030, 0x000082A6, + 0x030, 0x000092A6, 0x030, 0x0000A2A6, 0x030, 0x0000B2A6, + 0x0EF, 0x00000000, 0x9000100f, 0x0a0a0a0a, 0x40000000, 0x00000000, + 0x0EF, 0x00000200, 0x030, 0x000004A0, 0x030, 0x000014A0, + 0x030, 0x000024A0, 0x030, 0x000034A0, 0x030, 0x000044A0, + 0x030, 0x000054A0, 0x030, 0x000064A0, 0x030, 0x000074A0, + 0x030, 0x000084A0, 0x030, 0x000094A0, 0x030, 0x0000A4A0, + 0x030, 0x0000B4A0, 0x0EF, 0x00000000, 0x9000100f, 0x05050505, + 0x40000000, 0x00000000, 0x0EF, 0x00000200, 0x030, 0x000004A0, + 0x030, 0x000014A0, 0x030, 0x000024A0, 0x030, 0x000034A0, + 0x030, 0x000044A0, 0x030, 0x000054A0, 0x030, 0x000064A0, + 0x030, 0x000074A0, 0x030, 0x000084A0, 0x030, 0x000094A0, + 0x030, 0x0000A4A0, 0x030, 0x0000B4A0, 0x0EF, 0x00000000, + 0x9000100f, 0x00000000, 0x40000000, 0x00000000, 0x0EF, 0x00000200, + 0x030, 0x000004A0, 0x030, 0x000014A0, 0x030, 0x000024A0, + 0x030, 0x000034A0, 0x030, 0x000044A0, 0x030, 0x000054A0, + 0x030, 0x000064A0, 0x030, 0x000074A0, 0x030, 0x000084A0, + 0x030, 0x000094A0, 0x030, 0x0000A4A0, 0x030, 0x0000B4A0, + 0x0EF, 0x00000000, 0x9000200f, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00000200, 0x030, 0x000002A1, 0x030, 0x000012A1, + 0x030, 0x000022A1, 0x030, 0x000032A1, 0x030, 0x000042A1, + 0x030, 0x000052A1, 0x030, 0x000062A1, 0x030, 0x000072A1, + 0x030, 0x000082A1, 0x030, 0x000092A1, 0x030, 0x0000A2A1, + 0x030, 0x0000B2A1, 0x0EF, 0x00000000, 0x9300200c, 0x00000000, + 0x40000000, 0x00000000, 0x0EF, 0x00000200, 0x030, 0x000002A6, + 0x030, 0x000012A6, 0x030, 0x000022A6, 0x030, 0x000032A6, + 0x030, 0x000042A6, 0x030, 0x000052A6, 0x030, 0x000062A6, + 0x030, 0x000072A6, 0x030, 0x000082A6, 0x030, 0x000092A6, + 0x030, 0x0000A2A6, 0x030, 0x0000B2A6, 0x0EF, 0x00000000, + 0x93012100, 0x00000000, 0x40000000, 0x00000000, 0x0EF, 0x00000200, + 0x030, 0x00000384, 0x030, 0x00001384, 0x030, 0x00002384, + 0x030, 0x00003384, 0x030, 0x00004425, 0x030, 0x00005425, + 0x030, 0x00006425, 0x030, 0x00007425, 0x030, 0x000083A4, + 0x030, 0x000093A4, 0x030, 0x0000A3A4, 0x030, 0x0000B3A4, + 0x0EF, 0x00000000, 0x93002100, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00000200, 0x030, 0x000003A3, 0x030, 0x000013A3, + 0x030, 0x000023A3, 0x030, 0x000033A3, 0x030, 0x00004355, + 0x030, 0x00005355, 0x030, 0x00006355, 0x030, 0x00007355, + 0x030, 0x00008314, 0x030, 0x00009314, 0x030, 0x0000A314, + 0x030, 0x0000B314, 0x0EF, 0x00000000, 0x93011000, 0x00000000, + 0x40000000, 0x00000000, 0x0EF, 0x00000200, 0x030, 0x000003A1, + 0x030, 0x000013A1, 0x030, 0x000023A1, 0x030, 0x000033A1, + 0x030, 0x000043A3, 0x030, 0x000053A3, 0x030, 0x000063A3, + 0x030, 0x000073A3, 0x030, 0x000083A5, 0x030, 0x000093A5, + 0x030, 0x0000A3A5, 0x030, 0x0000B3A5, 0x0EF, 0x00000000, + 0x9000200c, 0x00000000, 0x40000000, 0x00000000, 0x0EF, 0x00000200, + 0x030, 0x000002A1, 0x030, 0x000012A1, 0x030, 0x000022A1, + 0x030, 0x000032A1, 0x030, 0x000042A1, 0x030, 0x000052A1, + 0x030, 0x000062A1, 0x030, 0x000072A1, 0x030, 0x000082A1, + 0x030, 0x000092A1, 0x030, 0x0000A2A1, 0x030, 0x0000B2A1, + 0x0EF, 0x00000000, 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00000200, 0x030, 0x00000463, 0x030, 0x00001463, + 0x030, 0x00002463, 0x030, 0x00003463, 0x030, 0x00004545, + 0x030, 0x00005545, 0x030, 0x00006545, 0x030, 0x00007545, + 0x030, 0x00008565, 0x030, 0x00009565, 0x030, 0x0000A565, + 0x030, 0x0000B565, 0x0EF, 0x00000000, 0x93002000, 0x00000000, + 0x40000000, 0x00000000, 0x0EF, 0x00000200, 0x030, 0x00000303, + 0x030, 0x00001303, 0x030, 0x00002303, 0x030, 0x00003303, + 0x030, 0x000043A4, 0x030, 0x000053A4, 0x030, 0x000063A4, + 0x030, 0x000073A4, 0x030, 0x00008365, 0x030, 0x00009365, + 0x030, 0x0000A365, 0x030, 0x0000B365, 0x0EF, 0x00000000, + 0x93001000, 0x00000000, 0x40000000, 0x00000000, 0x0EF, 0x00000200, + 0x030, 0x000003A2, 0x030, 0x000013A2, 0x030, 0x000023A2, + 0x030, 0x000033A2, 0x030, 0x00004343, 0x030, 0x00005343, + 0x030, 0x00006343, 0x030, 0x00007343, 0x030, 0x00008364, + 0x030, 0x00009364, 0x030, 0x0000A364, 0x030, 0x0000B364, + 0x0EF, 0x00000000, 0x90002100, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00000200, 0x030, 0x000003A0, 0x030, 0x000013A0, + 0x030, 0x000023A0, 0x030, 0x000033A0, 0x030, 0x00004430, + 0x030, 0x00005430, 0x030, 0x00006430, 0x030, 0x00007430, + 0x030, 0x00008372, 0x030, 0x00009372, 0x030, 0x0000A372, + 0x030, 0x0000B372, 0x0EF, 0x00000000, 0x90002000, 0x00000000, + 0x40000000, 0x00000000, 0x0EF, 0x00000200, 0x030, 0x000003A0, + 0x030, 0x000013A0, 0x030, 0x000023A0, 0x030, 0x000033A0, + 0x030, 0x000043A1, 0x030, 0x000053A1, 0x030, 0x000063A1, + 0x030, 0x000073A1, 0x030, 0x000083A2, 0x030, 0x000093A2, + 0x030, 0x0000A3A2, 0x030, 0x0000B3A2, 0x0EF, 0x00000000, + 0xA0000000, 0x00000000, 0x0EF, 0x00000200, 0x030, 0x000003D0, + 0x030, 0x000013D0, 0x030, 0x000023D0, 0x030, 0x000033D0, + 0x030, 0x000043D0, 0x030, 0x000053D0, 0x030, 0x000063D0, + 0x030, 0x000073D0, 0x030, 0x000083D0, 0x030, 0x000093D0, + 0x030, 0x0000A3D0, 0x030, 0x0000B3D0, 0x0EF, 0x00000000, + 0xB0000000, 0x00000000, 0x8300100f, 0x0a0a0a0a, 0x40000000, 0x00000000, + 0x0EF, 0x00000080, 0x030, 0x00000203, 0x030, 0x00001203, + 0x030, 0x00002203, 0x030, 0x00003203, 0x030, 0x00004203, + 0x030, 0x00005203, 0x030, 0x00006203, 0x030, 0x00007203, + 0x030, 0x00008203, 0x030, 0x00009203, 0x030, 0x0000A203, + 0x030, 0x0000B203, 0x9300100f, 0x05050505, 0x40000000, 0x00000000, + 0x0EF, 0x00000080, 0x030, 0x00000203, 0x030, 0x00001203, + 0x030, 0x00002203, 0x030, 0x00003203, 0x030, 0x00004203, + 0x030, 0x00005203, 0x030, 0x00006203, 0x030, 0x00007203, + 0x030, 0x00008203, 0x030, 0x00009203, 0x030, 0x0000A203, + 0x030, 0x0000B203, 0x9300100f, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00000080, 0x030, 0x00000203, 0x030, 0x00001203, + 0x030, 0x00002203, 0x030, 0x00003203, 0x030, 0x00004203, + 0x030, 0x00005203, 0x030, 0x00006203, 0x030, 0x00007203, + 0x030, 0x00008203, 0x030, 0x00009203, 0x030, 0x0000A203, + 0x030, 0x0000B203, 0x9300200f, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00000080, 0x030, 0x000003A2, 0x030, 0x000013A2, + 0x030, 0x000023A2, 0x030, 0x000033A2, 0x030, 0x000043A2, + 0x030, 0x000053A2, 0x030, 0x000063A2, 0x030, 0x000073A2, + 0x030, 0x000083A2, 0x030, 0x000093A2, 0x030, 0x0000A3A2, + 0x030, 0x0000B3A2, 0x9000100f, 0x0a0a0a0a, 0x40000000, 0x00000000, + 0x0EF, 0x00000080, 0x030, 0x00000203, 0x030, 0x00001203, + 0x030, 0x00002203, 0x030, 0x00003203, 0x030, 0x00004203, + 0x030, 0x00005203, 0x030, 0x00006203, 0x030, 0x00007203, + 0x030, 0x00008203, 0x030, 0x00009203, 0x030, 0x0000A203, + 0x030, 0x0000B203, 0x9000100f, 0x05050505, 0x40000000, 0x00000000, + 0x0EF, 0x00000080, 0x030, 0x00000203, 0x030, 0x00001203, + 0x030, 0x00002203, 0x030, 0x00003203, 0x030, 0x00004203, + 0x030, 0x00005203, 0x030, 0x00006203, 0x030, 0x00007203, + 0x030, 0x00008203, 0x030, 0x00009203, 0x030, 0x0000A203, + 0x030, 0x0000B203, 0x9000100f, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00000080, 0x030, 0x00000203, 0x030, 0x00001203, + 0x030, 0x00002203, 0x030, 0x00003203, 0x030, 0x00004203, + 0x030, 0x00005203, 0x030, 0x00006203, 0x030, 0x00007203, + 0x030, 0x00008203, 0x030, 0x00009203, 0x030, 0x0000A203, + 0x030, 0x0000B203, 0x9000200f, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00000080, 0x030, 0x000003A2, 0x030, 0x000013A2, + 0x030, 0x000023A2, 0x030, 0x000033A2, 0x030, 0x000043A2, + 0x030, 0x000053A2, 0x030, 0x000063A2, 0x030, 0x000073A2, + 0x030, 0x000083A2, 0x030, 0x000093A2, 0x030, 0x0000A3A2, + 0x030, 0x0000B3A2, 0x9300200c, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00000080, 0x030, 0x000003A2, 0x030, 0x000013A2, + 0x030, 0x000023A2, 0x030, 0x000033A2, 0x030, 0x000043A2, + 0x030, 0x000053A2, 0x030, 0x000063A2, 0x030, 0x000073A2, + 0x030, 0x000083A2, 0x030, 0x000093A2, 0x030, 0x0000A3A2, + 0x030, 0x0000B3A2, 0x93012100, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00000080, 0x030, 0x000003A3, 0x030, 0x000013A3, + 0x030, 0x000023A3, 0x030, 0x000033A3, 0x030, 0x000043A3, + 0x030, 0x000053A3, 0x030, 0x000063A3, 0x030, 0x000073A3, + 0x030, 0x000083A3, 0x030, 0x000093A3, 0x030, 0x0000A3A3, + 0x030, 0x0000B3A3, 0x93002100, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00000080, 0x030, 0x000003A2, 0x030, 0x000013A2, + 0x030, 0x000023A2, 0x030, 0x000033A2, 0x030, 0x000043A2, + 0x030, 0x000053A2, 0x030, 0x000063A2, 0x030, 0x000073A2, + 0x030, 0x000083A2, 0x030, 0x000093A2, 0x030, 0x0000A3A2, + 0x030, 0x0000B3A2, 0x93011000, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00000080, 0x030, 0x000003A2, 0x030, 0x000013A2, + 0x030, 0x000023A2, 0x030, 0x000033A2, 0x030, 0x000043A2, + 0x030, 0x000053A2, 0x030, 0x000063A2, 0x030, 0x000073A2, + 0x030, 0x000083A2, 0x030, 0x000093A2, 0x030, 0x0000A3A2, + 0x030, 0x0000B3A2, 0x9000200c, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00000080, 0x030, 0x000003A2, 0x030, 0x000013A2, + 0x030, 0x000023A2, 0x030, 0x000033A2, 0x030, 0x000043A2, + 0x030, 0x000053A2, 0x030, 0x000063A2, 0x030, 0x000073A2, + 0x030, 0x000083A2, 0x030, 0x000093A2, 0x030, 0x0000A3A2, + 0x030, 0x0000B3A2, 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00000080, 0x030, 0x000003A2, 0x030, 0x000013A2, + 0x030, 0x000023A2, 0x030, 0x000033A2, 0x030, 0x000043A2, + 0x030, 0x000053A2, 0x030, 0x000063A2, 0x030, 0x000073A2, + 0x030, 0x000083A2, 0x030, 0x000093A2, 0x030, 0x0000A3A2, + 0x030, 0x0000B3A2, 0x93002000, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00000080, 0x030, 0x000003A2, 0x030, 0x000013A2, + 0x030, 0x000023A2, 0x030, 0x000033A2, 0x030, 0x000043A2, + 0x030, 0x000053A2, 0x030, 0x000063A2, 0x030, 0x000073A2, + 0x030, 0x000083A2, 0x030, 0x000093A2, 0x030, 0x0000A3A2, + 0x030, 0x0000B3A2, 0x93001000, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00000080, 0x030, 0x000003A2, 0x030, 0x000013A2, + 0x030, 0x000023A2, 0x030, 0x000033A2, 0x030, 0x000043A2, + 0x030, 0x000053A2, 0x030, 0x000063A2, 0x030, 0x000073A2, + 0x030, 0x000083A2, 0x030, 0x000093A2, 0x030, 0x0000A3A2, + 0x030, 0x0000B3A2, 0x90002100, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00000080, 0x030, 0x000003A2, 0x030, 0x000013A2, + 0x030, 0x000023A2, 0x030, 0x000033A2, 0x030, 0x000043A2, + 0x030, 0x000053A2, 0x030, 0x000063A2, 0x030, 0x000073A2, + 0x030, 0x000083A2, 0x030, 0x000093A2, 0x030, 0x0000A3A2, + 0x030, 0x0000B3A2, 0x90002000, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00000080, 0x030, 0x000003A2, 0x030, 0x000013A2, + 0x030, 0x000023A2, 0x030, 0x000033A2, 0x030, 0x000043A2, + 0x030, 0x000053A2, 0x030, 0x000063A2, 0x030, 0x000073A2, + 0x030, 0x000083A2, 0x030, 0x000093A2, 0x030, 0x0000A3A2, + 0x030, 0x0000B3A2, 0xA0000000, 0x00000000, 0x0EF, 0x00000080, + 0x030, 0x000003A2, 0x030, 0x000013A2, 0x030, 0x000023A2, + 0x030, 0x000033A2, 0x030, 0x000043A2, 0x030, 0x000053A2, + 0x030, 0x000063A2, 0x030, 0x000073A2, 0x030, 0x000083A2, + 0x030, 0x000093A2, 0x030, 0x0000A3A2, 0x030, 0x0000B3A2, + 0xB0000000, 0x00000000, 0x0EF, 0x00000000, 0x8300100f, 0x0a0a0a0a, + 0x40000000, 0x00000000, 0x0EF, 0x00000040, 0x030, 0x00000645, + 0x030, 0x00001333, 0x030, 0x00002011, 0x030, 0x00004000, + 0x030, 0x00005000, 0x030, 0x00006000, 0x9300100f, 0x05050505, + 0x40000000, 0x00000000, 0x0EF, 0x00000040, 0x030, 0x00000645, + 0x030, 0x00001333, 0x030, 0x00002011, 0x030, 0x00004000, + 0x030, 0x00005000, 0x030, 0x00006000, 0x9300100f, 0x00000000, + 0x40000000, 0x00000000, 0x0EF, 0x00000040, 0x030, 0x00000645, + 0x030, 0x00001333, 0x030, 0x00002011, 0x030, 0x00004000, + 0x030, 0x00005000, 0x030, 0x00006000, 0x9300200f, 0x00000000, + 0x40000000, 0x00000000, 0x0EF, 0x00000040, 0x030, 0x00000645, + 0x030, 0x00001333, 0x030, 0x00002011, 0x030, 0x00004777, + 0x030, 0x00005777, 0x030, 0x00006777, 0x9000100f, 0x0a0a0a0a, + 0x40000000, 0x00000000, 0x0EF, 0x00000040, 0x030, 0x00000645, + 0x030, 0x00001333, 0x030, 0x00002011, 0x030, 0x00004000, + 0x030, 0x00005000, 0x030, 0x00006000, 0x9000100f, 0x05050505, + 0x40000000, 0x00000000, 0x0EF, 0x00000040, 0x030, 0x00000645, + 0x030, 0x00001333, 0x030, 0x00002011, 0x030, 0x00004000, + 0x030, 0x00005000, 0x030, 0x00006000, 0x9000100f, 0x00000000, + 0x40000000, 0x00000000, 0x0EF, 0x00000040, 0x030, 0x00000645, + 0x030, 0x00001333, 0x030, 0x00002011, 0x030, 0x00004000, + 0x030, 0x00005000, 0x030, 0x00006000, 0x9000200f, 0x00000000, + 0x40000000, 0x00000000, 0x0EF, 0x00000040, 0x030, 0x00000645, + 0x030, 0x00001333, 0x030, 0x00002011, 0x030, 0x00004000, + 0x030, 0x00005000, 0x030, 0x00006000, 0x9300200c, 0x00000000, + 0x40000000, 0x00000000, 0x0EF, 0x00000040, 0x030, 0x00000645, + 0x030, 0x00001333, 0x030, 0x00002011, 0x030, 0x00004777, + 0x030, 0x00005777, 0x030, 0x00006777, 0x93012100, 0x00000000, + 0x40000000, 0x00000000, 0x0EF, 0x00000040, 0x030, 0x00000660, + 0x030, 0x00001443, 0x030, 0x00002221, 0x030, 0x00004777, + 0x030, 0x00005777, 0x030, 0x00006777, 0x93002100, 0x00000000, + 0x40000000, 0x00000000, 0x0EF, 0x00000040, 0x030, 0x00000776, + 0x030, 0x00001455, 0x030, 0x00002325, 0x030, 0x00004777, + 0x030, 0x00005777, 0x030, 0x00006777, 0x93011000, 0x00000000, + 0x40000000, 0x00000000, 0x0EF, 0x00000040, 0x030, 0x00000764, + 0x030, 0x00001632, 0x030, 0x00002421, 0x030, 0x00004000, + 0x030, 0x00005000, 0x030, 0x00006000, 0x9000200c, 0x00000000, + 0x40000000, 0x00000000, 0x0EF, 0x00000040, 0x030, 0x00000645, + 0x030, 0x00001333, 0x030, 0x00002011, 0x030, 0x00004000, + 0x030, 0x00005000, 0x030, 0x00006000, 0x90001004, 0x00000000, + 0x40000000, 0x00000000, 0x0EF, 0x00000040, 0x030, 0x00000764, + 0x030, 0x00001632, 0x030, 0x00002421, 0x030, 0x00004000, + 0x030, 0x00005000, 0x030, 0x00006000, 0x93002000, 0x00000000, + 0x40000000, 0x00000000, 0x0EF, 0x00000040, 0x030, 0x00000777, + 0x030, 0x00001442, 0x030, 0x00002222, 0x030, 0x00004777, + 0x030, 0x00005777, 0x030, 0x00006777, 0x93001000, 0x00000000, + 0x40000000, 0x00000000, 0x0EF, 0x00000040, 0x030, 0x00000764, + 0x030, 0x00001632, 0x030, 0x00002421, 0x030, 0x00004000, + 0x030, 0x00005000, 0x030, 0x00006000, 0x90002100, 0x00000000, + 0x40000000, 0x00000000, 0x0EF, 0x00000040, 0x030, 0x00000775, + 0x030, 0x00001343, 0x030, 0x00002210, 0x030, 0x00004000, + 0x030, 0x00005000, 0x030, 0x00006000, 0x90002000, 0x00000000, + 0x40000000, 0x00000000, 0x0EF, 0x00000040, 0x030, 0x00000775, + 0x030, 0x00001422, 0x030, 0x00002210, 0x030, 0x00004000, + 0x030, 0x00005000, 0x030, 0x00006000, 0xA0000000, 0x00000000, + 0x0EF, 0x00000040, 0x030, 0x00000764, 0x030, 0x00001632, + 0x030, 0x00002421, 0x030, 0x00004000, 0x030, 0x00005000, + 0x030, 0x00006000, 0xB0000000, 0x00000000, 0x0EF, 0x00000000, + 0x0EF, 0x00000800, 0x8300100f, 0x0a0a0a0a, 0x40000000, 0x00000000, + 0x033, 0x00000020, 0x03F, 0x00000007, 0x033, 0x00000021, + 0x03F, 0x0000000A, 0x033, 0x00000022, 0x03F, 0x0000000D, + 0x033, 0x00000023, 0x03F, 0x0000002A, 0x033, 0x00000024, + 0x03F, 0x0000002D, 0x033, 0x00000025, 0x03F, 0x00000030, + 0x033, 0x00000026, 0x03F, 0x0000006D, 0x033, 0x00000027, + 0x03F, 0x00000070, 0x033, 0x00000028, 0x03F, 0x000000ED, + 0x033, 0x00000029, 0x03F, 0x000000F0, 0x033, 0x0000002A, + 0x03F, 0x000000F3, 0x9300100f, 0x05050505, 0x40000000, 0x00000000, + 0x033, 0x00000020, 0x03F, 0x00000007, 0x033, 0x00000021, + 0x03F, 0x0000000A, 0x033, 0x00000022, 0x03F, 0x0000000D, + 0x033, 0x00000023, 0x03F, 0x0000002A, 0x033, 0x00000024, + 0x03F, 0x0000002D, 0x033, 0x00000025, 0x03F, 0x00000030, + 0x033, 0x00000026, 0x03F, 0x0000006D, 0x033, 0x00000027, + 0x03F, 0x00000070, 0x033, 0x00000028, 0x03F, 0x000000ED, + 0x033, 0x00000029, 0x03F, 0x000000F0, 0x033, 0x0000002A, + 0x03F, 0x000000F3, 0x9300100f, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x00000020, 0x03F, 0x00000007, 0x033, 0x00000021, + 0x03F, 0x0000000A, 0x033, 0x00000022, 0x03F, 0x0000000D, + 0x033, 0x00000023, 0x03F, 0x0000002A, 0x033, 0x00000024, + 0x03F, 0x0000002D, 0x033, 0x00000025, 0x03F, 0x00000030, + 0x033, 0x00000026, 0x03F, 0x0000006D, 0x033, 0x00000027, + 0x03F, 0x00000070, 0x033, 0x00000028, 0x03F, 0x000000ED, + 0x033, 0x00000029, 0x03F, 0x000000F0, 0x033, 0x0000002A, + 0x03F, 0x000000F3, 0x9300200f, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x00000020, 0x03F, 0x00000005, 0x033, 0x00000021, + 0x03F, 0x00000008, 0x033, 0x00000022, 0x03F, 0x0000000B, + 0x033, 0x00000023, 0x03F, 0x0000000E, 0x033, 0x00000024, + 0x03F, 0x0000002B, 0x033, 0x00000025, 0x03F, 0x00000068, + 0x033, 0x00000026, 0x03F, 0x0000006B, 0x033, 0x00000027, + 0x03F, 0x0000006E, 0x033, 0x00000028, 0x03F, 0x00000071, + 0x033, 0x00000029, 0x03F, 0x00000074, 0x033, 0x0000002A, + 0x03F, 0x00000077, 0x9000100f, 0x0a0a0a0a, 0x40000000, 0x00000000, + 0x033, 0x00000020, 0x03F, 0x00000007, 0x033, 0x00000021, + 0x03F, 0x0000000A, 0x033, 0x00000022, 0x03F, 0x0000000D, + 0x033, 0x00000023, 0x03F, 0x0000002A, 0x033, 0x00000024, + 0x03F, 0x0000002D, 0x033, 0x00000025, 0x03F, 0x00000030, + 0x033, 0x00000026, 0x03F, 0x0000006D, 0x033, 0x00000027, + 0x03F, 0x00000070, 0x033, 0x00000028, 0x03F, 0x000000ED, + 0x033, 0x00000029, 0x03F, 0x000000F0, 0x033, 0x0000002A, + 0x03F, 0x000000F3, 0x9000100f, 0x05050505, 0x40000000, 0x00000000, + 0x033, 0x00000020, 0x03F, 0x00000007, 0x033, 0x00000021, + 0x03F, 0x0000000A, 0x033, 0x00000022, 0x03F, 0x0000000D, + 0x033, 0x00000023, 0x03F, 0x0000002A, 0x033, 0x00000024, + 0x03F, 0x0000002D, 0x033, 0x00000025, 0x03F, 0x00000030, + 0x033, 0x00000026, 0x03F, 0x0000006D, 0x033, 0x00000027, + 0x03F, 0x00000070, 0x033, 0x00000028, 0x03F, 0x000000ED, + 0x033, 0x00000029, 0x03F, 0x000000F0, 0x033, 0x0000002A, + 0x03F, 0x000000F3, 0x9000100f, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x00000020, 0x03F, 0x00000007, 0x033, 0x00000021, + 0x03F, 0x0000000A, 0x033, 0x00000022, 0x03F, 0x0000000D, + 0x033, 0x00000023, 0x03F, 0x0000002A, 0x033, 0x00000024, + 0x03F, 0x0000002D, 0x033, 0x00000025, 0x03F, 0x00000030, + 0x033, 0x00000026, 0x03F, 0x0000006D, 0x033, 0x00000027, + 0x03F, 0x00000070, 0x033, 0x00000028, 0x03F, 0x000000ED, + 0x033, 0x00000029, 0x03F, 0x000000F0, 0x033, 0x0000002A, + 0x03F, 0x000000F3, 0x9000200f, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x00000020, 0x03F, 0x00000005, 0x033, 0x00000021, + 0x03F, 0x00000008, 0x033, 0x00000022, 0x03F, 0x0000000B, + 0x033, 0x00000023, 0x03F, 0x0000000E, 0x033, 0x00000024, + 0x03F, 0x0000002B, 0x033, 0x00000025, 0x03F, 0x00000068, + 0x033, 0x00000026, 0x03F, 0x0000006B, 0x033, 0x00000027, + 0x03F, 0x0000006E, 0x033, 0x00000028, 0x03F, 0x00000071, + 0x033, 0x00000029, 0x03F, 0x00000074, 0x033, 0x0000002A, + 0x03F, 0x00000077, 0x9300200c, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x00000020, 0x03F, 0x00000005, 0x033, 0x00000021, + 0x03F, 0x00000008, 0x033, 0x00000022, 0x03F, 0x0000000B, + 0x033, 0x00000023, 0x03F, 0x0000000E, 0x033, 0x00000024, + 0x03F, 0x0000002B, 0x033, 0x00000025, 0x03F, 0x00000068, + 0x033, 0x00000026, 0x03F, 0x0000006B, 0x033, 0x00000027, + 0x03F, 0x0000006E, 0x033, 0x00000028, 0x03F, 0x00000071, + 0x033, 0x00000029, 0x03F, 0x00000074, 0x033, 0x0000002A, + 0x03F, 0x00000077, 0x93012100, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x00000020, 0x03F, 0x00000C0C, 0x033, 0x00000021, + 0x03F, 0x00000C29, 0x033, 0x00000022, 0x03F, 0x00000C2C, + 0x033, 0x00000023, 0x03F, 0x00000C69, 0x033, 0x00000024, + 0x03F, 0x00000CA8, 0x033, 0x00000025, 0x03F, 0x00000CE8, + 0x033, 0x00000026, 0x03F, 0x00000CEB, 0x033, 0x00000027, + 0x03F, 0x00000CEE, 0x033, 0x00000028, 0x03F, 0x00000CF1, + 0x033, 0x00000029, 0x03F, 0x00000CF4, 0x033, 0x0000002A, + 0x03F, 0x00000CF7, 0x93002100, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x00000020, 0x03F, 0x0000042B, 0x033, 0x00000021, + 0x03F, 0x0000082A, 0x033, 0x00000022, 0x03F, 0x00000849, + 0x033, 0x00000023, 0x03F, 0x0000084C, 0x033, 0x00000024, + 0x03F, 0x00000C4C, 0x033, 0x00000025, 0x03F, 0x00000CA9, + 0x033, 0x00000026, 0x03F, 0x00000CEA, 0x033, 0x00000027, + 0x03F, 0x00000CED, 0x033, 0x00000028, 0x03F, 0x00000CF0, + 0x033, 0x00000029, 0x03F, 0x00000CF3, 0x033, 0x0000002A, + 0x03F, 0x00000CF6, 0x93011000, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x00000020, 0x03F, 0x00000C09, 0x033, 0x00000021, + 0x03F, 0x00000C0C, 0x033, 0x00000022, 0x03F, 0x00000C0F, + 0x033, 0x00000023, 0x03F, 0x00000C2C, 0x033, 0x00000024, + 0x03F, 0x00000C2F, 0x033, 0x00000025, 0x03F, 0x00000C8A, + 0x033, 0x00000026, 0x03F, 0x00000C8D, 0x033, 0x00000027, + 0x03F, 0x00000C90, 0x033, 0x00000028, 0x03F, 0x00000CD0, + 0x033, 0x00000029, 0x03F, 0x00000CF2, 0x033, 0x0000002A, + 0x03F, 0x00000CF5, 0x9000200c, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x00000020, 0x03F, 0x00000005, 0x033, 0x00000021, + 0x03F, 0x00000008, 0x033, 0x00000022, 0x03F, 0x0000000B, + 0x033, 0x00000023, 0x03F, 0x0000000E, 0x033, 0x00000024, + 0x03F, 0x0000002B, 0x033, 0x00000025, 0x03F, 0x00000068, + 0x033, 0x00000026, 0x03F, 0x0000006B, 0x033, 0x00000027, + 0x03F, 0x0000006E, 0x033, 0x00000028, 0x03F, 0x00000071, + 0x033, 0x00000029, 0x03F, 0x00000074, 0x033, 0x0000002A, + 0x03F, 0x00000077, 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x00000020, 0x03F, 0x00000C09, 0x033, 0x00000021, + 0x03F, 0x00000C0C, 0x033, 0x00000022, 0x03F, 0x00000C0F, + 0x033, 0x00000023, 0x03F, 0x00000C2C, 0x033, 0x00000024, + 0x03F, 0x00000C2F, 0x033, 0x00000025, 0x03F, 0x00000C8A, + 0x033, 0x00000026, 0x03F, 0x00000C8D, 0x033, 0x00000027, + 0x03F, 0x00000C90, 0x033, 0x00000028, 0x03F, 0x00000CD0, + 0x033, 0x00000029, 0x03F, 0x00000CF2, 0x033, 0x0000002A, + 0x03F, 0x00000CF5, 0x93002000, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x00000020, 0x03F, 0x00000429, 0x033, 0x00000021, + 0x03F, 0x00000828, 0x033, 0x00000022, 0x03F, 0x00000847, + 0x033, 0x00000023, 0x03F, 0x0000084A, 0x033, 0x00000024, + 0x03F, 0x00000C4B, 0x033, 0x00000025, 0x03F, 0x00000C8A, + 0x033, 0x00000026, 0x03F, 0x00000CEA, 0x033, 0x00000027, + 0x03F, 0x00000CED, 0x033, 0x00000028, 0x03F, 0x00000CF0, + 0x033, 0x00000029, 0x03F, 0x00000CF3, 0x033, 0x0000002A, + 0x03F, 0x00000CF6, 0x93001000, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x00000020, 0x03F, 0x00000C09, 0x033, 0x00000021, + 0x03F, 0x00000C0C, 0x033, 0x00000022, 0x03F, 0x00000C0F, + 0x033, 0x00000023, 0x03F, 0x00000C2C, 0x033, 0x00000024, + 0x03F, 0x00000C2F, 0x033, 0x00000025, 0x03F, 0x00000C8A, + 0x033, 0x00000026, 0x03F, 0x00000C8D, 0x033, 0x00000027, + 0x03F, 0x00000C90, 0x033, 0x00000028, 0x03F, 0x00000CD0, + 0x033, 0x00000029, 0x03F, 0x00000CF2, 0x033, 0x0000002A, + 0x03F, 0x00000CF5, 0x90002100, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x00000020, 0x03F, 0x0000042B, 0x033, 0x00000021, + 0x03F, 0x0000082A, 0x033, 0x00000022, 0x03F, 0x00000849, + 0x033, 0x00000023, 0x03F, 0x0000084C, 0x033, 0x00000024, + 0x03F, 0x00000C4C, 0x033, 0x00000025, 0x03F, 0x00000C8A, + 0x033, 0x00000026, 0x03F, 0x00000C8D, 0x033, 0x00000027, + 0x03F, 0x00000CEB, 0x033, 0x00000028, 0x03F, 0x00000CEE, + 0x033, 0x00000029, 0x03F, 0x00000CF1, 0x033, 0x0000002A, + 0x03F, 0x00000CF4, 0x90002000, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x00000020, 0x03F, 0x0000042B, 0x033, 0x00000021, + 0x03F, 0x0000082A, 0x033, 0x00000022, 0x03F, 0x00000849, + 0x033, 0x00000023, 0x03F, 0x0000084C, 0x033, 0x00000024, + 0x03F, 0x00000C4C, 0x033, 0x00000025, 0x03F, 0x00000C8A, + 0x033, 0x00000026, 0x03F, 0x00000C8D, 0x033, 0x00000027, + 0x03F, 0x00000CEB, 0x033, 0x00000028, 0x03F, 0x00000CEE, + 0x033, 0x00000029, 0x03F, 0x00000CF1, 0x033, 0x0000002A, + 0x03F, 0x00000CF4, 0xA0000000, 0x00000000, 0x033, 0x00000020, + 0x03F, 0x00000C09, 0x033, 0x00000021, 0x03F, 0x00000C0C, + 0x033, 0x00000022, 0x03F, 0x00000C0F, 0x033, 0x00000023, + 0x03F, 0x00000C2C, 0x033, 0x00000024, 0x03F, 0x00000C2F, + 0x033, 0x00000025, 0x03F, 0x00000C8A, 0x033, 0x00000026, + 0x03F, 0x00000C8D, 0x033, 0x00000027, 0x03F, 0x00000C90, + 0x033, 0x00000028, 0x03F, 0x00000CD0, 0x033, 0x00000029, + 0x03F, 0x00000CF2, 0x033, 0x0000002A, 0x03F, 0x00000CF5, + 0xB0000000, 0x00000000, 0x8300100f, 0x0a0a0a0a, 0x40000000, 0x00000000, + 0x033, 0x00000060, 0x03F, 0x00000007, 0x033, 0x00000061, + 0x03F, 0x0000000A, 0x033, 0x00000062, 0x03F, 0x0000000D, + 0x033, 0x00000063, 0x03F, 0x0000002A, 0x033, 0x00000064, + 0x03F, 0x0000002D, 0x033, 0x00000065, 0x03F, 0x00000030, + 0x033, 0x00000066, 0x03F, 0x0000006D, 0x033, 0x00000067, + 0x03F, 0x00000070, 0x033, 0x00000068, 0x03F, 0x000000ED, + 0x033, 0x00000069, 0x03F, 0x000000F0, 0x033, 0x0000006A, + 0x03F, 0x000000F3, 0x9300100f, 0x05050505, 0x40000000, 0x00000000, + 0x033, 0x00000060, 0x03F, 0x00000007, 0x033, 0x00000061, + 0x03F, 0x0000000A, 0x033, 0x00000062, 0x03F, 0x0000000D, + 0x033, 0x00000063, 0x03F, 0x0000002A, 0x033, 0x00000064, + 0x03F, 0x0000002D, 0x033, 0x00000065, 0x03F, 0x00000030, + 0x033, 0x00000066, 0x03F, 0x0000006D, 0x033, 0x00000067, + 0x03F, 0x00000070, 0x033, 0x00000068, 0x03F, 0x000000ED, + 0x033, 0x00000069, 0x03F, 0x000000F0, 0x033, 0x0000006A, + 0x03F, 0x000000F3, 0x9300100f, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x00000060, 0x03F, 0x00000007, 0x033, 0x00000061, + 0x03F, 0x0000000A, 0x033, 0x00000062, 0x03F, 0x0000000D, + 0x033, 0x00000063, 0x03F, 0x0000002A, 0x033, 0x00000064, + 0x03F, 0x0000002D, 0x033, 0x00000065, 0x03F, 0x00000030, + 0x033, 0x00000066, 0x03F, 0x0000006D, 0x033, 0x00000067, + 0x03F, 0x00000070, 0x033, 0x00000068, 0x03F, 0x000000ED, + 0x033, 0x00000069, 0x03F, 0x000000F0, 0x033, 0x0000006A, + 0x03F, 0x000000F3, 0x9300200f, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x00000060, 0x03F, 0x00000005, 0x033, 0x00000061, + 0x03F, 0x00000008, 0x033, 0x00000062, 0x03F, 0x0000000B, + 0x033, 0x00000063, 0x03F, 0x0000000E, 0x033, 0x00000064, + 0x03F, 0x0000002B, 0x033, 0x00000065, 0x03F, 0x00000068, + 0x033, 0x00000066, 0x03F, 0x0000006B, 0x033, 0x00000067, + 0x03F, 0x0000006E, 0x033, 0x00000068, 0x03F, 0x00000071, + 0x033, 0x00000069, 0x03F, 0x00000074, 0x033, 0x0000006A, + 0x03F, 0x00000077, 0x9000100f, 0x0a0a0a0a, 0x40000000, 0x00000000, + 0x033, 0x00000060, 0x03F, 0x00000007, 0x033, 0x00000061, + 0x03F, 0x0000000A, 0x033, 0x00000062, 0x03F, 0x0000000D, + 0x033, 0x00000063, 0x03F, 0x0000002A, 0x033, 0x00000064, + 0x03F, 0x0000002D, 0x033, 0x00000065, 0x03F, 0x00000030, + 0x033, 0x00000066, 0x03F, 0x0000006D, 0x033, 0x00000067, + 0x03F, 0x00000070, 0x033, 0x00000068, 0x03F, 0x000000ED, + 0x033, 0x00000069, 0x03F, 0x000000F0, 0x033, 0x0000006A, + 0x03F, 0x000000F3, 0x9000100f, 0x05050505, 0x40000000, 0x00000000, + 0x033, 0x00000060, 0x03F, 0x00000007, 0x033, 0x00000061, + 0x03F, 0x0000000A, 0x033, 0x00000062, 0x03F, 0x0000000D, + 0x033, 0x00000063, 0x03F, 0x0000002A, 0x033, 0x00000064, + 0x03F, 0x0000002D, 0x033, 0x00000065, 0x03F, 0x00000030, + 0x033, 0x00000066, 0x03F, 0x0000006D, 0x033, 0x00000067, + 0x03F, 0x00000070, 0x033, 0x00000068, 0x03F, 0x000000ED, + 0x033, 0x00000069, 0x03F, 0x000000F0, 0x033, 0x0000006A, + 0x03F, 0x000000F3, 0x9000100f, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x00000060, 0x03F, 0x00000007, 0x033, 0x00000061, + 0x03F, 0x0000000A, 0x033, 0x00000062, 0x03F, 0x0000000D, + 0x033, 0x00000063, 0x03F, 0x0000002A, 0x033, 0x00000064, + 0x03F, 0x0000002D, 0x033, 0x00000065, 0x03F, 0x00000030, + 0x033, 0x00000066, 0x03F, 0x0000006D, 0x033, 0x00000067, + 0x03F, 0x00000070, 0x033, 0x00000068, 0x03F, 0x000000ED, + 0x033, 0x00000069, 0x03F, 0x000000F0, 0x033, 0x0000006A, + 0x03F, 0x000000F3, 0x9000200f, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x00000060, 0x03F, 0x00000005, 0x033, 0x00000061, + 0x03F, 0x00000008, 0x033, 0x00000062, 0x03F, 0x0000000B, + 0x033, 0x00000063, 0x03F, 0x0000000E, 0x033, 0x00000064, + 0x03F, 0x0000002B, 0x033, 0x00000065, 0x03F, 0x00000068, + 0x033, 0x00000066, 0x03F, 0x0000006B, 0x033, 0x00000067, + 0x03F, 0x0000006E, 0x033, 0x00000068, 0x03F, 0x00000071, + 0x033, 0x00000069, 0x03F, 0x00000074, 0x033, 0x0000006A, + 0x03F, 0x00000077, 0x9300200c, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x00000060, 0x03F, 0x00000005, 0x033, 0x00000061, + 0x03F, 0x00000008, 0x033, 0x00000062, 0x03F, 0x0000000B, + 0x033, 0x00000063, 0x03F, 0x0000000E, 0x033, 0x00000064, + 0x03F, 0x0000002B, 0x033, 0x00000065, 0x03F, 0x00000068, + 0x033, 0x00000066, 0x03F, 0x0000006B, 0x033, 0x00000067, + 0x03F, 0x0000006E, 0x033, 0x00000068, 0x03F, 0x00000071, + 0x033, 0x00000069, 0x03F, 0x00000074, 0x033, 0x0000006A, + 0x03F, 0x00000077, 0x93012100, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x00000060, 0x03F, 0x0000080B, 0x033, 0x00000061, + 0x03F, 0x0000080E, 0x033, 0x00000062, 0x03F, 0x00000848, + 0x033, 0x00000063, 0x03F, 0x00000869, 0x033, 0x00000064, + 0x03F, 0x000008A9, 0x033, 0x00000065, 0x03F, 0x00000CE8, + 0x033, 0x00000066, 0x03F, 0x00000CEB, 0x033, 0x00000067, + 0x03F, 0x00000CEE, 0x033, 0x00000068, 0x03F, 0x00000CF1, + 0x033, 0x00000069, 0x03F, 0x00000CF4, 0x033, 0x0000006A, + 0x03F, 0x00000CF7, 0x93002100, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x00000060, 0x03F, 0x0000042B, 0x033, 0x00000061, + 0x03F, 0x0000082A, 0x033, 0x00000062, 0x03F, 0x00000849, + 0x033, 0x00000063, 0x03F, 0x0000084C, 0x033, 0x00000064, + 0x03F, 0x00000C4C, 0x033, 0x00000065, 0x03F, 0x00000CA9, + 0x033, 0x00000066, 0x03F, 0x00000CEA, 0x033, 0x00000067, + 0x03F, 0x00000CED, 0x033, 0x00000068, 0x03F, 0x00000CF0, + 0x033, 0x00000069, 0x03F, 0x00000CF3, 0x033, 0x0000006A, + 0x03F, 0x00000CF6, 0x93011000, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x00000060, 0x03F, 0x00000C0A, 0x033, 0x00000061, + 0x03F, 0x00000C0D, 0x033, 0x00000062, 0x03F, 0x00000C2A, + 0x033, 0x00000063, 0x03F, 0x00000C2D, 0x033, 0x00000064, + 0x03F, 0x00000C6A, 0x033, 0x00000065, 0x03F, 0x00000CAA, + 0x033, 0x00000066, 0x03F, 0x00000CAD, 0x033, 0x00000067, + 0x03F, 0x00000CB0, 0x033, 0x00000068, 0x03F, 0x00000CF1, + 0x033, 0x00000069, 0x03F, 0x00000CF4, 0x033, 0x0000006A, + 0x03F, 0x00000CF7, 0x9000200c, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x00000060, 0x03F, 0x00000005, 0x033, 0x00000061, + 0x03F, 0x00000008, 0x033, 0x00000062, 0x03F, 0x0000000B, + 0x033, 0x00000063, 0x03F, 0x0000000E, 0x033, 0x00000064, + 0x03F, 0x0000002B, 0x033, 0x00000065, 0x03F, 0x00000068, + 0x033, 0x00000066, 0x03F, 0x0000006B, 0x033, 0x00000067, + 0x03F, 0x0000006E, 0x033, 0x00000068, 0x03F, 0x00000071, + 0x033, 0x00000069, 0x03F, 0x00000074, 0x033, 0x0000006A, + 0x03F, 0x00000077, 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x00000060, 0x03F, 0x00000C0A, 0x033, 0x00000061, + 0x03F, 0x00000C0D, 0x033, 0x00000062, 0x03F, 0x00000C2A, + 0x033, 0x00000063, 0x03F, 0x00000C2D, 0x033, 0x00000064, + 0x03F, 0x00000C6A, 0x033, 0x00000065, 0x03F, 0x00000CAA, + 0x033, 0x00000066, 0x03F, 0x00000CAD, 0x033, 0x00000067, + 0x03F, 0x00000CB0, 0x033, 0x00000068, 0x03F, 0x00000CF1, + 0x033, 0x00000069, 0x03F, 0x00000CF4, 0x033, 0x0000006A, + 0x03F, 0x00000CF7, 0x93002000, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x00000060, 0x03F, 0x00000429, 0x033, 0x00000061, + 0x03F, 0x00000828, 0x033, 0x00000062, 0x03F, 0x00000847, + 0x033, 0x00000063, 0x03F, 0x0000084A, 0x033, 0x00000064, + 0x03F, 0x00000C4B, 0x033, 0x00000065, 0x03F, 0x00000C8A, + 0x033, 0x00000066, 0x03F, 0x00000CEA, 0x033, 0x00000067, + 0x03F, 0x00000CED, 0x033, 0x00000068, 0x03F, 0x00000CF0, + 0x033, 0x00000069, 0x03F, 0x00000CF3, 0x033, 0x0000006A, + 0x03F, 0x00000CF6, 0x93001000, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x00000060, 0x03F, 0x00000C0A, 0x033, 0x00000061, + 0x03F, 0x00000C0D, 0x033, 0x00000062, 0x03F, 0x00000C2A, + 0x033, 0x00000063, 0x03F, 0x00000C2D, 0x033, 0x00000064, + 0x03F, 0x00000C6A, 0x033, 0x00000065, 0x03F, 0x00000CAA, + 0x033, 0x00000066, 0x03F, 0x00000CAD, 0x033, 0x00000067, + 0x03F, 0x00000CB0, 0x033, 0x00000068, 0x03F, 0x00000CF1, + 0x033, 0x00000069, 0x03F, 0x00000CF4, 0x033, 0x0000006A, + 0x03F, 0x00000CF7, 0x90002100, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x00000060, 0x03F, 0x0000042C, 0x033, 0x00000061, + 0x03F, 0x0000082B, 0x033, 0x00000062, 0x03F, 0x0000084A, + 0x033, 0x00000063, 0x03F, 0x0000084D, 0x033, 0x00000064, + 0x03F, 0x00000C4D, 0x033, 0x00000065, 0x03F, 0x00000C8B, + 0x033, 0x00000066, 0x03F, 0x00000C8E, 0x033, 0x00000067, + 0x03F, 0x00000CEC, 0x033, 0x00000068, 0x03F, 0x00000CEF, + 0x033, 0x00000069, 0x03F, 0x00000CF2, 0x033, 0x0000006A, + 0x03F, 0x00000CF5, 0x90002000, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x00000060, 0x03F, 0x0000042C, 0x033, 0x00000061, + 0x03F, 0x0000082B, 0x033, 0x00000062, 0x03F, 0x0000084A, + 0x033, 0x00000063, 0x03F, 0x0000084D, 0x033, 0x00000064, + 0x03F, 0x00000C4D, 0x033, 0x00000065, 0x03F, 0x00000C8B, + 0x033, 0x00000066, 0x03F, 0x00000C8E, 0x033, 0x00000067, + 0x03F, 0x00000CEC, 0x033, 0x00000068, 0x03F, 0x00000CEF, + 0x033, 0x00000069, 0x03F, 0x00000CF2, 0x033, 0x0000006A, + 0x03F, 0x00000CF5, 0xA0000000, 0x00000000, 0x033, 0x00000060, + 0x03F, 0x00000C0A, 0x033, 0x00000061, 0x03F, 0x00000C0D, + 0x033, 0x00000062, 0x03F, 0x00000C2A, 0x033, 0x00000063, + 0x03F, 0x00000C2D, 0x033, 0x00000064, 0x03F, 0x00000C6A, + 0x033, 0x00000065, 0x03F, 0x00000CAA, 0x033, 0x00000066, + 0x03F, 0x00000CAD, 0x033, 0x00000067, 0x03F, 0x00000CB0, + 0x033, 0x00000068, 0x03F, 0x00000CF1, 0x033, 0x00000069, + 0x03F, 0x00000CF4, 0x033, 0x0000006A, 0x03F, 0x00000CF7, + 0xB0000000, 0x00000000, 0x8300100f, 0x0a0a0a0a, 0x40000000, 0x00000000, + 0x033, 0x000000A0, 0x03F, 0x00000007, 0x033, 0x000000A1, + 0x03F, 0x0000000A, 0x033, 0x000000A2, 0x03F, 0x0000000D, + 0x033, 0x000000A3, 0x03F, 0x0000002A, 0x033, 0x000000A4, + 0x03F, 0x0000002D, 0x033, 0x000000A5, 0x03F, 0x00000030, + 0x033, 0x000000A6, 0x03F, 0x0000006D, 0x033, 0x000000A7, + 0x03F, 0x00000070, 0x033, 0x000000A8, 0x03F, 0x000000ED, + 0x033, 0x000000A9, 0x03F, 0x000000F0, 0x033, 0x000000AA, + 0x03F, 0x000000F3, 0x9300100f, 0x05050505, 0x40000000, 0x00000000, + 0x033, 0x000000A0, 0x03F, 0x00000007, 0x033, 0x000000A1, + 0x03F, 0x0000000A, 0x033, 0x000000A2, 0x03F, 0x0000000D, + 0x033, 0x000000A3, 0x03F, 0x0000002A, 0x033, 0x000000A4, + 0x03F, 0x0000002D, 0x033, 0x000000A5, 0x03F, 0x00000030, + 0x033, 0x000000A6, 0x03F, 0x0000006D, 0x033, 0x000000A7, + 0x03F, 0x00000070, 0x033, 0x000000A8, 0x03F, 0x000000ED, + 0x033, 0x000000A9, 0x03F, 0x000000F0, 0x033, 0x000000AA, + 0x03F, 0x000000F3, 0x9300100f, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x000000A0, 0x03F, 0x00000007, 0x033, 0x000000A1, + 0x03F, 0x0000000A, 0x033, 0x000000A2, 0x03F, 0x0000000D, + 0x033, 0x000000A3, 0x03F, 0x0000002A, 0x033, 0x000000A4, + 0x03F, 0x0000002D, 0x033, 0x000000A5, 0x03F, 0x00000030, + 0x033, 0x000000A6, 0x03F, 0x0000006D, 0x033, 0x000000A7, + 0x03F, 0x00000070, 0x033, 0x000000A8, 0x03F, 0x000000ED, + 0x033, 0x000000A9, 0x03F, 0x000000F0, 0x033, 0x000000AA, + 0x03F, 0x000000F3, 0x9300200f, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x000000A0, 0x03F, 0x00000005, 0x033, 0x000000A1, + 0x03F, 0x00000008, 0x033, 0x000000A2, 0x03F, 0x0000000B, + 0x033, 0x000000A3, 0x03F, 0x0000000E, 0x033, 0x000000A4, + 0x03F, 0x00000047, 0x033, 0x000000A5, 0x03F, 0x0000004A, + 0x033, 0x000000A6, 0x03F, 0x0000004D, 0x033, 0x000000A7, + 0x03F, 0x00000050, 0x033, 0x000000A8, 0x03F, 0x00000053, + 0x033, 0x000000A9, 0x03F, 0x00000056, 0x033, 0x000000AA, + 0x03F, 0x00000094, 0x9000100f, 0x0a0a0a0a, 0x40000000, 0x00000000, + 0x033, 0x000000A0, 0x03F, 0x00000007, 0x033, 0x000000A1, + 0x03F, 0x0000000A, 0x033, 0x000000A2, 0x03F, 0x0000000D, + 0x033, 0x000000A3, 0x03F, 0x0000002A, 0x033, 0x000000A4, + 0x03F, 0x0000002D, 0x033, 0x000000A5, 0x03F, 0x00000030, + 0x033, 0x000000A6, 0x03F, 0x0000006D, 0x033, 0x000000A7, + 0x03F, 0x00000070, 0x033, 0x000000A8, 0x03F, 0x000000ED, + 0x033, 0x000000A9, 0x03F, 0x000000F0, 0x033, 0x000000AA, + 0x03F, 0x000000F3, 0x9000100f, 0x05050505, 0x40000000, 0x00000000, + 0x033, 0x000000A0, 0x03F, 0x00000007, 0x033, 0x000000A1, + 0x03F, 0x0000000A, 0x033, 0x000000A2, 0x03F, 0x0000000D, + 0x033, 0x000000A3, 0x03F, 0x0000002A, 0x033, 0x000000A4, + 0x03F, 0x0000002D, 0x033, 0x000000A5, 0x03F, 0x00000030, + 0x033, 0x000000A6, 0x03F, 0x0000006D, 0x033, 0x000000A7, + 0x03F, 0x00000070, 0x033, 0x000000A8, 0x03F, 0x000000ED, + 0x033, 0x000000A9, 0x03F, 0x000000F0, 0x033, 0x000000AA, + 0x03F, 0x000000F3, 0x9000100f, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x000000A0, 0x03F, 0x00000007, 0x033, 0x000000A1, + 0x03F, 0x0000000A, 0x033, 0x000000A2, 0x03F, 0x0000000D, + 0x033, 0x000000A3, 0x03F, 0x0000002A, 0x033, 0x000000A4, + 0x03F, 0x0000002D, 0x033, 0x000000A5, 0x03F, 0x00000030, + 0x033, 0x000000A6, 0x03F, 0x0000006D, 0x033, 0x000000A7, + 0x03F, 0x00000070, 0x033, 0x000000A8, 0x03F, 0x000000ED, + 0x033, 0x000000A9, 0x03F, 0x000000F0, 0x033, 0x000000AA, + 0x03F, 0x000000F3, 0x9000200f, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x000000A0, 0x03F, 0x00000005, 0x033, 0x000000A1, + 0x03F, 0x00000008, 0x033, 0x000000A2, 0x03F, 0x0000000B, + 0x033, 0x000000A3, 0x03F, 0x0000000E, 0x033, 0x000000A4, + 0x03F, 0x00000047, 0x033, 0x000000A5, 0x03F, 0x0000004A, + 0x033, 0x000000A6, 0x03F, 0x0000004D, 0x033, 0x000000A7, + 0x03F, 0x00000050, 0x033, 0x000000A8, 0x03F, 0x00000053, + 0x033, 0x000000A9, 0x03F, 0x00000056, 0x033, 0x000000AA, + 0x03F, 0x00000094, 0x9300200c, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x000000A0, 0x03F, 0x00000005, 0x033, 0x000000A1, + 0x03F, 0x00000008, 0x033, 0x000000A2, 0x03F, 0x0000000B, + 0x033, 0x000000A3, 0x03F, 0x0000000E, 0x033, 0x000000A4, + 0x03F, 0x00000047, 0x033, 0x000000A5, 0x03F, 0x0000004A, + 0x033, 0x000000A6, 0x03F, 0x0000004D, 0x033, 0x000000A7, + 0x03F, 0x00000050, 0x033, 0x000000A8, 0x03F, 0x00000053, + 0x033, 0x000000A9, 0x03F, 0x00000056, 0x033, 0x000000AA, + 0x03F, 0x00000094, 0x93012100, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x000000A0, 0x03F, 0x00000C0A, 0x033, 0x000000A1, + 0x03F, 0x00000C0D, 0x033, 0x000000A2, 0x03F, 0x00000C2A, + 0x033, 0x000000A3, 0x03F, 0x00000C2D, 0x033, 0x000000A4, + 0x03F, 0x00000C6A, 0x033, 0x000000A5, 0x03F, 0x00000CE8, + 0x033, 0x000000A6, 0x03F, 0x00000CEB, 0x033, 0x000000A7, + 0x03F, 0x00000CEE, 0x033, 0x000000A8, 0x03F, 0x00000CF1, + 0x033, 0x000000A9, 0x03F, 0x00000CF4, 0x033, 0x000000AA, + 0x03F, 0x00000CF7, 0x93002100, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x000000A0, 0x03F, 0x0000042A, 0x033, 0x000000A1, + 0x03F, 0x00000829, 0x033, 0x000000A2, 0x03F, 0x00000848, + 0x033, 0x000000A3, 0x03F, 0x0000084B, 0x033, 0x000000A4, + 0x03F, 0x00000C4C, 0x033, 0x000000A5, 0x03F, 0x00000CA9, + 0x033, 0x000000A6, 0x03F, 0x00000CEA, 0x033, 0x000000A7, + 0x03F, 0x00000CED, 0x033, 0x000000A8, 0x03F, 0x00000CF0, + 0x033, 0x000000A9, 0x03F, 0x00000CF3, 0x033, 0x000000AA, + 0x03F, 0x00000CF6, 0x93011000, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x000000A0, 0x03F, 0x00000C09, 0x033, 0x000000A1, + 0x03F, 0x00000C0C, 0x033, 0x000000A2, 0x03F, 0x00000C0F, + 0x033, 0x000000A3, 0x03F, 0x00000C2C, 0x033, 0x000000A4, + 0x03F, 0x00000C2F, 0x033, 0x000000A5, 0x03F, 0x00000C8A, + 0x033, 0x000000A6, 0x03F, 0x00000C8D, 0x033, 0x000000A7, + 0x03F, 0x00000C90, 0x033, 0x000000A8, 0x03F, 0x00000CEF, + 0x033, 0x000000A9, 0x03F, 0x00000CF2, 0x033, 0x000000AA, + 0x03F, 0x00000CF5, 0x9000200c, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x000000A0, 0x03F, 0x00000005, 0x033, 0x000000A1, + 0x03F, 0x00000008, 0x033, 0x000000A2, 0x03F, 0x0000000B, + 0x033, 0x000000A3, 0x03F, 0x0000000E, 0x033, 0x000000A4, + 0x03F, 0x00000047, 0x033, 0x000000A5, 0x03F, 0x0000004A, + 0x033, 0x000000A6, 0x03F, 0x0000004D, 0x033, 0x000000A7, + 0x03F, 0x00000050, 0x033, 0x000000A8, 0x03F, 0x00000053, + 0x033, 0x000000A9, 0x03F, 0x00000056, 0x033, 0x000000AA, + 0x03F, 0x00000094, 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x000000A0, 0x03F, 0x00000C09, 0x033, 0x000000A1, + 0x03F, 0x00000C0C, 0x033, 0x000000A2, 0x03F, 0x00000C0F, + 0x033, 0x000000A3, 0x03F, 0x00000C2C, 0x033, 0x000000A4, + 0x03F, 0x00000C2F, 0x033, 0x000000A5, 0x03F, 0x00000C8A, + 0x033, 0x000000A6, 0x03F, 0x00000C8D, 0x033, 0x000000A7, + 0x03F, 0x00000C90, 0x033, 0x000000A8, 0x03F, 0x00000CEF, + 0x033, 0x000000A9, 0x03F, 0x00000CF2, 0x033, 0x000000AA, + 0x03F, 0x00000CF5, 0x93002000, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x000000A0, 0x03F, 0x00000429, 0x033, 0x000000A1, + 0x03F, 0x00000828, 0x033, 0x000000A2, 0x03F, 0x00000847, + 0x033, 0x000000A3, 0x03F, 0x0000084A, 0x033, 0x000000A4, + 0x03F, 0x00000C4B, 0x033, 0x000000A5, 0x03F, 0x00000C8A, + 0x033, 0x000000A6, 0x03F, 0x00000CEA, 0x033, 0x000000A7, + 0x03F, 0x00000CED, 0x033, 0x000000A8, 0x03F, 0x00000CF0, + 0x033, 0x000000A9, 0x03F, 0x00000CF3, 0x033, 0x000000AA, + 0x03F, 0x00000CF6, 0x93001000, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x000000A0, 0x03F, 0x00000C09, 0x033, 0x000000A1, + 0x03F, 0x00000C0C, 0x033, 0x000000A2, 0x03F, 0x00000C0F, + 0x033, 0x000000A3, 0x03F, 0x00000C2C, 0x033, 0x000000A4, + 0x03F, 0x00000C2F, 0x033, 0x000000A5, 0x03F, 0x00000C8A, + 0x033, 0x000000A6, 0x03F, 0x00000C8D, 0x033, 0x000000A7, + 0x03F, 0x00000C90, 0x033, 0x000000A8, 0x03F, 0x00000CEF, + 0x033, 0x000000A9, 0x03F, 0x00000CF2, 0x033, 0x000000AA, + 0x03F, 0x00000CF5, 0x90002100, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x000000A0, 0x03F, 0x0000042A, 0x033, 0x000000A1, + 0x03F, 0x00000829, 0x033, 0x000000A2, 0x03F, 0x00000848, + 0x033, 0x000000A3, 0x03F, 0x0000084B, 0x033, 0x000000A4, + 0x03F, 0x00000C4C, 0x033, 0x000000A5, 0x03F, 0x00000C8A, + 0x033, 0x000000A6, 0x03F, 0x00000C8D, 0x033, 0x000000A7, + 0x03F, 0x00000CEB, 0x033, 0x000000A8, 0x03F, 0x00000CEE, + 0x033, 0x000000A9, 0x03F, 0x00000CF1, 0x033, 0x000000AA, + 0x03F, 0x00000CF4, 0x90002000, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x000000A0, 0x03F, 0x0000042A, 0x033, 0x000000A1, + 0x03F, 0x00000829, 0x033, 0x000000A2, 0x03F, 0x00000848, + 0x033, 0x000000A3, 0x03F, 0x0000084B, 0x033, 0x000000A4, + 0x03F, 0x00000C4C, 0x033, 0x000000A5, 0x03F, 0x00000C8A, + 0x033, 0x000000A6, 0x03F, 0x00000C8D, 0x033, 0x000000A7, + 0x03F, 0x00000CEB, 0x033, 0x000000A8, 0x03F, 0x00000CEE, + 0x033, 0x000000A9, 0x03F, 0x00000CF1, 0x033, 0x000000AA, + 0x03F, 0x00000CF4, 0xA0000000, 0x00000000, 0x033, 0x000000A0, + 0x03F, 0x00000C09, 0x033, 0x000000A1, 0x03F, 0x00000C0C, + 0x033, 0x000000A2, 0x03F, 0x00000C0F, 0x033, 0x000000A3, + 0x03F, 0x00000C2C, 0x033, 0x000000A4, 0x03F, 0x00000C2F, + 0x033, 0x000000A5, 0x03F, 0x00000C8A, 0x033, 0x000000A6, + 0x03F, 0x00000C8D, 0x033, 0x000000A7, 0x03F, 0x00000C90, + 0x033, 0x000000A8, 0x03F, 0x00000CEF, 0x033, 0x000000A9, + 0x03F, 0x00000CF2, 0x033, 0x000000AA, 0x03F, 0x00000CF5, + 0xB0000000, 0x00000000, 0x0EF, 0x00000000, 0x0EF, 0x00000400, + 0x8300100f, 0x0a0a0a0a, 0x40000000, 0x00000000, 0x033, 0x00000000, + 0x03F, 0x0000047C, 0x033, 0x00000001, 0x03F, 0x0000047C, + 0x033, 0x00000002, 0x03F, 0x0000047C, 0x033, 0x00000003, + 0x03F, 0x0000047C, 0x9300100f, 0x05050505, 0x40000000, 0x00000000, + 0x033, 0x00000000, 0x03F, 0x0000047C, 0x033, 0x00000001, + 0x03F, 0x0000047C, 0x033, 0x00000002, 0x03F, 0x0000047C, + 0x033, 0x00000003, 0x03F, 0x0000047C, 0x9300100f, 0x00000000, + 0x40000000, 0x00000000, 0x033, 0x00000000, 0x03F, 0x0000047C, + 0x033, 0x00000001, 0x03F, 0x0000047C, 0x033, 0x00000002, + 0x03F, 0x0000047C, 0x033, 0x00000003, 0x03F, 0x0000047C, + 0x9300200f, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000000, + 0x03F, 0x0000047C, 0x033, 0x00000001, 0x03F, 0x0000047C, + 0x033, 0x00000002, 0x03F, 0x0000047C, 0x033, 0x00000003, + 0x03F, 0x0000047C, 0x9000100f, 0x0a0a0a0a, 0x40000000, 0x00000000, + 0x033, 0x00000000, 0x03F, 0x0000047C, 0x033, 0x00000001, + 0x03F, 0x0000047C, 0x033, 0x00000002, 0x03F, 0x0000047C, + 0x033, 0x00000003, 0x03F, 0x0000047C, 0x9000100f, 0x05050505, + 0x40000000, 0x00000000, 0x033, 0x00000000, 0x03F, 0x0000047C, + 0x033, 0x00000001, 0x03F, 0x0000047C, 0x033, 0x00000002, + 0x03F, 0x0000047C, 0x033, 0x00000003, 0x03F, 0x0000047C, + 0x9000100f, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000000, + 0x03F, 0x0000047C, 0x033, 0x00000001, 0x03F, 0x0000047C, + 0x033, 0x00000002, 0x03F, 0x0000047C, 0x033, 0x00000003, + 0x03F, 0x0000047C, 0x9000200f, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x00000000, 0x03F, 0x0000047C, 0x033, 0x00000001, + 0x03F, 0x0000047C, 0x033, 0x00000002, 0x03F, 0x0000047C, + 0x033, 0x00000003, 0x03F, 0x0000047C, 0xA0000000, 0x00000000, + 0x033, 0x00000000, 0x03F, 0x000004BB, 0x033, 0x00000001, + 0x03F, 0x000004BB, 0x033, 0x00000002, 0x03F, 0x000004BB, + 0x033, 0x00000003, 0x03F, 0x000004BB, 0xB0000000, 0x00000000, + 0x0EF, 0x00000000, 0x0EF, 0x00000100, 0x8300100f, 0x0a0a0a0a, + 0x40000000, 0x00000000, 0x033, 0x00000000, 0x03F, 0x00001726, + 0x033, 0x00000001, 0x03F, 0x00001726, 0x033, 0x00000002, + 0x03F, 0x00001726, 0x033, 0x00000003, 0x03F, 0x00001726, + 0x9300100f, 0x05050505, 0x40000000, 0x00000000, 0x033, 0x00000000, + 0x03F, 0x00001726, 0x033, 0x00000001, 0x03F, 0x00001726, + 0x033, 0x00000002, 0x03F, 0x00001726, 0x033, 0x00000003, + 0x03F, 0x00001726, 0x9300100f, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x00000000, 0x03F, 0x00001726, 0x033, 0x00000001, + 0x03F, 0x00001726, 0x033, 0x00000002, 0x03F, 0x00001726, + 0x033, 0x00000003, 0x03F, 0x00001726, 0x9300200f, 0x00000000, + 0x40000000, 0x00000000, 0x033, 0x00000000, 0x03F, 0x00001726, + 0x033, 0x00000001, 0x03F, 0x00001726, 0x033, 0x00000002, + 0x03F, 0x00001726, 0x033, 0x00000003, 0x03F, 0x00001726, + 0x9000100f, 0x0a0a0a0a, 0x40000000, 0x00000000, 0x033, 0x00000000, + 0x03F, 0x00001726, 0x033, 0x00000001, 0x03F, 0x00001726, + 0x033, 0x00000002, 0x03F, 0x00001726, 0x033, 0x00000003, + 0x03F, 0x00001726, 0x9000100f, 0x05050505, 0x40000000, 0x00000000, + 0x033, 0x00000000, 0x03F, 0x00001726, 0x033, 0x00000001, + 0x03F, 0x00001726, 0x033, 0x00000002, 0x03F, 0x00001726, + 0x033, 0x00000003, 0x03F, 0x00001726, 0x9000100f, 0x00000000, + 0x40000000, 0x00000000, 0x033, 0x00000000, 0x03F, 0x00001726, + 0x033, 0x00000001, 0x03F, 0x00001726, 0x033, 0x00000002, + 0x03F, 0x00001726, 0x033, 0x00000003, 0x03F, 0x00001726, + 0x9000200f, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000000, + 0x03F, 0x00001726, 0x033, 0x00000001, 0x03F, 0x00001726, + 0x033, 0x00000002, 0x03F, 0x00001726, 0x033, 0x00000003, + 0x03F, 0x00001726, 0xA0000000, 0x00000000, 0x033, 0x00000000, + 0x03F, 0x00000F34, 0x033, 0x00000001, 0x03F, 0x00000F34, + 0x033, 0x00000002, 0x03F, 0x00000F34, 0x033, 0x00000003, + 0x03F, 0x00000F34, 0xB0000000, 0x00000000, 0x0EF, 0x00000000, + 0x8300100f, 0x0a0a0a0a, 0x40000000, 0x00000000, 0x081, 0x0000F400, + 0x087, 0x00016040, 0x051, 0x00000808, 0x052, 0x00098002, + 0x053, 0x0000FA47, 0x054, 0x00058032, 0x056, 0x00051000, + 0x057, 0x0000CE0A, 0x058, 0x00082030, 0x9300100f, 0x05050505, + 0x40000000, 0x00000000, 0x081, 0x0000F400, 0x087, 0x00016040, + 0x051, 0x00000808, 0x052, 0x00098002, 0x053, 0x0000FA47, + 0x054, 0x00058032, 0x056, 0x00051000, 0x057, 0x0000CE0A, + 0x058, 0x00082030, 0x9300100f, 0x00000000, 0x40000000, 0x00000000, + 0x081, 0x0000F400, 0x087, 0x00016040, 0x051, 0x00000808, + 0x052, 0x00098002, 0x053, 0x0000FA47, 0x054, 0x00058032, + 0x056, 0x00051000, 0x057, 0x0000CE0A, 0x058, 0x00082030, + 0x9300200f, 0x00000000, 0x40000000, 0x00000000, 0x081, 0x0000F400, + 0x087, 0x00016040, 0x051, 0x00000808, 0x052, 0x00098002, + 0x053, 0x0000FA47, 0x054, 0x00058032, 0x056, 0x00051000, + 0x057, 0x0000CE0A, 0x058, 0x00082030, 0x9000100f, 0x0a0a0a0a, + 0x40000000, 0x00000000, 0x081, 0x0000F400, 0x087, 0x00016040, + 0x051, 0x00000808, 0x052, 0x00098002, 0x053, 0x0000FA47, + 0x054, 0x00058032, 0x056, 0x00051000, 0x057, 0x0000CE0A, + 0x058, 0x00082030, 0x9000100f, 0x05050505, 0x40000000, 0x00000000, + 0x081, 0x0000F400, 0x087, 0x00016040, 0x051, 0x00000808, + 0x052, 0x00098002, 0x053, 0x0000FA47, 0x054, 0x00058032, + 0x056, 0x00051000, 0x057, 0x0000CE0A, 0x058, 0x00082030, + 0x9000100f, 0x00000000, 0x40000000, 0x00000000, 0x081, 0x0000F400, + 0x087, 0x00016040, 0x051, 0x00000808, 0x052, 0x00098002, + 0x053, 0x0000FA47, 0x054, 0x00058032, 0x056, 0x00051000, + 0x057, 0x0000CE0A, 0x058, 0x00082030, 0x9000200f, 0x00000000, + 0x40000000, 0x00000000, 0x081, 0x0000F400, 0x087, 0x00016040, + 0x051, 0x00000808, 0x052, 0x00098002, 0x053, 0x0000FA47, + 0x054, 0x00058032, 0x056, 0x00051000, 0x057, 0x0000CE0A, + 0x058, 0x00082030, 0xA0000000, 0x00000000, 0x081, 0x0000F000, + 0x087, 0x00016040, 0x051, 0x00000C00, 0x052, 0x0007C241, + 0x053, 0x0001C069, 0x054, 0x00078032, 0x057, 0x0000CE0A, + 0x058, 0x00058750, 0xB0000000, 0x00000000, 0x0EF, 0x00000800, + 0x8300100f, 0x0a0a0a0a, 0x40000000, 0x00000000, 0x033, 0x00000000, + 0x03F, 0x00000003, 0x033, 0x00000001, 0x03F, 0x00000006, + 0x033, 0x00000002, 0x03F, 0x00000009, 0x033, 0x00000003, + 0x03F, 0x00000026, 0x033, 0x00000004, 0x03F, 0x00000029, + 0x033, 0x00000005, 0x03F, 0x0000002C, 0x033, 0x00000006, + 0x03F, 0x0000002F, 0x033, 0x00000007, 0x03F, 0x00000033, + 0x033, 0x00000008, 0x03F, 0x00000036, 0x033, 0x00000009, + 0x03F, 0x00000039, 0x033, 0x0000000A, 0x03F, 0x0000003C, + 0x9300100f, 0x05050505, 0x40000000, 0x00000000, 0x033, 0x00000000, + 0x03F, 0x00000003, 0x033, 0x00000001, 0x03F, 0x00000006, + 0x033, 0x00000002, 0x03F, 0x00000009, 0x033, 0x00000003, + 0x03F, 0x00000026, 0x033, 0x00000004, 0x03F, 0x00000029, + 0x033, 0x00000005, 0x03F, 0x0000002C, 0x033, 0x00000006, + 0x03F, 0x0000002F, 0x033, 0x00000007, 0x03F, 0x00000033, + 0x033, 0x00000008, 0x03F, 0x00000036, 0x033, 0x00000009, + 0x03F, 0x00000039, 0x033, 0x0000000A, 0x03F, 0x0000003C, + 0x9300100f, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000000, + 0x03F, 0x00000003, 0x033, 0x00000001, 0x03F, 0x00000006, + 0x033, 0x00000002, 0x03F, 0x00000009, 0x033, 0x00000003, + 0x03F, 0x00000026, 0x033, 0x00000004, 0x03F, 0x00000029, + 0x033, 0x00000005, 0x03F, 0x0000002C, 0x033, 0x00000006, + 0x03F, 0x0000002F, 0x033, 0x00000007, 0x03F, 0x00000033, + 0x033, 0x00000008, 0x03F, 0x00000036, 0x033, 0x00000009, + 0x03F, 0x00000039, 0x033, 0x0000000A, 0x03F, 0x0000003C, + 0x9300200f, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000000, + 0x03F, 0x00000003, 0x033, 0x00000001, 0x03F, 0x00000006, + 0x033, 0x00000002, 0x03F, 0x00000009, 0x033, 0x00000003, + 0x03F, 0x00000026, 0x033, 0x00000004, 0x03F, 0x00000029, + 0x033, 0x00000005, 0x03F, 0x0000002C, 0x033, 0x00000006, + 0x03F, 0x0000002F, 0x033, 0x00000007, 0x03F, 0x00000033, + 0x033, 0x00000008, 0x03F, 0x00000036, 0x033, 0x00000009, + 0x03F, 0x00000039, 0x033, 0x0000000A, 0x03F, 0x0000003C, + 0x9000100f, 0x0a0a0a0a, 0x40000000, 0x00000000, 0x033, 0x00000000, + 0x03F, 0x00000003, 0x033, 0x00000001, 0x03F, 0x00000006, + 0x033, 0x00000002, 0x03F, 0x00000009, 0x033, 0x00000003, + 0x03F, 0x00000026, 0x033, 0x00000004, 0x03F, 0x00000029, + 0x033, 0x00000005, 0x03F, 0x0000002C, 0x033, 0x00000006, + 0x03F, 0x0000002F, 0x033, 0x00000007, 0x03F, 0x00000033, + 0x033, 0x00000008, 0x03F, 0x00000036, 0x033, 0x00000009, + 0x03F, 0x00000039, 0x033, 0x0000000A, 0x03F, 0x0000003C, + 0x9000100f, 0x05050505, 0x40000000, 0x00000000, 0x033, 0x00000000, + 0x03F, 0x00000003, 0x033, 0x00000001, 0x03F, 0x00000006, + 0x033, 0x00000002, 0x03F, 0x00000009, 0x033, 0x00000003, + 0x03F, 0x00000026, 0x033, 0x00000004, 0x03F, 0x00000029, + 0x033, 0x00000005, 0x03F, 0x0000002C, 0x033, 0x00000006, + 0x03F, 0x0000002F, 0x033, 0x00000007, 0x03F, 0x00000033, + 0x033, 0x00000008, 0x03F, 0x00000036, 0x033, 0x00000009, + 0x03F, 0x00000039, 0x033, 0x0000000A, 0x03F, 0x0000003C, + 0x9000100f, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000000, + 0x03F, 0x00000003, 0x033, 0x00000001, 0x03F, 0x00000006, + 0x033, 0x00000002, 0x03F, 0x00000009, 0x033, 0x00000003, + 0x03F, 0x00000026, 0x033, 0x00000004, 0x03F, 0x00000029, + 0x033, 0x00000005, 0x03F, 0x0000002C, 0x033, 0x00000006, + 0x03F, 0x0000002F, 0x033, 0x00000007, 0x03F, 0x00000033, + 0x033, 0x00000008, 0x03F, 0x00000036, 0x033, 0x00000009, + 0x03F, 0x00000039, 0x033, 0x0000000A, 0x03F, 0x0000003C, + 0x9000200f, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000000, + 0x03F, 0x00000003, 0x033, 0x00000001, 0x03F, 0x00000006, + 0x033, 0x00000002, 0x03F, 0x00000009, 0x033, 0x00000003, + 0x03F, 0x00000026, 0x033, 0x00000004, 0x03F, 0x00000029, + 0x033, 0x00000005, 0x03F, 0x0000002C, 0x033, 0x00000006, + 0x03F, 0x0000002F, 0x033, 0x00000007, 0x03F, 0x00000033, + 0x033, 0x00000008, 0x03F, 0x00000036, 0x033, 0x00000009, + 0x03F, 0x00000039, 0x033, 0x0000000A, 0x03F, 0x0000003C, + 0xA0000000, 0x00000000, 0x033, 0x00000000, 0x03F, 0x0005142C, + 0x033, 0x00000001, 0x03F, 0x0005144B, 0x033, 0x00000002, + 0x03F, 0x0005144E, 0x033, 0x00000003, 0x03F, 0x00051C69, + 0x033, 0x00000004, 0x03F, 0x00051C6C, 0x033, 0x00000005, + 0x03F, 0x00051C6F, 0x033, 0x00000006, 0x03F, 0x00051CEB, + 0x033, 0x00000007, 0x03F, 0x00051CEE, 0x033, 0x00000008, + 0x03F, 0x00051CF1, 0x033, 0x00000009, 0x03F, 0x00051CF4, + 0x033, 0x0000000A, 0x03F, 0x00051CF7, 0xB0000000, 0x00000000, + 0x0EF, 0x00000000, 0x0EF, 0x00000010, 0x033, 0x00000000, + 0x008, 0x0009C060, 0x033, 0x00000001, 0x008, 0x0009C060, + 0x0EF, 0x00000000, 0x033, 0x000000A2, 0x0EF, 0x00080000, + 0x03E, 0x0000593F, 0x03F, 0x000C0F4F, 0x0EF, 0x00000000, + 0x033, 0x000000A3, 0x0EF, 0x00080000, 0x03E, 0x00005934, + 0x03F, 0x0005AFCF, 0x0EF, 0x00000000, + +}; + +void odm_read_and_config_mp_8822b_radioa(struct phy_dm_struct *dm) +{ + u32 i = 0; + u8 c_cond; + bool is_matched = true, is_skipped = false; + u32 array_len = sizeof(array_mp_8822b_radioa) / sizeof(u32); + u32 *array = array_mp_8822b_radioa; + + u32 v1 = 0, v2 = 0, pre_v1 = 0, pre_v2 = 0; + + ODM_RT_TRACE(dm, ODM_COMP_INIT, + "===> %s\n", __func__); + + for (; (i + 1) < array_len; i = i + 2) { + v1 = array[i]; + v2 = array[i + 1]; + + if (v1 & BIT(31)) { /* positive condition*/ + c_cond = (u8)((v1 & (BIT(29) | BIT(28))) >> 28); + if (c_cond == COND_ENDIF) { /*end*/ + is_matched = true; + is_skipped = false; + ODM_RT_TRACE(dm, ODM_COMP_INIT, "ENDIF\n"); + } else if (c_cond == COND_ELSE) { /*else*/ + is_matched = is_skipped ? false : true; + ODM_RT_TRACE(dm, ODM_COMP_INIT, "ELSE\n"); + } else { /*if , else if*/ + pre_v1 = v1; + pre_v2 = v2; + ODM_RT_TRACE(dm, ODM_COMP_INIT, + "IF or ELSE IF\n"); + } + } else if (v1 & BIT(30)) { /*negative condition*/ + if (is_skipped) { + is_matched = false; + continue; + } + + if (check_positive(dm, pre_v1, pre_v2, v1, v2)) { + is_matched = true; + is_skipped = true; + } else { + is_matched = false; + is_skipped = false; + } + } else if (is_matched) { + odm_config_rf_radio_a_8822b(dm, v1, v2); + } + } +} + +u32 odm_get_version_mp_8822b_radioa(void) { return 67; } + +/****************************************************************************** + * radiob.TXT + ******************************************************************************/ + +static u32 array_mp_8822b_radiob[] = { + 0x000, 0x00030000, 0x8300100f, 0x0a0a0a0a, 0x40000000, 0x00000000, + 0x001, 0x0004002D, 0x9300100f, 0x05050505, 0x40000000, 0x00000000, + 0x001, 0x0004002D, 0x9300100f, 0x00000000, 0x40000000, 0x00000000, + 0x001, 0x0004002D, 0x9300200f, 0x00000000, 0x40000000, 0x00000000, + 0x001, 0x0004002D, 0x9000100f, 0x0a0a0a0a, 0x40000000, 0x00000000, + 0x001, 0x0004002D, 0x9000100f, 0x05050505, 0x40000000, 0x00000000, + 0x001, 0x0004002D, 0x9000100f, 0x00000000, 0x40000000, 0x00000000, + 0x001, 0x0004002D, 0x9000200f, 0x00000000, 0x40000000, 0x00000000, + 0x001, 0x0004002D, 0x9300200c, 0x00000000, 0x40000000, 0x00000000, + 0x001, 0x00040029, 0x93012100, 0x00000000, 0x40000000, 0x00000000, + 0x001, 0x00040029, 0x93002100, 0x00000000, 0x40000000, 0x00000000, + 0x001, 0x00040029, 0x9000200c, 0x00000000, 0x40000000, 0x00000000, + 0x001, 0x00040029, 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x001, 0x00040029, 0x93002000, 0x00000000, 0x40000000, 0x00000000, + 0x001, 0x00040029, 0x90002100, 0x00000000, 0x40000000, 0x00000000, + 0x001, 0x00040029, 0x90002000, 0x00000000, 0x40000000, 0x00000000, + 0x001, 0x00040029, 0xA0000000, 0x00000000, 0x001, 0x00040029, + 0xB0000000, 0x00000000, 0x018, 0x00010D24, 0x0EF, 0x00080000, + 0x033, 0x00000002, 0x03E, 0x0000003F, 0x03F, 0x000C0F4E, + 0x033, 0x00000001, 0x03E, 0x00000034, 0x03F, 0x0004080E, + 0x0EF, 0x00080000, 0x0DF, 0x00002449, 0x033, 0x00000024, + 0x03E, 0x0000003F, 0x03F, 0x00060FDE, 0x0EF, 0x00000000, + 0x0EF, 0x00080000, 0x033, 0x00000025, 0x03E, 0x00000037, + 0x03F, 0x0007EFCE, 0x0EF, 0x00000000, 0x0EF, 0x00080000, + 0x033, 0x00000026, 0x03E, 0x00000037, 0x03F, 0x000DEFCE, + 0x0EF, 0x00000000, 0x0DF, 0x00000009, 0x018, 0x00010524, + 0x089, 0x00000207, 0x8300100f, 0x0a0a0a0a, 0x40000000, 0x00000000, + 0x08A, 0x000FF186, 0x9300100f, 0x05050505, 0x40000000, 0x00000000, + 0x08A, 0x000FE186, 0x9300100f, 0x00000000, 0x40000000, 0x00000000, + 0x08A, 0x000FF186, 0x9300200f, 0x00000000, 0x40000000, 0x00000000, + 0x08A, 0x000FF186, 0x9000100f, 0x0a0a0a0a, 0x40000000, 0x00000000, + 0x08A, 0x000FF186, 0x9000100f, 0x05050505, 0x40000000, 0x00000000, + 0x08A, 0x000FE186, 0xA0000000, 0x00000000, 0x08A, 0x000FF186, + 0xB0000000, 0x00000000, 0x08B, 0x00061E3C, 0x08C, 0x000112C7, + 0x08D, 0x000F4988, 0x08E, 0x00064D40, 0x0EF, 0x00020000, + 0x033, 0x00000007, 0x8300100f, 0x0a0a0a0a, 0x40000000, 0x00000000, + 0x03E, 0x00004040, 0x9300100f, 0x05050505, 0x40000000, 0x00000000, + 0x03E, 0x00004080, 0x9300100f, 0x00000000, 0x40000000, 0x00000000, + 0x03E, 0x00004040, 0x9300200f, 0x00000000, 0x40000000, 0x00000000, + 0x03E, 0x00004040, 0x9000100f, 0x0a0a0a0a, 0x40000000, 0x00000000, + 0x03E, 0x00004040, 0x9000100f, 0x05050505, 0x40000000, 0x00000000, + 0x03E, 0x00004080, 0x9000100f, 0x00000000, 0x40000000, 0x00000000, + 0x03E, 0x00004040, 0x9000200f, 0x00000000, 0x40000000, 0x00000000, + 0x03E, 0x00004040, 0x9300200c, 0x00000000, 0x40000000, 0x00000000, + 0x03E, 0x00004040, 0x93012100, 0x00000000, 0x40000000, 0x00000000, + 0x03E, 0x00004000, 0x93002100, 0x00000000, 0x40000000, 0x00000000, + 0x03E, 0x00004000, 0x93011000, 0x00000000, 0x40000000, 0x00000000, + 0x03E, 0x00004000, 0x9000200c, 0x00000000, 0x40000000, 0x00000000, + 0x03E, 0x00004040, 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x03E, 0x00004040, 0x93002000, 0x00000000, 0x40000000, 0x00000000, + 0x03E, 0x00004000, 0xA0000000, 0x00000000, 0x03E, 0x00004000, + 0xB0000000, 0x00000000, 0x8300100f, 0x0a0a0a0a, 0x40000000, 0x00000000, + 0x03F, 0x000C3186, 0x9300100f, 0x05050505, 0x40000000, 0x00000000, + 0x03F, 0x000C3186, 0x9300100f, 0x00000000, 0x40000000, 0x00000000, + 0x03F, 0x000C3186, 0x9300200f, 0x00000000, 0x40000000, 0x00000000, + 0x03F, 0x000C3186, 0x9000100f, 0x0a0a0a0a, 0x40000000, 0x00000000, + 0x03F, 0x000C3186, 0x9000100f, 0x05050505, 0x40000000, 0x00000000, + 0x03F, 0x000C3186, 0x9000100f, 0x00000000, 0x40000000, 0x00000000, + 0x03F, 0x000C3186, 0x9000200f, 0x00000000, 0x40000000, 0x00000000, + 0x03F, 0x000C3186, 0x9300200c, 0x00000000, 0x40000000, 0x00000000, + 0x03F, 0x000C3186, 0x93012100, 0x00000000, 0x40000000, 0x00000000, + 0x03F, 0x000C3186, 0x93002100, 0x00000000, 0x40000000, 0x00000000, + 0x03F, 0x000C0006, 0x93011000, 0x00000000, 0x40000000, 0x00000000, + 0x03F, 0x000C3186, 0x9000200c, 0x00000000, 0x40000000, 0x00000000, + 0x03F, 0x000C3186, 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x03F, 0x000C3186, 0x93002000, 0x00000000, 0x40000000, 0x00000000, + 0x03F, 0x000C0006, 0x93001000, 0x00000000, 0x40000000, 0x00000000, + 0x03F, 0x000C3186, 0xA0000000, 0x00000000, 0x03F, 0x000C3186, + 0xB0000000, 0x00000000, 0x033, 0x00000006, 0x03E, 0x00004080, + 0x03F, 0x000C3186, 0x033, 0x00000005, 0x03E, 0x000040C8, + 0x03F, 0x000C3186, 0x033, 0x00000004, 0x03E, 0x00004190, + 0x03F, 0x000C3186, 0x033, 0x00000003, 0x03E, 0x00004998, + 0x03F, 0x000C3186, 0x033, 0x00000002, 0x03E, 0x00005840, + 0x03F, 0x000C3186, 0x033, 0x00000001, 0x03E, 0x000058C2, + 0x03F, 0x000C3186, 0x033, 0x00000000, 0x03E, 0x00005930, + 0x03F, 0x000C3186, 0x033, 0x0000000F, 0x8300100f, 0x0a0a0a0a, + 0x40000000, 0x00000000, 0x03E, 0x00004040, 0x9300100f, 0x05050505, + 0x40000000, 0x00000000, 0x03E, 0x00004080, 0x9300100f, 0x00000000, + 0x40000000, 0x00000000, 0x03E, 0x00004040, 0x9300200f, 0x00000000, + 0x40000000, 0x00000000, 0x03E, 0x00004040, 0x9000100f, 0x0a0a0a0a, + 0x40000000, 0x00000000, 0x03E, 0x00004040, 0x9000100f, 0x05050505, + 0x40000000, 0x00000000, 0x03E, 0x00004080, 0x9000100f, 0x00000000, + 0x40000000, 0x00000000, 0x03E, 0x00004040, 0x9000200f, 0x00000000, + 0x40000000, 0x00000000, 0x03E, 0x00004040, 0x9300200c, 0x00000000, + 0x40000000, 0x00000000, 0x03E, 0x00004040, 0x93012100, 0x00000000, + 0x40000000, 0x00000000, 0x03E, 0x00004000, 0x93002100, 0x00000000, + 0x40000000, 0x00000000, 0x03E, 0x00004000, 0x93011000, 0x00000000, + 0x40000000, 0x00000000, 0x03E, 0x00004000, 0x9000200c, 0x00000000, + 0x40000000, 0x00000000, 0x03E, 0x00004040, 0x90001004, 0x00000000, + 0x40000000, 0x00000000, 0x03E, 0x00004040, 0x93002000, 0x00000000, + 0x40000000, 0x00000000, 0x03E, 0x00004000, 0xA0000000, 0x00000000, + 0x03E, 0x00004000, 0xB0000000, 0x00000000, 0x8300100f, 0x0a0a0a0a, + 0x40000000, 0x00000000, 0x03F, 0x000C3186, 0x9300100f, 0x05050505, + 0x40000000, 0x00000000, 0x03F, 0x000C3186, 0x9300100f, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x000C3186, 0x9300200f, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x000C3186, 0x9000100f, 0x0a0a0a0a, + 0x40000000, 0x00000000, 0x03F, 0x000C3186, 0x9000100f, 0x05050505, + 0x40000000, 0x00000000, 0x03F, 0x000C3186, 0x9000100f, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x000C3186, 0x9000200f, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x000C3186, 0x9300200c, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x000C3186, 0x93012100, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x000C3186, 0x93002100, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x000C3186, 0x93011000, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x000C3186, 0x9000200c, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x000C3186, 0x90001004, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x000C3186, 0x93002000, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x000C0006, 0x93001000, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x000C3186, 0xA0000000, 0x00000000, + 0x03F, 0x000C3186, 0xB0000000, 0x00000000, 0x033, 0x0000000E, + 0x03E, 0x00004080, 0x03F, 0x000C3186, 0x033, 0x0000000D, + 0x03E, 0x000040C8, 0x03F, 0x000C3186, 0x033, 0x0000000C, + 0x03E, 0x00004190, 0x03F, 0x000C3186, 0x033, 0x0000000B, + 0x03E, 0x00004998, 0x03F, 0x000C3186, 0x033, 0x0000000A, + 0x03E, 0x00005840, 0x03F, 0x000C3186, 0x033, 0x00000009, + 0x03E, 0x000058C2, 0x03F, 0x000C3186, 0x033, 0x00000008, + 0x03E, 0x00005930, 0x03F, 0x000C3186, 0x033, 0x00000017, + 0x8300100f, 0x0a0a0a0a, 0x40000000, 0x00000000, 0x03E, 0x00004040, + 0x9300100f, 0x05050505, 0x40000000, 0x00000000, 0x03E, 0x00004080, + 0x9300100f, 0x00000000, 0x40000000, 0x00000000, 0x03E, 0x00004040, + 0x9300200f, 0x00000000, 0x40000000, 0x00000000, 0x03E, 0x00004040, + 0x9000100f, 0x0a0a0a0a, 0x40000000, 0x00000000, 0x03E, 0x00004040, + 0x9000100f, 0x05050505, 0x40000000, 0x00000000, 0x03E, 0x00004080, + 0x9000100f, 0x00000000, 0x40000000, 0x00000000, 0x03E, 0x00004040, + 0x9000200f, 0x00000000, 0x40000000, 0x00000000, 0x03E, 0x00004040, + 0x9300200c, 0x00000000, 0x40000000, 0x00000000, 0x03E, 0x00004040, + 0x93012100, 0x00000000, 0x40000000, 0x00000000, 0x03E, 0x00004000, + 0x93002100, 0x00000000, 0x40000000, 0x00000000, 0x03E, 0x00004000, + 0x93011000, 0x00000000, 0x40000000, 0x00000000, 0x03E, 0x00004000, + 0x9000200c, 0x00000000, 0x40000000, 0x00000000, 0x03E, 0x00004040, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, 0x03E, 0x00004040, + 0x93002000, 0x00000000, 0x40000000, 0x00000000, 0x03E, 0x00004000, + 0xA0000000, 0x00000000, 0x03E, 0x00004000, 0xB0000000, 0x00000000, + 0x8300100f, 0x0a0a0a0a, 0x40000000, 0x00000000, 0x03F, 0x000C3186, + 0x9300100f, 0x05050505, 0x40000000, 0x00000000, 0x03F, 0x000C3186, + 0x9300100f, 0x00000000, 0x40000000, 0x00000000, 0x03F, 0x000C3186, + 0x9300200f, 0x00000000, 0x40000000, 0x00000000, 0x03F, 0x000C3186, + 0x9000100f, 0x0a0a0a0a, 0x40000000, 0x00000000, 0x03F, 0x000C3186, + 0x9000100f, 0x05050505, 0x40000000, 0x00000000, 0x03F, 0x000C3186, + 0x9000100f, 0x00000000, 0x40000000, 0x00000000, 0x03F, 0x000C3186, + 0x9000200f, 0x00000000, 0x40000000, 0x00000000, 0x03F, 0x000C3186, + 0x9300200c, 0x00000000, 0x40000000, 0x00000000, 0x03F, 0x000C3186, + 0x93012100, 0x00000000, 0x40000000, 0x00000000, 0x03F, 0x000C3186, + 0x93002100, 0x00000000, 0x40000000, 0x00000000, 0x03F, 0x000DFF86, + 0x93011000, 0x00000000, 0x40000000, 0x00000000, 0x03F, 0x000C3186, + 0x9000200c, 0x00000000, 0x40000000, 0x00000000, 0x03F, 0x000C3186, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, 0x03F, 0x000C3186, + 0x93002000, 0x00000000, 0x40000000, 0x00000000, 0x03F, 0x000C0006, + 0x93001000, 0x00000000, 0x40000000, 0x00000000, 0x03F, 0x000C3186, + 0xA0000000, 0x00000000, 0x03F, 0x000C3186, 0xB0000000, 0x00000000, + 0x033, 0x00000016, 0x03E, 0x00004080, 0x03F, 0x000C3186, + 0x033, 0x00000015, 0x03E, 0x000040C8, 0x03F, 0x000C3186, + 0x033, 0x00000014, 0x03E, 0x00004190, 0x03F, 0x000C3186, + 0x033, 0x00000013, 0x03E, 0x00004998, 0x03F, 0x000C3186, + 0x033, 0x00000012, 0x03E, 0x00005840, 0x03F, 0x000C3186, + 0x033, 0x00000011, 0x03E, 0x000058C2, 0x03F, 0x000C3186, + 0x033, 0x00000010, 0x03E, 0x00005930, 0x03F, 0x000C3186, + 0x0EF, 0x00000000, 0x0EF, 0x00004000, 0x033, 0x00000000, + 0x03F, 0x0000000A, 0x033, 0x00000001, 0x8300100f, 0x0a0a0a0a, + 0x40000000, 0x00000000, 0x03F, 0x00000000, 0x9300100f, 0x05050505, + 0x40000000, 0x00000000, 0x03F, 0x00000000, 0x9300100f, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x00000000, 0x9300200f, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x00000000, 0x9000100f, 0x0a0a0a0a, + 0x40000000, 0x00000000, 0x03F, 0x00000000, 0x9000100f, 0x05050505, + 0x40000000, 0x00000000, 0x03F, 0x00000000, 0x9000100f, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x00000000, 0x9000200f, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x00000000, 0x9300200c, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x00000000, 0x93012100, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x00000002, 0x93002100, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x00000000, 0x93011000, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x00000005, 0x9000200c, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x00000000, 0x90001004, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x00000000, 0x93002000, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x00000000, 0x93001000, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x00000005, 0x90002100, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x00000000, 0x90002000, 0x00000000, + 0x40000000, 0x00000000, 0x03F, 0x00000000, 0xA0000000, 0x00000000, + 0x03F, 0x00000005, 0xB0000000, 0x00000000, 0x033, 0x00000002, + 0x03F, 0x00000000, 0x0EF, 0x00000000, 0x018, 0x00000401, + 0x084, 0x00001209, 0x086, 0x000001A0, 0x8300100f, 0x0a0a0a0a, + 0x40000000, 0x00000000, 0x087, 0x00068080, 0x9300100f, 0x05050505, + 0x40000000, 0x00000000, 0x087, 0x00068080, 0x9300100f, 0x00000000, + 0x40000000, 0x00000000, 0x087, 0x00068080, 0x9300200f, 0x00000000, + 0x40000000, 0x00000000, 0x087, 0x00068080, 0x9000100f, 0x0a0a0a0a, + 0x40000000, 0x00000000, 0x087, 0x00068080, 0x9000100f, 0x05050505, + 0x40000000, 0x00000000, 0x087, 0x00068080, 0x9000100f, 0x00000000, + 0x40000000, 0x00000000, 0x087, 0x00068080, 0x9000200f, 0x00000000, + 0x40000000, 0x00000000, 0x087, 0x00068080, 0xA0000000, 0x00000000, + 0x087, 0x000E8180, 0xB0000000, 0x00000000, 0x088, 0x00070020, + 0x0DE, 0x00000010, 0x0EF, 0x00008000, 0x033, 0x0000000F, + 0x03F, 0x0000003C, 0x033, 0x0000000E, 0x03F, 0x00000038, + 0x033, 0x0000000D, 0x03F, 0x00000030, 0x033, 0x0000000C, + 0x03F, 0x00000028, 0x033, 0x0000000B, 0x03F, 0x00000020, + 0x033, 0x0000000A, 0x03F, 0x00000018, 0x033, 0x00000009, + 0x03F, 0x00000010, 0x033, 0x00000008, 0x03F, 0x00000008, + 0x033, 0x00000007, 0x03F, 0x0000003C, 0x033, 0x00000006, + 0x03F, 0x00000038, 0x033, 0x00000005, 0x03F, 0x00000030, + 0x033, 0x00000004, 0x03F, 0x00000028, 0x033, 0x00000003, + 0x03F, 0x00000020, 0x033, 0x00000002, 0x03F, 0x00000018, + 0x033, 0x00000001, 0x03F, 0x00000010, 0x033, 0x00000000, + 0x03F, 0x00000008, 0x0EF, 0x00000000, 0x018, 0x00018D24, + 0xFFE, 0x00000000, 0xFFE, 0x00000000, 0xFFE, 0x00000000, + 0xFFE, 0x00000000, 0x018, 0x00010D24, 0x01B, 0x00075A40, + 0x0EE, 0x00000002, 0x033, 0x00000000, 0x03F, 0x00000004, + 0x033, 0x00000001, 0x03F, 0x00000004, 0x033, 0x00000002, + 0x03F, 0x00000004, 0x033, 0x00000003, 0x03F, 0x00000004, + 0x033, 0x00000004, 0x03F, 0x00000004, 0x033, 0x00000005, + 0x03F, 0x00000006, 0x033, 0x00000006, 0x03F, 0x00000002, + 0x033, 0x00000007, 0x03F, 0x00000000, 0x0EE, 0x00000000, + 0x8300100f, 0x0a0a0a0a, 0x40000000, 0x00000000, 0x061, 0x0005D4A0, + 0x062, 0x0000D203, 0x063, 0x00000062, 0x9300100f, 0x05050505, + 0x40000000, 0x00000000, 0x061, 0x0005D4A0, 0x062, 0x0000D203, + 0x063, 0x00000062, 0x9300100f, 0x00000000, 0x40000000, 0x00000000, + 0x061, 0x0005D4A0, 0x062, 0x0000D203, 0x063, 0x00000062, + 0x9300200f, 0x00000000, 0x40000000, 0x00000000, 0x061, 0x0005D2A1, + 0x062, 0x0000D3A2, 0x063, 0x00000062, 0x9000100f, 0x0a0a0a0a, + 0x40000000, 0x00000000, 0x061, 0x0005D4A0, 0x062, 0x0000D203, + 0x063, 0x00000062, 0x9000100f, 0x05050505, 0x40000000, 0x00000000, + 0x061, 0x0005D4A0, 0x062, 0x0000D203, 0x063, 0x00000062, + 0x9000100f, 0x00000000, 0x40000000, 0x00000000, 0x061, 0x0005D4A0, + 0x062, 0x0000D203, 0x063, 0x00000062, 0x9000200f, 0x00000000, + 0x40000000, 0x00000000, 0x061, 0x0005D2A1, 0x062, 0x0000D3A2, + 0x063, 0x00000062, 0x9300200c, 0x00000000, 0x40000000, 0x00000000, + 0x061, 0x0005D2A1, 0x062, 0x0000D3A2, 0x063, 0x00000062, + 0x93012100, 0x00000000, 0x40000000, 0x00000000, 0x061, 0x0005D2A1, + 0x062, 0x0000D3A2, 0x063, 0x00000002, 0x93002100, 0x00000000, + 0x40000000, 0x00000000, 0x061, 0x0005D2A1, 0x062, 0x0000D3A2, + 0x063, 0x00000002, 0x93011000, 0x00000000, 0x40000000, 0x00000000, + 0x061, 0x0005D3D1, 0x062, 0x0000D3A2, 0x063, 0x00000002, + 0x9000200c, 0x00000000, 0x40000000, 0x00000000, 0x061, 0x0005D2A1, + 0x062, 0x0000D3A2, 0x063, 0x00000062, 0x90001004, 0x00000000, + 0x40000000, 0x00000000, 0x061, 0x0005D3D1, 0x062, 0x0000D3A2, + 0x063, 0x00000002, 0x93002000, 0x00000000, 0x40000000, 0x00000000, + 0x061, 0x0005D2A1, 0x062, 0x0000D3A2, 0x063, 0x00000002, + 0x93001000, 0x00000000, 0x40000000, 0x00000000, 0x061, 0x0005D3D1, + 0x062, 0x0000D3A2, 0x063, 0x00000002, 0x90002100, 0x00000000, + 0x40000000, 0x00000000, 0x061, 0x0005D2A1, 0x062, 0x0000D3A2, + 0x063, 0x00000002, 0x90002000, 0x00000000, 0x40000000, 0x00000000, + 0x061, 0x0005D2A1, 0x062, 0x0000D3A2, 0x063, 0x00000002, + 0xA0000000, 0x00000000, 0x061, 0x0005D3D0, 0x062, 0x0000D303, + 0x063, 0x00000002, 0xB0000000, 0x00000000, 0x0EF, 0x00000200, + 0x8300100f, 0x0a0a0a0a, 0x40000000, 0x00000000, 0x030, 0x000004A3, + 0x030, 0x000014A3, 0x030, 0x000024A3, 0x030, 0x000034A3, + 0x030, 0x000044A3, 0x030, 0x000054A3, 0x030, 0x000064A3, + 0x030, 0x000074A3, 0x030, 0x000084A3, 0x030, 0x000094A3, + 0x030, 0x0000A4A3, 0x030, 0x0000B4A3, 0x9300100f, 0x05050505, + 0x40000000, 0x00000000, 0x030, 0x000004A3, 0x030, 0x000014A3, + 0x030, 0x000024A3, 0x030, 0x000034A3, 0x030, 0x000044A3, + 0x030, 0x000054A3, 0x030, 0x000064A3, 0x030, 0x000074A3, + 0x030, 0x000084A3, 0x030, 0x000094A3, 0x030, 0x0000A4A3, + 0x030, 0x0000B4A3, 0x9300100f, 0x00000000, 0x40000000, 0x00000000, + 0x030, 0x000004A3, 0x030, 0x000014A3, 0x030, 0x000024A3, + 0x030, 0x000034A3, 0x030, 0x000044A3, 0x030, 0x000054A3, + 0x030, 0x000064A3, 0x030, 0x000074A3, 0x030, 0x000084A3, + 0x030, 0x000094A3, 0x030, 0x0000A4A3, 0x030, 0x0000B4A3, + 0x9300200f, 0x00000000, 0x40000000, 0x00000000, 0x030, 0x000002A6, + 0x030, 0x000012A6, 0x030, 0x000022A6, 0x030, 0x000032A6, + 0x030, 0x000042A6, 0x030, 0x000052A6, 0x030, 0x000062A6, + 0x030, 0x000072A6, 0x030, 0x000082A6, 0x030, 0x000092A6, + 0x030, 0x0000A2A6, 0x030, 0x0000B2A6, 0x9000100f, 0x0a0a0a0a, + 0x40000000, 0x00000000, 0x030, 0x000004A0, 0x030, 0x000014A0, + 0x030, 0x000024A0, 0x030, 0x000034A0, 0x030, 0x000044A0, + 0x030, 0x000054A0, 0x030, 0x000064A0, 0x030, 0x000074A0, + 0x030, 0x000084A0, 0x030, 0x000094A0, 0x030, 0x0000A4A0, + 0x030, 0x0000B4A0, 0x9000100f, 0x05050505, 0x40000000, 0x00000000, + 0x030, 0x000004A0, 0x030, 0x000014A0, 0x030, 0x000024A0, + 0x030, 0x000034A0, 0x030, 0x000044A0, 0x030, 0x000054A0, + 0x030, 0x000064A0, 0x030, 0x000074A0, 0x030, 0x000084A0, + 0x030, 0x000094A0, 0x030, 0x0000A4A0, 0x030, 0x0000B4A0, + 0x9000100f, 0x00000000, 0x40000000, 0x00000000, 0x030, 0x000004A0, + 0x030, 0x000014A0, 0x030, 0x000024A0, 0x030, 0x000034A0, + 0x030, 0x000044A0, 0x030, 0x000054A0, 0x030, 0x000064A0, + 0x030, 0x000074A0, 0x030, 0x000084A0, 0x030, 0x000094A0, + 0x030, 0x0000A4A0, 0x030, 0x0000B4A0, 0x9000200f, 0x00000000, + 0x40000000, 0x00000000, 0x030, 0x000002A1, 0x030, 0x000012A1, + 0x030, 0x000022A1, 0x030, 0x000032A1, 0x030, 0x000042A1, + 0x030, 0x000052A1, 0x030, 0x000062A1, 0x030, 0x000072A1, + 0x030, 0x000082A1, 0x030, 0x000092A1, 0x030, 0x0000A2A1, + 0x030, 0x0000B2A1, 0x9300200c, 0x00000000, 0x40000000, 0x00000000, + 0x030, 0x000002A6, 0x030, 0x000012A6, 0x030, 0x000022A6, + 0x030, 0x000032A6, 0x030, 0x000042A6, 0x030, 0x000052A6, + 0x030, 0x000062A6, 0x030, 0x000072A6, 0x030, 0x000082A6, + 0x030, 0x000092A6, 0x030, 0x0000A2A6, 0x030, 0x0000B2A6, + 0x93012100, 0x00000000, 0x40000000, 0x00000000, 0x030, 0x000002F4, + 0x030, 0x000012F4, 0x030, 0x000022F4, 0x030, 0x000032F4, + 0x030, 0x00004365, 0x030, 0x00005365, 0x030, 0x00006365, + 0x030, 0x00007365, 0x030, 0x000082A4, 0x030, 0x000092A4, + 0x030, 0x0000A2A4, 0x030, 0x0000B2A4, 0x93002100, 0x00000000, + 0x40000000, 0x00000000, 0x030, 0x000004A4, 0x030, 0x000014A4, + 0x030, 0x000024A4, 0x030, 0x000034A4, 0x030, 0x000043A4, + 0x030, 0x000053A4, 0x030, 0x000063A4, 0x030, 0x000073A4, + 0x030, 0x000083A5, 0x030, 0x000093A5, 0x030, 0x0000A3A5, + 0x030, 0x0000B3A5, 0x93011000, 0x00000000, 0x40000000, 0x00000000, + 0x030, 0x000003A1, 0x030, 0x000013A1, 0x030, 0x000023A1, + 0x030, 0x000033A1, 0x030, 0x000043A4, 0x030, 0x000053A4, + 0x030, 0x000063A4, 0x030, 0x000073A4, 0x030, 0x000083A6, + 0x030, 0x000093A6, 0x030, 0x0000A3A6, 0x030, 0x0000B3A6, + 0x9000200c, 0x00000000, 0x40000000, 0x00000000, 0x030, 0x000002A1, + 0x030, 0x000012A1, 0x030, 0x000022A1, 0x030, 0x000032A1, + 0x030, 0x000042A1, 0x030, 0x000052A1, 0x030, 0x000062A1, + 0x030, 0x000072A1, 0x030, 0x000082A1, 0x030, 0x000092A1, + 0x030, 0x0000A2A1, 0x030, 0x0000B2A1, 0x90001004, 0x00000000, + 0x40000000, 0x00000000, 0x030, 0x00000382, 0x030, 0x00001382, + 0x030, 0x00002382, 0x030, 0x00003382, 0x030, 0x00004445, + 0x030, 0x00005445, 0x030, 0x00006445, 0x030, 0x00007445, + 0x030, 0x00008425, 0x030, 0x00009425, 0x030, 0x0000A425, + 0x030, 0x0000B425, 0x93002000, 0x00000000, 0x40000000, 0x00000000, + 0x030, 0x00000303, 0x030, 0x00001303, 0x030, 0x00002303, + 0x030, 0x00003303, 0x030, 0x000043A4, 0x030, 0x000053A4, + 0x030, 0x000063A4, 0x030, 0x000073A4, 0x030, 0x00008365, + 0x030, 0x00009365, 0x030, 0x0000A365, 0x030, 0x0000B365, + 0x93001000, 0x00000000, 0x40000000, 0x00000000, 0x030, 0x000003A1, + 0x030, 0x000013A1, 0x030, 0x000023A1, 0x030, 0x000033A1, + 0x030, 0x00004364, 0x030, 0x00005364, 0x030, 0x00006364, + 0x030, 0x00007364, 0x030, 0x00008564, 0x030, 0x00009564, + 0x030, 0x0000A564, 0x030, 0x0000B564, 0x90002100, 0x00000000, + 0x40000000, 0x00000000, 0x030, 0x000004A1, 0x030, 0x000014A1, + 0x030, 0x000024A1, 0x030, 0x000034A1, 0x030, 0x000043A1, + 0x030, 0x000053A1, 0x030, 0x000063A1, 0x030, 0x000073A1, + 0x030, 0x000083A1, 0x030, 0x000093A1, 0x030, 0x0000A3A1, + 0x030, 0x0000B3A1, 0x90002000, 0x00000000, 0x40000000, 0x00000000, + 0x030, 0x000004A0, 0x030, 0x000014A0, 0x030, 0x000024A0, + 0x030, 0x000034A0, 0x030, 0x000043A1, 0x030, 0x000053A1, + 0x030, 0x000063A1, 0x030, 0x000073A1, 0x030, 0x000083A2, + 0x030, 0x000093A2, 0x030, 0x0000A3A2, 0x030, 0x0000B3A2, + 0xA0000000, 0x00000000, 0x030, 0x000002D0, 0x030, 0x000012D0, + 0x030, 0x000022D0, 0x030, 0x000032D0, 0x030, 0x000042D0, + 0x030, 0x000052D0, 0x030, 0x000062D0, 0x030, 0x000072D0, + 0x030, 0x000082D0, 0x030, 0x000092D0, 0x030, 0x0000A2D0, + 0x030, 0x0000B2D0, 0xB0000000, 0x00000000, 0x0EF, 0x00000000, + 0x0EF, 0x00000080, 0x8300100f, 0x0a0a0a0a, 0x40000000, 0x00000000, + 0x030, 0x00000203, 0x030, 0x00001203, 0x030, 0x00002203, + 0x030, 0x00003203, 0x030, 0x00004203, 0x030, 0x00005203, + 0x030, 0x00006203, 0x030, 0x00007203, 0x030, 0x00008203, + 0x030, 0x00009203, 0x030, 0x0000A203, 0x030, 0x0000B203, + 0x9300100f, 0x05050505, 0x40000000, 0x00000000, 0x030, 0x00000203, + 0x030, 0x00001203, 0x030, 0x00002203, 0x030, 0x00003203, + 0x030, 0x00004203, 0x030, 0x00005203, 0x030, 0x00006203, + 0x030, 0x00007203, 0x030, 0x00008203, 0x030, 0x00009203, + 0x030, 0x0000A203, 0x030, 0x0000B203, 0x9300100f, 0x00000000, + 0x40000000, 0x00000000, 0x030, 0x00000203, 0x030, 0x00001203, + 0x030, 0x00002203, 0x030, 0x00003203, 0x030, 0x00004203, + 0x030, 0x00005203, 0x030, 0x00006203, 0x030, 0x00007203, + 0x030, 0x00008203, 0x030, 0x00009203, 0x030, 0x0000A203, + 0x030, 0x0000B203, 0x9300200f, 0x00000000, 0x40000000, 0x00000000, + 0x030, 0x000003A2, 0x030, 0x000013A2, 0x030, 0x000023A2, + 0x030, 0x000033A2, 0x030, 0x000043A2, 0x030, 0x000053A2, + 0x030, 0x000063A2, 0x030, 0x000073A2, 0x030, 0x000083A2, + 0x030, 0x000093A2, 0x030, 0x0000A3A2, 0x030, 0x0000B3A2, + 0x9000100f, 0x0a0a0a0a, 0x40000000, 0x00000000, 0x030, 0x00000203, + 0x030, 0x00001203, 0x030, 0x00002203, 0x030, 0x00003203, + 0x030, 0x00004203, 0x030, 0x00005203, 0x030, 0x00006203, + 0x030, 0x00007203, 0x030, 0x00008203, 0x030, 0x00009203, + 0x030, 0x0000A203, 0x030, 0x0000B203, 0x9000100f, 0x05050505, + 0x40000000, 0x00000000, 0x030, 0x00000203, 0x030, 0x00001203, + 0x030, 0x00002203, 0x030, 0x00003203, 0x030, 0x00004203, + 0x030, 0x00005203, 0x030, 0x00006203, 0x030, 0x00007203, + 0x030, 0x00008203, 0x030, 0x00009203, 0x030, 0x0000A203, + 0x030, 0x0000B203, 0x9000100f, 0x00000000, 0x40000000, 0x00000000, + 0x030, 0x00000203, 0x030, 0x00001203, 0x030, 0x00002203, + 0x030, 0x00003203, 0x030, 0x00004203, 0x030, 0x00005203, + 0x030, 0x00006203, 0x030, 0x00007203, 0x030, 0x00008203, + 0x030, 0x00009203, 0x030, 0x0000A203, 0x030, 0x0000B203, + 0x9000200f, 0x00000000, 0x40000000, 0x00000000, 0x030, 0x000003A2, + 0x030, 0x000013A2, 0x030, 0x000023A2, 0x030, 0x000033A2, + 0x030, 0x000043A2, 0x030, 0x000053A2, 0x030, 0x000063A2, + 0x030, 0x000073A2, 0x030, 0x000083A2, 0x030, 0x000093A2, + 0x030, 0x0000A3A2, 0x030, 0x0000B3A2, 0x9300200c, 0x00000000, + 0x40000000, 0x00000000, 0x030, 0x000003A2, 0x030, 0x000013A2, + 0x030, 0x000023A2, 0x030, 0x000033A2, 0x030, 0x000043A2, + 0x030, 0x000053A2, 0x030, 0x000063A2, 0x030, 0x000073A2, + 0x030, 0x000083A2, 0x030, 0x000093A2, 0x030, 0x0000A3A2, + 0x030, 0x0000B3A2, 0x93012100, 0x00000000, 0x40000000, 0x00000000, + 0x030, 0x000003A3, 0x030, 0x000013A3, 0x030, 0x000023A3, + 0x030, 0x000033A3, 0x030, 0x000043A4, 0x030, 0x000053A4, + 0x030, 0x000063A4, 0x030, 0x000073A4, 0x030, 0x000083A3, + 0x030, 0x000093A3, 0x030, 0x0000A3A3, 0x030, 0x0000B3A3, + 0x93002100, 0x00000000, 0x40000000, 0x00000000, 0x030, 0x000003A2, + 0x030, 0x000013A2, 0x030, 0x000023A2, 0x030, 0x000033A2, + 0x030, 0x000043A2, 0x030, 0x000053A2, 0x030, 0x000063A2, + 0x030, 0x000073A2, 0x030, 0x000083A2, 0x030, 0x000093A2, + 0x030, 0x0000A3A2, 0x030, 0x0000B3A2, 0x93011000, 0x00000000, + 0x40000000, 0x00000000, 0x030, 0x000003A2, 0x030, 0x000013A2, + 0x030, 0x000023A2, 0x030, 0x000033A2, 0x030, 0x000043A2, + 0x030, 0x000053A2, 0x030, 0x000063A2, 0x030, 0x000073A2, + 0x030, 0x000083A2, 0x030, 0x000093A2, 0x030, 0x0000A3A2, + 0x030, 0x0000B3A2, 0x9000200c, 0x00000000, 0x40000000, 0x00000000, + 0x030, 0x000003A2, 0x030, 0x000013A2, 0x030, 0x000023A2, + 0x030, 0x000033A2, 0x030, 0x000043A2, 0x030, 0x000053A2, + 0x030, 0x000063A2, 0x030, 0x000073A2, 0x030, 0x000083A2, + 0x030, 0x000093A2, 0x030, 0x0000A3A2, 0x030, 0x0000B3A2, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, 0x030, 0x000003A2, + 0x030, 0x000013A2, 0x030, 0x000023A2, 0x030, 0x000033A2, + 0x030, 0x000043A2, 0x030, 0x000053A2, 0x030, 0x000063A2, + 0x030, 0x000073A2, 0x030, 0x000083A2, 0x030, 0x000093A2, + 0x030, 0x0000A3A2, 0x030, 0x0000B3A2, 0x93002000, 0x00000000, + 0x40000000, 0x00000000, 0x030, 0x000003A2, 0x030, 0x000013A2, + 0x030, 0x000023A2, 0x030, 0x000033A2, 0x030, 0x000043A2, + 0x030, 0x000053A2, 0x030, 0x000063A2, 0x030, 0x000073A2, + 0x030, 0x000083A2, 0x030, 0x000093A2, 0x030, 0x0000A3A2, + 0x030, 0x0000B3A2, 0x93001000, 0x00000000, 0x40000000, 0x00000000, + 0x030, 0x000003A2, 0x030, 0x000013A2, 0x030, 0x000023A2, + 0x030, 0x000033A2, 0x030, 0x000043A2, 0x030, 0x000053A2, + 0x030, 0x000063A2, 0x030, 0x000073A2, 0x030, 0x000083A2, + 0x030, 0x000093A2, 0x030, 0x0000A3A2, 0x030, 0x0000B3A2, + 0x90002100, 0x00000000, 0x40000000, 0x00000000, 0x030, 0x000003A2, + 0x030, 0x000013A2, 0x030, 0x000023A2, 0x030, 0x000033A2, + 0x030, 0x000043A2, 0x030, 0x000053A2, 0x030, 0x000063A2, + 0x030, 0x000073A2, 0x030, 0x000083A2, 0x030, 0x000093A2, + 0x030, 0x0000A3A2, 0x030, 0x0000B3A2, 0x90002000, 0x00000000, + 0x40000000, 0x00000000, 0x030, 0x000003A2, 0x030, 0x000013A2, + 0x030, 0x000023A2, 0x030, 0x000033A2, 0x030, 0x000043A2, + 0x030, 0x000053A2, 0x030, 0x000063A2, 0x030, 0x000073A2, + 0x030, 0x000083A2, 0x030, 0x000093A2, 0x030, 0x0000A3A2, + 0x030, 0x0000B3A2, 0xA0000000, 0x00000000, 0x030, 0x000003A2, + 0x030, 0x000013A2, 0x030, 0x000023A2, 0x030, 0x000033A2, + 0x030, 0x000043A2, 0x030, 0x000053A2, 0x030, 0x000063A2, + 0x030, 0x000073A2, 0x030, 0x000083A2, 0x030, 0x000093A2, + 0x030, 0x0000A3A2, 0x030, 0x0000B3A2, 0xB0000000, 0x00000000, + 0x0EF, 0x00000000, 0x0EF, 0x00000040, 0x8300100f, 0x0a0a0a0a, + 0x40000000, 0x00000000, 0x030, 0x00000645, 0x030, 0x00001333, + 0x030, 0x00002011, 0x030, 0x00004000, 0x030, 0x00005000, + 0x030, 0x00006000, 0x9300100f, 0x05050505, 0x40000000, 0x00000000, + 0x030, 0x00000645, 0x030, 0x00001333, 0x030, 0x00002011, + 0x030, 0x00004000, 0x030, 0x00005000, 0x030, 0x00006000, + 0x9300100f, 0x00000000, 0x40000000, 0x00000000, 0x030, 0x00000645, + 0x030, 0x00001333, 0x030, 0x00002011, 0x030, 0x00004000, + 0x030, 0x00005000, 0x030, 0x00006000, 0x9300200f, 0x00000000, + 0x40000000, 0x00000000, 0x030, 0x00000645, 0x030, 0x00001333, + 0x030, 0x00002011, 0x030, 0x00004777, 0x030, 0x00005777, + 0x030, 0x00006777, 0x9000100f, 0x0a0a0a0a, 0x40000000, 0x00000000, + 0x030, 0x00000645, 0x030, 0x00001333, 0x030, 0x00002011, + 0x030, 0x00004000, 0x030, 0x00005000, 0x030, 0x00006000, + 0x9000100f, 0x05050505, 0x40000000, 0x00000000, 0x030, 0x00000645, + 0x030, 0x00001333, 0x030, 0x00002011, 0x030, 0x00004000, + 0x030, 0x00005000, 0x030, 0x00006000, 0x9000100f, 0x00000000, + 0x40000000, 0x00000000, 0x030, 0x00000645, 0x030, 0x00001333, + 0x030, 0x00002011, 0x030, 0x00004000, 0x030, 0x00005000, + 0x030, 0x00006000, 0x9000200f, 0x00000000, 0x40000000, 0x00000000, + 0x030, 0x00000645, 0x030, 0x00001333, 0x030, 0x00002011, + 0x030, 0x00004000, 0x030, 0x00005000, 0x030, 0x00006000, + 0x9300200c, 0x00000000, 0x40000000, 0x00000000, 0x030, 0x00000645, + 0x030, 0x00001333, 0x030, 0x00002011, 0x030, 0x00004777, + 0x030, 0x00005777, 0x030, 0x00006777, 0x93012100, 0x00000000, + 0x40000000, 0x00000000, 0x030, 0x00000660, 0x030, 0x00001341, + 0x030, 0x00002220, 0x030, 0x00004777, 0x030, 0x00005777, + 0x030, 0x00006777, 0x93002100, 0x00000000, 0x40000000, 0x00000000, + 0x030, 0x00000764, 0x030, 0x00001452, 0x030, 0x00002220, + 0x030, 0x00004777, 0x030, 0x00005777, 0x030, 0x00006777, + 0x93011000, 0x00000000, 0x40000000, 0x00000000, 0x030, 0x00000764, + 0x030, 0x00001632, 0x030, 0x00002421, 0x030, 0x00004000, + 0x030, 0x00005000, 0x030, 0x00006000, 0x9000200c, 0x00000000, + 0x40000000, 0x00000000, 0x030, 0x00000645, 0x030, 0x00001333, + 0x030, 0x00002011, 0x030, 0x00004000, 0x030, 0x00005000, + 0x030, 0x00006000, 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x030, 0x00000764, 0x030, 0x00001632, 0x030, 0x00002421, + 0x030, 0x00004000, 0x030, 0x00005000, 0x030, 0x00006000, + 0x93002000, 0x00000000, 0x40000000, 0x00000000, 0x030, 0x00000777, + 0x030, 0x00001442, 0x030, 0x00002222, 0x030, 0x00004777, + 0x030, 0x00005777, 0x030, 0x00006777, 0x93001000, 0x00000000, + 0x40000000, 0x00000000, 0x030, 0x00000764, 0x030, 0x00001632, + 0x030, 0x00002421, 0x030, 0x00004000, 0x030, 0x00005000, + 0x030, 0x00006000, 0x90002100, 0x00000000, 0x40000000, 0x00000000, + 0x030, 0x00000775, 0x030, 0x00001222, 0x030, 0x00002210, + 0x030, 0x00004000, 0x030, 0x00005000, 0x030, 0x00006000, + 0x90002000, 0x00000000, 0x40000000, 0x00000000, 0x030, 0x00000775, + 0x030, 0x00001422, 0x030, 0x00002210, 0x030, 0x00004000, + 0x030, 0x00005000, 0x030, 0x00006000, 0xA0000000, 0x00000000, + 0x030, 0x00000764, 0x030, 0x00001632, 0x030, 0x00002421, + 0x030, 0x00004000, 0x030, 0x00005000, 0x030, 0x00006000, + 0xB0000000, 0x00000000, 0x0EF, 0x00000000, 0x0EF, 0x00000800, + 0x8300100f, 0x0a0a0a0a, 0x40000000, 0x00000000, 0x033, 0x00000020, + 0x03F, 0x00000007, 0x033, 0x00000021, 0x03F, 0x0000000A, + 0x033, 0x00000022, 0x03F, 0x0000000D, 0x033, 0x00000023, + 0x03F, 0x0000002A, 0x033, 0x00000024, 0x03F, 0x0000002D, + 0x033, 0x00000025, 0x03F, 0x00000030, 0x033, 0x00000026, + 0x03F, 0x0000006D, 0x033, 0x00000027, 0x03F, 0x00000070, + 0x033, 0x00000028, 0x03F, 0x000000ED, 0x033, 0x00000029, + 0x03F, 0x000000F0, 0x033, 0x0000002A, 0x03F, 0x000000F3, + 0x9300100f, 0x05050505, 0x40000000, 0x00000000, 0x033, 0x00000020, + 0x03F, 0x00000007, 0x033, 0x00000021, 0x03F, 0x0000000A, + 0x033, 0x00000022, 0x03F, 0x0000000D, 0x033, 0x00000023, + 0x03F, 0x0000002A, 0x033, 0x00000024, 0x03F, 0x0000002D, + 0x033, 0x00000025, 0x03F, 0x00000030, 0x033, 0x00000026, + 0x03F, 0x0000006D, 0x033, 0x00000027, 0x03F, 0x00000070, + 0x033, 0x00000028, 0x03F, 0x000000ED, 0x033, 0x00000029, + 0x03F, 0x000000F0, 0x033, 0x0000002A, 0x03F, 0x000000F3, + 0x9300100f, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000020, + 0x03F, 0x00000007, 0x033, 0x00000021, 0x03F, 0x0000000A, + 0x033, 0x00000022, 0x03F, 0x0000000D, 0x033, 0x00000023, + 0x03F, 0x0000002A, 0x033, 0x00000024, 0x03F, 0x0000002D, + 0x033, 0x00000025, 0x03F, 0x00000030, 0x033, 0x00000026, + 0x03F, 0x0000006D, 0x033, 0x00000027, 0x03F, 0x00000070, + 0x033, 0x00000028, 0x03F, 0x000000ED, 0x033, 0x00000029, + 0x03F, 0x000000F0, 0x033, 0x0000002A, 0x03F, 0x000000F3, + 0x9300200f, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000020, + 0x03F, 0x00000005, 0x033, 0x00000021, 0x03F, 0x00000008, + 0x033, 0x00000022, 0x03F, 0x0000000B, 0x033, 0x00000023, + 0x03F, 0x0000000E, 0x033, 0x00000024, 0x03F, 0x0000002B, + 0x033, 0x00000025, 0x03F, 0x00000068, 0x033, 0x00000026, + 0x03F, 0x0000006B, 0x033, 0x00000027, 0x03F, 0x0000006E, + 0x033, 0x00000028, 0x03F, 0x00000071, 0x033, 0x00000029, + 0x03F, 0x00000074, 0x033, 0x0000002A, 0x03F, 0x00000077, + 0x9000100f, 0x0a0a0a0a, 0x40000000, 0x00000000, 0x033, 0x00000020, + 0x03F, 0x00000007, 0x033, 0x00000021, 0x03F, 0x0000000A, + 0x033, 0x00000022, 0x03F, 0x0000000D, 0x033, 0x00000023, + 0x03F, 0x0000002A, 0x033, 0x00000024, 0x03F, 0x0000002D, + 0x033, 0x00000025, 0x03F, 0x00000030, 0x033, 0x00000026, + 0x03F, 0x0000006D, 0x033, 0x00000027, 0x03F, 0x00000070, + 0x033, 0x00000028, 0x03F, 0x000000ED, 0x033, 0x00000029, + 0x03F, 0x000000F0, 0x033, 0x0000002A, 0x03F, 0x000000F3, + 0x9000100f, 0x05050505, 0x40000000, 0x00000000, 0x033, 0x00000020, + 0x03F, 0x00000007, 0x033, 0x00000021, 0x03F, 0x0000000A, + 0x033, 0x00000022, 0x03F, 0x0000000D, 0x033, 0x00000023, + 0x03F, 0x0000002A, 0x033, 0x00000024, 0x03F, 0x0000002D, + 0x033, 0x00000025, 0x03F, 0x00000030, 0x033, 0x00000026, + 0x03F, 0x0000006D, 0x033, 0x00000027, 0x03F, 0x00000070, + 0x033, 0x00000028, 0x03F, 0x000000ED, 0x033, 0x00000029, + 0x03F, 0x000000F0, 0x033, 0x0000002A, 0x03F, 0x000000F3, + 0x9000100f, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000020, + 0x03F, 0x00000007, 0x033, 0x00000021, 0x03F, 0x0000000A, + 0x033, 0x00000022, 0x03F, 0x0000000D, 0x033, 0x00000023, + 0x03F, 0x0000002A, 0x033, 0x00000024, 0x03F, 0x0000002D, + 0x033, 0x00000025, 0x03F, 0x00000030, 0x033, 0x00000026, + 0x03F, 0x0000006D, 0x033, 0x00000027, 0x03F, 0x00000070, + 0x033, 0x00000028, 0x03F, 0x000000ED, 0x033, 0x00000029, + 0x03F, 0x000000F0, 0x033, 0x0000002A, 0x03F, 0x000000F3, + 0x9000200f, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000020, + 0x03F, 0x00000005, 0x033, 0x00000021, 0x03F, 0x00000008, + 0x033, 0x00000022, 0x03F, 0x0000000B, 0x033, 0x00000023, + 0x03F, 0x0000000E, 0x033, 0x00000024, 0x03F, 0x0000002B, + 0x033, 0x00000025, 0x03F, 0x00000068, 0x033, 0x00000026, + 0x03F, 0x0000006B, 0x033, 0x00000027, 0x03F, 0x0000006E, + 0x033, 0x00000028, 0x03F, 0x00000071, 0x033, 0x00000029, + 0x03F, 0x00000074, 0x033, 0x0000002A, 0x03F, 0x00000077, + 0x9300200c, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000020, + 0x03F, 0x00000005, 0x033, 0x00000021, 0x03F, 0x00000008, + 0x033, 0x00000022, 0x03F, 0x0000000B, 0x033, 0x00000023, + 0x03F, 0x0000000E, 0x033, 0x00000024, 0x03F, 0x0000002B, + 0x033, 0x00000025, 0x03F, 0x00000068, 0x033, 0x00000026, + 0x03F, 0x0000006B, 0x033, 0x00000027, 0x03F, 0x0000006E, + 0x033, 0x00000028, 0x03F, 0x00000071, 0x033, 0x00000029, + 0x03F, 0x00000074, 0x033, 0x0000002A, 0x03F, 0x00000077, + 0x93012100, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000020, + 0x03F, 0x00000828, 0x033, 0x00000021, 0x03F, 0x0000082B, + 0x033, 0x00000022, 0x03F, 0x00000868, 0x033, 0x00000023, + 0x03F, 0x00000889, 0x033, 0x00000024, 0x03F, 0x000008AA, + 0x033, 0x00000025, 0x03F, 0x00000CE8, 0x033, 0x00000026, + 0x03F, 0x00000CEB, 0x033, 0x00000027, 0x03F, 0x00000CEE, + 0x033, 0x00000028, 0x03F, 0x00000CF1, 0x033, 0x00000029, + 0x03F, 0x00000CF4, 0x033, 0x0000002A, 0x03F, 0x00000CF7, + 0x93002100, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000020, + 0x03F, 0x0000042A, 0x033, 0x00000021, 0x03F, 0x00000829, + 0x033, 0x00000022, 0x03F, 0x00000848, 0x033, 0x00000023, + 0x03F, 0x0000084B, 0x033, 0x00000024, 0x03F, 0x00000C4C, + 0x033, 0x00000025, 0x03F, 0x00000C8B, 0x033, 0x00000026, + 0x03F, 0x00000CEA, 0x033, 0x00000027, 0x03F, 0x00000CED, + 0x033, 0x00000028, 0x03F, 0x00000CF0, 0x033, 0x00000029, + 0x03F, 0x00000CF3, 0x033, 0x0000002A, 0x03F, 0x00000CF6, + 0x93011000, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000020, + 0x03F, 0x00000C09, 0x033, 0x00000021, 0x03F, 0x00000C0C, + 0x033, 0x00000022, 0x03F, 0x00000C0F, 0x033, 0x00000023, + 0x03F, 0x00000C2C, 0x033, 0x00000024, 0x03F, 0x00000C2F, + 0x033, 0x00000025, 0x03F, 0x00000C8A, 0x033, 0x00000026, + 0x03F, 0x00000C8D, 0x033, 0x00000027, 0x03F, 0x00000C90, + 0x033, 0x00000028, 0x03F, 0x00000CD0, 0x033, 0x00000029, + 0x03F, 0x00000CF2, 0x033, 0x0000002A, 0x03F, 0x00000CF5, + 0x9000200c, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000020, + 0x03F, 0x00000005, 0x033, 0x00000021, 0x03F, 0x00000008, + 0x033, 0x00000022, 0x03F, 0x0000000B, 0x033, 0x00000023, + 0x03F, 0x0000000E, 0x033, 0x00000024, 0x03F, 0x0000002B, + 0x033, 0x00000025, 0x03F, 0x00000068, 0x033, 0x00000026, + 0x03F, 0x0000006B, 0x033, 0x00000027, 0x03F, 0x0000006E, + 0x033, 0x00000028, 0x03F, 0x00000071, 0x033, 0x00000029, + 0x03F, 0x00000074, 0x033, 0x0000002A, 0x03F, 0x00000077, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000020, + 0x03F, 0x00000C09, 0x033, 0x00000021, 0x03F, 0x00000C0C, + 0x033, 0x00000022, 0x03F, 0x00000C0F, 0x033, 0x00000023, + 0x03F, 0x00000C2C, 0x033, 0x00000024, 0x03F, 0x00000C2F, + 0x033, 0x00000025, 0x03F, 0x00000C8A, 0x033, 0x00000026, + 0x03F, 0x00000C8D, 0x033, 0x00000027, 0x03F, 0x00000C90, + 0x033, 0x00000028, 0x03F, 0x00000CD0, 0x033, 0x00000029, + 0x03F, 0x00000CF2, 0x033, 0x0000002A, 0x03F, 0x00000CF5, + 0x93002000, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000020, + 0x03F, 0x00000429, 0x033, 0x00000021, 0x03F, 0x00000828, + 0x033, 0x00000022, 0x03F, 0x00000847, 0x033, 0x00000023, + 0x03F, 0x0000084A, 0x033, 0x00000024, 0x03F, 0x00000C4B, + 0x033, 0x00000025, 0x03F, 0x00000C8A, 0x033, 0x00000026, + 0x03F, 0x00000CEA, 0x033, 0x00000027, 0x03F, 0x00000CED, + 0x033, 0x00000028, 0x03F, 0x00000CF0, 0x033, 0x00000029, + 0x03F, 0x00000CF3, 0x033, 0x0000002A, 0x03F, 0x00000CF6, + 0x93001000, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000020, + 0x03F, 0x00000C09, 0x033, 0x00000021, 0x03F, 0x00000C0C, + 0x033, 0x00000022, 0x03F, 0x00000C0F, 0x033, 0x00000023, + 0x03F, 0x00000C2C, 0x033, 0x00000024, 0x03F, 0x00000C2F, + 0x033, 0x00000025, 0x03F, 0x00000C8A, 0x033, 0x00000026, + 0x03F, 0x00000C8D, 0x033, 0x00000027, 0x03F, 0x00000C90, + 0x033, 0x00000028, 0x03F, 0x00000CD0, 0x033, 0x00000029, + 0x03F, 0x00000CF2, 0x033, 0x0000002A, 0x03F, 0x00000CF5, + 0x90002100, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000020, + 0x03F, 0x0000042B, 0x033, 0x00000021, 0x03F, 0x0000082A, + 0x033, 0x00000022, 0x03F, 0x00000849, 0x033, 0x00000023, + 0x03F, 0x0000084C, 0x033, 0x00000024, 0x03F, 0x00000C4C, + 0x033, 0x00000025, 0x03F, 0x00000C8A, 0x033, 0x00000026, + 0x03F, 0x00000C8D, 0x033, 0x00000027, 0x03F, 0x00000CEB, + 0x033, 0x00000028, 0x03F, 0x00000CEE, 0x033, 0x00000029, + 0x03F, 0x00000CF1, 0x033, 0x0000002A, 0x03F, 0x00000CF4, + 0x90002000, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000020, + 0x03F, 0x0000042B, 0x033, 0x00000021, 0x03F, 0x0000082A, + 0x033, 0x00000022, 0x03F, 0x00000849, 0x033, 0x00000023, + 0x03F, 0x0000084C, 0x033, 0x00000024, 0x03F, 0x00000C4C, + 0x033, 0x00000025, 0x03F, 0x00000C8A, 0x033, 0x00000026, + 0x03F, 0x00000C8D, 0x033, 0x00000027, 0x03F, 0x00000CEB, + 0x033, 0x00000028, 0x03F, 0x00000CEE, 0x033, 0x00000029, + 0x03F, 0x00000CF1, 0x033, 0x0000002A, 0x03F, 0x00000CF4, + 0xA0000000, 0x00000000, 0x033, 0x00000020, 0x03F, 0x00000C09, + 0x033, 0x00000021, 0x03F, 0x00000C0C, 0x033, 0x00000022, + 0x03F, 0x00000C0F, 0x033, 0x00000023, 0x03F, 0x00000C2C, + 0x033, 0x00000024, 0x03F, 0x00000C2F, 0x033, 0x00000025, + 0x03F, 0x00000C8A, 0x033, 0x00000026, 0x03F, 0x00000C8D, + 0x033, 0x00000027, 0x03F, 0x00000C90, 0x033, 0x00000028, + 0x03F, 0x00000CD0, 0x033, 0x00000029, 0x03F, 0x00000CF2, + 0x033, 0x0000002A, 0x03F, 0x00000CF5, 0xB0000000, 0x00000000, + 0x8300100f, 0x0a0a0a0a, 0x40000000, 0x00000000, 0x033, 0x00000060, + 0x03F, 0x00000007, 0x033, 0x00000061, 0x03F, 0x0000000A, + 0x033, 0x00000062, 0x03F, 0x0000000D, 0x033, 0x00000063, + 0x03F, 0x0000002A, 0x033, 0x00000064, 0x03F, 0x0000002D, + 0x033, 0x00000065, 0x03F, 0x00000030, 0x033, 0x00000066, + 0x03F, 0x0000006D, 0x033, 0x00000067, 0x03F, 0x00000070, + 0x033, 0x00000068, 0x03F, 0x000000ED, 0x033, 0x00000069, + 0x03F, 0x000000F0, 0x033, 0x0000006A, 0x03F, 0x000000F3, + 0x9300100f, 0x05050505, 0x40000000, 0x00000000, 0x033, 0x00000060, + 0x03F, 0x00000007, 0x033, 0x00000061, 0x03F, 0x0000000A, + 0x033, 0x00000062, 0x03F, 0x0000000D, 0x033, 0x00000063, + 0x03F, 0x0000002A, 0x033, 0x00000064, 0x03F, 0x0000002D, + 0x033, 0x00000065, 0x03F, 0x00000030, 0x033, 0x00000066, + 0x03F, 0x0000006D, 0x033, 0x00000067, 0x03F, 0x00000070, + 0x033, 0x00000068, 0x03F, 0x000000ED, 0x033, 0x00000069, + 0x03F, 0x000000F0, 0x033, 0x0000006A, 0x03F, 0x000000F3, + 0x9300100f, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, + 0x03F, 0x00000007, 0x033, 0x00000061, 0x03F, 0x0000000A, + 0x033, 0x00000062, 0x03F, 0x0000000D, 0x033, 0x00000063, + 0x03F, 0x0000002A, 0x033, 0x00000064, 0x03F, 0x0000002D, + 0x033, 0x00000065, 0x03F, 0x00000030, 0x033, 0x00000066, + 0x03F, 0x0000006D, 0x033, 0x00000067, 0x03F, 0x00000070, + 0x033, 0x00000068, 0x03F, 0x000000ED, 0x033, 0x00000069, + 0x03F, 0x000000F0, 0x033, 0x0000006A, 0x03F, 0x000000F3, + 0x9300200f, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, + 0x03F, 0x00000005, 0x033, 0x00000061, 0x03F, 0x00000008, + 0x033, 0x00000062, 0x03F, 0x0000000B, 0x033, 0x00000063, + 0x03F, 0x0000000E, 0x033, 0x00000064, 0x03F, 0x0000002B, + 0x033, 0x00000065, 0x03F, 0x00000068, 0x033, 0x00000066, + 0x03F, 0x0000006B, 0x033, 0x00000067, 0x03F, 0x0000006E, + 0x033, 0x00000068, 0x03F, 0x00000071, 0x033, 0x00000069, + 0x03F, 0x00000074, 0x033, 0x0000006A, 0x03F, 0x00000077, + 0x9000100f, 0x0a0a0a0a, 0x40000000, 0x00000000, 0x033, 0x00000060, + 0x03F, 0x00000007, 0x033, 0x00000061, 0x03F, 0x0000000A, + 0x033, 0x00000062, 0x03F, 0x0000000D, 0x033, 0x00000063, + 0x03F, 0x0000002A, 0x033, 0x00000064, 0x03F, 0x0000002D, + 0x033, 0x00000065, 0x03F, 0x00000030, 0x033, 0x00000066, + 0x03F, 0x0000006D, 0x033, 0x00000067, 0x03F, 0x00000070, + 0x033, 0x00000068, 0x03F, 0x000000ED, 0x033, 0x00000069, + 0x03F, 0x000000F0, 0x033, 0x0000006A, 0x03F, 0x000000F3, + 0x9000100f, 0x05050505, 0x40000000, 0x00000000, 0x033, 0x00000060, + 0x03F, 0x00000007, 0x033, 0x00000061, 0x03F, 0x0000000A, + 0x033, 0x00000062, 0x03F, 0x0000000D, 0x033, 0x00000063, + 0x03F, 0x0000002A, 0x033, 0x00000064, 0x03F, 0x0000002D, + 0x033, 0x00000065, 0x03F, 0x00000030, 0x033, 0x00000066, + 0x03F, 0x0000006D, 0x033, 0x00000067, 0x03F, 0x00000070, + 0x033, 0x00000068, 0x03F, 0x000000ED, 0x033, 0x00000069, + 0x03F, 0x000000F0, 0x033, 0x0000006A, 0x03F, 0x000000F3, + 0x9000100f, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, + 0x03F, 0x00000007, 0x033, 0x00000061, 0x03F, 0x0000000A, + 0x033, 0x00000062, 0x03F, 0x0000000D, 0x033, 0x00000063, + 0x03F, 0x0000002A, 0x033, 0x00000064, 0x03F, 0x0000002D, + 0x033, 0x00000065, 0x03F, 0x00000030, 0x033, 0x00000066, + 0x03F, 0x0000006D, 0x033, 0x00000067, 0x03F, 0x00000070, + 0x033, 0x00000068, 0x03F, 0x000000ED, 0x033, 0x00000069, + 0x03F, 0x000000F0, 0x033, 0x0000006A, 0x03F, 0x000000F3, + 0x9000200f, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, + 0x03F, 0x00000005, 0x033, 0x00000061, 0x03F, 0x00000008, + 0x033, 0x00000062, 0x03F, 0x0000000B, 0x033, 0x00000063, + 0x03F, 0x0000000E, 0x033, 0x00000064, 0x03F, 0x0000002B, + 0x033, 0x00000065, 0x03F, 0x00000068, 0x033, 0x00000066, + 0x03F, 0x0000006B, 0x033, 0x00000067, 0x03F, 0x0000006E, + 0x033, 0x00000068, 0x03F, 0x00000071, 0x033, 0x00000069, + 0x03F, 0x00000074, 0x033, 0x0000006A, 0x03F, 0x00000077, + 0x9300200c, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, + 0x03F, 0x00000005, 0x033, 0x00000061, 0x03F, 0x00000008, + 0x033, 0x00000062, 0x03F, 0x0000000B, 0x033, 0x00000063, + 0x03F, 0x0000000E, 0x033, 0x00000064, 0x03F, 0x0000002B, + 0x033, 0x00000065, 0x03F, 0x00000068, 0x033, 0x00000066, + 0x03F, 0x0000006B, 0x033, 0x00000067, 0x03F, 0x0000006E, + 0x033, 0x00000068, 0x03F, 0x00000071, 0x033, 0x00000069, + 0x03F, 0x00000074, 0x033, 0x0000006A, 0x03F, 0x00000077, + 0x93012100, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, + 0x03F, 0x00000842, 0x033, 0x00000061, 0x03F, 0x00000845, + 0x033, 0x00000062, 0x03F, 0x00000866, 0x033, 0x00000063, + 0x03F, 0x000008A6, 0x033, 0x00000064, 0x03F, 0x000008C8, + 0x033, 0x00000065, 0x03F, 0x00000CE8, 0x033, 0x00000066, + 0x03F, 0x00000CEB, 0x033, 0x00000067, 0x03F, 0x00000CEE, + 0x033, 0x00000068, 0x03F, 0x00000CF1, 0x033, 0x00000069, + 0x03F, 0x00000CF4, 0x033, 0x0000006A, 0x03F, 0x00000CF7, + 0x93002100, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, + 0x03F, 0x0000042A, 0x033, 0x00000061, 0x03F, 0x00000829, + 0x033, 0x00000062, 0x03F, 0x00000848, 0x033, 0x00000063, + 0x03F, 0x0000084B, 0x033, 0x00000064, 0x03F, 0x00000C69, + 0x033, 0x00000065, 0x03F, 0x00000CA9, 0x033, 0x00000066, + 0x03F, 0x00000CEA, 0x033, 0x00000067, 0x03F, 0x00000CED, + 0x033, 0x00000068, 0x03F, 0x00000CF0, 0x033, 0x00000069, + 0x03F, 0x00000CF3, 0x033, 0x0000006A, 0x03F, 0x00000CF6, + 0x93011000, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, + 0x03F, 0x00000C0A, 0x033, 0x00000061, 0x03F, 0x00000C0D, + 0x033, 0x00000062, 0x03F, 0x00000C2A, 0x033, 0x00000063, + 0x03F, 0x00000C2D, 0x033, 0x00000064, 0x03F, 0x00000C6A, + 0x033, 0x00000065, 0x03F, 0x00000CAA, 0x033, 0x00000066, + 0x03F, 0x00000CAD, 0x033, 0x00000067, 0x03F, 0x00000CB0, + 0x033, 0x00000068, 0x03F, 0x00000CF1, 0x033, 0x00000069, + 0x03F, 0x00000CF4, 0x033, 0x0000006A, 0x03F, 0x00000CF7, + 0x9000200c, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, + 0x03F, 0x00000005, 0x033, 0x00000061, 0x03F, 0x00000008, + 0x033, 0x00000062, 0x03F, 0x0000000B, 0x033, 0x00000063, + 0x03F, 0x0000000E, 0x033, 0x00000064, 0x03F, 0x0000002B, + 0x033, 0x00000065, 0x03F, 0x00000068, 0x033, 0x00000066, + 0x03F, 0x0000006B, 0x033, 0x00000067, 0x03F, 0x0000006E, + 0x033, 0x00000068, 0x03F, 0x00000071, 0x033, 0x00000069, + 0x03F, 0x00000074, 0x033, 0x0000006A, 0x03F, 0x00000077, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, + 0x03F, 0x00000C0A, 0x033, 0x00000061, 0x03F, 0x00000C0D, + 0x033, 0x00000062, 0x03F, 0x00000C2A, 0x033, 0x00000063, + 0x03F, 0x00000C2D, 0x033, 0x00000064, 0x03F, 0x00000C6A, + 0x033, 0x00000065, 0x03F, 0x00000CAA, 0x033, 0x00000066, + 0x03F, 0x00000CAD, 0x033, 0x00000067, 0x03F, 0x00000CB0, + 0x033, 0x00000068, 0x03F, 0x00000CF1, 0x033, 0x00000069, + 0x03F, 0x00000CF4, 0x033, 0x0000006A, 0x03F, 0x00000CF7, + 0x93002000, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, + 0x03F, 0x00000429, 0x033, 0x00000061, 0x03F, 0x00000828, + 0x033, 0x00000062, 0x03F, 0x00000847, 0x033, 0x00000063, + 0x03F, 0x0000084A, 0x033, 0x00000064, 0x03F, 0x00000C4B, + 0x033, 0x00000065, 0x03F, 0x00000C8A, 0x033, 0x00000066, + 0x03F, 0x00000CEA, 0x033, 0x00000067, 0x03F, 0x00000CED, + 0x033, 0x00000068, 0x03F, 0x00000CF0, 0x033, 0x00000069, + 0x03F, 0x00000CF3, 0x033, 0x0000006A, 0x03F, 0x00000CF6, + 0x93001000, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, + 0x03F, 0x00000C0A, 0x033, 0x00000061, 0x03F, 0x00000C0D, + 0x033, 0x00000062, 0x03F, 0x00000C2A, 0x033, 0x00000063, + 0x03F, 0x00000C2D, 0x033, 0x00000064, 0x03F, 0x00000C6A, + 0x033, 0x00000065, 0x03F, 0x00000CAA, 0x033, 0x00000066, + 0x03F, 0x00000CAD, 0x033, 0x00000067, 0x03F, 0x00000CB0, + 0x033, 0x00000068, 0x03F, 0x00000CF1, 0x033, 0x00000069, + 0x03F, 0x00000CF4, 0x033, 0x0000006A, 0x03F, 0x00000CF7, + 0x90002100, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, + 0x03F, 0x0000042C, 0x033, 0x00000061, 0x03F, 0x0000082B, + 0x033, 0x00000062, 0x03F, 0x0000084A, 0x033, 0x00000063, + 0x03F, 0x0000084D, 0x033, 0x00000064, 0x03F, 0x00000C4E, + 0x033, 0x00000065, 0x03F, 0x00000C8C, 0x033, 0x00000066, + 0x03F, 0x00000C8F, 0x033, 0x00000067, 0x03F, 0x00000CEC, + 0x033, 0x00000068, 0x03F, 0x00000CEF, 0x033, 0x00000069, + 0x03F, 0x00000CF2, 0x033, 0x0000006A, 0x03F, 0x00000CF5, + 0x90002000, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, + 0x03F, 0x0000042C, 0x033, 0x00000061, 0x03F, 0x0000082B, + 0x033, 0x00000062, 0x03F, 0x0000084A, 0x033, 0x00000063, + 0x03F, 0x0000084D, 0x033, 0x00000064, 0x03F, 0x00000C4E, + 0x033, 0x00000065, 0x03F, 0x00000C8C, 0x033, 0x00000066, + 0x03F, 0x00000C8F, 0x033, 0x00000067, 0x03F, 0x00000CEC, + 0x033, 0x00000068, 0x03F, 0x00000CEF, 0x033, 0x00000069, + 0x03F, 0x00000CF2, 0x033, 0x0000006A, 0x03F, 0x00000CF5, + 0xA0000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000C0A, + 0x033, 0x00000061, 0x03F, 0x00000C0D, 0x033, 0x00000062, + 0x03F, 0x00000C2A, 0x033, 0x00000063, 0x03F, 0x00000C2D, + 0x033, 0x00000064, 0x03F, 0x00000C6A, 0x033, 0x00000065, + 0x03F, 0x00000CAA, 0x033, 0x00000066, 0x03F, 0x00000CAD, + 0x033, 0x00000067, 0x03F, 0x00000CB0, 0x033, 0x00000068, + 0x03F, 0x00000CF1, 0x033, 0x00000069, 0x03F, 0x00000CF4, + 0x033, 0x0000006A, 0x03F, 0x00000CF7, 0xB0000000, 0x00000000, + 0x8300100f, 0x0a0a0a0a, 0x40000000, 0x00000000, 0x033, 0x000000A0, + 0x03F, 0x00000007, 0x033, 0x000000A1, 0x03F, 0x0000000A, + 0x033, 0x000000A2, 0x03F, 0x0000000D, 0x033, 0x000000A3, + 0x03F, 0x0000002A, 0x033, 0x000000A4, 0x03F, 0x0000002D, + 0x033, 0x000000A5, 0x03F, 0x00000030, 0x033, 0x000000A6, + 0x03F, 0x0000006D, 0x033, 0x000000A7, 0x03F, 0x00000070, + 0x033, 0x000000A8, 0x03F, 0x000000ED, 0x033, 0x000000A9, + 0x03F, 0x000000F0, 0x033, 0x000000AA, 0x03F, 0x000000F3, + 0x9300100f, 0x05050505, 0x40000000, 0x00000000, 0x033, 0x000000A0, + 0x03F, 0x00000007, 0x033, 0x000000A1, 0x03F, 0x0000000A, + 0x033, 0x000000A2, 0x03F, 0x0000000D, 0x033, 0x000000A3, + 0x03F, 0x0000002A, 0x033, 0x000000A4, 0x03F, 0x0000002D, + 0x033, 0x000000A5, 0x03F, 0x00000030, 0x033, 0x000000A6, + 0x03F, 0x0000006D, 0x033, 0x000000A7, 0x03F, 0x00000070, + 0x033, 0x000000A8, 0x03F, 0x000000ED, 0x033, 0x000000A9, + 0x03F, 0x000000F0, 0x033, 0x000000AA, 0x03F, 0x000000F3, + 0x9300100f, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x000000A0, + 0x03F, 0x00000007, 0x033, 0x000000A1, 0x03F, 0x0000000A, + 0x033, 0x000000A2, 0x03F, 0x0000000D, 0x033, 0x000000A3, + 0x03F, 0x0000002A, 0x033, 0x000000A4, 0x03F, 0x0000002D, + 0x033, 0x000000A5, 0x03F, 0x00000030, 0x033, 0x000000A6, + 0x03F, 0x0000006D, 0x033, 0x000000A7, 0x03F, 0x00000070, + 0x033, 0x000000A8, 0x03F, 0x000000ED, 0x033, 0x000000A9, + 0x03F, 0x000000F0, 0x033, 0x000000AA, 0x03F, 0x000000F3, + 0x9300200f, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x000000A0, + 0x03F, 0x00000005, 0x033, 0x000000A1, 0x03F, 0x00000008, + 0x033, 0x000000A2, 0x03F, 0x0000000B, 0x033, 0x000000A3, + 0x03F, 0x0000000E, 0x033, 0x000000A4, 0x03F, 0x00000047, + 0x033, 0x000000A5, 0x03F, 0x0000004A, 0x033, 0x000000A6, + 0x03F, 0x0000004D, 0x033, 0x000000A7, 0x03F, 0x00000050, + 0x033, 0x000000A8, 0x03F, 0x00000053, 0x033, 0x000000A9, + 0x03F, 0x00000056, 0x033, 0x000000AA, 0x03F, 0x00000094, + 0x9000100f, 0x0a0a0a0a, 0x40000000, 0x00000000, 0x033, 0x000000A0, + 0x03F, 0x00000007, 0x033, 0x000000A1, 0x03F, 0x0000000A, + 0x033, 0x000000A2, 0x03F, 0x0000000D, 0x033, 0x000000A3, + 0x03F, 0x0000002A, 0x033, 0x000000A4, 0x03F, 0x0000002D, + 0x033, 0x000000A5, 0x03F, 0x00000030, 0x033, 0x000000A6, + 0x03F, 0x0000006D, 0x033, 0x000000A7, 0x03F, 0x00000070, + 0x033, 0x000000A8, 0x03F, 0x000000ED, 0x033, 0x000000A9, + 0x03F, 0x000000F0, 0x033, 0x000000AA, 0x03F, 0x000000F3, + 0x9000100f, 0x05050505, 0x40000000, 0x00000000, 0x033, 0x000000A0, + 0x03F, 0x00000007, 0x033, 0x000000A1, 0x03F, 0x0000000A, + 0x033, 0x000000A2, 0x03F, 0x0000000D, 0x033, 0x000000A3, + 0x03F, 0x0000002A, 0x033, 0x000000A4, 0x03F, 0x0000002D, + 0x033, 0x000000A5, 0x03F, 0x00000030, 0x033, 0x000000A6, + 0x03F, 0x0000006D, 0x033, 0x000000A7, 0x03F, 0x00000070, + 0x033, 0x000000A8, 0x03F, 0x000000ED, 0x033, 0x000000A9, + 0x03F, 0x000000F0, 0x033, 0x000000AA, 0x03F, 0x000000F3, + 0x9000100f, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x000000A0, + 0x03F, 0x00000007, 0x033, 0x000000A1, 0x03F, 0x0000000A, + 0x033, 0x000000A2, 0x03F, 0x0000000D, 0x033, 0x000000A3, + 0x03F, 0x0000002A, 0x033, 0x000000A4, 0x03F, 0x0000002D, + 0x033, 0x000000A5, 0x03F, 0x00000030, 0x033, 0x000000A6, + 0x03F, 0x0000006D, 0x033, 0x000000A7, 0x03F, 0x00000070, + 0x033, 0x000000A8, 0x03F, 0x000000ED, 0x033, 0x000000A9, + 0x03F, 0x000000F0, 0x033, 0x000000AA, 0x03F, 0x000000F3, + 0x9000200f, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x000000A0, + 0x03F, 0x00000005, 0x033, 0x000000A1, 0x03F, 0x00000008, + 0x033, 0x000000A2, 0x03F, 0x0000000B, 0x033, 0x000000A3, + 0x03F, 0x0000000E, 0x033, 0x000000A4, 0x03F, 0x00000047, + 0x033, 0x000000A5, 0x03F, 0x0000004A, 0x033, 0x000000A6, + 0x03F, 0x0000004D, 0x033, 0x000000A7, 0x03F, 0x00000050, + 0x033, 0x000000A8, 0x03F, 0x00000053, 0x033, 0x000000A9, + 0x03F, 0x00000056, 0x033, 0x000000AA, 0x03F, 0x00000094, + 0x9300200c, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x000000A0, + 0x03F, 0x00000005, 0x033, 0x000000A1, 0x03F, 0x00000008, + 0x033, 0x000000A2, 0x03F, 0x0000000B, 0x033, 0x000000A3, + 0x03F, 0x0000000E, 0x033, 0x000000A4, 0x03F, 0x00000047, + 0x033, 0x000000A5, 0x03F, 0x0000004A, 0x033, 0x000000A6, + 0x03F, 0x0000004D, 0x033, 0x000000A7, 0x03F, 0x00000050, + 0x033, 0x000000A8, 0x03F, 0x00000053, 0x033, 0x000000A9, + 0x03F, 0x00000056, 0x033, 0x000000AA, 0x03F, 0x00000094, + 0x93012100, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x000000A0, + 0x03F, 0x00000826, 0x033, 0x000000A1, 0x03F, 0x00000829, + 0x033, 0x000000A2, 0x03F, 0x0000082C, 0x033, 0x000000A3, + 0x03F, 0x0000082F, 0x033, 0x000000A4, 0x03F, 0x0000086C, + 0x033, 0x000000A5, 0x03F, 0x00000CE8, 0x033, 0x000000A6, + 0x03F, 0x00000CEB, 0x033, 0x000000A7, 0x03F, 0x00000CEE, + 0x033, 0x000000A8, 0x03F, 0x00000CF1, 0x033, 0x000000A9, + 0x03F, 0x00000CF4, 0x033, 0x000000AA, 0x03F, 0x00000CF7, + 0x93002100, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x000000A0, + 0x03F, 0x0000042A, 0x033, 0x000000A1, 0x03F, 0x00000829, + 0x033, 0x000000A2, 0x03F, 0x00000848, 0x033, 0x000000A3, + 0x03F, 0x0000084B, 0x033, 0x000000A4, 0x03F, 0x00000C4C, + 0x033, 0x000000A5, 0x03F, 0x00000CA9, 0x033, 0x000000A6, + 0x03F, 0x00000CEA, 0x033, 0x000000A7, 0x03F, 0x00000CED, + 0x033, 0x000000A8, 0x03F, 0x00000CF0, 0x033, 0x000000A9, + 0x03F, 0x00000CF3, 0x033, 0x000000AA, 0x03F, 0x00000CF6, + 0x93011000, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x000000A0, + 0x03F, 0x00000C09, 0x033, 0x000000A1, 0x03F, 0x00000C0C, + 0x033, 0x000000A2, 0x03F, 0x00000C0F, 0x033, 0x000000A3, + 0x03F, 0x00000C2C, 0x033, 0x000000A4, 0x03F, 0x00000C2F, + 0x033, 0x000000A5, 0x03F, 0x00000C8A, 0x033, 0x000000A6, + 0x03F, 0x00000C8D, 0x033, 0x000000A7, 0x03F, 0x00000C90, + 0x033, 0x000000A8, 0x03F, 0x00000CEF, 0x033, 0x000000A9, + 0x03F, 0x00000CF2, 0x033, 0x000000AA, 0x03F, 0x00000CF5, + 0x9000200c, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x000000A0, + 0x03F, 0x00000005, 0x033, 0x000000A1, 0x03F, 0x00000008, + 0x033, 0x000000A2, 0x03F, 0x0000000B, 0x033, 0x000000A3, + 0x03F, 0x0000000E, 0x033, 0x000000A4, 0x03F, 0x00000047, + 0x033, 0x000000A5, 0x03F, 0x0000004A, 0x033, 0x000000A6, + 0x03F, 0x0000004D, 0x033, 0x000000A7, 0x03F, 0x00000050, + 0x033, 0x000000A8, 0x03F, 0x00000053, 0x033, 0x000000A9, + 0x03F, 0x00000056, 0x033, 0x000000AA, 0x03F, 0x00000094, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x000000A0, + 0x03F, 0x00000C09, 0x033, 0x000000A1, 0x03F, 0x00000C0C, + 0x033, 0x000000A2, 0x03F, 0x00000C0F, 0x033, 0x000000A3, + 0x03F, 0x00000C2C, 0x033, 0x000000A4, 0x03F, 0x00000C2F, + 0x033, 0x000000A5, 0x03F, 0x00000C8A, 0x033, 0x000000A6, + 0x03F, 0x00000C8D, 0x033, 0x000000A7, 0x03F, 0x00000C90, + 0x033, 0x000000A8, 0x03F, 0x00000CEF, 0x033, 0x000000A9, + 0x03F, 0x00000CF2, 0x033, 0x000000AA, 0x03F, 0x00000CF5, + 0x93002000, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x000000A0, + 0x03F, 0x00000429, 0x033, 0x000000A1, 0x03F, 0x00000828, + 0x033, 0x000000A2, 0x03F, 0x00000847, 0x033, 0x000000A3, + 0x03F, 0x0000084A, 0x033, 0x000000A4, 0x03F, 0x00000C4B, + 0x033, 0x000000A5, 0x03F, 0x00000C8A, 0x033, 0x000000A6, + 0x03F, 0x00000CEA, 0x033, 0x000000A7, 0x03F, 0x00000CED, + 0x033, 0x000000A8, 0x03F, 0x00000CF0, 0x033, 0x000000A9, + 0x03F, 0x00000CF3, 0x033, 0x000000AA, 0x03F, 0x00000CF6, + 0x93001000, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x000000A0, + 0x03F, 0x00000C09, 0x033, 0x000000A1, 0x03F, 0x00000C0C, + 0x033, 0x000000A2, 0x03F, 0x00000C0F, 0x033, 0x000000A3, + 0x03F, 0x00000C2C, 0x033, 0x000000A4, 0x03F, 0x00000C2F, + 0x033, 0x000000A5, 0x03F, 0x00000C8A, 0x033, 0x000000A6, + 0x03F, 0x00000C8D, 0x033, 0x000000A7, 0x03F, 0x00000C90, + 0x033, 0x000000A8, 0x03F, 0x00000CEF, 0x033, 0x000000A9, + 0x03F, 0x00000CF2, 0x033, 0x000000AA, 0x03F, 0x00000CF5, + 0x90002100, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x000000A0, + 0x03F, 0x0000042A, 0x033, 0x000000A1, 0x03F, 0x00000829, + 0x033, 0x000000A2, 0x03F, 0x00000848, 0x033, 0x000000A3, + 0x03F, 0x0000084B, 0x033, 0x000000A4, 0x03F, 0x00000C4C, + 0x033, 0x000000A5, 0x03F, 0x00000C8A, 0x033, 0x000000A6, + 0x03F, 0x00000C8D, 0x033, 0x000000A7, 0x03F, 0x00000CEC, + 0x033, 0x000000A8, 0x03F, 0x00000CEF, 0x033, 0x000000A9, + 0x03F, 0x00000CF2, 0x033, 0x000000AA, 0x03F, 0x00000CF5, + 0x90002000, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x000000A0, + 0x03F, 0x0000042A, 0x033, 0x000000A1, 0x03F, 0x00000829, + 0x033, 0x000000A2, 0x03F, 0x00000848, 0x033, 0x000000A3, + 0x03F, 0x0000084B, 0x033, 0x000000A4, 0x03F, 0x00000C4C, + 0x033, 0x000000A5, 0x03F, 0x00000C8A, 0x033, 0x000000A6, + 0x03F, 0x00000C8D, 0x033, 0x000000A7, 0x03F, 0x00000CEC, + 0x033, 0x000000A8, 0x03F, 0x00000CEF, 0x033, 0x000000A9, + 0x03F, 0x00000CF2, 0x033, 0x000000AA, 0x03F, 0x00000CF5, + 0xA0000000, 0x00000000, 0x033, 0x000000A0, 0x03F, 0x00000C09, + 0x033, 0x000000A1, 0x03F, 0x00000C0C, 0x033, 0x000000A2, + 0x03F, 0x00000C0F, 0x033, 0x000000A3, 0x03F, 0x00000C2C, + 0x033, 0x000000A4, 0x03F, 0x00000C2F, 0x033, 0x000000A5, + 0x03F, 0x00000C8A, 0x033, 0x000000A6, 0x03F, 0x00000C8D, + 0x033, 0x000000A7, 0x03F, 0x00000C90, 0x033, 0x000000A8, + 0x03F, 0x00000CEF, 0x033, 0x000000A9, 0x03F, 0x00000CF2, + 0x033, 0x000000AA, 0x03F, 0x00000CF5, 0xB0000000, 0x00000000, + 0x0EF, 0x00000000, 0x0EF, 0x00000400, 0x8300100f, 0x0a0a0a0a, + 0x40000000, 0x00000000, 0x033, 0x00000000, 0x03F, 0x0000265A, + 0x033, 0x00000001, 0x03F, 0x0000265A, 0x033, 0x00000002, + 0x03F, 0x0000265A, 0x033, 0x00000003, 0x03F, 0x0000265A, + 0x9300100f, 0x05050505, 0x40000000, 0x00000000, 0x033, 0x00000000, + 0x03F, 0x0000265A, 0x033, 0x00000001, 0x03F, 0x0000265A, + 0x033, 0x00000002, 0x03F, 0x0000265A, 0x033, 0x00000003, + 0x03F, 0x0000265A, 0x9300100f, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x00000000, 0x03F, 0x0000265A, 0x033, 0x00000001, + 0x03F, 0x0000265A, 0x033, 0x00000002, 0x03F, 0x0000265A, + 0x033, 0x00000003, 0x03F, 0x0000265A, 0x9300200f, 0x00000000, + 0x40000000, 0x00000000, 0x033, 0x00000000, 0x03F, 0x0000265A, + 0x033, 0x00000001, 0x03F, 0x0000265A, 0x033, 0x00000002, + 0x03F, 0x0000265A, 0x033, 0x00000003, 0x03F, 0x0000265A, + 0x9000100f, 0x0a0a0a0a, 0x40000000, 0x00000000, 0x033, 0x00000000, + 0x03F, 0x0000265A, 0x033, 0x00000001, 0x03F, 0x0000265A, + 0x033, 0x00000002, 0x03F, 0x0000265A, 0x033, 0x00000003, + 0x03F, 0x0000265A, 0x9000100f, 0x05050505, 0x40000000, 0x00000000, + 0x033, 0x00000000, 0x03F, 0x0000265A, 0x033, 0x00000001, + 0x03F, 0x0000265A, 0x033, 0x00000002, 0x03F, 0x0000265A, + 0x033, 0x00000003, 0x03F, 0x0000265A, 0x9000100f, 0x00000000, + 0x40000000, 0x00000000, 0x033, 0x00000000, 0x03F, 0x0000265A, + 0x033, 0x00000001, 0x03F, 0x0000265A, 0x033, 0x00000002, + 0x03F, 0x0000265A, 0x033, 0x00000003, 0x03F, 0x0000265A, + 0x9000200f, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000000, + 0x03F, 0x0000265A, 0x033, 0x00000001, 0x03F, 0x0000265A, + 0x033, 0x00000002, 0x03F, 0x0000265A, 0x033, 0x00000003, + 0x03F, 0x0000265A, 0xA0000000, 0x00000000, 0x033, 0x00000000, + 0x03F, 0x000004BB, 0x033, 0x00000001, 0x03F, 0x000004BB, + 0x033, 0x00000002, 0x03F, 0x000004BB, 0x033, 0x00000003, + 0x03F, 0x000004BB, 0xB0000000, 0x00000000, 0x0EF, 0x00000000, + 0x0EF, 0x00000100, 0x8300100f, 0x0a0a0a0a, 0x40000000, 0x00000000, + 0x033, 0x00000000, 0x03F, 0x00000745, 0x033, 0x00000001, + 0x03F, 0x00000745, 0x033, 0x00000002, 0x03F, 0x00000745, + 0x033, 0x00000003, 0x03F, 0x00000745, 0x9300100f, 0x05050505, + 0x40000000, 0x00000000, 0x033, 0x00000000, 0x03F, 0x00000745, + 0x033, 0x00000001, 0x03F, 0x00000745, 0x033, 0x00000002, + 0x03F, 0x00000745, 0x033, 0x00000003, 0x03F, 0x00000745, + 0x9300100f, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000000, + 0x03F, 0x00000745, 0x033, 0x00000001, 0x03F, 0x00000745, + 0x033, 0x00000002, 0x03F, 0x00000745, 0x033, 0x00000003, + 0x03F, 0x00000745, 0x9300200f, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x00000000, 0x03F, 0x00000745, 0x033, 0x00000001, + 0x03F, 0x00000745, 0x033, 0x00000002, 0x03F, 0x00000745, + 0x033, 0x00000003, 0x03F, 0x00000745, 0x9000100f, 0x0a0a0a0a, + 0x40000000, 0x00000000, 0x033, 0x00000000, 0x03F, 0x00000745, + 0x033, 0x00000001, 0x03F, 0x00000745, 0x033, 0x00000002, + 0x03F, 0x00000745, 0x033, 0x00000003, 0x03F, 0x00000745, + 0x9000100f, 0x05050505, 0x40000000, 0x00000000, 0x033, 0x00000000, + 0x03F, 0x00000745, 0x033, 0x00000001, 0x03F, 0x00000745, + 0x033, 0x00000002, 0x03F, 0x00000745, 0x033, 0x00000003, + 0x03F, 0x00000745, 0x9000100f, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x00000000, 0x03F, 0x00000745, 0x033, 0x00000001, + 0x03F, 0x00000745, 0x033, 0x00000002, 0x03F, 0x00000745, + 0x033, 0x00000003, 0x03F, 0x00000745, 0x9000200f, 0x00000000, + 0x40000000, 0x00000000, 0x033, 0x00000000, 0x03F, 0x00000745, + 0x033, 0x00000001, 0x03F, 0x00000745, 0x033, 0x00000002, + 0x03F, 0x00000745, 0x033, 0x00000003, 0x03F, 0x00000745, + 0xA0000000, 0x00000000, 0x033, 0x00000000, 0x03F, 0x00000F34, + 0x033, 0x00000001, 0x03F, 0x00000F34, 0x033, 0x00000002, + 0x03F, 0x00000F34, 0x033, 0x00000003, 0x03F, 0x00000F34, + 0xB0000000, 0x00000000, 0x0EF, 0x00000000, 0x8300100f, 0x0a0a0a0a, + 0x40000000, 0x00000000, 0x081, 0x0000F400, 0x087, 0x00016040, + 0x051, 0x00000808, 0x052, 0x00098002, 0x053, 0x0000FA47, + 0x054, 0x00058032, 0x056, 0x00051000, 0x057, 0x0000CE0A, + 0x058, 0x00082030, 0x9300100f, 0x05050505, 0x40000000, 0x00000000, + 0x081, 0x0000F400, 0x087, 0x00016040, 0x051, 0x00000808, + 0x052, 0x00098002, 0x053, 0x0000FA47, 0x054, 0x00058032, + 0x056, 0x00051000, 0x057, 0x0000CE0A, 0x058, 0x00082030, + 0x9300100f, 0x00000000, 0x40000000, 0x00000000, 0x081, 0x0000F400, + 0x087, 0x00016040, 0x051, 0x00000808, 0x052, 0x00098002, + 0x053, 0x0000FA47, 0x054, 0x00058032, 0x056, 0x00051000, + 0x057, 0x0000CE0A, 0x058, 0x00082030, 0x9300200f, 0x00000000, + 0x40000000, 0x00000000, 0x081, 0x0000F400, 0x087, 0x00016040, + 0x051, 0x00000808, 0x052, 0x00098002, 0x053, 0x0000FA47, + 0x054, 0x00058032, 0x056, 0x00051000, 0x057, 0x0000CE0A, + 0x058, 0x00082030, 0x9000100f, 0x0a0a0a0a, 0x40000000, 0x00000000, + 0x081, 0x0000F400, 0x087, 0x00016040, 0x051, 0x00000808, + 0x052, 0x00098002, 0x053, 0x0000FA47, 0x054, 0x00058032, + 0x056, 0x00051000, 0x057, 0x0000CE0A, 0x058, 0x00082030, + 0x9000100f, 0x05050505, 0x40000000, 0x00000000, 0x081, 0x0000F400, + 0x087, 0x00016040, 0x051, 0x00000808, 0x052, 0x00098002, + 0x053, 0x0000FA47, 0x054, 0x00058032, 0x056, 0x00051000, + 0x057, 0x0000CE0A, 0x058, 0x00082030, 0x9000100f, 0x00000000, + 0x40000000, 0x00000000, 0x081, 0x0000F400, 0x087, 0x00016040, + 0x051, 0x00000808, 0x052, 0x00098002, 0x053, 0x0000FA47, + 0x054, 0x00058032, 0x056, 0x00051000, 0x057, 0x0000CE0A, + 0x058, 0x00082030, 0x9000200f, 0x00000000, 0x40000000, 0x00000000, + 0x081, 0x0000F400, 0x087, 0x00016040, 0x051, 0x00000808, + 0x052, 0x00098002, 0x053, 0x0000FA47, 0x054, 0x00058032, + 0x056, 0x00051000, 0x057, 0x0000CE0A, 0x058, 0x00082030, + 0xA0000000, 0x00000000, 0x081, 0x0000F000, 0x087, 0x00016040, + 0x051, 0x00000C00, 0x052, 0x0007C241, 0x053, 0x0001C069, + 0x054, 0x00078032, 0x057, 0x0000CE0A, 0x058, 0x00058750, + 0xB0000000, 0x00000000, 0x0EF, 0x00000800, 0x8300100f, 0x0a0a0a0a, + 0x40000000, 0x00000000, 0x033, 0x00000000, 0x03F, 0x00000003, + 0x033, 0x00000001, 0x03F, 0x00000006, 0x033, 0x00000002, + 0x03F, 0x00000009, 0x033, 0x00000003, 0x03F, 0x00000026, + 0x033, 0x00000004, 0x03F, 0x00000029, 0x033, 0x00000005, + 0x03F, 0x0000002C, 0x033, 0x00000006, 0x03F, 0x0000002F, + 0x033, 0x00000007, 0x03F, 0x00000033, 0x033, 0x00000008, + 0x03F, 0x00000036, 0x033, 0x00000009, 0x03F, 0x00000039, + 0x033, 0x0000000A, 0x03F, 0x0000003C, 0x9300100f, 0x05050505, + 0x40000000, 0x00000000, 0x033, 0x00000000, 0x03F, 0x00000003, + 0x033, 0x00000001, 0x03F, 0x00000006, 0x033, 0x00000002, + 0x03F, 0x00000009, 0x033, 0x00000003, 0x03F, 0x00000026, + 0x033, 0x00000004, 0x03F, 0x00000029, 0x033, 0x00000005, + 0x03F, 0x0000002C, 0x033, 0x00000006, 0x03F, 0x0000002F, + 0x033, 0x00000007, 0x03F, 0x00000033, 0x033, 0x00000008, + 0x03F, 0x00000036, 0x033, 0x00000009, 0x03F, 0x00000039, + 0x033, 0x0000000A, 0x03F, 0x0000003C, 0x9300100f, 0x00000000, + 0x40000000, 0x00000000, 0x033, 0x00000000, 0x03F, 0x00000003, + 0x033, 0x00000001, 0x03F, 0x00000006, 0x033, 0x00000002, + 0x03F, 0x00000009, 0x033, 0x00000003, 0x03F, 0x00000026, + 0x033, 0x00000004, 0x03F, 0x00000029, 0x033, 0x00000005, + 0x03F, 0x0000002C, 0x033, 0x00000006, 0x03F, 0x0000002F, + 0x033, 0x00000007, 0x03F, 0x00000033, 0x033, 0x00000008, + 0x03F, 0x00000036, 0x033, 0x00000009, 0x03F, 0x00000039, + 0x033, 0x0000000A, 0x03F, 0x0000003C, 0x9300200f, 0x00000000, + 0x40000000, 0x00000000, 0x033, 0x00000000, 0x03F, 0x00000003, + 0x033, 0x00000001, 0x03F, 0x00000006, 0x033, 0x00000002, + 0x03F, 0x00000009, 0x033, 0x00000003, 0x03F, 0x00000026, + 0x033, 0x00000004, 0x03F, 0x00000029, 0x033, 0x00000005, + 0x03F, 0x0000002C, 0x033, 0x00000006, 0x03F, 0x0000002F, + 0x033, 0x00000007, 0x03F, 0x00000033, 0x033, 0x00000008, + 0x03F, 0x00000036, 0x033, 0x00000009, 0x03F, 0x00000039, + 0x033, 0x0000000A, 0x03F, 0x0000003C, 0x9000100f, 0x0a0a0a0a, + 0x40000000, 0x00000000, 0x033, 0x00000000, 0x03F, 0x00000003, + 0x033, 0x00000001, 0x03F, 0x00000006, 0x033, 0x00000002, + 0x03F, 0x00000009, 0x033, 0x00000003, 0x03F, 0x00000026, + 0x033, 0x00000004, 0x03F, 0x00000029, 0x033, 0x00000005, + 0x03F, 0x0000002C, 0x033, 0x00000006, 0x03F, 0x0000002F, + 0x033, 0x00000007, 0x03F, 0x00000033, 0x033, 0x00000008, + 0x03F, 0x00000036, 0x033, 0x00000009, 0x03F, 0x00000039, + 0x033, 0x0000000A, 0x03F, 0x0000003C, 0x9000100f, 0x05050505, + 0x40000000, 0x00000000, 0x033, 0x00000000, 0x03F, 0x00000003, + 0x033, 0x00000001, 0x03F, 0x00000006, 0x033, 0x00000002, + 0x03F, 0x00000009, 0x033, 0x00000003, 0x03F, 0x00000026, + 0x033, 0x00000004, 0x03F, 0x00000029, 0x033, 0x00000005, + 0x03F, 0x0000002C, 0x033, 0x00000006, 0x03F, 0x0000002F, + 0x033, 0x00000007, 0x03F, 0x00000033, 0x033, 0x00000008, + 0x03F, 0x00000036, 0x033, 0x00000009, 0x03F, 0x00000039, + 0x033, 0x0000000A, 0x03F, 0x0000003C, 0x9000100f, 0x00000000, + 0x40000000, 0x00000000, 0x033, 0x00000000, 0x03F, 0x00000003, + 0x033, 0x00000001, 0x03F, 0x00000006, 0x033, 0x00000002, + 0x03F, 0x00000009, 0x033, 0x00000003, 0x03F, 0x00000026, + 0x033, 0x00000004, 0x03F, 0x00000029, 0x033, 0x00000005, + 0x03F, 0x0000002C, 0x033, 0x00000006, 0x03F, 0x0000002F, + 0x033, 0x00000007, 0x03F, 0x00000033, 0x033, 0x00000008, + 0x03F, 0x00000036, 0x033, 0x00000009, 0x03F, 0x00000039, + 0x033, 0x0000000A, 0x03F, 0x0000003C, 0x9000200f, 0x00000000, + 0x40000000, 0x00000000, 0x033, 0x00000000, 0x03F, 0x00000003, + 0x033, 0x00000001, 0x03F, 0x00000006, 0x033, 0x00000002, + 0x03F, 0x00000009, 0x033, 0x00000003, 0x03F, 0x00000026, + 0x033, 0x00000004, 0x03F, 0x00000029, 0x033, 0x00000005, + 0x03F, 0x0000002C, 0x033, 0x00000006, 0x03F, 0x0000002F, + 0x033, 0x00000007, 0x03F, 0x00000033, 0x033, 0x00000008, + 0x03F, 0x00000036, 0x033, 0x00000009, 0x03F, 0x00000039, + 0x033, 0x0000000A, 0x03F, 0x0000003C, 0xA0000000, 0x00000000, + 0x033, 0x00000000, 0x03F, 0x0005142C, 0x033, 0x00000001, + 0x03F, 0x0005142F, 0x033, 0x00000002, 0x03F, 0x00051432, + 0x033, 0x00000003, 0x03F, 0x00051C87, 0x033, 0x00000004, + 0x03F, 0x00051C8A, 0x033, 0x00000005, 0x03F, 0x00051C8D, + 0x033, 0x00000006, 0x03F, 0x00051CEB, 0x033, 0x00000007, + 0x03F, 0x00051CEE, 0x033, 0x00000008, 0x03F, 0x00051CF1, + 0x033, 0x00000009, 0x03F, 0x00051CF4, 0x033, 0x0000000A, + 0x03F, 0x00051CF7, 0xB0000000, 0x00000000, 0x0EF, 0x00000000, + 0x0EF, 0x00000010, 0x033, 0x00000000, 0x008, 0x0009C060, + 0x033, 0x00000001, 0x008, 0x0009C060, 0x0EF, 0x00000000, + 0x033, 0x000000A2, 0x0EF, 0x00080000, 0x03E, 0x0000593F, + 0x03F, 0x000C0F4F, 0x0EF, 0x00000000, 0x033, 0x000000A3, + 0x0EF, 0x00080000, 0x03E, 0x00005934, 0x03F, 0x0005AFCF, + 0x0EF, 0x00000000, + +}; + +void odm_read_and_config_mp_8822b_radiob(struct phy_dm_struct *dm) +{ + u32 i = 0; + u8 c_cond; + bool is_matched = true, is_skipped = false; + u32 array_len = sizeof(array_mp_8822b_radiob) / sizeof(u32); + u32 *array = array_mp_8822b_radiob; + + u32 v1 = 0, v2 = 0, pre_v1 = 0, pre_v2 = 0; + + ODM_RT_TRACE(dm, ODM_COMP_INIT, + "===> %s\n", __func__); + + for (; (i + 1) < array_len; i = i + 2) { + v1 = array[i]; + v2 = array[i + 1]; + + if (v1 & BIT(31)) { /* positive condition*/ + c_cond = (u8)((v1 & (BIT(29) | BIT(28))) >> 28); + if (c_cond == COND_ENDIF) { /*end*/ + is_matched = true; + is_skipped = false; + ODM_RT_TRACE(dm, ODM_COMP_INIT, "ENDIF\n"); + } else if (c_cond == COND_ELSE) { /*else*/ + is_matched = is_skipped ? false : true; + ODM_RT_TRACE(dm, ODM_COMP_INIT, "ELSE\n"); + } else { /*if , else if*/ + pre_v1 = v1; + pre_v2 = v2; + ODM_RT_TRACE(dm, ODM_COMP_INIT, + "IF or ELSE IF\n"); + } + } else if (v1 & BIT(30)) { /*negative condition*/ + if (is_skipped) { + is_matched = false; + continue; + } + + if (check_positive(dm, pre_v1, pre_v2, v1, v2)) { + is_matched = true; + is_skipped = true; + } else { + is_matched = false; + is_skipped = false; + } + } else if (is_matched) { + odm_config_rf_radio_b_8822b(dm, v1, v2); + } + } +} + +u32 odm_get_version_mp_8822b_radiob(void) { return 67; } + +/****************************************************************************** + * txpowertrack.TXT + ******************************************************************************/ + +static u8 delta_swing_index_mp_5gb_n_txpwrtrack_8822b[][DELTA_SWINGIDX_SIZE] = { + {0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 10, + 11, 11, 12, 12, 12, 13, 13, 14, 14, 14, 15, 15, 15, 15, 15}, + {0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 6, 7, 7, 8, 8, + 9, 10, 10, 11, 12, 12, 13, 13, 14, 14, 14, 14, 14, 14, 14}, + {0, 1, 2, 2, 3, 3, 4, 4, 5, 6, 6, 7, 7, 8, 9, + 9, 10, 10, 11, 12, 12, 13, 13, 14, 14, 14, 14, 14, 14, 14}, +}; + +static u8 delta_swing_index_mp_5gb_p_txpwrtrack_8822b[][DELTA_SWINGIDX_SIZE] = { + {0, 1, 2, 2, 3, 4, 5, 6, 7, 8, 8, 9, 10, 11, 11, + 12, 13, 14, 15, 15, 16, 17, 18, 18, 19, 19, 19, 19, 19, 19}, + {0, 1, 2, 2, 3, 4, 5, 6, 6, 7, 8, 8, 9, 9, 10, + 11, 12, 12, 13, 14, 15, 16, 17, 17, 18, 18, 18, 18, 18, 18}, + {0, 1, 2, 2, 3, 4, 5, 5, 6, 6, 7, 8, 8, 9, 10, + 10, 11, 12, 13, 14, 15, 15, 16, 16, 17, 17, 17, 17, 17, 17}, +}; + +static u8 delta_swing_index_mp_5ga_n_txpwrtrack_8822b[][DELTA_SWINGIDX_SIZE] = { + {0, 1, 2, 2, 3, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, + 11, 11, 12, 12, 12, 13, 13, 14, 14, 14, 15, 15, 15, 15, 15}, + {0, 1, 2, 2, 3, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, + 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 14, 14, 14, 14, 14}, + {0, 1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 7, 8, 8, 9, + 9, 10, 10, 11, 12, 12, 13, 13, 14, 14, 14, 14, 14, 14, 14}, +}; + +static u8 delta_swing_index_mp_5ga_p_txpwrtrack_8822b[][DELTA_SWINGIDX_SIZE] = { + {0, 1, 2, 2, 3, 4, 5, 5, 6, 7, 8, 9, 9, 10, 11, + 12, 13, 14, 14, 15, 16, 17, 18, 19, 19, 20, 20, 20, 20, 20}, + {0, 1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 7, 8, 9, 9, + 10, 11, 11, 12, 13, 14, 15, 16, 16, 17, 17, 18, 18, 18, 18}, + {0, 1, 2, 3, 3, 4, 5, 5, 6, 6, 7, 8, 8, 9, 10, + 11, 12, 12, 13, 14, 15, 15, 16, 17, 17, 18, 18, 18, 18, 18}, +}; + +static u8 delta_swing_index_mp_2gb_n_txpwrtrack_8822b[] = { + 0, 1, 2, 3, 3, 4, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 13, 14, 15, 16, 16, 17, 18, 18, 18, 18, 18, 18, 18, 18}; + +static u8 delta_swing_index_mp_2gb_p_txpwrtrack_8822b[] = { + 0, 1, 1, 2, 3, 4, 4, 5, 6, 7, 7, 8, 9, 10, 11, + 12, 12, 13, 14, 15, 16, 17, 17, 18, 19, 20, 21, 22, 22, 22}; + +static u8 delta_swing_index_mp_2ga_n_txpwrtrack_8822b[] = { + 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 10, 11, 12, + 13, 13, 14, 15, 16, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18}; + +static u8 delta_swing_index_mp_2ga_p_txpwrtrack_8822b[] = { + 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, + 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 22, 22}; + +static u8 delta_swing_index_mp_2g_cck_b_n_txpwrtrack_8822b[] = { + 0, 1, 1, 2, 3, 4, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 13, 14, 15, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17}; + +static u8 delta_swing_index_mp_2g_cck_b_p_txpwrtrack_8822b[] = { + 0, 1, 1, 2, 3, 4, 4, 5, 6, 7, 8, 9, 9, 10, 11, + 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 22, 22}; + +static u8 delta_swing_index_mp_2g_cck_a_n_txpwrtrack_8822b[] = { + 0, 1, 2, 3, 3, 4, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 13, 14, 15, 16, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18}; + +static u8 delta_swing_index_mp_2g_cck_a_p_txpwrtrack_8822b[] = { + 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, + 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 22, 22}; + +void odm_read_and_config_mp_8822b_txpowertrack(struct phy_dm_struct *dm) +{ + struct dm_rf_calibration_struct *cali_info = &dm->rf_calibrate_info; + + ODM_RT_TRACE(dm, ODM_COMP_INIT, "===> ODM_ReadAndConfig_MP_mp_8822b\n"); + + odm_move_memory(dm, cali_info->delta_swing_table_idx_2ga_p, + delta_swing_index_mp_2ga_p_txpwrtrack_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2ga_n, + delta_swing_index_mp_2ga_n_txpwrtrack_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2gb_p, + delta_swing_index_mp_2gb_p_txpwrtrack_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2gb_n, + delta_swing_index_mp_2gb_n_txpwrtrack_8822b, + DELTA_SWINGIDX_SIZE); + + odm_move_memory(dm, cali_info->delta_swing_table_idx_2g_cck_a_p, + delta_swing_index_mp_2g_cck_a_p_txpwrtrack_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2g_cck_a_n, + delta_swing_index_mp_2g_cck_a_n_txpwrtrack_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2g_cck_b_p, + delta_swing_index_mp_2g_cck_b_p_txpwrtrack_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2g_cck_b_n, + delta_swing_index_mp_2g_cck_b_n_txpwrtrack_8822b, + DELTA_SWINGIDX_SIZE); + + odm_move_memory(dm, cali_info->delta_swing_table_idx_5ga_p, + delta_swing_index_mp_5ga_p_txpwrtrack_8822b, + DELTA_SWINGIDX_SIZE * 3); + odm_move_memory(dm, cali_info->delta_swing_table_idx_5ga_n, + delta_swing_index_mp_5ga_n_txpwrtrack_8822b, + DELTA_SWINGIDX_SIZE * 3); + odm_move_memory(dm, cali_info->delta_swing_table_idx_5gb_p, + delta_swing_index_mp_5gb_p_txpwrtrack_8822b, + DELTA_SWINGIDX_SIZE * 3); + odm_move_memory(dm, cali_info->delta_swing_table_idx_5gb_n, + delta_swing_index_mp_5gb_n_txpwrtrack_8822b, + DELTA_SWINGIDX_SIZE * 3); +} + +/****************************************************************************** + * txpowertrack_type0.TXT + ******************************************************************************/ + +static u8 delta_swing_index_mp_5gb_n_txpwrtrack_type0_8822b + [][DELTA_SWINGIDX_SIZE] = { + {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, + 8, 8, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15}, + {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 8, + 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 14, 14}, + {0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 6, 7, 7, 8, 8, + 9, 9, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 15, 15}, +}; + +static u8 delta_swing_index_mp_5gb_p_txpwrtrack_type0_8822b + [][DELTA_SWINGIDX_SIZE] = { + {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, + 8, 8, 9, 9, 10, 10, 11, 12, 12, 13, 13, 14, 14, 15, 15}, + {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, + 8, 8, 9, 9, 10, 11, 11, 12, 13, 13, 14, 14, 15, 15, 15}, + {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, + 8, 8, 9, 10, 10, 11, 12, 13, 14, 14, 15, 15, 15, 16, 16}, +}; + +static u8 delta_swing_index_mp_5ga_n_txpwrtrack_type0_8822b + [][DELTA_SWINGIDX_SIZE] = { + {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, + 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 13, 14, 14}, + {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, + 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 14}, + {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, + 8, 8, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 14, 14}, +}; + +static u8 delta_swing_index_mp_5ga_p_txpwrtrack_type0_8822b + [][DELTA_SWINGIDX_SIZE] = { + {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, + 8, 8, 9, 9, 10, 10, 11, 12, 13, 13, 14, 14, 15, 15, 15}, + {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, + 8, 8, 9, 9, 10, 10, 11, 12, 12, 13, 13, 14, 14, 15, 15}, + {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, + 8, 9, 9, 10, 10, 11, 11, 12, 13, 13, 14, 14, 15, 15, 15}, +}; + +static u8 delta_swing_index_mp_2gb_n_txpwrtrack_type0_8822b[] = { + 0, 1, 2, 3, 3, 4, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 13, 14, 15, 16, 16, 17, 18, 18, 18, 18, 18, 18, 18, 18}; + +static u8 delta_swing_index_mp_2gb_p_txpwrtrack_type0_8822b[] = { + 0, 1, 1, 2, 3, 4, 4, 5, 6, 7, 7, 8, 9, 10, 11, + 12, 12, 13, 14, 15, 16, 17, 17, 18, 19, 20, 21, 22, 22, 22}; + +static u8 delta_swing_index_mp_2ga_n_txpwrtrack_type0_8822b[] = { + 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 10, 11, 12, + 13, 13, 14, 15, 16, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18}; + +static u8 delta_swing_index_mp_2ga_p_txpwrtrack_type0_8822b[] = { + 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, + 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 22, 22}; + +static u8 delta_swing_index_mp_2g_cck_b_n_txpwrtrack_type0_8822b[] = { + 0, 1, 1, 2, 3, 4, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 13, 14, 15, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17}; + +static u8 delta_swing_index_mp_2g_cck_b_p_txpwrtrack_type0_8822b[] = { + 0, 1, 1, 2, 3, 4, 4, 5, 6, 7, 8, 9, 9, 10, 11, + 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 22, 22}; + +static u8 delta_swing_index_mp_2g_cck_a_n_txpwrtrack_type0_8822b[] = { + 0, 1, 2, 3, 3, 4, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 13, 14, 15, 16, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18}; + +static u8 delta_swing_index_mp_2g_cck_a_p_txpwrtrack_type0_8822b[] = { + 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, + 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 22, 22}; + +void odm_read_and_config_mp_8822b_txpowertrack_type0(struct phy_dm_struct *dm) +{ + struct dm_rf_calibration_struct *cali_info = &dm->rf_calibrate_info; + + ODM_RT_TRACE(dm, ODM_COMP_INIT, "===> ODM_ReadAndConfig_MP_mp_8822b\n"); + + odm_move_memory(dm, cali_info->delta_swing_table_idx_2ga_p, + delta_swing_index_mp_2ga_p_txpwrtrack_type0_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2ga_n, + delta_swing_index_mp_2ga_n_txpwrtrack_type0_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2gb_p, + delta_swing_index_mp_2gb_p_txpwrtrack_type0_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2gb_n, + delta_swing_index_mp_2gb_n_txpwrtrack_type0_8822b, + DELTA_SWINGIDX_SIZE); + + odm_move_memory(dm, cali_info->delta_swing_table_idx_2g_cck_a_p, + delta_swing_index_mp_2g_cck_a_p_txpwrtrack_type0_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2g_cck_a_n, + delta_swing_index_mp_2g_cck_a_n_txpwrtrack_type0_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2g_cck_b_p, + delta_swing_index_mp_2g_cck_b_p_txpwrtrack_type0_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2g_cck_b_n, + delta_swing_index_mp_2g_cck_b_n_txpwrtrack_type0_8822b, + DELTA_SWINGIDX_SIZE); + + odm_move_memory(dm, cali_info->delta_swing_table_idx_5ga_p, + delta_swing_index_mp_5ga_p_txpwrtrack_type0_8822b, + DELTA_SWINGIDX_SIZE * 3); + odm_move_memory(dm, cali_info->delta_swing_table_idx_5ga_n, + delta_swing_index_mp_5ga_n_txpwrtrack_type0_8822b, + DELTA_SWINGIDX_SIZE * 3); + odm_move_memory(dm, cali_info->delta_swing_table_idx_5gb_p, + delta_swing_index_mp_5gb_p_txpwrtrack_type0_8822b, + DELTA_SWINGIDX_SIZE * 3); + odm_move_memory(dm, cali_info->delta_swing_table_idx_5gb_n, + delta_swing_index_mp_5gb_n_txpwrtrack_type0_8822b, + DELTA_SWINGIDX_SIZE * 3); +} + +/****************************************************************************** + * txpowertrack_type1.TXT + ******************************************************************************/ + +static u8 delta_swing_index_mp_5gb_n_txpwrtrack_type1_8822b + [][DELTA_SWINGIDX_SIZE] = { + {0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 10, + 11, 11, 12, 12, 12, 13, 13, 14, 14, 14, 15, 15, 15, 15, 15}, + {0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 6, 7, 7, 8, 8, + 9, 10, 10, 11, 12, 12, 13, 13, 14, 14, 14, 14, 14, 14, 14}, + {0, 1, 2, 2, 3, 3, 4, 4, 5, 6, 6, 7, 7, 8, 9, + 9, 10, 10, 11, 12, 12, 13, 13, 14, 14, 14, 14, 14, 14, 14}, +}; + +static u8 delta_swing_index_mp_5gb_p_txpwrtrack_type1_8822b + [][DELTA_SWINGIDX_SIZE] = { + {0, 1, 2, 2, 3, 4, 5, 6, 7, 8, 8, 9, 10, 11, 11, + 12, 13, 14, 15, 15, 16, 17, 18, 18, 19, 19, 19, 19, 19, 19}, + {0, 1, 2, 2, 3, 4, 5, 6, 6, 7, 8, 8, 9, 9, 10, + 11, 12, 12, 13, 14, 15, 16, 17, 17, 18, 18, 18, 18, 18, 18}, + {0, 1, 2, 2, 3, 4, 5, 5, 6, 6, 7, 8, 8, 9, 10, + 10, 11, 12, 13, 14, 15, 15, 16, 16, 17, 17, 17, 17, 17, 17}, +}; + +static u8 delta_swing_index_mp_5ga_n_txpwrtrack_type1_8822b + [][DELTA_SWINGIDX_SIZE] = { + {0, 1, 2, 2, 3, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, + 11, 11, 12, 12, 12, 13, 13, 14, 14, 14, 15, 15, 15, 15, 15}, + {0, 1, 2, 2, 3, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, + 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 14, 14, 14, 14, 14}, + {0, 1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 7, 8, 8, 9, + 9, 10, 10, 11, 12, 12, 13, 13, 14, 14, 14, 14, 14, 14, 14}, +}; + +static u8 delta_swing_index_mp_5ga_p_txpwrtrack_type1_8822b + [][DELTA_SWINGIDX_SIZE] = { + {0, 1, 2, 2, 3, 4, 5, 5, 6, 7, 8, 9, 9, 10, 11, + 12, 13, 14, 14, 15, 16, 17, 18, 19, 19, 20, 20, 20, 20, 20}, + {0, 1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 7, 8, 9, 9, + 10, 11, 11, 12, 13, 14, 15, 16, 16, 17, 17, 18, 18, 18, 18}, + {0, 1, 2, 3, 3, 4, 5, 5, 6, 6, 7, 8, 8, 9, 10, + 11, 12, 12, 13, 14, 15, 15, 16, 17, 17, 18, 18, 18, 18, 18}, +}; + +static u8 delta_swing_index_mp_2gb_n_txpwrtrack_type1_8822b[] = { + 0, 1, 2, 3, 3, 4, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 13, 14, 15, 16, 16, 17, 18, 18, 18, 18, 18, 18, 18, 18}; + +static u8 delta_swing_index_mp_2gb_p_txpwrtrack_type1_8822b[] = { + 0, 1, 1, 2, 3, 4, 4, 5, 6, 7, 7, 8, 9, 10, 11, + 12, 12, 13, 14, 15, 16, 17, 17, 18, 19, 20, 21, 22, 22, 22}; + +static u8 delta_swing_index_mp_2ga_n_txpwrtrack_type1_8822b[] = { + 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 10, 11, 12, + 13, 13, 14, 15, 16, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18}; + +static u8 delta_swing_index_mp_2ga_p_txpwrtrack_type1_8822b[] = { + 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, + 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 22, 22}; + +static u8 delta_swing_index_mp_2g_cck_b_n_txpwrtrack_type1_8822b[] = { + 0, 1, 1, 2, 3, 4, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 13, 14, 15, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17}; + +static u8 delta_swing_index_mp_2g_cck_b_p_txpwrtrack_type1_8822b[] = { + 0, 1, 1, 2, 3, 4, 4, 5, 6, 7, 8, 9, 9, 10, 11, + 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 22, 22}; + +static u8 delta_swing_index_mp_2g_cck_a_n_txpwrtrack_type1_8822b[] = { + 0, 1, 2, 3, 3, 4, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 13, 14, 15, 16, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18}; + +static u8 delta_swing_index_mp_2g_cck_a_p_txpwrtrack_type1_8822b[] = { + 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, + 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 22, 22}; + +void odm_read_and_config_mp_8822b_txpowertrack_type1(struct phy_dm_struct *dm) +{ + struct dm_rf_calibration_struct *cali_info = &dm->rf_calibrate_info; + + ODM_RT_TRACE(dm, ODM_COMP_INIT, "===> ODM_ReadAndConfig_MP_mp_8822b\n"); + + odm_move_memory(dm, cali_info->delta_swing_table_idx_2ga_p, + delta_swing_index_mp_2ga_p_txpwrtrack_type1_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2ga_n, + delta_swing_index_mp_2ga_n_txpwrtrack_type1_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2gb_p, + delta_swing_index_mp_2gb_p_txpwrtrack_type1_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2gb_n, + delta_swing_index_mp_2gb_n_txpwrtrack_type1_8822b, + DELTA_SWINGIDX_SIZE); + + odm_move_memory(dm, cali_info->delta_swing_table_idx_2g_cck_a_p, + delta_swing_index_mp_2g_cck_a_p_txpwrtrack_type1_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2g_cck_a_n, + delta_swing_index_mp_2g_cck_a_n_txpwrtrack_type1_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2g_cck_b_p, + delta_swing_index_mp_2g_cck_b_p_txpwrtrack_type1_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2g_cck_b_n, + delta_swing_index_mp_2g_cck_b_n_txpwrtrack_type1_8822b, + DELTA_SWINGIDX_SIZE); + + odm_move_memory(dm, cali_info->delta_swing_table_idx_5ga_p, + delta_swing_index_mp_5ga_p_txpwrtrack_type1_8822b, + DELTA_SWINGIDX_SIZE * 3); + odm_move_memory(dm, cali_info->delta_swing_table_idx_5ga_n, + delta_swing_index_mp_5ga_n_txpwrtrack_type1_8822b, + DELTA_SWINGIDX_SIZE * 3); + odm_move_memory(dm, cali_info->delta_swing_table_idx_5gb_p, + delta_swing_index_mp_5gb_p_txpwrtrack_type1_8822b, + DELTA_SWINGIDX_SIZE * 3); + odm_move_memory(dm, cali_info->delta_swing_table_idx_5gb_n, + delta_swing_index_mp_5gb_n_txpwrtrack_type1_8822b, + DELTA_SWINGIDX_SIZE * 3); +} + +/****************************************************************************** + * txpowertrack_type2.TXT + ******************************************************************************/ + +static u8 delta_swing_index_mp_5gb_n_txpwrtrack_type2_8822b + [][DELTA_SWINGIDX_SIZE] = { + {0, 1, 2, 2, 3, 4, 5, 5, 6, 7, 8, 8, 9, 10, 11, + 11, 12, 13, 14, 14, 15, 16, 17, 17, 18, 19, 20, 20, 21, 22}, + {0, 1, 2, 2, 3, 4, 5, 5, 6, 7, 8, 8, 9, 10, 11, + 11, 12, 13, 14, 14, 15, 16, 17, 17, 18, 19, 20, 20, 21, 22}, + {0, 1, 2, 2, 3, 4, 5, 5, 6, 7, 8, 8, 9, 10, 11, + 11, 12, 13, 14, 14, 15, 16, 17, 17, 18, 19, 20, 20, 21, 22}, +}; + +static u8 delta_swing_index_mp_5gb_p_txpwrtrack_type2_8822b + [][DELTA_SWINGIDX_SIZE] = { + {0, 1, 2, 2, 3, 4, 5, 5, 6, 7, 8, 9, 9, 10, 11, + 12, 13, 14, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 22, 23}, + {0, 1, 2, 2, 3, 4, 5, 5, 6, 7, 8, 9, 9, 10, 11, + 12, 13, 14, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 22, 23}, + {0, 1, 2, 2, 3, 4, 5, 5, 6, 7, 8, 9, 9, 10, 11, + 12, 13, 14, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 22, 23}, +}; + +static u8 delta_swing_index_mp_5ga_n_txpwrtrack_type2_8822b + [][DELTA_SWINGIDX_SIZE] = { + {0, 1, 2, 2, 3, 4, 5, 5, 6, 7, 8, 8, 9, 10, 11, + 11, 12, 13, 14, 14, 15, 16, 17, 17, 18, 19, 20, 20, 21, 22}, + {0, 1, 2, 2, 3, 4, 5, 5, 6, 7, 8, 8, 9, 10, 11, + 11, 12, 13, 14, 14, 15, 16, 17, 17, 18, 19, 20, 20, 21, 22}, + {0, 1, 2, 2, 3, 4, 5, 5, 6, 7, 8, 8, 9, 10, 11, + 11, 12, 13, 14, 14, 15, 16, 17, 17, 18, 19, 20, 20, 21, 22}, +}; + +static u8 delta_swing_index_mp_5ga_p_txpwrtrack_type2_8822b + [][DELTA_SWINGIDX_SIZE] = { + {0, 1, 2, 2, 3, 4, 5, 5, 6, 7, 8, 9, 9, 10, 11, + 12, 13, 14, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 22, 23}, + {0, 1, 2, 2, 3, 4, 5, 5, 6, 7, 8, 9, 9, 10, 11, + 12, 13, 14, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 22, 23}, + {0, 1, 2, 2, 3, 4, 5, 5, 6, 7, 8, 9, 9, 10, 11, + 12, 13, 14, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 22, 23}, +}; + +static u8 delta_swing_index_mp_2gb_n_txpwrtrack_type2_8822b[] = { + 0, 1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, + 6, 7, 7, 7, 8, 8, 9, 9, 9, 10, 10, 11, 11, 11, 12}; + +static u8 delta_swing_index_mp_2gb_p_txpwrtrack_type2_8822b[] = { + 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 7, 8, + 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15}; + +static u8 delta_swing_index_mp_2ga_n_txpwrtrack_type2_8822b[] = { + 0, 1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, + 6, 7, 7, 7, 8, 8, 9, 9, 9, 10, 10, 11, 11, 11, 12}; + +static u8 delta_swing_index_mp_2ga_p_txpwrtrack_type2_8822b[] = { + 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 7, 8, + 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15}; + +static u8 delta_swing_index_mp_2g_cck_b_n_txpwrtrack_type2_8822b[] = { + 0, 1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, + 6, 7, 7, 7, 8, 8, 9, 9, 9, 10, 10, 11, 11, 11, 12}; + +static u8 delta_swing_index_mp_2g_cck_b_p_txpwrtrack_type2_8822b[] = { + 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 7, 8, + 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15}; + +static u8 delta_swing_index_mp_2g_cck_a_n_txpwrtrack_type2_8822b[] = { + 0, 1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, + 6, 7, 7, 7, 8, 8, 9, 9, 9, 10, 10, 11, 11, 11, 12}; + +static u8 delta_swing_index_mp_2g_cck_a_p_txpwrtrack_type2_8822b[] = { + 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 7, 8, + 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15}; + +void odm_read_and_config_mp_8822b_txpowertrack_type2(struct phy_dm_struct *dm) +{ + struct dm_rf_calibration_struct *cali_info = &dm->rf_calibrate_info; + + ODM_RT_TRACE(dm, ODM_COMP_INIT, "===> ODM_ReadAndConfig_MP_mp_8822b\n"); + + odm_move_memory(dm, cali_info->delta_swing_table_idx_2ga_p, + delta_swing_index_mp_2ga_p_txpwrtrack_type2_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2ga_n, + delta_swing_index_mp_2ga_n_txpwrtrack_type2_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2gb_p, + delta_swing_index_mp_2gb_p_txpwrtrack_type2_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2gb_n, + delta_swing_index_mp_2gb_n_txpwrtrack_type2_8822b, + DELTA_SWINGIDX_SIZE); + + odm_move_memory(dm, cali_info->delta_swing_table_idx_2g_cck_a_p, + delta_swing_index_mp_2g_cck_a_p_txpwrtrack_type2_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2g_cck_a_n, + delta_swing_index_mp_2g_cck_a_n_txpwrtrack_type2_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2g_cck_b_p, + delta_swing_index_mp_2g_cck_b_p_txpwrtrack_type2_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2g_cck_b_n, + delta_swing_index_mp_2g_cck_b_n_txpwrtrack_type2_8822b, + DELTA_SWINGIDX_SIZE); + + odm_move_memory(dm, cali_info->delta_swing_table_idx_5ga_p, + delta_swing_index_mp_5ga_p_txpwrtrack_type2_8822b, + DELTA_SWINGIDX_SIZE * 3); + odm_move_memory(dm, cali_info->delta_swing_table_idx_5ga_n, + delta_swing_index_mp_5ga_n_txpwrtrack_type2_8822b, + DELTA_SWINGIDX_SIZE * 3); + odm_move_memory(dm, cali_info->delta_swing_table_idx_5gb_p, + delta_swing_index_mp_5gb_p_txpwrtrack_type2_8822b, + DELTA_SWINGIDX_SIZE * 3); + odm_move_memory(dm, cali_info->delta_swing_table_idx_5gb_n, + delta_swing_index_mp_5gb_n_txpwrtrack_type2_8822b, + DELTA_SWINGIDX_SIZE * 3); +} + +/****************************************************************************** + * txpowertrack_type3_type5.TXT + ******************************************************************************/ + +static u8 delta_swing_index_mp_5gb_n_txpwrtrack_type3_type5_8822b + [][DELTA_SWINGIDX_SIZE] = { + {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 7, 8, + 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15}, + {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 7, 8, + 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15}, + {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 7, 8, + 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15}, +}; + +static u8 delta_swing_index_mp_5gb_p_txpwrtrack_type3_type5_8822b + [][DELTA_SWINGIDX_SIZE] = { + {0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 6, 6, 7, 7, 8, + 9, 9, 10, 10, 11, 11, 12, 13, 13, 14, 14, 15, 15, 16, 17}, + {0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 6, 6, 7, 7, 8, + 9, 9, 10, 10, 11, 11, 12, 13, 13, 14, 14, 15, 15, 16, 17}, + {0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 6, 6, 7, 7, 8, + 9, 9, 10, 10, 11, 11, 12, 13, 13, 14, 14, 15, 15, 16, 17}, +}; + +static u8 delta_swing_index_mp_5ga_n_txpwrtrack_type3_type5_8822b + [][DELTA_SWINGIDX_SIZE] = { + {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 7, 8, + 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15}, + {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 7, 8, + 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15}, + {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 7, 8, + 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15}, +}; + +static u8 delta_swing_index_mp_5ga_p_txpwrtrack_type3_type5_8822b + [][DELTA_SWINGIDX_SIZE] = { + {0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 6, 6, 7, 7, 8, + 9, 9, 10, 10, 11, 11, 12, 13, 13, 14, 14, 15, 15, 16, 17}, + {0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 6, 6, 7, 7, 8, + 9, 9, 10, 10, 11, 11, 12, 13, 13, 14, 14, 15, 15, 16, 17}, + {0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 6, 6, 7, 7, 8, + 9, 9, 10, 10, 11, 11, 12, 13, 13, 14, 14, 15, 15, 16, 17}, +}; + +static u8 delta_swing_index_mp_2gb_n_txpwrtrack_type3_type5_8822b[] = { + 0, 1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, + 6, 7, 7, 7, 8, 8, 9, 9, 9, 10, 10, 11, 11, 11, 12}; + +static u8 delta_swing_index_mp_2gb_p_txpwrtrack_type3_type5_8822b[] = { + 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 7, 8, + 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15}; + +static u8 delta_swing_index_mp_2ga_n_txpwrtrack_type3_type5_8822b[] = { + 0, 1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, + 6, 7, 7, 7, 8, 8, 9, 9, 9, 10, 10, 11, 11, 11, 12}; + +static u8 delta_swing_index_mp_2ga_p_txpwrtrack_type3_type5_8822b[] = { + 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 7, 8, + 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15}; + +static u8 delta_swing_index_mp_2g_cck_b_n_txpwrtrack_type3_type5_8822b[] = { + 0, 1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, + 6, 7, 7, 7, 8, 8, 9, 9, 9, 10, 10, 11, 11, 11, 12}; + +static u8 delta_swing_index_mp_2g_cck_b_p_txpwrtrack_type3_type5_8822b[] = { + 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 7, 8, + 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15}; + +static u8 delta_swing_index_mp_2g_cck_a_n_txpwrtrack_type3_type5_8822b[] = { + 0, 1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, + 6, 7, 7, 7, 8, 8, 9, 9, 9, 10, 10, 11, 11, 11, 12}; + +static u8 delta_swing_index_mp_2g_cck_a_p_txpwrtrack_type3_type5_8822b[] = { + 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 7, 8, + 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15}; + +void odm_read_and_config_mp_8822b_txpowertrack_type3_type5( + struct phy_dm_struct *dm) +{ + struct dm_rf_calibration_struct *cali_info = &dm->rf_calibrate_info; + + ODM_RT_TRACE(dm, ODM_COMP_INIT, "===> ODM_ReadAndConfig_MP_mp_8822b\n"); + + odm_move_memory(dm, cali_info->delta_swing_table_idx_2ga_p, + delta_swing_index_mp_2ga_p_txpwrtrack_type3_type5_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2ga_n, + delta_swing_index_mp_2ga_n_txpwrtrack_type3_type5_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2gb_p, + delta_swing_index_mp_2gb_p_txpwrtrack_type3_type5_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2gb_n, + delta_swing_index_mp_2gb_n_txpwrtrack_type3_type5_8822b, + DELTA_SWINGIDX_SIZE); + + odm_move_memory( + dm, cali_info->delta_swing_table_idx_2g_cck_a_p, + delta_swing_index_mp_2g_cck_a_p_txpwrtrack_type3_type5_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory( + dm, cali_info->delta_swing_table_idx_2g_cck_a_n, + delta_swing_index_mp_2g_cck_a_n_txpwrtrack_type3_type5_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory( + dm, cali_info->delta_swing_table_idx_2g_cck_b_p, + delta_swing_index_mp_2g_cck_b_p_txpwrtrack_type3_type5_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory( + dm, cali_info->delta_swing_table_idx_2g_cck_b_n, + delta_swing_index_mp_2g_cck_b_n_txpwrtrack_type3_type5_8822b, + DELTA_SWINGIDX_SIZE); + + odm_move_memory(dm, cali_info->delta_swing_table_idx_5ga_p, + delta_swing_index_mp_5ga_p_txpwrtrack_type3_type5_8822b, + DELTA_SWINGIDX_SIZE * 3); + odm_move_memory(dm, cali_info->delta_swing_table_idx_5ga_n, + delta_swing_index_mp_5ga_n_txpwrtrack_type3_type5_8822b, + DELTA_SWINGIDX_SIZE * 3); + odm_move_memory(dm, cali_info->delta_swing_table_idx_5gb_p, + delta_swing_index_mp_5gb_p_txpwrtrack_type3_type5_8822b, + DELTA_SWINGIDX_SIZE * 3); + odm_move_memory(dm, cali_info->delta_swing_table_idx_5gb_n, + delta_swing_index_mp_5gb_n_txpwrtrack_type3_type5_8822b, + DELTA_SWINGIDX_SIZE * 3); +} + +/****************************************************************************** + * txpowertrack_type4.TXT + ******************************************************************************/ + +static u8 delta_swing_index_mp_5gb_n_txpwrtrack_type4_8822b + [][DELTA_SWINGIDX_SIZE] = { + {0, 1, 2, 2, 3, 4, 5, 5, 6, 7, 8, 8, 9, 10, 11, + 11, 12, 13, 14, 14, 15, 16, 17, 17, 18, 19, 20, 20, 21, 22}, + {0, 1, 2, 2, 3, 4, 5, 5, 6, 7, 8, 8, 9, 10, 11, + 11, 12, 13, 14, 14, 15, 16, 17, 17, 18, 19, 20, 20, 21, 22}, + {0, 1, 2, 2, 3, 4, 5, 5, 6, 7, 8, 8, 9, 10, 11, + 11, 12, 13, 14, 14, 15, 16, 17, 17, 18, 19, 20, 20, 21, 22}, +}; + +static u8 delta_swing_index_mp_5gb_p_txpwrtrack_type4_8822b + [][DELTA_SWINGIDX_SIZE] = { + {0, 1, 2, 2, 3, 4, 5, 5, 6, 7, 8, 9, 9, 10, 11, + 12, 13, 14, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 22, 23}, + {0, 1, 2, 2, 3, 4, 5, 5, 6, 7, 8, 9, 9, 10, 11, + 12, 13, 14, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 22, 23}, + {0, 1, 2, 2, 3, 4, 5, 5, 6, 7, 8, 9, 9, 10, 11, + 12, 13, 14, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 22, 23}, +}; + +static u8 delta_swing_index_mp_5ga_n_txpwrtrack_type4_8822b + [][DELTA_SWINGIDX_SIZE] = { + {0, 1, 2, 2, 3, 4, 5, 5, 6, 7, 8, 8, 9, 10, 11, + 11, 12, 13, 14, 14, 15, 16, 17, 17, 18, 19, 20, 20, 21, 22}, + {0, 1, 2, 2, 3, 4, 5, 5, 6, 7, 8, 8, 9, 10, 11, + 11, 12, 13, 14, 14, 15, 16, 17, 17, 18, 19, 20, 20, 21, 22}, + {0, 1, 2, 2, 3, 4, 5, 5, 6, 7, 8, 8, 9, 10, 11, + 11, 12, 13, 14, 14, 15, 16, 17, 17, 18, 19, 20, 20, 21, 22}, +}; + +static u8 delta_swing_index_mp_5ga_p_txpwrtrack_type4_8822b + [][DELTA_SWINGIDX_SIZE] = { + {0, 1, 2, 2, 3, 4, 5, 5, 6, 7, 8, 9, 9, 10, 11, + 12, 13, 14, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 22, 23}, + {0, 1, 2, 2, 3, 4, 5, 5, 6, 7, 8, 9, 9, 10, 11, + 12, 13, 14, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 22, 23}, + {0, 1, 2, 2, 3, 4, 5, 5, 6, 7, 8, 9, 9, 10, 11, + 12, 13, 14, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 22, 23}, +}; + +static u8 delta_swing_index_mp_2gb_n_txpwrtrack_type4_8822b[] = { + 0, 1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, + 6, 7, 7, 7, 8, 8, 9, 9, 9, 10, 10, 11, 11, 11, 12}; + +static u8 delta_swing_index_mp_2gb_p_txpwrtrack_type4_8822b[] = { + 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 7, 8, + 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15}; + +static u8 delta_swing_index_mp_2ga_n_txpwrtrack_type4_8822b[] = { + 0, 1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, + 6, 7, 7, 7, 8, 8, 9, 9, 9, 10, 10, 11, 11, 11, 12}; + +static u8 delta_swing_index_mp_2ga_p_txpwrtrack_type4_8822b[] = { + 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 7, 8, + 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15}; + +static u8 delta_swing_index_mp_2g_cck_b_n_txpwrtrack_type4_8822b[] = { + 0, 1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, + 6, 7, 7, 7, 8, 8, 9, 9, 9, 10, 10, 11, 11, 11, 12}; + +static u8 delta_swing_index_mp_2g_cck_b_p_txpwrtrack_type4_8822b[] = { + 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 7, 8, + 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15}; + +static u8 delta_swing_index_mp_2g_cck_a_n_txpwrtrack_type4_8822b[] = { + 0, 1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, + 6, 7, 7, 7, 8, 8, 9, 9, 9, 10, 10, 11, 11, 11, 12}; + +static u8 delta_swing_index_mp_2g_cck_a_p_txpwrtrack_type4_8822b[] = { + 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 7, 8, + 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15}; + +void odm_read_and_config_mp_8822b_txpowertrack_type4(struct phy_dm_struct *dm) +{ + struct dm_rf_calibration_struct *cali_info = &dm->rf_calibrate_info; + + ODM_RT_TRACE(dm, ODM_COMP_INIT, "===> ODM_ReadAndConfig_MP_mp_8822b\n"); + + odm_move_memory(dm, cali_info->delta_swing_table_idx_2ga_p, + delta_swing_index_mp_2ga_p_txpwrtrack_type4_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2ga_n, + delta_swing_index_mp_2ga_n_txpwrtrack_type4_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2gb_p, + delta_swing_index_mp_2gb_p_txpwrtrack_type4_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2gb_n, + delta_swing_index_mp_2gb_n_txpwrtrack_type4_8822b, + DELTA_SWINGIDX_SIZE); + + odm_move_memory(dm, cali_info->delta_swing_table_idx_2g_cck_a_p, + delta_swing_index_mp_2g_cck_a_p_txpwrtrack_type4_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2g_cck_a_n, + delta_swing_index_mp_2g_cck_a_n_txpwrtrack_type4_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2g_cck_b_p, + delta_swing_index_mp_2g_cck_b_p_txpwrtrack_type4_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2g_cck_b_n, + delta_swing_index_mp_2g_cck_b_n_txpwrtrack_type4_8822b, + DELTA_SWINGIDX_SIZE); + + odm_move_memory(dm, cali_info->delta_swing_table_idx_5ga_p, + delta_swing_index_mp_5ga_p_txpwrtrack_type4_8822b, + DELTA_SWINGIDX_SIZE * 3); + odm_move_memory(dm, cali_info->delta_swing_table_idx_5ga_n, + delta_swing_index_mp_5ga_n_txpwrtrack_type4_8822b, + DELTA_SWINGIDX_SIZE * 3); + odm_move_memory(dm, cali_info->delta_swing_table_idx_5gb_p, + delta_swing_index_mp_5gb_p_txpwrtrack_type4_8822b, + DELTA_SWINGIDX_SIZE * 3); + odm_move_memory(dm, cali_info->delta_swing_table_idx_5gb_n, + delta_swing_index_mp_5gb_n_txpwrtrack_type4_8822b, + DELTA_SWINGIDX_SIZE * 3); +} + +/****************************************************************************** + * txpowertrack_type6.TXT + ******************************************************************************/ + +static u8 delta_swing_index_mp_5gb_n_txpwrtrack_type6_8822b + [][DELTA_SWINGIDX_SIZE] = { + {0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 10, + 11, 11, 12, 12, 12, 13, 13, 14, 14, 14, 15, 15, 15, 15, 15}, + {0, 1, 2, 3, 4, 5, 5, 6, 7, 7, 8, 9, 9, 10, 10, + 11, 12, 12, 13, 14, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16}, + {0, 1, 2, 3, 4, 4, 5, 5, 6, 7, 8, 9, 10, 11, 12, + 12, 13, 13, 14, 15, 15, 16, 16, 17, 17, 17, 17, 17, 17, 17}, +}; + +static u8 delta_swing_index_mp_5gb_p_txpwrtrack_type6_8822b + [][DELTA_SWINGIDX_SIZE] = { + {0, 1, 2, 2, 3, 4, 5, 6, 7, 8, 8, 9, 10, 11, 11, + 12, 13, 14, 15, 15, 16, 17, 18, 18, 19, 19, 19, 19, 19, 19}, + {0, 1, 2, 2, 3, 4, 5, 6, 7, 8, 9, 9, 11, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 20, 21, 21, 21, 21, 21, 21}, + {0, 1, 2, 3, 4, 5, 6, 6, 7, 7, 8, 9, 10, 11, 12, + 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 20, 20, 21, 21, 21}, +}; + +static u8 delta_swing_index_mp_5ga_n_txpwrtrack_type6_8822b + [][DELTA_SWINGIDX_SIZE] = { + {0, 1, 2, 2, 3, 3, 4, 5, 6, 7, 8, 9, 10, 10, 11, + 12, 12, 13, 14, 14, 15, 15, 16, 16, 16, 17, 17, 17, 17, 17}, + {0, 1, 2, 2, 3, 4, 5, 5, 6, 6, 7, 8, 9, 9, 10, + 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 15, 15, 15, 15, 15}, + {0, 1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 8, 9, 9, 10, + 11, 12, 12, 13, 14, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16}, +}; + +static u8 delta_swing_index_mp_5ga_p_txpwrtrack_type6_8822b + [][DELTA_SWINGIDX_SIZE] = { + {0, 1, 2, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 11, 12, + 13, 14, 15, 15, 16, 17, 18, 19, 20, 20, 21, 21, 21, 21, 21}, + {0, 1, 2, 2, 3, 4, 4, 5, 7, 7, 8, 9, 10, 11, 11, + 12, 13, 13, 14, 15, 16, 17, 18, 18, 19, 19, 20, 20, 21, 21}, + {0, 1, 2, 3, 3, 4, 5, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 14, 14, 15, 16, 17, 17, 18, 19, 19, 20, 20, 20, 20, 20}, +}; + +static u8 delta_swing_index_mp_2gb_n_txpwrtrack_type6_8822b[] = { + 0, 1, 2, 3, 3, 4, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 13, 14, 15, 16, 16, 17, 18, 18, 18, 18, 18, 18, 18, 18}; + +static u8 delta_swing_index_mp_2gb_p_txpwrtrack_type6_8822b[] = { + 0, 1, 1, 2, 3, 4, 4, 5, 6, 7, 7, 8, 9, 10, 11, + 12, 12, 13, 14, 15, 16, 17, 17, 18, 19, 20, 21, 22, 22, 22}; + +static u8 delta_swing_index_mp_2ga_n_txpwrtrack_type6_8822b[] = { + 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 10, 11, 12, + 13, 13, 14, 15, 16, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18}; + +static u8 delta_swing_index_mp_2ga_p_txpwrtrack_type6_8822b[] = { + 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, + 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 22, 22}; + +static u8 delta_swing_index_mp_2g_cck_b_n_txpwrtrack_type6_8822b[] = { + 0, 1, 1, 2, 3, 4, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 13, 14, 15, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17}; + +static u8 delta_swing_index_mp_2g_cck_b_p_txpwrtrack_type6_8822b[] = { + 0, 1, 1, 2, 3, 4, 4, 5, 6, 7, 8, 9, 9, 10, 11, + 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 22, 22}; + +static u8 delta_swing_index_mp_2g_cck_a_n_txpwrtrack_type6_8822b[] = { + 0, 1, 2, 3, 3, 4, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 13, 14, 15, 16, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18}; + +static u8 delta_swing_index_mp_2g_cck_a_p_txpwrtrack_type6_8822b[] = { + 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, + 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 22, 22}; + +void odm_read_and_config_mp_8822b_txpowertrack_type6(struct phy_dm_struct *dm) +{ + struct dm_rf_calibration_struct *cali_info = &dm->rf_calibrate_info; + + ODM_RT_TRACE(dm, ODM_COMP_INIT, "===> ODM_ReadAndConfig_MP_mp_8822b\n"); + + odm_move_memory(dm, cali_info->delta_swing_table_idx_2ga_p, + delta_swing_index_mp_2ga_p_txpwrtrack_type6_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2ga_n, + delta_swing_index_mp_2ga_n_txpwrtrack_type6_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2gb_p, + delta_swing_index_mp_2gb_p_txpwrtrack_type6_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2gb_n, + delta_swing_index_mp_2gb_n_txpwrtrack_type6_8822b, + DELTA_SWINGIDX_SIZE); + + odm_move_memory(dm, cali_info->delta_swing_table_idx_2g_cck_a_p, + delta_swing_index_mp_2g_cck_a_p_txpwrtrack_type6_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2g_cck_a_n, + delta_swing_index_mp_2g_cck_a_n_txpwrtrack_type6_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2g_cck_b_p, + delta_swing_index_mp_2g_cck_b_p_txpwrtrack_type6_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2g_cck_b_n, + delta_swing_index_mp_2g_cck_b_n_txpwrtrack_type6_8822b, + DELTA_SWINGIDX_SIZE); + + odm_move_memory(dm, cali_info->delta_swing_table_idx_5ga_p, + delta_swing_index_mp_5ga_p_txpwrtrack_type6_8822b, + DELTA_SWINGIDX_SIZE * 3); + odm_move_memory(dm, cali_info->delta_swing_table_idx_5ga_n, + delta_swing_index_mp_5ga_n_txpwrtrack_type6_8822b, + DELTA_SWINGIDX_SIZE * 3); + odm_move_memory(dm, cali_info->delta_swing_table_idx_5gb_p, + delta_swing_index_mp_5gb_p_txpwrtrack_type6_8822b, + DELTA_SWINGIDX_SIZE * 3); + odm_move_memory(dm, cali_info->delta_swing_table_idx_5gb_n, + delta_swing_index_mp_5gb_n_txpwrtrack_type6_8822b, + DELTA_SWINGIDX_SIZE * 3); +} + +/****************************************************************************** + * txpowertrack_type7.TXT + ******************************************************************************/ + +static u8 delta_swing_index_mp_5gb_n_txpwrtrack_type7_8822b + [][DELTA_SWINGIDX_SIZE] = { + {0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 10, + 11, 11, 12, 12, 12, 13, 13, 14, 14, 14, 15, 15, 15, 15, 15}, + {0, 1, 2, 3, 4, 5, 5, 6, 7, 7, 8, 9, 9, 10, 10, + 11, 12, 12, 13, 14, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16}, + {0, 1, 2, 3, 4, 4, 5, 5, 6, 7, 8, 9, 10, 11, 12, + 12, 13, 13, 14, 15, 15, 16, 16, 17, 17, 17, 17, 17, 17, 17}, +}; + +static u8 delta_swing_index_mp_5gb_p_txpwrtrack_type7_8822b + [][DELTA_SWINGIDX_SIZE] = { + {0, 1, 2, 2, 3, 4, 5, 6, 7, 8, 8, 9, 10, 11, 11, + 12, 13, 14, 15, 15, 16, 17, 18, 18, 19, 19, 19, 19, 19, 19}, + {0, 1, 2, 2, 3, 4, 5, 6, 7, 8, 9, 9, 11, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 20, 21, 21, 21, 21, 21, 21}, + {0, 1, 2, 3, 4, 5, 6, 6, 7, 7, 8, 9, 10, 11, 12, + 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 20, 20, 21, 21, 21}, +}; + +static u8 delta_swing_index_mp_5ga_n_txpwrtrack_type7_8822b + [][DELTA_SWINGIDX_SIZE] = { + {0, 1, 2, 2, 3, 3, 4, 5, 6, 7, 8, 9, 10, 10, 11, + 12, 12, 13, 14, 14, 15, 15, 16, 16, 16, 17, 17, 17, 17, 17}, + {0, 1, 2, 2, 3, 4, 5, 5, 6, 6, 7, 8, 9, 9, 10, + 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 15, 15, 15, 15, 15}, + {0, 1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 8, 9, 9, 10, + 11, 12, 12, 13, 14, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16}, +}; + +static u8 delta_swing_index_mp_5ga_p_txpwrtrack_type7_8822b + [][DELTA_SWINGIDX_SIZE] = { + {0, 1, 2, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 11, 12, + 13, 14, 15, 15, 16, 17, 18, 19, 20, 20, 21, 21, 21, 21, 21}, + {0, 1, 2, 2, 3, 4, 4, 5, 7, 7, 8, 9, 10, 11, 11, + 12, 13, 13, 14, 15, 16, 17, 18, 18, 19, 19, 20, 20, 21, 21}, + {0, 1, 2, 3, 3, 4, 5, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 14, 14, 15, 16, 17, 17, 18, 19, 19, 20, 20, 20, 20, 20}, +}; + +static u8 delta_swing_index_mp_2gb_n_txpwrtrack_type7_8822b[] = { + 0, 1, 2, 3, 3, 4, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 13, 14, 15, 16, 16, 17, 18, 18, 18, 18, 18, 18, 18, 18}; + +static u8 delta_swing_index_mp_2gb_p_txpwrtrack_type7_8822b[] = { + 0, 1, 1, 2, 3, 4, 4, 5, 6, 7, 7, 8, 9, 10, 11, + 12, 12, 13, 14, 15, 16, 17, 17, 18, 19, 20, 21, 22, 22, 22}; + +static u8 delta_swing_index_mp_2ga_n_txpwrtrack_type7_8822b[] = { + 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 10, 11, 12, + 13, 13, 14, 15, 16, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18}; + +static u8 delta_swing_index_mp_2ga_p_txpwrtrack_type7_8822b[] = { + 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, + 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 22, 22}; + +static u8 delta_swing_index_mp_2g_cck_b_n_txpwrtrack_type7_8822b[] = { + 0, 1, 1, 2, 3, 4, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 13, 14, 15, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17}; + +static u8 delta_swing_index_mp_2g_cck_b_p_txpwrtrack_type7_8822b[] = { + 0, 1, 1, 2, 3, 4, 4, 5, 6, 7, 8, 9, 9, 10, 11, + 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 22, 22}; + +static u8 delta_swing_index_mp_2g_cck_a_n_txpwrtrack_type7_8822b[] = { + 0, 1, 2, 3, 3, 4, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 13, 14, 15, 16, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18}; + +static u8 delta_swing_index_mp_2g_cck_a_p_txpwrtrack_type7_8822b[] = { + 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, + 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 22, 22}; + +void odm_read_and_config_mp_8822b_txpowertrack_type7(struct phy_dm_struct *dm) +{ + struct dm_rf_calibration_struct *cali_info = &dm->rf_calibrate_info; + + ODM_RT_TRACE(dm, ODM_COMP_INIT, "===> ODM_ReadAndConfig_MP_mp_8822b\n"); + + odm_move_memory(dm, cali_info->delta_swing_table_idx_2ga_p, + delta_swing_index_mp_2ga_p_txpwrtrack_type7_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2ga_n, + delta_swing_index_mp_2ga_n_txpwrtrack_type7_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2gb_p, + delta_swing_index_mp_2gb_p_txpwrtrack_type7_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2gb_n, + delta_swing_index_mp_2gb_n_txpwrtrack_type7_8822b, + DELTA_SWINGIDX_SIZE); + + odm_move_memory(dm, cali_info->delta_swing_table_idx_2g_cck_a_p, + delta_swing_index_mp_2g_cck_a_p_txpwrtrack_type7_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2g_cck_a_n, + delta_swing_index_mp_2g_cck_a_n_txpwrtrack_type7_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2g_cck_b_p, + delta_swing_index_mp_2g_cck_b_p_txpwrtrack_type7_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2g_cck_b_n, + delta_swing_index_mp_2g_cck_b_n_txpwrtrack_type7_8822b, + DELTA_SWINGIDX_SIZE); + + odm_move_memory(dm, cali_info->delta_swing_table_idx_5ga_p, + delta_swing_index_mp_5ga_p_txpwrtrack_type7_8822b, + DELTA_SWINGIDX_SIZE * 3); + odm_move_memory(dm, cali_info->delta_swing_table_idx_5ga_n, + delta_swing_index_mp_5ga_n_txpwrtrack_type7_8822b, + DELTA_SWINGIDX_SIZE * 3); + odm_move_memory(dm, cali_info->delta_swing_table_idx_5gb_p, + delta_swing_index_mp_5gb_p_txpwrtrack_type7_8822b, + DELTA_SWINGIDX_SIZE * 3); + odm_move_memory(dm, cali_info->delta_swing_table_idx_5gb_n, + delta_swing_index_mp_5gb_n_txpwrtrack_type7_8822b, + DELTA_SWINGIDX_SIZE * 3); +} + +/****************************************************************************** + * txpowertrack_type8.TXT + ******************************************************************************/ + +static u8 delta_swing_index_mp_5gb_n_txpwrtrack_type8_8822b + [][DELTA_SWINGIDX_SIZE] = { + {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 7, 8, + 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15}, + {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 7, 8, + 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15}, + {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 7, 8, + 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15}, +}; + +static u8 delta_swing_index_mp_5gb_p_txpwrtrack_type8_8822b + [][DELTA_SWINGIDX_SIZE] = { + {0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 6, 6, 7, 7, 8, + 9, 9, 10, 10, 11, 11, 12, 13, 13, 14, 14, 15, 15, 16, 17}, + {0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 6, 6, 7, 7, 8, + 9, 9, 10, 10, 11, 11, 12, 13, 13, 14, 14, 15, 15, 16, 17}, + {0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 6, 6, 7, 7, 8, + 9, 9, 10, 10, 11, 11, 12, 13, 13, 14, 14, 15, 15, 16, 17}, +}; + +static u8 delta_swing_index_mp_5ga_n_txpwrtrack_type8_8822b + [][DELTA_SWINGIDX_SIZE] = { + {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 7, 8, + 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15}, + {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 7, 8, + 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15}, + {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 7, 8, + 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15}, +}; + +static u8 delta_swing_index_mp_5ga_p_txpwrtrack_type8_8822b + [][DELTA_SWINGIDX_SIZE] = { + {0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 6, 6, 7, 7, 8, + 9, 9, 10, 10, 11, 11, 12, 13, 13, 14, 14, 15, 15, 16, 17}, + {0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 6, 6, 7, 7, 8, + 9, 9, 10, 10, 11, 11, 12, 13, 13, 14, 14, 15, 15, 16, 17}, + {0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 6, 6, 7, 7, 8, + 9, 9, 10, 10, 11, 11, 12, 13, 13, 14, 14, 15, 15, 16, 17}, +}; + +static u8 delta_swing_index_mp_2gb_n_txpwrtrack_type8_8822b[] = { + 0, 1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, + 6, 7, 7, 7, 8, 8, 9, 9, 9, 10, 10, 11, 11, 11, 12}; + +static u8 delta_swing_index_mp_2gb_p_txpwrtrack_type8_8822b[] = { + 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 7, 8, + 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15}; + +static u8 delta_swing_index_mp_2ga_n_txpwrtrack_type8_8822b[] = { + 0, 1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, + 6, 7, 7, 7, 8, 8, 9, 9, 9, 10, 10, 11, 11, 11, 12}; + +static u8 delta_swing_index_mp_2ga_p_txpwrtrack_type8_8822b[] = { + 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 7, 8, + 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15}; + +static u8 delta_swing_index_mp_2g_cck_b_n_txpwrtrack_type8_8822b[] = { + 0, 1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, + 6, 7, 7, 7, 8, 8, 9, 9, 9, 10, 10, 11, 11, 11, 12}; + +static u8 delta_swing_index_mp_2g_cck_b_p_txpwrtrack_type8_8822b[] = { + 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 7, 8, + 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15}; + +static u8 delta_swing_index_mp_2g_cck_a_n_txpwrtrack_type8_8822b[] = { + 0, 1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, + 6, 7, 7, 7, 8, 8, 9, 9, 9, 10, 10, 11, 11, 11, 12}; + +static u8 delta_swing_index_mp_2g_cck_a_p_txpwrtrack_type8_8822b[] = { + 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 7, 8, + 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15}; + +void odm_read_and_config_mp_8822b_txpowertrack_type8(struct phy_dm_struct *dm) +{ + struct dm_rf_calibration_struct *cali_info = &dm->rf_calibrate_info; + + ODM_RT_TRACE(dm, ODM_COMP_INIT, "===> ODM_ReadAndConfig_MP_mp_8822b\n"); + + odm_move_memory(dm, cali_info->delta_swing_table_idx_2ga_p, + delta_swing_index_mp_2ga_p_txpwrtrack_type8_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2ga_n, + delta_swing_index_mp_2ga_n_txpwrtrack_type8_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2gb_p, + delta_swing_index_mp_2gb_p_txpwrtrack_type8_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2gb_n, + delta_swing_index_mp_2gb_n_txpwrtrack_type8_8822b, + DELTA_SWINGIDX_SIZE); + + odm_move_memory(dm, cali_info->delta_swing_table_idx_2g_cck_a_p, + delta_swing_index_mp_2g_cck_a_p_txpwrtrack_type8_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2g_cck_a_n, + delta_swing_index_mp_2g_cck_a_n_txpwrtrack_type8_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2g_cck_b_p, + delta_swing_index_mp_2g_cck_b_p_txpwrtrack_type8_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2g_cck_b_n, + delta_swing_index_mp_2g_cck_b_n_txpwrtrack_type8_8822b, + DELTA_SWINGIDX_SIZE); + + odm_move_memory(dm, cali_info->delta_swing_table_idx_5ga_p, + delta_swing_index_mp_5ga_p_txpwrtrack_type8_8822b, + DELTA_SWINGIDX_SIZE * 3); + odm_move_memory(dm, cali_info->delta_swing_table_idx_5ga_n, + delta_swing_index_mp_5ga_n_txpwrtrack_type8_8822b, + DELTA_SWINGIDX_SIZE * 3); + odm_move_memory(dm, cali_info->delta_swing_table_idx_5gb_p, + delta_swing_index_mp_5gb_p_txpwrtrack_type8_8822b, + DELTA_SWINGIDX_SIZE * 3); + odm_move_memory(dm, cali_info->delta_swing_table_idx_5gb_n, + delta_swing_index_mp_5gb_n_txpwrtrack_type8_8822b, + DELTA_SWINGIDX_SIZE * 3); +} + +/****************************************************************************** + * txpowertrack_type9.TXT + ******************************************************************************/ + +static u8 delta_swing_index_mp_5gb_n_txpwrtrack_type9_8822b + [][DELTA_SWINGIDX_SIZE] = { + {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, + 8, 8, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15}, + {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 8, + 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 14, 14}, + {0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 6, 7, 7, 8, 8, + 9, 9, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 15, 15}, +}; + +static u8 delta_swing_index_mp_5gb_p_txpwrtrack_type9_8822b + [][DELTA_SWINGIDX_SIZE] = { + {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, + 8, 8, 9, 9, 10, 10, 11, 12, 12, 13, 13, 14, 14, 15, 15}, + {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, + 8, 8, 9, 9, 10, 11, 11, 12, 13, 13, 14, 14, 15, 15, 15}, + {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, + 8, 8, 9, 10, 10, 11, 12, 13, 14, 14, 15, 15, 15, 16, 16}, +}; + +static u8 delta_swing_index_mp_5ga_n_txpwrtrack_type9_8822b + [][DELTA_SWINGIDX_SIZE] = { + {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, + 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 13, 14, 14}, + {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, + 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 14}, + {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, + 8, 8, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 14, 14}, +}; + +static u8 delta_swing_index_mp_5ga_p_txpwrtrack_type9_8822b + [][DELTA_SWINGIDX_SIZE] = { + {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, + 8, 8, 9, 9, 10, 10, 11, 12, 13, 13, 14, 14, 15, 15, 15}, + {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, + 8, 8, 9, 9, 10, 10, 11, 12, 12, 13, 13, 14, 14, 15, 15}, + {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, + 8, 9, 9, 10, 10, 11, 11, 12, 13, 13, 14, 14, 15, 15, 15}, +}; + +static u8 delta_swing_index_mp_2gb_n_txpwrtrack_type9_8822b[] = { + 0, 1, 2, 3, 3, 4, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 13, 14, 15, 16, 16, 17, 18, 18, 18, 18, 18, 18, 18, 18}; + +static u8 delta_swing_index_mp_2gb_p_txpwrtrack_type9_8822b[] = { + 0, 1, 1, 2, 3, 4, 4, 5, 6, 7, 7, 8, 9, 10, 11, + 12, 12, 13, 14, 15, 16, 17, 17, 18, 19, 20, 21, 22, 22, 22}; + +static u8 delta_swing_index_mp_2ga_n_txpwrtrack_type9_8822b[] = { + 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 10, 11, 12, + 13, 13, 14, 15, 16, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18}; + +static u8 delta_swing_index_mp_2ga_p_txpwrtrack_type9_8822b[] = { + 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, + 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 22, 22}; + +static u8 delta_swing_index_mp_2g_cck_b_n_txpwrtrack_type9_8822b[] = { + 0, 1, 1, 2, 3, 4, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 13, 14, 15, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17}; + +static u8 delta_swing_index_mp_2g_cck_b_p_txpwrtrack_type9_8822b[] = { + 0, 1, 1, 2, 3, 4, 4, 5, 6, 7, 8, 9, 9, 10, 11, + 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 22, 22}; + +static u8 delta_swing_index_mp_2g_cck_a_n_txpwrtrack_type9_8822b[] = { + 0, 1, 2, 3, 3, 4, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 13, 14, 15, 16, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18}; + +static u8 delta_swing_index_mp_2g_cck_a_p_txpwrtrack_type9_8822b[] = { + 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, + 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 22, 22}; + +void odm_read_and_config_mp_8822b_txpowertrack_type9(struct phy_dm_struct *dm) +{ + struct dm_rf_calibration_struct *cali_info = &dm->rf_calibrate_info; + + ODM_RT_TRACE(dm, ODM_COMP_INIT, "===> ODM_ReadAndConfig_MP_mp_8822b\n"); + + odm_move_memory(dm, cali_info->delta_swing_table_idx_2ga_p, + delta_swing_index_mp_2ga_p_txpwrtrack_type9_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2ga_n, + delta_swing_index_mp_2ga_n_txpwrtrack_type9_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2gb_p, + delta_swing_index_mp_2gb_p_txpwrtrack_type9_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2gb_n, + delta_swing_index_mp_2gb_n_txpwrtrack_type9_8822b, + DELTA_SWINGIDX_SIZE); + + odm_move_memory(dm, cali_info->delta_swing_table_idx_2g_cck_a_p, + delta_swing_index_mp_2g_cck_a_p_txpwrtrack_type9_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2g_cck_a_n, + delta_swing_index_mp_2g_cck_a_n_txpwrtrack_type9_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2g_cck_b_p, + delta_swing_index_mp_2g_cck_b_p_txpwrtrack_type9_8822b, + DELTA_SWINGIDX_SIZE); + odm_move_memory(dm, cali_info->delta_swing_table_idx_2g_cck_b_n, + delta_swing_index_mp_2g_cck_b_n_txpwrtrack_type9_8822b, + DELTA_SWINGIDX_SIZE); + + odm_move_memory(dm, cali_info->delta_swing_table_idx_5ga_p, + delta_swing_index_mp_5ga_p_txpwrtrack_type9_8822b, + DELTA_SWINGIDX_SIZE * 3); + odm_move_memory(dm, cali_info->delta_swing_table_idx_5ga_n, + delta_swing_index_mp_5ga_n_txpwrtrack_type9_8822b, + DELTA_SWINGIDX_SIZE * 3); + odm_move_memory(dm, cali_info->delta_swing_table_idx_5gb_p, + delta_swing_index_mp_5gb_p_txpwrtrack_type9_8822b, + DELTA_SWINGIDX_SIZE * 3); + odm_move_memory(dm, cali_info->delta_swing_table_idx_5gb_n, + delta_swing_index_mp_5gb_n_txpwrtrack_type9_8822b, + DELTA_SWINGIDX_SIZE * 3); +} + +/****************************************************************************** + * txpwr_lmt.TXT + ******************************************************************************/ + +static const char *const array_mp_8822b_txpwr_lmt[] = { + "FCC", "2.4G", "20M", "CCK", "1T", "01", "32", "ETSI", "2.4G", + "20M", "CCK", "1T", "01", "28", "MKK", "2.4G", "20M", "CCK", + "1T", "01", "30", "FCC", "2.4G", "20M", "CCK", "1T", "02", + "32", "ETSI", "2.4G", "20M", "CCK", "1T", "02", "28", "MKK", + "2.4G", "20M", "CCK", "1T", "02", "30", "FCC", "2.4G", "20M", + "CCK", "1T", "03", "32", "ETSI", "2.4G", "20M", "CCK", "1T", + "03", "28", "MKK", "2.4G", "20M", "CCK", "1T", "03", "30", + "FCC", "2.4G", "20M", "CCK", "1T", "04", "32", "ETSI", "2.4G", + "20M", "CCK", "1T", "04", "28", "MKK", "2.4G", "20M", "CCK", + "1T", "04", "30", "FCC", "2.4G", "20M", "CCK", "1T", "05", + "32", "ETSI", "2.4G", "20M", "CCK", "1T", "05", "28", "MKK", + "2.4G", "20M", "CCK", "1T", "05", "30", "FCC", "2.4G", "20M", + "CCK", "1T", "06", "32", "ETSI", "2.4G", "20M", "CCK", "1T", + "06", "28", "MKK", "2.4G", "20M", "CCK", "1T", "06", "30", + "FCC", "2.4G", "20M", "CCK", "1T", "07", "32", "ETSI", "2.4G", + "20M", "CCK", "1T", "07", "28", "MKK", "2.4G", "20M", "CCK", + "1T", "07", "30", "FCC", "2.4G", "20M", "CCK", "1T", "08", + "32", "ETSI", "2.4G", "20M", "CCK", "1T", "08", "28", "MKK", + "2.4G", "20M", "CCK", "1T", "08", "30", "FCC", "2.4G", "20M", + "CCK", "1T", "09", "32", "ETSI", "2.4G", "20M", "CCK", "1T", + "09", "28", "MKK", "2.4G", "20M", "CCK", "1T", "09", "30", + "FCC", "2.4G", "20M", "CCK", "1T", "10", "32", "ETSI", "2.4G", + "20M", "CCK", "1T", "10", "28", "MKK", "2.4G", "20M", "CCK", + "1T", "10", "30", "FCC", "2.4G", "20M", "CCK", "1T", "11", + "32", "ETSI", "2.4G", "20M", "CCK", "1T", "11", "28", "MKK", + "2.4G", "20M", "CCK", "1T", "11", "30", "FCC", "2.4G", "20M", + "CCK", "1T", "12", "26", "ETSI", "2.4G", "20M", "CCK", "1T", + "12", "28", "MKK", "2.4G", "20M", "CCK", "1T", "12", "30", + "FCC", "2.4G", "20M", "CCK", "1T", "13", "20", "ETSI", "2.4G", + "20M", "CCK", "1T", "13", "28", "MKK", "2.4G", "20M", "CCK", + "1T", "13", "28", "FCC", "2.4G", "20M", "CCK", "1T", "14", + "63", "ETSI", "2.4G", "20M", "CCK", "1T", "14", "63", "MKK", + "2.4G", "20M", "CCK", "1T", "14", "32", "FCC", "2.4G", "20M", + "OFDM", "1T", "01", "26", "ETSI", "2.4G", "20M", "OFDM", "1T", + "01", "30", "MKK", "2.4G", "20M", "OFDM", "1T", "01", "34", + "FCC", "2.4G", "20M", "OFDM", "1T", "02", "30", "ETSI", "2.4G", + "20M", "OFDM", "1T", "02", "30", "MKK", "2.4G", "20M", "OFDM", + "1T", "02", "34", "FCC", "2.4G", "20M", "OFDM", "1T", "03", + "32", "ETSI", "2.4G", "20M", "OFDM", "1T", "03", "30", "MKK", + "2.4G", "20M", "OFDM", "1T", "03", "34", "FCC", "2.4G", "20M", + "OFDM", "1T", "04", "34", "ETSI", "2.4G", "20M", "OFDM", "1T", + "04", "30", "MKK", "2.4G", "20M", "OFDM", "1T", "04", "34", + "FCC", "2.4G", "20M", "OFDM", "1T", "05", "34", "ETSI", "2.4G", + "20M", "OFDM", "1T", "05", "30", "MKK", "2.4G", "20M", "OFDM", + "1T", "05", "34", "FCC", "2.4G", "20M", "OFDM", "1T", "06", + "34", "ETSI", "2.4G", "20M", "OFDM", "1T", "06", "30", "MKK", + "2.4G", "20M", "OFDM", "1T", "06", "34", "FCC", "2.4G", "20M", + "OFDM", "1T", "07", "34", "ETSI", "2.4G", "20M", "OFDM", "1T", + "07", "30", "MKK", "2.4G", "20M", "OFDM", "1T", "07", "34", + "FCC", "2.4G", "20M", "OFDM", "1T", "08", "34", "ETSI", "2.4G", + "20M", "OFDM", "1T", "08", "30", "MKK", "2.4G", "20M", "OFDM", + "1T", "08", "34", "FCC", "2.4G", "20M", "OFDM", "1T", "09", + "32", "ETSI", "2.4G", "20M", "OFDM", "1T", "09", "30", "MKK", + "2.4G", "20M", "OFDM", "1T", "09", "34", "FCC", "2.4G", "20M", + "OFDM", "1T", "10", "30", "ETSI", "2.4G", "20M", "OFDM", "1T", + "10", "30", "MKK", "2.4G", "20M", "OFDM", "1T", "10", "34", + "FCC", "2.4G", "20M", "OFDM", "1T", "11", "28", "ETSI", "2.4G", + "20M", "OFDM", "1T", "11", "30", "MKK", "2.4G", "20M", "OFDM", + "1T", "11", "34", "FCC", "2.4G", "20M", "OFDM", "1T", "12", + "22", "ETSI", "2.4G", "20M", "OFDM", "1T", "12", "30", "MKK", + "2.4G", "20M", "OFDM", "1T", "12", "34", "FCC", "2.4G", "20M", + "OFDM", "1T", "13", "14", "ETSI", "2.4G", "20M", "OFDM", "1T", + "13", "30", "MKK", "2.4G", "20M", "OFDM", "1T", "13", "34", + "FCC", "2.4G", "20M", "OFDM", "1T", "14", "63", "ETSI", "2.4G", + "20M", "OFDM", "1T", "14", "63", "MKK", "2.4G", "20M", "OFDM", + "1T", "14", "63", "FCC", "2.4G", "20M", "HT", "1T", "01", + "26", "ETSI", "2.4G", "20M", "HT", "1T", "01", "30", "MKK", + "2.4G", "20M", "HT", "1T", "01", "34", "FCC", "2.4G", "20M", + "HT", "1T", "02", "30", "ETSI", "2.4G", "20M", "HT", "1T", + "02", "30", "MKK", "2.4G", "20M", "HT", "1T", "02", "34", + "FCC", "2.4G", "20M", "HT", "1T", "03", "32", "ETSI", "2.4G", + "20M", "HT", "1T", "03", "30", "MKK", "2.4G", "20M", "HT", + "1T", "03", "34", "FCC", "2.4G", "20M", "HT", "1T", "04", + "34", "ETSI", "2.4G", "20M", "HT", "1T", "04", "30", "MKK", + "2.4G", "20M", "HT", "1T", "04", "34", "FCC", "2.4G", "20M", + "HT", "1T", "05", "34", "ETSI", "2.4G", "20M", "HT", "1T", + "05", "30", "MKK", "2.4G", "20M", "HT", "1T", "05", "34", + "FCC", "2.4G", "20M", "HT", "1T", "06", "34", "ETSI", "2.4G", + "20M", "HT", "1T", "06", "30", "MKK", "2.4G", "20M", "HT", + "1T", "06", "34", "FCC", "2.4G", "20M", "HT", "1T", "07", + "34", "ETSI", "2.4G", "20M", "HT", "1T", "07", "30", "MKK", + "2.4G", "20M", "HT", "1T", "07", "34", "FCC", "2.4G", "20M", + "HT", "1T", "08", "34", "ETSI", "2.4G", "20M", "HT", "1T", + "08", "30", "MKK", "2.4G", "20M", "HT", "1T", "08", "34", + "FCC", "2.4G", "20M", "HT", "1T", "09", "32", "ETSI", "2.4G", + "20M", "HT", "1T", "09", "30", "MKK", "2.4G", "20M", "HT", + "1T", "09", "34", "FCC", "2.4G", "20M", "HT", "1T", "10", + "30", "ETSI", "2.4G", "20M", "HT", "1T", "10", "30", "MKK", + "2.4G", "20M", "HT", "1T", "10", "34", "FCC", "2.4G", "20M", + "HT", "1T", "11", "26", "ETSI", "2.4G", "20M", "HT", "1T", + "11", "30", "MKK", "2.4G", "20M", "HT", "1T", "11", "34", + "FCC", "2.4G", "20M", "HT", "1T", "12", "20", "ETSI", "2.4G", + "20M", "HT", "1T", "12", "30", "MKK", "2.4G", "20M", "HT", + "1T", "12", "34", "FCC", "2.4G", "20M", "HT", "1T", "13", + "14", "ETSI", "2.4G", "20M", "HT", "1T", "13", "30", "MKK", + "2.4G", "20M", "HT", "1T", "13", "34", "FCC", "2.4G", "20M", + "HT", "1T", "14", "63", "ETSI", "2.4G", "20M", "HT", "1T", + "14", "63", "MKK", "2.4G", "20M", "HT", "1T", "14", "63", + "FCC", "2.4G", "20M", "HT", "2T", "01", "26", "ETSI", "2.4G", + "20M", "HT", "2T", "01", "18", "MKK", "2.4G", "20M", "HT", + "2T", "01", "30", "FCC", "2.4G", "20M", "HT", "2T", "02", + "28", "ETSI", "2.4G", "20M", "HT", "2T", "02", "18", "MKK", + "2.4G", "20M", "HT", "2T", "02", "30", "FCC", "2.4G", "20M", + "HT", "2T", "03", "30", "ETSI", "2.4G", "20M", "HT", "2T", + "03", "18", "MKK", "2.4G", "20M", "HT", "2T", "03", "30", + "FCC", "2.4G", "20M", "HT", "2T", "04", "30", "ETSI", "2.4G", + "20M", "HT", "2T", "04", "18", "MKK", "2.4G", "20M", "HT", + "2T", "04", "30", "FCC", "2.4G", "20M", "HT", "2T", "05", + "32", "ETSI", "2.4G", "20M", "HT", "2T", "05", "18", "MKK", + "2.4G", "20M", "HT", "2T", "05", "30", "FCC", "2.4G", "20M", + "HT", "2T", "06", "32", "ETSI", "2.4G", "20M", "HT", "2T", + "06", "18", "MKK", "2.4G", "20M", "HT", "2T", "06", "30", + "FCC", "2.4G", "20M", "HT", "2T", "07", "32", "ETSI", "2.4G", + "20M", "HT", "2T", "07", "18", "MKK", "2.4G", "20M", "HT", + "2T", "07", "30", "FCC", "2.4G", "20M", "HT", "2T", "08", + "30", "ETSI", "2.4G", "20M", "HT", "2T", "08", "18", "MKK", + "2.4G", "20M", "HT", "2T", "08", "30", "FCC", "2.4G", "20M", + "HT", "2T", "09", "30", "ETSI", "2.4G", "20M", "HT", "2T", + "09", "18", "MKK", "2.4G", "20M", "HT", "2T", "09", "30", + "FCC", "2.4G", "20M", "HT", "2T", "10", "28", "ETSI", "2.4G", + "20M", "HT", "2T", "10", "18", "MKK", "2.4G", "20M", "HT", + "2T", "10", "30", "FCC", "2.4G", "20M", "HT", "2T", "11", + "26", "ETSI", "2.4G", "20M", "HT", "2T", "11", "18", "MKK", + "2.4G", "20M", "HT", "2T", "11", "30", "FCC", "2.4G", "20M", + "HT", "2T", "12", "20", "ETSI", "2.4G", "20M", "HT", "2T", + "12", "18", "MKK", "2.4G", "20M", "HT", "2T", "12", "30", + "FCC", "2.4G", "20M", "HT", "2T", "13", "14", "ETSI", "2.4G", + "20M", "HT", "2T", "13", "18", "MKK", "2.4G", "20M", "HT", + "2T", "13", "30", "FCC", "2.4G", "20M", "HT", "2T", "14", + "63", "ETSI", "2.4G", "20M", "HT", "2T", "14", "63", "MKK", + "2.4G", "20M", "HT", "2T", "14", "63", "FCC", "2.4G", "40M", + "HT", "1T", "01", "63", "ETSI", "2.4G", "40M", "HT", "1T", + "01", "63", "MKK", "2.4G", "40M", "HT", "1T", "01", "63", + "FCC", "2.4G", "40M", "HT", "1T", "02", "63", "ETSI", "2.4G", + "40M", "HT", "1T", "02", "63", "MKK", "2.4G", "40M", "HT", + "1T", "02", "63", "FCC", "2.4G", "40M", "HT", "1T", "03", + "26", "ETSI", "2.4G", "40M", "HT", "1T", "03", "30", "MKK", + "2.4G", "40M", "HT", "1T", "03", "34", "FCC", "2.4G", "40M", + "HT", "1T", "04", "26", "ETSI", "2.4G", "40M", "HT", "1T", + "04", "30", "MKK", "2.4G", "40M", "HT", "1T", "04", "34", + "FCC", "2.4G", "40M", "HT", "1T", "05", "30", "ETSI", "2.4G", + "40M", "HT", "1T", "05", "30", "MKK", "2.4G", "40M", "HT", + "1T", "05", "34", "FCC", "2.4G", "40M", "HT", "1T", "06", + "32", "ETSI", "2.4G", "40M", "HT", "1T", "06", "30", "MKK", + "2.4G", "40M", "HT", "1T", "06", "34", "FCC", "2.4G", "40M", + "HT", "1T", "07", "30", "ETSI", "2.4G", "40M", "HT", "1T", + "07", "30", "MKK", "2.4G", "40M", "HT", "1T", "07", "34", + "FCC", "2.4G", "40M", "HT", "1T", "08", "26", "ETSI", "2.4G", + "40M", "HT", "1T", "08", "30", "MKK", "2.4G", "40M", "HT", + "1T", "08", "34", "FCC", "2.4G", "40M", "HT", "1T", "09", + "26", "ETSI", "2.4G", "40M", "HT", "1T", "09", "30", "MKK", + "2.4G", "40M", "HT", "1T", "09", "34", "FCC", "2.4G", "40M", + "HT", "1T", "10", "20", "ETSI", "2.4G", "40M", "HT", "1T", + "10", "30", "MKK", "2.4G", "40M", "HT", "1T", "10", "34", + "FCC", "2.4G", "40M", "HT", "1T", "11", "14", "ETSI", "2.4G", + "40M", "HT", "1T", "11", "30", "MKK", "2.4G", "40M", "HT", + "1T", "11", "34", "FCC", "2.4G", "40M", "HT", "1T", "12", + "63", "ETSI", "2.4G", "40M", "HT", "1T", "12", "63", "MKK", + "2.4G", "40M", "HT", "1T", "12", "63", "FCC", "2.4G", "40M", + "HT", "1T", "13", "63", "ETSI", "2.4G", "40M", "HT", "1T", + "13", "63", "MKK", "2.4G", "40M", "HT", "1T", "13", "63", + "FCC", "2.4G", "40M", "HT", "1T", "14", "63", "ETSI", "2.4G", + "40M", "HT", "1T", "14", "63", "MKK", "2.4G", "40M", "HT", + "1T", "14", "63", "FCC", "2.4G", "40M", "HT", "2T", "01", + "63", "ETSI", "2.4G", "40M", "HT", "2T", "01", "63", "MKK", + "2.4G", "40M", "HT", "2T", "01", "63", "FCC", "2.4G", "40M", + "HT", "2T", "02", "63", "ETSI", "2.4G", "40M", "HT", "2T", + "02", "63", "MKK", "2.4G", "40M", "HT", "2T", "02", "63", + "FCC", "2.4G", "40M", "HT", "2T", "03", "24", "ETSI", "2.4G", + "40M", "HT", "2T", "03", "18", "MKK", "2.4G", "40M", "HT", + "2T", "03", "30", "FCC", "2.4G", "40M", "HT", "2T", "04", + "24", "ETSI", "2.4G", "40M", "HT", "2T", "04", "18", "MKK", + "2.4G", "40M", "HT", "2T", "04", "30", "FCC", "2.4G", "40M", + "HT", "2T", "05", "26", "ETSI", "2.4G", "40M", "HT", "2T", + "05", "18", "MKK", "2.4G", "40M", "HT", "2T", "05", "30", + "FCC", "2.4G", "40M", "HT", "2T", "06", "28", "ETSI", "2.4G", + "40M", "HT", "2T", "06", "18", "MKK", "2.4G", "40M", "HT", + "2T", "06", "30", "FCC", "2.4G", "40M", "HT", "2T", "07", + "26", "ETSI", "2.4G", "40M", "HT", "2T", "07", "18", "MKK", + "2.4G", "40M", "HT", "2T", "07", "30", "FCC", "2.4G", "40M", + "HT", "2T", "08", "26", "ETSI", "2.4G", "40M", "HT", "2T", + "08", "18", "MKK", "2.4G", "40M", "HT", "2T", "08", "30", + "FCC", "2.4G", "40M", "HT", "2T", "09", "26", "ETSI", "2.4G", + "40M", "HT", "2T", "09", "18", "MKK", "2.4G", "40M", "HT", + "2T", "09", "30", "FCC", "2.4G", "40M", "HT", "2T", "10", + "20", "ETSI", "2.4G", "40M", "HT", "2T", "10", "18", "MKK", + "2.4G", "40M", "HT", "2T", "10", "30", "FCC", "2.4G", "40M", + "HT", "2T", "11", "14", "ETSI", "2.4G", "40M", "HT", "2T", + "11", "18", "MKK", "2.4G", "40M", "HT", "2T", "11", "30", + "FCC", "2.4G", "40M", "HT", "2T", "12", "63", "ETSI", "2.4G", + "40M", "HT", "2T", "12", "63", "MKK", "2.4G", "40M", "HT", + "2T", "12", "63", "FCC", "2.4G", "40M", "HT", "2T", "13", + "63", "ETSI", "2.4G", "40M", "HT", "2T", "13", "63", "MKK", + "2.4G", "40M", "HT", "2T", "13", "63", "FCC", "2.4G", "40M", + "HT", "2T", "14", "63", "ETSI", "2.4G", "40M", "HT", "2T", + "14", "63", "MKK", "2.4G", "40M", "HT", "2T", "14", "63", + "FCC", "5G", "20M", "OFDM", "1T", "36", "30", "ETSI", "5G", + "20M", "OFDM", "1T", "36", "32", "MKK", "5G", "20M", "OFDM", + "1T", "36", "30", "FCC", "5G", "20M", "OFDM", "1T", "40", + "32", "ETSI", "5G", "20M", "OFDM", "1T", "40", "32", "MKK", + "5G", "20M", "OFDM", "1T", "40", "30", "FCC", "5G", "20M", + "OFDM", "1T", "44", "32", "ETSI", "5G", "20M", "OFDM", "1T", + "44", "32", "MKK", "5G", "20M", "OFDM", "1T", "44", "30", + "FCC", "5G", "20M", "OFDM", "1T", "48", "32", "ETSI", "5G", + "20M", "OFDM", "1T", "48", "32", "MKK", "5G", "20M", "OFDM", + "1T", "48", "30", "FCC", "5G", "20M", "OFDM", "1T", "52", + "32", "ETSI", "5G", "20M", "OFDM", "1T", "52", "32", "MKK", + "5G", "20M", "OFDM", "1T", "52", "28", "FCC", "5G", "20M", + "OFDM", "1T", "56", "32", "ETSI", "5G", "20M", "OFDM", "1T", + "56", "32", "MKK", "5G", "20M", "OFDM", "1T", "56", "28", + "FCC", "5G", "20M", "OFDM", "1T", "60", "32", "ETSI", "5G", + "20M", "OFDM", "1T", "60", "32", "MKK", "5G", "20M", "OFDM", + "1T", "60", "28", "FCC", "5G", "20M", "OFDM", "1T", "64", + "28", "ETSI", "5G", "20M", "OFDM", "1T", "64", "32", "MKK", + "5G", "20M", "OFDM", "1T", "64", "28", "FCC", "5G", "20M", + "OFDM", "1T", "100", "26", "ETSI", "5G", "20M", "OFDM", "1T", + "100", "32", "MKK", "5G", "20M", "OFDM", "1T", "100", "32", + "FCC", "5G", "20M", "OFDM", "1T", "104", "32", "ETSI", "5G", + "20M", "OFDM", "1T", "104", "32", "MKK", "5G", "20M", "OFDM", + "1T", "104", "32", "FCC", "5G", "20M", "OFDM", "1T", "108", + "32", "ETSI", "5G", "20M", "OFDM", "1T", "108", "32", "MKK", + "5G", "20M", "OFDM", "1T", "108", "32", "FCC", "5G", "20M", + "OFDM", "1T", "112", "32", "ETSI", "5G", "20M", "OFDM", "1T", + "112", "32", "MKK", "5G", "20M", "OFDM", "1T", "112", "32", + "FCC", "5G", "20M", "OFDM", "1T", "116", "32", "ETSI", "5G", + "20M", "OFDM", "1T", "116", "32", "MKK", "5G", "20M", "OFDM", + "1T", "116", "32", "FCC", "5G", "20M", "OFDM", "1T", "120", + "32", "ETSI", "5G", "20M", "OFDM", "1T", "120", "32", "MKK", + "5G", "20M", "OFDM", "1T", "120", "32", "FCC", "5G", "20M", + "OFDM", "1T", "124", "32", "ETSI", "5G", "20M", "OFDM", "1T", + "124", "32", "MKK", "5G", "20M", "OFDM", "1T", "124", "32", + "FCC", "5G", "20M", "OFDM", "1T", "128", "32", "ETSI", "5G", + "20M", "OFDM", "1T", "128", "32", "MKK", "5G", "20M", "OFDM", + "1T", "128", "32", "FCC", "5G", "20M", "OFDM", "1T", "132", + "32", "ETSI", "5G", "20M", "OFDM", "1T", "132", "32", "MKK", + "5G", "20M", "OFDM", "1T", "132", "32", "FCC", "5G", "20M", + "OFDM", "1T", "136", "32", "ETSI", "5G", "20M", "OFDM", "1T", + "136", "32", "MKK", "5G", "20M", "OFDM", "1T", "136", "32", + "FCC", "5G", "20M", "OFDM", "1T", "140", "28", "ETSI", "5G", + "20M", "OFDM", "1T", "140", "32", "MKK", "5G", "20M", "OFDM", + "1T", "140", "32", "FCC", "5G", "20M", "OFDM", "1T", "144", + "28", "ETSI", "5G", "20M", "OFDM", "1T", "144", "32", "MKK", + "5G", "20M", "OFDM", "1T", "144", "63", "FCC", "5G", "20M", + "OFDM", "1T", "149", "32", "ETSI", "5G", "20M", "OFDM", "1T", + "149", "63", "MKK", "5G", "20M", "OFDM", "1T", "149", "63", + "FCC", "5G", "20M", "OFDM", "1T", "153", "32", "ETSI", "5G", + "20M", "OFDM", "1T", "153", "63", "MKK", "5G", "20M", "OFDM", + "1T", "153", "63", "FCC", "5G", "20M", "OFDM", "1T", "157", + "32", "ETSI", "5G", "20M", "OFDM", "1T", "157", "63", "MKK", + "5G", "20M", "OFDM", "1T", "157", "63", "FCC", "5G", "20M", + "OFDM", "1T", "161", "32", "ETSI", "5G", "20M", "OFDM", "1T", + "161", "63", "MKK", "5G", "20M", "OFDM", "1T", "161", "63", + "FCC", "5G", "20M", "OFDM", "1T", "165", "32", "ETSI", "5G", + "20M", "OFDM", "1T", "165", "63", "MKK", "5G", "20M", "OFDM", + "1T", "165", "63", "FCC", "5G", "20M", "HT", "1T", "36", + "30", "ETSI", "5G", "20M", "HT", "1T", "36", "32", "MKK", + "5G", "20M", "HT", "1T", "36", "28", "FCC", "5G", "20M", + "HT", "1T", "40", "32", "ETSI", "5G", "20M", "HT", "1T", + "40", "32", "MKK", "5G", "20M", "HT", "1T", "40", "28", + "FCC", "5G", "20M", "HT", "1T", "44", "32", "ETSI", "5G", + "20M", "HT", "1T", "44", "32", "MKK", "5G", "20M", "HT", + "1T", "44", "28", "FCC", "5G", "20M", "HT", "1T", "48", + "32", "ETSI", "5G", "20M", "HT", "1T", "48", "32", "MKK", + "5G", "20M", "HT", "1T", "48", "28", "FCC", "5G", "20M", + "HT", "1T", "52", "32", "ETSI", "5G", "20M", "HT", "1T", + "52", "32", "MKK", "5G", "20M", "HT", "1T", "52", "28", + "FCC", "5G", "20M", "HT", "1T", "56", "32", "ETSI", "5G", + "20M", "HT", "1T", "56", "32", "MKK", "5G", "20M", "HT", + "1T", "56", "28", "FCC", "5G", "20M", "HT", "1T", "60", + "32", "ETSI", "5G", "20M", "HT", "1T", "60", "32", "MKK", + "5G", "20M", "HT", "1T", "60", "28", "FCC", "5G", "20M", + "HT", "1T", "64", "28", "ETSI", "5G", "20M", "HT", "1T", + "64", "32", "MKK", "5G", "20M", "HT", "1T", "64", "28", + "FCC", "5G", "20M", "HT", "1T", "100", "26", "ETSI", "5G", + "20M", "HT", "1T", "100", "32", "MKK", "5G", "20M", "HT", + "1T", "100", "32", "FCC", "5G", "20M", "HT", "1T", "104", + "32", "ETSI", "5G", "20M", "HT", "1T", "104", "32", "MKK", + "5G", "20M", "HT", "1T", "104", "32", "FCC", "5G", "20M", + "HT", "1T", "108", "32", "ETSI", "5G", "20M", "HT", "1T", + "108", "32", "MKK", "5G", "20M", "HT", "1T", "108", "32", + "FCC", "5G", "20M", "HT", "1T", "112", "32", "ETSI", "5G", + "20M", "HT", "1T", "112", "32", "MKK", "5G", "20M", "HT", + "1T", "112", "32", "FCC", "5G", "20M", "HT", "1T", "116", + "32", "ETSI", "5G", "20M", "HT", "1T", "116", "32", "MKK", + "5G", "20M", "HT", "1T", "116", "32", "FCC", "5G", "20M", + "HT", "1T", "120", "32", "ETSI", "5G", "20M", "HT", "1T", + "120", "32", "MKK", "5G", "20M", "HT", "1T", "120", "32", + "FCC", "5G", "20M", "HT", "1T", "124", "32", "ETSI", "5G", + "20M", "HT", "1T", "124", "32", "MKK", "5G", "20M", "HT", + "1T", "124", "32", "FCC", "5G", "20M", "HT", "1T", "128", + "32", "ETSI", "5G", "20M", "HT", "1T", "128", "32", "MKK", + "5G", "20M", "HT", "1T", "128", "32", "FCC", "5G", "20M", + "HT", "1T", "132", "32", "ETSI", "5G", "20M", "HT", "1T", + "132", "32", "MKK", "5G", "20M", "HT", "1T", "132", "32", + "FCC", "5G", "20M", "HT", "1T", "136", "32", "ETSI", "5G", + "20M", "HT", "1T", "136", "32", "MKK", "5G", "20M", "HT", + "1T", "136", "32", "FCC", "5G", "20M", "HT", "1T", "140", + "26", "ETSI", "5G", "20M", "HT", "1T", "140", "32", "MKK", + "5G", "20M", "HT", "1T", "140", "32", "FCC", "5G", "20M", + "HT", "1T", "144", "26", "ETSI", "5G", "20M", "HT", "1T", + "144", "63", "MKK", "5G", "20M", "HT", "1T", "144", "63", + "FCC", "5G", "20M", "HT", "1T", "149", "32", "ETSI", "5G", + "20M", "HT", "1T", "149", "63", "MKK", "5G", "20M", "HT", + "1T", "149", "63", "FCC", "5G", "20M", "HT", "1T", "153", + "32", "ETSI", "5G", "20M", "HT", "1T", "153", "63", "MKK", + "5G", "20M", "HT", "1T", "153", "63", "FCC", "5G", "20M", + "HT", "1T", "157", "32", "ETSI", "5G", "20M", "HT", "1T", + "157", "63", "MKK", "5G", "20M", "HT", "1T", "157", "63", + "FCC", "5G", "20M", "HT", "1T", "161", "32", "ETSI", "5G", + "20M", "HT", "1T", "161", "63", "MKK", "5G", "20M", "HT", + "1T", "161", "63", "FCC", "5G", "20M", "HT", "1T", "165", + "32", "ETSI", "5G", "20M", "HT", "1T", "165", "63", "MKK", + "5G", "20M", "HT", "1T", "165", "63", "FCC", "5G", "20M", + "HT", "2T", "36", "28", "ETSI", "5G", "20M", "HT", "2T", + "36", "20", "MKK", "5G", "20M", "HT", "2T", "36", "22", + "FCC", "5G", "20M", "HT", "2T", "40", "30", "ETSI", "5G", + "20M", "HT", "2T", "40", "20", "MKK", "5G", "20M", "HT", + "2T", "40", "22", "FCC", "5G", "20M", "HT", "2T", "44", + "30", "ETSI", "5G", "20M", "HT", "2T", "44", "20", "MKK", + "5G", "20M", "HT", "2T", "44", "22", "FCC", "5G", "20M", + "HT", "2T", "48", "30", "ETSI", "5G", "20M", "HT", "2T", + "48", "20", "MKK", "5G", "20M", "HT", "2T", "48", "22", + "FCC", "5G", "20M", "HT", "2T", "52", "30", "ETSI", "5G", + "20M", "HT", "2T", "52", "20", "MKK", "5G", "20M", "HT", + "2T", "52", "22", "FCC", "5G", "20M", "HT", "2T", "56", + "30", "ETSI", "5G", "20M", "HT", "2T", "56", "20", "MKK", + "5G", "20M", "HT", "2T", "56", "22", "FCC", "5G", "20M", + "HT", "2T", "60", "30", "ETSI", "5G", "20M", "HT", "2T", + "60", "20", "MKK", "5G", "20M", "HT", "2T", "60", "22", + "FCC", "5G", "20M", "HT", "2T", "64", "28", "ETSI", "5G", + "20M", "HT", "2T", "64", "20", "MKK", "5G", "20M", "HT", + "2T", "64", "22", "FCC", "5G", "20M", "HT", "2T", "100", + "26", "ETSI", "5G", "20M", "HT", "2T", "100", "20", "MKK", + "5G", "20M", "HT", "2T", "100", "30", "FCC", "5G", "20M", + "HT", "2T", "104", "30", "ETSI", "5G", "20M", "HT", "2T", + "104", "20", "MKK", "5G", "20M", "HT", "2T", "104", "30", + "FCC", "5G", "20M", "HT", "2T", "108", "32", "ETSI", "5G", + "20M", "HT", "2T", "108", "20", "MKK", "5G", "20M", "HT", + "2T", "108", "30", "FCC", "5G", "20M", "HT", "2T", "112", + "32", "ETSI", "5G", "20M", "HT", "2T", "112", "20", "MKK", + "5G", "20M", "HT", "2T", "112", "30", "FCC", "5G", "20M", + "HT", "2T", "116", "32", "ETSI", "5G", "20M", "HT", "2T", + "116", "20", "MKK", "5G", "20M", "HT", "2T", "116", "30", + "FCC", "5G", "20M", "HT", "2T", "120", "32", "ETSI", "5G", + "20M", "HT", "2T", "120", "20", "MKK", "5G", "20M", "HT", + "2T", "120", "30", "FCC", "5G", "20M", "HT", "2T", "124", + "32", "ETSI", "5G", "20M", "HT", "2T", "124", "20", "MKK", + "5G", "20M", "HT", "2T", "124", "30", "FCC", "5G", "20M", + "HT", "2T", "128", "32", "ETSI", "5G", "20M", "HT", "2T", + "128", "20", "MKK", "5G", "20M", "HT", "2T", "128", "30", + "FCC", "5G", "20M", "HT", "2T", "132", "32", "ETSI", "5G", + "20M", "HT", "2T", "132", "20", "MKK", "5G", "20M", "HT", + "2T", "132", "30", "FCC", "5G", "20M", "HT", "2T", "136", + "30", "ETSI", "5G", "20M", "HT", "2T", "136", "20", "MKK", + "5G", "20M", "HT", "2T", "136", "30", "FCC", "5G", "20M", + "HT", "2T", "140", "26", "ETSI", "5G", "20M", "HT", "2T", + "140", "20", "MKK", "5G", "20M", "HT", "2T", "140", "30", + "FCC", "5G", "20M", "HT", "2T", "144", "26", "ETSI", "5G", + "20M", "HT", "2T", "144", "63", "MKK", "5G", "20M", "HT", + "2T", "144", "63", "FCC", "5G", "20M", "HT", "2T", "149", + "32", "ETSI", "5G", "20M", "HT", "2T", "149", "63", "MKK", + "5G", "20M", "HT", "2T", "149", "63", "FCC", "5G", "20M", + "HT", "2T", "153", "32", "ETSI", "5G", "20M", "HT", "2T", + "153", "63", "MKK", "5G", "20M", "HT", "2T", "153", "63", + "FCC", "5G", "20M", "HT", "2T", "157", "32", "ETSI", "5G", + "20M", "HT", "2T", "157", "63", "MKK", "5G", "20M", "HT", + "2T", "157", "63", "FCC", "5G", "20M", "HT", "2T", "161", + "32", "ETSI", "5G", "20M", "HT", "2T", "161", "63", "MKK", + "5G", "20M", "HT", "2T", "161", "63", "FCC", "5G", "20M", + "HT", "2T", "165", "32", "ETSI", "5G", "20M", "HT", "2T", + "165", "63", "MKK", "5G", "20M", "HT", "2T", "165", "63", + "FCC", "5G", "40M", "HT", "1T", "38", "22", "ETSI", "5G", + "40M", "HT", "1T", "38", "30", "MKK", "5G", "40M", "HT", + "1T", "38", "30", "FCC", "5G", "40M", "HT", "1T", "46", + "30", "ETSI", "5G", "40M", "HT", "1T", "46", "30", "MKK", + "5G", "40M", "HT", "1T", "46", "30", "FCC", "5G", "40M", + "HT", "1T", "54", "30", "ETSI", "5G", "40M", "HT", "1T", + "54", "30", "MKK", "5G", "40M", "HT", "1T", "54", "30", + "FCC", "5G", "40M", "HT", "1T", "62", "24", "ETSI", "5G", + "40M", "HT", "1T", "62", "30", "MKK", "5G", "40M", "HT", + "1T", "62", "30", "FCC", "5G", "40M", "HT", "1T", "102", + "24", "ETSI", "5G", "40M", "HT", "1T", "102", "30", "MKK", + "5G", "40M", "HT", "1T", "102", "30", "FCC", "5G", "40M", + "HT", "1T", "110", "30", "ETSI", "5G", "40M", "HT", "1T", + "110", "30", "MKK", "5G", "40M", "HT", "1T", "110", "30", + "FCC", "5G", "40M", "HT", "1T", "118", "30", "ETSI", "5G", + "40M", "HT", "1T", "118", "30", "MKK", "5G", "40M", "HT", + "1T", "118", "30", "FCC", "5G", "40M", "HT", "1T", "126", + "30", "ETSI", "5G", "40M", "HT", "1T", "126", "30", "MKK", + "5G", "40M", "HT", "1T", "126", "30", "FCC", "5G", "40M", + "HT", "1T", "134", "30", "ETSI", "5G", "40M", "HT", "1T", + "134", "30", "MKK", "5G", "40M", "HT", "1T", "134", "30", + "FCC", "5G", "40M", "HT", "1T", "142", "30", "ETSI", "5G", + "40M", "HT", "1T", "142", "63", "MKK", "5G", "40M", "HT", + "1T", "142", "63", "FCC", "5G", "40M", "HT", "1T", "151", + "30", "ETSI", "5G", "40M", "HT", "1T", "151", "63", "MKK", + "5G", "40M", "HT", "1T", "151", "63", "FCC", "5G", "40M", + "HT", "1T", "159", "30", "ETSI", "5G", "40M", "HT", "1T", + "159", "63", "MKK", "5G", "40M", "HT", "1T", "159", "63", + "FCC", "5G", "40M", "HT", "2T", "38", "20", "ETSI", "5G", + "40M", "HT", "2T", "38", "20", "MKK", "5G", "40M", "HT", + "2T", "38", "22", "FCC", "5G", "40M", "HT", "2T", "46", + "30", "ETSI", "5G", "40M", "HT", "2T", "46", "20", "MKK", + "5G", "40M", "HT", "2T", "46", "22", "FCC", "5G", "40M", + "HT", "2T", "54", "30", "ETSI", "5G", "40M", "HT", "2T", + "54", "20", "MKK", "5G", "40M", "HT", "2T", "54", "22", + "FCC", "5G", "40M", "HT", "2T", "62", "22", "ETSI", "5G", + "40M", "HT", "2T", "62", "20", "MKK", "5G", "40M", "HT", + "2T", "62", "22", "FCC", "5G", "40M", "HT", "2T", "102", + "22", "ETSI", "5G", "40M", "HT", "2T", "102", "20", "MKK", + "5G", "40M", "HT", "2T", "102", "30", "FCC", "5G", "40M", + "HT", "2T", "110", "30", "ETSI", "5G", "40M", "HT", "2T", + "110", "20", "MKK", "5G", "40M", "HT", "2T", "110", "30", + "FCC", "5G", "40M", "HT", "2T", "118", "30", "ETSI", "5G", + "40M", "HT", "2T", "118", "20", "MKK", "5G", "40M", "HT", + "2T", "118", "30", "FCC", "5G", "40M", "HT", "2T", "126", + "30", "ETSI", "5G", "40M", "HT", "2T", "126", "20", "MKK", + "5G", "40M", "HT", "2T", "126", "30", "FCC", "5G", "40M", + "HT", "2T", "134", "30", "ETSI", "5G", "40M", "HT", "2T", + "134", "20", "MKK", "5G", "40M", "HT", "2T", "134", "30", + "FCC", "5G", "40M", "HT", "2T", "142", "30", "ETSI", "5G", + "40M", "HT", "2T", "142", "63", "MKK", "5G", "40M", "HT", + "2T", "142", "63", "FCC", "5G", "40M", "HT", "2T", "151", + "30", "ETSI", "5G", "40M", "HT", "2T", "151", "63", "MKK", + "5G", "40M", "HT", "2T", "151", "63", "FCC", "5G", "40M", + "HT", "2T", "159", "30", "ETSI", "5G", "40M", "HT", "2T", + "159", "63", "MKK", "5G", "40M", "HT", "2T", "159", "63", + "FCC", "5G", "80M", "VHT", "1T", "42", "20", "ETSI", "5G", + "80M", "VHT", "1T", "42", "30", "MKK", "5G", "80M", "VHT", + "1T", "42", "28", "FCC", "5G", "80M", "VHT", "1T", "58", + "20", "ETSI", "5G", "80M", "VHT", "1T", "58", "30", "MKK", + "5G", "80M", "VHT", "1T", "58", "28", "FCC", "5G", "80M", + "VHT", "1T", "106", "20", "ETSI", "5G", "80M", "VHT", "1T", + "106", "30", "MKK", "5G", "80M", "VHT", "1T", "106", "30", + "FCC", "5G", "80M", "VHT", "1T", "122", "30", "ETSI", "5G", + "80M", "VHT", "1T", "122", "30", "MKK", "5G", "80M", "VHT", + "1T", "122", "30", "FCC", "5G", "80M", "VHT", "1T", "138", + "30", "ETSI", "5G", "80M", "VHT", "1T", "138", "63", "MKK", + "5G", "80M", "VHT", "1T", "138", "63", "FCC", "5G", "80M", + "VHT", "1T", "155", "30", "ETSI", "5G", "80M", "VHT", "1T", + "155", "63", "MKK", "5G", "80M", "VHT", "1T", "155", "63", + "FCC", "5G", "80M", "VHT", "2T", "42", "18", "ETSI", "5G", + "80M", "VHT", "2T", "42", "20", "MKK", "5G", "80M", "VHT", + "2T", "42", "22", "FCC", "5G", "80M", "VHT", "2T", "58", + "18", "ETSI", "5G", "80M", "VHT", "2T", "58", "20", "MKK", + "5G", "80M", "VHT", "2T", "58", "22", "FCC", "5G", "80M", + "VHT", "2T", "106", "20", "ETSI", "5G", "80M", "VHT", "2T", + "106", "20", "MKK", "5G", "80M", "VHT", "2T", "106", "30", + "FCC", "5G", "80M", "VHT", "2T", "122", "30", "ETSI", "5G", + "80M", "VHT", "2T", "122", "20", "MKK", "5G", "80M", "VHT", + "2T", "122", "30", "FCC", "5G", "80M", "VHT", "2T", "138", + "30", "ETSI", "5G", "80M", "VHT", "2T", "138", "63", "MKK", + "5G", "80M", "VHT", "2T", "138", "63", "FCC", "5G", "80M", + "VHT", "2T", "155", "30", "ETSI", "5G", "80M", "VHT", "2T", + "155", "63", "MKK", "5G", "80M", "VHT", "2T", "155", "63"}; + +void odm_read_and_config_mp_8822b_txpwr_lmt(struct phy_dm_struct *dm) +{ + u32 i = 0; + u32 array_len = sizeof(array_mp_8822b_txpwr_lmt) / sizeof(u8 *); + u8 **array = (u8 **)array_mp_8822b_txpwr_lmt; + + ODM_RT_TRACE(dm, ODM_COMP_INIT, + "===> %s\n", __func__); + + for (i = 0; i < array_len; i += 7) { + u8 *regulation = array[i]; + u8 *band = array[i + 1]; + u8 *bandwidth = array[i + 2]; + u8 *rate = array[i + 3]; + u8 *rf_path = array[i + 4]; + u8 *chnl = array[i + 5]; + u8 *val = array[i + 6]; + + odm_config_bb_txpwr_lmt_8822b(dm, regulation, band, bandwidth, + rate, rf_path, chnl, val); + } +} + +/****************************************************************************** +* txpwr_lmt_type5.TXT +******************************************************************************/ + +static const char *const array_mp_8822b_txpwr_lmt_type5[] = { + "FCC", "2.4G", "20M", "CCK", "1T", "01", "32", "ETSI", "2.4G", + "20M", "CCK", "1T", "01", "28", "MKK", "2.4G", "20M", "CCK", + "1T", "01", "30", "FCC", "2.4G", "20M", "CCK", "1T", "02", + "32", "ETSI", "2.4G", "20M", "CCK", "1T", "02", "28", "MKK", + "2.4G", "20M", "CCK", "1T", "02", "30", "FCC", "2.4G", "20M", + "CCK", "1T", "03", "32", "ETSI", "2.4G", "20M", "CCK", "1T", + "03", "28", "MKK", "2.4G", "20M", "CCK", "1T", "03", "30", + "FCC", "2.4G", "20M", "CCK", "1T", "04", "32", "ETSI", "2.4G", + "20M", "CCK", "1T", "04", "28", "MKK", "2.4G", "20M", "CCK", + "1T", "04", "30", "FCC", "2.4G", "20M", "CCK", "1T", "05", + "32", "ETSI", "2.4G", "20M", "CCK", "1T", "05", "28", "MKK", + "2.4G", "20M", "CCK", "1T", "05", "30", "FCC", "2.4G", "20M", + "CCK", "1T", "06", "32", "ETSI", "2.4G", "20M", "CCK", "1T", + "06", "28", "MKK", "2.4G", "20M", "CCK", "1T", "06", "30", + "FCC", "2.4G", "20M", "CCK", "1T", "07", "32", "ETSI", "2.4G", + "20M", "CCK", "1T", "07", "28", "MKK", "2.4G", "20M", "CCK", + "1T", "07", "30", "FCC", "2.4G", "20M", "CCK", "1T", "08", + "32", "ETSI", "2.4G", "20M", "CCK", "1T", "08", "28", "MKK", + "2.4G", "20M", "CCK", "1T", "08", "30", "FCC", "2.4G", "20M", + "CCK", "1T", "09", "32", "ETSI", "2.4G", "20M", "CCK", "1T", + "09", "28", "MKK", "2.4G", "20M", "CCK", "1T", "09", "30", + "FCC", "2.4G", "20M", "CCK", "1T", "10", "32", "ETSI", "2.4G", + "20M", "CCK", "1T", "10", "28", "MKK", "2.4G", "20M", "CCK", + "1T", "10", "30", "FCC", "2.4G", "20M", "CCK", "1T", "11", + "32", "ETSI", "2.4G", "20M", "CCK", "1T", "11", "28", "MKK", + "2.4G", "20M", "CCK", "1T", "11", "30", "FCC", "2.4G", "20M", + "CCK", "1T", "12", "26", "ETSI", "2.4G", "20M", "CCK", "1T", + "12", "28", "MKK", "2.4G", "20M", "CCK", "1T", "12", "30", + "FCC", "2.4G", "20M", "CCK", "1T", "13", "20", "ETSI", "2.4G", + "20M", "CCK", "1T", "13", "28", "MKK", "2.4G", "20M", "CCK", + "1T", "13", "28", "FCC", "2.4G", "20M", "CCK", "1T", "14", + "63", "ETSI", "2.4G", "20M", "CCK", "1T", "14", "63", "MKK", + "2.4G", "20M", "CCK", "1T", "14", "32", "FCC", "2.4G", "20M", + "OFDM", "1T", "01", "26", "ETSI", "2.4G", "20M", "OFDM", "1T", + "01", "30", "MKK", "2.4G", "20M", "OFDM", "1T", "01", "34", + "FCC", "2.4G", "20M", "OFDM", "1T", "02", "30", "ETSI", "2.4G", + "20M", "OFDM", "1T", "02", "30", "MKK", "2.4G", "20M", "OFDM", + "1T", "02", "34", "FCC", "2.4G", "20M", "OFDM", "1T", "03", + "32", "ETSI", "2.4G", "20M", "OFDM", "1T", "03", "30", "MKK", + "2.4G", "20M", "OFDM", "1T", "03", "34", "FCC", "2.4G", "20M", + "OFDM", "1T", "04", "34", "ETSI", "2.4G", "20M", "OFDM", "1T", + "04", "30", "MKK", "2.4G", "20M", "OFDM", "1T", "04", "34", + "FCC", "2.4G", "20M", "OFDM", "1T", "05", "34", "ETSI", "2.4G", + "20M", "OFDM", "1T", "05", "30", "MKK", "2.4G", "20M", "OFDM", + "1T", "05", "34", "FCC", "2.4G", "20M", "OFDM", "1T", "06", + "34", "ETSI", "2.4G", "20M", "OFDM", "1T", "06", "30", "MKK", + "2.4G", "20M", "OFDM", "1T", "06", "34", "FCC", "2.4G", "20M", + "OFDM", "1T", "07", "34", "ETSI", "2.4G", "20M", "OFDM", "1T", + "07", "30", "MKK", "2.4G", "20M", "OFDM", "1T", "07", "34", + "FCC", "2.4G", "20M", "OFDM", "1T", "08", "34", "ETSI", "2.4G", + "20M", "OFDM", "1T", "08", "30", "MKK", "2.4G", "20M", "OFDM", + "1T", "08", "34", "FCC", "2.4G", "20M", "OFDM", "1T", "09", + "32", "ETSI", "2.4G", "20M", "OFDM", "1T", "09", "30", "MKK", + "2.4G", "20M", "OFDM", "1T", "09", "34", "FCC", "2.4G", "20M", + "OFDM", "1T", "10", "30", "ETSI", "2.4G", "20M", "OFDM", "1T", + "10", "30", "MKK", "2.4G", "20M", "OFDM", "1T", "10", "34", + "FCC", "2.4G", "20M", "OFDM", "1T", "11", "28", "ETSI", "2.4G", + "20M", "OFDM", "1T", "11", "30", "MKK", "2.4G", "20M", "OFDM", + "1T", "11", "34", "FCC", "2.4G", "20M", "OFDM", "1T", "12", + "22", "ETSI", "2.4G", "20M", "OFDM", "1T", "12", "30", "MKK", + "2.4G", "20M", "OFDM", "1T", "12", "34", "FCC", "2.4G", "20M", + "OFDM", "1T", "13", "14", "ETSI", "2.4G", "20M", "OFDM", "1T", + "13", "30", "MKK", "2.4G", "20M", "OFDM", "1T", "13", "34", + "FCC", "2.4G", "20M", "OFDM", "1T", "14", "63", "ETSI", "2.4G", + "20M", "OFDM", "1T", "14", "63", "MKK", "2.4G", "20M", "OFDM", + "1T", "14", "63", "FCC", "2.4G", "20M", "HT", "1T", "01", + "26", "ETSI", "2.4G", "20M", "HT", "1T", "01", "30", "MKK", + "2.4G", "20M", "HT", "1T", "01", "34", "FCC", "2.4G", "20M", + "HT", "1T", "02", "30", "ETSI", "2.4G", "20M", "HT", "1T", + "02", "30", "MKK", "2.4G", "20M", "HT", "1T", "02", "34", + "FCC", "2.4G", "20M", "HT", "1T", "03", "32", "ETSI", "2.4G", + "20M", "HT", "1T", "03", "30", "MKK", "2.4G", "20M", "HT", + "1T", "03", "34", "FCC", "2.4G", "20M", "HT", "1T", "04", + "34", "ETSI", "2.4G", "20M", "HT", "1T", "04", "30", "MKK", + "2.4G", "20M", "HT", "1T", "04", "34", "FCC", "2.4G", "20M", + "HT", "1T", "05", "34", "ETSI", "2.4G", "20M", "HT", "1T", + "05", "30", "MKK", "2.4G", "20M", "HT", "1T", "05", "34", + "FCC", "2.4G", "20M", "HT", "1T", "06", "34", "ETSI", "2.4G", + "20M", "HT", "1T", "06", "30", "MKK", "2.4G", "20M", "HT", + "1T", "06", "34", "FCC", "2.4G", "20M", "HT", "1T", "07", + "34", "ETSI", "2.4G", "20M", "HT", "1T", "07", "30", "MKK", + "2.4G", "20M", "HT", "1T", "07", "34", "FCC", "2.4G", "20M", + "HT", "1T", "08", "34", "ETSI", "2.4G", "20M", "HT", "1T", + "08", "30", "MKK", "2.4G", "20M", "HT", "1T", "08", "34", + "FCC", "2.4G", "20M", "HT", "1T", "09", "32", "ETSI", "2.4G", + "20M", "HT", "1T", "09", "30", "MKK", "2.4G", "20M", "HT", + "1T", "09", "34", "FCC", "2.4G", "20M", "HT", "1T", "10", + "30", "ETSI", "2.4G", "20M", "HT", "1T", "10", "30", "MKK", + "2.4G", "20M", "HT", "1T", "10", "34", "FCC", "2.4G", "20M", + "HT", "1T", "11", "26", "ETSI", "2.4G", "20M", "HT", "1T", + "11", "30", "MKK", "2.4G", "20M", "HT", "1T", "11", "34", + "FCC", "2.4G", "20M", "HT", "1T", "12", "20", "ETSI", "2.4G", + "20M", "HT", "1T", "12", "30", "MKK", "2.4G", "20M", "HT", + "1T", "12", "34", "FCC", "2.4G", "20M", "HT", "1T", "13", + "14", "ETSI", "2.4G", "20M", "HT", "1T", "13", "30", "MKK", + "2.4G", "20M", "HT", "1T", "13", "34", "FCC", "2.4G", "20M", + "HT", "1T", "14", "63", "ETSI", "2.4G", "20M", "HT", "1T", + "14", "63", "MKK", "2.4G", "20M", "HT", "1T", "14", "63", + "FCC", "2.4G", "20M", "HT", "2T", "01", "26", "ETSI", "2.4G", + "20M", "HT", "2T", "01", "18", "MKK", "2.4G", "20M", "HT", + "2T", "01", "30", "FCC", "2.4G", "20M", "HT", "2T", "02", + "28", "ETSI", "2.4G", "20M", "HT", "2T", "02", "18", "MKK", + "2.4G", "20M", "HT", "2T", "02", "30", "FCC", "2.4G", "20M", + "HT", "2T", "03", "30", "ETSI", "2.4G", "20M", "HT", "2T", + "03", "18", "MKK", "2.4G", "20M", "HT", "2T", "03", "30", + "FCC", "2.4G", "20M", "HT", "2T", "04", "30", "ETSI", "2.4G", + "20M", "HT", "2T", "04", "18", "MKK", "2.4G", "20M", "HT", + "2T", "04", "30", "FCC", "2.4G", "20M", "HT", "2T", "05", + "32", "ETSI", "2.4G", "20M", "HT", "2T", "05", "18", "MKK", + "2.4G", "20M", "HT", "2T", "05", "30", "FCC", "2.4G", "20M", + "HT", "2T", "06", "32", "ETSI", "2.4G", "20M", "HT", "2T", + "06", "18", "MKK", "2.4G", "20M", "HT", "2T", "06", "30", + "FCC", "2.4G", "20M", "HT", "2T", "07", "32", "ETSI", "2.4G", + "20M", "HT", "2T", "07", "18", "MKK", "2.4G", "20M", "HT", + "2T", "07", "30", "FCC", "2.4G", "20M", "HT", "2T", "08", + "30", "ETSI", "2.4G", "20M", "HT", "2T", "08", "18", "MKK", + "2.4G", "20M", "HT", "2T", "08", "30", "FCC", "2.4G", "20M", + "HT", "2T", "09", "30", "ETSI", "2.4G", "20M", "HT", "2T", + "09", "18", "MKK", "2.4G", "20M", "HT", "2T", "09", "30", + "FCC", "2.4G", "20M", "HT", "2T", "10", "28", "ETSI", "2.4G", + "20M", "HT", "2T", "10", "18", "MKK", "2.4G", "20M", "HT", + "2T", "10", "30", "FCC", "2.4G", "20M", "HT", "2T", "11", + "26", "ETSI", "2.4G", "20M", "HT", "2T", "11", "18", "MKK", + "2.4G", "20M", "HT", "2T", "11", "30", "FCC", "2.4G", "20M", + "HT", "2T", "12", "20", "ETSI", "2.4G", "20M", "HT", "2T", + "12", "18", "MKK", "2.4G", "20M", "HT", "2T", "12", "30", + "FCC", "2.4G", "20M", "HT", "2T", "13", "14", "ETSI", "2.4G", + "20M", "HT", "2T", "13", "18", "MKK", "2.4G", "20M", "HT", + "2T", "13", "30", "FCC", "2.4G", "20M", "HT", "2T", "14", + "63", "ETSI", "2.4G", "20M", "HT", "2T", "14", "63", "MKK", + "2.4G", "20M", "HT", "2T", "14", "63", "FCC", "2.4G", "40M", + "HT", "1T", "01", "63", "ETSI", "2.4G", "40M", "HT", "1T", + "01", "63", "MKK", "2.4G", "40M", "HT", "1T", "01", "63", + "FCC", "2.4G", "40M", "HT", "1T", "02", "63", "ETSI", "2.4G", + "40M", "HT", "1T", "02", "63", "MKK", "2.4G", "40M", "HT", + "1T", "02", "63", "FCC", "2.4G", "40M", "HT", "1T", "03", + "26", "ETSI", "2.4G", "40M", "HT", "1T", "03", "30", "MKK", + "2.4G", "40M", "HT", "1T", "03", "34", "FCC", "2.4G", "40M", + "HT", "1T", "04", "26", "ETSI", "2.4G", "40M", "HT", "1T", + "04", "30", "MKK", "2.4G", "40M", "HT", "1T", "04", "34", + "FCC", "2.4G", "40M", "HT", "1T", "05", "30", "ETSI", "2.4G", + "40M", "HT", "1T", "05", "30", "MKK", "2.4G", "40M", "HT", + "1T", "05", "34", "FCC", "2.4G", "40M", "HT", "1T", "06", + "32", "ETSI", "2.4G", "40M", "HT", "1T", "06", "30", "MKK", + "2.4G", "40M", "HT", "1T", "06", "34", "FCC", "2.4G", "40M", + "HT", "1T", "07", "30", "ETSI", "2.4G", "40M", "HT", "1T", + "07", "30", "MKK", "2.4G", "40M", "HT", "1T", "07", "34", + "FCC", "2.4G", "40M", "HT", "1T", "08", "26", "ETSI", "2.4G", + "40M", "HT", "1T", "08", "30", "MKK", "2.4G", "40M", "HT", + "1T", "08", "34", "FCC", "2.4G", "40M", "HT", "1T", "09", + "26", "ETSI", "2.4G", "40M", "HT", "1T", "09", "30", "MKK", + "2.4G", "40M", "HT", "1T", "09", "34", "FCC", "2.4G", "40M", + "HT", "1T", "10", "20", "ETSI", "2.4G", "40M", "HT", "1T", + "10", "30", "MKK", "2.4G", "40M", "HT", "1T", "10", "34", + "FCC", "2.4G", "40M", "HT", "1T", "11", "14", "ETSI", "2.4G", + "40M", "HT", "1T", "11", "30", "MKK", "2.4G", "40M", "HT", + "1T", "11", "34", "FCC", "2.4G", "40M", "HT", "1T", "12", + "63", "ETSI", "2.4G", "40M", "HT", "1T", "12", "63", "MKK", + "2.4G", "40M", "HT", "1T", "12", "63", "FCC", "2.4G", "40M", + "HT", "1T", "13", "63", "ETSI", "2.4G", "40M", "HT", "1T", + "13", "63", "MKK", "2.4G", "40M", "HT", "1T", "13", "63", + "FCC", "2.4G", "40M", "HT", "1T", "14", "63", "ETSI", "2.4G", + "40M", "HT", "1T", "14", "63", "MKK", "2.4G", "40M", "HT", + "1T", "14", "63", "FCC", "2.4G", "40M", "HT", "2T", "01", + "63", "ETSI", "2.4G", "40M", "HT", "2T", "01", "63", "MKK", + "2.4G", "40M", "HT", "2T", "01", "63", "FCC", "2.4G", "40M", + "HT", "2T", "02", "63", "ETSI", "2.4G", "40M", "HT", "2T", + "02", "63", "MKK", "2.4G", "40M", "HT", "2T", "02", "63", + "FCC", "2.4G", "40M", "HT", "2T", "03", "24", "ETSI", "2.4G", + "40M", "HT", "2T", "03", "18", "MKK", "2.4G", "40M", "HT", + "2T", "03", "30", "FCC", "2.4G", "40M", "HT", "2T", "04", + "24", "ETSI", "2.4G", "40M", "HT", "2T", "04", "18", "MKK", + "2.4G", "40M", "HT", "2T", "04", "30", "FCC", "2.4G", "40M", + "HT", "2T", "05", "26", "ETSI", "2.4G", "40M", "HT", "2T", + "05", "18", "MKK", "2.4G", "40M", "HT", "2T", "05", "30", + "FCC", "2.4G", "40M", "HT", "2T", "06", "28", "ETSI", "2.4G", + "40M", "HT", "2T", "06", "18", "MKK", "2.4G", "40M", "HT", + "2T", "06", "30", "FCC", "2.4G", "40M", "HT", "2T", "07", + "26", "ETSI", "2.4G", "40M", "HT", "2T", "07", "18", "MKK", + "2.4G", "40M", "HT", "2T", "07", "30", "FCC", "2.4G", "40M", + "HT", "2T", "08", "26", "ETSI", "2.4G", "40M", "HT", "2T", + "08", "18", "MKK", "2.4G", "40M", "HT", "2T", "08", "30", + "FCC", "2.4G", "40M", "HT", "2T", "09", "26", "ETSI", "2.4G", + "40M", "HT", "2T", "09", "18", "MKK", "2.4G", "40M", "HT", + "2T", "09", "30", "FCC", "2.4G", "40M", "HT", "2T", "10", + "20", "ETSI", "2.4G", "40M", "HT", "2T", "10", "18", "MKK", + "2.4G", "40M", "HT", "2T", "10", "30", "FCC", "2.4G", "40M", + "HT", "2T", "11", "14", "ETSI", "2.4G", "40M", "HT", "2T", + "11", "18", "MKK", "2.4G", "40M", "HT", "2T", "11", "30", + "FCC", "2.4G", "40M", "HT", "2T", "12", "63", "ETSI", "2.4G", + "40M", "HT", "2T", "12", "63", "MKK", "2.4G", "40M", "HT", + "2T", "12", "63", "FCC", "2.4G", "40M", "HT", "2T", "13", + "63", "ETSI", "2.4G", "40M", "HT", "2T", "13", "63", "MKK", + "2.4G", "40M", "HT", "2T", "13", "63", "FCC", "2.4G", "40M", + "HT", "2T", "14", "63", "ETSI", "2.4G", "40M", "HT", "2T", + "14", "63", "MKK", "2.4G", "40M", "HT", "2T", "14", "63", + "FCC", "5G", "20M", "OFDM", "1T", "36", "30", "ETSI", "5G", + "20M", "OFDM", "1T", "36", "32", "MKK", "5G", "20M", "OFDM", + "1T", "36", "30", "FCC", "5G", "20M", "OFDM", "1T", "40", + "32", "ETSI", "5G", "20M", "OFDM", "1T", "40", "32", "MKK", + "5G", "20M", "OFDM", "1T", "40", "30", "FCC", "5G", "20M", + "OFDM", "1T", "44", "32", "ETSI", "5G", "20M", "OFDM", "1T", + "44", "32", "MKK", "5G", "20M", "OFDM", "1T", "44", "30", + "FCC", "5G", "20M", "OFDM", "1T", "48", "32", "ETSI", "5G", + "20M", "OFDM", "1T", "48", "32", "MKK", "5G", "20M", "OFDM", + "1T", "48", "30", "FCC", "5G", "20M", "OFDM", "1T", "52", + "32", "ETSI", "5G", "20M", "OFDM", "1T", "52", "32", "MKK", + "5G", "20M", "OFDM", "1T", "52", "28", "FCC", "5G", "20M", + "OFDM", "1T", "56", "32", "ETSI", "5G", "20M", "OFDM", "1T", + "56", "32", "MKK", "5G", "20M", "OFDM", "1T", "56", "28", + "FCC", "5G", "20M", "OFDM", "1T", "60", "32", "ETSI", "5G", + "20M", "OFDM", "1T", "60", "32", "MKK", "5G", "20M", "OFDM", + "1T", "60", "28", "FCC", "5G", "20M", "OFDM", "1T", "64", + "28", "ETSI", "5G", "20M", "OFDM", "1T", "64", "32", "MKK", + "5G", "20M", "OFDM", "1T", "64", "28", "FCC", "5G", "20M", + "OFDM", "1T", "100", "26", "ETSI", "5G", "20M", "OFDM", "1T", + "100", "32", "MKK", "5G", "20M", "OFDM", "1T", "100", "32", + "FCC", "5G", "20M", "OFDM", "1T", "104", "32", "ETSI", "5G", + "20M", "OFDM", "1T", "104", "32", "MKK", "5G", "20M", "OFDM", + "1T", "104", "32", "FCC", "5G", "20M", "OFDM", "1T", "108", + "32", "ETSI", "5G", "20M", "OFDM", "1T", "108", "32", "MKK", + "5G", "20M", "OFDM", "1T", "108", "32", "FCC", "5G", "20M", + "OFDM", "1T", "112", "32", "ETSI", "5G", "20M", "OFDM", "1T", + "112", "32", "MKK", "5G", "20M", "OFDM", "1T", "112", "32", + "FCC", "5G", "20M", "OFDM", "1T", "116", "32", "ETSI", "5G", + "20M", "OFDM", "1T", "116", "32", "MKK", "5G", "20M", "OFDM", + "1T", "116", "32", "FCC", "5G", "20M", "OFDM", "1T", "120", + "32", "ETSI", "5G", "20M", "OFDM", "1T", "120", "32", "MKK", + "5G", "20M", "OFDM", "1T", "120", "32", "FCC", "5G", "20M", + "OFDM", "1T", "124", "32", "ETSI", "5G", "20M", "OFDM", "1T", + "124", "32", "MKK", "5G", "20M", "OFDM", "1T", "124", "32", + "FCC", "5G", "20M", "OFDM", "1T", "128", "32", "ETSI", "5G", + "20M", "OFDM", "1T", "128", "32", "MKK", "5G", "20M", "OFDM", + "1T", "128", "32", "FCC", "5G", "20M", "OFDM", "1T", "132", + "32", "ETSI", "5G", "20M", "OFDM", "1T", "132", "32", "MKK", + "5G", "20M", "OFDM", "1T", "132", "32", "FCC", "5G", "20M", + "OFDM", "1T", "136", "32", "ETSI", "5G", "20M", "OFDM", "1T", + "136", "32", "MKK", "5G", "20M", "OFDM", "1T", "136", "32", + "FCC", "5G", "20M", "OFDM", "1T", "140", "28", "ETSI", "5G", + "20M", "OFDM", "1T", "140", "32", "MKK", "5G", "20M", "OFDM", + "1T", "140", "32", "FCC", "5G", "20M", "OFDM", "1T", "144", + "28", "ETSI", "5G", "20M", "OFDM", "1T", "144", "32", "MKK", + "5G", "20M", "OFDM", "1T", "144", "63", "FCC", "5G", "20M", + "OFDM", "1T", "149", "32", "ETSI", "5G", "20M", "OFDM", "1T", + "149", "63", "MKK", "5G", "20M", "OFDM", "1T", "149", "63", + "FCC", "5G", "20M", "OFDM", "1T", "153", "32", "ETSI", "5G", + "20M", "OFDM", "1T", "153", "63", "MKK", "5G", "20M", "OFDM", + "1T", "153", "63", "FCC", "5G", "20M", "OFDM", "1T", "157", + "32", "ETSI", "5G", "20M", "OFDM", "1T", "157", "63", "MKK", + "5G", "20M", "OFDM", "1T", "157", "63", "FCC", "5G", "20M", + "OFDM", "1T", "161", "32", "ETSI", "5G", "20M", "OFDM", "1T", + "161", "63", "MKK", "5G", "20M", "OFDM", "1T", "161", "63", + "FCC", "5G", "20M", "OFDM", "1T", "165", "32", "ETSI", "5G", + "20M", "OFDM", "1T", "165", "63", "MKK", "5G", "20M", "OFDM", + "1T", "165", "63", "FCC", "5G", "20M", "HT", "1T", "36", + "30", "ETSI", "5G", "20M", "HT", "1T", "36", "32", "MKK", + "5G", "20M", "HT", "1T", "36", "28", "FCC", "5G", "20M", + "HT", "1T", "40", "32", "ETSI", "5G", "20M", "HT", "1T", + "40", "32", "MKK", "5G", "20M", "HT", "1T", "40", "28", + "FCC", "5G", "20M", "HT", "1T", "44", "32", "ETSI", "5G", + "20M", "HT", "1T", "44", "32", "MKK", "5G", "20M", "HT", + "1T", "44", "28", "FCC", "5G", "20M", "HT", "1T", "48", + "32", "ETSI", "5G", "20M", "HT", "1T", "48", "32", "MKK", + "5G", "20M", "HT", "1T", "48", "28", "FCC", "5G", "20M", + "HT", "1T", "52", "32", "ETSI", "5G", "20M", "HT", "1T", + "52", "32", "MKK", "5G", "20M", "HT", "1T", "52", "28", + "FCC", "5G", "20M", "HT", "1T", "56", "32", "ETSI", "5G", + "20M", "HT", "1T", "56", "32", "MKK", "5G", "20M", "HT", + "1T", "56", "28", "FCC", "5G", "20M", "HT", "1T", "60", + "32", "ETSI", "5G", "20M", "HT", "1T", "60", "32", "MKK", + "5G", "20M", "HT", "1T", "60", "28", "FCC", "5G", "20M", + "HT", "1T", "64", "28", "ETSI", "5G", "20M", "HT", "1T", + "64", "32", "MKK", "5G", "20M", "HT", "1T", "64", "28", + "FCC", "5G", "20M", "HT", "1T", "100", "26", "ETSI", "5G", + "20M", "HT", "1T", "100", "32", "MKK", "5G", "20M", "HT", + "1T", "100", "32", "FCC", "5G", "20M", "HT", "1T", "104", + "32", "ETSI", "5G", "20M", "HT", "1T", "104", "32", "MKK", + "5G", "20M", "HT", "1T", "104", "32", "FCC", "5G", "20M", + "HT", "1T", "108", "32", "ETSI", "5G", "20M", "HT", "1T", + "108", "32", "MKK", "5G", "20M", "HT", "1T", "108", "32", + "FCC", "5G", "20M", "HT", "1T", "112", "32", "ETSI", "5G", + "20M", "HT", "1T", "112", "32", "MKK", "5G", "20M", "HT", + "1T", "112", "32", "FCC", "5G", "20M", "HT", "1T", "116", + "32", "ETSI", "5G", "20M", "HT", "1T", "116", "32", "MKK", + "5G", "20M", "HT", "1T", "116", "32", "FCC", "5G", "20M", + "HT", "1T", "120", "32", "ETSI", "5G", "20M", "HT", "1T", + "120", "32", "MKK", "5G", "20M", "HT", "1T", "120", "32", + "FCC", "5G", "20M", "HT", "1T", "124", "32", "ETSI", "5G", + "20M", "HT", "1T", "124", "32", "MKK", "5G", "20M", "HT", + "1T", "124", "32", "FCC", "5G", "20M", "HT", "1T", "128", + "32", "ETSI", "5G", "20M", "HT", "1T", "128", "32", "MKK", + "5G", "20M", "HT", "1T", "128", "32", "FCC", "5G", "20M", + "HT", "1T", "132", "32", "ETSI", "5G", "20M", "HT", "1T", + "132", "32", "MKK", "5G", "20M", "HT", "1T", "132", "32", + "FCC", "5G", "20M", "HT", "1T", "136", "32", "ETSI", "5G", + "20M", "HT", "1T", "136", "32", "MKK", "5G", "20M", "HT", + "1T", "136", "32", "FCC", "5G", "20M", "HT", "1T", "140", + "26", "ETSI", "5G", "20M", "HT", "1T", "140", "32", "MKK", + "5G", "20M", "HT", "1T", "140", "32", "FCC", "5G", "20M", + "HT", "1T", "144", "26", "ETSI", "5G", "20M", "HT", "1T", + "144", "63", "MKK", "5G", "20M", "HT", "1T", "144", "63", + "FCC", "5G", "20M", "HT", "1T", "149", "32", "ETSI", "5G", + "20M", "HT", "1T", "149", "63", "MKK", "5G", "20M", "HT", + "1T", "149", "63", "FCC", "5G", "20M", "HT", "1T", "153", + "32", "ETSI", "5G", "20M", "HT", "1T", "153", "63", "MKK", + "5G", "20M", "HT", "1T", "153", "63", "FCC", "5G", "20M", + "HT", "1T", "157", "32", "ETSI", "5G", "20M", "HT", "1T", + "157", "63", "MKK", "5G", "20M", "HT", "1T", "157", "63", + "FCC", "5G", "20M", "HT", "1T", "161", "32", "ETSI", "5G", + "20M", "HT", "1T", "161", "63", "MKK", "5G", "20M", "HT", + "1T", "161", "63", "FCC", "5G", "20M", "HT", "1T", "165", + "32", "ETSI", "5G", "20M", "HT", "1T", "165", "63", "MKK", + "5G", "20M", "HT", "1T", "165", "63", "FCC", "5G", "20M", + "HT", "2T", "36", "28", "ETSI", "5G", "20M", "HT", "2T", + "36", "20", "MKK", "5G", "20M", "HT", "2T", "36", "22", + "FCC", "5G", "20M", "HT", "2T", "40", "30", "ETSI", "5G", + "20M", "HT", "2T", "40", "20", "MKK", "5G", "20M", "HT", + "2T", "40", "22", "FCC", "5G", "20M", "HT", "2T", "44", + "30", "ETSI", "5G", "20M", "HT", "2T", "44", "20", "MKK", + "5G", "20M", "HT", "2T", "44", "22", "FCC", "5G", "20M", + "HT", "2T", "48", "30", "ETSI", "5G", "20M", "HT", "2T", + "48", "20", "MKK", "5G", "20M", "HT", "2T", "48", "22", + "FCC", "5G", "20M", "HT", "2T", "52", "30", "ETSI", "5G", + "20M", "HT", "2T", "52", "20", "MKK", "5G", "20M", "HT", + "2T", "52", "22", "FCC", "5G", "20M", "HT", "2T", "56", + "30", "ETSI", "5G", "20M", "HT", "2T", "56", "20", "MKK", + "5G", "20M", "HT", "2T", "56", "22", "FCC", "5G", "20M", + "HT", "2T", "60", "30", "ETSI", "5G", "20M", "HT", "2T", + "60", "20", "MKK", "5G", "20M", "HT", "2T", "60", "22", + "FCC", "5G", "20M", "HT", "2T", "64", "28", "ETSI", "5G", + "20M", "HT", "2T", "64", "20", "MKK", "5G", "20M", "HT", + "2T", "64", "22", "FCC", "5G", "20M", "HT", "2T", "100", + "26", "ETSI", "5G", "20M", "HT", "2T", "100", "20", "MKK", + "5G", "20M", "HT", "2T", "100", "30", "FCC", "5G", "20M", + "HT", "2T", "104", "30", "ETSI", "5G", "20M", "HT", "2T", + "104", "20", "MKK", "5G", "20M", "HT", "2T", "104", "30", + "FCC", "5G", "20M", "HT", "2T", "108", "32", "ETSI", "5G", + "20M", "HT", "2T", "108", "20", "MKK", "5G", "20M", "HT", + "2T", "108", "30", "FCC", "5G", "20M", "HT", "2T", "112", + "32", "ETSI", "5G", "20M", "HT", "2T", "112", "20", "MKK", + "5G", "20M", "HT", "2T", "112", "30", "FCC", "5G", "20M", + "HT", "2T", "116", "32", "ETSI", "5G", "20M", "HT", "2T", + "116", "20", "MKK", "5G", "20M", "HT", "2T", "116", "30", + "FCC", "5G", "20M", "HT", "2T", "120", "32", "ETSI", "5G", + "20M", "HT", "2T", "120", "20", "MKK", "5G", "20M", "HT", + "2T", "120", "30", "FCC", "5G", "20M", "HT", "2T", "124", + "32", "ETSI", "5G", "20M", "HT", "2T", "124", "20", "MKK", + "5G", "20M", "HT", "2T", "124", "30", "FCC", "5G", "20M", + "HT", "2T", "128", "32", "ETSI", "5G", "20M", "HT", "2T", + "128", "20", "MKK", "5G", "20M", "HT", "2T", "128", "30", + "FCC", "5G", "20M", "HT", "2T", "132", "32", "ETSI", "5G", + "20M", "HT", "2T", "132", "20", "MKK", "5G", "20M", "HT", + "2T", "132", "30", "FCC", "5G", "20M", "HT", "2T", "136", + "30", "ETSI", "5G", "20M", "HT", "2T", "136", "20", "MKK", + "5G", "20M", "HT", "2T", "136", "30", "FCC", "5G", "20M", + "HT", "2T", "140", "26", "ETSI", "5G", "20M", "HT", "2T", + "140", "20", "MKK", "5G", "20M", "HT", "2T", "140", "30", + "FCC", "5G", "20M", "HT", "2T", "144", "26", "ETSI", "5G", + "20M", "HT", "2T", "144", "63", "MKK", "5G", "20M", "HT", + "2T", "144", "63", "FCC", "5G", "20M", "HT", "2T", "149", + "32", "ETSI", "5G", "20M", "HT", "2T", "149", "63", "MKK", + "5G", "20M", "HT", "2T", "149", "63", "FCC", "5G", "20M", + "HT", "2T", "153", "32", "ETSI", "5G", "20M", "HT", "2T", + "153", "63", "MKK", "5G", "20M", "HT", "2T", "153", "63", + "FCC", "5G", "20M", "HT", "2T", "157", "32", "ETSI", "5G", + "20M", "HT", "2T", "157", "63", "MKK", "5G", "20M", "HT", + "2T", "157", "63", "FCC", "5G", "20M", "HT", "2T", "161", + "32", "ETSI", "5G", "20M", "HT", "2T", "161", "63", "MKK", + "5G", "20M", "HT", "2T", "161", "63", "FCC", "5G", "20M", + "HT", "2T", "165", "32", "ETSI", "5G", "20M", "HT", "2T", + "165", "63", "MKK", "5G", "20M", "HT", "2T", "165", "63", + "FCC", "5G", "40M", "HT", "1T", "38", "22", "ETSI", "5G", + "40M", "HT", "1T", "38", "30", "MKK", "5G", "40M", "HT", + "1T", "38", "30", "FCC", "5G", "40M", "HT", "1T", "46", + "30", "ETSI", "5G", "40M", "HT", "1T", "46", "30", "MKK", + "5G", "40M", "HT", "1T", "46", "30", "FCC", "5G", "40M", + "HT", "1T", "54", "30", "ETSI", "5G", "40M", "HT", "1T", + "54", "30", "MKK", "5G", "40M", "HT", "1T", "54", "30", + "FCC", "5G", "40M", "HT", "1T", "62", "24", "ETSI", "5G", + "40M", "HT", "1T", "62", "30", "MKK", "5G", "40M", "HT", + "1T", "62", "30", "FCC", "5G", "40M", "HT", "1T", "102", + "24", "ETSI", "5G", "40M", "HT", "1T", "102", "30", "MKK", + "5G", "40M", "HT", "1T", "102", "30", "FCC", "5G", "40M", + "HT", "1T", "110", "30", "ETSI", "5G", "40M", "HT", "1T", + "110", "30", "MKK", "5G", "40M", "HT", "1T", "110", "30", + "FCC", "5G", "40M", "HT", "1T", "118", "30", "ETSI", "5G", + "40M", "HT", "1T", "118", "30", "MKK", "5G", "40M", "HT", + "1T", "118", "30", "FCC", "5G", "40M", "HT", "1T", "126", + "30", "ETSI", "5G", "40M", "HT", "1T", "126", "30", "MKK", + "5G", "40M", "HT", "1T", "126", "30", "FCC", "5G", "40M", + "HT", "1T", "134", "30", "ETSI", "5G", "40M", "HT", "1T", + "134", "30", "MKK", "5G", "40M", "HT", "1T", "134", "30", + "FCC", "5G", "40M", "HT", "1T", "142", "30", "ETSI", "5G", + "40M", "HT", "1T", "142", "63", "MKK", "5G", "40M", "HT", + "1T", "142", "63", "FCC", "5G", "40M", "HT", "1T", "151", + "30", "ETSI", "5G", "40M", "HT", "1T", "151", "63", "MKK", + "5G", "40M", "HT", "1T", "151", "63", "FCC", "5G", "40M", + "HT", "1T", "159", "30", "ETSI", "5G", "40M", "HT", "1T", + "159", "63", "MKK", "5G", "40M", "HT", "1T", "159", "63", + "FCC", "5G", "40M", "HT", "2T", "38", "20", "ETSI", "5G", + "40M", "HT", "2T", "38", "20", "MKK", "5G", "40M", "HT", + "2T", "38", "22", "FCC", "5G", "40M", "HT", "2T", "46", + "30", "ETSI", "5G", "40M", "HT", "2T", "46", "20", "MKK", + "5G", "40M", "HT", "2T", "46", "22", "FCC", "5G", "40M", + "HT", "2T", "54", "30", "ETSI", "5G", "40M", "HT", "2T", + "54", "20", "MKK", "5G", "40M", "HT", "2T", "54", "22", + "FCC", "5G", "40M", "HT", "2T", "62", "22", "ETSI", "5G", + "40M", "HT", "2T", "62", "20", "MKK", "5G", "40M", "HT", + "2T", "62", "22", "FCC", "5G", "40M", "HT", "2T", "102", + "22", "ETSI", "5G", "40M", "HT", "2T", "102", "20", "MKK", + "5G", "40M", "HT", "2T", "102", "30", "FCC", "5G", "40M", + "HT", "2T", "110", "30", "ETSI", "5G", "40M", "HT", "2T", + "110", "20", "MKK", "5G", "40M", "HT", "2T", "110", "30", + "FCC", "5G", "40M", "HT", "2T", "118", "30", "ETSI", "5G", + "40M", "HT", "2T", "118", "20", "MKK", "5G", "40M", "HT", + "2T", "118", "30", "FCC", "5G", "40M", "HT", "2T", "126", + "30", "ETSI", "5G", "40M", "HT", "2T", "126", "20", "MKK", + "5G", "40M", "HT", "2T", "126", "30", "FCC", "5G", "40M", + "HT", "2T", "134", "30", "ETSI", "5G", "40M", "HT", "2T", + "134", "20", "MKK", "5G", "40M", "HT", "2T", "134", "30", + "FCC", "5G", "40M", "HT", "2T", "142", "30", "ETSI", "5G", + "40M", "HT", "2T", "142", "63", "MKK", "5G", "40M", "HT", + "2T", "142", "63", "FCC", "5G", "40M", "HT", "2T", "151", + "30", "ETSI", "5G", "40M", "HT", "2T", "151", "63", "MKK", + "5G", "40M", "HT", "2T", "151", "63", "FCC", "5G", "40M", + "HT", "2T", "159", "30", "ETSI", "5G", "40M", "HT", "2T", + "159", "63", "MKK", "5G", "40M", "HT", "2T", "159", "63", + "FCC", "5G", "80M", "VHT", "1T", "42", "20", "ETSI", "5G", + "80M", "VHT", "1T", "42", "30", "MKK", "5G", "80M", "VHT", + "1T", "42", "28", "FCC", "5G", "80M", "VHT", "1T", "58", + "20", "ETSI", "5G", "80M", "VHT", "1T", "58", "30", "MKK", + "5G", "80M", "VHT", "1T", "58", "28", "FCC", "5G", "80M", + "VHT", "1T", "106", "20", "ETSI", "5G", "80M", "VHT", "1T", + "106", "30", "MKK", "5G", "80M", "VHT", "1T", "106", "30", + "FCC", "5G", "80M", "VHT", "1T", "122", "30", "ETSI", "5G", + "80M", "VHT", "1T", "122", "30", "MKK", "5G", "80M", "VHT", + "1T", "122", "30", "FCC", "5G", "80M", "VHT", "1T", "138", + "30", "ETSI", "5G", "80M", "VHT", "1T", "138", "63", "MKK", + "5G", "80M", "VHT", "1T", "138", "63", "FCC", "5G", "80M", + "VHT", "1T", "155", "30", "ETSI", "5G", "80M", "VHT", "1T", + "155", "63", "MKK", "5G", "80M", "VHT", "1T", "155", "63", + "FCC", "5G", "80M", "VHT", "2T", "42", "18", "ETSI", "5G", + "80M", "VHT", "2T", "42", "20", "MKK", "5G", "80M", "VHT", + "2T", "42", "22", "FCC", "5G", "80M", "VHT", "2T", "58", + "18", "ETSI", "5G", "80M", "VHT", "2T", "58", "20", "MKK", + "5G", "80M", "VHT", "2T", "58", "22", "FCC", "5G", "80M", + "VHT", "2T", "106", "20", "ETSI", "5G", "80M", "VHT", "2T", + "106", "20", "MKK", "5G", "80M", "VHT", "2T", "106", "30", + "FCC", "5G", "80M", "VHT", "2T", "122", "30", "ETSI", "5G", + "80M", "VHT", "2T", "122", "20", "MKK", "5G", "80M", "VHT", + "2T", "122", "30", "FCC", "5G", "80M", "VHT", "2T", "138", + "30", "ETSI", "5G", "80M", "VHT", "2T", "138", "63", "MKK", + "5G", "80M", "VHT", "2T", "138", "63", "FCC", "5G", "80M", + "VHT", "2T", "155", "30", "ETSI", "5G", "80M", "VHT", "2T", + "155", "63", "MKK", "5G", "80M", "VHT", "2T", "155", "63"}; + +void odm_read_and_config_mp_8822b_txpwr_lmt_type5(struct phy_dm_struct *dm) +{ + u32 i = 0; + u32 array_len = sizeof(array_mp_8822b_txpwr_lmt_type5) / sizeof(u8 *); + u8 **array = (u8 **)array_mp_8822b_txpwr_lmt_type5; + + ODM_RT_TRACE(dm, ODM_COMP_INIT, + "===> odm_read_and_config_mp_8822b_txpwr_lmt_type5\n"); + + for (i = 0; i < array_len; i += 7) { + u8 *regulation = array[i]; + u8 *band = array[i + 1]; + u8 *bandwidth = array[i + 2]; + u8 *rate = array[i + 3]; + u8 *rf_path = array[i + 4]; + u8 *chnl = array[i + 5]; + u8 *val = array[i + 6]; + + odm_config_bb_txpwr_lmt_8822b(dm, regulation, band, bandwidth, + rate, rf_path, chnl, val); + } +} diff --git a/drivers/staging/rtlwifi/phydm/rtl8822b/halhwimg8822b_rf.h b/drivers/staging/rtlwifi/phydm/rtl8822b/halhwimg8822b_rf.h new file mode 100644 index 000000000000..1340fa9f369b --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/rtl8822b/halhwimg8822b_rf.h @@ -0,0 +1,129 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +/*Image2HeaderVersion: 3.2*/ +#ifndef __INC_MP_RF_HW_IMG_8822B_H +#define __INC_MP_RF_HW_IMG_8822B_H + +/****************************************************************************** + * radioa.TXT + ******************************************************************************/ + +void odm_read_and_config_mp_8822b_radioa(struct phy_dm_struct *dm); +u32 odm_get_version_mp_8822b_radioa(void); + +/****************************************************************************** + * radiob.TXT + ******************************************************************************/ + +void odm_read_and_config_mp_8822b_radiob(struct phy_dm_struct *dm); +u32 odm_get_version_mp_8822b_radiob(void); + +/****************************************************************************** + * txpowertrack.TXT + ******************************************************************************/ + +void odm_read_and_config_mp_8822b_txpowertrack(struct phy_dm_struct *dm); +u32 odm_get_version_mp_8822b_txpowertrack(void); + +/****************************************************************************** + * txpowertrack_type0.TXT + ******************************************************************************/ + +void odm_read_and_config_mp_8822b_txpowertrack_type0(struct phy_dm_struct *dm); +u32 odm_get_version_mp_8822b_txpowertrack_type0(void); + +/****************************************************************************** + * txpowertrack_type1.TXT + ******************************************************************************/ + +void odm_read_and_config_mp_8822b_txpowertrack_type1(struct phy_dm_struct *dm); +u32 odm_get_version_mp_8822b_txpowertrack_type1(void); + +/****************************************************************************** + * txpowertrack_type2.TXT + ******************************************************************************/ + +void odm_read_and_config_mp_8822b_txpowertrack_type2(struct phy_dm_struct *dm); +u32 odm_get_version_mp_8822b_txpowertrack_type2(void); + +/****************************************************************************** + * txpowertrack_type3_type5.TXT + ******************************************************************************/ + +void odm_read_and_config_mp_8822b_txpowertrack_type3_type5( + struct phy_dm_struct *dm); +u32 odm_get_version_mp_8822b_txpowertrack_type3_type5(void); + +/****************************************************************************** + * txpowertrack_type4.TXT + ******************************************************************************/ + +void odm_read_and_config_mp_8822b_txpowertrack_type4(struct phy_dm_struct *dm); +u32 odm_get_version_mp_8822b_txpowertrack_type4(void); + +/****************************************************************************** + * txpowertrack_type6.TXT + ******************************************************************************/ + +void odm_read_and_config_mp_8822b_txpowertrack_type6(struct phy_dm_struct *dm); +u32 odm_get_version_mp_8822b_txpowertrack_type6(void); + +/****************************************************************************** + * txpowertrack_type7.TXT + ******************************************************************************/ + +void odm_read_and_config_mp_8822b_txpowertrack_type7(struct phy_dm_struct *dm); +u32 odm_get_version_mp_8822b_txpowertrack_type7(void); + +/****************************************************************************** + * txpowertrack_type8.TXT + *****************************************************************************/ + +void odm_read_and_config_mp_8822b_txpowertrack_type8(struct phy_dm_struct *dm); +u32 odm_get_version_mp_8822b_txpowertrack_type8(void); + +/****************************************************************************** + * txpowertrack_type9.TXT + ******************************************************************************/ + +void odm_read_and_config_mp_8822b_txpowertrack_type9(struct phy_dm_struct *dm); +u32 odm_get_version_mp_8822b_txpowertrack_type9(void); + +/****************************************************************************** + * txpwr_lmt.TXT + ******************************************************************************/ + +void odm_read_and_config_mp_8822b_txpwr_lmt(struct phy_dm_struct *dm); +u32 odm_get_version_mp_8822b_txpwr_lmt(void); + +/****************************************************************************** + * txpwr_lmt_type5.TXT + ******************************************************************************/ + +void odm_read_and_config_mp_8822b_txpwr_lmt_type5(struct phy_dm_struct *dm); +u32 odm_get_version_mp_8822b_txpwr_lmt_type5(void); + +#endif diff --git a/drivers/staging/rtlwifi/phydm/rtl8822b/halphyrf_8822b.c b/drivers/staging/rtlwifi/phydm/rtl8822b/halphyrf_8822b.c new file mode 100644 index 000000000000..ae3e2278fefd --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/rtl8822b/halphyrf_8822b.c @@ -0,0 +1,351 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include "../mp_precomp.h" +#include "../phydm_precomp.h" + +static bool +get_mix_mode_tx_agc_bb_swing_offset_8822b(void *dm_void, + enum pwrtrack_method method, + u8 rf_path, u8 tx_power_index_offest) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct dm_rf_calibration_struct *cali_info = &dm->rf_calibrate_info; + + u8 bb_swing_upper_bound = cali_info->default_ofdm_index + 10; + u8 bb_swing_lower_bound = 0; + + s8 tx_agc_index = 0; + u8 tx_bb_swing_index = cali_info->default_ofdm_index; + + ODM_RT_TRACE( + dm, ODM_COMP_TX_PWR_TRACK, + "Path_%d cali_info->absolute_ofdm_swing_idx[rf_path]=%d, tx_power_index_offest=%d\n", + rf_path, cali_info->absolute_ofdm_swing_idx[rf_path], + tx_power_index_offest); + + if (tx_power_index_offest > 0XF) + tx_power_index_offest = 0XF; + + if (cali_info->absolute_ofdm_swing_idx[rf_path] >= 0 && + cali_info->absolute_ofdm_swing_idx[rf_path] <= + tx_power_index_offest) { + tx_agc_index = cali_info->absolute_ofdm_swing_idx[rf_path]; + tx_bb_swing_index = cali_info->default_ofdm_index; + } else if (cali_info->absolute_ofdm_swing_idx[rf_path] > + tx_power_index_offest) { + tx_agc_index = tx_power_index_offest; + cali_info->remnant_ofdm_swing_idx[rf_path] = + cali_info->absolute_ofdm_swing_idx[rf_path] - + tx_power_index_offest; + tx_bb_swing_index = cali_info->default_ofdm_index + + cali_info->remnant_ofdm_swing_idx[rf_path]; + + if (tx_bb_swing_index > bb_swing_upper_bound) + tx_bb_swing_index = bb_swing_upper_bound; + } else { + tx_agc_index = 0; + + if (cali_info->default_ofdm_index > + (cali_info->absolute_ofdm_swing_idx[rf_path] * (-1))) + tx_bb_swing_index = + cali_info->default_ofdm_index + + cali_info->absolute_ofdm_swing_idx[rf_path]; + else + tx_bb_swing_index = bb_swing_lower_bound; + + if (tx_bb_swing_index < bb_swing_lower_bound) + tx_bb_swing_index = bb_swing_lower_bound; + } + + cali_info->absolute_ofdm_swing_idx[rf_path] = tx_agc_index; + cali_info->bb_swing_idx_ofdm[rf_path] = tx_bb_swing_index; + + ODM_RT_TRACE( + dm, ODM_COMP_TX_PWR_TRACK, + "MixMode Offset Path_%d cali_info->absolute_ofdm_swing_idx[rf_path]=%d cali_info->bb_swing_idx_ofdm[rf_path]=%d tx_power_index_offest=%d\n", + rf_path, cali_info->absolute_ofdm_swing_idx[rf_path], + cali_info->bb_swing_idx_ofdm[rf_path], tx_power_index_offest); + + return true; +} + +void odm_tx_pwr_track_set_pwr8822b(void *dm_void, enum pwrtrack_method method, + u8 rf_path, u8 channel_mapped_index) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct dm_rf_calibration_struct *cali_info = &dm->rf_calibrate_info; + u8 tx_power_index_offest = 0; + u8 tx_power_index = 0; + + struct rtl_priv *rtlpriv = (struct rtl_priv *)dm->adapter; + struct rtl_phy *rtlphy = &rtlpriv->phy; + u8 channel = rtlphy->current_channel; + u8 band_width = rtlphy->current_chan_bw; + u8 tx_rate = 0xFF; + + if (!dm->mp_mode) { + u16 rate = *dm->forced_data_rate; + + if (!rate) /*auto rate*/ + tx_rate = dm->tx_rate; + else /*force rate*/ + tx_rate = (u8)rate; + } + + ODM_RT_TRACE(dm, ODM_COMP_TX_PWR_TRACK, "Call:%s tx_rate=0x%X\n", + __func__, tx_rate); + + ODM_RT_TRACE(dm, ODM_COMP_TX_PWR_TRACK, + "pRF->default_ofdm_index=%d pRF->default_cck_index=%d\n", + cali_info->default_ofdm_index, + cali_info->default_cck_index); + + ODM_RT_TRACE( + dm, ODM_COMP_TX_PWR_TRACK, + "pRF->absolute_ofdm_swing_idx=%d pRF->remnant_ofdm_swing_idx=%d pRF->absolute_cck_swing_idx=%d pRF->remnant_cck_swing_idx=%d rf_path=%d\n", + cali_info->absolute_ofdm_swing_idx[rf_path], + cali_info->remnant_ofdm_swing_idx[rf_path], + cali_info->absolute_cck_swing_idx[rf_path], + cali_info->remnant_cck_swing_idx, rf_path); + + if (dm->number_linked_client != 0) + tx_power_index = odm_get_tx_power_index( + dm, (enum odm_rf_radio_path)rf_path, tx_rate, + band_width, channel); + + if (tx_power_index >= 63) + tx_power_index = 63; + + tx_power_index_offest = 63 - tx_power_index; + + ODM_RT_TRACE(dm, ODM_COMP_TX_PWR_TRACK, + "tx_power_index=%d tx_power_index_offest=%d rf_path=%d\n", + tx_power_index, tx_power_index_offest, rf_path); + + if (method == + BBSWING) { /*use for mp driver clean power tracking status*/ + switch (rf_path) { + case ODM_RF_PATH_A: + odm_set_bb_reg( + dm, 0xC94, (BIT(29) | BIT(28) | BIT(27) | + BIT(26) | BIT(25)), + cali_info->absolute_ofdm_swing_idx[rf_path]); + odm_set_bb_reg( + dm, REG_A_TX_SCALE_JAGUAR, 0xFFE00000, + tx_scaling_table_jaguar + [cali_info + ->bb_swing_idx_ofdm[rf_path]]); + break; + case ODM_RF_PATH_B: + odm_set_bb_reg( + dm, 0xE94, (BIT(29) | BIT(28) | BIT(27) | + BIT(26) | BIT(25)), + cali_info->absolute_ofdm_swing_idx[rf_path]); + odm_set_bb_reg( + dm, REG_B_TX_SCALE_JAGUAR, 0xFFE00000, + tx_scaling_table_jaguar + [cali_info + ->bb_swing_idx_ofdm[rf_path]]); + break; + + default: + break; + } + } else if (method == MIX_MODE) { + switch (rf_path) { + case ODM_RF_PATH_A: + get_mix_mode_tx_agc_bb_swing_offset_8822b( + dm, method, rf_path, tx_power_index_offest); + odm_set_bb_reg( + dm, 0xC94, (BIT(29) | BIT(28) | BIT(27) | + BIT(26) | BIT(25)), + cali_info->absolute_ofdm_swing_idx[rf_path]); + odm_set_bb_reg( + dm, REG_A_TX_SCALE_JAGUAR, 0xFFE00000, + tx_scaling_table_jaguar + [cali_info + ->bb_swing_idx_ofdm[rf_path]]); + + ODM_RT_TRACE( + dm, ODM_COMP_TX_PWR_TRACK, + "TXAGC(0xC94)=0x%x BBSwing(0xc1c)=0x%x BBSwingIndex=%d rf_path=%d\n", + odm_get_bb_reg(dm, 0xC94, + (BIT(29) | BIT(28) | BIT(27) | + BIT(26) | BIT(25))), + odm_get_bb_reg(dm, 0xc1c, 0xFFE00000), + cali_info->bb_swing_idx_ofdm[rf_path], rf_path); + break; + + case ODM_RF_PATH_B: + get_mix_mode_tx_agc_bb_swing_offset_8822b( + dm, method, rf_path, tx_power_index_offest); + odm_set_bb_reg( + dm, 0xE94, (BIT(29) | BIT(28) | BIT(27) | + BIT(26) | BIT(25)), + cali_info->absolute_ofdm_swing_idx[rf_path]); + odm_set_bb_reg( + dm, REG_B_TX_SCALE_JAGUAR, 0xFFE00000, + tx_scaling_table_jaguar + [cali_info + ->bb_swing_idx_ofdm[rf_path]]); + + ODM_RT_TRACE( + dm, ODM_COMP_TX_PWR_TRACK, + "TXAGC(0xE94)=0x%x BBSwing(0xe1c)=0x%x BBSwingIndex=%d rf_path=%d\n", + odm_get_bb_reg(dm, 0xE94, + (BIT(29) | BIT(28) | BIT(27) | + BIT(26) | BIT(25))), + odm_get_bb_reg(dm, 0xe1c, 0xFFE00000), + cali_info->bb_swing_idx_ofdm[rf_path], rf_path); + break; + + default: + break; + } + } +} + +void get_delta_swing_table_8822b(void *dm_void, u8 **temperature_up_a, + u8 **temperature_down_a, u8 **temperature_up_b, + u8 **temperature_down_b) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct dm_rf_calibration_struct *cali_info = &dm->rf_calibrate_info; + + struct rtl_priv *rtlpriv = (struct rtl_priv *)dm->adapter; + struct rtl_phy *rtlphy = &rtlpriv->phy; + u8 channel = rtlphy->current_channel; + + *temperature_up_a = cali_info->delta_swing_table_idx_2ga_p; + *temperature_down_a = cali_info->delta_swing_table_idx_2ga_n; + *temperature_up_b = cali_info->delta_swing_table_idx_2gb_p; + *temperature_down_b = cali_info->delta_swing_table_idx_2gb_n; + + if (channel >= 36 && channel <= 64) { + *temperature_up_a = cali_info->delta_swing_table_idx_5ga_p[0]; + *temperature_down_a = cali_info->delta_swing_table_idx_5ga_n[0]; + *temperature_up_b = cali_info->delta_swing_table_idx_5gb_p[0]; + *temperature_down_b = cali_info->delta_swing_table_idx_5gb_n[0]; + } else if (channel >= 100 && channel <= 144) { + *temperature_up_a = cali_info->delta_swing_table_idx_5ga_p[1]; + *temperature_down_a = cali_info->delta_swing_table_idx_5ga_n[1]; + *temperature_up_b = cali_info->delta_swing_table_idx_5gb_p[1]; + *temperature_down_b = cali_info->delta_swing_table_idx_5gb_n[1]; + } else if (channel >= 149 && channel <= 177) { + *temperature_up_a = cali_info->delta_swing_table_idx_5ga_p[2]; + *temperature_down_a = cali_info->delta_swing_table_idx_5ga_n[2]; + *temperature_up_b = cali_info->delta_swing_table_idx_5gb_p[2]; + *temperature_down_b = cali_info->delta_swing_table_idx_5gb_n[2]; + } +} + +static void _phy_lc_calibrate_8822b(struct phy_dm_struct *dm) +{ + u32 lc_cal = 0, cnt = 0; + + /*backup RF0x18*/ + lc_cal = odm_get_rf_reg(dm, ODM_RF_PATH_A, RF_CHNLBW, RFREGOFFSETMASK); + + /*Start LCK*/ + odm_set_rf_reg(dm, ODM_RF_PATH_A, RF_CHNLBW, RFREGOFFSETMASK, + lc_cal | 0x08000); + + ODM_delay_ms(100); + + for (cnt = 0; cnt < 100; cnt++) { + if (odm_get_rf_reg(dm, ODM_RF_PATH_A, RF_CHNLBW, 0x8000) != 0x1) + break; + ODM_delay_ms(10); + } + + /*Recover channel number*/ + odm_set_rf_reg(dm, ODM_RF_PATH_A, RF_CHNLBW, RFREGOFFSETMASK, lc_cal); +} + +void phy_lc_calibrate_8822b(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + bool is_start_cont_tx = false, is_single_tone = false, + is_carrier_suppression = false; + u64 start_time; + u64 progressing_time; + + if (is_start_cont_tx || is_single_tone || is_carrier_suppression) { + ODM_RT_TRACE(dm, ODM_COMP_CALIBRATION, + "[LCK]continues TX ing !!! LCK return\n"); + return; + } + + start_time = odm_get_current_time(dm); + _phy_lc_calibrate_8822b(dm); + progressing_time = odm_get_progressing_time(dm, start_time); + ODM_RT_TRACE(dm, ODM_COMP_CALIBRATION, + "[LCK]LCK progressing_time = %lld\n", progressing_time); +} + +void configure_txpower_track_8822b(struct txpwrtrack_cfg *config) +{ + config->swing_table_size_cck = TXSCALE_TABLE_SIZE; + config->swing_table_size_ofdm = TXSCALE_TABLE_SIZE; + config->threshold_iqk = IQK_THRESHOLD; + config->threshold_dpk = DPK_THRESHOLD; + config->average_thermal_num = AVG_THERMAL_NUM_8822B; + config->rf_path_count = MAX_PATH_NUM_8822B; + config->thermal_reg_addr = RF_T_METER_8822B; + + config->odm_tx_pwr_track_set_pwr = odm_tx_pwr_track_set_pwr8822b; + config->do_iqk = do_iqk_8822b; + config->phy_lc_calibrate = phy_lc_calibrate_8822b; + + config->get_delta_swing_table = get_delta_swing_table_8822b; +} + +void phy_set_rf_path_switch_8822b(struct phy_dm_struct *dm, bool is_main) +{ + /*BY SY Request */ + odm_set_bb_reg(dm, 0x4C, (BIT(24) | BIT(23)), 0x2); + odm_set_bb_reg(dm, 0x974, 0xff, 0xff); + + /*odm_set_bb_reg(dm, 0x1991, 0x3, 0x0);*/ + odm_set_bb_reg(dm, 0x1990, (BIT(9) | BIT(8)), 0x0); + + /*odm_set_bb_reg(dm, 0xCBE, 0x8, 0x0);*/ + odm_set_bb_reg(dm, 0xCBC, BIT(19), 0x0); + + odm_set_bb_reg(dm, 0xCB4, 0xff, 0x77); + + odm_set_bb_reg(dm, 0x70, MASKBYTE3, 0x0e); + odm_set_bb_reg(dm, 0x1704, MASKDWORD, 0x0000ff00); + odm_set_bb_reg(dm, 0x1700, MASKDWORD, 0xc00f0038); + + if (is_main) { + /*odm_set_bb_reg(dm, 0xCBD, 0x3, 0x2); WiFi */ + odm_set_bb_reg(dm, 0xCBC, (BIT(9) | BIT(8)), 0x2); /*WiFi */ + } else { + /*odm_set_bb_reg(dm, 0xCBD, 0x3, 0x1); BT*/ + odm_set_bb_reg(dm, 0xCBC, (BIT(9) | BIT(8)), 0x1); /*BT*/ + } +} diff --git a/drivers/staging/rtlwifi/phydm/rtl8822b/halphyrf_8822b.h b/drivers/staging/rtlwifi/phydm/rtl8822b/halphyrf_8822b.h new file mode 100644 index 000000000000..4f3bfe316ee9 --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/rtl8822b/halphyrf_8822b.h @@ -0,0 +1,45 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __HAL_PHY_RF_8822B_H__ +#define __HAL_PHY_RF_8822B_H__ + +#define AVG_THERMAL_NUM_8822B 4 +#define RF_T_METER_8822B 0x42 + +void configure_txpower_track_8822b(struct txpwrtrack_cfg *config); + +void odm_tx_pwr_track_set_pwr8822b(void *dm_void, enum pwrtrack_method method, + u8 rf_path, u8 channel_mapped_index); + +void get_delta_swing_table_8822b(void *dm_void, u8 **temperature_up_a, + u8 **temperature_down_a, u8 **temperature_up_b, + u8 **temperature_down_b); + +void phy_lc_calibrate_8822b(void *dm_void); + +void phy_set_rf_path_switch_8822b(struct phy_dm_struct *dm, bool is_main); + +#endif /* #ifndef __HAL_PHY_RF_8822B_H__ */ diff --git a/drivers/staging/rtlwifi/phydm/rtl8822b/phydm_hal_api8822b.c b/drivers/staging/rtlwifi/phydm/rtl8822b/phydm_hal_api8822b.c new file mode 100644 index 000000000000..26d1022e851c --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/rtl8822b/phydm_hal_api8822b.c @@ -0,0 +1,1815 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include "../mp_precomp.h" +#include "../phydm_precomp.h" + +/* ======================================================================== */ +/* These following functions can be used for PHY DM only*/ + +static u32 reg82c_8822b; +static u32 reg838_8822b; +static u32 reg830_8822b; +static u32 reg83c_8822b; +static u32 rega20_8822b; +static u32 rega24_8822b; +static u32 rega28_8822b; +static enum odm_bw bw_8822b; +static u8 central_ch_8822b; + +static u32 cca_ifem_ccut[12][4] = { + /*20M*/ + {0x75D97010, 0x75D97010, 0x75D97010, 0x75D97010}, /*Reg82C*/ + {0x00000000, 0x79a0ea2c, 0x00000000, 0x00000000}, /*Reg830*/ + {0x00000000, 0x00000000, 0x00000000, 0x00000000}, /*Reg838*/ + {0x00000000, 0x00000000, 0x00000000, 0x00000000}, /*Reg83C*/ + /*40M*/ + {0x75D97010, 0x75D97010, 0x75D97010, 0x75D97010}, /*Reg82C*/ + {0x00000000, 0x79a0ea2c, 0x00000000, 0x79a0ea28}, /*Reg830*/ + {0x87765541, 0x87766341, 0x87765541, 0x87766341}, /*Reg838*/ + {0x00000000, 0x00000000, 0x00000000, 0x00000000}, /*Reg83C*/ + /*80M*/ + {0x75C97010, 0x75C97010, 0x75C97010, 0x75C97010}, /*Reg82C*/ + {0x00000000, 0x00000000, 0x00000000, 0x00000000}, /*Reg830*/ + {0x00000000, 0x87746641, 0x00000000, 0x87746641}, /*Reg838*/ + {0x00000000, 0x00000000, 0x00000000, 0x00000000}, +}; /*Reg83C*/ +static u32 cca_efem_ccut[12][4] = { + /*20M*/ + {0x75A76010, 0x75A76010, 0x75A76010, 0x75A75010}, /*Reg82C*/ + {0x00000000, 0x79a0ea2c, 0x00000000, 0x00000000}, /*Reg830*/ + {0x87766651, 0x87766431, 0x87766451, 0x87766431}, /*Reg838*/ + {0x9194b2b9, 0x9194b2b9, 0x9194b2b9, 0x9194b2b9}, /*Reg83C*/ + /*40M*/ + {0x75A85010, 0x75A75010, 0x75A85010, 0x75A75010}, /*Reg82C*/ + {0x00000000, 0x79a0ea2c, 0x00000000, 0x00000000}, /*Reg830*/ + {0x87766431, 0x87766431, 0x87766431, 0x87766431}, /*Reg838*/ + {0x00000000, 0x00000000, 0x00000000, 0x00000000}, /*Reg83C*/ + /*80M*/ + {0x76BA7010, 0x75BA7010, 0x76BA7010, 0x75BA7010}, /*Reg82C*/ + {0x79a0ea28, 0x00000000, 0x79a0ea28, 0x00000000}, /*Reg830*/ + {0x87766431, 0x87766431, 0x87766431, 0x87766431}, /*Reg838*/ + {0x00000000, 0x00000000, 0x00000000, 0x00000000}, +}; /*Reg83C*/ +static u32 cca_ifem_ccut_rfetype5[12][4] = { + /*20M*/ + {0x75D97010, 0x75D97010, 0x75D97010, 0x75D97010}, /*Reg82C*/ + {0x00000000, 0x79a0ea2c, 0x00000000, 0x00000000}, /*Reg830*/ + {0x00000000, 0x00000000, 0x87766461, 0x87766461}, /*Reg838*/ + {0x00000000, 0x00000000, 0x00000000, 0x00000000}, /*Reg83C*/ + /*40M*/ + {0x75D97010, 0x75D97010, 0x75D97010, 0x75D97010}, /*Reg82C*/ + {0x00000000, 0x79a0ea2c, 0x00000000, 0x79a0ea28}, /*Reg830*/ + {0x87765541, 0x87766341, 0x87765541, 0x87766341}, /*Reg838*/ + {0x00000000, 0x00000000, 0x00000000, 0x00000000}, /*Reg83C*/ + /*80M*/ + {0x75C97010, 0x75C97010, 0x75C97010, 0x75C97010}, /*Reg82C*/ + {0x00000000, 0x00000000, 0x00000000, 0x00000000}, /*Reg830*/ + {0x00000000, 0x76666641, 0x00000000, 0x76666641}, /*Reg838*/ + {0x00000000, 0x00000000, 0x00000000, 0x00000000}, +}; /*Reg83C*/ +static u32 cca_ifem_ccut_rfetype3[12][4] = { + /*20M*/ + {0x75D97010, 0x75D97010, 0x75D97010, 0x75D97010}, /*Reg82C*/ + {0x00000000, 0x79a0ea2c, 0x00000000, 0x00000000}, /*Reg830*/ + {0x00000000, 0x00000000, 0x87766461, 0x87766461}, /*Reg838*/ + {0x00000000, 0x00000000, 0x00000000, 0x00000000}, /*Reg83C*/ + /*40M*/ + {0x75D97010, 0x75D97010, 0x75D97010, 0x75D97010}, /*Reg82C*/ + {0x00000000, 0x79a0ea2c, 0x00000000, 0x79a0ea28}, /*Reg830*/ + {0x87765541, 0x87766341, 0x87765541, 0x87766341}, /*Reg838*/ + {0x00000000, 0x00000000, 0x00000000, 0x00000000}, /*Reg83C*/ + /*80M*/ + {0x75C97010, 0x75C97010, 0x75C97010, 0x75C97010}, /*Reg82C*/ + {0x00000000, 0x00000000, 0x00000000, 0x00000000}, /*Reg830*/ + {0x00000000, 0x76666641, 0x00000000, 0x76666641}, /*Reg838*/ + {0x00000000, 0x00000000, 0x00000000, 0x00000000}, +}; /*Reg83C*/ + +static inline u32 phydm_check_bit_mask(u32 bit_mask, u32 data_original, + u32 data) +{ + u8 bit_shift; + + if (bit_mask != 0xfffff) { + for (bit_shift = 0; bit_shift <= 19; bit_shift++) { + if (((bit_mask >> bit_shift) & 0x1) == 1) + break; + } + return ((data_original) & (~bit_mask)) | (data << bit_shift); + } + return data; +} + +static bool phydm_rfe_8822b(struct phy_dm_struct *dm, u8 channel) +{ + if (dm->rfe_type == 4) { + /* Default setting is in PHY parameters */ + + if (channel <= 14) { + /* signal source */ + odm_set_bb_reg(dm, 0xcb0, (MASKBYTE2 | MASKLWORD), + 0x745774); + odm_set_bb_reg(dm, 0xeb0, (MASKBYTE2 | MASKLWORD), + 0x745774); + odm_set_bb_reg(dm, 0xcb4, MASKBYTE1, 0x57); + odm_set_bb_reg(dm, 0xeb4, MASKBYTE1, 0x57); + + /* inverse or not */ + odm_set_bb_reg(dm, 0xcbc, (BIT(5) | BIT(4) | BIT(3) | + BIT(2) | BIT(1) | BIT(0)), + 0x8); + odm_set_bb_reg(dm, 0xcbc, (BIT(11) | BIT(10)), 0x2); + odm_set_bb_reg(dm, 0xebc, (BIT(5) | BIT(4) | BIT(3) | + BIT(2) | BIT(1) | BIT(0)), + 0x8); + odm_set_bb_reg(dm, 0xebc, (BIT(11) | BIT(10)), 0x2); + + /* antenna switch table */ + if ((dm->rx_ant_status == (ODM_RF_A | ODM_RF_B)) || + (dm->tx_ant_status == (ODM_RF_A | ODM_RF_B))) { + /* 2TX or 2RX */ + odm_set_bb_reg(dm, 0xca0, MASKLWORD, 0xf050); + odm_set_bb_reg(dm, 0xea0, MASKLWORD, 0xf050); + } else if (dm->rx_ant_status == dm->tx_ant_status) { + /* TXA+RXA or TXB+RXB */ + odm_set_bb_reg(dm, 0xca0, MASKLWORD, 0xf055); + odm_set_bb_reg(dm, 0xea0, MASKLWORD, 0xf055); + } else { + /* TXB+RXA or TXA+RXB */ + odm_set_bb_reg(dm, 0xca0, MASKLWORD, 0xf550); + odm_set_bb_reg(dm, 0xea0, MASKLWORD, 0xf550); + } + + } else if (channel > 35) { + /* signal source */ + odm_set_bb_reg(dm, 0xcb0, (MASKBYTE2 | MASKLWORD), + 0x477547); + odm_set_bb_reg(dm, 0xeb0, (MASKBYTE2 | MASKLWORD), + 0x477547); + odm_set_bb_reg(dm, 0xcb4, MASKBYTE1, 0x75); + odm_set_bb_reg(dm, 0xeb4, MASKBYTE1, 0x75); + + /* inverse or not */ + odm_set_bb_reg(dm, 0xcbc, (BIT(5) | BIT(4) | BIT(3) | + BIT(2) | BIT(1) | BIT(0)), + 0x0); + odm_set_bb_reg(dm, 0xcbc, (BIT(11) | BIT(10)), 0x0); + odm_set_bb_reg(dm, 0xebc, (BIT(5) | BIT(4) | BIT(3) | + BIT(2) | BIT(1) | BIT(0)), + 0x0); + odm_set_bb_reg(dm, 0xebc, (BIT(11) | BIT(10)), 0x0); + + /* antenna switch table */ + if ((dm->rx_ant_status == (ODM_RF_A | ODM_RF_B)) || + (dm->tx_ant_status == (ODM_RF_A | ODM_RF_B))) { + /* 2TX or 2RX */ + odm_set_bb_reg(dm, 0xca0, MASKLWORD, 0xa501); + odm_set_bb_reg(dm, 0xea0, MASKLWORD, 0xa501); + } else if (dm->rx_ant_status == dm->tx_ant_status) { + /* TXA+RXA or TXB+RXB */ + odm_set_bb_reg(dm, 0xca0, MASKLWORD, 0xa500); + odm_set_bb_reg(dm, 0xea0, MASKLWORD, 0xa500); + } else { + /* TXB+RXA or TXA+RXB */ + odm_set_bb_reg(dm, 0xca0, MASKLWORD, 0xa005); + odm_set_bb_reg(dm, 0xea0, MASKLWORD, 0xa005); + } + } else { + return false; + } + + } else if ((dm->rfe_type == 1) || (dm->rfe_type == 2) || + (dm->rfe_type == 7) || (dm->rfe_type == 9)) { + /* eFem */ + if (((dm->cut_version == ODM_CUT_A) || + (dm->cut_version == ODM_CUT_B)) && + (dm->rfe_type < 2)) { + if (channel <= 14) { + /* signal source */ + odm_set_bb_reg(dm, 0xcb0, + (MASKBYTE2 | MASKLWORD), + 0x704570); + odm_set_bb_reg(dm, 0xeb0, + (MASKBYTE2 | MASKLWORD), + 0x704570); + odm_set_bb_reg(dm, 0xcb4, MASKBYTE1, 0x45); + odm_set_bb_reg(dm, 0xeb4, MASKBYTE1, 0x45); + } else if (channel > 35) { + odm_set_bb_reg(dm, 0xcb0, + (MASKBYTE2 | MASKLWORD), + 0x174517); + odm_set_bb_reg(dm, 0xeb0, + (MASKBYTE2 | MASKLWORD), + 0x174517); + odm_set_bb_reg(dm, 0xcb4, MASKBYTE1, 0x45); + odm_set_bb_reg(dm, 0xeb4, MASKBYTE1, 0x45); + } else { + return false; + } + + /* delay 400ns for PAPE */ + odm_set_bb_reg(dm, 0x810, + MASKBYTE3 | BIT(20) | BIT(21) | BIT(22) | + BIT(23), + 0x211); + + /* antenna switch table */ + odm_set_bb_reg(dm, 0xca0, MASKLWORD, 0xa555); + odm_set_bb_reg(dm, 0xea0, MASKLWORD, 0xa555); + + /* inverse or not */ + odm_set_bb_reg(dm, 0xcbc, (BIT(5) | BIT(4) | BIT(3) | + BIT(2) | BIT(1) | BIT(0)), + 0x0); + odm_set_bb_reg(dm, 0xcbc, (BIT(11) | BIT(10)), 0x0); + odm_set_bb_reg(dm, 0xebc, (BIT(5) | BIT(4) | BIT(3) | + BIT(2) | BIT(1) | BIT(0)), + 0x0); + odm_set_bb_reg(dm, 0xebc, (BIT(11) | BIT(10)), 0x0); + + ODM_RT_TRACE( + dm, ODM_PHY_CONFIG, + "%s: Using old RFE control pin setting for A-cut and B-cut\n", + __func__); + } else { + if (channel <= 14) { + /* signal source */ + odm_set_bb_reg(dm, 0xcb0, + (MASKBYTE2 | MASKLWORD), + 0x705770); + odm_set_bb_reg(dm, 0xeb0, + (MASKBYTE2 | MASKLWORD), + 0x705770); + odm_set_bb_reg(dm, 0xcb4, MASKBYTE1, 0x57); + odm_set_bb_reg(dm, 0xeb4, MASKBYTE1, 0x57); + odm_set_bb_reg(dm, 0xcb8, BIT(4), 0); + odm_set_bb_reg(dm, 0xeb8, BIT(4), 0); + } else if (channel > 35) { + /* signal source */ + odm_set_bb_reg(dm, 0xcb0, + (MASKBYTE2 | MASKLWORD), + 0x177517); + odm_set_bb_reg(dm, 0xeb0, + (MASKBYTE2 | MASKLWORD), + 0x177517); + odm_set_bb_reg(dm, 0xcb4, MASKBYTE1, 0x75); + odm_set_bb_reg(dm, 0xeb4, MASKBYTE1, 0x75); + odm_set_bb_reg(dm, 0xcb8, BIT(5), 0); + odm_set_bb_reg(dm, 0xeb8, BIT(5), 0); + } else { + return false; + } + + /* inverse or not */ + odm_set_bb_reg(dm, 0xcbc, (BIT(5) | BIT(4) | BIT(3) | + BIT(2) | BIT(1) | BIT(0)), + 0x0); + odm_set_bb_reg(dm, 0xcbc, (BIT(11) | BIT(10)), 0x0); + odm_set_bb_reg(dm, 0xebc, (BIT(5) | BIT(4) | BIT(3) | + BIT(2) | BIT(1) | BIT(0)), + 0x0); + odm_set_bb_reg(dm, 0xebc, (BIT(11) | BIT(10)), 0x0); + + /* antenna switch table */ + if ((dm->rx_ant_status == (ODM_RF_A | ODM_RF_B)) || + (dm->tx_ant_status == (ODM_RF_A | ODM_RF_B))) { + /* 2TX or 2RX */ + odm_set_bb_reg(dm, 0xca0, MASKLWORD, 0xa501); + odm_set_bb_reg(dm, 0xea0, MASKLWORD, 0xa501); + } else if (dm->rx_ant_status == dm->tx_ant_status) { + /* TXA+RXA or TXB+RXB */ + odm_set_bb_reg(dm, 0xca0, MASKLWORD, 0xa500); + odm_set_bb_reg(dm, 0xea0, MASKLWORD, 0xa500); + } else { + /* TXB+RXA or TXA+RXB */ + odm_set_bb_reg(dm, 0xca0, MASKLWORD, 0xa005); + odm_set_bb_reg(dm, 0xea0, MASKLWORD, 0xa005); + } + } + } else if ((dm->rfe_type == 0) || (dm->rfe_type == 3) || + (dm->rfe_type == 5) || (dm->rfe_type == 6) || + (dm->rfe_type == 8) || (dm->rfe_type == 10)) { + /* iFEM */ + if (channel <= 14) { + /* signal source */ + + odm_set_bb_reg(dm, 0xcb0, (MASKBYTE2 | MASKLWORD), + 0x745774); + odm_set_bb_reg(dm, 0xeb0, (MASKBYTE2 | MASKLWORD), + 0x745774); + odm_set_bb_reg(dm, 0xcb4, MASKBYTE1, 0x57); + odm_set_bb_reg(dm, 0xeb4, MASKBYTE1, 0x57); + + } else if (channel > 35) { + /* signal source */ + + odm_set_bb_reg(dm, 0xcb0, (MASKBYTE2 | MASKLWORD), + 0x477547); + odm_set_bb_reg(dm, 0xeb0, (MASKBYTE2 | MASKLWORD), + 0x477547); + odm_set_bb_reg(dm, 0xcb4, MASKBYTE1, 0x75); + odm_set_bb_reg(dm, 0xeb4, MASKBYTE1, 0x75); + + } else { + return false; + } + + /* inverse or not */ + odm_set_bb_reg(dm, 0xcbc, (BIT(5) | BIT(4) | BIT(3) | BIT(2) | + BIT(1) | BIT(0)), + 0x0); + odm_set_bb_reg(dm, 0xcbc, (BIT(11) | BIT(10)), 0x0); + odm_set_bb_reg(dm, 0xebc, (BIT(5) | BIT(4) | BIT(3) | BIT(2) | + BIT(1) | BIT(0)), + 0x0); + odm_set_bb_reg(dm, 0xebc, (BIT(11) | BIT(10)), 0x0); + + /* antenna switch table */ + if (channel <= 14) { + if ((dm->rx_ant_status == (ODM_RF_A | ODM_RF_B)) || + (dm->tx_ant_status == (ODM_RF_A | ODM_RF_B))) { + /* 2TX or 2RX */ + odm_set_bb_reg(dm, 0xca0, MASKLWORD, 0xa501); + odm_set_bb_reg(dm, 0xea0, MASKLWORD, 0xa501); + } else if (dm->rx_ant_status == dm->tx_ant_status) { + /* TXA+RXA or TXB+RXB */ + odm_set_bb_reg(dm, 0xca0, MASKLWORD, 0xa500); + odm_set_bb_reg(dm, 0xea0, MASKLWORD, 0xa500); + } else { + /* TXB+RXA or TXA+RXB */ + odm_set_bb_reg(dm, 0xca0, MASKLWORD, 0xa005); + odm_set_bb_reg(dm, 0xea0, MASKLWORD, 0xa005); + } + } else if (channel > 35) { + odm_set_bb_reg(dm, 0xca0, MASKLWORD, 0xa5a5); + odm_set_bb_reg(dm, 0xea0, MASKLWORD, 0xa5a5); + } + } + + /* chip top mux */ + odm_set_bb_reg(dm, 0x64, BIT(29) | BIT(28), 0x3); + odm_set_bb_reg(dm, 0x4c, BIT(26) | BIT(25), 0x0); + odm_set_bb_reg(dm, 0x40, BIT(2), 0x1); + + /* from s0 or s1 */ + odm_set_bb_reg(dm, 0x1990, + (BIT(5) | BIT(4) | BIT(3) | BIT(2) | BIT(1) | BIT(0)), + 0x30); + odm_set_bb_reg(dm, 0x1990, (BIT(11) | BIT(10)), 0x3); + + /* input or output */ + odm_set_bb_reg(dm, 0x974, + (BIT(5) | BIT(4) | BIT(3) | BIT(2) | BIT(1) | BIT(0)), + 0x3f); + odm_set_bb_reg(dm, 0x974, (BIT(11) | BIT(10)), 0x3); + + ODM_RT_TRACE( + dm, ODM_PHY_CONFIG, + "%s: Update RFE control pin setting (ch%d, tx_path 0x%x, rx_path 0x%x)\n", + __func__, channel, dm->tx_ant_status, dm->rx_ant_status); + + return true; +} + +static void phydm_ccapar_by_rfe_8822b(struct phy_dm_struct *dm) +{ + u32 cca_ifem[12][4], cca_efem[12][4]; + u8 row, col; + u32 reg82c, reg830, reg838, reg83c; + + if (dm->cut_version == ODM_CUT_A) + return; + { + odm_move_memory(dm, cca_efem, cca_efem_ccut, 48 * 4); + if (dm->rfe_type == 5) + odm_move_memory(dm, cca_ifem, cca_ifem_ccut_rfetype5, + 48 * 4); + else if (dm->rfe_type == 3) + odm_move_memory(dm, cca_ifem, cca_ifem_ccut_rfetype3, + 48 * 4); + else + odm_move_memory(dm, cca_ifem, cca_ifem_ccut, 48 * 4); + + ODM_RT_TRACE(dm, ODM_PHY_CONFIG, + "%s: Update CCA parameters for Ccut\n", __func__); + } + + if (bw_8822b == ODM_BW20M) + row = 0; + else if (bw_8822b == ODM_BW40M) + row = 4; + else + row = 8; + + if (central_ch_8822b <= 14) { + if ((dm->rx_ant_status == ODM_RF_A) || + (dm->rx_ant_status == ODM_RF_B)) + col = 0; + else + col = 1; + } else { + if ((dm->rx_ant_status == ODM_RF_A) || + (dm->rx_ant_status == ODM_RF_B)) + col = 2; + else + col = 3; + } + + if ((dm->rfe_type == 1) || (dm->rfe_type == 4) || (dm->rfe_type == 6) || + (dm->rfe_type == 7)) { + /*eFEM => RFE type 1 & RFE type 4 & RFE type 6 & RFE type 7*/ + reg82c = (cca_efem[row][col] != 0) ? cca_efem[row][col] : + reg82c_8822b; + reg830 = (cca_efem[row + 1][col] != 0) ? + cca_efem[row + 1][col] : + reg830_8822b; + reg838 = (cca_efem[row + 2][col] != 0) ? + cca_efem[row + 2][col] : + reg838_8822b; + reg83c = (cca_efem[row + 3][col] != 0) ? + cca_efem[row + 3][col] : + reg83c_8822b; + } else if ((dm->rfe_type == 2) || (dm->rfe_type == 9)) { + /*5G eFEM, 2G iFEM => RFE type 2, 5G eFEM => RFE type 9 */ + if (central_ch_8822b <= 14) { + reg82c = (cca_ifem[row][col] != 0) ? + cca_ifem[row][col] : + reg82c_8822b; + reg830 = (cca_ifem[row + 1][col] != 0) ? + cca_ifem[row + 1][col] : + reg830_8822b; + reg838 = (cca_ifem[row + 2][col] != 0) ? + cca_ifem[row + 2][col] : + reg838_8822b; + reg83c = (cca_ifem[row + 3][col] != 0) ? + cca_ifem[row + 3][col] : + reg83c_8822b; + } else { + reg82c = (cca_efem[row][col] != 0) ? + cca_efem[row][col] : + reg82c_8822b; + reg830 = (cca_efem[row + 1][col] != 0) ? + cca_efem[row + 1][col] : + reg830_8822b; + reg838 = (cca_efem[row + 2][col] != 0) ? + cca_efem[row + 2][col] : + reg838_8822b; + reg83c = (cca_efem[row + 3][col] != 0) ? + cca_efem[row + 3][col] : + reg83c_8822b; + } + } else { + /* iFEM =>RFE type 3 & RFE type 5 & RFE type 0 & RFE type 8 & + * RFE type 10 + */ + reg82c = (cca_ifem[row][col] != 0) ? cca_ifem[row][col] : + reg82c_8822b; + reg830 = (cca_ifem[row + 1][col] != 0) ? + cca_ifem[row + 1][col] : + reg830_8822b; + reg838 = (cca_ifem[row + 2][col] != 0) ? + cca_ifem[row + 2][col] : + reg838_8822b; + reg83c = (cca_ifem[row + 3][col] != 0) ? + cca_ifem[row + 3][col] : + reg83c_8822b; + } + + odm_set_bb_reg(dm, 0x82c, MASKDWORD, reg82c); + odm_set_bb_reg(dm, 0x830, MASKDWORD, reg830); + odm_set_bb_reg(dm, 0x838, MASKDWORD, reg838); + odm_set_bb_reg(dm, 0x83c, MASKDWORD, reg83c); + ODM_RT_TRACE(dm, ODM_PHY_CONFIG, + "%s: (Pkt%d, Intf%d, RFE%d), row = %d, col = %d\n", + __func__, dm->package_type, dm->support_interface, + dm->rfe_type, row, col); +} + +static void phydm_ccapar_by_bw_8822b(struct phy_dm_struct *dm, + enum odm_bw bandwidth) +{ + u32 reg82c; + + if (dm->cut_version != ODM_CUT_A) + return; + + /* A-cut */ + reg82c = odm_get_bb_reg(dm, 0x82c, MASKDWORD); + + if (bandwidth == ODM_BW20M) { + /* 82c[15:12] = 4 */ + /* 82c[27:24] = 6 */ + + reg82c &= (~(0x0f00f000)); + reg82c |= ((0x4) << 12); + reg82c |= ((0x6) << 24); + } else if (bandwidth == ODM_BW40M) { + /* 82c[19:16] = 9 */ + /* 82c[27:24] = 6 */ + + reg82c &= (~(0x0f0f0000)); + reg82c |= ((0x9) << 16); + reg82c |= ((0x6) << 24); + } else if (bandwidth == ODM_BW80M) { + /* 82c[15:12] 7 */ + /* 82c[19:16] b */ + /* 82c[23:20] d */ + /* 82c[27:24] 3 */ + + reg82c &= (~(0x0ffff000)); + reg82c |= ((0xdb7) << 12); + reg82c |= ((0x3) << 24); + } + + odm_set_bb_reg(dm, 0x82c, MASKDWORD, reg82c); + ODM_RT_TRACE(dm, ODM_PHY_CONFIG, + "%s(): Update CCA parameters for Acut\n", __func__); +} + +static void phydm_ccapar_by_rxpath_8822b(struct phy_dm_struct *dm) +{ + if (dm->cut_version != ODM_CUT_A) + return; + + if ((dm->rx_ant_status == ODM_RF_A) || + (dm->rx_ant_status == ODM_RF_B)) { + /* 838[7:4] = 8 */ + /* 838[11:8] = 7 */ + /* 838[15:12] = 6 */ + /* 838[19:16] = 7 */ + /* 838[23:20] = 7 */ + /* 838[27:24] = 7 */ + odm_set_bb_reg(dm, 0x838, 0x0ffffff0, 0x777678); + } else { + /* 838[7:4] = 3 */ + /* 838[11:8] = 3 */ + /* 838[15:12] = 6 */ + /* 838[19:16] = 6 */ + /* 838[23:20] = 7 */ + /* 838[27:24] = 7 */ + odm_set_bb_reg(dm, 0x838, 0x0ffffff0, 0x776633); + } + ODM_RT_TRACE(dm, ODM_PHY_CONFIG, + "%s(): Update CCA parameters for Acut\n", __func__); +} + +static void phydm_rxdfirpar_by_bw_8822b(struct phy_dm_struct *dm, + enum odm_bw bandwidth) +{ + if (bandwidth == ODM_BW40M) { + /* RX DFIR for BW40 */ + odm_set_bb_reg(dm, 0x948, BIT(29) | BIT(28), 0x1); + odm_set_bb_reg(dm, 0x94c, BIT(29) | BIT(28), 0x0); + odm_set_bb_reg(dm, 0xc20, BIT(31), 0x0); + odm_set_bb_reg(dm, 0xe20, BIT(31), 0x0); + } else if (bandwidth == ODM_BW80M) { + /* RX DFIR for BW80 */ + odm_set_bb_reg(dm, 0x948, BIT(29) | BIT(28), 0x2); + odm_set_bb_reg(dm, 0x94c, BIT(29) | BIT(28), 0x1); + odm_set_bb_reg(dm, 0xc20, BIT(31), 0x0); + odm_set_bb_reg(dm, 0xe20, BIT(31), 0x0); + } else { + /* RX DFIR for BW20, BW10 and BW5*/ + odm_set_bb_reg(dm, 0x948, BIT(29) | BIT(28), 0x2); + odm_set_bb_reg(dm, 0x94c, BIT(29) | BIT(28), 0x2); + odm_set_bb_reg(dm, 0xc20, BIT(31), 0x1); + odm_set_bb_reg(dm, 0xe20, BIT(31), 0x1); + } +} + +bool phydm_write_txagc_1byte_8822b(struct phy_dm_struct *dm, u32 power_index, + enum odm_rf_radio_path path, u8 hw_rate) +{ + u32 offset_txagc[2] = {0x1d00, 0x1d80}; + u8 rate_idx = (hw_rate & 0xfc), i; + u8 rate_offset = (hw_rate & 0x3); + u32 txagc_content = 0x0; + + /* For debug command only!!!! */ + + /* Error handling */ + if ((path > ODM_RF_PATH_B) || (hw_rate > 0x53)) { + ODM_RT_TRACE(dm, ODM_PHY_CONFIG, + "%s(): unsupported path (%d)\n", __func__, path); + return false; + } + + /* For HW limitation, We can't write TXAGC once a byte. */ + for (i = 0; i < 4; i++) { + if (i != rate_offset) + txagc_content = + txagc_content | (config_phydm_read_txagc_8822b( + dm, path, rate_idx + i) + << (i << 3)); + else + txagc_content = txagc_content | + ((power_index & 0x3f) << (i << 3)); + } + odm_set_bb_reg(dm, (offset_txagc[path] + rate_idx), MASKDWORD, + txagc_content); + + ODM_RT_TRACE(dm, ODM_PHY_CONFIG, + "%s(): path-%d rate index 0x%x (0x%x) = 0x%x\n", __func__, + path, hw_rate, (offset_txagc[path] + hw_rate), + power_index); + return true; +} + +void phydm_init_hw_info_by_rfe_type_8822b(struct phy_dm_struct *dm) +{ + u16 mask_path_a = 0x0303; + u16 mask_path_b = 0x0c0c; + /*u16 mask_path_c = 0x3030;*/ + /*u16 mask_path_d = 0xc0c0;*/ + + dm->is_init_hw_info_by_rfe = false; + + if ((dm->rfe_type == 1) || (dm->rfe_type == 6) || (dm->rfe_type == 7)) { + odm_cmn_info_init(dm, ODM_CMNINFO_BOARD_TYPE, + (ODM_BOARD_EXT_LNA | ODM_BOARD_EXT_LNA_5G | + ODM_BOARD_EXT_PA | ODM_BOARD_EXT_PA_5G)); + + if (dm->rfe_type == 6) { + odm_cmn_info_init( + dm, ODM_CMNINFO_GPA, + (TYPE_GPA1 & (mask_path_a | mask_path_b))); + odm_cmn_info_init( + dm, ODM_CMNINFO_APA, + (TYPE_APA1 & (mask_path_a | mask_path_b))); + odm_cmn_info_init( + dm, ODM_CMNINFO_GLNA, + (TYPE_GLNA1 & (mask_path_a | mask_path_b))); + odm_cmn_info_init( + dm, ODM_CMNINFO_ALNA, + (TYPE_ALNA1 & (mask_path_a | mask_path_b))); + } else if (dm->rfe_type == 7) { + odm_cmn_info_init( + dm, ODM_CMNINFO_GPA, + (TYPE_GPA2 & (mask_path_a | mask_path_b))); + odm_cmn_info_init( + dm, ODM_CMNINFO_APA, + (TYPE_APA2 & (mask_path_a | mask_path_b))); + odm_cmn_info_init( + dm, ODM_CMNINFO_GLNA, + (TYPE_GLNA2 & (mask_path_a | mask_path_b))); + odm_cmn_info_init( + dm, ODM_CMNINFO_ALNA, + (TYPE_ALNA2 & (mask_path_a | mask_path_b))); + } else { + odm_cmn_info_init( + dm, ODM_CMNINFO_GPA, + (TYPE_GPA0 & (mask_path_a | mask_path_b))); + odm_cmn_info_init( + dm, ODM_CMNINFO_APA, + (TYPE_APA0 & (mask_path_a | mask_path_b))); + odm_cmn_info_init( + dm, ODM_CMNINFO_GLNA, + (TYPE_GLNA0 & (mask_path_a | mask_path_b))); + odm_cmn_info_init( + dm, ODM_CMNINFO_ALNA, + (TYPE_ALNA0 & (mask_path_a | mask_path_b))); + } + + odm_cmn_info_init(dm, ODM_CMNINFO_PACKAGE_TYPE, 1); + + odm_cmn_info_init(dm, ODM_CMNINFO_EXT_LNA, true); + odm_cmn_info_init(dm, ODM_CMNINFO_5G_EXT_LNA, true); + odm_cmn_info_init(dm, ODM_CMNINFO_EXT_PA, true); + odm_cmn_info_init(dm, ODM_CMNINFO_5G_EXT_PA, true); + } else if (dm->rfe_type == 2) { + odm_cmn_info_init(dm, ODM_CMNINFO_BOARD_TYPE, + (ODM_BOARD_EXT_LNA_5G | ODM_BOARD_EXT_PA_5G)); + odm_cmn_info_init(dm, ODM_CMNINFO_APA, + (TYPE_APA0 & (mask_path_a | mask_path_b))); + odm_cmn_info_init(dm, ODM_CMNINFO_ALNA, + (TYPE_ALNA0 & (mask_path_a | mask_path_b))); + + odm_cmn_info_init(dm, ODM_CMNINFO_PACKAGE_TYPE, 2); + + odm_cmn_info_init(dm, ODM_CMNINFO_EXT_LNA, false); + odm_cmn_info_init(dm, ODM_CMNINFO_5G_EXT_LNA, true); + odm_cmn_info_init(dm, ODM_CMNINFO_EXT_PA, false); + odm_cmn_info_init(dm, ODM_CMNINFO_5G_EXT_PA, true); + } else if (dm->rfe_type == 9) { + odm_cmn_info_init(dm, ODM_CMNINFO_BOARD_TYPE, + (ODM_BOARD_EXT_LNA_5G)); + odm_cmn_info_init(dm, ODM_CMNINFO_ALNA, + (TYPE_ALNA0 & (mask_path_a | mask_path_b))); + + odm_cmn_info_init(dm, ODM_CMNINFO_PACKAGE_TYPE, 1); + + odm_cmn_info_init(dm, ODM_CMNINFO_EXT_LNA, false); + odm_cmn_info_init(dm, ODM_CMNINFO_5G_EXT_LNA, true); + odm_cmn_info_init(dm, ODM_CMNINFO_EXT_PA, false); + odm_cmn_info_init(dm, ODM_CMNINFO_5G_EXT_PA, false); + } else if ((dm->rfe_type == 3) || (dm->rfe_type == 5)) { + /* RFE type 3: 8822BS\8822BU TFBGA iFEM */ + /* RFE type 5: 8822BE TFBGA iFEM */ + odm_cmn_info_init(dm, ODM_CMNINFO_BOARD_TYPE, 0); + + odm_cmn_info_init(dm, ODM_CMNINFO_PACKAGE_TYPE, 2); + + odm_cmn_info_init(dm, ODM_CMNINFO_EXT_LNA, false); + odm_cmn_info_init(dm, ODM_CMNINFO_5G_EXT_LNA, false); + odm_cmn_info_init(dm, ODM_CMNINFO_EXT_PA, false); + odm_cmn_info_init(dm, ODM_CMNINFO_5G_EXT_PA, false); + } else if (dm->rfe_type == 4) { + odm_cmn_info_init(dm, ODM_CMNINFO_BOARD_TYPE, + (ODM_BOARD_EXT_LNA | ODM_BOARD_EXT_LNA_5G | + ODM_BOARD_EXT_PA | ODM_BOARD_EXT_PA_5G)); + odm_cmn_info_init(dm, ODM_CMNINFO_GPA, + (TYPE_GPA0 & (mask_path_a | mask_path_b))); + odm_cmn_info_init(dm, ODM_CMNINFO_APA, + (TYPE_APA0 & (mask_path_a | mask_path_b))); + odm_cmn_info_init(dm, ODM_CMNINFO_GLNA, + (TYPE_GLNA0 & (mask_path_a | mask_path_b))); + odm_cmn_info_init(dm, ODM_CMNINFO_ALNA, + (TYPE_ALNA0 & (mask_path_a | mask_path_b))); + + odm_cmn_info_init(dm, ODM_CMNINFO_PACKAGE_TYPE, 2); + + odm_cmn_info_init(dm, ODM_CMNINFO_EXT_LNA, true); + odm_cmn_info_init(dm, ODM_CMNINFO_5G_EXT_LNA, true); + odm_cmn_info_init(dm, ODM_CMNINFO_EXT_PA, true); + odm_cmn_info_init(dm, ODM_CMNINFO_5G_EXT_PA, true); + } else if (dm->rfe_type == 8) { + /* RFE type 8: TFBGA iFEM AP */ + odm_cmn_info_init(dm, ODM_CMNINFO_BOARD_TYPE, 0); + + odm_cmn_info_init(dm, ODM_CMNINFO_PACKAGE_TYPE, 2); + + odm_cmn_info_init(dm, ODM_CMNINFO_EXT_LNA, false); + odm_cmn_info_init(dm, ODM_CMNINFO_5G_EXT_LNA, false); + odm_cmn_info_init(dm, ODM_CMNINFO_EXT_PA, false); + odm_cmn_info_init(dm, ODM_CMNINFO_5G_EXT_PA, false); + } else { + /* RFE Type 0 & 9 & 10: QFN iFEM */ + odm_cmn_info_init(dm, ODM_CMNINFO_BOARD_TYPE, 0); + + odm_cmn_info_init(dm, ODM_CMNINFO_PACKAGE_TYPE, 1); + + odm_cmn_info_init(dm, ODM_CMNINFO_EXT_LNA, false); + odm_cmn_info_init(dm, ODM_CMNINFO_5G_EXT_LNA, false); + odm_cmn_info_init(dm, ODM_CMNINFO_EXT_PA, false); + odm_cmn_info_init(dm, ODM_CMNINFO_5G_EXT_PA, false); + } + + dm->is_init_hw_info_by_rfe = true; + + ODM_RT_TRACE( + dm, ODM_PHY_CONFIG, + "%s(): RFE type (%d), Board type (0x%x), Package type (%d)\n", + __func__, dm->rfe_type, dm->board_type, dm->package_type); + ODM_RT_TRACE( + dm, ODM_PHY_CONFIG, + "%s(): 5G ePA (%d), 5G eLNA (%d), 2G ePA (%d), 2G eLNA (%d)\n", + __func__, dm->ext_pa_5g, dm->ext_lna_5g, dm->ext_pa, + dm->ext_lna); + ODM_RT_TRACE( + dm, ODM_PHY_CONFIG, + "%s(): 5G PA type (%d), 5G LNA type (%d), 2G PA type (%d), 2G LNA type (%d)\n", + __func__, dm->type_apa, dm->type_alna, dm->type_gpa, + dm->type_glna); +} + +s32 phydm_get_condition_number_8822B(struct phy_dm_struct *dm) +{ + s32 ret_val; + + odm_set_bb_reg(dm, 0x1988, BIT(22), 0x1); + ret_val = + (s32)odm_get_bb_reg(dm, 0xf84, (BIT(17) | BIT(16) | MASKLWORD)); + + if (bw_8822b == 0) { + ret_val = ret_val << (8 - 4); + ret_val = ret_val / 234; + } else if (bw_8822b == 1) { + ret_val = ret_val << (7 - 4); + ret_val = ret_val / 108; + } else if (bw_8822b == 2) { + ret_val = ret_val << (6 - 4); + ret_val = ret_val / 52; + } + + return ret_val; +} + +/* ======================================================================== */ + +/* ======================================================================== */ +/* These following functions can be used by driver*/ + +u32 config_phydm_read_rf_reg_8822b(struct phy_dm_struct *dm, + enum odm_rf_radio_path rf_path, u32 reg_addr, + u32 bit_mask) +{ + u32 readback_value, direct_addr; + u32 offset_read_rf[2] = {0x2800, 0x2c00}; + u32 power_RF[2] = {0x1c, 0xec}; + + /* Error handling.*/ + if (rf_path > ODM_RF_PATH_B) { + ODM_RT_TRACE(dm, ODM_PHY_CONFIG, + "%s(): unsupported path (%d)\n", __func__, + rf_path); + return INVALID_RF_DATA; + } + + /* Error handling. Check if RF power is enable or not */ + /* 0xffffffff means RF power is disable */ + if (odm_get_mac_reg(dm, power_RF[rf_path], MASKBYTE3) != 0x7) { + ODM_RT_TRACE(dm, ODM_PHY_CONFIG, + "%s(): Read fail, RF is disabled\n", __func__); + return INVALID_RF_DATA; + } + + /* Calculate offset */ + reg_addr &= 0xff; + direct_addr = offset_read_rf[rf_path] + (reg_addr << 2); + + /* RF register only has 20bits */ + bit_mask &= RFREGOFFSETMASK; + + /* Read RF register directly */ + readback_value = odm_get_bb_reg(dm, direct_addr, bit_mask); + ODM_RT_TRACE(dm, ODM_PHY_CONFIG, + "%s(): RF-%d 0x%x = 0x%x, bit mask = 0x%x\n", __func__, + rf_path, reg_addr, readback_value, bit_mask); + return readback_value; +} + +bool config_phydm_write_rf_reg_8822b(struct phy_dm_struct *dm, + enum odm_rf_radio_path rf_path, + u32 reg_addr, u32 bit_mask, u32 data) +{ + u32 data_and_addr = 0, data_original = 0; + u32 offset_write_rf[2] = {0xc90, 0xe90}; + u32 power_RF[2] = {0x1c, 0xec}; + + /* Error handling.*/ + if (rf_path > ODM_RF_PATH_B) { + ODM_RT_TRACE(dm, ODM_PHY_CONFIG, + "%s(): unsupported path (%d)\n", __func__, + rf_path); + return false; + } + + /* Read RF register content first */ + reg_addr &= 0xff; + bit_mask = bit_mask & RFREGOFFSETMASK; + + if (bit_mask != RFREGOFFSETMASK) { + data_original = config_phydm_read_rf_reg_8822b( + dm, rf_path, reg_addr, RFREGOFFSETMASK); + + /* Error handling. RF is disabled */ + if (!config_phydm_read_rf_check_8822b(data_original)) { + ODM_RT_TRACE(dm, ODM_PHY_CONFIG, + "%s(): Write fail, RF is disable\n", + __func__); + return false; + } + + /* check bit mask */ + data = phydm_check_bit_mask(bit_mask, data_original, data); + } else if (odm_get_mac_reg(dm, power_RF[rf_path], MASKBYTE3) != 0x7) { + ODM_RT_TRACE(dm, ODM_PHY_CONFIG, + "%s(): Write fail, RF is disabled\n", __func__); + return false; + } + + /* Put write addr in [27:20] and write data in [19:00] */ + data_and_addr = ((reg_addr << 20) | (data & 0x000fffff)) & 0x0fffffff; + + /* Write operation */ + odm_set_bb_reg(dm, offset_write_rf[rf_path], MASKDWORD, data_and_addr); + ODM_RT_TRACE( + dm, ODM_PHY_CONFIG, + "%s(): RF-%d 0x%x = 0x%x (original: 0x%x), bit mask = 0x%x\n", + __func__, rf_path, reg_addr, data, data_original, bit_mask); + return true; +} + +bool config_phydm_write_txagc_8822b(struct phy_dm_struct *dm, u32 power_index, + enum odm_rf_radio_path path, u8 hw_rate) +{ + u32 offset_txagc[2] = {0x1d00, 0x1d80}; + u8 rate_idx = (hw_rate & 0xfc); + + /* Input need to be HW rate index, not driver rate index!!!! */ + + if (dm->is_disable_phy_api) { + ODM_RT_TRACE(dm, ODM_PHY_CONFIG, + "%s(): disable PHY API for debug!!\n", __func__); + return true; + } + + /* Error handling */ + if ((path > ODM_RF_PATH_B) || (hw_rate > 0x53)) { + ODM_RT_TRACE(dm, ODM_PHY_CONFIG, + "%s(): unsupported path (%d)\n", __func__, path); + return false; + } + + /* driver need to construct a 4-byte power index */ + odm_set_bb_reg(dm, (offset_txagc[path] + rate_idx), MASKDWORD, + power_index); + + ODM_RT_TRACE(dm, ODM_PHY_CONFIG, + "%s(): path-%d rate index 0x%x (0x%x) = 0x%x\n", __func__, + path, hw_rate, (offset_txagc[path] + hw_rate), + power_index); + return true; +} + +u8 config_phydm_read_txagc_8822b(struct phy_dm_struct *dm, + enum odm_rf_radio_path path, u8 hw_rate) +{ + u8 read_back_data; + + /* Input need to be HW rate index, not driver rate index!!!! */ + + /* Error handling */ + if ((path > ODM_RF_PATH_B) || (hw_rate > 0x53)) { + ODM_RT_TRACE(dm, ODM_PHY_CONFIG, + "%s(): unsupported path (%d)\n", __func__, path); + return INVALID_TXAGC_DATA; + } + + /* Disable TX AGC report */ + odm_set_bb_reg(dm, 0x1998, BIT(16), 0x0); /* need to check */ + + /* Set data rate index (bit0~6) and path index (bit7) */ + odm_set_bb_reg(dm, 0x1998, MASKBYTE0, (hw_rate | (path << 7))); + + /* Enable TXAGC report */ + odm_set_bb_reg(dm, 0x1998, BIT(16), 0x1); + + /* Read TX AGC report */ + read_back_data = (u8)odm_get_bb_reg(dm, 0xd30, 0x7f0000); + + /* Driver have to disable TXAGC report after reading TXAGC + * (ref. user guide v11) + */ + odm_set_bb_reg(dm, 0x1998, BIT(16), 0x0); + + ODM_RT_TRACE(dm, ODM_PHY_CONFIG, + "%s(): path-%d rate index 0x%x = 0x%x\n", __func__, path, + hw_rate, read_back_data); + return read_back_data; +} + +bool config_phydm_switch_band_8822b(struct phy_dm_struct *dm, u8 central_ch) +{ + u32 rf_reg18; + bool rf_reg_status = true; + + ODM_RT_TRACE(dm, ODM_PHY_CONFIG, "%s()======================>\n", + __func__); + + if (dm->is_disable_phy_api) { + ODM_RT_TRACE(dm, ODM_PHY_CONFIG, + "%s(): disable PHY API for debug!!\n", __func__); + return true; + } + + rf_reg18 = config_phydm_read_rf_reg_8822b(dm, ODM_RF_PATH_A, 0x18, + RFREGOFFSETMASK); + rf_reg_status = + rf_reg_status & config_phydm_read_rf_check_8822b(rf_reg18); + + if (central_ch <= 14) { + /* 2.4G */ + + /* Enable CCK block */ + odm_set_bb_reg(dm, 0x808, BIT(28), 0x1); + + /* Disable MAC CCK check */ + odm_set_bb_reg(dm, 0x454, BIT(7), 0x0); + + /* Disable BB CCK check */ + odm_set_bb_reg(dm, 0xa80, BIT(18), 0x0); + + /*CCA Mask*/ + odm_set_bb_reg(dm, 0x814, 0x0000FC00, 15); /*default value*/ + + /* RF band */ + rf_reg18 = (rf_reg18 & (~(BIT(16) | BIT(9) | BIT(8)))); + + /* RxHP dynamic control */ + if ((dm->rfe_type == 2) || (dm->rfe_type == 3) || + (dm->rfe_type == 5)) { + odm_set_bb_reg(dm, 0x8cc, MASKDWORD, 0x08108492); + odm_set_bb_reg(dm, 0x8d8, MASKDWORD, 0x29095612); + } + + } else if (central_ch > 35) { + /* 5G */ + + /* Enable BB CCK check */ + odm_set_bb_reg(dm, 0xa80, BIT(18), 0x1); + + /* Enable CCK check */ + odm_set_bb_reg(dm, 0x454, BIT(7), 0x1); + + /* Disable CCK block */ + odm_set_bb_reg(dm, 0x808, BIT(28), 0x0); + + /*CCA Mask*/ + odm_set_bb_reg(dm, 0x814, 0x0000FC00, 15); /*default value*/ + + /* RF band */ + rf_reg18 = (rf_reg18 & (~(BIT(16) | BIT(9) | BIT(8)))); + rf_reg18 = (rf_reg18 | BIT(8) | BIT(16)); + + /* RxHP dynamic control */ + if ((dm->rfe_type == 2) || (dm->rfe_type == 3) || + (dm->rfe_type == 5)) { + odm_set_bb_reg(dm, 0x8cc, MASKDWORD, 0x08100000); + odm_set_bb_reg(dm, 0x8d8, MASKDWORD, 0x21095612); + } + + } else { + ODM_RT_TRACE(dm, ODM_PHY_CONFIG, + "%s(): Fail to switch band (ch: %d)\n", __func__, + central_ch); + return false; + } + + rf_reg_status = rf_reg_status & config_phydm_write_rf_reg_8822b( + dm, ODM_RF_PATH_A, 0x18, + RFREGOFFSETMASK, rf_reg18); + + if (dm->rf_type > ODM_1T1R) + rf_reg_status = + rf_reg_status & config_phydm_write_rf_reg_8822b( + dm, ODM_RF_PATH_B, 0x18, + RFREGOFFSETMASK, rf_reg18); + + if (!phydm_rfe_8822b(dm, central_ch)) + return false; + + if (!rf_reg_status) { + ODM_RT_TRACE( + dm, ODM_PHY_CONFIG, + "%s(): Fail to switch band (ch: %d), because writing RF register is fail\n", + __func__, central_ch); + return false; + } + + ODM_RT_TRACE(dm, ODM_PHY_CONFIG, + "%s(): Success to switch band (ch: %d)\n", __func__, + central_ch); + return true; +} + +bool config_phydm_switch_channel_8822b(struct phy_dm_struct *dm, u8 central_ch) +{ + struct dig_thres *dig_tab = &dm->dm_dig_table; + u32 rf_reg18 = 0, rf_reg_b8 = 0, rf_reg_be = 0xff; + bool rf_reg_status = true; + u8 low_band[15] = {0x7, 0x6, 0x6, 0x5, 0x0, 0x0, 0x7, 0xff, + 0x6, 0x5, 0x0, 0x0, 0x7, 0x6, 0x6}; + u8 middle_band[23] = {0x6, 0x5, 0x0, 0x0, 0x7, 0x6, 0x6, 0xff, + 0x0, 0x0, 0x7, 0x6, 0x6, 0x5, 0x0, 0xff, + 0x7, 0x6, 0x6, 0x5, 0x0, 0x0, 0x7}; + u8 high_band[15] = {0x5, 0x5, 0x0, 0x7, 0x7, 0x6, 0x5, 0xff, + 0x0, 0x7, 0x7, 0x6, 0x5, 0x5, 0x0}; + + ODM_RT_TRACE(dm, ODM_PHY_CONFIG, "%s()====================>\n", + __func__); + + if (dm->is_disable_phy_api) { + ODM_RT_TRACE(dm, ODM_PHY_CONFIG, + "%s(): disable PHY API for debug!!\n", __func__); + return true; + } + + central_ch_8822b = central_ch; + rf_reg18 = config_phydm_read_rf_reg_8822b(dm, ODM_RF_PATH_A, 0x18, + RFREGOFFSETMASK); + rf_reg_status = + rf_reg_status & config_phydm_read_rf_check_8822b(rf_reg18); + rf_reg18 = (rf_reg18 & (~(BIT(18) | BIT(17) | MASKBYTE0))); + + if (dm->cut_version == ODM_CUT_A) { + rf_reg_b8 = config_phydm_read_rf_reg_8822b( + dm, ODM_RF_PATH_A, 0xb8, RFREGOFFSETMASK); + rf_reg_status = rf_reg_status & + config_phydm_read_rf_check_8822b(rf_reg_b8); + } + + /* Switch band and channel */ + if (central_ch <= 14) { + /* 2.4G */ + + /* 1. RF band and channel*/ + rf_reg18 = (rf_reg18 | central_ch); + + /* 2. AGC table selection */ + odm_set_bb_reg(dm, 0x958, 0x1f, 0x0); + dig_tab->agc_table_idx = 0x0; + + /* 3. Set central frequency for clock offset tracking */ + odm_set_bb_reg(dm, 0x860, 0x1ffe0000, 0x96a); + + /* Fix A-cut LCK fail issue @ 5285MHz~5375MHz, 0xb8[19]=0x0 */ + if (dm->cut_version == ODM_CUT_A) + rf_reg_b8 = rf_reg_b8 | BIT(19); + + /* CCK TX filter parameters */ + if (central_ch == 14) { + odm_set_bb_reg(dm, 0xa20, MASKHWORD, 0x8488); + odm_set_bb_reg(dm, 0xa24, MASKDWORD, 0x00006577); + odm_set_bb_reg(dm, 0xa28, MASKLWORD, 0x0000); + } else { + odm_set_bb_reg(dm, 0xa20, MASKHWORD, + (rega20_8822b >> 16)); + odm_set_bb_reg(dm, 0xa24, MASKDWORD, rega24_8822b); + odm_set_bb_reg(dm, 0xa28, MASKLWORD, + (rega28_8822b & MASKLWORD)); + } + + } else if (central_ch > 35) { + /* 5G */ + + /* 1. RF band and channel*/ + rf_reg18 = (rf_reg18 | central_ch); + + /* 2. AGC table selection */ + if ((central_ch >= 36) && (central_ch <= 64)) { + odm_set_bb_reg(dm, 0x958, 0x1f, 0x1); + dig_tab->agc_table_idx = 0x1; + } else if ((central_ch >= 100) && (central_ch <= 144)) { + odm_set_bb_reg(dm, 0x958, 0x1f, 0x2); + dig_tab->agc_table_idx = 0x2; + } else if (central_ch >= 149) { + odm_set_bb_reg(dm, 0x958, 0x1f, 0x3); + dig_tab->agc_table_idx = 0x3; + } else { + ODM_RT_TRACE( + dm, ODM_PHY_CONFIG, + "%s(): Fail to switch channel (AGC) (ch: %d)\n", + __func__, central_ch); + return false; + } + + /* 3. Set central frequency for clock offset tracking */ + if ((central_ch >= 36) && (central_ch <= 48)) { + odm_set_bb_reg(dm, 0x860, 0x1ffe0000, 0x494); + } else if ((central_ch >= 52) && (central_ch <= 64)) { + odm_set_bb_reg(dm, 0x860, 0x1ffe0000, 0x453); + } else if ((central_ch >= 100) && (central_ch <= 116)) { + odm_set_bb_reg(dm, 0x860, 0x1ffe0000, 0x452); + } else if ((central_ch >= 118) && (central_ch <= 177)) { + odm_set_bb_reg(dm, 0x860, 0x1ffe0000, 0x412); + } else { + ODM_RT_TRACE( + dm, ODM_PHY_CONFIG, + "%s(): Fail to switch channel (fc_area) (ch: %d)\n", + __func__, central_ch); + return false; + } + + /* Fix A-cut LCK fail issue @ 5285MHz~5375MHz, 0xb8[19]=0x0 */ + if (dm->cut_version == ODM_CUT_A) { + if ((central_ch >= 57) && (central_ch <= 75)) + rf_reg_b8 = rf_reg_b8 & (~BIT(19)); + else + rf_reg_b8 = rf_reg_b8 | BIT(19); + } + } else { + ODM_RT_TRACE(dm, ODM_PHY_CONFIG, + "%s(): Fail to switch channel (ch: %d)\n", + __func__, central_ch); + return false; + } + + /* Modify IGI for MP driver to aviod PCIE interference */ + if (dm->mp_mode && ((dm->rfe_type == 3) || (dm->rfe_type == 5))) { + if (central_ch == 14) + odm_write_dig(dm, 0x26); + else + odm_write_dig(dm, 0x20); + } + + /* Modify the setting of register 0xBE to reduce phase noise */ + if (central_ch <= 14) + rf_reg_be = 0x0; + else if ((central_ch >= 36) && (central_ch <= 64)) + rf_reg_be = low_band[(central_ch - 36) >> 1]; + else if ((central_ch >= 100) && (central_ch <= 144)) + rf_reg_be = middle_band[(central_ch - 100) >> 1]; + else if ((central_ch >= 149) && (central_ch <= 177)) + rf_reg_be = high_band[(central_ch - 149) >> 1]; + else + rf_reg_be = 0xff; + + if (rf_reg_be != 0xff) { + rf_reg_status = + rf_reg_status & config_phydm_write_rf_reg_8822b( + dm, ODM_RF_PATH_A, 0xbe, + (BIT(17) | BIT(16) | BIT(15)), + rf_reg_be); + } else { + ODM_RT_TRACE( + dm, ODM_PHY_CONFIG, + "%s(): Fail to switch channel (ch: %d, Phase noise)\n", + __func__, central_ch); + return false; + } + + /* Fix channel 144 issue, ask by RFSI Alvin*/ + /* 00 when freq < 5400; 01 when 5400<=freq<=5720; 10 when freq > 5720; + * 2G don't care + */ + /* need to set 0xdf[18]=1 before writing RF18 when channel 144 */ + if (central_ch == 144) { + rf_reg_status = rf_reg_status & + config_phydm_write_rf_reg_8822b( + dm, ODM_RF_PATH_A, 0xdf, BIT(18), 0x1); + rf_reg18 = (rf_reg18 | BIT(17)); + } else { + rf_reg_status = rf_reg_status & + config_phydm_write_rf_reg_8822b( + dm, ODM_RF_PATH_A, 0xdf, BIT(18), 0x0); + + if (central_ch > 144) + rf_reg18 = (rf_reg18 | BIT(18)); + else if (central_ch >= 80) + rf_reg18 = (rf_reg18 | BIT(17)); + } + + rf_reg_status = rf_reg_status & config_phydm_write_rf_reg_8822b( + dm, ODM_RF_PATH_A, 0x18, + RFREGOFFSETMASK, rf_reg18); + + if (dm->cut_version == ODM_CUT_A) + rf_reg_status = + rf_reg_status & config_phydm_write_rf_reg_8822b( + dm, ODM_RF_PATH_A, 0xb8, + RFREGOFFSETMASK, rf_reg_b8); + + if (dm->rf_type > ODM_1T1R) { + rf_reg_status = + rf_reg_status & config_phydm_write_rf_reg_8822b( + dm, ODM_RF_PATH_B, 0x18, + RFREGOFFSETMASK, rf_reg18); + + if (dm->cut_version == ODM_CUT_A) + rf_reg_status = rf_reg_status & + config_phydm_write_rf_reg_8822b( + dm, ODM_RF_PATH_B, 0xb8, + RFREGOFFSETMASK, rf_reg_b8); + } + + if (!rf_reg_status) { + ODM_RT_TRACE( + dm, ODM_PHY_CONFIG, + "%s(): Fail to switch channel (ch: %d), because writing RF register is fail\n", + __func__, central_ch); + return false; + } + + phydm_ccapar_by_rfe_8822b(dm); + ODM_RT_TRACE(dm, ODM_PHY_CONFIG, + "%s(): Success to switch channel (ch: %d)\n", __func__, + central_ch); + return true; +} + +bool config_phydm_switch_bandwidth_8822b(struct phy_dm_struct *dm, + u8 primary_ch_idx, + enum odm_bw bandwidth) +{ + u32 rf_reg18; + bool rf_reg_status = true; + u8 IGI = 0; + + ODM_RT_TRACE(dm, ODM_PHY_CONFIG, "%s()===================>\n", + __func__); + + if (dm->is_disable_phy_api) { + ODM_RT_TRACE(dm, ODM_PHY_CONFIG, + "%s(): disable PHY API for debug!!\n", __func__); + return true; + } + + /* Error handling */ + if ((bandwidth >= ODM_BW_MAX) || + ((bandwidth == ODM_BW40M) && (primary_ch_idx > 2)) || + ((bandwidth == ODM_BW80M) && (primary_ch_idx > 4))) { + ODM_RT_TRACE( + dm, ODM_PHY_CONFIG, + "%s(): Fail to switch bandwidth (bw: %d, primary ch: %d)\n", + __func__, bandwidth, primary_ch_idx); + return false; + } + + bw_8822b = bandwidth; + rf_reg18 = config_phydm_read_rf_reg_8822b(dm, ODM_RF_PATH_A, 0x18, + RFREGOFFSETMASK); + rf_reg_status = + rf_reg_status & config_phydm_read_rf_check_8822b(rf_reg18); + + /* Switch bandwidth */ + switch (bandwidth) { + case ODM_BW20M: { + /* Small BW([7:6]) = 0, primary channel ([5:2]) = 0, + * rf mode([1:0]) = 20M + */ + odm_set_bb_reg(dm, 0x8ac, MASKBYTE0, ODM_BW20M); + + /* ADC clock = 160M clock for BW20 */ + odm_set_bb_reg(dm, 0x8ac, (BIT(9) | BIT(8)), 0x0); + odm_set_bb_reg(dm, 0x8ac, BIT(16), 0x1); + + /* DAC clock = 160M clock for BW20 */ + odm_set_bb_reg(dm, 0x8ac, (BIT(21) | BIT(20)), 0x0); + odm_set_bb_reg(dm, 0x8ac, BIT(28), 0x1); + + /* ADC buffer clock */ + odm_set_bb_reg(dm, 0x8c4, BIT(30), 0x1); + + /* RF bandwidth */ + rf_reg18 = (rf_reg18 | BIT(11) | BIT(10)); + + break; + } + case ODM_BW40M: { + /* Small BW([7:6]) = 0, primary channel ([5:2]) = sub-channel, + * rf mode([1:0]) = 40M + */ + odm_set_bb_reg(dm, 0x8ac, MASKBYTE0, + (((primary_ch_idx & 0xf) << 2) | ODM_BW40M)); + + /* CCK primary channel */ + if (primary_ch_idx == 1) + odm_set_bb_reg(dm, 0xa00, BIT(4), primary_ch_idx); + else + odm_set_bb_reg(dm, 0xa00, BIT(4), 0); + + /* ADC clock = 160M clock for BW40 */ + odm_set_bb_reg(dm, 0x8ac, (BIT(11) | BIT(10)), 0x0); + odm_set_bb_reg(dm, 0x8ac, BIT(17), 0x1); + + /* DAC clock = 160M clock for BW20 */ + odm_set_bb_reg(dm, 0x8ac, (BIT(23) | BIT(22)), 0x0); + odm_set_bb_reg(dm, 0x8ac, BIT(29), 0x1); + + /* ADC buffer clock */ + odm_set_bb_reg(dm, 0x8c4, BIT(30), 0x1); + + /* RF bandwidth */ + rf_reg18 = (rf_reg18 & (~(BIT(11) | BIT(10)))); + rf_reg18 = (rf_reg18 | BIT(11)); + + break; + } + case ODM_BW80M: { + /* Small BW([7:6]) = 0, primary channel ([5:2]) = sub-channel, + * rf mode([1:0]) = 80M + */ + odm_set_bb_reg(dm, 0x8ac, MASKBYTE0, + (((primary_ch_idx & 0xf) << 2) | ODM_BW80M)); + + /* ADC clock = 160M clock for BW80 */ + odm_set_bb_reg(dm, 0x8ac, (BIT(13) | BIT(12)), 0x0); + odm_set_bb_reg(dm, 0x8ac, BIT(18), 0x1); + + /* DAC clock = 160M clock for BW20 */ + odm_set_bb_reg(dm, 0x8ac, (BIT(25) | BIT(24)), 0x0); + odm_set_bb_reg(dm, 0x8ac, BIT(30), 0x1); + + /* ADC buffer clock */ + odm_set_bb_reg(dm, 0x8c4, BIT(30), 0x1); + + /* RF bandwidth */ + rf_reg18 = (rf_reg18 & (~(BIT(11) | BIT(10)))); + rf_reg18 = (rf_reg18 | BIT(10)); + + break; + } + case ODM_BW5M: { + /* Small BW([7:6]) = 1, primary channel ([5:2]) = 0, + * rf mode([1:0]) = 20M + */ + odm_set_bb_reg(dm, 0x8ac, MASKBYTE0, (BIT(6) | ODM_BW20M)); + + /* ADC clock = 40M clock */ + odm_set_bb_reg(dm, 0x8ac, (BIT(9) | BIT(8)), 0x2); + odm_set_bb_reg(dm, 0x8ac, BIT(16), 0x0); + + /* DAC clock = 160M clock for BW20 */ + odm_set_bb_reg(dm, 0x8ac, (BIT(21) | BIT(20)), 0x2); + odm_set_bb_reg(dm, 0x8ac, BIT(28), 0x0); + + /* ADC buffer clock */ + odm_set_bb_reg(dm, 0x8c4, BIT(30), 0x0); + odm_set_bb_reg(dm, 0x8c8, BIT(31), 0x1); + + /* RF bandwidth */ + rf_reg18 = (rf_reg18 | BIT(11) | BIT(10)); + + break; + } + case ODM_BW10M: { + /* Small BW([7:6]) = 1, primary channel ([5:2]) = 0, + * rf mode([1:0]) = 20M + */ + odm_set_bb_reg(dm, 0x8ac, MASKBYTE0, (BIT(7) | ODM_BW20M)); + + /* ADC clock = 80M clock */ + odm_set_bb_reg(dm, 0x8ac, (BIT(9) | BIT(8)), 0x3); + odm_set_bb_reg(dm, 0x8ac, BIT(16), 0x0); + + /* DAC clock = 160M clock for BW20 */ + odm_set_bb_reg(dm, 0x8ac, (BIT(21) | BIT(20)), 0x3); + odm_set_bb_reg(dm, 0x8ac, BIT(28), 0x0); + + /* ADC buffer clock */ + odm_set_bb_reg(dm, 0x8c4, BIT(30), 0x0); + odm_set_bb_reg(dm, 0x8c8, BIT(31), 0x1); + + /* RF bandwidth */ + rf_reg18 = (rf_reg18 | BIT(11) | BIT(10)); + + break; + } + default: + ODM_RT_TRACE( + dm, ODM_PHY_CONFIG, + "%s(): Fail to switch bandwidth (bw: %d, primary ch: %d)\n", + __func__, bandwidth, primary_ch_idx); + } + + /* Write RF register */ + rf_reg_status = rf_reg_status & config_phydm_write_rf_reg_8822b( + dm, ODM_RF_PATH_A, 0x18, + RFREGOFFSETMASK, rf_reg18); + + if (dm->rf_type > ODM_1T1R) + rf_reg_status = + rf_reg_status & config_phydm_write_rf_reg_8822b( + dm, ODM_RF_PATH_B, 0x18, + RFREGOFFSETMASK, rf_reg18); + + if (!rf_reg_status) { + ODM_RT_TRACE( + dm, ODM_PHY_CONFIG, + "%s(): Fail to switch bandwidth (bw: %d, primary ch: %d), because writing RF register is fail\n", + __func__, bandwidth, primary_ch_idx); + return false; + } + + /* Modify RX DFIR parameters */ + phydm_rxdfirpar_by_bw_8822b(dm, bandwidth); + + /* Modify CCA parameters */ + phydm_ccapar_by_bw_8822b(dm, bandwidth); + phydm_ccapar_by_rfe_8822b(dm); + + /* Toggle RX path to avoid RX dead zone issue */ + odm_set_bb_reg(dm, 0x808, MASKBYTE0, 0x0); + odm_set_bb_reg(dm, 0x808, MASKBYTE0, + (dm->rx_ant_status | (dm->rx_ant_status << 4))); + + /* Toggle IGI to let RF enter RX mode */ + IGI = (u8)odm_get_bb_reg(dm, ODM_REG(IGI_A, dm), ODM_BIT(IGI, dm)); + odm_set_bb_reg(dm, ODM_REG(IGI_A, dm), ODM_BIT(IGI, dm), IGI - 2); + odm_set_bb_reg(dm, ODM_REG(IGI_B, dm), ODM_BIT(IGI, dm), IGI - 2); + odm_set_bb_reg(dm, ODM_REG(IGI_A, dm), ODM_BIT(IGI, dm), IGI); + odm_set_bb_reg(dm, ODM_REG(IGI_B, dm), ODM_BIT(IGI, dm), IGI); + + ODM_RT_TRACE( + dm, ODM_PHY_CONFIG, + "%s(): Success to switch bandwidth (bw: %d, primary ch: %d)\n", + __func__, bandwidth, primary_ch_idx); + return true; +} + +bool config_phydm_switch_channel_bw_8822b(struct phy_dm_struct *dm, + u8 central_ch, u8 primary_ch_idx, + enum odm_bw bandwidth) +{ + /* Switch band */ + if (!config_phydm_switch_band_8822b(dm, central_ch)) + return false; + + /* Switch channel */ + if (!config_phydm_switch_channel_8822b(dm, central_ch)) + return false; + + /* Switch bandwidth */ + if (!config_phydm_switch_bandwidth_8822b(dm, primary_ch_idx, bandwidth)) + return false; + + return true; +} + +bool config_phydm_trx_mode_8822b(struct phy_dm_struct *dm, + enum odm_rf_path tx_path, + enum odm_rf_path rx_path, bool is_tx2_path) +{ + bool rf_reg_status = true; + u8 IGI; + u32 rf_reg33 = 0; + u16 counter = 0; + + ODM_RT_TRACE(dm, ODM_PHY_CONFIG, "%s()=====================>\n", + __func__); + + if (dm->is_disable_phy_api) { + ODM_RT_TRACE(dm, ODM_PHY_CONFIG, + "%s(): disable PHY API for debug!!\n", __func__); + return true; + } + + if ((tx_path & (~(ODM_RF_A | ODM_RF_B))) != 0) { + ODM_RT_TRACE(dm, ODM_PHY_CONFIG, + "%s(): Wrong TX setting (TX: 0x%x)\n", __func__, + tx_path); + return false; + } + + if ((rx_path & (~(ODM_RF_A | ODM_RF_B))) != 0) { + ODM_RT_TRACE(dm, ODM_PHY_CONFIG, + "%s(): Wrong RX setting (RX: 0x%x)\n", __func__, + rx_path); + return false; + } + + /* RF mode of path-A and path-B */ + /* Cannot shut down path-A, beacause synthesizer will be shut down when + * path-A is in shut down mode + */ + if ((tx_path | rx_path) & ODM_RF_A) + odm_set_bb_reg(dm, 0xc08, MASKLWORD, 0x3231); + else + odm_set_bb_reg(dm, 0xc08, MASKLWORD, 0x1111); + + if ((tx_path | rx_path) & ODM_RF_B) + odm_set_bb_reg(dm, 0xe08, MASKLWORD, 0x3231); + else + odm_set_bb_reg(dm, 0xe08, MASKLWORD, 0x1111); + + /* Set TX antenna by Nsts */ + odm_set_bb_reg(dm, 0x93c, (BIT(19) | BIT(18)), 0x3); + odm_set_bb_reg(dm, 0x80c, (BIT(29) | BIT(28)), 0x1); + + /* Control CCK TX path by 0xa07[7] */ + odm_set_bb_reg(dm, 0x80c, BIT(30), 0x1); + + /* TX logic map and TX path en for Nsts = 1, and CCK TX path*/ + if (tx_path & ODM_RF_A) { + odm_set_bb_reg(dm, 0x93c, 0xfff00000, 0x001); + odm_set_bb_reg(dm, 0xa04, 0xf0000000, 0x8); + } else if (tx_path & ODM_RF_B) { + odm_set_bb_reg(dm, 0x93c, 0xfff00000, 0x002); + odm_set_bb_reg(dm, 0xa04, 0xf0000000, 0x4); + } + + /* TX logic map and TX path en for Nsts = 2*/ + if ((tx_path == ODM_RF_A) || (tx_path == ODM_RF_B)) + odm_set_bb_reg(dm, 0x940, 0xfff0, 0x01); + else + odm_set_bb_reg(dm, 0x940, 0xfff0, 0x43); + + /* TX path enable */ + odm_set_bb_reg(dm, 0x80c, MASKBYTE0, ((tx_path << 4) | tx_path)); + + /* Tx2path for 1ss */ + if (!((tx_path == ODM_RF_A) || (tx_path == ODM_RF_B))) { + if (is_tx2_path || dm->mp_mode) { + /* 2Tx for OFDM */ + odm_set_bb_reg(dm, 0x93c, 0xfff00000, 0x043); + + /* 2Tx for CCK */ + odm_set_bb_reg(dm, 0xa04, 0xf0000000, 0xc); + } + } + + /* Always disable MRC for CCK CCA */ + odm_set_bb_reg(dm, 0xa2c, BIT(22), 0x0); + + /* Always disable MRC for CCK barker */ + odm_set_bb_reg(dm, 0xa2c, BIT(18), 0x0); + + /* CCK RX 1st and 2nd path setting*/ + if (rx_path & ODM_RF_A) + odm_set_bb_reg(dm, 0xa04, 0x0f000000, 0x0); + else if (rx_path & ODM_RF_B) + odm_set_bb_reg(dm, 0xa04, 0x0f000000, 0x5); + + /* RX path enable */ + odm_set_bb_reg(dm, 0x808, MASKBYTE0, ((rx_path << 4) | rx_path)); + + if ((rx_path == ODM_RF_A) || (rx_path == ODM_RF_B)) { + /* 1R */ + + /* Disable MRC for CCA */ + /* odm_set_bb_reg(dm, 0xa2c, BIT22, 0x0); */ + + /* Disable MRC for barker */ + /* odm_set_bb_reg(dm, 0xa2c, BIT18, 0x0); */ + + /* Disable CCK antenna diversity */ + /* odm_set_bb_reg(dm, 0xa00, BIT15, 0x0); */ + + /* Disable Antenna weighting */ + odm_set_bb_reg(dm, 0x1904, BIT(16), 0x0); + odm_set_bb_reg(dm, 0x800, BIT(28), 0x0); + odm_set_bb_reg(dm, 0x850, BIT(23), 0x0); + } else { + /* 2R */ + + /* Enable MRC for CCA */ + /* odm_set_bb_reg(dm, 0xa2c, BIT22, 0x1); */ + + /* Enable MRC for barker */ + /* odm_set_bb_reg(dm, 0xa2c, BIT18, 0x1); */ + + /* Disable CCK antenna diversity */ + /* odm_set_bb_reg(dm, 0xa00, BIT15, 0x0); */ + + /* Enable Antenna weighting */ + odm_set_bb_reg(dm, 0x1904, BIT(16), 0x1); + odm_set_bb_reg(dm, 0x800, BIT(28), 0x1); + odm_set_bb_reg(dm, 0x850, BIT(23), 0x1); + } + + /* Update TXRX antenna status for PHYDM */ + dm->tx_ant_status = (tx_path & 0x3); + dm->rx_ant_status = (rx_path & 0x3); + + /* MP driver need to support path-B TX\RX */ + + while (1) { + counter++; + rf_reg_status = + rf_reg_status & config_phydm_write_rf_reg_8822b( + dm, ODM_RF_PATH_A, 0xef, + RFREGOFFSETMASK, 0x80000); + rf_reg_status = + rf_reg_status & config_phydm_write_rf_reg_8822b( + dm, ODM_RF_PATH_A, 0x33, + RFREGOFFSETMASK, 0x00001); + + ODM_delay_us(2); + rf_reg33 = config_phydm_read_rf_reg_8822b( + dm, ODM_RF_PATH_A, 0x33, RFREGOFFSETMASK); + + if ((rf_reg33 == 0x00001) && + (config_phydm_read_rf_check_8822b(rf_reg33))) + break; + else if (counter == 100) { + ODM_RT_TRACE( + dm, ODM_PHY_CONFIG, + "%s(): Fail to set TRx mode setting, because writing RF mode table is fail\n", + __func__); + return false; + } + } + + if ((dm->mp_mode) || *dm->antenna_test || (dm->normal_rx_path)) { + /* 0xef 0x80000 0x33 0x00001 0x3e 0x00034 0x3f 0x4080e + * 0xef 0x00000 suggested by Lucas + */ + rf_reg_status = + rf_reg_status & config_phydm_write_rf_reg_8822b( + dm, ODM_RF_PATH_A, 0xef, + RFREGOFFSETMASK, 0x80000); + rf_reg_status = + rf_reg_status & config_phydm_write_rf_reg_8822b( + dm, ODM_RF_PATH_A, 0x33, + RFREGOFFSETMASK, 0x00001); + rf_reg_status = + rf_reg_status & config_phydm_write_rf_reg_8822b( + dm, ODM_RF_PATH_A, 0x3e, + RFREGOFFSETMASK, 0x00034); + rf_reg_status = + rf_reg_status & config_phydm_write_rf_reg_8822b( + dm, ODM_RF_PATH_A, 0x3f, + RFREGOFFSETMASK, 0x4080e); + rf_reg_status = + rf_reg_status & config_phydm_write_rf_reg_8822b( + dm, ODM_RF_PATH_A, 0xef, + RFREGOFFSETMASK, 0x00000); + ODM_RT_TRACE( + dm, ODM_PHY_CONFIG, + "%s(): MP mode or Antenna test mode!! support path-B TX and RX\n", + __func__); + } else { + /* 0xef 0x80000 0x33 0x00001 0x3e 0x00034 0x3f 0x4080c + * 0xef 0x00000 + */ + rf_reg_status = + rf_reg_status & config_phydm_write_rf_reg_8822b( + dm, ODM_RF_PATH_A, 0xef, + RFREGOFFSETMASK, 0x80000); + rf_reg_status = + rf_reg_status & config_phydm_write_rf_reg_8822b( + dm, ODM_RF_PATH_A, 0x33, + RFREGOFFSETMASK, 0x00001); + rf_reg_status = + rf_reg_status & config_phydm_write_rf_reg_8822b( + dm, ODM_RF_PATH_A, 0x3e, + RFREGOFFSETMASK, 0x00034); + rf_reg_status = + rf_reg_status & config_phydm_write_rf_reg_8822b( + dm, ODM_RF_PATH_A, 0x3f, + RFREGOFFSETMASK, 0x4080c); + rf_reg_status = + rf_reg_status & config_phydm_write_rf_reg_8822b( + dm, ODM_RF_PATH_A, 0xef, + RFREGOFFSETMASK, 0x00000); + ODM_RT_TRACE( + dm, ODM_PHY_CONFIG, + "%s(): Normal mode!! Do not support path-B TX and RX\n", + __func__); + } + + rf_reg_status = rf_reg_status & config_phydm_write_rf_reg_8822b( + dm, ODM_RF_PATH_A, 0xef, + RFREGOFFSETMASK, 0x00000); + + if (!rf_reg_status) { + ODM_RT_TRACE( + dm, ODM_PHY_CONFIG, + "%s(): Fail to set TRx mode setting (TX: 0x%x, RX: 0x%x), because writing RF register is fail\n", + __func__, tx_path, rx_path); + return false; + } + + /* Toggle IGI to let RF enter RX mode, + * because BB doesn't send 3-wire command when RX path is enable + */ + IGI = (u8)odm_get_bb_reg(dm, ODM_REG(IGI_A, dm), ODM_BIT(IGI, dm)); + odm_write_dig(dm, IGI - 2); + odm_write_dig(dm, IGI); + + /* Modify CCA parameters */ + phydm_ccapar_by_rxpath_8822b(dm); + phydm_ccapar_by_rfe_8822b(dm); + phydm_rfe_8822b(dm, central_ch_8822b); + + ODM_RT_TRACE( + dm, ODM_PHY_CONFIG, + "%s(): Success to set TRx mode setting (TX: 0x%x, RX: 0x%x)\n", + __func__, tx_path, rx_path); + return true; +} + +bool config_phydm_parameter_init(struct phy_dm_struct *dm, + enum odm_parameter_init type) +{ + if (type == ODM_PRE_SETTING) { + odm_set_bb_reg(dm, 0x808, (BIT(28) | BIT(29)), 0x0); + ODM_RT_TRACE(dm, ODM_PHY_CONFIG, + "%s(): Pre setting: disable OFDM and CCK block\n", + __func__); + } else if (type == ODM_POST_SETTING) { + odm_set_bb_reg(dm, 0x808, (BIT(28) | BIT(29)), 0x3); + ODM_RT_TRACE(dm, ODM_PHY_CONFIG, + "%s(): Post setting: enable OFDM and CCK block\n", + __func__); + reg82c_8822b = odm_get_bb_reg(dm, 0x82c, MASKDWORD); + reg838_8822b = odm_get_bb_reg(dm, 0x838, MASKDWORD); + reg830_8822b = odm_get_bb_reg(dm, 0x830, MASKDWORD); + reg83c_8822b = odm_get_bb_reg(dm, 0x83c, MASKDWORD); + rega20_8822b = odm_get_bb_reg(dm, 0xa20, MASKDWORD); + rega24_8822b = odm_get_bb_reg(dm, 0xa24, MASKDWORD); + rega28_8822b = odm_get_bb_reg(dm, 0xa28, MASKDWORD); + } else { + ODM_RT_TRACE(dm, ODM_PHY_CONFIG, "%s(): Wrong type!!\n", + __func__); + return false; + } + + return true; +} + +/* ======================================================================== */ diff --git a/drivers/staging/rtlwifi/phydm/rtl8822b/phydm_hal_api8822b.h b/drivers/staging/rtlwifi/phydm/rtl8822b/phydm_hal_api8822b.h new file mode 100644 index 000000000000..279ef06298e2 --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/rtl8822b/phydm_hal_api8822b.h @@ -0,0 +1,84 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef __INC_PHYDM_API_H_8822B__ +#define __INC_PHYDM_API_H_8822B__ + +/*2016.08.01 (HW user guide version: R27, SW user guide version: R05, + * Modification: R31) + */ +#define PHY_CONFIG_VERSION_8822B "27.5.31" + +#define INVALID_RF_DATA 0xffffffff +#define INVALID_TXAGC_DATA 0xff + +#define config_phydm_read_rf_check_8822b(data) (data != INVALID_RF_DATA) +#define config_phydm_read_txagc_check_8822b(data) (data != INVALID_TXAGC_DATA) + +u32 config_phydm_read_rf_reg_8822b(struct phy_dm_struct *dm, + enum odm_rf_radio_path rf_path, u32 reg_addr, + u32 bit_mask); + +bool config_phydm_write_rf_reg_8822b(struct phy_dm_struct *dm, + enum odm_rf_radio_path rf_path, + u32 reg_addr, u32 bit_mask, u32 data); + +bool config_phydm_write_txagc_8822b(struct phy_dm_struct *dm, u32 power_index, + enum odm_rf_radio_path path, u8 hw_rate); + +u8 config_phydm_read_txagc_8822b(struct phy_dm_struct *dm, + enum odm_rf_radio_path path, u8 hw_rate); + +bool config_phydm_switch_band_8822b(struct phy_dm_struct *dm, u8 central_ch); + +bool config_phydm_switch_channel_8822b(struct phy_dm_struct *dm, u8 central_ch); + +bool config_phydm_switch_bandwidth_8822b(struct phy_dm_struct *dm, + u8 primary_ch_idx, + enum odm_bw bandwidth); + +bool config_phydm_switch_channel_bw_8822b(struct phy_dm_struct *dm, + u8 central_ch, u8 primary_ch_idx, + enum odm_bw bandwidth); + +bool config_phydm_trx_mode_8822b(struct phy_dm_struct *dm, + enum odm_rf_path tx_path, + enum odm_rf_path rx_path, bool is_tx2_path); + +bool config_phydm_parameter_init(struct phy_dm_struct *dm, + enum odm_parameter_init type); + +/* ======================================================================== */ +/* These following functions can be used for PHY DM only*/ + +bool phydm_write_txagc_1byte_8822b(struct phy_dm_struct *dm, u32 power_index, + enum odm_rf_radio_path path, u8 hw_rate); + +void phydm_init_hw_info_by_rfe_type_8822b(struct phy_dm_struct *dm); + +s32 phydm_get_condition_number_8822B(struct phy_dm_struct *dm); + +/* ======================================================================== */ + +#endif /* __INC_PHYDM_API_H_8822B__ */ diff --git a/drivers/staging/rtlwifi/phydm/rtl8822b/phydm_iqk_8822b.c b/drivers/staging/rtlwifi/phydm/rtl8822b/phydm_iqk_8822b.c new file mode 100644 index 000000000000..d320311213cc --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/rtl8822b/phydm_iqk_8822b.c @@ -0,0 +1,1410 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include "../mp_precomp.h" +#include "../phydm_precomp.h" + +/*---------------------------Define Local Constant---------------------------*/ + +static bool _iqk_rx_iqk_by_path_8822b(void *, u8); + +static inline void phydm_set_iqk_info(struct phy_dm_struct *dm, + struct dm_iqk_info *iqk_info, u8 status) +{ + bool KFAIL = true; + + while (1) { + KFAIL = _iqk_rx_iqk_by_path_8822b(dm, ODM_RF_PATH_A); + if (status == 0) + ODM_RT_TRACE(dm, ODM_COMP_CALIBRATION, + "[IQK]S0RXK KFail = 0x%x\n", KFAIL); + else if (status == 1) + ODM_RT_TRACE(dm, ODM_COMP_CALIBRATION, + "[IQK]S1RXK KFail = 0x%x\n", KFAIL); + if (iqk_info->rxiqk_step == 5) { + dm->rf_calibrate_info.iqk_step++; + iqk_info->rxiqk_step = 1; + if (KFAIL && status == 0) + ODM_RT_TRACE(dm, ODM_COMP_CALIBRATION, + "[IQK]S0RXK fail code: %d!!!\n", + iqk_info->rxiqk_fail_code + [0][ODM_RF_PATH_A]); + else if (KFAIL && status == 1) + ODM_RT_TRACE(dm, ODM_COMP_CALIBRATION, + "[IQK]S1RXK fail code: %d!!!\n", + iqk_info->rxiqk_fail_code + [0][ODM_RF_PATH_A]); + break; + } + } + + iqk_info->kcount++; +} + +static inline void phydm_init_iqk_information(struct dm_iqk_info *iqk_info) +{ + u8 i, j, k, m; + + for (i = 0; i < 2; i++) { + iqk_info->iqk_channel[i] = 0x0; + + for (j = 0; j < SS_8822B; j++) { + iqk_info->lok_idac[i][j] = 0x0; + iqk_info->rxiqk_agc[i][j] = 0x0; + iqk_info->bypass_iqk[i][j] = 0x0; + + for (k = 0; k < 2; k++) { + iqk_info->iqk_fail_report[i][j][k] = true; + for (m = 0; m < 8; m++) { + iqk_info->iqk_cfir_real[i][j][k][m] = + 0x0; + iqk_info->iqk_cfir_imag[i][j][k][m] = + 0x0; + } + } + + for (k = 0; k < 3; k++) + iqk_info->retry_count[i][j][k] = 0x0; + } + } +} + +static inline void phydm_backup_iqk_information(struct dm_iqk_info *iqk_info) +{ + u8 i, j, k; + + iqk_info->iqk_channel[1] = iqk_info->iqk_channel[0]; + for (i = 0; i < 2; i++) { + iqk_info->lok_idac[1][i] = iqk_info->lok_idac[0][i]; + iqk_info->rxiqk_agc[1][i] = iqk_info->rxiqk_agc[0][i]; + iqk_info->bypass_iqk[1][i] = iqk_info->bypass_iqk[0][i]; + iqk_info->rxiqk_fail_code[1][i] = + iqk_info->rxiqk_fail_code[0][i]; + for (j = 0; j < 2; j++) { + iqk_info->iqk_fail_report[1][i][j] = + iqk_info->iqk_fail_report[0][i][j]; + for (k = 0; k < 8; k++) { + iqk_info->iqk_cfir_real[1][i][j][k] = + iqk_info->iqk_cfir_real[0][i][j][k]; + iqk_info->iqk_cfir_imag[1][i][j][k] = + iqk_info->iqk_cfir_imag[0][i][j][k]; + } + } + } + + for (i = 0; i < 4; i++) { + iqk_info->rxiqk_fail_code[0][i] = 0x0; + iqk_info->rxiqk_agc[0][i] = 0x0; + for (j = 0; j < 2; j++) { + iqk_info->iqk_fail_report[0][i][j] = true; + iqk_info->gs_retry_count[0][i][j] = 0x0; + } + for (j = 0; j < 3; j++) + iqk_info->retry_count[0][i][j] = 0x0; + } +} + +static inline void phydm_set_iqk_cfir(struct phy_dm_struct *dm, + struct dm_iqk_info *iqk_info, u8 path) +{ + u8 idx, i; + u32 tmp; + + for (idx = 0; idx < 2; idx++) { + odm_set_bb_reg(dm, 0x1b00, MASKDWORD, 0xf8000008 | path << 1); + + if (idx == 0) + odm_set_bb_reg(dm, 0x1b0c, BIT(13) | BIT(12), 0x3); + else + odm_set_bb_reg(dm, 0x1b0c, BIT(13) | BIT(12), 0x1); + + odm_set_bb_reg(dm, 0x1bd4, + BIT(20) | BIT(19) | BIT(18) | BIT(17) | BIT(16), + 0x10); + + for (i = 0; i < 8; i++) { + odm_set_bb_reg(dm, 0x1bd8, MASKDWORD, + 0xe0000001 + (i * 4)); + tmp = odm_get_bb_reg(dm, 0x1bfc, MASKDWORD); + iqk_info->iqk_cfir_real[0][path][idx][i] = + (tmp & 0x0fff0000) >> 16; + iqk_info->iqk_cfir_imag[0][path][idx][i] = tmp & 0xfff; + } + } +} + +static inline void phydm_get_read_counter(struct phy_dm_struct *dm) +{ + u32 counter = 0x0; + + while (1) { + if (((odm_read_4byte(dm, 0x1bf0) >> 24) == 0x7f) || + (counter > 300)) + break; + + counter++; + ODM_delay_ms(1); + } + + ODM_RT_TRACE(dm, ODM_COMP_CALIBRATION, "[IQK]counter = %d\n", counter); +} + +/*---------------------------Define Local Constant---------------------------*/ + +void do_iqk_8822b(void *dm_void, u8 delta_thermal_index, u8 thermal_value, + u8 threshold) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + + odm_reset_iqk_result(dm); + + dm->rf_calibrate_info.thermal_value_iqk = thermal_value; + + phy_iq_calibrate_8822b(dm, true); +} + +static void _iqk_fill_iqk_report_8822b(void *dm_void, u8 channel) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct dm_iqk_info *iqk_info = &dm->IQK_info; + u32 tmp1 = 0x0, tmp2 = 0x0, tmp3 = 0x0; + u8 i; + + for (i = 0; i < SS_8822B; i++) { + tmp1 = tmp1 + + ((iqk_info->iqk_fail_report[channel][i][TX_IQK] & 0x1) + << i); + tmp2 = tmp2 + + ((iqk_info->iqk_fail_report[channel][i][RX_IQK] & 0x1) + << (i + 4)); + tmp3 = tmp3 + ((iqk_info->rxiqk_fail_code[channel][i] & 0x3) + << (i * 2 + 8)); + } + odm_write_4byte(dm, 0x1b00, 0xf8000008); + odm_set_bb_reg(dm, 0x1bf0, 0x0000ffff, tmp1 | tmp2 | tmp3); + + for (i = 0; i < 2; i++) + odm_write_4byte( + dm, 0x1be8 + (i * 4), + (iqk_info->rxiqk_agc[channel][(i * 2) + 1] << 16) | + iqk_info->rxiqk_agc[channel][i * 2]); +} + +static void _iqk_backup_mac_bb_8822b(struct phy_dm_struct *dm, u32 *MAC_backup, + u32 *BB_backup, u32 *backup_mac_reg, + u32 *backup_bb_reg) +{ + u32 i; + + for (i = 0; i < MAC_REG_NUM_8822B; i++) + MAC_backup[i] = odm_read_4byte(dm, backup_mac_reg[i]); + + for (i = 0; i < BB_REG_NUM_8822B; i++) + BB_backup[i] = odm_read_4byte(dm, backup_bb_reg[i]); +} + +static void _iqk_backup_rf_8822b(struct phy_dm_struct *dm, u32 RF_backup[][2], + u32 *backup_rf_reg) +{ + u32 i; + + for (i = 0; i < RF_REG_NUM_8822B; i++) { + RF_backup[i][ODM_RF_PATH_A] = odm_get_rf_reg( + dm, ODM_RF_PATH_A, backup_rf_reg[i], RFREGOFFSETMASK); + RF_backup[i][ODM_RF_PATH_B] = odm_get_rf_reg( + dm, ODM_RF_PATH_B, backup_rf_reg[i], RFREGOFFSETMASK); + } +} + +static void _iqk_agc_bnd_int_8822b(struct phy_dm_struct *dm) +{ + /*initialize RX AGC bnd, it must do after bbreset*/ + odm_write_4byte(dm, 0x1b00, 0xf8000008); + odm_write_4byte(dm, 0x1b00, 0xf80a7008); + odm_write_4byte(dm, 0x1b00, 0xf8015008); + odm_write_4byte(dm, 0x1b00, 0xf8000008); +} + +static void _iqk_bb_reset_8822b(struct phy_dm_struct *dm) +{ + bool cca_ing = false; + u32 count = 0; + + odm_set_rf_reg(dm, ODM_RF_PATH_A, 0x0, RFREGOFFSETMASK, 0x10000); + odm_set_rf_reg(dm, ODM_RF_PATH_B, 0x0, RFREGOFFSETMASK, 0x10000); + + while (1) { + odm_write_4byte(dm, 0x8fc, 0x0); + odm_set_bb_reg(dm, 0x198c, 0x7, 0x7); + cca_ing = (bool)odm_get_bb_reg(dm, 0xfa0, BIT(3)); + + if (count > 30) + cca_ing = false; + + if (cca_ing) { + ODM_delay_ms(1); + count++; + } else { + odm_write_1byte(dm, 0x808, 0x0); /*RX ant off*/ + odm_set_bb_reg(dm, 0xa04, + BIT(27) | BIT(26) | BIT(25) | BIT(24), + 0x0); /*CCK RX path off*/ + + /*BBreset*/ + odm_set_bb_reg(dm, 0x0, BIT(16), 0x0); + odm_set_bb_reg(dm, 0x0, BIT(16), 0x1); + + if (odm_get_bb_reg(dm, 0x660, BIT(16))) + odm_write_4byte(dm, 0x6b4, 0x89000006); + break; + } + } +} + +static void _iqk_afe_setting_8822b(struct phy_dm_struct *dm, bool do_iqk) +{ + if (do_iqk) { + odm_write_4byte(dm, 0xc60, 0x50000000); + odm_write_4byte(dm, 0xc60, 0x70070040); + odm_write_4byte(dm, 0xe60, 0x50000000); + odm_write_4byte(dm, 0xe60, 0x70070040); + + odm_write_4byte(dm, 0xc58, 0xd8000402); + odm_write_4byte(dm, 0xc5c, 0xd1000120); + odm_write_4byte(dm, 0xc6c, 0x00000a15); + odm_write_4byte(dm, 0xe58, 0xd8000402); + odm_write_4byte(dm, 0xe5c, 0xd1000120); + odm_write_4byte(dm, 0xe6c, 0x00000a15); + _iqk_bb_reset_8822b(dm); + } else { + odm_write_4byte(dm, 0xc60, 0x50000000); + odm_write_4byte(dm, 0xc60, 0x70038040); + odm_write_4byte(dm, 0xe60, 0x50000000); + odm_write_4byte(dm, 0xe60, 0x70038040); + + odm_write_4byte(dm, 0xc58, 0xd8020402); + odm_write_4byte(dm, 0xc5c, 0xde000120); + odm_write_4byte(dm, 0xc6c, 0x0000122a); + odm_write_4byte(dm, 0xe58, 0xd8020402); + odm_write_4byte(dm, 0xe5c, 0xde000120); + odm_write_4byte(dm, 0xe6c, 0x0000122a); + } +} + +static void _iqk_restore_mac_bb_8822b(struct phy_dm_struct *dm, u32 *MAC_backup, + u32 *BB_backup, u32 *backup_mac_reg, + u32 *backup_bb_reg) +{ + u32 i; + + for (i = 0; i < MAC_REG_NUM_8822B; i++) + odm_write_4byte(dm, backup_mac_reg[i], MAC_backup[i]); + for (i = 0; i < BB_REG_NUM_8822B; i++) + odm_write_4byte(dm, backup_bb_reg[i], BB_backup[i]); +} + +static void _iqk_restore_rf_8822b(struct phy_dm_struct *dm, u32 *backup_rf_reg, + u32 RF_backup[][2]) +{ + u32 i; + + odm_set_rf_reg(dm, ODM_RF_PATH_A, 0xef, RFREGOFFSETMASK, 0x0); + odm_set_rf_reg(dm, ODM_RF_PATH_B, 0xef, RFREGOFFSETMASK, 0x0); + /*0xdf[4]=0*/ + odm_set_rf_reg(dm, ODM_RF_PATH_A, 0xdf, RFREGOFFSETMASK, + RF_backup[0][ODM_RF_PATH_A] & (~BIT(4))); + odm_set_rf_reg(dm, ODM_RF_PATH_B, 0xdf, RFREGOFFSETMASK, + RF_backup[0][ODM_RF_PATH_B] & (~BIT(4))); + + for (i = 1; i < RF_REG_NUM_8822B; i++) { + odm_set_rf_reg(dm, ODM_RF_PATH_A, backup_rf_reg[i], + RFREGOFFSETMASK, RF_backup[i][ODM_RF_PATH_A]); + odm_set_rf_reg(dm, ODM_RF_PATH_B, backup_rf_reg[i], + RFREGOFFSETMASK, RF_backup[i][ODM_RF_PATH_B]); + } +} + +static void _iqk_backup_iqk_8822b(struct phy_dm_struct *dm, u8 step) +{ + struct dm_iqk_info *iqk_info = &dm->IQK_info; + u8 path; + u16 iqk_apply[2] = {0xc94, 0xe94}; + + if (step == 0x0) { + phydm_backup_iqk_information(iqk_info); + } else { + iqk_info->iqk_channel[0] = iqk_info->rf_reg18; + for (path = 0; path < 2; path++) { + iqk_info->lok_idac[0][path] = + odm_get_rf_reg(dm, (enum odm_rf_radio_path)path, + 0x58, RFREGOFFSETMASK); + iqk_info->bypass_iqk[0][path] = + odm_get_bb_reg(dm, iqk_apply[path], MASKDWORD); + + phydm_set_iqk_cfir(dm, iqk_info, path); + odm_set_bb_reg(dm, 0x1bd8, MASKDWORD, 0x0); + odm_set_bb_reg(dm, 0x1b0c, BIT(13) | BIT(12), 0x0); + } + } +} + +static void _iqk_reload_iqk_setting_8822b( + struct phy_dm_struct *dm, u8 channel, + u8 reload_idx /*1: reload TX, 2: reload LO, TX, RX*/ + ) +{ + struct dm_iqk_info *iqk_info = &dm->IQK_info; + u8 i, path, idx; + u16 iqk_apply[2] = {0xc94, 0xe94}; + + for (path = 0; path < 2; path++) { + if (reload_idx == 2) { + odm_set_rf_reg(dm, (enum odm_rf_radio_path)path, 0xdf, + BIT(4), 0x1); + odm_set_rf_reg(dm, (enum odm_rf_radio_path)path, 0x58, + RFREGOFFSETMASK, + iqk_info->lok_idac[channel][path]); + } + + for (idx = 0; idx < reload_idx; idx++) { + odm_set_bb_reg(dm, 0x1b00, MASKDWORD, + 0xf8000008 | path << 1); + odm_set_bb_reg(dm, 0x1b2c, MASKDWORD, 0x7); + odm_set_bb_reg(dm, 0x1b38, MASKDWORD, 0x20000000); + odm_set_bb_reg(dm, 0x1b3c, MASKDWORD, 0x20000000); + odm_set_bb_reg(dm, 0x1bcc, MASKDWORD, 0x00000000); + + if (idx == 0) + odm_set_bb_reg(dm, 0x1b0c, BIT(13) | BIT(12), + 0x3); + else + odm_set_bb_reg(dm, 0x1b0c, BIT(13) | BIT(12), + 0x1); + + odm_set_bb_reg(dm, 0x1bd4, BIT(20) | BIT(19) | BIT(18) | + BIT(17) | BIT(16), + 0x10); + + for (i = 0; i < 8; i++) { + odm_write_4byte( + dm, 0x1bd8, + ((0xc0000000 >> idx) + 0x3) + (i * 4) + + (iqk_info->iqk_cfir_real + [channel][path][idx][i] + << 9)); + odm_write_4byte( + dm, 0x1bd8, + ((0xc0000000 >> idx) + 0x1) + (i * 4) + + (iqk_info->iqk_cfir_imag + [channel][path][idx][i] + << 9)); + } + } + odm_set_bb_reg(dm, iqk_apply[path], MASKDWORD, + iqk_info->bypass_iqk[channel][path]); + + odm_set_bb_reg(dm, 0x1bd8, MASKDWORD, 0x0); + odm_set_bb_reg(dm, 0x1b0c, BIT(13) | BIT(12), 0x0); + } +} + +static bool _iqk_reload_iqk_8822b(struct phy_dm_struct *dm, bool reset) +{ + struct dm_iqk_info *iqk_info = &dm->IQK_info; + u8 i; + bool reload = false; + + if (reset) { + for (i = 0; i < 2; i++) + iqk_info->iqk_channel[i] = 0x0; + } else { + iqk_info->rf_reg18 = odm_get_rf_reg(dm, ODM_RF_PATH_A, 0x18, + RFREGOFFSETMASK); + + for (i = 0; i < 2; i++) { + if (iqk_info->rf_reg18 == iqk_info->iqk_channel[i]) { + _iqk_reload_iqk_setting_8822b(dm, i, 2); + _iqk_fill_iqk_report_8822b(dm, i); + ODM_RT_TRACE( + dm, ODM_COMP_CALIBRATION, + "[IQK]reload IQK result before!!!!\n"); + reload = true; + } + } + } + return reload; +} + +static void _iqk_rfe_setting_8822b(struct phy_dm_struct *dm, bool ext_pa_on) +{ + if (ext_pa_on) { + /*RFE setting*/ + odm_write_4byte(dm, 0xcb0, 0x77777777); + odm_write_4byte(dm, 0xcb4, 0x00007777); + odm_write_4byte(dm, 0xcbc, 0x0000083B); + odm_write_4byte(dm, 0xeb0, 0x77777777); + odm_write_4byte(dm, 0xeb4, 0x00007777); + odm_write_4byte(dm, 0xebc, 0x0000083B); + ODM_RT_TRACE(dm, ODM_COMP_CALIBRATION, + "[IQK]external PA on!!!!\n"); + } else { + /*RFE setting*/ + odm_write_4byte(dm, 0xcb0, 0x77777777); + odm_write_4byte(dm, 0xcb4, 0x00007777); + odm_write_4byte(dm, 0xcbc, 0x00000100); + odm_write_4byte(dm, 0xeb0, 0x77777777); + odm_write_4byte(dm, 0xeb4, 0x00007777); + odm_write_4byte(dm, 0xebc, 0x00000100); + } +} + +static void _iqk_rf_setting_8822b(struct phy_dm_struct *dm) +{ + u8 path; + u32 tmp; + + odm_write_4byte(dm, 0x1b00, 0xf8000008); + odm_write_4byte(dm, 0x1bb8, 0x00000000); + + for (path = 0; path < 2; path++) { + /*0xdf:B11 = 1,B4 = 0, B1 = 1*/ + tmp = odm_get_rf_reg(dm, (enum odm_rf_radio_path)path, 0xdf, + RFREGOFFSETMASK); + tmp = (tmp & (~BIT(4))) | BIT(1) | BIT(11); + odm_set_rf_reg(dm, (enum odm_rf_radio_path)path, 0xdf, + RFREGOFFSETMASK, tmp); + + /*release 0x56 TXBB*/ + odm_set_rf_reg(dm, (enum odm_rf_radio_path)path, 0x65, + RFREGOFFSETMASK, 0x09000); + + if (*dm->band_type == ODM_BAND_5G) { + odm_set_rf_reg(dm, (enum odm_rf_radio_path)path, 0xef, + BIT(19), 0x1); + odm_set_rf_reg(dm, (enum odm_rf_radio_path)path, 0x33, + RFREGOFFSETMASK, 0x00026); + odm_set_rf_reg(dm, (enum odm_rf_radio_path)path, 0x3e, + RFREGOFFSETMASK, 0x00037); + odm_set_rf_reg(dm, (enum odm_rf_radio_path)path, 0x3f, + RFREGOFFSETMASK, 0xdefce); + odm_set_rf_reg(dm, (enum odm_rf_radio_path)path, 0xef, + BIT(19), 0x0); + } else { + odm_set_rf_reg(dm, (enum odm_rf_radio_path)path, 0xef, + BIT(19), 0x1); + odm_set_rf_reg(dm, (enum odm_rf_radio_path)path, 0x33, + RFREGOFFSETMASK, 0x00026); + odm_set_rf_reg(dm, (enum odm_rf_radio_path)path, 0x3e, + RFREGOFFSETMASK, 0x00037); + odm_set_rf_reg(dm, (enum odm_rf_radio_path)path, 0x3f, + RFREGOFFSETMASK, 0x5efce); + odm_set_rf_reg(dm, (enum odm_rf_radio_path)path, 0xef, + BIT(19), 0x0); + } + } +} + +static void _iqk_configure_macbb_8822b(struct phy_dm_struct *dm) +{ + /*MACBB register setting*/ + odm_write_1byte(dm, 0x522, 0x7f); + odm_set_bb_reg(dm, 0x550, BIT(11) | BIT(3), 0x0); + odm_set_bb_reg(dm, 0x90c, BIT(15), + 0x1); /*0x90c[15]=1: dac_buf reset selection*/ + odm_set_bb_reg(dm, 0x9a4, BIT(31), + 0x0); /*0x9a4[31]=0: Select da clock*/ + /*0xc94[0]=1, 0xe94[0]=1: let tx through iqk*/ + odm_set_bb_reg(dm, 0xc94, BIT(0), 0x1); + odm_set_bb_reg(dm, 0xe94, BIT(0), 0x1); + /* 3-wire off*/ + odm_write_4byte(dm, 0xc00, 0x00000004); + odm_write_4byte(dm, 0xe00, 0x00000004); +} + +static void _iqk_lok_setting_8822b(struct phy_dm_struct *dm, u8 path) +{ + odm_write_4byte(dm, 0x1b00, 0xf8000008 | path << 1); + odm_write_4byte(dm, 0x1bcc, 0x9); + odm_write_1byte(dm, 0x1b23, 0x00); + + switch (*dm->band_type) { + case ODM_BAND_2_4G: + odm_write_1byte(dm, 0x1b2b, 0x00); + odm_set_rf_reg(dm, (enum odm_rf_radio_path)path, 0x56, + RFREGOFFSETMASK, 0x50df2); + odm_set_rf_reg(dm, (enum odm_rf_radio_path)path, 0x8f, + RFREGOFFSETMASK, 0xadc00); + /* WE_LUT_TX_LOK*/ + odm_set_rf_reg(dm, (enum odm_rf_radio_path)path, 0xef, BIT(4), + 0x1); + odm_set_rf_reg(dm, (enum odm_rf_radio_path)path, 0x33, + BIT(1) | BIT(0), 0x0); + break; + case ODM_BAND_5G: + odm_write_1byte(dm, 0x1b2b, 0x80); + odm_set_rf_reg(dm, (enum odm_rf_radio_path)path, 0x56, + RFREGOFFSETMASK, 0x5086c); + odm_set_rf_reg(dm, (enum odm_rf_radio_path)path, 0x8f, + RFREGOFFSETMASK, 0xa9c00); + /* WE_LUT_TX_LOK*/ + odm_set_rf_reg(dm, (enum odm_rf_radio_path)path, 0xef, BIT(4), + 0x1); + odm_set_rf_reg(dm, (enum odm_rf_radio_path)path, 0x33, + BIT(1) | BIT(0), 0x1); + break; + } +} + +static void _iqk_txk_setting_8822b(struct phy_dm_struct *dm, u8 path) +{ + odm_write_4byte(dm, 0x1b00, 0xf8000008 | path << 1); + odm_write_4byte(dm, 0x1bcc, 0x9); + odm_write_4byte(dm, 0x1b20, 0x01440008); + + if (path == 0x0) + odm_write_4byte(dm, 0x1b00, 0xf800000a); + else + odm_write_4byte(dm, 0x1b00, 0xf8000008); + odm_write_4byte(dm, 0x1bcc, 0x3f); + + switch (*dm->band_type) { + case ODM_BAND_2_4G: + odm_set_rf_reg(dm, (enum odm_rf_radio_path)path, 0x56, + RFREGOFFSETMASK, 0x50df2); + odm_set_rf_reg(dm, (enum odm_rf_radio_path)path, 0x8f, + RFREGOFFSETMASK, 0xadc00); + odm_write_1byte(dm, 0x1b2b, 0x00); + break; + case ODM_BAND_5G: + odm_set_rf_reg(dm, (enum odm_rf_radio_path)path, 0x56, + RFREGOFFSETMASK, 0x500ef); + odm_set_rf_reg(dm, (enum odm_rf_radio_path)path, 0x8f, + RFREGOFFSETMASK, 0xa9c00); + odm_write_1byte(dm, 0x1b2b, 0x80); + break; + } +} + +static void _iqk_rxk1_setting_8822b(struct phy_dm_struct *dm, u8 path) +{ + odm_write_4byte(dm, 0x1b00, 0xf8000008 | path << 1); + + switch (*dm->band_type) { + case ODM_BAND_2_4G: + odm_write_1byte(dm, 0x1bcc, 0x9); + odm_write_1byte(dm, 0x1b2b, 0x00); + odm_write_4byte(dm, 0x1b20, 0x01450008); + odm_write_4byte(dm, 0x1b24, 0x01460c88); + odm_set_rf_reg(dm, (enum odm_rf_radio_path)path, 0x56, + RFREGOFFSETMASK, 0x510e0); + odm_set_rf_reg(dm, (enum odm_rf_radio_path)path, 0x8f, + RFREGOFFSETMASK, 0xacc00); + break; + case ODM_BAND_5G: + odm_write_1byte(dm, 0x1bcc, 0x09); + odm_write_1byte(dm, 0x1b2b, 0x80); + odm_write_4byte(dm, 0x1b20, 0x00850008); + odm_write_4byte(dm, 0x1b24, 0x00460048); + odm_set_rf_reg(dm, (enum odm_rf_radio_path)path, 0x56, + RFREGOFFSETMASK, 0x510e0); + odm_set_rf_reg(dm, (enum odm_rf_radio_path)path, 0x8f, + RFREGOFFSETMASK, 0xadc00); + break; + } +} + +static void _iqk_rxk2_setting_8822b(struct phy_dm_struct *dm, u8 path, + bool is_gs) +{ + struct dm_iqk_info *iqk_info = &dm->IQK_info; + + odm_write_4byte(dm, 0x1b00, 0xf8000008 | path << 1); + + switch (*dm->band_type) { + case ODM_BAND_2_4G: + if (is_gs) + iqk_info->tmp1bcc = 0x12; + odm_write_1byte(dm, 0x1bcc, iqk_info->tmp1bcc); + odm_write_1byte(dm, 0x1b2b, 0x00); + odm_write_4byte(dm, 0x1b20, 0x01450008); + odm_write_4byte(dm, 0x1b24, 0x01460848); + odm_set_rf_reg(dm, (enum odm_rf_radio_path)path, 0x56, + RFREGOFFSETMASK, 0x510e0); + odm_set_rf_reg(dm, (enum odm_rf_radio_path)path, 0x8f, + RFREGOFFSETMASK, 0xa9c00); + break; + case ODM_BAND_5G: + if (is_gs) { + if (path == ODM_RF_PATH_A) + iqk_info->tmp1bcc = 0x12; + else + iqk_info->tmp1bcc = 0x09; + } + odm_write_1byte(dm, 0x1bcc, iqk_info->tmp1bcc); + odm_write_1byte(dm, 0x1b2b, 0x80); + odm_write_4byte(dm, 0x1b20, 0x00850008); + odm_write_4byte(dm, 0x1b24, 0x00460848); + odm_set_rf_reg(dm, (enum odm_rf_radio_path)path, 0x56, + RFREGOFFSETMASK, 0x51060); + odm_set_rf_reg(dm, (enum odm_rf_radio_path)path, 0x8f, + RFREGOFFSETMASK, 0xa9c00); + break; + } +} + +static bool _iqk_check_cal_8822b(struct phy_dm_struct *dm, u32 IQK_CMD) +{ + bool notready = true, fail = true; + u32 delay_count = 0x0; + + while (notready) { + if (odm_read_4byte(dm, 0x1b00) == (IQK_CMD & 0xffffff0f)) { + fail = (bool)odm_get_bb_reg(dm, 0x1b08, BIT(26)); + notready = false; + } else { + ODM_delay_ms(1); + delay_count++; + } + + if (delay_count >= 50) { + fail = true; + ODM_RT_TRACE(dm, ODM_COMP_CALIBRATION, + "[IQK]IQK timeout!!!\n"); + break; + } + } + ODM_RT_TRACE(dm, ODM_COMP_CALIBRATION, "[IQK]delay count = 0x%x!!!\n", + delay_count); + return fail; +} + +static bool _iqk_rx_iqk_gain_search_fail_8822b(struct phy_dm_struct *dm, + u8 path, u8 step) +{ + struct dm_iqk_info *iqk_info = &dm->IQK_info; + bool fail = true; + u32 IQK_CMD = 0x0, rf_reg0, tmp, bb_idx; + u8 IQMUX[4] = {0x9, 0x12, 0x1b, 0x24}; + u8 idx; + + for (idx = 0; idx < 4; idx++) + if (iqk_info->tmp1bcc == IQMUX[idx]) + break; + + odm_write_4byte(dm, 0x1b00, 0xf8000008 | path << 1); + odm_write_4byte(dm, 0x1bcc, iqk_info->tmp1bcc); + + if (step == RXIQK1) + ODM_RT_TRACE( + dm, ODM_COMP_CALIBRATION, + "[IQK]============ S%d RXIQK GainSearch ============\n", + path); + + if (step == RXIQK1) + IQK_CMD = 0xf8000208 | (1 << (path + 4)); + else + IQK_CMD = 0xf8000308 | (1 << (path + 4)); + + ODM_RT_TRACE(dm, ODM_COMP_CALIBRATION, "[IQK]S%d GS%d_Trigger = 0x%x\n", + path, step, IQK_CMD); + + odm_write_4byte(dm, 0x1b00, IQK_CMD); + odm_write_4byte(dm, 0x1b00, IQK_CMD + 0x1); + ODM_delay_ms(GS_delay_8822B); + fail = _iqk_check_cal_8822b(dm, IQK_CMD); + + if (step == RXIQK2) { + rf_reg0 = odm_get_rf_reg(dm, (enum odm_rf_radio_path)path, 0x0, + RFREGOFFSETMASK); + odm_write_4byte(dm, 0x1b00, 0xf8000008 | path << 1); + ODM_RT_TRACE( + dm, ODM_COMP_CALIBRATION, + "[IQK]S%d ==> RF0x0 = 0x%x, tmp1bcc = 0x%x, idx = %d, 0x1b3c = 0x%x\n", + path, rf_reg0, iqk_info->tmp1bcc, idx, + odm_read_4byte(dm, 0x1b3c)); + tmp = (rf_reg0 & 0x1fe0) >> 5; + iqk_info->lna_idx = tmp >> 5; + bb_idx = tmp & 0x1f; + if (bb_idx == 0x1) { + if (iqk_info->lna_idx != 0x0) + iqk_info->lna_idx--; + else if (idx != 3) + idx++; + else + iqk_info->isbnd = true; + fail = true; + } else if (bb_idx == 0xa) { + if (idx != 0) + idx--; + else if (iqk_info->lna_idx != 0x7) + iqk_info->lna_idx++; + else + iqk_info->isbnd = true; + fail = true; + } else { + fail = false; + } + + if (iqk_info->isbnd) + fail = false; + + iqk_info->tmp1bcc = IQMUX[idx]; + + if (fail) { + odm_write_4byte(dm, 0x1b00, 0xf8000008 | path << 1); + odm_write_4byte( + dm, 0x1b24, + (odm_read_4byte(dm, 0x1b24) & 0xffffe3ff) | + (iqk_info->lna_idx << 10)); + } + } + + return fail; +} + +static bool _lok_one_shot_8822b(void *dm_void, u8 path) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct dm_iqk_info *iqk_info = &dm->IQK_info; + u8 delay_count = 0; + bool LOK_notready = false; + u32 LOK_temp = 0; + u32 IQK_CMD = 0x0; + + ODM_RT_TRACE(dm, ODM_COMP_CALIBRATION, + "[IQK]==========S%d LOK ==========\n", path); + + IQK_CMD = 0xf8000008 | (1 << (4 + path)); + + ODM_RT_TRACE(dm, ODM_COMP_CALIBRATION, "[IQK]LOK_Trigger = 0x%x\n", + IQK_CMD); + + odm_write_4byte(dm, 0x1b00, IQK_CMD); + odm_write_4byte(dm, 0x1b00, IQK_CMD + 1); + /*LOK: CMD ID = 0 {0xf8000018, 0xf8000028}*/ + /*LOK: CMD ID = 0 {0xf8000019, 0xf8000029}*/ + ODM_delay_ms(LOK_delay_8822B); + + delay_count = 0; + LOK_notready = true; + + while (LOK_notready) { + if (odm_read_4byte(dm, 0x1b00) == (IQK_CMD & 0xffffff0f)) + LOK_notready = false; + else + LOK_notready = true; + + if (LOK_notready) { + ODM_delay_ms(1); + delay_count++; + } + + if (delay_count >= 50) { + ODM_RT_TRACE(dm, ODM_COMP_CALIBRATION, + "[IQK]S%d LOK timeout!!!\n", path); + break; + } + } + + ODM_RT_TRACE(dm, ODM_COMP_CALIBRATION, + "[IQK]S%d ==> delay_count = 0x%x\n", path, delay_count); + if (ODM_COMP_CALIBRATION) { + if (!LOK_notready) { + LOK_temp = + odm_get_rf_reg(dm, (enum odm_rf_radio_path)path, + 0x58, RFREGOFFSETMASK); + ODM_RT_TRACE(dm, ODM_COMP_CALIBRATION, + "[IQK]0x58 = 0x%x\n", LOK_temp); + } else { + ODM_RT_TRACE(dm, ODM_COMP_CALIBRATION, + "[IQK]==>S%d LOK Fail!!!\n", path); + } + } + iqk_info->lok_fail[path] = LOK_notready; + return LOK_notready; +} + +static bool _iqk_one_shot_8822b(void *dm_void, u8 path, u8 idx) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct dm_iqk_info *iqk_info = &dm->IQK_info; + u8 delay_count = 0; + bool notready = true, fail = true; + u32 IQK_CMD = 0x0; + u16 iqk_apply[2] = {0xc94, 0xe94}; + + if (idx == TXIQK) + ODM_RT_TRACE(dm, ODM_COMP_CALIBRATION, + "[IQK]============ S%d WBTXIQK ============\n", + path); + else if (idx == RXIQK1) + ODM_RT_TRACE( + dm, ODM_COMP_CALIBRATION, + "[IQK]============ S%d WBRXIQK STEP1============\n", + path); + else + ODM_RT_TRACE( + dm, ODM_COMP_CALIBRATION, + "[IQK]============ S%d WBRXIQK STEP2============\n", + path); + + if (idx == TXIQK) { + IQK_CMD = 0xf8000008 | ((*dm->band_width + 4) << 8) | + (1 << (path + 4)); + ODM_RT_TRACE(dm, ODM_COMP_CALIBRATION, + "[IQK]TXK_Trigger = 0x%x\n", IQK_CMD); + /*{0xf8000418, 0xf800042a} ==> 20 WBTXK (CMD = 4)*/ + /*{0xf8000518, 0xf800052a} ==> 40 WBTXK (CMD = 5)*/ + /*{0xf8000618, 0xf800062a} ==> 80 WBTXK (CMD = 6)*/ + } else if (idx == RXIQK1) { + if (*dm->band_width == 2) + IQK_CMD = 0xf8000808 | (1 << (path + 4)); + else + IQK_CMD = 0xf8000708 | (1 << (path + 4)); + ODM_RT_TRACE(dm, ODM_COMP_CALIBRATION, + "[IQK]RXK1_Trigger = 0x%x\n", IQK_CMD); + /*{0xf8000718, 0xf800072a} ==> 20 WBTXK (CMD = 7)*/ + /*{0xf8000718, 0xf800072a} ==> 40 WBTXK (CMD = 7)*/ + /*{0xf8000818, 0xf800082a} ==> 80 WBTXK (CMD = 8)*/ + } else if (idx == RXIQK2) { + IQK_CMD = 0xf8000008 | ((*dm->band_width + 9) << 8) | + (1 << (path + 4)); + ODM_RT_TRACE(dm, ODM_COMP_CALIBRATION, + "[IQK]RXK2_Trigger = 0x%x\n", IQK_CMD); + /*{0xf8000918, 0xf800092a} ==> 20 WBRXK (CMD = 9)*/ + /*{0xf8000a18, 0xf8000a2a} ==> 40 WBRXK (CMD = 10)*/ + /*{0xf8000b18, 0xf8000b2a} ==> 80 WBRXK (CMD = 11)*/ + odm_write_4byte(dm, 0x1b00, 0xf8000008 | path << 1); + odm_write_4byte(dm, 0x1b24, + (odm_read_4byte(dm, 0x1b24) & 0xffffe3ff) | + ((iqk_info->lna_idx & 0x7) << 10)); + } + odm_write_4byte(dm, 0x1b00, IQK_CMD); + odm_write_4byte(dm, 0x1b00, IQK_CMD + 0x1); + ODM_delay_ms(WBIQK_delay_8822B); + + while (notready) { + if (odm_read_4byte(dm, 0x1b00) == (IQK_CMD & 0xffffff0f)) + notready = false; + else + notready = true; + + if (notready) { + ODM_delay_ms(1); + delay_count++; + } else { + fail = (bool)odm_get_bb_reg(dm, 0x1b08, BIT(26)); + break; + } + + if (delay_count >= 50) { + ODM_RT_TRACE(dm, ODM_COMP_CALIBRATION, + "[IQK]S%d IQK timeout!!!\n", path); + break; + } + } + + if (dm->debug_components & ODM_COMP_CALIBRATION) { + odm_write_4byte(dm, 0x1b00, 0xf8000008 | path << 1); + ODM_RT_TRACE(dm, ODM_COMP_CALIBRATION, + "[IQK]S%d ==> 0x1b00 = 0x%x, 0x1b08 = 0x%x\n", + path, odm_read_4byte(dm, 0x1b00), + odm_read_4byte(dm, 0x1b08)); + ODM_RT_TRACE(dm, ODM_COMP_CALIBRATION, + "[IQK]S%d ==> delay_count = 0x%x\n", path, + delay_count); + if (idx != TXIQK) + ODM_RT_TRACE( + dm, ODM_COMP_CALIBRATION, + "[IQK]S%d ==> RF0x0 = 0x%x, RF0x56 = 0x%x\n", + path, + odm_get_rf_reg(dm, (enum odm_rf_radio_path)path, + 0x0, RFREGOFFSETMASK), + odm_get_rf_reg(dm, (enum odm_rf_radio_path)path, + 0x56, RFREGOFFSETMASK)); + } + + odm_write_4byte(dm, 0x1b00, 0xf8000008 | path << 1); + + if (idx == TXIQK) + if (fail) + odm_set_bb_reg(dm, iqk_apply[path], BIT(0), 0x0); + + if (idx == RXIQK2) { + iqk_info->rxiqk_agc[0][path] = + (u16)(((odm_get_rf_reg(dm, (enum odm_rf_radio_path)path, + 0x0, RFREGOFFSETMASK) >> + 5) & + 0xff) | + (iqk_info->tmp1bcc << 8)); + + odm_write_4byte(dm, 0x1b38, 0x20000000); + + if (!fail) + odm_set_bb_reg(dm, iqk_apply[path], (BIT(11) | BIT(10)), + 0x1); + else + odm_set_bb_reg(dm, iqk_apply[path], (BIT(11) | BIT(10)), + 0x0); + } + + if (idx == TXIQK) + iqk_info->iqk_fail_report[0][path][TXIQK] = fail; + else + iqk_info->iqk_fail_report[0][path][RXIQK] = fail; + + return fail; +} + +static bool _iqk_rx_iqk_by_path_8822b(void *dm_void, u8 path) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct dm_iqk_info *iqk_info = &dm->IQK_info; + bool KFAIL = true, gonext; + + switch (iqk_info->rxiqk_step) { + case 1: /*gain search_RXK1*/ + _iqk_rxk1_setting_8822b(dm, path); + gonext = false; + while (1) { + KFAIL = _iqk_rx_iqk_gain_search_fail_8822b(dm, path, + RXIQK1); + if (KFAIL && + (iqk_info->gs_retry_count[0][path][GSRXK1] < 2)) + iqk_info->gs_retry_count[0][path][GSRXK1]++; + else if (KFAIL) { + iqk_info->rxiqk_fail_code[0][path] = 0; + iqk_info->rxiqk_step = 5; + gonext = true; + } else { + iqk_info->rxiqk_step++; + gonext = true; + } + if (gonext) + break; + } + break; + case 2: /*gain search_RXK2*/ + _iqk_rxk2_setting_8822b(dm, path, true); + iqk_info->isbnd = false; + while (1) { + KFAIL = _iqk_rx_iqk_gain_search_fail_8822b(dm, path, + RXIQK2); + if (KFAIL && + (iqk_info->gs_retry_count[0][path][GSRXK2] < + rxiqk_gs_limit)) { + iqk_info->gs_retry_count[0][path][GSRXK2]++; + } else { + iqk_info->rxiqk_step++; + break; + } + } + break; + case 3: /*RXK1*/ + _iqk_rxk1_setting_8822b(dm, path); + gonext = false; + while (1) { + KFAIL = _iqk_one_shot_8822b(dm, path, RXIQK1); + if (KFAIL && + (iqk_info->retry_count[0][path][RXIQK1] < 2)) + iqk_info->retry_count[0][path][RXIQK1]++; + else if (KFAIL) { + iqk_info->rxiqk_fail_code[0][path] = 1; + iqk_info->rxiqk_step = 5; + gonext = true; + } else { + iqk_info->rxiqk_step++; + gonext = true; + } + if (gonext) + break; + } + break; + case 4: /*RXK2*/ + _iqk_rxk2_setting_8822b(dm, path, false); + gonext = false; + while (1) { + KFAIL = _iqk_one_shot_8822b(dm, path, RXIQK2); + if (KFAIL && + (iqk_info->retry_count[0][path][RXIQK2] < 2)) + iqk_info->retry_count[0][path][RXIQK2]++; + else if (KFAIL) { + iqk_info->rxiqk_fail_code[0][path] = 2; + iqk_info->rxiqk_step = 5; + gonext = true; + } else { + iqk_info->rxiqk_step++; + gonext = true; + } + if (gonext) + break; + } + break; + } + return KFAIL; +} + +static void _iqk_iqk_by_path_8822b(void *dm_void, bool segment_iqk) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct dm_iqk_info *iqk_info = &dm->IQK_info; + bool KFAIL = true; + u8 i, kcount_limit; + + if (*dm->band_width == 2) + kcount_limit = kcount_limit_80m; + else + kcount_limit = kcount_limit_others; + + while (1) { + switch (dm->rf_calibrate_info.iqk_step) { + case 1: /*S0 LOK*/ + _iqk_lok_setting_8822b(dm, ODM_RF_PATH_A); + _lok_one_shot_8822b(dm, ODM_RF_PATH_A); + dm->rf_calibrate_info.iqk_step++; + break; + case 2: /*S1 LOK*/ + _iqk_lok_setting_8822b(dm, ODM_RF_PATH_B); + _lok_one_shot_8822b(dm, ODM_RF_PATH_B); + dm->rf_calibrate_info.iqk_step++; + break; + case 3: /*S0 TXIQK*/ + _iqk_txk_setting_8822b(dm, ODM_RF_PATH_A); + KFAIL = _iqk_one_shot_8822b(dm, ODM_RF_PATH_A, TXIQK); + iqk_info->kcount++; + ODM_RT_TRACE(dm, ODM_COMP_CALIBRATION, + "[IQK]S0TXK KFail = 0x%x\n", KFAIL); + + if (KFAIL && + (iqk_info->retry_count[0][ODM_RF_PATH_A][TXIQK] < + 3)) + iqk_info->retry_count[0][ODM_RF_PATH_A] + [TXIQK]++; + else + dm->rf_calibrate_info.iqk_step++; + break; + case 4: /*S1 TXIQK*/ + _iqk_txk_setting_8822b(dm, ODM_RF_PATH_B); + KFAIL = _iqk_one_shot_8822b(dm, ODM_RF_PATH_B, TXIQK); + iqk_info->kcount++; + ODM_RT_TRACE(dm, ODM_COMP_CALIBRATION, + "[IQK]S1TXK KFail = 0x%x\n", KFAIL); + if (KFAIL && + iqk_info->retry_count[0][ODM_RF_PATH_B][TXIQK] < 3) + iqk_info->retry_count[0][ODM_RF_PATH_B] + [TXIQK]++; + else + dm->rf_calibrate_info.iqk_step++; + break; + case 5: /*S0 RXIQK*/ + phydm_set_iqk_info(dm, iqk_info, 0); + break; + case 6: /*S1 RXIQK*/ + phydm_set_iqk_info(dm, iqk_info, 1); + break; + } + + if (dm->rf_calibrate_info.iqk_step == 7) { + ODM_RT_TRACE(dm, ODM_COMP_CALIBRATION, + "[IQK]==========LOK summary ==========\n"); + ODM_RT_TRACE( + dm, ODM_COMP_CALIBRATION, + "[IQK]PathA_LOK_notready = %d, PathB_LOK1_notready = %d\n", + iqk_info->lok_fail[ODM_RF_PATH_A], + iqk_info->lok_fail[ODM_RF_PATH_B]); + ODM_RT_TRACE(dm, ODM_COMP_CALIBRATION, + "[IQK]==========IQK summary ==========\n"); + ODM_RT_TRACE( + dm, ODM_COMP_CALIBRATION, + "[IQK]PathA_TXIQK_fail = %d, PathB_TXIQK_fail = %d\n", + iqk_info->iqk_fail_report[0][ODM_RF_PATH_A] + [TXIQK], + iqk_info->iqk_fail_report[0][ODM_RF_PATH_B] + [TXIQK]); + ODM_RT_TRACE( + dm, ODM_COMP_CALIBRATION, + "[IQK]PathA_RXIQK_fail = %d, PathB_RXIQK_fail = %d\n", + iqk_info->iqk_fail_report[0][ODM_RF_PATH_A] + [RXIQK], + iqk_info->iqk_fail_report[0][ODM_RF_PATH_B] + [RXIQK]); + ODM_RT_TRACE( + dm, ODM_COMP_CALIBRATION, + "[IQK]PathA_TXIQK_retry = %d, PathB_TXIQK_retry = %d\n", + iqk_info->retry_count[0][ODM_RF_PATH_A][TXIQK], + iqk_info->retry_count[0][ODM_RF_PATH_B][TXIQK]); + ODM_RT_TRACE( + dm, ODM_COMP_CALIBRATION, + "[IQK]PathA_RXK1_retry = %d, PathA_RXK2_retry = %d, PathB_RXK1_retry = %d, PathB_RXK2_retry = %d\n", + iqk_info->retry_count[0][ODM_RF_PATH_A][RXIQK1], + iqk_info->retry_count[0][ODM_RF_PATH_A][RXIQK2], + iqk_info->retry_count[0][ODM_RF_PATH_B][RXIQK1], + iqk_info->retry_count[0][ODM_RF_PATH_B] + [RXIQK2]); + ODM_RT_TRACE( + dm, ODM_COMP_CALIBRATION, + "[IQK]PathA_GS1_retry = %d, PathA_GS2_retry = %d, PathB_GS1_retry = %d, PathB_GS2_retry = %d\n", + iqk_info->gs_retry_count[0][ODM_RF_PATH_A] + [GSRXK1], + iqk_info->gs_retry_count[0][ODM_RF_PATH_A] + [GSRXK2], + iqk_info->gs_retry_count[0][ODM_RF_PATH_B] + [GSRXK1], + iqk_info->gs_retry_count[0][ODM_RF_PATH_B] + [GSRXK2]); + for (i = 0; i < 2; i++) { + odm_write_4byte(dm, 0x1b00, + 0xf8000008 | i << 1); + odm_write_4byte(dm, 0x1b2c, 0x7); + odm_write_4byte(dm, 0x1bcc, 0x0); + } + break; + } + + if (segment_iqk && (iqk_info->kcount == kcount_limit)) + break; + } +} + +static void _iqk_start_iqk_8822b(struct phy_dm_struct *dm, bool segment_iqk) +{ + u32 tmp; + + /*GNT_WL = 1*/ + tmp = odm_get_rf_reg(dm, ODM_RF_PATH_A, 0x1, RFREGOFFSETMASK); + tmp = tmp | BIT(5) | BIT(0); + odm_set_rf_reg(dm, ODM_RF_PATH_A, 0x1, RFREGOFFSETMASK, tmp); + + tmp = odm_get_rf_reg(dm, ODM_RF_PATH_B, 0x1, RFREGOFFSETMASK); + tmp = tmp | BIT(5) | BIT(0); + odm_set_rf_reg(dm, ODM_RF_PATH_B, 0x1, RFREGOFFSETMASK, tmp); + + _iqk_iqk_by_path_8822b(dm, segment_iqk); +} + +static void _iq_calibrate_8822b_init(void *dm_void) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + struct dm_iqk_info *iqk_info = &dm->IQK_info; + u8 i, j; + + if (iqk_info->iqk_times == 0) { + ODM_RT_TRACE(dm, ODM_COMP_CALIBRATION, + "[IQK]=====>PHY_IQCalibrate_8822B_Init\n"); + + for (i = 0; i < SS_8822B; i++) { + for (j = 0; j < 2; j++) { + iqk_info->lok_fail[i] = true; + iqk_info->iqk_fail[j][i] = true; + iqk_info->iqc_matrix[j][i] = 0x20000000; + } + } + + phydm_init_iqk_information(iqk_info); + } +} + +static void _phy_iq_calibrate_8822b(struct phy_dm_struct *dm, bool reset) +{ + u32 MAC_backup[MAC_REG_NUM_8822B], BB_backup[BB_REG_NUM_8822B], + RF_backup[RF_REG_NUM_8822B][SS_8822B]; + u32 backup_mac_reg[MAC_REG_NUM_8822B] = {0x520, 0x550}; + u32 backup_bb_reg[BB_REG_NUM_8822B] = { + 0x808, 0x90c, 0xc00, 0xcb0, 0xcb4, 0xcbc, 0xe00, + 0xeb0, 0xeb4, 0xebc, 0x1990, 0x9a4, 0xa04}; + u32 backup_rf_reg[RF_REG_NUM_8822B] = {0xdf, 0x8f, 0x65, 0x0, 0x1}; + bool segment_iqk = false, is_mp = false; + + struct dm_iqk_info *iqk_info = &dm->IQK_info; + + if (dm->mp_mode) + is_mp = true; + else if (dm->is_linked) + segment_iqk = true; + + if (!is_mp) + if (_iqk_reload_iqk_8822b(dm, reset)) + return; + + ODM_RT_TRACE(dm, ODM_COMP_CALIBRATION, + "[IQK]==========IQK strat!!!!!==========\n"); + + ODM_RT_TRACE( + dm, ODM_COMP_CALIBRATION, + "[IQK]band_type = %s, band_width = %d, ExtPA2G = %d, ext_pa_5g = %d\n", + (*dm->band_type == ODM_BAND_5G) ? "5G" : "2G", *dm->band_width, + dm->ext_pa, dm->ext_pa_5g); + ODM_RT_TRACE(dm, ODM_COMP_CALIBRATION, + "[IQK]Interface = %d, cut_version = %x\n", + dm->support_interface, dm->cut_version); + + iqk_info->iqk_times++; + + iqk_info->kcount = 0; + dm->rf_calibrate_info.iqk_total_progressing_time = 0; + dm->rf_calibrate_info.iqk_step = 1; + iqk_info->rxiqk_step = 1; + + _iqk_backup_iqk_8822b(dm, 0); + _iqk_backup_mac_bb_8822b(dm, MAC_backup, BB_backup, backup_mac_reg, + backup_bb_reg); + _iqk_backup_rf_8822b(dm, RF_backup, backup_rf_reg); + + while (1) { + if (!is_mp) + dm->rf_calibrate_info.iqk_start_time = + odm_get_current_time(dm); + + _iqk_configure_macbb_8822b(dm); + _iqk_afe_setting_8822b(dm, true); + _iqk_rfe_setting_8822b(dm, false); + _iqk_agc_bnd_int_8822b(dm); + _iqk_rf_setting_8822b(dm); + + _iqk_start_iqk_8822b(dm, segment_iqk); + + _iqk_afe_setting_8822b(dm, false); + _iqk_restore_mac_bb_8822b(dm, MAC_backup, BB_backup, + backup_mac_reg, backup_bb_reg); + _iqk_restore_rf_8822b(dm, backup_rf_reg, RF_backup); + + if (!is_mp) { + dm->rf_calibrate_info.iqk_progressing_time = + odm_get_progressing_time( + dm, + dm->rf_calibrate_info.iqk_start_time); + dm->rf_calibrate_info.iqk_total_progressing_time += + odm_get_progressing_time( + dm, + dm->rf_calibrate_info.iqk_start_time); + ODM_RT_TRACE( + dm, ODM_COMP_CALIBRATION, + "[IQK]IQK progressing_time = %lld ms\n", + dm->rf_calibrate_info.iqk_progressing_time); + } + + if (dm->rf_calibrate_info.iqk_step == 7) + break; + + iqk_info->kcount = 0; + ODM_RT_TRACE(dm, ODM_COMP_CALIBRATION, "[IQK]delay 50ms!!!\n"); + ODM_delay_ms(50); + }; + + _iqk_backup_iqk_8822b(dm, 1); + _iqk_fill_iqk_report_8822b(dm, 0); + + if (!is_mp) + ODM_RT_TRACE(dm, ODM_COMP_CALIBRATION, + "[IQK]Total IQK progressing_time = %lld ms\n", + dm->rf_calibrate_info.iqk_total_progressing_time); + + ODM_RT_TRACE(dm, ODM_COMP_CALIBRATION, + "[IQK]==========IQK end!!!!!==========\n"); +} + +static void _phy_iq_calibrate_by_fw_8822b(void *dm_void, u8 clear) {} + +/*IQK version:v3.3, NCTL v0.6*/ +/*1.The new gainsearch method for RXIQK*/ +/*2.The new format of IQK report register: 0x1be8/0x1bec*/ +/*3. add the option of segment IQK*/ +void phy_iq_calibrate_8822b(void *dm_void, bool clear) +{ + struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void; + + dm->iqk_fw_offload = 0; + + /*FW IQK*/ + if (dm->iqk_fw_offload) { + if (!dm->rf_calibrate_info.is_iqk_in_progress) { + odm_acquire_spin_lock(dm, RT_IQK_SPINLOCK); + dm->rf_calibrate_info.is_iqk_in_progress = true; + odm_release_spin_lock(dm, RT_IQK_SPINLOCK); + + dm->rf_calibrate_info.iqk_start_time = + odm_get_current_time(dm); + + odm_write_4byte(dm, 0x1b00, 0xf8000008); + odm_set_bb_reg(dm, 0x1bf0, 0xff000000, 0xff); + ODM_RT_TRACE(dm, ODM_COMP_CALIBRATION, + "[IQK]0x1bf0 = 0x%x\n", + odm_read_4byte(dm, 0x1bf0)); + + _phy_iq_calibrate_by_fw_8822b(dm, clear); + phydm_get_read_counter(dm); + + dm->rf_calibrate_info.iqk_progressing_time = + odm_get_progressing_time( + dm, + dm->rf_calibrate_info.iqk_start_time); + + ODM_RT_TRACE( + dm, ODM_COMP_CALIBRATION, + "[IQK]IQK progressing_time = %lld ms\n", + dm->rf_calibrate_info.iqk_progressing_time); + + odm_acquire_spin_lock(dm, RT_IQK_SPINLOCK); + dm->rf_calibrate_info.is_iqk_in_progress = false; + odm_release_spin_lock(dm, RT_IQK_SPINLOCK); + } else { + ODM_RT_TRACE( + dm, ODM_COMP_CALIBRATION, + "== Return the IQK CMD, because the IQK in Progress ==\n"); + } + + } else { + _iq_calibrate_8822b_init(dm_void); + + if (!dm->rf_calibrate_info.is_iqk_in_progress) { + odm_acquire_spin_lock(dm, RT_IQK_SPINLOCK); + dm->rf_calibrate_info.is_iqk_in_progress = true; + odm_release_spin_lock(dm, RT_IQK_SPINLOCK); + if (dm->mp_mode) + dm->rf_calibrate_info.iqk_start_time = + odm_get_current_time(dm); + + _phy_iq_calibrate_8822b(dm, clear); + if (dm->mp_mode) { + dm->rf_calibrate_info.iqk_progressing_time = + odm_get_progressing_time( + dm, dm->rf_calibrate_info + .iqk_start_time); + ODM_RT_TRACE( + dm, ODM_COMP_CALIBRATION, + "[IQK]IQK progressing_time = %lld ms\n", + dm->rf_calibrate_info + .iqk_progressing_time); + } + odm_acquire_spin_lock(dm, RT_IQK_SPINLOCK); + dm->rf_calibrate_info.is_iqk_in_progress = false; + odm_release_spin_lock(dm, RT_IQK_SPINLOCK); + } else { + ODM_RT_TRACE( + dm, ODM_COMP_CALIBRATION, + "[IQK]== Return the IQK CMD, because the IQK in Progress ==\n"); + } + } +} diff --git a/drivers/staging/rtlwifi/phydm/rtl8822b/phydm_iqk_8822b.h b/drivers/staging/rtlwifi/phydm/rtl8822b/phydm_iqk_8822b.h new file mode 100644 index 000000000000..ea19deb512d5 --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/rtl8822b/phydm_iqk_8822b.h @@ -0,0 +1,48 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef __PHYDM_IQK_8822B_H__ +#define __PHYDM_IQK_8822B_H__ + +/*--------------------------Define Parameters-------------------------------*/ +#define MAC_REG_NUM_8822B 2 +#define BB_REG_NUM_8822B 13 +#define RF_REG_NUM_8822B 5 + +#define LOK_delay_8822B 2 +#define GS_delay_8822B 2 +#define WBIQK_delay_8822B 2 + +#define TXIQK 0 +#define RXIQK 1 +#define SS_8822B 2 + +/*------------------------End Define Parameters-------------------------------*/ + +void do_iqk_8822b(void *dm_void, u8 delta_thermal_index, u8 thermal_value, + u8 threshold); + +void phy_iq_calibrate_8822b(void *dm_void, bool clear); + +#endif /* #ifndef __PHYDM_IQK_8822B_H__*/ diff --git a/drivers/staging/rtlwifi/phydm/rtl8822b/phydm_regconfig8822b.c b/drivers/staging/rtlwifi/phydm/rtl8822b/phydm_regconfig8822b.c new file mode 100644 index 000000000000..644fca822c61 --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/rtl8822b/phydm_regconfig8822b.c @@ -0,0 +1,168 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include "../mp_precomp.h" +#include "../phydm_precomp.h" + +void odm_config_rf_reg_8822b(struct phy_dm_struct *dm, u32 addr, u32 data, + enum odm_rf_radio_path RF_PATH, u32 reg_addr) +{ + if (addr == 0xffe) { + ODM_sleep_ms(50); + } else if (addr == 0xfe) { + ODM_delay_us(100); + } else { + odm_set_rf_reg(dm, RF_PATH, reg_addr, RFREGOFFSETMASK, data); + + /* Add 1us delay between BB/RF register setting. */ + ODM_delay_us(1); + } +} + +void odm_config_rf_radio_a_8822b(struct phy_dm_struct *dm, u32 addr, u32 data) +{ + u32 content = 0x1000; /* RF_Content: radioa_txt */ + u32 maskfor_phy_set = (u32)(content & 0xE000); + + odm_config_rf_reg_8822b(dm, addr, data, ODM_RF_PATH_A, + addr | maskfor_phy_set); + + ODM_RT_TRACE( + dm, ODM_COMP_INIT, + "===> odm_config_rf_with_header_file: [RadioA] %08X %08X\n", + addr, data); +} + +void odm_config_rf_radio_b_8822b(struct phy_dm_struct *dm, u32 addr, u32 data) +{ + u32 content = 0x1001; /* RF_Content: radiob_txt */ + u32 maskfor_phy_set = (u32)(content & 0xE000); + + odm_config_rf_reg_8822b(dm, addr, data, ODM_RF_PATH_B, + addr | maskfor_phy_set); + + ODM_RT_TRACE( + dm, ODM_COMP_INIT, + "===> odm_config_rf_with_header_file: [RadioB] %08X %08X\n", + addr, data); +} + +void odm_config_mac_8822b(struct phy_dm_struct *dm, u32 addr, u8 data) +{ + odm_write_1byte(dm, addr, data); + ODM_RT_TRACE( + dm, ODM_COMP_INIT, + "===> odm_config_mac_with_header_file: [MAC_REG] %08X %08X\n", + addr, data); +} + +void odm_update_agc_big_jump_lmt_8822b(struct phy_dm_struct *dm, u32 addr, + u32 data) +{ + struct dig_thres *dig_tab = &dm->dm_dig_table; + u8 rf_gain_idx = (u8)((data & 0xFF000000) >> 24); + u8 bb_gain_idx = (u8)((data & 0x00ff0000) >> 16); + u8 agc_table_idx = (u8)((data & 0x00000f00) >> 8); + static bool is_limit; + + if (addr != 0x81c) + return; + + if (bb_gain_idx > 0x3c) { + if ((rf_gain_idx == dig_tab->rf_gain_idx) && !is_limit) { + is_limit = true; + dig_tab->big_jump_lmt[agc_table_idx] = bb_gain_idx - 2; + ODM_RT_TRACE( + dm, ODM_COMP_DIG, + "===> [AGC_TAB] big_jump_lmt [%d] = 0x%x\n", + agc_table_idx, + dig_tab->big_jump_lmt[agc_table_idx]); + } + } else { + is_limit = false; + } + + dig_tab->rf_gain_idx = rf_gain_idx; +} + +void odm_config_bb_agc_8822b(struct phy_dm_struct *dm, u32 addr, u32 bitmask, + u32 data) +{ + odm_update_agc_big_jump_lmt_8822b(dm, addr, data); + + odm_set_bb_reg(dm, addr, bitmask, data); + + /* Add 1us delay between BB/RF register setting. */ + ODM_delay_us(1); + + ODM_RT_TRACE(dm, ODM_COMP_INIT, "===> %s: [AGC_TAB] %08X %08X\n", + __func__, addr, data); +} + +void odm_config_bb_phy_reg_pg_8822b(struct phy_dm_struct *dm, u32 band, + u32 rf_path, u32 tx_num, u32 addr, + u32 bitmask, u32 data) +{ + if (addr == 0xfe || addr == 0xffe) { + ODM_sleep_ms(50); + } else { + phy_store_tx_power_by_rate(dm->adapter, band, rf_path, tx_num, + addr, bitmask, data); + } + ODM_RT_TRACE(dm, ODM_COMP_INIT, "===> %s: [PHY_REG] %08X %08X %08X\n", + __func__, addr, bitmask, data); +} + +void odm_config_bb_phy_8822b(struct phy_dm_struct *dm, u32 addr, u32 bitmask, + u32 data) +{ + if (addr == 0xfe) + ODM_sleep_ms(50); + else if (addr == 0xfd) + ODM_delay_ms(5); + else if (addr == 0xfc) + ODM_delay_ms(1); + else if (addr == 0xfb) + ODM_delay_us(50); + else if (addr == 0xfa) + ODM_delay_us(5); + else if (addr == 0xf9) + ODM_delay_us(1); + else + odm_set_bb_reg(dm, addr, bitmask, data); + + /* Add 1us delay between BB/RF register setting. */ + ODM_delay_us(1); + ODM_RT_TRACE(dm, ODM_COMP_INIT, "===> %s: [PHY_REG] %08X %08X\n", + __func__, addr, data); +} + +void odm_config_bb_txpwr_lmt_8822b(struct phy_dm_struct *dm, u8 *regulation, + u8 *band, u8 *bandwidth, u8 *rate_section, + u8 *rf_path, u8 *channel, u8 *power_limit) +{ + phy_set_tx_power_limit(dm, regulation, band, bandwidth, rate_section, + rf_path, channel, power_limit); +} diff --git a/drivers/staging/rtlwifi/phydm/rtl8822b/phydm_regconfig8822b.h b/drivers/staging/rtlwifi/phydm/rtl8822b/phydm_regconfig8822b.h new file mode 100644 index 000000000000..4817cf6b1ed9 --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/rtl8822b/phydm_regconfig8822b.h @@ -0,0 +1,54 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef __INC_ODM_REGCONFIG_H_8822B +#define __INC_ODM_REGCONFIG_H_8822B + +void odm_config_rf_reg_8822b(struct phy_dm_struct *dm, u32 addr, u32 data, + enum odm_rf_radio_path RF_PATH, u32 reg_addr); + +void odm_config_rf_radio_a_8822b(struct phy_dm_struct *dm, u32 addr, u32 data); + +void odm_config_rf_radio_b_8822b(struct phy_dm_struct *dm, u32 addr, u32 data); + +void odm_config_mac_8822b(struct phy_dm_struct *dm, u32 addr, u8 data); + +void odm_update_agc_big_jump_lmt_8822b(struct phy_dm_struct *dm, u32 addr, + u32 data); + +void odm_config_bb_agc_8822b(struct phy_dm_struct *dm, u32 addr, u32 bitmask, + u32 data); + +void odm_config_bb_phy_reg_pg_8822b(struct phy_dm_struct *dm, u32 band, + u32 rf_path, u32 tx_num, u32 addr, + u32 bitmask, u32 data); + +void odm_config_bb_phy_8822b(struct phy_dm_struct *dm, u32 addr, u32 bitmask, + u32 data); + +void odm_config_bb_txpwr_lmt_8822b(struct phy_dm_struct *dm, u8 *regulation, + u8 *band, u8 *bandwidth, u8 *rate_section, + u8 *rf_path, u8 *channel, u8 *power_limit); + +#endif /* RTL8822B_SUPPORT == 1*/ diff --git a/drivers/staging/rtlwifi/phydm/rtl8822b/phydm_rtl8822b.c b/drivers/staging/rtlwifi/phydm/rtl8822b/phydm_rtl8822b.c new file mode 100644 index 000000000000..59adabda09de --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/rtl8822b/phydm_rtl8822b.c @@ -0,0 +1,225 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include "../mp_precomp.h" +#include "../phydm_precomp.h" + +static void phydm_dynamic_switch_htstf_mumimo_8822b(struct phy_dm_struct *dm) +{ + /*if rssi > 40dBm, enable HT-STF gain controller, + *otherwise, if rssi < 40dBm, disable the controller + */ + /*add by Chun-Hung Ho 20160711 */ + if (dm->rssi_min >= 40) + odm_set_bb_reg(dm, 0x8d8, BIT(17), 0x1); + else if (dm->rssi_min < 35) + odm_set_bb_reg(dm, 0x8d8, BIT(17), 0x0); + + ODM_RT_TRACE(dm, ODM_COMP_COMMON, "%s, rssi_min = %d\n", __func__, + dm->rssi_min); +} + +static void _set_tx_a_cali_value(struct phy_dm_struct *dm, u8 rf_path, + u8 offset, u8 tx_a_bias_offset) +{ + u32 modi_tx_a_value = 0; + u8 tmp1_byte = 0; + bool is_minus = false; + u8 comp_value = 0; + + switch (offset) { + case 0x0: + odm_set_rf_reg(dm, rf_path, 0x18, 0xFFFFF, 0X10124); + break; + case 0x1: + odm_set_rf_reg(dm, rf_path, 0x18, 0xFFFFF, 0X10524); + break; + case 0x2: + odm_set_rf_reg(dm, rf_path, 0x18, 0xFFFFF, 0X10924); + break; + case 0x3: + odm_set_rf_reg(dm, rf_path, 0x18, 0xFFFFF, 0X10D24); + break; + case 0x4: + odm_set_rf_reg(dm, rf_path, 0x18, 0xFFFFF, 0X30164); + break; + case 0x5: + odm_set_rf_reg(dm, rf_path, 0x18, 0xFFFFF, 0X30564); + break; + case 0x6: + odm_set_rf_reg(dm, rf_path, 0x18, 0xFFFFF, 0X30964); + break; + case 0x7: + odm_set_rf_reg(dm, rf_path, 0x18, 0xFFFFF, 0X30D64); + break; + case 0x8: + odm_set_rf_reg(dm, rf_path, 0x18, 0xFFFFF, 0X50195); + break; + case 0x9: + odm_set_rf_reg(dm, rf_path, 0x18, 0xFFFFF, 0X50595); + break; + case 0xa: + odm_set_rf_reg(dm, rf_path, 0x18, 0xFFFFF, 0X50995); + break; + case 0xb: + odm_set_rf_reg(dm, rf_path, 0x18, 0xFFFFF, 0X50D95); + break; + default: + ODM_RT_TRACE(dm, ODM_COMP_COMMON, + "Invalid TxA band offset...\n"); + return; + } + + /* Get TxA value */ + modi_tx_a_value = odm_get_rf_reg(dm, rf_path, 0x61, 0xFFFFF); + tmp1_byte = (u8)modi_tx_a_value & (BIT(3) | BIT(2) | BIT(1) | BIT(0)); + + /* check how much need to calibration */ + switch (tx_a_bias_offset) { + case 0xF6: + is_minus = true; + comp_value = 3; + break; + + case 0xF4: + is_minus = true; + comp_value = 2; + break; + + case 0xF2: + is_minus = true; + comp_value = 1; + break; + + case 0xF3: + is_minus = false; + comp_value = 1; + break; + + case 0xF5: + is_minus = false; + comp_value = 2; + break; + + case 0xF7: + is_minus = false; + comp_value = 3; + break; + + case 0xF9: + is_minus = false; + comp_value = 4; + break; + + /* do nothing case */ + case 0xF0: + default: + ODM_RT_TRACE(dm, ODM_COMP_COMMON, + "No need to do TxA bias current calibration\n"); + return; + } + + /* calc correct value to calibrate */ + if (is_minus) { + if (tmp1_byte >= comp_value) { + tmp1_byte -= comp_value; + /*modi_tx_a_value += tmp1_byte;*/ + } else { + tmp1_byte = 0; + } + } else { + tmp1_byte += comp_value; + if (tmp1_byte >= 7) + tmp1_byte = 7; + } + + /* Write back to RF reg */ + odm_set_rf_reg(dm, rf_path, 0x30, 0xFFFF, + (offset << 12 | (modi_tx_a_value & 0xFF0) | tmp1_byte)); +} + +static void _txa_bias_cali_4_each_path(struct phy_dm_struct *dm, u8 rf_path, + u8 efuse_value) +{ + /* switch on set TxA bias */ + odm_set_rf_reg(dm, rf_path, 0xEF, 0xFFFFF, 0x200); + + /* Set 12 sets of TxA value */ + _set_tx_a_cali_value(dm, rf_path, 0x0, efuse_value); + _set_tx_a_cali_value(dm, rf_path, 0x1, efuse_value); + _set_tx_a_cali_value(dm, rf_path, 0x2, efuse_value); + _set_tx_a_cali_value(dm, rf_path, 0x3, efuse_value); + _set_tx_a_cali_value(dm, rf_path, 0x4, efuse_value); + _set_tx_a_cali_value(dm, rf_path, 0x5, efuse_value); + _set_tx_a_cali_value(dm, rf_path, 0x6, efuse_value); + _set_tx_a_cali_value(dm, rf_path, 0x7, efuse_value); + _set_tx_a_cali_value(dm, rf_path, 0x8, efuse_value); + _set_tx_a_cali_value(dm, rf_path, 0x9, efuse_value); + _set_tx_a_cali_value(dm, rf_path, 0xa, efuse_value); + _set_tx_a_cali_value(dm, rf_path, 0xb, efuse_value); + + /* switch off set TxA bias */ + odm_set_rf_reg(dm, rf_path, 0xEF, 0xFFFFF, 0x0); +} + +/* + * for 8822B PCIE D-cut patch only + * Normal driver and MP driver need this patch + */ + +void phydm_txcurrentcalibration(struct phy_dm_struct *dm) +{ + u8 efuse0x3D8, efuse0x3D7; + u32 orig_rf0x18_path_a = 0, orig_rf0x18_path_b = 0; + + /* save original 0x18 value */ + orig_rf0x18_path_a = odm_get_rf_reg(dm, ODM_RF_PATH_A, 0x18, 0xFFFFF); + orig_rf0x18_path_b = odm_get_rf_reg(dm, ODM_RF_PATH_B, 0x18, 0xFFFFF); + + /* define efuse content */ + efuse0x3D8 = dm->efuse0x3d8; + efuse0x3D7 = dm->efuse0x3d7; + + /* check efuse content to judge whether need to calibration or not */ + if (efuse0x3D7 == 0xFF) { + ODM_RT_TRACE( + dm, ODM_COMP_COMMON, + "efuse content 0x3D7 == 0xFF, No need to do TxA cali\n"); + return; + } + + /* write RF register for calibration */ + _txa_bias_cali_4_each_path(dm, ODM_RF_PATH_A, efuse0x3D7); + _txa_bias_cali_4_each_path(dm, ODM_RF_PATH_B, efuse0x3D8); + + /* restore original 0x18 value */ + odm_set_rf_reg(dm, ODM_RF_PATH_A, 0x18, 0xFFFFF, orig_rf0x18_path_a); + odm_set_rf_reg(dm, ODM_RF_PATH_B, 0x18, 0xFFFFF, orig_rf0x18_path_b); +} + +void phydm_hwsetting_8822b(struct phy_dm_struct *dm) +{ + phydm_dynamic_switch_htstf_mumimo_8822b(dm); +} diff --git a/drivers/staging/rtlwifi/phydm/rtl8822b/phydm_rtl8822b.h b/drivers/staging/rtlwifi/phydm/rtl8822b/phydm_rtl8822b.h new file mode 100644 index 000000000000..af91a6f958ed --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/rtl8822b/phydm_rtl8822b.h @@ -0,0 +1,30 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef __ODM_RTL8822B_H__ +#define __ODM_RTL8822B_H__ + +void phydm_hwsetting_8822b(struct phy_dm_struct *dm); + +#endif /* #define __ODM_RTL8822B_H__ */ diff --git a/drivers/staging/rtlwifi/phydm/rtl8822b/version_rtl8822b.h b/drivers/staging/rtlwifi/phydm/rtl8822b/version_rtl8822b.h new file mode 100644 index 000000000000..ad0d32fce0a9 --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/rtl8822b/version_rtl8822b.h @@ -0,0 +1,34 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +/*RTL8822B PHY Parameters*/ +/* + * [Caution] + * Since 01/Aug/2015, the commit rules will be simplified. + * You do not need to fill up the version.h anymore, + * only the maintenance supervisor fills it before formal release. + */ +#define RELEASE_DATE_8822B 20161103 +#define COMMIT_BY_8822B "BB_JOE" +#define RELEASE_VERSION_8822B 67 diff --git a/drivers/staging/rtlwifi/phydm/rtl_phydm.c b/drivers/staging/rtlwifi/phydm/rtl_phydm.c new file mode 100644 index 000000000000..85e490d3601f --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/rtl_phydm.c @@ -0,0 +1,874 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#include "mp_precomp.h" +#include "phydm_precomp.h" +#include <linux/module.h> + +static int _rtl_phydm_init_com_info(struct rtl_priv *rtlpriv, + enum odm_ic_type ic_type, + struct rtl_phydm_params *params) +{ + struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv); + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + struct rtl_phy *rtlphy = &rtlpriv->phy; + struct rtl_mac *mac = rtl_mac(rtlpriv); + struct rtl_ps_ctl *ppsc = rtl_psc(rtlpriv); + struct rtl_efuse *rtlefuse = rtl_efuse(rtlpriv); + u8 odm_board_type = ODM_BOARD_DEFAULT; + u32 support_ability; + int i; + + dm->adapter = (void *)rtlpriv; + + odm_cmn_info_init(dm, ODM_CMNINFO_PLATFORM, ODM_CE); + + odm_cmn_info_init(dm, ODM_CMNINFO_IC_TYPE, ic_type); + + odm_cmn_info_init(dm, ODM_CMNINFO_INTERFACE, ODM_ITRF_PCIE); + + odm_cmn_info_init(dm, ODM_CMNINFO_MP_TEST_CHIP, params->mp_chip); + + odm_cmn_info_init(dm, ODM_CMNINFO_PATCH_ID, rtlhal->oem_id); + + odm_cmn_info_init(dm, ODM_CMNINFO_BWIFI_TEST, 1); + + if (rtlphy->rf_type == RF_1T1R) + odm_cmn_info_init(dm, ODM_CMNINFO_RF_TYPE, ODM_1T1R); + else if (rtlphy->rf_type == RF_1T2R) + odm_cmn_info_init(dm, ODM_CMNINFO_RF_TYPE, ODM_1T2R); + else if (rtlphy->rf_type == RF_2T2R) + odm_cmn_info_init(dm, ODM_CMNINFO_RF_TYPE, ODM_2T2R); + else if (rtlphy->rf_type == RF_2T2R_GREEN) + odm_cmn_info_init(dm, ODM_CMNINFO_RF_TYPE, ODM_2T2R_GREEN); + else if (rtlphy->rf_type == RF_2T3R) + odm_cmn_info_init(dm, ODM_CMNINFO_RF_TYPE, ODM_2T3R); + else if (rtlphy->rf_type == RF_2T4R) + odm_cmn_info_init(dm, ODM_CMNINFO_RF_TYPE, ODM_2T4R); + else if (rtlphy->rf_type == RF_3T3R) + odm_cmn_info_init(dm, ODM_CMNINFO_RF_TYPE, ODM_3T3R); + else if (rtlphy->rf_type == RF_3T4R) + odm_cmn_info_init(dm, ODM_CMNINFO_RF_TYPE, ODM_3T4R); + else if (rtlphy->rf_type == RF_4T4R) + odm_cmn_info_init(dm, ODM_CMNINFO_RF_TYPE, ODM_4T4R); + else + odm_cmn_info_init(dm, ODM_CMNINFO_RF_TYPE, ODM_XTXR); + + /* 1 ======= BoardType: ODM_CMNINFO_BOARD_TYPE ======= */ + if (rtlhal->external_lna_2g != 0) { + odm_board_type |= ODM_BOARD_EXT_LNA; + odm_cmn_info_init(dm, ODM_CMNINFO_EXT_LNA, 1); + } + if (rtlhal->external_lna_5g != 0) { + odm_board_type |= ODM_BOARD_EXT_LNA_5G; + odm_cmn_info_init(dm, ODM_CMNINFO_5G_EXT_LNA, 1); + } + if (rtlhal->external_pa_2g != 0) { + odm_board_type |= ODM_BOARD_EXT_PA; + odm_cmn_info_init(dm, ODM_CMNINFO_EXT_PA, 1); + } + if (rtlhal->external_pa_5g != 0) { + odm_board_type |= ODM_BOARD_EXT_PA_5G; + odm_cmn_info_init(dm, ODM_CMNINFO_5G_EXT_PA, 1); + } + if (rtlpriv->cfg->ops->get_btc_status()) + odm_board_type |= ODM_BOARD_BT; + + odm_cmn_info_init(dm, ODM_CMNINFO_BOARD_TYPE, odm_board_type); + /* 1 ============== End of BoardType ============== */ + + odm_cmn_info_init(dm, ODM_CMNINFO_GPA, rtlhal->type_gpa); + odm_cmn_info_init(dm, ODM_CMNINFO_APA, rtlhal->type_apa); + odm_cmn_info_init(dm, ODM_CMNINFO_GLNA, rtlhal->type_glna); + odm_cmn_info_init(dm, ODM_CMNINFO_ALNA, rtlhal->type_alna); + + odm_cmn_info_init(dm, ODM_CMNINFO_RFE_TYPE, rtlhal->rfe_type); + + odm_cmn_info_init(dm, ODM_CMNINFO_EXT_TRSW, 0); + + /*Add by YuChen for kfree init*/ + odm_cmn_info_init(dm, ODM_CMNINFO_REGRFKFREEENABLE, 2); + odm_cmn_info_init(dm, ODM_CMNINFO_RFKFREEENABLE, 0); + + /*Antenna diversity relative parameters*/ + odm_cmn_info_hook(dm, ODM_CMNINFO_ANT_DIV, + &rtlefuse->antenna_div_cfg); + odm_cmn_info_init(dm, ODM_CMNINFO_RF_ANTENNA_TYPE, + rtlefuse->antenna_div_type); + odm_cmn_info_init(dm, ODM_CMNINFO_BE_FIX_TX_ANT, 0); + odm_cmn_info_init(dm, ODM_CMNINFO_WITH_EXT_ANTENNA_SWITCH, 0); + + /* (8822B) efuse 0x3D7 & 0x3D8 for TX PA bias */ + odm_cmn_info_init(dm, ODM_CMNINFO_EFUSE0X3D7, params->efuse0x3d7); + odm_cmn_info_init(dm, ODM_CMNINFO_EFUSE0X3D8, params->efuse0x3d8); + + /*Add by YuChen for adaptivity init*/ + odm_cmn_info_hook(dm, ODM_CMNINFO_ADAPTIVITY, + &rtlpriv->phydm.adaptivity_en); + phydm_adaptivity_info_init(dm, PHYDM_ADAPINFO_CARRIER_SENSE_ENABLE, + false); + phydm_adaptivity_info_init(dm, PHYDM_ADAPINFO_DCBACKOFF, 0); + phydm_adaptivity_info_init(dm, PHYDM_ADAPINFO_DYNAMICLINKADAPTIVITY, + false); + phydm_adaptivity_info_init(dm, PHYDM_ADAPINFO_TH_L2H_INI, 0); + phydm_adaptivity_info_init(dm, PHYDM_ADAPINFO_TH_EDCCA_HL_DIFF, 0); + + odm_cmn_info_init(dm, ODM_CMNINFO_IQKFWOFFLOAD, 0); + + /* Pointer reference */ + odm_cmn_info_hook(dm, ODM_CMNINFO_TX_UNI, + &rtlpriv->stats.txbytesunicast); + odm_cmn_info_hook(dm, ODM_CMNINFO_RX_UNI, + &rtlpriv->stats.rxbytesunicast); + odm_cmn_info_hook(dm, ODM_CMNINFO_BAND, &rtlhal->current_bandtype); + odm_cmn_info_hook(dm, ODM_CMNINFO_FORCED_RATE, + &rtlpriv->phydm.forced_data_rate); + odm_cmn_info_hook(dm, ODM_CMNINFO_FORCED_IGI_LB, + &rtlpriv->phydm.forced_igi_lb); + + odm_cmn_info_hook(dm, ODM_CMNINFO_SEC_CHNL_OFFSET, + &mac->cur_40_prime_sc); + odm_cmn_info_hook(dm, ODM_CMNINFO_BW, &rtlphy->current_chan_bw); + odm_cmn_info_hook(dm, ODM_CMNINFO_CHNL, &rtlphy->current_channel); + + odm_cmn_info_hook(dm, ODM_CMNINFO_SCAN, &mac->act_scanning); + odm_cmn_info_hook(dm, ODM_CMNINFO_POWER_SAVING, + &ppsc->dot11_psmode); /* may add new boolean flag */ + /*Add by Yuchen for phydm beamforming*/ + odm_cmn_info_hook(dm, ODM_CMNINFO_TX_TP, + &rtlpriv->stats.txbytesunicast_inperiod_tp); + odm_cmn_info_hook(dm, ODM_CMNINFO_RX_TP, + &rtlpriv->stats.rxbytesunicast_inperiod_tp); + odm_cmn_info_hook(dm, ODM_CMNINFO_ANT_TEST, + &rtlpriv->phydm.antenna_test); + for (i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++) + odm_cmn_info_ptr_array_hook(dm, ODM_CMNINFO_STA_STATUS, i, + NULL); + + phydm_init_debug_setting(dm); + + odm_cmn_info_init(dm, ODM_CMNINFO_FAB_VER, params->fab_ver); + odm_cmn_info_init(dm, ODM_CMNINFO_CUT_VER, params->cut_ver); + + /* after ifup, ability is updated again */ + support_ability = ODM_RF_CALIBRATION | ODM_RF_TX_PWR_TRACK; + odm_cmn_info_update(dm, ODM_CMNINFO_ABILITY, support_ability); + + return 0; +} + +static int rtl_phydm_init_priv(struct rtl_priv *rtlpriv, + struct rtl_phydm_params *params) +{ + struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv); + enum odm_ic_type ic; + + if (IS_HARDWARE_TYPE_8822B(rtlpriv)) + ic = ODM_RTL8822B; + else + return 0; + + rtlpriv->phydm.internal = + kzalloc(sizeof(struct phy_dm_struct), GFP_KERNEL); + + _rtl_phydm_init_com_info(rtlpriv, ic, params); + + odm_init_all_timers(dm); + + return 1; +} + +static int rtl_phydm_deinit_priv(struct rtl_priv *rtlpriv) +{ + struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv); + + odm_cancel_all_timers(dm); + + kfree(rtlpriv->phydm.internal); + rtlpriv->phydm.internal = NULL; + + return 0; +} + +static bool rtl_phydm_load_txpower_by_rate(struct rtl_priv *rtlpriv) +{ + struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv); + enum hal_status status; + + status = odm_config_bb_with_header_file(dm, CONFIG_BB_PHY_REG_PG); + if (status != HAL_STATUS_SUCCESS) + return false; + + return true; +} + +static bool rtl_phydm_load_txpower_limit(struct rtl_priv *rtlpriv) +{ + struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv); + enum hal_status status; + + if (IS_HARDWARE_TYPE_8822B(rtlpriv)) { + odm_read_and_config_mp_8822b_txpwr_lmt(dm); + } else { + status = odm_config_rf_with_header_file(dm, CONFIG_RF_TXPWR_LMT, + 0); + if (status != HAL_STATUS_SUCCESS) + return false; + } + + return true; +} + +static int rtl_phydm_init_dm(struct rtl_priv *rtlpriv) +{ + struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv); + u32 support_ability = 0; + + /* clang-format off */ + support_ability = 0 + | ODM_BB_DIG + | ODM_BB_RA_MASK + | ODM_BB_DYNAMIC_TXPWR + | ODM_BB_FA_CNT + | ODM_BB_RSSI_MONITOR + | ODM_BB_CCK_PD + /* | ODM_BB_PWR_SAVE*/ + | ODM_BB_CFO_TRACKING + | ODM_MAC_EDCA_TURBO + | ODM_RF_TX_PWR_TRACK + | ODM_RF_CALIBRATION + | ODM_BB_NHM_CNT + /* | ODM_BB_PWR_TRAIN*/ + ; + /* clang-format on */ + + odm_cmn_info_update(dm, ODM_CMNINFO_ABILITY, support_ability); + + odm_dm_init(dm); + + return 0; +} + +static int rtl_phydm_deinit_dm(struct rtl_priv *rtlpriv) +{ + return 0; +} + +static int rtl_phydm_reset_dm(struct rtl_priv *rtlpriv) +{ + struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv); + + odm_dm_reset(dm); + + return 0; +} + +static bool rtl_phydm_parameter_init(struct rtl_priv *rtlpriv, bool post) +{ + struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv); + + if (IS_HARDWARE_TYPE_8822B(rtlpriv)) + return config_phydm_parameter_init(dm, post ? ODM_POST_SETTING : + ODM_PRE_SETTING); + + return false; +} + +static bool rtl_phydm_phy_bb_config(struct rtl_priv *rtlpriv) +{ + struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv); + enum hal_status status; + + status = odm_config_bb_with_header_file(dm, CONFIG_BB_PHY_REG); + if (status != HAL_STATUS_SUCCESS) + return false; + + status = odm_config_bb_with_header_file(dm, CONFIG_BB_AGC_TAB); + if (status != HAL_STATUS_SUCCESS) + return false; + + return true; +} + +static bool rtl_phydm_phy_rf_config(struct rtl_priv *rtlpriv) +{ + struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv); + struct rtl_phy *rtlphy = &rtlpriv->phy; + enum hal_status status; + enum odm_rf_radio_path rfpath; + + for (rfpath = 0; rfpath < rtlphy->num_total_rfpath; rfpath++) { + status = odm_config_rf_with_header_file(dm, CONFIG_RF_RADIO, + rfpath); + if (status != HAL_STATUS_SUCCESS) + return false; + } + + status = odm_config_rf_with_tx_pwr_track_header_file(dm); + if (status != HAL_STATUS_SUCCESS) + return false; + + return true; +} + +static bool rtl_phydm_phy_mac_config(struct rtl_priv *rtlpriv) +{ + struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv); + enum hal_status status; + + status = odm_config_mac_with_header_file(dm); + if (status != HAL_STATUS_SUCCESS) + return false; + + return true; +} + +static bool rtl_phydm_trx_mode(struct rtl_priv *rtlpriv, + enum radio_mask tx_path, enum radio_mask rx_path, + bool is_tx2_path) +{ + struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv); + + if (IS_HARDWARE_TYPE_8822B(rtlpriv)) + return config_phydm_trx_mode_8822b(dm, + (enum odm_rf_path)tx_path, + (enum odm_rf_path)rx_path, + is_tx2_path); + + return false; +} + +static bool rtl_phydm_watchdog(struct rtl_priv *rtlpriv) +{ + struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv); + struct rtl_mac *mac = rtl_mac(rtlpriv); + struct rtl_ps_ctl *ppsc = rtl_psc(rtlpriv); + bool fw_current_inpsmode = false; + bool fw_ps_awake = true; + u8 is_linked = false; + u8 bsta_state = false; + u8 is_bt_enabled = false; + + /* check whether do watchdog */ + rtlpriv->cfg->ops->get_hw_reg(rtlpriv->hw, HW_VAR_FW_PSMODE_STATUS, + (u8 *)(&fw_current_inpsmode)); + rtlpriv->cfg->ops->get_hw_reg(rtlpriv->hw, HW_VAR_FWLPS_RF_ON, + (u8 *)(&fw_ps_awake)); + if (ppsc->p2p_ps_info.p2p_ps_mode) + fw_ps_awake = false; + + if ((ppsc->rfpwr_state == ERFON) && + ((!fw_current_inpsmode) && fw_ps_awake) && + (!ppsc->rfchange_inprogress)) + ; + else + return false; + + /* update common info before doing watchdog */ + if (mac->link_state >= MAC80211_LINKED) { + is_linked = true; + if (mac->vif && mac->vif->type == NL80211_IFTYPE_STATION) + bsta_state = true; + } + + if (rtlpriv->cfg->ops->get_btc_status()) + is_bt_enabled = !rtlpriv->btcoexist.btc_ops->btc_is_bt_disabled( + rtlpriv); + + odm_cmn_info_update(dm, ODM_CMNINFO_LINK, is_linked); + odm_cmn_info_update(dm, ODM_CMNINFO_STATION_STATE, bsta_state); + odm_cmn_info_update(dm, ODM_CMNINFO_BT_ENABLED, is_bt_enabled); + + /* do watchdog */ + odm_dm_watchdog(dm); + + return true; +} + +static bool rtl_phydm_switch_band(struct rtl_priv *rtlpriv, u8 central_ch) +{ + struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv); + + if (IS_HARDWARE_TYPE_8822B(rtlpriv)) + return config_phydm_switch_band_8822b(dm, central_ch); + + return false; +} + +static bool rtl_phydm_switch_channel(struct rtl_priv *rtlpriv, u8 central_ch) +{ + struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv); + + if (IS_HARDWARE_TYPE_8822B(rtlpriv)) + return config_phydm_switch_channel_8822b(dm, central_ch); + + return false; +} + +static bool rtl_phydm_switch_bandwidth(struct rtl_priv *rtlpriv, + u8 primary_ch_idx, + enum ht_channel_width bandwidth) +{ + struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv); + enum odm_bw odm_bw = (enum odm_bw)bandwidth; + + if (IS_HARDWARE_TYPE_8822B(rtlpriv)) + return config_phydm_switch_bandwidth_8822b(dm, primary_ch_idx, + odm_bw); + + return false; +} + +static bool rtl_phydm_iq_calibrate(struct rtl_priv *rtlpriv) +{ + struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv); + + if (IS_HARDWARE_TYPE_8822B(rtlpriv)) + phy_iq_calibrate_8822b(dm, false); + else + return false; + + return true; +} + +static bool rtl_phydm_clear_txpowertracking_state(struct rtl_priv *rtlpriv) +{ + struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv); + + odm_clear_txpowertracking_state(dm); + + return true; +} + +static bool rtl_phydm_pause_dig(struct rtl_priv *rtlpriv, bool pause) +{ + struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv); + + if (pause) + odm_pause_dig(dm, PHYDM_PAUSE, PHYDM_PAUSE_LEVEL_0, 0x1e); + else /* resume */ + odm_pause_dig(dm, PHYDM_RESUME, PHYDM_PAUSE_LEVEL_0, 0xff); + + return true; +} + +static u32 rtl_phydm_read_rf_reg(struct rtl_priv *rtlpriv, + enum radio_path rfpath, u32 addr, u32 mask) +{ + struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv); + enum odm_rf_radio_path odm_rfpath = (enum odm_rf_radio_path)rfpath; + + if (IS_HARDWARE_TYPE_8822B(rtlpriv)) + return config_phydm_read_rf_reg_8822b(dm, odm_rfpath, addr, + mask); + + return -1; +} + +static bool rtl_phydm_write_rf_reg(struct rtl_priv *rtlpriv, + enum radio_path rfpath, u32 addr, u32 mask, + u32 data) +{ + struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv); + enum odm_rf_radio_path odm_rfpath = (enum odm_rf_radio_path)rfpath; + + if (IS_HARDWARE_TYPE_8822B(rtlpriv)) + return config_phydm_write_rf_reg_8822b(dm, odm_rfpath, addr, + mask, data); + + return false; +} + +static u8 rtl_phydm_read_txagc(struct rtl_priv *rtlpriv, enum radio_path rfpath, + u8 hw_rate) +{ + struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv); + enum odm_rf_radio_path odm_rfpath = (enum odm_rf_radio_path)rfpath; + + if (IS_HARDWARE_TYPE_8822B(rtlpriv)) + return config_phydm_read_txagc_8822b(dm, odm_rfpath, hw_rate); + + return -1; +} + +static bool rtl_phydm_write_txagc(struct rtl_priv *rtlpriv, u32 power_index, + enum radio_path rfpath, u8 hw_rate) +{ + struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv); + enum odm_rf_radio_path odm_rfpath = (enum odm_rf_radio_path)rfpath; + + if (IS_HARDWARE_TYPE_8822B(rtlpriv)) + return config_phydm_write_txagc_8822b(dm, power_index, + odm_rfpath, hw_rate); + + return false; +} + +static bool rtl_phydm_c2h_content_parsing(struct rtl_priv *rtlpriv, u8 cmd_id, + u8 cmd_len, u8 *content) +{ + struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv); + + if (phydm_c2H_content_parsing(dm, cmd_id, cmd_len, content)) + return true; + + return false; +} + +static bool rtl_phydm_query_phy_status(struct rtl_priv *rtlpriv, u8 *phystrpt, + struct ieee80211_hdr *hdr, + struct rtl_stats *pstatus) +{ + /* NOTE: phystrpt may be NULL, and need to fill default value */ + + struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv); + struct rtl_efuse *rtlefuse = rtl_efuse(rtlpriv); + struct rtl_mac *mac = rtl_mac(rtlpriv); + struct dm_per_pkt_info pktinfo; /* input of pydm */ + struct dm_phy_status_info phy_info; /* output of phydm */ + __le16 fc = hdr->frame_control; + + /* fill driver pstatus */ + ether_addr_copy(pstatus->psaddr, ieee80211_get_SA(hdr)); + + /* fill pktinfo */ + memset(&pktinfo, 0, sizeof(pktinfo)); + + pktinfo.data_rate = pstatus->rate; + + if (rtlpriv->mac80211.opmode == NL80211_IFTYPE_STATION) { + pktinfo.station_id = 0; + } else { + /* TODO: use rtl_find_sta() to find ID */ + pktinfo.station_id = 0xFF; + } + + pktinfo.is_packet_match_bssid = + (!ieee80211_is_ctl(fc) && + (ether_addr_equal(mac->bssid, + ieee80211_has_tods(fc) ? + hdr->addr1 : + ieee80211_has_fromds(fc) ? + hdr->addr2 : + hdr->addr3)) && + (!pstatus->hwerror) && (!pstatus->crc) && (!pstatus->icv)); + pktinfo.is_packet_to_self = + pktinfo.is_packet_match_bssid && + (ether_addr_equal(hdr->addr1, rtlefuse->dev_addr)); + pktinfo.is_to_self = (!pstatus->icv) && (!pstatus->crc) && + (ether_addr_equal(hdr->addr1, rtlefuse->dev_addr)); + pktinfo.is_packet_beacon = (ieee80211_is_beacon(fc) ? true : false); + + /* query phy status */ + if (phystrpt) + odm_phy_status_query(dm, &phy_info, phystrpt, &pktinfo); + else + memset(&phy_info, 0, sizeof(phy_info)); + + /* copy phy_info from phydm to driver */ + pstatus->rx_pwdb_all = phy_info.rx_pwdb_all; + pstatus->bt_rx_rssi_percentage = phy_info.bt_rx_rssi_percentage; + pstatus->recvsignalpower = phy_info.recv_signal_power; + pstatus->signalquality = phy_info.signal_quality; + pstatus->rx_mimo_signalquality[0] = phy_info.rx_mimo_signal_quality[0]; + pstatus->rx_mimo_signalquality[1] = phy_info.rx_mimo_signal_quality[1]; + pstatus->rx_packet_bw = + phy_info.band_width; /* HT_CHANNEL_WIDTH_20 <- ODM_BW20M */ + + /* fill driver pstatus */ + pstatus->packet_matchbssid = pktinfo.is_packet_match_bssid; + pstatus->packet_toself = pktinfo.is_packet_to_self; + pstatus->packet_beacon = pktinfo.is_packet_beacon; + + return true; +} + +static u8 rtl_phydm_rate_id_mapping(struct rtl_priv *rtlpriv, + enum wireless_mode wireless_mode, + enum rf_type rf_type, + enum ht_channel_width bw) +{ + struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv); + + return phydm_rate_id_mapping(dm, wireless_mode, rf_type, bw); +} + +static bool rtl_phydm_get_ra_bitmap(struct rtl_priv *rtlpriv, + enum wireless_mode wireless_mode, + enum rf_type rf_type, + enum ht_channel_width bw, + u8 tx_rate_level, /* 0~6 */ + u32 *tx_bitmap_msb, + u32 *tx_bitmap_lsb) +{ + struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv); + const u8 mimo_ps_enable = 0; + const u8 disable_cck_rate = 0; + + phydm_update_hal_ra_mask(dm, wireless_mode, rf_type, bw, mimo_ps_enable, + disable_cck_rate, tx_bitmap_msb, tx_bitmap_lsb, + tx_rate_level); + + return true; +} + +static u8 _rtl_phydm_get_macid(struct rtl_priv *rtlpriv, + struct ieee80211_sta *sta) +{ + struct rtl_mac *mac = rtl_mac(rtlpriv); + + if (mac->opmode == NL80211_IFTYPE_STATION || + mac->opmode == NL80211_IFTYPE_MESH_POINT) { + return 0; + } else if (mac->opmode == NL80211_IFTYPE_AP || + mac->opmode == NL80211_IFTYPE_ADHOC) + return sta->aid + 1; + + return 0; +} + +static bool rtl_phydm_add_sta(struct rtl_priv *rtlpriv, + struct ieee80211_sta *sta) +{ + struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv); + struct rtl_sta_info *sta_entry = (struct rtl_sta_info *)sta->drv_priv; + u8 mac_id = _rtl_phydm_get_macid(rtlpriv, sta); + + odm_cmn_info_ptr_array_hook(dm, ODM_CMNINFO_STA_STATUS, mac_id, + sta_entry); + + return true; +} + +static bool rtl_phydm_del_sta(struct rtl_priv *rtlpriv, + struct ieee80211_sta *sta) +{ + struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv); + u8 mac_id = _rtl_phydm_get_macid(rtlpriv, sta); + + odm_cmn_info_ptr_array_hook(dm, ODM_CMNINFO_STA_STATUS, mac_id, NULL); + + return true; +} + +static u32 rtl_phydm_get_version(struct rtl_priv *rtlpriv) +{ + u32 ver = 0; + + if (IS_HARDWARE_TYPE_8822B(rtlpriv)) + ver = RELEASE_VERSION_8822B; + + return ver; +} + +static bool rtl_phydm_modify_ra_pcr_threshold(struct rtl_priv *rtlpriv, + u8 ra_offset_direction, + u8 ra_threshold_offset) +{ + struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv); + + phydm_modify_RA_PCR_threshold(dm, ra_offset_direction, + ra_threshold_offset); + + return true; +} + +static u32 rtl_phydm_query_counter(struct rtl_priv *rtlpriv, + const char *info_type) +{ + struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv); + static const struct query_entry { + const char *query_name; + enum phydm_info_query query_id; + } query_table[] = { +#define QUERY_ENTRY(name) {#name, name} + QUERY_ENTRY(PHYDM_INFO_FA_OFDM), + QUERY_ENTRY(PHYDM_INFO_FA_CCK), + QUERY_ENTRY(PHYDM_INFO_CCA_OFDM), + QUERY_ENTRY(PHYDM_INFO_CCA_CCK), + QUERY_ENTRY(PHYDM_INFO_CRC32_OK_CCK), + QUERY_ENTRY(PHYDM_INFO_CRC32_OK_LEGACY), + QUERY_ENTRY(PHYDM_INFO_CRC32_OK_HT), + QUERY_ENTRY(PHYDM_INFO_CRC32_OK_VHT), + QUERY_ENTRY(PHYDM_INFO_CRC32_ERROR_CCK), + QUERY_ENTRY(PHYDM_INFO_CRC32_ERROR_LEGACY), + QUERY_ENTRY(PHYDM_INFO_CRC32_ERROR_HT), + QUERY_ENTRY(PHYDM_INFO_CRC32_ERROR_VHT), + }; +#define QUERY_TABLE_SIZE ARRAY_SIZE(query_table) + + int i; + const struct query_entry *entry; + + if (!strcmp(info_type, "IQK_TOTAL")) + return dm->n_iqk_cnt; + + if (!strcmp(info_type, "IQK_OK")) + return dm->n_iqk_ok_cnt; + + if (!strcmp(info_type, "IQK_FAIL")) + return dm->n_iqk_fail_cnt; + + for (i = 0; i < QUERY_TABLE_SIZE; i++) { + entry = &query_table[i]; + + if (!strcmp(info_type, entry->query_name)) + return phydm_cmn_info_query(dm, entry->query_id); + } + + pr_err("Unrecognized info_type:%s!!!!:\n", info_type); + + return 0xDEADDEAD; +} + +static bool rtl_phydm_debug_cmd(struct rtl_priv *rtlpriv, char *in, u32 in_len, + char *out, u32 out_len) +{ + struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv); + + phydm_cmd(dm, in, in_len, 1, out, out_len); + + return true; +} + +static struct rtl_phydm_ops rtl_phydm_operation = { + /* init/deinit priv */ + .phydm_init_priv = rtl_phydm_init_priv, + .phydm_deinit_priv = rtl_phydm_deinit_priv, + .phydm_load_txpower_by_rate = rtl_phydm_load_txpower_by_rate, + .phydm_load_txpower_limit = rtl_phydm_load_txpower_limit, + + /* init hw */ + .phydm_init_dm = rtl_phydm_init_dm, + .phydm_deinit_dm = rtl_phydm_deinit_dm, + .phydm_reset_dm = rtl_phydm_reset_dm, + .phydm_parameter_init = rtl_phydm_parameter_init, + .phydm_phy_bb_config = rtl_phydm_phy_bb_config, + .phydm_phy_rf_config = rtl_phydm_phy_rf_config, + .phydm_phy_mac_config = rtl_phydm_phy_mac_config, + .phydm_trx_mode = rtl_phydm_trx_mode, + + /* watchdog */ + .phydm_watchdog = rtl_phydm_watchdog, + + /* channel */ + .phydm_switch_band = rtl_phydm_switch_band, + .phydm_switch_channel = rtl_phydm_switch_channel, + .phydm_switch_bandwidth = rtl_phydm_switch_bandwidth, + .phydm_iq_calibrate = rtl_phydm_iq_calibrate, + .phydm_clear_txpowertracking_state = + rtl_phydm_clear_txpowertracking_state, + .phydm_pause_dig = rtl_phydm_pause_dig, + + /* read/write reg */ + .phydm_read_rf_reg = rtl_phydm_read_rf_reg, + .phydm_write_rf_reg = rtl_phydm_write_rf_reg, + .phydm_read_txagc = rtl_phydm_read_txagc, + .phydm_write_txagc = rtl_phydm_write_txagc, + + /* RX */ + .phydm_c2h_content_parsing = rtl_phydm_c2h_content_parsing, + .phydm_query_phy_status = rtl_phydm_query_phy_status, + + /* TX */ + .phydm_rate_id_mapping = rtl_phydm_rate_id_mapping, + .phydm_get_ra_bitmap = rtl_phydm_get_ra_bitmap, + + /* STA */ + .phydm_add_sta = rtl_phydm_add_sta, + .phydm_del_sta = rtl_phydm_del_sta, + + /* BTC */ + .phydm_get_version = rtl_phydm_get_version, + .phydm_modify_ra_pcr_threshold = rtl_phydm_modify_ra_pcr_threshold, + .phydm_query_counter = rtl_phydm_query_counter, + + /* debug */ + .phydm_debug_cmd = rtl_phydm_debug_cmd, +}; + +struct rtl_phydm_ops *rtl_phydm_get_ops_pointer(void) +{ + return &rtl_phydm_operation; +} +EXPORT_SYMBOL(rtl_phydm_get_ops_pointer); + +/* ******************************************************** + * Define phydm callout function in below + * ******************************************************** + */ + +u8 phy_get_tx_power_index(void *adapter, u8 rf_path, u8 rate, + enum ht_channel_width bandwidth, u8 channel) +{ + /* rate: DESC_RATE1M */ + struct rtl_priv *rtlpriv = (struct rtl_priv *)adapter; + + return rtlpriv->cfg->ops->get_txpower_index(rtlpriv->hw, rf_path, rate, + bandwidth, channel); +} + +void phy_set_tx_power_index_by_rs(void *adapter, u8 ch, u8 path, u8 rs) +{ + struct rtl_priv *rtlpriv = (struct rtl_priv *)adapter; + + return rtlpriv->cfg->ops->set_tx_power_index_by_rs(rtlpriv->hw, ch, + path, rs); +} + +void phy_store_tx_power_by_rate(void *adapter, u32 band, u32 rfpath, u32 txnum, + u32 regaddr, u32 bitmask, u32 data) +{ + struct rtl_priv *rtlpriv = (struct rtl_priv *)adapter; + + rtlpriv->cfg->ops->store_tx_power_by_rate( + rtlpriv->hw, band, rfpath, txnum, regaddr, bitmask, data); +} + +void phy_set_tx_power_limit(void *dm, u8 *regulation, u8 *band, u8 *bandwidth, + u8 *rate_section, u8 *rf_path, u8 *channel, + u8 *power_limit) +{ + struct rtl_priv *rtlpriv = + (struct rtl_priv *)((struct phy_dm_struct *)dm)->adapter; + + rtlpriv->cfg->ops->phy_set_txpower_limit(rtlpriv->hw, regulation, band, + bandwidth, rate_section, + rf_path, channel, power_limit); +} + +void rtl_hal_update_ra_mask(void *adapter, struct rtl_sta_info *psta, + u8 rssi_level) +{ + struct rtl_priv *rtlpriv = (struct rtl_priv *)adapter; + struct ieee80211_sta *sta = + container_of((void *)psta, struct ieee80211_sta, drv_priv); + + rtlpriv->cfg->ops->update_rate_tbl(rtlpriv->hw, sta, rssi_level, false); +} + +MODULE_AUTHOR("Realtek WlanFAE <wlanfae@realtek.com>"); +MODULE_AUTHOR("Larry Finger <Larry.FInger@lwfinger.net>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Realtek 802.11n PCI wireless core"); diff --git a/drivers/staging/rtlwifi/phydm/rtl_phydm.h b/drivers/staging/rtlwifi/phydm/rtl_phydm.h new file mode 100644 index 000000000000..483d2418699b --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/rtl_phydm.h @@ -0,0 +1,45 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef __RTL_PHYDM_H__ +#define __RTL_PHYDM_H__ + +struct rtl_phydm_ops *rtl_phydm_get_ops_pointer(void); + +#define rtlpriv_to_phydm(priv) \ + ((struct phy_dm_struct *)((priv)->phydm.internal)) + +u8 phy_get_tx_power_index(void *adapter, u8 rf_path, u8 rate, + enum ht_channel_width bandwidth, u8 channel); +void phy_set_tx_power_index_by_rs(void *adapter, u8 ch, u8 path, u8 rs); +void phy_store_tx_power_by_rate(void *adapter, u32 band, u32 rfpath, u32 txnum, + u32 regaddr, u32 bitmask, u32 data); +void phy_set_tx_power_limit(void *dm, u8 *regulation, u8 *band, u8 *bandwidth, + u8 *rate_section, u8 *rf_path, u8 *channel, + u8 *power_limit); + +void rtl_hal_update_ra_mask(void *adapter, struct rtl_sta_info *psta, + u8 rssi_level); + +#endif diff --git a/drivers/staging/rtlwifi/phydm/txbf/halcomtxbf.h b/drivers/staging/rtlwifi/phydm/txbf/halcomtxbf.h new file mode 100644 index 000000000000..6cacca12d792 --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/txbf/halcomtxbf.h @@ -0,0 +1,67 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef __HAL_COM_TXBF_H__ +#define __HAL_COM_TXBF_H__ + +enum txbf_set_type { + TXBF_SET_SOUNDING_ENTER, + TXBF_SET_SOUNDING_LEAVE, + TXBF_SET_SOUNDING_RATE, + TXBF_SET_SOUNDING_STATUS, + TXBF_SET_SOUNDING_FW_NDPA, + TXBF_SET_SOUNDING_CLK, + TXBF_SET_TX_PATH_RESET, + TXBF_SET_GET_TX_RATE +}; + +enum txbf_get_type { + TXBF_GET_EXPLICIT_BEAMFORMEE, + TXBF_GET_EXPLICIT_BEAMFORMER, + TXBF_GET_MU_MIMO_STA, + TXBF_GET_MU_MIMO_AP +}; + +/* 2 HAL TXBF related */ +struct _HAL_TXBF_INFO { + u8 txbf_idx; + u8 ndpa_idx; + u8 BW; + u8 rate; + + struct timer_list txbf_fw_ndpa_timer; +}; + +#define hal_com_txbf_beamform_init(dm_void) NULL +#define hal_com_txbf_config_gtab(dm_void) NULL +#define hal_com_txbf_enter_work_item_callback(_adapter) NULL +#define hal_com_txbf_leave_work_item_callback(_adapter) NULL +#define hal_com_txbf_fw_ndpa_work_item_callback(_adapter) NULL +#define hal_com_txbf_clk_work_item_callback(_adapter) NULL +#define hal_com_txbf_rate_work_item_callback(_adapter) NULL +#define hal_com_txbf_fw_ndpa_timer_callback(_adapter) NULL +#define hal_com_txbf_status_work_item_callback(_adapter) NULL +#define hal_com_txbf_get(_adapter, _get_type, _pout_buf) + +#endif /* #ifndef __HAL_COM_TXBF_H__ */ diff --git a/drivers/staging/rtlwifi/phydm/txbf/haltxbf8822b.h b/drivers/staging/rtlwifi/phydm/txbf/haltxbf8822b.h new file mode 100644 index 000000000000..5c92c4326f7e --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/txbf/haltxbf8822b.h @@ -0,0 +1,39 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef __HAL_TXBF_8822B_H__ +#define __HAL_TXBF_8822B_H__ + +#define hal_txbf_8822b_enter(dm_void, idx) +#define hal_txbf_8822b_leave(dm_void, idx) +#define hal_txbf_8822b_status(dm_void, idx) +#define hal_txbf_8822b_fw_txbf(dm_void, idx) +#define hal_txbf_8822b_config_gtab(dm_void) + +void phydm_8822btxbf_rfmode(void *dm_void, u8 su_bfee_cnt, u8 mu_bfee_cnt); + +void phydm_8822b_sutxbfer_workaroud(void *dm_void, bool enable_su_bfer, u8 nc, + u8 nr, u8 ng, u8 CB, u8 BW, bool is_vht); + +#endif diff --git a/drivers/staging/rtlwifi/phydm/txbf/haltxbfinterface.h b/drivers/staging/rtlwifi/phydm/txbf/haltxbfinterface.h new file mode 100644 index 000000000000..82aeac1ff3e0 --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/txbf/haltxbfinterface.h @@ -0,0 +1,38 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef __HAL_TXBF_INTERFACE_H__ +#define __HAL_TXBF_INTERFACE_H__ + +#define beamforming_get_ndpa_frame(dm, _pdu_os) +#define beamforming_get_report_frame(adapter, precv_frame) RT_STATUS_FAILURE +#define send_fw_ht_ndpa_packet(dm_void, RA, BW) +#define send_sw_ht_ndpa_packet(dm_void, RA, BW) +#define send_fw_vht_ndpa_packet(dm_void, RA, AID, BW) +#define send_sw_vht_ndpa_packet(dm_void, RA, AID, BW) +#define send_sw_vht_gid_mgnt_frame(dm_void, RA, idx) +#define send_sw_vht_bf_report_poll(dm_void, RA, is_final_poll) +#define send_sw_vht_mu_ndpa_packet(dm_void, BW) + +#endif diff --git a/drivers/staging/rtlwifi/phydm/txbf/haltxbfjaguar.h b/drivers/staging/rtlwifi/phydm/txbf/haltxbfjaguar.h new file mode 100644 index 000000000000..c5ddd9cb9cd5 --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/txbf/haltxbfjaguar.h @@ -0,0 +1,36 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef __HAL_TXBF_JAGUAR_H__ +#define __HAL_TXBF_JAGUAR_H__ + +#define hal_txbf_8812a_set_ndpa_rate(dm_void, BW, rate) +#define hal_txbf_jaguar_enter(dm_void, idx) +#define hal_txbf_jaguar_leave(dm_void, idx) +#define hal_txbf_jaguar_status(dm_void, idx) +#define hal_txbf_jaguar_fw_txbf(dm_void, idx) +#define hal_txbf_jaguar_patch(dm_void, operation) +#define hal_txbf_jaguar_clk_8812a(dm_void) + +#endif /* #ifndef __HAL_TXBF_JAGUAR_H__ */ diff --git a/drivers/staging/rtlwifi/phydm/txbf/phydm_hal_txbf_api.h b/drivers/staging/rtlwifi/phydm/txbf/phydm_hal_txbf_api.h new file mode 100644 index 000000000000..41358fce2875 --- /dev/null +++ b/drivers/staging/rtlwifi/phydm/txbf/phydm_hal_txbf_api.h @@ -0,0 +1,41 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#ifndef __PHYDM_HAL_TXBF_API_H__ +#define __PHYDM_HAL_TXBF_API_H__ + +#define tx_bf_nr(a, b) ((a > b) ? (b) : (a)) + +u8 beamforming_get_htndp_tx_rate(void *dm_void, u8 comp_steering_num_of_bfer); + +u8 beamforming_get_vht_ndp_tx_rate(void *dm_void, u8 comp_steering_num_of_bfer); + +u8 phydm_get_beamforming_sounding_info(void *dm_void, u16 *troughput, + u8 total_bfee_num, u8 *tx_rate); + +u8 phydm_get_ndpa_rate(void *dm_void); + +u8 phydm_get_mu_bfee_snding_decision(void *dm_void, u16 throughput); + +#endif diff --git a/drivers/staging/rtlwifi/ps.c b/drivers/staging/rtlwifi/ps.c new file mode 100644 index 000000000000..9172cee45f74 --- /dev/null +++ b/drivers/staging/rtlwifi/ps.c @@ -0,0 +1,1007 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include "wifi.h" +#include "base.h" +#include "ps.h" +#include <linux/export.h> +#include "btcoexist/rtl_btc.h" + +bool rtl_ps_enable_nic(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_mac *rtlmac = rtl_mac(rtl_priv(hw)); + + /*<1> reset trx ring */ + if (rtlhal->interface == INTF_PCI) + rtlpriv->intf_ops->reset_trx_ring(hw); + + if (is_hal_stop(rtlhal)) + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "Driver is already down!\n"); + + /*<2> Enable Adapter */ + if (rtlpriv->cfg->ops->hw_init(hw)) + return false; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RETRY_LIMIT, + &rtlmac->retry_long); + RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); + + /*<2.1> Switch Channel & Bandwidth to last rtl_op_config setting*/ + rtlpriv->cfg->ops->switch_channel(hw); + rtlpriv->cfg->ops->set_channel_access(hw); + rtlpriv->cfg->ops->set_bw_mode(hw, + cfg80211_get_chandef_type(&hw->conf.chandef)); + + /*<3> Enable Interrupt */ + rtlpriv->cfg->ops->enable_interrupt(hw); + + /*<enable timer> */ + rtl_watch_dog_timer_callback((unsigned long)hw); + + return true; +} + +bool rtl_ps_disable_nic(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + /*<1> Stop all timer */ + rtl_deinit_deferred_work(hw); + + /*<2> Disable Interrupt */ + rtlpriv->cfg->ops->disable_interrupt(hw); + tasklet_kill(&rtlpriv->works.irq_tasklet); + + /*<3> Disable Adapter */ + rtlpriv->cfg->ops->hw_disable(hw); + + return true; +} + +static bool rtl_ps_set_rf_state(struct ieee80211_hw *hw, + enum rf_pwrstate state_toset, + u32 changesource) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + enum rf_pwrstate rtstate; + bool actionallowed = false; + u16 rfwait_cnt = 0; + + /*Only one thread can change + *the RF state at one time, and others + *should wait to be executed. + */ + while (true) { + spin_lock(&rtlpriv->locks.rf_ps_lock); + if (ppsc->rfchange_inprogress) { + spin_unlock(&rtlpriv->locks.rf_ps_lock); + + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "RF Change in progress! Wait to set..state_toset(%d).\n", + state_toset); + + /* Set RF after the previous action is done. */ + while (ppsc->rfchange_inprogress) { + rfwait_cnt++; + mdelay(1); + /*Wait too long, return false to avoid + *to be stuck here. + */ + if (rfwait_cnt > 100) + return false; + } + } else { + ppsc->rfchange_inprogress = true; + spin_unlock(&rtlpriv->locks.rf_ps_lock); + break; + } + } + + rtstate = ppsc->rfpwr_state; + + switch (state_toset) { + case ERFON: + ppsc->rfoff_reason &= (~changesource); + + if ((changesource == RF_CHANGE_BY_HW) && + (ppsc->hwradiooff)) { + ppsc->hwradiooff = false; + } + + if (!ppsc->rfoff_reason) { + ppsc->rfoff_reason = 0; + actionallowed = true; + } + break; + case ERFOFF: + if ((changesource == RF_CHANGE_BY_HW) && !ppsc->hwradiooff) + ppsc->hwradiooff = true; + + ppsc->rfoff_reason |= changesource; + actionallowed = true; + break; + case ERFSLEEP: + ppsc->rfoff_reason |= changesource; + actionallowed = true; + break; + default: + pr_err("switch case %#x not processed\n", state_toset); + break; + } + + if (actionallowed) + rtlpriv->cfg->ops->set_rf_power_state(hw, state_toset); + + spin_lock(&rtlpriv->locks.rf_ps_lock); + ppsc->rfchange_inprogress = false; + spin_unlock(&rtlpriv->locks.rf_ps_lock); + + return actionallowed; +} + +static void _rtl_ps_inactive_ps(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + + ppsc->swrf_processing = true; + + if (ppsc->inactive_pwrstate == ERFON && + rtlhal->interface == INTF_PCI) { + if ((ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) && + RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM) && + rtlhal->interface == INTF_PCI) { + rtlpriv->intf_ops->disable_aspm(hw); + RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); + } + } + + rtl_ps_set_rf_state(hw, ppsc->inactive_pwrstate, + RF_CHANGE_BY_IPS); + + if (ppsc->inactive_pwrstate == ERFOFF && + rtlhal->interface == INTF_PCI) { + if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM && + !RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) { + rtlpriv->intf_ops->enable_aspm(hw); + RT_SET_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); + } + } + + ppsc->swrf_processing = false; +} + +void rtl_ips_nic_off_wq_callback(void *data) +{ + struct rtl_works *rtlworks = + container_of_dwork_rtl(data, struct rtl_works, ips_nic_off_wq); + struct ieee80211_hw *hw = rtlworks->hw; + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + enum rf_pwrstate rtstate; + + if (mac->opmode != NL80211_IFTYPE_STATION) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "not station return\n"); + return; + } + + if (mac->p2p_in_use) + return; + + if (mac->link_state > MAC80211_NOLINK) + return; + + if (is_hal_stop(rtlhal)) + return; + + if (rtlpriv->sec.being_setkey) + return; + + if (rtlpriv->cfg->ops->bt_coex_off_before_lps) + rtlpriv->cfg->ops->bt_coex_off_before_lps(hw); + + if (ppsc->inactiveps) { + rtstate = ppsc->rfpwr_state; + + /* + *Do not enter IPS in the following conditions: + *(1) RF is already OFF or Sleep + *(2) swrf_processing (indicates the IPS is still under going) + *(3) Connectted (only disconnected can trigger IPS) + *(4) IBSS (send Beacon) + *(5) AP mode (send Beacon) + *(6) monitor mode (rcv packet) + */ + + if (rtstate == ERFON && + !ppsc->swrf_processing && + (mac->link_state == MAC80211_NOLINK) && + !mac->act_scanning) { + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, + "IPSEnter(): Turn off RF\n"); + + ppsc->inactive_pwrstate = ERFOFF; + ppsc->in_powersavemode = true; + + /* call before RF off */ + if (rtlpriv->cfg->ops->get_btc_status()) + rtlpriv->btcoexist.btc_ops->btc_ips_notify(rtlpriv, + ppsc->inactive_pwrstate); + + /*rtl_pci_reset_trx_ring(hw); */ + _rtl_ps_inactive_ps(hw); + } + } +} + +void rtl_ips_nic_off(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + /* because when link with ap, mac80211 will ask us + * to disable nic quickly after scan before linking, + * this will cause link failed, so we delay 100ms here + */ + queue_delayed_work(rtlpriv->works.rtl_wq, + &rtlpriv->works.ips_nic_off_wq, MSECS(100)); +} + +/* NOTICE: any opmode should exc nic_on, or disable without + * nic_on may something wrong, like adhoc TP + */ +void rtl_ips_nic_on(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + enum rf_pwrstate rtstate; + + cancel_delayed_work(&rtlpriv->works.ips_nic_off_wq); + + mutex_lock(&rtlpriv->locks.ips_mutex); + if (ppsc->inactiveps) { + rtstate = ppsc->rfpwr_state; + + if (rtstate != ERFON && + !ppsc->swrf_processing && + ppsc->rfoff_reason <= RF_CHANGE_BY_IPS) { + ppsc->inactive_pwrstate = ERFON; + ppsc->in_powersavemode = false; + _rtl_ps_inactive_ps(hw); + /* call after RF on */ + if (rtlpriv->phydm.ops) + rtlpriv->phydm.ops->phydm_reset_dm(rtlpriv); + if (rtlpriv->cfg->ops->get_btc_status()) + rtlpriv->btcoexist.btc_ops->btc_ips_notify(rtlpriv, + ppsc->inactive_pwrstate); + } + } + mutex_unlock(&rtlpriv->locks.ips_mutex); +} + +/*for FW LPS*/ + +/* + *Determine if we can set Fw into PS mode + *in current condition.Return TRUE if it + *can enter PS mode. + */ +static bool rtl_get_fwlps_doze(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + u32 ps_timediff; + + ps_timediff = jiffies_to_msecs(jiffies - + ppsc->last_delaylps_stamp_jiffies); + + if (ps_timediff < 2000) { + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "Delay enter Fw LPS for DHCP, ARP, or EAPOL exchanging state\n"); + return false; + } + + if (mac->link_state != MAC80211_LINKED) + return false; + + if (mac->opmode == NL80211_IFTYPE_ADHOC) + return false; + + return true; +} + +/* Change current and default preamble mode.*/ +void rtl_lps_set_psmode(struct ieee80211_hw *hw, u8 rt_psmode) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + bool enter_fwlps; + + if (mac->opmode == NL80211_IFTYPE_ADHOC) + return; + + if (mac->link_state != MAC80211_LINKED) + return; + + if (ppsc->dot11_psmode == rt_psmode && rt_psmode == EACTIVE) + return; + + /* Update power save mode configured. */ + ppsc->dot11_psmode = rt_psmode; + + /* + *<FW control LPS> + *1. Enter PS mode + * Set RPWM to Fw to turn RF off and send H2C fw_pwrmode + * cmd to set Fw into PS mode. + *2. Leave PS mode + * Send H2C fw_pwrmode cmd to Fw to set Fw into Active + * mode and set RPWM to turn RF on. + */ + + if ((ppsc->fwctrl_lps) && ppsc->report_linked) { + if (ppsc->dot11_psmode == EACTIVE) { + RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, + "FW LPS leave ps_mode:%x\n", + FW_PS_ACTIVE_MODE); + enter_fwlps = false; + ppsc->pwr_mode = FW_PS_ACTIVE_MODE; + ppsc->smart_ps = 0; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_LPS_ACTION, + (u8 *)(&enter_fwlps)); + if (ppsc->p2p_ps_info.opp_ps) + rtl_p2p_ps_cmd(hw, P2P_PS_ENABLE); + + if (rtlpriv->cfg->ops->get_btc_status()) + rtlpriv->btcoexist.btc_ops->btc_lps_notify(rtlpriv, rt_psmode); + } else { + if (rtl_get_fwlps_doze(hw)) { + RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, + "FW LPS enter ps_mode:%x\n", + ppsc->fwctrl_psmode); + if (rtlpriv->cfg->ops->get_btc_status()) + rtlpriv->btcoexist.btc_ops->btc_lps_notify(rtlpriv, rt_psmode); + enter_fwlps = true; + ppsc->pwr_mode = ppsc->fwctrl_psmode; + ppsc->smart_ps = 2; + rtlpriv->cfg->ops->set_hw_reg(hw, + HW_VAR_FW_LPS_ACTION, + (u8 *)(&enter_fwlps)); + + } else { + /* Reset the power save related parameters. */ + ppsc->dot11_psmode = EACTIVE; + } + } + } +} + +/* Interrupt safe routine to enter the leisure power save mode.*/ +static void rtl_lps_enter_core(struct ieee80211_hw *hw) +{ + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (!ppsc->fwctrl_lps) + return; + + if (rtlpriv->sec.being_setkey) + return; + + if (rtlpriv->link_info.busytraffic) + return; + + /*sleep after linked 10s, to let DHCP and 4-way handshake ok enough!! */ + if (mac->cnt_after_linked < 5) + return; + + if (mac->opmode == NL80211_IFTYPE_ADHOC) + return; + + if (mac->link_state != MAC80211_LINKED) + return; + + mutex_lock(&rtlpriv->locks.lps_mutex); + + /* Don't need to check (ppsc->dot11_psmode == EACTIVE), because + * bt_ccoexist may ask to enter lps. + * In normal case, this constraint move to rtl_lps_set_psmode(). + */ + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "Enter 802.11 power save mode...\n"); + rtl_lps_set_psmode(hw, EAUTOPS); + + mutex_unlock(&rtlpriv->locks.lps_mutex); +} + +/* Interrupt safe routine to leave the leisure power save mode.*/ +static void rtl_lps_leave_core(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + + mutex_lock(&rtlpriv->locks.lps_mutex); + + if (ppsc->fwctrl_lps) { + if (ppsc->dot11_psmode != EACTIVE) { + /*FIX ME */ + /*rtlpriv->cfg->ops->enable_interrupt(hw); */ + + if (ppsc->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM && + RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM) && + rtlhal->interface == INTF_PCI) { + rtlpriv->intf_ops->disable_aspm(hw); + RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); + } + + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "Busy Traffic,Leave 802.11 power save..\n"); + + rtl_lps_set_psmode(hw, EACTIVE); + } + } + mutex_unlock(&rtlpriv->locks.lps_mutex); +} + +/* For sw LPS*/ +void rtl_swlps_beacon(struct ieee80211_hw *hw, void *data, unsigned int len) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct ieee80211_hdr *hdr = data; + struct ieee80211_tim_ie *tim_ie; + u8 *tim; + u8 tim_len; + bool u_buffed; + bool m_buffed; + + if (mac->opmode != NL80211_IFTYPE_STATION) + return; + + if (!rtlpriv->psc.swctrl_lps) + return; + + if (rtlpriv->mac80211.link_state != MAC80211_LINKED) + return; + + if (!rtlpriv->psc.sw_ps_enabled) + return; + + if (rtlpriv->psc.fwctrl_lps) + return; + + if (likely(!(hw->conf.flags & IEEE80211_CONF_PS))) + return; + + /* check if this really is a beacon */ + if (!ieee80211_is_beacon(hdr->frame_control)) + return; + + /* min. beacon length + FCS_LEN */ + if (len <= 40 + FCS_LEN) + return; + + /* and only beacons from the associated BSSID, please */ + if (!ether_addr_equal_64bits(hdr->addr3, rtlpriv->mac80211.bssid)) + return; + + rtlpriv->psc.last_beacon = jiffies; + + tim = rtl_find_ie(data, len - FCS_LEN, WLAN_EID_TIM); + if (!tim) + return; + + if (tim[1] < sizeof(*tim_ie)) + return; + + tim_len = tim[1]; + tim_ie = (struct ieee80211_tim_ie *)&tim[2]; + + if (!WARN_ON_ONCE(!hw->conf.ps_dtim_period)) + rtlpriv->psc.dtim_counter = tim_ie->dtim_count; + + /* Check whenever the PHY can be turned off again. */ + + /* 1. What about buffered unicast traffic for our AID? */ + u_buffed = ieee80211_check_tim(tim_ie, tim_len, + rtlpriv->mac80211.assoc_id); + + /* 2. Maybe the AP wants to send multicast/broadcast data? */ + m_buffed = tim_ie->bitmap_ctrl & 0x01; + rtlpriv->psc.multi_buffered = m_buffed; + + /* unicast will process by mac80211 through + * set ~IEEE80211_CONF_PS, So we just check + * multicast frames here + */ + if (!m_buffed) { + /* back to low-power land. and delay is + * prevent null power save frame tx fail + */ + queue_delayed_work(rtlpriv->works.rtl_wq, + &rtlpriv->works.ps_work, MSECS(5)); + } else { + RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, + "u_bufferd: %x, m_buffered: %x\n", u_buffed, m_buffed); + } +} + +void rtl_swlps_rf_awake(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + + if (!rtlpriv->psc.swctrl_lps) + return; + if (mac->link_state != MAC80211_LINKED) + return; + + if (ppsc->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM && + RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) { + rtlpriv->intf_ops->disable_aspm(hw); + RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); + } + + mutex_lock(&rtlpriv->locks.lps_mutex); + rtl_ps_set_rf_state(hw, ERFON, RF_CHANGE_BY_PS); + mutex_unlock(&rtlpriv->locks.lps_mutex); +} + +void rtl_swlps_rfon_wq_callback(void *data) +{ + struct rtl_works *rtlworks = + container_of_dwork_rtl(data, struct rtl_works, ps_rfon_wq); + struct ieee80211_hw *hw = rtlworks->hw; + + rtl_swlps_rf_awake(hw); +} + +void rtl_swlps_rf_sleep(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + u8 sleep_intv; + + if (!rtlpriv->psc.sw_ps_enabled) + return; + + if ((rtlpriv->sec.being_setkey) || + (mac->opmode == NL80211_IFTYPE_ADHOC)) + return; + + /*sleep after linked 10s, to let DHCP and 4-way handshake ok enough!! */ + if ((mac->link_state != MAC80211_LINKED) || (mac->cnt_after_linked < 5)) + return; + + if (rtlpriv->link_info.busytraffic) + return; + + spin_lock(&rtlpriv->locks.rf_ps_lock); + if (rtlpriv->psc.rfchange_inprogress) { + spin_unlock(&rtlpriv->locks.rf_ps_lock); + return; + } + spin_unlock(&rtlpriv->locks.rf_ps_lock); + + mutex_lock(&rtlpriv->locks.lps_mutex); + rtl_ps_set_rf_state(hw, ERFSLEEP, RF_CHANGE_BY_PS); + mutex_unlock(&rtlpriv->locks.lps_mutex); + + if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM && + !RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) { + rtlpriv->intf_ops->enable_aspm(hw); + RT_SET_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); + } + + /* here is power save alg, when this beacon is DTIM + * we will set sleep time to dtim_period * n; + * when this beacon is not DTIM, we will set sleep + * time to sleep_intv = rtlpriv->psc.dtim_counter or + * MAX_SW_LPS_SLEEP_INTV(default set to 5) + */ + + if (rtlpriv->psc.dtim_counter == 0) { + if (hw->conf.ps_dtim_period == 1) + sleep_intv = hw->conf.ps_dtim_period * 2; + else + sleep_intv = hw->conf.ps_dtim_period; + } else { + sleep_intv = rtlpriv->psc.dtim_counter; + } + + if (sleep_intv > MAX_SW_LPS_SLEEP_INTV) + sleep_intv = MAX_SW_LPS_SLEEP_INTV; + + /* this print should always be dtim_conter = 0 & + * sleep = dtim_period, that meaons, we should + * awake before every dtim + */ + RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, + "dtim_counter:%x will sleep :%d beacon_intv\n", + rtlpriv->psc.dtim_counter, sleep_intv); + + /* we tested that 40ms is enough for sw & hw sw delay */ + queue_delayed_work(rtlpriv->works.rtl_wq, &rtlpriv->works.ps_rfon_wq, + MSECS(sleep_intv * + mac->vif->bss_conf.beacon_int - 40)); +} + +void rtl_lps_change_work_callback(struct work_struct *work) +{ + struct rtl_works *rtlworks = + container_of(work, struct rtl_works, lps_change_work); + struct ieee80211_hw *hw = rtlworks->hw; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (rtlpriv->enter_ps) + rtl_lps_enter_core(hw); + else + rtl_lps_leave_core(hw); +} + +void rtl_lps_enter(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (!in_interrupt()) + return rtl_lps_enter_core(hw); + rtlpriv->enter_ps = true; + schedule_work(&rtlpriv->works.lps_change_work); +} + +void rtl_lps_leave(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (!in_interrupt()) + return rtl_lps_leave_core(hw); + rtlpriv->enter_ps = false; + schedule_work(&rtlpriv->works.lps_change_work); +} + +void rtl_swlps_wq_callback(void *data) +{ + struct rtl_works *rtlworks = container_of_dwork_rtl(data, + struct rtl_works, + ps_work); + struct ieee80211_hw *hw = rtlworks->hw; + struct rtl_priv *rtlpriv = rtl_priv(hw); + bool ps = false; + + ps = (hw->conf.flags & IEEE80211_CONF_PS); + + /* we can sleep after ps null send ok */ + if (rtlpriv->psc.state_inap) { + rtl_swlps_rf_sleep(hw); + + if (rtlpriv->psc.state && !ps) { + rtlpriv->psc.sleep_ms = jiffies_to_msecs(jiffies - + rtlpriv->psc.last_action); + } + + if (ps) + rtlpriv->psc.last_slept = jiffies; + + rtlpriv->psc.last_action = jiffies; + rtlpriv->psc.state = ps; + } +} + +static void rtl_p2p_noa_ie(struct ieee80211_hw *hw, void *data, + unsigned int len) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct ieee80211_mgmt *mgmt = data; + struct rtl_p2p_ps_info *p2pinfo = &rtlpriv->psc.p2p_ps_info; + u8 *pos, *end, *ie; + u16 noa_len; + static u8 p2p_oui_ie_type[4] = {0x50, 0x6f, 0x9a, 0x09}; + u8 noa_num, index, i, noa_index = 0; + bool find_p2p_ie = false, find_p2p_ps_ie = false; + + pos = (u8 *)mgmt->u.beacon.variable; + end = data + len; + ie = NULL; + + while (pos + 1 < end) { + if (pos + 2 + pos[1] > end) + return; + + if (pos[0] == 221 && pos[1] > 4) { + if (memcmp(&pos[2], p2p_oui_ie_type, 4) == 0) { + ie = pos + 2 + 4; + break; + } + } + pos += 2 + pos[1]; + } + + if (!ie) + return; + find_p2p_ie = true; + /*to find noa ie*/ + while (ie + 1 < end) { + noa_len = READEF2BYTE((__le16 *)&ie[1]); + if (ie + 3 + ie[1] > end) + return; + + if (ie[0] == 12) { + find_p2p_ps_ie = true; + if ((noa_len - 2) % 13 != 0) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "P2P notice of absence: invalid length.%d\n", + noa_len); + return; + } + noa_num = (noa_len - 2) / 13; + noa_index = ie[3]; + if (rtlpriv->psc.p2p_ps_info.p2p_ps_mode == + P2P_PS_NONE || noa_index != p2pinfo->noa_index) { + RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, + "update NOA ie.\n"); + p2pinfo->noa_index = noa_index; + p2pinfo->opp_ps = (ie[4] >> 7); + p2pinfo->ctwindow = ie[4] & 0x7F; + p2pinfo->noa_num = noa_num; + index = 5; + for (i = 0; i < noa_num; i++) { + p2pinfo->noa_count_type[i] = + READEF1BYTE(ie + index); + index += 1; + p2pinfo->noa_duration[i] = + READEF4BYTE((__le32 *)ie + index); + index += 4; + p2pinfo->noa_interval[i] = + READEF4BYTE((__le32 *)ie + index); + index += 4; + p2pinfo->noa_start_time[i] = + READEF4BYTE((__le32 *)ie + index); + index += 4; + } + + if (p2pinfo->opp_ps == 1) { + p2pinfo->p2p_ps_mode = P2P_PS_CTWINDOW; + /* Driver should wait LPS entering + * CTWindow + */ + if (rtlpriv->psc.fw_current_inpsmode) + rtl_p2p_ps_cmd(hw, + P2P_PS_ENABLE); + } else if (p2pinfo->noa_num > 0) { + p2pinfo->p2p_ps_mode = P2P_PS_NOA; + rtl_p2p_ps_cmd(hw, P2P_PS_ENABLE); + } else if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) { + rtl_p2p_ps_cmd(hw, P2P_PS_DISABLE); + } + } + break; + } + ie += 3 + noa_len; + } + + if (find_p2p_ie) { + if ((p2pinfo->p2p_ps_mode > P2P_PS_NONE) && + (!find_p2p_ps_ie)) + rtl_p2p_ps_cmd(hw, P2P_PS_DISABLE); + } +} + +static void rtl_p2p_action_ie(struct ieee80211_hw *hw, void *data, + unsigned int len) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct ieee80211_mgmt *mgmt = data; + struct rtl_p2p_ps_info *p2pinfo = &rtlpriv->psc.p2p_ps_info; + u8 noa_num, index, i, noa_index = 0; + u8 *pos, *end, *ie; + u16 noa_len; + static u8 p2p_oui_ie_type[4] = {0x50, 0x6f, 0x9a, 0x09}; + + pos = (u8 *)&mgmt->u.action.category; + end = data + len; + ie = NULL; + + if (pos[0] == 0x7f) { + if (memcmp(&pos[1], p2p_oui_ie_type, 4) == 0) + ie = pos + 3 + 4; + } + + if (!ie) + return; + + RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "action frame find P2P IE.\n"); + /*to find noa ie*/ + while (ie + 1 < end) { + noa_len = READEF2BYTE((__le16 *)&ie[1]); + if (ie + 3 + ie[1] > end) + return; + + if (ie[0] == 12) { + RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "find NOA IE.\n"); + RT_PRINT_DATA(rtlpriv, COMP_FW, DBG_LOUD, "noa ie ", + ie, noa_len); + if ((noa_len - 2) % 13 != 0) { + RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, + "P2P notice of absence: invalid length.%d\n", + noa_len); + return; + } + noa_num = (noa_len - 2) / 13; + noa_index = ie[3]; + if (rtlpriv->psc.p2p_ps_info.p2p_ps_mode == + P2P_PS_NONE || noa_index != p2pinfo->noa_index) { + p2pinfo->noa_index = noa_index; + p2pinfo->opp_ps = (ie[4] >> 7); + p2pinfo->ctwindow = ie[4] & 0x7F; + p2pinfo->noa_num = noa_num; + index = 5; + for (i = 0; i < noa_num; i++) { + p2pinfo->noa_count_type[i] = + READEF1BYTE(ie + index); + index += 1; + p2pinfo->noa_duration[i] = + READEF4BYTE((__le32 *)ie + index); + index += 4; + p2pinfo->noa_interval[i] = + READEF4BYTE((__le32 *)ie + index); + index += 4; + p2pinfo->noa_start_time[i] = + READEF4BYTE((__le32 *)ie + index); + index += 4; + } + + if (p2pinfo->opp_ps == 1) { + p2pinfo->p2p_ps_mode = P2P_PS_CTWINDOW; + /* Driver should wait LPS entering + * CTWindow + */ + if (rtlpriv->psc.fw_current_inpsmode) + rtl_p2p_ps_cmd(hw, + P2P_PS_ENABLE); + } else if (p2pinfo->noa_num > 0) { + p2pinfo->p2p_ps_mode = P2P_PS_NOA; + rtl_p2p_ps_cmd(hw, P2P_PS_ENABLE); + } else if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) { + rtl_p2p_ps_cmd(hw, P2P_PS_DISABLE); + } + } + break; + } + ie += 3 + noa_len; + } +} + +void rtl_p2p_ps_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw)); + struct rtl_p2p_ps_info *p2pinfo = &rtlpriv->psc.p2p_ps_info; + + RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "p2p state %x\n", p2p_ps_state); + switch (p2p_ps_state) { + case P2P_PS_DISABLE: + p2pinfo->p2p_ps_state = p2p_ps_state; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_P2P_PS_OFFLOAD, + &p2p_ps_state); + p2pinfo->noa_index = 0; + p2pinfo->ctwindow = 0; + p2pinfo->opp_ps = 0; + p2pinfo->noa_num = 0; + p2pinfo->p2p_ps_mode = P2P_PS_NONE; + if (rtlps->fw_current_inpsmode) { + if (rtlps->smart_ps == 0) { + rtlps->smart_ps = 2; + rtlpriv->cfg->ops->set_hw_reg(hw, + HW_VAR_H2C_FW_PWRMODE, + &rtlps->pwr_mode); + } + } + break; + case P2P_PS_ENABLE: + if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) { + p2pinfo->p2p_ps_state = p2p_ps_state; + + if (p2pinfo->ctwindow > 0) { + if (rtlps->smart_ps != 0) { + rtlps->smart_ps = 0; + rtlpriv->cfg->ops->set_hw_reg(hw, + HW_VAR_H2C_FW_PWRMODE, + &rtlps->pwr_mode); + } + } + rtlpriv->cfg->ops->set_hw_reg(hw, + HW_VAR_H2C_FW_P2P_PS_OFFLOAD, + &p2p_ps_state); + } + break; + case P2P_PS_SCAN: + case P2P_PS_SCAN_DONE: + case P2P_PS_ALLSTASLEEP: + if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) { + p2pinfo->p2p_ps_state = p2p_ps_state; + rtlpriv->cfg->ops->set_hw_reg(hw, + HW_VAR_H2C_FW_P2P_PS_OFFLOAD, + &p2p_ps_state); + } + break; + default: + break; + } + RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, + "ctwindow %x oppps %x\n", + p2pinfo->ctwindow, p2pinfo->opp_ps); + RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, + "count %x duration %x index %x interval %x start time %x noa num %x\n", + p2pinfo->noa_count_type[0], + p2pinfo->noa_duration[0], + p2pinfo->noa_index, + p2pinfo->noa_interval[0], + p2pinfo->noa_start_time[0], + p2pinfo->noa_num); + RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "end\n"); +} + +void rtl_p2p_info(struct ieee80211_hw *hw, void *data, unsigned int len) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct ieee80211_hdr *hdr = data; + + if (!mac->p2p) + return; + if (mac->link_state != MAC80211_LINKED) + return; + /* min. beacon length + FCS_LEN */ + if (len <= 40 + FCS_LEN) + return; + + /* and only beacons from the associated BSSID, please */ + if (!ether_addr_equal_64bits(hdr->addr3, rtlpriv->mac80211.bssid)) + return; + + /* check if this really is a beacon */ + if (!(ieee80211_is_beacon(hdr->frame_control) || + ieee80211_is_probe_resp(hdr->frame_control) || + ieee80211_is_action(hdr->frame_control))) + return; + + if (ieee80211_is_action(hdr->frame_control)) + rtl_p2p_action_ie(hw, data, len - FCS_LEN); + else + rtl_p2p_noa_ie(hw, data, len - FCS_LEN); +} diff --git a/drivers/staging/rtlwifi/ps.h b/drivers/staging/rtlwifi/ps.h new file mode 100644 index 000000000000..6c187daced4a --- /dev/null +++ b/drivers/staging/rtlwifi/ps.h @@ -0,0 +1,50 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __REALTEK_RTL_PCI_PS_H__ +#define __REALTEK_RTL_PCI_PS_H__ + +#define MAX_SW_LPS_SLEEP_INTV 5 + +bool rtl_ps_enable_nic(struct ieee80211_hw *hw); +bool rtl_ps_disable_nic(struct ieee80211_hw *hw); +void rtl_ips_nic_off(struct ieee80211_hw *hw); +void rtl_ips_nic_on(struct ieee80211_hw *hw); +void rtl_ips_nic_off_wq_callback(void *data); +void rtl_lps_enter(struct ieee80211_hw *hw); +void rtl_lps_leave(struct ieee80211_hw *hw); + +void rtl_lps_set_psmode(struct ieee80211_hw *hw, u8 rt_psmode); + +void rtl_swlps_beacon(struct ieee80211_hw *hw, void *data, unsigned int len); +void rtl_swlps_wq_callback(void *data); +void rtl_swlps_rfon_wq_callback(void *data); +void rtl_swlps_rf_awake(struct ieee80211_hw *hw); +void rtl_swlps_rf_sleep(struct ieee80211_hw *hw); +void rtl_p2p_ps_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state); +void rtl_p2p_info(struct ieee80211_hw *hw, void *data, unsigned int len); +void rtl_lps_change_work_callback(struct work_struct *work); + +#endif diff --git a/drivers/staging/rtlwifi/pwrseqcmd.h b/drivers/staging/rtlwifi/pwrseqcmd.h new file mode 100644 index 000000000000..f411b7ebb08f --- /dev/null +++ b/drivers/staging/rtlwifi/pwrseqcmd.h @@ -0,0 +1,94 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL8723E_PWRSEQCMD_H__ +#define __RTL8723E_PWRSEQCMD_H__ + +#include "wifi.h" +/*--------------------------------------------- + * 3 The value of cmd: 4 bits + *--------------------------------------------- + */ +#define PWR_CMD_READ 0x00 +#define PWR_CMD_WRITE 0x01 +#define PWR_CMD_POLLING 0x02 +#define PWR_CMD_DELAY 0x03 +#define PWR_CMD_END 0x04 + +/* define the base address of each block */ +#define PWR_BASEADDR_MAC 0x00 +#define PWR_BASEADDR_USB 0x01 +#define PWR_BASEADDR_PCIE 0x02 +#define PWR_BASEADDR_SDIO 0x03 + +#define PWR_INTF_SDIO_MSK BIT(0) +#define PWR_INTF_USB_MSK BIT(1) +#define PWR_INTF_PCI_MSK BIT(2) +#define PWR_INTF_ALL_MSK (BIT(0) | BIT(1) | BIT(2) | BIT(3)) + +#define PWR_FAB_TSMC_MSK BIT(0) +#define PWR_FAB_UMC_MSK BIT(1) +#define PWR_FAB_ALL_MSK (BIT(0) | BIT(1) | BIT(2) | BIT(3)) + +#define PWR_CUT_TESTCHIP_MSK BIT(0) +#define PWR_CUT_A_MSK BIT(1) +#define PWR_CUT_B_MSK BIT(2) +#define PWR_CUT_C_MSK BIT(3) +#define PWR_CUT_D_MSK BIT(4) +#define PWR_CUT_E_MSK BIT(5) +#define PWR_CUT_F_MSK BIT(6) +#define PWR_CUT_G_MSK BIT(7) +#define PWR_CUT_ALL_MSK 0xFF + +enum pwrseq_delay_unit { + PWRSEQ_DELAY_US, + PWRSEQ_DELAY_MS, +}; + +struct wlan_pwr_cfg { + u16 offset; + u8 cut_msk; + u8 fab_msk:4; + u8 interface_msk:4; + u8 base:4; + u8 cmd:4; + u8 msk; + u8 value; +}; + +#define GET_PWR_CFG_OFFSET(__PWR_CMD) (__PWR_CMD.offset) +#define GET_PWR_CFG_CUT_MASK(__PWR_CMD) (__PWR_CMD.cut_msk) +#define GET_PWR_CFG_FAB_MASK(__PWR_CMD) (__PWR_CMD.fab_msk) +#define GET_PWR_CFG_INTF_MASK(__PWR_CMD) (__PWR_CMD.interface_msk) +#define GET_PWR_CFG_BASE(__PWR_CMD) (__PWR_CMD.base) +#define GET_PWR_CFG_CMD(__PWR_CMD) (__PWR_CMD.cmd) +#define GET_PWR_CFG_MASK(__PWR_CMD) (__PWR_CMD.msk) +#define GET_PWR_CFG_VALUE(__PWR_CMD) (__PWR_CMD.value) + +bool rtl_hal_pwrseqcmdparsing(struct rtl_priv *rtlpriv, u8 cut_version, + u8 fab_version, u8 interface_type, + struct wlan_pwr_cfg pwrcfgcmd[]); + +#endif diff --git a/drivers/staging/rtlwifi/rc.c b/drivers/staging/rtlwifi/rc.c new file mode 100644 index 000000000000..65de0c7b5a67 --- /dev/null +++ b/drivers/staging/rtlwifi/rc.c @@ -0,0 +1,322 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include "wifi.h" +#include "base.h" +#include "rc.h" + +/* + *Finds the highest rate index we can use + *if skb is special data like DHCP/EAPOL, we set should + *it to lowest rate CCK_1M, otherwise we set rate to + *highest rate based on wireless mode used for iwconfig + *show Tx rate. + */ +static u8 _rtl_rc_get_highest_rix(struct rtl_priv *rtlpriv, + struct ieee80211_sta *sta, + struct sk_buff *skb, bool not_data) +{ + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + struct rtl_phy *rtlphy = &rtlpriv->phy; + struct rtl_sta_info *sta_entry = NULL; + u16 wireless_mode = 0; + u8 nss; /* NSS -1 */ + + if (get_rf_type(rtlphy) >= RF_4T4R) + nss = 3; + else if (get_rf_type(rtlphy) >= RF_3T3R) + nss = 2; + else if (get_rf_type(rtlphy) >= RF_2T2R) + nss = 1; + else + nss = 0; + + /* + *this rate is no use for true rate, firmware + *will control rate at all it just used for + *1.show in iwconfig in B/G mode + *2.in rtl_get_tcb_desc when we check rate is + * 1M we will not use FW rate but user rate. + */ + + if (sta) { + sta_entry = (struct rtl_sta_info *)sta->drv_priv; + wireless_mode = sta_entry->wireless_mode; + } + + if (rtl_is_special_data(rtlpriv->mac80211.hw, skb, true, false) || + not_data) { + return 0; + } + if (rtlhal->current_bandtype == BAND_ON_2_4G) { + if (wireless_mode == WIRELESS_MODE_B) { + return B_MODE_MAX_RIX; + } else if (wireless_mode == WIRELESS_MODE_G) { + return G_MODE_MAX_RIX; + } else if (wireless_mode == WIRELESS_MODE_N_24G) { + if (nss == 0) + return N_MODE_MCS7_RIX; + else + return N_MODE_MCS15_RIX; + } else if (wireless_mode == WIRELESS_MODE_AC_24G) { + if (sta->bandwidth == IEEE80211_STA_RX_BW_20) + return AC_MODE_MCS8_RIX | (nss << 4); + else + return AC_MODE_MCS9_RIX | (nss << 4); + } + return 0; + } + if (wireless_mode == WIRELESS_MODE_A) { + return A_MODE_MAX_RIX; + } else if (wireless_mode == WIRELESS_MODE_N_5G) { + if (nss == 0) + return N_MODE_MCS7_RIX; + else + return N_MODE_MCS15_RIX; + } else if (wireless_mode == WIRELESS_MODE_AC_5G) { + if (sta->bandwidth == IEEE80211_STA_RX_BW_20) + return AC_MODE_MCS8_RIX | (nss << 4); + else + return AC_MODE_MCS9_RIX | (nss << 4); + } + return 0; +} + +static void _rtl_rc_rate_set_series(struct rtl_priv *rtlpriv, + struct ieee80211_sta *sta, + struct ieee80211_tx_rate *rate, + struct ieee80211_tx_rate_control *txrc, + u8 tries, s8 rix, int rtsctsenable, + bool not_data) +{ + struct rtl_mac *mac = rtl_mac(rtlpriv); + struct rtl_sta_info *sta_entry = NULL; + u16 wireless_mode = 0; + u8 sgi_20 = 0, sgi_40 = 0, sgi_80 = 0; + + if (sta) { + sgi_20 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20; + sgi_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40; + sgi_80 = sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80; + sta_entry = (struct rtl_sta_info *)sta->drv_priv; + wireless_mode = sta_entry->wireless_mode; + } + rate->count = tries; + rate->idx = rix >= 0x00 ? rix : 0x00; + if (((rtlpriv->rtlhal.hw_type == HARDWARE_TYPE_RTL8812AE) || + (rtlpriv->rtlhal.hw_type == HARDWARE_TYPE_RTL8822BE)) && + wireless_mode == WIRELESS_MODE_AC_5G) + rate->idx |= 0x10;/*2NSS for 8812AE, 8822BE*/ + + if (!not_data) { + if (txrc->short_preamble) + rate->flags |= IEEE80211_TX_RC_USE_SHORT_PREAMBLE; + if (mac->opmode == NL80211_IFTYPE_AP || + mac->opmode == NL80211_IFTYPE_ADHOC) { + if (sta && (sta->ht_cap.cap & + IEEE80211_HT_CAP_SUP_WIDTH_20_40)) + rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; + if (sta && (sta->vht_cap.vht_supported)) + rate->flags |= IEEE80211_TX_RC_80_MHZ_WIDTH; + } else { + if (mac->bw_80) + rate->flags |= IEEE80211_TX_RC_80_MHZ_WIDTH; + else if (mac->bw_40) + rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; + } + + if (sgi_20 || sgi_40 || sgi_80) + rate->flags |= IEEE80211_TX_RC_SHORT_GI; + if (sta && sta->ht_cap.ht_supported && + ((wireless_mode == WIRELESS_MODE_N_5G) || + (wireless_mode == WIRELESS_MODE_N_24G))) + rate->flags |= IEEE80211_TX_RC_MCS; + if (sta && sta->vht_cap.vht_supported && + (wireless_mode == WIRELESS_MODE_AC_5G || + wireless_mode == WIRELESS_MODE_AC_24G || + wireless_mode == WIRELESS_MODE_AC_ONLY)) + rate->flags |= IEEE80211_TX_RC_VHT_MCS; + } +} + +static void rtl_get_rate(void *ppriv, struct ieee80211_sta *sta, + void *priv_sta, + struct ieee80211_tx_rate_control *txrc) +{ + struct rtl_priv *rtlpriv = ppriv; + struct sk_buff *skb = txrc->skb; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ieee80211_tx_rate *rates = tx_info->control.rates; + __le16 fc = rtl_get_fc(skb); + u8 try_per_rate, i, rix; + bool not_data = !ieee80211_is_data(fc); + + if (rate_control_send_low(sta, priv_sta, txrc)) + return; + + rix = _rtl_rc_get_highest_rix(rtlpriv, sta, skb, not_data); + try_per_rate = 1; + _rtl_rc_rate_set_series(rtlpriv, sta, &rates[0], txrc, + try_per_rate, rix, 1, not_data); + + if (!not_data) { + for (i = 1; i < 4; i++) + _rtl_rc_rate_set_series(rtlpriv, sta, &rates[i], + txrc, i, (rix - i), 1, + not_data); + } +} + +static bool _rtl_tx_aggr_check(struct rtl_priv *rtlpriv, + struct rtl_sta_info *sta_entry, u16 tid) +{ + struct rtl_mac *mac = rtl_mac(rtlpriv); + + if (mac->act_scanning) + return false; + + if (mac->opmode == NL80211_IFTYPE_STATION && + mac->cnt_after_linked < 3) + return false; + + if (sta_entry->tids[tid].agg.agg_state == RTL_AGG_STOP) + return true; + + return false; +} + +/*mac80211 Rate Control callbacks*/ +static void rtl_tx_status(void *ppriv, + struct ieee80211_supported_band *sband, + struct ieee80211_sta *sta, void *priv_sta, + struct sk_buff *skb) +{ + struct rtl_priv *rtlpriv = ppriv; + struct rtl_mac *mac = rtl_mac(rtlpriv); + struct ieee80211_hdr *hdr = rtl_get_hdr(skb); + __le16 fc = rtl_get_fc(skb); + struct rtl_sta_info *sta_entry; + + if (!priv_sta || !ieee80211_is_data(fc)) + return; + + if (rtl_is_special_data(mac->hw, skb, true, true)) + return; + + if (is_multicast_ether_addr(ieee80211_get_DA(hdr)) || + is_broadcast_ether_addr(ieee80211_get_DA(hdr))) + return; + + if (sta) { + /* Check if aggregation has to be enabled for this tid */ + sta_entry = (struct rtl_sta_info *)sta->drv_priv; + if ((sta->ht_cap.ht_supported) && + !(skb->protocol == cpu_to_be16(ETH_P_PAE))) { + if (ieee80211_is_data_qos(fc)) { + u8 tid = rtl_get_tid(skb); + + if (_rtl_tx_aggr_check(rtlpriv, sta_entry, + tid)) { + sta_entry->tids[tid].agg.agg_state = + RTL_AGG_PROGRESS; + ieee80211_start_tx_ba_session(sta, tid, + 5000); + } + } + } + } +} + +static void rtl_rate_init(void *ppriv, + struct ieee80211_supported_band *sband, + struct cfg80211_chan_def *chandef, + struct ieee80211_sta *sta, void *priv_sta) +{ +} + +static void rtl_rate_update(void *ppriv, + struct ieee80211_supported_band *sband, + struct cfg80211_chan_def *chandef, + struct ieee80211_sta *sta, void *priv_sta, + u32 changed) +{ +} + +static void *rtl_rate_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + return rtlpriv; +} + +static void rtl_rate_free(void *rtlpriv) +{ +} + +static void *rtl_rate_alloc_sta(void *ppriv, + struct ieee80211_sta *sta, gfp_t gfp) +{ + struct rtl_priv *rtlpriv = ppriv; + struct rtl_rate_priv *rate_priv; + + rate_priv = kzalloc(sizeof(*rate_priv), gfp); + if (!rate_priv) { + pr_err("Unable to allocate private rc structure\n"); + return NULL; + } + + rtlpriv->rate_priv = rate_priv; + + return rate_priv; +} + +static void rtl_rate_free_sta(void *rtlpriv, + struct ieee80211_sta *sta, void *priv_sta) +{ + struct rtl_rate_priv *rate_priv = priv_sta; + + kfree(rate_priv); +} + +static const struct rate_control_ops rtl_rate_ops = { + .name = "rtl_rc", + .alloc = rtl_rate_alloc, + .free = rtl_rate_free, + .alloc_sta = rtl_rate_alloc_sta, + .free_sta = rtl_rate_free_sta, + .rate_init = rtl_rate_init, + .rate_update = rtl_rate_update, + .tx_status = rtl_tx_status, + .get_rate = rtl_get_rate, +}; + +int rtl_rate_control_register(void) +{ + return ieee80211_rate_control_register(&rtl_rate_ops); +} + +void rtl_rate_control_unregister(void) +{ + ieee80211_rate_control_unregister(&rtl_rate_ops); +} diff --git a/drivers/staging/rtlwifi/rc.h b/drivers/staging/rtlwifi/rc.h new file mode 100644 index 000000000000..dcc8520866b7 --- /dev/null +++ b/drivers/staging/rtlwifi/rc.h @@ -0,0 +1,49 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL_RC_H__ +#define __RTL_RC_H__ + +#define B_MODE_MAX_RIX 3 +#define G_MODE_MAX_RIX 11 +#define A_MODE_MAX_RIX 7 + +/* in mac80211 mcs0-mcs15 is idx0-idx15*/ +#define N_MODE_MCS7_RIX 7 +#define N_MODE_MCS15_RIX 15 + +/* in mac80211 vht mcs0-9 is in [3:0], nss is in [:4] */ +#define AC_MODE_MCS7_RIX 7 +#define AC_MODE_MCS8_RIX 8 +#define AC_MODE_MCS9_RIX 9 + +struct rtl_rate_priv { + u8 ht_cap; +}; + +int rtl_rate_control_register(void); +void rtl_rate_control_unregister(void); + +#endif diff --git a/drivers/staging/rtlwifi/regd.c b/drivers/staging/rtlwifi/regd.c new file mode 100644 index 000000000000..e0a3ff85edb6 --- /dev/null +++ b/drivers/staging/rtlwifi/regd.c @@ -0,0 +1,469 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include "wifi.h" +#include "regd.h" + +static struct country_code_to_enum_rd allcountries[] = { + {COUNTRY_CODE_FCC, "US"}, + {COUNTRY_CODE_IC, "US"}, + {COUNTRY_CODE_ETSI, "EC"}, + {COUNTRY_CODE_SPAIN, "EC"}, + {COUNTRY_CODE_FRANCE, "EC"}, + {COUNTRY_CODE_MKK, "JP"}, + {COUNTRY_CODE_MKK1, "JP"}, + {COUNTRY_CODE_ISRAEL, "EC"}, + {COUNTRY_CODE_TELEC, "JP"}, + {COUNTRY_CODE_MIC, "JP"}, + {COUNTRY_CODE_GLOBAL_DOMAIN, "JP"}, + {COUNTRY_CODE_WORLD_WIDE_13, "EC"}, + {COUNTRY_CODE_TELEC_NETGEAR, "EC"}, + {COUNTRY_CODE_WORLD_WIDE_13_5G_ALL, "US"}, +}; + +/*Only these channels all allow active + *scan on all world regulatory domains + */ +#define RTL819x_2GHZ_CH01_11 \ + REG_RULE(2412 - 10, 2462 + 10, 40, 0, 20, 0) + +/*We enable active scan on these a case + *by case basis by regulatory domain + */ +#define RTL819x_2GHZ_CH12_13 \ + REG_RULE(2467 - 10, 2472 + 10, 40, 0, 20,\ + NL80211_RRF_PASSIVE_SCAN) + +#define RTL819x_2GHZ_CH14 \ + REG_RULE(2484 - 10, 2484 + 10, 40, 0, 20, \ + NL80211_RRF_PASSIVE_SCAN | \ + NL80211_RRF_NO_OFDM) + +/* 5G chan 36 - chan 64*/ +#define RTL819x_5GHZ_5150_5350 \ + REG_RULE(5150 - 10, 5350 + 10, 80, 0, 30, 0) +/* 5G chan 100 - chan 165*/ +#define RTL819x_5GHZ_5470_5850 \ + REG_RULE(5470 - 10, 5850 + 10, 80, 0, 30, 0) +/* 5G chan 149 - chan 165*/ +#define RTL819x_5GHZ_5725_5850 \ + REG_RULE(5725 - 10, 5850 + 10, 80, 0, 30, 0) + +#define RTL819x_5GHZ_ALL \ + (RTL819x_5GHZ_5150_5350, RTL819x_5GHZ_5470_5850) + +static const struct ieee80211_regdomain rtl_regdom_11 = { + .n_reg_rules = 1, + .alpha2 = "99", + .reg_rules = { + RTL819x_2GHZ_CH01_11, + } +}; + +static const struct ieee80211_regdomain rtl_regdom_12_13 = { + .n_reg_rules = 2, + .alpha2 = "99", + .reg_rules = { + RTL819x_2GHZ_CH01_11, + RTL819x_2GHZ_CH12_13, + } +}; + +static const struct ieee80211_regdomain rtl_regdom_no_midband = { + .n_reg_rules = 3, + .alpha2 = "99", + .reg_rules = { + RTL819x_2GHZ_CH01_11, + RTL819x_5GHZ_5150_5350, + RTL819x_5GHZ_5725_5850, + } +}; + +static const struct ieee80211_regdomain rtl_regdom_60_64 = { + .n_reg_rules = 3, + .alpha2 = "99", + .reg_rules = { + RTL819x_2GHZ_CH01_11, + RTL819x_2GHZ_CH12_13, + RTL819x_5GHZ_5725_5850, + } +}; + +static const struct ieee80211_regdomain rtl_regdom_14_60_64 = { + .n_reg_rules = 4, + .alpha2 = "99", + .reg_rules = { + RTL819x_2GHZ_CH01_11, + RTL819x_2GHZ_CH12_13, + RTL819x_2GHZ_CH14, + RTL819x_5GHZ_5725_5850, + } +}; + +static const struct ieee80211_regdomain rtl_regdom_12_13_5g_all = { + .n_reg_rules = 4, + .alpha2 = "99", + .reg_rules = { + RTL819x_2GHZ_CH01_11, + RTL819x_2GHZ_CH12_13, + RTL819x_5GHZ_5150_5350, + RTL819x_5GHZ_5470_5850, + } +}; + +static const struct ieee80211_regdomain rtl_regdom_14 = { + .n_reg_rules = 3, + .alpha2 = "99", + .reg_rules = { + RTL819x_2GHZ_CH01_11, + RTL819x_2GHZ_CH12_13, + RTL819x_2GHZ_CH14, + } +}; + +static bool _rtl_is_radar_freq(u16 center_freq) +{ + return center_freq >= 5260 && center_freq <= 5700; +} + +static void _rtl_reg_apply_beaconing_flags(struct wiphy *wiphy, + enum nl80211_reg_initiator initiator) +{ + enum nl80211_band band; + struct ieee80211_supported_band *sband; + const struct ieee80211_reg_rule *reg_rule; + struct ieee80211_channel *ch; + unsigned int i; + + for (band = 0; band < NUM_NL80211_BANDS; band++) { + if (!wiphy->bands[band]) + continue; + + sband = wiphy->bands[band]; + + for (i = 0; i < sband->n_channels; i++) { + ch = &sband->channels[i]; + if (_rtl_is_radar_freq(ch->center_freq) || + (ch->flags & IEEE80211_CHAN_RADAR)) + continue; + if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) { + reg_rule = freq_reg_info(wiphy, + ch->center_freq); + if (IS_ERR(reg_rule)) + continue; + /* + *If 11d had a rule for this channel ensure + *we enable adhoc/beaconing if it allows us to + *use it. Note that we would have disabled it + *by applying our static world regdomain by + *default during init, prior to calling our + *regulatory_hint(). + */ + + if (!(reg_rule->flags & NL80211_RRF_NO_IBSS)) + ch->flags &= ~IEEE80211_CHAN_NO_IBSS; + if (!(reg_rule->flags & + NL80211_RRF_PASSIVE_SCAN)) + ch->flags &= + ~IEEE80211_CHAN_PASSIVE_SCAN; + } else { + if (ch->beacon_found) + ch->flags &= ~(IEEE80211_CHAN_NO_IBSS | + IEEE80211_CHAN_PASSIVE_SCAN); + } + } + } +} + +/* Allows active scan scan on Ch 12 and 13 */ +static void _rtl_reg_apply_active_scan_flags(struct wiphy *wiphy, + enum nl80211_reg_initiator + initiator) +{ + struct ieee80211_supported_band *sband; + struct ieee80211_channel *ch; + const struct ieee80211_reg_rule *reg_rule; + + if (!wiphy->bands[NL80211_BAND_2GHZ]) + return; + sband = wiphy->bands[NL80211_BAND_2GHZ]; + + /* + *If no country IE has been received always enable active scan + *on these channels. This is only done for specific regulatory SKUs + */ + if (initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) { + ch = &sband->channels[11]; /* CH 12 */ + if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) + ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; + ch = &sband->channels[12]; /* CH 13 */ + if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) + ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; + return; + } + + /*If a country IE has been received check its rule for this + *channel first before enabling active scan. The passive scan + *would have been enforced by the initial processing of our + *custom regulatory domain. + */ + + ch = &sband->channels[11]; /* CH 12 */ + reg_rule = freq_reg_info(wiphy, ch->center_freq); + if (!IS_ERR(reg_rule)) { + if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN)) + if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) + ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; + } + + ch = &sband->channels[12]; /* CH 13 */ + reg_rule = freq_reg_info(wiphy, ch->center_freq); + if (!IS_ERR(reg_rule)) { + if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN)) + if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) + ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; + } +} + +/* + *Always apply Radar/DFS rules on + *freq range 5260 MHz - 5700 MHz + */ +static void _rtl_reg_apply_radar_flags(struct wiphy *wiphy) +{ + struct ieee80211_supported_band *sband; + struct ieee80211_channel *ch; + unsigned int i; + + if (!wiphy->bands[NL80211_BAND_5GHZ]) + return; + + sband = wiphy->bands[NL80211_BAND_5GHZ]; + + for (i = 0; i < sband->n_channels; i++) { + ch = &sband->channels[i]; + if (!_rtl_is_radar_freq(ch->center_freq)) + continue; + + /* + *We always enable radar detection/DFS on this + *frequency range. Additionally we also apply on + *this frequency range: + *- If STA mode does not yet have DFS supports disable + * active scanning + *- If adhoc mode does not support DFS yet then disable + * adhoc in the frequency. + *- If AP mode does not yet support radar detection/DFS + *do not allow AP mode + */ + if (!(ch->flags & IEEE80211_CHAN_DISABLED)) + ch->flags |= IEEE80211_CHAN_RADAR | + IEEE80211_CHAN_NO_IBSS | + IEEE80211_CHAN_PASSIVE_SCAN; + } +} + +static void _rtl_reg_apply_world_flags(struct wiphy *wiphy, + enum nl80211_reg_initiator initiator, + struct rtl_regulatory *reg) +{ + _rtl_reg_apply_beaconing_flags(wiphy, initiator); + _rtl_reg_apply_active_scan_flags(wiphy, initiator); +} + +static void _rtl_dump_channel_map(struct wiphy *wiphy) +{ + enum nl80211_band band; + struct ieee80211_supported_band *sband; + struct ieee80211_channel *ch; + unsigned int i; + + for (band = 0; band < NUM_NL80211_BANDS; band++) { + if (!wiphy->bands[band]) + continue; + sband = wiphy->bands[band]; + for (i = 0; i < sband->n_channels; i++) + ch = &sband->channels[i]; + } +} + +static int _rtl_reg_notifier_apply(struct wiphy *wiphy, + struct regulatory_request *request, + struct rtl_regulatory *reg) +{ + /* We always apply this */ + _rtl_reg_apply_radar_flags(wiphy); + + switch (request->initiator) { + case NL80211_REGDOM_SET_BY_DRIVER: + case NL80211_REGDOM_SET_BY_CORE: + case NL80211_REGDOM_SET_BY_USER: + break; + case NL80211_REGDOM_SET_BY_COUNTRY_IE: + _rtl_reg_apply_world_flags(wiphy, request->initiator, reg); + break; + } + + _rtl_dump_channel_map(wiphy); + + return 0; +} + +static const struct ieee80211_regdomain *_rtl_regdomain_select( + struct rtl_regulatory *reg) +{ + switch (reg->country_code) { + case COUNTRY_CODE_FCC: + return &rtl_regdom_no_midband; + case COUNTRY_CODE_IC: + return &rtl_regdom_11; + case COUNTRY_CODE_TELEC_NETGEAR: + return &rtl_regdom_60_64; + case COUNTRY_CODE_ETSI: + case COUNTRY_CODE_SPAIN: + case COUNTRY_CODE_FRANCE: + case COUNTRY_CODE_ISRAEL: + return &rtl_regdom_12_13; + case COUNTRY_CODE_MKK: + case COUNTRY_CODE_MKK1: + case COUNTRY_CODE_TELEC: + case COUNTRY_CODE_MIC: + return &rtl_regdom_14_60_64; + case COUNTRY_CODE_GLOBAL_DOMAIN: + return &rtl_regdom_14; + case COUNTRY_CODE_WORLD_WIDE_13: + case COUNTRY_CODE_WORLD_WIDE_13_5G_ALL: + return &rtl_regdom_12_13_5g_all; + default: + return &rtl_regdom_no_midband; + } +} + +static int _rtl_regd_init_wiphy(struct rtl_regulatory *reg, + struct wiphy *wiphy, + void (*reg_notifier)(struct wiphy *wiphy, + struct regulatory_request * + request)) +{ + const struct ieee80211_regdomain *regd; + + wiphy->reg_notifier = reg_notifier; + + wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG; + wiphy->regulatory_flags &= ~REGULATORY_STRICT_REG; + wiphy->regulatory_flags &= ~REGULATORY_DISABLE_BEACON_HINTS; + regd = _rtl_regdomain_select(reg); + wiphy_apply_custom_regulatory(wiphy, regd); + _rtl_reg_apply_radar_flags(wiphy); + _rtl_reg_apply_world_flags(wiphy, NL80211_REGDOM_SET_BY_DRIVER, reg); + return 0; +} + +static struct country_code_to_enum_rd *_rtl_regd_find_country(u16 countrycode) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(allcountries); i++) { + if (allcountries[i].countrycode == countrycode) + return &allcountries[i]; + } + return NULL; +} + +static u8 channel_plan_to_country_code(u8 channelplan) +{ + switch (channelplan) { + case 0x20: + case 0x21: + return COUNTRY_CODE_WORLD_WIDE_13; + case 0x22: + return COUNTRY_CODE_IC; + case 0x25: + return COUNTRY_CODE_ETSI; + case 0x32: + return COUNTRY_CODE_TELEC_NETGEAR; + case 0x41: + return COUNTRY_CODE_GLOBAL_DOMAIN; + case 0x7f: + return COUNTRY_CODE_WORLD_WIDE_13_5G_ALL; + default: + return COUNTRY_CODE_MAX; /*Error*/ + } +} + +int rtl_regd_init(struct ieee80211_hw *hw, + void (*reg_notifier)(struct wiphy *wiphy, + struct regulatory_request *request)) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct wiphy *wiphy = hw->wiphy; + struct country_code_to_enum_rd *country = NULL; + + if (!wiphy || !&rtlpriv->regd) + return -EINVAL; + + /* init country_code from efuse channel plan */ + rtlpriv->regd.country_code = + channel_plan_to_country_code(rtlpriv->efuse.channel_plan); + + RT_TRACE(rtlpriv, COMP_REGD, DBG_DMESG, + "rtl: EEPROM regdomain: 0x%0x country code: %d\n", + rtlpriv->efuse.channel_plan, rtlpriv->regd.country_code); + + if (rtlpriv->regd.country_code >= COUNTRY_CODE_MAX) { + RT_TRACE(rtlpriv, COMP_REGD, DBG_DMESG, + "rtl: EEPROM indicates invalid country code, world wide 13 should be used\n"); + + rtlpriv->regd.country_code = COUNTRY_CODE_WORLD_WIDE_13; + } + + country = _rtl_regd_find_country(rtlpriv->regd.country_code); + + if (country) { + rtlpriv->regd.alpha2[0] = country->iso_name[0]; + rtlpriv->regd.alpha2[1] = country->iso_name[1]; + } else { + rtlpriv->regd.alpha2[0] = '0'; + rtlpriv->regd.alpha2[1] = '0'; + } + + RT_TRACE(rtlpriv, COMP_REGD, DBG_TRACE, + "rtl: Country alpha2 being used: %c%c\n", + rtlpriv->regd.alpha2[0], rtlpriv->regd.alpha2[1]); + + _rtl_regd_init_wiphy(&rtlpriv->regd, wiphy, reg_notifier); + + return 0; +} + +void rtl_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) +{ + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct rtl_priv *rtlpriv = rtl_priv(hw); + + RT_TRACE(rtlpriv, COMP_REGD, DBG_LOUD, "\n"); + + _rtl_reg_notifier_apply(wiphy, request, &rtlpriv->regd); +} diff --git a/drivers/staging/rtlwifi/regd.h b/drivers/staging/rtlwifi/regd.h new file mode 100644 index 000000000000..5626015a6d0d --- /dev/null +++ b/drivers/staging/rtlwifi/regd.h @@ -0,0 +1,63 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL_REGD_H__ +#define __RTL_REGD_H__ + +/* for kernel 3.14 , both value are changed to IEEE80211_CHAN_NO_IR*/ +#define IEEE80211_CHAN_NO_IBSS IEEE80211_CHAN_NO_IR +#define IEEE80211_CHAN_PASSIVE_SCAN IEEE80211_CHAN_NO_IR + +struct country_code_to_enum_rd { + u16 countrycode; + const char *iso_name; +}; + +enum country_code_type_t { + COUNTRY_CODE_FCC = 0, + COUNTRY_CODE_IC = 1, + COUNTRY_CODE_ETSI = 2, + COUNTRY_CODE_SPAIN = 3, + COUNTRY_CODE_FRANCE = 4, + COUNTRY_CODE_MKK = 5, + COUNTRY_CODE_MKK1 = 6, + COUNTRY_CODE_ISRAEL = 7, + COUNTRY_CODE_TELEC = 8, + COUNTRY_CODE_MIC = 9, + COUNTRY_CODE_GLOBAL_DOMAIN = 10, + COUNTRY_CODE_WORLD_WIDE_13 = 11, + COUNTRY_CODE_TELEC_NETGEAR = 12, + COUNTRY_CODE_WORLD_WIDE_13_5G_ALL = 13, + + /*add new channel plan above this line */ + COUNTRY_CODE_MAX +}; + +int rtl_regd_init(struct ieee80211_hw *hw, + void (*reg_notifier)(struct wiphy *wiphy, + struct regulatory_request *request)); +void rtl_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request); + +#endif diff --git a/drivers/staging/rtlwifi/rtl8822be/Makefile b/drivers/staging/rtlwifi/rtl8822be/Makefile new file mode 100644 index 000000000000..d535ff8febf1 --- /dev/null +++ b/drivers/staging/rtlwifi/rtl8822be/Makefile @@ -0,0 +1,7 @@ +rtl8822be-objs := \ + fw.o \ + hw.o \ + led.o \ + phy.o \ + sw.o \ + trx.o diff --git a/drivers/staging/rtlwifi/rtl8822be/def.h b/drivers/staging/rtlwifi/rtl8822be/def.h new file mode 100644 index 000000000000..7942ddfdcf43 --- /dev/null +++ b/drivers/staging/rtlwifi/rtl8822be/def.h @@ -0,0 +1,82 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL8822B_DEF_H__ +#define __RTL8822B_DEF_H__ + +#define RX_DESC_NUM_8822BE 512 + +#define HAL_PRIME_CHNL_OFFSET_DONT_CARE 0 +#define HAL_PRIME_CHNL_OFFSET_LOWER 1 +#define HAL_PRIME_CHNL_OFFSET_UPPER 2 + +#define RX_MPDU_QUEUE 0 + +#define IS_HT_RATE(_rate) (_rate >= DESC_RATEMCS0) +#define IS_CCK_RATE(_rate) (_rate >= DESC_RATE1M && _rate <= DESC_RATE11M) +#define IS_OFDM_RATE(_rate) (_rate >= DESC_RATE6M && _rate <= DESC_RATE54M) +#define IS_1T_RATE(_rate) \ + ((_rate >= DESC_RATE1M && _rate <= DESC_RATEMCS7) || \ + (_rate >= DESC_RATEVHT1SS_MCS0 && _rate <= DESC_RATEVHT1SS_MCS9)) +#define IS_2T_RATE(_rate) \ + ((_rate >= DESC_RATEMCS8 && _rate <= DESC_RATEMCS15) || \ + (_rate >= DESC_RATEVHT2SS_MCS0 && _rate <= DESC_RATEVHT2SS_MCS9)) + +#define IS_1T_RATESEC(_rs) \ + ((_rs == CCK) || (_rs == OFDM) || (_rs == HT_MCS0_MCS7) || \ + (_rs == VHT_1SSMCS0_1SSMCS9)) +#define IS_2T_RATESEC(_rs) \ + ((_rs == HT_MCS8_MCS15) || (_rs == VHT_2SSMCS0_2SSMCS9)) + +enum rx_packet_type { + NORMAL_RX, + C2H_PACKET, +}; + +enum rtl_desc_qsel { + QSLT_BK = 0x2, + QSLT_BE = 0x0, + QSLT_VI = 0x5, + QSLT_VO = 0x7, + QSLT_BEACON = 0x10, + QSLT_HIGH = 0x11, + QSLT_MGNT = 0x12, + QSLT_CMD = 0x13, +}; + +enum vht_data_sc { + VHT_DATA_SC_DONOT_CARE = 0, + VHT_DATA_SC_20_UPPER_OF_80MHZ = 1, + VHT_DATA_SC_20_LOWER_OF_80MHZ = 2, + VHT_DATA_SC_20_UPPERST_OF_80MHZ = 3, + VHT_DATA_SC_20_LOWEST_OF_80MHZ = 4, + VHT_DATA_SC_20_RECV1 = 5, + VHT_DATA_SC_20_RECV2 = 6, + VHT_DATA_SC_20_RECV3 = 7, + VHT_DATA_SC_20_RECV4 = 8, + VHT_DATA_SC_40_UPPER_OF_80MHZ = 9, + VHT_DATA_SC_40_LOWER_OF_80MHZ = 10, +}; +#endif diff --git a/drivers/staging/rtlwifi/rtl8822be/fw.c b/drivers/staging/rtlwifi/rtl8822be/fw.c new file mode 100644 index 000000000000..8e24da16752c --- /dev/null +++ b/drivers/staging/rtlwifi/rtl8822be/fw.c @@ -0,0 +1,968 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../pci.h" +#include "../base.h" +#include "reg.h" +#include "def.h" +#include "fw.h" + +static bool _rtl8822be_check_fw_read_last_h2c(struct ieee80211_hw *hw, + u8 boxnum) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 val_hmetfr; + bool result = false; + + val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR_8822B); + if (((val_hmetfr >> boxnum) & BIT(0)) == 0) + result = true; + return result; +} + +static void _rtl8822be_fill_h2c_command(struct ieee80211_hw *hw, u8 element_id, + u32 cmd_len, u8 *cmdbuffer) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u8 boxnum; + u16 box_reg = 0, box_extreg = 0; + u8 u1b_tmp; + bool isfw_read; + u8 buf_index = 0; + bool bwrite_success = false; + u8 wait_h2c_limmit = 100; + u8 boxcontent[4], boxextcontent[4]; + u32 h2c_waitcounter = 0; + unsigned long flag; + u8 idx; + + /* 1. Prevent race condition in setting H2C cmd. + * (copy from MgntActSet_RF_State().) + */ + while (true) { + spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag); + if (rtlhal->h2c_setinprogress) { + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + "H2C set in progress! wait..H2C_ID=%d.\n", + element_id); + + while (rtlhal->h2c_setinprogress) { + spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, + flag); + h2c_waitcounter++; + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + "Wait 100 us (%d times)...\n", + h2c_waitcounter); + udelay(100); + + if (h2c_waitcounter > 1000) + return; + spin_lock_irqsave(&rtlpriv->locks.h2c_lock, + flag); + } + spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag); + } else { + rtlhal->h2c_setinprogress = true; + spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag); + break; + } + } + + while (!bwrite_success) { + /* 2. Find the last BOX number which has been writen. */ + boxnum = rtlhal->last_hmeboxnum; + switch (boxnum) { + case 0: + box_reg = REG_HMEBOX0_8822B; + box_extreg = REG_HMEBOX_E0_8822B; + break; + case 1: + box_reg = REG_HMEBOX1_8822B; + box_extreg = REG_HMEBOX_E1_8822B; + break; + case 2: + box_reg = REG_HMEBOX2_8822B; + box_extreg = REG_HMEBOX_E2_8822B; + break; + case 3: + box_reg = REG_HMEBOX3_8822B; + box_extreg = REG_HMEBOX_E3_8822B; + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD, + "switch case not process\n"); + break; + } + + /* 3. Check if the box content is empty. */ + u1b_tmp = rtl_read_byte(rtlpriv, REG_CR_8822B); + + if (u1b_tmp == 0xea) { + if (rtl_read_byte(rtlpriv, REG_TXDMA_STATUS_8822B) == + 0xea || + rtl_read_byte(rtlpriv, REG_TXPKT_EMPTY_8822B) == + 0xea) + rtl_write_byte(rtlpriv, REG_SYS_CFG1_8822B + 3, + 0xff); + + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + "REG_CR is unavaliable\n"); + break; + } + + wait_h2c_limmit = 100; + isfw_read = _rtl8822be_check_fw_read_last_h2c(hw, boxnum); + while (!isfw_read) { + wait_h2c_limmit--; + if (wait_h2c_limmit == 0) { + RT_TRACE(rtlpriv, COMP_CMD, DBG_WARNING, + "Wait too long for FW clear MB%d!!!\n", + boxnum); + break; + } + udelay(10); + isfw_read = + _rtl8822be_check_fw_read_last_h2c(hw, boxnum); + u1b_tmp = rtl_read_byte(rtlpriv, 0x130); + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + "Waiting for FW clear MB%d!!! 0x130 = %2x\n", + boxnum, u1b_tmp); + } + + /* If Fw has not read the last H2C cmd, + * break and give up this H2C. + */ + if (!isfw_read) { + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + "Write H2C reg BOX[%d] fail,Fw don't read.\n", + boxnum); + break; + } + /* 4. Fill the H2C cmd into box */ + memset(boxcontent, 0, sizeof(boxcontent)); + memset(boxextcontent, 0, sizeof(boxextcontent)); + boxcontent[0] = element_id; + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + "Write element_id box_reg(%4x) = %2x\n", box_reg, + element_id); + + switch (cmd_len) { + case 1: + case 2: + case 3: + /*boxcontent[0] &= ~(BIT(7));*/ + memcpy((u8 *)(boxcontent) + 1, cmdbuffer + buf_index, + cmd_len); + + for (idx = 0; idx < 4; idx++) { + rtl_write_byte(rtlpriv, box_reg + idx, + boxcontent[idx]); + } + break; + case 4: + case 5: + case 6: + case 7: + /*boxcontent[0] |= (BIT(7));*/ + memcpy((u8 *)(boxextcontent), cmdbuffer + buf_index + 3, + cmd_len - 3); + memcpy((u8 *)(boxcontent) + 1, cmdbuffer + buf_index, + 3); + + for (idx = 0; idx < 4; idx++) { + rtl_write_byte(rtlpriv, box_extreg + idx, + boxextcontent[idx]); + } + + for (idx = 0; idx < 4; idx++) { + rtl_write_byte(rtlpriv, box_reg + idx, + boxcontent[idx]); + } + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD, + "switch case not process\n"); + break; + } + + bwrite_success = true; + + rtlhal->last_hmeboxnum = boxnum + 1; + if (rtlhal->last_hmeboxnum == 4) + rtlhal->last_hmeboxnum = 0; + + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + "pHalData->last_hmeboxnum = %d\n", + rtlhal->last_hmeboxnum); + } + + spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag); + rtlhal->h2c_setinprogress = false; + spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag); + + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "go out\n"); +} + +void rtl8822be_fill_h2c_cmd(struct ieee80211_hw *hw, u8 element_id, u32 cmd_len, + u8 *cmdbuffer) +{ + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 tmp_cmdbuf[8]; + + if (!rtlhal->fw_ready) { + WARN_ONCE(true, + "return H2C cmd because of Fw download fail!!!\n"); + return; + } + + memset(tmp_cmdbuf, 0, 8); + memcpy(tmp_cmdbuf, cmdbuffer, cmd_len); + + RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG, + "h2c cmd: len=%d %02X%02X%02X%02X %02X%02X%02X%02X\n", cmd_len, + tmp_cmdbuf[2], tmp_cmdbuf[1], tmp_cmdbuf[0], element_id, + tmp_cmdbuf[6], tmp_cmdbuf[5], tmp_cmdbuf[4], tmp_cmdbuf[3]); + + _rtl8822be_fill_h2c_command(hw, element_id, cmd_len, tmp_cmdbuf); +} + +void rtl8822be_set_default_port_id_cmd(struct ieee80211_hw *hw) +{ + u8 h2c_set_default_port_id[H2C_DEFAULT_PORT_ID_LEN]; + + SET_H2CCMD_DFTPID_PORT_ID(h2c_set_default_port_id, 0); + SET_H2CCMD_DFTPID_MAC_ID(h2c_set_default_port_id, 0); + + rtl8822be_fill_h2c_cmd(hw, H2C_8822B_DEFAULT_PORT_ID, + H2C_DEFAULT_PORT_ID_LEN, + h2c_set_default_port_id); +} + +void rtl8822be_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 u1_h2c_set_pwrmode[H2C_8822B_PWEMODE_LENGTH] = {0}; + static u8 prev_h2c[H2C_8822B_PWEMODE_LENGTH] = {0}; + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + u8 rlbm, power_state = 0, byte5 = 0; + u8 awake_intvl; /* DTIM = (awake_intvl - 1) */ + u8 smart_ps = 0; + struct rtl_btc_ops *btc_ops = rtlpriv->btcoexist.btc_ops; + bool bt_ctrl_lps = (rtlpriv->cfg->ops->get_btc_status() ? + btc_ops->btc_is_bt_ctrl_lps(rtlpriv) : false); + bool bt_lps_on = (rtlpriv->cfg->ops->get_btc_status() ? + btc_ops->btc_is_bt_lps_on(rtlpriv) : false); + + memset(u1_h2c_set_pwrmode, 0, H2C_8822B_PWEMODE_LENGTH); + + if (bt_ctrl_lps) + mode = (bt_lps_on ? FW_PS_MIN_MODE : FW_PS_ACTIVE_MODE); + + RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, "FW LPS mode = %d (coex:%d)\n", + mode, bt_ctrl_lps); + + switch (mode) { + case FW_PS_MIN_MODE: + rlbm = 0; + awake_intvl = 2; + smart_ps = ppsc->smart_ps; + break; + case FW_PS_MAX_MODE: + rlbm = 1; + awake_intvl = 2; + smart_ps = ppsc->smart_ps; + break; + case FW_PS_DTIM_MODE: + rlbm = 2; + awake_intvl = ppsc->reg_max_lps_awakeintvl; + /* + * hw->conf.ps_dtim_period or mac->vif->bss_conf.dtim_period + * is only used in swlps. + */ + smart_ps = ppsc->smart_ps; + break; + case FW_PS_ACTIVE_MODE: + rlbm = 0; + awake_intvl = 1; + break; + default: + rlbm = 2; + awake_intvl = 4; + smart_ps = ppsc->smart_ps; + break; + } + + if (rtlpriv->mac80211.p2p) { + awake_intvl = 2; + rlbm = 1; + } + + if (mode == FW_PS_ACTIVE_MODE) { + byte5 = 0x40; + power_state = FW_PWR_STATE_ACTIVE; + } else { + if (bt_ctrl_lps) { + byte5 = btc_ops->btc_get_lps_val(rtlpriv); + power_state = btc_ops->btc_get_rpwm_val(rtlpriv); + + if ((rlbm == 2) && (byte5 & BIT(4))) { + /* Keep awake interval to 1 to prevent from + * decreasing coex performance + */ + awake_intvl = 2; + rlbm = 2; + } + smart_ps = 0; + } else { + byte5 = 0x40; + power_state = FW_PWR_STATE_RF_OFF; + } + } + + SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, ((mode) ? 1 : 0)); + SET_H2CCMD_PWRMODE_PARM_RLBM(u1_h2c_set_pwrmode, rlbm); + SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode, smart_ps); + SET_H2CCMD_PWRMODE_PARM_AWAKE_INTERVAL(u1_h2c_set_pwrmode, awake_intvl); + SET_H2CCMD_PWRMODE_PARM_ALL_QUEUE_UAPSD(u1_h2c_set_pwrmode, 0); + SET_H2CCMD_PWRMODE_PARM_PWR_STATE(u1_h2c_set_pwrmode, power_state); + SET_H2CCMD_PWRMODE_PARM_BYTE5(u1_h2c_set_pwrmode, byte5); + + RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, + "rtl8822be_set_fw_pwrmode(): u1_h2c_set_pwrmode\n", + u1_h2c_set_pwrmode, H2C_8822B_PWEMODE_LENGTH); + if (rtlpriv->cfg->ops->get_btc_status()) + btc_ops->btc_record_pwr_mode(rtlpriv, u1_h2c_set_pwrmode, + H2C_8822B_PWEMODE_LENGTH); + + if (!memcmp(prev_h2c, u1_h2c_set_pwrmode, H2C_8822B_PWEMODE_LENGTH)) + return; + memcpy(prev_h2c, u1_h2c_set_pwrmode, H2C_8822B_PWEMODE_LENGTH); + + rtl8822be_set_default_port_id_cmd(hw); + rtl8822be_fill_h2c_cmd(hw, H2C_8822B_SETPWRMODE, + H2C_8822B_PWEMODE_LENGTH, u1_h2c_set_pwrmode); +} + +void rtl8822be_set_fw_media_status_rpt_cmd(struct ieee80211_hw *hw, u8 mstatus) +{ + u8 parm[4] = {0, 0, 0, 0}; + /* parm[0]: bit0=0-->Disconnect, bit0=1-->Connect + * bit1=0-->update Media Status to MACID + * bit1=1-->update Media Status from MACID to MACID_End + * parm[1]: MACID, if this is INFRA_STA, MacID = 0 + * parm[2]: MACID_End + * parm[3]: bit2-0: port ID + */ + + SET_H2CCMD_MSRRPT_PARM_OPMODE(parm, mstatus); + SET_H2CCMD_MSRRPT_PARM_MACID_IND(parm, 0); + + rtl8822be_fill_h2c_cmd(hw, H2C_8822B_MSRRPT, 4, parm); +} + +static bool _rtl8822be_send_bcn_or_cmd_packet(struct ieee80211_hw *hw, + struct sk_buff *skb, u8 hw_queue) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl8192_tx_ring *ring; + struct rtl_tx_desc *pdesc; + struct rtl_tx_buffer_desc *pbd_desc; + unsigned long flags; + struct sk_buff *pskb = NULL; + u8 *pdesc_or_bddesc; + dma_addr_t dma_addr; + + if (hw_queue != BEACON_QUEUE && hw_queue != H2C_QUEUE) + return false; + + ring = &rtlpci->tx_ring[hw_queue]; + + spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags); + + if (hw_queue == BEACON_QUEUE) { + pdesc = &ring->desc[0]; + pbd_desc = &ring->buffer_desc[0]; + pdesc_or_bddesc = (u8 *)pbd_desc; + + /* free previous beacon queue */ + pskb = __skb_dequeue(&ring->queue); + + if (!pskb) + goto free_prev_skb_done; + + dma_addr = rtlpriv->cfg->ops->get_desc( + hw, (u8 *)pbd_desc, true, HW_DESC_TXBUFF_ADDR); + + pci_unmap_single(rtlpci->pdev, dma_addr, skb->len, + PCI_DMA_TODEVICE); + kfree_skb(pskb); + +free_prev_skb_done: + ; + + } else { /* hw_queue == TXCMD_QUEUE */ + if (rtlpriv->cfg->ops->get_available_desc(hw, hw_queue) == 0) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "get_available_desc fail hw_queue=%d\n", + hw_queue); + spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, + flags); + return false; + } + + pdesc = &ring->desc[ring->cur_tx_wp]; + pbd_desc = &ring->buffer_desc[ring->cur_tx_wp]; + pdesc_or_bddesc = (u8 *)pdesc; + } + + rtlpriv->cfg->ops->fill_tx_special_desc(hw, (u8 *)pdesc, (u8 *)pbd_desc, + skb, hw_queue); + + __skb_queue_tail(&ring->queue, skb); + + rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc_or_bddesc, true, + HW_DESC_OWN, (u8 *)&hw_queue); + + spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); + + rtlpriv->cfg->ops->tx_polling(hw, hw_queue); + + return true; +} + +bool rtl8822b_halmac_cb_write_data_rsvd_page(struct rtl_priv *rtlpriv, u8 *buf, + u32 size) +{ + struct sk_buff *skb = NULL; + u8 u1b_tmp; + int count; + + skb = dev_alloc_skb(size); + memcpy((u8 *)skb_put(skb, size), buf, size); + + if (!_rtl8822be_send_bcn_or_cmd_packet(rtlpriv->hw, skb, BEACON_QUEUE)) + return false; + + /* These code isn't actually need, because halmac will check + * BCN_VALID + */ + + /* Polling Beacon Queue to send Beacon */ + u1b_tmp = rtl_read_byte(rtlpriv, REG_RX_RXBD_NUM_8822B + 1); + count = 0; + while ((count < 20) && (u1b_tmp & BIT(4))) { + count++; + udelay(10); + u1b_tmp = rtl_read_byte(rtlpriv, REG_RX_RXBD_NUM_8822B + 1); + } + + if (count >= 20) + pr_err("%s polling beacon fail\n", __func__); + + return true; +} + +bool rtl8822b_halmac_cb_write_data_h2c(struct rtl_priv *rtlpriv, u8 *buf, + u32 size) +{ + struct sk_buff *skb = NULL; + + /* without GFP_DMA, pci_map_single() may not work */ + skb = __netdev_alloc_skb(NULL, size, GFP_ATOMIC | GFP_DMA); + memcpy((u8 *)skb_put(skb, size), buf, size); + + return _rtl8822be_send_bcn_or_cmd_packet(rtlpriv->hw, skb, H2C_QUEUE); +} + +/* Rsvd page HALMAC_RSVD_DRV_PGNUM_8822B occupies 16 page (2048 byte) */ +#define BEACON_PG 0 /* ->1 */ +#define PSPOLL_PG 2 +#define NULL_PG 3 +#define PROBERSP_PG 4 /* ->5 */ +#define QOS_NULL_PG 6 +#define BT_QOS_NULL_PG 7 + +#define TOTAL_RESERVED_PKT_LEN 1024 + +static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {/* page size = 128 */ + /* page 0 beacon */ + 0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x02, 0xB1, 0x78, + 0xEC, 0x1A, 0x59, 0x0B, 0xAD, 0xD4, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x64, 0x00, 0x10, 0x04, 0x00, 0x05, 0x54, 0x65, + 0x73, 0x74, 0x32, 0x01, 0x08, 0x82, 0x84, 0x0B, + 0x16, 0x24, 0x30, 0x48, 0x6C, 0x03, 0x01, 0x06, + 0x06, 0x02, 0x00, 0x00, 0x2A, 0x01, 0x02, 0x32, + 0x04, 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, + 0x09, 0x03, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x3D, 0x00, 0xDD, 0x07, 0x00, 0xE0, 0x4C, + 0x02, 0x02, 0x00, 0x00, 0xDD, 0x18, 0x00, 0x50, + 0xF2, 0x01, 0x01, 0x00, 0x00, 0x50, 0xF2, 0x04, + 0x01, 0x00, 0x00, 0x50, 0xF2, 0x04, 0x01, 0x00, + + /* page 1 beacon */ + 0x00, 0x50, 0xF2, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x30, 0x84, 0x00, 0x12, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* page 2 ps-poll */ + 0xA4, 0x10, 0x01, 0xC0, 0xEC, 0x1A, 0x59, 0x0B, + 0xAD, 0xD4, 0x00, 0xE0, 0x4C, 0x02, 0xB1, 0x78, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x30, 0x84, 0x00, 0x12, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* page 3 null */ + 0x48, 0x01, 0x00, 0x00, 0xEC, 0x1A, 0x59, 0x0B, + 0xAD, 0xD4, 0x00, 0xE0, 0x4C, 0x02, 0xB1, 0x78, + 0xEC, 0x1A, 0x59, 0x0B, 0xAD, 0xD4, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x72, 0x00, 0x30, 0x84, 0x00, 0x12, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* page 4 probe_resp */ + 0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10, + 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42, + 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00, + 0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00, + 0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69, + 0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C, + 0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96, + 0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A, + 0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C, + 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02, + 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* page 5 probe_resp */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1A, 0x00, 0x30, 0x84, 0x00, 0x12, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* page 6 qos null data */ + 0xC8, 0x01, 0x00, 0x00, 0x84, 0xC9, 0xB2, 0xA7, + 0xB3, 0x6E, 0x00, 0xE0, 0x4C, 0x02, 0x51, 0x02, + 0x84, 0xC9, 0xB2, 0xA7, 0xB3, 0x6E, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1A, 0x00, 0x30, 0x84, 0x00, 0x12, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* page 7 BT-qos null data */ + 0xC8, 0x01, 0x00, 0x00, 0x84, 0xC9, 0xB2, 0xA7, + 0xB3, 0x6E, 0x00, 0xE0, 0x4C, 0x02, 0x51, 0x02, + 0x84, 0xC9, 0xB2, 0xA7, 0xB3, 0x6E, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +void rtl8822be_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct sk_buff *skb = NULL; + + u32 totalpacketlen; + bool rtstatus; + u8 u1_rsvd_page_loc[7] = {0}; + bool b_dlok = false; + + u8 *beacon; + u8 *p_pspoll; + u8 *nullfunc; + u8 *p_probersp; + u8 *qosnull; + u8 *btqosnull; + + memset(u1_rsvd_page_loc, 0, sizeof(u1_rsvd_page_loc)); + + /*--------------------------------------------------------- + * (1) beacon + *--------------------------------------------------------- + */ + beacon = &reserved_page_packet[BEACON_PG * 128]; + SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr); + SET_80211_HDR_ADDRESS3(beacon, mac->bssid); + + /*------------------------------------------------------- + * (2) ps-poll + *-------------------------------------------------------- + */ + p_pspoll = &reserved_page_packet[PSPOLL_PG * 128]; + SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000)); + SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid); + SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr); + + SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1_rsvd_page_loc, PSPOLL_PG); + + /*-------------------------------------------------------- + * (3) null data + *--------------------------------------------------------- + */ + nullfunc = &reserved_page_packet[NULL_PG * 128]; + SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid); + SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr); + SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid); + + SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1_rsvd_page_loc, NULL_PG); + + /*--------------------------------------------------------- + * (4) probe response + *---------------------------------------------------------- + */ + p_probersp = &reserved_page_packet[PROBERSP_PG * 128]; + SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid); + SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr); + SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid); + + SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1_rsvd_page_loc, PROBERSP_PG); + + /*--------------------------------------------------------- + * (5) QoS null data + *---------------------------------------------------------- + */ + qosnull = &reserved_page_packet[QOS_NULL_PG * 128]; + SET_80211_HDR_ADDRESS1(qosnull, mac->bssid); + SET_80211_HDR_ADDRESS2(qosnull, mac->mac_addr); + SET_80211_HDR_ADDRESS3(qosnull, mac->bssid); + + SET_H2CCMD_RSVDPAGE_LOC_QOS_NULL_DATA(u1_rsvd_page_loc, QOS_NULL_PG); + + /*--------------------------------------------------------- + * (6) BT QoS null data + *---------------------------------------------------------- + */ + btqosnull = &reserved_page_packet[BT_QOS_NULL_PG * 128]; + SET_80211_HDR_ADDRESS1(btqosnull, mac->bssid); + SET_80211_HDR_ADDRESS2(btqosnull, mac->mac_addr); + SET_80211_HDR_ADDRESS3(btqosnull, mac->bssid); + + SET_H2CCMD_RSVDPAGE_LOC_BT_QOS_NULL_DATA(u1_rsvd_page_loc, + BT_QOS_NULL_PG); + + totalpacketlen = TOTAL_RESERVED_PKT_LEN; + + RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD, + "rtl8822be_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n", + &reserved_page_packet[0], totalpacketlen); + RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD, + "rtl8822be_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n", + u1_rsvd_page_loc, 3); + + skb = dev_alloc_skb(totalpacketlen); + memcpy((u8 *)skb_put(skb, totalpacketlen), &reserved_page_packet, + totalpacketlen); + + rtstatus = _rtl8822be_send_bcn_or_cmd_packet(hw, skb, BEACON_QUEUE); + + if (rtstatus) + b_dlok = true; + + if (b_dlok) { + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "Set RSVD page location to Fw.\n"); + RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD, "H2C_RSVDPAGE:\n", + u1_rsvd_page_loc, 3); + rtl8822be_fill_h2c_cmd(hw, H2C_8822B_RSVDPAGE, + sizeof(u1_rsvd_page_loc), + u1_rsvd_page_loc); + } else + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "Set RSVD page location to Fw FAIL!!!!!!.\n"); +} + +/* Should check FW support p2p or not. */ +static void rtl8822be_set_p2p_ctw_period_cmd(struct ieee80211_hw *hw, + u8 ctwindow) +{ + u8 u1_ctwindow_period[1] = {ctwindow}; + + rtl8822be_fill_h2c_cmd(hw, H2C_8822B_P2P_PS_CTW_CMD, 1, + u1_ctwindow_period); +} + +void rtl8822be_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_p2p_ps_info *p2pinfo = &rtlps->p2p_ps_info; + struct p2p_ps_offload_t *p2p_ps_offload = &rtlhal->p2p_ps_offload; + u8 i; + u16 ctwindow; + u32 start_time, tsf_low; + + switch (p2p_ps_state) { + case P2P_PS_DISABLE: + RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_DISABLE\n"); + memset(p2p_ps_offload, 0, sizeof(*p2p_ps_offload)); + break; + case P2P_PS_ENABLE: + RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_ENABLE\n"); + /* update CTWindow value. */ + if (p2pinfo->ctwindow > 0) { + p2p_ps_offload->ctwindow_en = 1; + ctwindow = p2pinfo->ctwindow; + rtl8822be_set_p2p_ctw_period_cmd(hw, ctwindow); + } + /* hw only support 2 set of NoA */ + for (i = 0; i < p2pinfo->noa_num; i++) { + /* To control the register setting for which NOA*/ + rtl_write_byte(rtlpriv, 0x5cf, (i << 4)); + if (i == 0) + p2p_ps_offload->noa0_en = 1; + else + p2p_ps_offload->noa1_en = 1; + /* config P2P NoA Descriptor Register */ + rtl_write_dword(rtlpriv, 0x5E0, + p2pinfo->noa_duration[i]); + rtl_write_dword(rtlpriv, 0x5E4, + p2pinfo->noa_interval[i]); + + /*Get Current TSF value */ + tsf_low = rtl_read_dword(rtlpriv, REG_TSFTR_8822B); + + start_time = p2pinfo->noa_start_time[i]; + if (p2pinfo->noa_count_type[i] != 1) { + while (start_time <= (tsf_low + (50 * 1024))) { + start_time += p2pinfo->noa_interval[i]; + if (p2pinfo->noa_count_type[i] != 255) + p2pinfo->noa_count_type[i]--; + } + } + rtl_write_dword(rtlpriv, 0x5E8, start_time); + rtl_write_dword(rtlpriv, 0x5EC, + p2pinfo->noa_count_type[i]); + } + if ((p2pinfo->opp_ps == 1) || (p2pinfo->noa_num > 0)) { + /* rst p2p circuit */ + rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST_8822B, BIT(4)); + p2p_ps_offload->offload_en = 1; + + if (rtlpriv->mac80211.p2p == P2P_ROLE_GO) { + p2p_ps_offload->role = 1; + p2p_ps_offload->allstasleep = 0; + } else { + p2p_ps_offload->role = 0; + } + p2p_ps_offload->discovery = 0; + } + break; + case P2P_PS_SCAN: + RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN\n"); + p2p_ps_offload->discovery = 1; + break; + case P2P_PS_SCAN_DONE: + RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN_DONE\n"); + p2p_ps_offload->discovery = 0; + p2pinfo->p2p_ps_state = P2P_PS_ENABLE; + break; + default: + break; + } + + rtl8822be_fill_h2c_cmd(hw, H2C_8822B_P2P_PS_OFFLOAD, 1, + (u8 *)p2p_ps_offload); +} + +static +void rtl8822be_c2h_content_parsing_ext(struct ieee80211_hw *hw, + u8 c2h_sub_cmd_id, + u8 c2h_cmd_len, + u8 *c2h_content_buf) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_halmac_ops *halmac_ops; + + switch (c2h_sub_cmd_id) { + case 0x0F: + RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, + "[C2H], C2H_8822BE_TX_REPORT!\n"); + rtl_tx_report_handler(hw, c2h_content_buf, c2h_cmd_len); + break; + default: + /* indicate c2h pkt + rx desc to halmac */ + halmac_ops = rtlpriv->halmac.ops; + halmac_ops->halmac_c2h_handle(rtlpriv, + c2h_content_buf - 24 - 2 - 2, + c2h_cmd_len + 24 + 2 + 2); + break; + } +} + +void rtl8822be_c2h_content_parsing(struct ieee80211_hw *hw, u8 c2h_cmd_id, + u8 c2h_cmd_len, u8 *tmp_buf) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_btc_ops *btc_ops = rtlpriv->btcoexist.btc_ops; + + if (c2h_cmd_id == 0xFF) { + rtl8822be_c2h_content_parsing_ext(hw, tmp_buf[0], + c2h_cmd_len - 2, + tmp_buf + 2); + return; + } + + switch (c2h_cmd_id) { + case C2H_8822B_DBG: + RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, + "[C2H], C2H_8822BE_DBG!!\n"); + break; + case C2H_8822B_TXBF: + RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, + "[C2H], C2H_8822B_TXBF!!\n"); + break; + case C2H_8822B_BT_INFO: + RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, + "[C2H], C2H_8822BE_BT_INFO!!\n"); + if (rtlpriv->cfg->ops->get_btc_status()) + btc_ops->btc_btinfo_notify(rtlpriv, tmp_buf, + c2h_cmd_len); + break; + case C2H_8822B_BT_MP: + RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, + "[C2H], C2H_8822BE_BT_MP!!\n"); + if (rtlpriv->cfg->ops->get_btc_status()) + btc_ops->btc_btmpinfo_notify(rtlpriv, tmp_buf, + c2h_cmd_len); + break; + default: + if (!rtlpriv->phydm.ops->phydm_c2h_content_parsing( + rtlpriv, c2h_cmd_id, c2h_cmd_len, tmp_buf)) + break; + + RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, + "[C2H], Unknown packet!! CmdId(%#X)!\n", c2h_cmd_id); + break; + } +} + +void rtl8822be_c2h_packet_handler(struct ieee80211_hw *hw, u8 *buffer, u8 len) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 c2h_cmd_id = 0, c2h_cmd_seq = 0, c2h_cmd_len = 0; + u8 *tmp_buf = NULL; + + c2h_cmd_id = buffer[0]; + c2h_cmd_seq = buffer[1]; + c2h_cmd_len = len - 2; + tmp_buf = buffer + 2; + + RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, + "[C2H packet], c2hCmdId=0x%x, c2hCmdSeq=0x%x, c2hCmdLen=%d\n", + c2h_cmd_id, c2h_cmd_seq, c2h_cmd_len); + + RT_PRINT_DATA(rtlpriv, COMP_FW, DBG_TRACE, + "[C2H packet], Content Hex:\n", tmp_buf, c2h_cmd_len); + + switch (c2h_cmd_id) { + case C2H_8822B_BT_INFO: + case C2H_8822B_BT_MP: + rtl_c2hcmd_enqueue(hw, c2h_cmd_id, c2h_cmd_len, tmp_buf); + break; + default: + rtl8822be_c2h_content_parsing(hw, c2h_cmd_id, c2h_cmd_len, + tmp_buf); + break; + } +} diff --git a/drivers/staging/rtlwifi/rtl8822be/fw.h b/drivers/staging/rtlwifi/rtl8822be/fw.h new file mode 100644 index 000000000000..3ad7a66e80a3 --- /dev/null +++ b/drivers/staging/rtlwifi/rtl8822be/fw.h @@ -0,0 +1,198 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL8822B__FW__H__ +#define __RTL8822B__FW__H__ + +#define USE_OLD_WOWLAN_DEBUG_FW 0 + +#define H2C_8822B_RSVDPAGE_LOC_LEN 5 +#define H2C_8822B_PWEMODE_LENGTH 7 +#define H2C_8822B_JOINBSSRPT_LENGTH 1 +#define H2C_8822B_AP_OFFLOAD_LENGTH 3 +#define H2C_8822B_WOWLAN_LENGTH 3 +#define H2C_8822B_KEEP_ALIVE_CTRL_LENGTH 3 +#if (USE_OLD_WOWLAN_DEBUG_FW == 0) +#define H2C_8822B_REMOTE_WAKE_CTRL_LEN 1 +#else +#define H2C_8822B_REMOTE_WAKE_CTRL_LEN 3 +#endif +#define H2C_8822B_AOAC_GLOBAL_INFO_LEN 2 +#define H2C_8822B_AOAC_RSVDPAGE_LOC_LEN 7 +#define H2C_DEFAULT_PORT_ID_LEN 2 + +/* Fw PS state for RPWM. + *BIT[2:0] = HW state + *BIT[3] = Protocol PS state, 1: register active state, 0: register sleep state + *BIT[4] = sub-state + */ +#define FW_PS_RF_ON BIT(2) +#define FW_PS_REGISTER_ACTIVE BIT(3) + +#define FW_PS_ACK BIT(6) +#define FW_PS_TOGGLE BIT(7) + +/* 8822B RPWM value*/ +/* BIT[0] = 1: 32k, 0: 40M*/ +#define FW_PS_CLOCK_OFF BIT(0) /* 32k */ +#define FW_PS_CLOCK_ON 0 /* 40M */ + +#define FW_PS_STATE_MASK (0x0F) +#define FW_PS_STATE_HW_MASK (0x07) +#define FW_PS_STATE_INT_MASK (0x3F) + +#define FW_PS_STATE(x) (FW_PS_STATE_MASK & (x)) + +#define FW_PS_STATE_ALL_ON_8822B (FW_PS_CLOCK_ON) +#define FW_PS_STATE_RF_ON_8822B (FW_PS_CLOCK_ON) +#define FW_PS_STATE_RF_OFF_8822B (FW_PS_CLOCK_ON) +#define FW_PS_STATE_RF_OFF_LOW_PWR (FW_PS_CLOCK_OFF) + +/* For 8822B H2C PwrMode Cmd ID 5.*/ +#define FW_PWR_STATE_ACTIVE ((FW_PS_RF_ON) | (FW_PS_REGISTER_ACTIVE)) +#define FW_PWR_STATE_RF_OFF 0 + +#define FW_PS_IS_ACK(x) ((x) & FW_PS_ACK) + +#define IS_IN_LOW_POWER_STATE_8822B(fw_ps_state) \ + (FW_PS_STATE(fw_ps_state) == FW_PS_CLOCK_OFF) + +#define FW_PWR_STATE_ACTIVE ((FW_PS_RF_ON) | (FW_PS_REGISTER_ACTIVE)) +#define FW_PWR_STATE_RF_OFF 0 + +enum rtl8822b_h2c_cmd { + H2C_8822B_RSVDPAGE = 0, + H2C_8822B_MSRRPT = 1, + H2C_8822B_SCAN = 2, + H2C_8822B_KEEP_ALIVE_CTRL = 3, + H2C_8822B_DISCONNECT_DECISION = 4, +#if (USE_OLD_WOWLAN_DEBUG_FW == 1) + H2C_8822B_WO_WLAN = 5, +#endif + H2C_8822B_INIT_OFFLOAD = 6, +#if (USE_OLD_WOWLAN_DEBUG_FW == 1) + H2C_8822B_REMOTE_WAKE_CTRL = 7, +#endif + H2C_8822B_AP_OFFLOAD = 8, + H2C_8822B_BCN_RSVDPAGE = 9, + H2C_8822B_PROBERSP_RSVDPAGE = 10, + + H2C_8822B_SETPWRMODE = 0x20, + H2C_8822B_PS_TUNING_PARA = 0x21, + H2C_8822B_PS_TUNING_PARA2 = 0x22, + H2C_8822B_PS_LPS_PARA = 0x23, + H2C_8822B_P2P_PS_OFFLOAD = 024, + H2C_8822B_DEFAULT_PORT_ID = 0x2C, + +#if (USE_OLD_WOWLAN_DEBUG_FW == 0) + H2C_8822B_WO_WLAN = 0x80, + H2C_8822B_REMOTE_WAKE_CTRL = 0x81, + H2C_8822B_AOAC_GLOBAL_INFO = 0x82, + H2C_8822B_AOAC_RSVDPAGE = 0x83, +#endif + H2C_8822B_MACID_CFG = 0x40, + H2C_8822B_RSSI_REPORT = 0x42, + H2C_8822B_MACID_CFG_3SS = 0x46, + /*Not defined CTW CMD for P2P yet*/ + H2C_8822B_P2P_PS_CTW_CMD = 0x99, + MAX_8822B_H2CCMD +}; + +enum rtl8822b_c2h_evt { + C2H_8822B_DBG = 0x00, + C2H_8822B_LB = 0x01, + C2H_8822B_TXBF = 0x02, + C2H_8822B_TX_REPORT = 0x03, + C2H_8822B_BT_INFO = 0x09, + C2H_8822B_BT_MP = 0x0B, + C2H_8822B_RA_RPT = 0x0C, + MAX_8822B_C2HEVENT +}; + +/* H2C: 0x20 */ +#define SET_H2CCMD_PWRMODE_PARM_MODE(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 7, __val) +#define SET_H2CCMD_PWRMODE_PARM_CLK_REQ(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE(__ph2ccmd, 7, 1, __val) +#define SET_H2CCMD_PWRMODE_PARM_RLBM(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE((__ph2ccmd) + 1, 0, 4, __val) +#define SET_H2CCMD_PWRMODE_PARM_SMART_PS(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE((__ph2ccmd) + 1, 4, 4, __val) +#define SET_H2CCMD_PWRMODE_PARM_AWAKE_INTERVAL(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE((__ph2ccmd) + 2, 0, 8, __val) +#define SET_H2CCMD_PWRMODE_PARM_ALL_QUEUE_UAPSD(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE((__ph2ccmd) + 3, 0, 1, __val) +#define SET_H2CCMD_PWRMODE_PARM_BCN_EARLY_RPT(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE((__ph2ccmd) + 3, 2, 1, __val) +#define SET_H2CCMD_PWRMODE_PARM_PORT_ID(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE((__ph2ccmd) + 3, 5, 3, __val) +#define SET_H2CCMD_PWRMODE_PARM_PWR_STATE(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE((__ph2ccmd) + 4, 0, 8, __val) +#define SET_H2CCMD_PWRMODE_PARM_BYTE5(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE((__ph2ccmd) + 5, 0, 8, __val) + +/* H2C: 0x00 */ +#define SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val) +#define SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE((__ph2ccmd) + 1, 0, 8, __val) +#define SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE((__ph2ccmd) + 2, 0, 8, __val) +#define SET_H2CCMD_RSVDPAGE_LOC_QOS_NULL_DATA(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE((__ph2ccmd) + 3, 0, 8, __val) +#define SET_H2CCMD_RSVDPAGE_LOC_BT_QOS_NULL_DATA(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE((__ph2ccmd) + 4, 0, 8, __val) + +/* H2C: 0x01 */ +#define SET_H2CCMD_MSRRPT_PARM_OPMODE(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 1, __val) +#define SET_H2CCMD_MSRRPT_PARM_MACID_IND(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE(__ph2ccmd, 1, 1, __val) +#define SET_H2CCMD_MSRRPT_PARM_MACID(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE(__ph2ccmd + 1, 0, 8, __val) +#define SET_H2CCMD_MSRRPT_PARM_MACID_END(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE(__ph2ccmd + 2, 0, 8, __val) + +/* H2C: 0x2C */ +#define SET_H2CCMD_DFTPID_PORT_ID(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE(((u8 *)(__ph2ccmd)), 0, 8, (__val)) +#define SET_H2CCMD_DFTPID_MAC_ID(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE(((u8 *)(__ph2ccmd)) + 1, 0, 8, (__val)) + +void rtl8822be_fill_h2c_cmd(struct ieee80211_hw *hw, u8 element_id, u32 cmd_len, + u8 *cmdbuffer); +void rtl8822be_set_default_port_id_cmd(struct ieee80211_hw *hw); +void rtl8822be_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode); +void rtl8822be_set_fw_media_status_rpt_cmd(struct ieee80211_hw *hw, u8 mstatus); +void rtl8822be_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished); +void rtl8822be_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state); +void rtl8822be_c2h_packet_handler(struct ieee80211_hw *hw, u8 *buffer, u8 len); +void rtl8822be_c2h_content_parsing(struct ieee80211_hw *hw, u8 c2h_cmd_id, + u8 c2h_cmd_len, u8 *tmp_buf); +bool rtl8822b_halmac_cb_write_data_rsvd_page(struct rtl_priv *rtlpriv, u8 *buf, + u32 size); +bool rtl8822b_halmac_cb_write_data_h2c(struct rtl_priv *rtlpriv, u8 *buf, + u32 size); +#endif diff --git a/drivers/staging/rtlwifi/rtl8822be/hw.c b/drivers/staging/rtlwifi/rtl8822be/hw.c new file mode 100644 index 000000000000..74386003044f --- /dev/null +++ b/drivers/staging/rtlwifi/rtl8822be/hw.c @@ -0,0 +1,2441 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../efuse.h" +#include "../base.h" +#include "../regd.h" +#include "../cam.h" +#include "../ps.h" +#include "../pci.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "fw.h" +#include "led.h" +#include "hw.h" + +#define LLT_CONFIG 5 + +u8 rtl_channel5g[CHANNEL_MAX_NUMBER_5G] = { + 36, 38, 40, 42, 44, 46, 48, /* Band 1 */ + 52, 54, 56, 58, 60, 62, 64, /* Band 2 */ + 100, 102, 104, 106, 108, 110, 112, /* Band 3 */ + 116, 118, 120, 122, 124, 126, 128, /* Band 3 */ + 132, 134, 136, 138, 140, 142, 144, /* Band 3 */ + 149, 151, 153, 155, 157, 159, 161, /* Band 4 */ + 165, 167, 169, 171, 173, 175, 177}; /* Band 4 */ +u8 rtl_channel5g_80m[CHANNEL_MAX_NUMBER_5G_80M] = {42, 58, 106, 122, + 138, 155, 171}; + +static void _rtl8822be_set_bcn_ctrl_reg(struct ieee80211_hw *hw, u8 set_bits, + u8 clear_bits) +{ + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtlpci->reg_bcn_ctrl_val |= set_bits; + rtlpci->reg_bcn_ctrl_val &= ~clear_bits; + + rtl_write_byte(rtlpriv, REG_BCN_CTRL_8822B, + (u8)rtlpci->reg_bcn_ctrl_val); +} + +static void _rtl8822be_stop_tx_beacon(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 tmp; + + tmp = rtl_read_byte(rtlpriv, REG_FWHW_TXQ_CTRL_8822B + 2); + rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL_8822B + 2, tmp & (~BIT(6))); + rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT_8822B + 1, 0x64); + tmp = rtl_read_byte(rtlpriv, REG_TBTT_PROHIBIT_8822B + 2); + tmp &= ~(BIT(0)); + rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT_8822B + 2, tmp); +} + +static void _rtl8822be_resume_tx_beacon(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 tmp; + + tmp = rtl_read_byte(rtlpriv, REG_FWHW_TXQ_CTRL_8822B + 2); + rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL_8822B + 2, tmp | BIT(6)); + rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT_8822B + 1, 0xff); + tmp = rtl_read_byte(rtlpriv, REG_TBTT_PROHIBIT_8822B + 2); + tmp |= BIT(0); + rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT_8822B + 2, tmp); +} + +static void _rtl8822be_enable_bcn_sub_func(struct ieee80211_hw *hw) +{ + _rtl8822be_set_bcn_ctrl_reg(hw, 0, BIT(1)); +} + +static void _rtl8822be_disable_bcn_sub_func(struct ieee80211_hw *hw) +{ + _rtl8822be_set_bcn_ctrl_reg(hw, BIT(1), 0); +} + +static void _rtl8822be_set_fw_clock_on(struct ieee80211_hw *hw, u8 rpwm_val, + bool b_need_turn_off_ckk) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u32 count = 0, isr_regaddr, content; + bool b_schedule_timer = b_need_turn_off_ckk; + + if (!rtlhal->fw_ready) + return; + if (!rtlpriv->psc.fw_current_inpsmode) + return; + + while (1) { + spin_lock_bh(&rtlpriv->locks.fw_ps_lock); + if (rtlhal->fw_clk_change_in_progress) { + while (rtlhal->fw_clk_change_in_progress) { + spin_unlock_bh(&rtlpriv->locks.fw_ps_lock); + count++; + udelay(100); + if (count > 1000) + return; + spin_lock_bh(&rtlpriv->locks.fw_ps_lock); + } + spin_unlock_bh(&rtlpriv->locks.fw_ps_lock); + } else { + rtlhal->fw_clk_change_in_progress = false; + spin_unlock_bh(&rtlpriv->locks.fw_ps_lock); + break; + } + } + + if (IS_IN_LOW_POWER_STATE_8822B(rtlhal->fw_ps_state)) { + rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_SET_RPWM, + (u8 *)(&rpwm_val)); + if (FW_PS_IS_ACK(rpwm_val)) { + isr_regaddr = REG_HISR0_8822B; + content = rtl_read_dword(rtlpriv, isr_regaddr); + while (!(content & IMR_CPWM) && (count < 500)) { + udelay(50); + count++; + content = rtl_read_dword(rtlpriv, isr_regaddr); + } + + if (content & IMR_CPWM) { + rtl_write_word(rtlpriv, isr_regaddr, 0x0100); + rtlhal->fw_ps_state = FW_PS_STATE_RF_ON_8822B; + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "Receive CPWM INT!!! PSState = %X\n", + rtlhal->fw_ps_state); + } + } + + spin_lock_bh(&rtlpriv->locks.fw_ps_lock); + rtlhal->fw_clk_change_in_progress = false; + spin_unlock_bh(&rtlpriv->locks.fw_ps_lock); + if (b_schedule_timer) { + mod_timer(&rtlpriv->works.fw_clockoff_timer, + jiffies + MSECS(10)); + } + + } else { + spin_lock_bh(&rtlpriv->locks.fw_ps_lock); + rtlhal->fw_clk_change_in_progress = false; + spin_unlock_bh(&rtlpriv->locks.fw_ps_lock); + } +} + +static void _rtl8822be_set_fw_clock_off(struct ieee80211_hw *hw, u8 rpwm_val) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl8192_tx_ring *ring; + enum rf_pwrstate rtstate; + bool b_schedule_timer = false; + u8 queue; + + if (!rtlhal->fw_ready) + return; + if (!rtlpriv->psc.fw_current_inpsmode) + return; + if (!rtlhal->allow_sw_to_change_hwclc) + return; + + rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RF_STATE, (u8 *)(&rtstate)); + if (rtstate == ERFOFF || rtlpriv->psc.inactive_pwrstate == ERFOFF) + return; + + for (queue = 0; queue < RTL_PCI_MAX_TX_QUEUE_COUNT; queue++) { + ring = &rtlpci->tx_ring[queue]; + if (skb_queue_len(&ring->queue)) { + b_schedule_timer = true; + break; + } + } + + if (b_schedule_timer) { + mod_timer(&rtlpriv->works.fw_clockoff_timer, + jiffies + MSECS(10)); + return; + } + + if (FW_PS_STATE(rtlhal->fw_ps_state) != FW_PS_STATE_RF_OFF_LOW_PWR) { + spin_lock_bh(&rtlpriv->locks.fw_ps_lock); + if (!rtlhal->fw_clk_change_in_progress) { + rtlhal->fw_clk_change_in_progress = true; + spin_unlock_bh(&rtlpriv->locks.fw_ps_lock); + rtlhal->fw_ps_state = FW_PS_STATE(rpwm_val); + rtl_write_word(rtlpriv, REG_HISR0_8822B, 0x0100); + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM, + (u8 *)(&rpwm_val)); + spin_lock_bh(&rtlpriv->locks.fw_ps_lock); + rtlhal->fw_clk_change_in_progress = false; + spin_unlock_bh(&rtlpriv->locks.fw_ps_lock); + } else { + spin_unlock_bh(&rtlpriv->locks.fw_ps_lock); + mod_timer(&rtlpriv->works.fw_clockoff_timer, + jiffies + MSECS(10)); + } + } +} + +static void _rtl8822be_set_fw_ps_rf_on(struct ieee80211_hw *hw) +{ + u8 rpwm_val = 0; + + rpwm_val |= (FW_PS_STATE_RF_OFF_8822B | FW_PS_ACK); + _rtl8822be_set_fw_clock_on(hw, rpwm_val, true); +} + +static void _rtl8822be_set_fw_ps_rf_off_low_power(struct ieee80211_hw *hw) +{ + u8 rpwm_val = 0; + + rpwm_val |= FW_PS_STATE_RF_OFF_LOW_PWR; + _rtl8822be_set_fw_clock_off(hw, rpwm_val); +} + +void rtl8822be_fw_clk_off_timer_callback(unsigned long data) +{ + struct ieee80211_hw *hw = (struct ieee80211_hw *)data; + + _rtl8822be_set_fw_ps_rf_off_low_power(hw); +} + +static void _rtl8822be_fwlps_leave(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + bool fw_current_inps = false; + u8 rpwm_val = 0, fw_pwrmode = FW_PS_ACTIVE_MODE; + + if (ppsc->low_power_enable) { + rpwm_val = (FW_PS_STATE_ALL_ON_8822B | FW_PS_ACK); /* RF on */ + _rtl8822be_set_fw_clock_on(hw, rpwm_val, false); + rtlhal->allow_sw_to_change_hwclc = false; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE, + (u8 *)(&fw_pwrmode)); + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS, + (u8 *)(&fw_current_inps)); + } else { + rpwm_val = FW_PS_STATE_ALL_ON_8822B; /* RF on */ + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM, + (u8 *)(&rpwm_val)); + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE, + (u8 *)(&fw_pwrmode)); + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS, + (u8 *)(&fw_current_inps)); + } +} + +static void _rtl8822be_fwlps_enter(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + bool fw_current_inps = true; + u8 rpwm_val; + + if (ppsc->low_power_enable) { + rpwm_val = FW_PS_STATE_RF_OFF_LOW_PWR; /* RF off */ + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS, + (u8 *)(&fw_current_inps)); + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE, + (u8 *)(&ppsc->fwctrl_psmode)); + rtlhal->allow_sw_to_change_hwclc = true; + _rtl8822be_set_fw_clock_off(hw, rpwm_val); + } else { + rpwm_val = FW_PS_STATE_RF_OFF_8822B; /* RF off */ + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS, + (u8 *)(&fw_current_inps)); + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE, + (u8 *)(&ppsc->fwctrl_psmode)); + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM, + (u8 *)(&rpwm_val)); + } +} + +void rtl8822be_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + + switch (variable) { + case HW_VAR_RCR: + *((u32 *)(val)) = rtlpci->receive_config; + break; + case HW_VAR_RF_STATE: + *((enum rf_pwrstate *)(val)) = ppsc->rfpwr_state; + break; + case HW_VAR_FWLPS_RF_ON: { + enum rf_pwrstate rf_state; + u32 val_rcr; + + rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RF_STATE, + (u8 *)(&rf_state)); + if (rf_state == ERFOFF) { + *((bool *)(val)) = true; + } else { + val_rcr = rtl_read_dword(rtlpriv, REG_RCR_8822B); + val_rcr &= 0x00070000; + if (val_rcr) + *((bool *)(val)) = false; + else + *((bool *)(val)) = true; + } + } break; + case HW_VAR_FW_PSMODE_STATUS: + *((bool *)(val)) = ppsc->fw_current_inpsmode; + break; + case HW_VAR_CORRECT_TSF: { + u64 tsf; + u32 *ptsf_low = (u32 *)&tsf; + u32 *ptsf_high = ((u32 *)&tsf) + 1; + + *ptsf_high = rtl_read_dword(rtlpriv, (REG_TSFTR_8822B + 4)); + *ptsf_low = rtl_read_dword(rtlpriv, REG_TSFTR_8822B); + + *((u64 *)(val)) = tsf; + + } break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_DMESG, + "switch case not process %x\n", variable); + break; + } +} + +static void _rtl8822be_download_rsvd_page(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 tmp_regcr, tmp_reg422; + u8 bcnvalid_reg /*, txbc_reg*/; + u8 count = 0, dlbcn_count = 0; + bool b_recover = false; + + /*Set REG_CR_8822B bit 8. DMA beacon by SW.*/ + tmp_regcr = rtl_read_byte(rtlpriv, REG_CR_8822B + 1); + rtl_write_byte(rtlpriv, REG_CR_8822B + 1, tmp_regcr | BIT(0)); + + /* Disable Hw protection for a time which revserd for Hw sending beacon. + * Fix download reserved page packet fail + * that access collision with the protection time. + * 2010.05.11. Added by tynli. + */ + _rtl8822be_set_bcn_ctrl_reg(hw, 0, BIT(3)); + _rtl8822be_set_bcn_ctrl_reg(hw, BIT(4), 0); + + /* Set FWHW_TXQ_CTRL 0x422[6]=0 to + * tell Hw the packet is not a real beacon frame. + */ + tmp_reg422 = rtl_read_byte(rtlpriv, REG_FWHW_TXQ_CTRL_8822B + 2); + rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL_8822B + 2, + tmp_reg422 & (~BIT(6))); + + if (tmp_reg422 & BIT(6)) + b_recover = true; + + do { + /* Clear beacon valid check bit */ + bcnvalid_reg = + rtl_read_byte(rtlpriv, REG_FIFOPAGE_CTRL_2_8822B + 1); + bcnvalid_reg = bcnvalid_reg | BIT(7); + rtl_write_byte(rtlpriv, REG_FIFOPAGE_CTRL_2_8822B + 1, + bcnvalid_reg); + + /* download rsvd page */ + rtl8822be_set_fw_rsvdpagepkt(hw, false); + + /* check rsvd page download OK. */ + bcnvalid_reg = + rtl_read_byte(rtlpriv, REG_FIFOPAGE_CTRL_2_8822B + 1); + + count = 0; + while (!(BIT(7) & bcnvalid_reg) && count < 20) { + count++; + udelay(50); + bcnvalid_reg = rtl_read_byte( + rtlpriv, REG_FIFOPAGE_CTRL_2_8822B + 1); + } + + dlbcn_count++; + } while (!(BIT(7) & bcnvalid_reg) && dlbcn_count < 5); + + if (!(BIT(7) & bcnvalid_reg)) + RT_TRACE(rtlpriv, COMP_INIT, DBG_WARNING, + "Download RSVD page failed!\n"); + + /* Enable Bcn */ + _rtl8822be_set_bcn_ctrl_reg(hw, BIT(3), 0); + _rtl8822be_set_bcn_ctrl_reg(hw, 0, BIT(4)); + + if (b_recover) + rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL_8822B + 2, + tmp_reg422); +} + +void rtl8822be_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_efuse *efuse = rtl_efuse(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + + switch (variable) { + case HW_VAR_ETHER_ADDR: + rtlpriv->halmac.ops->halmac_set_mac_address(rtlpriv, 0, val); + break; + case HW_VAR_BASIC_RATE: { + u16 b_rate_cfg = ((u16 *)val)[0]; + + b_rate_cfg = b_rate_cfg & 0x15f; + b_rate_cfg |= 0x01; + b_rate_cfg = (b_rate_cfg | 0xd) & (~BIT(1)); + rtl_write_byte(rtlpriv, REG_RRSR_8822B, b_rate_cfg & 0xff); + rtl_write_byte(rtlpriv, REG_RRSR_8822B + 1, + (b_rate_cfg >> 8) & 0xff); + } break; + case HW_VAR_BSSID: + rtlpriv->halmac.ops->halmac_set_bssid(rtlpriv, 0, val); + break; + case HW_VAR_SIFS: + rtl_write_byte(rtlpriv, REG_SIFS_8822B + 1, val[0]); + rtl_write_byte(rtlpriv, REG_SIFS_TRX_8822B + 1, val[1]); + + rtl_write_byte(rtlpriv, REG_SPEC_SIFS_8822B + 1, val[0]); + rtl_write_byte(rtlpriv, REG_MAC_SPEC_SIFS_8822B + 1, val[0]); + + if (!mac->ht_enable) + rtl_write_word(rtlpriv, REG_RESP_SIFS_OFDM_8822B, + 0x0e0e); + else + rtl_write_word(rtlpriv, REG_RESP_SIFS_OFDM_8822B, + *((u16 *)val)); + break; + case HW_VAR_SLOT_TIME: { + u8 e_aci; + + RT_TRACE(rtlpriv, COMP_MLME, DBG_TRACE, "HW_VAR_SLOT_TIME %x\n", + val[0]); + + rtl_write_byte(rtlpriv, REG_SLOT_8822B, val[0]); + + for (e_aci = 0; e_aci < AC_MAX; e_aci++) { + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AC_PARAM, + (u8 *)(&e_aci)); + } + } break; + case HW_VAR_ACK_PREAMBLE: { + u8 reg_tmp; + u8 short_preamble = (bool)(*(u8 *)val); + + reg_tmp = (rtlpriv->mac80211.cur_40_prime_sc) << 5; + if (short_preamble) + reg_tmp |= 0x80; + rtl_write_byte(rtlpriv, REG_RRSR_8822B + 2, reg_tmp); + rtlpriv->mac80211.short_preamble = short_preamble; + } break; + case HW_VAR_WPA_CONFIG: + rtl_write_byte(rtlpriv, REG_SECCFG_8822B, *((u8 *)val)); + break; + case HW_VAR_AMPDU_FACTOR: { + u32 ampdu_len = (*((u8 *)val)); + + ampdu_len = (0x2000 << ampdu_len) - 1; + rtl_write_dword(rtlpriv, REG_AMPDU_MAX_LENGTH_8822B, ampdu_len); + } break; + case HW_VAR_AC_PARAM: { + u8 e_aci = *((u8 *)val); + + if (mac->vif && mac->vif->bss_conf.assoc && !mac->act_scanning) + rtl8822be_set_qos(hw, e_aci); + + if (rtlpci->acm_method != EACMWAY2_SW) + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ACM_CTRL, + (u8 *)(&e_aci)); + } break; + case HW_VAR_ACM_CTRL: { + u8 e_aci = *((u8 *)val); + union aci_aifsn *aifs = (union aci_aifsn *)&mac->ac[0].aifs; + + u8 acm = aifs->f.acm; + u8 acm_ctrl = rtl_read_byte(rtlpriv, REG_ACMHWCTRL_8822B); + + acm_ctrl = acm_ctrl | ((rtlpci->acm_method == 2) ? 0x0 : 0x1); + + if (acm) { + switch (e_aci) { + case AC0_BE: + acm_ctrl |= ACMHW_BEQ_EN; + break; + case AC2_VI: + acm_ctrl |= ACMHW_VIQ_EN; + break; + case AC3_VO: + acm_ctrl |= ACMHW_VOQ_EN; + break; + default: + RT_TRACE( + rtlpriv, COMP_ERR, DBG_WARNING, + "HW_VAR_ACM_CTRL acm set failed: eACI is %d\n", + acm); + break; + } + } else { + switch (e_aci) { + case AC0_BE: + acm_ctrl &= (~ACMHW_BEQ_EN); + break; + case AC2_VI: + acm_ctrl &= (~ACMHW_VIQ_EN); + break; + case AC3_VO: + acm_ctrl &= (~ACMHW_VOQ_EN); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_DMESG, + "switch case not process\n"); + break; + } + } + + RT_TRACE(rtlpriv, COMP_QOS, DBG_TRACE, + "SetHwReg8190pci(): [HW_VAR_ACM_CTRL] Write 0x%X\n", + acm_ctrl); + rtl_write_byte(rtlpriv, REG_ACMHWCTRL_8822B, acm_ctrl); + } break; + case HW_VAR_RCR: { + rtl_write_dword(rtlpriv, REG_RCR_8822B, ((u32 *)(val))[0]); + rtlpci->receive_config = ((u32 *)(val))[0]; + } break; + case HW_VAR_RETRY_LIMIT: { + u8 retry_limit = ((u8 *)(val))[0]; + + rtl_write_word(rtlpriv, REG_RETRY_LIMIT_8822B, + retry_limit << RETRY_LIMIT_SHORT_SHIFT | + retry_limit << RETRY_LIMIT_LONG_SHIFT); + } break; + case HW_VAR_DUAL_TSF_RST: + rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST_8822B, + (BIT(0) | BIT(1))); + break; + case HW_VAR_EFUSE_BYTES: + efuse->efuse_usedbytes = *((u16 *)val); + break; + case HW_VAR_EFUSE_USAGE: + efuse->efuse_usedpercentage = *((u8 *)val); + break; + case HW_VAR_IO_CMD: + rtl8822be_phy_set_io_cmd(hw, (*(enum io_type *)val)); + break; + case HW_VAR_SET_RPWM: + break; + case HW_VAR_H2C_FW_PWRMODE: + rtl8822be_set_fw_pwrmode_cmd(hw, (*(u8 *)val)); + break; + case HW_VAR_FW_PSMODE_STATUS: + ppsc->fw_current_inpsmode = *((bool *)val); + break; + case HW_VAR_RESUME_CLK_ON: + _rtl8822be_set_fw_ps_rf_on(hw); + break; + case HW_VAR_FW_LPS_ACTION: { + bool b_enter_fwlps = *((bool *)val); + + if (b_enter_fwlps) + _rtl8822be_fwlps_enter(hw); + else + _rtl8822be_fwlps_leave(hw); + } break; + case HW_VAR_H2C_FW_JOINBSSRPT: { + u8 mstatus = (*(u8 *)val); + + if (mstatus == RT_MEDIA_CONNECT) { + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AID, NULL); + _rtl8822be_download_rsvd_page(hw); + } + rtl8822be_set_default_port_id_cmd(hw); + rtl8822be_set_fw_media_status_rpt_cmd(hw, mstatus); + } break; + case HW_VAR_H2C_FW_P2P_PS_OFFLOAD: + rtl8822be_set_p2p_ps_offload_cmd(hw, (*(u8 *)val)); + break; + case HW_VAR_AID: { + u16 u2btmp; + + u2btmp = rtl_read_word(rtlpriv, REG_BCN_PSR_RPT_8822B); + u2btmp &= 0xC000; + rtl_write_word(rtlpriv, REG_BCN_PSR_RPT_8822B, + (u2btmp | mac->assoc_id)); + } break; + case HW_VAR_CORRECT_TSF: { + u8 btype_ibss = ((u8 *)(val))[0]; + + if (btype_ibss) + _rtl8822be_stop_tx_beacon(hw); + + _rtl8822be_set_bcn_ctrl_reg(hw, 0, BIT(3)); + + rtl_write_dword(rtlpriv, REG_TSFTR_8822B, + (u32)(mac->tsf & 0xffffffff)); + rtl_write_dword(rtlpriv, REG_TSFTR_8822B + 4, + (u32)((mac->tsf >> 32) & 0xffffffff)); + + _rtl8822be_set_bcn_ctrl_reg(hw, BIT(3), 0); + + if (btype_ibss) + _rtl8822be_resume_tx_beacon(hw); + } break; + case HW_VAR_KEEP_ALIVE: { + u8 array[2]; + + array[0] = 0xff; + array[1] = *((u8 *)val); + rtl8822be_fill_h2c_cmd(hw, H2C_8822B_KEEP_ALIVE_CTRL, 2, array); + } break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_DMESG, + "switch case not process %x\n", variable); + break; + } +} + +static void _rtl8822be_gen_refresh_led_state(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_led *led0 = &pcipriv->ledctl.sw_led0; + + if (rtlpriv->rtlhal.up_first_time) + return; + + if (ppsc->rfoff_reason == RF_CHANGE_BY_IPS) + rtl8822be_sw_led_on(hw, led0); + else if (ppsc->rfoff_reason == RF_CHANGE_BY_INIT) + rtl8822be_sw_led_on(hw, led0); + else + rtl8822be_sw_led_off(hw, led0); +} + +static bool _rtl8822be_init_trxbd(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + /*struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));*/ + + u8 bytetmp; + /*u16 wordtmp;*/ + u32 dwordtmp; + + /* Set TX/RX descriptor physical address -- HI part */ + if (!rtlpriv->cfg->mod_params->dma64) + goto dma64_end; + + rtl_write_dword(rtlpriv, REG_H2CQ_TXBD_DESA_8822B + 4, + ((u64)rtlpci->tx_ring[H2C_QUEUE].buffer_desc_dma) >> + 32); + rtl_write_dword(rtlpriv, REG_BCNQ_TXBD_DESA_8822B + 4, + ((u64)rtlpci->tx_ring[BEACON_QUEUE].buffer_desc_dma) >> + 32); + rtl_write_dword(rtlpriv, REG_MGQ_TXBD_DESA_8822B + 4, + (u64)rtlpci->tx_ring[MGNT_QUEUE].buffer_desc_dma >> 32); + rtl_write_dword(rtlpriv, REG_VOQ_TXBD_DESA_8822B + 4, + (u64)rtlpci->tx_ring[VO_QUEUE].buffer_desc_dma >> 32); + rtl_write_dword(rtlpriv, REG_VIQ_TXBD_DESA_8822B + 4, + (u64)rtlpci->tx_ring[VI_QUEUE].buffer_desc_dma >> 32); + rtl_write_dword(rtlpriv, REG_BEQ_TXBD_DESA_8822B + 4, + (u64)rtlpci->tx_ring[BE_QUEUE].buffer_desc_dma >> 32); + rtl_write_dword(rtlpriv, REG_BKQ_TXBD_DESA_8822B + 4, + (u64)rtlpci->tx_ring[BK_QUEUE].buffer_desc_dma >> 32); + rtl_write_dword(rtlpriv, REG_HI0Q_TXBD_DESA_8822B + 4, + (u64)rtlpci->tx_ring[HIGH_QUEUE].buffer_desc_dma >> 32); + + rtl_write_dword(rtlpriv, REG_RXQ_RXBD_DESA_8822B + 4, + (u64)rtlpci->rx_ring[RX_MPDU_QUEUE].dma >> 32); + +dma64_end: + /* Set TX/RX descriptor physical address(from OS API). */ + rtl_write_dword(rtlpriv, REG_H2CQ_TXBD_DESA_8822B, + ((u64)rtlpci->tx_ring[H2C_QUEUE].buffer_desc_dma) & + DMA_BIT_MASK(32)); + rtl_write_dword(rtlpriv, REG_BCNQ_TXBD_DESA_8822B, + ((u64)rtlpci->tx_ring[BEACON_QUEUE].buffer_desc_dma) & + DMA_BIT_MASK(32)); + rtl_write_dword(rtlpriv, REG_MGQ_TXBD_DESA_8822B, + (u64)rtlpci->tx_ring[MGNT_QUEUE].buffer_desc_dma & + DMA_BIT_MASK(32)); + rtl_write_dword(rtlpriv, REG_VOQ_TXBD_DESA_8822B, + (u64)rtlpci->tx_ring[VO_QUEUE].buffer_desc_dma & + DMA_BIT_MASK(32)); + rtl_write_dword(rtlpriv, REG_VIQ_TXBD_DESA_8822B, + (u64)rtlpci->tx_ring[VI_QUEUE].buffer_desc_dma & + DMA_BIT_MASK(32)); + rtl_write_dword(rtlpriv, REG_BEQ_TXBD_DESA_8822B, + (u64)rtlpci->tx_ring[BE_QUEUE].buffer_desc_dma & + DMA_BIT_MASK(32)); + dwordtmp = rtl_read_dword(rtlpriv, REG_BEQ_TXBD_DESA_8822B); /* need? */ + rtl_write_dword(rtlpriv, REG_BKQ_TXBD_DESA_8822B, + (u64)rtlpci->tx_ring[BK_QUEUE].buffer_desc_dma & + DMA_BIT_MASK(32)); + rtl_write_dword(rtlpriv, REG_HI0Q_TXBD_DESA_8822B, + (u64)rtlpci->tx_ring[HIGH_QUEUE].buffer_desc_dma & + DMA_BIT_MASK(32)); + + rtl_write_dword(rtlpriv, REG_RXQ_RXBD_DESA_8822B, + (u64)rtlpci->rx_ring[RX_MPDU_QUEUE].dma & + DMA_BIT_MASK(32)); + + /* Reset R/W point */ + rtl_write_dword(rtlpriv, REG_BD_RWPTR_CLR_8822B, 0x3fffffff); + + /* Reset the H2CQ R/W point index to 0 */ + dwordtmp = rtl_read_dword(rtlpriv, REG_H2CQ_CSR_8822B); + rtl_write_dword(rtlpriv, REG_H2CQ_CSR_8822B, + (dwordtmp | BIT(8) | BIT(16))); + + bytetmp = rtl_read_byte(rtlpriv, REG_PCIE_CTRL_8822B + 3); + rtl_write_byte(rtlpriv, REG_PCIE_CTRL_8822B + 3, bytetmp | 0xF7); + + rtl_write_dword(rtlpriv, REG_INT_MIG_8822B, 0); + + rtl_write_dword(rtlpriv, REG_MCUTST_I_8822B, 0x0); + + rtl_write_word(rtlpriv, REG_H2CQ_TXBD_NUM_8822B, + TX_DESC_NUM_8822B | + ((RTL8822BE_SEG_NUM << 12) & 0x3000)); + rtl_write_word(rtlpriv, REG_MGQ_TXBD_NUM_8822B, + TX_DESC_NUM_8822B | + ((RTL8822BE_SEG_NUM << 12) & 0x3000)); + rtl_write_word(rtlpriv, REG_VOQ_TXBD_NUM_8822B, + TX_DESC_NUM_8822B | + ((RTL8822BE_SEG_NUM << 12) & 0x3000)); + rtl_write_word(rtlpriv, REG_VIQ_TXBD_NUM_8822B, + TX_DESC_NUM_8822B | + ((RTL8822BE_SEG_NUM << 12) & 0x3000)); + rtl_write_word(rtlpriv, REG_BEQ_TXBD_NUM_8822B, + TX_DESC_NUM_8822B | + ((RTL8822BE_SEG_NUM << 12) & 0x3000)); + rtl_write_word(rtlpriv, REG_VOQ_TXBD_NUM_8822B, + TX_DESC_NUM_8822B | + ((RTL8822BE_SEG_NUM << 12) & 0x3000)); + rtl_write_word(rtlpriv, REG_BKQ_TXBD_NUM_8822B, + TX_DESC_NUM_8822B | + ((RTL8822BE_SEG_NUM << 12) & 0x3000)); + rtl_write_word(rtlpriv, REG_HI0Q_TXBD_NUM_8822B, + TX_DESC_NUM_8822B | + ((RTL8822BE_SEG_NUM << 12) & 0x3000)); + rtl_write_word(rtlpriv, REG_HI1Q_TXBD_NUM_8822B, + TX_DESC_NUM_8822B | + ((RTL8822BE_SEG_NUM << 12) & 0x3000)); + rtl_write_word(rtlpriv, REG_HI2Q_TXBD_NUM_8822B, + TX_DESC_NUM_8822B | + ((RTL8822BE_SEG_NUM << 12) & 0x3000)); + rtl_write_word(rtlpriv, REG_HI3Q_TXBD_NUM_8822B, + TX_DESC_NUM_8822B | + ((RTL8822BE_SEG_NUM << 12) & 0x3000)); + rtl_write_word(rtlpriv, REG_HI4Q_TXBD_NUM_8822B, + TX_DESC_NUM_8822B | + ((RTL8822BE_SEG_NUM << 12) & 0x3000)); + rtl_write_word(rtlpriv, REG_HI5Q_TXBD_NUM_8822B, + TX_DESC_NUM_8822B | + ((RTL8822BE_SEG_NUM << 12) & 0x3000)); + rtl_write_word(rtlpriv, REG_HI6Q_TXBD_NUM_8822B, + TX_DESC_NUM_8822B | + ((RTL8822BE_SEG_NUM << 12) & 0x3000)); + rtl_write_word(rtlpriv, REG_HI7Q_TXBD_NUM_8822B, + TX_DESC_NUM_8822B | + ((RTL8822BE_SEG_NUM << 12) & 0x3000)); + /*Rx*/ + rtl_write_word(rtlpriv, REG_RX_RXBD_NUM_8822B, + RX_DESC_NUM_8822BE | + ((RTL8822BE_SEG_NUM << 13) & 0x6000) | 0x8000); + + rtl_write_dword(rtlpriv, REG_BD_RWPTR_CLR_8822B, 0XFFFFFFFF); + + _rtl8822be_gen_refresh_led_state(hw); + + return true; +} + +static void _rtl8822be_enable_aspm_back_door(struct ieee80211_hw *hw) +{ + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + u8 tmp; + + if (!ppsc->support_backdoor) + return; + + pci_read_config_byte(rtlpci->pdev, 0x70f, &tmp); + pci_write_config_byte(rtlpci->pdev, 0x70f, tmp | BIT(7)); + + pci_read_config_byte(rtlpci->pdev, 0x719, &tmp); + pci_write_config_byte(rtlpci->pdev, 0x719, tmp | BIT(3) | BIT(4)); +} + +void rtl8822be_enable_hw_security_config(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 sec_reg_value; + u8 tmp; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "PairwiseEncAlgorithm = %d GroupEncAlgorithm = %d\n", + rtlpriv->sec.pairwise_enc_algorithm, + rtlpriv->sec.group_enc_algorithm); + + if (rtlpriv->cfg->mod_params->sw_crypto || rtlpriv->sec.use_sw_sec) { + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + "not open hw encryption\n"); + return; + } + + sec_reg_value = SCR_TX_ENC_ENABLE | SRC_RX_DEC_ENABLE; + + if (rtlpriv->sec.use_defaultkey) { + sec_reg_value |= SCR_TX_USE_DK; + sec_reg_value |= SCR_RX_USE_DK; + } + + sec_reg_value |= (SCR_RXBCUSEDK | SCR_TXBCUSEDK); + + tmp = rtl_read_byte(rtlpriv, REG_CR_8822B + 1); + rtl_write_byte(rtlpriv, REG_CR_8822B + 1, tmp | BIT(1)); + + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "The SECR-value %x\n", + sec_reg_value); + + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_WPA_CONFIG, &sec_reg_value); +} + +static bool _rtl8822be_check_pcie_dma_hang(struct rtl_priv *rtlpriv) +{ + u8 tmp; + + /* write reg 0x350 Bit[26]=1. Enable debug port. */ + tmp = rtl_read_byte(rtlpriv, REG_DBI_FLAG_V1_8822B + 3); + if (!(tmp & BIT(2))) { + rtl_write_byte(rtlpriv, REG_DBI_FLAG_V1_8822B + 3, + (tmp | BIT(2))); + mdelay(100); /* Suggested by DD Justin_tsai. */ + } + + /* read reg 0x350 Bit[25] if 1 : RX hang + * read reg 0x350 Bit[24] if 1 : TX hang + */ + tmp = rtl_read_byte(rtlpriv, REG_DBI_FLAG_V1_8822B + 3); + if ((tmp & BIT(0)) || (tmp & BIT(1))) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "CheckPcieDMAHang8822BE(): true!!\n"); + return true; + } else { + return false; + } +} + +static void _rtl8822be_reset_pcie_interface_dma(struct rtl_priv *rtlpriv, + bool mac_power_on) +{ + u8 tmp; + bool release_mac_rx_pause; + u8 backup_pcie_dma_pause; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "ResetPcieInterfaceDMA8822BE()\n"); + + /* Revise Note: Follow the document "PCIe RX DMA Hang Reset Flow_v03" + * released by SD1 Alan. + * 2013.05.07, by tynli. + */ + + /* 1. disable register write lock + * write 0x1C bit[1:0] = 2'h0 + * write 0xCC bit[2] = 1'b1 + */ + tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL_8822B); + tmp &= ~(BIT(1) | BIT(0)); + rtl_write_byte(rtlpriv, REG_RSV_CTRL_8822B, tmp); + tmp = rtl_read_byte(rtlpriv, REG_PMC_DBG_CTRL2_8822B); + tmp |= BIT(2); + rtl_write_byte(rtlpriv, REG_PMC_DBG_CTRL2_8822B, tmp); + + /* 2. Check and pause TRX DMA + * write 0x284 bit[18] = 1'b1 + * write 0x301 = 0xFF + */ + tmp = rtl_read_byte(rtlpriv, REG_RXDMA_CONTROL_8822B); + if (tmp & BIT(2)) { + /* Already pause before the function for another purpose. */ + release_mac_rx_pause = false; + } else { + rtl_write_byte(rtlpriv, REG_RXDMA_CONTROL_8822B, + (tmp | BIT(2))); + release_mac_rx_pause = true; + } + + backup_pcie_dma_pause = rtl_read_byte(rtlpriv, REG_PCIE_CTRL_8822B + 1); + if (backup_pcie_dma_pause != 0xFF) + rtl_write_byte(rtlpriv, REG_PCIE_CTRL_8822B + 1, 0xFF); + + if (mac_power_on) { + /* 3. reset TRX function + * write 0x100 = 0x00 + */ + rtl_write_byte(rtlpriv, REG_CR_8822B, 0); + } + + /* 4. Reset PCIe DMA + * write 0x003 bit[0] = 0 + */ + tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN_8822B + 1); + tmp &= ~(BIT(0)); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN_8822B + 1, tmp); + + /* 5. Enable PCIe DMA + * write 0x003 bit[0] = 1 + */ + tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN_8822B + 1); + tmp |= BIT(0); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN_8822B + 1, tmp); + + if (mac_power_on) { + /* 6. enable TRX function + * write 0x100 = 0xFF + */ + rtl_write_byte(rtlpriv, REG_CR_8822B, 0xFF); + + /* We should init LLT & RQPN and + * prepare Tx/Rx descrptor address later + * because MAC function is reset. + */ + } + + /* 7. Restore PCIe autoload down bit + * write 0xF8 bit[17] = 1'b1 + */ + tmp = rtl_read_byte(rtlpriv, REG_SYS_STATUS2_8822B + 2); + tmp |= BIT(1); + rtl_write_byte(rtlpriv, REG_SYS_STATUS2_8822B + 2, tmp); + + /* In MAC power on state, BB and RF maybe in ON state, + * if we release TRx DMA here + * it will cause packets to be started to Tx/Rx, + * so we release Tx/Rx DMA later. + */ + if (!mac_power_on) { + /* 8. release TRX DMA + * write 0x284 bit[18] = 1'b0 + * write 0x301 = 0x00 + */ + if (release_mac_rx_pause) { + tmp = rtl_read_byte(rtlpriv, REG_RXDMA_CONTROL_8822B); + rtl_write_byte(rtlpriv, REG_RXDMA_CONTROL_8822B, + (tmp & (~BIT(2)))); + } + rtl_write_byte(rtlpriv, REG_PCIE_CTRL_8822B + 1, + backup_pcie_dma_pause); + } + + /* 9. lock system register + * write 0xCC bit[2] = 1'b0 + */ + tmp = rtl_read_byte(rtlpriv, REG_PMC_DBG_CTRL2_8822B); + tmp &= ~(BIT(2)); + rtl_write_byte(rtlpriv, REG_PMC_DBG_CTRL2_8822B, tmp); +} + +int rtl8822be_hw_init(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_phy *rtlphy = &rtlpriv->phy; + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + int err = 0; + u8 tmp_u1b; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, " Rtl8822BE hw init\n"); + rtlpriv->rtlhal.being_init_adapter = true; + rtlpriv->intf_ops->disable_aspm(hw); + + if (_rtl8822be_check_pcie_dma_hang(rtlpriv)) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "8822be dma hang!\n"); + _rtl8822be_reset_pcie_interface_dma(rtlpriv, + rtlhal->mac_func_enable); + rtlhal->mac_func_enable = false; + } + + /* init TRX BD */ + _rtl8822be_init_trxbd(hw); + + /* use halmac to init */ + err = rtlpriv->halmac.ops->halmac_init_hal(rtlpriv); + if (err) { + pr_err("halmac_init_hal failed\n"); + rtlhal->fw_ready = false; + return err; + } + + rtlhal->fw_ready = true; + + /* have to init after halmac init */ + tmp_u1b = rtl_read_byte(rtlpriv, REG_PCIE_CTRL_8822B + 2); + rtl_write_byte(rtlpriv, REG_PCIE_CTRL_8822B + 2, (tmp_u1b | BIT(4))); + + /*rtl_write_word(rtlpriv, REG_PCIE_CTRL_8822B, 0x8000);*/ + rtlhal->rx_tag = 0; + + rtl_write_byte(rtlpriv, REG_RX_DRVINFO_SZ_8822B, 0x4); + + /*fw related variable initialize */ + ppsc->fw_current_inpsmode = false; + rtlhal->fw_ps_state = FW_PS_STATE_ALL_ON_8822B; + rtlhal->fw_clk_change_in_progress = false; + rtlhal->allow_sw_to_change_hwclc = false; + rtlhal->last_hmeboxnum = 0; + + rtlphy->rfreg_chnlval[0] = + rtl_get_rfreg(hw, RF90_PATH_A, RF_CHNLBW, RFREG_OFFSET_MASK); + rtlphy->rfreg_chnlval[1] = + rtl_get_rfreg(hw, RF90_PATH_B, RF_CHNLBW, RFREG_OFFSET_MASK); + rtlphy->backup_rf_0x1a = (u32)rtl_get_rfreg(hw, RF90_PATH_A, RF_RX_G1, + RFREG_OFFSET_MASK); + rtlphy->rfreg_chnlval[0] = + (rtlphy->rfreg_chnlval[0] & 0xfffff3ff) | BIT(10) | BIT(11); + + rtlhal->mac_func_enable = true; + + if (rtlpriv->cfg->ops->get_btc_status()) + rtlpriv->btcoexist.btc_ops->btc_power_on_setting(rtlpriv); + + /* reset cam / set security */ + rtl_cam_reset_all_entry(hw); + rtl8822be_enable_hw_security_config(hw); + + /* check RCR/ICV bit */ + rtlpci->receive_config &= ~(RCR_ACRC32 | RCR_AICV); + rtl_write_dword(rtlpriv, REG_RCR_8822B, rtlpci->receive_config); + + /* clear rx ctrl frame */ + rtl_write_word(rtlpriv, REG_RXFLTMAP1_8822B, 0); + + ppsc->rfpwr_state = ERFON; + + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ETHER_ADDR, mac->mac_addr); + _rtl8822be_enable_aspm_back_door(hw); + rtlpriv->intf_ops->enable_aspm(hw); + + if (rtlpriv->cfg->ops->get_btc_status()) + rtlpriv->btcoexist.btc_ops->btc_init_hw_config(rtlpriv); + else + rtlpriv->btcoexist.btc_ops->btc_init_hw_config_wifi_only( + rtlpriv); + + rtlpriv->rtlhal.being_init_adapter = false; + + rtlpriv->phydm.ops->phydm_init_dm(rtlpriv); + + /* clear ISR, and IMR will be on later */ + rtl_write_dword(rtlpriv, REG_HISR0_8822B, + rtl_read_dword(rtlpriv, REG_HISR0_8822B)); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "end of Rtl8822BE hw init %x\n", + err); + return 0; +} + +static u32 _rtl8822be_read_chip_version(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &rtlpriv->phy; + /*enum version_8822b version = VERSION_UNKNOWN;*/ + u32 version; + u32 value32; + + rtlphy->rf_type = RF_2T2R; + + value32 = rtl_read_dword(rtlpriv, REG_SYS_CFG1_8822B); + + version = value32; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Chip RF Type: %s\n", + (rtlphy->rf_type == RF_2T2R) ? "RF_2T2R" : "RF_1T1R"); + + return version; +} + +static int _rtl8822be_set_media_status(struct ieee80211_hw *hw, + enum nl80211_iftype type) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 bt_msr = rtl_read_byte(rtlpriv, MSR); + enum led_ctl_mode ledaction = LED_CTL_NO_LINK; + u8 mode = MSR_NOLINK; + + bt_msr &= 0xfc; + + switch (type) { + case NL80211_IFTYPE_UNSPECIFIED: + mode = MSR_NOLINK; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "Set Network type to NO LINK!\n"); + break; + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_MESH_POINT: + mode = MSR_ADHOC; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "Set Network type to Ad Hoc!\n"); + break; + case NL80211_IFTYPE_STATION: + mode = MSR_INFRA; + ledaction = LED_CTL_LINK; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "Set Network type to STA!\n"); + break; + case NL80211_IFTYPE_AP: + mode = MSR_AP; + ledaction = LED_CTL_LINK; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "Set Network type to AP!\n"); + break; + default: + pr_err("Network type %d not support!\n", type); + return 1; + } + + /* MSR_INFRA == Link in infrastructure network; + * MSR_ADHOC == Link in ad hoc network; + * Therefore, check link state is necessary. + * + * MSR_AP == AP mode; link state is not cared here. + */ + if (mode != MSR_AP && rtlpriv->mac80211.link_state < MAC80211_LINKED) { + mode = MSR_NOLINK; + ledaction = LED_CTL_NO_LINK; + } + + if (mode == MSR_NOLINK || mode == MSR_INFRA) { + _rtl8822be_stop_tx_beacon(hw); + _rtl8822be_enable_bcn_sub_func(hw); + } else if (mode == MSR_ADHOC || mode == MSR_AP) { + _rtl8822be_resume_tx_beacon(hw); + _rtl8822be_disable_bcn_sub_func(hw); + } else { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "Set HW_VAR_MEDIA_STATUS: No such media status(%x).\n", + mode); + } + + rtl_write_byte(rtlpriv, (MSR), bt_msr | mode); + rtlpriv->cfg->ops->led_control(hw, ledaction); + if (mode == MSR_AP) + rtl_write_byte(rtlpriv, REG_BCNTCFG_8822B + 1, 0x00); + else + rtl_write_byte(rtlpriv, REG_BCNTCFG_8822B + 1, 0x66); + return 0; +} + +void rtl8822be_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + u32 reg_rcr = rtlpci->receive_config; + + if (rtlpriv->psc.rfpwr_state != ERFON) + return; + + if (check_bssid) { + reg_rcr |= (RCR_CBSSID_DATA | RCR_CBSSID_BCN); + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, (u8 *)(®_rcr)); + _rtl8822be_set_bcn_ctrl_reg(hw, 0, BIT(4)); + } else if (!check_bssid) { + reg_rcr &= (~(RCR_CBSSID_DATA | RCR_CBSSID_BCN)); + _rtl8822be_set_bcn_ctrl_reg(hw, BIT(4), 0); + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, (u8 *)(®_rcr)); + } +} + +int rtl8822be_set_network_type(struct ieee80211_hw *hw, + enum nl80211_iftype type) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (_rtl8822be_set_media_status(hw, type)) + return -EOPNOTSUPP; + + if (rtlpriv->mac80211.link_state == MAC80211_LINKED) { + if (type != NL80211_IFTYPE_AP && + type != NL80211_IFTYPE_MESH_POINT) + rtl8822be_set_check_bssid(hw, true); + } else { + rtl8822be_set_check_bssid(hw, false); + } + + return 0; +} + +void rtl8822be_set_qos(struct ieee80211_hw *hw, int aci) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtlpriv); + u32 ac_param; + + ac_param = rtl_get_hal_edca_param(hw, mac->vif, mac->mode, + &mac->edca_param[aci]); + + switch (aci) { + case AC1_BK: + rtl_write_dword(rtlpriv, REG_EDCA_BK_PARAM_8822B, ac_param); + break; + case AC0_BE: + rtl_write_dword(rtlpriv, REG_EDCA_BE_PARAM_8822B, ac_param); + break; + case AC2_VI: + rtl_write_dword(rtlpriv, REG_EDCA_VI_PARAM_8822B, ac_param); + break; + case AC3_VO: + rtl_write_dword(rtlpriv, REG_EDCA_VO_PARAM_8822B, ac_param); + break; + default: + WARN_ONCE(true, "invalid aci: %d !\n", aci); + break; + } +} + +void rtl8822be_enable_interrupt(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + + rtl_write_dword(rtlpriv, REG_HIMR0_8822B, + rtlpci->irq_mask[0] & 0xFFFFFFFF); + rtl_write_dword(rtlpriv, REG_HIMR1_8822B, + rtlpci->irq_mask[1] & 0xFFFFFFFF); + rtl_write_dword(rtlpriv, REG_HIMR3_8822B, + rtlpci->irq_mask[3] & 0xFFFFFFFF); + rtlpci->irq_enabled = true; +} + +void rtl8822be_disable_interrupt(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + + rtl_write_dword(rtlpriv, REG_HIMR0_8822B, IMR_DISABLED); + rtl_write_dword(rtlpriv, REG_HIMR1_8822B, IMR_DISABLED); + rtl_write_dword(rtlpriv, REG_HIMR3_8822B, IMR_DISABLED); + rtlpci->irq_enabled = false; + /*synchronize_irq(rtlpci->pdev->irq);*/ +} + +void rtl8822be_card_disable(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + enum nl80211_iftype opmode; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "RTL8822be card disable\n"); + + RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); + + mac->link_state = MAC80211_NOLINK; + opmode = NL80211_IFTYPE_UNSPECIFIED; + + _rtl8822be_set_media_status(hw, opmode); + + if (rtlpriv->rtlhal.driver_is_goingto_unload || + ppsc->rfoff_reason > RF_CHANGE_BY_PS) + rtlpriv->cfg->ops->led_control(hw, LED_CTL_POWER_OFF); + + rtlpriv->phydm.ops->phydm_deinit_dm(rtlpriv); + + rtlpriv->halmac.ops->halmac_deinit_hal(rtlpriv); + + /* after power off we should do iqk again */ + if (!rtlpriv->cfg->ops->get_btc_status()) + rtlpriv->phy.iqk_initialized = false; +} + +void rtl8822be_interrupt_recognized(struct ieee80211_hw *hw, u32 *p_inta, + u32 *p_intb, u32 *p_intc, u32 *p_intd) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + + *p_inta = + rtl_read_dword(rtlpriv, REG_HISR0_8822B) & rtlpci->irq_mask[0]; + rtl_write_dword(rtlpriv, REG_HISR0_8822B, *p_inta); + + *p_intb = + rtl_read_dword(rtlpriv, REG_HISR1_8822B) & rtlpci->irq_mask[1]; + rtl_write_dword(rtlpriv, REG_HISR1_8822B, *p_intb); + + *p_intd = + rtl_read_dword(rtlpriv, REG_HISR3_8822B) & rtlpci->irq_mask[3]; + rtl_write_dword(rtlpriv, REG_HISR3_8822B, *p_intd); +} + +void rtl8822be_set_beacon_related_registers(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + u16 bcn_interval, atim_window; + + bcn_interval = mac->beacon_interval; + atim_window = 2; /*FIX MERGE */ + rtl8822be_disable_interrupt(hw); + rtl_write_word(rtlpriv, REG_ATIMWND_8822B, atim_window); + rtl_write_word(rtlpriv, REG_MBSSID_BCN_SPACE_8822B, bcn_interval); + rtl_write_word(rtlpriv, REG_BCNTCFG_8822B, 0x660f); + rtl_write_byte(rtlpriv, REG_RXTSF_OFFSET_CCK_8822B, 0x18); + rtl_write_byte(rtlpriv, REG_RXTSF_OFFSET_OFDM_8822B, 0x18); + rtl_write_byte(rtlpriv, 0x606, 0x30); + rtlpci->reg_bcn_ctrl_val |= BIT(3); + rtl_write_byte(rtlpriv, REG_BCN_CTRL_8822B, + (u8)rtlpci->reg_bcn_ctrl_val); +} + +void rtl8822be_set_beacon_interval(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + u16 bcn_interval = mac->beacon_interval; + + RT_TRACE(rtlpriv, COMP_BEACON, DBG_DMESG, "beacon_interval:%d\n", + bcn_interval); + rtl_write_word(rtlpriv, REG_MBSSID_BCN_SPACE_8822B, bcn_interval); +} + +void rtl8822be_update_interrupt_mask(struct ieee80211_hw *hw, u32 add_msr, + u32 rm_msr) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + + RT_TRACE(rtlpriv, COMP_INTR, DBG_LOUD, "add_msr:%x, rm_msr:%x\n", + add_msr, rm_msr); + + if (add_msr) + rtlpci->irq_mask[0] |= add_msr; + if (rm_msr) + rtlpci->irq_mask[0] &= (~rm_msr); + rtl8822be_disable_interrupt(hw); + rtl8822be_enable_interrupt(hw); +} + +static bool _rtl8822be_get_chnl_group(u8 chnl, u8 *group) +{ + bool in_24g; + + if (chnl <= 14) { + in_24g = true; + + if (chnl >= 1 && chnl <= 2) + *group = 0; + else if (chnl >= 3 && chnl <= 5) + *group = 1; + else if (chnl >= 6 && chnl <= 8) + *group = 2; + else if (chnl >= 9 && chnl <= 11) + *group = 3; + else if (chnl >= 12 && chnl <= 14) + *group = 4; + } else { + in_24g = false; + + if (chnl >= 36 && chnl <= 42) + *group = 0; + else if (chnl >= 44 && chnl <= 48) + *group = 1; + else if (chnl >= 50 && chnl <= 58) + *group = 2; + else if (chnl >= 60 && chnl <= 64) + *group = 3; + else if (chnl >= 100 && chnl <= 106) + *group = 4; + else if (chnl >= 108 && chnl <= 114) + *group = 5; + else if (chnl >= 116 && chnl <= 122) + *group = 6; + else if (chnl >= 124 && chnl <= 130) + *group = 7; + else if (chnl >= 132 && chnl <= 138) + *group = 8; + else if (chnl >= 140 && chnl <= 144) + *group = 9; + else if (chnl >= 149 && chnl <= 155) + *group = 10; + else if (chnl >= 157 && chnl <= 161) + *group = 11; + else if (chnl >= 165 && chnl <= 171) + *group = 12; + else if (chnl >= 173 && chnl <= 177) + *group = 13; + } + return in_24g; +} + +static inline bool power_valid(u8 power) +{ + if (power <= 63) + return true; + + return false; +} + +static inline s8 power_diff(s8 diff) +{ + /* bit sign number to 8 bit sign number */ + if (diff & BIT(3)) + diff |= 0xF0; + + return diff; +} + +static void _rtl8822be_read_power_value_fromprom(struct ieee80211_hw *hw, + struct txpower_info_2g *pwr2g, + struct txpower_info_5g *pwr5g, + bool autoload_fail, u8 *hwinfo) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 rf, addr = EEPROM_TX_PWR_INX_8822B, group, i = 0; + u8 power; + s8 diff; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "hal_ReadPowerValueFromPROM8822B(): PROMContent[0x%x]=0x%x\n", + (addr + 1), hwinfo[addr + 1]); + if (hwinfo[addr + 1] == 0xFF) /*YJ,add,120316*/ + autoload_fail = true; + + memset(pwr2g, 0, sizeof(struct txpower_info_2g)); + memset(pwr5g, 0, sizeof(struct txpower_info_5g)); + + if (autoload_fail) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "auto load fail : Use Default value!\n"); + for (rf = 0; rf < MAX_RF_PATH; rf++) { + /* 2.4G default value */ + for (group = 0; group < MAX_CHNL_GROUP_24G; group++) { + pwr2g->index_cck_base[rf][group] = 0x2D; + pwr2g->index_bw40_base[rf][group] = 0x2D; + } + for (i = 0; i < MAX_TX_COUNT; i++) { + if (i == 0) { + pwr2g->bw20_diff[rf][0] = 0x02; + pwr2g->ofdm_diff[rf][0] = 0x04; + } else { + pwr2g->bw20_diff[rf][i] = 0xFE; + pwr2g->bw40_diff[rf][i] = 0xFE; + pwr2g->cck_diff[rf][i] = 0xFE; + pwr2g->ofdm_diff[rf][i] = 0xFE; + } + } + + /*5G default value*/ + for (group = 0; group < MAX_CHNL_GROUP_5G; group++) + pwr5g->index_bw40_base[rf][group] = 0x2A; + + for (i = 0; i < MAX_TX_COUNT; i++) { + if (i == 0) { + pwr5g->ofdm_diff[rf][0] = 0x04; + pwr5g->bw20_diff[rf][0] = 0x00; + pwr5g->bw80_diff[rf][0] = 0xFE; + pwr5g->bw160_diff[rf][0] = 0xFE; + } else { + pwr5g->ofdm_diff[rf][i] = 0xFE; + pwr5g->bw20_diff[rf][i] = 0xFE; + pwr5g->bw40_diff[rf][i] = 0xFE; + pwr5g->bw80_diff[rf][i] = 0xFE; + pwr5g->bw160_diff[rf][i] = 0xFE; + } + } + } + return; + } + + rtl_priv(hw)->efuse.txpwr_fromeprom = true; + + for (rf = 0; rf < 2 /*MAX_RF_PATH*/; rf++) { + /*2.4G default value*/ + for (group = 0; group < MAX_CHNL_GROUP_24G; group++) { + power = hwinfo[addr++]; + if (power_valid(power)) + pwr2g->index_cck_base[rf][group] = power; + } + for (group = 0; group < MAX_CHNL_GROUP_24G - 1; group++) { + power = hwinfo[addr++]; + if (power_valid(power)) + pwr2g->index_bw40_base[rf][group] = power; + } + for (i = 0; i < MAX_TX_COUNT; i++) { + if (i == 0) { + pwr2g->bw40_diff[rf][i] = 0; + + diff = (hwinfo[addr] & 0xF0) >> 4; + pwr2g->bw20_diff[rf][i] = power_diff(diff); + + diff = hwinfo[addr] & 0x0F; + pwr2g->ofdm_diff[rf][i] = power_diff(diff); + + pwr2g->cck_diff[rf][i] = 0; + + addr++; + } else { + diff = (hwinfo[addr] & 0xF0) >> 4; + pwr2g->bw40_diff[rf][i] = power_diff(diff); + + diff = hwinfo[addr] & 0x0F; + pwr2g->bw20_diff[rf][i] = power_diff(diff); + + addr++; + + diff = (hwinfo[addr] & 0xF0) >> 4; + pwr2g->ofdm_diff[rf][i] = power_diff(diff); + + diff = hwinfo[addr] & 0x0F; + pwr2g->cck_diff[rf][i] = power_diff(diff); + + addr++; + } + } + + /*5G default value*/ + for (group = 0; group < MAX_CHNL_GROUP_5G; group++) { + power = hwinfo[addr++]; + if (power_valid(power)) + pwr5g->index_bw40_base[rf][group] = power; + } + + for (i = 0; i < MAX_TX_COUNT; i++) { + if (i == 0) { + pwr5g->bw40_diff[rf][i] = 0; + + diff = (hwinfo[addr] & 0xF0) >> 4; + pwr5g->bw20_diff[rf][i] = power_diff(diff); + + diff = hwinfo[addr] & 0x0F; + pwr5g->ofdm_diff[rf][i] = power_diff(diff); + + addr++; + } else { + diff = (hwinfo[addr] & 0xF0) >> 4; + pwr5g->bw40_diff[rf][i] = power_diff(diff); + + diff = hwinfo[addr] & 0x0F; + pwr5g->bw20_diff[rf][i] = power_diff(diff); + + addr++; + } + } + + diff = (hwinfo[addr] & 0xF0) >> 4; + pwr5g->ofdm_diff[rf][1] = power_diff(diff); + + diff = hwinfo[addr] & 0x0F; + pwr5g->ofdm_diff[rf][2] = power_diff(diff); + + addr++; + + diff = hwinfo[addr] & 0x0F; + pwr5g->ofdm_diff[rf][3] = power_diff(diff); + + addr++; + + for (i = 0; i < MAX_TX_COUNT; i++) { + diff = (hwinfo[addr] & 0xF0) >> 4; + pwr5g->bw80_diff[rf][i] = power_diff(diff); + + diff = hwinfo[addr] & 0x0F; + pwr5g->bw160_diff[rf][i] = power_diff(diff); + + addr++; + } + } +} + +static void _rtl8822be_read_txpower_info_from_hwpg(struct ieee80211_hw *hw, + bool autoload_fail, + u8 *hwinfo) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_efuse *efu = rtl_efuse(rtl_priv(hw)); + struct txpower_info_2g pwr2g; + struct txpower_info_5g pwr5g; + u8 channel5g[CHANNEL_MAX_NUMBER_5G] = { + 36, 38, 40, 42, 44, 46, 48, /* Band 1 */ + 52, 54, 56, 58, 60, 62, 64, /* Band 2 */ + 100, 102, 104, 106, 108, 110, 112, /* Band 3 */ + 116, 118, 120, 122, 124, 126, 128, /* Band 3 */ + 132, 134, 136, 138, 140, 142, 144, /* Band 3 */ + 149, 151, 153, 155, 157, 159, 161, /* Band 4 */ + 165, 167, 169, 171, 173, 175, 177}; /* Band 4 */ + u8 channel5g_80m[CHANNEL_MAX_NUMBER_5G_80M] = {42, 58, 106, 122, + 138, 155, 171}; + u8 rf, group; + u8 i; + + _rtl8822be_read_power_value_fromprom(hw, &pwr2g, &pwr5g, autoload_fail, + hwinfo); + + for (rf = 0; rf < MAX_RF_PATH; rf++) { + for (i = 0; i < CHANNEL_MAX_NUMBER_2G; i++) { + _rtl8822be_get_chnl_group(i + 1, &group); + + if (i == CHANNEL_MAX_NUMBER_2G - 1) { + efu->txpwrlevel_cck[rf][i] = + pwr2g.index_cck_base[rf][5]; + efu->txpwrlevel_ht40_1s[rf][i] = + pwr2g.index_bw40_base[rf][group]; + } else { + efu->txpwrlevel_cck[rf][i] = + pwr2g.index_cck_base[rf][group]; + efu->txpwrlevel_ht40_1s[rf][i] = + pwr2g.index_bw40_base[rf][group]; + } + } + for (i = 0; i < CHANNEL_MAX_NUMBER_5G; i++) { + _rtl8822be_get_chnl_group(channel5g[i], &group); + efu->txpwr_5g_bw40base[rf][i] = + pwr5g.index_bw40_base[rf][group]; + } + for (i = 0; i < CHANNEL_MAX_NUMBER_5G_80M; i++) { + u8 upper, lower; + + _rtl8822be_get_chnl_group(channel5g_80m[i], &group); + upper = pwr5g.index_bw40_base[rf][group]; + lower = pwr5g.index_bw40_base[rf][group + 1]; + + efu->txpwr_5g_bw80base[rf][i] = (upper + lower) / 2; + } + for (i = 0; i < MAX_TX_COUNT; i++) { + efu->txpwr_cckdiff[rf][i] = pwr2g.cck_diff[rf][i]; + efu->txpwr_legacyhtdiff[rf][i] = pwr2g.ofdm_diff[rf][i]; + efu->txpwr_ht20diff[rf][i] = pwr2g.bw20_diff[rf][i]; + efu->txpwr_ht40diff[rf][i] = pwr2g.bw40_diff[rf][i]; + + efu->txpwr_5g_ofdmdiff[rf][i] = pwr5g.ofdm_diff[rf][i]; + efu->txpwr_5g_bw20diff[rf][i] = pwr5g.bw20_diff[rf][i]; + efu->txpwr_5g_bw40diff[rf][i] = pwr5g.bw40_diff[rf][i]; + efu->txpwr_5g_bw80diff[rf][i] = pwr5g.bw80_diff[rf][i]; + } + } + + if (!autoload_fail) + efu->eeprom_thermalmeter = hwinfo[EEPROM_THERMAL_METER_8822B]; + else + efu->eeprom_thermalmeter = EEPROM_DEFAULT_THERMALMETER; + + if (efu->eeprom_thermalmeter == 0xff || autoload_fail) { + efu->apk_thermalmeterignore = true; + efu->eeprom_thermalmeter = EEPROM_DEFAULT_THERMALMETER; + } + + efu->thermalmeter[0] = efu->eeprom_thermalmeter; + RTPRINT(rtlpriv, FINIT, INIT_TXPOWER, "thermalmeter = 0x%x\n", + efu->eeprom_thermalmeter); + + if (!autoload_fail) { + efu->eeprom_regulatory = + hwinfo[EEPROM_RF_BOARD_OPTION_8822B] & 0x07; + if (hwinfo[EEPROM_RF_BOARD_OPTION_8822B] == 0xFF) + efu->eeprom_regulatory = 0; + } else { + efu->eeprom_regulatory = 0; + } + RTPRINT(rtlpriv, FINIT, INIT_TXPOWER, "eeprom_regulatory = 0x%x\n", + efu->eeprom_regulatory); +} + +static void _rtl8822be_read_pa_type(struct ieee80211_hw *hw, u8 *hwinfo, + bool autoload_fail) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + + if (!autoload_fail) { + rtlhal->pa_type_2g = hwinfo[EEPROM_2G_5G_PA_TYPE_8822B]; + rtlhal->lna_type_2g = + hwinfo[EEPROM_2G_LNA_TYPE_GAIN_SEL_AB_8822B]; + if (rtlhal->pa_type_2g == 0xFF) + rtlhal->pa_type_2g = 0; + if (rtlhal->lna_type_2g == 0xFF) + rtlhal->lna_type_2g = 0; + + rtlhal->external_pa_2g = (rtlhal->pa_type_2g & BIT(4)) ? 1 : 0; + rtlhal->external_lna_2g = + (rtlhal->lna_type_2g & BIT(3)) ? 1 : 0; + + rtlhal->pa_type_5g = hwinfo[EEPROM_2G_5G_PA_TYPE_8822B]; + rtlhal->lna_type_5g = + hwinfo[EEPROM_5G_LNA_TYPE_GAIN_SEL_AB_8822B]; + if (rtlhal->pa_type_5g == 0xFF) + rtlhal->pa_type_5g = 0; + if (rtlhal->lna_type_5g == 0xFF) + rtlhal->lna_type_5g = 0; + + rtlhal->external_pa_5g = (rtlhal->pa_type_5g & BIT(0)) ? 1 : 0; + rtlhal->external_lna_5g = + (rtlhal->lna_type_5g & BIT(3)) ? 1 : 0; + } else { + rtlhal->external_pa_2g = 0; + rtlhal->external_lna_2g = 0; + rtlhal->external_pa_5g = 0; + rtlhal->external_lna_5g = 0; + } +} + +static void _rtl8822be_read_amplifier_type(struct ieee80211_hw *hw, u8 *hwinfo, + bool autoload_fail) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + + u8 ext_type_pa_2g_a = + (hwinfo[EEPROM_2G_LNA_TYPE_GAIN_SEL_AB_8822B] & BIT(2)) >> + 2; /* 0xBD[2] */ + u8 ext_type_pa_2g_b = + (hwinfo[EEPROM_2G_LNA_TYPE_GAIN_SEL_AB_8822B] & BIT(6)) >> + 6; /* 0xBD[6] */ + u8 ext_type_pa_5g_a = + (hwinfo[EEPROM_5G_LNA_TYPE_GAIN_SEL_AB_8822B] & BIT(2)) >> + 2; /* 0xBF[2] */ + u8 ext_type_pa_5g_b = + (hwinfo[EEPROM_5G_LNA_TYPE_GAIN_SEL_AB_8822B] & BIT(6)) >> + 6; /* 0xBF[6] */ + u8 ext_type_lna_2g_a = (hwinfo[EEPROM_2G_LNA_TYPE_GAIN_SEL_AB_8822B] & + (BIT(1) | BIT(0))) >> + 0; /* 0xBD[1:0] */ + u8 ext_type_lna_2g_b = (hwinfo[EEPROM_2G_LNA_TYPE_GAIN_SEL_AB_8822B] & + (BIT(5) | BIT(4))) >> + 4; /* 0xBD[5:4] */ + u8 ext_type_lna_5g_a = (hwinfo[EEPROM_5G_LNA_TYPE_GAIN_SEL_AB_8822B] & + (BIT(1) | BIT(0))) >> + 0; /* 0xBF[1:0] */ + u8 ext_type_lna_5g_b = (hwinfo[EEPROM_5G_LNA_TYPE_GAIN_SEL_AB_8822B] & + (BIT(5) | BIT(4))) >> + 4; /* 0xBF[5:4] */ + + _rtl8822be_read_pa_type(hw, hwinfo, autoload_fail); + + /* [2.4G] Path A and B are both extPA */ + if ((rtlhal->pa_type_2g & (BIT(5) | BIT(4))) == (BIT(5) | BIT(4))) + rtlhal->type_gpa = ext_type_pa_2g_b << 2 | ext_type_pa_2g_a; + + /* [5G] Path A and B are both extPA */ + if ((rtlhal->pa_type_5g & (BIT(1) | BIT(0))) == (BIT(1) | BIT(0))) + rtlhal->type_apa = ext_type_pa_5g_b << 2 | ext_type_pa_5g_a; + + /* [2.4G] Path A and B are both extLNA */ + if ((rtlhal->lna_type_2g & (BIT(7) | BIT(3))) == (BIT(7) | BIT(3))) + rtlhal->type_glna = ext_type_lna_2g_b << 2 | ext_type_lna_2g_a; + + /* [5G] Path A and B are both extLNA */ + if ((rtlhal->lna_type_5g & (BIT(7) | BIT(3))) == (BIT(7) | BIT(3))) + rtlhal->type_alna = ext_type_lna_5g_b << 2 | ext_type_lna_5g_a; +} + +static void _rtl8822be_read_rfe_type(struct ieee80211_hw *hw, u8 *hwinfo, + bool autoload_fail) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + + if (!autoload_fail) + rtlhal->rfe_type = hwinfo[EEPROM_RFE_OPTION_8822B]; + else + rtlhal->rfe_type = 0; + + if (rtlhal->rfe_type == 0xFF) + rtlhal->rfe_type = 0; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "RFE Type: 0x%2x\n", + rtlhal->rfe_type); +} + +static void _rtl8822be_read_adapter_info(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct rtl_halmac_ops *halmac_ops = rtlpriv->halmac.ops; + u16 i, usvalue; + u8 *hwinfo; + u16 eeprom_id; + u32 efuse_size; + int err; + + if (rtlefuse->epromtype != EEPROM_BOOT_EFUSE) { + pr_err("RTL8822B Not boot from efuse!!"); + return; + } + + /* read logical efuse size (normalely, 0x0300) */ + err = halmac_ops->halmac_get_logical_efuse_size(rtlpriv, &efuse_size); + + if (err || !efuse_size) { + pr_err("halmac_get_logical_efuse_size err=%d efuse_size=0x%X", + err, efuse_size); + efuse_size = HWSET_MAX_SIZE; + } + + if (efuse_size > HWSET_MAX_SIZE) { + pr_err("halmac_get_logical_efuse_size efuse_size=0x%X > 0x%X", + efuse_size, HWSET_MAX_SIZE); + efuse_size = HWSET_MAX_SIZE; + } + + /* read efuse */ + hwinfo = kzalloc(efuse_size, GFP_KERNEL); + + err = halmac_ops->halmac_read_logical_efuse_map(rtlpriv, hwinfo, + efuse_size); + if (err) { + pr_err("%s: <ERROR> fail to get efuse map!\n", __func__); + goto label_end; + } + + /* copy to efuse_map (need?) */ + memcpy(&rtlefuse->efuse_map[EFUSE_INIT_MAP][0], hwinfo, + EFUSE_MAX_LOGICAL_SIZE); + memcpy(&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][0], hwinfo, + EFUSE_MAX_LOGICAL_SIZE); + + /* parse content */ + RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, "MAP\n", hwinfo, + HWSET_MAX_SIZE); + + eeprom_id = *((u16 *)&hwinfo[0]); + if (eeprom_id != RTL8822B_EEPROM_ID) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "EEPROM ID(%#x) is invalid!!\n", eeprom_id); + rtlefuse->autoload_failflag = true; + } else { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Autoload OK\n"); + rtlefuse->autoload_failflag = false; + } + + if (rtlefuse->autoload_failflag) + goto label_end; + + /*VID DID SVID SDID*/ + rtlefuse->eeprom_vid = *(u16 *)&hwinfo[EEPROM_VID]; + rtlefuse->eeprom_did = *(u16 *)&hwinfo[EEPROM_DID]; + rtlefuse->eeprom_svid = *(u16 *)&hwinfo[EEPROM_SVID]; + rtlefuse->eeprom_smid = *(u16 *)&hwinfo[EEPROM_SMID]; + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "EEPROMId = 0x%4x\n", eeprom_id); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "EEPROM VID = 0x%4x\n", + rtlefuse->eeprom_vid); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "EEPROM DID = 0x%4x\n", + rtlefuse->eeprom_did); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "EEPROM SVID = 0x%4x\n", + rtlefuse->eeprom_svid); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "EEPROM SMID = 0x%4x\n", + rtlefuse->eeprom_smid); + /*customer ID*/ + rtlefuse->eeprom_oemid = *(u8 *)&hwinfo[EEPROM_CUSTOM_ID_8822B]; + if (rtlefuse->eeprom_oemid == 0xFF) + rtlefuse->eeprom_oemid = 0; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "EEPROM Customer ID: 0x%2x\n", + rtlefuse->eeprom_oemid); + /*EEPROM version*/ + rtlefuse->eeprom_version = *(u8 *)&hwinfo[EEPROM_VERSION_8822B]; + /*mac address*/ + for (i = 0; i < 6; i += 2) { + usvalue = *(u16 *)&hwinfo[EEPROM_MAC_ADDR_8822BE + i]; + *((u16 *)(&rtlefuse->dev_addr[i])) = usvalue; + } + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "dev_addr: %pM\n", + rtlefuse->dev_addr); + + /* channel plan */ + rtlefuse->eeprom_channelplan = + *(u8 *)&hwinfo[EEPROM_CHANNEL_PLAN_8822B]; + + /* set channel plan from efuse */ + rtlefuse->channel_plan = rtlefuse->eeprom_channelplan; + if (rtlefuse->channel_plan == 0xFF) + rtlefuse->channel_plan = 0x7f; /* use 2G + 5G as default */ + + /*tx power*/ + _rtl8822be_read_txpower_info_from_hwpg(hw, rtlefuse->autoload_failflag, + hwinfo); + + rtl8822be_read_bt_coexist_info_from_hwpg( + hw, rtlefuse->autoload_failflag, hwinfo); + + /*amplifier type*/ + _rtl8822be_read_amplifier_type(hw, hwinfo, rtlefuse->autoload_failflag); + + /*rfe type*/ + _rtl8822be_read_rfe_type(hw, hwinfo, rtlefuse->autoload_failflag); + + /*board type*/ + rtlefuse->board_type = + (((*(u8 *)&hwinfo[EEPROM_RF_BOARD_OPTION_8822B]) & 0xE0) >> 5); + if ((*(u8 *)&hwinfo[EEPROM_RF_BOARD_OPTION_8822B]) == 0xFF) + rtlefuse->board_type = 0; + + if (rtlpriv->btcoexist.btc_info.btcoexist == 1) + rtlefuse->board_type |= BIT(2); /* ODM_BOARD_BT */ + + /* phydm maintain rtlhal->board_type and rtlhal->package_type */ + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "board_type = 0x%x\n", + rtlefuse->board_type); + /*parse xtal*/ + rtlefuse->crystalcap = hwinfo[EEPROM_XTAL_8822B]; + if (hwinfo[EEPROM_XTAL_8822B] == 0xFF) + rtlefuse->crystalcap = 0; /*0x20;*/ + + /*antenna diversity*/ + rtlefuse->antenna_div_type = 0; + rtlefuse->antenna_div_cfg = 0; + +label_end: + kfree(hwinfo); +} + +static void _rtl8822be_hal_customized_behavior(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + + pcipriv->ledctl.led_opendrain = true; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "RT Customized ID: 0x%02X\n", + rtlhal->oem_id); +} + +static void _rtl8822be_read_pa_bias(struct ieee80211_hw *hw, + struct rtl_phydm_params *params) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_halmac_ops *halmac_ops = rtlpriv->halmac.ops; + u32 size; + u8 *map = NULL; + + /* fill default values */ + params->efuse0x3d7 = 0xFF; + params->efuse0x3d8 = 0xFF; + + if (halmac_ops->halmac_get_physical_efuse_size(rtlpriv, &size)) + goto err; + + map = kmalloc(size, GFP_KERNEL); + if (!map) + goto err; + + if (halmac_ops->halmac_read_physical_efuse_map(rtlpriv, map, size)) + goto err; + + params->efuse0x3d7 = map[0x3d7]; + params->efuse0x3d8 = map[0x3d8]; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "efuse0x3d7 = 0x%2x, efuse0x3d8 = 0x%2x\n", + params->efuse0x3d7, params->efuse0x3d8); + +err: + kfree(map); +} + +void rtl8822be_read_eeprom_info(struct ieee80211_hw *hw, + struct rtl_phydm_params *params) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct rtl_phy *rtlphy = &rtlpriv->phy; + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u8 tmp_u1b; + + rtlhal->version = _rtl8822be_read_chip_version(hw); + + params->mp_chip = (rtlhal->version & BIT_RTL_ID_8822B) ? 0 : 1; + params->fab_ver = BIT_GET_VENDOR_ID_8822B(rtlhal->version) >> 2; + params->cut_ver = BIT_GET_CHIP_VER_8822B(rtlhal->version); + + /* fab_ver mapping */ + if (params->fab_ver == 2) + params->fab_ver = 1; + else if (params->fab_ver == 1) + params->fab_ver = 2; + + /* read PA bias: params->efuse0x3d7/efuse0x3d8 */ + _rtl8822be_read_pa_bias(hw, params); + + if (get_rf_type(rtlphy) == RF_1T1R) + rtlpriv->dm.rfpath_rxenable[0] = true; + else + rtlpriv->dm.rfpath_rxenable[0] = + rtlpriv->dm.rfpath_rxenable[1] = true; + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "VersionID = 0x%4x\n", + rtlhal->version); + tmp_u1b = rtl_read_byte(rtlpriv, REG_SYS_EEPROM_CTRL_8822B); + if (tmp_u1b & BIT(4)) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "Boot from EEPROM\n"); + rtlefuse->epromtype = EEPROM_93C46; + } else { + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "Boot from EFUSE\n"); + rtlefuse->epromtype = EEPROM_BOOT_EFUSE; + } + if (tmp_u1b & BIT(5)) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Autoload OK\n"); + rtlefuse->autoload_failflag = false; + _rtl8822be_read_adapter_info(hw); + } else { + pr_err("Autoload ERR!!\n"); + } + _rtl8822be_hal_customized_behavior(hw); + + rtlphy->rfpath_rx_enable[0] = true; + if (rtlphy->rf_type == RF_2T2R) + rtlphy->rfpath_rx_enable[1] = true; +} + +void rtl8822be_read_eeprom_info_dummy(struct ieee80211_hw *hw) +{ + /* + * 8822b use halmac, so + * move rtl8822be_read_eeprom_info() to rtl8822be_init_sw_vars() + * after halmac_init_adapter(). + */ +} + +static u32 _rtl8822be_rate_to_bitmap_2ssvht(__le16 vht_rate) +{ + u8 i, j, tmp_rate; + u32 rate_bitmap = 0; + + for (i = j = 0; i < 4; i += 2, j += 10) { + tmp_rate = (le16_to_cpu(vht_rate) >> i) & 3; + + switch (tmp_rate) { + case 2: + rate_bitmap = rate_bitmap | (0x03ff << j); + break; + + case 1: + rate_bitmap = rate_bitmap | (0x01ff << j); + break; + + case 0: + rate_bitmap = rate_bitmap | (0x00ff << j); + break; + + default: + break; + } + } + + return rate_bitmap; +} + +static u8 _rtl8822be_get_vht_en(enum wireless_mode wirelessmode, + u32 ratr_bitmap) +{ + u8 ret = 0; + + if (wirelessmode < WIRELESS_MODE_N_24G) { + ret = 0; + } else if (wirelessmode == WIRELESS_MODE_AC_24G) { + if (ratr_bitmap & 0xfff00000) /* Mix , 2SS */ + ret = 3; + else /* Mix, 1SS */ + ret = 2; + } else if (wirelessmode == WIRELESS_MODE_AC_5G) { + ret = 1; + } /* VHT */ + + return ret << 4; +} + +static u8 _rtl8822be_get_ra_ldpc(struct ieee80211_hw *hw, u8 mac_id, + struct rtl_sta_info *sta_entry, + enum wireless_mode wirelessmode) +{ + u8 b_ldpc = 0; + /*not support ldpc, do not open*/ + return b_ldpc << 2; +} + +static u8 _rtl8822be_get_ra_rftype(struct ieee80211_hw *hw, + enum wireless_mode wirelessmode, + u32 ratr_bitmap) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &rtlpriv->phy; + u8 rf_type = RF_1T1R; + + if (rtlphy->rf_type == RF_1T1R) { + rf_type = RF_1T1R; + } else if (wirelessmode == WIRELESS_MODE_AC_5G || + wirelessmode == WIRELESS_MODE_AC_24G || + wirelessmode == WIRELESS_MODE_AC_ONLY) { + if (ratr_bitmap & 0xffc00000) + rf_type = RF_2T2R; + } else if (wirelessmode == WIRELESS_MODE_N_5G || + wirelessmode == WIRELESS_MODE_N_24G) { + if (ratr_bitmap & 0xfff00000) + rf_type = RF_2T2R; + } + + return rf_type; +} + +static bool _rtl8822be_get_ra_shortgi(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u8 mac_id) +{ + bool b_short_gi = false; + u8 b_curshortgi_40mhz = + (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? 1 : 0; + u8 b_curshortgi_20mhz = + (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? 1 : 0; + u8 b_curshortgi_80mhz = 0; + + b_curshortgi_80mhz = + (sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80) ? 1 : 0; + + if (mac_id == 99 /*MAC_ID_STATIC_FOR_BROADCAST_MULTICAST*/) + b_short_gi = false; + + if (b_curshortgi_40mhz || b_curshortgi_80mhz || b_curshortgi_20mhz) + b_short_gi = true; + + return b_short_gi; +} + +static void rtl8822be_update_hal_rate_mask(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, + u8 rssi_level, bool update_bw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &rtlpriv->phy; + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_sta_info *sta_entry = NULL; + u32 ratr_bitmap, ratr_bitmap_msb = 0; + u8 ratr_index; + enum wireless_mode wirelessmode = 0; + u8 curtxbw_40mhz = + (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) ? 1 : 0; + bool b_shortgi = false; + u8 rate_mask[7]; + u8 macid = 0; + u8 rf_type; + + sta_entry = (struct rtl_sta_info *)sta->drv_priv; + wirelessmode = sta_entry->wireless_mode; + + RT_TRACE(rtlpriv, COMP_RATR, DBG_LOUD, "wireless mode = 0x%x\n", + wirelessmode); + if (mac->opmode == NL80211_IFTYPE_STATION || + mac->opmode == NL80211_IFTYPE_MESH_POINT) { + curtxbw_40mhz = mac->bw_40; + } else if (mac->opmode == NL80211_IFTYPE_AP || + mac->opmode == NL80211_IFTYPE_ADHOC) + macid = sta->aid + 1; + if (wirelessmode == WIRELESS_MODE_N_5G || + wirelessmode == WIRELESS_MODE_AC_5G || + wirelessmode == WIRELESS_MODE_A) + ratr_bitmap = (sta->supp_rates[NL80211_BAND_5GHZ]) << 4; + else + ratr_bitmap = sta->supp_rates[NL80211_BAND_2GHZ]; + + if (mac->opmode == NL80211_IFTYPE_ADHOC) + ratr_bitmap = 0xfff; + + if (wirelessmode == WIRELESS_MODE_N_24G || + wirelessmode == WIRELESS_MODE_N_5G) + ratr_bitmap |= (sta->ht_cap.mcs.rx_mask[1] << 20 | + sta->ht_cap.mcs.rx_mask[0] << 12); + else if (wirelessmode == WIRELESS_MODE_AC_24G || + wirelessmode == WIRELESS_MODE_AC_5G || + wirelessmode == WIRELESS_MODE_AC_ONLY) + ratr_bitmap |= _rtl8822be_rate_to_bitmap_2ssvht( + sta->vht_cap.vht_mcs.rx_mcs_map) + << 12; + + b_shortgi = _rtl8822be_get_ra_shortgi(hw, sta, macid); + rf_type = _rtl8822be_get_ra_rftype(hw, wirelessmode, ratr_bitmap); + + ratr_index = rtlpriv->phydm.ops->phydm_rate_id_mapping( + rtlpriv, wirelessmode, rf_type, rtlphy->current_chan_bw); + sta_entry->ratr_index = ratr_index; + + rtlpriv->phydm.ops->phydm_get_ra_bitmap( + rtlpriv, wirelessmode, rf_type, rtlphy->current_chan_bw, + rssi_level, &ratr_bitmap_msb, &ratr_bitmap); + + RT_TRACE(rtlpriv, COMP_RATR, DBG_LOUD, "ratr_bitmap :%x\n", + ratr_bitmap); + + rate_mask[0] = macid; + rate_mask[1] = ratr_index | (b_shortgi ? 0x80 : 0x00); + rate_mask[2] = + rtlphy->current_chan_bw | ((!update_bw) << 3) | + _rtl8822be_get_vht_en(wirelessmode, ratr_bitmap) | + _rtl8822be_get_ra_ldpc(hw, macid, sta_entry, wirelessmode); + + rate_mask[3] = (u8)(ratr_bitmap & 0x000000ff); + rate_mask[4] = (u8)((ratr_bitmap & 0x0000ff00) >> 8); + rate_mask[5] = (u8)((ratr_bitmap & 0x00ff0000) >> 16); + rate_mask[6] = (u8)((ratr_bitmap & 0xff000000) >> 24); + + RT_TRACE( + rtlpriv, COMP_RATR, DBG_DMESG, + "Rate_index:%x, ratr_val:%08x, %02x:%02x:%02x:%02x:%02x:%02x:%02x\n", + ratr_index, ratr_bitmap, rate_mask[0], rate_mask[1], + rate_mask[2], rate_mask[3], rate_mask[4], rate_mask[5], + rate_mask[6]); + rtl8822be_fill_h2c_cmd(hw, H2C_8822B_MACID_CFG, 7, rate_mask); + + /* for h2c cmd 0x46, only modify cmd id & ra mask */ + /* Keep rate_mask0~2 of cmd 0x40, but clear byte3 and later */ + /* 8822B has no 3SS, so keep it zeros. */ + memset(rate_mask + 3, 0, 4); + + rtl8822be_fill_h2c_cmd(hw, H2C_8822B_MACID_CFG_3SS, 7, rate_mask); + + _rtl8822be_set_bcn_ctrl_reg(hw, BIT(3), 0); +} + +void rtl8822be_update_hal_rate_tbl(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u8 rssi_level, + bool update_bw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (rtlpriv->dm.useramask) + rtl8822be_update_hal_rate_mask(hw, sta, rssi_level, update_bw); +} + +void rtl8822be_update_channel_access_setting(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + u16 sifs_timer; + + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SLOT_TIME, + (u8 *)&mac->slot_time); + if (!mac->ht_enable) + sifs_timer = 0x0a0a; + else + sifs_timer = 0x0e0e; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SIFS, (u8 *)&sifs_timer); +} + +bool rtl8822be_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid) +{ + *valid = 1; + return true; +} + +void rtl8822be_set_key(struct ieee80211_hw *hw, u32 key_index, u8 *p_macaddr, + bool is_group, u8 enc_algo, bool is_wepkey, + bool clear_all) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u8 *macaddr = p_macaddr; + u32 entry_id = 0; + bool is_pairwise = false; + + static u8 cam_const_addr[4][6] = { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x03}, + }; + static u8 cam_const_broad[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + + if (clear_all) { + u8 idx = 0; + u8 cam_offset = 0; + u8 clear_number = 5; + + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "clear_all\n"); + + for (idx = 0; idx < clear_number; idx++) { + rtl_cam_mark_invalid(hw, cam_offset + idx); + rtl_cam_empty_entry(hw, cam_offset + idx); + + if (idx < 5) { + memset(rtlpriv->sec.key_buf[idx], 0, + MAX_KEY_LEN); + rtlpriv->sec.key_len[idx] = 0; + } + } + + return; + } + + switch (enc_algo) { + case WEP40_ENCRYPTION: + enc_algo = CAM_WEP40; + break; + case WEP104_ENCRYPTION: + enc_algo = CAM_WEP104; + break; + case TKIP_ENCRYPTION: + enc_algo = CAM_TKIP; + break; + case AESCCMP_ENCRYPTION: + enc_algo = CAM_AES; + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD, + "switch case %#x not processed\n", enc_algo); + enc_algo = CAM_TKIP; + break; + } + + if (is_wepkey || rtlpriv->sec.use_defaultkey) { + macaddr = cam_const_addr[key_index]; + entry_id = key_index; + } else { + if (is_group) { + macaddr = cam_const_broad; + entry_id = key_index; + } else { + if (mac->opmode == NL80211_IFTYPE_AP) { + entry_id = + rtl_cam_get_free_entry(hw, p_macaddr); + if (entry_id >= TOTAL_CAM_ENTRY) { + pr_err("Can not find free hwsecurity cam entry\n"); + return; + } + } else { + entry_id = CAM_PAIRWISE_KEY_POSITION; + } + + key_index = PAIRWISE_KEYIDX; + is_pairwise = true; + } + } + + if (rtlpriv->sec.key_len[key_index] == 0) { + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + "delete one entry, entry_id is %d\n", entry_id); + if (mac->opmode == NL80211_IFTYPE_AP) + rtl_cam_del_entry(hw, p_macaddr); + rtl_cam_delete_one_entry(hw, p_macaddr, entry_id); + } else { + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "add one entry\n"); + if (is_pairwise) { + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + "set Pairwise key\n"); + + rtl_cam_add_one_entry(hw, macaddr, key_index, entry_id, + enc_algo, CAM_CONFIG_NO_USEDK, + rtlpriv->sec.key_buf[key_index]); + } else { + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + "set group key\n"); + + if (mac->opmode == NL80211_IFTYPE_ADHOC) { + rtl_cam_add_one_entry( + hw, rtlefuse->dev_addr, PAIRWISE_KEYIDX, + CAM_PAIRWISE_KEY_POSITION, enc_algo, + CAM_CONFIG_NO_USEDK, + rtlpriv->sec.key_buf[entry_id]); + } + + rtl_cam_add_one_entry(hw, macaddr, key_index, entry_id, + enc_algo, CAM_CONFIG_NO_USEDK, + rtlpriv->sec.key_buf[entry_id]); + } + } +} + +void rtl8822be_read_bt_coexist_info_from_hwpg(struct ieee80211_hw *hw, + bool auto_load_fail, u8 *hwinfo) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 value; + u32 val32; + + val32 = rtl_read_dword(rtlpriv, REG_WL_BT_PWR_CTRL_8822B); + if (val32 & BIT_BT_FUNC_EN_8822B) + rtlpriv->btcoexist.btc_info.btcoexist = 1; + else + rtlpriv->btcoexist.btc_info.btcoexist = 0; + + if (!auto_load_fail) { + value = hwinfo[EEPROM_RF_BT_SETTING_8822B]; + + rtlpriv->btcoexist.btc_info.bt_type = BT_RTL8822B; + rtlpriv->btcoexist.btc_info.ant_num = + (value & BIT(0) ? ANT_TOTAL_X1 : ANT_TOTAL_X2); + } else { + rtlpriv->btcoexist.btc_info.bt_type = BT_RTL8822B; + rtlpriv->btcoexist.btc_info.ant_num = ANT_TOTAL_X2; + } +} + +void rtl8822be_bt_reg_init(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + /* 0:Low, 1:High, 2:From Efuse. */ + rtlpriv->btcoexist.reg_bt_iso = 2; + /* 0:Idle, 1:None-SCO, 2:SCO, 3:From Counter. */ + rtlpriv->btcoexist.reg_bt_sco = 3; + /* 0:Disable BT control A-MPDU, 1:Enable BT control A-MPDU. */ + rtlpriv->btcoexist.reg_bt_sco = 0; +} + +void rtl8822be_suspend(struct ieee80211_hw *hw) {} + +void rtl8822be_resume(struct ieee80211_hw *hw) {} diff --git a/drivers/staging/rtlwifi/rtl8822be/hw.h b/drivers/staging/rtlwifi/rtl8822be/hw.h new file mode 100644 index 000000000000..a91c276c5794 --- /dev/null +++ b/drivers/staging/rtlwifi/rtl8822be/hw.h @@ -0,0 +1,66 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL8822B_HW_H__ +#define __RTL8822B_HW_H__ + +extern u8 rtl_channel5g[CHANNEL_MAX_NUMBER_5G]; +extern u8 rtl_channel5g_80m[CHANNEL_MAX_NUMBER_5G_80M]; + +void rtl8822be_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val); +void rtl8822be_read_eeprom_info(struct ieee80211_hw *hw, + struct rtl_phydm_params *params); +void rtl8822be_read_eeprom_info_dummy(struct ieee80211_hw *hw); +void rtl8822be_interrupt_recognized(struct ieee80211_hw *hw, u32 *p_inta, + u32 *p_intb, u32 *p_intc, u32 *p_intd); +int rtl8822be_hw_init(struct ieee80211_hw *hw); +void rtl8822be_card_disable(struct ieee80211_hw *hw); +void rtl8822be_enable_interrupt(struct ieee80211_hw *hw); +void rtl8822be_disable_interrupt(struct ieee80211_hw *hw); +int rtl8822be_set_network_type(struct ieee80211_hw *hw, + enum nl80211_iftype type); +void rtl8822be_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid); +void rtl8822be_set_qos(struct ieee80211_hw *hw, int aci); +void rtl8822be_set_beacon_related_registers(struct ieee80211_hw *hw); +void rtl8822be_set_beacon_interval(struct ieee80211_hw *hw); +void rtl8822be_update_interrupt_mask(struct ieee80211_hw *hw, u32 add_msr, + u32 rm_msr); +void rtl8822be_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val); +void rtl8822be_update_hal_rate_tbl(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u8 rssi_level, + bool update_bw); +void rtl8822be_update_channel_access_setting(struct ieee80211_hw *hw); +bool rtl8822be_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid); +void rtl8822be_set_key(struct ieee80211_hw *hw, u32 key_index, u8 *p_macaddr, + bool is_group, u8 enc_algo, bool is_wepkey, + bool clear_all); +void rtl8822be_enable_hw_security_config(struct ieee80211_hw *hw); +void rtl8822be_read_bt_coexist_info_from_hwpg(struct ieee80211_hw *hw, + bool autoload_fail, u8 *hwinfo); +void rtl8822be_bt_reg_init(struct ieee80211_hw *hw); +void rtl8822be_suspend(struct ieee80211_hw *hw); +void rtl8822be_resume(struct ieee80211_hw *hw); +void rtl8822be_fw_clk_off_timer_callback(unsigned long data); +#endif diff --git a/drivers/staging/rtlwifi/rtl8822be/led.c b/drivers/staging/rtlwifi/rtl8822be/led.c new file mode 100644 index 000000000000..f4b5af8ab116 --- /dev/null +++ b/drivers/staging/rtlwifi/rtl8822be/led.c @@ -0,0 +1,127 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../pci.h" +#include "reg.h" +#include "led.h" + +static void _rtl8822be_init_led(struct ieee80211_hw *hw, struct rtl_led *pled, + enum rtl_led_pin ledpin) +{ + pled->hw = hw; + pled->ledpin = ledpin; + pled->ledon = false; +} + +void rtl8822be_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, "LedAddr:%X ledpin=%d\n", + REG_LEDCFG2_8822B, pled->ledpin); + + switch (pled->ledpin) { + case LED_PIN_GPIO0: + break; + case LED_PIN_LED0: + break; + case LED_PIN_LED1: + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD, + "switch case not process\n"); + break; + } + pled->ledon = true; +} + +void rtl8822be_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, "LedAddr:%X ledpin=%d\n", + REG_LEDCFG2_8822B, pled->ledpin); + + switch (pled->ledpin) { + case LED_PIN_GPIO0: + break; + case LED_PIN_LED0: + break; + case LED_PIN_LED1: + + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD, + "switch case not process\n"); + break; + } + pled->ledon = false; +} + +void rtl8822be_init_sw_leds(struct ieee80211_hw *hw) +{ + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + + _rtl8822be_init_led(hw, &pcipriv->ledctl.sw_led0, LED_PIN_LED0); + _rtl8822be_init_led(hw, &pcipriv->ledctl.sw_led1, LED_PIN_LED1); +} + +static void _rtl8822be_sw_led_control(struct ieee80211_hw *hw, + enum led_ctl_mode ledaction) +{ + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + struct rtl_led *led0 = &pcipriv->ledctl.sw_led0; + + switch (ledaction) { + case LED_CTL_POWER_ON: + case LED_CTL_LINK: + case LED_CTL_NO_LINK: + rtl8822be_sw_led_on(hw, led0); + break; + case LED_CTL_POWER_OFF: + rtl8822be_sw_led_off(hw, led0); + break; + default: + break; + } +} + +void rtl8822be_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + + if ((ppsc->rfoff_reason > RF_CHANGE_BY_PS) && + (ledaction == LED_CTL_TX || ledaction == LED_CTL_RX || + ledaction == LED_CTL_SITE_SURVEY || ledaction == LED_CTL_LINK || + ledaction == LED_CTL_NO_LINK || + ledaction == LED_CTL_START_TO_LINK || + ledaction == LED_CTL_POWER_ON)) { + return; + } + RT_TRACE(rtlpriv, COMP_LED, DBG_TRACE, "ledaction %d,\n", ledaction); + _rtl8822be_sw_led_control(hw, ledaction); +} diff --git a/drivers/staging/rtlwifi/rtl8822be/led.h b/drivers/staging/rtlwifi/rtl8822be/led.h new file mode 100644 index 000000000000..9c0a2290df7d --- /dev/null +++ b/drivers/staging/rtlwifi/rtl8822be/led.h @@ -0,0 +1,34 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL8822B_LED_H__ +#define __RTL8822B_LED_H__ + +void rtl8822be_init_sw_leds(struct ieee80211_hw *hw); +void rtl8822be_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled); +void rtl8822be_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled); +void rtl8822be_led_control(struct ieee80211_hw *hw, + enum led_ctl_mode ledaction); +#endif diff --git a/drivers/staging/rtlwifi/rtl8822be/phy.c b/drivers/staging/rtlwifi/rtl8822be/phy.c new file mode 100644 index 000000000000..4cba2adc3165 --- /dev/null +++ b/drivers/staging/rtlwifi/rtl8822be/phy.c @@ -0,0 +1,2233 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../pci.h" +#include "../ps.h" +#include "../base.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "trx.h" +#include "../btcoexist/halbt_precomp.h" +#include "hw.h" +#include "../efuse.h" + +static u32 _rtl8822be_phy_calculate_bit_shift(u32 bitmask); +static void +_rtl8822be_phy_init_bb_rf_register_definition(struct ieee80211_hw *hw); + +static long _rtl8822be_phy_txpwr_idx_to_dbm(struct ieee80211_hw *hw, + enum wireless_mode wirelessmode, + u8 txpwridx); +static void rtl8822be_phy_set_rf_on(struct ieee80211_hw *hw); +static void rtl8822be_phy_set_io(struct ieee80211_hw *hw); + +static u8 cck_rates[] = {DESC_RATE1M, DESC_RATE2M, DESC_RATE5_5M, DESC_RATE11M}; +static u8 sizes_of_cck_retes = 4; +static u8 ofdm_rates[] = {DESC_RATE6M, DESC_RATE9M, DESC_RATE12M, + DESC_RATE18M, DESC_RATE24M, DESC_RATE36M, + DESC_RATE48M, DESC_RATE54M}; +static u8 sizes_of_ofdm_retes = 8; +static u8 ht_rates_1t[] = {DESC_RATEMCS0, DESC_RATEMCS1, DESC_RATEMCS2, + DESC_RATEMCS3, DESC_RATEMCS4, DESC_RATEMCS5, + DESC_RATEMCS6, DESC_RATEMCS7}; +static u8 sizes_of_ht_retes_1t = 8; +static u8 ht_rates_2t[] = {DESC_RATEMCS8, DESC_RATEMCS9, DESC_RATEMCS10, + DESC_RATEMCS11, DESC_RATEMCS12, DESC_RATEMCS13, + DESC_RATEMCS14, DESC_RATEMCS15}; +static u8 sizes_of_ht_retes_2t = 8; +static u8 vht_rates_1t[] = {DESC_RATEVHT1SS_MCS0, DESC_RATEVHT1SS_MCS1, + DESC_RATEVHT1SS_MCS2, DESC_RATEVHT1SS_MCS3, + DESC_RATEVHT1SS_MCS4, DESC_RATEVHT1SS_MCS5, + DESC_RATEVHT1SS_MCS6, DESC_RATEVHT1SS_MCS7, + DESC_RATEVHT1SS_MCS8, DESC_RATEVHT1SS_MCS9}; +static u8 vht_rates_2t[] = {DESC_RATEVHT2SS_MCS0, DESC_RATEVHT2SS_MCS1, + DESC_RATEVHT2SS_MCS2, DESC_RATEVHT2SS_MCS3, + DESC_RATEVHT2SS_MCS4, DESC_RATEVHT2SS_MCS5, + DESC_RATEVHT2SS_MCS6, DESC_RATEVHT2SS_MCS7, + DESC_RATEVHT2SS_MCS8, DESC_RATEVHT2SS_MCS9}; +static u8 sizes_of_vht_retes = 10; + +u32 rtl8822be_phy_query_bb_reg(struct ieee80211_hw *hw, u32 regaddr, + u32 bitmask) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 returnvalue, originalvalue, bitshift; + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "regaddr(%#x), bitmask(%#x)\n", + regaddr, bitmask); + originalvalue = rtl_read_dword(rtlpriv, regaddr); + bitshift = _rtl8822be_phy_calculate_bit_shift(bitmask); + returnvalue = (originalvalue & bitmask) >> bitshift; + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "BBR MASK=0x%x Addr[0x%x]=0x%x\n", + bitmask, regaddr, originalvalue); + + return returnvalue; +} + +void rtl8822be_phy_set_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask, + u32 data) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 originalvalue, bitshift; + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, + "regaddr(%#x), bitmask(%#x), data(%#x)\n", regaddr, bitmask, + data); + + if (bitmask != MASKDWORD) { + originalvalue = rtl_read_dword(rtlpriv, regaddr); + bitshift = _rtl8822be_phy_calculate_bit_shift(bitmask); + data = ((originalvalue & (~bitmask)) | + ((data << bitshift) & bitmask)); + } + + rtl_write_dword(rtlpriv, regaddr, data); + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, + "regaddr(%#x), bitmask(%#x), data(%#x)\n", regaddr, bitmask, + data); +} + +u32 rtl8822be_phy_query_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath, + u32 regaddr, u32 bitmask) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 /*original_value,*/ readback_value /*, bitshift*/; + unsigned long flags; + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, + "regaddr(%#x), rfpath(%#x), bitmask(%#x)\n", regaddr, rfpath, + bitmask); + + spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags); + + readback_value = rtlpriv->phydm.ops->phydm_read_rf_reg( + rtlpriv, rfpath, regaddr, bitmask); + + spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags); + + return readback_value; +} + +void rtl8822be_phy_set_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath, + u32 regaddr, u32 bitmask, u32 data) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + unsigned long flags; + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, + "regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n", + regaddr, bitmask, data, rfpath); + + spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags); + + rtlpriv->phydm.ops->phydm_write_rf_reg(rtlpriv, rfpath, regaddr, + bitmask, data); + + spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags); + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, + "regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n", + regaddr, bitmask, data, rfpath); +} + +static u32 _rtl8822be_phy_calculate_bit_shift(u32 bitmask) +{ + u32 i; + + for (i = 0; i <= 31; i++) { + if (((bitmask >> i) & 0x1) == 1) + break; + } + return i; +} + +bool rtl8822be_halmac_cb_init_mac_register(struct rtl_priv *rtlpriv) +{ + return rtlpriv->phydm.ops->phydm_phy_mac_config(rtlpriv); +} + +bool rtl8822be_phy_bb_config(struct ieee80211_hw *hw) +{ + bool rtstatus = true; + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u8 crystal_cap; + /* u32 tmp; */ + + rtstatus = rtlpriv->phydm.ops->phydm_phy_bb_config(rtlpriv); + + /* write 0x28[6:1] = 0x24[30:25] = CrystalCap */ + crystal_cap = rtlefuse->crystalcap & 0x3F; + rtl_set_bbreg(hw, REG_AFE_XTAL_CTRL_8822B, 0x7E000000, crystal_cap); + rtl_set_bbreg(hw, REG_AFE_PLL_CTRL_8822B, 0x7E, crystal_cap); + + /*rtlphy->reg_837 = rtl_read_byte(rtlpriv, 0x837);*/ /*unused*/ + + return rtstatus; +} + +bool rtl8822be_phy_rf_config(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &rtlpriv->phy; + + if (rtlphy->rf_type == RF_1T1R) + rtlphy->num_total_rfpath = 1; + else + rtlphy->num_total_rfpath = 2; + + return rtlpriv->phydm.ops->phydm_phy_rf_config(rtlpriv); +} + +bool rtl8822be_halmac_cb_init_bb_rf_register(struct rtl_priv *rtlpriv) +{ + struct ieee80211_hw *hw = rtlpriv->hw; + enum radio_mask txpath, rxpath; + bool tx2path; + bool ret = false; + + _rtl8822be_phy_init_bb_rf_register_definition(hw); + + rtlpriv->halmac.ops->halmac_phy_power_switch(rtlpriv, 1); + + /* beofre bb/rf config */ + rtlpriv->phydm.ops->phydm_parameter_init(rtlpriv, 0); + + /* do bb/rf config */ + if (rtl8822be_phy_bb_config(hw) && rtl8822be_phy_rf_config(hw)) + ret = true; + + /* after bb/rf config */ + rtlpriv->phydm.ops->phydm_parameter_init(rtlpriv, 1); + + /* set trx mode (keep it to be last, r17376) */ + txpath = RF_MASK_A | RF_MASK_B; + rxpath = RF_MASK_A | RF_MASK_B; + tx2path = false; + ret = rtlpriv->phydm.ops->phydm_trx_mode(rtlpriv, txpath, rxpath, + tx2path); + + return ret; +} + +static void _rtl8822be_phy_init_tx_power_by_rate(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &rtlpriv->phy; + + u8 band, rfpath, txnum, rate; + + for (band = BAND_ON_2_4G; band <= BAND_ON_5G; ++band) + for (rfpath = 0; rfpath < TX_PWR_BY_RATE_NUM_RF; ++rfpath) + for (txnum = 0; txnum < TX_PWR_BY_RATE_NUM_RF; ++txnum) + for (rate = 0; rate < TX_PWR_BY_RATE_NUM_RATE; + ++rate) + rtlphy->tx_power_by_rate_offset + [band][rfpath][txnum][rate] = 0; +} + +static void _rtl8822be_phy_set_txpower_by_rate_base(struct ieee80211_hw *hw, + u8 band, u8 path, + u8 rate_section, u8 txnum, + u8 value) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &rtlpriv->phy; + + if (path > RF90_PATH_D) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "Invalid Rf Path %d in phy_SetTxPowerByRatBase()\n", + path); + return; + } + + if (band != BAND_ON_2_4G && band != BAND_ON_5G) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "Invalid band %d in phy_SetTxPowerByRatBase()\n", + band); + return; + } + + if (rate_section >= MAX_RATE_SECTION || + (band == BAND_ON_5G && rate_section == CCK)) { + RT_TRACE( + rtlpriv, COMP_INIT, DBG_LOUD, + "Invalid rate_section %d in phy_SetTxPowerByRatBase()\n", + rate_section); + return; + } + + if (band == BAND_ON_2_4G) + rtlphy->txpwr_by_rate_base_24g[path][txnum][rate_section] = + value; + else /* BAND_ON_5G */ + rtlphy->txpwr_by_rate_base_5g[path][txnum][rate_section - 1] = + value; +} + +static u8 _rtl8822be_phy_get_txpower_by_rate_base(struct ieee80211_hw *hw, + u8 band, u8 path, u8 txnum, + u8 rate_section) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &rtlpriv->phy; + u8 value; + + if (path > RF90_PATH_D) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "Invalid Rf Path %d in phy_GetTxPowerByRatBase()\n", + path); + return 0; + } + + if (band != BAND_ON_2_4G && band != BAND_ON_5G) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "Invalid band %d in phy_GetTxPowerByRatBase()\n", + band); + return 0; + } + + if (rate_section >= MAX_RATE_SECTION || + (band == BAND_ON_5G && rate_section == CCK)) { + RT_TRACE( + rtlpriv, COMP_INIT, DBG_LOUD, + "Invalid rate_section %d in phy_GetTxPowerByRatBase()\n", + rate_section); + return 0; + } + + if (band == BAND_ON_2_4G) + value = rtlphy->txpwr_by_rate_base_24g[path][txnum] + [rate_section]; + else /* BAND_ON_5G */ + value = rtlphy->txpwr_by_rate_base_5g[path][txnum] + [rate_section - 1]; + + return value; +} + +static void _rtl8822be_phy_store_txpower_by_rate_base(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &rtlpriv->phy; + + struct { + enum rtl_desc_rate rate; + enum rate_section section; + } rate_sec_base[] = { + {DESC_RATE11M, CCK}, + {DESC_RATE54M, OFDM}, + {DESC_RATEMCS7, HT_MCS0_MCS7}, + {DESC_RATEMCS15, HT_MCS8_MCS15}, + {DESC_RATEVHT1SS_MCS7, VHT_1SSMCS0_1SSMCS9}, + {DESC_RATEVHT2SS_MCS7, VHT_2SSMCS0_2SSMCS9}, + }; + + u8 band, path, rs, tx_num, base; + u8 rate, section; + + for (band = BAND_ON_2_4G; band <= BAND_ON_5G; band++) { + for (path = RF90_PATH_A; path <= RF90_PATH_B; path++) { + for (rs = 0; rs < MAX_RATE_SECTION; rs++) { + rate = rate_sec_base[rs].rate; + section = rate_sec_base[rs].section; + + if (IS_1T_RATE(rate)) + tx_num = RF_1TX; + else + tx_num = RF_2TX; + + if (band == BAND_ON_5G && + RX_HAL_IS_CCK_RATE(rate)) + continue; + + base = rtlphy->tx_power_by_rate_offset + [band][path][tx_num][rate]; + _rtl8822be_phy_set_txpower_by_rate_base( + hw, band, path, section, tx_num, base); + } + } + } +} + +static void __rtl8822be_phy_cross_reference_core(struct ieee80211_hw *hw, + u8 regulation, u8 bw, + u8 channel) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &rtlpriv->phy; + u8 rs, ref_rs; + s8 pwrlmt, ref_pwrlmt; + + for (rs = 0; rs < MAX_RATE_SECTION_NUM; ++rs) { + /*5G 20M 40M VHT and HT can cross reference*/ + if (bw != HT_CHANNEL_WIDTH_20 && bw != HT_CHANNEL_WIDTH_20_40) + continue; + + if (rs == HT_MCS0_MCS7) + ref_rs = VHT_1SSMCS0_1SSMCS9; + else if (rs == HT_MCS8_MCS15) + ref_rs = VHT_2SSMCS0_2SSMCS9; + else if (rs == VHT_1SSMCS0_1SSMCS9) + ref_rs = HT_MCS0_MCS7; + else if (rs == VHT_2SSMCS0_2SSMCS9) + ref_rs = HT_MCS8_MCS15; + else + continue; + + ref_pwrlmt = rtlphy->txpwr_limit_5g[regulation][bw][ref_rs] + [channel][RF90_PATH_A]; + if (ref_pwrlmt == MAX_POWER_INDEX) + continue; + + pwrlmt = rtlphy->txpwr_limit_5g[regulation][bw][rs][channel] + [RF90_PATH_A]; + if (pwrlmt != MAX_POWER_INDEX) + continue; + + rtlphy->txpwr_limit_5g[regulation][bw][rs][channel] + [RF90_PATH_A] = ref_pwrlmt; + } +} + +static void +_rtl8822be_phy_cross_reference_ht_and_vht_txpower_limit(struct ieee80211_hw *hw) +{ + u8 regulation, bw, channel; + + for (regulation = 0; regulation < MAX_REGULATION_NUM; ++regulation) { + for (bw = 0; bw < MAX_5G_BANDWIDTH_NUM; ++bw) { + for (channel = 0; channel < CHANNEL_MAX_NUMBER_5G; + ++channel) { + __rtl8822be_phy_cross_reference_core( + hw, regulation, bw, channel); + } + } + } +} + +static void __rtl8822be_txpwr_limit_to_index_2g(struct ieee80211_hw *hw, + u8 regulation, u8 bw, + u8 channel) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &rtlpriv->phy; + u8 bw40_pwr_base_dbm2_4G; + u8 rate_section; + s8 temp_pwrlmt; + enum rf_tx_num txnum; + s8 temp_value; + u8 rf_path; + + for (rate_section = 0; rate_section < MAX_RATE_SECTION_NUM; + ++rate_section) { + /* obtain the base dBm values in 2.4G band + * CCK => 11M, OFDM => 54M, HT 1T => MCS7, HT 2T => MCS15 + */ + + temp_pwrlmt = + rtlphy->txpwr_limit_2_4g[regulation][bw][rate_section] + [channel][RF90_PATH_A]; + txnum = IS_1T_RATESEC(rate_section) ? RF_1TX : RF_2TX; + + if (temp_pwrlmt == MAX_POWER_INDEX) + continue; + + for (rf_path = RF90_PATH_A; rf_path < MAX_RF_PATH_NUM; + ++rf_path) { + bw40_pwr_base_dbm2_4G = + _rtl8822be_phy_get_txpower_by_rate_base( + hw, BAND_ON_2_4G, rf_path, txnum, + rate_section); + + temp_value = temp_pwrlmt - bw40_pwr_base_dbm2_4G; + rtlphy->txpwr_limit_2_4g[regulation][bw][rate_section] + [channel][rf_path] = temp_value; + + RT_TRACE( + rtlpriv, COMP_INIT, DBG_TRACE, + "TxPwrLimit_2_4G[regulation %d][bw %d][rateSection %d][channel %d] = %d\n(TxPwrLimit in dBm %d - BW40PwrLmt2_4G[channel %d][rfPath %d] %d)\n", + regulation, bw, rate_section, channel, + rtlphy->txpwr_limit_2_4g[regulation][bw] + [rate_section][channel] + [rf_path], + (temp_pwrlmt == 63) ? 0 : temp_pwrlmt / 2, + channel, rf_path, bw40_pwr_base_dbm2_4G); + } + } +} + +static void __rtl8822be_txpwr_limit_to_index_5g(struct ieee80211_hw *hw, + u8 regulation, u8 bw, + u8 channel) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &rtlpriv->phy; + u8 bw40_pwr_base_dbm5G; + u8 rate_section; + s8 temp_pwrlmt; + enum rf_tx_num txnum; + s8 temp_value; + u8 rf_path; + + for (rate_section = 0; rate_section < MAX_RATE_SECTION_NUM; + ++rate_section) { + /* obtain the base dBm values in 5G band + * OFDM => 54M, HT 1T => MCS7, HT 2T => MCS15, + * VHT => 1SSMCS7, VHT 2T => 2SSMCS7 + */ + + temp_pwrlmt = + rtlphy->txpwr_limit_5g[regulation][bw][rate_section] + [channel][RF90_PATH_A]; + txnum = IS_1T_RATESEC(rate_section) ? RF_1TX : RF_2TX; + + if (temp_pwrlmt == MAX_POWER_INDEX) + continue; + + for (rf_path = RF90_PATH_A; rf_path < MAX_RF_PATH_NUM; + ++rf_path) { + bw40_pwr_base_dbm5G = + _rtl8822be_phy_get_txpower_by_rate_base( + hw, BAND_ON_5G, rf_path, txnum, + rate_section); + + temp_value = temp_pwrlmt - bw40_pwr_base_dbm5G; + rtlphy->txpwr_limit_5g[regulation][bw][rate_section] + [channel][rf_path] = temp_value; + + RT_TRACE( + rtlpriv, COMP_INIT, DBG_TRACE, + "TxPwrLimit_5G[regulation %d][bw %d][rateSection %d][channel %d] =%d\n(TxPwrLimit in dBm %d - BW40PwrLmt5G[chnl group %d][rfPath %d] %d)\n", + regulation, bw, rate_section, channel, + rtlphy->txpwr_limit_5g[regulation][bw] + [rate_section][channel] + [rf_path], + temp_pwrlmt, channel, rf_path, + bw40_pwr_base_dbm5G); + } + } +} + +static void +_rtl8822be_phy_convert_txpower_limit_to_power_index(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 regulation, bw, channel; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "=====> %s()\n", __func__); + + _rtl8822be_phy_cross_reference_ht_and_vht_txpower_limit(hw); + + for (regulation = 0; regulation < MAX_REGULATION_NUM; ++regulation) { + for (bw = 0; bw < MAX_2_4G_BANDWIDTH_NUM; ++bw) { + for (channel = 0; channel < CHANNEL_MAX_NUMBER_2G; + ++channel) { + __rtl8822be_txpwr_limit_to_index_2g( + hw, regulation, bw, channel); + } + } + } + + for (regulation = 0; regulation < MAX_REGULATION_NUM; ++regulation) { + for (bw = 0; bw < MAX_5G_BANDWIDTH_NUM; ++bw) { + for (channel = 0; channel < CHANNEL_MAX_NUMBER_5G; + ++channel) { + __rtl8822be_txpwr_limit_to_index_5g( + hw, regulation, bw, channel); + } + } + } + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "<===== %s()\n", __func__); +} + +static void _rtl8822be_phy_init_txpower_limit(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &rtlpriv->phy; + u8 i, j, k, l, m; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "=====> %s()!\n", __func__); + + for (i = 0; i < MAX_REGULATION_NUM; ++i) { + for (j = 0; j < MAX_2_4G_BANDWIDTH_NUM; ++j) + for (k = 0; k < MAX_RATE_SECTION_NUM; ++k) + for (m = 0; m < CHANNEL_MAX_NUMBER_2G; ++m) + for (l = 0; l < MAX_RF_PATH_NUM; ++l) + rtlphy->txpwr_limit_2_4g[i][j] + [k][m] + [l] = + MAX_POWER_INDEX; + } + for (i = 0; i < MAX_REGULATION_NUM; ++i) { + for (j = 0; j < MAX_5G_BANDWIDTH_NUM; ++j) + for (k = 0; k < MAX_RATE_SECTION_NUM; ++k) + for (m = 0; m < CHANNEL_MAX_NUMBER_5G; ++m) + for (l = 0; l < MAX_RF_PATH_NUM; ++l) + rtlphy->txpwr_limit_5g[i][j][k] + [m][l] = + MAX_POWER_INDEX; + } + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "<===== %s()!\n", __func__); +} + +static void +_rtl8822be_phy_convert_txpower_dbm_to_relative_value(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &rtlpriv->phy; + + u8 base = 0, i = 0, value = 0, band = 0, path = 0, txnum = 0; + + for (band = BAND_ON_2_4G; band <= BAND_ON_5G; ++band) { + for (path = RF90_PATH_A; path <= RF90_PATH_B; ++path) { + for (txnum = RF_1TX; txnum <= RF_2TX; ++txnum) { + /* CCK */ + base = rtlphy->tx_power_by_rate_offset + [band][path][txnum] + [DESC_RATE11M]; + for (i = 0; i < sizeof(cck_rates); ++i) { + value = rtlphy->tx_power_by_rate_offset + [band][path][txnum] + [cck_rates[i]]; + rtlphy->tx_power_by_rate_offset + [band][path][txnum] + [cck_rates[i]] = value - base; + } + + /* OFDM */ + base = rtlphy->tx_power_by_rate_offset + [band][path][txnum] + [DESC_RATE54M]; + for (i = 0; i < sizeof(ofdm_rates); ++i) { + value = rtlphy->tx_power_by_rate_offset + [band][path][txnum] + [ofdm_rates[i]]; + rtlphy->tx_power_by_rate_offset + [band][path][txnum] + [ofdm_rates[i]] = value - base; + } + + /* HT MCS0~7 */ + base = rtlphy->tx_power_by_rate_offset + [band][path][txnum] + [DESC_RATEMCS7]; + for (i = 0; i < sizeof(ht_rates_1t); ++i) { + value = rtlphy->tx_power_by_rate_offset + [band][path][txnum] + [ht_rates_1t[i]]; + rtlphy->tx_power_by_rate_offset + [band][path][txnum] + [ht_rates_1t[i]] = value - base; + } + + /* HT MCS8~15 */ + base = rtlphy->tx_power_by_rate_offset + [band][path][txnum] + [DESC_RATEMCS15]; + for (i = 0; i < sizeof(ht_rates_2t); ++i) { + value = rtlphy->tx_power_by_rate_offset + [band][path][txnum] + [ht_rates_2t[i]]; + rtlphy->tx_power_by_rate_offset + [band][path][txnum] + [ht_rates_2t[i]] = value - base; + } + + /* VHT 1SS */ + base = rtlphy->tx_power_by_rate_offset + [band][path][txnum] + [DESC_RATEVHT1SS_MCS7]; + for (i = 0; i < sizeof(vht_rates_1t); ++i) { + value = rtlphy->tx_power_by_rate_offset + [band][path][txnum] + [vht_rates_1t[i]]; + rtlphy->tx_power_by_rate_offset + [band][path][txnum] + [vht_rates_1t[i]] = + value - base; + } + + /* VHT 2SS */ + base = rtlphy->tx_power_by_rate_offset + [band][path][txnum] + [DESC_RATEVHT2SS_MCS7]; + for (i = 0; i < sizeof(vht_rates_2t); ++i) { + value = rtlphy->tx_power_by_rate_offset + [band][path][txnum] + [vht_rates_2t[i]]; + rtlphy->tx_power_by_rate_offset + [band][path][txnum] + [vht_rates_2t[i]] = + value - base; + } + } + } + } + + RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE, "<===%s()\n", __func__); +} + +static void +_rtl8822be_phy_txpower_by_rate_configuration(struct ieee80211_hw *hw) +{ + /* copy rate_section from + * tx_power_by_rate_offset[][rate] to txpwr_by_rate_base_24g/_5g[][rs] + */ + _rtl8822be_phy_store_txpower_by_rate_base(hw); + + /* convert tx_power_by_rate_offset[] to relative value */ + _rtl8822be_phy_convert_txpower_dbm_to_relative_value(hw); +} + +/* string is in decimal */ +static bool _rtl8822be_get_integer_from_string(char *str, u8 *pint) +{ + u16 i = 0; + *pint = 0; + + while (str[i] != '\0') { + if (str[i] >= '0' && str[i] <= '9') { + *pint *= 10; + *pint += (str[i] - '0'); + } else { + return false; + } + ++i; + } + + return true; +} + +static bool _rtl8822be_eq_n_byte(u8 *str1, u8 *str2, u32 num) +{ + if (num == 0) + return false; + while (num > 0) { + num--; + if (str1[num] != str2[num]) + return false; + } + return true; +} + +static char _rtl8822be_phy_get_chnl_idx_of_txpwr_lmt(struct ieee80211_hw *hw, + u8 band, u8 channel) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + char channel_index = -1; + u8 i = 0; + + if (band == BAND_ON_2_4G) { + channel_index = channel - 1; + } else if (band == BAND_ON_5G) { + for (i = 0; i < sizeof(rtl_channel5g) / sizeof(u8); ++i) { + if (rtl_channel5g[i] == channel) + channel_index = i; + } + } else { + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "Invalid Band %d in %s", + band, __func__); + } + + if (channel_index == -1) + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "Invalid Channel %d of Band %d in %s", channel, band, + __func__); + + return channel_index; +} + +void rtl8822be_phy_set_txpower_limit(struct ieee80211_hw *hw, u8 *pregulation, + u8 *pband, u8 *pbandwidth, + u8 *prate_section, u8 *prf_path, + u8 *pchannel, u8 *ppower_limit) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &rtlpriv->phy; + u8 regulation = 0, bandwidth = 0, rate_section = 0, channel; + u8 channel_index; + char power_limit = 0, prev_power_limit, ret; + + if (!_rtl8822be_get_integer_from_string((char *)pchannel, &channel) || + !_rtl8822be_get_integer_from_string((char *)ppower_limit, + &power_limit)) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "Illegal index of pwr_lmt table [chnl %d][val %d]\n", + channel, power_limit); + } + + power_limit = + power_limit > MAX_POWER_INDEX ? MAX_POWER_INDEX : power_limit; + + if (_rtl8822be_eq_n_byte(pregulation, (u8 *)("FCC"), 3)) + regulation = 0; + else if (_rtl8822be_eq_n_byte(pregulation, (u8 *)("MKK"), 3)) + regulation = 1; + else if (_rtl8822be_eq_n_byte(pregulation, (u8 *)("ETSI"), 4)) + regulation = 2; + else if (_rtl8822be_eq_n_byte(pregulation, (u8 *)("WW13"), 4)) + regulation = 3; + + if (_rtl8822be_eq_n_byte(prate_section, (u8 *)("CCK"), 3)) + rate_section = CCK; + else if (_rtl8822be_eq_n_byte(prate_section, (u8 *)("OFDM"), 4)) + rate_section = OFDM; + else if (_rtl8822be_eq_n_byte(prate_section, (u8 *)("HT"), 2) && + _rtl8822be_eq_n_byte(prf_path, (u8 *)("1T"), 2)) + rate_section = HT_MCS0_MCS7; + else if (_rtl8822be_eq_n_byte(prate_section, (u8 *)("HT"), 2) && + _rtl8822be_eq_n_byte(prf_path, (u8 *)("2T"), 2)) + rate_section = HT_MCS8_MCS15; + else if (_rtl8822be_eq_n_byte(prate_section, (u8 *)("VHT"), 3) && + _rtl8822be_eq_n_byte(prf_path, (u8 *)("1T"), 2)) + rate_section = VHT_1SSMCS0_1SSMCS9; + else if (_rtl8822be_eq_n_byte(prate_section, (u8 *)("VHT"), 3) && + _rtl8822be_eq_n_byte(prf_path, (u8 *)("2T"), 2)) + rate_section = VHT_2SSMCS0_2SSMCS9; + + if (_rtl8822be_eq_n_byte(pbandwidth, (u8 *)("20M"), 3)) + bandwidth = HT_CHANNEL_WIDTH_20; + else if (_rtl8822be_eq_n_byte(pbandwidth, (u8 *)("40M"), 3)) + bandwidth = HT_CHANNEL_WIDTH_20_40; + else if (_rtl8822be_eq_n_byte(pbandwidth, (u8 *)("80M"), 3)) + bandwidth = HT_CHANNEL_WIDTH_80; + else if (_rtl8822be_eq_n_byte(pbandwidth, (u8 *)("160M"), 4)) + bandwidth = 3; + + if (_rtl8822be_eq_n_byte(pband, (u8 *)("2.4G"), 4)) { + ret = _rtl8822be_phy_get_chnl_idx_of_txpwr_lmt(hw, BAND_ON_2_4G, + channel); + + if (ret == -1) + return; + + channel_index = ret; + + prev_power_limit = + rtlphy->txpwr_limit_2_4g[regulation][bandwidth] + [rate_section][channel_index] + [RF90_PATH_A]; + + if (power_limit < prev_power_limit) + rtlphy->txpwr_limit_2_4g[regulation][bandwidth] + [rate_section][channel_index] + [RF90_PATH_A] = power_limit; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "2.4G [regula %d][bw %d][sec %d][chnl %d][val %d]\n", + regulation, bandwidth, rate_section, channel_index, + rtlphy->txpwr_limit_2_4g[regulation][bandwidth] + [rate_section][channel_index] + [RF90_PATH_A]); + } else if (_rtl8822be_eq_n_byte(pband, (u8 *)("5G"), 2)) { + ret = _rtl8822be_phy_get_chnl_idx_of_txpwr_lmt(hw, BAND_ON_5G, + channel); + + if (ret == -1) + return; + + channel_index = ret; + + prev_power_limit = + rtlphy->txpwr_limit_5g[regulation][bandwidth] + [rate_section][channel_index] + [RF90_PATH_A]; + + if (power_limit < prev_power_limit) + rtlphy->txpwr_limit_5g[regulation][bandwidth] + [rate_section][channel_index] + [RF90_PATH_A] = power_limit; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "5G: [regul %d][bw %d][sec %d][chnl %d][val %d]\n", + regulation, bandwidth, rate_section, channel, + rtlphy->txpwr_limit_5g[regulation][bandwidth] + [rate_section][channel_index] + [RF90_PATH_A]); + + } else { + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "Cannot recognize the band info in %s\n", pband); + return; + } +} + +bool rtl8822be_load_txpower_by_rate(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + bool rtstatus = true; + + _rtl8822be_phy_init_tx_power_by_rate(hw); + + rtstatus = rtlpriv->phydm.ops->phydm_load_txpower_by_rate(rtlpriv); + + if (!rtstatus) { + pr_err("BB_PG Reg Fail!!"); + return false; + } + + _rtl8822be_phy_txpower_by_rate_configuration(hw); + + return true; +} + +bool rtl8822be_load_txpower_limit(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_efuse *rtlefuse = rtl_efuse(rtlpriv); + bool rtstatus = true; + + _rtl8822be_phy_init_txpower_limit(hw); + + if (rtlefuse->eeprom_regulatory == 1) + ; + else + return true; + + rtstatus = rtlpriv->phydm.ops->phydm_load_txpower_limit(rtlpriv); + + if (!rtstatus) { + pr_err("RF TxPwr Limit Fail!!"); + return false; + } + + _rtl8822be_phy_convert_txpower_limit_to_power_index(hw); + + return true; +} + +static void _rtl8822be_get_rate_values_of_tx_power_by_rate( + struct ieee80211_hw *hw, u32 reg_addr, u32 bit_mask, u32 value, + u8 *rate, s8 *pwr_by_rate_val, u8 *rate_num) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 /*index = 0,*/ i = 0; + + switch (reg_addr) { + case 0xE00: /*rTxAGC_A_Rate18_06:*/ + case 0x830: /*rTxAGC_B_Rate18_06:*/ + rate[0] = DESC_RATE6M; + rate[1] = DESC_RATE9M; + rate[2] = DESC_RATE12M; + rate[3] = DESC_RATE18M; + for (i = 0; i < 4; ++i) { + pwr_by_rate_val[i] = + (s8)((((value >> (i * 8 + 4)) & 0xF)) * 10 + + ((value >> (i * 8)) & 0xF)); + } + *rate_num = 4; + break; + + case 0xE04: /*rTxAGC_A_Rate54_24:*/ + case 0x834: /*rTxAGC_B_Rate54_24:*/ + rate[0] = DESC_RATE24M; + rate[1] = DESC_RATE36M; + rate[2] = DESC_RATE48M; + rate[3] = DESC_RATE54M; + for (i = 0; i < 4; ++i) { + pwr_by_rate_val[i] = + (s8)((((value >> (i * 8 + 4)) & 0xF)) * 10 + + ((value >> (i * 8)) & 0xF)); + } + *rate_num = 4; + break; + + case 0xE08: /*rTxAGC_A_CCK1_Mcs32:*/ + rate[0] = DESC_RATE1M; + pwr_by_rate_val[0] = (s8)((((value >> (8 + 4)) & 0xF)) * 10 + + ((value >> 8) & 0xF)); + *rate_num = 1; + break; + + case 0x86C: /*rTxAGC_B_CCK11_A_CCK2_11:*/ + if (bit_mask == 0xffffff00) { + rate[0] = DESC_RATE2M; + rate[1] = DESC_RATE5_5M; + rate[2] = DESC_RATE11M; + for (i = 1; i < 4; ++i) { + pwr_by_rate_val[i - 1] = (s8)( + (((value >> (i * 8 + 4)) & 0xF)) * 10 + + ((value >> (i * 8)) & 0xF)); + } + *rate_num = 3; + } else if (bit_mask == 0x000000ff) { + rate[0] = DESC_RATE11M; + pwr_by_rate_val[0] = (s8)((((value >> 4) & 0xF)) * 10 + + (value & 0xF)); + *rate_num = 1; + } + break; + + case 0xE10: /*rTxAGC_A_Mcs03_Mcs00:*/ + case 0x83C: /*rTxAGC_B_Mcs03_Mcs00:*/ + rate[0] = DESC_RATEMCS0; + rate[1] = DESC_RATEMCS1; + rate[2] = DESC_RATEMCS2; + rate[3] = DESC_RATEMCS3; + for (i = 0; i < 4; ++i) { + pwr_by_rate_val[i] = + (s8)((((value >> (i * 8 + 4)) & 0xF)) * 10 + + ((value >> (i * 8)) & 0xF)); + } + *rate_num = 4; + break; + + case 0xE14: /*rTxAGC_A_Mcs07_Mcs04:*/ + case 0x848: /*rTxAGC_B_Mcs07_Mcs04:*/ + rate[0] = DESC_RATEMCS4; + rate[1] = DESC_RATEMCS5; + rate[2] = DESC_RATEMCS6; + rate[3] = DESC_RATEMCS7; + for (i = 0; i < 4; ++i) { + pwr_by_rate_val[i] = + (s8)((((value >> (i * 8 + 4)) & 0xF)) * 10 + + ((value >> (i * 8)) & 0xF)); + } + *rate_num = 4; + break; + + case 0xE18: /*rTxAGC_A_Mcs11_Mcs08:*/ + case 0x84C: /*rTxAGC_B_Mcs11_Mcs08:*/ + rate[0] = DESC_RATEMCS8; + rate[1] = DESC_RATEMCS9; + rate[2] = DESC_RATEMCS10; + rate[3] = DESC_RATEMCS11; + for (i = 0; i < 4; ++i) { + pwr_by_rate_val[i] = + (s8)((((value >> (i * 8 + 4)) & 0xF)) * 10 + + ((value >> (i * 8)) & 0xF)); + } + *rate_num = 4; + break; + + case 0xE1C: /*rTxAGC_A_Mcs15_Mcs12:*/ + case 0x868: /*rTxAGC_B_Mcs15_Mcs12:*/ + rate[0] = DESC_RATEMCS12; + rate[1] = DESC_RATEMCS13; + rate[2] = DESC_RATEMCS14; + rate[3] = DESC_RATEMCS15; + for (i = 0; i < 4; ++i) { + pwr_by_rate_val[i] = + (s8)((((value >> (i * 8 + 4)) & 0xF)) * 10 + + ((value >> (i * 8)) & 0xF)); + } + *rate_num = 4; + + break; + + case 0x838: /*rTxAGC_B_CCK1_55_Mcs32:*/ + rate[0] = DESC_RATE1M; + rate[1] = DESC_RATE2M; + rate[2] = DESC_RATE5_5M; + for (i = 1; i < 4; ++i) { + pwr_by_rate_val[i - 1] = + (s8)((((value >> (i * 8 + 4)) & 0xF)) * 10 + + ((value >> (i * 8)) & 0xF)); + } + *rate_num = 3; + break; + + case 0xC20: + case 0xE20: + case 0x1820: + case 0x1a20: + rate[0] = DESC_RATE1M; + rate[1] = DESC_RATE2M; + rate[2] = DESC_RATE5_5M; + rate[3] = DESC_RATE11M; + for (i = 0; i < 4; ++i) { + pwr_by_rate_val[i] = + (s8)((((value >> (i * 8 + 4)) & 0xF)) * 10 + + ((value >> (i * 8)) & 0xF)); + } + *rate_num = 4; + break; + + case 0xC24: + case 0xE24: + case 0x1824: + case 0x1a24: + rate[0] = DESC_RATE6M; + rate[1] = DESC_RATE9M; + rate[2] = DESC_RATE12M; + rate[3] = DESC_RATE18M; + for (i = 0; i < 4; ++i) { + pwr_by_rate_val[i] = + (s8)((((value >> (i * 8 + 4)) & 0xF)) * 10 + + ((value >> (i * 8)) & 0xF)); + } + *rate_num = 4; + break; + + case 0xC28: + case 0xE28: + case 0x1828: + case 0x1a28: + rate[0] = DESC_RATE24M; + rate[1] = DESC_RATE36M; + rate[2] = DESC_RATE48M; + rate[3] = DESC_RATE54M; + for (i = 0; i < 4; ++i) { + pwr_by_rate_val[i] = + (s8)((((value >> (i * 8 + 4)) & 0xF)) * 10 + + ((value >> (i * 8)) & 0xF)); + } + *rate_num = 4; + break; + + case 0xC2C: + case 0xE2C: + case 0x182C: + case 0x1a2C: + rate[0] = DESC_RATEMCS0; + rate[1] = DESC_RATEMCS1; + rate[2] = DESC_RATEMCS2; + rate[3] = DESC_RATEMCS3; + for (i = 0; i < 4; ++i) { + pwr_by_rate_val[i] = + (s8)((((value >> (i * 8 + 4)) & 0xF)) * 10 + + ((value >> (i * 8)) & 0xF)); + } + *rate_num = 4; + break; + + case 0xC30: + case 0xE30: + case 0x1830: + case 0x1a30: + rate[0] = DESC_RATEMCS4; + rate[1] = DESC_RATEMCS5; + rate[2] = DESC_RATEMCS6; + rate[3] = DESC_RATEMCS7; + for (i = 0; i < 4; ++i) { + pwr_by_rate_val[i] = + (s8)((((value >> (i * 8 + 4)) & 0xF)) * 10 + + ((value >> (i * 8)) & 0xF)); + } + *rate_num = 4; + break; + + case 0xC34: + case 0xE34: + case 0x1834: + case 0x1a34: + rate[0] = DESC_RATEMCS8; + rate[1] = DESC_RATEMCS9; + rate[2] = DESC_RATEMCS10; + rate[3] = DESC_RATEMCS11; + for (i = 0; i < 4; ++i) { + pwr_by_rate_val[i] = + (s8)((((value >> (i * 8 + 4)) & 0xF)) * 10 + + ((value >> (i * 8)) & 0xF)); + } + *rate_num = 4; + break; + + case 0xC38: + case 0xE38: + case 0x1838: + case 0x1a38: + rate[0] = DESC_RATEMCS12; + rate[1] = DESC_RATEMCS13; + rate[2] = DESC_RATEMCS14; + rate[3] = DESC_RATEMCS15; + for (i = 0; i < 4; ++i) { + pwr_by_rate_val[i] = + (s8)((((value >> (i * 8 + 4)) & 0xF)) * 10 + + ((value >> (i * 8)) & 0xF)); + } + *rate_num = 4; + break; + + case 0xC3C: + case 0xE3C: + case 0x183C: + case 0x1a3C: + rate[0] = DESC_RATEVHT1SS_MCS0; + rate[1] = DESC_RATEVHT1SS_MCS1; + rate[2] = DESC_RATEVHT1SS_MCS2; + rate[3] = DESC_RATEVHT1SS_MCS3; + for (i = 0; i < 4; ++i) { + pwr_by_rate_val[i] = + (s8)((((value >> (i * 8 + 4)) & 0xF)) * 10 + + ((value >> (i * 8)) & 0xF)); + } + *rate_num = 4; + break; + + case 0xC40: + case 0xE40: + case 0x1840: + case 0x1a40: + rate[0] = DESC_RATEVHT1SS_MCS4; + rate[1] = DESC_RATEVHT1SS_MCS5; + rate[2] = DESC_RATEVHT1SS_MCS6; + rate[3] = DESC_RATEVHT1SS_MCS7; + for (i = 0; i < 4; ++i) { + pwr_by_rate_val[i] = + (s8)((((value >> (i * 8 + 4)) & 0xF)) * 10 + + ((value >> (i * 8)) & 0xF)); + } + *rate_num = 4; + break; + + case 0xC44: + case 0xE44: + case 0x1844: + case 0x1a44: + rate[0] = DESC_RATEVHT1SS_MCS8; + rate[1] = DESC_RATEVHT1SS_MCS9; + rate[2] = DESC_RATEVHT2SS_MCS0; + rate[3] = DESC_RATEVHT2SS_MCS1; + for (i = 0; i < 4; ++i) { + pwr_by_rate_val[i] = + (s8)((((value >> (i * 8 + 4)) & 0xF)) * 10 + + ((value >> (i * 8)) & 0xF)); + } + *rate_num = 4; + break; + + case 0xC48: + case 0xE48: + case 0x1848: + case 0x1a48: + rate[0] = DESC_RATEVHT2SS_MCS2; + rate[1] = DESC_RATEVHT2SS_MCS3; + rate[2] = DESC_RATEVHT2SS_MCS4; + rate[3] = DESC_RATEVHT2SS_MCS5; + for (i = 0; i < 4; ++i) { + pwr_by_rate_val[i] = + (s8)((((value >> (i * 8 + 4)) & 0xF)) * 10 + + ((value >> (i * 8)) & 0xF)); + } + *rate_num = 4; + break; + + case 0xC4C: + case 0xE4C: + case 0x184C: + case 0x1a4C: + rate[0] = DESC_RATEVHT2SS_MCS6; + rate[1] = DESC_RATEVHT2SS_MCS7; + rate[2] = DESC_RATEVHT2SS_MCS8; + rate[3] = DESC_RATEVHT2SS_MCS9; + for (i = 0; i < 4; ++i) { + pwr_by_rate_val[i] = + (s8)((((value >> (i * 8 + 4)) & 0xF)) * 10 + + ((value >> (i * 8)) & 0xF)); + } + *rate_num = 4; + break; + + default: + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "Invalid reg_addr 0x%x in %s()\n", reg_addr, __func__); + break; + }; +} + +void rtl8822be_store_tx_power_by_rate(struct ieee80211_hw *hw, u32 band, + u32 rfpath, u32 txnum, u32 regaddr, + u32 bitmask, u32 data) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &rtlpriv->phy; + u8 i = 0, rates[4] = {0}, rate_num = 0; + s8 pwr_by_rate_val[4] = {0}; + + _rtl8822be_get_rate_values_of_tx_power_by_rate( + hw, regaddr, bitmask, data, rates, pwr_by_rate_val, &rate_num); + + if (band != BAND_ON_2_4G && band != BAND_ON_5G) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_WARNING, "Invalid Band %d\n", + band); + band = BAND_ON_2_4G; + } + if (rfpath >= MAX_RF_PATH) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_WARNING, "Invalid RfPath %d\n", + rfpath); + rfpath = MAX_RF_PATH - 1; + } + if (txnum >= MAX_RF_PATH) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_WARNING, "Invalid TxNum %d\n", + txnum); + txnum = MAX_RF_PATH - 1; + } + + for (i = 0; i < rate_num; ++i) { + u8 rate_idx = rates[i]; + + if (IS_1T_RATE(rates[i])) + txnum = RF_1TX; + else if (IS_2T_RATE(rates[i])) + txnum = RF_2TX; + else + WARN_ON(1); + + rtlphy->tx_power_by_rate_offset[band][rfpath][txnum][rate_idx] = + pwr_by_rate_val[i]; + + RT_TRACE( + rtlpriv, COMP_INIT, DBG_LOUD, + "TxPwrByRateOffset[Band %d][RfPath %d][TxNum %d][rate_idx %d] = 0x%x\n", + band, rfpath, txnum, rate_idx, + rtlphy->tx_power_by_rate_offset[band][rfpath][txnum] + [rate_idx]); + } +} + +static void +_rtl8822be_phy_init_bb_rf_register_definition(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &rtlpriv->phy; + + rtlphy->phyreg_def[RF90_PATH_A].rfintfs = RFPGA0_XAB_RFINTERFACESW; + rtlphy->phyreg_def[RF90_PATH_B].rfintfs = RFPGA0_XAB_RFINTERFACESW; + + rtlphy->phyreg_def[RF90_PATH_A].rfintfo = RFPGA0_XA_RFINTERFACEOE; + rtlphy->phyreg_def[RF90_PATH_B].rfintfo = RFPGA0_XB_RFINTERFACEOE; + + rtlphy->phyreg_def[RF90_PATH_A].rfintfe = RFPGA0_XA_RFINTERFACEOE; + rtlphy->phyreg_def[RF90_PATH_B].rfintfe = RFPGA0_XB_RFINTERFACEOE; + + rtlphy->phyreg_def[RF90_PATH_A].rf3wire_offset = RA_LSSIWRITE_8822B; + rtlphy->phyreg_def[RF90_PATH_B].rf3wire_offset = RB_LSSIWRITE_8822B; + + rtlphy->phyreg_def[RF90_PATH_A].rfhssi_para2 = RHSSIREAD_8822BE; + rtlphy->phyreg_def[RF90_PATH_B].rfhssi_para2 = RHSSIREAD_8822BE; + + rtlphy->phyreg_def[RF90_PATH_A].rf_rb = RA_SIREAD_8822B; + rtlphy->phyreg_def[RF90_PATH_B].rf_rb = RB_SIREAD_8822B; + + rtlphy->phyreg_def[RF90_PATH_A].rf_rbpi = RA_PIREAD_8822B; + rtlphy->phyreg_def[RF90_PATH_B].rf_rbpi = RB_PIREAD_8822B; +} + +void rtl8822be_phy_get_txpower_level(struct ieee80211_hw *hw, long *powerlevel) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &rtlpriv->phy; + u8 txpwr_level; + long txpwr_dbm; + + txpwr_level = rtlphy->cur_cck_txpwridx; + txpwr_dbm = _rtl8822be_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_B, + txpwr_level); + txpwr_level = rtlphy->cur_ofdm24g_txpwridx; + if (_rtl8822be_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_G, txpwr_level) > + txpwr_dbm) + txpwr_dbm = _rtl8822be_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_G, + txpwr_level); + txpwr_level = rtlphy->cur_ofdm24g_txpwridx; + if (_rtl8822be_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_N_24G, + txpwr_level) > txpwr_dbm) + txpwr_dbm = _rtl8822be_phy_txpwr_idx_to_dbm( + hw, WIRELESS_MODE_N_24G, txpwr_level); + *powerlevel = txpwr_dbm; +} + +static bool _rtl8822be_phy_get_chnl_index(u8 channel, u8 *chnl_index) +{ + u8 rtl_channel5g[CHANNEL_MAX_NUMBER_5G] = { + 36, 38, 40, 42, 44, 46, 48, /* Band 1 */ + 52, 54, 56, 58, 60, 62, 64, /* Band 2 */ + 100, 102, 104, 106, 108, 110, 112, /* Band 3 */ + 116, 118, 120, 122, 124, 126, 128, /* Band 3 */ + 132, 134, 136, 138, 140, 142, 144, /* Band 3 */ + 149, 151, 153, 155, 157, 159, 161, /* Band 4 */ + 165, 167, 169, 171, 173, 175, 177}; /* Band 4 */ + u8 i = 0; + bool in_24g = true; + + if (channel <= 14) { + in_24g = true; + *chnl_index = channel - 1; + } else { + in_24g = false; + + for (i = 0; i < CHANNEL_MAX_NUMBER_5G; ++i) { + if (rtl_channel5g[i] == channel) { + *chnl_index = i; + return in_24g; + } + } + } + return in_24g; +} + +static char _rtl8822be_phy_get_world_wide_limit(char *limit_table) +{ + char min = limit_table[0]; + u8 i = 0; + + for (i = 0; i < MAX_REGULATION_NUM; ++i) { + if (limit_table[i] < min) + min = limit_table[i]; + } + return min; +} + +static char _rtl8822be_phy_get_txpower_limit(struct ieee80211_hw *hw, u8 band, + enum ht_channel_width bandwidth, + enum radio_path rf_path, u8 rate, + u8 channel) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_efuse *rtlefuse = rtl_efuse(rtlpriv); + struct rtl_phy *rtlphy = &rtlpriv->phy; + short regulation = -1, rate_section = -1, channel_index = -1; + char power_limit = MAX_POWER_INDEX; + + if (rtlefuse->eeprom_regulatory == 2) + return MAX_POWER_INDEX; + + regulation = TXPWR_LMT_WW; + + switch (rate) { + case DESC_RATE1M: + case DESC_RATE2M: + case DESC_RATE5_5M: + case DESC_RATE11M: + rate_section = CCK; + break; + + case DESC_RATE6M: + case DESC_RATE9M: + case DESC_RATE12M: + case DESC_RATE18M: + case DESC_RATE24M: + case DESC_RATE36M: + case DESC_RATE48M: + case DESC_RATE54M: + rate_section = OFDM; + break; + + case DESC_RATEMCS0: + case DESC_RATEMCS1: + case DESC_RATEMCS2: + case DESC_RATEMCS3: + case DESC_RATEMCS4: + case DESC_RATEMCS5: + case DESC_RATEMCS6: + case DESC_RATEMCS7: + rate_section = HT_MCS0_MCS7; + break; + + case DESC_RATEMCS8: + case DESC_RATEMCS9: + case DESC_RATEMCS10: + case DESC_RATEMCS11: + case DESC_RATEMCS12: + case DESC_RATEMCS13: + case DESC_RATEMCS14: + case DESC_RATEMCS15: + rate_section = HT_MCS8_MCS15; + break; + + case DESC_RATEVHT1SS_MCS0: + case DESC_RATEVHT1SS_MCS1: + case DESC_RATEVHT1SS_MCS2: + case DESC_RATEVHT1SS_MCS3: + case DESC_RATEVHT1SS_MCS4: + case DESC_RATEVHT1SS_MCS5: + case DESC_RATEVHT1SS_MCS6: + case DESC_RATEVHT1SS_MCS7: + case DESC_RATEVHT1SS_MCS8: + case DESC_RATEVHT1SS_MCS9: + rate_section = VHT_1SSMCS0_1SSMCS9; + break; + + case DESC_RATEVHT2SS_MCS0: + case DESC_RATEVHT2SS_MCS1: + case DESC_RATEVHT2SS_MCS2: + case DESC_RATEVHT2SS_MCS3: + case DESC_RATEVHT2SS_MCS4: + case DESC_RATEVHT2SS_MCS5: + case DESC_RATEVHT2SS_MCS6: + case DESC_RATEVHT2SS_MCS7: + case DESC_RATEVHT2SS_MCS8: + case DESC_RATEVHT2SS_MCS9: + rate_section = VHT_2SSMCS0_2SSMCS9; + break; + + default: + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "Wrong rate 0x%x\n", + rate); + break; + } + + if (band == BAND_ON_5G && rate_section == 0) + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "Wrong rate 0x%x: No CCK in 5G Band\n", rate); + + /* workaround for wrong index combination to obtain tx power limit, + * OFDM only exists in BW 20M + */ + if (rate_section == 1) + bandwidth = 0; + + /* workaround for wrong index combination to obtain tx power limit, + * CCK table will only be given in BW 20M + */ + if (rate_section == 0) + bandwidth = 0; + + /* workaround for wrong indxe combination to obtain tx power limit, + * HT on 80M will reference to HT on 40M + */ + if ((rate_section == 2 || rate_section == 3) && band == BAND_ON_5G && + bandwidth == 2) + bandwidth = 1; + + if (band == BAND_ON_2_4G) + channel_index = _rtl8822be_phy_get_chnl_idx_of_txpwr_lmt( + hw, BAND_ON_2_4G, channel); + else if (band == BAND_ON_5G) + channel_index = _rtl8822be_phy_get_chnl_idx_of_txpwr_lmt( + hw, BAND_ON_5G, channel); + else if (band == BAND_ON_BOTH) + ; /* BAND_ON_BOTH don't care temporarily */ + + if (band >= BANDMAX || regulation == -1 || bandwidth == -1 || + rate_section == -1 || channel_index == -1) { + RT_TRACE( + rtlpriv, COMP_POWER, DBG_LOUD, + "Wrong index value to access power limit table [band %d][regulation %d][bandwidth %d][rf_path %d][rate_section %d][chnl %d]\n", + band, regulation, bandwidth, rf_path, rate_section, + channel_index); + return MAX_POWER_INDEX; + } + + if (band == BAND_ON_2_4G) { + char limits[10] = {0}; + u8 i = 0; + + for (i = 0; i < 4; ++i) + limits[i] = rtlphy->txpwr_limit_2_4g[i][bandwidth] + [rate_section] + [channel_index] + [rf_path]; + + power_limit = + (regulation == TXPWR_LMT_WW) ? + _rtl8822be_phy_get_world_wide_limit(limits) : + rtlphy->txpwr_limit_2_4g[regulation][bandwidth] + [rate_section] + [channel_index] + [rf_path]; + + } else if (band == BAND_ON_5G) { + char limits[10] = {0}; + u8 i = 0; + + for (i = 0; i < MAX_REGULATION_NUM; ++i) + limits[i] = + rtlphy->txpwr_limit_5g[i][bandwidth] + [rate_section] + [channel_index][rf_path]; + + power_limit = + (regulation == TXPWR_LMT_WW) ? + _rtl8822be_phy_get_world_wide_limit(limits) : + rtlphy->txpwr_limit_5g[regulation] + [channel_index] + [rate_section] + [channel_index][rf_path]; + } else + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "No power limit table of the specified band\n"); + + return power_limit; +} + +static char +_rtl8822be_phy_get_txpower_by_rate(struct ieee80211_hw *hw, u8 band, u8 path, + u8 rate /* enum rtl_desc8822b_rate */) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &rtlpriv->phy; + u8 tx_num; + char tx_pwr_diff = 0; + + if (band != BAND_ON_2_4G && band != BAND_ON_5G) + return tx_pwr_diff; + + if (path > RF90_PATH_B) + return tx_pwr_diff; + + if ((rate >= DESC_RATEMCS8 && rate <= DESC_RATEMCS15) || + (rate >= DESC_RATEVHT2SS_MCS0 && rate <= DESC_RATEVHT2SS_MCS9)) + tx_num = RF_2TX; + else + tx_num = RF_1TX; + + tx_pwr_diff = (char)(rtlphy->tx_power_by_rate_offset[band][path][tx_num] + [rate] & + 0xff); + + return tx_pwr_diff; +} + +u8 rtl8822be_get_txpower_index(struct ieee80211_hw *hw, u8 path, u8 rate, + u8 bandwidth, u8 channel) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u8 index = (channel - 1); + u8 txpower = 0; + bool in_24g = false; + char limit; + char powerdiff_byrate = 0; + + if (((rtlhal->current_bandtype == BAND_ON_2_4G) && + (channel > 14 || channel < 1)) || + ((rtlhal->current_bandtype == BAND_ON_5G) && (channel <= 14))) { + index = 0; + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + "Illegal channel!!\n"); + } + + /* 1. base tx power */ + in_24g = _rtl8822be_phy_get_chnl_index(channel, &index); + if (in_24g) { + if (RX_HAL_IS_CCK_RATE(rate)) + txpower = rtlefuse->txpwrlevel_cck[path][index]; + else if (rate >= DESC_RATE6M) + txpower = rtlefuse->txpwrlevel_ht40_1s[path][index]; + else + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + "invalid rate\n"); + + if (rate >= DESC_RATE6M && rate <= DESC_RATE54M && + !RX_HAL_IS_CCK_RATE(rate)) + txpower += rtlefuse->txpwr_legacyhtdiff[path][TX_1S]; + + if (bandwidth == HT_CHANNEL_WIDTH_20) { + if ((rate >= DESC_RATEMCS0 && rate <= DESC_RATEMCS15) || + (rate >= DESC_RATEVHT1SS_MCS0 && + rate <= DESC_RATEVHT2SS_MCS9)) + txpower += + rtlefuse->txpwr_ht20diff[path][TX_1S]; + if ((rate >= DESC_RATEMCS8 && rate <= DESC_RATEMCS15) || + (rate >= DESC_RATEVHT2SS_MCS0 && + rate <= DESC_RATEVHT2SS_MCS9)) + txpower += + rtlefuse->txpwr_ht20diff[path][TX_2S]; + } else if (bandwidth == HT_CHANNEL_WIDTH_20_40) { + if ((rate >= DESC_RATEMCS0 && rate <= DESC_RATEMCS15) || + (rate >= DESC_RATEVHT1SS_MCS0 && + rate <= DESC_RATEVHT2SS_MCS9)) + txpower += + rtlefuse->txpwr_ht40diff[path][TX_1S]; + if ((rate >= DESC_RATEMCS8 && rate <= DESC_RATEMCS15) || + (rate >= DESC_RATEVHT2SS_MCS0 && + rate <= DESC_RATEVHT2SS_MCS9)) + txpower += + rtlefuse->txpwr_ht40diff[path][TX_2S]; + } else if (bandwidth == HT_CHANNEL_WIDTH_80) { + if ((rate >= DESC_RATEMCS0 && rate <= DESC_RATEMCS15) || + (rate >= DESC_RATEVHT1SS_MCS0 && + rate <= DESC_RATEVHT2SS_MCS9)) + txpower += + rtlefuse->txpwr_ht40diff[path][TX_1S]; + if ((rate >= DESC_RATEMCS8 && rate <= DESC_RATEMCS15) || + (rate >= DESC_RATEVHT2SS_MCS0 && + rate <= DESC_RATEVHT2SS_MCS9)) + txpower += + rtlefuse->txpwr_ht40diff[path][TX_2S]; + } + + } else { + if (rate >= DESC_RATE6M) + txpower = rtlefuse->txpwr_5g_bw40base[path][index]; + else + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_WARNING, + "INVALID Rate.\n"); + + if (rate >= DESC_RATE6M && rate <= DESC_RATE54M && + !RX_HAL_IS_CCK_RATE(rate)) + txpower += rtlefuse->txpwr_5g_ofdmdiff[path][TX_1S]; + + if (bandwidth == HT_CHANNEL_WIDTH_20) { + if ((rate >= DESC_RATEMCS0 && rate <= DESC_RATEMCS15) || + (rate >= DESC_RATEVHT1SS_MCS0 && + rate <= DESC_RATEVHT2SS_MCS9)) + txpower += rtlefuse->txpwr_5g_bw20diff[path] + [TX_1S]; + if ((rate >= DESC_RATEMCS8 && rate <= DESC_RATEMCS15) || + (rate >= DESC_RATEVHT2SS_MCS0 && + rate <= DESC_RATEVHT2SS_MCS9)) + txpower += rtlefuse->txpwr_5g_bw20diff[path] + [TX_2S]; + } else if (bandwidth == HT_CHANNEL_WIDTH_20_40) { + if ((rate >= DESC_RATEMCS0 && rate <= DESC_RATEMCS15) || + (rate >= DESC_RATEVHT1SS_MCS0 && + rate <= DESC_RATEVHT2SS_MCS9)) + txpower += rtlefuse->txpwr_5g_bw40diff[path] + [TX_1S]; + if ((rate >= DESC_RATEMCS8 && rate <= DESC_RATEMCS15) || + (rate >= DESC_RATEVHT2SS_MCS0 && + rate <= DESC_RATEVHT2SS_MCS9)) + txpower += rtlefuse->txpwr_5g_bw40diff[path] + [TX_2S]; + } else if (bandwidth == HT_CHANNEL_WIDTH_80) { + u8 i = 0; + + for (i = 0; i < sizeof(rtl_channel5g_80m) / sizeof(u8); + ++i) + if (rtl_channel5g_80m[i] == channel) + index = i; + + txpower = rtlefuse->txpwr_5g_bw80base[path][index]; + + if ((rate >= DESC_RATEMCS0 && rate <= DESC_RATEMCS15) || + (rate >= DESC_RATEVHT1SS_MCS0 && + rate <= DESC_RATEVHT2SS_MCS9)) + txpower += rtlefuse->txpwr_5g_bw80diff[path] + [TX_1S]; + if ((rate >= DESC_RATEMCS8 && rate <= DESC_RATEMCS15) || + (rate >= DESC_RATEVHT2SS_MCS0 && + rate <= DESC_RATEVHT2SS_MCS9)) + txpower += rtlefuse->txpwr_5g_bw80diff[path] + [TX_2S]; + } + } + + /* 2. tx power by rate */ + if (rtlefuse->eeprom_regulatory != 2) + powerdiff_byrate = _rtl8822be_phy_get_txpower_by_rate( + hw, (u8)(!in_24g), path, rate); + + /* 3. tx power limit */ + if (rtlefuse->eeprom_regulatory == 1) + limit = _rtl8822be_phy_get_txpower_limit( + hw, (u8)(!in_24g), bandwidth, path, rate, + channel); + else + limit = MAX_POWER_INDEX; + + /* ----- */ + powerdiff_byrate = powerdiff_byrate > limit ? limit : powerdiff_byrate; + + txpower += powerdiff_byrate; + + if (txpower > MAX_POWER_INDEX) + txpower = MAX_POWER_INDEX; + + return txpower; +} + +static void _rtl8822be_phy_set_txpower_index(struct ieee80211_hw *hw, + u8 power_index, u8 path, u8 rate) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 shift = 0; + static u32 index; + + /* + * For 8822B, phydm api use 4 bytes txagc value + * driver must combine every four 1 byte to one 4 byte and send to phydm + */ + shift = rate & 0x03; + index |= ((u32)power_index << (shift * 8)); + + if (shift == 3) { + rate = rate - 3; + + if (!rtlpriv->phydm.ops->phydm_write_txagc(rtlpriv, index, path, + rate)) { + RT_TRACE(rtlpriv, COMP_TXAGC, DBG_LOUD, + "%s(index:%d, rfpath:%d, rate:0x%02x) fail\n", + __func__, index, path, rate); + + WARN_ON(1); + } + index = 0; + } +} + +static void _rtl8822be_phy_set_txpower_level_by_path(struct ieee80211_hw *hw, + u8 *array, u8 path, + u8 channel, u8 size) +{ + struct rtl_phy *rtlphy = &(rtl_priv(hw)->phy); + u8 i; + u8 power_index; + + for (i = 0; i < size; i++) { + power_index = rtl8822be_get_txpower_index( + hw, path, array[i], rtlphy->current_chan_bw, channel); + _rtl8822be_phy_set_txpower_index(hw, power_index, path, + array[i]); + } +} + +void rtl8822be_phy_set_txpower_level_by_path(struct ieee80211_hw *hw, + u8 channel, u8 path) +{ + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + + /* + * Below order is *VERY* important! + * Because _rtl8822be_phy_set_txpower_index() do actually writing + * every four power values. + */ + if (rtlhal->current_bandtype == BAND_ON_2_4G) + _rtl8822be_phy_set_txpower_level_by_path( + hw, cck_rates, path, channel, sizes_of_cck_retes); + _rtl8822be_phy_set_txpower_level_by_path(hw, ofdm_rates, path, channel, + sizes_of_ofdm_retes); + _rtl8822be_phy_set_txpower_level_by_path(hw, ht_rates_1t, path, channel, + sizes_of_ht_retes_1t); + _rtl8822be_phy_set_txpower_level_by_path(hw, ht_rates_2t, path, channel, + sizes_of_ht_retes_2t); + _rtl8822be_phy_set_txpower_level_by_path(hw, vht_rates_1t, path, + channel, sizes_of_vht_retes); + _rtl8822be_phy_set_txpower_level_by_path(hw, vht_rates_2t, path, + channel, sizes_of_vht_retes); +} + +void rtl8822be_phy_set_tx_power_index_by_rs(struct ieee80211_hw *hw, u8 channel, + u8 path, enum rate_section rs) +{ + struct { + u8 *array; + u8 size; + } rs_ref[MAX_RATE_SECTION] = { + {cck_rates, sizes_of_cck_retes}, + {ofdm_rates, sizes_of_ofdm_retes}, + {ht_rates_1t, sizes_of_ht_retes_1t}, + {ht_rates_2t, sizes_of_ht_retes_2t}, + {vht_rates_1t, sizes_of_vht_retes}, + {vht_rates_2t, sizes_of_vht_retes}, + }; + + if (rs >= MAX_RATE_SECTION) + return; + + _rtl8822be_phy_set_txpower_level_by_path(hw, rs_ref[rs].array, path, + channel, rs_ref[rs].size); +} + +void rtl8822be_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &rtlpriv->phy; + u8 path = 0; + + for (path = RF90_PATH_A; path < rtlphy->num_total_rfpath; ++path) + rtl8822be_phy_set_txpower_level_by_path(hw, channel, path); +} + +static long _rtl8822be_phy_txpwr_idx_to_dbm(struct ieee80211_hw *hw, + enum wireless_mode wirelessmode, + u8 txpwridx) +{ + long offset; + long pwrout_dbm; + + switch (wirelessmode) { + case WIRELESS_MODE_B: + offset = -7; + break; + case WIRELESS_MODE_G: + case WIRELESS_MODE_N_24G: + offset = -8; + break; + default: + offset = -8; + break; + } + pwrout_dbm = txpwridx / 2 + offset; + return pwrout_dbm; +} + +void rtl8822be_phy_scan_operation_backup(struct ieee80211_hw *hw, u8 operation) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + enum io_type iotype = IO_CMD_PAUSE_BAND0_DM_BY_SCAN; + + if (!is_hal_stop(rtlhal)) { + switch (operation) { + case SCAN_OPT_BACKUP_BAND0: + iotype = IO_CMD_PAUSE_BAND0_DM_BY_SCAN; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_IO_CMD, + (u8 *)&iotype); + + break; + case SCAN_OPT_BACKUP_BAND1: + iotype = IO_CMD_PAUSE_BAND1_DM_BY_SCAN; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_IO_CMD, + (u8 *)&iotype); + + break; + case SCAN_OPT_RESTORE: + iotype = IO_CMD_RESUME_DM_BY_SCAN; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_IO_CMD, + (u8 *)&iotype); + break; + default: + pr_err("Unknown Scan Backup operation.\n"); + break; + } + } +} + +static u8 _rtl8822be_phy_get_pri_ch_id(struct rtl_priv *rtlpriv) +{ + struct rtl_phy *rtlphy = &rtlpriv->phy; + struct rtl_mac *mac = rtl_mac(rtlpriv); + u8 pri_ch_idx = 0; + + if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_80) { + /* primary channel is at lower subband of 80MHz & 40MHz */ + if ((mac->cur_40_prime_sc == HAL_PRIME_CHNL_OFFSET_LOWER) && + (mac->cur_80_prime_sc == HAL_PRIME_CHNL_OFFSET_LOWER)) { + pri_ch_idx = VHT_DATA_SC_20_LOWEST_OF_80MHZ; + /* primary channel is at + * lower subband of 80MHz & upper subband of 40MHz + */ + } else if ((mac->cur_40_prime_sc == + HAL_PRIME_CHNL_OFFSET_UPPER) && + (mac->cur_80_prime_sc == + HAL_PRIME_CHNL_OFFSET_LOWER)) { + pri_ch_idx = VHT_DATA_SC_20_LOWER_OF_80MHZ; + /* primary channel is at + * upper subband of 80MHz & lower subband of 40MHz + */ + } else if ((mac->cur_40_prime_sc == + HAL_PRIME_CHNL_OFFSET_LOWER) && + (mac->cur_80_prime_sc == + HAL_PRIME_CHNL_OFFSET_UPPER)) { + pri_ch_idx = VHT_DATA_SC_20_UPPER_OF_80MHZ; + /* primary channel is at + * upper subband of 80MHz & upper subband of 40MHz + */ + } else if ((mac->cur_40_prime_sc == + HAL_PRIME_CHNL_OFFSET_UPPER) && + (mac->cur_80_prime_sc == + HAL_PRIME_CHNL_OFFSET_UPPER)) { + pri_ch_idx = VHT_DATA_SC_20_UPPERST_OF_80MHZ; + } else { + if (mac->cur_80_prime_sc == HAL_PRIME_CHNL_OFFSET_LOWER) + pri_ch_idx = VHT_DATA_SC_40_LOWER_OF_80MHZ; + else if (mac->cur_80_prime_sc == + HAL_PRIME_CHNL_OFFSET_UPPER) + pri_ch_idx = VHT_DATA_SC_40_UPPER_OF_80MHZ; + } + } else if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) { + /* primary channel is at upper subband of 40MHz */ + if (mac->cur_40_prime_sc == HAL_PRIME_CHNL_OFFSET_UPPER) + pri_ch_idx = VHT_DATA_SC_20_UPPER_OF_80MHZ; + /* primary channel is at lower subband of 40MHz */ + else if (mac->cur_40_prime_sc == HAL_PRIME_CHNL_OFFSET_LOWER) + pri_ch_idx = VHT_DATA_SC_20_LOWER_OF_80MHZ; + else + ; + } + + return pri_ch_idx; +} + +void rtl8822be_phy_set_bw_mode(struct ieee80211_hw *hw, + enum nl80211_channel_type ch_type) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &rtlpriv->phy; + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + u8 tmp_bw = rtlphy->current_chan_bw; + + if (rtlphy->set_bwmode_inprogress) + return; + rtlphy->set_bwmode_inprogress = true; + if ((!is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) { + /* get primary channel index */ + u8 pri_ch_idx = _rtl8822be_phy_get_pri_ch_id(rtlpriv); + + /* 3.1 set MAC register */ + rtlpriv->halmac.ops->halmac_set_bandwidth( + rtlpriv, rtlphy->current_channel, pri_ch_idx, + rtlphy->current_chan_bw); + + /* 3.2 set BB/RF registet */ + rtlpriv->phydm.ops->phydm_switch_bandwidth( + rtlpriv, pri_ch_idx, rtlphy->current_chan_bw); + + if (!mac->act_scanning) + rtlpriv->phydm.ops->phydm_iq_calibrate(rtlpriv); + + rtlphy->set_bwmode_inprogress = false; + } else { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "FALSE driver sleep or unload\n"); + rtlphy->set_bwmode_inprogress = false; + rtlphy->current_chan_bw = tmp_bw; + } +} + +u8 rtl8822be_phy_sw_chnl(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &rtlpriv->phy; + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + u32 timeout = 1000, timecount = 0; + u8 channel = rtlphy->current_channel; + + if (rtlphy->sw_chnl_inprogress) + return 0; + if (rtlphy->set_bwmode_inprogress) + return 0; + + if ((is_hal_stop(rtlhal)) || (RT_CANNOT_IO(hw))) { + RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD, + "sw_chnl_inprogress false driver sleep or unload\n"); + return 0; + } + while (rtlphy->lck_inprogress && timecount < timeout) { + mdelay(50); + timecount += 50; + } + + if (rtlphy->current_channel > 14) + rtlhal->current_bandtype = BAND_ON_5G; + else if (rtlphy->current_channel <= 14) + rtlhal->current_bandtype = BAND_ON_2_4G; + + if (rtlpriv->cfg->ops->get_btc_status()) + rtlpriv->btcoexist.btc_ops->btc_switch_band_notify( + rtlpriv, rtlhal->current_bandtype, mac->act_scanning); + else + rtlpriv->btcoexist.btc_ops->btc_switch_band_notify_wifi_only( + rtlpriv, rtlhal->current_bandtype, mac->act_scanning); + + rtlpriv->phydm.ops->phydm_switch_band(rtlpriv, rtlphy->current_channel); + + rtlphy->sw_chnl_inprogress = true; + if (channel == 0) + channel = 1; + + RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, + "switch to channel%d, band type is %d\n", + rtlphy->current_channel, rtlhal->current_bandtype); + + rtlpriv->phydm.ops->phydm_switch_channel(rtlpriv, + rtlphy->current_channel); + + rtlpriv->phydm.ops->phydm_clear_txpowertracking_state(rtlpriv); + + rtl8822be_phy_set_txpower_level(hw, rtlphy->current_channel); + + RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, "\n"); + rtlphy->sw_chnl_inprogress = false; + return 1; +} + +bool rtl8822be_phy_set_io_cmd(struct ieee80211_hw *hw, enum io_type iotype) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &rtlpriv->phy; + bool postprocessing = false; + + RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE, + "-->IO Cmd(%#x), set_io_inprogress(%d)\n", iotype, + rtlphy->set_io_inprogress); + do { + switch (iotype) { + case IO_CMD_RESUME_DM_BY_SCAN: + RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE, + "[IO CMD] Resume DM after scan.\n"); + postprocessing = true; + break; + case IO_CMD_PAUSE_BAND0_DM_BY_SCAN: + case IO_CMD_PAUSE_BAND1_DM_BY_SCAN: + RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE, + "[IO CMD] Pause DM before scan.\n"); + postprocessing = true; + break; + default: + pr_err("switch case not process\n"); + break; + } + } while (false); + if (postprocessing && !rtlphy->set_io_inprogress) { + rtlphy->set_io_inprogress = true; + rtlphy->current_io_type = iotype; + } else { + return false; + } + rtl8822be_phy_set_io(hw); + RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE, "IO Type(%#x)\n", iotype); + return true; +} + +static void rtl8822be_phy_set_io(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &rtlpriv->phy; + + RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE, + "--->Cmd(%#x), set_io_inprogress(%d)\n", + rtlphy->current_io_type, rtlphy->set_io_inprogress); + switch (rtlphy->current_io_type) { + case IO_CMD_RESUME_DM_BY_SCAN: + break; + case IO_CMD_PAUSE_BAND0_DM_BY_SCAN: + break; + case IO_CMD_PAUSE_BAND1_DM_BY_SCAN: + break; + default: + pr_err("switch case not process\n"); + break; + } + rtlphy->set_io_inprogress = false; + RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE, "(%#x)\n", + rtlphy->current_io_type); +} + +static void rtl8822be_phy_set_rf_on(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtl_write_byte(rtlpriv, REG_SPS0_CTRL_8822B, 0x2b); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN_8822B, 0xE3); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN_8822B, 0xE2); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN_8822B, 0xE3); + rtl_write_byte(rtlpriv, REG_TXPAUSE_8822B, 0x00); +} + +static bool _rtl8822be_phy_set_rf_power_state(struct ieee80211_hw *hw, + enum rf_pwrstate rfpwr_state) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + bool bresult = true; + u8 i, queue_id; + struct rtl8192_tx_ring *ring = NULL; + + switch (rfpwr_state) { + case ERFON: + if ((ppsc->rfpwr_state == ERFOFF) && + RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC)) { + bool rtstatus = false; + u32 initialize_count = 0; + + do { + initialize_count++; + RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, + "IPS Set eRf nic enable\n"); + rtstatus = rtl_ps_enable_nic(hw); + } while ((!rtstatus) && (initialize_count < 10)); + RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); + } else { + RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, + "Set ERFON slept:%d ms\n", + jiffies_to_msecs(jiffies - + ppsc->last_sleep_jiffies)); + ppsc->last_awake_jiffies = jiffies; + rtl8822be_phy_set_rf_on(hw); + } + if (mac->link_state == MAC80211_LINKED) + rtlpriv->cfg->ops->led_control(hw, LED_CTL_LINK); + else + rtlpriv->cfg->ops->led_control(hw, LED_CTL_NO_LINK); + break; + case ERFOFF: + for (queue_id = 0, i = 0; + queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) { + ring = &pcipriv->dev.tx_ring[queue_id]; + if (queue_id == BEACON_QUEUE || + skb_queue_len(&ring->queue) == 0) { + queue_id++; + continue; + } else { + RT_TRACE( + rtlpriv, COMP_ERR, DBG_WARNING, + "eRf Off/Sleep: %d times TcbBusyQueue[%d] =%d before doze!\n", + (i + 1), queue_id, + skb_queue_len(&ring->queue)); + + udelay(10); + i++; + } + if (i >= MAX_DOZE_WAITING_TIMES_9x) { + RT_TRACE( + rtlpriv, COMP_ERR, DBG_WARNING, + "\n ERFSLEEP: %d times TcbBusyQueue[%d] = %d !\n", + MAX_DOZE_WAITING_TIMES_9x, queue_id, + skb_queue_len(&ring->queue)); + break; + } + } + + if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC) { + RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, + "IPS Set eRf nic disable\n"); + rtl_ps_disable_nic(hw); + RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); + } else { + if (ppsc->rfoff_reason == RF_CHANGE_BY_IPS) { + rtlpriv->cfg->ops->led_control(hw, + LED_CTL_NO_LINK); + } else { + rtlpriv->cfg->ops->led_control( + hw, LED_CTL_POWER_OFF); + } + } + break; + default: + pr_err("switch case not process\n"); + bresult = false; + break; + } + if (bresult) + ppsc->rfpwr_state = rfpwr_state; + return bresult; +} + +bool rtl8822be_phy_set_rf_power_state(struct ieee80211_hw *hw, + enum rf_pwrstate rfpwr_state) +{ + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + + bool bresult = false; + + if (rfpwr_state == ppsc->rfpwr_state) + return bresult; + bresult = _rtl8822be_phy_set_rf_power_state(hw, rfpwr_state); + return bresult; +} diff --git a/drivers/staging/rtlwifi/rtl8822be/phy.h b/drivers/staging/rtlwifi/rtl8822be/phy.h new file mode 100644 index 000000000000..5c33f16bcaa4 --- /dev/null +++ b/drivers/staging/rtlwifi/rtl8822be/phy.h @@ -0,0 +1,145 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL8822BE_PHY_H__ +#define __RTL8822BE_PHY_H__ + +/* It must always set to 4, otherwise read + * efuse table sequence will be wrong. + */ +#define MAX_TX_COUNT 4 +#define TX_1S 0 +#define TX_2S 1 +#define TX_3S 2 +#define TX_4S 3 + +#define MAX_POWER_INDEX 0x3F + +#define MAX_PRECMD_CNT 16 +#define MAX_RFDEPENDCMD_CNT 16 +#define MAX_POSTCMD_CNT 16 + +#define MAX_DOZE_WAITING_TIMES_9x 64 + +#define RT_CANNOT_IO(hw) false +#define HIGHPOWER_RADIOA_ARRAYLEN 22 + +#define IQK_ADDA_REG_NUM 16 +#define IQK_BB_REG_NUM 9 +#define MAX_TOLERANCE 5 +#define IQK_DELAY_TIME 10 +#define index_mapping_NUM 15 + +#define APK_BB_REG_NUM 5 +#define APK_AFE_REG_NUM 16 +#define APK_CURVE_REG_NUM 4 +#define PATH_NUM 2 + +#define LOOP_LIMIT 5 +#define MAX_STALL_TIME 50 +#define ANTENNA_DIVERSITY_VALUE 0x80 +#define MAX_TXPWR_IDX_NMODE_92S 63 +#define RESET_CNT_LIMIT 3 + +#define IQK_ADDA_REG_NUM 16 +#define IQK_MAC_REG_NUM 4 + +#define RF6052_MAX_PATH 2 + +#define CT_OFFSET_MAC_ADDR 0X16 + +#define CT_OFFSET_CCK_TX_PWR_IDX 0x5A +#define CT_OFFSET_HT401S_TX_PWR_IDX 0x60 +#define CT_OFFSET_HT402S_TX_PWR_IDX_DIFF 0x66 +#define CT_OFFSET_HT20_TX_PWR_IDX_DIFF 0x69 +#define CT_OFFSET_OFDM_TX_PWR_IDX_DIFF 0x6C + +#define CT_OFFSET_HT40_MAX_PWR_OFFSET 0x6F +#define CT_OFFSET_HT20_MAX_PWR_OFFSET 0x72 + +#define CT_OFFSET_CHANNEL_PLAH 0x75 +#define CT_OFFSET_THERMAL_METER 0x78 +#define CT_OFFSET_RF_OPTION 0x79 +#define CT_OFFSET_VERSION 0x7E +#define CT_OFFSET_CUSTOMER_ID 0x7F + +#define RTL8822BE_MAX_PATH_NUM 2 + +#define TARGET_CHNL_NUM_2G_5G_8822B 59 + +u32 rtl8822be_phy_query_bb_reg(struct ieee80211_hw *hw, u32 regaddr, + u32 bitmask); +void rtl8822be_phy_set_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask, + u32 data); +u32 rtl8822be_phy_query_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath, + u32 regaddr, u32 bitmask); +void rtl8822be_phy_set_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath, + u32 regaddr, u32 bitmask, u32 data); +bool rtl8822be_phy_bb_config(struct ieee80211_hw *hw); +bool rtl8822be_phy_rf_config(struct ieee80211_hw *hw); +bool rtl8822be_halmac_cb_init_mac_register(struct rtl_priv *rtlpriv); +bool rtl8822be_halmac_cb_init_bb_rf_register(struct rtl_priv *rtlpriv); +void rtl8822be_phy_get_txpower_level(struct ieee80211_hw *hw, long *powerlevel); +void rtl8822be_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel); +void rtl8822be_phy_scan_operation_backup(struct ieee80211_hw *hw, u8 operation); +void rtl8822be_phy_set_bw_mode_callback(struct ieee80211_hw *hw); +void rtl8822be_phy_set_bw_mode(struct ieee80211_hw *hw, + enum nl80211_channel_type ch_type); +u8 rtl8822be_phy_sw_chnl(struct ieee80211_hw *hw); +void rtl8822be_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery); +void rtl8822be_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery); +void rtl8822be_phy_ap_calibrate(struct ieee80211_hw *hw, char delta); +void rtl8822be_phy_lc_calibrate(struct ieee80211_hw *hw); +void rtl8822be_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain); +bool rtl8822be_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, + enum radio_path rfpath); +bool rtl8822be_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, + enum radio_path rfpath); +bool rtl8822be_phy_set_io_cmd(struct ieee80211_hw *hw, enum io_type iotype); +bool rtl8822be_phy_set_rf_power_state(struct ieee80211_hw *hw, + enum rf_pwrstate rfpwr_state); +void rtl8822be_phy_set_txpower_level_by_path(struct ieee80211_hw *hw, + u8 channel, u8 path); +void rtl8822be_do_iqk(struct ieee80211_hw *hw, u8 delta_thermal_index, + u8 thermal_value, u8 threshold); +void rtl8822be_do_iqk(struct ieee80211_hw *hw, u8 delta_thermal_index, + u8 thermal_value, u8 threshold); +void rtl8822be_reset_iqk_result(struct ieee80211_hw *hw); + +u8 rtl8822be_get_txpower_index(struct ieee80211_hw *hw, u8 path, u8 rate, + u8 bandwidth, u8 channel); +void rtl8822be_phy_set_tx_power_index_by_rs(struct ieee80211_hw *hw, u8 channel, + u8 path, enum rate_section rs); +void rtl8822be_store_tx_power_by_rate(struct ieee80211_hw *hw, u32 band, + u32 rfpath, u32 txnum, u32 regaddr, + u32 bitmask, u32 data); +void rtl8822be_phy_set_txpower_limit(struct ieee80211_hw *hw, u8 *pregulation, + u8 *pband, u8 *pbandwidth, + u8 *prate_section, u8 *prf_path, + u8 *pchannel, u8 *ppower_limit); +bool rtl8822be_load_txpower_by_rate(struct ieee80211_hw *hw); +bool rtl8822be_load_txpower_limit(struct ieee80211_hw *hw); + +#endif diff --git a/drivers/staging/rtlwifi/rtl8822be/reg.h b/drivers/staging/rtlwifi/rtl8822be/reg.h new file mode 100644 index 000000000000..0dca5dccf49a --- /dev/null +++ b/drivers/staging/rtlwifi/rtl8822be/reg.h @@ -0,0 +1,1653 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL8822B_REG_H__ +#define __RTL8822B_REG_H__ + +#include "../halmac/halmac_reg_8822b.h" +#include "../halmac/halmac_bit_8822b.h" + +#define TXPKT_BUF_SELECT 0x69 +#define RXPKT_BUF_SELECT 0xA5 +#define DISABLE_TRXPKT_BUF_ACCESS 0x0 + +/* Page 0 */ +#define REG_LEDCFG2_8822B 0x004E /* need review */ +#define REG_SPS0_CTRL_8822B 0x0011 /* need review: swlps */ + +#define REG_EFUSE_ACCESS_8822B (REG_PMC_DBG_CTRL2_8822B + 3) /*0x00CF*/ +#define REG_AFE_XTAL_CTRL_8822B REG_AFE_CTRL1_8822B +#define REG_AFE_PLL_CTRL_8822B REG_AFE_CTRL2_8822B + +/* Page 1 */ + +#define MSR (REG_CR_8822B + 2) + +/* for MSR 0x102 */ +#define MSR_NOLINK 0x00 +#define MSR_ADHOC 0x01 +#define MSR_INFRA 0x02 +#define MSR_AP 0x03 + +/*----------------------------------------------------- + * + * 0x0200h ~ 0x027Fh TXDMA Configuration + * + *----------------------------------------------------- + */ + +/*----------------------------------------------------- + * + * 0x0280h ~ 0x02FFh RXDMA Configuration + * + *----------------------------------------------------- + */ +#define REG_RXDMA_CONTROL_8822B (REG_RXPKT_NUM_8822B + 2) /* 0x0286 */ + +/*----------------------------------------------------- + * + * 0x0300h ~ 0x03FFh PCIe + * + *----------------------------------------------------- + */ + +/* REG_HIMR3_8822B */ +#define IMR_H2CDOK BIT_SETH2CDOK_MASK_8822B + +/* spec version 11 + *----------------------------------------------------- + * + * 0x0400h ~ 0x047Fh Protocol Configuration + * + *----------------------------------------------------- + */ + +#define REG_MAX_AGGR_NUM_8822B (REG_PROT_MODE_CTRL_8822B + 2) /*0x04CA*/ + +/* for RRSR 0x440 */ +#define RRSR_RSC_OFFSET 21 +#define RRSR_SHORT_OFFSET 23 +#define RRSR_RSC_BW_40M 0x600000 +#define RRSR_RSC_UPSUBCHNL 0x400000 +#define RRSR_RSC_LOWSUBCHNL 0x200000 +#define RRSR_1M BIT(0) +#define RRSR_2M BIT(1) +#define RRSR_5_5M BIT(2) +#define RRSR_11M BIT(3) +#define RRSR_6M BIT(4) +#define RRSR_9M BIT(5) +#define RRSR_12M BIT(6) +#define RRSR_18M BIT(7) +#define RRSR_24M BIT(8) +#define RRSR_36M BIT(9) +#define RRSR_48M BIT(10) +#define RRSR_54M BIT(11) +#define RRSR_MCS0 BIT(12) +#define RRSR_MCS1 BIT(13) +#define RRSR_MCS2 BIT(14) +#define RRSR_MCS3 BIT(15) +#define RRSR_MCS4 BIT(16) +#define RRSR_MCS5 BIT(17) +#define RRSR_MCS6 BIT(18) +#define RRSR_MCS7 BIT(19) + +#define RRSR_ALL_CCK (RRSR_1M | RRSR_2M | RRSR_5_5M | RRSR_11M) +#define RRSR_ALL_OFDM_AG \ + (RRSR_6M | RRSR_9M | RRSR_12M | RRSR_18M | RRSR_24M | RRSR_36M | \ + RRSR_48M | RRSR_54M) + +/*----------------------------------------------------- + * + * 0x0500h ~ 0x05FFh EDCA Configuration + * + *----------------------------------------------------- + */ + +#define REG_SIFS_TRX_8822B (REG_SIFS_8822B + 2) /*0x0516*/ + +/*----------------------------------------------------- + * + * 0x0600h ~ 0x07FFh WMAC Configuration + * + *----------------------------------------------------- + */ + +#define RATR_1M 0x00000001 +#define RATR_2M 0x00000002 +#define RATR_55M 0x00000004 +#define RATR_11M 0x00000008 +#define RATR_6M 0x00000010 +#define RATR_9M 0x00000020 +#define RATR_12M 0x00000040 +#define RATR_18M 0x00000080 +#define RATR_24M 0x00000100 +#define RATR_36M 0x00000200 +#define RATR_48M 0x00000400 +#define RATR_54M 0x00000800 +#define RATR_MCS0 0x00001000 +#define RATR_MCS1 0x00002000 +#define RATR_MCS2 0x00004000 +#define RATR_MCS3 0x00008000 +#define RATR_MCS4 0x00010000 +#define RATR_MCS5 0x00020000 +#define RATR_MCS6 0x00040000 +#define RATR_MCS7 0x00080000 +#define RATR_MCS8 0x00100000 +#define RATR_MCS9 0x00200000 +#define RATR_MCS10 0x00400000 +#define RATR_MCS11 0x00800000 +#define RATR_MCS12 0x01000000 +#define RATR_MCS13 0x02000000 +#define RATR_MCS14 0x04000000 +#define RATR_MCS15 0x08000000 + +#define RATE_1M BIT(0) +#define RATE_2M BIT(1) +#define RATE_5_5M BIT(2) +#define RATE_11M BIT(3) +#define RATE_6M BIT(4) +#define RATE_9M BIT(5) +#define RATE_12M BIT(6) +#define RATE_18M BIT(7) +#define RATE_24M BIT(8) +#define RATE_36M BIT(9) +#define RATE_48M BIT(10) +#define RATE_54M BIT(11) +#define RATE_MCS0 BIT(12) +#define RATE_MCS1 BIT(13) +#define RATE_MCS2 BIT(14) +#define RATE_MCS3 BIT(15) +#define RATE_MCS4 BIT(16) +#define RATE_MCS5 BIT(17) +#define RATE_MCS6 BIT(18) +#define RATE_MCS7 BIT(19) +#define RATE_MCS8 BIT(20) +#define RATE_MCS9 BIT(21) +#define RATE_MCS10 BIT(22) +#define RATE_MCS11 BIT(23) +#define RATE_MCS12 BIT(24) +#define RATE_MCS13 BIT(25) +#define RATE_MCS14 BIT(26) +#define RATE_MCS15 BIT(27) + +/* CAM definition */ + +#define CAM_NONE 0x0 +#define CAM_WEP40 0x01 +#define CAM_TKIP 0x02 +#define CAM_AES 0x04 +#define CAM_WEP104 0x05 + +/*#define TOTAL_CAM_ENTRY 64*/ +/*#define HALF_CAM_ENTRY 32*/ + +#define CAM_WRITE BIT(16) +#define CAM_READ 0x00000000 +#define CAM_POLLINIG BIT(31) + +/********************************************* + * 8822BE IMR/ISR bits + ********************************************* + */ +#define IMR_DISABLED 0x0 +/* IMR DW0(0x0060-0063) Bit 0-31 */ +#define IMR_TIMER2 BIT(31) +#define IMR_TIMER1 BIT(30) +#define IMR_PSTIMEOUT BIT(29) +#define IMR_GTINT4 BIT(28) +#define IMR_GTINT3 BIT(27) +#define IMR_TBDER BIT(26) +#define IMR_TBDOK BIT(25) +#define IMR_TSF_BIT32_TOGGLE BIT(24) +#define IMR_BCNDMAINT0 BIT(20) +#define IMR_BCNDOK0 BIT(16) +#define IMR_HSISR_IND_ON_INT BIT(15) +#define IMR_BCNDMAINT_E BIT(14) +#define IMR_ATIMEND BIT(12) +#define IMR_HISR1_IND_INT BIT(11) +#define IMR_C2HCMD BIT(10) +#define IMR_CPWM2 BIT(9) +#define IMR_CPWM BIT(8) +#define IMR_HIGHDOK BIT(7) +#define IMR_MGNTDOK BIT(6) +#define IMR_BKDOK BIT(5) +#define IMR_BEDOK BIT(4) +#define IMR_VIDOK BIT(3) +#define IMR_VODOK BIT(2) +#define IMR_RDU BIT(1) +#define IMR_ROK BIT(0) + +/* IMR DW1(0x00B4-00B7) Bit 0-31 */ +#define IMR_TXFIFO_TH_INT_8822B BIT_TXFIFO_TH_INT_8822B +#define IMR_BTON_STS_UPDATE_MASK_8822B BIT_BTON_STS_UPDATE_MASK_8822B +#define IMR_MCUERR BIT(28) +#define IMR_BCNDMAINT7 BIT(27) +#define IMR_BCNDMAINT6 BIT(26) +#define IMR_BCNDMAINT5 BIT(25) +#define IMR_BCNDMAINT4 BIT(24) +#define IMR_BCNDMAINT3 BIT(23) +#define IMR_BCNDMAINT2 BIT(22) +#define IMR_BCNDMAINT1 BIT(21) +#define IMR_BCNDOK7 BIT(20) +#define IMR_BCNDOK6 BIT(19) +#define IMR_BCNDOK5 BIT(18) +#define IMR_BCNDOK4 BIT(17) +#define IMR_BCNDOK3 BIT(16) +#define IMR_BCNDOK2 BIT(15) +#define IMR_BCNDOK1 BIT(14) +#define IMR_ATIMEND_E BIT(13) +#define IMR_ATIMEND BIT(12) +#define IMR_TXERR BIT(11) +#define IMR_RXERR BIT(10) +#define IMR_TXFOVW BIT(9) +#define IMR_RXFOVW BIT(8) +#define IMR_CPU_MGQ_TXDONE_MSK_8822B BIT_CPU_MGQ_TXDONE_MSK_8822B +#define IMR_PS_TIMER_C_MSK_8822B BIT_PS_TIMER_C_MSK_8822B +#define IMR_PS_TIMER_B_MSK_8822B BIT_PS_TIMER_B_MSK_8822B +#define IMR_PS_TIMER_A_MSK_8822B BIT_PS_TIMER_A_MSK_8822B +#define IMR_CPUMGQ_TX_TIMER_MSK_8822B BIT_CPUMGQ_TX_TIMER_MSK_8822B + +/********************************************* + * 8822BE EFUSE definition + ********************************************* + */ +#define HWSET_MAX_SIZE 1024 +#define EFUSE_MAX_SECTION 64 +#define EFUSE_REAL_CONTENT_LEN 1024 +#define EFUSE_OOB_PROTECT_BYTES 18 + +#define EEPROM_DEFAULT_THERMALMETER 0x12 + +#define RTL8822B_EEPROM_ID 0x8129 + +#define PPG_BB_GAIN_2G_TXA_OFFSET_8822B 0xEE +#define PPG_THERMAL_OFFSET_8822B 0xEF + +#define EEPROM_TX_PWR_INX_8822B 0x10 + +#define EEPROM_CHANNEL_PLAN_8822B 0xB8 +#define EEPROM_XTAL_8822B 0xB9 +#define EEPROM_THERMAL_METER_8822B 0xBA +#define EEPROM_IQK_LCK_8822B 0xBB +#define EEPROM_2G_5G_PA_TYPE_8822B 0xBC +/* PATH A & PATH B */ +#define EEPROM_2G_LNA_TYPE_GAIN_SEL_AB_8822B 0xBD +/* PATH C & PATH D */ +#define EEPROM_2G_LNA_TYPE_GAIN_SEL_CD_8822B 0xBE +/* PATH A & PATH B */ +#define EEPROM_5G_LNA_TYPE_GAIN_SEL_AB_8822B 0xBF +/* PATH C & PATH D */ +#define EEPROM_5G_LNA_TYPE_GAIN_SEL_CD_8822B 0xC0 + +#define EEPROM_RF_BOARD_OPTION_8822B 0xC1 +#define EEPROM_FEATURE_OPTION_8822B 0xC2 +#define EEPROM_RF_BT_SETTING_8822B 0xC3 +#define EEPROM_VERSION_8822B 0xC4 +#define EEPROM_CUSTOM_ID_8822B 0xC5 +#define EEPROM_TX_BBSWING_2G_8822B 0xC6 +#define EEPROM_TX_PWR_CALIBRATE_RATE_8822B 0xC8 +#define EEPROM_RF_ANTENNA_OPT_8822B 0xC9 +#define EEPROM_RFE_OPTION_8822B 0xCA +#define EEPROM_COUNTRY_CODE_8822B 0xCB + +#define EEPROM_VID 0xD6 +#define EEPROM_DID 0xD8 +#define EEPROM_SVID 0xDA +#define EEPROM_SMID 0xDC + +/* RTL8822BU */ +#define EEPROM_MAC_ADDR_8822BU 0x107 +#define EEPROM_VID_8822BU 0x100 +#define EEPROM_PID_8822BU 0x102 +#define EEPROM_USB_OPTIONAL_FUNCTION0_8822BU 0x104 +#define EEPROM_USB_MODE_8822BU 0x06 + +/* RTL8822BS */ +#define EEPROM_MAC_ADDR_8822BS 0x11A + +/* RTL8822BE */ +#define EEPROM_MAC_ADDR_8822BE 0xD0 + +/* ------------------------- */ + +#define STOPBECON BIT(6) +#define STOPHIGHT BIT(5) +#define STOPMGT BIT(4) +#define STOPVO BIT(3) +#define STOPVI BIT(2) +#define STOPBE BIT(1) +#define STOPBK BIT(0) + +#define RCR_APPFCS BIT(31) +#define RCR_APP_MIC BIT(30) +#define RCR_APP_ICV BIT(29) +#define RCR_APP_PHYST_RXFF BIT(28) +#define RCR_APP_BA_SSN BIT(27) +#define RCR_VHT_DACK BIT(26) +#define RCR_ENMBID BIT(24) +#define RCR_LSIGEN BIT(23) +#define RCR_MFBEN BIT(22) +#define RCR_HTC_LOC_CTRL BIT(14) +#define RCR_AMF BIT(13) +#define RCR_ACF BIT(12) +#define RCR_ADF BIT(11) +#define RCR_AICV BIT(9) +#define RCR_ACRC32 BIT(8) +#define RCR_CBSSID_BCN BIT(7) +#define RCR_CBSSID_DATA BIT(6) +#define RCR_CBSSID RCR_CBSSID_DATA +#define RCR_APWRMGT BIT(5) +#define RCR_ADD3 BIT(4) +#define RCR_AB BIT(3) +#define RCR_AM BIT(2) +#define RCR_APM BIT(1) +#define RCR_AAP BIT(0) +#define RCR_MXDMA_OFFSET 8 +#define RCR_FIFO_OFFSET 13 + +#define RSV_CTRL 0x001C +#define RD_CTRL 0x0524 + +#define REG_USB_INFO_8822B 0xFE17 +#define REG_USB_SPECIAL_OPTION_8822B 0xFE55 +#define REG_USB_DMA_AGG_TO_8822B 0xFE5B +#define REG_USB_AGG_TO_8822B 0xFE5C +#define REG_USB_AGG_TH_8822B 0xFE5D + +#define REG_USB_VID_8822B 0xFE60 +#define REG_USB_PID_8822B 0xFE62 +#define REG_USB_OPTIONAL_8822B 0xFE64 +#define REG_USB_CHIRP_K_8822B 0xFE65 +#define REG_USB_PHY_8822B 0xFE66 +#define REG_USB_MAC_ADDR_8822B 0xFE70 +#define REG_USB_HRPWM_8822B 0xFE58 +#define REG_USB_HCPWM_8822B 0xFE57 + +#define SW18_FPWM BIT(3) + +#define ISO_MD2PP BIT(0) +#define ISO_UA2USB BIT(1) +#define ISO_UD2CORE BIT(2) +#define ISO_PA2PCIE BIT(3) +#define ISO_PD2CORE BIT(4) +#define ISO_IP2MAC BIT(5) +#define ISO_DIOP BIT(6) +#define ISO_DIOE BIT(7) +#define ISO_EB2CORE BIT(8) +#define ISO_DIOR BIT(9) + +#define PWC_EV25V BIT(14) +#define PWC_EV12V BIT(15) + +#define FEN_BBRSTB BIT(0) +#define FEN_BB_GLB_RSTN BIT(1) +#define FEN_USBA BIT(2) +#define FEN_UPLL BIT(3) +#define FEN_USBD BIT(4) +#define FEN_DIO_PCIE BIT(5) +#define FEN_PCIEA BIT(6) +#define FEN_PPLL BIT(7) +#define FEN_PCIED BIT(8) +#define FEN_DIOE BIT(9) +#define FEN_CPUEN BIT(10) +#define FEN_DCORE BIT(11) +#define FEN_ELDR BIT(12) +#define FEN_DIO_RF BIT(13) +#define FEN_HWPDN BIT(14) +#define FEN_MREGEN BIT(15) + +#define PFM_LDALL BIT(0) +#define PFM_ALDN BIT(1) +#define PFM_LDKP BIT(2) +#define PFM_WOWL BIT(3) +#define EN_PDN BIT(4) +#define PDN_PL BIT(5) +#define APFM_ONMAC BIT(8) +#define APFM_OFF BIT(9) +#define APFM_RSM BIT(10) +#define AFSM_HSUS BIT(11) +#define AFSM_PCIE BIT(12) +#define APDM_MAC BIT(13) +#define APDM_HOST BIT(14) +#define APDM_HPDN BIT(15) +#define RDY_MACON BIT(16) +#define SUS_HOST BIT(17) +#define ROP_ALD BIT(20) +#define ROP_PWR BIT(21) +#define ROP_SPS BIT(22) +#define SOP_MRST BIT(25) +#define SOP_FUSE BIT(26) +#define SOP_ABG BIT(27) +#define SOP_AMB BIT(28) +#define SOP_RCK BIT(29) +#define SOP_A8M BIT(30) +#define XOP_BTCK BIT(31) + +#define ANAD16V_EN BIT(0) +#define ANA8M BIT(1) +#define MACSLP BIT(4) +#define LOADER_CLK_EN BIT(5) +#define _80M_SSC_DIS BIT(7) +#define _80M_SSC_EN_HO BIT(8) +#define PHY_SSC_RSTB BIT(9) +#define SEC_CLK_EN BIT(10) +#define MAC_CLK_EN BIT(11) +#define SYS_CLK_EN BIT(12) +#define RING_CLK_EN BIT(13) + +#define BOOT_FROM_EEPROM BIT(4) +#define EEPROM_EN BIT(5) + +#define AFE_BGEN BIT(0) +#define AFE_MBEN BIT(1) +#define MAC_ID_EN BIT(7) + +#define WLOCK_ALL BIT(0) +#define WLOCK_00 BIT(1) +#define WLOCK_04 BIT(2) +#define WLOCK_08 BIT(3) +#define WLOCK_40 BIT(4) +#define R_DIS_PRST_0 BIT(5) +#define R_DIS_PRST_1 BIT(6) +#define LOCK_ALL_EN BIT(7) + +#define RF_EN BIT(0) +#define RF_RSTB BIT(1) +#define RF_SDMRSTB BIT(2) + +#define LDA15_EN BIT(0) +#define LDA15_STBY BIT(1) +#define LDA15_OBUF BIT(2) +#define LDA15_REG_VOS BIT(3) +#define _LDA15_VOADJ(x) (((x) & 0x7) << 4) + +#define LDV12_EN BIT(0) +#define LDV12_SDBY BIT(1) +#define LPLDO_HSM BIT(2) +#define LPLDO_LSM_DIS BIT(3) +#define _LDV12_VADJ(x) (((x) & 0xF) << 4) + +#define XTAL_EN BIT(0) +#define XTAL_BSEL BIT(1) +#define _XTAL_BOSC(x) (((x) & 0x3) << 2) +#define _XTAL_CADJ(x) (((x) & 0xF) << 4) +#define XTAL_GATE_USB BIT(8) +#define _XTAL_USB_DRV(x) (((x) & 0x3) << 9) +#define XTAL_GATE_AFE BIT(11) +#define _XTAL_AFE_DRV(x) (((x) & 0x3) << 12) +#define XTAL_RF_GATE BIT(14) +#define _XTAL_RF_DRV(x) (((x) & 0x3) << 15) +#define XTAL_GATE_DIG BIT(17) +#define _XTAL_DIG_DRV(x) (((x) & 0x3) << 18) +#define XTAL_BT_GATE BIT(20) +#define _XTAL_BT_DRV(x) (((x) & 0x3) << 21) +#define _XTAL_GPIO(x) (((x) & 0x7) << 23) + +#define CKDLY_AFE BIT(26) +#define CKDLY_USB BIT(27) +#define CKDLY_DIG BIT(28) +#define CKDLY_BT BIT(29) + +#define APLL_EN BIT(0) +#define APLL_320_EN BIT(1) +#define APLL_FREF_SEL BIT(2) +#define APLL_EDGE_SEL BIT(3) +#define APLL_WDOGB BIT(4) +#define APLL_LPFEN BIT(5) + +#define APLL_REF_CLK_13MHZ 0x1 +#define APLL_REF_CLK_19_2MHZ 0x2 +#define APLL_REF_CLK_20MHZ 0x3 +#define APLL_REF_CLK_25MHZ 0x4 +#define APLL_REF_CLK_26MHZ 0x5 +#define APLL_REF_CLK_38_4MHZ 0x6 +#define APLL_REF_CLK_40MHZ 0x7 + +#define APLL_320EN BIT(14) +#define APLL_80EN BIT(15) +#define APLL_1MEN BIT(24) + +#define ALD_EN BIT(18) +#define EF_PD BIT(19) +#define EF_FLAG BIT(31) + +#define EF_TRPT BIT(7) +#define LDOE25_EN BIT(31) + +#define RSM_EN BIT(0) +#define TIMER_EN BIT(4) + +#define TRSW0EN BIT(2) +#define TRSW1EN BIT(3) +#define EROM_EN BIT(4) +#define EN_BT BIT(5) +#define EN_UART BIT(8) +#define UART_910 BIT(9) +#define EN_PMAC BIT(10) +#define SIC_SWRST BIT(11) +#define EN_SIC BIT(12) +#define SIC_23 BIT(13) +#define EN_HDP BIT(14) +#define SIC_LBK BIT(15) + +#define LED0PL BIT(4) +#define LED1PL BIT(12) +#define LED0DIS BIT(7) + +#define MCUFWDL_EN BIT(0) +#define MCUFWDL_RDY BIT(1) +#define FWDL_CHKSUM_RPT BIT(2) +#define MACINI_RDY BIT(3) +#define BBINI_RDY BIT(4) +#define RFINI_RDY BIT(5) +#define WINTINI_RDY BIT(6) +#define CPRST BIT(23) + +#define XCLK_VLD BIT(0) +#define ACLK_VLD BIT(1) +#define UCLK_VLD BIT(2) +#define PCLK_VLD BIT(3) +#define PCIRSTB BIT(4) +#define V15_VLD BIT(5) +#define TRP_B15V_EN BIT(7) +#define SIC_IDLE BIT(8) +#define BD_MAC2 BIT(9) +#define BD_MAC1 BIT(10) +#define IC_MACPHY_MODE BIT(11) +#define VENDOR_ID BIT(19) +#define PAD_HWPD_IDN BIT(22) +#define TRP_VAUX_EN BIT(23) +#define TRP_BT_EN BIT(24) +#define BD_PKG_SEL BIT(25) +#define BD_HCI_SEL BIT(26) +#define TYPE_ID BIT(27) + +#define CHIP_VER_RTL_MASK 0xF000 +#define CHIP_VER_RTL_SHIFT 12 + +#define REG_LBMODE_8822B (REG_CR_8822B + 3) + +#define HCI_TXDMA_EN BIT(0) +#define HCI_RXDMA_EN BIT(1) +#define TXDMA_EN BIT(2) +#define RXDMA_EN BIT(3) +#define PROTOCOL_EN BIT(4) +#define SCHEDULE_EN BIT(5) +#define MACTXEN BIT(6) +#define MACRXEN BIT(7) +#define ENSWBCN BIT(8) +#define ENSEC BIT(9) + +#define _NETTYPE(x) (((x) & 0x3) << 16) +#define MASK_NETTYPE 0x30000 +#define NT_NO_LINK 0x0 +#define NT_LINK_AD_HOC 0x1 +#define NT_LINK_AP 0x2 +#define NT_AS_AP 0x3 + +#define _LBMODE(x) (((x) & 0xF) << 24) +#define MASK_LBMODE 0xF000000 +#define LOOPBACK_NORMAL 0x0 +#define LOOPBACK_IMMEDIATELY 0xB +#define LOOPBACK_MAC_DELAY 0x3 +#define LOOPBACK_PHY 0x1 +#define LOOPBACK_DMA 0x7 + +#define GET_RX_PAGE_SIZE(value) ((value) & 0xF) +#define GET_TX_PAGE_SIZE(value) (((value) & 0xF0) >> 4) +#define _PSRX_MASK 0xF +#define _PSTX_MASK 0xF0 +#define _PSRX(x) (x) +#define _PSTX(x) ((x) << 4) + +#define PBP_64 0x0 +#define PBP_128 0x1 +#define PBP_256 0x2 +#define PBP_512 0x3 +#define PBP_1024 0x4 + +#define RXDMA_ARBBW_EN BIT(0) +#define RXSHFT_EN BIT(1) +#define RXDMA_AGG_EN BIT(2) +#define QS_VO_QUEUE BIT(8) +#define QS_VI_QUEUE BIT(9) +#define QS_BE_QUEUE BIT(10) +#define QS_BK_QUEUE BIT(11) +#define QS_MANAGER_QUEUE BIT(12) +#define QS_HIGH_QUEUE BIT(13) + +#define HQSEL_VOQ BIT(0) +#define HQSEL_VIQ BIT(1) +#define HQSEL_BEQ BIT(2) +#define HQSEL_BKQ BIT(3) +#define HQSEL_MGTQ BIT(4) +#define HQSEL_HIQ BIT(5) + +#define _TXDMA_HIQ_MAP(x) (((x) & 0x3) << 14) +#define _TXDMA_MGQ_MAP(x) (((x) & 0x3) << 12) +#define _TXDMA_BKQ_MAP(x) (((x) & 0x3) << 10) +#define _TXDMA_BEQ_MAP(x) (((x) & 0x3) << 8) +#define _TXDMA_VIQ_MAP(x) (((x) & 0x3) << 6) +#define _TXDMA_VOQ_MAP(x) (((x) & 0x3) << 4) + +#define QUEUE_LOW 1 +#define QUEUE_NORMAL 2 +#define QUEUE_HIGH 3 + +#define _LLT_NO_ACTIVE 0x0 +#define _LLT_WRITE_ACCESS 0x1 +#define _LLT_READ_ACCESS 0x2 + +#define _LLT_INIT_DATA(x) ((x) & 0xFF) +#define _LLT_INIT_ADDR(x) (((x) & 0xFF) << 8) +#define _LLT_OP(x) (((x) & 0x3) << 30) +#define _LLT_OP_VALUE(x) (((x) >> 30) & 0x3) + +#define BB_WRITE_READ_MASK (BIT(31) | BIT(30)) +#define BB_WRITE_EN BIT(30) +#define BB_READ_EN BIT(31) + +#define _HPQ(x) ((x) & 0xFF) +#define _LPQ(x) (((x) & 0xFF) << 8) +#define _PUBQ(x) (((x) & 0xFF) << 16) +#define _NPQ(x) ((x) & 0xFF) + +#define HPQ_PUBLIC_DIS BIT(24) +#define LPQ_PUBLIC_DIS BIT(25) +#define LD_RQPN BIT(31) + +#define BCN_VALID BIT(16) +#define BCN_HEAD(x) (((x) & 0xFF) << 8) +#define BCN_HEAD_MASK 0xFF00 + +#define BLK_DESC_NUM_SHIFT 4 +#define BLK_DESC_NUM_MASK 0xF + +#define DROP_DATA_EN BIT(9) + +#define EN_AMPDU_RTY_NEW BIT(7) + +#define _INIRTSMCS_SEL(x) ((x) & 0x3F) + +#define _SPEC_SIFS_CCK(x) ((x) & 0xFF) +#define _SPEC_SIFS_OFDM(x) (((x) & 0xFF) << 8) + +#define RATE_REG_BITMAP_ALL 0xFFFFF + +#define _RRSC_BITMAP(x) ((x) & 0xFFFFF) + +#define _RRSR_RSC(x) (((x) & 0x3) << 21) +#define RRSR_RSC_RESERVED 0x0 +#define RRSR_RSC_UPPER_SUBCHANNEL 0x1 +#define RRSR_RSC_LOWER_SUBCHANNEL 0x2 +#define RRSR_RSC_DUPLICATE_MODE 0x3 + +#define USE_SHORT_G1 BIT(20) + +#define _AGGLMT_MCS0(x) ((x) & 0xF) +#define _AGGLMT_MCS1(x) (((x) & 0xF) << 4) +#define _AGGLMT_MCS2(x) (((x) & 0xF) << 8) +#define _AGGLMT_MCS3(x) (((x) & 0xF) << 12) +#define _AGGLMT_MCS4(x) (((x) & 0xF) << 16) +#define _AGGLMT_MCS5(x) (((x) & 0xF) << 20) +#define _AGGLMT_MCS6(x) (((x) & 0xF) << 24) +#define _AGGLMT_MCS7(x) (((x) & 0xF) << 28) + +#define RETRY_LIMIT_SHORT_SHIFT 8 +#define RETRY_LIMIT_LONG_SHIFT 0 + +#define _DARF_RC1(x) ((x) & 0x1F) +#define _DARF_RC2(x) (((x) & 0x1F) << 8) +#define _DARF_RC3(x) (((x) & 0x1F) << 16) +#define _DARF_RC4(x) (((x) & 0x1F) << 24) +#define _DARF_RC5(x) ((x) & 0x1F) +#define _DARF_RC6(x) (((x) & 0x1F) << 8) +#define _DARF_RC7(x) (((x) & 0x1F) << 16) +#define _DARF_RC8(x) (((x) & 0x1F) << 24) + +#define _RARF_RC1(x) ((x) & 0x1F) +#define _RARF_RC2(x) (((x) & 0x1F) << 8) +#define _RARF_RC3(x) (((x) & 0x1F) << 16) +#define _RARF_RC4(x) (((x) & 0x1F) << 24) +#define _RARF_RC5(x) ((x) & 0x1F) +#define _RARF_RC6(x) (((x) & 0x1F) << 8) +#define _RARF_RC7(x) (((x) & 0x1F) << 16) +#define _RARF_RC8(x) (((x) & 0x1F) << 24) + +#define AC_PARAM_TXOP_LIMIT_OFFSET 16 +#define AC_PARAM_ECW_MAX_OFFSET 12 +#define AC_PARAM_ECW_MIN_OFFSET 8 +#define AC_PARAM_AIFS_OFFSET 0 + +#define _AIFS(x) (x) +#define _ECW_MAX_MIN(x) ((x) << 8) +#define _TXOP_LIMIT(x) ((x) << 16) + +#define _BCNIFS(x) ((x) & 0xFF) +#define _BCNECW(x) ((((x) & 0xF)) << 8) + +#define _LRL(x) ((x) & 0x3F) +#define _SRL(x) (((x) & 0x3F) << 8) + +#define _SIFS_CCK_CTX(x) ((x) & 0xFF) +#define _SIFS_CCK_TRX(x) (((x) & 0xFF) << 8) + +#define _SIFS_OFDM_CTX(x) ((x) & 0xFF) +#define _SIFS_OFDM_TRX(x) (((x) & 0xFF) << 8) + +#define _TBTT_PROHIBIT_HOLD(x) (((x) & 0xFF) << 8) + +#define DIS_EDCA_CNT_DWN BIT(11) + +#define EN_MBSSID BIT(1) +#define EN_TXBCN_RPT BIT(2) +#define EN_BCN_FUNCTION BIT(3) + +#define TSFTR_RST BIT(0) +#define TSFTR1_RST BIT(1) + +#define STOP_BCNQ BIT(6) + +#define DIS_TSF_UDT0_NORMAL_CHIP BIT(4) +#define DIS_TSF_UDT0_TEST_CHIP BIT(5) + +#define ACMHW_HW_EN BIT(0) +#define ACMHW_BEQ_EN BIT(1) +#define ACMHW_VIQ_EN BIT(2) +#define ACMHW_VOQ_EN BIT(3) +#define ACMHW_BEQ_STATUS BIT(4) +#define ACMHW_VIQ_STATUS BIT(5) +#define ACMHW_VOQ_STATUS BIT(6) + +#define APSDOFF BIT(6) +#define APSDOFF_STATUS BIT(7) + +#define BW_20MHZ BIT(2) + +#define RATE_BITMAP_ALL 0xFFFFF + +#define RATE_RRSR_CCK_ONLY_1M 0xFFFF1 + +#define TSFRST BIT(0) +#define DIS_GCLK BIT(1) +#define PAD_SEL BIT(2) +#define PWR_ST BIT(6) +#define PWRBIT_OW_EN BIT(7) +#define ACRC BIT(8) +#define CFENDFORM BIT(9) +#define ICV BIT(10) + +#define AAP BIT(0) +#define APM BIT(1) +#define AM BIT(2) +#define AB BIT(3) +#define ADD3 BIT(4) +#define APWRMGT BIT(5) +#define CBSSID BIT(6) +#define CBSSID_DATA BIT(6) +#define CBSSID_BCN BIT(7) +#define ACRC32 BIT(8) +#define AICV BIT(9) +#define ADF BIT(11) +#define ACF BIT(12) +#define AMF BIT(13) +#define HTC_LOC_CTRL BIT(14) +#define UC_DATA_EN BIT(16) +#define BM_DATA_EN BIT(17) +#define MFBEN BIT(22) +#define LSIGEN BIT(23) +#define EN_MBID BIT(24) +#define APP_BASSN BIT(27) +#define APP_PHYSTS BIT(28) +#define APP_ICV BIT(29) +#define APP_MIC BIT(30) +#define APP_FCS BIT(31) + +#define _MIN_SPACE(x) ((x) & 0x7) +#define _SHORT_GI_PADDING(x) (((x) & 0x1F) << 3) + +#define RXERR_TYPE_OFDM_PPDU 0 +#define RXERR_TYPE_OFDM_FALSE_ALARM 1 +#define RXERR_TYPE_OFDM_MPDU_OK 2 +#define RXERR_TYPE_OFDM_MPDU_FAIL 3 +#define RXERR_TYPE_CCK_PPDU 4 +#define RXERR_TYPE_CCK_FALSE_ALARM 5 +#define RXERR_TYPE_CCK_MPDU_OK 6 +#define RXERR_TYPE_CCK_MPDU_FAIL 7 +#define RXERR_TYPE_HT_PPDU 8 +#define RXERR_TYPE_HT_FALSE_ALARM 9 +#define RXERR_TYPE_HT_MPDU_TOTAL 10 +#define RXERR_TYPE_HT_MPDU_OK 11 +#define RXERR_TYPE_HT_MPDU_FAIL 12 +#define RXERR_TYPE_RX_FULL_DROP 15 + +#define RXERR_COUNTER_MASK 0xFFFFF +#define RXERR_RPT_RST BIT(27) +#define _RXERR_RPT_SEL(type) ((type) << 28) + +#define SCR_TX_USE_DK BIT(0) +#define SCR_RX_USE_DK BIT(1) +#define SCR_TX_ENC_ENABLE BIT(2) +#define SRC_RX_DEC_ENABLE BIT(3) +#define SCR_SK_BY_A2 BIT(4) +#define SCR_NO_SKMC BIT(5) +#define SCR_TXBCUSEDK BIT(6) +#define SCR_RXBCUSEDK BIT(7) + +#define USB_IS_HIGH_SPEED 0 +#define USB_IS_FULL_SPEED 1 +#define USB_SPEED_MASK BIT(5) + +#define USB_NORMAL_SIE_EP_MASK 0xF +#define USB_NORMAL_SIE_EP_SHIFT 4 + +#define USB_TEST_EP_MASK 0x30 +#define USB_TEST_EP_SHIFT 4 + +#define USB_AGG_EN BIT(3) + +#define MAC_ADDR_LEN 6 +#define LAST_ENTRY_OF_TX_PKT_BUFFER 175 + +#define POLLING_LLT_THRESHOLD 20 +#define POLLING_READY_TIMEOUT_COUNT 3000 + +#define MAX_MSS_DENSITY_2T 0x13 +#define MAX_MSS_DENSITY_1T 0x0A + +#define EPROM_CMD_OPERATING_MODE_MASK ((1 << 7) | (1 << 6)) +#define EPROM_CMD_CONFIG 0x3 +#define EPROM_CMD_LOAD 1 + +#define HAL_8822B_HW_GPIO_WPS_BIT BIT(2) + +/*----------------------------------------------------- + * BB / RF register + *----------------------------------------------------- + */ + +#define RFPGA0_XA_HSSIPARAMETER1 0x820 +#define RFPGA0_XA_HSSIPARAMETER2 0x824 +#define RFPGA0_XB_HSSIPARAMETER1 0x828 +#define RFPGA0_XB_HSSIPARAMETER2 0x82c +#define RCCAONSEC 0x838 + +#define RFPGA0_XA_LSSIPARAMETER 0x840 +#define RFPGA0_XB_LSSIPARAMETER 0x844 +#define RL1PEAKTH 0x848 + +#define RFPGA0_RFWAKEUPPARAMETER 0x850 +#define RFPGA0_RFSLEEPUPPARAMETER 0x854 + +#define RFPGA0_XAB_SWITCHCONTROL 0x858 +#define RFPGA0_XCD_SWITCHCONTROL 0x85c + +#define RFPGA0_XA_RFINTERFACEOE 0x860 +#define RFC_AREA 0x860 +#define RFPGA0_XB_RFINTERFACEOE 0x864 + +#define RFPGA0_XAB_RFINTERFACESW 0x870 +#define RFPGA0_XCD_RFINTERFACESW 0x874 + +#define RFPGA0_XAB_RF_PARA_METER 0x878 +#define RFPGA0_XCD_RF_PARA_METER 0x87c + +#define RFPGA0_ANALOGPARAMETER1 0x880 +#define RFPGA0_ANALOGPARAMETER2 0x884 +#define RFPGA0_ANALOGPARAMETER3 0x888 +#define RFPGA0_ANALOGPARAMETER4 0x88c + +#define RFPGA0_XA_LSSIREADBACK 0x8a0 +#define RFPGA0_XB_LSSIREADBACK 0x8a4 +#define RFPGA0_XC_LSSIREADBACK 0x8a8 +/*#define RFPGA0_XD_LSSIREADBACK 0x8ac*/ +#define RRFMOD 0x8ac +#define RHSSIREAD_8822BE 0x8b0 + +#define RFPGA0_PSDREPORT 0x8b4 +#define TRANSCEIVEA_HSPI_READBACK 0x8b8 +#define TRANSCEIVEB_HSPI_READBACK 0x8bc +/*#define REG_SC_CNT_8822B 0x8c4*/ +#define RADC_BUF_CLK 0x8c4 +#define RFPGA0_XAB_RFINTERFACERB 0x8e0 +#define RFPGA0_XCD_RFINTERFACERB 0x8e4 + +/* PageB(0xB00) */ + +/*Page C*/ + +#define RA_TXPWRTRAING 0xc54 +#define RB_TXPWRTRAING 0xe54 + +#define RA_LSSIWRITE_8822B 0xc90 +#define RB_LSSIWRITE_8822B 0xe90 + +#define RA_PIREAD_8822B 0xd04 +#define RB_PIREAD_8822B 0xd44 +#define RA_SIREAD_8822B 0xd08 +#define RB_SIREAD_8822B 0xd48 + +#define RZEBRA1_HSSIENABLE 0x0 +#define RZEBRA1_TRXENABLE1 0x1 +#define RZEBRA1_TRXENABLE2 0x2 +#define RZEBRA1_AGC 0x4 +#define RZEBRA1_CHARGEPUMP 0x5 +#define RZEBRA1_CHANNEL 0x7 + +#define RZEBRA1_TXGAIN 0x8 +#define RZEBRA1_TXLPF 0x9 +#define RZEBRA1_RXLPF 0xb +#define RZEBRA1_RXHPFCORNER 0xc + +#define RGLOBALCTRL 0 +#define RRTL8256_TXLPF 19 +#define RRTL8256_RXLPF 11 +#define RRTL8258_TXLPF 0x11 +#define RRTL8258_RXLPF 0x13 +#define RRTL8258_RSSILPF 0xa + +#define RF_AC 0x00 + +#define RF_IQADJ_G1 0x01 +#define RF_IQADJ_G2 0x02 +#define RF_POW_TRSW 0x05 + +#define RF_GAIN_RX 0x06 +#define RF_GAIN_TX 0x07 + +#define RF_TXM_IDAC 0x08 +#define RF_BS_IQGEN 0x0F + +#define RF_MODE1 0x10 +#define RF_MODE2 0x11 + +#define RF_RX_AGC_HP 0x12 +#define RF_TX_AGC 0x13 +#define RF_BIAS 0x14 +#define RF_IPA 0x15 +#define RF_POW_ABILITY 0x17 +#define RF_MODE_AG 0x18 +#define RRFCHANNEL 0x18 +#define RF_CHNLBW 0x18 +#define RF_TOP 0x19 + +#define RF_RX_G1 0x1A +#define RF_RX_G2 0x1B + +#define RF_RX_BB2 0x1C +#define RF_RX_BB1 0x1D + +#define RF_RCK1 0x1E +#define RF_RCK2 0x1F + +#define RF_TX_G1 0x20 +#define RF_TX_G2 0x21 +#define RF_TX_G3 0x22 + +#define RF_TX_BB1 0x23 +#define RF_T_METER 0x42 + +#define RF_SYN_G1 0x25 +#define RF_SYN_G2 0x26 +#define RF_SYN_G3 0x27 +#define RF_SYN_G4 0x28 +#define RF_SYN_G5 0x29 +#define RF_SYN_G6 0x2A +#define RF_SYN_G7 0x2B +#define RF_SYN_G8 0x2C + +#define RF_RCK_OS 0x30 +#define RF_TXPA_G1 0x31 +#define RF_TXPA_G2 0x32 +#define RF_TXPA_G3 0x33 + +#define RF_TX_BIAS_A 0x35 +#define RF_TX_BIAS_D 0x36 +#define RF_LOBF_9 0x38 +#define RF_RXRF_A3 0x3C +#define RF_TRSW 0x3F + +#define RF_TXRF_A2 0x41 +#define RF_TXPA_G4 0x46 +#define RF_TXPA_A4 0x4B + +#define RF_APK 0x63 + +#define RF_WE_LUT 0xEF + +#define BBBRESETB 0x100 +#define BGLOBALRESETB 0x200 +#define BOFDMTXSTART 0x4 +#define BCCKTXSTART 0x8 +#define BCRC32DEBUG 0x100 +#define BPMACLOOPBACK 0x10 +#define BTXLSIG 0xffffff +#define BOFDMTXRATE 0xf +#define BOFDMTXRESERVED 0x10 +#define BOFDMTXLENGTH 0x1ffe0 +#define BOFDMTXPARITY 0x20000 +#define BTXHTSIG1 0xffffff +#define BTXHTMCSRATE 0x7f +#define BTXHTBW 0x80 +#define BTXHTLENGTH 0xffff00 +#define BTXHTSIG2 0xffffff +#define BTXHTSMOOTHING 0x1 +#define BTXHTSOUNDING 0x2 +#define BTXHTRESERVED 0x4 +#define BTXHTAGGREATION 0x8 +#define BTXHTSTBC 0x30 +#define BTXHTADVANCECODING 0x40 +#define BTXHTSHORTGI 0x80 +#define BTXHTNUMBERHT_LTF 0x300 +#define BTXHTCRC8 0x3fc00 +#define BCOUNTERRESET 0x10000 +#define BNUMOFOFDMTX 0xffff +#define BNUMOFCCKTX 0xffff0000 +#define BTXIDLEINTERVAL 0xffff +#define BOFDMSERVICE 0xffff0000 +#define BTXMACHEADER 0xffffffff +#define BTXDATAINIT 0xff +#define BTXHTMODE 0x100 +#define BTXDATATYPE 0x30000 +#define BTXRANDOMSEED 0xffffffff +#define BCCKTXPREAMBLE 0x1 +#define BCCKTXSFD 0xffff0000 +#define BCCKTXSIG 0xff +#define BCCKTXSERVICE 0xff00 +#define BCCKLENGTHEXT 0x8000 +#define BCCKTXLENGHT 0xffff0000 +#define BCCKTXCRC16 0xffff +#define BCCKTXSTATUS 0x1 +#define BOFDMTXSTATUS 0x2 +#define IS_BB_REG_OFFSET_92S(_offset) ((_offset >= 0x800) && (_offset <= 0xfff)) + +#define BRFMOD 0x1 +#define BJAPANMODE 0x2 +#define BCCKTXSC 0x30 +/* Block & Path enable*/ +#define ROFDMCCKEN 0x808 +#define BCCKEN 0x10000000 +#define BOFDMEN 0x20000000 +/* Rx antenna*/ +#define RRXPATH 0x808 +#define BRXPATH 0xff +/* Tx antenna*/ +#define RTXPATH 0x80c +#define BTXPATH 0x0fffffff +/* for cck rx path selection*/ +#define RCCK_RX 0xa04 +#define BCCK_RX 0x0c000000 +/* Use LSIG for VHT length*/ +#define RVHTLEN_USE_LSIG 0x8c3 + +#define BOFDMRXADCPHASE 0x10000 +#define BOFDMTXDACPHASE 0x40000 +#define BXATXAGC 0x3f + +#define BXBTXAGC 0xf00 +#define BXCTXAGC 0xf000 +#define BXDTXAGC 0xf0000 + +#define BPASTART 0xf0000000 +#define BTRSTART 0x00f00000 +#define BRFSTART 0x0000f000 +#define BBBSTART 0x000000f0 +#define BBBCCKSTART 0x0000000f +#define BPAEND 0xf +#define BTREND 0x0f000000 +#define BRFEND 0x000f0000 +#define BCCAMASK 0x000000f0 +#define BR2RCCAMASK 0x00000f00 +#define BHSSI_R2TDELAY 0xf8000000 +#define BHSSI_T2RDELAY 0xf80000 +#define BCONTXHSSI 0x400 +#define BIGFROMCCK 0x200 +#define BAGCADDRESS 0x3f +#define BRXHPTX 0x7000 +#define BRXHP2RX 0x38000 +#define BRXHPCCKINI 0xc0000 +#define BAGCTXCODE 0xc00000 +#define BAGCRXCODE 0x300000 + +#define B3WIREDATALENGTH 0x800 +#define B3WIREADDREAALENGTH 0x400 + +#define B3WIRERFPOWERDOWN 0x1 +#define B5GPAPEPOLARITY 0x40000000 +#define B2GPAPEPOLARITY 0x80000000 +#define BRFSW_TXDEFAULTANT 0x3 +#define BRFSW_TXOPTIONANT 0x30 +#define BRFSW_RXDEFAULTANT 0x300 +#define BRFSW_RXOPTIONANT 0x3000 +#define BRFSI_3WIREDATA 0x1 +#define BRFSI_3WIRECLOCK 0x2 +#define BRFSI_3WIRELOAD 0x4 +#define BRFSI_3WIRERW 0x8 +#define BRFSI_3WIRE 0xf + +#define BRFSI_RFENV 0x10 + +#define BRFSI_TRSW 0x20 +#define BRFSI_TRSWB 0x40 +#define BRFSI_ANTSW 0x100 +#define BRFSI_ANTSWB 0x200 +#define BRFSI_PAPE 0x400 +#define BRFSI_PAPE5G 0x800 +#define BBANDSELECT 0x1 +#define BHTSIG2_GI 0x80 +#define BHTSIG2_SMOOTHING 0x01 +#define BHTSIG2_SOUNDING 0x02 +#define BHTSIG2_AGGREATON 0x08 +#define BHTSIG2_STBC 0x30 +#define BHTSIG2_ADVCODING 0x40 +#define BHTSIG2_NUMOFHTLTF 0x300 +#define BHTSIG2_CRC8 0x3fc +#define BHTSIG1_MCS 0x7f +#define BHTSIG1_BANDWIDTH 0x80 +#define BHTSIG1_HTLENGTH 0xffff +#define BLSIG_RATE 0xf +#define BLSIG_RESERVED 0x10 +#define BLSIG_LENGTH 0x1fffe +#define BLSIG_PARITY 0x20 +#define BCCKRXPHASE 0x4 + +#define BLSSIREADADDRESS 0x7f800000 +#define BLSSIREADEDGE 0x80000000 + +#define BLSSIREADBACKDATA 0xfffff + +#define BLSSIREADOKFLAG 0x1000 +#define BCCKSAMPLERATE 0x8 +#define BREGULATOR0STANDBY 0x1 +#define BREGULATORPLLSTANDBY 0x2 +#define BREGULATOR1STANDBY 0x4 +#define BPLLPOWERUP 0x8 +#define BDPLLPOWERUP 0x10 +#define BDA10POWERUP 0x20 +#define BAD7POWERUP 0x200 +#define BDA6POWERUP 0x2000 +#define BXTALPOWERUP 0x4000 +#define B40MDCLKPOWERUP 0x8000 +#define BDA6DEBUGMODE 0x20000 +#define BDA6SWING 0x380000 + +#define BADCLKPHASE 0x4000000 +#define B80MCLKDELAY 0x18000000 +#define BAFEWATCHDOGENABLE 0x20000000 + +#define BXTALCAP01 0xc0000000 +#define BXTALCAP23 0x3 +#define BXTALCAP92X 0x0f000000 +#define BXTALCAP 0x0f000000 + +#define BINTDIFCLKENABLE 0x400 +#define BEXTSIGCLKENABLE 0x800 +#define BBANDGAP_MBIAS_POWERUP 0x10000 +#define BAD11SH_GAIN 0xc0000 +#define BAD11NPUT_RANGE 0x700000 +#define BAD110P_CURRENT 0x3800000 +#define BLPATH_LOOPBACK 0x4000000 +#define BQPATH_LOOPBACK 0x8000000 +#define BAFE_LOOPBACK 0x10000000 +#define BDA10_SWING 0x7e0 +#define BDA10_REVERSE 0x800 +#define BDA_CLK_SOURCE 0x1000 +#define BDA7INPUT_RANGE 0x6000 +#define BDA7_GAIN 0x38000 +#define BDA7OUTPUT_CM_MODE 0x40000 +#define BDA7INPUT_CM_MODE 0x380000 +#define BDA7CURRENT 0xc00000 +#define BREGULATOR_ADJUST 0x7000000 +#define BAD11POWERUP_ATTX 0x1 +#define BDA10PS_ATTX 0x10 +#define BAD11POWERUP_ATRX 0x100 +#define BDA10PS_ATRX 0x1000 +#define BCCKRX_AGC_FORMAT 0x200 +#define BPSDFFT_SAMPLE_POINT 0xc000 +#define BPSD_AVERAGE_NUM 0x3000 +#define BIQPATH_CONTROL 0xc00 +#define BPSD_FREQ 0x3ff +#define BPSD_ANTENNA_PATH 0x30 +#define BPSD_IQ_SWITCH 0x40 +#define BPSD_RX_TRIGGER 0x400000 +#define BPSD_TX_TRIGGER 0x80000000 +#define BPSD_SINE_TONE_SCALE 0x7f000000 +#define BPSD_REPORT 0xffff + +#define BOFDM_TXSC 0x30000000 +#define BCCK_TXON 0x1 +#define BOFDM_TXON 0x2 +#define BDEBUG_PAGE 0xfff +#define BDEBUG_ITEM 0xff +#define BANTL 0x10 +#define BANT_NONHT 0x100 +#define BANT_HT1 0x1000 +#define BANT_HT2 0x10000 +#define BANT_HT1S1 0x100000 +#define BANT_NONHTS1 0x1000000 + +#define BCCK_BBMODE 0x3 +#define BCCK_TXPOWERSAVING 0x80 +#define BCCK_RXPOWERSAVING 0x40 + +#define BCCK_SIDEBAND 0x10 + +#define BCCK_SCRAMBLE 0x8 +#define BCCK_ANTDIVERSITY 0x8000 +#define BCCK_CARRIER_RECOVERY 0x4000 +#define BCCK_TXRATE 0x3000 +#define BCCK_DCCANCEL 0x0800 +#define BCCK_ISICANCEL 0x0400 +#define BCCK_MATCH_FILTER 0x0200 +#define BCCK_EQUALIZER 0x0100 +#define BCCK_PREAMBLE_DETECT 0x800000 +#define BCCK_FAST_FALSECCA 0x400000 +#define BCCK_CH_ESTSTART 0x300000 +#define BCCK_CCA_COUNT 0x080000 +#define BCCK_CS_LIM 0x070000 +#define BCCK_BIST_MODE 0x80000000 +#define BCCK_CCAMASK 0x40000000 +#define BCCK_TX_DAC_PHASE 0x4 +#define BCCK_RX_ADC_PHASE 0x20000000 +#define BCCKR_CP_MODE 0x0100 +#define BCCK_TXDC_OFFSET 0xf0 +#define BCCK_RXDC_OFFSET 0xf +#define BCCK_CCA_MODE 0xc000 +#define BCCK_FALSECS_LIM 0x3f00 +#define BCCK_CS_RATIO 0xc00000 +#define BCCK_CORGBIT_SEL 0x300000 +#define BCCK_PD_LIM 0x0f0000 +#define BCCK_NEWCCA 0x80000000 +#define BCCK_RXHP_OF_IG 0x8000 +#define BCCK_RXIG 0x7f00 +#define BCCK_LNA_POLARITY 0x800000 +#define BCCK_RX1ST_BAIN 0x7f0000 +#define BCCK_RF_EXTEND 0x20000000 +#define BCCK_RXAGC_SATLEVEL 0x1f000000 +#define BCCK_RXAGC_SATCOUNT 0xe0 +#define BCCK_RX_RF_SETTLE 0x1f +#define BCCK_FIXED_RXAGC 0x8000 +#define BCCK_ANTENNA_POLARITY 0x2000 +#define BCCK_TXFILTER_TYPE 0x0c00 +#define BCCK_RXAGC_REPORTTYPE 0x0300 +#define BCCK_RXDAGC_EN 0x80000000 +#define BCCK_RXDAGC_PERIOD 0x20000000 +#define BCCK_RXDAGC_SATLEVEL 0x1f000000 +#define BCCK_TIMING_RECOVERY 0x800000 +#define BCCK_TXC0 0x3f0000 +#define BCCK_TXC1 0x3f000000 +#define BCCK_TXC2 0x3f +#define BCCK_TXC3 0x3f00 +#define BCCK_TXC4 0x3f0000 +#define BCCK_TXC5 0x3f000000 +#define BCCK_TXC6 0x3f +#define BCCK_TXC7 0x3f00 +#define BCCK_DEBUGPORT 0xff0000 +#define BCCK_DAC_DEBUG 0x0f000000 +#define BCCK_FALSEALARM_ENABLE 0x8000 +#define BCCK_FALSEALARM_READ 0x4000 +#define BCCK_TRSSI 0x7f +#define BCCK_RXAGC_REPORT 0xfe +#define BCCK_RXREPORT_ANTSEL 0x80000000 +#define BCCK_RXREPORT_MFOFF 0x40000000 +#define BCCK_RXREPORT_SQLOSS 0x20000000 +#define BCCK_RXREPORT_PKTLOSS 0x10000000 +#define BCCK_RXREPORT_LOCKEDBIT 0x08000000 +#define BCCK_RXREPORT_RATEERROR 0x04000000 +#define BCCK_RXREPORT_RXRATE 0x03000000 +#define BCCK_RXFA_COUNTER_LOWER 0xff +#define BCCK_RXFA_COUNTER_UPPER 0xff000000 +#define BCCK_RXHPAGC_START 0xe000 +#define BCCK_RXHPAGC_FINAL 0x1c00 +#define BCCK_RXFALSEALARM_ENABLE 0x8000 +#define BCCK_FACOUNTER_FREEZE 0x4000 +#define BCCK_TXPATH_SEL 0x10000000 +#define BCCK_DEFAULT_RXPATH 0xc000000 +#define BCCK_OPTION_RXPATH 0x3000000 + +#define BNUM_OFSTF 0x3 +#define BSHIFT_L 0xc0 +#define BGI_TH 0xc +#define BRXPATH_A 0x1 +#define BRXPATH_B 0x2 +#define BRXPATH_C 0x4 +#define BRXPATH_D 0x8 +#define BTXPATH_A 0x1 +#define BTXPATH_B 0x2 +#define BTXPATH_C 0x4 +#define BTXPATH_D 0x8 +#define BTRSSI_FREQ 0x200 +#define BADC_BACKOFF 0x3000 +#define BDFIR_BACKOFF 0xc000 +#define BTRSSI_LATCH_PHASE 0x10000 +#define BRX_LDC_OFFSET 0xff +#define BRX_QDC_OFFSET 0xff00 +#define BRX_DFIR_MODE 0x1800000 +#define BRX_DCNF_TYPE 0xe000000 +#define BRXIQIMB_A 0x3ff +#define BRXIQIMB_B 0xfc00 +#define BRXIQIMB_C 0x3f0000 +#define BRXIQIMB_D 0xffc00000 +#define BDC_DC_NOTCH 0x60000 +#define BRXNB_NOTCH 0x1f000000 +#define BPD_TH 0xf +#define BPD_TH_OPT2 0xc000 +#define BPWED_TH 0x700 +#define BIFMF_WIN_L 0x800 +#define BPD_OPTION 0x1000 +#define BMF_WIN_L 0xe000 +#define BBW_SEARCH_L 0x30000 +#define BWIN_ENH_L 0xc0000 +#define BBW_TH 0x700000 +#define BED_TH2 0x3800000 +#define BBW_OPTION 0x4000000 +#define BRADIO_TH 0x18000000 +#define BWINDOW_L 0xe0000000 +#define BSBD_OPTION 0x1 +#define BFRAME_TH 0x1c +#define BFS_OPTION 0x60 +#define BDC_SLOPE_CHECK 0x80 +#define BFGUARD_COUNTER_DC_L 0xe00 +#define BFRAME_WEIGHT_SHORT 0x7000 +#define BSUB_TUNE 0xe00000 +#define BFRAME_DC_LENGTH 0xe000000 +#define BSBD_START_OFFSET 0x30000000 +#define BFRAME_TH_2 0x7 +#define BFRAME_GI2_TH 0x38 +#define BGI2_SYNC_EN 0x40 +#define BSARCH_SHORT_EARLY 0x300 +#define BSARCH_SHORT_LATE 0xc00 +#define BSARCH_GI2_LATE 0x70000 +#define BCFOANTSUM 0x1 +#define BCFOACC 0x2 +#define BCFOSTARTOFFSET 0xc +#define BCFOLOOPBACK 0x70 +#define BCFOSUMWEIGHT 0x80 +#define BDAGCENABLE 0x10000 +#define BTXIQIMB_A 0x3ff +#define BTXIQIMB_b 0xfc00 +#define BTXIQIMB_C 0x3f0000 +#define BTXIQIMB_D 0xffc00000 +#define BTXIDCOFFSET 0xff +#define BTXIQDCOFFSET 0xff00 +#define BTXDFIRMODE 0x10000 +#define BTXPESUDO_NOISEON 0x4000000 +#define BTXPESUDO_NOISE_A 0xff +#define BTXPESUDO_NOISE_B 0xff00 +#define BTXPESUDO_NOISE_C 0xff0000 +#define BTXPESUDO_NOISE_D 0xff000000 +#define BCCA_DROPOPTION 0x20000 +#define BCCA_DROPTHRES 0xfff00000 +#define BEDCCA_H 0xf +#define BEDCCA_L 0xf0 +#define BLAMBDA_ED 0x300 +#define BRX_INITIALGAIN 0x7f +#define BRX_ANTDIV_EN 0x80 +#define BRX_AGC_ADDRESS_FOR_LNA 0x7f00 +#define BRX_HIGHPOWER_FLOW 0x8000 +#define BRX_AGC_FREEZE_THRES 0xc0000 +#define BRX_FREEZESTEP_AGC1 0x300000 +#define BRX_FREEZESTEP_AGC2 0xc00000 +#define BRX_FREEZESTEP_AGC3 0x3000000 +#define BRX_FREEZESTEP_AGC0 0xc000000 +#define BRXRSSI_CMP_EN 0x10000000 +#define BRXQUICK_AGCEN 0x20000000 +#define BRXAGC_FREEZE_THRES_MODE 0x40000000 +#define BRX_OVERFLOW_CHECKTYPE 0x80000000 +#define BRX_AGCSHIFT 0x7f +#define BTRSW_TRI_ONLY 0x80 +#define BPOWER_THRES 0x300 +#define BRXAGC_EN 0x1 +#define BRXAGC_TOGETHER_EN 0x2 +#define BRXAGC_MIN 0x4 +#define BRXHP_INI 0x7 +#define BRXHP_TRLNA 0x70 +#define BRXHP_RSSI 0x700 +#define BRXHP_BBP1 0x7000 +#define BRXHP_BBP2 0x70000 +#define BRXHP_BBP3 0x700000 +#define BRSSI_H 0x7f0000 +#define BRSSI_GEN 0x7f000000 +#define BRXSETTLE_TRSW 0x7 +#define BRXSETTLE_LNA 0x38 +#define BRXSETTLE_RSSI 0x1c0 +#define BRXSETTLE_BBP 0xe00 +#define BRXSETTLE_RXHP 0x7000 +#define BRXSETTLE_ANTSW_RSSI 0x38000 +#define BRXSETTLE_ANTSW 0xc0000 +#define BRXPROCESS_TIME_DAGC 0x300000 +#define BRXSETTLE_HSSI 0x400000 +#define BRXPROCESS_TIME_BBPPW 0x800000 +#define BRXANTENNA_POWER_SHIFT 0x3000000 +#define BRSSI_TABLE_SELECT 0xc000000 +#define BRXHP_FINAL 0x7000000 +#define BRXHPSETTLE_BBP 0x7 +#define BRXHTSETTLE_HSSI 0x8 +#define BRXHTSETTLE_RXHP 0x70 +#define BRXHTSETTLE_BBPPW 0x80 +#define BRXHTSETTLE_IDLE 0x300 +#define BRXHTSETTLE_RESERVED 0x1c00 +#define BRXHT_RXHP_EN 0x8000 +#define BRXAGC_FREEZE_THRES 0x30000 +#define BRXAGC_TOGETHEREN 0x40000 +#define BRXHTAGC_MIN 0x80000 +#define BRXHTAGC_EN 0x100000 +#define BRXHTDAGC_EN 0x200000 +#define BRXHT_RXHP_BBP 0x1c00000 +#define BRXHT_RXHP_FINAL 0xe0000000 +#define BRXPW_RADIO_TH 0x3 +#define BRXPW_RADIO_EN 0x4 +#define BRXMF_HOLD 0x3800 +#define BRXPD_DELAY_TH1 0x38 +#define BRXPD_DELAY_TH2 0x1c0 +#define BRXPD_DC_COUNT_MAX 0x600 +#define BRXPD_DELAY_TH 0x8000 +#define BRXPROCESS_DELAY 0xf0000 +#define BRXSEARCHRANGE_GI2_EARLY 0x700000 +#define BRXFRAME_FUARD_COUNTER_L 0x3800000 +#define BRXSGI_GUARD_L 0xc000000 +#define BRXSGI_SEARCH_L 0x30000000 +#define BRXSGI_TH 0xc0000000 +#define BDFSCNT0 0xff +#define BDFSCNT1 0xff00 +#define BDFSFLAG 0xf0000 +#define BMF_WEIGHT_SUM 0x300000 +#define BMINIDX_TH 0x7f000000 +#define BDAFORMAT 0x40000 +#define BTXCH_EMU_ENABLE 0x01000000 +#define BTRSW_ISOLATION_A 0x7f +#define BTRSW_ISOLATION_B 0x7f00 +#define BTRSW_ISOLATION_C 0x7f0000 +#define BTRSW_ISOLATION_D 0x7f000000 +#define BEXT_LNA_GAIN 0x7c00 + +#define BSTBC_EN 0x4 +#define BANTENNA_MAPPING 0x10 +#define BNSS 0x20 +#define BCFO_ANTSUM_ID 0x200 +#define BPHY_COUNTER_RESET 0x8000000 +#define BCFO_REPORT_GET 0x4000000 +#define BOFDM_CONTINUE_TX 0x10000000 +#define BOFDM_SINGLE_CARRIER 0x20000000 +#define BOFDM_SINGLE_TONE 0x40000000 +#define BHT_DETECT 0x100 +#define BCFOEN 0x10000 +#define BCFOVALUE 0xfff00000 +#define BSIGTONE_RE 0x3f +#define BSIGTONE_IM 0x7f00 +#define BCOUNTER_CCA 0xffff +#define BCOUNTER_PARITYFAIL 0xffff0000 +#define BCOUNTER_RATEILLEGAL 0xffff +#define BCOUNTER_CRC8FAIL 0xffff0000 +#define BCOUNTER_MCSNOSUPPORT 0xffff +#define BCOUNTER_FASTSYNC 0xffff +#define BSHORTCFO 0xfff +#define BSHORTCFOT_LENGTH 12 +#define BSHORTCFOF_LENGTH 11 +#define BLONGCFO 0x7ff +#define BLONGCFOT_LENGTH 11 +#define BLONGCFOF_LENGTH 11 +#define BTAILCFO 0x1fff +#define BTAILCFOT_LENGTH 13 +#define BTAILCFOF_LENGTH 12 +#define BNOISE_EN_PWDB 0xffff +#define BCC_POWER_DB 0xffff0000 +#define BMOISE_PWDB 0xffff +#define BPOWERMEAST_LENGTH 10 +#define BPOWERMEASF_LENGTH 3 +#define BRX_HT_BW 0x1 +#define BRXSC 0x6 +#define BRX_HT 0x8 +#define BNB_INTF_DET_ON 0x1 +#define BINTF_WIN_LEN_CFG 0x30 +#define BNB_INTF_TH_CFG 0x1c0 +#define BRFGAIN 0x3f +#define BTABLESEL 0x40 +#define BTRSW 0x80 +#define BRXSNR_A 0xff +#define BRXSNR_B 0xff00 +#define BRXSNR_C 0xff0000 +#define BRXSNR_D 0xff000000 +#define BSNR_EVMT_LENGTH 8 +#define BSNR_EVMF_LENGTH 1 +#define BCSI1ST 0xff +#define BCSI2ND 0xff00 +#define BRXEVM1ST 0xff0000 +#define BRXEVM2ND 0xff000000 +#define BSIGEVM 0xff +#define BPWDB 0xff00 +#define BSGIEN 0x10000 + +#define BSFACTOR_QMA1 0xf +#define BSFACTOR_QMA2 0xf0 +#define BSFACTOR_QMA3 0xf00 +#define BSFACTOR_QMA4 0xf000 +#define BSFACTOR_QMA5 0xf0000 +#define BSFACTOR_QMA6 0xf0000 +#define BSFACTOR_QMA7 0xf00000 +#define BSFACTOR_QMA8 0xf000000 +#define BSFACTOR_QMA9 0xf0000000 +#define BCSI_SCHEME 0x100000 + +#define BNOISE_LVL_TOP_SET 0x3 +#define BCHSMOOTH 0x4 +#define BCHSMOOTH_CFG1 0x38 +#define BCHSMOOTH_CFG2 0x1c0 +#define BCHSMOOTH_CFG3 0xe00 +#define BCHSMOOTH_CFG4 0x7000 +#define BMRCMODE 0x800000 +#define BTHEVMCFG 0x7000000 + +#define BLOOP_FIT_TYPE 0x1 +#define BUPD_CFO 0x40 +#define BUPD_CFO_OFFDATA 0x80 +#define BADV_UPD_CFO 0x100 +#define BADV_TIME_CTRL 0x800 +#define BUPD_CLKO 0x1000 +#define BFC 0x6000 +#define BTRACKING_MODE 0x8000 +#define BPHCMP_ENABLE 0x10000 +#define BUPD_CLKO_LTF 0x20000 +#define BCOM_CH_CFO 0x40000 +#define BCSI_ESTI_MODE 0x80000 +#define BADV_UPD_EQZ 0x100000 +#define BUCHCFG 0x7000000 +#define BUPDEQZ 0x8000000 + +#define BRX_PESUDO_NOISE_ON 0x20000000 +#define BRX_PESUDO_NOISE_A 0xff +#define BRX_PESUDO_NOISE_B 0xff00 +#define BRX_PESUDO_NOISE_C 0xff0000 +#define BRX_PESUDO_NOISE_D 0xff000000 +#define BRX_PESUDO_NOISESTATE_A 0xffff +#define BRX_PESUDO_NOISESTATE_B 0xffff0000 +#define BRX_PESUDO_NOISESTATE_C 0xffff +#define BRX_PESUDO_NOISESTATE_D 0xffff0000 + +#define BZEBRA1_HSSIENABLE 0x8 +#define BZEBRA1_TRXCONTROL 0xc00 +#define BZEBRA1_TRXGAINSETTING 0x07f +#define BZEBRA1_RXCOUNTER 0xc00 +#define BZEBRA1_TXCHANGEPUMP 0x38 +#define BZEBRA1_RXCHANGEPUMP 0x7 +#define BZEBRA1_CHANNEL_NUM 0xf80 +#define BZEBRA1_TXLPFBW 0x400 +#define BZEBRA1_RXLPFBW 0x600 + +#define BRTL8256REG_MODE_CTRL1 0x100 +#define BRTL8256REG_MODE_CTRL0 0x40 +#define BRTL8256REG_TXLPFBW 0x18 +#define BRTL8256REG_RXLPFBW 0x600 + +#define BRTL8258_TXLPFBW 0xc +#define BRTL8258_RXLPFBW 0xc00 +#define BRTL8258_RSSILPFBW 0xc0 + +#define BBYTE0 0x1 +#define BBYTE1 0x2 +#define BBYTE2 0x4 +#define BBYTE3 0x8 +#define BWORD0 0x3 +#define BWORD1 0xc +#define BWORD 0xf + +#define MASKBYTE0 0xff +#define MASKBYTE1 0xff00 +#define MASKBYTE2 0xff0000 +#define MASKBYTE3 0xff000000 +#define MASKHWORD 0xffff0000 +#define MASKLWORD 0x0000ffff +#define MASKDWORD 0xffffffff +#define MASK12BITS 0xfff +#define MASKH4BITS 0xf0000000 +#define MASKOFDM_D 0xffc00000 +#define MASKCCK 0x3f3f3f3f + +#define MASK4BITS 0x0f +#define MASK20BITS 0xfffff +#define RFREG_OFFSET_MASK 0xfffff + +#define BMASKBYTE0 0xff +#define BMASKBYTE1 0xff00 +#define BMASKBYTE2 0xff0000 +#define BMASKBYTE3 0xff000000 +#define BMASKHWORD 0xffff0000 +#define BMASKLWORD 0x0000ffff +#define BMASKDWORD 0xffffffff +#define BMASK12BITS 0xfff +#define BMASKH4BITS 0xf0000000 +#define BMASKOFDM_D 0xffc00000 +#define BMASKCCK 0x3f3f3f3f + +#define BRFREGOFFSETMASK 0xfffff + +/* WOL bit information */ +#define WOL_REASON_PTK_UPDATE BIT(0) +#define WOL_REASON_GTK_UPDATE BIT(1) +#define WOL_REASON_DISASSOC BIT(2) +#define WOL_REASON_DEAUTH BIT(3) +#define WOL_REASON_FW_DISCONNECT BIT(4) + +#endif diff --git a/drivers/staging/rtlwifi/rtl8822be/sw.c b/drivers/staging/rtlwifi/rtl8822be/sw.c new file mode 100644 index 000000000000..91b784b6d1c5 --- /dev/null +++ b/drivers/staging/rtlwifi/rtl8822be/sw.c @@ -0,0 +1,481 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../core.h" +#include "../pci.h" +#include "../base.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "hw.h" +#include "sw.h" +#include "fw.h" +#include "trx.h" +#include "led.h" +#include "../btcoexist/rtl_btc.h" +#include "../halmac/rtl_halmac.h" +#include "../phydm/rtl_phydm.h" +#include <linux/vmalloc.h> +#include <linux/module.h> + +static void rtl8822be_init_aspm_vars(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + + /*close ASPM for AMD defaultly */ + rtlpci->const_amdpci_aspm = 0; + + /* + * ASPM PS mode. + * 0 - Disable ASPM, + * 1 - Enable ASPM without Clock Req, + * 2 - Enable ASPM with Clock Req, + * 3 - Alwyas Enable ASPM with Clock Req, + * 4 - Always Enable ASPM without Clock Req. + * set default to RTL8822BE:3 RTL8822B:2 + * + */ + rtlpci->const_pci_aspm = 3; + + /*Setting for PCI-E device */ + rtlpci->const_devicepci_aspm_setting = 0x03; + + /*Setting for PCI-E bridge */ + rtlpci->const_hostpci_aspm_setting = 0x02; + + /* + * In Hw/Sw Radio Off situation. + * 0 - Default, + * 1 - From ASPM setting without low Mac Pwr, + * 2 - From ASPM setting with low Mac Pwr, + * 3 - Bus D3 + * set default to RTL8822BE:0 RTL8192SE:2 + */ + rtlpci->const_hwsw_rfoff_d3 = 0; + + /* + * This setting works for those device with + * backdoor ASPM setting such as EPHY setting. + * 0 - Not support ASPM, + * 1 - Support ASPM, + * 2 - According to chipset. + */ + rtlpci->const_support_pciaspm = rtlpriv->cfg->mod_params->aspm_support; +} + +int rtl8822be_init_sw_vars(struct ieee80211_hw *hw) +{ + int err = 0; + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + const char *fw_name; + struct rtl_phydm_params params; + + rtl8822be_bt_reg_init(hw); + rtlpci->msi_support = rtlpriv->cfg->mod_params->msi_support; + rtlpriv->btcoexist.btc_ops = rtl_btc_get_ops_pointer(); + rtlpriv->halmac.ops = rtl_halmac_get_ops_pointer(); + rtlpriv->halmac.ops->halmac_init_adapter(rtlpriv); + + /* should after halmac_init_adapter() */ + rtl8822be_read_eeprom_info(hw, ¶ms); + + /* need eeprom info */ + rtlpriv->phydm.ops = rtl_phydm_get_ops_pointer(); + rtlpriv->phydm.ops->phydm_init_priv(rtlpriv, ¶ms); + + rtlpriv->dm.dm_initialgain_enable = 1; + rtlpriv->dm.dm_flag = 0; + rtlpriv->dm.disable_framebursting = 0; + /*rtlpriv->dm.thermalvalue = 0;*/ + rtlpriv->dm.useramask = 1; /* turn on RA */ + rtlpci->transmit_config = CFENDFORM | BIT(15); + + rtlpriv->rtlhal.current_bandtype = BAND_ON_2_4G; + /*following 2 is for register 5G band, refer to _rtl_init_mac80211()*/ + rtlpriv->rtlhal.bandset = BAND_ON_BOTH; + rtlpriv->rtlhal.macphymode = SINGLEMAC_SINGLEPHY; + + rtlpci->receive_config = (RCR_APPFCS | + RCR_APP_MIC | + RCR_APP_ICV | + RCR_APP_PHYST_RXFF | + RCR_VHT_DACK | + RCR_HTC_LOC_CTRL | + /*RCR_AMF |*/ + RCR_CBSSID_BCN | + RCR_CBSSID_DATA | + /*RCR_ACF |*/ + /*RCR_ADF |*/ + /*RCR_AICV |*/ + /*RCR_ACRC32 |*/ + RCR_AB | + RCR_AM | + RCR_APM | + 0); + + rtlpci->irq_mask[0] = (u32)(IMR_PSTIMEOUT | + /*IMR_TBDER |*/ + /*IMR_TBDOK |*/ + /*IMR_BCNDMAINT0 |*/ + IMR_GTINT3 | + IMR_HSISR_IND_ON_INT | + IMR_C2HCMD | + IMR_HIGHDOK | + IMR_MGNTDOK | + IMR_BKDOK | + IMR_BEDOK | + IMR_VIDOK | + IMR_VODOK | + IMR_RDU | + IMR_ROK | + 0); + + rtlpci->irq_mask[1] = (u32)(IMR_RXFOVW | IMR_TXFOVW | 0); + rtlpci->irq_mask[3] = (u32)(BIT_SETH2CDOK_MASK | 0); + + /* for LPS & IPS */ + rtlpriv->psc.inactiveps = rtlpriv->cfg->mod_params->inactiveps; + rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps; + rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps; + rtlpci->msi_support = rtlpriv->cfg->mod_params->msi_support; + if (rtlpriv->cfg->mod_params->disable_watchdog) + pr_info("watchdog disabled\n"); + rtlpriv->psc.reg_fwctrl_lps = 2; + rtlpriv->psc.reg_max_lps_awakeintvl = 2; + /* for ASPM, you can close aspm through + * set const_support_pciaspm = 0 + */ + rtl8822be_init_aspm_vars(hw); + + if (rtlpriv->psc.reg_fwctrl_lps == 1) + rtlpriv->psc.fwctrl_psmode = FW_PS_MIN_MODE; + else if (rtlpriv->psc.reg_fwctrl_lps == 2) + rtlpriv->psc.fwctrl_psmode = FW_PS_MAX_MODE; + else if (rtlpriv->psc.reg_fwctrl_lps == 3) + rtlpriv->psc.fwctrl_psmode = FW_PS_DTIM_MODE; + + /* for early mode */ + rtlpriv->rtlhal.earlymode_enable = false; + + /*low power */ + rtlpriv->psc.low_power_enable = false; + + /* for firmware buf */ + rtlpriv->rtlhal.pfirmware = vzalloc(0x40000); + if (!rtlpriv->rtlhal.pfirmware) { + /*pr_err("Can't alloc buffer for fw\n");*/ + return 1; + } + + /* request fw */ + fw_name = "rtlwifi/rtl8822befw.bin"; + + rtlpriv->max_fw_size = 0x40000; + pr_info("Using firmware %s\n", fw_name); + err = request_firmware_nowait(THIS_MODULE, 1, fw_name, rtlpriv->io.dev, + GFP_KERNEL, hw, rtl_fw_cb); + if (err) { + pr_err("Failed to request firmware!\n"); + return 1; + } + + /* init table of tx power by rate & limit */ + rtl8822be_load_txpower_by_rate(hw); + rtl8822be_load_txpower_limit(hw); + + return 0; +} + +void rtl8822be_deinit_sw_vars(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtlpriv->halmac.ops->halmac_deinit_adapter(rtlpriv); + rtlpriv->phydm.ops->phydm_deinit_priv(rtlpriv); + + if (rtlpriv->rtlhal.pfirmware) { + vfree(rtlpriv->rtlhal.pfirmware); + rtlpriv->rtlhal.pfirmware = NULL; + } +} + +/* get bt coexist status */ +bool rtl8822be_get_btc_status(void) +{ + return true; +} + +static void rtl8822be_phydm_watchdog(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 tmp; + + tmp = rtl_read_dword(rtlpriv, 0xc00); + if (tmp & 0xFF000000) { /* Recover 0xC00: 0xF800000C --> 0x0000000C */ + RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, + "found regaddr_c00=%08X\n", tmp); + tmp &= ~0xFF000000; + rtl_write_dword(rtlpriv, 0xc00, tmp); + RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, + "apply regaddr_c00=%08X\n", tmp); + } + + rtlpriv->phydm.ops->phydm_watchdog(rtlpriv); +} + +static struct rtl_hal_ops rtl8822be_hal_ops = { + .init_sw_vars = rtl8822be_init_sw_vars, + .deinit_sw_vars = rtl8822be_deinit_sw_vars, + .read_eeprom_info = rtl8822be_read_eeprom_info_dummy, + .interrupt_recognized = rtl8822be_interrupt_recognized, + .hw_init = rtl8822be_hw_init, + .hw_disable = rtl8822be_card_disable, + .hw_suspend = rtl8822be_suspend, + .hw_resume = rtl8822be_resume, + .enable_interrupt = rtl8822be_enable_interrupt, + .disable_interrupt = rtl8822be_disable_interrupt, + .set_network_type = rtl8822be_set_network_type, + .set_chk_bssid = rtl8822be_set_check_bssid, + .set_qos = rtl8822be_set_qos, + .set_bcn_reg = rtl8822be_set_beacon_related_registers, + .set_bcn_intv = rtl8822be_set_beacon_interval, + .update_interrupt_mask = rtl8822be_update_interrupt_mask, + .get_hw_reg = rtl8822be_get_hw_reg, + .set_hw_reg = rtl8822be_set_hw_reg, + .update_rate_tbl = rtl8822be_update_hal_rate_tbl, + .pre_fill_tx_bd_desc = rtl8822be_pre_fill_tx_bd_desc, + .rx_desc_buff_remained_cnt = rtl8822be_rx_desc_buff_remained_cnt, + .rx_check_dma_ok = rtl8822be_rx_check_dma_ok, + .fill_tx_desc = rtl8822be_tx_fill_desc, + .fill_tx_special_desc = rtl8822be_tx_fill_special_desc, + .query_rx_desc = rtl8822be_rx_query_desc, + .radio_onoff_checking = rtl8822be_gpio_radio_on_off_checking, + .switch_channel = rtl8822be_phy_sw_chnl, + .set_channel_access = rtl8822be_update_channel_access_setting, + .set_bw_mode = rtl8822be_phy_set_bw_mode, + .dm_watchdog = rtl8822be_phydm_watchdog, + .scan_operation_backup = rtl8822be_phy_scan_operation_backup, + .set_rf_power_state = rtl8822be_phy_set_rf_power_state, + .led_control = rtl8822be_led_control, + .set_desc = rtl8822be_set_desc, + .get_desc = rtl8822be_get_desc, + .is_tx_desc_closed = rtl8822be_is_tx_desc_closed, + .get_available_desc = rtl8822be_get_available_desc, + .tx_polling = rtl8822be_tx_polling, + .enable_hw_sec = rtl8822be_enable_hw_security_config, + .set_key = rtl8822be_set_key, + .init_sw_leds = rtl8822be_init_sw_leds, + .get_bbreg = rtl8822be_phy_query_bb_reg, + .set_bbreg = rtl8822be_phy_set_bb_reg, + .get_rfreg = rtl8822be_phy_query_rf_reg, + .set_rfreg = rtl8822be_phy_set_rf_reg, + .fill_h2c_cmd = rtl8822be_fill_h2c_cmd, + .set_default_port_id_cmd = rtl8822be_set_default_port_id_cmd, + .get_btc_status = rtl8822be_get_btc_status, + .rx_command_packet = rtl8822be_rx_command_packet, + .c2h_content_parsing = rtl8822be_c2h_content_parsing, + /* ops for halmac cb */ + .halmac_cb_init_mac_register = rtl8822be_halmac_cb_init_mac_register, + .halmac_cb_init_bb_rf_register = + rtl8822be_halmac_cb_init_bb_rf_register, + .halmac_cb_write_data_rsvd_page = + rtl8822b_halmac_cb_write_data_rsvd_page, + .halmac_cb_write_data_h2c = rtl8822b_halmac_cb_write_data_h2c, + /* ops for phydm cb */ + .get_txpower_index = rtl8822be_get_txpower_index, + .set_tx_power_index_by_rs = rtl8822be_phy_set_tx_power_index_by_rs, + .store_tx_power_by_rate = rtl8822be_store_tx_power_by_rate, + .phy_set_txpower_limit = rtl8822be_phy_set_txpower_limit, +}; + +static struct rtl_mod_params rtl8822be_mod_params = { + .sw_crypto = false, + .inactiveps = true, + .swctrl_lps = false, + .fwctrl_lps = true, + .msi_support = true, + .dma64 = false, + .aspm_support = 1, + .disable_watchdog = false, + .debug_level = 0, + .debug_mask = 0, +}; + +static struct rtl_hal_cfg rtl8822be_hal_cfg = { + .bar_id = 2, + .write_readback = false, + .name = "rtl8822be_pci", + .ops = &rtl8822be_hal_ops, + .mod_params = &rtl8822be_mod_params, + .spec_ver = RTL_SPEC_NEW_RATEID | RTL_SPEC_SUPPORT_VHT | + RTL_SPEC_NEW_FW_C2H, + .maps[SYS_ISO_CTRL] = REG_SYS_ISO_CTRL_8822B, + .maps[SYS_FUNC_EN] = REG_SYS_FUNC_EN_8822B, + .maps[SYS_CLK] = REG_SYS_CLK_CTRL_8822B, + .maps[MAC_RCR_AM] = AM, + .maps[MAC_RCR_AB] = AB, + .maps[MAC_RCR_ACRC32] = ACRC32, + .maps[MAC_RCR_ACF] = ACF, + .maps[MAC_RCR_AAP] = AAP, + .maps[MAC_HIMR] = REG_HIMR0_8822B, + .maps[MAC_HIMRE] = REG_HIMR1_8822B, + + .maps[EFUSE_ACCESS] = REG_EFUSE_ACCESS_8822B, + + .maps[EFUSE_TEST] = REG_LDO_EFUSE_CTRL_8822B, + .maps[EFUSE_CTRL] = REG_EFUSE_CTRL_8822B, + .maps[EFUSE_CLK] = 0, + .maps[EFUSE_CLK_CTRL] = REG_EFUSE_CTRL_8822B, + .maps[EFUSE_PWC_EV12V] = PWC_EV12V, + .maps[EFUSE_FEN_ELDR] = FEN_ELDR, + .maps[EFUSE_LOADER_CLK_EN] = LOADER_CLK_EN, + .maps[EFUSE_ANA8M] = ANA8M, + .maps[EFUSE_HWSET_MAX_SIZE] = HWSET_MAX_SIZE, + .maps[EFUSE_MAX_SECTION_MAP] = EFUSE_MAX_SECTION, + .maps[EFUSE_REAL_CONTENT_SIZE] = EFUSE_REAL_CONTENT_LEN, + .maps[EFUSE_OOB_PROTECT_BYTES_LEN] = EFUSE_OOB_PROTECT_BYTES, + + .maps[RWCAM] = REG_CAMCMD_8822B, + .maps[WCAMI] = REG_CAMWRITE_8822B, + .maps[RCAMO] = REG_CAMREAD_8822B, + .maps[CAMDBG] = REG_CAMDBG_8822B, + .maps[SECR] = REG_SECCFG_8822B, + .maps[SEC_CAM_NONE] = CAM_NONE, + .maps[SEC_CAM_WEP40] = CAM_WEP40, + .maps[SEC_CAM_TKIP] = CAM_TKIP, + .maps[SEC_CAM_AES] = CAM_AES, + .maps[SEC_CAM_WEP104] = CAM_WEP104, + + .maps[RTL_IMR_BCNDMAINT6] = IMR_BCNDMAINT6, + .maps[RTL_IMR_BCNDMAINT5] = IMR_BCNDMAINT5, + .maps[RTL_IMR_BCNDMAINT4] = IMR_BCNDMAINT4, + .maps[RTL_IMR_BCNDMAINT3] = IMR_BCNDMAINT3, + .maps[RTL_IMR_BCNDMAINT2] = IMR_BCNDMAINT2, + .maps[RTL_IMR_BCNDMAINT1] = IMR_BCNDMAINT1, + /* .maps[RTL_IMR_BCNDOK8] = IMR_BCNDOK8, */ /*need check*/ + .maps[RTL_IMR_BCNDOK7] = IMR_BCNDOK7, + .maps[RTL_IMR_BCNDOK6] = IMR_BCNDOK6, + .maps[RTL_IMR_BCNDOK5] = IMR_BCNDOK5, + .maps[RTL_IMR_BCNDOK4] = IMR_BCNDOK4, + .maps[RTL_IMR_BCNDOK3] = IMR_BCNDOK3, + .maps[RTL_IMR_BCNDOK2] = IMR_BCNDOK2, + .maps[RTL_IMR_BCNDOK1] = IMR_BCNDOK1, + /* .maps[RTL_IMR_TIMEOUT2] = IMR_TIMEOUT2,*/ + /* .maps[RTL_IMR_TIMEOUT1] = IMR_TIMEOUT1,*/ + + .maps[RTL_IMR_TXFOVW] = IMR_TXFOVW, + .maps[RTL_IMR_PSTIMEOUT] = IMR_PSTIMEOUT, + .maps[RTL_IMR_BCNINT] = IMR_BCNDMAINT0, + .maps[RTL_IMR_RXFOVW] = IMR_RXFOVW, + .maps[RTL_IMR_RDU] = IMR_RDU, + .maps[RTL_IMR_ATIMEND] = IMR_ATIMEND, + .maps[RTL_IMR_H2CDOK] = IMR_H2CDOK, + .maps[RTL_IMR_BDOK] = IMR_BCNDOK0, + .maps[RTL_IMR_MGNTDOK] = IMR_MGNTDOK, + .maps[RTL_IMR_TBDER] = IMR_TBDER, + .maps[RTL_IMR_HIGHDOK] = IMR_HIGHDOK, + .maps[RTL_IMR_TBDOK] = IMR_TBDOK, + .maps[RTL_IMR_BKDOK] = IMR_BKDOK, + .maps[RTL_IMR_BEDOK] = IMR_BEDOK, + .maps[RTL_IMR_VIDOK] = IMR_VIDOK, + .maps[RTL_IMR_VODOK] = IMR_VODOK, + .maps[RTL_IMR_ROK] = IMR_ROK, + .maps[RTL_IBSS_INT_MASKS] = (IMR_BCNDMAINT0 | IMR_TBDOK | IMR_TBDER), + + .maps[RTL_RC_CCK_RATE1M] = DESC_RATE1M, + .maps[RTL_RC_CCK_RATE2M] = DESC_RATE2M, + .maps[RTL_RC_CCK_RATE5_5M] = DESC_RATE5_5M, + .maps[RTL_RC_CCK_RATE11M] = DESC_RATE11M, + .maps[RTL_RC_OFDM_RATE6M] = DESC_RATE6M, + .maps[RTL_RC_OFDM_RATE9M] = DESC_RATE9M, + .maps[RTL_RC_OFDM_RATE12M] = DESC_RATE12M, + .maps[RTL_RC_OFDM_RATE18M] = DESC_RATE18M, + .maps[RTL_RC_OFDM_RATE24M] = DESC_RATE24M, + .maps[RTL_RC_OFDM_RATE36M] = DESC_RATE36M, + .maps[RTL_RC_OFDM_RATE48M] = DESC_RATE48M, + .maps[RTL_RC_OFDM_RATE54M] = DESC_RATE54M, + + .maps[RTL_RC_HT_RATEMCS7] = DESC_RATEMCS7, + .maps[RTL_RC_HT_RATEMCS15] = DESC_RATEMCS15, + + /*VHT hightest rate*/ + .maps[RTL_RC_VHT_RATE_1SS_MCS7] = DESC_RATEVHT1SS_MCS7, + .maps[RTL_RC_VHT_RATE_1SS_MCS8] = DESC_RATEVHT1SS_MCS8, + .maps[RTL_RC_VHT_RATE_1SS_MCS9] = DESC_RATEVHT1SS_MCS9, + .maps[RTL_RC_VHT_RATE_2SS_MCS7] = DESC_RATEVHT2SS_MCS7, + .maps[RTL_RC_VHT_RATE_2SS_MCS8] = DESC_RATEVHT2SS_MCS8, + .maps[RTL_RC_VHT_RATE_2SS_MCS9] = DESC_RATEVHT2SS_MCS9, +}; + +static const struct pci_device_id rtl8822be_pci_ids[] = { + {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0xB822, rtl8822be_hal_cfg)}, + {}, +}; + +MODULE_DEVICE_TABLE(pci, rtl8822be_pci_ids); + +MODULE_AUTHOR("Realtek WlanFAE <wlanfae@realtek.com>"); +MODULE_AUTHOR("Larry Finger <Larry.Finger@lwfinger.net>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Realtek 8822BE 802.11n PCI wireless"); +MODULE_FIRMWARE("rtlwifi/rtl8822befw.bin"); + +module_param_named(swenc, rtl8822be_mod_params.sw_crypto, bool, 0444); +module_param_named(debug_level, rtl8822be_mod_params.debug_level, int, 0644); +module_param_named(debug_mask, rtl8822be_mod_params.debug_mask, ullong, 0644); +module_param_named(ips, rtl8822be_mod_params.inactiveps, bool, 0444); +module_param_named(swlps, rtl8822be_mod_params.swctrl_lps, bool, 0444); +module_param_named(fwlps, rtl8822be_mod_params.fwctrl_lps, bool, 0444); +module_param_named(msi, rtl8822be_mod_params.msi_support, bool, 0444); +module_param_named(dma64, rtl8822be_mod_params.dma64, bool, 0444); +module_param_named(aspm, rtl8822be_mod_params.aspm_support, int, 0444); +module_param_named(disable_watchdog, rtl8822be_mod_params.disable_watchdog, + bool, 0444); +MODULE_PARM_DESC(swenc, "Set to 1 for software crypto (default 0)\n"); +MODULE_PARM_DESC(ips, "Set to 0 to not use link power save (default 1)\n"); +MODULE_PARM_DESC(swlps, "Set to 1 to use SW control power save (default 0)\n"); +MODULE_PARM_DESC(fwlps, "Set to 1 to use FW control power save (default 1)\n"); +MODULE_PARM_DESC(msi, "Set to 1 to use MSI interrupts mode (default 1)\n"); +MODULE_PARM_DESC(dma64, "Set to 1 to use DMA 64 (default 0)\n"); +MODULE_PARM_DESC(aspm, "Set to 1 to enable ASPM (default 1)\n"); +MODULE_PARM_DESC(debug, "Set debug level (0-5) (default 0)"); +MODULE_PARM_DESC(debug_mask, "Set debug mask (default 0)"); +MODULE_PARM_DESC(disable_watchdog, + "Set to 1 to disable the watchdog (default 0)\n"); + +static SIMPLE_DEV_PM_OPS(rtlwifi_pm_ops, rtl_pci_suspend, rtl_pci_resume); + +static struct pci_driver rtl8822be_driver = { + .name = KBUILD_MODNAME, + .id_table = rtl8822be_pci_ids, + .probe = rtl_pci_probe, + .remove = rtl_pci_disconnect, + .driver.pm = &rtlwifi_pm_ops, +}; + +module_pci_driver(rtl8822be_driver); diff --git a/drivers/staging/rtlwifi/rtl8822be/sw.h b/drivers/staging/rtlwifi/rtl8822be/sw.h new file mode 100644 index 000000000000..931eba98bd80 --- /dev/null +++ b/drivers/staging/rtlwifi/rtl8822be/sw.h @@ -0,0 +1,32 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL8822B_SW_H__ +#define __RTL8822B_SW_H__ + +int rtl8822be_init_sw_vars(struct ieee80211_hw *hw); +void rtl8822be_deinit_sw_vars(struct ieee80211_hw *hw); +bool rtl8822be_get_btc_status(void); +#endif diff --git a/drivers/staging/rtlwifi/rtl8822be/trx.c b/drivers/staging/rtlwifi/rtl8822be/trx.c new file mode 100644 index 000000000000..38f80e48a399 --- /dev/null +++ b/drivers/staging/rtlwifi/rtl8822be/trx.c @@ -0,0 +1,1015 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../pci.h" +#include "../base.h" +#include "../stats.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "trx.h" +#include "led.h" +#include "fw.h" + +#include <linux/vermagic.h> + +static u8 _rtl8822be_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 hw_queue) +{ + switch (hw_queue) { + case BEACON_QUEUE: + return QSLT_BEACON; + case H2C_QUEUE: + return QSLT_CMD; + case MGNT_QUEUE: + return QSLT_MGNT; + case HIGH_QUEUE: + return QSLT_HIGH; + default: + return skb->priority; + } +} + +static void _rtl8822be_query_rxphystatus(struct ieee80211_hw *hw, u8 *phystrpt, + struct ieee80211_hdr *hdr, + struct rtl_stats *pstatus) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtlpriv->phydm.ops->phydm_query_phy_status(rtlpriv, phystrpt, hdr, + pstatus); + + /* UI BSS List signal strength(in percentage), + * make it good looking, from 0~100. + */ + pstatus->signalstrength = + (u8)(rtl_signal_scale_mapping(hw, pstatus->rx_pwdb_all)); +} + +static void _rtl8822be_translate_rx_signal_stuff(struct ieee80211_hw *hw, + struct sk_buff *skb, + struct rtl_stats *pstatus, + u8 *p_phystrpt) +{ + struct ieee80211_hdr *hdr; + u8 *tmp_buf; + + tmp_buf = skb->data + pstatus->rx_drvinfo_size + pstatus->rx_bufshift + + 24; + + hdr = (struct ieee80211_hdr *)tmp_buf; + + /* query phy status */ + _rtl8822be_query_rxphystatus(hw, p_phystrpt, hdr, pstatus); + + /* packet statistics */ + if (pstatus->packet_beacon && pstatus->packet_matchbssid) + rtl_priv(hw)->dm.dbginfo.num_qry_beacon_pkt++; + + if (pstatus->packet_matchbssid && + ieee80211_is_data_qos(hdr->frame_control) && + !is_multicast_ether_addr(ieee80211_get_DA(hdr))) { + struct ieee80211_qos_hdr *hdr_qos = + (struct ieee80211_qos_hdr *)tmp_buf; + u16 tid = le16_to_cpu(hdr_qos->qos_ctrl) & 0xf; + + if (tid != 0 && tid != 3) + rtl_priv(hw)->dm.dbginfo.num_non_be_pkt++; + } + + /* signal statistics */ + if (p_phystrpt) + rtl_process_phyinfo(hw, tmp_buf, pstatus); +} + +static void _rtl8822be_insert_emcontent(struct rtl_tcb_desc *ptcb_desc, + u8 *virtualaddress) +{ + u32 dwtmp = 0; + + memset(virtualaddress, 0, 8); + + SET_EARLYMODE_PKTNUM(virtualaddress, ptcb_desc->empkt_num); + if (ptcb_desc->empkt_num == 1) { + dwtmp = ptcb_desc->empkt_len[0]; + } else { + dwtmp = ptcb_desc->empkt_len[0]; + dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0) + 4; + dwtmp += ptcb_desc->empkt_len[1]; + } + SET_EARLYMODE_LEN0(virtualaddress, dwtmp); + + if (ptcb_desc->empkt_num <= 3) { + dwtmp = ptcb_desc->empkt_len[2]; + } else { + dwtmp = ptcb_desc->empkt_len[2]; + dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0) + 4; + dwtmp += ptcb_desc->empkt_len[3]; + } + SET_EARLYMODE_LEN1(virtualaddress, dwtmp); + if (ptcb_desc->empkt_num <= 5) { + dwtmp = ptcb_desc->empkt_len[4]; + } else { + dwtmp = ptcb_desc->empkt_len[4]; + dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0) + 4; + dwtmp += ptcb_desc->empkt_len[5]; + } + SET_EARLYMODE_LEN2_1(virtualaddress, dwtmp & 0xF); + SET_EARLYMODE_LEN2_2(virtualaddress, dwtmp >> 4); + if (ptcb_desc->empkt_num <= 7) { + dwtmp = ptcb_desc->empkt_len[6]; + } else { + dwtmp = ptcb_desc->empkt_len[6]; + dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0) + 4; + dwtmp += ptcb_desc->empkt_len[7]; + } + SET_EARLYMODE_LEN3(virtualaddress, dwtmp); + if (ptcb_desc->empkt_num <= 9) { + dwtmp = ptcb_desc->empkt_len[8]; + } else { + dwtmp = ptcb_desc->empkt_len[8]; + dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0) + 4; + dwtmp += ptcb_desc->empkt_len[9]; + } + SET_EARLYMODE_LEN4(virtualaddress, dwtmp); +} + +static bool rtl8822be_get_rxdesc_is_ht(struct ieee80211_hw *hw, u8 *pdesc) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 rx_rate = 0; + + rx_rate = GET_RX_DESC_RX_RATE(pdesc); + + RT_TRACE(rtlpriv, COMP_RXDESC, DBG_LOUD, "rx_rate=0x%02x.\n", rx_rate); + + if ((rx_rate >= DESC_RATEMCS0) && (rx_rate <= DESC_RATEMCS15)) + return true; + else + return false; +} + +static bool rtl8822be_get_rxdesc_is_vht(struct ieee80211_hw *hw, u8 *pdesc) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 rx_rate = 0; + + rx_rate = GET_RX_DESC_RX_RATE(pdesc); + + RT_TRACE(rtlpriv, COMP_RXDESC, DBG_LOUD, "rx_rate=0x%02x.\n", rx_rate); + + if (rx_rate >= DESC_RATEVHT1SS_MCS0) + return true; + else + return false; +} + +static u8 rtl8822be_get_rx_vht_nss(struct ieee80211_hw *hw, u8 *pdesc) +{ + u8 rx_rate = 0; + u8 vht_nss = 0; + + rx_rate = GET_RX_DESC_RX_RATE(pdesc); + + if ((rx_rate >= DESC_RATEVHT1SS_MCS0) && + (rx_rate <= DESC_RATEVHT1SS_MCS9)) + vht_nss = 1; + else if ((rx_rate >= DESC_RATEVHT2SS_MCS0) && + (rx_rate <= DESC_RATEVHT2SS_MCS9)) + vht_nss = 2; + + return vht_nss; +} + +bool rtl8822be_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *status, + struct ieee80211_rx_status *rx_status, u8 *pdesc, + struct sk_buff *skb) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 *p_phystrpt = NULL; + struct ieee80211_hdr *hdr; + + u32 phystatus = GET_RX_DESC_PHYST(pdesc); + + if (GET_RX_DESC_C2H(pdesc) == 0) + status->packet_report_type = NORMAL_RX; + else + status->packet_report_type = C2H_PACKET; + + status->length = (u16)GET_RX_DESC_PKT_LEN(pdesc); + status->rx_drvinfo_size = + (u8)GET_RX_DESC_DRV_INFO_SIZE(pdesc) * RX_DRV_INFO_SIZE_UNIT; + status->rx_bufshift = (u8)(GET_RX_DESC_SHIFT(pdesc) & 0x03); + status->icv = (u16)GET_RX_DESC_ICV_ERR(pdesc); + status->crc = (u16)GET_RX_DESC_CRC32(pdesc); + status->hwerror = (status->crc | status->icv); + status->decrypted = !GET_RX_DESC_SWDEC(pdesc); + status->rate = (u8)GET_RX_DESC_RX_RATE(pdesc); + status->isampdu = (bool)(GET_RX_DESC_PAGGR(pdesc) == 1); + status->isfirst_ampdu = (bool)(GET_RX_DESC_PAGGR(pdesc) == 1); + status->timestamp_low = GET_RX_DESC_TSFL(pdesc); + status->is_ht = rtl8822be_get_rxdesc_is_ht(hw, pdesc); + status->is_vht = rtl8822be_get_rxdesc_is_vht(hw, pdesc); + status->vht_nss = rtl8822be_get_rx_vht_nss(hw, pdesc); + status->is_cck = RX_HAL_IS_CCK_RATE(status->rate); + + status->macid = GET_RX_DESC_MACID(pdesc); + if (GET_RX_DESC_PATTERN_MATCH(pdesc)) + status->wake_match = BIT(2); + else if (GET_RX_DESC_MAGIC_WAKE(pdesc)) + status->wake_match = BIT(1); + else if (GET_RX_DESC_UNICAST_WAKE(pdesc)) + status->wake_match = BIT(0); + else + status->wake_match = 0; + if (status->wake_match) + RT_TRACE(rtlpriv, COMP_RXDESC, DBG_LOUD, + "GGGGGGGGGGGGGet Wakeup Packet!! WakeMatch=%d\n", + status->wake_match); + rx_status->freq = hw->conf.chandef.chan->center_freq; + rx_status->band = hw->conf.chandef.chan->band; + + if (phystatus) + p_phystrpt = (skb->data + status->rx_bufshift + 24); + + hdr = (struct ieee80211_hdr *)(skb->data + status->rx_drvinfo_size + + status->rx_bufshift + 24); + + if (status->crc) + rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; + + if (status->is_ht) + rx_status->encoding = RX_ENC_HT; + if (status->is_vht) + rx_status->encoding = RX_ENC_VHT; + + rx_status->nss = status->vht_nss; + + rx_status->flag |= RX_FLAG_MACTIME_START; + + /* hw will set status->decrypted true, if it finds the + * frame is open data frame or mgmt frame. + */ + /* So hw will not decryption robust management frame + * for IEEE80211w but still set status->decrypted + * true, so here we should set it back to undecrypted + * for IEEE80211w frame, and mac80211 sw will help + * to decrypt it + */ + if (status->decrypted) { + if ((!_ieee80211_is_robust_mgmt_frame(hdr)) && + (ieee80211_has_protected(hdr->frame_control))) + rx_status->flag |= RX_FLAG_DECRYPTED; + else + rx_status->flag &= ~RX_FLAG_DECRYPTED; + } + + /* rate_idx: index of data rate into band's + * supported rates or MCS index if HT rates + * are use (RX_FLAG_HT) + */ + /* Notice: this is diff with windows define */ + rx_status->rate_idx = rtlwifi_rate_mapping( + hw, status->is_ht, status->is_vht, status->rate); + + rx_status->mactime = status->timestamp_low; + + _rtl8822be_translate_rx_signal_stuff(hw, skb, status, p_phystrpt); + + /* below info. are filled by _rtl8822be_translate_rx_signal_stuff() */ + if (!p_phystrpt) + goto label_no_physt; + + rx_status->signal = status->recvsignalpower; + + if (status->rx_packet_bw == HT_CHANNEL_WIDTH_20_40) + rx_status->bw = RATE_INFO_BW_40; + else if (status->rx_packet_bw == HT_CHANNEL_WIDTH_80) + rx_status->bw = RATE_INFO_BW_80; + +label_no_physt: + + return true; +} + +void rtl8822be_rx_check_dma_ok(struct ieee80211_hw *hw, u8 *header_desc, + u8 queue_index) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 first_seg; + u8 last_seg; + u16 total_len; + u16 read_cnt = 0; + + if (!header_desc) + return; + + do { + total_len = (u16)GET_RX_BUFFER_DESC_TOTAL_LENGTH(header_desc); + first_seg = (u8)GET_RX_BUFFER_DESC_FS(header_desc); + last_seg = (u8)GET_RX_BUFFER_DESC_LS(header_desc); + + if (read_cnt++ > 20) { + RT_TRACE(rtlpriv, COMP_RECV, DBG_DMESG, + "RX chk DMA over %d times\n", read_cnt); + break; + } + + } while (total_len == 0 && first_seg == 0 && last_seg == 0); +} + +u16 rtl8822be_rx_desc_buff_remained_cnt(struct ieee80211_hw *hw, u8 queue_index) +{ + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_priv *rtlpriv = rtl_priv(hw); + u16 desc_idx_hw = 0, desc_idx_host = 0, remind_cnt = 0; + u32 tmp_4byte = 0; + + u32 rw_mask = 0x1ff; + + tmp_4byte = rtl_read_dword(rtlpriv, REG_RXQ_RXBD_IDX_8822B); + desc_idx_hw = (u16)((tmp_4byte >> 16) & rw_mask); + desc_idx_host = (u16)(tmp_4byte & rw_mask); + + /* may be no data, donot rx */ + if (desc_idx_hw == desc_idx_host) + return 0; + + remind_cnt = + (desc_idx_hw > desc_idx_host) ? + (desc_idx_hw - desc_idx_host) : + (RX_DESC_NUM_8822BE - (desc_idx_host - desc_idx_hw)); + + rtlpci->rx_ring[queue_index].next_rx_rp = desc_idx_host; + + return remind_cnt; +} + +static u16 get_desc_address_from_queue_index(u16 queue_index) +{ + /* + * Note: Access these registers will take a lot of cost. + */ + u16 desc_address = REG_BEQ_TXBD_IDX_8822B; + + switch (queue_index) { + case BK_QUEUE: + desc_address = REG_BKQ_TXBD_IDX_8822B; + break; + case BE_QUEUE: + desc_address = REG_BEQ_TXBD_IDX_8822B; + break; + case VI_QUEUE: + desc_address = REG_VIQ_TXBD_IDX_8822B; + break; + case VO_QUEUE: + desc_address = REG_VOQ_TXBD_IDX_8822B; + break; + case BEACON_QUEUE: + desc_address = REG_BEQ_TXBD_IDX_8822B; + break; + case H2C_QUEUE: + desc_address = REG_H2CQ_TXBD_IDX_8822B; + break; + case MGNT_QUEUE: + desc_address = REG_MGQ_TXBD_IDX_8822B; + break; + case HIGH_QUEUE: + desc_address = REG_HI0Q_TXBD_IDX_8822B; + break; + case HCCA_QUEUE: + desc_address = REG_BEQ_TXBD_IDX_8822B; + break; + default: + break; + } + return desc_address; +} + +/*free desc that can be used */ +u16 rtl8822be_get_available_desc(struct ieee80211_hw *hw, u8 q_idx) +{ + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[q_idx]; + + return calc_fifo_space(ring->cur_tx_rp, ring->cur_tx_wp, + TX_DESC_NUM_8822B); +} + +void rtl8822be_pre_fill_tx_bd_desc(struct ieee80211_hw *hw, u8 *tx_bd_desc, + u8 *desc, u8 queue_index, + struct sk_buff *skb, dma_addr_t data_addr) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + u32 pkt_len = skb->len; + u16 desc_size = 48; /*tx desc size*/ + u32 psblen = 0; + u32 total_packet_size = 0; + u16 current_bd_desc; + u8 i = 0; + /*u16 real_desc_size = 0x28;*/ + u16 append_early_mode_size = 0; + u8 segmentnum = 1 << (RTL8822BE_SEG_NUM + 1); + dma_addr_t desc_dma_addr; + bool dma64 = rtlpriv->cfg->mod_params->dma64; + + current_bd_desc = rtlpci->tx_ring[queue_index].cur_tx_wp; + + total_packet_size = desc_size + pkt_len; + + if (rtlpriv->rtlhal.earlymode_enable) { + if (queue_index < BEACON_QUEUE) { + append_early_mode_size = 8; + total_packet_size += append_early_mode_size; + } + } + + /* page number (round up) */ + psblen = (total_packet_size - 1) / 128 + 1; + + /* tx desc addr */ + desc_dma_addr = rtlpci->tx_ring[queue_index].dma + + (current_bd_desc * TX_DESC_SIZE); + + /* Reset */ + SET_TX_BUFF_DESC_LEN_0(tx_bd_desc, 0); + SET_TX_BUFF_DESC_PSB(tx_bd_desc, 0); + SET_TX_BUFF_DESC_OWN(tx_bd_desc, 0); + + for (i = 1; i < segmentnum; i++) { + SET_TXBUFFER_DESC_LEN_WITH_OFFSET(tx_bd_desc, i, 0); + SET_TXBUFFER_DESC_AMSDU_WITH_OFFSET(tx_bd_desc, i, 0); + SET_TXBUFFER_DESC_ADD_LOW_WITH_OFFSET(tx_bd_desc, i, 0); + SET_TXBUFFER_DESC_ADD_HIGH_WITH_OFFSET(tx_bd_desc, i, 0, dma64); + } + + /* Clear all status */ + CLEAR_PCI_TX_DESC_CONTENT(desc, TX_DESC_SIZE); + + if (rtlpriv->rtlhal.earlymode_enable) { + if (queue_index < BEACON_QUEUE) + SET_TX_BUFF_DESC_LEN_0(tx_bd_desc, desc_size + 8); + else + SET_TX_BUFF_DESC_LEN_0(tx_bd_desc, desc_size); + } else { + SET_TX_BUFF_DESC_LEN_0(tx_bd_desc, desc_size); + } + SET_TX_BUFF_DESC_PSB(tx_bd_desc, psblen); + SET_TX_BUFF_DESC_ADDR_LOW_0(tx_bd_desc, desc_dma_addr); + SET_TX_BUFF_DESC_ADDR_HIGH_0(tx_bd_desc, ((u64)desc_dma_addr >> 32), + dma64); + + SET_TXBUFFER_DESC_LEN_WITH_OFFSET(tx_bd_desc, 1, pkt_len); + SET_TXBUFFER_DESC_AMSDU_WITH_OFFSET(tx_bd_desc, 1, 0); + SET_TXBUFFER_DESC_ADD_LOW_WITH_OFFSET(tx_bd_desc, 1, data_addr); + SET_TXBUFFER_DESC_ADD_HIGH_WITH_OFFSET(tx_bd_desc, 1, + ((u64)data_addr >> 32), dma64); + + SET_TX_DESC_TXPKTSIZE(desc, (u16)(pkt_len)); +} + +static u8 rtl8822be_bw_mapping(struct ieee80211_hw *hw, + struct rtl_tcb_desc *ptcb_desc) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &rtlpriv->phy; + u8 bw_setting_of_desc = 0; + + RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, + "%s, current_chan_bw %d, packet_bw %d\n", __func__, + rtlphy->current_chan_bw, ptcb_desc->packet_bw); + + if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_80) { + if (ptcb_desc->packet_bw == HT_CHANNEL_WIDTH_80) + bw_setting_of_desc = 2; + else if (ptcb_desc->packet_bw == HT_CHANNEL_WIDTH_20_40) + bw_setting_of_desc = 1; + else + bw_setting_of_desc = 0; + } else if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) { + if ((ptcb_desc->packet_bw == HT_CHANNEL_WIDTH_20_40) || + (ptcb_desc->packet_bw == HT_CHANNEL_WIDTH_80)) + bw_setting_of_desc = 1; + else + bw_setting_of_desc = 0; + } else { + bw_setting_of_desc = 0; + } + + return bw_setting_of_desc; +} + +static u8 rtl8822be_sc_mapping(struct ieee80211_hw *hw, + struct rtl_tcb_desc *ptcb_desc) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &rtlpriv->phy; + struct rtl_mac *mac = rtl_mac(rtlpriv); + u8 sc_setting_of_desc = 0; + + if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_80) { + if (ptcb_desc->packet_bw == HT_CHANNEL_WIDTH_80) { + sc_setting_of_desc = VHT_DATA_SC_DONOT_CARE; + } else if (ptcb_desc->packet_bw == HT_CHANNEL_WIDTH_20_40) { + if (mac->cur_80_prime_sc == HAL_PRIME_CHNL_OFFSET_LOWER) + sc_setting_of_desc = + VHT_DATA_SC_40_LOWER_OF_80MHZ; + else if (mac->cur_80_prime_sc == + HAL_PRIME_CHNL_OFFSET_UPPER) + sc_setting_of_desc = + VHT_DATA_SC_40_UPPER_OF_80MHZ; + else + RT_TRACE(rtlpriv, COMP_SEND, DBG_LOUD, + "%s: Not Correct Primary40MHz Setting\n", + __func__); + } else { + if ((mac->cur_40_prime_sc == + HAL_PRIME_CHNL_OFFSET_LOWER) && + (mac->cur_80_prime_sc == + HAL_PRIME_CHNL_OFFSET_LOWER)) + sc_setting_of_desc = + VHT_DATA_SC_20_LOWEST_OF_80MHZ; + else if ((mac->cur_40_prime_sc == + HAL_PRIME_CHNL_OFFSET_UPPER) && + (mac->cur_80_prime_sc == + HAL_PRIME_CHNL_OFFSET_LOWER)) + sc_setting_of_desc = + VHT_DATA_SC_20_LOWER_OF_80MHZ; + else if ((mac->cur_40_prime_sc == + HAL_PRIME_CHNL_OFFSET_LOWER) && + (mac->cur_80_prime_sc == + HAL_PRIME_CHNL_OFFSET_UPPER)) + sc_setting_of_desc = + VHT_DATA_SC_20_UPPER_OF_80MHZ; + else if ((mac->cur_40_prime_sc == + HAL_PRIME_CHNL_OFFSET_UPPER) && + (mac->cur_80_prime_sc == + HAL_PRIME_CHNL_OFFSET_UPPER)) + sc_setting_of_desc = + VHT_DATA_SC_20_UPPERST_OF_80MHZ; + else + RT_TRACE( + rtlpriv, COMP_SEND, DBG_LOUD, + "rtl8822be_sc_mapping: Not Correct Primary40MHz Setting\n"); + } + } else if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) { + if (ptcb_desc->packet_bw == HT_CHANNEL_WIDTH_20_40) { + sc_setting_of_desc = VHT_DATA_SC_DONOT_CARE; + } else if (ptcb_desc->packet_bw == HT_CHANNEL_WIDTH_20) { + if (mac->cur_40_prime_sc == + HAL_PRIME_CHNL_OFFSET_UPPER) { + sc_setting_of_desc = + VHT_DATA_SC_20_UPPER_OF_80MHZ; + } else if (mac->cur_40_prime_sc == + HAL_PRIME_CHNL_OFFSET_LOWER) { + sc_setting_of_desc = + VHT_DATA_SC_20_LOWER_OF_80MHZ; + } else { + sc_setting_of_desc = VHT_DATA_SC_DONOT_CARE; + } + } + } else { + sc_setting_of_desc = VHT_DATA_SC_DONOT_CARE; + } + + return sc_setting_of_desc; +} + +void rtl8822be_tx_fill_desc(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, + u8 *pdesc_tx, u8 *pbd_desc_tx, + struct ieee80211_tx_info *info, + struct ieee80211_sta *sta, struct sk_buff *skb, + u8 hw_queue, struct rtl_tcb_desc *ptcb_desc) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + struct rtl_phy *rtlphy = &rtlpriv->phy; + u8 *pdesc = (u8 *)pdesc_tx; + u16 seq_number; + __le16 fc = hdr->frame_control; + u8 fw_qsel = _rtl8822be_map_hwqueue_to_fwqueue(skb, hw_queue); + bool firstseg = + ((hdr->seq_ctrl & cpu_to_le16(IEEE80211_SCTL_FRAG)) == 0); + bool lastseg = ((hdr->frame_control & + cpu_to_le16(IEEE80211_FCTL_MOREFRAGS)) == 0); + dma_addr_t mapping; + u8 short_gi = 0; + + seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; + rtl_get_tcb_desc(hw, info, sta, skb, ptcb_desc); + /* reserve 8 byte for AMPDU early mode */ + if (rtlhal->earlymode_enable) { + skb_push(skb, EM_HDR_LEN); + memset(skb->data, 0, EM_HDR_LEN); + } + mapping = pci_map_single(rtlpci->pdev, skb->data, skb->len, + PCI_DMA_TODEVICE); + if (pci_dma_mapping_error(rtlpci->pdev, mapping)) { + RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, "DMA mapping error"); + return; + } + + if (pbd_desc_tx) + rtl8822be_pre_fill_tx_bd_desc(hw, pbd_desc_tx, pdesc, hw_queue, + skb, mapping); + + if (ieee80211_is_nullfunc(fc) || ieee80211_is_ctl(fc)) { + firstseg = true; + lastseg = true; + } + if (firstseg) { + if (rtlhal->earlymode_enable) { + SET_TX_DESC_PKT_OFFSET(pdesc, 1); + SET_TX_DESC_OFFSET(pdesc, + USB_HWDESC_HEADER_LEN + EM_HDR_LEN); + if (ptcb_desc->empkt_num) { + RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, + "Insert 8 byte.pTcb->EMPktNum:%d\n", + ptcb_desc->empkt_num); + _rtl8822be_insert_emcontent(ptcb_desc, + (u8 *)(skb->data)); + } + } else { + SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN); + } + + /* tx report */ + rtl_get_tx_report(ptcb_desc, pdesc, hw); + + if (rtlpriv->rtlhal.current_bandtype == BAND_ON_5G && + ptcb_desc->hw_rate < DESC_RATE6M) { + RT_TRACE(rtlpriv, COMP_SEND, DBG_WARNING, + "hw_rate=0x%X is invalid in 5G\n", + ptcb_desc->hw_rate); + ptcb_desc->hw_rate = DESC_RATE6M; + } + SET_TX_DESC_DATARATE(pdesc, ptcb_desc->hw_rate); + + if (ptcb_desc->hw_rate > DESC_RATEMCS0) + short_gi = (ptcb_desc->use_shortgi) ? 1 : 0; + else + short_gi = (ptcb_desc->use_shortpreamble) ? 1 : 0; + + if (info->flags & IEEE80211_TX_CTL_AMPDU) { + SET_TX_DESC_AGG_EN(pdesc, 1); + SET_TX_DESC_MAX_AGG_NUM(pdesc, 0x1F); + } + SET_TX_DESC_SW_SEQ(pdesc, seq_number); + SET_TX_DESC_RTSEN(pdesc, ((ptcb_desc->rts_enable && + !ptcb_desc->cts_enable) ? + 1 : + 0)); + SET_TX_DESC_HW_RTS_EN(pdesc, 0); + SET_TX_DESC_CTS2SELF(pdesc, ((ptcb_desc->cts_enable) ? 1 : 0)); + + SET_TX_DESC_RTSRATE(pdesc, ptcb_desc->rts_rate); + SET_TX_DESC_RTS_SC(pdesc, ptcb_desc->rts_sc); + SET_TX_DESC_RTS_SHORT( + pdesc, + ((ptcb_desc->rts_rate <= DESC_RATE54M) ? + (ptcb_desc->rts_use_shortpreamble ? 1 : 0) : + (ptcb_desc->rts_use_shortgi ? 1 : 0))); + + if (ptcb_desc->tx_enable_sw_calc_duration) + SET_TX_DESC_NAVUSEHDR(pdesc, 1); + + SET_TX_DESC_DATA_BW(pdesc, rtl8822be_bw_mapping(hw, ptcb_desc)); + SET_TX_DESC_DATA_SC(pdesc, rtl8822be_sc_mapping(hw, ptcb_desc)); + + if (sta) { + u8 ampdu_density = sta->ht_cap.ampdu_density; + + SET_TX_DESC_AMPDU_DENSITY(pdesc, ampdu_density); + } + if (info->control.hw_key) { + struct ieee80211_key_conf *key = info->control.hw_key; + + switch (key->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + case WLAN_CIPHER_SUITE_TKIP: + SET_TX_DESC_SEC_TYPE(pdesc, 0x1); + break; + case WLAN_CIPHER_SUITE_CCMP: + SET_TX_DESC_SEC_TYPE(pdesc, 0x3); + break; + default: + SET_TX_DESC_SEC_TYPE(pdesc, 0x0); + break; + } + } + + SET_TX_DESC_QSEL(pdesc, fw_qsel); + + if (rtlphy->current_channel > 14) { + /* OFDM 6M */ + SET_TX_DESC_DATA_RTY_LOWEST_RATE(pdesc, 4); + SET_TX_DESC_RTS_RTY_LOWEST_RATE(pdesc, 4); + } else { + /* CCK 1M */ + SET_TX_DESC_DATA_RTY_LOWEST_RATE(pdesc, 0); + SET_TX_DESC_RTS_RTY_LOWEST_RATE(pdesc, 0); + } + SET_TX_DESC_DISDATAFB(pdesc, + ptcb_desc->disable_ratefallback ? 1 : 0); + SET_TX_DESC_USE_RATE(pdesc, ptcb_desc->use_driver_rate ? 1 : 0); + + /*SET_TX_DESC_PWR_STATUS(pdesc, pwr_status);*/ + /* Set TxRate and RTSRate in TxDesc */ + /* This prevent Tx initial rate of new-coming packets */ + /* from being overwritten by retried packet rate.*/ + if (!ptcb_desc->use_driver_rate) { + /*SET_TX_DESC_RTS_RATE(pdesc, 0x08); */ + /* SET_TX_DESC_TX_RATE(pdesc, 0x0b); */ + } + if (ieee80211_is_data_qos(fc)) { + if (mac->rdg_en) { + RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, + "Enable RDG function.\n"); + SET_TX_DESC_RDG_EN(pdesc, 1); + SET_TX_DESC_HTC(pdesc, 1); + } + } + + SET_TX_DESC_PORT_ID(pdesc, 0); + SET_TX_DESC_MULTIPLE_PORT(pdesc, 0); + } + + SET_TX_DESC_LS(pdesc, (lastseg ? 1 : 0)); + if (rtlpriv->dm.useramask) { + SET_TX_DESC_RATE_ID(pdesc, ptcb_desc->ratr_index); + SET_TX_DESC_MACID(pdesc, ptcb_desc->mac_id); + } else { + SET_TX_DESC_RATE_ID(pdesc, 0xC + ptcb_desc->ratr_index); + SET_TX_DESC_MACID(pdesc, ptcb_desc->ratr_index); + } + + SET_TX_DESC_MOREFRAG(pdesc, (lastseg ? 0 : 1)); + if (ptcb_desc->multicast || ptcb_desc->broadcast) { + SET_TX_DESC_BMC(pdesc, 1); + /* BMC must be not AGG */ + SET_TX_DESC_AGG_EN(pdesc, 0); + } + RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, "\n"); + + /* debug purpose: used to check tx desc is correct or not */ + /*rtlpriv->halmac.ops->halmac_chk_txdesc(rtlpriv, pdesc, + * skb->len + USB_HWDESC_HEADER_LEN); + */ +} + +void rtl8822be_tx_fill_special_desc(struct ieee80211_hw *hw, u8 *pdesc, + u8 *pbd_desc, struct sk_buff *skb, + u8 hw_queue) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + u8 fw_queue; + u8 txdesc_len = 48; + + dma_addr_t mapping = pci_map_single(rtlpci->pdev, skb->data, skb->len, + PCI_DMA_TODEVICE); + + if (pci_dma_mapping_error(rtlpci->pdev, mapping)) { + RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, "DMA mapping error"); + return; + } + + rtl8822be_pre_fill_tx_bd_desc(hw, pbd_desc, pdesc, hw_queue, skb, + mapping); + + /* it should be BEACON_QUEUE or H2C_QUEUE, + * so skb=NULL is safe to assert + */ + fw_queue = _rtl8822be_map_hwqueue_to_fwqueue(NULL, hw_queue); + + CLEAR_PCI_TX_DESC_CONTENT(pdesc, txdesc_len); + + /* common part for BEACON and H2C */ + SET_TX_DESC_TXPKTSIZE((u8 *)pdesc, (u16)(skb->len)); + + SET_TX_DESC_QSEL(pdesc, fw_queue); + + if (hw_queue == H2C_QUEUE) { + /* fill H2C */ + SET_TX_DESC_OFFSET(pdesc, 0); + + } else { + /* fill beacon */ + SET_TX_DESC_OFFSET(pdesc, txdesc_len); + + SET_TX_DESC_DATARATE(pdesc, DESC_RATE1M); + + SET_TX_DESC_SW_SEQ(pdesc, 0); + + SET_TX_DESC_RATE_ID(pdesc, 7); + SET_TX_DESC_MACID(pdesc, 0); + + SET_TX_DESC_LS(pdesc, 1); + + SET_TX_DESC_OFFSET(pdesc, 48); + + SET_TX_DESC_USE_RATE(pdesc, 1); + } + + RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD, "H2C Tx Cmd Content\n", + pdesc, txdesc_len); +} + +void rtl8822be_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx, + u8 desc_name, u8 *val) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 q_idx = *val; + bool dma64 = rtlpriv->cfg->mod_params->dma64; + + if (istx) { + switch (desc_name) { + case HW_DESC_OWN: { + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[q_idx]; + u16 max_tx_desc = ring->entries; + + if (q_idx == BEACON_QUEUE) { + /* in case of beacon, pdesc is BD desc. */ + u8 *pbd_desc = pdesc; + + ring->cur_tx_wp = 0; + ring->cur_tx_rp = 0; + SET_TX_BUFF_DESC_OWN(pbd_desc, 1); + return; + } + + /* make sure tx desc is available by caller */ + ring->cur_tx_wp = ((ring->cur_tx_wp + 1) % max_tx_desc); + + rtl_write_word( + rtlpriv, + get_desc_address_from_queue_index( + q_idx), + ring->cur_tx_wp); + } break; + } + } else { + switch (desc_name) { + case HW_DESC_RX_PREPARE: + SET_RX_BUFFER_DESC_LS(pdesc, 0); + SET_RX_BUFFER_DESC_FS(pdesc, 0); + SET_RX_BUFFER_DESC_TOTAL_LENGTH(pdesc, 0); + + SET_RX_BUFFER_DESC_DATA_LENGTH( + pdesc, MAX_RECEIVE_BUFFER_SIZE + RX_DESC_SIZE); + + SET_RX_BUFFER_PHYSICAL_LOW( + pdesc, (*(dma_addr_t *)val) & DMA_BIT_MASK(32)); + SET_RX_BUFFER_PHYSICAL_HIGH( + pdesc, ((u64)(*(dma_addr_t *)val) >> 32), + dma64); + break; + default: + WARN_ONCE(true, "ERR rxdesc :%d not process\n", + desc_name); + break; + } + } +} + +u64 rtl8822be_get_desc(struct ieee80211_hw *hw, + u8 *pdesc, bool istx, u8 desc_name) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u64 ret = 0; + u8 *pbd_desc = pdesc; + bool dma64 = rtlpriv->cfg->mod_params->dma64; + + if (istx) { + switch (desc_name) { + case HW_DESC_TXBUFF_ADDR: + ret = GET_TXBUFFER_DESC_ADDR_LOW(pbd_desc, 1); + ret |= (u64)GET_TXBUFFER_DESC_ADDR_HIGH(pbd_desc, 1, + dma64) << 32; + break; + default: + WARN_ONCE(true, "ERR txdesc :%d not process\n", + desc_name); + break; + } + } else { + switch (desc_name) { + case HW_DESC_RXPKT_LEN: + ret = GET_RX_DESC_PKT_LEN(pdesc); + break; + default: + WARN_ONCE(true, "ERR rxdesc :%d not process\n", + desc_name); + break; + } + } + return ret; +} + +bool rtl8822be_is_tx_desc_closed(struct ieee80211_hw *hw, u8 hw_queue, + u16 index) +{ + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_priv *rtlpriv = rtl_priv(hw); + bool ret = false; + struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[hw_queue]; + u16 cur_tx_rp, cur_tx_wp; + u16 tmp16; + + /* + * design rule: + * idx <= cur_tx_rp <= hw_rp <= cur_tx_wp = hw_wp + */ + + if (index == ring->cur_tx_rp) { + /* update only if sw_rp reach hw_rp */ + tmp16 = rtl_read_word( + rtlpriv, + get_desc_address_from_queue_index(hw_queue) + 2); + + cur_tx_rp = tmp16 & 0x01ff; + cur_tx_wp = ring->cur_tx_wp; + + /* don't need to update ring->cur_tx_wp */ + ring->cur_tx_rp = cur_tx_rp; + } + + if (index == ring->cur_tx_rp) + ret = false; /* no more */ + else + ret = true; /* more */ + + if (hw_queue == BEACON_QUEUE) + ret = true; + + if (rtlpriv->rtlhal.driver_is_goingto_unload || + rtlpriv->psc.rfoff_reason > RF_CHANGE_BY_PS) + ret = true; + + return ret; +} + +void rtl8822be_tx_polling(struct ieee80211_hw *hw, u8 hw_queue) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (hw_queue == BEACON_QUEUE) { + /* kick start */ + rtl_write_byte( + rtlpriv, REG_RX_RXBD_NUM_8822B + 1, + rtl_read_byte(rtlpriv, REG_RX_RXBD_NUM_8822B + 1) | + BIT(4)); + } +} + +u32 rtl8822be_rx_command_packet(struct ieee80211_hw *hw, + const struct rtl_stats *status, + struct sk_buff *skb) +{ + u32 result = 0; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + switch (status->packet_report_type) { + case NORMAL_RX: + result = 0; + break; + case C2H_PACKET: + rtl8822be_c2h_packet_handler(hw, skb->data, (u8)skb->len); + result = 1; + break; + default: + RT_TRACE(rtlpriv, COMP_RECV, DBG_TRACE, + "Unknown packet type %d\n", + status->packet_report_type); + break; + } + + return result; +} diff --git a/drivers/staging/rtlwifi/rtl8822be/trx.h b/drivers/staging/rtlwifi/rtl8822be/trx.h new file mode 100644 index 000000000000..db769f3c4cd6 --- /dev/null +++ b/drivers/staging/rtlwifi/rtl8822be/trx.h @@ -0,0 +1,165 @@ +/****************************************************************************** + * + * Copyright(c) 2016 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL8822B_TRX_H__ +#define __RTL8822B_TRX_H__ + +#include "../halmac/halmac_tx_desc_nic.h" +#include "../halmac/halmac_rx_desc_nic.h" + +#define TX_DESC_SIZE 64 + +#define RX_DRV_INFO_SIZE_UNIT 8 + +#define TX_DESC_NEXT_DESC_OFFSET 48 +#define USB_HWDESC_HEADER_LEN 48 + +#define RX_DESC_SIZE 24 +#define MAX_RECEIVE_BUFFER_SIZE 8192 + +#define SET_EARLYMODE_PKTNUM(__paddr, __val) \ + SET_BITS_TO_LE_4BYTE(__paddr, 0, 4, __val) +#define SET_EARLYMODE_LEN0(__paddr, __val) \ + SET_BITS_TO_LE_4BYTE(__paddr, 4, 15, __val) +#define SET_EARLYMODE_LEN1(__paddr, __val) \ + SET_BITS_TO_LE_4BYTE(__paddr, 16, 2, __val) +#define SET_EARLYMODE_LEN1_1(__paddr, __val) \ + SET_BITS_TO_LE_4BYTE(__paddr, 19, 13, __val) +#define SET_EARLYMODE_LEN1_2(__paddr, __val) \ + SET_BITS_TO_LE_4BYTE(__paddr + 4, 0, 2, __val) +#define SET_EARLYMODE_LEN2(__paddr, __val) \ + SET_BITS_TO_LE_4BYTE(__paddr + 4, 2, 15, __val) +#define SET_EARLYMODE_LEN2_1(__paddr, __val) \ + SET_BITS_TO_LE_4BYTE(__paddr, 2, 4, __val) +#define SET_EARLYMODE_LEN2_2(__paddr, __val) \ + SET_BITS_TO_LE_4BYTE(__paddr + 4, 0, 8, __val) +#define SET_EARLYMODE_LEN3(__paddr, __val) \ + SET_BITS_TO_LE_4BYTE(__paddr + 4, 17, 15, __val) +#define SET_EARLYMODE_LEN4(__paddr, __val) \ + SET_BITS_TO_LE_4BYTE(__paddr + 4, 20, 12, __val) + +/* TX/RX buffer descriptor */ + +/* for Txfilldescroptor8822be, fill the desc content. */ +#define SET_TXBUFFER_DESC_LEN_WITH_OFFSET(__pdesc, __offset, __val) \ + SET_BITS_TO_LE_4BYTE((__pdesc) + ((__offset) * 16), 0, 16, __val) +#define SET_TXBUFFER_DESC_AMSDU_WITH_OFFSET(__pdesc, __offset, __val) \ + SET_BITS_TO_LE_4BYTE((__pdesc) + ((__offset) * 16), 31, 1, __val) +#define SET_TXBUFFER_DESC_ADD_LOW_WITH_OFFSET(__pdesc, __offset, __val) \ + SET_BITS_TO_LE_4BYTE((__pdesc) + ((__offset) * 16) + 4, 0, 32, __val) +#define SET_TXBUFFER_DESC_ADD_HIGH_WITH_OFFSET(pbd, off, val, dma64) \ + (dma64 ? SET_BITS_TO_LE_4BYTE((pbd) + ((off) * 16) + 8, 0, 32, val) : 0) +#define GET_TXBUFFER_DESC_ADDR_LOW(__pdesc, __offset) \ + LE_BITS_TO_4BYTE((__pdesc) + ((__offset) * 16) + 4, 0, 32) +#define GET_TXBUFFER_DESC_ADDR_HIGH(pbd, off, dma64) \ + (dma64 ? LE_BITS_TO_4BYTE((pbd) + ((off) * 16) + 8, 0, 32) : 0) + +/* Dword 0 */ +#define SET_TX_BUFF_DESC_LEN_0(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc, 0, 14, __val) +#define SET_TX_BUFF_DESC_PSB(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc, 16, 15, __val) +#define SET_TX_BUFF_DESC_OWN(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc, 31, 1, __val) + +/* Dword 1 */ +#define SET_TX_BUFF_DESC_ADDR_LOW_0(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE((__pdesc) + 4, 0, 32, __val) +/* Dword 2 */ +#define SET_TX_BUFF_DESC_ADDR_HIGH_0(bdesc, val, dma64) \ + SET_TXBUFFER_DESC_ADD_HIGH_WITH_OFFSET(bdesc, 0, val, dma64) +/* Dword 3 / RESERVED 0 */ + +/* RX buffer */ + +/* DWORD 0 */ +#define SET_RX_BUFFER_DESC_DATA_LENGTH(__rx_status_desc, __val) \ + SET_BITS_TO_LE_4BYTE(__rx_status_desc, 0, 14, __val) +#define SET_RX_BUFFER_DESC_LS(__rx_status_desc, __val) \ + SET_BITS_TO_LE_4BYTE(__rx_status_desc, 15, 1, __val) +#define SET_RX_BUFFER_DESC_FS(__rx_status_desc, __val) \ + SET_BITS_TO_LE_4BYTE(__rx_status_desc, 16, 1, __val) +#define SET_RX_BUFFER_DESC_TOTAL_LENGTH(__rx_status_desc, __val) \ + SET_BITS_TO_LE_4BYTE(__rx_status_desc, 16, 15, __val) + +#define GET_RX_BUFFER_DESC_OWN(__rx_status_desc) \ + LE_BITS_TO_4BYTE(__rx_status_desc, 31, 1) +#define GET_RX_BUFFER_DESC_LS(__rx_status_desc) \ + LE_BITS_TO_4BYTE(__rx_status_desc, 15, 1) +#define GET_RX_BUFFER_DESC_FS(__rx_status_desc) \ + LE_BITS_TO_4BYTE(__rx_status_desc, 16, 1) +#define GET_RX_BUFFER_DESC_TOTAL_LENGTH(__rx_status_desc) \ + LE_BITS_TO_4BYTE(__rx_status_desc, 16, 15) + +/* DWORD 1 */ +#define SET_RX_BUFFER_PHYSICAL_LOW(__rx_status_desc, __val) \ + SET_BITS_TO_LE_4BYTE(__rx_status_desc + 4, 0, 32, __val) + +/* DWORD 2 */ +#define SET_RX_BUFFER_PHYSICAL_HIGH(__rx_status_desc, __val, dma64) \ + (dma64 ? SET_BITS_TO_LE_4BYTE((__rx_status_desc) + 8, 0, 32, __val) : 0) + +#define CLEAR_PCI_TX_DESC_CONTENT(__pdesc, _size) \ + do { \ + if (_size > TX_DESC_NEXT_DESC_OFFSET) \ + memset(__pdesc, 0, TX_DESC_NEXT_DESC_OFFSET); \ + else \ + memset(__pdesc, 0, _size); \ + } while (0) + +void rtl8822be_rx_check_dma_ok(struct ieee80211_hw *hw, u8 *header_desc, + u8 queue_index); +u16 rtl8822be_rx_desc_buff_remained_cnt(struct ieee80211_hw *hw, + u8 queue_index); +u16 rtl8822be_get_available_desc(struct ieee80211_hw *hw, u8 queue_index); +void rtl8822be_pre_fill_tx_bd_desc(struct ieee80211_hw *hw, u8 *tx_bd_desc, + u8 *desc, u8 queue_index, + struct sk_buff *skb, dma_addr_t addr); + +void rtl8822be_tx_fill_desc(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, + u8 *pdesc_tx, u8 *pbd_desc_tx, + struct ieee80211_tx_info *info, + struct ieee80211_sta *sta, struct sk_buff *skb, + u8 hw_queue, struct rtl_tcb_desc *ptcb_desc); +void rtl8822be_tx_fill_special_desc(struct ieee80211_hw *hw, u8 *pdesc, + u8 *pbd_desc, struct sk_buff *skb, + u8 hw_queue); +bool rtl8822be_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *status, + struct ieee80211_rx_status *rx_status, u8 *pdesc, + struct sk_buff *skb); +void rtl8822be_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx, + u8 desc_name, u8 *val); +u64 rtl8822be_get_desc(struct ieee80211_hw *hw, + u8 *pdesc, bool istx, u8 desc_name); +bool rtl8822be_is_tx_desc_closed(struct ieee80211_hw *hw, u8 hw_queue, + u16 index); +void rtl8822be_tx_polling(struct ieee80211_hw *hw, u8 hw_queue); +void rtl8822be_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, + bool firstseg, bool lastseg, + struct sk_buff *skb); +u32 rtl8822be_rx_command_packet(struct ieee80211_hw *hw, + const struct rtl_stats *status, + struct sk_buff *skb); +#endif diff --git a/drivers/staging/rtlwifi/stats.c b/drivers/staging/rtlwifi/stats.c new file mode 100644 index 000000000000..96eb14c92c01 --- /dev/null +++ b/drivers/staging/rtlwifi/stats.c @@ -0,0 +1,260 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#include "wifi.h" +#include "stats.h" +#include <linux/export.h> + +u8 rtl_query_rxpwrpercentage(s8 antpower) +{ + if ((antpower <= -100) || (antpower >= 20)) + return 0; + else if (antpower >= 0) + return 100; + else + return 100 + antpower; +} + +u8 rtl_evm_db_to_percentage(s8 value) +{ + s8 ret_val = clamp(-value, 0, 33) * 3; + + if (ret_val == 99) + ret_val = 100; + + return ret_val; +} + +static long rtl_translate_todbm(struct ieee80211_hw *hw, + u8 signal_strength_index) +{ + long signal_power; + + signal_power = (long)((signal_strength_index + 1) >> 1); + signal_power -= 95; + return signal_power; +} + +long rtl_signal_scale_mapping(struct ieee80211_hw *hw, long currsig) +{ + long retsig; + + if (currsig >= 61 && currsig <= 100) + retsig = 90 + ((currsig - 60) / 4); + else if (currsig >= 41 && currsig <= 60) + retsig = 78 + ((currsig - 40) / 2); + else if (currsig >= 31 && currsig <= 40) + retsig = 66 + (currsig - 30); + else if (currsig >= 21 && currsig <= 30) + retsig = 54 + (currsig - 20); + else if (currsig >= 5 && currsig <= 20) + retsig = 42 + (((currsig - 5) * 2) / 3); + else if (currsig == 4) + retsig = 36; + else if (currsig == 3) + retsig = 27; + else if (currsig == 2) + retsig = 18; + else if (currsig == 1) + retsig = 9; + else + retsig = currsig; + + return retsig; +} + +static void rtl_process_ui_rssi(struct ieee80211_hw *hw, + struct rtl_stats *pstatus) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &rtlpriv->phy; + u8 rfpath; + u32 last_rssi, tmpval; + + if (!pstatus->packet_toself && !pstatus->packet_beacon) + return; + + rtlpriv->stats.pwdb_all_cnt += pstatus->rx_pwdb_all; + rtlpriv->stats.rssi_calculate_cnt++; + + if (rtlpriv->stats.ui_rssi.total_num++ >= PHY_RSSI_SLID_WIN_MAX) { + rtlpriv->stats.ui_rssi.total_num = PHY_RSSI_SLID_WIN_MAX; + last_rssi = rtlpriv->stats.ui_rssi.elements[ + rtlpriv->stats.ui_rssi.index]; + rtlpriv->stats.ui_rssi.total_val -= last_rssi; + } + rtlpriv->stats.ui_rssi.total_val += pstatus->signalstrength; + rtlpriv->stats.ui_rssi.elements[rtlpriv->stats.ui_rssi.index++] = + pstatus->signalstrength; + if (rtlpriv->stats.ui_rssi.index >= PHY_RSSI_SLID_WIN_MAX) + rtlpriv->stats.ui_rssi.index = 0; + tmpval = rtlpriv->stats.ui_rssi.total_val / + rtlpriv->stats.ui_rssi.total_num; + rtlpriv->stats.signal_strength = rtl_translate_todbm(hw, (u8)tmpval); + pstatus->rssi = rtlpriv->stats.signal_strength; + + if (pstatus->is_cck) + return; + + for (rfpath = RF90_PATH_A; rfpath < rtlphy->num_total_rfpath; + rfpath++) { + if (rtlpriv->stats.rx_rssi_percentage[rfpath] == 0) { + rtlpriv->stats.rx_rssi_percentage[rfpath] = + pstatus->rx_mimo_signalstrength[rfpath]; + } + if (pstatus->rx_mimo_signalstrength[rfpath] > + rtlpriv->stats.rx_rssi_percentage[rfpath]) { + rtlpriv->stats.rx_rssi_percentage[rfpath] = + ((rtlpriv->stats.rx_rssi_percentage[rfpath] * + (RX_SMOOTH_FACTOR - 1)) + + (pstatus->rx_mimo_signalstrength[rfpath])) / + (RX_SMOOTH_FACTOR); + rtlpriv->stats.rx_rssi_percentage[rfpath] = + rtlpriv->stats.rx_rssi_percentage[rfpath] + 1; + } else { + rtlpriv->stats.rx_rssi_percentage[rfpath] = + ((rtlpriv->stats.rx_rssi_percentage[rfpath] * + (RX_SMOOTH_FACTOR - 1)) + + (pstatus->rx_mimo_signalstrength[rfpath])) / + (RX_SMOOTH_FACTOR); + } + rtlpriv->stats.rx_snr_db[rfpath] = pstatus->rx_snr[rfpath]; + rtlpriv->stats.rx_evm_dbm[rfpath] = + pstatus->rx_mimo_evm_dbm[rfpath]; + rtlpriv->stats.rx_cfo_short[rfpath] = + pstatus->cfo_short[rfpath]; + rtlpriv->stats.rx_cfo_tail[rfpath] = pstatus->cfo_tail[rfpath]; + } +} + +static void rtl_update_rxsignalstatistics(struct ieee80211_hw *hw, + struct rtl_stats *pstatus) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + int weighting = 0; + + if (rtlpriv->stats.recv_signal_power == 0) + rtlpriv->stats.recv_signal_power = pstatus->recvsignalpower; + if (pstatus->recvsignalpower > rtlpriv->stats.recv_signal_power) + weighting = 5; + else if (pstatus->recvsignalpower < rtlpriv->stats.recv_signal_power) + weighting = (-5); + rtlpriv->stats.recv_signal_power = (rtlpriv->stats.recv_signal_power * + 5 + pstatus->recvsignalpower + weighting) / 6; +} + +static void rtl_process_pwdb(struct ieee80211_hw *hw, struct rtl_stats *pstatus) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_sta_info *drv_priv = NULL; + struct ieee80211_sta *sta = NULL; + long undec_sm_pwdb; + + rcu_read_lock(); + if (rtlpriv->mac80211.opmode != NL80211_IFTYPE_STATION) + sta = rtl_find_sta(hw, pstatus->psaddr); + + /* adhoc or ap mode */ + if (sta) { + drv_priv = (struct rtl_sta_info *)sta->drv_priv; + undec_sm_pwdb = drv_priv->rssi_stat.undec_sm_pwdb; + } else { + undec_sm_pwdb = rtlpriv->dm.undec_sm_pwdb; + } + + if (undec_sm_pwdb < 0) + undec_sm_pwdb = pstatus->rx_pwdb_all; + if (pstatus->rx_pwdb_all > (u32)undec_sm_pwdb) { + undec_sm_pwdb = (((undec_sm_pwdb) * + (RX_SMOOTH_FACTOR - 1)) + + (pstatus->rx_pwdb_all)) / (RX_SMOOTH_FACTOR); + undec_sm_pwdb = undec_sm_pwdb + 1; + } else { + undec_sm_pwdb = (((undec_sm_pwdb) * + (RX_SMOOTH_FACTOR - 1)) + + (pstatus->rx_pwdb_all)) / (RX_SMOOTH_FACTOR); + } + + if (sta) + drv_priv->rssi_stat.undec_sm_pwdb = undec_sm_pwdb; + else + rtlpriv->dm.undec_sm_pwdb = undec_sm_pwdb; + rcu_read_unlock(); + + rtl_update_rxsignalstatistics(hw, pstatus); +} + +static void rtl_process_ui_link_quality(struct ieee80211_hw *hw, + struct rtl_stats *pstatus) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 last_evm, n_stream, tmpval; + + if (pstatus->signalquality == 0) + return; + + if (rtlpriv->stats.ui_link_quality.total_num++ >= + PHY_LINKQUALITY_SLID_WIN_MAX) { + rtlpriv->stats.ui_link_quality.total_num = + PHY_LINKQUALITY_SLID_WIN_MAX; + last_evm = rtlpriv->stats.ui_link_quality.elements[ + rtlpriv->stats.ui_link_quality.index]; + rtlpriv->stats.ui_link_quality.total_val -= last_evm; + } + rtlpriv->stats.ui_link_quality.total_val += pstatus->signalquality; + rtlpriv->stats.ui_link_quality.elements[ + rtlpriv->stats.ui_link_quality.index++] = + pstatus->signalquality; + if (rtlpriv->stats.ui_link_quality.index >= + PHY_LINKQUALITY_SLID_WIN_MAX) + rtlpriv->stats.ui_link_quality.index = 0; + tmpval = rtlpriv->stats.ui_link_quality.total_val / + rtlpriv->stats.ui_link_quality.total_num; + rtlpriv->stats.signal_quality = tmpval; + rtlpriv->stats.last_sigstrength_inpercent = tmpval; + for (n_stream = 0; n_stream < 2; n_stream++) { + if (pstatus->rx_mimo_sig_qual[n_stream] != -1) { + if (rtlpriv->stats.rx_evm_percentage[n_stream] == 0) { + rtlpriv->stats.rx_evm_percentage[n_stream] = + pstatus->rx_mimo_sig_qual[n_stream]; + } + rtlpriv->stats.rx_evm_percentage[n_stream] = + ((rtlpriv->stats.rx_evm_percentage[n_stream] + * (RX_SMOOTH_FACTOR - 1)) + + (pstatus->rx_mimo_sig_qual[n_stream] * 1)) / + (RX_SMOOTH_FACTOR); + } + } +} + +void rtl_process_phyinfo(struct ieee80211_hw *hw, u8 *buffer, + struct rtl_stats *pstatus) +{ + if (!pstatus->packet_matchbssid) + return; + + rtl_process_ui_rssi(hw, pstatus); + rtl_process_pwdb(hw, pstatus); + rtl_process_ui_link_quality(hw, pstatus); +} diff --git a/drivers/staging/rtlwifi/stats.h b/drivers/staging/rtlwifi/stats.h new file mode 100644 index 000000000000..bd0108f93182 --- /dev/null +++ b/drivers/staging/rtlwifi/stats.h @@ -0,0 +1,42 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL_STATS_H__ +#define __RTL_STATS_H__ + +#define PHY_RSSI_SLID_WIN_MAX 100 +#define PHY_LINKQUALITY_SLID_WIN_MAX 20 +#define PHY_BEACON_RSSI_SLID_WIN_MAX 10 + +/* Rx smooth factor */ +#define RX_SMOOTH_FACTOR 20 + +u8 rtl_query_rxpwrpercentage(s8 antpower); +u8 rtl_evm_db_to_percentage(s8 value); +long rtl_signal_scale_mapping(struct ieee80211_hw *hw, long currsig); +void rtl_process_phyinfo(struct ieee80211_hw *hw, u8 *buffer, + struct rtl_stats *pstatus); + +#endif diff --git a/drivers/staging/rtlwifi/wifi.h b/drivers/staging/rtlwifi/wifi.h new file mode 100644 index 000000000000..eb91c130b245 --- /dev/null +++ b/drivers/staging/rtlwifi/wifi.h @@ -0,0 +1,3375 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL_WIFI_H__ +#define __RTL_WIFI_H__ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/sched.h> +#include <linux/firmware.h> +#include <linux/etherdevice.h> +#include <linux/vmalloc.h> +#include <linux/usb.h> +#include <net/mac80211.h> +#include <linux/completion.h> +#include "debug.h" + +#define MASKBYTE0 0xff +#define MASKBYTE1 0xff00 +#define MASKBYTE2 0xff0000 +#define MASKBYTE3 0xff000000 +#define MASKHWORD 0xffff0000 +#define MASKLWORD 0x0000ffff +#define MASKDWORD 0xffffffff +#define MASK12BITS 0xfff +#define MASKH4BITS 0xf0000000 +#define MASKOFDM_D 0xffc00000 +#define MASKCCK 0x3f3f3f3f + +#define MASK4BITS 0x0f +#define MASK20BITS 0xfffff +#define RFREG_OFFSET_MASK 0xfffff + +#define MASKBYTE0 0xff +#define MASKBYTE1 0xff00 +#define MASKBYTE2 0xff0000 +#define MASKBYTE3 0xff000000 +#define MASKHWORD 0xffff0000 +#define MASKLWORD 0x0000ffff +#define MASKDWORD 0xffffffff +#define MASK12BITS 0xfff +#define MASKH4BITS 0xf0000000 +#define MASKOFDM_D 0xffc00000 +#define MASKCCK 0x3f3f3f3f + +#define MASK4BITS 0x0f +#define MASK20BITS 0xfffff +#define RFREG_OFFSET_MASK 0xfffff + +#define RF_CHANGE_BY_INIT 0 +#define RF_CHANGE_BY_IPS BIT(28) +#define RF_CHANGE_BY_PS BIT(29) +#define RF_CHANGE_BY_HW BIT(30) +#define RF_CHANGE_BY_SW BIT(31) + +#define IQK_ADDA_REG_NUM 16 +#define IQK_MAC_REG_NUM 4 +#define IQK_THRESHOLD 8 + +#define MAX_KEY_LEN 61 +#define KEY_BUF_SIZE 5 + +/* QoS related. */ +/*aci: 0x00 Best Effort*/ +/*aci: 0x01 Background*/ +/*aci: 0x10 Video*/ +/*aci: 0x11 Voice*/ +/*Max: define total number.*/ +#define AC0_BE 0 +#define AC1_BK 1 +#define AC2_VI 2 +#define AC3_VO 3 +#define AC_MAX 4 +#define QOS_QUEUE_NUM 4 +#define RTL_MAC80211_NUM_QUEUE 5 +#define REALTEK_USB_VENQT_MAX_BUF_SIZE 254 +#define RTL_USB_MAX_RX_COUNT 100 +#define QBSS_LOAD_SIZE 5 +#define MAX_WMMELE_LENGTH 64 + +#define TOTAL_CAM_ENTRY 32 + +/*slot time for 11g. */ +#define RTL_SLOT_TIME_9 9 +#define RTL_SLOT_TIME_20 20 + +/*related to tcp/ip. */ +#define SNAP_SIZE 6 +#define PROTOC_TYPE_SIZE 2 + +/*related with 802.11 frame*/ +#define MAC80211_3ADDR_LEN 24 +#define MAC80211_4ADDR_LEN 30 + +#define CHANNEL_MAX_NUMBER (14 + 24 + 21) /* 14 is the max channel no */ +#define CHANNEL_MAX_NUMBER_2G 14 +#define CHANNEL_MAX_NUMBER_5G 49 /* Please refer to + *"phy_GetChnlGroup8812A" and + * "Hal_ReadTxPowerInfo8812A" + */ +#define CHANNEL_MAX_NUMBER_5G_80M 7 +#define CHANNEL_GROUP_MAX (3 + 9) /* ch1~3, 4~9, 10~14 = three groups */ +#define MAX_PG_GROUP 13 +#define CHANNEL_GROUP_MAX_2G 3 +#define CHANNEL_GROUP_IDX_5GL 3 +#define CHANNEL_GROUP_IDX_5GM 6 +#define CHANNEL_GROUP_IDX_5GH 9 +#define CHANNEL_GROUP_MAX_5G 9 +#define CHANNEL_MAX_NUMBER_2G 14 +#define AVG_THERMAL_NUM 8 +#define AVG_THERMAL_NUM_88E 4 +#define AVG_THERMAL_NUM_8723BE 4 +#define MAX_TID_COUNT 9 + +/* for early mode */ +#define FCS_LEN 4 +#define EM_HDR_LEN 8 + +enum rtl8192c_h2c_cmd { + H2C_AP_OFFLOAD = 0, + H2C_SETPWRMODE = 1, + H2C_JOINBSSRPT = 2, + H2C_RSVDPAGE = 3, + H2C_RSSI_REPORT = 5, + H2C_RA_MASK = 6, + H2C_MACID_PS_MODE = 7, + H2C_P2P_PS_OFFLOAD = 8, + H2C_MAC_MODE_SEL = 9, + H2C_PWRM = 15, + H2C_P2P_PS_CTW_CMD = 24, + MAX_H2CCMD +}; + +#define MAX_TX_COUNT 4 +#define MAX_REGULATION_NUM 4 +#define MAX_RF_PATH_NUM 4 +#define MAX_RATE_SECTION_NUM 6 /* = MAX_RATE_SECTION */ +#define MAX_2_4G_BANDWIDTH_NUM 4 +#define MAX_5G_BANDWIDTH_NUM 4 +#define MAX_RF_PATH 4 +#define MAX_CHNL_GROUP_24G 6 +#define MAX_CHNL_GROUP_5G 14 + +#define TX_PWR_BY_RATE_NUM_BAND 2 +#define TX_PWR_BY_RATE_NUM_RF 4 +#define TX_PWR_BY_RATE_NUM_SECTION 12 +/* compatible with TX_PWR_BY_RATE_NUM_SECTION */ +#define TX_PWR_BY_RATE_NUM_RATE 84 +#define MAX_BASE_NUM_IN_PHY_REG_PG_24G 6 /* MAX_RATE_SECTION */ +#define MAX_BASE_NUM_IN_PHY_REG_PG_5G 5 /* MAX_RATE_SECTION -1 */ + +#define BUFDESC_SEG_NUM 1 /* 0:2 seg, 1: 4 seg, 2: 8 seg */ + +#define DEL_SW_IDX_SZ 30 + +/* For now, it's just for 8192ee + * but not OK yet, keep it 0 + */ +#define RTL8192EE_SEG_NUM BUFDESC_SEG_NUM +#define RTL8822BE_SEG_NUM BUFDESC_SEG_NUM + +enum rf_tx_num { + RF_1TX = 0, + RF_2TX, + RF_MAX_TX_NUM, + RF_TX_NUM_NONIMPLEMENT, +}; + +#define PACKET_NORMAL 0 +#define PACKET_DHCP 1 +#define PACKET_ARP 2 +#define PACKET_EAPOL 3 + +#define MAX_SUPPORT_WOL_PATTERN_NUM 16 +#define RSVD_WOL_PATTERN_NUM 1 +#define WKFMCAM_ADDR_NUM 6 +#define WKFMCAM_SIZE 24 + +#define MAX_WOL_BIT_MASK_SIZE 16 +/* MIN LEN keeps 13 here */ +#define MIN_WOL_PATTERN_SIZE 13 +#define MAX_WOL_PATTERN_SIZE 128 + +#define WAKE_ON_MAGIC_PACKET BIT(0) +#define WAKE_ON_PATTERN_MATCH BIT(1) + +#define WOL_REASON_PTK_UPDATE BIT(0) +#define WOL_REASON_GTK_UPDATE BIT(1) +#define WOL_REASON_DISASSOC BIT(2) +#define WOL_REASON_DEAUTH BIT(3) +#define WOL_REASON_AP_LOST BIT(4) +#define WOL_REASON_MAGIC_PKT BIT(5) +#define WOL_REASON_UNICAST_PKT BIT(6) +#define WOL_REASON_PATTERN_PKT BIT(7) +#define WOL_REASON_RTD3_SSID_MATCH BIT(8) +#define WOL_REASON_REALWOW_V2_WAKEUPPKT BIT(9) +#define WOL_REASON_REALWOW_V2_ACKLOST BIT(10) + +struct rtlwifi_firmware_header { + __le16 signature; + u8 category; + u8 function; + __le16 version; + u8 subversion; + u8 rsvd1; + u8 month; + u8 date; + u8 hour; + u8 minute; + __le16 ramcodesize; + __le16 rsvd2; + __le32 svnindex; + __le32 rsvd3; + __le32 rsvd4; + __le32 rsvd5; +}; + +struct txpower_info_2g { + u8 index_cck_base[MAX_RF_PATH][MAX_CHNL_GROUP_24G]; + u8 index_bw40_base[MAX_RF_PATH][MAX_CHNL_GROUP_24G]; + /*If only one tx, only BW20 and OFDM are used.*/ + u8 cck_diff[MAX_RF_PATH][MAX_TX_COUNT]; + u8 ofdm_diff[MAX_RF_PATH][MAX_TX_COUNT]; + u8 bw20_diff[MAX_RF_PATH][MAX_TX_COUNT]; + u8 bw40_diff[MAX_RF_PATH][MAX_TX_COUNT]; + u8 bw80_diff[MAX_RF_PATH][MAX_TX_COUNT]; + u8 bw160_diff[MAX_RF_PATH][MAX_TX_COUNT]; +}; + +struct txpower_info_5g { + u8 index_bw40_base[MAX_RF_PATH][MAX_CHNL_GROUP_5G]; + /*If only one tx, only BW20, OFDM, BW80 and BW160 are used.*/ + u8 ofdm_diff[MAX_RF_PATH][MAX_TX_COUNT]; + u8 bw20_diff[MAX_RF_PATH][MAX_TX_COUNT]; + u8 bw40_diff[MAX_RF_PATH][MAX_TX_COUNT]; + u8 bw80_diff[MAX_RF_PATH][MAX_TX_COUNT]; + u8 bw160_diff[MAX_RF_PATH][MAX_TX_COUNT]; +}; + +enum rate_section { + CCK = 0, + OFDM, + HT_MCS0_MCS7, + HT_MCS8_MCS15, + VHT_1SSMCS0_1SSMCS9, + VHT_2SSMCS0_2SSMCS9, + MAX_RATE_SECTION, +}; + +enum intf_type { + INTF_PCI = 0, + INTF_USB = 1, +}; + +enum radio_path { + RF90_PATH_A = 0, + RF90_PATH_B = 1, + RF90_PATH_C = 2, + RF90_PATH_D = 3, +}; + +enum radio_mask { + RF_MASK_A = BIT(0), + RF_MASK_B = BIT(1), + RF_MASK_C = BIT(2), + RF_MASK_D = BIT(3), +}; + +enum regulation_txpwr_lmt { + TXPWR_LMT_FCC = 0, + TXPWR_LMT_MKK = 1, + TXPWR_LMT_ETSI = 2, + TXPWR_LMT_WW = 3, + + TXPWR_LMT_MAX_REGULATION_NUM = 4 +}; + +enum rt_eeprom_type { + EEPROM_93C46, + EEPROM_93C56, + EEPROM_BOOT_EFUSE, +}; + +enum ttl_status { + RTL_STATUS_INTERFACE_START = 0, +}; + +enum hardware_type { + HARDWARE_TYPE_RTL8192E, + HARDWARE_TYPE_RTL8192U, + HARDWARE_TYPE_RTL8192SE, + HARDWARE_TYPE_RTL8192SU, + HARDWARE_TYPE_RTL8192CE, + HARDWARE_TYPE_RTL8192CU, + HARDWARE_TYPE_RTL8192DE, + HARDWARE_TYPE_RTL8192DU, + HARDWARE_TYPE_RTL8723AE, + HARDWARE_TYPE_RTL8723U, + HARDWARE_TYPE_RTL8188EE, + HARDWARE_TYPE_RTL8723BE, + HARDWARE_TYPE_RTL8192EE, + HARDWARE_TYPE_RTL8821AE, + HARDWARE_TYPE_RTL8812AE, + HARDWARE_TYPE_RTL8822BE, + + /* keep it last */ + HARDWARE_TYPE_NUM +}; + +#define RTL_HW_TYPE(rtlpriv) (rtl_hal((struct rtl_priv *)rtlpriv)->hw_type) +#define IS_NEW_GENERATION_IC(rtlpriv) \ + (RTL_HW_TYPE(rtlpriv) >= HARDWARE_TYPE_RTL8192EE) +#define IS_HARDWARE_TYPE_8192CE(rtlpriv) \ + (RTL_HW_TYPE(rtlpriv) == HARDWARE_TYPE_RTL8192CE) +#define IS_HARDWARE_TYPE_8812(rtlpriv) \ + (RTL_HW_TYPE(rtlpriv) == HARDWARE_TYPE_RTL8812AE) +#define IS_HARDWARE_TYPE_8821(rtlpriv) \ + (RTL_HW_TYPE(rtlpriv) == HARDWARE_TYPE_RTL8821AE) +#define IS_HARDWARE_TYPE_8723A(rtlpriv) \ + (RTL_HW_TYPE(rtlpriv) == HARDWARE_TYPE_RTL8723AE) +#define IS_HARDWARE_TYPE_8723B(rtlpriv) \ + (RTL_HW_TYPE(rtlpriv) == HARDWARE_TYPE_RTL8723BE) +#define IS_HARDWARE_TYPE_8192E(rtlpriv) \ + (RTL_HW_TYPE(rtlpriv) == HARDWARE_TYPE_RTL8192EE) +#define IS_HARDWARE_TYPE_8822B(rtlpriv) \ + (RTL_HW_TYPE(rtlpriv) == HARDWARE_TYPE_RTL8822BE) + +#define RX_HAL_IS_CCK_RATE(rxmcs) \ + ((rxmcs) == DESC_RATE1M || \ + (rxmcs) == DESC_RATE2M || \ + (rxmcs) == DESC_RATE5_5M || \ + (rxmcs) == DESC_RATE11M) + +enum scan_operation_backup_opt { + SCAN_OPT_BACKUP = 0, + SCAN_OPT_BACKUP_BAND0 = 0, + SCAN_OPT_BACKUP_BAND1, + SCAN_OPT_RESTORE, + SCAN_OPT_MAX +}; + +/*RF state.*/ +enum rf_pwrstate { + ERFON, + ERFSLEEP, + ERFOFF +}; + +struct bb_reg_def { + u32 rfintfs; + u32 rfintfi; + u32 rfintfo; + u32 rfintfe; + u32 rf3wire_offset; + u32 rflssi_select; + u32 rftxgain_stage; + u32 rfhssi_para1; + u32 rfhssi_para2; + u32 rfsw_ctrl; + u32 rfagc_control1; + u32 rfagc_control2; + u32 rfrxiq_imbal; + u32 rfrx_afe; + u32 rftxiq_imbal; + u32 rftx_afe; + u32 rf_rb; /* rflssi_readback */ + u32 rf_rbpi; /* rflssi_readbackpi */ +}; + +enum io_type { + IO_CMD_PAUSE_DM_BY_SCAN = 0, + IO_CMD_PAUSE_BAND0_DM_BY_SCAN = 0, + IO_CMD_PAUSE_BAND1_DM_BY_SCAN = 1, + IO_CMD_RESUME_DM_BY_SCAN = 2, +}; + +enum hw_variables { + HW_VAR_ETHER_ADDR = 0x0, + HW_VAR_MULTICAST_REG = 0x1, + HW_VAR_BASIC_RATE = 0x2, + HW_VAR_BSSID = 0x3, + HW_VAR_MEDIA_STATUS = 0x4, + HW_VAR_SECURITY_CONF = 0x5, + HW_VAR_BEACON_INTERVAL = 0x6, + HW_VAR_ATIM_WINDOW = 0x7, + HW_VAR_LISTEN_INTERVAL = 0x8, + HW_VAR_CS_COUNTER = 0x9, + HW_VAR_DEFAULTKEY0 = 0xa, + HW_VAR_DEFAULTKEY1 = 0xb, + HW_VAR_DEFAULTKEY2 = 0xc, + HW_VAR_DEFAULTKEY3 = 0xd, + HW_VAR_SIFS = 0xe, + HW_VAR_R2T_SIFS = 0xf, + HW_VAR_DIFS = 0x10, + HW_VAR_EIFS = 0x11, + HW_VAR_SLOT_TIME = 0x12, + HW_VAR_ACK_PREAMBLE = 0x13, + HW_VAR_CW_CONFIG = 0x14, + HW_VAR_CW_VALUES = 0x15, + HW_VAR_RATE_FALLBACK_CONTROL = 0x16, + HW_VAR_CONTENTION_WINDOW = 0x17, + HW_VAR_RETRY_COUNT = 0x18, + HW_VAR_TR_SWITCH = 0x19, + HW_VAR_COMMAND = 0x1a, + HW_VAR_WPA_CONFIG = 0x1b, + HW_VAR_AMPDU_MIN_SPACE = 0x1c, + HW_VAR_SHORTGI_DENSITY = 0x1d, + HW_VAR_AMPDU_FACTOR = 0x1e, + HW_VAR_MCS_RATE_AVAILABLE = 0x1f, + HW_VAR_AC_PARAM = 0x20, + HW_VAR_ACM_CTRL = 0x21, + HW_VAR_DIS_REQ_QSIZE = 0x22, + HW_VAR_CCX_CHNL_LOAD = 0x23, + HW_VAR_CCX_NOISE_HISTOGRAM = 0x24, + HW_VAR_CCX_CLM_NHM = 0x25, + HW_VAR_TXOPLIMIT = 0x26, + HW_VAR_TURBO_MODE = 0x27, + HW_VAR_RF_STATE = 0x28, + HW_VAR_RF_OFF_BY_HW = 0x29, + HW_VAR_BUS_SPEED = 0x2a, + HW_VAR_SET_DEV_POWER = 0x2b, + + HW_VAR_RCR = 0x2c, + HW_VAR_RATR_0 = 0x2d, + HW_VAR_RRSR = 0x2e, + HW_VAR_CPU_RST = 0x2f, + HW_VAR_CHECK_BSSID = 0x30, + HW_VAR_LBK_MODE = 0x31, + HW_VAR_AES_11N_FIX = 0x32, + HW_VAR_USB_RX_AGGR = 0x33, + HW_VAR_USER_CONTROL_TURBO_MODE = 0x34, + HW_VAR_RETRY_LIMIT = 0x35, + HW_VAR_INIT_TX_RATE = 0x36, + HW_VAR_TX_RATE_REG = 0x37, + HW_VAR_EFUSE_USAGE = 0x38, + HW_VAR_EFUSE_BYTES = 0x39, + HW_VAR_AUTOLOAD_STATUS = 0x3a, + HW_VAR_RF_2R_DISABLE = 0x3b, + HW_VAR_SET_RPWM = 0x3c, + HW_VAR_H2C_FW_PWRMODE = 0x3d, + HW_VAR_H2C_FW_JOINBSSRPT = 0x3e, + HW_VAR_H2C_FW_MEDIASTATUSRPT = 0x3f, + HW_VAR_H2C_FW_P2P_PS_OFFLOAD = 0x40, + HW_VAR_FW_PSMODE_STATUS = 0x41, + HW_VAR_INIT_RTS_RATE = 0x42, + HW_VAR_RESUME_CLK_ON = 0x43, + HW_VAR_FW_LPS_ACTION = 0x44, + HW_VAR_1X1_RECV_COMBINE = 0x45, + HW_VAR_STOP_SEND_BEACON = 0x46, + HW_VAR_TSF_TIMER = 0x47, + HW_VAR_IO_CMD = 0x48, + + HW_VAR_RF_RECOVERY = 0x49, + HW_VAR_H2C_FW_UPDATE_GTK = 0x4a, + HW_VAR_WF_MASK = 0x4b, + HW_VAR_WF_CRC = 0x4c, + HW_VAR_WF_IS_MAC_ADDR = 0x4d, + HW_VAR_H2C_FW_OFFLOAD = 0x4e, + HW_VAR_RESET_WFCRC = 0x4f, + + HW_VAR_HANDLE_FW_C2H = 0x50, + HW_VAR_DL_FW_RSVD_PAGE = 0x51, + HW_VAR_AID = 0x52, + HW_VAR_HW_SEQ_ENABLE = 0x53, + HW_VAR_CORRECT_TSF = 0x54, + HW_VAR_BCN_VALID = 0x55, + HW_VAR_FWLPS_RF_ON = 0x56, + HW_VAR_DUAL_TSF_RST = 0x57, + HW_VAR_SWITCH_EPHY_WOWLAN = 0x58, + HW_VAR_INT_MIGRATION = 0x59, + HW_VAR_INT_AC = 0x5a, + HW_VAR_RF_TIMING = 0x5b, + + HAL_DEF_WOWLAN = 0x5c, + HW_VAR_MRC = 0x5d, + HW_VAR_KEEP_ALIVE = 0x5e, + HW_VAR_NAV_UPPER = 0x5f, + + HW_VAR_MGT_FILTER = 0x60, + HW_VAR_CTRL_FILTER = 0x61, + HW_VAR_DATA_FILTER = 0x62, +}; + +enum rt_media_status { + RT_MEDIA_DISCONNECT = 0, + RT_MEDIA_CONNECT = 1 +}; + +enum rt_oem_id { + RT_CID_DEFAULT = 0, + RT_CID_8187_ALPHA0 = 1, + RT_CID_8187_SERCOMM_PS = 2, + RT_CID_8187_HW_LED = 3, + RT_CID_8187_NETGEAR = 4, + RT_CID_WHQL = 5, + RT_CID_819X_CAMEO = 6, + RT_CID_819X_RUNTOP = 7, + RT_CID_819X_SENAO = 8, + RT_CID_TOSHIBA = 9, + RT_CID_819X_NETCORE = 10, + RT_CID_NETTRONIX = 11, + RT_CID_DLINK = 12, + RT_CID_PRONET = 13, + RT_CID_COREGA = 14, + RT_CID_819X_ALPHA = 15, + RT_CID_819X_SITECOM = 16, + RT_CID_CCX = 17, + RT_CID_819X_LENOVO = 18, + RT_CID_819X_QMI = 19, + RT_CID_819X_EDIMAX_BELKIN = 20, + RT_CID_819X_SERCOMM_BELKIN = 21, + RT_CID_819X_CAMEO1 = 22, + RT_CID_819X_MSI = 23, + RT_CID_819X_ACER = 24, + RT_CID_819X_HP = 27, + RT_CID_819X_CLEVO = 28, + RT_CID_819X_ARCADYAN_BELKIN = 29, + RT_CID_819X_SAMSUNG = 30, + RT_CID_819X_WNC_COREGA = 31, + RT_CID_819X_FOXCOON = 32, + RT_CID_819X_DELL = 33, + RT_CID_819X_PRONETS = 34, + RT_CID_819X_EDIMAX_ASUS = 35, + RT_CID_NETGEAR = 36, + RT_CID_PLANEX = 37, + RT_CID_CC_C = 38, +}; + +enum hw_descs { + HW_DESC_OWN, + HW_DESC_RXOWN, + HW_DESC_TX_NEXTDESC_ADDR, + HW_DESC_TXBUFF_ADDR, + HW_DESC_RXBUFF_ADDR, + HW_DESC_RXPKT_LEN, + HW_DESC_RXERO, + HW_DESC_RX_PREPARE, +}; + +enum prime_sc { + PRIME_CHNL_OFFSET_DONT_CARE = 0, + PRIME_CHNL_OFFSET_LOWER = 1, + PRIME_CHNL_OFFSET_UPPER = 2, +}; + +enum rf_type { + RF_1T1R = 0, + RF_1T2R = 1, + RF_2T2R = 2, + RF_2T2R_GREEN = 3, + RF_2T3R = 4, + RF_2T4R = 5, + RF_3T3R = 6, + RF_3T4R = 7, + RF_4T4R = 8, +}; + +enum ht_channel_width { + HT_CHANNEL_WIDTH_20 = 0, + HT_CHANNEL_WIDTH_20_40 = 1, + HT_CHANNEL_WIDTH_80 = 2, + HT_CHANNEL_WIDTH_MAX, +}; + +/* Ref: 802.11i spec D10.0 7.3.2.25.1 + * Cipher Suites Encryption Algorithms + */ +enum rt_enc_alg { + NO_ENCRYPTION = 0, + WEP40_ENCRYPTION = 1, + TKIP_ENCRYPTION = 2, + RSERVED_ENCRYPTION = 3, + AESCCMP_ENCRYPTION = 4, + WEP104_ENCRYPTION = 5, + AESCMAC_ENCRYPTION = 6, /*IEEE802.11w */ +}; + +enum rtl_hal_state { + _HAL_STATE_STOP = 0, + _HAL_STATE_START = 1, +}; + +enum rtl_desc_rate { + DESC_RATE1M = 0x00, + DESC_RATE2M = 0x01, + DESC_RATE5_5M = 0x02, + DESC_RATE11M = 0x03, + + DESC_RATE6M = 0x04, + DESC_RATE9M = 0x05, + DESC_RATE12M = 0x06, + DESC_RATE18M = 0x07, + DESC_RATE24M = 0x08, + DESC_RATE36M = 0x09, + DESC_RATE48M = 0x0a, + DESC_RATE54M = 0x0b, + + DESC_RATEMCS0 = 0x0c, + DESC_RATEMCS1 = 0x0d, + DESC_RATEMCS2 = 0x0e, + DESC_RATEMCS3 = 0x0f, + DESC_RATEMCS4 = 0x10, + DESC_RATEMCS5 = 0x11, + DESC_RATEMCS6 = 0x12, + DESC_RATEMCS7 = 0x13, + DESC_RATEMCS8 = 0x14, + DESC_RATEMCS9 = 0x15, + DESC_RATEMCS10 = 0x16, + DESC_RATEMCS11 = 0x17, + DESC_RATEMCS12 = 0x18, + DESC_RATEMCS13 = 0x19, + DESC_RATEMCS14 = 0x1a, + DESC_RATEMCS15 = 0x1b, + DESC_RATEMCS15_SG = 0x1c, + DESC_RATEMCS32 = 0x20, + + DESC_RATEVHT1SS_MCS0 = 0x2c, + DESC_RATEVHT1SS_MCS1 = 0x2d, + DESC_RATEVHT1SS_MCS2 = 0x2e, + DESC_RATEVHT1SS_MCS3 = 0x2f, + DESC_RATEVHT1SS_MCS4 = 0x30, + DESC_RATEVHT1SS_MCS5 = 0x31, + DESC_RATEVHT1SS_MCS6 = 0x32, + DESC_RATEVHT1SS_MCS7 = 0x33, + DESC_RATEVHT1SS_MCS8 = 0x34, + DESC_RATEVHT1SS_MCS9 = 0x35, + DESC_RATEVHT2SS_MCS0 = 0x36, + DESC_RATEVHT2SS_MCS1 = 0x37, + DESC_RATEVHT2SS_MCS2 = 0x38, + DESC_RATEVHT2SS_MCS3 = 0x39, + DESC_RATEVHT2SS_MCS4 = 0x3a, + DESC_RATEVHT2SS_MCS5 = 0x3b, + DESC_RATEVHT2SS_MCS6 = 0x3c, + DESC_RATEVHT2SS_MCS7 = 0x3d, + DESC_RATEVHT2SS_MCS8 = 0x3e, + DESC_RATEVHT2SS_MCS9 = 0x3f, +}; + +enum rtl_var_map { + /*reg map */ + SYS_ISO_CTRL = 0, + SYS_FUNC_EN, + SYS_CLK, + MAC_RCR_AM, + MAC_RCR_AB, + MAC_RCR_ACRC32, + MAC_RCR_ACF, + MAC_RCR_AAP, + MAC_HIMR, + MAC_HIMRE, + MAC_HSISR, + + /*efuse map */ + EFUSE_TEST, + EFUSE_CTRL, + EFUSE_CLK, + EFUSE_CLK_CTRL, + EFUSE_PWC_EV12V, + EFUSE_FEN_ELDR, + EFUSE_LOADER_CLK_EN, + EFUSE_ANA8M, + EFUSE_HWSET_MAX_SIZE, + EFUSE_MAX_SECTION_MAP, + EFUSE_REAL_CONTENT_SIZE, + EFUSE_OOB_PROTECT_BYTES_LEN, + EFUSE_ACCESS, + + /*CAM map */ + RWCAM, + WCAMI, + RCAMO, + CAMDBG, + SECR, + SEC_CAM_NONE, + SEC_CAM_WEP40, + SEC_CAM_TKIP, + SEC_CAM_AES, + SEC_CAM_WEP104, + + /*IMR map */ + RTL_IMR_BCNDMAINT6, /*Beacon DMA Interrupt 6 */ + RTL_IMR_BCNDMAINT5, /*Beacon DMA Interrupt 5 */ + RTL_IMR_BCNDMAINT4, /*Beacon DMA Interrupt 4 */ + RTL_IMR_BCNDMAINT3, /*Beacon DMA Interrupt 3 */ + RTL_IMR_BCNDMAINT2, /*Beacon DMA Interrupt 2 */ + RTL_IMR_BCNDMAINT1, /*Beacon DMA Interrupt 1 */ + RTL_IMR_BCNDOK8, /*Beacon Queue DMA OK Interrupt 8 */ + RTL_IMR_BCNDOK7, /*Beacon Queue DMA OK Interrupt 7 */ + RTL_IMR_BCNDOK6, /*Beacon Queue DMA OK Interrupt 6 */ + RTL_IMR_BCNDOK5, /*Beacon Queue DMA OK Interrupt 5 */ + RTL_IMR_BCNDOK4, /*Beacon Queue DMA OK Interrupt 4 */ + RTL_IMR_BCNDOK3, /*Beacon Queue DMA OK Interrupt 3 */ + RTL_IMR_BCNDOK2, /*Beacon Queue DMA OK Interrupt 2 */ + RTL_IMR_BCNDOK1, /*Beacon Queue DMA OK Interrupt 1 */ + RTL_IMR_TIMEOUT2, /*Timeout interrupt 2 */ + RTL_IMR_TIMEOUT1, /*Timeout interrupt 1 */ + RTL_IMR_TXFOVW, /*Transmit FIFO Overflow */ + RTL_IMR_PSTIMEOUT, /*Power save time out interrupt */ + RTL_IMR_BCNINT, /*Beacon DMA Interrupt 0 */ + RTL_IMR_RXFOVW, /*Receive FIFO Overflow */ + RTL_IMR_RDU, /*Receive Descriptor Unavailable */ + RTL_IMR_ATIMEND, /*For 92C,ATIM Window End Interrupt */ + RTL_IMR_H2CDOK, /*H2C Queue DMA OK Interrupt */ + RTL_IMR_BDOK, /*Beacon Queue DMA OK Interrupt */ + RTL_IMR_HIGHDOK, /*High Queue DMA OK Interrupt */ + RTL_IMR_COMDOK, /*Command Queue DMA OK Interrupt*/ + RTL_IMR_TBDOK, /*Transmit Beacon OK interrupt */ + RTL_IMR_MGNTDOK, /*Management Queue DMA OK Interrupt */ + RTL_IMR_TBDER, /*For 92C,Transmit Beacon Error Interrupt */ + RTL_IMR_BKDOK, /*AC_BK DMA OK Interrupt */ + RTL_IMR_BEDOK, /*AC_BE DMA OK Interrupt */ + RTL_IMR_VIDOK, /*AC_VI DMA OK Interrupt */ + RTL_IMR_VODOK, /*AC_VO DMA Interrupt */ + RTL_IMR_ROK, /*Receive DMA OK Interrupt */ + RTL_IMR_HSISR_IND, /*HSISR Interrupt*/ + RTL_IBSS_INT_MASKS, /*(RTL_IMR_BCNINT | RTL_IMR_TBDOK | + * RTL_IMR_TBDER) + */ + RTL_IMR_C2HCMD, /*fw interrupt*/ + + /*CCK Rates, TxHT = 0 */ + RTL_RC_CCK_RATE1M, + RTL_RC_CCK_RATE2M, + RTL_RC_CCK_RATE5_5M, + RTL_RC_CCK_RATE11M, + + /*OFDM Rates, TxHT = 0 */ + RTL_RC_OFDM_RATE6M, + RTL_RC_OFDM_RATE9M, + RTL_RC_OFDM_RATE12M, + RTL_RC_OFDM_RATE18M, + RTL_RC_OFDM_RATE24M, + RTL_RC_OFDM_RATE36M, + RTL_RC_OFDM_RATE48M, + RTL_RC_OFDM_RATE54M, + + RTL_RC_HT_RATEMCS7, + RTL_RC_HT_RATEMCS15, + + RTL_RC_VHT_RATE_1SS_MCS7, + RTL_RC_VHT_RATE_1SS_MCS8, + RTL_RC_VHT_RATE_1SS_MCS9, + RTL_RC_VHT_RATE_2SS_MCS7, + RTL_RC_VHT_RATE_2SS_MCS8, + RTL_RC_VHT_RATE_2SS_MCS9, + + /*keep it last */ + RTL_VAR_MAP_MAX, +}; + +/*Firmware PS mode for control LPS.*/ +enum _fw_ps_mode { + FW_PS_ACTIVE_MODE = 0, + FW_PS_MIN_MODE = 1, + FW_PS_MAX_MODE = 2, + FW_PS_DTIM_MODE = 3, + FW_PS_VOIP_MODE = 4, + FW_PS_UAPSD_WMM_MODE = 5, + FW_PS_UAPSD_MODE = 6, + FW_PS_IBSS_MODE = 7, + FW_PS_WWLAN_MODE = 8, + FW_PS_PM_RADIO_OFF = 9, + FW_PS_PM_CARD_DISABLE = 10, +}; + +enum rt_psmode { + EACTIVE, /*Active/Continuous access. */ + EMAXPS, /*Max power save mode. */ + EFASTPS, /*Fast power save mode. */ + EAUTOPS, /*Auto power save mode. */ +}; + +/*LED related.*/ +enum led_ctl_mode { + LED_CTL_POWER_ON = 1, + LED_CTL_LINK = 2, + LED_CTL_NO_LINK = 3, + LED_CTL_TX = 4, + LED_CTL_RX = 5, + LED_CTL_SITE_SURVEY = 6, + LED_CTL_POWER_OFF = 7, + LED_CTL_START_TO_LINK = 8, + LED_CTL_START_WPS = 9, + LED_CTL_STOP_WPS = 10, +}; + +enum rtl_led_pin { + LED_PIN_GPIO0, + LED_PIN_LED0, + LED_PIN_LED1, + LED_PIN_LED2 +}; + +/* QoS related.*/ +/* acm implementation method.*/ +enum acm_method { + EACMWAY0_SWANDHW = 0, + EACMWAY1_HW = 1, + EACMWAY2_SW = 2, +}; + +enum macphy_mode { + SINGLEMAC_SINGLEPHY = 0, + DUALMAC_DUALPHY, + DUALMAC_SINGLEPHY, +}; + +enum band_type { + BAND_ON_2_4G = 0, + BAND_ON_5G, + BAND_ON_BOTH, + BANDMAX +}; + +/* aci/aifsn Field. + * Ref: WMM spec 2.2.2: WME Parameter Element, p.12. + */ +union aci_aifsn { + u8 char_data; + + struct { + u8 aifsn:4; + u8 acm:1; + u8 aci:2; + u8 reserved:1; + } f; /* Field */ +}; + +/*mlme related.*/ +enum wireless_mode { + WIRELESS_MODE_UNKNOWN = 0x00, + WIRELESS_MODE_A = 0x01, + WIRELESS_MODE_B = 0x02, + WIRELESS_MODE_G = 0x04, + WIRELESS_MODE_AUTO = 0x08, + WIRELESS_MODE_N_24G = 0x10, + WIRELESS_MODE_N_5G = 0x20, + WIRELESS_MODE_AC_5G = 0x40, + WIRELESS_MODE_AC_24G = 0x80, + WIRELESS_MODE_AC_ONLY = 0x100, + WIRELESS_MODE_MAX = 0x800 +}; + +#define IS_WIRELESS_MODE_A(wirelessmode) \ + (wirelessmode == WIRELESS_MODE_A) +#define IS_WIRELESS_MODE_B(wirelessmode) \ + (wirelessmode == WIRELESS_MODE_B) +#define IS_WIRELESS_MODE_G(wirelessmode) \ + (wirelessmode == WIRELESS_MODE_G) +#define IS_WIRELESS_MODE_N_24G(wirelessmode) \ + (wirelessmode == WIRELESS_MODE_N_24G) +#define IS_WIRELESS_MODE_N_5G(wirelessmode) \ + (wirelessmode == WIRELESS_MODE_N_5G) + +enum ratr_table_mode { + RATR_INX_WIRELESS_NGB = 0, + RATR_INX_WIRELESS_NG = 1, + RATR_INX_WIRELESS_NB = 2, + RATR_INX_WIRELESS_N = 3, + RATR_INX_WIRELESS_GB = 4, + RATR_INX_WIRELESS_G = 5, + RATR_INX_WIRELESS_B = 6, + RATR_INX_WIRELESS_MC = 7, + RATR_INX_WIRELESS_A = 8, + RATR_INX_WIRELESS_AC_5N = 8, + RATR_INX_WIRELESS_AC_24N = 9, +}; + +enum ratr_table_mode_new { + RATEID_IDX_BGN_40M_2SS = 0, + RATEID_IDX_BGN_40M_1SS = 1, + RATEID_IDX_BGN_20M_2SS_BN = 2, + RATEID_IDX_BGN_20M_1SS_BN = 3, + RATEID_IDX_GN_N2SS = 4, + RATEID_IDX_GN_N1SS = 5, + RATEID_IDX_BG = 6, + RATEID_IDX_G = 7, + RATEID_IDX_B = 8, + RATEID_IDX_VHT_2SS = 9, + RATEID_IDX_VHT_1SS = 10, + RATEID_IDX_MIX1 = 11, + RATEID_IDX_MIX2 = 12, + RATEID_IDX_VHT_3SS = 13, + RATEID_IDX_BGN_3SS = 14, +}; + +enum rtl_link_state { + MAC80211_NOLINK = 0, + MAC80211_LINKING = 1, + MAC80211_LINKED = 2, + MAC80211_LINKED_SCANNING = 3, +}; + +enum act_category { + ACT_CAT_QOS = 1, + ACT_CAT_DLS = 2, + ACT_CAT_BA = 3, + ACT_CAT_HT = 7, + ACT_CAT_WMM = 17, +}; + +enum ba_action { + ACT_ADDBAREQ = 0, + ACT_ADDBARSP = 1, + ACT_DELBA = 2, +}; + +enum rt_polarity_ctl { + RT_POLARITY_LOW_ACT = 0, + RT_POLARITY_HIGH_ACT = 1, +}; + +/* After 8188E, we use V2 reason define. 88C/8723A use V1 reason. */ +enum fw_wow_reason_v2 { + FW_WOW_V2_PTK_UPDATE_EVENT = 0x01, + FW_WOW_V2_GTK_UPDATE_EVENT = 0x02, + FW_WOW_V2_DISASSOC_EVENT = 0x04, + FW_WOW_V2_DEAUTH_EVENT = 0x08, + FW_WOW_V2_FW_DISCONNECT_EVENT = 0x10, + FW_WOW_V2_MAGIC_PKT_EVENT = 0x21, + FW_WOW_V2_UNICAST_PKT_EVENT = 0x22, + FW_WOW_V2_PATTERN_PKT_EVENT = 0x23, + FW_WOW_V2_RTD3_SSID_MATCH_EVENT = 0x24, + FW_WOW_V2_REALWOW_V2_WAKEUPPKT = 0x30, + FW_WOW_V2_REALWOW_V2_ACKLOST = 0x31, + FW_WOW_V2_REASON_MAX = 0xff, +}; + +enum wolpattern_type { + UNICAST_PATTERN = 0, + MULTICAST_PATTERN = 1, + BROADCAST_PATTERN = 2, + DONT_CARE_DA = 3, + UNKNOWN_TYPE = 4, +}; + +enum package_type { + PACKAGE_DEFAULT, + PACKAGE_QFN68, + PACKAGE_TFBGA90, + PACKAGE_TFBGA80, + PACKAGE_TFBGA79 +}; + +enum rtl_spec_ver { + RTL_SPEC_NEW_RATEID = BIT(0), /* use ratr_table_mode_new */ + RTL_SPEC_SUPPORT_VHT = BIT(1), /* support VHT */ + RTL_SPEC_NEW_FW_C2H = BIT(2), /* new FW C2H (e.g. TX REPORT) */ +}; + +struct octet_string { + u8 *octet; + u16 length; +}; + +struct rtl_hdr_3addr { + __le16 frame_ctl; + __le16 duration_id; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + u8 addr3[ETH_ALEN]; + __le16 seq_ctl; + u8 payload[0]; +} __packed; + +struct rtl_info_element { + u8 id; + u8 len; + u8 data[0]; +} __packed; + +struct rtl_probe_rsp { + struct rtl_hdr_3addr header; + u32 time_stamp[2]; + __le16 beacon_interval; + __le16 capability; + /* SSID, supported rates, FH params, DS params, + * CF params, IBSS params, TIM (if beacon), RSN + */ + struct rtl_info_element info_element[0]; +} __packed; + +struct rtl_beacon_keys { + /*u8 ssid[32];*/ + /*u32 ssid_len;*/ + u8 bcn_channel; + __le16 ht_cap_info; + u8 ht_info_infos_0_sco; /* bit0 & bit1 in infos[0] is 2nd ch offset */ + bool valid; +}; + +/*LED related.*/ +/*ledpin Identify how to implement this SW led.*/ +struct rtl_led { + void *hw; + enum rtl_led_pin ledpin; + bool ledon; +}; + +struct rtl_led_ctl { + bool led_opendrain; + struct rtl_led sw_led0; + struct rtl_led sw_led1; +}; + +struct rtl_qos_parameters { + __le16 cw_min; + __le16 cw_max; + u8 aifs; + u8 flag; + __le16 tx_op; +} __packed; + +struct rt_smooth_data { + u32 elements[100]; /*array to store values */ + u32 index; /*index to current array to store */ + u32 total_num; /*num of valid elements */ + u32 total_val; /*sum of valid elements */ +}; + +struct false_alarm_statistics { + u32 cnt_parity_fail; + u32 cnt_rate_illegal; + u32 cnt_crc8_fail; + u32 cnt_mcs_fail; + u32 cnt_fast_fsync_fail; + u32 cnt_sb_search_fail; + u32 cnt_ofdm_fail; + u32 cnt_cck_fail; + u32 cnt_all; + u32 cnt_ofdm_cca; + u32 cnt_cck_cca; + u32 cnt_cca_all; + u32 cnt_bw_usc; + u32 cnt_bw_lsc; +}; + +struct init_gain { + u8 xaagccore1; + u8 xbagccore1; + u8 xcagccore1; + u8 xdagccore1; + u8 cca; + +}; + +struct wireless_stats { + u64 txbytesunicast; + u64 txbytesmulticast; + u64 txbytesbroadcast; + u64 rxbytesunicast; + + u64 txbytesunicast_inperiod; + u64 rxbytesunicast_inperiod; + u32 txbytesunicast_inperiod_tp; + u32 rxbytesunicast_inperiod_tp; + u64 txbytesunicast_last; + u64 rxbytesunicast_last; + + long rx_snr_db[4]; + /* Correct smoothed ss in Dbm, only used + * in driver to report real power now. + */ + long recv_signal_power; + long signal_quality; + long last_sigstrength_inpercent; + + u32 rssi_calculate_cnt; + u32 pwdb_all_cnt; + + /* Transformed, in dbm. Beautified signal + * strength for UI, not correct. + */ + long signal_strength; + + u8 rx_rssi_percentage[4]; + u8 rx_evm_dbm[4]; + u8 rx_evm_percentage[2]; + + u16 rx_cfo_short[4]; + u16 rx_cfo_tail[4]; + + struct rt_smooth_data ui_rssi; + struct rt_smooth_data ui_link_quality; +}; + +struct rate_adaptive { + u8 rate_adaptive_disabled; + u8 ratr_state; + u16 reserve; + + u32 high_rssi_thresh_for_ra; + u32 high2low_rssi_thresh_for_ra; + u8 low2high_rssi_thresh_for_ra40m; + u32 low_rssi_thresh_for_ra40m; + u8 low2high_rssi_thresh_for_ra20m; + u32 low_rssi_thresh_for_ra20m; + u32 upper_rssi_threshold_ratr; + u32 middleupper_rssi_threshold_ratr; + u32 middle_rssi_threshold_ratr; + u32 middlelow_rssi_threshold_ratr; + u32 low_rssi_threshold_ratr; + u32 ultralow_rssi_threshold_ratr; + u32 low_rssi_threshold_ratr_40m; + u32 low_rssi_threshold_ratr_20m; + u8 ping_rssi_enable; + u32 ping_rssi_ratr; + u32 ping_rssi_thresh_for_ra; + u32 last_ratr; + u8 pre_ratr_state; + u8 ldpc_thres; + bool use_ldpc; + bool lower_rts_rate; + bool is_special_data; +}; + +struct regd_pair_mapping { + u16 reg_dmnenum; + u16 reg_5ghz_ctl; + u16 reg_2ghz_ctl; +}; + +struct dynamic_primary_cca { + u8 pricca_flag; + u8 intf_flag; + u8 intf_type; + u8 dup_rts_flag; + u8 monitor_flag; + u8 ch_offset; + u8 mf_state; +}; + +struct rtl_regulatory { + s8 alpha2[2]; + u16 country_code; + u16 max_power_level; + u32 tp_scale; + u16 current_rd; + u16 current_rd_ext; + s16 power_limit; + struct regd_pair_mapping *regpair; +}; + +struct rtl_rfkill { + bool rfkill_state; /*0 is off, 1 is on */ +}; + +/*for P2P PS**/ +#define P2P_MAX_NOA_NUM 2 + +enum p2p_role { + P2P_ROLE_DISABLE = 0, + P2P_ROLE_DEVICE = 1, + P2P_ROLE_CLIENT = 2, + P2P_ROLE_GO = 3 +}; + +enum p2p_ps_state { + P2P_PS_DISABLE = 0, + P2P_PS_ENABLE = 1, + P2P_PS_SCAN = 2, + P2P_PS_SCAN_DONE = 3, + P2P_PS_ALLSTASLEEP = 4, /* for P2P GO */ +}; + +enum p2p_ps_mode { + P2P_PS_NONE = 0, + P2P_PS_CTWINDOW = 1, + P2P_PS_NOA = 2, + P2P_PS_MIX = 3, /* CTWindow and NoA */ +}; + +struct rtl_p2p_ps_info { + enum p2p_ps_mode p2p_ps_mode; /* indicate p2p ps mode */ + enum p2p_ps_state p2p_ps_state; /* indicate p2p ps state */ + u8 noa_index; /* Identifies instance of Notice of Absence timing. */ + /* Client traffic window. A period of time in TU after TBTT. */ + u8 ctwindow; + u8 opp_ps; /* opportunistic power save. */ + u8 noa_num; /* number of NoA descriptor in P2P IE. */ + /* Count for owner, Type of client. */ + u8 noa_count_type[P2P_MAX_NOA_NUM]; + /* Max duration for owner, preferred or min acceptable duration + * for client. + */ + u32 noa_duration[P2P_MAX_NOA_NUM]; + /* Length of interval for owner, preferred or max acceptable intervali + * of client. + */ + u32 noa_interval[P2P_MAX_NOA_NUM]; + /* schedule in terms of the lower 4 bytes of the TSF timer. */ + u32 noa_start_time[P2P_MAX_NOA_NUM]; +}; + +struct p2p_ps_offload_t { + u8 offload_en:1; + u8 role:1; /* 1: Owner, 0: Client */ + u8 ctwindow_en:1; + u8 noa0_en:1; + u8 noa1_en:1; + u8 allstasleep:1; + u8 discovery:1; + u8 reserved:1; +}; + +#define IQK_MATRIX_REG_NUM 8 +#define IQK_MATRIX_SETTINGS_NUM (1 + 24 + 21) + +struct iqk_matrix_regs { + bool iqk_done; + long value[1][IQK_MATRIX_REG_NUM]; +}; + +struct phy_parameters { + u16 length; + u32 *pdata; +}; + +enum hw_param_tab_index { + PHY_REG_2T, + PHY_REG_1T, + PHY_REG_PG, + RADIOA_2T, + RADIOB_2T, + RADIOA_1T, + RADIOB_1T, + MAC_REG, + AGCTAB_2T, + AGCTAB_1T, + MAX_TAB +}; + +struct rtl_phy { + struct bb_reg_def phyreg_def[4]; /*Radio A/B/C/D */ + struct init_gain initgain_backup; + enum io_type current_io_type; + + u8 rf_mode; + u8 rf_type; + u8 current_chan_bw; + u8 max_ht_chan_bw; + u8 max_vht_chan_bw; + u8 set_bwmode_inprogress; + u8 sw_chnl_inprogress; + u8 sw_chnl_stage; + u8 sw_chnl_step; + u8 current_channel; + u8 h2c_box_num; + u8 set_io_inprogress; + u8 lck_inprogress; + + /* record for power tracking */ + s32 reg_e94; + s32 reg_e9c; + s32 reg_ea4; + s32 reg_eac; + s32 reg_eb4; + s32 reg_ebc; + s32 reg_ec4; + s32 reg_ecc; + u8 rfpienable; + u8 reserve_0; + u16 reserve_1; + u32 reg_c04, reg_c08, reg_874; + u32 adda_backup[16]; + u32 iqk_mac_backup[IQK_MAC_REG_NUM]; + u32 iqk_bb_backup[10]; + bool iqk_initialized; + + bool rfpath_rx_enable[MAX_RF_PATH]; + u8 reg_837; + /* Dual mac */ + bool need_iqk; + struct iqk_matrix_regs iqk_matrix[IQK_MATRIX_SETTINGS_NUM]; + + bool rfpi_enable; + bool iqk_in_progress; + + u8 pwrgroup_cnt; + u8 cck_high_power; + /* this is for 88E & 8723A */ + u32 mcs_txpwrlevel_origoffset[MAX_PG_GROUP][16]; + /* MAX_PG_GROUP groups of pwr diff by rates */ + u32 mcs_offset[MAX_PG_GROUP][16]; + u32 tx_power_by_rate_offset[TX_PWR_BY_RATE_NUM_BAND] + [TX_PWR_BY_RATE_NUM_RF] + [TX_PWR_BY_RATE_NUM_RF] + [TX_PWR_BY_RATE_NUM_RATE]; + /* compatible with TX_PWR_BY_RATE_NUM_SECTION*/ + u8 txpwr_by_rate_base_24g[TX_PWR_BY_RATE_NUM_RF] + [TX_PWR_BY_RATE_NUM_RF] + [MAX_BASE_NUM_IN_PHY_REG_PG_24G]; + u8 txpwr_by_rate_base_5g[TX_PWR_BY_RATE_NUM_RF] + [TX_PWR_BY_RATE_NUM_RF] + [MAX_BASE_NUM_IN_PHY_REG_PG_5G]; + u8 default_initialgain[4]; + + /* the current Tx power level */ + u8 cur_cck_txpwridx; + u8 cur_ofdm24g_txpwridx; + u8 cur_bw20_txpwridx; + u8 cur_bw40_txpwridx; + + s8 txpwr_limit_2_4g[MAX_REGULATION_NUM] + [MAX_2_4G_BANDWIDTH_NUM] + [MAX_RATE_SECTION_NUM] + [CHANNEL_MAX_NUMBER_2G] + [MAX_RF_PATH_NUM]; + s8 txpwr_limit_5g[MAX_REGULATION_NUM] + [MAX_5G_BANDWIDTH_NUM] + [MAX_RATE_SECTION_NUM] + [CHANNEL_MAX_NUMBER_5G] + [MAX_RF_PATH_NUM]; + + u32 rfreg_chnlval[2]; + bool apk_done; + u32 reg_rf3c[2]; /* pathA / pathB */ + + u32 backup_rf_0x1a;/*92ee*/ + /* bfsync */ + u8 framesync; + u32 framesync_c34; + + u8 num_total_rfpath; + struct phy_parameters hwparam_tables[MAX_TAB]; + u16 rf_pathmap; + + u8 hw_rof_enable; /*Enable GPIO[9] as WL RF HW PDn source*/ + enum rt_polarity_ctl polarity_ctl; +}; + +#define MAX_TID_COUNT 9 +#define RTL_AGG_STOP 0 +#define RTL_AGG_PROGRESS 1 +#define RTL_AGG_START 2 +#define RTL_AGG_OPERATIONAL 3 +#define RTL_AGG_OFF 0 +#define RTL_AGG_ON 1 +#define RTL_RX_AGG_START 1 +#define RTL_RX_AGG_STOP 0 +#define RTL_AGG_EMPTYING_HW_QUEUE_ADDBA 2 +#define RTL_AGG_EMPTYING_HW_QUEUE_DELBA 3 + +struct rtl_ht_agg { + u16 txq_id; + u16 wait_for_ba; + u16 start_idx; + u64 bitmap; + u32 rate_n_flags; + u8 agg_state; + u8 rx_agg_state; +}; + +struct rssi_sta { + /* for old dm */ + long undec_sm_pwdb; + long undec_sm_cck; + + /* for new phydm_mod */ + s32 undecorated_smoothed_pwdb; + s32 undecorated_smoothed_cck; + s32 undecorated_smoothed_ofdm; + u8 ofdm_pkt; + u8 cck_pkt; + u16 cck_sum_power; + u8 is_send_rssi; + u64 packet_map; + u8 valid_bit; +}; + +struct rtl_tid_data { + u16 seq_number; + struct rtl_ht_agg agg; +}; + +struct rtl_sta_info { + struct list_head list; + struct rtl_tid_data tids[MAX_TID_COUNT]; + /* just used for ap adhoc or mesh*/ + struct rssi_sta rssi_stat; + u8 rssi_level; + u16 wireless_mode; + u8 ratr_index; + u8 mimo_ps; + u8 mac_addr[ETH_ALEN]; +} __packed; + +struct rtl_priv; +struct rtl_io { + struct device *dev; + struct mutex bb_mutex; + + /*PCI MEM map */ + unsigned long pci_mem_end; /*shared mem end */ + unsigned long pci_mem_start; /*shared mem start */ + + /*PCI IO map */ + unsigned long pci_base_addr; /*device I/O address */ + + void (*write8_async)(struct rtl_priv *rtlpriv, u32 addr, u8 val); + void (*write16_async)(struct rtl_priv *rtlpriv, u32 addr, u16 val); + void (*write32_async)(struct rtl_priv *rtlpriv, u32 addr, u32 val); + void (*writeN_sync)(struct rtl_priv *rtlpriv, u32 addr, void *buf, + u16 len); + + u8 (*read8_sync)(struct rtl_priv *rtlpriv, u32 addr); + u16 (*read16_sync)(struct rtl_priv *rtlpriv, u32 addr); + u32 (*read32_sync)(struct rtl_priv *rtlpriv, u32 addr); + +}; + +struct rtl_mac { + u8 mac_addr[ETH_ALEN]; + u8 mac80211_registered; + u8 beacon_enabled; + + u32 tx_ss_num; + u32 rx_ss_num; + + struct ieee80211_supported_band bands[NUM_NL80211_BANDS]; + struct ieee80211_hw *hw; + struct ieee80211_vif *vif; + enum nl80211_iftype opmode; + + /*Probe Beacon management */ + struct rtl_tid_data tids[MAX_TID_COUNT]; + enum rtl_link_state link_state; + struct rtl_beacon_keys cur_beacon_keys; + u8 new_beacon_cnt; + + int n_channels; + int n_bitrates; + + bool offchan_delay; + u8 p2p; /*using p2p role*/ + bool p2p_in_use; + + /*filters */ + u32 rx_conf; + u16 rx_mgt_filter; + u16 rx_ctrl_filter; + u16 rx_data_filter; + + bool act_scanning; + u8 cnt_after_linked; + bool skip_scan; + + /* early mode */ + /* skb wait queue */ + struct sk_buff_head skb_waitq[MAX_TID_COUNT]; + + u8 ht_stbc_cap; + u8 ht_cur_stbc; + + /*vht support*/ + u8 vht_enable; + u8 bw_80; + u8 vht_cur_ldpc; + u8 vht_cur_stbc; + u8 vht_stbc_cap; + u8 vht_ldpc_cap; + + /*RDG*/ + bool rdg_en; + + /*AP*/ + u8 bssid[ETH_ALEN] __aligned(2); + u32 vendor; + u8 mcs[16]; /* 16 bytes mcs for HT rates. */ + u32 basic_rates; /* b/g rates */ + u8 ht_enable; + u8 sgi_40; + u8 sgi_20; + u8 bw_40; + u16 mode; /* wireless mode */ + u8 slot_time; + u8 short_preamble; + u8 use_cts_protect; + u8 cur_40_prime_sc; + u8 cur_40_prime_sc_bk; + u8 cur_80_prime_sc; + u64 tsf; + u8 retry_short; + u8 retry_long; + u16 assoc_id; + bool hiddenssid; + + /*IBSS*/ + int beacon_interval; + + /*AMPDU*/ + u8 min_space_cfg; /*For Min spacing configurations */ + u8 max_mss_density; + u8 current_ampdu_factor; + u8 current_ampdu_density; + + /*QOS & EDCA */ + struct ieee80211_tx_queue_params edca_param[RTL_MAC80211_NUM_QUEUE]; + struct rtl_qos_parameters ac[AC_MAX]; + + /* counters */ + u64 last_txok_cnt; + u64 last_rxok_cnt; + u32 last_bt_edca_ul; + u32 last_bt_edca_dl; +}; + +struct btdm_8723 { + bool all_off; + bool agc_table_en; + bool adc_back_off_on; + bool b2_ant_hid_en; + bool low_penalty_rate_adaptive; + bool rf_rx_lpf_shrink; + bool reject_aggre_pkt; + bool tra_tdma_on; + u8 tra_tdma_nav; + u8 tra_tdma_ant; + bool tdma_on; + u8 tdma_ant; + u8 tdma_nav; + u8 tdma_dac_swing; + u8 fw_dac_swing_lvl; + bool ps_tdma_on; + u8 ps_tdma_byte[5]; + bool pta_on; + u32 val_0x6c0; + u32 val_0x6c8; + u32 val_0x6cc; + bool sw_dac_swing_on; + u32 sw_dac_swing_lvl; + u32 wlan_act_hi; + u32 wlan_act_lo; + u32 bt_retry_index; + bool dec_bt_pwr; + bool ignore_wlan_act; +}; + +struct bt_coexist_8723 { + u32 high_priority_tx; + u32 high_priority_rx; + u32 low_priority_tx; + u32 low_priority_rx; + u8 c2h_bt_info; + bool c2h_bt_info_req_sent; + bool c2h_bt_inquiry_page; + u32 bt_inq_page_start_time; + u8 bt_retry_cnt; + u8 c2h_bt_info_original; + u8 bt_inquiry_page_cnt; + struct btdm_8723 btdm; +}; + +struct rtl_hal { + struct ieee80211_hw *hw; + bool driver_is_goingto_unload; + bool up_first_time; + bool first_init; + bool being_init_adapter; + bool bbrf_ready; + bool mac_func_enable; + bool pre_edcca_enable; + struct bt_coexist_8723 hal_coex_8723; + + enum intf_type interface; + u16 hw_type; /*92c or 92d or 92s and so on */ + u8 ic_class; + u8 oem_id; + u32 version; /*version of chip */ + u8 state; /*stop 0, start 1 */ + u8 board_type; + u8 package_type; + u8 external_pa; + + u8 pa_mode; + u8 pa_type_2g; + u8 pa_type_5g; + u8 lna_type_2g; + u8 lna_type_5g; + u8 external_pa_2g; + u8 external_lna_2g; + u8 external_pa_5g; + u8 external_lna_5g; + u8 type_glna; + u8 type_gpa; + u8 type_alna; + u8 type_apa; + u8 rfe_type; + + /*firmware */ + u32 fwsize; + u8 *pfirmware; + u16 fw_version; + u16 fw_subversion; + bool h2c_setinprogress; + u8 last_hmeboxnum; + bool fw_ready; + /*Reserve page start offset except beacon in TxQ. */ + u8 fw_rsvdpage_startoffset; + u8 h2c_txcmd_seq; + u8 current_ra_rate; + + /* FW Cmd IO related */ + u16 fwcmd_iomap; + u32 fwcmd_ioparam; + bool set_fwcmd_inprogress; + u8 current_fwcmd_io; + + struct p2p_ps_offload_t p2p_ps_offload; + bool fw_clk_change_in_progress; + bool allow_sw_to_change_hwclc; + u8 fw_ps_state; + /**/ + bool driver_going2unload; + + /*AMPDU init min space*/ + u8 minspace_cfg; /*For Min spacing configurations */ + + /* Dual mac */ + enum macphy_mode macphymode; + enum band_type current_bandtype; /* 0:2.4G, 1:5G */ + enum band_type current_bandtypebackup; + enum band_type bandset; + /* dual MAC 0--Mac0 1--Mac1 */ + u32 interfaceindex; + /* just for DualMac S3S4 */ + u8 macphyctl_reg; + bool earlymode_enable; + u8 max_earlymode_num; + /* Dual mac*/ + bool during_mac0init_radiob; + bool during_mac1init_radioa; + bool reloadtxpowerindex; + /* True if IMR or IQK have done + * for 2.4G in scan progress + */ + bool load_imrandiqk_setting_for2g; + + bool disable_amsdu_8k; + bool master_of_dmsp; + bool slave_of_dmsp; + + u16 rx_tag;/*for 92ee*/ + u8 rts_en; + + /*for wowlan*/ + bool wow_enable; + bool enter_pnp_sleep; + bool wake_from_pnp_sleep; + bool wow_enabled; + __kernel_time_t last_suspend_sec; + u32 wowlan_fwsize; + u8 *wowlan_firmware; + + u8 hw_rof_enable; /*Enable GPIO[9] as WL RF HW PDn source*/ + + bool real_wow_v2_enable; + bool re_init_llt_table; +}; + +struct rtl_security { + /*default 0 */ + bool use_sw_sec; + + bool being_setkey; + bool use_defaultkey; + /*Encryption Algorithm for Unicast Packet */ + enum rt_enc_alg pairwise_enc_algorithm; + /*Encryption Algorithm for Brocast/Multicast */ + enum rt_enc_alg group_enc_algorithm; + /*Cam Entry Bitmap */ + u32 hwsec_cam_bitmap; + u8 hwsec_cam_sta_addr[TOTAL_CAM_ENTRY][ETH_ALEN]; + /* local Key buffer, indx 0 is for + * pairwise key 1-4 is for agoup key. + */ + u8 key_buf[KEY_BUF_SIZE][MAX_KEY_LEN]; + u8 key_len[KEY_BUF_SIZE]; + + /* The pointer of Pairwise Key, + * it always points to KeyBuf[4] + */ + u8 *pairwise_key; +}; + +#define ASSOCIATE_ENTRY_NUM 33 + +struct fast_ant_training { + u8 bssid[6]; + u8 antsel_rx_keep_0; + u8 antsel_rx_keep_1; + u8 antsel_rx_keep_2; + u32 ant_sum[7]; + u32 ant_cnt[7]; + u32 ant_ave[7]; + u8 fat_state; + u32 train_idx; + u8 antsel_a[ASSOCIATE_ENTRY_NUM]; + u8 antsel_b[ASSOCIATE_ENTRY_NUM]; + u8 antsel_c[ASSOCIATE_ENTRY_NUM]; + u32 main_ant_sum[ASSOCIATE_ENTRY_NUM]; + u32 aux_ant_sum[ASSOCIATE_ENTRY_NUM]; + u32 main_ant_cnt[ASSOCIATE_ENTRY_NUM]; + u32 aux_ant_cnt[ASSOCIATE_ENTRY_NUM]; + u8 rx_idle_ant; + bool becomelinked; +}; + +struct dm_phy_dbg_info { + s8 rx_snrdb[4]; + u64 num_qry_phy_status; + u64 num_qry_phy_status_cck; + u64 num_qry_phy_status_ofdm; + u16 num_qry_beacon_pkt; + u16 num_non_be_pkt; + s32 rx_evm[4]; +}; + +struct rtl_dm { + /*PHY status for Dynamic Management */ + long entry_min_undec_sm_pwdb; + long undec_sm_cck; + long undec_sm_pwdb; /*out dm */ + long entry_max_undec_sm_pwdb; + s32 ofdm_pkt_cnt; + bool dm_initialgain_enable; + bool dynamic_txpower_enable; + bool current_turbo_edca; + bool is_any_nonbepkts; /*out dm */ + bool is_cur_rdlstate; + bool txpower_trackinginit; + bool disable_framebursting; + bool cck_inch14; + bool txpower_tracking; + bool useramask; + bool rfpath_rxenable[4]; + bool inform_fw_driverctrldm; + bool current_mrc_switch; + u8 txpowercount; + u8 powerindex_backup[6]; + + u8 thermalvalue_rxgain; + u8 thermalvalue_iqk; + u8 thermalvalue_lck; + u8 thermalvalue; + u8 last_dtp_lvl; + u8 thermalvalue_avg[AVG_THERMAL_NUM]; + u8 thermalvalue_avg_index; + u8 tm_trigger; + bool done_txpower; + u8 dynamic_txhighpower_lvl; /*Tx high power level */ + u8 dm_flag; /*Indicate each dynamic mechanism's status. */ + u8 dm_flag_tmp; + u8 dm_type; + u8 dm_rssi_sel; + u8 txpower_track_control; + bool interrupt_migration; + bool disable_tx_int; + s8 ofdm_index[MAX_RF_PATH]; + u8 default_ofdm_index; + u8 default_cck_index; + s8 cck_index; + s8 delta_power_index[MAX_RF_PATH]; + s8 delta_power_index_last[MAX_RF_PATH]; + s8 power_index_offset[MAX_RF_PATH]; + s8 absolute_ofdm_swing_idx[MAX_RF_PATH]; + s8 remnant_ofdm_swing_idx[MAX_RF_PATH]; + s8 remnant_cck_idx; + bool modify_txagc_flag_path_a; + bool modify_txagc_flag_path_b; + + bool one_entry_only; + struct dm_phy_dbg_info dbginfo; + + /* Dynamic ATC switch */ + bool atc_status; + bool large_cfo_hit; + bool is_freeze; + int cfo_tail[2]; + int cfo_ave_pre; + int crystal_cap; + u8 cfo_threshold; + u32 packet_count; + u32 packet_count_pre; + u8 tx_rate; + + /*88e tx power tracking*/ + u8 swing_idx_ofdm[MAX_RF_PATH]; + u8 swing_idx_ofdm_cur; + u8 swing_idx_ofdm_base[MAX_RF_PATH]; + bool swing_flag_ofdm; + u8 swing_idx_cck; + u8 swing_idx_cck_cur; + u8 swing_idx_cck_base; + bool swing_flag_cck; + + s8 swing_diff_2g; + s8 swing_diff_5g; + + /* DMSP */ + bool supp_phymode_switch; + + /* DulMac */ + struct fast_ant_training fat_table; + + u8 resp_tx_path; + u8 path_sel; + u32 patha_sum; + u32 pathb_sum; + u32 patha_cnt; + u32 pathb_cnt; + + u8 pre_channel; + u8 *p_channel; + u8 linked_interval; + + u64 last_tx_ok_cnt; + u64 last_rx_ok_cnt; +}; + +#define EFUSE_MAX_LOGICAL_SIZE 512 + +struct rtl_efuse { + bool autoload_ok; + bool bootfromefuse; + u16 max_physical_size; + + u8 efuse_map[2][EFUSE_MAX_LOGICAL_SIZE]; + u16 efuse_usedbytes; + u8 efuse_usedpercentage; +#ifdef EFUSE_REPG_WORKAROUND + bool efuse_re_pg_sec1flag; + u8 efuse_re_pg_data[8]; +#endif + + u8 autoload_failflag; + u8 autoload_status; + + short epromtype; + u16 eeprom_vid; + u16 eeprom_did; + u16 eeprom_svid; + u16 eeprom_smid; + u8 eeprom_oemid; + u16 eeprom_channelplan; + u8 eeprom_version; + u8 board_type; + u8 external_pa; + + u8 dev_addr[6]; + u8 wowlan_enable; + u8 antenna_div_cfg; + u8 antenna_div_type; + + bool txpwr_fromeprom; + u8 eeprom_crystalcap; + u8 eeprom_tssi[2]; + u8 eeprom_tssi_5g[3][2]; /* for 5GL/5GM/5GH band. */ + u8 eeprom_pwrlimit_ht20[CHANNEL_GROUP_MAX]; + u8 eeprom_pwrlimit_ht40[CHANNEL_GROUP_MAX]; + u8 eeprom_chnlarea_txpwr_cck[MAX_RF_PATH][CHANNEL_GROUP_MAX_2G]; + u8 eeprom_chnlarea_txpwr_ht40_1s[MAX_RF_PATH][CHANNEL_GROUP_MAX]; + u8 eprom_chnl_txpwr_ht40_2sdf[MAX_RF_PATH][CHANNEL_GROUP_MAX]; + + u8 internal_pa_5g[2]; /* pathA / pathB */ + u8 eeprom_c9; + u8 eeprom_cc; + + /*For power group */ + u8 eeprom_pwrgroup[2][3]; + u8 pwrgroup_ht20[2][CHANNEL_MAX_NUMBER]; + u8 pwrgroup_ht40[2][CHANNEL_MAX_NUMBER]; + + u8 txpwrlevel_cck[MAX_RF_PATH][CHANNEL_MAX_NUMBER_2G]; + /*For HT 40MHZ pwr */ + u8 txpwrlevel_ht40_1s[MAX_RF_PATH][CHANNEL_MAX_NUMBER]; + /*For HT 40MHZ pwr */ + u8 txpwrlevel_ht40_2s[MAX_RF_PATH][CHANNEL_MAX_NUMBER]; + + /*--------------------------------------------------------* + * 8192CE\8192SE\8192DE\8723AE use the following 4 arrays, + * other ICs (8188EE\8723BE\8192EE\8812AE...) + * define new arrays in Windows code. + * BUT, in linux code, we use the same array for all ICs. + * + * The Correspondance relation between two arrays is: + * txpwr_cckdiff[][] == CCK_24G_Diff[][] + * txpwr_ht20diff[][] == BW20_24G_Diff[][] + * txpwr_ht40diff[][] == BW40_24G_Diff[][] + * txpwr_legacyhtdiff[][] == OFDM_24G_Diff[][] + * + * Sizes of these arrays are decided by the larger ones. + */ + s8 txpwr_cckdiff[MAX_RF_PATH][CHANNEL_MAX_NUMBER]; + s8 txpwr_ht20diff[MAX_RF_PATH][CHANNEL_MAX_NUMBER]; + s8 txpwr_ht40diff[MAX_RF_PATH][CHANNEL_MAX_NUMBER]; + s8 txpwr_legacyhtdiff[MAX_RF_PATH][CHANNEL_MAX_NUMBER]; + + u8 txpwr_5g_bw40base[MAX_RF_PATH][CHANNEL_MAX_NUMBER]; + u8 txpwr_5g_bw80base[MAX_RF_PATH][CHANNEL_MAX_NUMBER_5G_80M]; + s8 txpwr_5g_ofdmdiff[MAX_RF_PATH][MAX_TX_COUNT]; + s8 txpwr_5g_bw20diff[MAX_RF_PATH][MAX_TX_COUNT]; + s8 txpwr_5g_bw40diff[MAX_RF_PATH][MAX_TX_COUNT]; + s8 txpwr_5g_bw80diff[MAX_RF_PATH][MAX_TX_COUNT]; + + u8 txpwr_safetyflag; /* Band edge enable flag */ + u16 eeprom_txpowerdiff; + u8 legacy_httxpowerdiff; /* Legacy to HT rate power diff */ + u8 antenna_txpwdiff[3]; + + u8 eeprom_regulatory; + u8 eeprom_thermalmeter; + u8 thermalmeter[2]; /*ThermalMeter, index 0 for RFIC0, 1 for RFIC1 */ + u16 tssi_13dbm; + u8 crystalcap; /* CrystalCap. */ + u8 delta_iqk; + u8 delta_lck; + + u8 legacy_ht_txpowerdiff; /*Legacy to HT rate power diff */ + bool apk_thermalmeterignore; + + bool b1x1_recvcombine; + bool b1ss_support; + + /*channel plan */ + u8 channel_plan; +}; + +struct rtl_tx_report { + atomic_t sn; + u16 last_sent_sn; + unsigned long last_sent_time; + u16 last_recv_sn; +}; + +struct rtl_ps_ctl { + bool pwrdomain_protect; + bool in_powersavemode; + bool rfchange_inprogress; + bool swrf_processing; + bool hwradiooff; + /* just for PCIE ASPM + * If it supports ASPM, Offset[560h] = 0x40, + * otherwise Offset[560h] = 0x00. + */ + bool support_aspm; + bool support_backdoor; + + /*for LPS */ + enum rt_psmode dot11_psmode; /*Power save mode configured. */ + bool swctrl_lps; + bool leisure_ps; + bool fwctrl_lps; + u8 fwctrl_psmode; + /*For Fw control LPS mode */ + u8 reg_fwctrl_lps; + /*Record Fw PS mode status. */ + bool fw_current_inpsmode; + u8 reg_max_lps_awakeintvl; + bool report_linked; + bool low_power_enable;/*for 32k*/ + + /*for IPS */ + bool inactiveps; + + u32 rfoff_reason; + + /*RF OFF Level */ + u32 cur_ps_level; + u32 reg_rfps_level; + + /*just for PCIE ASPM */ + u8 const_amdpci_aspm; + bool pwrdown_mode; + + enum rf_pwrstate inactive_pwrstate; + enum rf_pwrstate rfpwr_state; /*cur power state */ + + /* for SW LPS*/ + bool sw_ps_enabled; + bool state; + bool state_inap; + bool multi_buffered; + u16 nullfunc_seq; + unsigned int dtim_counter; + unsigned int sleep_ms; + unsigned long last_sleep_jiffies; + unsigned long last_awake_jiffies; + unsigned long last_delaylps_stamp_jiffies; + unsigned long last_dtim; + unsigned long last_beacon; + unsigned long last_action; + unsigned long last_slept; + + /*For P2P PS */ + struct rtl_p2p_ps_info p2p_ps_info; + u8 pwr_mode; + u8 smart_ps; + + /* wake up on line */ + u8 wo_wlan_mode; + u8 arp_offload_enable; + u8 gtk_offload_enable; + /* Used for WOL, indicates the reason for waking event.*/ + u32 wakeup_reason; + /* Record the last waking time for comparison with setting key. */ + u64 last_wakeup_time; +}; + +struct rtl_stats { + u8 psaddr[ETH_ALEN]; + u32 mac_time[2]; + s8 rssi; + u8 signal; + u8 noise; + u8 rate; /* hw desc rate */ + u8 received_channel; + u8 control; + u8 mask; + u8 freq; + u16 len; + u64 tsf; + u32 beacon_time; + u8 nic_type; + u16 length; + u8 signalquality; /*in 0-100 index. */ + /* + * Real power in dBm for this packet, + * no beautification and aggregation. + */ + s32 recvsignalpower; + s8 rxpower; /*in dBm Translate from PWdB */ + u8 signalstrength; /*in 0-100 index. */ + u16 hwerror:1; + u16 crc:1; + u16 icv:1; + u16 shortpreamble:1; + u16 antenna:1; + u16 decrypted:1; + u16 wakeup:1; + u32 timestamp_low; + u32 timestamp_high; + bool shift; + + u8 rx_drvinfo_size; + u8 rx_bufshift; + bool isampdu; + bool isfirst_ampdu; + bool rx_is40mhzpacket; + u8 rx_packet_bw; + u32 rx_pwdb_all; + u8 rx_mimo_signalstrength[4]; /*in 0~100 index */ + s8 rx_mimo_signalquality[4]; + u8 rx_mimo_evm_dbm[4]; + u16 cfo_short[4]; /* per-path's Cfo_short */ + u16 cfo_tail[4]; + + s8 rx_mimo_sig_qual[4]; + u8 rx_pwr[4]; /* per-path's pwdb */ + u8 rx_snr[4]; /* per-path's SNR */ + u8 bandwidth; + u8 bt_coex_pwr_adjust; + bool packet_matchbssid; + bool is_cck; + bool is_ht; + bool packet_toself; + bool packet_beacon; /*for rssi */ + s8 cck_adc_pwdb[4]; /*for rx path selection */ + + bool is_vht; + bool is_short_gi; + u8 vht_nss; + + u8 packet_report_type; + + u32 macid; + u8 wake_match; + u32 bt_rx_rssi_percentage; + u32 macid_valid_entry[2]; +}; + +struct rt_link_detect { + /* count for roaming */ + u32 bcn_rx_inperiod; + u32 roam_times; + + u32 num_tx_in4period[4]; + u32 num_rx_in4period[4]; + + u32 num_tx_inperiod; + u32 num_rx_inperiod; + + bool busytraffic; + bool tx_busy_traffic; + bool rx_busy_traffic; + bool higher_busytraffic; + bool higher_busyrxtraffic; + + u32 tidtx_in4period[MAX_TID_COUNT][4]; + u32 tidtx_inperiod[MAX_TID_COUNT]; + bool higher_busytxtraffic[MAX_TID_COUNT]; +}; + +struct rtl_tcb_desc { + u8 packet_bw:2; + u8 multicast:1; + u8 broadcast:1; + + u8 rts_stbc:1; + u8 rts_enable:1; + u8 cts_enable:1; + u8 rts_use_shortpreamble:1; + u8 rts_use_shortgi:1; + u8 rts_sc:1; + u8 rts_bw:1; + u8 rts_rate; + + u8 use_shortgi:1; + u8 use_shortpreamble:1; + u8 use_driver_rate:1; + u8 disable_ratefallback:1; + + u8 use_spe_rpt:1; + + u8 ratr_index; + u8 mac_id; + u8 hw_rate; + + u8 last_inipkt:1; + u8 cmd_or_init:1; + u8 queue_index; + + /* early mode */ + u8 empkt_num; + /* The max value by HW */ + u32 empkt_len[10]; + bool tx_enable_sw_calc_duration; +}; + +struct rtl_wow_pattern { + u8 type; + u16 crc; + u32 mask[4]; +}; + +struct rtl_hal_ops { + int (*init_sw_vars)(struct ieee80211_hw *hw); + void (*deinit_sw_vars)(struct ieee80211_hw *hw); + void (*read_chip_version)(struct ieee80211_hw *hw); + void (*read_eeprom_info)(struct ieee80211_hw *hw); + void (*interrupt_recognized)(struct ieee80211_hw *hw, + u32 *p_inta, u32 *p_intb, + u32 *p_intc, u32 *p_intd); + int (*hw_init)(struct ieee80211_hw *hw); + void (*hw_disable)(struct ieee80211_hw *hw); + void (*hw_suspend)(struct ieee80211_hw *hw); + void (*hw_resume)(struct ieee80211_hw *hw); + void (*enable_interrupt)(struct ieee80211_hw *hw); + void (*disable_interrupt)(struct ieee80211_hw *hw); + int (*set_network_type)(struct ieee80211_hw *hw, + enum nl80211_iftype type); + void (*set_chk_bssid)(struct ieee80211_hw *hw, + bool check_bssid); + void (*set_bw_mode)(struct ieee80211_hw *hw, + enum nl80211_channel_type ch_type); + u8 (*switch_channel)(struct ieee80211_hw *hw); + void (*set_qos)(struct ieee80211_hw *hw, int aci); + void (*set_bcn_reg)(struct ieee80211_hw *hw); + void (*set_bcn_intv)(struct ieee80211_hw *hw); + void (*update_interrupt_mask)(struct ieee80211_hw *hw, + u32 add_msr, u32 rm_msr); + void (*get_hw_reg)(struct ieee80211_hw *hw, u8 variable, u8 *val); + void (*set_hw_reg)(struct ieee80211_hw *hw, u8 variable, u8 *val); + void (*update_rate_tbl)(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u8 rssi_leve, + bool update_bw); + void (*pre_fill_tx_bd_desc)(struct ieee80211_hw *hw, u8 *tx_bd_desc, + u8 *desc, u8 queue_index, + struct sk_buff *skb, dma_addr_t addr); + void (*update_rate_mask)(struct ieee80211_hw *hw, u8 rssi_level); + u16 (*rx_desc_buff_remained_cnt)(struct ieee80211_hw *hw, + u8 queue_index); + void (*rx_check_dma_ok)(struct ieee80211_hw *hw, u8 *header_desc, + u8 queue_index); + void (*fill_tx_desc)(struct ieee80211_hw *hw, + struct ieee80211_hdr *hdr, u8 *pdesc_tx, + u8 *pbd_desc_tx, + struct ieee80211_tx_info *info, + struct ieee80211_sta *sta, + struct sk_buff *skb, u8 hw_queue, + struct rtl_tcb_desc *ptcb_desc); + void (*fill_fake_txdesc)(struct ieee80211_hw *hw, u8 *pdesc, + u32 buffer_len, bool bispspoll); + void (*fill_tx_cmddesc)(struct ieee80211_hw *hw, u8 *pdesc, + bool firstseg, bool lastseg, + struct sk_buff *skb); + void (*fill_tx_special_desc)(struct ieee80211_hw *hw, + u8 *pdesc, u8 *pbd_desc, + struct sk_buff *skb, u8 hw_queue); + bool (*query_rx_desc)(struct ieee80211_hw *hw, + struct rtl_stats *stats, + struct ieee80211_rx_status *rx_status, + u8 *pdesc, struct sk_buff *skb); + void (*set_channel_access)(struct ieee80211_hw *hw); + bool (*radio_onoff_checking)(struct ieee80211_hw *hw, u8 *valid); + void (*dm_watchdog)(struct ieee80211_hw *hw); + void (*scan_operation_backup)(struct ieee80211_hw *hw, u8 operation); + bool (*set_rf_power_state)(struct ieee80211_hw *hw, + enum rf_pwrstate rfpwr_state); + void (*led_control)(struct ieee80211_hw *hw, + enum led_ctl_mode ledaction); + void (*set_desc)(struct ieee80211_hw *hw, u8 *pdesc, bool istx, + u8 desc_name, u8 *val); + u64 (*get_desc)(struct ieee80211_hw *hw, u8 *pdesc, bool istx, + u8 desc_name); + bool (*is_tx_desc_closed)(struct ieee80211_hw *hw, + u8 hw_queue, u16 index); + void (*tx_polling)(struct ieee80211_hw *hw, u8 hw_queue); + void (*enable_hw_sec)(struct ieee80211_hw *hw); + void (*set_key)(struct ieee80211_hw *hw, u32 key_index, + u8 *macaddr, bool is_group, u8 enc_algo, + bool is_wepkey, bool clear_all); + void (*init_sw_leds)(struct ieee80211_hw *hw); + void (*deinit_sw_leds)(struct ieee80211_hw *hw); + u32 (*get_bbreg)(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask); + void (*set_bbreg)(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask, + u32 data); + u32 (*get_rfreg)(struct ieee80211_hw *hw, enum radio_path rfpath, + u32 regaddr, u32 bitmask); + void (*set_rfreg)(struct ieee80211_hw *hw, enum radio_path rfpath, + u32 regaddr, u32 bitmask, u32 data); + void (*linked_set_reg)(struct ieee80211_hw *hw); + void (*chk_switch_dmdp)(struct ieee80211_hw *hw); + void (*dualmac_easy_concurrent)(struct ieee80211_hw *hw); + void (*dualmac_switch_to_dmdp)(struct ieee80211_hw *hw); + bool (*phy_rf6052_config)(struct ieee80211_hw *hw); + void (*phy_rf6052_set_cck_txpower)(struct ieee80211_hw *hw, + u8 *powerlevel); + void (*phy_rf6052_set_ofdm_txpower)(struct ieee80211_hw *hw, + u8 *ppowerlevel, u8 channel); + bool (*config_bb_with_headerfile)(struct ieee80211_hw *hw, + u8 configtype); + bool (*config_bb_with_pgheaderfile)(struct ieee80211_hw *hw, + u8 configtype); + void (*phy_lc_calibrate)(struct ieee80211_hw *hw, bool is2t); + void (*phy_set_bw_mode_callback)(struct ieee80211_hw *hw); + void (*dm_dynamic_txpower)(struct ieee80211_hw *hw); + void (*c2h_command_handle)(struct ieee80211_hw *hw); + void (*bt_wifi_media_status_notify)(struct ieee80211_hw *hw, + bool mstate); + void (*bt_coex_off_before_lps)(struct ieee80211_hw *hw); + void (*fill_h2c_cmd)(struct ieee80211_hw *hw, u8 element_id, + u32 cmd_len, u8 *p_cmdbuffer); + void (*set_default_port_id_cmd)(struct ieee80211_hw *hw); + bool (*get_btc_status)(void); + bool (*is_fw_header)(struct rtlwifi_firmware_header *hdr); + u32 (*rx_command_packet)(struct ieee80211_hw *hw, + const struct rtl_stats *status, + struct sk_buff *skb); + void (*add_wowlan_pattern)(struct ieee80211_hw *hw, + struct rtl_wow_pattern *rtl_pattern, + u8 index); + u16 (*get_available_desc)(struct ieee80211_hw *hw, u8 q_idx); + void (*c2h_content_parsing)(struct ieee80211_hw *hw, u8 tag, u8 len, + u8 *val); + /* ops for halmac cb */ + bool (*halmac_cb_init_mac_register)(struct rtl_priv *rtlpriv); + bool (*halmac_cb_init_bb_rf_register)(struct rtl_priv *rtlpriv); + bool (*halmac_cb_write_data_rsvd_page)(struct rtl_priv *rtlpriv, + u8 *buf, u32 size); + bool (*halmac_cb_write_data_h2c)(struct rtl_priv *rtlpriv, u8 *buf, + u32 size); + /* ops for phydm cb */ + u8 (*get_txpower_index)(struct ieee80211_hw *hw, u8 path, + u8 rate, u8 bandwidth, u8 channel); + void (*set_tx_power_index_by_rs)(struct ieee80211_hw *hw, + u8 channel, u8 path, + enum rate_section rs); + void (*store_tx_power_by_rate)(struct ieee80211_hw *hw, + u32 band, u32 rfpath, + u32 txnum, u32 regaddr, + u32 bitmask, u32 data); + void (*phy_set_txpower_limit)(struct ieee80211_hw *hw, u8 *pregulation, + u8 *pband, u8 *pbandwidth, + u8 *prate_section, u8 *prf_path, + u8 *pchannel, u8 *ppower_limit); +}; + +struct rtl_intf_ops { + /*com */ + void (*read_efuse_byte)(struct ieee80211_hw *hw, u16 _offset, u8 *pbuf); + int (*adapter_start)(struct ieee80211_hw *hw); + void (*adapter_stop)(struct ieee80211_hw *hw); + bool (*check_buddy_priv)(struct ieee80211_hw *hw, + struct rtl_priv **buddy_priv); + + int (*adapter_tx)(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, + struct sk_buff *skb, + struct rtl_tcb_desc *ptcb_desc); + void (*flush)(struct ieee80211_hw *hw, u32 queues, bool drop); + int (*reset_trx_ring)(struct ieee80211_hw *hw); + bool (*waitq_insert)(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, + struct sk_buff *skb); + + /*pci */ + void (*disable_aspm)(struct ieee80211_hw *hw); + void (*enable_aspm)(struct ieee80211_hw *hw); + + /*usb */ +}; + +struct rtl_mod_params { + /* default: 0,0 */ + u64 debug_mask; + /* default: 0 = using hardware encryption */ + bool sw_crypto; + + /* default: 0 = DBG_EMERG (0)*/ + int debug_level; + + /* default: 1 = using no linked power save */ + bool inactiveps; + + /* default: 1 = using linked sw power save */ + bool swctrl_lps; + + /* default: 1 = using linked fw power save */ + bool fwctrl_lps; + + /* default: 0 = not using MSI interrupts mode + * submodules should set their own default value + */ + bool msi_support; + + /* default: 0 = dma 32 */ + bool dma64; + + /* default: 1 = enable aspm */ + int aspm_support; + + /* default 0: 1 means disable */ + bool disable_watchdog; + + /* default 0: 1 means do not disable interrupts */ + bool int_clear; + + /* select antenna */ + int ant_sel; +}; + +struct rtl_hal_usbint_cfg { + /* data - rx */ + u32 in_ep_num; + u32 rx_urb_num; + u32 rx_max_size; + + /* op - rx */ + void (*usb_rx_hdl)(struct ieee80211_hw *, struct sk_buff *); + void (*usb_rx_segregate_hdl)(struct ieee80211_hw *, struct sk_buff *, + struct sk_buff_head *); + + /* tx */ + void (*usb_tx_cleanup)(struct ieee80211_hw *, struct sk_buff *); + int (*usb_tx_post_hdl)(struct ieee80211_hw *, struct urb *, + struct sk_buff *); + struct sk_buff *(*usb_tx_aggregate_hdl)(struct ieee80211_hw *, + struct sk_buff_head *); + + /* endpoint mapping */ + int (*usb_endpoint_mapping)(struct ieee80211_hw *hw); + u16 (*usb_mq_to_hwq)(__le16 fc, u16 mac80211_queue_index); +}; + +struct rtl_hal_cfg { + u8 bar_id; + bool write_readback; + char *name; + char *alt_fw_name; + struct rtl_hal_ops *ops; + struct rtl_mod_params *mod_params; + struct rtl_hal_usbint_cfg *usb_interface_cfg; + enum rtl_spec_ver spec_ver; + + /* this map used for some registers or vars + * defined int HAL but used in MAIN + */ + u32 maps[RTL_VAR_MAP_MAX]; + +}; + +struct rtl_locks { + /* mutex */ + struct mutex conf_mutex; + struct mutex ips_mutex; /* mutex for enter/leave IPS */ + struct mutex lps_mutex; /* mutex for enter/leave LPS */ + + /*spin lock */ + spinlock_t irq_th_lock; + spinlock_t h2c_lock; + spinlock_t rf_ps_lock; + spinlock_t rf_lock; + spinlock_t waitq_lock; + spinlock_t entry_list_lock; + spinlock_t usb_lock; + spinlock_t c2hcmd_lock; + spinlock_t scan_list_lock; /* lock for the scan list */ + + /*FW clock change */ + spinlock_t fw_ps_lock; + + /*Dual mac*/ + spinlock_t cck_and_rw_pagea_lock; + + spinlock_t iqk_lock; +}; + +struct rtl_works { + struct ieee80211_hw *hw; + + /*timer */ + struct timer_list watchdog_timer; + struct timer_list dualmac_easyconcurrent_retrytimer; + struct timer_list fw_clockoff_timer; + struct timer_list fast_antenna_training_timer; + /*task */ + struct tasklet_struct irq_tasklet; + struct tasklet_struct irq_prepare_bcn_tasklet; + + /*work queue */ + struct workqueue_struct *rtl_wq; + struct delayed_work watchdog_wq; + struct delayed_work ips_nic_off_wq; + struct delayed_work c2hcmd_wq; + + /* For SW LPS */ + struct delayed_work ps_work; + struct delayed_work ps_rfon_wq; + struct delayed_work fwevt_wq; + + struct work_struct lps_change_work; + struct work_struct fill_h2c_cmd; +}; + +struct rtl_debug { + /* add for debug */ + struct dentry *debugfs_dir; + char debugfs_name[20]; + + char *msg_buf; +}; + +#define MIMO_PS_STATIC 0 +#define MIMO_PS_DYNAMIC 1 +#define MIMO_PS_NOLIMIT 3 + +struct rtl_dualmac_easy_concurrent_ctl { + enum band_type currentbandtype_backfordmdp; + bool close_bbandrf_for_dmsp; + bool change_to_dmdp; + bool change_to_dmsp; + bool switch_in_process; +}; + +struct rtl_dmsp_ctl { + bool activescan_for_slaveofdmsp; + bool scan_for_anothermac_fordmsp; + bool scan_for_itself_fordmsp; + bool writedig_for_anothermacofdmsp; + u32 curdigvalue_for_anothermacofdmsp; + bool changecckpdstate_for_anothermacofdmsp; + u8 curcckpdstate_for_anothermacofdmsp; + bool changetxhighpowerlvl_for_anothermacofdmsp; + u8 curtxhighlvl_for_anothermacofdmsp; + long rssivalmin_for_anothermacofdmsp; +}; + +struct ps_t { + u8 pre_ccastate; + u8 cur_ccasate; + u8 pre_rfstate; + u8 cur_rfstate; + u8 initialize; + long rssi_val_min; +}; + +struct dig_t { + u32 rssi_lowthresh; + u32 rssi_highthresh; + u32 fa_lowthresh; + u32 fa_highthresh; + long last_min_undec_pwdb_for_dm; + long rssi_highpower_lowthresh; + long rssi_highpower_highthresh; + u32 recover_cnt; + u32 pre_igvalue; + u32 cur_igvalue; + long rssi_val; + u8 dig_enable_flag; + u8 dig_ext_port_stage; + u8 dig_algorithm; + u8 dig_twoport_algorithm; + u8 dig_dbgmode; + u8 dig_slgorithm_switch; + u8 cursta_cstate; + u8 presta_cstate; + u8 curmultista_cstate; + u8 stop_dig; + s8 back_val; + s8 back_range_max; + s8 back_range_min; + u8 rx_gain_max; + u8 rx_gain_min; + u8 min_undec_pwdb_for_dm; + u8 rssi_val_min; + u8 pre_cck_cca_thres; + u8 cur_cck_cca_thres; + u8 pre_cck_pd_state; + u8 cur_cck_pd_state; + u8 pre_cck_fa_state; + u8 cur_cck_fa_state; + u8 pre_ccastate; + u8 cur_ccasate; + u8 large_fa_hit; + u8 forbidden_igi; + u8 dig_state; + u8 dig_highpwrstate; + u8 cur_sta_cstate; + u8 pre_sta_cstate; + u8 cur_ap_cstate; + u8 pre_ap_cstate; + u8 cur_pd_thstate; + u8 pre_pd_thstate; + u8 cur_cs_ratiostate; + u8 pre_cs_ratiostate; + u8 backoff_enable_flag; + s8 backoffval_range_max; + s8 backoffval_range_min; + u8 dig_min_0; + u8 dig_min_1; + u8 bt30_cur_igi; + bool media_connect_0; + bool media_connect_1; + + u32 antdiv_rssi_max; + u32 rssi_max; +}; + +struct rtl_global_var { + /* from this list we can get + * other adapter's rtl_priv + */ + struct list_head glb_priv_list; + spinlock_t glb_list_lock; +}; + +#define IN_4WAY_TIMEOUT_TIME (30 * MSEC_PER_SEC) /* 30 seconds */ + +struct rtl_btc_info { + u8 bt_type; + u8 btcoexist; + u8 ant_num; + u8 single_ant_path; + + u8 ap_num; + bool in_4way; + unsigned long in_4way_ts; +}; + +struct bt_coexist_info { + struct rtl_btc_ops *btc_ops; + struct rtl_btc_info btc_info; + /* btc context */ + void *btc_context; + void *wifi_only_context; + /* EEPROM BT info. */ + u8 eeprom_bt_coexist; + u8 eeprom_bt_type; + u8 eeprom_bt_ant_num; + u8 eeprom_bt_ant_isol; + u8 eeprom_bt_radio_shared; + + u8 bt_coexistence; + u8 bt_ant_num; + u8 bt_coexist_type; + u8 bt_state; + u8 bt_cur_state; /* 0:on, 1:off */ + u8 bt_ant_isolation; /* 0:good, 1:bad */ + u8 bt_pape_ctrl; /* 0:SW, 1:SW/HW dynamic */ + u8 bt_service; + u8 bt_radio_shared_type; + u8 bt_rfreg_origin_1e; + u8 bt_rfreg_origin_1f; + u8 bt_rssi_state; + u32 ratio_tx; + u32 ratio_pri; + u32 bt_edca_ul; + u32 bt_edca_dl; + + bool init_set; + bool bt_busy_traffic; + bool bt_traffic_mode_set; + bool bt_non_traffic_mode_set; + + bool fw_coexist_all_off; + bool sw_coexist_all_off; + bool hw_coexist_all_off; + u32 cstate; + u32 previous_state; + u32 cstate_h; + u32 previous_state_h; + + u8 bt_pre_rssi_state; + u8 bt_pre_rssi_state1; + + u8 reg_bt_iso; + u8 reg_bt_sco; + bool balance_on; + u8 bt_active_zero_cnt; + bool cur_bt_disabled; + bool pre_bt_disabled; + + u8 bt_profile_case; + u8 bt_profile_action; + bool bt_busy; + bool hold_for_bt_operation; + u8 lps_counter; +}; + +struct rtl_btc_ops { + void (*btc_init_variables)(struct rtl_priv *rtlpriv); + void (*btc_init_variables_wifi_only)(struct rtl_priv *rtlpriv); + void (*btc_deinit_variables)(struct rtl_priv *rtlpriv); + void (*btc_init_hal_vars)(struct rtl_priv *rtlpriv); + void (*btc_power_on_setting)(struct rtl_priv *rtlpriv); + void (*btc_init_hw_config)(struct rtl_priv *rtlpriv); + void (*btc_init_hw_config_wifi_only)(struct rtl_priv *rtlpriv); + void (*btc_ips_notify)(struct rtl_priv *rtlpriv, u8 type); + void (*btc_lps_notify)(struct rtl_priv *rtlpriv, u8 type); + void (*btc_scan_notify)(struct rtl_priv *rtlpriv, u8 scantype); + void (*btc_scan_notify_wifi_only)(struct rtl_priv *rtlpriv, + u8 scantype); + void (*btc_connect_notify)(struct rtl_priv *rtlpriv, u8 action); + void (*btc_mediastatus_notify)(struct rtl_priv *rtlpriv, + enum rt_media_status mstatus); + void (*btc_periodical)(struct rtl_priv *rtlpriv); + void (*btc_halt_notify)(struct rtl_priv *rtlpriv); + void (*btc_btinfo_notify)(struct rtl_priv *rtlpriv, + u8 *tmp_buf, u8 length); + void (*btc_btmpinfo_notify)(struct rtl_priv *rtlpriv, + u8 *tmp_buf, u8 length); + bool (*btc_is_limited_dig)(struct rtl_priv *rtlpriv); + bool (*btc_is_disable_edca_turbo)(struct rtl_priv *rtlpriv); + bool (*btc_is_bt_disabled)(struct rtl_priv *rtlpriv); + void (*btc_special_packet_notify)(struct rtl_priv *rtlpriv, + u8 pkt_type); + void (*btc_switch_band_notify)(struct rtl_priv *rtlpriv, u8 type, + bool scanning); + void (*btc_switch_band_notify_wifi_only)(struct rtl_priv *rtlpriv, + u8 type, bool scanning); + void (*btc_display_bt_coex_info)(struct rtl_priv *rtlpriv, + struct seq_file *m); + void (*btc_record_pwr_mode)(struct rtl_priv *rtlpriv, u8 *buf, u8 len); + u8 (*btc_get_lps_val)(struct rtl_priv *rtlpriv); + u8 (*btc_get_rpwm_val)(struct rtl_priv *rtlpriv); + bool (*btc_is_bt_ctrl_lps)(struct rtl_priv *rtlpriv); + void (*btc_get_ampdu_cfg)(struct rtl_priv *rtlpriv, u8 *reject_agg, + u8 *ctrl_agg_size, u8 *agg_size); + bool (*btc_is_bt_lps_on)(struct rtl_priv *rtlpriv); +}; + +struct rtl_halmac_ops { + int (*halmac_init_adapter)(struct rtl_priv *); + int (*halmac_deinit_adapter)(struct rtl_priv *); + int (*halmac_init_hal)(struct rtl_priv *); + int (*halmac_deinit_hal)(struct rtl_priv *); + int (*halmac_poweron)(struct rtl_priv *); + int (*halmac_poweroff)(struct rtl_priv *); + + int (*halmac_phy_power_switch)(struct rtl_priv *rtlpriv, u8 enable); + int (*halmac_set_mac_address)(struct rtl_priv *rtlpriv, u8 hwport, + u8 *addr); + int (*halmac_set_bssid)(struct rtl_priv *rtlpriv, u8 hwport, u8 *addr); + + int (*halmac_get_physical_efuse_size)(struct rtl_priv *rtlpriv, + u32 *size); + int (*halmac_read_physical_efuse_map)(struct rtl_priv *rtlpriv, + u8 *map, u32 size); + int (*halmac_get_logical_efuse_size)(struct rtl_priv *rtlpriv, + u32 *size); + int (*halmac_read_logical_efuse_map)(struct rtl_priv *rtlpriv, u8 *map, + u32 size); + + int (*halmac_set_bandwidth)(struct rtl_priv *rtlpriv, u8 channel, + u8 pri_ch_idx, u8 bw); + + int (*halmac_c2h_handle)(struct rtl_priv *rtlpriv, u8 *c2h, u32 size); + + int (*halmac_chk_txdesc)(struct rtl_priv *rtlpriv, u8 *txdesc, + u32 size); +}; + +struct rtl_halmac_indicator { + struct completion *comp; + u32 wait_ms; + + u8 *buffer; + u32 buf_size; + u32 ret_size; + u32 status; +}; + +struct rtl_halmac { + struct rtl_halmac_ops *ops; /* halmac ops (halmac.ko own this object) */ + void *internal; /* internal context of halmac, i.e. PHALMAC_ADAPTER */ + struct rtl_halmac_indicator *indicator; /* size=10 */ + + /* flags */ + /* + * send_general_info + * 0: no need to call halmac_send_general_info() + * 1: need to call halmac_send_general_info() + */ + u8 send_general_info; +}; + +struct rtl_phydm_params { + u8 mp_chip; /* 1: MP chip, 0: test chip */ + u8 fab_ver; /* 0: TSMC, 1: UMC, ...*/ + u8 cut_ver; /* 0: A, 1: B, ..., 10: K */ + u8 efuse0x3d7; /* default: 0xff */ + u8 efuse0x3d8; /* default: 0xff */ +}; + +struct rtl_phydm_ops { + /* init/deinit priv */ + int (*phydm_init_priv)(struct rtl_priv *rtlpriv, + struct rtl_phydm_params *params); + int (*phydm_deinit_priv)(struct rtl_priv *rtlpriv); + bool (*phydm_load_txpower_by_rate)(struct rtl_priv *rtlpriv); + bool (*phydm_load_txpower_limit)(struct rtl_priv *rtlpriv); + + /* init hw */ + int (*phydm_init_dm)(struct rtl_priv *rtlpriv); + int (*phydm_deinit_dm)(struct rtl_priv *rtlpriv); + int (*phydm_reset_dm)(struct rtl_priv *rtlpriv); + bool (*phydm_parameter_init)(struct rtl_priv *rtlpriv, bool post); + bool (*phydm_phy_bb_config)(struct rtl_priv *rtlpriv); + bool (*phydm_phy_rf_config)(struct rtl_priv *rtlpriv); + bool (*phydm_phy_mac_config)(struct rtl_priv *rtlpriv); + bool (*phydm_trx_mode)(struct rtl_priv *rtlpriv, + enum radio_mask tx_path, enum radio_mask rx_path, + bool is_tx2_path); + /* watchdog */ + bool (*phydm_watchdog)(struct rtl_priv *rtlpriv); + + /* channel */ + bool (*phydm_switch_band)(struct rtl_priv *rtlpriv, u8 central_ch); + bool (*phydm_switch_channel)(struct rtl_priv *rtlpriv, u8 central_ch); + bool (*phydm_switch_bandwidth)(struct rtl_priv *rtlpriv, + u8 primary_ch_idx, + enum ht_channel_width width); + bool (*phydm_iq_calibrate)(struct rtl_priv *rtlpriv); + bool (*phydm_clear_txpowertracking_state)(struct rtl_priv *rtlpriv); + bool (*phydm_pause_dig)(struct rtl_priv *rtlpriv, bool pause); + + /* read/write reg */ + u32 (*phydm_read_rf_reg)(struct rtl_priv *rtlpriv, + enum radio_path rfpath, + u32 addr, u32 mask); + bool (*phydm_write_rf_reg)(struct rtl_priv *rtlpriv, + enum radio_path rfpath, + u32 addr, u32 mask, u32 data); + u8 (*phydm_read_txagc)(struct rtl_priv *rtlpriv, + enum radio_path rfpath, u8 hw_rate); + bool (*phydm_write_txagc)(struct rtl_priv *rtlpriv, u32 power_index, + enum radio_path rfpath, u8 hw_rate); + + /* RX */ + bool (*phydm_c2h_content_parsing)(struct rtl_priv *rtlpriv, u8 cmd_id, + u8 cmd_len, u8 *content); + bool (*phydm_query_phy_status)(struct rtl_priv *rtlpriv, u8 *phystrpt, + struct ieee80211_hdr *hdr, + struct rtl_stats *pstatus); + + /* TX */ + u8 (*phydm_rate_id_mapping)(struct rtl_priv *rtlpriv, + enum wireless_mode wireless_mode, + enum rf_type rf_type, + enum ht_channel_width bw); + bool (*phydm_get_ra_bitmap)(struct rtl_priv *rtlpriv, + enum wireless_mode wireless_mode, + enum rf_type rf_type, + enum ht_channel_width bw, + u8 tx_rate_level, /* 0~6 */ + u32 *tx_bitmap_msb, + u32 *tx_bitmap_lsb); + + /* STA */ + bool (*phydm_add_sta)(struct rtl_priv *rtlpriv, + struct ieee80211_sta *sta); + bool (*phydm_del_sta)(struct rtl_priv *rtlpriv, + struct ieee80211_sta *sta); + + /* BTC */ + u32 (*phydm_get_version)(struct rtl_priv *rtlpriv); + bool (*phydm_modify_ra_pcr_threshold)(struct rtl_priv *rtlpriv, + u8 ra_offset_direction, + u8 ra_threshold_offset); + u32 (*phydm_query_counter)(struct rtl_priv *rtlpriv, + const char *info_type); + + /* debug */ + bool (*phydm_debug_cmd)(struct rtl_priv *rtlpriv, char *in, u32 in_len, + char *out, u32 out_len); + +}; + +struct rtl_phydm { + struct rtl_phydm_ops *ops;/* phydm ops (phydm_mod.ko own this object) */ + void *internal; /* internal context of phydm, i.e. PHY_DM_STRUCT */ + + u8 adaptivity_en; + /* debug */ + u16 forced_data_rate; + u8 forced_igi_lb; + u8 antenna_test; +}; + +struct proxim { + bool proxim_on; + + void *proximity_priv; + int (*proxim_rx)(struct ieee80211_hw *hw, struct rtl_stats *status, + struct sk_buff *skb); + u8 (*proxim_get_var)(struct ieee80211_hw *hw, u8 type); +}; + +struct rtl_c2hcmd { + struct list_head list; + u8 tag; + u8 len; + u8 *val; +}; + +struct rtl_bssid_entry { + struct list_head list; + u8 bssid[ETH_ALEN]; + u32 age; +}; + +struct rtl_scan_list { + int num; + struct list_head list; /* sort by age */ +}; + +struct rtl_priv { + struct ieee80211_hw *hw; + struct completion firmware_loading_complete; + struct list_head list; + struct rtl_priv *buddy_priv; + struct rtl_global_var *glb_var; + struct rtl_dualmac_easy_concurrent_ctl easy_concurrent_ctl; + struct rtl_dmsp_ctl dmsp_ctl; + struct rtl_locks locks; + struct rtl_works works; + struct rtl_mac mac80211; + struct rtl_hal rtlhal; + struct rtl_regulatory regd; + struct rtl_rfkill rfkill; + struct rtl_io io; + struct rtl_phy phy; + struct rtl_dm dm; + struct rtl_security sec; + struct rtl_efuse efuse; + struct rtl_led_ctl ledctl; + struct rtl_tx_report tx_report; + struct rtl_scan_list scan_list; + struct rtl_ps_ctl psc; + struct rate_adaptive ra; + struct dynamic_primary_cca primarycca; + struct wireless_stats stats; + struct rt_link_detect link_info; + struct false_alarm_statistics falsealm_cnt; + struct rtl_rate_priv *rate_priv; + /* sta entry list for ap adhoc or mesh */ + struct list_head entry_list; + /* c2hcmd list for kthread level access */ + struct list_head c2hcmd_list; + struct rtl_debug dbg; + int max_fw_size; + + /*hal_cfg : for diff cards + *intf_ops : for diff interface usb/pcie + */ + struct rtl_hal_cfg *cfg; + const struct rtl_intf_ops *intf_ops; + + /* this var will be set by set_bit, + * and was used to indicate status of + * interface or hardware + */ + unsigned long status; + + /* tables for dm */ + struct dig_t dm_digtable; + struct ps_t dm_pstable; + + u32 reg_874; + u32 reg_c70; + u32 reg_85c; + u32 reg_a74; + bool reg_init; /* true if regs saved */ + bool bt_operation_on; + __le32 *usb_data; + int usb_data_index; + bool initialized; + bool enter_ps; /* true when entering PS */ + u8 rate_mask[5]; + + /* intel Proximity, should be alloc mem + * in intel Proximity module and can only + * be used in intel Proximity mode + */ + struct proxim proximity; + + /*for bt coexist use*/ + struct bt_coexist_info btcoexist; + + /* halmac for newer IC. (e.g. 8822B) */ + struct rtl_halmac halmac; + + /* phydm for newer IC. (e.g. 8822B) */ + struct rtl_phydm phydm; + + /* separate 92ee from other ICs, + * 92ee use new trx flow. + */ + bool use_new_trx_flow; + +#ifdef CONFIG_PM + struct wiphy_wowlan_support wowlan; +#endif + /* This must be the last item so + * that it points to the data allocated + * beyond this structure like: + * rtl_pci_priv or rtl_usb_priv + */ + u8 priv[0] __aligned(sizeof(void *)); +}; + +#define rtl_priv(hw) (((struct rtl_priv *)(hw)->priv)) +#define rtl_mac(rtlpriv) (&((rtlpriv)->mac80211)) +#define rtl_hal(rtlpriv) (&((rtlpriv)->rtlhal)) +#define rtl_efuse(rtlpriv) (&((rtlpriv)->efuse)) +#define rtl_psc(rtlpriv) (&((rtlpriv)->psc)) + +/*************************************** + * Bluetooth Co-existence Related + ***************************************/ + +enum bt_ant_num { + ANT_X2 = 0, + ANT_X1 = 1, +}; + +enum bt_co_type { + BT_2WIRE = 0, + BT_ISSC_3WIRE = 1, + BT_ACCEL = 2, + BT_CSR_BC4 = 3, + BT_CSR_BC8 = 4, + BT_RTL8756 = 5, + BT_RTL8723A = 6, + BT_RTL8821A = 7, + BT_RTL8723B = 8, + BT_RTL8192E = 9, + BT_RTL8812A = 11, + BT_RTL8822B = 12, +}; + +enum bt_total_ant_num { + ANT_TOTAL_X2 = 0, + ANT_TOTAL_X1 = 1 +}; + +enum bt_cur_state { + BT_OFF = 0, + BT_ON = 1, +}; + +enum bt_service_type { + BT_SCO = 0, + BT_A2DP = 1, + BT_HID = 2, + BT_HID_IDLE = 3, + BT_SCAN = 4, + BT_IDLE = 5, + BT_OTHER_ACTION = 6, + BT_BUSY = 7, + BT_OTHERBUSY = 8, + BT_PAN = 9, +}; + +enum bt_radio_shared { + BT_RADIO_SHARED = 0, + BT_RADIO_INDIVIDUAL = 1, +}; + +/**************************************** + * mem access macro define start + * Call endian free function when + * 1. Read/write packet content. + * 2. Before write integer to IO. + * 3. After read integer from IO. + ***************************************/ +/* Convert little data endian to host ordering */ +#define EF1BYTE(_val) \ + ((u8)(_val)) +#define EF2BYTE(_val) \ + (le16_to_cpu(_val)) +#define EF4BYTE(_val) \ + (le32_to_cpu(_val)) + +/* Read data from memory */ +#define READEF1BYTE(_ptr) \ + EF1BYTE(*((u8 *)(_ptr))) +/* Read le16 data from memory and convert to host ordering */ +#define READEF2BYTE(_ptr) \ + EF2BYTE(*(_ptr)) +#define READEF4BYTE(_ptr) \ + EF4BYTE(*(_ptr)) + +/* Create a bit mask + * Examples: + * BIT_LEN_MASK_32(0) => 0x00000000 + * BIT_LEN_MASK_32(1) => 0x00000001 + * BIT_LEN_MASK_32(2) => 0x00000003 + * BIT_LEN_MASK_32(32) => 0xFFFFFFFF + */ +#define BIT_LEN_MASK_32(__bitlen) \ + (0xFFFFFFFF >> (32 - (__bitlen))) +#define BIT_LEN_MASK_16(__bitlen) \ + (0xFFFF >> (16 - (__bitlen))) +#define BIT_LEN_MASK_8(__bitlen) \ + (0xFF >> (8 - (__bitlen))) + +/* Create an offset bit mask + * Examples: + * BIT_OFFSET_LEN_MASK_32(0, 2) => 0x00000003 + * BIT_OFFSET_LEN_MASK_32(16, 2) => 0x00030000 + */ +#define BIT_OFFSET_LEN_MASK_32(__bitoffset, __bitlen) \ + (BIT_LEN_MASK_32(__bitlen) << (__bitoffset)) +#define BIT_OFFSET_LEN_MASK_16(__bitoffset, __bitlen) \ + (BIT_LEN_MASK_16(__bitlen) << (__bitoffset)) +#define BIT_OFFSET_LEN_MASK_8(__bitoffset, __bitlen) \ + (BIT_LEN_MASK_8(__bitlen) << (__bitoffset)) + +/*Description: + * Return 4-byte value in host byte ordering from + * 4-byte pointer in little-endian system. + */ +#define LE_P4BYTE_TO_HOST_4BYTE(__pstart) \ + (EF4BYTE(*((__le32 *)(__pstart)))) +#define LE_P2BYTE_TO_HOST_2BYTE(__pstart) \ + (EF2BYTE(*((__le16 *)(__pstart)))) +#define LE_P1BYTE_TO_HOST_1BYTE(__pstart) \ + (EF1BYTE(*((u8 *)(__pstart)))) + +/* Description: + * Translate subfield (continuous bits in little-endian) of 4-byte + * value to host byte ordering. + */ +#define LE_BITS_TO_4BYTE(__pstart, __bitoffset, __bitlen) \ + ( \ + (LE_P4BYTE_TO_HOST_4BYTE(__pstart) >> (__bitoffset)) & \ + BIT_LEN_MASK_32(__bitlen) \ + ) +#define LE_BITS_TO_2BYTE(__pstart, __bitoffset, __bitlen) \ + ( \ + (LE_P2BYTE_TO_HOST_2BYTE(__pstart) >> (__bitoffset)) & \ + BIT_LEN_MASK_16(__bitlen) \ + ) +#define LE_BITS_TO_1BYTE(__pstart, __bitoffset, __bitlen) \ + ( \ + (LE_P1BYTE_TO_HOST_1BYTE(__pstart) >> (__bitoffset)) & \ + BIT_LEN_MASK_8(__bitlen) \ + ) + +/* Description: + * Mask subfield (continuous bits in little-endian) of 4-byte value + * and return the result in 4-byte value in host byte ordering. + */ +#define LE_BITS_CLEARED_TO_4BYTE(__pstart, __bitoffset, __bitlen) \ + ( \ + LE_P4BYTE_TO_HOST_4BYTE(__pstart) & \ + (~BIT_OFFSET_LEN_MASK_32(__bitoffset, __bitlen)) \ + ) +#define LE_BITS_CLEARED_TO_2BYTE(__pstart, __bitoffset, __bitlen) \ + ( \ + LE_P2BYTE_TO_HOST_2BYTE(__pstart) & \ + (~BIT_OFFSET_LEN_MASK_16(__bitoffset, __bitlen)) \ + ) +#define LE_BITS_CLEARED_TO_1BYTE(__pstart, __bitoffset, __bitlen) \ + ( \ + LE_P1BYTE_TO_HOST_1BYTE(__pstart) & \ + (~BIT_OFFSET_LEN_MASK_8(__bitoffset, __bitlen)) \ + ) + +/* Description: + * Set subfield of little-endian 4-byte value to specified value. + */ +#define SET_BITS_TO_LE_4BYTE(__pstart, __bitoffset, __bitlen, __val) \ + (*((__le32 *)(__pstart)) = \ + cpu_to_le32( \ + LE_BITS_CLEARED_TO_4BYTE(__pstart, __bitoffset, __bitlen) | \ + ((((u32)__val) & BIT_LEN_MASK_32(__bitlen)) << (__bitoffset)) \ + )) +#define SET_BITS_TO_LE_2BYTE(__pstart, __bitoffset, __bitlen, __val) \ + (*((__le16 *)(__pstart)) = \ + cpu_to_le16( \ + LE_BITS_CLEARED_TO_2BYTE(__pstart, __bitoffset, __bitlen) | \ + ((((u16)__val) & BIT_LEN_MASK_16(__bitlen)) << (__bitoffset)) \ + )) +#define SET_BITS_TO_LE_1BYTE(__pstart, __bitoffset, __bitlen, __val) \ + (*((u8 *)(__pstart)) = EF1BYTE \ + ( \ + LE_BITS_CLEARED_TO_1BYTE(__pstart, __bitoffset, __bitlen) | \ + ((((u8)__val) & BIT_LEN_MASK_8(__bitlen)) << (__bitoffset)) \ + )) + +#define N_BYTE_ALIGNMENT(__value, __alignment) ((__alignment == 1) ? \ + (__value) : (((__value + __alignment - 1) / \ + __alignment) * __alignment)) + +/**************************************** + * mem access macro define end + ****************************************/ + +#define byte(x, n) ((x >> (8 * n)) & 0xff) + +#define packet_get_type(_packet) (EF1BYTE((_packet).octet[0]) & 0xFC) +#define RTL_WATCH_DOG_TIME 2000 +#define MSECS(t) msecs_to_jiffies(t) +#define WLAN_FC_GET_VERS(fc) (le16_to_cpu(fc) & IEEE80211_FCTL_VERS) +#define WLAN_FC_GET_TYPE(fc) (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE) +#define WLAN_FC_GET_STYPE(fc) (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE) +#define WLAN_FC_MORE_DATA(fc) (le16_to_cpu(fc) & IEEE80211_FCTL_MOREDATA) +#define rtl_dm(rtlpriv) (&((rtlpriv)->dm)) + +#define RT_RF_OFF_LEVL_ASPM BIT(0) /*PCI ASPM */ +#define RT_RF_OFF_LEVL_CLK_REQ BIT(1) /*PCI clock request */ +#define RT_RF_OFF_LEVL_PCI_D3 BIT(2) /*PCI D3 mode */ +/*NIC halt, re-initialize hw parameters*/ +#define RT_RF_OFF_LEVL_HALT_NIC BIT(3) +#define RT_RF_OFF_LEVL_FREE_FW BIT(4) /*FW free, re-download the FW */ +#define RT_RF_OFF_LEVL_FW_32K BIT(5) /*FW in 32k */ +/*Always enable ASPM and Clock Req in initialization.*/ +#define RT_RF_PS_LEVEL_ALWAYS_ASPM BIT(6) +/* no matter RFOFF or SLEEP we set PS_ASPM_LEVL*/ +#define RT_PS_LEVEL_ASPM BIT(7) +/*When LPS is on, disable 2R if no packet is received or transmitted.*/ +#define RT_RF_LPS_DISALBE_2R BIT(30) +#define RT_RF_LPS_LEVEL_ASPM BIT(31) /*LPS with ASPM */ +#define RT_IN_PS_LEVEL(ppsc, _ps_flg) \ + ((ppsc->cur_ps_level & _ps_flg) ? true : false) +#define RT_CLEAR_PS_LEVEL(ppsc, _ps_flg) \ + (ppsc->cur_ps_level &= (~(_ps_flg))) +#define RT_SET_PS_LEVEL(ppsc, _ps_flg) \ + (ppsc->cur_ps_level |= _ps_flg) + +#define container_of_dwork_rtl(x, y, z) \ + container_of(to_delayed_work(x), y, z) + +#define FILL_OCTET_STRING(_os, _octet, _len) \ + (_os).octet = (u8 *)(_octet); \ + (_os).length = (_len) + +#define CP_MACADDR(des, src) \ + ((des)[0] = (src)[0], (des)[1] = (src)[1],\ + (des)[2] = (src)[2], (des)[3] = (src)[3],\ + (des)[4] = (src)[4], (des)[5] = (src)[5]) + +#define LDPC_HT_ENABLE_RX BIT(0) +#define LDPC_HT_ENABLE_TX BIT(1) +#define LDPC_HT_TEST_TX_ENABLE BIT(2) +#define LDPC_HT_CAP_TX BIT(3) + +#define STBC_HT_ENABLE_RX BIT(0) +#define STBC_HT_ENABLE_TX BIT(1) +#define STBC_HT_TEST_TX_ENABLE BIT(2) +#define STBC_HT_CAP_TX BIT(3) + +#define LDPC_VHT_ENABLE_RX BIT(0) +#define LDPC_VHT_ENABLE_TX BIT(1) +#define LDPC_VHT_TEST_TX_ENABLE BIT(2) +#define LDPC_VHT_CAP_TX BIT(3) + +#define STBC_VHT_ENABLE_RX BIT(0) +#define STBC_VHT_ENABLE_TX BIT(1) +#define STBC_VHT_TEST_TX_ENABLE BIT(2) +#define STBC_VHT_CAP_TX BIT(3) + +extern u8 channel5g[CHANNEL_MAX_NUMBER_5G]; + +extern u8 channel5g_80m[CHANNEL_MAX_NUMBER_5G_80M]; + +static inline u8 rtl_read_byte(struct rtl_priv *rtlpriv, u32 addr) +{ + return rtlpriv->io.read8_sync(rtlpriv, addr); +} + +static inline u16 rtl_read_word(struct rtl_priv *rtlpriv, u32 addr) +{ + return rtlpriv->io.read16_sync(rtlpriv, addr); +} + +static inline u32 rtl_read_dword(struct rtl_priv *rtlpriv, u32 addr) +{ + return rtlpriv->io.read32_sync(rtlpriv, addr); +} + +static inline void rtl_write_byte(struct rtl_priv *rtlpriv, u32 addr, u8 val8) +{ + rtlpriv->io.write8_async(rtlpriv, addr, val8); + + if (rtlpriv->cfg->write_readback) + rtlpriv->io.read8_sync(rtlpriv, addr); +} + +static inline void rtl_write_byte_with_val32(struct ieee80211_hw *hw, + u32 addr, u32 val8) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtl_write_byte(rtlpriv, addr, (u8)val8); +} + +static inline void rtl_write_word(struct rtl_priv *rtlpriv, u32 addr, u16 val16) +{ + rtlpriv->io.write16_async(rtlpriv, addr, val16); + + if (rtlpriv->cfg->write_readback) + rtlpriv->io.read16_sync(rtlpriv, addr); +} + +static inline void rtl_write_dword(struct rtl_priv *rtlpriv, + u32 addr, u32 val32) +{ + rtlpriv->io.write32_async(rtlpriv, addr, val32); + + if (rtlpriv->cfg->write_readback) + rtlpriv->io.read32_sync(rtlpriv, addr); +} + +static inline u32 rtl_get_bbreg(struct ieee80211_hw *hw, + u32 regaddr, u32 bitmask) +{ + struct rtl_priv *rtlpriv = hw->priv; + + return rtlpriv->cfg->ops->get_bbreg(hw, regaddr, bitmask); +} + +static inline void rtl_set_bbreg(struct ieee80211_hw *hw, u32 regaddr, + u32 bitmask, u32 data) +{ + struct rtl_priv *rtlpriv = hw->priv; + + rtlpriv->cfg->ops->set_bbreg(hw, regaddr, bitmask, data); +} + +static inline void rtl_set_bbreg_with_dwmask(struct ieee80211_hw *hw, + u32 regaddr, u32 data) +{ + rtl_set_bbreg(hw, regaddr, 0xffffffff, data); +} + +static inline u32 rtl_get_rfreg(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 regaddr, + u32 bitmask) +{ + struct rtl_priv *rtlpriv = hw->priv; + + return rtlpriv->cfg->ops->get_rfreg(hw, rfpath, regaddr, bitmask); +} + +static inline void rtl_set_rfreg(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 regaddr, + u32 bitmask, u32 data) +{ + struct rtl_priv *rtlpriv = hw->priv; + + rtlpriv->cfg->ops->set_rfreg(hw, rfpath, regaddr, bitmask, data); +} + +static inline bool is_hal_stop(struct rtl_hal *rtlhal) +{ + return (rtlhal->state == _HAL_STATE_STOP); +} + +static inline void set_hal_start(struct rtl_hal *rtlhal) +{ + rtlhal->state = _HAL_STATE_START; +} + +static inline void set_hal_stop(struct rtl_hal *rtlhal) +{ + rtlhal->state = _HAL_STATE_STOP; +} + +static inline u8 get_rf_type(struct rtl_phy *rtlphy) +{ + return rtlphy->rf_type; +} + +static inline struct ieee80211_hdr *rtl_get_hdr(struct sk_buff *skb) +{ + return (struct ieee80211_hdr *)(skb->data); +} + +static inline __le16 rtl_get_fc(struct sk_buff *skb) +{ + return rtl_get_hdr(skb)->frame_control; +} + +static inline u16 rtl_get_tid_h(struct ieee80211_hdr *hdr) +{ + return (ieee80211_get_qos_ctl(hdr))[0] & IEEE80211_QOS_CTL_TID_MASK; +} + +static inline u16 rtl_get_tid(struct sk_buff *skb) +{ + return rtl_get_tid_h(rtl_get_hdr(skb)); +} + +static inline struct ieee80211_sta *get_sta(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + const u8 *bssid) +{ + return ieee80211_find_sta(vif, bssid); +} + +static inline struct ieee80211_sta *rtl_find_sta(struct ieee80211_hw *hw, + u8 *mac_addr) +{ + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + + return ieee80211_find_sta(mac->vif, mac_addr); +} + +#endif diff --git a/drivers/staging/rts5208/ms.c b/drivers/staging/rts5208/ms.c index 482a29dd06f8..7cdce87f3051 100644 --- a/drivers/staging/rts5208/ms.c +++ b/drivers/staging/rts5208/ms.c @@ -3064,7 +3064,8 @@ static int mspro_rw_multi_sector(struct scsi_cmnd *srb, if (detect_card_cd(chip, MS_CARD) != STATUS_SUCCESS) { chip->rw_need_retry = 0; - dev_dbg(rtsx_dev(chip), "No card exist, exit mspro_rw_multi_sector\n"); + dev_dbg(rtsx_dev(chip), "No card exist, exit %s\n", + __func__); rtsx_trace(chip); return STATUS_FAIL; } @@ -3101,7 +3102,7 @@ static int mspro_read_format_progress(struct rtsx_chip *chip, u8 cnt, tmp; u8 data[8]; - dev_dbg(rtsx_dev(chip), "mspro_read_format_progress, short_data_len = %d\n", + dev_dbg(rtsx_dev(chip), "%s, short_data_len = %d\n", __func__, short_data_len); retval = ms_switch_clock(chip); diff --git a/drivers/staging/rts5208/rtsx.c b/drivers/staging/rts5208/rtsx.c index b8177f50fabc..89e2cfe7d1cc 100644 --- a/drivers/staging/rts5208/rtsx.c +++ b/drivers/staging/rts5208/rtsx.c @@ -205,16 +205,6 @@ static int device_reset(struct scsi_cmnd *srb) return SUCCESS; } -/* Simulate a SCSI bus reset by resetting the device's USB port. */ -static int bus_reset(struct scsi_cmnd *srb) -{ - struct rtsx_dev *dev = host_to_rtsx(srb->device->host); - - dev_info(&dev->pci->dev, "%s called\n", __func__); - - return SUCCESS; -} - /* * this defines our host template, with which we'll allocate hosts */ @@ -231,7 +221,6 @@ static struct scsi_host_template rtsx_host_template = { /* error and abort handlers */ .eh_abort_handler = command_abort, .eh_device_reset_handler = device_reset, - .eh_bus_reset_handler = bus_reset, /* queue commands only, only one command per LUN */ .can_queue = 1, @@ -999,7 +988,7 @@ static int rtsx_probe(struct pci_dev *pci, /* We come here if there are any problems */ errout: - dev_err(&pci->dev, "rtsx_probe() failed\n"); + dev_err(&pci->dev, "%s failed\n", __func__); release_everything(dev); return err; @@ -1009,7 +998,7 @@ static void rtsx_remove(struct pci_dev *pci) { struct rtsx_dev *dev = pci_get_drvdata(pci); - dev_info(&pci->dev, "rtsx_remove() called\n"); + dev_info(&pci->dev, "%s called\n", __func__); quiesce_and_remove_host(dev); release_everything(dev); diff --git a/drivers/staging/rts5208/rtsx_chip.c b/drivers/staging/rts5208/rtsx_chip.c index 7f4107bffe31..4ad472dd9daf 100644 --- a/drivers/staging/rts5208/rtsx_chip.c +++ b/drivers/staging/rts5208/rtsx_chip.c @@ -616,8 +616,8 @@ int rtsx_reset_chip(struct rtsx_chip *chip) else retval = rtsx_pre_handle_sdio_new(chip); - dev_dbg(rtsx_dev(chip), "chip->need_reset = 0x%x (rtsx_reset_chip)\n", - (unsigned int)(chip->need_reset)); + dev_dbg(rtsx_dev(chip), "chip->need_reset = 0x%x (%s)\n", + (unsigned int)(chip->need_reset), __func__); #else /* HW_AUTO_SWITCH_SD_BUS */ retval = rtsx_pre_handle_sdio_old(chip); #endif /* HW_AUTO_SWITCH_SD_BUS */ diff --git a/drivers/staging/rts5208/rtsx_scsi.c b/drivers/staging/rts5208/rtsx_scsi.c index 36b5a11f21d2..a401b13f5f5e 100644 --- a/drivers/staging/rts5208/rtsx_scsi.c +++ b/drivers/staging/rts5208/rtsx_scsi.c @@ -414,7 +414,7 @@ void set_sense_data(struct rtsx_chip *chip, unsigned int lun, u8 err_code, sense->ascq = ascq; if (sns_key_info0 != 0) { sense->sns_key_info[0] = SKSV | sns_key_info0; - sense->sns_key_info[1] = (sns_key_info1 & 0xf0) >> 8; + sense->sns_key_info[1] = (sns_key_info1 & 0xf0) >> 4; sense->sns_key_info[2] = sns_key_info1 & 0x0f; } } diff --git a/drivers/staging/rts5208/sd.c b/drivers/staging/rts5208/sd.c index c2eb072cbe1d..4033a2cf7ac9 100644 --- a/drivers/staging/rts5208/sd.c +++ b/drivers/staging/rts5208/sd.c @@ -910,8 +910,8 @@ static int sd_change_phase(struct rtsx_chip *chip, u8 sample_point, u8 tune_dir) int retval; bool ddr_rx = false; - dev_dbg(rtsx_dev(chip), "sd_change_phase (sample_point = %d, tune_dir = %d)\n", - sample_point, tune_dir); + dev_dbg(rtsx_dev(chip), "%s (sample_point = %d, tune_dir = %d)\n", + __func__, sample_point, tune_dir); if (tune_dir == TUNE_RX) { SD_VP_CTL = SD_VPRX_CTL; @@ -1225,8 +1225,8 @@ static int sd_check_switch_mode(struct rtsx_chip *chip, u8 mode, u8 func_group, int retval; u8 cmd[5], buf[64]; - dev_dbg(rtsx_dev(chip), "sd_check_switch_mode (mode = %d, func_group = %d, func_to_switch = %d)\n", - mode, func_group, func_to_switch); + dev_dbg(rtsx_dev(chip), "%s (mode = %d, func_group = %d, func_to_switch = %d)\n", + __func__, mode, func_group, func_to_switch); cmd[0] = 0x40 | SWITCH; cmd[1] = mode; @@ -1654,7 +1654,7 @@ static int sd_ddr_tuning_rx_cmd(struct rtsx_chip *chip, u8 sample_point) return STATUS_SUCCESS; } -static int mmc_ddr_tunning_rx_cmd(struct rtsx_chip *chip, u8 sample_point) +static int mmc_ddr_tuning_rx_cmd(struct rtsx_chip *chip, u8 sample_point) { struct sd_info *sd_card = &chip->sd_card; int retval; @@ -1933,7 +1933,7 @@ static int sd_tuning_rx(struct rtsx_chip *chip) } else { if (CHK_MMC_DDR52(sd_card)) { - tuning_cmd = mmc_ddr_tunning_rx_cmd; + tuning_cmd = mmc_ddr_tuning_rx_cmd; } else { rtsx_trace(chip); return STATUS_FAIL; @@ -3575,8 +3575,8 @@ static int reset_mmc_only(struct rtsx_chip *chip) return STATUS_FAIL; } - dev_dbg(rtsx_dev(chip), "In reset_mmc_only, sd_card->sd_type = 0x%x\n", - sd_card->sd_type); + dev_dbg(rtsx_dev(chip), "In %s, sd_card->sd_type = 0x%x\n", + __func__, sd_card->sd_type); return STATUS_SUCCESS; } @@ -3699,11 +3699,11 @@ int sd_rw(struct scsi_cmnd *srb, struct rtsx_chip *chip, u32 start_sector, int retval; if (srb->sc_data_direction == DMA_FROM_DEVICE) { - dev_dbg(rtsx_dev(chip), "sd_rw: Read %d %s from 0x%x\n", + dev_dbg(rtsx_dev(chip), "%s: Read %d %s from 0x%x\n", __func__, sector_cnt, (sector_cnt > 1) ? "sectors" : "sector", start_sector); } else { - dev_dbg(rtsx_dev(chip), "sd_rw: Write %d %s to 0x%x\n", + dev_dbg(rtsx_dev(chip), "%s: Write %d %s to 0x%x\n", __func__, sector_cnt, (sector_cnt > 1) ? "sectors" : "sector", start_sector); } @@ -3921,7 +3921,8 @@ int sd_rw(struct scsi_cmnd *srb, struct rtsx_chip *chip, u32 start_sector, rtsx_clear_sd_error(chip); if (detect_card_cd(chip, SD_CARD) != STATUS_SUCCESS) { chip->rw_need_retry = 0; - dev_dbg(rtsx_dev(chip), "No card exist, exit sd_rw\n"); + dev_dbg(rtsx_dev(chip), "No card exist, exit %s\n", + __func__); rtsx_trace(chip); return STATUS_FAIL; } @@ -3964,7 +3965,7 @@ RW_FAIL: if (detect_card_cd(chip, SD_CARD) != STATUS_SUCCESS) { chip->rw_need_retry = 0; - dev_dbg(rtsx_dev(chip), "No card exist, exit sd_rw\n"); + dev_dbg(rtsx_dev(chip), "No card exist, exit %s\n", __func__); rtsx_trace(chip); return STATUS_FAIL; } diff --git a/drivers/staging/rts5208/spi.c b/drivers/staging/rts5208/spi.c index 8b8cd955dfeb..b5646b62ec9e 100644 --- a/drivers/staging/rts5208/spi.c +++ b/drivers/staging/rts5208/spi.c @@ -520,7 +520,7 @@ int spi_get_status(struct scsi_cmnd *srb, struct rtsx_chip *chip) { struct spi_info *spi = &chip->spi; - dev_dbg(rtsx_dev(chip), "spi_get_status: err_code = 0x%x\n", + dev_dbg(rtsx_dev(chip), "%s: err_code = 0x%x\n", __func__, spi->err_code); rtsx_stor_set_xfer_buf(&spi->err_code, min_t(int, scsi_bufflen(srb), 1), srb); @@ -543,8 +543,10 @@ int spi_set_parameter(struct scsi_cmnd *srb, struct rtsx_chip *chip) spi->clk_div = ((u16)(srb->cmnd[4]) << 8) | srb->cmnd[5]; spi->write_en = srb->cmnd[6]; - dev_dbg(rtsx_dev(chip), "spi_set_parameter: spi_clock = %d, clk_div = %d, write_en = %d\n", - spi->spi_clock, spi->clk_div, spi->write_en); + dev_dbg(rtsx_dev(chip), "%s: ", __func__); + dev_dbg(rtsx_dev(chip), "spi_clock = %d, ", spi->spi_clock); + dev_dbg(rtsx_dev(chip), "clk_div = %d, ", spi->clk_div); + dev_dbg(rtsx_dev(chip), "write_en = %d\n", spi->write_en); return STATUS_SUCCESS; } diff --git a/drivers/staging/rts5208/xd.c b/drivers/staging/rts5208/xd.c index 74d36f9a4c1d..11ea0c658e28 100644 --- a/drivers/staging/rts5208/xd.c +++ b/drivers/staging/rts5208/xd.c @@ -885,7 +885,7 @@ static int xd_init_l2p_tbl(struct rtsx_chip *chip) struct xd_info *xd_card = &chip->xd_card; int size, i; - dev_dbg(rtsx_dev(chip), "xd_init_l2p_tbl: zone_cnt = %d\n", + dev_dbg(rtsx_dev(chip), "%s: zone_cnt = %d\n", __func__, xd_card->zone_cnt); if (xd_card->zone_cnt < 1) { @@ -1026,7 +1026,8 @@ static u32 xd_get_l2p_tbl(struct rtsx_chip *chip, int zone_no, u16 log_off) #ifdef XD_DELAY_WRITE retval = xd_delay_write(chip); if (retval != STATUS_SUCCESS) { - dev_dbg(rtsx_dev(chip), "In xd_get_l2p_tbl, delay write fail!\n"); + dev_dbg(rtsx_dev(chip), "In %s, delay write fail!\n", + __func__); return BLK_NOT_FOUND; } #endif @@ -1434,7 +1435,7 @@ static int xd_build_l2p_tbl(struct rtsx_chip *chip, int zone_no) u16 cur_lst_page_logoff, ent_lst_page_logoff; u8 redunt[11]; - dev_dbg(rtsx_dev(chip), "xd_build_l2p_tbl: %d\n", zone_no); + dev_dbg(rtsx_dev(chip), "%s: %d\n", __func__, zone_no); if (!xd_card->zone) { retval = xd_init_l2p_tbl(chip); @@ -1774,8 +1775,10 @@ static int xd_finish_write(struct rtsx_chip *chip, int retval, zone_no; u16 log_off; - dev_dbg(rtsx_dev(chip), "xd_finish_write, old_blk = 0x%x, new_blk = 0x%x, log_blk = 0x%x\n", - old_blk, new_blk, log_blk); + dev_dbg(rtsx_dev(chip), "%s ", __func__); + dev_dbg(rtsx_dev(chip), "old_blk = 0x%x, ", old_blk); + dev_dbg(rtsx_dev(chip), "new_blk = 0x%x, ", new_blk); + dev_dbg(rtsx_dev(chip), "log_blk = 0x%x\n", log_blk); if (page_off > xd_card->page_off) { rtsx_trace(chip); @@ -1960,7 +1963,7 @@ int xd_delay_write(struct rtsx_chip *chip) int retval; if (delay_write->delay_write_flag) { - dev_dbg(rtsx_dev(chip), "xd_delay_write\n"); + dev_dbg(rtsx_dev(chip), "%s\n", __func__); retval = xd_switch_clock(chip); if (retval != STATUS_SUCCESS) { rtsx_trace(chip); @@ -2002,7 +2005,7 @@ int xd_rw(struct scsi_cmnd *srb, struct rtsx_chip *chip, xd_card->cleanup_counter = 0; - dev_dbg(rtsx_dev(chip), "xd_rw: scsi_sg_count = %d\n", + dev_dbg(rtsx_dev(chip), "%s: scsi_sg_count = %d\n", __func__, scsi_sg_count(srb)); ptr = (u8 *)scsi_sglist(srb); diff --git a/drivers/staging/skein/skein_block.c b/drivers/staging/skein/skein_block.c index 256657077a46..3bc25e149034 100644 --- a/drivers/staging/skein/skein_block.c +++ b/drivers/staging/skein/skein_block.c @@ -21,329 +21,6 @@ #include "skein_base.h" #include "skein_block.h" -#ifndef SKEIN_USE_ASM -#define SKEIN_USE_ASM (0) /* default is all C code (no ASM) */ -#endif - -#ifndef SKEIN_LOOP -#define SKEIN_LOOP 001 /* default: unroll 256 and 512, but not 1024 */ -#endif - -#define BLK_BITS (WCNT * 64) /* some useful definitions for code here */ -#define KW_TWK_BASE (0) -#define KW_KEY_BASE (3) -#define ks (kw + KW_KEY_BASE) -#define ts (kw + KW_TWK_BASE) - -#ifdef SKEIN_DEBUG -#define debug_save_tweak(ctx) \ -{ \ - ctx->h.tweak[0] = ts[0]; \ - ctx->h.tweak[1] = ts[1]; \ -} -#else -#define debug_save_tweak(ctx) -#endif - -#if !(SKEIN_USE_ASM & 256) -#undef RCNT -#define RCNT (SKEIN_256_ROUNDS_TOTAL / 8) -#ifdef SKEIN_LOOP /* configure how much to unroll the loop */ -#define SKEIN_UNROLL_256 (((SKEIN_LOOP) / 100) % 10) -#else -#define SKEIN_UNROLL_256 (0) -#endif - -#if SKEIN_UNROLL_256 -#if (RCNT % SKEIN_UNROLL_256) -#error "Invalid SKEIN_UNROLL_256" /* sanity check on unroll count */ -#endif -#endif -#define ROUND256(p0, p1, p2, p3, ROT, r_num) \ - do { \ - X##p0 += X##p1; \ - X##p1 = rol64(X##p1, ROT##_0); \ - X##p1 ^= X##p0; \ - X##p2 += X##p3; \ - X##p3 = rol64(X##p3, ROT##_1); \ - X##p3 ^= X##p2; \ - } while (0) - -#if SKEIN_UNROLL_256 == 0 -#define R256(p0, p1, p2, p3, ROT, r_num) /* fully unrolled */ \ - ROUND256(p0, p1, p2, p3, ROT, r_num) - -#define I256(R) \ - do { \ - /* inject the key schedule value */ \ - X0 += ks[((R) + 1) % 5]; \ - X1 += ks[((R) + 2) % 5] + ts[((R) + 1) % 3]; \ - X2 += ks[((R) + 3) % 5] + ts[((R) + 2) % 3]; \ - X3 += ks[((R) + 4) % 5] + (R) + 1; \ - } while (0) -#else -/* looping version */ -#define R256(p0, p1, p2, p3, ROT, r_num) ROUND256(p0, p1, p2, p3, ROT, r_num) - -#define I256(R) \ - do { \ - /* inject the key schedule value */ \ - X0 += ks[r + (R) + 0]; \ - X1 += ks[r + (R) + 1] + ts[r + (R) + 0];\ - X2 += ks[r + (R) + 2] + ts[r + (R) + 1];\ - X3 += ks[r + (R) + 3] + r + (R); \ - /* rotate key schedule */ \ - ks[r + (R) + 4] = ks[r + (R) - 1]; \ - ts[r + (R) + 2] = ts[r + (R) - 1]; \ - } while (0) -#endif -#define R256_8_ROUNDS(R) \ - do { \ - R256(0, 1, 2, 3, R_256_0, 8 * (R) + 1); \ - R256(0, 3, 2, 1, R_256_1, 8 * (R) + 2); \ - R256(0, 1, 2, 3, R_256_2, 8 * (R) + 3); \ - R256(0, 3, 2, 1, R_256_3, 8 * (R) + 4); \ - I256(2 * (R)); \ - R256(0, 1, 2, 3, R_256_4, 8 * (R) + 5); \ - R256(0, 3, 2, 1, R_256_5, 8 * (R) + 6); \ - R256(0, 1, 2, 3, R_256_6, 8 * (R) + 7); \ - R256(0, 3, 2, 1, R_256_7, 8 * (R) + 8); \ - I256(2 * (R) + 1); \ - } while (0) - -#define R256_UNROLL_R(NN) \ - ((SKEIN_UNROLL_256 == 0 && \ - SKEIN_256_ROUNDS_TOTAL / 8 > (NN)) || \ - (SKEIN_UNROLL_256 > (NN))) - -#if (SKEIN_UNROLL_256 > 14) -#error "need more unrolling in skein_256_process_block" -#endif -#endif - -#if !(SKEIN_USE_ASM & 512) -#undef RCNT -#define RCNT (SKEIN_512_ROUNDS_TOTAL / 8) - -#ifdef SKEIN_LOOP /* configure how much to unroll the loop */ -#define SKEIN_UNROLL_512 (((SKEIN_LOOP) / 10) % 10) -#else -#define SKEIN_UNROLL_512 (0) -#endif - -#if SKEIN_UNROLL_512 -#if (RCNT % SKEIN_UNROLL_512) -#error "Invalid SKEIN_UNROLL_512" /* sanity check on unroll count */ -#endif -#endif -#define ROUND512(p0, p1, p2, p3, p4, p5, p6, p7, ROT, r_num) \ - do { \ - X##p0 += X##p1; \ - X##p1 = rol64(X##p1, ROT##_0); \ - X##p1 ^= X##p0; \ - X##p2 += X##p3; \ - X##p3 = rol64(X##p3, ROT##_1); \ - X##p3 ^= X##p2; \ - X##p4 += X##p5; \ - X##p5 = rol64(X##p5, ROT##_2); \ - X##p5 ^= X##p4; \ - X##p6 += X##p7; \ - X##p7 = rol64(X##p7, ROT##_3); \ - X##p7 ^= X##p6; \ - } while (0) - -#if SKEIN_UNROLL_512 == 0 -#define R512(p0, p1, p2, p3, p4, p5, p6, p7, ROT, r_num) /* unrolled */ \ - ROUND512(p0, p1, p2, p3, p4, p5, p6, p7, ROT, r_num) - -#define I512(R) \ - do { \ - /* inject the key schedule value */ \ - X0 += ks[((R) + 1) % 9]; \ - X1 += ks[((R) + 2) % 9]; \ - X2 += ks[((R) + 3) % 9]; \ - X3 += ks[((R) + 4) % 9]; \ - X4 += ks[((R) + 5) % 9]; \ - X5 += ks[((R) + 6) % 9] + ts[((R) + 1) % 3]; \ - X6 += ks[((R) + 7) % 9] + ts[((R) + 2) % 3]; \ - X7 += ks[((R) + 8) % 9] + (R) + 1; \ - } while (0) - -#else /* looping version */ -#define R512(p0, p1, p2, p3, p4, p5, p6, p7, ROT, r_num) \ - ROUND512(p0, p1, p2, p3, p4, p5, p6, p7, ROT, r_num) \ - -#define I512(R) \ - do { \ - /* inject the key schedule value */ \ - X0 += ks[r + (R) + 0]; \ - X1 += ks[r + (R) + 1]; \ - X2 += ks[r + (R) + 2]; \ - X3 += ks[r + (R) + 3]; \ - X4 += ks[r + (R) + 4]; \ - X5 += ks[r + (R) + 5] + ts[r + (R) + 0]; \ - X6 += ks[r + (R) + 6] + ts[r + (R) + 1]; \ - X7 += ks[r + (R) + 7] + r + (R); \ - /* rotate key schedule */ \ - ks[r + (R) + 8] = ks[r + (R) - 1]; \ - ts[r + (R) + 2] = ts[r + (R) - 1]; \ - } while (0) -#endif /* end of looped code definitions */ -#define R512_8_ROUNDS(R) /* do 8 full rounds */ \ - do { \ - R512(0, 1, 2, 3, 4, 5, 6, 7, R_512_0, 8 * (R) + 1); \ - R512(2, 1, 4, 7, 6, 5, 0, 3, R_512_1, 8 * (R) + 2); \ - R512(4, 1, 6, 3, 0, 5, 2, 7, R_512_2, 8 * (R) + 3); \ - R512(6, 1, 0, 7, 2, 5, 4, 3, R_512_3, 8 * (R) + 4); \ - I512(2 * (R)); \ - R512(0, 1, 2, 3, 4, 5, 6, 7, R_512_4, 8 * (R) + 5); \ - R512(2, 1, 4, 7, 6, 5, 0, 3, R_512_5, 8 * (R) + 6); \ - R512(4, 1, 6, 3, 0, 5, 2, 7, R_512_6, 8 * (R) + 7); \ - R512(6, 1, 0, 7, 2, 5, 4, 3, R_512_7, 8 * (R) + 8); \ - I512(2 * (R) + 1); /* and key injection */ \ - } while (0) -#define R512_UNROLL_R(NN) \ - ((SKEIN_UNROLL_512 == 0 && \ - SKEIN_512_ROUNDS_TOTAL / 8 > (NN)) || \ - (SKEIN_UNROLL_512 > (NN))) - -#if (SKEIN_UNROLL_512 > 14) -#error "need more unrolling in skein_512_process_block" -#endif -#endif - -#if !(SKEIN_USE_ASM & 1024) -#undef RCNT -#define RCNT (SKEIN_1024_ROUNDS_TOTAL / 8) -#ifdef SKEIN_LOOP /* configure how much to unroll the loop */ -#define SKEIN_UNROLL_1024 ((SKEIN_LOOP) % 10) -#else -#define SKEIN_UNROLL_1024 (0) -#endif - -#if (SKEIN_UNROLL_1024 != 0) -#if (RCNT % SKEIN_UNROLL_1024) -#error "Invalid SKEIN_UNROLL_1024" /* sanity check on unroll count */ -#endif -#endif -#define ROUND1024(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pA, pB, pC, pD, pE, \ - pF, ROT, r_num) \ - do { \ - X##p0 += X##p1; \ - X##p1 = rol64(X##p1, ROT##_0); \ - X##p1 ^= X##p0; \ - X##p2 += X##p3; \ - X##p3 = rol64(X##p3, ROT##_1); \ - X##p3 ^= X##p2; \ - X##p4 += X##p5; \ - X##p5 = rol64(X##p5, ROT##_2); \ - X##p5 ^= X##p4; \ - X##p6 += X##p7; \ - X##p7 = rol64(X##p7, ROT##_3); \ - X##p7 ^= X##p6; \ - X##p8 += X##p9; \ - X##p9 = rol64(X##p9, ROT##_4); \ - X##p9 ^= X##p8; \ - X##pA += X##pB; \ - X##pB = rol64(X##pB, ROT##_5); \ - X##pB ^= X##pA; \ - X##pC += X##pD; \ - X##pD = rol64(X##pD, ROT##_6); \ - X##pD ^= X##pC; \ - X##pE += X##pF; \ - X##pF = rol64(X##pF, ROT##_7); \ - X##pF ^= X##pE; \ - } while (0) - -#if SKEIN_UNROLL_1024 == 0 -#define R1024(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pA, pB, pC, pD, pE, pF, \ - ROT, rn) \ - ROUND1024(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pA, pB, pC, pD, pE, \ - pF, ROT, rn) \ - -#define I1024(R) \ - do { \ - /* inject the key schedule value */ \ - X00 += ks[((R) + 1) % 17]; \ - X01 += ks[((R) + 2) % 17]; \ - X02 += ks[((R) + 3) % 17]; \ - X03 += ks[((R) + 4) % 17]; \ - X04 += ks[((R) + 5) % 17]; \ - X05 += ks[((R) + 6) % 17]; \ - X06 += ks[((R) + 7) % 17]; \ - X07 += ks[((R) + 8) % 17]; \ - X08 += ks[((R) + 9) % 17]; \ - X09 += ks[((R) + 10) % 17]; \ - X10 += ks[((R) + 11) % 17]; \ - X11 += ks[((R) + 12) % 17]; \ - X12 += ks[((R) + 13) % 17]; \ - X13 += ks[((R) + 14) % 17] + ts[((R) + 1) % 3]; \ - X14 += ks[((R) + 15) % 17] + ts[((R) + 2) % 3]; \ - X15 += ks[((R) + 16) % 17] + (R) + 1; \ - } while (0) -#else /* looping version */ -#define R1024(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pA, pB, pC, pD, pE, pF, \ - ROT, rn) \ - ROUND1024(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pA, pB, pC, pD, pE, \ - pF, ROT, rn) \ - -#define I1024(R) \ - do { \ - /* inject the key schedule value */ \ - X00 += ks[r + (R) + 0]; \ - X01 += ks[r + (R) + 1]; \ - X02 += ks[r + (R) + 2]; \ - X03 += ks[r + (R) + 3]; \ - X04 += ks[r + (R) + 4]; \ - X05 += ks[r + (R) + 5]; \ - X06 += ks[r + (R) + 6]; \ - X07 += ks[r + (R) + 7]; \ - X08 += ks[r + (R) + 8]; \ - X09 += ks[r + (R) + 9]; \ - X10 += ks[r + (R) + 10]; \ - X11 += ks[r + (R) + 11]; \ - X12 += ks[r + (R) + 12]; \ - X13 += ks[r + (R) + 13] + ts[r + (R) + 0]; \ - X14 += ks[r + (R) + 14] + ts[r + (R) + 1]; \ - X15 += ks[r + (R) + 15] + r + (R); \ - /* rotate key schedule */ \ - ks[r + (R) + 16] = ks[r + (R) - 1]; \ - ts[r + (R) + 2] = ts[r + (R) - 1]; \ - } while (0) - -#endif -#define R1024_8_ROUNDS(R) \ - do { \ - R1024(00, 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12, \ - 13, 14, 15, R1024_0, 8 * (R) + 1); \ - R1024(00, 09, 02, 13, 06, 11, 04, 15, 10, 07, 12, 03, 14, \ - 05, 08, 01, R1024_1, 8 * (R) + 2); \ - R1024(00, 07, 02, 05, 04, 03, 06, 01, 12, 15, 14, 13, 08, \ - 11, 10, 09, R1024_2, 8 * (R) + 3); \ - R1024(00, 15, 02, 11, 06, 13, 04, 09, 14, 01, 08, 05, 10, \ - 03, 12, 07, R1024_3, 8 * (R) + 4); \ - I1024(2 * (R)); \ - R1024(00, 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12, \ - 13, 14, 15, R1024_4, 8 * (R) + 5); \ - R1024(00, 09, 02, 13, 06, 11, 04, 15, 10, 07, 12, 03, 14, \ - 05, 08, 01, R1024_5, 8 * (R) + 6); \ - R1024(00, 07, 02, 05, 04, 03, 06, 01, 12, 15, 14, 13, 08, \ - 11, 10, 09, R1024_6, 8 * (R) + 7); \ - R1024(00, 15, 02, 11, 06, 13, 04, 09, 14, 01, 08, 05, 10, \ - 03, 12, 07, R1024_7, 8 * (R) + 8); \ - I1024(2 * (R) + 1); \ - } while (0) - -#define R1024_UNROLL_R(NN) \ - ((SKEIN_UNROLL_1024 == 0 && \ - SKEIN_1024_ROUNDS_TOTAL / 8 > (NN)) || \ - (SKEIN_UNROLL_1024 > (NN))) - -#if (SKEIN_UNROLL_1024 > 14) -#error "need more unrolling in Skein_1024_Process_Block" -#endif -#endif - /***************************** SKEIN_256 ******************************/ #if !(SKEIN_USE_ASM & 256) void skein_256_process_block(struct skein_256_ctx *ctx, const u8 *blk_ptr, diff --git a/drivers/staging/skein/skein_block.h b/drivers/staging/skein/skein_block.h index ec1baea25c9e..b3bb3d24273b 100644 --- a/drivers/staging/skein/skein_block.h +++ b/drivers/staging/skein/skein_block.h @@ -14,6 +14,329 @@ #include "skein_base.h" /* get the Skein API definitions */ +#ifndef SKEIN_USE_ASM +#define SKEIN_USE_ASM (0) /* default is all C code (no ASM) */ +#endif + +#ifndef SKEIN_LOOP +#define SKEIN_LOOP 001 /* default: unroll 256 and 512, but not 1024 */ +#endif + +#define BLK_BITS (WCNT * 64) /* some useful definitions for code here */ +#define KW_TWK_BASE (0) +#define KW_KEY_BASE (3) +#define ks (kw + KW_KEY_BASE) +#define ts (kw + KW_TWK_BASE) + +#ifdef SKEIN_DEBUG +#define debug_save_tweak(ctx) \ +{ \ + ctx->h.tweak[0] = ts[0]; \ + ctx->h.tweak[1] = ts[1]; \ +} +#else +#define debug_save_tweak(ctx) +#endif + +#if !(SKEIN_USE_ASM & 256) +#undef RCNT +#define RCNT (SKEIN_256_ROUNDS_TOTAL / 8) +#ifdef SKEIN_LOOP /* configure how much to unroll the loop */ +#define SKEIN_UNROLL_256 (((SKEIN_LOOP) / 100) % 10) +#else +#define SKEIN_UNROLL_256 (0) +#endif + +#if SKEIN_UNROLL_256 +#if (RCNT % SKEIN_UNROLL_256) +#error "Invalid SKEIN_UNROLL_256" /* sanity check on unroll count */ +#endif +#endif +#define ROUND256(p0, p1, p2, p3, ROT, r_num) \ + do { \ + X##p0 += X##p1; \ + X##p1 = rol64(X##p1, ROT##_0); \ + X##p1 ^= X##p0; \ + X##p2 += X##p3; \ + X##p3 = rol64(X##p3, ROT##_1); \ + X##p3 ^= X##p2; \ + } while (0) + +#if SKEIN_UNROLL_256 == 0 +#define R256(p0, p1, p2, p3, ROT, r_num) /* fully unrolled */ \ + ROUND256(p0, p1, p2, p3, ROT, r_num) + +#define I256(R) \ + do { \ + /* inject the key schedule value */ \ + X0 += ks[((R) + 1) % 5]; \ + X1 += ks[((R) + 2) % 5] + ts[((R) + 1) % 3]; \ + X2 += ks[((R) + 3) % 5] + ts[((R) + 2) % 3]; \ + X3 += ks[((R) + 4) % 5] + (R) + 1; \ + } while (0) +#else +/* looping version */ +#define R256(p0, p1, p2, p3, ROT, r_num) ROUND256(p0, p1, p2, p3, ROT, r_num) + +#define I256(R) \ + do { \ + /* inject the key schedule value */ \ + X0 += ks[r + (R) + 0]; \ + X1 += ks[r + (R) + 1] + ts[r + (R) + 0];\ + X2 += ks[r + (R) + 2] + ts[r + (R) + 1];\ + X3 += ks[r + (R) + 3] + r + (R); \ + /* rotate key schedule */ \ + ks[r + (R) + 4] = ks[r + (R) - 1]; \ + ts[r + (R) + 2] = ts[r + (R) - 1]; \ + } while (0) +#endif +#define R256_8_ROUNDS(R) \ + do { \ + R256(0, 1, 2, 3, R_256_0, 8 * (R) + 1); \ + R256(0, 3, 2, 1, R_256_1, 8 * (R) + 2); \ + R256(0, 1, 2, 3, R_256_2, 8 * (R) + 3); \ + R256(0, 3, 2, 1, R_256_3, 8 * (R) + 4); \ + I256(2 * (R)); \ + R256(0, 1, 2, 3, R_256_4, 8 * (R) + 5); \ + R256(0, 3, 2, 1, R_256_5, 8 * (R) + 6); \ + R256(0, 1, 2, 3, R_256_6, 8 * (R) + 7); \ + R256(0, 3, 2, 1, R_256_7, 8 * (R) + 8); \ + I256(2 * (R) + 1); \ + } while (0) + +#define R256_UNROLL_R(NN) \ + ((SKEIN_UNROLL_256 == 0 && \ + SKEIN_256_ROUNDS_TOTAL / 8 > (NN)) || \ + (SKEIN_UNROLL_256 > (NN))) + +#if (SKEIN_UNROLL_256 > 14) +#error "need more unrolling in skein_256_process_block" +#endif +#endif + +#if !(SKEIN_USE_ASM & 512) +#undef RCNT +#define RCNT (SKEIN_512_ROUNDS_TOTAL / 8) + +#ifdef SKEIN_LOOP /* configure how much to unroll the loop */ +#define SKEIN_UNROLL_512 (((SKEIN_LOOP) / 10) % 10) +#else +#define SKEIN_UNROLL_512 (0) +#endif + +#if SKEIN_UNROLL_512 +#if (RCNT % SKEIN_UNROLL_512) +#error "Invalid SKEIN_UNROLL_512" /* sanity check on unroll count */ +#endif +#endif +#define ROUND512(p0, p1, p2, p3, p4, p5, p6, p7, ROT, r_num) \ + do { \ + X##p0 += X##p1; \ + X##p1 = rol64(X##p1, ROT##_0); \ + X##p1 ^= X##p0; \ + X##p2 += X##p3; \ + X##p3 = rol64(X##p3, ROT##_1); \ + X##p3 ^= X##p2; \ + X##p4 += X##p5; \ + X##p5 = rol64(X##p5, ROT##_2); \ + X##p5 ^= X##p4; \ + X##p6 += X##p7; \ + X##p7 = rol64(X##p7, ROT##_3); \ + X##p7 ^= X##p6; \ + } while (0) + +#if SKEIN_UNROLL_512 == 0 +#define R512(p0, p1, p2, p3, p4, p5, p6, p7, ROT, r_num) /* unrolled */ \ + ROUND512(p0, p1, p2, p3, p4, p5, p6, p7, ROT, r_num) + +#define I512(R) \ + do { \ + /* inject the key schedule value */ \ + X0 += ks[((R) + 1) % 9]; \ + X1 += ks[((R) + 2) % 9]; \ + X2 += ks[((R) + 3) % 9]; \ + X3 += ks[((R) + 4) % 9]; \ + X4 += ks[((R) + 5) % 9]; \ + X5 += ks[((R) + 6) % 9] + ts[((R) + 1) % 3]; \ + X6 += ks[((R) + 7) % 9] + ts[((R) + 2) % 3]; \ + X7 += ks[((R) + 8) % 9] + (R) + 1; \ + } while (0) + +#else /* looping version */ +#define R512(p0, p1, p2, p3, p4, p5, p6, p7, ROT, r_num) \ + ROUND512(p0, p1, p2, p3, p4, p5, p6, p7, ROT, r_num) \ + +#define I512(R) \ + do { \ + /* inject the key schedule value */ \ + X0 += ks[r + (R) + 0]; \ + X1 += ks[r + (R) + 1]; \ + X2 += ks[r + (R) + 2]; \ + X3 += ks[r + (R) + 3]; \ + X4 += ks[r + (R) + 4]; \ + X5 += ks[r + (R) + 5] + ts[r + (R) + 0]; \ + X6 += ks[r + (R) + 6] + ts[r + (R) + 1]; \ + X7 += ks[r + (R) + 7] + r + (R); \ + /* rotate key schedule */ \ + ks[r + (R) + 8] = ks[r + (R) - 1]; \ + ts[r + (R) + 2] = ts[r + (R) - 1]; \ + } while (0) +#endif /* end of looped code definitions */ +#define R512_8_ROUNDS(R) /* do 8 full rounds */ \ + do { \ + R512(0, 1, 2, 3, 4, 5, 6, 7, R_512_0, 8 * (R) + 1); \ + R512(2, 1, 4, 7, 6, 5, 0, 3, R_512_1, 8 * (R) + 2); \ + R512(4, 1, 6, 3, 0, 5, 2, 7, R_512_2, 8 * (R) + 3); \ + R512(6, 1, 0, 7, 2, 5, 4, 3, R_512_3, 8 * (R) + 4); \ + I512(2 * (R)); \ + R512(0, 1, 2, 3, 4, 5, 6, 7, R_512_4, 8 * (R) + 5); \ + R512(2, 1, 4, 7, 6, 5, 0, 3, R_512_5, 8 * (R) + 6); \ + R512(4, 1, 6, 3, 0, 5, 2, 7, R_512_6, 8 * (R) + 7); \ + R512(6, 1, 0, 7, 2, 5, 4, 3, R_512_7, 8 * (R) + 8); \ + I512(2 * (R) + 1); /* and key injection */ \ + } while (0) +#define R512_UNROLL_R(NN) \ + ((SKEIN_UNROLL_512 == 0 && \ + SKEIN_512_ROUNDS_TOTAL / 8 > (NN)) || \ + (SKEIN_UNROLL_512 > (NN))) + +#if (SKEIN_UNROLL_512 > 14) +#error "need more unrolling in skein_512_process_block" +#endif +#endif + +#if !(SKEIN_USE_ASM & 1024) +#undef RCNT +#define RCNT (SKEIN_1024_ROUNDS_TOTAL / 8) +#ifdef SKEIN_LOOP /* configure how much to unroll the loop */ +#define SKEIN_UNROLL_1024 ((SKEIN_LOOP) % 10) +#else +#define SKEIN_UNROLL_1024 (0) +#endif + +#if (SKEIN_UNROLL_1024 != 0) +#if (RCNT % SKEIN_UNROLL_1024) +#error "Invalid SKEIN_UNROLL_1024" /* sanity check on unroll count */ +#endif +#endif +#define ROUND1024(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pA, pB, pC, pD, pE, \ + pF, ROT, r_num) \ + do { \ + X##p0 += X##p1; \ + X##p1 = rol64(X##p1, ROT##_0); \ + X##p1 ^= X##p0; \ + X##p2 += X##p3; \ + X##p3 = rol64(X##p3, ROT##_1); \ + X##p3 ^= X##p2; \ + X##p4 += X##p5; \ + X##p5 = rol64(X##p5, ROT##_2); \ + X##p5 ^= X##p4; \ + X##p6 += X##p7; \ + X##p7 = rol64(X##p7, ROT##_3); \ + X##p7 ^= X##p6; \ + X##p8 += X##p9; \ + X##p9 = rol64(X##p9, ROT##_4); \ + X##p9 ^= X##p8; \ + X##pA += X##pB; \ + X##pB = rol64(X##pB, ROT##_5); \ + X##pB ^= X##pA; \ + X##pC += X##pD; \ + X##pD = rol64(X##pD, ROT##_6); \ + X##pD ^= X##pC; \ + X##pE += X##pF; \ + X##pF = rol64(X##pF, ROT##_7); \ + X##pF ^= X##pE; \ + } while (0) + +#if SKEIN_UNROLL_1024 == 0 +#define R1024(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pA, pB, pC, pD, pE, pF, \ + ROT, rn) \ + ROUND1024(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pA, pB, pC, pD, pE, \ + pF, ROT, rn) \ + +#define I1024(R) \ + do { \ + /* inject the key schedule value */ \ + X00 += ks[((R) + 1) % 17]; \ + X01 += ks[((R) + 2) % 17]; \ + X02 += ks[((R) + 3) % 17]; \ + X03 += ks[((R) + 4) % 17]; \ + X04 += ks[((R) + 5) % 17]; \ + X05 += ks[((R) + 6) % 17]; \ + X06 += ks[((R) + 7) % 17]; \ + X07 += ks[((R) + 8) % 17]; \ + X08 += ks[((R) + 9) % 17]; \ + X09 += ks[((R) + 10) % 17]; \ + X10 += ks[((R) + 11) % 17]; \ + X11 += ks[((R) + 12) % 17]; \ + X12 += ks[((R) + 13) % 17]; \ + X13 += ks[((R) + 14) % 17] + ts[((R) + 1) % 3]; \ + X14 += ks[((R) + 15) % 17] + ts[((R) + 2) % 3]; \ + X15 += ks[((R) + 16) % 17] + (R) + 1; \ + } while (0) +#else /* looping version */ +#define R1024(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pA, pB, pC, pD, pE, pF, \ + ROT, rn) \ + ROUND1024(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pA, pB, pC, pD, pE, \ + pF, ROT, rn) \ + +#define I1024(R) \ + do { \ + /* inject the key schedule value */ \ + X00 += ks[r + (R) + 0]; \ + X01 += ks[r + (R) + 1]; \ + X02 += ks[r + (R) + 2]; \ + X03 += ks[r + (R) + 3]; \ + X04 += ks[r + (R) + 4]; \ + X05 += ks[r + (R) + 5]; \ + X06 += ks[r + (R) + 6]; \ + X07 += ks[r + (R) + 7]; \ + X08 += ks[r + (R) + 8]; \ + X09 += ks[r + (R) + 9]; \ + X10 += ks[r + (R) + 10]; \ + X11 += ks[r + (R) + 11]; \ + X12 += ks[r + (R) + 12]; \ + X13 += ks[r + (R) + 13] + ts[r + (R) + 0]; \ + X14 += ks[r + (R) + 14] + ts[r + (R) + 1]; \ + X15 += ks[r + (R) + 15] + r + (R); \ + /* rotate key schedule */ \ + ks[r + (R) + 16] = ks[r + (R) - 1]; \ + ts[r + (R) + 2] = ts[r + (R) - 1]; \ + } while (0) + +#endif +#define R1024_8_ROUNDS(R) \ + do { \ + R1024(00, 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12, \ + 13, 14, 15, R1024_0, 8 * (R) + 1); \ + R1024(00, 09, 02, 13, 06, 11, 04, 15, 10, 07, 12, 03, 14, \ + 05, 08, 01, R1024_1, 8 * (R) + 2); \ + R1024(00, 07, 02, 05, 04, 03, 06, 01, 12, 15, 14, 13, 08, \ + 11, 10, 09, R1024_2, 8 * (R) + 3); \ + R1024(00, 15, 02, 11, 06, 13, 04, 09, 14, 01, 08, 05, 10, \ + 03, 12, 07, R1024_3, 8 * (R) + 4); \ + I1024(2 * (R)); \ + R1024(00, 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12, \ + 13, 14, 15, R1024_4, 8 * (R) + 5); \ + R1024(00, 09, 02, 13, 06, 11, 04, 15, 10, 07, 12, 03, 14, \ + 05, 08, 01, R1024_5, 8 * (R) + 6); \ + R1024(00, 07, 02, 05, 04, 03, 06, 01, 12, 15, 14, 13, 08, \ + 11, 10, 09, R1024_6, 8 * (R) + 7); \ + R1024(00, 15, 02, 11, 06, 13, 04, 09, 14, 01, 08, 05, 10, \ + 03, 12, 07, R1024_7, 8 * (R) + 8); \ + I1024(2 * (R) + 1); \ + } while (0) + +#define R1024_UNROLL_R(NN) \ + ((SKEIN_UNROLL_1024 == 0 && \ + SKEIN_1024_ROUNDS_TOTAL / 8 > (NN)) || \ + (SKEIN_UNROLL_1024 > (NN))) + +#if (SKEIN_UNROLL_1024 > 14) +#error "need more unrolling in Skein_1024_Process_Block" +#endif +#endif + void skein_256_process_block(struct skein_256_ctx *ctx, const u8 *blk_ptr, size_t blk_cnt, size_t byte_cnt_add); void skein_512_process_block(struct skein_512_ctx *ctx, const u8 *blk_ptr, diff --git a/drivers/staging/speakup/spk_ttyio.c b/drivers/staging/speakup/spk_ttyio.c index fe340b07c482..4d7d8f2f66ea 100644 --- a/drivers/staging/speakup/spk_ttyio.c +++ b/drivers/staging/speakup/spk_ttyio.c @@ -7,11 +7,6 @@ #include "spk_types.h" #include "spk_priv.h" -#define DEV_PREFIX_LP "lp" - -static const char * const lp_supported[] = { "acntsa", "bns", "dummy", - "txprt" }; - struct spk_ldisc_data { char buf; struct semaphore sem; @@ -20,6 +15,11 @@ struct spk_ldisc_data { static struct spk_synth *spk_ttyio_synth; static struct tty_struct *speakup_tty; +/* mutex to protect against speakup_tty disappearing from underneath us while + * we are using it. this can happen when the device physically unplugged, + * while in use. it also serialises access to speakup_tty. + */ +static DEFINE_MUTEX(speakup_tty_mutex); static int ser_to_dev(int ser, dev_t *dev_no) { @@ -36,24 +36,8 @@ static int get_dev_to_use(struct spk_synth *synth, dev_t *dev_no) { /* use ser only when dev is not specified */ if (strcmp(synth->dev_name, SYNTH_DEFAULT_DEV) || - synth->ser == SYNTH_DEFAULT_SER) { - /* for /dev/lp* check if synth is supported */ - if (strncmp(synth->dev_name, DEV_PREFIX_LP, - strlen(DEV_PREFIX_LP)) == 0) - if (match_string(lp_supported, ARRAY_SIZE(lp_supported), - synth->name) < 0) { - int i; - - pr_err("speakup: lp* is only supported on:"); - for (i = 0; i < ARRAY_SIZE(lp_supported); i++) - pr_cont(" %s", lp_supported[i]); - pr_cont("\n"); - - return -ENOTSUPP; - } - + synth->ser == SYNTH_DEFAULT_SER) return tty_dev_name_to_number(synth->dev_name, dev_no); - } return ser_to_dev(synth->ser, dev_no); } @@ -81,8 +65,10 @@ static int spk_ttyio_ldisc_open(struct tty_struct *tty) static void spk_ttyio_ldisc_close(struct tty_struct *tty) { + mutex_lock(&speakup_tty_mutex); kfree(speakup_tty->disc_data); speakup_tty = NULL; + mutex_unlock(&speakup_tty_mutex); } static int spk_ttyio_receive_buf2(struct tty_struct *tty, @@ -158,7 +144,7 @@ static int spk_ttyio_initialise_ldisc(struct spk_synth *synth) if (ret) return ret; - tty = tty_open_by_driver(dev, NULL, NULL); + tty = tty_kopen(dev); if (IS_ERR(tty)) return PTR_ERR(tty); @@ -210,9 +196,11 @@ void spk_ttyio_unregister_ldisc(void) static int spk_ttyio_out(struct spk_synth *in_synth, const char ch) { + mutex_lock(&speakup_tty_mutex); if (in_synth->alive && speakup_tty && speakup_tty->ops->write) { int ret = speakup_tty->ops->write(speakup_tty, &ch, 1); + mutex_unlock(&speakup_tty_mutex); if (ret == 0) /* No room */ return 0; @@ -228,17 +216,50 @@ static int spk_ttyio_out(struct spk_synth *in_synth, const char ch) } return 1; } + + mutex_unlock(&speakup_tty_mutex); + return 0; +} + +static int check_tty(struct tty_struct *tty) +{ + if (!tty) { + pr_warn("%s: I/O error, deactivating speakup\n", + spk_ttyio_synth->long_name); + /* No synth any more, so nobody will restart TTYs, and we thus + * need to do it ourselves. Now that there is no synth we can + * let application flood anyway + */ + spk_ttyio_synth->alive = 0; + speakup_start_ttys(); + return 1; + } + return 0; } static void spk_ttyio_send_xchar(char ch) { + mutex_lock(&speakup_tty_mutex); + if (check_tty(speakup_tty)) { + mutex_unlock(&speakup_tty_mutex); + return; + } + speakup_tty->ops->send_xchar(speakup_tty, ch); + mutex_unlock(&speakup_tty_mutex); } static void spk_ttyio_tiocmset(unsigned int set, unsigned int clear) { + mutex_lock(&speakup_tty_mutex); + if (check_tty(speakup_tty)) { + mutex_unlock(&speakup_tty_mutex); + return; + } + speakup_tty->ops->tiocmset(speakup_tty, set, clear); + mutex_unlock(&speakup_tty_mutex); } static unsigned char ttyio_in(int timeout) @@ -278,8 +299,16 @@ static unsigned char spk_ttyio_in_nowait(void) static void spk_ttyio_flush_buffer(void) { + mutex_lock(&speakup_tty_mutex); + if (check_tty(speakup_tty)) { + mutex_unlock(&speakup_tty_mutex); + return; + } + if (speakup_tty->ops->flush_buffer) speakup_tty->ops->flush_buffer(speakup_tty); + + mutex_unlock(&speakup_tty_mutex); } int spk_ttyio_synth_probe(struct spk_synth *synth) @@ -308,7 +337,7 @@ void spk_ttyio_release(void) tty_ldisc_flush(speakup_tty); tty_unlock(speakup_tty); - tty_release_struct(speakup_tty, speakup_tty->index); + tty_kclose(speakup_tty); } EXPORT_SYMBOL_GPL(spk_ttyio_release); diff --git a/drivers/staging/typec/fusb302/Kconfig b/drivers/staging/typec/fusb302/Kconfig index fce099ff39fe..48a4f2fcee03 100644 --- a/drivers/staging/typec/fusb302/Kconfig +++ b/drivers/staging/typec/fusb302/Kconfig @@ -1,6 +1,6 @@ config TYPEC_FUSB302 tristate "Fairchild FUSB302 Type-C chip driver" - depends on I2C + depends on I2C && POWER_SUPPLY help The Fairchild FUSB302 Type-C chip driver that works with Type-C Port Controller Manager to provide USB PD and USB diff --git a/drivers/staging/typec/fusb302/TODO b/drivers/staging/typec/fusb302/TODO index 4933a1d92c32..19b466eb585d 100644 --- a/drivers/staging/typec/fusb302/TODO +++ b/drivers/staging/typec/fusb302/TODO @@ -4,3 +4,7 @@ fusb302: - Find a non-hacky way to coordinate between PM and I2C access - Documentation? The FUSB302 datasheet provides information on the chip to help understand the code. But it may still be helpful to have a documentation. +- We may want to replace the "fcs,max-snk-microvolt", "fcs,max-snk-microamp", + "fcs,max-snk-microwatt" and "fcs,operating-snk-microwatt" device(tree) + properties with properties which are part of a generic type-c controller + devicetree binding. diff --git a/drivers/staging/typec/fusb302/fusb302.c b/drivers/staging/typec/fusb302/fusb302.c index 03a3809d18f0..fc6a3cf74eb3 100644 --- a/drivers/staging/typec/fusb302/fusb302.c +++ b/drivers/staging/typec/fusb302/fusb302.c @@ -17,6 +17,7 @@ #include <linux/debugfs.h> #include <linux/delay.h> #include <linux/errno.h> +#include <linux/extcon.h> #include <linux/gpio.h> #include <linux/i2c.h> #include <linux/interrupt.h> @@ -27,6 +28,7 @@ #include <linux/of_device.h> #include <linux/of_gpio.h> #include <linux/pinctrl/consumer.h> +#include <linux/power_supply.h> #include <linux/proc_fs.h> #include <linux/regulator/consumer.h> #include <linux/sched/clock.h> @@ -90,11 +92,13 @@ struct fusb302_chip { struct i2c_client *i2c_client; struct tcpm_port *tcpm_port; struct tcpc_dev tcpc_dev; + struct tcpc_config tcpc_config; struct regulator *vbus; int gpio_int_n; int gpio_int_n_irq; + struct extcon_dev *extcon; struct workqueue_struct *wq; struct delayed_work bc_lvl_handler; @@ -105,6 +109,11 @@ struct fusb302_chip { /* lock for sharing chip states */ struct mutex lock; + /* psy + psy status */ + struct power_supply *psy; + u32 current_limit; + u32 supply_voltage; + /* chip status */ enum toggling_mode toggling_mode; enum src_current_status src_current_status; @@ -515,6 +524,38 @@ static int tcpm_get_vbus(struct tcpc_dev *dev) return ret; } +static int tcpm_get_current_limit(struct tcpc_dev *dev) +{ + struct fusb302_chip *chip = container_of(dev, struct fusb302_chip, + tcpc_dev); + int current_limit = 0; + unsigned long timeout; + + if (!chip->extcon) + return 0; + + /* + * USB2 Charger detection may still be in progress when we get here, + * this can take upto 600ms, wait 800ms max. + */ + timeout = jiffies + msecs_to_jiffies(800); + do { + if (extcon_get_state(chip->extcon, EXTCON_CHG_USB_SDP) == 1) + current_limit = 500; + + if (extcon_get_state(chip->extcon, EXTCON_CHG_USB_CDP) == 1 || + extcon_get_state(chip->extcon, EXTCON_CHG_USB_ACA) == 1) + current_limit = 1500; + + if (extcon_get_state(chip->extcon, EXTCON_CHG_USB_DCP) == 1) + current_limit = 2000; + + msleep(50); + } while (current_limit == 0 && time_before(jiffies, timeout)); + + return current_limit; +} + static int fusb302_set_cc_pull(struct fusb302_chip *chip, bool pull_up, bool pull_down) { @@ -841,11 +882,13 @@ static int tcpm_set_vbus(struct tcpc_dev *dev, bool on, bool charge) chip->vbus_on = on; fusb302_log(chip, "vbus := %s", on ? "On" : "Off"); } - if (chip->charge_on == charge) + if (chip->charge_on == charge) { fusb302_log(chip, "charge is already %s", charge ? "On" : "Off"); - else + } else { chip->charge_on = charge; + power_supply_changed(chip->psy); + } done: mutex_unlock(&chip->lock); @@ -861,6 +904,11 @@ static int tcpm_set_current_limit(struct tcpc_dev *dev, u32 max_ma, u32 mv) fusb302_log(chip, "current limit: %d ma, %d mv (not implemented)", max_ma, mv); + chip->supply_voltage = mv; + chip->current_limit = max_ma; + + power_supply_changed(chip->psy); + return 0; } @@ -1187,9 +1235,9 @@ static const struct tcpc_config fusb302_tcpc_config = { .nr_src_pdo = ARRAY_SIZE(src_pdo), .snk_pdo = snk_pdo, .nr_snk_pdo = ARRAY_SIZE(snk_pdo), - .max_snk_mv = 9000, + .max_snk_mv = 5000, .max_snk_ma = 3000, - .max_snk_mw = 27000, + .max_snk_mw = 15000, .operating_snk_mw = 2500, .type = TYPEC_PORT_DRP, .default_role = TYPEC_SINK, @@ -1198,9 +1246,9 @@ static const struct tcpc_config fusb302_tcpc_config = { static void init_tcpc_dev(struct tcpc_dev *fusb302_tcpc_dev) { - fusb302_tcpc_dev->config = &fusb302_tcpc_config; fusb302_tcpc_dev->init = tcpm_init; fusb302_tcpc_dev->get_vbus = tcpm_get_vbus; + fusb302_tcpc_dev->get_current_limit = tcpm_get_current_limit; fusb302_tcpc_dev->set_cc = tcpm_set_cc; fusb302_tcpc_dev->get_cc = tcpm_get_cc; fusb302_tcpc_dev->set_polarity = tcpm_set_polarity; @@ -1646,6 +1694,43 @@ done: return IRQ_HANDLED; } +static int fusb302_psy_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct fusb302_chip *chip = power_supply_get_drvdata(psy); + + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + val->intval = chip->charge_on; + break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + val->intval = chip->supply_voltage * 1000; /* mV -> µV */ + break; + case POWER_SUPPLY_PROP_CURRENT_MAX: + val->intval = chip->current_limit * 1000; /* mA -> µA */ + break; + default: + return -ENODATA; + } + + return 0; +} + +static enum power_supply_property fusb302_psy_properties[] = { + POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_CURRENT_MAX, +}; + +static const struct power_supply_desc fusb302_psy_desc = { + .name = "fusb302-typec-source", + .type = POWER_SUPPLY_TYPE_USB_TYPE_C, + .properties = fusb302_psy_properties, + .num_properties = ARRAY_SIZE(fusb302_psy_properties), + .get_property = fusb302_psy_get_property, +}; + static int init_gpio(struct fusb302_chip *chip) { struct device_node *node; @@ -1684,7 +1769,11 @@ static int fusb302_probe(struct i2c_client *client, { struct fusb302_chip *chip; struct i2c_adapter *adapter; + struct device *dev = &client->dev; + struct power_supply_config cfg = {}; + const char *name; int ret = 0; + u32 v; adapter = to_i2c_adapter(client->dev.parent); if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) { @@ -1699,8 +1788,43 @@ static int fusb302_probe(struct i2c_client *client, chip->i2c_client = client; i2c_set_clientdata(client, chip); chip->dev = &client->dev; + chip->tcpc_config = fusb302_tcpc_config; + chip->tcpc_dev.config = &chip->tcpc_config; mutex_init(&chip->lock); + if (!device_property_read_u32(dev, "fcs,max-sink-microvolt", &v)) + chip->tcpc_config.max_snk_mv = v / 1000; + + if (!device_property_read_u32(dev, "fcs,max-sink-microamp", &v)) + chip->tcpc_config.max_snk_ma = v / 1000; + + if (!device_property_read_u32(dev, "fcs,max-sink-microwatt", &v)) + chip->tcpc_config.max_snk_mw = v / 1000; + + if (!device_property_read_u32(dev, "fcs,operating-sink-microwatt", &v)) + chip->tcpc_config.operating_snk_mw = v / 1000; + + /* + * Devicetree platforms should get extcon via phandle (not yet + * supported). On ACPI platforms, we get the name from a device prop. + * This device prop is for kernel internal use only and is expected + * to be set by the platform code which also registers the i2c client + * for the fusb302. + */ + if (device_property_read_string(dev, "fcs,extcon-name", &name) == 0) { + chip->extcon = extcon_get_extcon_dev(name); + if (!chip->extcon) + return -EPROBE_DEFER; + } + + cfg.drv_data = chip; + chip->psy = devm_power_supply_register(dev, &fusb302_psy_desc, &cfg); + if (IS_ERR(chip->psy)) { + ret = PTR_ERR(chip->psy); + dev_err(chip->dev, "Error registering power-supply: %d\n", ret); + return ret; + } + ret = fusb302_debugfs_init(chip); if (ret < 0) return ret; @@ -1719,9 +1843,13 @@ static int fusb302_probe(struct i2c_client *client, goto destroy_workqueue; } - ret = init_gpio(chip); - if (ret < 0) - goto destroy_workqueue; + if (client->irq) { + chip->gpio_int_n_irq = client->irq; + } else { + ret = init_gpio(chip); + if (ret < 0) + goto destroy_workqueue; + } chip->tcpm_port = tcpm_register_port(&client->dev, &chip->tcpc_dev); if (IS_ERR(chip->tcpm_port)) { diff --git a/drivers/staging/typec/pd.h b/drivers/staging/typec/pd.h index 510ef7279900..30b32ad72acd 100644 --- a/drivers/staging/typec/pd.h +++ b/drivers/staging/typec/pd.h @@ -278,6 +278,8 @@ static inline unsigned int rdo_max_power(u32 rdo) #define PD_T_VCONN_SOURCE_ON 100 #define PD_T_SINK_REQUEST 100 /* 100 ms minimum */ #define PD_T_ERROR_RECOVERY 100 /* minimum 25 is insufficient */ +#define PD_T_SRCSWAPSTDBY 625 /* Maximum of 650ms */ +#define PD_T_NEWSRC 250 /* Maximum of 275ms */ #define PD_T_DRP_TRY 100 /* 75 - 150 ms */ #define PD_T_DRP_TRYWAIT 600 /* 400 - 800 ms */ diff --git a/drivers/staging/typec/tcpm.c b/drivers/staging/typec/tcpm.c index 20eb4ebcf8c3..8af62e74d54c 100644 --- a/drivers/staging/typec/tcpm.c +++ b/drivers/staging/typec/tcpm.c @@ -17,6 +17,7 @@ #include <linux/completion.h> #include <linux/debugfs.h> #include <linux/device.h> +#include <linux/jiffies.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/mutex.h> @@ -89,9 +90,11 @@ S(PR_SWAP_START), \ S(PR_SWAP_SRC_SNK_TRANSITION_OFF), \ S(PR_SWAP_SRC_SNK_SOURCE_OFF), \ + S(PR_SWAP_SRC_SNK_SOURCE_OFF_CC_DEBOUNCED), \ S(PR_SWAP_SRC_SNK_SINK_ON), \ S(PR_SWAP_SNK_SRC_SINK_OFF), \ S(PR_SWAP_SNK_SRC_SOURCE_ON), \ + S(PR_SWAP_SNK_SRC_SOURCE_ON_VBUS_RAMPED_UP), \ \ S(VCONN_SWAP_ACCEPT), \ S(VCONN_SWAP_SEND), \ @@ -104,10 +107,14 @@ \ S(SNK_TRY), \ S(SNK_TRY_WAIT), \ + S(SNK_TRY_WAIT_DEBOUNCE), \ + S(SNK_TRY_WAIT_DEBOUNCE_CHECK_VBUS), \ S(SRC_TRYWAIT), \ + S(SRC_TRYWAIT_DEBOUNCE), \ S(SRC_TRYWAIT_UNATTACHED), \ \ S(SRC_TRY), \ + S(SRC_TRY_WAIT), \ S(SRC_TRY_DEBOUNCE), \ S(SNK_TRYWAIT), \ S(SNK_TRYWAIT_DEBOUNCE), \ @@ -115,7 +122,8 @@ S(BIST_RX), \ \ S(ERROR_RECOVERY), \ - S(ERROR_RECOVERY_WAIT_OFF) + S(PORT_RESET), \ + S(PORT_RESET_WAIT_OFF) #define GENERATE_ENUM(e) e #define GENERATE_STRING(s) #s @@ -196,6 +204,7 @@ struct tcpm_port { bool attached; bool connected; + enum typec_port_type port_type; bool vbus_present; bool vbus_never_low; bool vbus_source; @@ -230,6 +239,7 @@ struct tcpm_port { struct mutex swap_lock; /* swap command lock */ bool swap_pending; + bool non_pd_role_swap; struct completion swap_complete; int swap_status; @@ -281,6 +291,9 @@ struct tcpm_port { struct typec_altmode *partner_altmode[SVID_DISCOVERY_MAX]; struct typec_altmode *port_altmode[SVID_DISCOVERY_MAX]; + /* Deadline in jiffies to exit src_try_wait state */ + unsigned long max_wait; + #ifdef CONFIG_DEBUG_FS struct dentry *dentry; struct mutex logbuffer_lock; /* log buffer access lock */ @@ -325,19 +338,26 @@ struct pd_rx_event { (tcpm_cc_is_audio((port)->cc2) && tcpm_cc_is_open((port)->cc1))) #define tcpm_try_snk(port) \ - ((port)->try_snk_count == 0 && (port)->try_role == TYPEC_SINK) + ((port)->try_snk_count == 0 && (port)->try_role == TYPEC_SINK && \ + (port)->port_type == TYPEC_PORT_DRP) #define tcpm_try_src(port) \ - ((port)->try_src_count == 0 && (port)->try_role == TYPEC_SOURCE) + ((port)->try_src_count == 0 && (port)->try_role == TYPEC_SOURCE && \ + (port)->port_type == TYPEC_PORT_DRP) static enum tcpm_state tcpm_default_state(struct tcpm_port *port) { - if (port->try_role == TYPEC_SINK) - return SNK_UNATTACHED; - else if (port->try_role == TYPEC_SOURCE) - return SRC_UNATTACHED; - else if (port->tcpc->config->default_role == TYPEC_SINK) + if (port->port_type == TYPEC_PORT_DRP) { + if (port->try_role == TYPEC_SINK) + return SNK_UNATTACHED; + else if (port->try_role == TYPEC_SOURCE) + return SRC_UNATTACHED; + else if (port->tcpc->config->default_role == TYPEC_SINK) + return SNK_UNATTACHED; + /* Fall through to return SRC_UNATTACHED */ + } else if (port->port_type == TYPEC_PORT_UFP) { return SNK_UNATTACHED; + } return SRC_UNATTACHED; } @@ -369,6 +389,7 @@ static bool tcpm_log_full(struct tcpm_port *port) (port->logbuffer_head + 1) % LOG_BUFFER_ENTRIES; } +__printf(2, 0) static void _tcpm_log(struct tcpm_port *port, const char *fmt, va_list args) { char tmpbuffer[LOG_BUFFER_ENTRY_SIZE]; @@ -415,6 +436,7 @@ abort: mutex_unlock(&port->logbuffer_lock); } +__printf(2, 3) static void tcpm_log(struct tcpm_port *port, const char *fmt, ...) { va_list args; @@ -430,6 +452,7 @@ static void tcpm_log(struct tcpm_port *port, const char *fmt, ...) va_end(args); } +__printf(2, 3) static void tcpm_log_force(struct tcpm_port *port, const char *fmt, ...) { va_list args; @@ -546,7 +569,9 @@ static void tcpm_debugfs_exit(struct tcpm_port *port) #else +__printf(2, 3) static void tcpm_log(const struct tcpm_port *port, const char *fmt, ...) { } +__printf(2, 3) static void tcpm_log_force(struct tcpm_port *port, const char *fmt, ...) { } static void tcpm_log_source_caps(struct tcpm_port *port) { } static int tcpm_debugfs_init(const struct tcpm_port *port) { return 0; } @@ -660,7 +685,10 @@ static u32 tcpm_get_current_limit(struct tcpm_port *port) break; case TYPEC_CC_RP_DEF: default: - limit = 0; + if (port->tcpc->get_current_limit) + limit = port->tcpc->get_current_limit(port->tcpc); + else + limit = 0; break; } @@ -1015,8 +1043,7 @@ static int tcpm_pd_svdm(struct tcpm_port *port, const __le32 *payload, int cnt, if (port->data_role == TYPEC_DEVICE && port->nr_snk_vdo) { for (i = 0; i < port->nr_snk_vdo; i++) - response[i + 1] - = cpu_to_le32(port->snk_vdo[i]); + response[i + 1] = port->snk_vdo[i]; rlen = port->nr_snk_vdo + 1; } break; @@ -1367,6 +1394,7 @@ static void tcpm_pd_ctrl_request(struct tcpm_port *port, tcpm_set_current_limit(port, port->current_limit, port->supply_voltage); + port->explicit_contract = true; tcpm_set_state(port, SNK_READY, 0); } else { /* @@ -1377,7 +1405,7 @@ static void tcpm_pd_ctrl_request(struct tcpm_port *port, SNK_TRANSITION_SINK_VBUS, 0); } break; - case PR_SWAP_SRC_SNK_SOURCE_OFF: + case PR_SWAP_SRC_SNK_SOURCE_OFF_CC_DEBOUNCED: tcpm_set_state(port, PR_SWAP_SRC_SNK_SINK_ON, 0); break; case PR_SWAP_SNK_SRC_SINK_OFF: @@ -1451,7 +1479,7 @@ static void tcpm_pd_ctrl_request(struct tcpm_port *port, tcpm_set_state(port, SOFT_RESET, 0); break; case PD_CTRL_DR_SWAP: - if (port->typec_caps.type != TYPEC_PORT_DRP) { + if (port->port_type != TYPEC_PORT_DRP) { tcpm_queue_message(port, PD_MSG_CTRL_REJECT); break; } @@ -1471,7 +1499,7 @@ static void tcpm_pd_ctrl_request(struct tcpm_port *port, } break; case PD_CTRL_PR_SWAP: - if (port->typec_caps.type != TYPEC_PORT_DRP) { + if (port->port_type != TYPEC_PORT_DRP) { tcpm_queue_message(port, PD_MSG_CTRL_REJECT); break; } @@ -1846,7 +1874,7 @@ static bool tcpm_start_drp_toggling(struct tcpm_port *port) int ret; if (port->tcpc->start_drp_toggling && - port->typec_caps.type == TYPEC_PORT_DRP) { + port->port_type == TYPEC_PORT_DRP) { tcpm_log_force(port, "Start DRP toggling"); ret = port->tcpc->start_drp_toggling(port->tcpc, tcpm_rp_cc(port)); @@ -2099,10 +2127,16 @@ static inline enum tcpm_state ready_state(struct tcpm_port *port) static inline enum tcpm_state unattached_state(struct tcpm_port *port) { - if (port->pwr_role == TYPEC_SOURCE) + if (port->port_type == TYPEC_PORT_DRP) { + if (port->pwr_role == TYPEC_SOURCE) + return SRC_UNATTACHED; + else + return SNK_UNATTACHED; + } else if (port->port_type == TYPEC_PORT_DFP) { return SRC_UNATTACHED; - else - return SNK_UNATTACHED; + } + + return SNK_UNATTACHED; } static void tcpm_check_send_discover(struct tcpm_port *port) @@ -2119,13 +2153,29 @@ static void tcpm_swap_complete(struct tcpm_port *port, int result) if (port->swap_pending) { port->swap_status = result; port->swap_pending = false; + port->non_pd_role_swap = false; complete(&port->swap_complete); } } +static enum typec_pwr_opmode tcpm_get_pwr_opmode(enum typec_cc_status cc) +{ + switch (cc) { + case TYPEC_CC_RP_1_5: + return TYPEC_PWR_MODE_1_5A; + case TYPEC_CC_RP_3_0: + return TYPEC_PWR_MODE_3_0A; + case TYPEC_CC_RP_DEF: + default: + return TYPEC_PWR_MODE_USB; + } +} + static void run_state_machine(struct tcpm_port *port) { int ret; + enum typec_pwr_opmode opmode; + unsigned int msecs; port->enter_state = port->state; switch (port->state) { @@ -2133,14 +2183,15 @@ static void run_state_machine(struct tcpm_port *port) break; /* SRC states */ case SRC_UNATTACHED: - tcpm_swap_complete(port, -ENOTCONN); + if (!port->non_pd_role_swap) + tcpm_swap_complete(port, -ENOTCONN); tcpm_src_detach(port); if (tcpm_start_drp_toggling(port)) { tcpm_set_state(port, DRP_TOGGLING, 0); break; } tcpm_set_cc(port, tcpm_rp_cc(port)); - if (port->typec_caps.type == TYPEC_PORT_DRP) + if (port->port_type == TYPEC_PORT_DRP) tcpm_set_state(port, SNK_UNATTACHED, PD_T_DRP_SNK); break; case SRC_ATTACH_WAIT: @@ -2171,25 +2222,43 @@ static void run_state_machine(struct tcpm_port *port) tcpm_set_state(port, SNK_TRY_WAIT, PD_T_DRP_TRY); break; case SNK_TRY_WAIT: + if (tcpm_port_is_sink(port)) { + tcpm_set_state(port, SNK_TRY_WAIT_DEBOUNCE, 0); + } else { + tcpm_set_state(port, SRC_TRYWAIT, 0); + port->max_wait = 0; + } + break; + case SNK_TRY_WAIT_DEBOUNCE: + tcpm_set_state(port, SNK_TRY_WAIT_DEBOUNCE_CHECK_VBUS, + PD_T_PD_DEBOUNCE); + break; + case SNK_TRY_WAIT_DEBOUNCE_CHECK_VBUS: if (port->vbus_present && tcpm_port_is_sink(port)) { tcpm_set_state(port, SNK_ATTACHED, 0); - break; - } - if (!tcpm_port_is_sink(port)) { - tcpm_set_state(port, SRC_TRYWAIT, - PD_T_PD_DEBOUNCE); - break; + } else { + tcpm_set_state(port, SRC_TRYWAIT, 0); + port->max_wait = 0; } - /* No vbus, cc state is sink or open */ - tcpm_set_state(port, SRC_TRYWAIT_UNATTACHED, PD_T_DRP_TRYWAIT); break; case SRC_TRYWAIT: tcpm_set_cc(port, tcpm_rp_cc(port)); - if (!port->vbus_present && tcpm_port_is_source(port)) - tcpm_set_state(port, SRC_ATTACHED, PD_T_CC_DEBOUNCE); - else + if (port->max_wait == 0) { + port->max_wait = jiffies + + msecs_to_jiffies(PD_T_DRP_TRY); tcpm_set_state(port, SRC_TRYWAIT_UNATTACHED, PD_T_DRP_TRY); + } else { + if (time_is_after_jiffies(port->max_wait)) + tcpm_set_state(port, SRC_TRYWAIT_UNATTACHED, + jiffies_to_msecs(port->max_wait - + jiffies)); + else + tcpm_set_state(port, SNK_UNATTACHED, 0); + } + break; + case SRC_TRYWAIT_DEBOUNCE: + tcpm_set_state(port, SRC_ATTACHED, PD_T_CC_DEBOUNCE); break; case SRC_TRYWAIT_UNATTACHED: tcpm_set_state(port, SNK_UNATTACHED, 0); @@ -2201,7 +2270,8 @@ static void run_state_machine(struct tcpm_port *port) ret < 0 ? 0 : PD_T_PS_SOURCE_ON); break; case SRC_STARTUP: - typec_set_pwr_opmode(port->typec_port, TYPEC_PWR_MODE_USB); + opmode = tcpm_get_pwr_opmode(tcpm_rp_cc(port)); + typec_set_pwr_opmode(port->typec_port, opmode); port->pwr_opmode = TYPEC_PWR_MODE_USB; port->caps_count = 0; port->message_id = 0; @@ -2262,8 +2332,8 @@ static void run_state_machine(struct tcpm_port *port) #endif port->try_src_count = 0; + tcpm_swap_complete(port, 0); tcpm_typec_connect(port); - tcpm_check_send_discover(port); /* * 6.3.5 @@ -2273,14 +2343,11 @@ static void run_state_machine(struct tcpm_port *port) * - The system is not operating in PD mode * or * - Both partners are connected using a Type-C connector - * XXX How do we know that ? + * + * There is no actual need to send PD messages since the local + * port type-c and the spec does not clearly say whether PD is + * possible when type-c is connected to Type-A/B */ - if (port->pwr_opmode == TYPEC_PWR_MODE_PD && - !port->op_vsafe5v) { - tcpm_pd_send_control(port, PD_CTRL_PING); - tcpm_set_state_cond(port, SRC_READY, - PD_T_SOURCE_ACTIVITY); - } break; case SRC_WAIT_NEW_CAPABILITIES: /* Nothing to do... */ @@ -2288,14 +2355,15 @@ static void run_state_machine(struct tcpm_port *port) /* SNK states */ case SNK_UNATTACHED: - tcpm_swap_complete(port, -ENOTCONN); + if (!port->non_pd_role_swap) + tcpm_swap_complete(port, -ENOTCONN); tcpm_snk_detach(port); if (tcpm_start_drp_toggling(port)) { tcpm_set_state(port, DRP_TOGGLING, 0); break; } tcpm_set_cc(port, TYPEC_CC_RD); - if (port->typec_caps.type == TYPEC_PORT_DRP) + if (port->port_type == TYPEC_PORT_DRP) tcpm_set_state(port, SRC_UNATTACHED, PD_T_DRP_SRC); break; case SNK_ATTACH_WAIT: @@ -2320,39 +2388,52 @@ static void run_state_machine(struct tcpm_port *port) 0); else /* Wait for VBUS, but not forever */ - tcpm_set_state(port, SNK_UNATTACHED, PD_T_PS_SOURCE_ON); + tcpm_set_state(port, PORT_RESET, PD_T_PS_SOURCE_ON); break; case SRC_TRY: port->try_src_count++; tcpm_set_cc(port, tcpm_rp_cc(port)); - tcpm_set_state(port, SNK_TRYWAIT, PD_T_DRP_TRY); + port->max_wait = 0; + tcpm_set_state(port, SRC_TRY_WAIT, 0); + break; + case SRC_TRY_WAIT: + if (port->max_wait == 0) { + port->max_wait = jiffies + + msecs_to_jiffies(PD_T_DRP_TRY); + msecs = PD_T_DRP_TRY; + } else { + if (time_is_after_jiffies(port->max_wait)) + msecs = jiffies_to_msecs(port->max_wait - + jiffies); + else + msecs = 0; + } + tcpm_set_state(port, SNK_TRYWAIT, msecs); break; case SRC_TRY_DEBOUNCE: tcpm_set_state(port, SRC_ATTACHED, PD_T_PD_DEBOUNCE); break; case SNK_TRYWAIT: tcpm_set_cc(port, TYPEC_CC_RD); - tcpm_set_state(port, SNK_TRYWAIT_DEBOUNCE, PD_T_CC_DEBOUNCE); + tcpm_set_state(port, SNK_TRYWAIT_VBUS, PD_T_CC_DEBOUNCE); break; - case SNK_TRYWAIT_DEBOUNCE: - if (port->vbus_present) { + case SNK_TRYWAIT_VBUS: + /* + * TCPM stays in this state indefinitely until VBUS + * is detected as long as Rp is not detected for + * more than a time period of tPDDebounce. + */ + if (port->vbus_present && tcpm_port_is_sink(port)) { tcpm_set_state(port, SNK_ATTACHED, 0); break; } - if (tcpm_port_is_disconnected(port)) { - tcpm_set_state(port, SNK_UNATTACHED, - PD_T_PD_DEBOUNCE); - break; - } - if (tcpm_port_is_source(port)) - tcpm_set_state(port, SRC_ATTACHED, 0); - /* XXX Are we supposed to stay in this state ? */ + if (!tcpm_port_is_sink(port)) + tcpm_set_state(port, SNK_TRYWAIT_DEBOUNCE, 0); break; - case SNK_TRYWAIT_VBUS: - tcpm_set_state(port, SNK_ATTACHED, PD_T_CC_DEBOUNCE); + case SNK_TRYWAIT_DEBOUNCE: + tcpm_set_state(port, SNK_UNATTACHED, PD_T_PD_DEBOUNCE); break; - case SNK_ATTACHED: ret = tcpm_snk_attach(port); if (ret < 0) @@ -2362,7 +2443,9 @@ static void run_state_machine(struct tcpm_port *port) break; case SNK_STARTUP: /* XXX: callback into infrastructure */ - typec_set_pwr_opmode(port->typec_port, TYPEC_PWR_MODE_USB); + opmode = tcpm_get_pwr_opmode(port->polarity ? + port->cc2 : port->cc1); + typec_set_pwr_opmode(port->typec_port, opmode); port->pwr_opmode = TYPEC_PWR_MODE_USB; port->message_id = 0; port->rx_msgid = -1; @@ -2384,7 +2467,7 @@ static void run_state_machine(struct tcpm_port *port) * see USB power delivery specification, section 8.3.3.6.1.5.1). */ tcpm_set_state(port, hard_reset_state(port), - port->typec_caps.type == TYPEC_PORT_DRP ? + port->port_type == TYPEC_PORT_DRP ? PD_T_DB_DETECT : PD_T_NO_RESPONSE); break; case SNK_DISCOVERY_DEBOUNCE: @@ -2441,12 +2524,14 @@ static void run_state_machine(struct tcpm_port *port) break; case SNK_READY: port->try_snk_count = 0; - port->explicit_contract = true; - typec_set_pwr_opmode(port->typec_port, TYPEC_PWR_MODE_PD); - port->pwr_opmode = TYPEC_PWR_MODE_PD; + if (port->explicit_contract) { + typec_set_pwr_opmode(port->typec_port, + TYPEC_PWR_MODE_PD); + port->pwr_opmode = TYPEC_PWR_MODE_PD; + } + tcpm_swap_complete(port, 0); tcpm_typec_connect(port); - tcpm_check_send_discover(port); break; @@ -2574,7 +2659,6 @@ static void run_state_machine(struct tcpm_port *port) TYPEC_HOST); port->send_discover = true; } - tcpm_swap_complete(port, 0); tcpm_set_state(port, ready_state(port), 0); break; @@ -2602,11 +2686,17 @@ static void run_state_machine(struct tcpm_port *port) case PR_SWAP_SRC_SNK_TRANSITION_OFF: tcpm_set_vbus(port, false); port->explicit_contract = false; + /* allow time for Vbus discharge, must be < tSrcSwapStdby */ tcpm_set_state(port, PR_SWAP_SRC_SNK_SOURCE_OFF, - PD_T_PS_SOURCE_OFF); + PD_T_SRCSWAPSTDBY); break; case PR_SWAP_SRC_SNK_SOURCE_OFF: tcpm_set_cc(port, TYPEC_CC_RD); + /* allow CC debounce */ + tcpm_set_state(port, PR_SWAP_SRC_SNK_SOURCE_OFF_CC_DEBOUNCED, + PD_T_CC_DEBOUNCE); + break; + case PR_SWAP_SRC_SNK_SOURCE_OFF_CC_DEBOUNCED: /* * USB-PD standard, 6.2.1.4, Port Power Role: * "During the Power Role Swap Sequence, for the initial Source @@ -2622,7 +2712,6 @@ static void run_state_machine(struct tcpm_port *port) tcpm_set_state_cond(port, SNK_UNATTACHED, PD_T_PS_SOURCE_ON); break; case PR_SWAP_SRC_SNK_SINK_ON: - tcpm_swap_complete(port, 0); tcpm_set_state(port, SNK_STARTUP, 0); break; case PR_SWAP_SNK_SRC_SINK_OFF: @@ -2634,6 +2723,15 @@ static void run_state_machine(struct tcpm_port *port) tcpm_set_cc(port, tcpm_rp_cc(port)); tcpm_set_vbus(port, true); /* + * allow time VBUS ramp-up, must be < tNewSrc + * Also, this window overlaps with CC debounce as well. + * So, Wait for the max of two which is PD_T_NEWSRC + */ + tcpm_set_state(port, PR_SWAP_SNK_SRC_SOURCE_ON_VBUS_RAMPED_UP, + PD_T_NEWSRC); + break; + case PR_SWAP_SNK_SRC_SOURCE_ON_VBUS_RAMPED_UP: + /* * USB PD standard, 6.2.1.4: * "Subsequent Messages initiated by the Policy Engine, * such as the PS_RDY Message sent to indicate that Vbus @@ -2642,7 +2740,6 @@ static void run_state_machine(struct tcpm_port *port) */ tcpm_set_pwr_role(port, TYPEC_SOURCE); tcpm_pd_send_control(port, PD_CTRL_PS_RDY); - tcpm_swap_complete(port, 0); tcpm_set_state(port, SRC_STARTUP, 0); break; @@ -2672,12 +2769,10 @@ static void run_state_machine(struct tcpm_port *port) case VCONN_SWAP_TURN_ON_VCONN: tcpm_set_vconn(port, true); tcpm_pd_send_control(port, PD_CTRL_PS_RDY); - tcpm_swap_complete(port, 0); tcpm_set_state(port, ready_state(port), 0); break; case VCONN_SWAP_TURN_OFF_VCONN: tcpm_set_vconn(port, false); - tcpm_swap_complete(port, 0); tcpm_set_state(port, ready_state(port), 0); break; @@ -2704,13 +2799,15 @@ static void run_state_machine(struct tcpm_port *port) break; case ERROR_RECOVERY: tcpm_swap_complete(port, -EPROTO); + tcpm_set_state(port, PORT_RESET, 0); + break; + case PORT_RESET: tcpm_reset_port(port); - tcpm_set_cc(port, TYPEC_CC_OPEN); - tcpm_set_state(port, ERROR_RECOVERY_WAIT_OFF, + tcpm_set_state(port, PORT_RESET_WAIT_OFF, PD_T_ERROR_RECOVERY); break; - case ERROR_RECOVERY_WAIT_OFF: + case PORT_RESET_WAIT_OFF: tcpm_set_state(port, tcpm_default_state(port), port->vbus_present ? PD_T_PS_SOURCE_OFF : 0); @@ -2799,10 +2896,12 @@ static void _tcpm_cc_change(struct tcpm_port *port, enum typec_cc_status cc1, tcpm_set_state(port, SRC_ATTACH_WAIT, 0); break; case SRC_ATTACHED: - if (tcpm_port_is_disconnected(port)) + case SRC_SEND_CAPABILITIES: + case SRC_READY: + if (tcpm_port_is_disconnected(port) || + !tcpm_port_is_source(port)) tcpm_set_state(port, SRC_UNATTACHED, 0); break; - case SNK_UNATTACHED: if (tcpm_port_is_sink(port)) tcpm_set_state(port, SNK_ATTACH_WAIT, 0); @@ -2869,52 +2968,43 @@ static void _tcpm_cc_change(struct tcpm_port *port, enum typec_cc_status cc1, case SRC_TRYWAIT: /* Hand over to state machine if needed */ if (!port->vbus_present && tcpm_port_is_source(port)) - new_state = SRC_ATTACHED; - else - new_state = SRC_TRYWAIT_UNATTACHED; - - if (new_state != port->delayed_state) + tcpm_set_state(port, SRC_TRYWAIT_DEBOUNCE, 0); + break; + case SRC_TRYWAIT_DEBOUNCE: + if (port->vbus_present || !tcpm_port_is_source(port)) tcpm_set_state(port, SRC_TRYWAIT, 0); break; - case SNK_TRY_WAIT: - if (port->vbus_present && tcpm_port_is_sink(port)) { - tcpm_set_state(port, SNK_ATTACHED, 0); - break; + case SNK_TRY_WAIT_DEBOUNCE: + if (!tcpm_port_is_sink(port)) { + port->max_wait = 0; + tcpm_set_state(port, SRC_TRYWAIT, 0); } - if (!tcpm_port_is_sink(port)) - new_state = SRC_TRYWAIT; - else - new_state = SRC_TRYWAIT_UNATTACHED; - - if (new_state != port->delayed_state) - tcpm_set_state(port, SNK_TRY_WAIT, 0); break; - - case SRC_TRY: - tcpm_set_state(port, SRC_TRY_DEBOUNCE, 0); + case SRC_TRY_WAIT: + if (tcpm_port_is_source(port)) + tcpm_set_state(port, SRC_TRY_DEBOUNCE, 0); break; case SRC_TRY_DEBOUNCE: - tcpm_set_state(port, SRC_TRY, 0); + tcpm_set_state(port, SRC_TRY_WAIT, 0); break; case SNK_TRYWAIT_DEBOUNCE: - if (port->vbus_present) { - tcpm_set_state(port, SNK_ATTACHED, 0); - break; - } - if (tcpm_port_is_source(port)) { - tcpm_set_state(port, SRC_ATTACHED, 0); - break; - } - if (tcpm_port_is_disconnected(port) && - port->delayed_state != SNK_UNATTACHED) + if (tcpm_port_is_sink(port)) + tcpm_set_state(port, SNK_TRYWAIT_VBUS, 0); + break; + case SNK_TRYWAIT_VBUS: + if (!tcpm_port_is_sink(port)) tcpm_set_state(port, SNK_TRYWAIT_DEBOUNCE, 0); break; - + case SNK_TRYWAIT: + /* Do nothing, waiting for tCCDebounce */ + break; case PR_SWAP_SNK_SRC_SINK_OFF: case PR_SWAP_SRC_SNK_TRANSITION_OFF: case PR_SWAP_SRC_SNK_SOURCE_OFF: + case PR_SWAP_SRC_SNK_SOURCE_OFF_CC_DEBOUNCED: + case PR_SWAP_SNK_SRC_SOURCE_ON: /* - * CC state change is expected here; we just turned off power. + * CC state change is expected in PR_SWAP * Ignore it. */ break; @@ -2928,12 +3018,11 @@ static void _tcpm_cc_change(struct tcpm_port *port, enum typec_cc_status cc1, static void _tcpm_pd_vbus_on(struct tcpm_port *port) { - enum tcpm_state new_state; - tcpm_log_force(port, "VBUS on"); port->vbus_present = true; switch (port->state) { case SNK_TRANSITION_SINK_VBUS: + port->explicit_contract = true; tcpm_set_state(port, SNK_READY, 0); break; case SNK_DISCOVERY: @@ -2959,27 +3048,28 @@ static void _tcpm_pd_vbus_on(struct tcpm_port *port) /* Do nothing, waiting for timeout */ break; case SRC_TRYWAIT: - /* Hand over to state machine if needed */ - if (port->delayed_state != SRC_TRYWAIT_UNATTACHED) - tcpm_set_state(port, SRC_TRYWAIT, 0); + /* Do nothing, Waiting for Rd to be detected */ break; - case SNK_TRY_WAIT: - if (tcpm_port_is_sink(port)) { - tcpm_set_state(port, SNK_ATTACHED, 0); - break; - } - if (!tcpm_port_is_sink(port)) - new_state = SRC_TRYWAIT; - else - new_state = SRC_TRYWAIT_UNATTACHED; - - if (new_state != port->delayed_state) - tcpm_set_state(port, SNK_TRY_WAIT, 0); + case SRC_TRYWAIT_DEBOUNCE: + tcpm_set_state(port, SRC_TRYWAIT, 0); + break; + case SNK_TRY_WAIT_DEBOUNCE: + /* Do nothing, waiting for PD_DEBOUNCE to do be done */ break; case SNK_TRYWAIT: - tcpm_set_state(port, SNK_TRYWAIT_VBUS, 0); + /* Do nothing, waiting for tCCDebounce */ + break; + case SNK_TRYWAIT_VBUS: + if (tcpm_port_is_sink(port)) + tcpm_set_state(port, SNK_ATTACHED, 0); + break; + case SNK_TRYWAIT_DEBOUNCE: + /* Do nothing, waiting for Rp */ + break; + case SRC_TRY_WAIT: + case SRC_TRY_DEBOUNCE: + /* Do nothing, waiting for sink detection */ break; - default: break; } @@ -2987,8 +3077,6 @@ static void _tcpm_pd_vbus_on(struct tcpm_port *port) static void _tcpm_pd_vbus_off(struct tcpm_port *port) { - enum tcpm_state new_state; - tcpm_log_force(port, "VBUS off"); port->vbus_present = false; port->vbus_never_low = false; @@ -3008,25 +3096,15 @@ static void _tcpm_pd_vbus_off(struct tcpm_port *port) case SRC_TRYWAIT: /* Hand over to state machine if needed */ if (tcpm_port_is_source(port)) - new_state = SRC_ATTACHED; - else - new_state = SRC_TRYWAIT_UNATTACHED; - if (new_state != port->delayed_state) - tcpm_set_state(port, SRC_TRYWAIT, 0); + tcpm_set_state(port, SRC_TRYWAIT_DEBOUNCE, 0); break; - case SNK_TRY_WAIT: - if (!tcpm_port_is_sink(port)) - new_state = SRC_TRYWAIT; - else - new_state = SRC_TRYWAIT_UNATTACHED; - - if (new_state != port->delayed_state) - tcpm_set_state(port, SNK_TRY_WAIT, 0); + case SNK_TRY_WAIT_DEBOUNCE: + /* Do nothing, waiting for PD_DEBOUNCE to do be done */ break; + case SNK_TRYWAIT: case SNK_TRYWAIT_VBUS: - tcpm_set_state(port, SNK_TRYWAIT, 0); + case SNK_TRYWAIT_DEBOUNCE: break; - case SNK_ATTACH_WAIT: tcpm_set_state(port, SNK_UNATTACHED, 0); break; @@ -3042,13 +3120,13 @@ static void _tcpm_pd_vbus_off(struct tcpm_port *port) /* Do nothing, expected */ break; - case ERROR_RECOVERY_WAIT_OFF: - tcpm_set_state(port, - port->pwr_role == TYPEC_SOURCE ? - SRC_UNATTACHED : SNK_UNATTACHED, - 0); + case PORT_RESET_WAIT_OFF: + tcpm_set_state(port, tcpm_default_state(port), 0); + break; + case SRC_TRY_WAIT: + case SRC_TRY_DEBOUNCE: + /* Do nothing, waiting for sink detection */ break; - default: if (port->pwr_role == TYPEC_SINK && port->attached) @@ -3142,7 +3220,7 @@ static int tcpm_dr_set(const struct typec_capability *cap, mutex_lock(&port->swap_lock); mutex_lock(&port->lock); - if (port->typec_caps.type != TYPEC_PORT_DRP || !port->pd_capable) { + if (port->port_type != TYPEC_PORT_DRP) { ret = -EINVAL; goto port_unlock; } @@ -3163,15 +3241,35 @@ static int tcpm_dr_set(const struct typec_capability *cap, * Reject data role swap request in this case. */ + if (!port->pd_capable) { + /* + * If the partner is not PD capable, reset the port to + * trigger a role change. This can only work if a preferred + * role is configured, and if it matches the requested role. + */ + if (port->try_role == TYPEC_NO_PREFERRED_ROLE || + port->try_role == port->pwr_role) { + ret = -EINVAL; + goto port_unlock; + } + port->non_pd_role_swap = true; + tcpm_set_state(port, PORT_RESET, 0); + } else { + tcpm_set_state(port, DR_SWAP_SEND, 0); + } + port->swap_status = 0; port->swap_pending = true; reinit_completion(&port->swap_complete); - tcpm_set_state(port, DR_SWAP_SEND, 0); mutex_unlock(&port->lock); - wait_for_completion(&port->swap_complete); + if (!wait_for_completion_timeout(&port->swap_complete, + msecs_to_jiffies(PD_ROLE_SWAP_TIMEOUT))) + ret = -ETIMEDOUT; + else + ret = port->swap_status; - ret = port->swap_status; + port->non_pd_role_swap = false; goto swap_unlock; port_unlock: @@ -3190,7 +3288,7 @@ static int tcpm_pr_set(const struct typec_capability *cap, mutex_lock(&port->swap_lock); mutex_lock(&port->lock); - if (port->typec_caps.type != TYPEC_PORT_DRP) { + if (port->port_type != TYPEC_PORT_DRP) { ret = -EINVAL; goto port_unlock; } @@ -3204,31 +3302,18 @@ static int tcpm_pr_set(const struct typec_capability *cap, goto port_unlock; } - if (!port->pd_capable) { - /* - * If the partner is not PD capable, reset the port to - * trigger a role change. This can only work if a preferred - * role is configured, and if it matches the requested role. - */ - if (port->try_role == TYPEC_NO_PREFERRED_ROLE || - port->try_role == port->pwr_role) { - ret = -EINVAL; - goto port_unlock; - } - tcpm_set_state(port, HARD_RESET_SEND, 0); - ret = 0; - goto port_unlock; - } - port->swap_status = 0; port->swap_pending = true; reinit_completion(&port->swap_complete); tcpm_set_state(port, PR_SWAP_SEND, 0); mutex_unlock(&port->lock); - wait_for_completion(&port->swap_complete); + if (!wait_for_completion_timeout(&port->swap_complete, + msecs_to_jiffies(PD_ROLE_SWAP_TIMEOUT))) + ret = -ETIMEDOUT; + else + ret = port->swap_status; - ret = port->swap_status; goto swap_unlock; port_unlock: @@ -3263,9 +3348,12 @@ static int tcpm_vconn_set(const struct typec_capability *cap, tcpm_set_state(port, VCONN_SWAP_SEND, 0); mutex_unlock(&port->lock); - wait_for_completion(&port->swap_complete); + if (!wait_for_completion_timeout(&port->swap_complete, + msecs_to_jiffies(PD_ROLE_SWAP_TIMEOUT))) + ret = -ETIMEDOUT; + else + ret = port->swap_status; - ret = port->swap_status; goto swap_unlock; port_unlock: @@ -3319,7 +3407,35 @@ static void tcpm_init(struct tcpm_port *port) * Some adapters need a clean slate at startup, and won't recover * otherwise. So do not try to be fancy and force a clean disconnect. */ - tcpm_set_state(port, ERROR_RECOVERY, 0); + tcpm_set_state(port, PORT_RESET, 0); +} + +static int tcpm_port_type_set(const struct typec_capability *cap, + enum typec_port_type type) +{ + struct tcpm_port *port = typec_cap_to_tcpm(cap); + + mutex_lock(&port->lock); + if (type == port->port_type) + goto port_unlock; + + port->port_type = type; + + if (!port->connected) { + tcpm_set_state(port, PORT_RESET, 0); + } else if (type == TYPEC_PORT_UFP) { + if (!(port->pwr_role == TYPEC_SINK && + port->data_role == TYPEC_DEVICE)) + tcpm_set_state(port, PORT_RESET, 0); + } else if (type == TYPEC_PORT_DFP) { + if (!(port->pwr_role == TYPEC_SOURCE && + port->data_role == TYPEC_HOST)) + tcpm_set_state(port, PORT_RESET, 0); + } + +port_unlock: + mutex_unlock(&port->lock); + return 0; } void tcpm_tcpc_reset(struct tcpm_port *port) @@ -3469,9 +3585,10 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc) port->typec_caps.pr_set = tcpm_pr_set; port->typec_caps.vconn_set = tcpm_vconn_set; port->typec_caps.try_role = tcpm_try_role; + port->typec_caps.port_type_set = tcpm_port_type_set; port->partner_desc.identity = &port->partner_ident; - + port->port_type = tcpc->config->type; /* * TODO: * - alt_modes, set_alt_mode @@ -3485,7 +3602,7 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc) } if (tcpc->config->alt_modes) { - struct typec_altmode_desc *paltmode = tcpc->config->alt_modes; + const struct typec_altmode_desc *paltmode = tcpc->config->alt_modes; i = 0; while (paltmode->svid && i < ARRAY_SIZE(port->port_altmode)) { diff --git a/drivers/staging/typec/tcpm.h b/drivers/staging/typec/tcpm.h index 19c307d31a5a..7e9a6b7b5cd6 100644 --- a/drivers/staging/typec/tcpm.h +++ b/drivers/staging/typec/tcpm.h @@ -34,7 +34,8 @@ enum typec_cc_polarity { }; /* Time to wait for TCPC to complete transmit */ -#define PD_T_TCPC_TX_TIMEOUT 100 +#define PD_T_TCPC_TX_TIMEOUT 100 /* in ms */ +#define PD_ROLE_SWAP_TIMEOUT (MSEC_PER_SEC * 10) enum tcpm_transmit_status { TCPC_TX_SUCCESS = 0, @@ -72,7 +73,7 @@ struct tcpc_config { enum typec_role default_role; bool try_role_hw; /* try.{src,snk} implemented in hardware */ - struct typec_altmode_desc *alt_modes; + const struct typec_altmode_desc *alt_modes; }; enum tcpc_usb_switch { @@ -108,6 +109,13 @@ struct tcpc_dev { int (*init)(struct tcpc_dev *dev); int (*get_vbus)(struct tcpc_dev *dev); + /* + * This optional callback gets called by the tcpm core when configured + * as a snk and cc=Rp-def. This allows the tcpm to provide a fallback + * current-limit detection method for the cc=Rp-def case. E.g. some + * tcpcs may include BC1.2 charger detection and use that in this case. + */ + int (*get_current_limit)(struct tcpc_dev *dev); int (*set_cc)(struct tcpc_dev *dev, enum typec_cc_status cc); int (*get_cc)(struct tcpc_dev *dev, enum typec_cc_status *cc1, enum typec_cc_status *cc2); diff --git a/drivers/staging/unisys/Documentation/overview.txt b/drivers/staging/unisys/Documentation/overview.txt index e0466bfada2f..9ab30af265a5 100644 --- a/drivers/staging/unisys/Documentation/overview.txt +++ b/drivers/staging/unisys/Documentation/overview.txt @@ -221,7 +221,7 @@ The following files exist under /sys/devices/visorbus<x>/vbus<x>:dev<y>: The visorhba driver registers with visorbus as the function driver to handle virtual scsi disk devices, specified using the -VISOR_VHBA_CHANNEL_UUID type in the visorbus_register_visor_driver() +VISOR_VHBA_CHANNEL_GUID type in the visorbus_register_visor_driver() call. visorhba uses scsi_add_host() to expose a Linux block device (e.g., /sys/block/) in the guest environment for each s-Par virtual device. @@ -240,7 +240,7 @@ When compiled as a module, visorhba can be autoloaded by visorbus in standard udev/systemd environments, as it includes the modules.alias definition: - "visorbus:"+VISOR_VHBA_CHANNEL_UUID_STR + "visorbus:"+VISOR_VHBA_CHANNEL_GUID_STR i.e.: @@ -252,7 +252,7 @@ i.e.: The visornic driver registers with visorbus as the function driver to handle virtual network devices, specified using the -VISOR_VNIC_CHANNEL_UUID type in the visorbus_register_visor_driver() +VISOR_VNIC_CHANNEL_GUID type in the visorbus_register_visor_driver() call. visornic uses register_netdev() to expose a Linux device of class net (e.g., /sys/class/net/) in the guest environment for each s-Par virtual device. @@ -270,7 +270,7 @@ When compiled as a module, visornic can be autoloaded by visorbus in standard udev/systemd environments, as it includes the modules.alias definition: - "visorbus:"+VISOR_VNIC_CHANNEL_UUID_STR + "visorbus:"+VISOR_VNIC_CHANNEL_GUID_STR i.e.: @@ -282,7 +282,7 @@ i.e.: The visorinput driver registers with visorbus as the function driver to handle human input devices, specified using the -VISOR_KEYBOARD_CHANNEL_UUID and VISOR_MOUSE_CHANNEL_UUID +VISOR_KEYBOARD_CHANNEL_GUID and VISOR_MOUSE_CHANNEL_GUID types in the visorbus_register_visor_driver() call. visorinput uses input_register_device() to expose devices of class input (e.g., /sys/class/input/) for virtual keyboard and virtual mouse devices. @@ -307,8 +307,8 @@ When compiled as a module, visorinput can be autoloaded by visorbus in standard udev/systemd environments, as it includes the modules.alias definition: - "visorbus:"+VISOR_MOUSE_CHANNEL_UUID_STR - "visorbus:"+VISOR_KEYBOARD_CHANNEL_UUID_STR + "visorbus:"+VISOR_MOUSE_CHANNEL_GUID_STR + "visorbus:"+VISOR_KEYBOARD_CHANNEL_GUID_STR i.e.: diff --git a/drivers/staging/unisys/include/channel.h b/drivers/staging/unisys/include/channel.h index 692efcb38245..2babe93631f3 100644 --- a/drivers/staging/unisys/include/channel.h +++ b/drivers/staging/unisys/include/channel.h @@ -1,4 +1,5 @@ -/* Copyright (C) 2010 - 2013 UNISYS CORPORATION +/* + * Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify @@ -20,87 +21,48 @@ #include <linux/io.h> #include <linux/uuid.h> -#define __SUPERVISOR_CHANNEL_H__ - #define SIGNATURE_16(A, B) ((A) | ((B) << 8)) #define SIGNATURE_32(A, B, C, D) \ (SIGNATURE_16(A, B) | (SIGNATURE_16(C, D) << 16)) -#define SIGNATURE_64(A, B, C, D, E, F, G, H) \ - (SIGNATURE_32(A, B, C, D) | ((u64)(SIGNATURE_32(E, F, G, H)) << 32)) - -#ifndef COVER -#define COVER(v, d) ((d) * DIV_ROUND_UP(v, d)) -#endif - #define VISOR_CHANNEL_SIGNATURE SIGNATURE_32('E', 'C', 'N', 'L') +/* + * enum channel_serverstate + * @CHANNELSRV_UNINITIALIZED: Channel is in an undefined state. + * @CHANNELSRV_READY: Channel has been initialized by server. + */ enum channel_serverstate { - CHANNELSRV_UNINITIALIZED = 0, /* channel is in an undefined state */ - CHANNELSRV_READY = 1 /* channel has been initialized by server */ + CHANNELSRV_UNINITIALIZED = 0, + CHANNELSRV_READY = 1 }; +/* + * enum channel_clientstate + * @CHANNELCLI_DETACHED: + * @CHANNELCLI_DISABLED: Client can see channel but is NOT allowed to use it + * unless given TBD* explicit request + * (should actually be < DETACHED). + * @CHANNELCLI_ATTACHING: Legacy EFI client request for EFI server to attach. + * @CHANNELCLI_ATTACHED: Idle, but client may want to use channel any time. + * @CHANNELCLI_BUSY: Client either wants to use or is using channel. + * @CHANNELCLI_OWNED: "No worries" state - client can access channel + * anytime. + */ enum channel_clientstate { CHANNELCLI_DETACHED = 0, - CHANNELCLI_DISABLED = 1, /* client can see channel but is NOT - * allowed to use it unless given TBD - * explicit request (should actually be - * < DETACHED) - */ - CHANNELCLI_ATTACHING = 2, /* legacy EFI client request - * for EFI server to attach - */ - CHANNELCLI_ATTACHED = 3, /* idle, but client may want - * to use channel any time - */ - CHANNELCLI_BUSY = 4, /* client either wants to use or is - * using channel - */ - CHANNELCLI_OWNED = 5 /* "no worries" state - client can */ - /* access channel anytime */ + CHANNELCLI_DISABLED = 1, + CHANNELCLI_ATTACHING = 2, + CHANNELCLI_ATTACHED = 3, + CHANNELCLI_BUSY = 4, + CHANNELCLI_OWNED = 5 }; -#define VISOR_CHANNEL_SERVER_READY(ch) \ - (readl(&(ch)->srv_state) == CHANNELSRV_READY) - -#define VISOR_VALID_CHANNELCLI_TRANSITION(o, n) \ - (((((o) == CHANNELCLI_DETACHED) && ((n) == CHANNELCLI_DISABLED)) || \ - (((o) == CHANNELCLI_ATTACHING) && ((n) == CHANNELCLI_DISABLED)) || \ - (((o) == CHANNELCLI_ATTACHED) && ((n) == CHANNELCLI_DISABLED)) || \ - (((o) == CHANNELCLI_ATTACHING) && ((n) == CHANNELCLI_DETACHED)) || \ - (((o) == CHANNELCLI_ATTACHED) && ((n) == CHANNELCLI_DETACHED)) || \ - (((o) == CHANNELCLI_DETACHED) && ((n) == CHANNELCLI_ATTACHING)) || \ - (((o) == CHANNELCLI_ATTACHING) && ((n) == CHANNELCLI_ATTACHED)) || \ - (((o) == CHANNELCLI_DETACHED) && ((n) == CHANNELCLI_ATTACHED)) || \ - (((o) == CHANNELCLI_BUSY) && ((n) == CHANNELCLI_ATTACHED)) || \ - (((o) == CHANNELCLI_ATTACHED) && ((n) == CHANNELCLI_BUSY)) || \ - (((o) == CHANNELCLI_DETACHED) && ((n) == CHANNELCLI_OWNED)) || \ - (((o) == CHANNELCLI_DISABLED) && ((n) == CHANNELCLI_OWNED)) || \ - (((o) == CHANNELCLI_ATTACHING) && ((n) == CHANNELCLI_OWNED)) || \ - (((o) == CHANNELCLI_ATTACHED) && ((n) == CHANNELCLI_OWNED)) || \ - (((o) == CHANNELCLI_BUSY) && ((n) == CHANNELCLI_OWNED)) || (0)) \ - ? (1) : (0)) - -/* Values for VISORA_CHANNEL_PROTOCOL.CliErrorBoot: */ -/* throttling invalid boot channel statetransition error due to client - * disabled - */ -#define VISOR_CLIERRORBOOT_THROTTLEMSG_DISABLED 0x01 - -/* throttling invalid boot channel statetransition error due to client - * not attached - */ -#define VISOR_CLIERRORBOOT_THROTTLEMSG_NOTATTACHED 0x02 - -/* throttling invalid boot channel statetransition error due to busy channel */ -#define VISOR_CLIERRORBOOT_THROTTLEMSG_BUSY 0x04 - -/* Values for VISOR_CHANNEL_PROTOCOL.Features: This define exists so - * that windows guest can look at the FeatureFlags in the io channel, - * and configure the windows driver to use interrupts or not based on - * this setting. This flag is set in uislib after the - * VISOR_VHBA_init_channel is called. All feature bits for all - * channels should be defined here. The io channel feature bits are - * defined right here +/* + * Values for VISOR_CHANNEL_PROTOCOL.Features: This define exists so that + * a guest can look at the FeatureFlags in the io channel, and configure the + * driver to use interrupts or not based on this setting. All feature bits for + * all channels should be defined here. The io channel feature bits are defined + * below. */ #define VISOR_DRIVER_ENABLES_INTS (0x1ULL << 1) #define VISOR_CHANNEL_IS_POLLING (0x1ULL << 3) @@ -108,171 +70,124 @@ enum channel_clientstate { #define VISOR_DRIVER_DISABLES_INTS (0x1ULL << 5) #define VISOR_DRIVER_ENHANCED_RCVBUF_CHECKING (0x1ULL << 6) -/* Common Channel Header */ +/* + * struct channel_header - Common Channel Header + * @signature: Signature. + * @legacy_state: DEPRECATED - being replaced by. + * @header_size: sizeof(struct channel_header). + * @size: Total size of this channel in bytes. + * @features: Flags to modify behavior. + * @chtype: Channel type: data, bus, control, etc.. + * @partition_handle: ID of guest partition. + * @handle: Device number of this channel in client. + * @ch_space_offset: Offset in bytes to channel specific area. + * @version_id: Struct channel_header Version ID. + * @partition_index: Index of guest partition. + * @zone_uuid: Guid of Channel's zone. + * @cli_str_offset: Offset from channel header to null-terminated + * ClientString (0 if ClientString not present). + * @cli_state_boot: CHANNEL_CLIENTSTATE of pre-boot EFI client of this + * channel. + * @cmd_state_cli: CHANNEL_COMMANDSTATE (overloaded in Windows drivers, see + * ServerStateUp, ServerStateDown, etc). + * @cli_state_os: CHANNEL_CLIENTSTATE of Guest OS client of this channel. + * @ch_characteristic: CHANNEL_CHARACTERISTIC_<xxx>. + * @cmd_state_srv: CHANNEL_COMMANDSTATE (overloaded in Windows drivers, see + * ServerStateUp, ServerStateDown, etc). + * @srv_state: CHANNEL_SERVERSTATE. + * @cli_error_boot: Bits to indicate err states for boot clients, so err + * messages can be throttled. + * @cli_error_os: Bits to indicate err states for OS clients, so err + * messages can be throttled. + * @filler: Pad out to 128 byte cacheline. + * @recover_channel: Please add all new single-byte values below here. + */ struct channel_header { - u64 signature; /* Signature */ - u32 legacy_state; /* DEPRECATED - being replaced by */ - /* SrvState, CliStateBoot, and CliStateOS below */ - u32 header_size; /* sizeof(struct channel_header) */ - u64 size; /* Total size of this channel in bytes */ - u64 features; /* Flags to modify behavior */ - uuid_le chtype; /* Channel type: data, bus, control, etc. */ - u64 partition_handle; /* ID of guest partition */ - u64 handle; /* Device number of this channel in client */ - u64 ch_space_offset; /* Offset in bytes to channel specific area */ - u32 version_id; /* struct channel_header Version ID */ - u32 partition_index; /* Index of guest partition */ - uuid_le zone_uuid; /* Guid of Channel's zone */ - u32 cli_str_offset; /* offset from channel header to - * nul-terminated ClientString (0 if - * ClientString not present) - */ - u32 cli_state_boot; /* CHANNEL_CLIENTSTATE of pre-boot - * EFI client of this channel - */ - u32 cmd_state_cli; /* CHANNEL_COMMANDSTATE (overloaded in - * Windows drivers, see ServerStateUp, - * ServerStateDown, etc) - */ - u32 cli_state_os; /* CHANNEL_CLIENTSTATE of Guest OS - * client of this channel - */ - u32 ch_characteristic; /* CHANNEL_CHARACTERISTIC_<xxx> */ - u32 cmd_state_srv; /* CHANNEL_COMMANDSTATE (overloaded in - * Windows drivers, see ServerStateUp, - * ServerStateDown, etc) - */ - u32 srv_state; /* CHANNEL_SERVERSTATE */ - u8 cli_error_boot; /* bits to indicate err states for - * boot clients, so err messages can - * be throttled - */ - u8 cli_error_os; /* bits to indicate err states for OS - * clients, so err messages can be - * throttled - */ - u8 filler[1]; /* Pad out to 128 byte cacheline */ - /* Please add all new single-byte values below here */ + u64 signature; + u32 legacy_state; + /* SrvState, CliStateBoot, and CliStateOS below */ + u32 header_size; + u64 size; + u64 features; + guid_t chtype; + u64 partition_handle; + u64 handle; + u64 ch_space_offset; + u32 version_id; + u32 partition_index; + guid_t zone_guid; + u32 cli_str_offset; + u32 cli_state_boot; + u32 cmd_state_cli; + u32 cli_state_os; + u32 ch_characteristic; + u32 cmd_state_srv; + u32 srv_state; + u8 cli_error_boot; + u8 cli_error_os; + u8 filler[1]; u8 recover_channel; } __packed; #define VISOR_CHANNEL_ENABLE_INTS (0x1ULL << 0) -/* Subheader for the Signal Type variation of the Common Channel */ +/* + * struct signal_queue_header - Subheader for the Signal Type variation of the + * Common Channel. + * @version: SIGNAL_QUEUE_HEADER Version ID. + * @chtype: Queue type: storage, network. + * @size: Total size of this queue in bytes. + * @sig_base_offset: Offset to signal queue area. + * @features: Flags to modify behavior. + * @num_sent: Total # of signals placed in this queue. + * @num_overflows: Total # of inserts failed due to full queue. + * @signal_size: Total size of a signal for this queue. + * @max_slots: Max # of slots in queue, 1 slot is always empty. + * @max_signals: Max # of signals in queue (MaxSignalSlots-1). + * @head: Queue head signal #. + * @num_received: Total # of signals removed from this queue. + * @tail: Queue tail signal. + * @reserved1: Reserved field. + * @reserved2: Reserved field. + * @client_queue: + * @num_irq_received: Total # of Interrupts received. This is incremented by the + * ISR in the guest windows driver. + * @num_empty: Number of times that visor_signal_remove is called and + * returned Empty Status. + * @errorflags: Error bits set during SignalReinit to denote trouble with + * client's fields. + * @filler: Pad out to 64 byte cacheline. + */ struct signal_queue_header { /* 1st cache line */ - u32 version; /* SIGNAL_QUEUE_HEADER Version ID */ - u32 chtype; /* Queue type: storage, network */ - u64 size; /* Total size of this queue in bytes */ - u64 sig_base_offset; /* Offset to signal queue area */ - u64 features; /* Flags to modify behavior */ - u64 num_sent; /* Total # of signals placed in this queue */ - u64 num_overflows; /* Total # of inserts failed due to - * full queue - */ - u32 signal_size; /* Total size of a signal for this queue */ - u32 max_slots; /* Max # of slots in queue, 1 slot is - * always empty - */ - u32 max_signals; /* Max # of signals in queue - * (MaxSignalSlots-1) - */ - u32 head; /* Queue head signal # */ + u32 version; + u32 chtype; + u64 size; + u64 sig_base_offset; + u64 features; + u64 num_sent; + u64 num_overflows; + u32 signal_size; + u32 max_slots; + u32 max_signals; + u32 head; /* 2nd cache line */ - u64 num_received; /* Total # of signals removed from this queue */ - u32 tail; /* Queue tail signal */ - u32 reserved1; /* Reserved field */ - u64 reserved2; /* Reserved field */ + u64 num_received; + u32 tail; + u32 reserved1; + u64 reserved2; u64 client_queue; - u64 num_irq_received; /* Total # of Interrupts received. This - * is incremented by the ISR in the - * guest windows driver - */ - u64 num_empty; /* Number of times that visor_signal_remove - * is called and returned Empty Status. - */ - u32 errorflags; /* Error bits set during SignalReinit - * to denote trouble with client's - * fields - */ - u8 filler[12]; /* Pad out to 64 byte cacheline */ + u64 num_irq_received; + u64 num_empty; + u32 errorflags; + u8 filler[12]; } __packed; -/* Generic function useful for validating any type of channel when it is - * received by the client that will be accessing the channel. - * Note that <logCtx> is only needed for callers in the EFI environment, and - * is used to pass the EFI_DIAG_CAPTURE_PROTOCOL needed to log messages. - */ -static inline int -visor_check_channel(struct channel_header *ch, - uuid_le expected_uuid, - char *chname, - u64 expected_min_bytes, - u32 expected_version, - u64 expected_signature) -{ - if (uuid_le_cmp(expected_uuid, NULL_UUID_LE) != 0) { - /* caller wants us to verify type GUID */ - if (uuid_le_cmp(ch->chtype, expected_uuid) != 0) { - pr_err("Channel mismatch on channel=%s(%pUL) field=type expected=%pUL actual=%pUL\n", - chname, &expected_uuid, - &expected_uuid, &ch->chtype); - return 0; - } - } - if (expected_min_bytes > 0) { /* verify channel size */ - if (ch->size < expected_min_bytes) { - pr_err("Channel mismatch on channel=%s(%pUL) field=size expected=0x%-8.8Lx actual=0x%-8.8Lx\n", - chname, &expected_uuid, - (unsigned long long)expected_min_bytes, - ch->size); - return 0; - } - } - if (expected_version > 0) { /* verify channel version */ - if (ch->version_id != expected_version) { - pr_err("Channel mismatch on channel=%s(%pUL) field=version expected=0x%-8.8lx actual=0x%-8.8x\n", - chname, &expected_uuid, - (unsigned long)expected_version, - ch->version_id); - return 0; - } - } - if (expected_signature > 0) { /* verify channel signature */ - if (ch->signature != expected_signature) { - pr_err("Channel mismatch on channel=%s(%pUL) field=signature expected=0x%-8.8Lx actual=0x%-8.8Lx\n", - chname, &expected_uuid, - expected_signature, ch->signature); - return 0; - } - } - return 1; -} - -/* - * CHANNEL Guids - */ - +/* CHANNEL Guids */ /* {414815ed-c58c-11da-95a9-00e08161165f} */ -#define VISOR_VHBA_CHANNEL_UUID \ - UUID_LE(0x414815ed, 0xc58c, 0x11da, \ - 0x95, 0xa9, 0x0, 0xe0, 0x81, 0x61, 0x16, 0x5f) -static const uuid_le visor_vhba_channel_uuid = VISOR_VHBA_CHANNEL_UUID; -#define VISOR_VHBA_CHANNEL_UUID_STR \ +#define VISOR_VHBA_CHANNEL_GUID \ + GUID_INIT(0x414815ed, 0xc58c, 0x11da, \ + 0x95, 0xa9, 0x0, 0xe0, 0x81, 0x61, 0x16, 0x5f) +#define VISOR_VHBA_CHANNEL_GUID_STR \ "414815ed-c58c-11da-95a9-00e08161165f" - -/* {8cd5994d-c58e-11da-95a9-00e08161165f} */ -#define VISOR_VNIC_CHANNEL_UUID \ - UUID_LE(0x8cd5994d, 0xc58e, 0x11da, \ - 0x95, 0xa9, 0x0, 0xe0, 0x81, 0x61, 0x16, 0x5f) -static const uuid_le visor_vnic_channel_uuid = VISOR_VNIC_CHANNEL_UUID; -#define VISOR_VNIC_CHANNEL_UUID_STR \ - "8cd5994d-c58e-11da-95a9-00e08161165f" - -/* {72120008-4AAB-11DC-8530-444553544200} */ -#define VISOR_SIOVM_UUID \ - UUID_LE(0x72120008, 0x4AAB, 0x11DC, \ - 0x85, 0x30, 0x44, 0x45, 0x53, 0x54, 0x42, 0x00) -static const uuid_le visor_siovm_uuid = VISOR_SIOVM_UUID; - #endif diff --git a/drivers/staging/unisys/include/iochannel.h b/drivers/staging/unisys/include/iochannel.h index c7cb3fbde7b2..a70760f48566 100644 --- a/drivers/staging/unisys/include/iochannel.h +++ b/drivers/staging/unisys/include/iochannel.h @@ -1,5 +1,19 @@ -/* Copyright (C) 2010 - 2016 UNISYS CORPORATION */ -/* All rights reserved. */ +/* + * Copyright (C) 2010 - 2016 UNISYS CORPORATION + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + */ + #ifndef __IOCHANNEL_H__ #define __IOCHANNEL_H__ @@ -7,9 +21,7 @@ * Everything needed for IOPart-GuestPart communication is define in * this file. Note: Everything is OS-independent because this file is * used by Windows, Linux and possible EFI drivers. - */ - -/* + * * Communication flow between the IOPart and GuestPart uses the channel headers * channel state. The following states are currently being used: * UNINIT(All Zeroes), CHANNEL_ATTACHING, CHANNEL_ATTACHED, CHANNEL_OPENED @@ -30,14 +42,10 @@ */ #include <linux/uuid.h> +#include <linux/skbuff.h> -#include <linux/dma-direction.h> #include "channel.h" -#define VISOR_VHBA_CHANNEL_SIGNATURE VISOR_CHANNEL_SIGNATURE -#define VISOR_VNIC_CHANNEL_SIGNATURE VISOR_CHANNEL_SIGNATURE -#define VISOR_VSWITCH_CHANNEL_SIGNATURE VISOR_CHANNEL_SIGNATURE - /* * Must increment these whenever you insert or delete fields within this channel * struct. Also increment whenever you change the meaning of fields within this @@ -47,82 +55,73 @@ */ #define VISOR_VHBA_CHANNEL_VERSIONID 2 #define VISOR_VNIC_CHANNEL_VERSIONID 2 -#define VISOR_VSWITCH_CHANNEL_VERSIONID 1 - -#define VISOR_VHBA_CHANNEL_OK_CLIENT(ch) \ - (visor_check_channel(ch, visor_vhba_channel_uuid, \ - "vhba", MIN_IO_CHANNEL_SIZE, \ - VISOR_VHBA_CHANNEL_VERSIONID, \ - VISOR_VHBA_CHANNEL_SIGNATURE)) - -#define VISOR_VNIC_CHANNEL_OK_CLIENT(ch) \ - (visor_check_channel(ch, visor_vnic_channel_uuid, \ - "vnic", MIN_IO_CHANNEL_SIZE, \ - VISOR_VNIC_CHANNEL_VERSIONID, \ - VISOR_VNIC_CHANNEL_SIGNATURE)) /* * Everything necessary to handle SCSI & NIC traffic between Guest Partition and * IO Partition is defined below. */ -/* Defines and enums. */ -#define MINNUM(a, b) (((a) < (b)) ? (a) : (b)) -#define MAXNUM(a, b) (((a) > (b)) ? (a) : (b)) - -/* Define the two queues per data channel between iopart and ioguestparts. */ -/* Used by ioguestpart to 'insert' signals to iopart. */ +/* + * Define the two queues per data channel between iopart and ioguestparts. + * IOCHAN_TO_IOPART -- used by guest to 'insert' signals to iopart. + * IOCHAN_FROM_IOPART -- used by guest to 'remove' signals from IO part. + */ #define IOCHAN_TO_IOPART 0 -/* Used by ioguestpart to 'remove' signals from iopart, same previous queue. */ #define IOCHAN_FROM_IOPART 1 /* Size of cdb - i.e., SCSI cmnd */ #define MAX_CMND_SIZE 16 -#define MAX_SENSE_SIZE 64 +/* Unisys-specific DMA direction values */ +enum uis_dma_data_direction { + UIS_DMA_BIDIRECTIONAL = 0, + UIS_DMA_TO_DEVICE = 1, + UIS_DMA_FROM_DEVICE = 2, + UIS_DMA_NONE = 3 +}; +#define MAX_SENSE_SIZE 64 #define MAX_PHYS_INFO 64 -/* Various types of network packets that can be sent in cmdrsp. */ +/* + * enum net_types - Various types of network packets that can be sent in cmdrsp. + * @NET_RCV_POST: Submit buffer to hold receiving incoming packet. + * @NET_RCV: visornic -> uisnic. Incoming packet received. + * @NET_XMIT: uisnic -> visornic. For outgoing packet. + * @NET_XMIT_DONE: visornic -> uisnic. Outgoing packet xmitted. + * @NET_RCV_ENBDIS: uisnic -> visornic. Enable/Disable packet reception. + * @NET_RCV_ENBDIS_ACK: visornic -> uisnic. Acknowledge enable/disable packet. + * @NET_RCV_PROMISC: uisnic -> visornic. Enable/Disable promiscuous mode. + * @NET_CONNECT_STATUS: visornic -> uisnic. Indicate the loss or restoration of + * a network connection. + * @NET_MACADDR: uisnic -> visornic. Indicates the client has requested + * to update it's MAC address. + * @NET_MACADDR_ACK: MAC address acknowledge. + */ enum net_types { - NET_RCV_POST = 0, /* - * Submit buffer to hold receiving - * incoming packet - */ - /* visornic -> uisnic */ - NET_RCV, /* incoming packet received */ - /* uisnic -> visornic */ - NET_XMIT, /* for outgoing net packets */ - /* visornic -> uisnic */ - NET_XMIT_DONE, /* outgoing packet xmitted */ - /* uisnic -> visornic */ - NET_RCV_ENBDIS, /* enable/disable packet reception */ - /* visornic -> uisnic */ - NET_RCV_ENBDIS_ACK, /* acknowledge enable/disable packet */ - /* reception */ - /* uisnic -> visornic */ - NET_RCV_PROMISC, /* enable/disable promiscuous mode */ - /* visornic -> uisnic */ - NET_CONNECT_STATUS, /* - * indicate the loss or restoration of a network - * connection - */ - /* uisnic -> visornic */ - NET_MACADDR, /* - * Indicates the client has requested to update - * it's MAC address - */ - NET_MACADDR_ACK, /* MAC address acknowledge */ - + NET_RCV_POST = 0, + NET_RCV, + NET_XMIT, + NET_XMIT_DONE, + NET_RCV_ENBDIS, + NET_RCV_ENBDIS_ACK, + /* Reception */ + NET_RCV_PROMISC, + NET_CONNECT_STATUS, + NET_MACADDR, + NET_MACADDR_ACK, }; -#define ETH_MIN_DATA_SIZE 46 /* minimum eth data size */ +/* Minimum eth data size */ +#define ETH_MIN_DATA_SIZE 46 #define ETH_MIN_PACKET_SIZE (ETH_HLEN + ETH_MIN_DATA_SIZE) -#define VISOR_ETH_MAX_MTU 16384 /* maximum data size */ +/* Maximum data size */ +#define VISOR_ETH_MAX_MTU 16384 #ifndef MAX_MACADDR_LEN -#define MAX_MACADDR_LEN 6 /* number of bytes in MAC address */ +/* Number of bytes in MAC address */ +#define MAX_MACADDR_LEN 6 #endif /* Various types of scsi task mgmt commands. */ @@ -154,12 +153,16 @@ struct guest_phys_info { u64 length; } __packed; -#define GPI_ENTRIES_PER_PAGE (PAGE_SIZE / sizeof(struct guest_phys_info)) - +/* + * struct uisscsi_dest + * @channel: Bus number. + * @id: Target number. + * @lun: Logical unit number. + */ struct uisscsi_dest { - u32 channel; /* channel == bus number */ - u32 id; /* id == target number */ - u32 lun; /* lun == logical unit number */ + u32 channel; + u32 id; + u32 lun; } __packed; struct vhba_wwnn { @@ -168,61 +171,77 @@ struct vhba_wwnn { } __packed; /* - * WARNING: Values stired in this structure must contain maximum counts (not + * struct vhba_config_max + * @max_channel: Maximum channel for devices attached to this bus. + * @max_id: Maximum SCSI ID for devices attached to bus. + * @max_lun: Maximum SCSI LUN for devices attached to bus. + * @cmd_per_lun: Maximum number of outstanding commands per LUN. + * @max_io_size: Maximum io size for devices attached to this bus. Max io size + * is often determined by the resource of the hba. + * e.g Max scatter gather list length * page size / sector size. + * + * WARNING: Values stored in this structure must contain maximum counts (not * maximum values). + * + * 20 bytes */ -struct vhba_config_max {/* 20 bytes */ - u32 max_channel;/* maximum channel for devices attached to this bus */ - u32 max_id; /* maximum SCSI ID for devices attached to bus */ - u32 max_lun; /* maximum SCSI LUN for devices attached to bus */ - u32 cmd_per_lun;/* maximum number of outstanding commands per LUN */ - u32 max_io_size;/* maximum io size for devices attached to this bus */ - /* max io size is often determined by the resource of the hba. e.g */ - /* max scatter gather list length * page size / sector size */ +struct vhba_config_max { + u32 max_channel; + u32 max_id; + u32 max_lun; + u32 cmd_per_lun; + u32 max_io_size; } __packed; +/* + * struct uiscmdrsp_scsi + * + * @handle: The handle to the cmd that was received. Send it back as + * is in the rsp packet. + * @cmnd: The cdb for the command. + * @bufflen: Length of data to be transferred out or in. + * @guest_phys_entries: Number of entries in scatter-gather list. + * @struct gpi_list: Physical address information for each fragment. + * @data_dir: Direction of the data, if any. + * @struct vdest: Identifies the virtual hba, id, channel, lun to which + * cmd was sent. + * @linuxstat: Original Linux status used by Linux vdisk. + * @scsistat: The scsi status. + * @addlstat: Non-scsi status. + * @sensebuf: Sense info in case cmd failed. sensebuf holds the + * sense_data struct. See sense_data struct for more + * details. + * @*vdisk: Pointer to the vdisk to clean up when IO completes. + * @no_disk_result: Used to return no disk inquiry result when + * no_disk_result is set to 1 + * scsi.scsistat is SAM_STAT_GOOD + * scsi.addlstat is 0 + * scsi.linuxstat is SAM_STAT_GOOD + * That is, there is NO error. + */ struct uiscmdrsp_scsi { - u64 handle; /* the handle to the cmd that was received */ - /* send it back as is in the rsp packet. */ - u8 cmnd[MAX_CMND_SIZE]; /* the cdb for the command */ - u32 bufflen; /* length of data to be transferred out or in */ - u16 guest_phys_entries; /* Number of entries in scatter-gather list */ - struct guest_phys_info gpi_list[MAX_PHYS_INFO]; /* physical address - * information for each - * fragment - */ - enum dma_data_direction data_dir; /* direction of the data, if any */ - struct uisscsi_dest vdest; /* identifies the virtual hba, id, */ - /* channel, lun to which cmd was sent */ - + u64 handle; + u8 cmnd[MAX_CMND_SIZE]; + u32 bufflen; + u16 guest_phys_entries; + struct guest_phys_info gpi_list[MAX_PHYS_INFO]; + u32 data_dir; + struct uisscsi_dest vdest; /* Needed to queue the rsp back to cmd originator. */ - int linuxstat; /* original Linux status used by Linux vdisk */ - u8 scsistat; /* the scsi status */ - u8 addlstat; /* non-scsi status */ + int linuxstat; + u8 scsistat; + u8 addlstat; #define ADDL_SEL_TIMEOUT 4 - /* The following fields are need to determine the result of command. */ - u8 sensebuf[MAX_SENSE_SIZE]; /* sense info in case cmd failed; */ - /* sensebuf holds the sense_data struct; */ - /* See sense_data struct for more details. */ - void *vdisk; /* Pointer to the vdisk to clean up when IO completes. */ + u8 sensebuf[MAX_SENSE_SIZE]; + void *vdisk; int no_disk_result; - /* - * Used to return no disk inquiry result - * when no_disk_result is set to 1, - * scsi.scsistat is SAM_STAT_GOOD - * scsi.addlstat is 0 - * scsi.linuxstat is SAM_STAT_GOOD - * That is, there is NO error. - */ } __packed; /* * Defines to support sending correct inquiry result when no disk is * configured. - */ - -/* + * * From SCSI SPC2 - * * If the target is not capable of supporting a device on this logical unit, the @@ -234,22 +253,35 @@ struct uiscmdrsp_scsi { * connected to this logical unit. */ -#define DEV_NOT_CAPABLE 0x7f /* - * peripheral qualifier of 0x3 - * peripheral type of 0x1f - * specifies no device but target present - */ - -#define DEV_DISK_CAPABLE_NOT_PRESENT 0x20 /* peripheral qualifier of 0x1 - * peripheral type of 0 - disk - * Specifies device capable, but - * not present - */ +/* + * Peripheral qualifier of 0x3 + * Peripheral type of 0x1f + * Specifies no device but target present + */ +#define DEV_NOT_CAPABLE 0x7f +/* + * Peripheral qualifier of 0x1 + * Peripheral type of 0 - disk + * Specifies device capable, but not present + */ +#define DEV_DISK_CAPABLE_NOT_PRESENT 0x20 +/* HiSup = 1; shows support for report luns must be returned for lun 0. */ +#define DEV_HISUPPORT 0x10 -#define DEV_HISUPPORT 0x10 /* - * HiSup = 1; shows support for report luns - * must be returned for lun 0. - */ +/* + * Peripheral qualifier of 0x3 + * Peripheral type of 0x1f + * Specifies no device but target present + */ +#define DEV_NOT_CAPABLE 0x7f +/* + * Peripheral qualifier of 0x1 + * Peripheral type of 0 - disk + * Specifies device capable, but not present + */ +#define DEV_DISK_CAPABLE_NOT_PRESENT 0x20 +/* HiSup = 1; shows support for report luns must be returned for lun 0. */ +#define DEV_HISUPPORT 0x10 /* * NOTE: Linux code assumes inquiry contains 36 bytes. Without checking length @@ -258,11 +290,12 @@ struct uiscmdrsp_scsi { * inquiry result. */ #define NO_DISK_INQUIRY_RESULT_LEN 36 - -#define MIN_INQUIRY_RESULT_LEN 5 /* 5 bytes minimum for inquiry result */ +/* 5 bytes minimum for inquiry result */ +#define MIN_INQUIRY_RESULT_LEN 5 /* SCSI device version for no disk inquiry result */ -#define SCSI_SPC2_VER 4 /* indicates SCSI SPC2 (SPC3 is 5) */ +/* indicates SCSI SPC2 (SPC3 is 5) */ +#define SCSI_SPC2_VER 4 /* Struct and Defines to support sense information. */ @@ -297,35 +330,48 @@ struct sense_data { u8 sense_key_specific[3]; } __packed; +/* + * struct net_pkt_xmt + * @len: Full length of data in the packet. + * @num_frags: Number of fragments in frags containing data. + * @struct phys_info frags: Physical page information. + * @ethhdr: The ethernet header. + * @struct lincsum: These are needed for csum at uisnic end. + * @valid: 1 = struct is valid - else ignore. + * @hrawoffv: 1 = hwrafoff is valid. + * @nhrawoffv: 1 = nhwrafoff is valid. + * @protocol: Specifies packet protocol. + * @csum: Value used to set skb->csum at IOPart. + * @hrawoff: Value used to set skb->h.raw at IOPart. hrawoff points to + * the start of the TRANSPORT LAYER HEADER. + * @nhrawoff: Value used to set skb->nh.raw at IOPart. nhrawoff points to + * the start of the NETWORK LAYER HEADER. + * + * NOTE: + * The full packet is described in frags but the ethernet header is + * separately kept in ethhdr so that uisnic doesn't have "MAP" the + * guest memory to get to the header. uisnic needs ethhdr to + * determine how to route the packet. + */ struct net_pkt_xmt { - int len; /* full length of data in the packet */ - int num_frags; /* number of fragments in frags containing data */ - struct phys_info frags[MAX_PHYS_INFO]; /* physical page information */ - char ethhdr[ETH_HLEN]; /* the ethernet header */ + int len; + int num_frags; + struct phys_info frags[MAX_PHYS_INFO]; + char ethhdr[ETH_HLEN]; struct { - /* These are needed for csum at uisnic end */ - u8 valid; /* 1 = struct is valid - else ignore */ - u8 hrawoffv; /* 1 = hwrafoff is valid */ - u8 nhrawoffv; /* 1 = nhwrafoff is valid */ - __be16 protocol; /* specifies packet protocol */ - __wsum csum; /* value used to set skb->csum at IOPart */ - u32 hrawoff; /* value used to set skb->h.raw at IOPart */ - /* hrawoff points to the start of the TRANSPORT LAYER HEADER */ - u32 nhrawoff; /* value used to set skb->nh.raw at IOPart */ - /* nhrawoff points to the start of the NETWORK LAYER HEADER */ + u8 valid; + u8 hrawoffv; + u8 nhrawoffv; + __be16 protocol; + __wsum csum; + u32 hrawoff; + u32 nhrawoff; } lincsum; - - /* - * NOTE: - * The full packet is described in frags but the ethernet header is - * separately kept in ethhdr so that uisnic doesn't have "MAP" the - * guest memory to get to the header. uisnic needs ethhdr to - * determine how to route the packet. - */ } __packed; struct net_pkt_xmtdone { - u32 xmt_done_result; /* result of NET_XMIT */ + /* Result of NET_XMIT */ + u32 xmt_done_result; } __packed; /* @@ -341,14 +387,12 @@ struct net_pkt_xmtdone { ((VISOR_ETH_MAX_MTU + ETH_HLEN + RCVPOST_BUF_SIZE - 1) \ / RCVPOST_BUF_SIZE) -/* - * rcv buf size must be large enough to include ethernet data len + ethernet +/* rcv buf size must be large enough to include ethernet data len + ethernet * header len - we are choosing 2K because it is guaranteed to be describable. */ struct net_pkt_rcvpost { /* Physical page information for the single fragment 2K rcv buf */ struct phys_info frag; - /* * Ensures that receive posts are returned to the adapter which we sent * them from originally. @@ -358,172 +402,157 @@ struct net_pkt_rcvpost { } __packed; /* + * struct net_pkt_rcv + * @rcv_done_len: Length of the received data. + * @numrcvbufs: Contains the incoming data. Guest side MUST chain these + * together. + * @*rcvbuf: List of chained rcvbufa. Each entry is a receive buffer + * provided by NET_RCV_POST. NOTE: First rcvbuf in the + * chain will also be provided in net.buf. + * @unique_num: + * @rcvs_dropped_delta: + * * The number of rcvbuf that can be chained is based on max mtu and size of each * rcvbuf. */ struct net_pkt_rcv { - u32 rcv_done_len; /* length of received data */ - - /* - * numrcvbufs: contain the incoming data; guest side MUST chain these - * together. - */ + u32 rcv_done_len; u8 numrcvbufs; - - void *rcvbuf[MAX_NET_RCV_CHAIN]; /* list of chained rcvbufs */ - - /* Each entry is a receive buffer provided by NET_RCV_POST. */ - /* NOTE: first rcvbuf in the chain will also be provided in net.buf. */ + void *rcvbuf[MAX_NET_RCV_CHAIN]; u64 unique_num; u32 rcvs_dropped_delta; } __packed; struct net_pkt_enbdis { void *context; - u16 enable; /* 1 = enable, 0 = disable */ + /* 1 = enable, 0 = disable */ + u16 enable; } __packed; struct net_pkt_macaddr { void *context; - u8 macaddr[MAX_MACADDR_LEN]; /* 6 bytes */ + /* 6 bytes */ + u8 macaddr[MAX_MACADDR_LEN]; } __packed; -/* cmd rsp packet used for VNIC network traffic */ +/* + * struct uiscmdrsp_net - cmd rsp packet used for VNIC network traffic. + * @enum type: + * @*buf: + * @union: + * @struct xmt: Used for NET_XMIT. + * @struct xmtdone: Used for NET_XMIT_DONE. + * @struct rcvpost: Used for NET_RCV_POST. + * @struct rcv: Used for NET_RCV. + * @struct enbdis: Used for NET_RCV_ENBDIS, NET_RCV_ENBDIS_ACK, + * NET_RCV_PROMSIC, and NET_CONNECT_STATUS. + * @struct macaddr: + */ struct uiscmdrsp_net { enum net_types type; void *buf; union { - struct net_pkt_xmt xmt; /* used for NET_XMIT */ - struct net_pkt_xmtdone xmtdone; /* used for NET_XMIT_DONE */ - struct net_pkt_rcvpost rcvpost; /* used for NET_RCV_POST */ - struct net_pkt_rcv rcv; /* used for NET_RCV */ - struct net_pkt_enbdis enbdis; /* used for NET_RCV_ENBDIS, */ - /* NET_RCV_ENBDIS_ACK, */ - /* NET_RCV_PROMSIC, */ - /* and NET_CONNECT_STATUS */ + struct net_pkt_xmt xmt; + struct net_pkt_xmtdone xmtdone; + struct net_pkt_rcvpost rcvpost; + struct net_pkt_rcv rcv; + struct net_pkt_enbdis enbdis; struct net_pkt_macaddr macaddr; }; } __packed; +/* + * struct uiscmdrsp_scsitaskmgmt + * @enum tasktype: The type of task. + * @struct vdest: The vdisk for which this task mgmt is generated. + * @handle: This is a handle that the guest has saved off for its + * own use. The handle value is preserved by iopart and + * returned as in task mgmt rsp. + * @notify_handle: For Linux guests, this is a pointer to wait_queue_head + * that a thread is waiting on to see if the taskmgmt + * command has completed. When the rsp is received by + * guest, the thread receiving the response uses this to + * notify the thread waiting for taskmgmt command + * completion. It's value is preserved by iopart and + * returned as in the task mgmt rsp. + * @notifyresult_handle: This is a handle to the location in the guest where + * the result of the taskmgmt command (result field) is + * saved to when the response is handled. It's value is + * preserved by iopart and returned as is in the task mgmt + * rsp. + * @result: Result of taskmgmt command - set by IOPart. + */ struct uiscmdrsp_scsitaskmgmt { - /* The type of task. */ enum task_mgmt_types tasktype; - - /* The vdisk for which this task mgmt is generated. */ struct uisscsi_dest vdest; - - /* - * This is a handle that the guest has saved off for its own use. - * The handle value is preserved by iopart and returned as in task - * mgmt rsp. - */ u64 handle; - - /* - * For Linux guests, this is a pointer to wait_queue_head that a - * thread is waiting on to see if the taskmgmt command has completed. - * When the rsp is received by guest, the thread receiving the - * response uses this to notify the thread waiting for taskmgmt - * command completion. It's value is preserved by iopart and returned - * as in the task mgmt rsp. - */ u64 notify_handle; - - /* - * This is a handle to the location in the guest where the result of - * the taskmgmt command (result field) is saved to when the response - * is handled. It's value is preserved by iopart and returned as in - * the task mgmt rsp. - */ u64 notifyresult_handle; - - /* Result of taskmgmt command - set by IOPart - values are: */ char result; #define TASK_MGMT_FAILED 0 } __packed; -/* Used by uissd to send disk add/remove notifications to Guest. */ -/* Note that the vHba pointer is not used by the Client/Guest side. */ -struct uiscmdrsp_disknotify { - u8 add; /* 0-remove, 1-add */ - void *v_hba; /* channel info to route msg */ - u32 channel, id, lun; /* SCSI Path of Disk to added or removed */ -} __packed; - /* - * The following is used by virthba/vSCSI to send the Acquire/Release commands - * to the IOVM. + * struct uiscmdrsp_disknotify - Used by uissd to send disk add/remove + * notifications to Guest. + * @add: 0-remove, 1-add. + * @*v_hba: Channel info to route msg. + * @channel: SCSI Path of Disk to added or removed. + * @id: SCSI Path of Disk to added or removed. + * @lun: SCSI Path of Disk to added or removed. + * + * Note that the vHba pointer is not used by the Client/Guest side. */ -struct uiscmdrsp_vdiskmgmt { - /* The type of task */ - enum vdisk_mgmt_types vdisktype; - - /* The vdisk for which this task mgmt is generated */ - struct uisscsi_dest vdest; - - /* - * This is a handle that the guest has saved off for its own use. It's - * value is preserved by iopart and returned as in the task mgmt rsp. - */ - u64 handle; - - /* - * For Linux guests, this is a pointer to wait_queue_head that a - * thread is waiting on to see if the tskmgmt command has completed. - * When the rsp is received by guest, the thread receiving the - * response uses this to notify the thread waiting for taskmgmt - * command completion. It's value is preserved by iopart and returned - * as in the task mgmt rsp. - */ - u64 notify_handle; - - /* - * Handle to the location in guest where the result of the - * taskmgmt command (result field) is saved to when the response - * is handled. It's value is preserved by iopart and returned as in - * the task mgmt rsp. - */ - u64 notifyresult_handle; - - /* Result of taskmgmt command - set by IOPart - values are: */ - char result; +struct uiscmdrsp_disknotify { + u8 add; + void *v_hba; + u32 channel, id, lun; } __packed; /* Keeping cmd and rsp info in one structure for now cmd rsp packet for SCSI */ struct uiscmdrsp { char cmdtype; - -/* Describes what type of information is in the struct */ + /* Describes what type of information is in the struct */ #define CMD_SCSI_TYPE 1 #define CMD_NET_TYPE 2 #define CMD_SCSITASKMGMT_TYPE 3 #define CMD_NOTIFYGUEST_TYPE 4 -#define CMD_VDISKMGMT_TYPE 5 union { struct uiscmdrsp_scsi scsi; struct uiscmdrsp_net net; struct uiscmdrsp_scsitaskmgmt scsitaskmgmt; struct uiscmdrsp_disknotify disknotify; - struct uiscmdrsp_vdiskmgmt vdiskmgmt; }; /* Send the response when the cmd is done (scsi and scsittaskmgmt). */ void *private_data; - struct uiscmdrsp *next; /* General Purpose Queue Link */ - struct uiscmdrsp *activeQ_next; /* Pointer to the nextactive commands */ - struct uiscmdrsp *activeQ_prev; /* Pointer to the prevactive commands */ + /* General Purpose Queue Link */ + struct uiscmdrsp *next; + /* Pointer to the nextactive commands */ + struct uiscmdrsp *activeQ_next; + /* Pointer to the prevactive commands */ + struct uiscmdrsp *activeQ_prev; } __packed; +/* total = 28 bytes */ struct iochannel_vhba { - struct vhba_wwnn wwnn; /* 8 bytes */ - struct vhba_config_max max; /* 20 bytes */ -} __packed; /* total = 28 bytes */ + /* 8 bytes */ + struct vhba_wwnn wwnn; + /* 20 bytes */ + struct vhba_config_max max; +} __packed; + struct iochannel_vnic { - u8 macaddr[6]; /* 6 bytes */ - u32 num_rcv_bufs; /* 4 bytes */ - u32 mtu; /* 4 bytes */ - uuid_le zone_uuid; /* 16 bytes */ + /* 6 bytes */ + u8 macaddr[6]; + /* 4 bytes */ + u32 num_rcv_bufs; + /* 4 bytes */ + u32 mtu; + /* 16 bytes */ + guid_t zone_guid; } __packed; + /* * This is just the header of the IO channel. It is assumed that directly after * this header there is a large region of memory which contains the command and @@ -544,10 +573,11 @@ struct visor_io_channel { } __packed; /* INLINE functions for initializing and accessing I/O data channels. */ -#define SIZEOF_CMDRSP (COVER(sizeof(struct uiscmdrsp), 64)) +#define SIZEOF_CMDRSP (64 * DIV_ROUND_UP(sizeof(struct uiscmdrsp), 64)) /* Use 4K page sizes when passing page info between Guest and IOPartition. */ #define PI_PAGE_SIZE 0x1000 #define PI_PAGE_MASK 0x0FFF -#endif /* __IOCHANNEL_H__ */ +/* __IOCHANNEL_H__ */ +#endif diff --git a/drivers/staging/unisys/include/visorbus.h b/drivers/staging/unisys/include/visorbus.h index de0635542fbd..e4ee38c3dbe4 100644 --- a/drivers/staging/unisys/include/visorbus.h +++ b/drivers/staging/unisys/include/visorbus.h @@ -1,5 +1,4 @@ -/* visorbus.h - * +/* * Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * @@ -23,7 +22,6 @@ * * There should be nothing in this file that is private to the visorbus * bus implementation itself. - * */ #ifndef __VISORBUS_H__ @@ -31,20 +29,16 @@ #include <linux/device.h> #include <linux/module.h> -#include <linux/poll.h> -#include <linux/kernel.h> -#include <linux/uuid.h> -#include <linux/seq_file.h> #include <linux/slab.h> #include "channel.h" -struct visor_driver; struct visor_device; extern struct bus_type visorbus_type; typedef void (*visorbus_state_complete_func) (struct visor_device *dev, int status); + struct visorchipset_state { u32 created:1; u32 attached:1; @@ -54,11 +48,12 @@ struct visorchipset_state { /* Remaining bits in this 32-bit word are unused. */ }; -/** This struct describes a specific Supervisor channel, by providing its - * GUID, name, and sizes. +/* + * This struct describes a specific Supervisor channel, by providing its + * GUID, name, and sizes. */ struct visor_channeltype_descriptor { - const uuid_le guid; + const guid_t guid; const char *name; }; @@ -109,8 +104,7 @@ struct visor_driver { struct device_driver driver; }; -#define to_visor_driver(x) ((x) ? \ - (container_of(x, struct visor_driver, driver)) : (NULL)) +#define to_visor_driver(x) (container_of(x, struct visor_driver, driver)) /** * struct visor_device - A device type for things "plugged" into the visorbus @@ -125,8 +119,8 @@ struct visor_driver { * activity. * @being_removed: Indicates that the device is being removed from * the bus. Private bus driver use only. - * @visordriver_callback_lock: Used by the bus driver to lock when handling - * channel events. + * @visordriver_callback_lock: Used by the bus driver to lock when adding and + * removing devices. * @pausing: Indicates that a change towards a paused state. * is in progress. Only modified by the bus driver. * @resuming: Indicates that a change towards a running state @@ -141,37 +135,42 @@ struct visor_driver { * hypervisor requests. * @vbus_hdr_info: A pointer to header info. Private use by bus * driver. - * @partition_uuid: Indicates client partion id. This should be the + * @partition_guid: Indicates client partion id. This should be the * same across all visor_devices in the current * guest. Private use by bus driver only. */ struct visor_device { struct visorchannel *visorchannel; - uuid_le channel_type_guid; + guid_t channel_type_guid; /* These fields are for private use by the bus driver only. */ struct device device; struct list_head list_all; struct timer_list timer; bool timer_active; bool being_removed; - struct mutex visordriver_callback_lock; + struct mutex visordriver_callback_lock; /* synchronize probe/remove */ bool pausing; bool resuming; u32 chipset_bus_no; u32 chipset_dev_no; struct visorchipset_state state; - uuid_le inst; + guid_t inst; u8 *name; struct controlvm_message_header *pending_msg_hdr; void *vbus_hdr_info; - uuid_le partition_uuid; + guid_t partition_guid; struct dentry *debugfs_dir; struct dentry *debugfs_client_bus_info; }; #define to_visor_device(x) container_of(x, struct visor_device, device) +int visor_check_channel(struct channel_header *ch, struct device *dev, + const guid_t *expected_uuid, char *chname, + u64 expected_min_bytes, u32 expected_version, + u64 expected_signature); + int visorbus_register_visor_driver(struct visor_driver *drv); void visorbus_unregister_visor_driver(struct visor_driver *drv); int visorbus_read_channel(struct visor_device *dev, @@ -183,7 +182,8 @@ int visorbus_write_channel(struct visor_device *dev, int visorbus_enable_channel_interrupts(struct visor_device *dev); void visorbus_disable_channel_interrupts(struct visor_device *dev); -/* Levels of severity for diagnostic events, in order from lowest severity to +/* + * Levels of severity for diagnostic events, in order from lowest severity to * highest (i.e. fatal errors are the most severe, and should always be logged, * but info events rarely need to be logged except during debugging). The * values DIAG_SEVERITY_ENUM_BEGIN and DIAG_SEVERITY_ENUM_END are not valid @@ -207,7 +207,7 @@ int visorchannel_signalremove(struct visorchannel *channel, u32 queue, int visorchannel_signalinsert(struct visorchannel *channel, u32 queue, void *msg); bool visorchannel_signalempty(struct visorchannel *channel, u32 queue); -uuid_le visorchannel_get_uuid(struct visorchannel *channel); +const guid_t *visorchannel_get_guid(struct visorchannel *channel); #define BUS_ROOT_DEVICE UINT_MAX struct visor_device *visorbus_get_device_by_id(u32 bus_no, u32 dev_no, diff --git a/drivers/staging/unisys/visorbus/controlvmchannel.h b/drivers/staging/unisys/visorbus/controlvmchannel.h index ed045eff0e33..32ff5c1bb6ba 100644 --- a/drivers/staging/unisys/visorbus/controlvmchannel.h +++ b/drivers/staging/unisys/visorbus/controlvmchannel.h @@ -1,4 +1,5 @@ -/* Copyright (C) 2010 - 2015 UNISYS CORPORATION +/* + * Copyright (C) 2010 - 2015 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify it @@ -19,60 +20,55 @@ #include "channel.h" /* {2B3C2D10-7EF5-4ad8-B966-3448B7386B3D} */ -#define VISOR_CONTROLVM_CHANNEL_UUID \ - UUID_LE(0x2b3c2d10, 0x7ef5, 0x4ad8, \ - 0xb9, 0x66, 0x34, 0x48, 0xb7, 0x38, 0x6b, 0x3d) +#define VISOR_CONTROLVM_CHANNEL_GUID \ + GUID_INIT(0x2b3c2d10, 0x7ef5, 0x4ad8, \ + 0xb9, 0x66, 0x34, 0x48, 0xb7, 0x38, 0x6b, 0x3d) -#define VISOR_CONTROLVM_CHANNEL_SIGNATURE VISOR_CHANNEL_SIGNATURE #define CONTROLVM_MESSAGE_MAX 64 -/* Must increment this whenever you insert or delete fields within - * this channel struct. Also increment whenever you change the meaning - * of fields within this channel struct so as to break pre-existing - * software. Note that you can usually add fields to the END of the - * channel struct withOUT needing to increment this. +/* + * Must increment this whenever you insert or delete fields within this channel + * struct. Also increment whenever you change the meaning of fields within this + * channel struct so as to break pre-existing software. Note that you can + * usually add fields to the END of the channel struct withOUT needing to + * increment this. */ #define VISOR_CONTROLVM_CHANNEL_VERSIONID 1 -#define VISOR_CONTROLVM_CHANNEL_OK_CLIENT(ch) \ - (visor_check_channel(ch, \ - VISOR_CONTROLVM_CHANNEL_UUID, \ - "controlvm", \ - sizeof(struct visor_controlvm_channel), \ - VISOR_CONTROLVM_CHANNEL_VERSIONID, \ - VISOR_CONTROLVM_CHANNEL_SIGNATURE)) - /* Defines for various channel queues */ -#define CONTROLVM_QUEUE_REQUEST 0 -#define CONTROLVM_QUEUE_RESPONSE 1 -#define CONTROLVM_QUEUE_EVENT 2 -#define CONTROLVM_QUEUE_ACK 3 +#define CONTROLVM_QUEUE_REQUEST 0 +#define CONTROLVM_QUEUE_RESPONSE 1 +#define CONTROLVM_QUEUE_EVENT 2 +#define CONTROLVM_QUEUE_ACK 3 /* Max num of messages stored during IOVM creation to be reused after crash */ #define CONTROLVM_CRASHMSG_MAX 2 +/* + * struct visor_segment_state + * @enabled: May enter other states. + * @active: Assigned to active partition. + * @alive: Configure message sent to service/server. + * @revoked: Similar to partition state ShuttingDown. + * @allocated: Memory (device/port number) has been selected by Command. + * @known: Has been introduced to the service/guest partition. + * @ready: Service/Guest partition has responded to introduction. + * @operating: Resource is configured and operating. + * @reserved: Natural alignment. + * + * Note: Don't use high bit unless we need to switch to ushort which is + * non-compliant. + */ struct visor_segment_state { - /* Bit 0: May enter other states */ u16 enabled:1; - /* Bit 1: Assigned to active partition */ u16 active:1; - /* Bit 2: Configure message sent to service/server */ u16 alive:1; - /* Bit 3: similar to partition state ShuttingDown */ u16 revoked:1; - /* Bit 4: memory (device/port number) has been selected by Command */ u16 allocated:1; - /* Bit 5: has been introduced to the service/guest partition */ u16 known:1; - /* Bit 6: service/Guest partition has responded to introduction */ u16 ready:1; - /* Bit 7: resource is configured and operating */ u16 operating:1; - /* Natural alignment*/ u16 reserved:8; -/* Note: don't use high bit unless we need to switch to ushort - * which is non-compliant - */ } __packed; static const struct visor_segment_state segment_state_running = { @@ -87,74 +83,101 @@ static const struct visor_segment_state segment_state_standby = { 1, 1, 0, 0, 1, 1, 1, 0 }; -/* Ids for commands that may appear in either queue of a ControlVm channel. +/* + * enum controlvm_id + * @CONTROLVM_INVALID: + * @CONTROLVM_BUS_CREATE: CP --> SP, GP. + * @CONTROLVM_BUS_DESTROY: CP --> SP, GP. + * @CONTROLVM_BUS_CONFIGURE: CP --> SP. + * @CONTROLVM_BUS_CHANGESTATE: CP --> SP, GP. + * @CONTROLVM_BUS_CHANGESTATE_EVENT: SP, GP --> CP. + * @CONTROLVM_DEVICE_CREATE: CP --> SP, GP. + * @CONTROLVM_DEVICE_DESTROY: CP --> SP, GP. + * @CONTROLVM_DEVICE_CONFIGURE: CP --> SP. + * @CONTROLVM_DEVICE_CHANGESTATE: CP --> SP, GP. + * @CONTROLVM_DEVICE_CHANGESTATE_EVENT: SP, GP --> CP. + * @CONTROLVM_DEVICE_RECONFIGURE: CP --> Boot. + * @CONTROLVM_CHIPSET_INIT: CP --> SP, GP. + * @CONTROLVM_CHIPSET_STOP: CP --> SP, GP. + * @CONTROLVM_CHIPSET_READY: CP --> SP. + * @CONTROLVM_CHIPSET_SELFTEST: CP --> SP. * - * Commands that are initiated by the command partition (CP), by an IO or - * console service partition (SP), or by a guest partition (GP)are: - * - issued on the RequestQueue queue (q #0) in the ControlVm channel - * - responded to on the ResponseQueue queue (q #1) in the ControlVm channel + * Ids for commands that may appear in either queue of a ControlVm channel. * - * Events that are initiated by an IO or console service partition (SP) or - * by a guest partition (GP) are: - * - issued on the EventQueue queue (q #2) in the ControlVm channel - * - responded to on the EventAckQueue queue (q #3) in the ControlVm channel + * Commands that are initiated by the command partition (CP), by an IO or + * console service partition (SP), or by a guest partition (GP) are: + * - issued on the RequestQueue queue (q #0) in the ControlVm channel + * - responded to on the ResponseQueue queue (q #1) in the ControlVm channel + * + * Events that are initiated by an IO or console service partition (SP) or + * by a guest partition (GP) are: + * - issued on the EventQueue queue (q #2) in the ControlVm channel + * - responded to on the EventAckQueue queue (q #3) in the ControlVm channel */ enum controlvm_id { CONTROLVM_INVALID = 0, - /* SWITCH commands required Parameter: SwitchNumber */ - /* BUS commands required Parameter: BusNumber */ - CONTROLVM_BUS_CREATE = 0x101, /* CP --> SP, GP */ - CONTROLVM_BUS_DESTROY = 0x102, /* CP --> SP, GP */ - CONTROLVM_BUS_CONFIGURE = 0x104, /* CP --> SP */ - CONTROLVM_BUS_CHANGESTATE = 0x105, /* CP --> SP, GP */ - CONTROLVM_BUS_CHANGESTATE_EVENT = 0x106, /* SP, GP --> CP */ -/* DEVICE commands required Parameter: BusNumber, DeviceNumber */ - - CONTROLVM_DEVICE_CREATE = 0x201, /* CP --> SP, GP */ - CONTROLVM_DEVICE_DESTROY = 0x202, /* CP --> SP, GP */ - CONTROLVM_DEVICE_CONFIGURE = 0x203, /* CP --> SP */ - CONTROLVM_DEVICE_CHANGESTATE = 0x204, /* CP --> SP, GP */ - CONTROLVM_DEVICE_CHANGESTATE_EVENT = 0x205, /* SP, GP --> CP */ - CONTROLVM_DEVICE_RECONFIGURE = 0x206, /* CP --> Boot */ -/* CHIPSET commands */ - CONTROLVM_CHIPSET_INIT = 0x301, /* CP --> SP, GP */ - CONTROLVM_CHIPSET_STOP = 0x302, /* CP --> SP, GP */ - CONTROLVM_CHIPSET_READY = 0x304, /* CP --> SP */ - CONTROLVM_CHIPSET_SELFTEST = 0x305, /* CP --> SP */ - + /* + * SWITCH commands required Parameter: SwitchNumber. + * BUS commands required Parameter: BusNumber + */ + CONTROLVM_BUS_CREATE = 0x101, + CONTROLVM_BUS_DESTROY = 0x102, + CONTROLVM_BUS_CONFIGURE = 0x104, + CONTROLVM_BUS_CHANGESTATE = 0x105, + CONTROLVM_BUS_CHANGESTATE_EVENT = 0x106, + /* DEVICE commands required Parameter: BusNumber, DeviceNumber */ + CONTROLVM_DEVICE_CREATE = 0x201, + CONTROLVM_DEVICE_DESTROY = 0x202, + CONTROLVM_DEVICE_CONFIGURE = 0x203, + CONTROLVM_DEVICE_CHANGESTATE = 0x204, + CONTROLVM_DEVICE_CHANGESTATE_EVENT = 0x205, + CONTROLVM_DEVICE_RECONFIGURE = 0x206, + /* CHIPSET commands */ + CONTROLVM_CHIPSET_INIT = 0x301, + CONTROLVM_CHIPSET_STOP = 0x302, + CONTROLVM_CHIPSET_READY = 0x304, + CONTROLVM_CHIPSET_SELFTEST = 0x305, }; +/* + * struct irq_info + * @reserved1: Natural alignment purposes + * @recv_irq_handle: Specifies interrupt handle. It is used to retrieve the + * corresponding interrupt pin from Monitor; and the interrupt + * pin is used to connect to the corresponding interrupt. + * Used by IOPart-GP only. + * @recv_irq_vector: Specifies interrupt vector. It, interrupt pin, and shared + * are used to connect to the corresponding interrupt. + * Used by IOPart-GP only. + * @recv_irq_shared: Specifies if the recvInterrupt is shared. It, interrupt + * pin and vector are used to connect to 0 = not shared; + * 1 = shared the corresponding interrupt. + * Used by IOPart-GP only. + * @reserved: Natural alignment purposes + */ struct irq_info { u64 reserved1; - - /* specifies interrupt handle. It is used to retrieve the - * corresponding interrupt pin from Monitor; and the - * interrupt pin is used to connect to the corresponding - * interrupt. Used by IOPart-GP only. - */ u64 recv_irq_handle; - - /* specifies interrupt vector. It, interrupt pin, and shared are - * used to connect to the corresponding interrupt. Used by - * IOPart-GP only. - */ u32 recv_irq_vector; - - /* specifies if the recvInterrupt is shared. It, interrupt pin - * and vector are used to connect to 0 = not shared; 1 = shared. - * the corresponding interrupt. Used by IOPart-GP only. - */ u8 recv_irq_shared; - u8 reserved[3]; /* Natural alignment purposes */ + u8 reserved[3]; } __packed; +/* + * struct efi_visor_indication + * @boot_to_fw_ui: Stop in UEFI UI + * @clear_nvram: Clear NVRAM + * @clear_cmos: Clear CMOS + * @boot_to_tool: Run install tool + * @reserved: Natural alignment + */ struct efi_visor_indication { - u64 boot_to_fw_ui:1; /* Bit 0: Stop in uefi ui */ - u64 clear_nvram:1; /* Bit 1: Clear NVRAM */ - u64 clear_cmos:1; /* Bit 2: Clear CMOS */ - u64 boot_to_tool:1; /* Bit 3: Run install tool */ - /* remaining bits are available */ - u64 reserved:60; /* Natural alignment */ + u64 boot_to_fw_ui:1; + u64 clear_nvram:1; + u64 clear_cmos:1; + u64 boot_to_tool:1; + /* Remaining bits are available */ + u64 reserved:60; } __packed; enum visor_chipset_feature { @@ -162,182 +185,248 @@ enum visor_chipset_feature { VISOR_CHIPSET_FEATURE_PARA_HOTPLUG = 0x00000002, }; -/* This is the common structure that is at the beginning of every - * ControlVm message (both commands and responses) in any ControlVm - * queue. Commands are easily distinguished from responses by - * looking at the flags.response field. +/* + * struct controlvm_message_header + * @id: See CONTROLVM_ID. + * @message_size: Includes size of this struct + size of message. + * @segment_index: Index of segment containing Vm message/information. + * @completion_status: Error status code or result of message completion. + * @struct flags: + * @failed: =1 in a response to signify failure. + * @response_expected: =1 in all messages that expect a response. + * @server: =1 in all bus & device-related messages where the + * message receiver is to act as the bus or device + * server. + * @test_message: =1 for testing use only (Control and Command + * ignore this). + * @partial_completion: =1 if there are forthcoming responses/acks + * associated with this message. + * @preserve: =1 this is to let us know to preserve channel + * contents. + * @writer_in_diag: =1 the DiagWriter is active in the Diagnostic + * Partition. + * @reserve: Natural alignment. + * @reserved: Natural alignment. + * @message_handle: Identifies the particular message instance. + * @payload_vm_offset: Offset of payload area from start of this instance. + * @payload_max_bytes: Maximum bytes allocated in payload area of ControlVm + * segment. + * @payload_bytes: Actual number of bytes of payload area to copy between + * IO/Command. If non-zero, there is a payload to copy. + * + * This is the common structure that is at the beginning of every + * ControlVm message (both commands and responses) in any ControlVm + * queue. Commands are easily distinguished from responses by + * looking at the flags.response field. */ struct controlvm_message_header { - u32 id; /* See CONTROLVM_ID. */ - /* For requests, indicates the message type. */ - /* For responses, indicates the type of message we are responding to. */ - - /* Includes size of this struct + size of message */ + u32 id; + /* + * For requests, indicates the message type. For responses, indicates + * the type of message we are responding to. + */ u32 message_size; - /* Index of segment containing Vm message/information */ u32 segment_index; - /* Error status code or result of message completion */ u32 completion_status; struct { - /* =1 in a response to signify failure */ u32 failed:1; - /* =1 in all messages that expect a response */ u32 response_expected:1; - /* =1 in all bus & device-related messages where the message - * receiver is to act as the bus or device server - */ u32 server:1; - /* =1 for testing use only (Control and Command ignore this */ u32 test_message:1; - /* =1 if there are forthcoming responses/acks associated - * with this message - */ u32 partial_completion:1; - /* =1 this is to let us know to preserve channel contents */ u32 preserve:1; - /* =1 the DiagWriter is active in the Diagnostic Partition */ u32 writer_in_diag:1; - /* Natural alignment */ u32 reserve:25; } __packed flags; - /* Natural alignment */ u32 reserved; - /* Identifies the particular message instance */ u64 message_handle; - /* request instances with the corresponding response instance. */ - /* Offset of payload area from start of this instance */ u64 payload_vm_offset; - /* Maximum bytes allocated in payload area of ControlVm segment */ u32 payload_max_bytes; - /* Actual number of bytes of payload area to copy between IO/Command */ u32 payload_bytes; - /* if non-zero, there is a payload to copy. */ } __packed; +/* + * struct controlvm_packet_device_create - For CONTROLVM_DEVICE_CREATE + * @bus_no: Bus # (0..n-1) from the msg receiver's end. + * @dev_no: Bus-relative (0..n-1) device number. + * @channel_addr: Guest physical address of the channel, which can be + * dereferenced by the receiver of this ControlVm command. + * @channel_bytes: Specifies size of the channel in bytes. + * @data_type_uuid: Specifies format of data in channel. + * @dev_inst_uuid: Instance guid for the device. + * @irq_info intr: Specifies interrupt information. + */ struct controlvm_packet_device_create { - u32 bus_no; /* bus # (0..n-1) from the msg receiver's end */ - u32 dev_no; /* bus-relative (0..n-1) device number */ - /* Guest physical address of the channel, which can be dereferenced by - * the receiver of this ControlVm command - */ + u32 bus_no; + u32 dev_no; u64 channel_addr; - u64 channel_bytes; /* specifies size of the channel in bytes */ - uuid_le data_type_uuid; /* specifies format of data in channel */ - uuid_le dev_inst_uuid; /* instance guid for the device */ - struct irq_info intr; /* specifies interrupt information */ -} __packed; /* for CONTROLVM_DEVICE_CREATE */ + u64 channel_bytes; + guid_t data_type_guid; + guid_t dev_inst_guid; + struct irq_info intr; +} __packed; +/* + * struct controlvm_packet_device_configure - For CONTROLVM_DEVICE_CONFIGURE + * @bus_no: Bus number (0..n-1) from the msg receiver's perspective. + * @dev_no: Bus-relative (0..n-1) device number. + */ struct controlvm_packet_device_configure { - /* bus # (0..n-1) from the msg receiver's perspective */ u32 bus_no; - /* Control uses header SegmentIndex field to access bus number... */ - u32 dev_no; /* bus-relative (0..n-1) device number */ -} __packed; /* for CONTROLVM_DEVICE_CONFIGURE */ + u32 dev_no; +} __packed; +/* Total 128 bytes */ struct controlvm_message_device_create { struct controlvm_message_header header; struct controlvm_packet_device_create packet; -} __packed; /* total 128 bytes */ +} __packed; +/* Total 56 bytes */ struct controlvm_message_device_configure { struct controlvm_message_header header; struct controlvm_packet_device_configure packet; -} __packed; /* total 56 bytes */ +} __packed; -/* This is the format for a message in any ControlVm queue. */ +/* + * struct controlvm_message_packet - This is the format for a message in any + * ControlVm queue. + * @struct create_bus: For CONTROLVM_BUS_CREATE. + * @bus_no: Bus # (0..n-1) from the msg receiver's perspective. + * @dev_count: Indicates the max number of devices on this bus. + * @channel_addr: Guest physical address of the channel, which can be + * dereferenced by the receiver of this ControlVM + * command. + * @channel_bytes: Size of the channel. + * @bus_data_type_uuid: Indicates format of data in bus channel. + * @bus_inst_uuid: Instance uuid for the bus. + * + * @struct destroy_bus: For CONTROLVM_BUS_DESTROY. + * @bus_no: Bus # (0..n-1) from the msg receiver's perspective. + * @reserved: Natural alignment purposes. + * + * @struct configure_bus: For CONTROLVM_BUS_CONFIGURE. + * @bus_no: Bus # (0..n-1) from the receiver's perspective. + * @reserved1: For alignment purposes. + * @guest_handle: This is used to convert guest physical address to + * physical address. + * @recv_bus_irq_handle: Specifies interrupt info. It is used by SP to + * register to receive interrupts from the CP. This + * interrupt is used for bus level notifications. + * The corresponding sendBusInterruptHandle is kept + * in CP. + * + * @struct create_device: For CONTROLVM_DEVICE_CREATE. + * + * @struct destroy_device: For CONTROLVM_DEVICE_DESTROY. + * @bus_no: Bus # (0..n-1) from the msg receiver's perspective. + * @dev_no: Bus-relative (0..n-1) device number. + * + * @struct configure_device: For CONTROLVM_DEVICE_CONFIGURE. + * + * @struct reconfigure_device: For CONTROLVM_DEVICE_RECONFIGURE. + * @bus_no: Bus # (0..n-1) from the msg receiver's perspective. + * @dev_no: Bus-relative (0..n-1) device number. + * + * @struct bus_change_state: For CONTROLVM_BUS_CHANGESTATE. + * @bus_no: + * @struct state: + * @reserved: Natural alignment purposes. + * + * @struct device_change_state: For CONTROLVM_DEVICE_CHANGESTATE. + * @bus_no: + * @dev_no: + * @struct state: + * @struct flags: + * @phys_device: =1 if message is for a physical device. + * @reserved: Natural alignment. + * @reserved1: Natural alignment. + * @reserved: Natural alignment purposes. + * + * @struct device_change_state_event: For CONTROLVM_DEVICE_CHANGESTATE_EVENT. + * @bus_no: + * @dev_no: + * @struct state: + * @reserved: Natural alignment purposes. + * + * @struct init_chipset: For CONTROLVM_CHIPSET_INIT. + * @bus_count: Indicates the max number of busses. + * @switch_count: Indicates the max number of switches. + * @enum features: + * @platform_number: + * + * @struct chipset_selftest: For CONTROLVM_CHIPSET_SELFTEST. + * @options: Reserved. + * @test: Bit 0 set to run embedded selftest. + * + * @addr: A physical address of something, that can be dereferenced by the + * receiver of this ControlVm command. + * + * @handle: A handle of something (depends on command id). + */ struct controlvm_message_packet { union { struct { - /* bus # (0..n-1) from the msg receiver's perspective */ u32 bus_no; - /* indicates the max number of devices on this bus */ u32 dev_count; - /* Guest physical address of the channel, which can be - * dereferenced by the receiver of this ControlVm command - */ u64 channel_addr; - u64 channel_bytes; /* size of the channel */ - /* indicates format of data in bus channel*/ - uuid_le bus_data_type_uuid; - uuid_le bus_inst_uuid; /* instance uuid for the bus */ - } __packed create_bus; /* for CONTROLVM_BUS_CREATE */ + u64 channel_bytes; + guid_t bus_data_type_guid; + guid_t bus_inst_guid; + } __packed create_bus; struct { - /* bus # (0..n-1) from the msg receiver's perspective */ u32 bus_no; - u32 reserved; /* Natural alignment purposes */ - } __packed destroy_bus; /* for CONTROLVM_BUS_DESTROY */ + u32 reserved; + } __packed destroy_bus; struct { - /* bus # (0..n-1) from the receiver's perspective */ u32 bus_no; - u32 reserved1; /* for alignment purposes */ - /* This is used to convert guest physical address to physical address */ + u32 reserved1; u64 guest_handle; u64 recv_bus_irq_handle; - /* specifies interrupt info. It is used by SP - * to register to receive interrupts from the - * CP. This interrupt is used for bus level - * notifications. The corresponding - * sendBusInterruptHandle is kept in CP. - */ - } __packed configure_bus; /* for CONTROLVM_BUS_CONFIGURE */ - /* for CONTROLVM_DEVICE_CREATE */ + } __packed configure_bus; struct controlvm_packet_device_create create_device; struct { - /* bus # (0..n-1) from the msg receiver's perspective */ u32 bus_no; - u32 dev_no; /* bus-relative (0..n-1) device # */ - } __packed destroy_device; /* for CONTROLVM_DEVICE_DESTROY */ - /* for CONTROLVM_DEVICE_CONFIGURE */ + u32 dev_no; + } __packed destroy_device; struct controlvm_packet_device_configure configure_device; struct { - /* bus # (0..n-1) from the msg receiver's perspective */ u32 bus_no; - u32 dev_no; /* bus-relative (0..n-1) device # */ + u32 dev_no; } __packed reconfigure_device; - /* for CONTROLVM_DEVICE_RECONFIGURE */ struct { u32 bus_no; struct visor_segment_state state; - u8 reserved[2]; /* Natural alignment purposes */ - } __packed bus_change_state; /* for CONTROLVM_BUS_CHANGESTATE */ + u8 reserved[2]; + } __packed bus_change_state; struct { u32 bus_no; u32 dev_no; struct visor_segment_state state; struct { - /* =1 if message is for a physical device */ u32 phys_device:1; - u32 reserved:31; /* Natural alignment */ - u32 reserved1; /* Natural alignment */ + u32 reserved:31; + u32 reserved1; } __packed flags; - u8 reserved[2]; /* Natural alignment purposes */ + u8 reserved[2]; } __packed device_change_state; - /* for CONTROLVM_DEVICE_CHANGESTATE */ struct { u32 bus_no; u32 dev_no; struct visor_segment_state state; - u8 reserved[6]; /* Natural alignment purposes */ + u8 reserved[6]; } __packed device_change_state_event; - /* for CONTROLVM_DEVICE_CHANGESTATE_EVENT */ struct { - /* indicates the max number of busses */ u32 bus_count; - /* indicates the max number of switches */ u32 switch_count; enum visor_chipset_feature features; - u32 platform_number; /* Platform Number */ - } __packed init_chipset; /* for CONTROLVM_CHIPSET_INIT */ + u32 platform_number; + } __packed init_chipset; struct { - u32 options; /* reserved */ - u32 test; /* bit 0 set to run embedded selftest */ + u32 options; + u32 test; } __packed chipset_selftest; - /* for CONTROLVM_CHIPSET_SELFTEST */ - /* a physical address of something, that can be dereferenced - * by the receiver of this ControlVm command - */ u64 addr; - /* a handle of something (depends on command id) */ u64 handle; }; } __packed; @@ -348,93 +437,139 @@ struct controlvm_message { struct controlvm_message_packet cmd; } __packed; +/* + * struct visor_controlvm_channel + * @struct header: + * @gp_controlvm: Guest phys addr of this channel. + * @gp_partition_tables: Guest phys addr of partition tables. + * @gp_diag_guest: Guest phys addr of diagnostic channel. + * @gp_boot_romdisk: Guest phys addr of (read* only) Boot + * ROM disk. + * @gp_boot_ramdisk: Guest phys addr of writable Boot RAM + * disk. + * @gp_acpi_table: Guest phys addr of acpi table. + * @gp_control_channel: Guest phys addr of control channel. + * @gp_diag_romdisk: Guest phys addr of diagnostic ROM disk. + * @gp_nvram: Guest phys addr of NVRAM channel. + * @request_payload_offset: Offset to request payload area. + * @event_payload_offset: Offset to event payload area. + * @request_payload_bytes: Bytes available in request payload area. + * @event_payload_bytes: Bytes available in event payload area. + * @control_channel_bytes: + * @nvram_channel_bytes: Bytes in PartitionNvram segment. + * @message_bytes: sizeof(CONTROLVM_MESSAGE). + * @message_count: CONTROLVM_MESSAGE_MAX. + * @gp_smbios_table: Guest phys addr of SMBIOS tables. + * @gp_physical_smbios_table: Guest phys addr of SMBIOS table. + * @gp_reserved: VISOR_MAX_GUESTS_PER_SERVICE. + * @virtual_guest_firmware_image_base: Guest physical address of EFI firmware + * image base. + * @virtual_guest_firmware_entry_point: Guest physical address of EFI firmware + * entry point. + * @virtual_guest_firmware_image_size: Guest EFI firmware image size. + * @virtual_guest_firmware_boot_base: GPA = 1MB where EFI firmware image is + * copied to. + * @virtual_guest_image_base: + * @virtual_guest_image_size: + * @prototype_control_channel_offset: + * @virtual_guest_partition_handle: + * @restore_action: Restore Action field to restore the + * guest partition. + * @dump_action: For Windows guests it shows if the + * visordisk is in dump mode. + * @nvram_fail_count: + * @saved_crash_message_count: = CONTROLVM_CRASHMSG_MAX. + * @saved_crash_message_offset: Offset to request payload area needed + * for crash dump. + * @installation_error: Type of error encountered during + * installation. + * @installation_text_id: Id of string to display. + * @installation_remaining_steps: Number of remaining installation steps + * (for progress bars). + * @tool_action: VISOR_TOOL_ACTIONS Installation Action + * field. + * @reserved: Alignment. + * @struct efi_visor_ind: + * @sp_reserved: + * @reserved2: Force signals to begin on 128-byte + * cache line. + * @struct request_queue: Guest partition uses this queue to send + * requests to Control. + * @struct response_queue: Control uses this queue to respond to + * service or guest partition request. + * @struct event_queue: Control uses this queue to send events + * to guest partition. + * @struct event_ack_queue: Service or guest partition uses this + * queue to ack Control events. + * @struct request_msg: Request fixed-size message pool - + * does not include payload. + * @struct response_msg: Response fixed-size message pool - + * does not include payload. + * @struct event_msg: Event fixed-size message pool - + * does not include payload. + * @struct event_ack_msg: Ack fixed-size message pool - + * does not include payload. + * @struct saved_crash_msg: Message stored during IOVM creation to + * be reused after crash. + */ struct visor_controlvm_channel { struct channel_header header; - u64 gp_controlvm; /* guest phys addr of this channel */ - u64 gp_partition_tables;/* guest phys addr of partition tables */ - u64 gp_diag_guest; /* guest phys addr of diagnostic channel */ - u64 gp_boot_romdisk;/* guest phys addr of (read* only) Boot ROM disk */ - u64 gp_boot_ramdisk;/* guest phys addr of writable Boot RAM disk */ - u64 gp_acpi_table; /* guest phys addr of acpi table */ - u64 gp_control_channel;/* guest phys addr of control channel */ - u64 gp_diag_romdisk;/* guest phys addr of diagnostic ROM disk */ - u64 gp_nvram; /* guest phys addr of NVRAM channel */ - u64 request_payload_offset; /* Offset to request payload area */ - u64 event_payload_offset; /* Offset to event payload area */ - /* Bytes available in request payload area */ + u64 gp_controlvm; + u64 gp_partition_tables; + u64 gp_diag_guest; + u64 gp_boot_romdisk; + u64 gp_boot_ramdisk; + u64 gp_acpi_table; + u64 gp_control_channel; + u64 gp_diag_romdisk; + u64 gp_nvram; + u64 request_payload_offset; + u64 event_payload_offset; u32 request_payload_bytes; - u32 event_payload_bytes;/* Bytes available in event payload area */ + u32 event_payload_bytes; u32 control_channel_bytes; - u32 nvram_channel_bytes; /* Bytes in PartitionNvram segment */ - u32 message_bytes; /* sizeof(CONTROLVM_MESSAGE) */ - u32 message_count; /* CONTROLVM_MESSAGE_MAX */ - u64 gp_smbios_table; /* guest phys addr of SMBIOS tables */ - u64 gp_physical_smbios_table; /* guest phys addr of SMBIOS table */ - /* VISOR_MAX_GUESTS_PER_SERVICE */ + u32 nvram_channel_bytes; + u32 message_bytes; + u32 message_count; + u64 gp_smbios_table; + u64 gp_physical_smbios_table; char gp_reserved[2688]; - - /* guest physical address of EFI firmware image base */ u64 virtual_guest_firmware_image_base; - - /* guest physical address of EFI firmware entry point */ u64 virtual_guest_firmware_entry_point; - - /* guest EFI firmware image size */ u64 virtual_guest_firmware_image_size; - - /* GPA = 1MB where EFI firmware image is copied to */ u64 virtual_guest_firmware_boot_base; u64 virtual_guest_image_base; u64 virtual_guest_image_size; u64 prototype_control_channel_offset; u64 virtual_guest_partition_handle; - /* Restore Action field to restore the guest partition */ u16 restore_action; - /* For Windows guests it shows if the visordisk is in dump mode */ u16 dump_action; u16 nvram_fail_count; - u16 saved_crash_message_count; /* = CONTROLVM_CRASHMSG_MAX */ - /* Offset to request payload area needed for crash dump */ + u16 saved_crash_message_count; u32 saved_crash_message_offset; - /* Type of error encountered during installation */ u32 installation_error; - u32 installation_text_id; /* Id of string to display */ - /* Number of remaining installation steps (for progress bars) */ + u32 installation_text_id; u16 installation_remaining_steps; - /* VISOR_TOOL_ACTIONS Installation Action field */ u8 tool_action; - u8 reserved; /* alignment */ + u8 reserved; struct efi_visor_indication efi_visor_ind; u32 sp_reserved; - /* Force signals to begin on 128-byte cache line */ u8 reserved2[28]; - /* guest partition uses this queue to send requests to Control */ struct signal_queue_header request_queue; - /* Control uses this queue to respond to service or guest - * partition requests - */ struct signal_queue_header response_queue; - /* Control uses this queue to send events to guest partition */ struct signal_queue_header event_queue; - /* Service or guest partition uses this queue to ack Control events */ struct signal_queue_header event_ack_queue; - /* Request fixed-size message pool - does not include payload */ - struct controlvm_message request_msg[CONTROLVM_MESSAGE_MAX]; - - /* Response fixed-size message pool - does not include payload */ - struct controlvm_message response_msg[CONTROLVM_MESSAGE_MAX]; - - /* Event fixed-size message pool - does not include payload */ - struct controlvm_message event_msg[CONTROLVM_MESSAGE_MAX]; - - /* Ack fixed-size message pool - does not include payload */ - struct controlvm_message event_ack_msg[CONTROLVM_MESSAGE_MAX]; - - /* Message stored during IOVM creation to be reused after crash */ - struct controlvm_message saved_crash_msg[CONTROLVM_CRASHMSG_MAX]; + struct controlvm_message request_msg[CONTROLVM_MESSAGE_MAX]; + struct controlvm_message response_msg[CONTROLVM_MESSAGE_MAX]; + struct controlvm_message event_msg[CONTROLVM_MESSAGE_MAX]; + struct controlvm_message event_ack_msg[CONTROLVM_MESSAGE_MAX]; + struct controlvm_message saved_crash_msg[CONTROLVM_CRASHMSG_MAX]; } __packed; -/* The following header will be located at the beginning of PayloadVmOffset for +/* + * struct visor_controlvm_parameters_header + * + * The following header will be located at the beginning of PayloadVmOffset for * various ControlVm commands. The receiver of a ControlVm command with a * PayloadVmOffset will dereference this address and then use connection_offset, * initiator_offset, and target_offset to get the location of UTF-8 formatted @@ -455,9 +590,10 @@ struct visor_controlvm_parameters_header { u32 client_length; u32 name_offset; u32 name_length; - uuid_le id; + guid_t id; u32 revision; - u32 reserved; /* Natural alignment */ + /* Natural alignment */ + u32 reserved; } __packed; /* General Errors------------------------------------------------------[0-99] */ @@ -467,72 +603,57 @@ struct visor_controlvm_parameters_header { #define CONTROLVM_RESP_KMALLOC_FAILED 3 #define CONTROLVM_RESP_ID_UNKNOWN 4 #define CONTROLVM_RESP_ID_INVALID_FOR_CLIENT 5 - /* CONTROLVM_INIT_CHIPSET-------------------------------------------[100-199] */ #define CONTROLVM_RESP_CLIENT_SWITCHCOUNT_NONZERO 100 #define CONTROLVM_RESP_EXPECTED_CHIPSET_INIT 101 - /* Maximum Limit----------------------------------------------------[200-299] */ -#define CONTROLVM_RESP_ERROR_MAX_BUSES 201 /* BUS_CREATE */ -#define CONTROLVM_RESP_ERROR_MAX_DEVICES 202 /* DEVICE_CREATE */ +/* BUS_CREATE */ +#define CONTROLVM_RESP_ERROR_MAX_BUSES 201 +/* DEVICE_CREATE */ +#define CONTROLVM_RESP_ERROR_MAX_DEVICES 202 /* Payload and Parameter Related------------------------------------[400-499] */ -#define CONTROLVM_RESP_PAYLOAD_INVALID 400 /* SWITCH_ATTACHEXTPORT, - * DEVICE_CONFIGURE - */ -#define CONTROLVM_RESP_INITIATOR_PARAMETER_INVALID 401 /* Multiple */ -#define CONTROLVM_RESP_TARGET_PARAMETER_INVALID 402 /* DEVICE_CONFIGURE */ -#define CONTROLVM_RESP_CLIENT_PARAMETER_INVALID 403 /* DEVICE_CONFIGURE */ -/* Specified[Packet Structure] Value-------------------------------[500-599] */ -#define CONTROLVM_RESP_BUS_INVALID 500 /* SWITCH_ATTACHINTPORT, - * BUS_CONFIGURE, - * DEVICE_CREATE, - * DEVICE_CONFIG - * DEVICE_DESTROY - */ -#define CONTROLVM_RESP_DEVICE_INVALID 501 /* SWITCH_ATTACHINTPORT*/ - /* DEVICE_CREATE, - * DEVICE_CONFIGURE, - * DEVICE_DESTROY - */ -#define CONTROLVM_RESP_CHANNEL_INVALID 502 /* DEVICE_CREATE, - * DEVICE_CONFIGURE - */ -/* Partition Driver Callback Interface----------------------[600-699] */ -#define CONTROLVM_RESP_VIRTPCI_DRIVER_FAILURE 604 /* BUS_CREATE, - * BUS_DESTROY, - * DEVICE_CREATE, - * DEVICE_DESTROY - */ -/* Unable to invoke VIRTPCI callback */ -#define CONTROLVM_RESP_VIRTPCI_DRIVER_CALLBACK_ERROR 605 /* BUS_CREATE, - * BUS_DESTROY, - * DEVICE_CREATE, - * DEVICE_DESTROY - */ -/* VIRTPCI Callback returned error */ +/* SWITCH_ATTACHEXTPORT, DEVICE_CONFIGURE */ +#define CONTROLVM_RESP_PAYLOAD_INVALID 400 +/* Multiple */ +#define CONTROLVM_RESP_INITIATOR_PARAMETER_INVALID 401 +/* DEVICE_CONFIGURE */ +#define CONTROLVM_RESP_TARGET_PARAMETER_INVALID 402 +/* DEVICE_CONFIGURE */ +#define CONTROLVM_RESP_CLIENT_PARAMETER_INVALID 403 +/* Specified[Packet Structure] Value--------------------------------[500-599] */ +/* SWITCH_ATTACHINTPORT */ +/* BUS_CONFIGURE, DEVICE_CREATE, DEVICE_CONFIG, DEVICE_DESTROY */ +#define CONTROLVM_RESP_BUS_INVALID 500 +/* SWITCH_ATTACHINTPORT*/ +/* DEVICE_CREATE, DEVICE_CONFIGURE, DEVICE_DESTROY */ +#define CONTROLVM_RESP_DEVICE_INVALID 501 +/* DEVICE_CREATE, DEVICE_CONFIGURE */ +#define CONTROLVM_RESP_CHANNEL_INVALID 502 +/* Partition Driver Callback Interface------------------------------[600-699] */ +/* BUS_CREATE, BUS_DESTROY, DEVICE_CREATE, DEVICE_DESTROY */ +#define CONTROLVM_RESP_VIRTPCI_DRIVER_FAILURE 604 +/* Unable to invoke VIRTPCI callback. VIRTPCI Callback returned error. */ +/* BUS_CREATE, BUS_DESTROY, DEVICE_CREATE, DEVICE_DESTROY */ +#define CONTROLVM_RESP_VIRTPCI_DRIVER_CALLBACK_ERROR 605 +/* Generic device callback returned error. */ +/* SWITCH_ATTACHEXTPORT, SWITCH_DETACHEXTPORT, DEVICE_CONFIGURE */ #define CONTROLVM_RESP_GENERIC_DRIVER_CALLBACK_ERROR 606 - /* SWITCH_ATTACHEXTPORT, - * SWITCH_DETACHEXTPORT - * DEVICE_CONFIGURE - */ - -/* generic device callback returned error */ /* Bus Related------------------------------------------------------[700-799] */ -#define CONTROLVM_RESP_ERROR_BUS_DEVICE_ATTACHED 700 /* BUS_DESTROY */ +/* BUS_DESTROY */ +#define CONTROLVM_RESP_ERROR_BUS_DEVICE_ATTACHED 700 /* Channel Related--------------------------------------------------[800-899] */ -#define CONTROLVM_RESP_CHANNEL_TYPE_UNKNOWN 800 /* GET_CHANNELINFO, - * DEVICE_DESTROY - */ -#define CONTROLVM_RESP_CHANNEL_SIZE_TOO_SMALL 801 /* DEVICE_CREATE */ +/* GET_CHANNELINFO, DEVICE_DESTROY */ +#define CONTROLVM_RESP_CHANNEL_TYPE_UNKNOWN 800 +/* DEVICE_CREATE */ +#define CONTROLVM_RESP_CHANNEL_SIZE_TOO_SMALL 801 /* Chipset Shutdown Related---------------------------------------[1000-1099] */ #define CONTROLVM_RESP_CHIPSET_SHUTDOWN_FAILED 1000 #define CONTROLVM_RESP_CHIPSET_SHUTDOWN_ALREADY_ACTIVE 1001 - /* Chipset Stop Related-------------------------------------------[1100-1199] */ #define CONTROLVM_RESP_CHIPSET_STOP_FAILED_BUS 1100 #define CONTROLVM_RESP_CHIPSET_STOP_FAILED_SWITCH 1101 - /* Device Related-------------------------------------------------[1400-1499] */ #define CONTROLVM_RESP_DEVICE_UDEV_TIMEOUT 1400 -#endif /* __CONTROLVMCHANNEL_H__ */ +/* __CONTROLVMCHANNEL_H__ */ +#endif diff --git a/drivers/staging/unisys/visorbus/vbuschannel.h b/drivers/staging/unisys/visorbus/vbuschannel.h index 01d7d517dba7..27e04de14818 100644 --- a/drivers/staging/unisys/visorbus/vbuschannel.h +++ b/drivers/staging/unisys/visorbus/vbuschannel.h @@ -1,4 +1,5 @@ -/* Copyright (C) 2010 - 2015 UNISYS CORPORATION +/* + * Copyright (C) 2010 - 2015 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify it @@ -15,26 +16,26 @@ #ifndef __VBUSCHANNEL_H__ #define __VBUSCHANNEL_H__ -/* The vbus channel is the channel area provided via the BUS_CREATE controlvm - * message for each virtual bus. This channel area is provided to both server - * and client ends of the bus. The channel header area is initialized by - * the server, and the remaining information is filled in by the client. - * We currently use this for the client to provide various information about - * the client devices and client drivers for the server end to see. +/* + * The vbus channel is the channel area provided via the BUS_CREATE controlvm + * message for each virtual bus. This channel area is provided to both server + * and client ends of the bus. The channel header area is initialized by + * the server, and the remaining information is filled in by the client. + * We currently use this for the client to provide various information about + * the client devices and client drivers for the server end to see. */ + #include <linux/uuid.h> #include <linux/ctype.h> #include "channel.h" /* {193b331b-c58f-11da-95a9-00e08161165f} */ -#define VISOR_VBUS_CHANNEL_UUID \ - UUID_LE(0x193b331b, 0xc58f, 0x11da, \ - 0x95, 0xa9, 0x0, 0xe0, 0x81, 0x61, 0x16, 0x5f) -static const uuid_le visor_vbus_channel_uuid = VISOR_VBUS_CHANNEL_UUID; +#define VISOR_VBUS_CHANNEL_GUID \ + GUID_INIT(0x193b331b, 0xc58f, 0x11da, \ + 0x95, 0xa9, 0x0, 0xe0, 0x81, 0x61, 0x16, 0x5f) -#define VISOR_VBUS_CHANNEL_SIGNATURE VISOR_CHANNEL_SIGNATURE - -/* Must increment this whenever you insert or delete fields within this channel +/* + * Must increment this whenever you insert or delete fields within this channel * struct. Also increment whenever you change the meaning of fields within this * channel struct so as to break pre-existing software. Note that you can * usually add fields to the END of the channel struct withOUT needing to @@ -43,42 +44,63 @@ static const uuid_le visor_vbus_channel_uuid = VISOR_VBUS_CHANNEL_UUID; #define VISOR_VBUS_CHANNEL_VERSIONID 1 /* + * struct visor_vbus_deviceinfo + * @devtype: Short string identifying the device type. + * @drvname: Driver .sys file name. + * @infostrs: Kernel vversion. + * @reserved: Pad size to 256 bytes. + * * An array of this struct is present in the channel area for each vbus. - * (See vbuschannel.h.) - * It is filled in by the client side to provide info about the device - * and driver from the client's perspective. + * (See vbuschannel.h.). It is filled in by the client side to provide info + * about the device and driver from the client's perspective. */ struct visor_vbus_deviceinfo { - u8 devtype[16]; /* short string identifying the device type */ - u8 drvname[16]; /* driver .sys file name */ - u8 infostrs[96]; /* kernel version */ - u8 reserved[128]; /* pad size to 256 bytes */ + u8 devtype[16]; + u8 drvname[16]; + u8 infostrs[96]; + u8 reserved[128]; } __packed; +/* + * struct visor_vbus_headerinfo + * @struct_bytes: Size of this struct in bytes. + * @device_info_struct_bytes: Size of VISOR_VBUS_DEVICEINFO. + * @dev_info_count: Num of items in DevInfo member. This is the + * allocated size. + * @chp_info_offset: Byte offset from beginning of this struct to the + * ChpInfo struct. + * @bus_info_offset: Byte offset from beginning of this struct to the + * BusInfo struct. + * @dev_info_offset: Byte offset from beginning of this struct to the + * DevInfo array. + * @reserved: Natural Alignment + */ struct visor_vbus_headerinfo { - u32 struct_bytes; /* size of this struct in bytes */ - u32 device_info_struct_bytes; /* sizeof(VISOR_VBUS_DEVICEINFO) */ - u32 dev_info_count; /* num of items in DevInfo member */ - /* (this is the allocated size) */ - u32 chp_info_offset; /* byte offset from beginning of this struct */ - /* to the ChpInfo struct (below) */ - u32 bus_info_offset; /* byte offset from beginning of this struct */ - /* to the BusInfo struct (below) */ - u32 dev_info_offset; /* byte offset from beginning of this struct */ - /* to the DevInfo array (below) */ + u32 struct_bytes; + u32 device_info_struct_bytes; + u32 dev_info_count; + u32 chp_info_offset; + u32 bus_info_offset; + u32 dev_info_offset; u8 reserved[104]; } __packed; +/* + * struct visor_vbus_channel + * @channel_header: Initialized by server. + * @hdr_info: Initialized by server. + * @chp_info: Describes client chipset device and driver. + * @bus_info: Describes client bus device and driver. + * @dev_info: Describes client device and driver for each device on the + * bus. + */ struct visor_vbus_channel { - struct channel_header channel_header; /* initialized by server */ - struct visor_vbus_headerinfo hdr_info; /* initialized by server */ - /* the remainder of this channel is filled in by the client */ + struct channel_header channel_header; + struct visor_vbus_headerinfo hdr_info; + /* The remainder of this channel is filled in by the client */ struct visor_vbus_deviceinfo chp_info; - /* describes client chipset device and driver */ struct visor_vbus_deviceinfo bus_info; - /* describes client bus device and driver */ struct visor_vbus_deviceinfo dev_info[0]; - /* describes client device and driver for each device on the bus */ } __packed; #endif diff --git a/drivers/staging/unisys/visorbus/visorbus_main.c b/drivers/staging/unisys/visorbus/visorbus_main.c index 1c785dd19ddd..2bc7ff7bb96a 100644 --- a/drivers/staging/unisys/visorbus/visorbus_main.c +++ b/drivers/staging/unisys/visorbus/visorbus_main.c @@ -1,5 +1,4 @@ -/* visorbus_main.c - * +/* * Copyright ďż˝ 2010 - 2015 UNISYS CORPORATION * All rights reserved. * @@ -20,15 +19,14 @@ #include "visorbus.h" #include "visorbus_private.h" -#define MYDRVNAME "visorbus" +static const guid_t visor_vbus_channel_guid = VISOR_VBUS_CHANNEL_GUID; -/* Display string that is guaranteed to be no longer the 99 characters*/ +/* Display string that is guaranteed to be no longer the 99 characters */ #define LINESIZE 99 - -#define CURRENT_FILE_PC VISOR_BUS_PC_visorbus_main_c #define POLLJIFFIES_NORMALCHANNEL 10 -static bool initialized; /* stores whether bus_registration was successful */ +/* stores whether bus_registration was successful */ +static bool initialized; static struct dentry *visorbus_debugfs_dir; /* @@ -40,11 +38,11 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf) { struct visor_device *vdev; - uuid_le guid; + const guid_t *guid; vdev = to_visor_device(dev); - guid = visorchannel_get_uuid(vdev->visorchannel); - return sprintf(buf, "visorbus:%pUl\n", &guid); + guid = visorchannel_get_guid(vdev->visorchannel); + return sprintf(buf, "visorbus:%pUl\n", guid); } static DEVICE_ATTR_RO(modalias); @@ -53,15 +51,7 @@ static struct attribute *visorbus_dev_attrs[] = { NULL, }; -/* sysfs example for bridge-only sysfs files using device_type's */ -static const struct attribute_group visorbus_dev_group = { - .attrs = visorbus_dev_attrs, -}; - -static const struct attribute_group *visorbus_dev_groups[] = { - &visorbus_dev_group, - NULL, -}; +ATTRIBUTE_GROUPS(visorbus_dev); /* filled in with info about parent chipset driver when we register with it */ static struct visor_vbus_deviceinfo chipset_driverinfo; @@ -73,16 +63,70 @@ static LIST_HEAD(list_all_bus_instances); /* list of visor_device structs, linked via .list_all */ static LIST_HEAD(list_all_device_instances); -static int -visorbus_uevent(struct device *xdev, struct kobj_uevent_env *env) +/* + * Generic function useful for validating any type of channel when it is + * received by the client that will be accessing the channel. + * Note that <logCtx> is only needed for callers in the EFI environment, and + * is used to pass the EFI_DIAG_CAPTURE_PROTOCOL needed to log messages. + */ +int visor_check_channel(struct channel_header *ch, + struct device *dev, + const guid_t *expected_guid, + char *chname, + u64 expected_min_bytes, + u32 expected_version, + u64 expected_signature) +{ + if (!guid_is_null(expected_guid)) { + /* caller wants us to verify type GUID */ + if (!guid_equal(&ch->chtype, expected_guid)) { + dev_err(dev, "Channel mismatch on channel=%s(%pUL) field=type expected=%pUL actual=%pUL\n", + chname, expected_guid, expected_guid, + &ch->chtype); + return 0; + } + } + /* verify channel size */ + if (expected_min_bytes > 0) { + if (ch->size < expected_min_bytes) { + dev_err(dev, "Channel mismatch on channel=%s(%pUL) field=size expected=0x%-8.8Lx actual=0x%-8.8Lx\n", + chname, expected_guid, + (unsigned long long)expected_min_bytes, + ch->size); + return 0; + } + } + /* verify channel version */ + if (expected_version > 0) { + if (ch->version_id != expected_version) { + dev_err(dev, "Channel mismatch on channel=%s(%pUL) field=version expected=0x%-8.8lx actual=0x%-8.8x\n", + chname, expected_guid, + (unsigned long)expected_version, + ch->version_id); + return 0; + } + } + /* verify channel signature */ + if (expected_signature > 0) { + if (ch->signature != expected_signature) { + dev_err(dev, "Channel mismatch on channel=%s(%pUL) field=signature expected=0x%-8.8Lx actual=0x%-8.8Lx\n", + chname, expected_guid, expected_signature, + ch->signature); + return 0; + } + } + return 1; +} + +static int visorbus_uevent(struct device *xdev, struct kobj_uevent_env *env) { struct visor_device *dev; - uuid_le guid; + const guid_t *guid; dev = to_visor_device(xdev); - guid = visorchannel_get_uuid(dev->visorchannel); + guid = visorchannel_get_guid(dev->visorchannel); - return add_uevent_var(env, "MODALIAS=visorbus:%pUl", &guid); + return add_uevent_var(env, "MODALIAS=visorbus:%pUl", guid); } /* @@ -94,27 +138,21 @@ visorbus_uevent(struct device *xdev, struct kobj_uevent_env *env) * * Return: 1 iff the provided driver can control the specified device */ -static int -visorbus_match(struct device *xdev, struct device_driver *xdrv) +static int visorbus_match(struct device *xdev, struct device_driver *xdrv) { - uuid_le channel_type; + const guid_t *channel_type; int i; struct visor_device *dev; struct visor_driver *drv; dev = to_visor_device(xdev); + channel_type = visorchannel_get_guid(dev->visorchannel); drv = to_visor_driver(xdrv); - channel_type = visorchannel_get_uuid(dev->visorchannel); - if (!drv->channel_types) return 0; - for (i = 0; - (uuid_le_cmp(drv->channel_types[i].guid, NULL_UUID_LE) != 0) || - (drv->channel_types[i].name); - i++) - if (uuid_le_cmp(drv->channel_types[i].guid, - channel_type) == 0) + for (i = 0; !guid_is_null(&drv->channel_types[i].guid); i++) + if (guid_equal(&drv->channel_types[i].guid, channel_type)) return i + 1; return 0; @@ -122,7 +160,7 @@ visorbus_match(struct device *xdev, struct device_driver *xdrv) /* * This describes the TYPE of bus. - * (Don't confuse this with an INSTANCE of the bus.) + * (Don't confuse this with an INSTANCE of the bus.) */ struct bus_type visorbus_type = { .name = "visorbus", @@ -137,8 +175,7 @@ struct bus_type visorbus_type = { * involved with destroying the dev are complete * @xdev: struct device for the bus being released */ -static void -visorbus_release_busdevice(struct device *xdev) +static void visorbus_release_busdevice(struct device *xdev) { struct visor_device *dev = dev_get_drvdata(xdev); @@ -152,15 +189,11 @@ visorbus_release_busdevice(struct device *xdev) * each child device instance * @xdev: struct device for the visor device being released */ -static void -visorbus_release_device(struct device *xdev) +static void visorbus_release_device(struct device *xdev) { struct visor_device *dev = to_visor_device(xdev); - if (dev->visorchannel) { - visorchannel_destroy(dev->visorchannel); - dev->visorchannel = NULL; - } + visorchannel_destroy(dev->visorchannel); kfree(dev); } @@ -229,7 +262,7 @@ static ssize_t typename_show(struct device *dev, struct device_attribute *attr, struct device_driver *xdrv = dev->driver; struct visor_driver *drv = NULL; - if (!xbus || !xdrv) + if (!xdrv) return 0; i = xbus->match(dev, xdrv); if (!i) @@ -240,24 +273,16 @@ static ssize_t typename_show(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR_RO(typename); static struct attribute *channel_attrs[] = { - &dev_attr_physaddr.attr, - &dev_attr_nbytes.attr, - &dev_attr_clientpartition.attr, - &dev_attr_typeguid.attr, - &dev_attr_zoneguid.attr, - &dev_attr_typename.attr, - NULL + &dev_attr_physaddr.attr, + &dev_attr_nbytes.attr, + &dev_attr_clientpartition.attr, + &dev_attr_typeguid.attr, + &dev_attr_zoneguid.attr, + &dev_attr_typename.attr, + NULL }; -static struct attribute_group channel_attr_grp = { - .name = "channel", - .attrs = channel_attrs, -}; - -static const struct attribute_group *visorbus_channel_groups[] = { - &channel_attr_grp, - NULL -}; +ATTRIBUTE_GROUPS(channel); /* end implementation of specific channel attributes */ @@ -270,7 +295,8 @@ static const struct attribute_group *visorbus_channel_groups[] = { static ssize_t partition_handle_show(struct device *dev, struct device_attribute *attr, - char *buf) { + char *buf) +{ struct visor_device *vdev = to_visor_device(dev); u64 handle = visorchannel_get_clientpartition(vdev->visorchannel); @@ -280,16 +306,18 @@ static DEVICE_ATTR_RO(partition_handle); static ssize_t partition_guid_show(struct device *dev, struct device_attribute *attr, - char *buf) { + char *buf) +{ struct visor_device *vdev = to_visor_device(dev); - return sprintf(buf, "{%pUb}\n", &vdev->partition_uuid); + return sprintf(buf, "{%pUb}\n", &vdev->partition_guid); } static DEVICE_ATTR_RO(partition_guid); static ssize_t partition_name_show(struct device *dev, struct device_attribute *attr, - char *buf) { + char *buf) +{ struct visor_device *vdev = to_visor_device(dev); return sprintf(buf, "%s\n", vdev->name); @@ -298,7 +326,8 @@ static DEVICE_ATTR_RO(partition_name); static ssize_t channel_addr_show(struct device *dev, struct device_attribute *attr, - char *buf) { + char *buf) +{ struct visor_device *vdev = to_visor_device(dev); u64 addr = visorchannel_get_physaddr(vdev->visorchannel); @@ -308,7 +337,8 @@ static DEVICE_ATTR_RO(channel_addr); static ssize_t channel_bytes_show(struct device *dev, struct device_attribute *attr, - char *buf) { + char *buf) +{ struct visor_device *vdev = to_visor_device(dev); u64 nbytes = visorchannel_get_nbytes(vdev->visorchannel); @@ -318,7 +348,8 @@ static DEVICE_ATTR_RO(channel_bytes); static ssize_t channel_id_show(struct device *dev, struct device_attribute *attr, - char *buf) { + char *buf) +{ struct visor_device *vdev = to_visor_device(dev); int len = 0; @@ -330,24 +361,17 @@ static ssize_t channel_id_show(struct device *dev, } static DEVICE_ATTR_RO(channel_id); -static struct attribute *dev_attrs[] = { - &dev_attr_partition_handle.attr, - &dev_attr_partition_guid.attr, - &dev_attr_partition_name.attr, - &dev_attr_channel_addr.attr, - &dev_attr_channel_bytes.attr, - &dev_attr_channel_id.attr, - NULL -}; - -static struct attribute_group dev_attr_grp = { - .attrs = dev_attrs, +static struct attribute *visorbus_attrs[] = { + &dev_attr_partition_handle.attr, + &dev_attr_partition_guid.attr, + &dev_attr_partition_name.attr, + &dev_attr_channel_addr.attr, + &dev_attr_channel_bytes.attr, + &dev_attr_channel_id.attr, + NULL }; -static const struct attribute_group *visorbus_groups[] = { - &dev_attr_grp, - NULL -}; +ATTRIBUTE_GROUPS(visorbus); /* * BUS debugfs entries @@ -355,6 +379,7 @@ static const struct attribute_group *visorbus_groups[] = { * define & implement display of debugfs attributes under * /sys/kernel/debug/visorbus/visorbus<n>. */ + /* * vbuschannel_print_devinfo() - format a struct visor_vbus_deviceinfo * and write it to a seq_file @@ -365,12 +390,12 @@ static const struct attribute_group *visorbus_groups[] = { * * Reads @devInfo, and writes it in human-readable notation to @seq. */ -static void -vbuschannel_print_devinfo(struct visor_vbus_deviceinfo *devinfo, - struct seq_file *seq, int devix) +static void vbuschannel_print_devinfo(struct visor_vbus_deviceinfo *devinfo, + struct seq_file *seq, int devix) { + /* uninitialized vbus device entry */ if (!isprint(devinfo->devtype[0])) - return; /* uninitialized vbus device entry */ + return; if (devix >= 0) seq_printf(seq, "[%d]", devix); @@ -392,12 +417,11 @@ vbuschannel_print_devinfo(struct visor_vbus_deviceinfo *devinfo, static int client_bus_info_debugfs_show(struct seq_file *seq, void *v) { - struct visor_device *vdev = seq->private; - struct visorchannel *channel = vdev->visorchannel; - - int i; + int i = 0; unsigned long off; struct visor_vbus_deviceinfo dev_info; + struct visor_device *vdev = seq->private; + struct visorchannel *channel = vdev->visorchannel; if (!channel) return 0; @@ -406,6 +430,7 @@ static int client_bus_info_debugfs_show(struct seq_file *seq, void *v) "Client device / client driver info for %s partition (vbus #%u):\n", ((vdev->name) ? (char *)(vdev->name) : ""), vdev->chipset_bus_no); + if (visorchannel_read(channel, offsetof(struct visor_vbus_channel, chp_info), &dev_info, sizeof(dev_info)) >= 0) @@ -414,8 +439,8 @@ static int client_bus_info_debugfs_show(struct seq_file *seq, void *v) offsetof(struct visor_vbus_channel, bus_info), &dev_info, sizeof(dev_info)) >= 0) vbuschannel_print_devinfo(&dev_info, seq, -1); + off = offsetof(struct visor_vbus_channel, dev_info); - i = 0; while (off + sizeof(dev_info) <= visorchannel_get_nbytes(channel)) { if (visorchannel_read(channel, off, &dev_info, sizeof(dev_info)) >= 0) @@ -441,8 +466,7 @@ static const struct file_operations client_bus_info_debugfs_fops = { .release = single_release, }; -static void -dev_periodic_work(unsigned long __opaque) +static void dev_periodic_work(unsigned long __opaque) { struct visor_device *dev = (struct visor_device *)__opaque; struct visor_driver *drv = to_visor_driver(dev->device.driver); @@ -451,8 +475,7 @@ dev_periodic_work(unsigned long __opaque) mod_timer(&dev->timer, jiffies + POLLJIFFIES_NORMALCHANNEL); } -static int -dev_start_periodic_work(struct visor_device *dev) +static int dev_start_periodic_work(struct visor_device *dev) { if (dev->being_removed || dev->timer_active) return -EINVAL; @@ -464,8 +487,7 @@ dev_start_periodic_work(struct visor_device *dev) return 0; } -static void -dev_stop_periodic_work(struct visor_device *dev) +static void dev_stop_periodic_work(struct visor_device *dev) { if (!dev->timer_active) return; @@ -484,40 +506,39 @@ dev_stop_periodic_work(struct visor_device *dev) * * Return: 0 iff successful */ -static int -visordriver_remove_device(struct device *xdev) +static int visordriver_remove_device(struct device *xdev) { struct visor_device *dev; struct visor_driver *drv; dev = to_visor_device(xdev); drv = to_visor_driver(xdev->driver); + mutex_lock(&dev->visordriver_callback_lock); dev->being_removed = true; - if (drv->remove) - drv->remove(dev); + drv->remove(dev); mutex_unlock(&dev->visordriver_callback_lock); - dev_stop_periodic_work(dev); + dev_stop_periodic_work(dev); put_device(&dev->device); + return 0; } -/** +/* * visorbus_unregister_visor_driver() - unregisters the provided driver * @drv: the driver to unregister * * A visor function driver calls this function to unregister the driver, * i.e., within its module_exit function. */ -void -visorbus_unregister_visor_driver(struct visor_driver *drv) +void visorbus_unregister_visor_driver(struct visor_driver *drv) { driver_unregister(&drv->driver); } EXPORT_SYMBOL_GPL(visorbus_unregister_visor_driver); -/** +/* * visorbus_read_channel() - reads from the designated channel into * the provided buffer * @dev: the device whose channel is read from @@ -530,15 +551,14 @@ EXPORT_SYMBOL_GPL(visorbus_unregister_visor_driver); * * Return: integer indicating success (zero) or failure (non-zero) */ -int -visorbus_read_channel(struct visor_device *dev, unsigned long offset, - void *dest, unsigned long nbytes) +int visorbus_read_channel(struct visor_device *dev, unsigned long offset, + void *dest, unsigned long nbytes) { return visorchannel_read(dev->visorchannel, offset, dest, nbytes); } EXPORT_SYMBOL_GPL(visorbus_read_channel); -/** +/* * visorbus_write_channel() - writes the provided buffer into the designated * channel * @dev: the device whose channel is written to @@ -551,15 +571,14 @@ EXPORT_SYMBOL_GPL(visorbus_read_channel); * * Return: integer indicating success (zero) or failure (non-zero) */ -int -visorbus_write_channel(struct visor_device *dev, unsigned long offset, - void *src, unsigned long nbytes) +int visorbus_write_channel(struct visor_device *dev, unsigned long offset, + void *src, unsigned long nbytes) { return visorchannel_write(dev->visorchannel, offset, src, nbytes); } EXPORT_SYMBOL_GPL(visorbus_write_channel); -/** +/* * visorbus_enable_channel_interrupts() - enables interrupts on the * designated device * @dev: the device on which to enable interrupts @@ -567,8 +586,7 @@ EXPORT_SYMBOL_GPL(visorbus_write_channel); * Currently we don't yet have a real interrupt, so for now we just call the * interrupt function periodically via a timer. */ -int -visorbus_enable_channel_interrupts(struct visor_device *dev) +int visorbus_enable_channel_interrupts(struct visor_device *dev) { struct visor_driver *drv = to_visor_driver(dev->device.driver); @@ -581,13 +599,12 @@ visorbus_enable_channel_interrupts(struct visor_device *dev) } EXPORT_SYMBOL_GPL(visorbus_enable_channel_interrupts); -/** +/* * visorbus_disable_channel_interrupts() - disables interrupts on the * designated device * @dev: the device on which to disable interrupts */ -void -visorbus_disable_channel_interrupts(struct visor_device *dev) +void visorbus_disable_channel_interrupts(struct visor_device *dev) { dev_stop_periodic_work(dev); } @@ -616,8 +633,7 @@ EXPORT_SYMBOL_GPL(visorbus_disable_channel_interrupts); * Return: 0 if successful, otherwise the negative value returned by * device_add() indicating the reason for failure */ -static int -create_visor_device(struct visor_device *dev) +int create_visor_device(struct visor_device *dev) { int err; u32 chipset_bus_no = dev->chipset_bus_no; @@ -625,7 +641,7 @@ create_visor_device(struct visor_device *dev) mutex_init(&dev->visordriver_callback_lock); dev->device.bus = &visorbus_type; - dev->device.groups = visorbus_channel_groups; + dev->device.groups = channel_groups; device_initialize(&dev->device); dev->device.release = visorbus_release_device; /* keep a reference just for us (now 2) */ @@ -664,7 +680,10 @@ create_visor_device(struct visor_device *dev) goto err_put; list_add_tail(&dev->list_all, &list_all_device_instances); - return 0; /* success: reference kept via unmatched get_device() */ + dev->state.created = 1; + visorbus_response(dev, err, CONTROLVM_DEVICE_CREATE); + /* success: reference kept via unmatched get_device() */ + return 0; err_put: put_device(&dev->device); @@ -672,26 +691,27 @@ err_put: return err; } -static void -remove_visor_device(struct visor_device *dev) +void remove_visor_device(struct visor_device *dev) { list_del(&dev->list_all); put_device(&dev->device); device_unregister(&dev->device); + visorbus_response(dev, 0, CONTROLVM_DEVICE_DESTROY); } -static int -get_vbus_header_info(struct visorchannel *chan, - struct visor_vbus_headerinfo *hdr_info) +static int get_vbus_header_info(struct visorchannel *chan, + struct device *dev, + struct visor_vbus_headerinfo *hdr_info) { int err; if (!visor_check_channel(visorchannel_get_header(chan), - visor_vbus_channel_uuid, + dev, + &visor_vbus_channel_guid, "vbus", sizeof(struct visor_vbus_channel), VISOR_VBUS_CHANNEL_VERSIONID, - VISOR_VBUS_CHANNEL_SIGNATURE)) + VISOR_CHANNEL_SIGNATURE)) return -EINVAL; err = visorchannel_read(chan, sizeof(struct channel_header), hdr_info, @@ -722,10 +742,9 @@ get_vbus_header_info(struct visorchannel *chan, * Returns no value since this is debug information and not needed for * device functionality. */ -static void -write_vbus_chp_info(struct visorchannel *chan, - struct visor_vbus_headerinfo *hdr_info, - struct visor_vbus_deviceinfo *info) +static void write_vbus_chp_info(struct visorchannel *chan, + struct visor_vbus_headerinfo *hdr_info, + struct visor_vbus_deviceinfo *info) { int off = sizeof(struct channel_header) + hdr_info->chp_info_offset; @@ -748,10 +767,9 @@ write_vbus_chp_info(struct visorchannel *chan, * Returns no value since this is debug information and not needed for * device functionality. */ -static void -write_vbus_bus_info(struct visorchannel *chan, - struct visor_vbus_headerinfo *hdr_info, - struct visor_vbus_deviceinfo *info) +static void write_vbus_bus_info(struct visorchannel *chan, + struct visor_vbus_headerinfo *hdr_info, + struct visor_vbus_deviceinfo *info) { int off = sizeof(struct channel_header) + hdr_info->bus_info_offset; @@ -775,10 +793,10 @@ write_vbus_bus_info(struct visorchannel *chan, * Returns no value since this is debug information and not needed for * device functionality. */ -static void -write_vbus_dev_info(struct visorchannel *chan, - struct visor_vbus_headerinfo *hdr_info, - struct visor_vbus_deviceinfo *info, unsigned int devix) +static void write_vbus_dev_info(struct visorchannel *chan, + struct visor_vbus_headerinfo *hdr_info, + struct visor_vbus_deviceinfo *info, + unsigned int devix) { int off = (sizeof(struct channel_header) + hdr_info->dev_info_offset) + @@ -807,14 +825,13 @@ static void bus_device_info_init( } /* - * fix_vbus_dev_info() - for a child device just created on a client bus, fill - * in information about the driver that is controlling - * this device into the appropriate slot within the - * vbus channel of the bus instance + * publish_vbus_dev_info() - for a child device just created on a client bus, + * fill in information about the driver that is + * controlling this device into the appropriate slot + * within the vbus channel of the bus instance * @visordev: struct visor_device for the desired device */ -static void -fix_vbus_dev_info(struct visor_device *visordev) +static void publish_vbus_dev_info(struct visor_device *visordev) { int i; struct visor_device *bdev; @@ -853,7 +870,6 @@ fix_vbus_dev_info(struct visor_device *visordev) bus_device_info_init(&dev_info, chan_type_name, visordrv->name); write_vbus_dev_info(bdev->visorchannel, hdr_info, &dev_info, dev_no); - write_vbus_chp_info(bdev->visorchannel, hdr_info, &chipset_driverinfo); write_vbus_bus_info(bdev->visorchannel, hdr_info, &clientbus_driverinfo); @@ -874,18 +890,14 @@ fix_vbus_dev_info(struct visor_device *visordev) * was successful with this device, otherwise a negative errno * value indicating failure reason */ -static int -visordriver_probe_device(struct device *xdev) +static int visordriver_probe_device(struct device *xdev) { int res; struct visor_driver *drv; struct visor_device *dev; - drv = to_visor_driver(xdev->driver); dev = to_visor_device(xdev); - - if (!drv->probe) - return -ENODEV; + drv = to_visor_driver(xdev->driver); mutex_lock(&dev->visordriver_callback_lock); dev->being_removed = false; @@ -894,14 +906,14 @@ visordriver_probe_device(struct device *xdev) if (res >= 0) { /* success: reference kept via unmatched get_device() */ get_device(&dev->device); - fix_vbus_dev_info(dev); + publish_vbus_dev_info(dev); } mutex_unlock(&dev->visordriver_callback_lock); return res; } -/** +/* * visorbus_register_visor_driver() - registers the provided visor driver * for handling one or more visor device * types (channel_types) @@ -952,8 +964,21 @@ visordriver_probe_device(struct device *xdev) */ int visorbus_register_visor_driver(struct visor_driver *drv) { + /* can't register on a nonexistent bus */ if (!initialized) - return -ENODEV; /* can't register on a nonexistent bus */ + return -ENODEV; + + if (!drv->probe) + return -EINVAL; + + if (!drv->remove) + return -EINVAL; + + if (!drv->pause) + return -EINVAL; + + if (!drv->resume) + return -EINVAL; drv->driver.name = drv->name; drv->driver.bus = &visorbus_type; @@ -985,8 +1010,7 @@ EXPORT_SYMBOL_GPL(visorbus_register_visor_driver); * Return: 0 for success, otherwise negative errno value indicating reason for * failure */ -static int -visorbus_create_instance(struct visor_device *dev) +int visorbus_create_instance(struct visor_device *dev) { int id = dev->chipset_bus_no; int err; @@ -1009,7 +1033,7 @@ visorbus_create_instance(struct visor_device *dev) &client_bus_info_debugfs_fops); dev_set_drvdata(&dev->device, dev); - err = get_vbus_header_info(dev->visorchannel, hdr_info); + err = get_vbus_header_info(dev->visorchannel, &dev->device, hdr_info); if (err < 0) goto err_debugfs_dir; @@ -1019,18 +1043,21 @@ visorbus_create_instance(struct visor_device *dev) list_add_tail(&dev->list_all, &list_all_bus_instances); + dev->state.created = 1; dev->vbus_hdr_info = (void *)hdr_info; write_vbus_chp_info(dev->visorchannel, hdr_info, &chipset_driverinfo); write_vbus_bus_info(dev->visorchannel, hdr_info, &clientbus_driverinfo); + visorbus_response(dev, err, CONTROLVM_BUS_CREATE); + return 0; err_debugfs_dir: debugfs_remove_recursive(dev->debugfs_dir); kfree(hdr_info); - dev_err(&dev->device, "visorbus_create_instance failed: %d\n", err); + dev_err(&dev->device, "%s failed: %d\n", __func__, err); return err; } @@ -1038,8 +1065,7 @@ err_debugfs_dir: * visorbus_remove_instance() - remove a device instance for the visorbus itself * @dev: struct visor_device indentifying the bus to remove */ -static void -visorbus_remove_instance(struct visor_device *dev) +void visorbus_remove_instance(struct visor_device *dev) { /* * Note that this will result in the release method for @@ -1049,20 +1075,17 @@ visorbus_remove_instance(struct visor_device *dev) * successfully been able to trace thru the code to see where/how * release() gets called. But I know it does. */ - if (dev->visorchannel) { - visorchannel_destroy(dev->visorchannel); - dev->visorchannel = NULL; - } + visorchannel_destroy(dev->visorchannel); kfree(dev->vbus_hdr_info); list_del(&dev->list_all); device_unregister(&dev->device); + visorbus_response(dev, 0, CONTROLVM_BUS_DESTROY); } /* * remove_all_visor_devices() - remove all child visorbus device instances */ -static void -remove_all_visor_devices(void) +static void remove_all_visor_devices(void) { struct list_head *listentry, *listtmp; @@ -1074,50 +1097,6 @@ remove_all_visor_devices(void) } } -int -visorchipset_bus_create(struct visor_device *dev) -{ - int err; - - err = visorbus_create_instance(dev); - - if (err < 0) - return err; - - visorbus_create_response(dev, err); - - return 0; -} - -void -visorchipset_bus_destroy(struct visor_device *dev) -{ - visorbus_remove_instance(dev); - visorbus_destroy_response(dev, 0); -} - -int -visorchipset_device_create(struct visor_device *dev_info) -{ - int err; - - err = create_visor_device(dev_info); - if (err < 0) - return err; - - visorbus_device_create_response(dev_info, err); - - return 0; -} - -void -visorchipset_device_destroy(struct visor_device *dev_info) -{ - remove_visor_device(dev_info); - - visorbus_device_destroy_response(dev_info, 0); -} - /* * pause_state_change_complete() - the callback function to be called by a * visorbus function driver when a @@ -1127,15 +1106,14 @@ visorchipset_device_destroy(struct visor_device *dev_info) * @status: 0 iff the pause state change completed successfully, otherwise * a negative errno value indicating the reason for failure */ -static void -pause_state_change_complete(struct visor_device *dev, int status) +static void pause_state_change_complete(struct visor_device *dev, int status) { if (!dev->pausing) return; dev->pausing = false; - - visorbus_device_pause_response(dev, status); + visorbus_device_changestate_response(dev, status, + segment_state_standby); } /* @@ -1147,8 +1125,7 @@ pause_state_change_complete(struct visor_device *dev, int status) * @status: 0 iff the resume state change completed successfully, otherwise * a negative errno value indicating the reason for failure */ -static void -resume_state_change_complete(struct visor_device *dev, int status) +static void resume_state_change_complete(struct visor_device *dev, int status) { if (!dev->resuming) return; @@ -1160,7 +1137,8 @@ resume_state_change_complete(struct visor_device *dev, int status) * which will presumably want to send some sort of response to * the initiator. */ - visorbus_device_resume_response(dev, status); + visorbus_device_changestate_response(dev, status, + segment_state_running); } /* @@ -1174,34 +1152,28 @@ resume_state_change_complete(struct visor_device *dev, int status) * via a callback function; see pause_state_change_complete() and * resume_state_change_complete(). */ -static int -visorchipset_initiate_device_pause_resume(struct visor_device *dev, - bool is_pause) +static int visorchipset_initiate_device_pause_resume(struct visor_device *dev, + bool is_pause) { int err; struct visor_driver *drv = NULL; - drv = to_visor_driver(dev->device.driver); - if (!drv) - return -ENODEV; - + /* If no driver associated with the device nothing to pause/resume */ + if (!dev->device.driver) + return 0; if (dev->pausing || dev->resuming) return -EBUSY; + drv = to_visor_driver(dev->device.driver); if (is_pause) { - if (!drv->pause) - return -EINVAL; - dev->pausing = true; err = drv->pause(dev, pause_state_change_complete); } else { - /* The vbus_dev_info structure in the channel was been - * cleared, make sure it is valid. + /* + * The vbus_dev_info structure in the channel was been cleared, + * make sure it is valid. */ - fix_vbus_dev_info(dev); - if (!drv->resume) - return -EINVAL; - + publish_vbus_dev_info(dev); dev->resuming = true; err = drv->resume(dev, resume_state_change_complete); } @@ -1209,7 +1181,7 @@ visorchipset_initiate_device_pause_resume(struct visor_device *dev, return err; } -/** +/* * visorchipset_device_pause() - start a pause operation for a visor device * @dev_info: struct visor_device identifying the device being paused * @@ -1217,13 +1189,11 @@ visorchipset_initiate_device_pause_resume(struct visor_device *dev, * that device. Success/failure result is returned asynchronously * via a callback function; see pause_state_change_complete(). */ -int -visorchipset_device_pause(struct visor_device *dev_info) +int visorchipset_device_pause(struct visor_device *dev_info) { int err; err = visorchipset_initiate_device_pause_resume(dev_info, true); - if (err < 0) { dev_info->pausing = false; return err; @@ -1232,7 +1202,7 @@ visorchipset_device_pause(struct visor_device *dev_info) return 0; } -/** +/* * visorchipset_device_resume() - start a resume operation for a visor device * @dev_info: struct visor_device identifying the device being resumed * @@ -1240,13 +1210,11 @@ visorchipset_device_pause(struct visor_device *dev_info) * that device. Success/failure result is returned asynchronously * via a callback function; see resume_state_change_complete(). */ -int -visorchipset_device_resume(struct visor_device *dev_info) +int visorchipset_device_resume(struct visor_device *dev_info) { int err; err = visorchipset_initiate_device_pause_resume(dev_info, false); - if (err < 0) { dev_info->resuming = false; return err; @@ -1255,8 +1223,7 @@ visorchipset_device_resume(struct visor_device *dev_info) return 0; } -int -visorbus_init(void) +int visorbus_init(void) { int err; @@ -1271,14 +1238,12 @@ visorbus_init(void) return err; initialized = true; - bus_device_info_init(&chipset_driverinfo, "chipset", "visorchipset"); return 0; } -void -visorbus_exit(void) +void visorbus_exit(void) { struct list_head *listentry, *listtmp; diff --git a/drivers/staging/unisys/visorbus/visorbus_private.h b/drivers/staging/unisys/visorbus/visorbus_private.h index 98a5af19189d..e878d65ab668 100644 --- a/drivers/staging/unisys/visorbus/visorbus_private.h +++ b/drivers/staging/unisys/visorbus/visorbus_private.h @@ -1,5 +1,4 @@ -/* visorbus_private.h - * +/* * Copyright (C) 2010 - 2015 UNISYS CORPORATION * All rights reserved. * @@ -22,36 +21,27 @@ #include "controlvmchannel.h" #include "vbuschannel.h" +#include "visorbus.h" -/* TARGET_HOSTNAME specified as -DTARGET_HOSTNAME=\"thename\" on the - * command line - */ - -int visorchipset_bus_create(struct visor_device *bus_info); -void visorchipset_bus_destroy(struct visor_device *bus_info); -int visorchipset_device_create(struct visor_device *dev_info); -void visorchipset_device_destroy(struct visor_device *dev_info); +int visorbus_create_instance(struct visor_device *dev); +void visorbus_remove_instance(struct visor_device *bus_info); +int create_visor_device(struct visor_device *dev_info); +void remove_visor_device(struct visor_device *dev_info); int visorchipset_device_pause(struct visor_device *dev_info); int visorchipset_device_resume(struct visor_device *dev_info); -void visorbus_create_response(struct visor_device *p, int response); -void visorbus_destroy_response(struct visor_device *p, int response); -void visorbus_device_create_response(struct visor_device *p, int response); -void visorbus_device_destroy_response(struct visor_device *p, int response); -void visorbus_device_resume_response(struct visor_device *p, int response); -void visorbus_device_pause_response(struct visor_device *p, int response); +void visorbus_response(struct visor_device *p, int response, int controlvm_id); +void visorbus_device_changestate_response(struct visor_device *p, int response, + struct visor_segment_state state); int visorbus_init(void); void visorbus_exit(void); /* visorchannel access functions */ - -struct visorchannel *visorchannel_create(u64 physaddr, - unsigned long channel_bytes, - gfp_t gfp, uuid_le guid); -struct visorchannel *visorchannel_create_with_lock(u64 physaddr, - unsigned long channel_bytes, - gfp_t gfp, uuid_le guid); +struct visorchannel *visorchannel_create(u64 physaddr, gfp_t gfp, + const guid_t *guid); +struct visorchannel *visorchannel_create_with_lock(u64 physaddr, gfp_t gfp, + const guid_t *guid); void visorchannel_destroy(struct visorchannel *channel); int visorchannel_read(struct visorchannel *channel, ulong offset, void *dest, ulong nbytes); @@ -64,6 +54,6 @@ char *visorchannel_zoneid(struct visorchannel *channel, char *s); u64 visorchannel_get_clientpartition(struct visorchannel *channel); int visorchannel_set_clientpartition(struct visorchannel *channel, u64 partition_handle); -char *visorchannel_uuid_id(uuid_le *guid, char *s); +char *visorchannel_guid_id(const guid_t *guid, char *s); void *visorchannel_get_header(struct visorchannel *channel); #endif diff --git a/drivers/staging/unisys/visorbus/visorchannel.c b/drivers/staging/unisys/visorbus/visorchannel.c index 6885c2cb7135..2a000fee3119 100644 --- a/drivers/staging/unisys/visorbus/visorchannel.c +++ b/drivers/staging/unisys/visorbus/visorchannel.c @@ -1,5 +1,4 @@ -/* visorchannel_funcs.c - * +/* * Copyright (C) 2010 - 2015 UNISYS CORPORATION * All rights reserved. * @@ -26,13 +25,13 @@ #include "visorbus_private.h" #include "controlvmchannel.h" -#define MYDRVNAME "visorchannel" +#define VISOR_DRV_NAME "visorchannel" #define VISOR_CONSOLEVIDEO_CHANNEL_GUID \ - UUID_LE(0x3cd6e705, 0xd6a2, 0x4aa5, \ - 0xad, 0x5c, 0x7b, 0x8, 0x88, 0x9d, 0xff, 0xe2) + GUID_INIT(0x3cd6e705, 0xd6a2, 0x4aa5, \ + 0xad, 0x5c, 0x7b, 0x8, 0x88, 0x9d, 0xff, 0xe2) -static const uuid_le visor_video_guid = VISOR_CONSOLEVIDEO_CHANNEL_GUID; +static const guid_t visor_video_guid = VISOR_CONSOLEVIDEO_CHANNEL_GUID; struct visorchannel { u64 physaddr; @@ -40,18 +39,21 @@ struct visorchannel { void *mapped; bool requested; struct channel_header chan_hdr; - uuid_le guid; - bool needs_lock; /* channel creator knows if more than one */ - /* thread will be inserting or removing */ - spinlock_t insert_lock; /* protect head writes in chan_hdr */ - spinlock_t remove_lock; /* protect tail writes in chan_hdr */ - - uuid_le type; - uuid_le inst; + guid_t guid; + /* + * channel creator knows if more than one + * thread will be inserting or removing + */ + bool needs_lock; + /* protect head writes in chan_hdr */ + spinlock_t insert_lock; + /* protect tail writes in chan_hdr */ + spinlock_t remove_lock; + guid_t type; + guid_t inst; }; -void -visorchannel_destroy(struct visorchannel *channel) +void visorchannel_destroy(struct visorchannel *channel) { if (!channel) return; @@ -63,67 +65,58 @@ visorchannel_destroy(struct visorchannel *channel) kfree(channel); } -u64 -visorchannel_get_physaddr(struct visorchannel *channel) +u64 visorchannel_get_physaddr(struct visorchannel *channel) { return channel->physaddr; } -ulong -visorchannel_get_nbytes(struct visorchannel *channel) +ulong visorchannel_get_nbytes(struct visorchannel *channel) { return channel->nbytes; } -char * -visorchannel_uuid_id(uuid_le *guid, char *s) +char *visorchannel_guid_id(const guid_t *guid, char *s) { sprintf(s, "%pUL", guid); return s; } -char * -visorchannel_id(struct visorchannel *channel, char *s) +char *visorchannel_id(struct visorchannel *channel, char *s) { - return visorchannel_uuid_id(&channel->guid, s); + return visorchannel_guid_id(&channel->guid, s); } -char * -visorchannel_zoneid(struct visorchannel *channel, char *s) +char *visorchannel_zoneid(struct visorchannel *channel, char *s) { - return visorchannel_uuid_id(&channel->chan_hdr.zone_uuid, s); + return visorchannel_guid_id(&channel->chan_hdr.zone_guid, s); } -u64 -visorchannel_get_clientpartition(struct visorchannel *channel) +u64 visorchannel_get_clientpartition(struct visorchannel *channel) { return channel->chan_hdr.partition_handle; } -int -visorchannel_set_clientpartition(struct visorchannel *channel, - u64 partition_handle) +int visorchannel_set_clientpartition(struct visorchannel *channel, + u64 partition_handle) { channel->chan_hdr.partition_handle = partition_handle; return 0; } /** - * visorchannel_get_uuid() - queries the UUID of the designated channel + * visorchannel_get_guid() - queries the GUID of the designated channel * @channel: the channel to query * - * Return: the UUID of the provided channel + * Return: the GUID of the provided channel */ -uuid_le -visorchannel_get_uuid(struct visorchannel *channel) +const guid_t *visorchannel_get_guid(struct visorchannel *channel) { - return channel->guid; + return &channel->guid; } -EXPORT_SYMBOL_GPL(visorchannel_get_uuid); +EXPORT_SYMBOL_GPL(visorchannel_get_guid); -int -visorchannel_read(struct visorchannel *channel, ulong offset, - void *dest, ulong nbytes) +int visorchannel_read(struct visorchannel *channel, ulong offset, void *dest, + ulong nbytes) { if (offset + nbytes > channel->nbytes) return -EIO; @@ -133,9 +126,8 @@ visorchannel_read(struct visorchannel *channel, ulong offset, return 0; } -int -visorchannel_write(struct visorchannel *channel, ulong offset, - void *dest, ulong nbytes) +int visorchannel_write(struct visorchannel *channel, ulong offset, void *dest, + ulong nbytes) { size_t chdr_size = sizeof(struct channel_header); size_t copy_size; @@ -154,8 +146,7 @@ visorchannel_write(struct visorchannel *channel, ulong offset, return 0; } -void * -visorchannel_get_header(struct visorchannel *channel) +void *visorchannel_get_header(struct visorchannel *channel) { return &channel->chan_hdr; } @@ -164,17 +155,22 @@ visorchannel_get_header(struct visorchannel *channel) * Return offset of a specific SIGNAL_QUEUE_HEADER from the beginning of a * channel header */ -#define SIG_QUEUE_OFFSET(chan_hdr, q) \ - ((chan_hdr)->ch_space_offset + \ - ((q) * sizeof(struct signal_queue_header))) +static int sig_queue_offset(struct channel_header *chan_hdr, int q) +{ + return ((chan_hdr)->ch_space_offset + + ((q) * sizeof(struct signal_queue_header))); +} /* * Return offset of a specific queue entry (data) from the beginning of a * channel header */ -#define SIG_DATA_OFFSET(chan_hdr, q, sig_hdr, slot) \ - (SIG_QUEUE_OFFSET(chan_hdr, q) + (sig_hdr)->sig_base_offset + \ - ((slot) * (sig_hdr)->signal_size)) +static int sig_data_offset(struct channel_header *chan_hdr, int q, + struct signal_queue_header *sig_hdr, int slot) +{ + return (sig_queue_offset(chan_hdr, q) + sig_hdr->sig_base_offset + + (slot * sig_hdr->signal_size)); +} /* * Write the contents of a specific field within a SIGNAL_QUEUE_HEADER back @@ -182,48 +178,47 @@ visorchannel_get_header(struct visorchannel *channel) */ #define SIG_WRITE_FIELD(channel, queue, sig_hdr, FIELD) \ visorchannel_write(channel, \ - SIG_QUEUE_OFFSET(&channel->chan_hdr, queue) + \ + sig_queue_offset(&channel->chan_hdr, queue) + \ offsetof(struct signal_queue_header, FIELD), \ &((sig_hdr)->FIELD), \ sizeof((sig_hdr)->FIELD)) -static int -sig_read_header(struct visorchannel *channel, u32 queue, - struct signal_queue_header *sig_hdr) +static int sig_read_header(struct visorchannel *channel, u32 queue, + struct signal_queue_header *sig_hdr) { if (channel->chan_hdr.ch_space_offset < sizeof(struct channel_header)) return -EINVAL; /* Read the appropriate SIGNAL_QUEUE_HEADER into local memory. */ return visorchannel_read(channel, - SIG_QUEUE_OFFSET(&channel->chan_hdr, queue), + sig_queue_offset(&channel->chan_hdr, queue), sig_hdr, sizeof(struct signal_queue_header)); } -static int -sig_read_data(struct visorchannel *channel, u32 queue, - struct signal_queue_header *sig_hdr, u32 slot, void *data) +static int sig_read_data(struct visorchannel *channel, u32 queue, + struct signal_queue_header *sig_hdr, u32 slot, + void *data) { - int signal_data_offset = SIG_DATA_OFFSET(&channel->chan_hdr, queue, + int signal_data_offset = sig_data_offset(&channel->chan_hdr, queue, sig_hdr, slot); return visorchannel_read(channel, signal_data_offset, data, sig_hdr->signal_size); } -static int -sig_write_data(struct visorchannel *channel, u32 queue, - struct signal_queue_header *sig_hdr, u32 slot, void *data) +static int sig_write_data(struct visorchannel *channel, u32 queue, + struct signal_queue_header *sig_hdr, u32 slot, + void *data) { - int signal_data_offset = SIG_DATA_OFFSET(&channel->chan_hdr, queue, + int signal_data_offset = sig_data_offset(&channel->chan_hdr, queue, sig_hdr, slot); return visorchannel_write(channel, signal_data_offset, data, sig_hdr->signal_size); } -static int -signalremove_inner(struct visorchannel *channel, u32 queue, void *msg) +static int signalremove_inner(struct visorchannel *channel, u32 queue, + void *msg) { struct signal_queue_header sig_hdr; int error; @@ -246,9 +241,9 @@ signalremove_inner(struct visorchannel *channel, u32 queue, void *msg) /* * For each data field in SIGNAL_QUEUE_HEADER that was modified, - * update host memory. + * update host memory. Required for channel sync. */ - mb(); /* required for channel synch */ + mb(); error = SIG_WRITE_FIELD(channel, queue, &sig_hdr, tail); if (error) @@ -269,8 +264,8 @@ signalremove_inner(struct visorchannel *channel, u32 queue, void *msg) * * Return: integer error code indicating the status of the removal */ -int -visorchannel_signalremove(struct visorchannel *channel, u32 queue, void *msg) +int visorchannel_signalremove(struct visorchannel *channel, u32 queue, + void *msg) { int rc; unsigned long flags; @@ -287,8 +282,7 @@ visorchannel_signalremove(struct visorchannel *channel, u32 queue, void *msg) } EXPORT_SYMBOL_GPL(visorchannel_signalremove); -static bool -queue_empty(struct visorchannel *channel, u32 queue) +static bool queue_empty(struct visorchannel *channel, u32 queue) { struct signal_queue_header sig_hdr; @@ -307,8 +301,7 @@ queue_empty(struct visorchannel *channel, u32 queue) * Return: boolean indicating whether any messages in the designated * channel/queue are present */ -bool -visorchannel_signalempty(struct visorchannel *channel, u32 queue) +bool visorchannel_signalempty(struct visorchannel *channel, u32 queue) { bool rc; unsigned long flags; @@ -324,8 +317,8 @@ visorchannel_signalempty(struct visorchannel *channel, u32 queue) } EXPORT_SYMBOL_GPL(visorchannel_signalempty); -static int -signalinsert_inner(struct visorchannel *channel, u32 queue, void *msg) +static int signalinsert_inner(struct visorchannel *channel, u32 queue, + void *msg) { struct signal_queue_header sig_hdr; int err; @@ -351,9 +344,9 @@ signalinsert_inner(struct visorchannel *channel, u32 queue, void *msg) /* * For each data field in SIGNAL_QUEUE_HEADER that was modified, - * update host memory. + * update host memory. Required for channel sync. */ - mb(); /* required for channel synch */ + mb(); err = SIG_WRITE_FIELD(channel, queue, &sig_hdr, head); if (err) @@ -370,17 +363,8 @@ signalinsert_inner(struct visorchannel *channel, u32 queue, void *msg) * for a data area in memory, but does NOT modify * this data area * @physaddr: physical address of start of channel - * @channel_bytes: size of the channel in bytes; this may 0 if the channel has - * already been initialized in memory (which is true for all - * channels provided to guest environments by the s-Par - * back-end), in which case the actual channel size will be - * read from the channel header in memory * @gfp: gfp_t to use when allocating memory for the data struct - * @guid: uuid that identifies channel type; this may 0 if the channel - * has already been initialized in memory (which is true for all - * channels provided to guest environments by the s-Par - * back-end), in which case the actual channel guid will be - * read from the channel header in memory + * @guid: GUID that identifies channel type; * @needs_lock: must specify true if you have multiple threads of execution * that will be calling visorchannel methods of this * visorchannel at the same time @@ -388,9 +372,9 @@ signalinsert_inner(struct visorchannel *channel, u32 queue, void *msg) * Return: pointer to visorchannel that was created if successful, * otherwise NULL */ -static struct visorchannel * -visorchannel_create_guts(u64 physaddr, unsigned long channel_bytes, - gfp_t gfp, uuid_le guid, bool needs_lock) +static struct visorchannel *visorchannel_create_guts(u64 physaddr, gfp_t gfp, + const guid_t *guid, + bool needs_lock) { struct visorchannel *channel; int err; @@ -414,8 +398,8 @@ visorchannel_create_guts(u64 physaddr, unsigned long channel_bytes, * this. Remember that we haven't requested it so we don't try to * release later on. */ - channel->requested = request_mem_region(physaddr, size, MYDRVNAME); - if (!channel->requested && uuid_le_cmp(guid, visor_video_guid)) + channel->requested = request_mem_region(physaddr, size, VISOR_DRV_NAME); + if (!channel->requested && !guid_equal(guid, &visor_video_guid)) /* we only care about errors if this is not the video channel */ goto err_destroy_channel; @@ -428,36 +412,29 @@ visorchannel_create_guts(u64 physaddr, unsigned long channel_bytes, channel->physaddr = physaddr; channel->nbytes = size; - err = visorchannel_read(channel, 0, &channel->chan_hdr, - sizeof(struct channel_header)); + err = visorchannel_read(channel, 0, &channel->chan_hdr, size); if (err) goto err_destroy_channel; - - /* we had better be a CLIENT of this channel */ - if (channel_bytes == 0) - channel_bytes = (ulong)channel->chan_hdr.size; - if (uuid_le_cmp(guid, NULL_UUID_LE) == 0) - guid = channel->chan_hdr.chtype; + size = (ulong)channel->chan_hdr.size; memunmap(channel->mapped); if (channel->requested) release_mem_region(channel->physaddr, channel->nbytes); channel->mapped = NULL; - channel->requested = request_mem_region(channel->physaddr, - channel_bytes, MYDRVNAME); - if (!channel->requested && uuid_le_cmp(guid, visor_video_guid)) + channel->requested = request_mem_region(channel->physaddr, size, + VISOR_DRV_NAME); + if (!channel->requested && !guid_equal(guid, &visor_video_guid)) /* we only care about errors if this is not the video channel */ goto err_destroy_channel; - channel->mapped = memremap(channel->physaddr, channel_bytes, - MEMREMAP_WB); + channel->mapped = memremap(channel->physaddr, size, MEMREMAP_WB); if (!channel->mapped) { - release_mem_region(channel->physaddr, channel_bytes); + release_mem_region(channel->physaddr, size); goto err_destroy_channel; } - channel->nbytes = channel_bytes; - channel->guid = guid; + channel->nbytes = size; + guid_copy(&channel->guid, guid); return channel; err_destroy_channel: @@ -465,20 +442,16 @@ err_destroy_channel: return NULL; } -struct visorchannel * -visorchannel_create(u64 physaddr, unsigned long channel_bytes, - gfp_t gfp, uuid_le guid) +struct visorchannel *visorchannel_create(u64 physaddr, gfp_t gfp, + const guid_t *guid) { - return visorchannel_create_guts(physaddr, channel_bytes, gfp, guid, - false); + return visorchannel_create_guts(physaddr, gfp, guid, false); } -struct visorchannel * -visorchannel_create_with_lock(u64 physaddr, unsigned long channel_bytes, - gfp_t gfp, uuid_le guid) +struct visorchannel *visorchannel_create_with_lock(u64 physaddr, gfp_t gfp, + const guid_t *guid) { - return visorchannel_create_guts(physaddr, channel_bytes, gfp, guid, - true); + return visorchannel_create_guts(physaddr, gfp, guid, true); } /** @@ -490,8 +463,8 @@ visorchannel_create_with_lock(u64 physaddr, unsigned long channel_bytes, * * Return: integer error code indicating the status of the insertion */ -int -visorchannel_signalinsert(struct visorchannel *channel, u32 queue, void *msg) +int visorchannel_signalinsert(struct visorchannel *channel, u32 queue, + void *msg) { int rc; unsigned long flags; diff --git a/drivers/staging/unisys/visorbus/visorchipset.c b/drivers/staging/unisys/visorbus/visorchipset.c index 22150564b4fb..74cce4f1a7bd 100644 --- a/drivers/staging/unisys/visorbus/visorchipset.c +++ b/drivers/staging/unisys/visorbus/visorchipset.c @@ -1,5 +1,4 @@ -/* visorchipset_main.c - * +/* * Copyright (C) 2010 - 2015 UNISYS CORPORATION * All rights reserved. * @@ -15,19 +14,18 @@ */ #include <linux/acpi.h> -#include <linux/ctype.h> -#include <linux/fs.h> -#include <linux/mm.h> -#include <linux/nls.h> -#include <linux/netdevice.h> -#include <linux/uuid.h> #include <linux/crash_dump.h> #include "visorbus.h" #include "visorbus_private.h" -#include "vmcallinterface.h" -#define CURRENT_FILE_PC VISOR_BUS_PC_visorchipset_c +/* {72120008-4AAB-11DC-8530-444553544200} */ +#define VISOR_SIOVM_GUID GUID_INIT(0x72120008, 0x4AAB, 0x11DC, 0x85, 0x30, \ + 0x44, 0x45, 0x53, 0x54, 0x42, 0x00) + +static const guid_t visor_vhba_channel_guid = VISOR_VHBA_CHANNEL_GUID; +static const guid_t visor_siovm_guid = VISOR_SIOVM_GUID; +static const guid_t visor_controlvm_channel_guid = VISOR_CONTROLVM_CHANNEL_GUID; #define POLLJIFFIES_CONTROLVMCHANNEL_FAST 1 #define POLLJIFFIES_CONTROLVMCHANNEL_SLOW 100 @@ -42,9 +40,9 @@ #define UNISYS_VISOR_ID_EDX 0x34367261 /* - * When the controlvm channel is idle for at least MIN_IDLE_SECONDS, - * we switch to slow polling mode. As soon as we get a controlvm - * message, we switch back to fast polling mode. + * When the controlvm channel is idle for at least MIN_IDLE_SECONDS, we switch + * to slow polling mode. As soon as we get a controlvm message, we switch back + * to fast polling mode. */ #define MIN_IDLE_SECONDS 10 @@ -54,15 +52,39 @@ struct parser_context { u8 *curr; unsigned long bytes_remaining; bool byte_stream; - char data[0]; + struct visor_controlvm_parameters_header data; }; -struct vmcall_controlvm_addr { - struct vmcall_io_controlvm_addr_params params; - int err; - u64 physaddr; +/* VMCALL_CONTROLVM_ADDR: Used by all guests, not just IO. */ +#define VMCALL_CONTROLVM_ADDR 0x0501 + +enum vmcall_result { + VMCALL_RESULT_SUCCESS = 0, + VMCALL_RESULT_INVALID_PARAM = 1, + VMCALL_RESULT_DATA_UNAVAILABLE = 2, + VMCALL_RESULT_FAILURE_UNAVAILABLE = 3, + VMCALL_RESULT_DEVICE_ERROR = 4, + VMCALL_RESULT_DEVICE_NOT_READY = 5 }; +/* + * struct vmcall_io_controlvm_addr_params - Structure for IO VMCALLS. Has + * parameters to VMCALL_CONTROLVM_ADDR + * interface. + * @address: The Guest-relative physical address of the ControlVm channel. + * This VMCall fills this in with the appropriate address. + * Contents provided by this VMCALL (OUT). + * @channel_bytes: The size of the ControlVm channel in bytes This VMCall fills + * this in with the appropriate address. Contents provided by + * this VMCALL (OUT). + * @unused: Unused Bytes in the 64-Bit Aligned Struct. + */ +struct vmcall_io_controlvm_addr_params { + u64 address; + u32 channel_bytes; + u8 unused[4]; +} __packed; + struct visorchipset_device { struct acpi_device *acpi_device; unsigned long poll_jiffies; @@ -80,7 +102,7 @@ struct visorchipset_device { */ struct controlvm_message controlvm_pending_msg; bool controlvm_pending_msg_valid; - struct vmcall_controlvm_addr controlvm_addr; + struct vmcall_io_controlvm_addr_params controlvm_params; }; static struct visorchipset_device *chipset_dev; @@ -124,7 +146,6 @@ static ssize_t toolaction_store(struct device *dev, offsetof(struct visor_controlvm_channel, tool_action), &tool_action, sizeof(u8)); - if (err) return err; return count; @@ -143,7 +164,6 @@ static ssize_t boottotool_show(struct device *dev, efi_visor_ind), &efi_visor_indication, sizeof(struct efi_visor_indication)); - if (err) return err; return sprintf(buf, "%u\n", efi_visor_indication.boot_to_tool); @@ -165,7 +185,6 @@ static ssize_t boottotool_store(struct device *dev, efi_visor_ind), &(efi_visor_indication), sizeof(struct efi_visor_indication)); - if (err) return err; return count; @@ -184,7 +203,7 @@ static ssize_t error_show(struct device *dev, struct device_attribute *attr, &error, sizeof(u32)); if (err) return err; - return sprintf(buf, "%i\n", error); + return sprintf(buf, "%u\n", error); } static ssize_t error_store(struct device *dev, struct device_attribute *attr, @@ -219,7 +238,7 @@ static ssize_t textid_show(struct device *dev, struct device_attribute *attr, if (err) return err; - return sprintf(buf, "%i\n", text_id); + return sprintf(buf, "%u\n", text_id); } static ssize_t textid_store(struct device *dev, struct device_attribute *attr, @@ -277,67 +296,6 @@ static ssize_t remaining_steps_store(struct device *dev, } static DEVICE_ATTR_RW(remaining_steps); -static uuid_le -parser_id_get(struct parser_context *ctx) -{ - struct visor_controlvm_parameters_header *phdr = NULL; - - phdr = (struct visor_controlvm_parameters_header *)(ctx->data); - return phdr->id; -} - -static void parser_done(struct parser_context *ctx) -{ - chipset_dev->controlvm_payload_bytes_buffered -= ctx->param_bytes; - kfree(ctx); -} - -static void * -parser_string_get(struct parser_context *ctx) -{ - u8 *pscan; - unsigned long nscan; - int value_length = -1; - void *value = NULL; - int i; - - pscan = ctx->curr; - nscan = ctx->bytes_remaining; - if (nscan == 0) - return NULL; - if (!pscan) - return NULL; - for (i = 0, value_length = -1; i < nscan; i++) - if (pscan[i] == '\0') { - value_length = i; - break; - } - if (value_length < 0) /* '\0' was not included in the length */ - value_length = nscan; - value = kmalloc(value_length + 1, GFP_KERNEL); - if (!value) - return NULL; - if (value_length > 0) - memcpy(value, pscan, value_length); - ((u8 *)(value))[value_length] = '\0'; - return value; -} - -static void * -parser_name_get(struct parser_context *ctx) -{ - struct visor_controlvm_parameters_header *phdr = NULL; - - phdr = (struct visor_controlvm_parameters_header *)(ctx->data); - - if (phdr->name_offset + phdr->name_length > ctx->param_bytes) - return NULL; - - ctx->curr = ctx->data + phdr->name_offset; - ctx->bytes_remaining = phdr->name_length; - return parser_string_get(ctx); -} - struct visor_busdev { u32 bus_no; u32 dev_no; @@ -347,11 +305,9 @@ static int match_visorbus_dev_by_id(struct device *dev, void *data) { struct visor_device *vdev = to_visor_device(dev); struct visor_busdev *id = data; - u32 bus_no = id->bus_no; - u32 dev_no = id->dev_no; - if ((vdev->chipset_bus_no == bus_no) && - (vdev->chipset_dev_no == dev_no)) + if ((vdev->chipset_bus_no == id->bus_no) && + (vdev->chipset_dev_no == id->dev_no)) return 1; return 0; @@ -364,9 +320,9 @@ struct visor_device *visorbus_get_device_by_id(u32 bus_no, u32 dev_no, struct device *dev_start = NULL; struct visor_device *vdev = NULL; struct visor_busdev id = { - .bus_no = bus_no, - .dev_no = dev_no - }; + .bus_no = bus_no, + .dev_no = dev_no + }; if (from) dev_start = &from->device; @@ -377,9 +333,9 @@ struct visor_device *visorbus_get_device_by_id(u32 bus_no, u32 dev_no, return vdev; } -static void -controlvm_init_response(struct controlvm_message *msg, - struct controlvm_message_header *msg_hdr, int response) +static void controlvm_init_response(struct controlvm_message *msg, + struct controlvm_message_header *msg_hdr, + int response) { memset(msg, 0, sizeof(struct controlvm_message)); memcpy(&msg->hdr, msg_hdr, sizeof(struct controlvm_message_header)); @@ -392,10 +348,10 @@ controlvm_init_response(struct controlvm_message *msg, } } -static int -controlvm_respond_chipset_init(struct controlvm_message_header *msg_hdr, - int response, - enum visor_chipset_feature features) +static int controlvm_respond_chipset_init( + struct controlvm_message_header *msg_hdr, + int response, + enum visor_chipset_feature features) { struct controlvm_message outmsg; @@ -405,8 +361,7 @@ controlvm_respond_chipset_init(struct controlvm_message_header *msg_hdr, CONTROLVM_QUEUE_REQUEST, &outmsg); } -static int -chipset_init(struct controlvm_message *inmsg) +static int chipset_init(struct controlvm_message *inmsg) { static int chipset_inited; enum visor_chipset_feature features = 0; @@ -421,15 +376,15 @@ chipset_init(struct controlvm_message *inmsg) chipset_inited = 1; /* - * Set features to indicate we support parahotplug (if Command - * also supports it). + * Set features to indicate we support parahotplug (if Command also + * supports it). */ features = inmsg->cmd.init_chipset.features & VISOR_CHIPSET_FEATURE_PARA_HOTPLUG; /* - * Set the "reply" bit so Command knows this is a - * features-aware driver. + * Set the "reply" bit so Command knows this is a features-aware + * driver. */ features |= VISOR_CHIPSET_FEATURE_REPLY; @@ -440,9 +395,9 @@ out_respond: return res; } -static int -controlvm_respond(struct controlvm_message_header *msg_hdr, int response, - struct visor_segment_state *state) +static int controlvm_respond(struct controlvm_message_header *msg_hdr, + int response, + struct visor_segment_state *state) { struct controlvm_message outmsg; @@ -464,8 +419,8 @@ enum crash_obj_type { CRASH_BUS, }; -static int -save_crash_message(struct controlvm_message *msg, enum crash_obj_type cr_type) +static int save_crash_message(struct controlvm_message *msg, + enum crash_obj_type cr_type) { u32 local_crash_msg_offset; u16 local_crash_msg_count; @@ -529,10 +484,9 @@ save_crash_message(struct controlvm_message *msg, enum crash_obj_type cr_type) return 0; } -static int -controlvm_responder(enum controlvm_id cmd_id, - struct controlvm_message_header *pending_msg_hdr, - int response) +static int controlvm_responder(enum controlvm_id cmd_id, + struct controlvm_message_header *pending_msg_hdr, + int response) { if (!pending_msg_hdr) return -EIO; @@ -543,14 +497,12 @@ controlvm_responder(enum controlvm_id cmd_id, return controlvm_respond(pending_msg_hdr, response, NULL); } -static int -device_changestate_responder(enum controlvm_id cmd_id, - struct visor_device *p, int response, - struct visor_segment_state response_state) +static int device_changestate_responder( + enum controlvm_id cmd_id, + struct visor_device *p, int response, + struct visor_segment_state response_state) { struct controlvm_message outmsg; - u32 bus_no = p->chipset_bus_no; - u32 dev_no = p->chipset_dev_no; if (!p->pending_msg_hdr) return -EIO; @@ -559,16 +511,15 @@ device_changestate_responder(enum controlvm_id cmd_id, controlvm_init_response(&outmsg, p->pending_msg_hdr, response); - outmsg.cmd.device_change_state.bus_no = bus_no; - outmsg.cmd.device_change_state.dev_no = dev_no; + outmsg.cmd.device_change_state.bus_no = p->chipset_bus_no; + outmsg.cmd.device_change_state.dev_no = p->chipset_dev_no; outmsg.cmd.device_change_state.state = response_state; return visorchannel_signalinsert(chipset_dev->controlvm_channel, CONTROLVM_QUEUE_REQUEST, &outmsg); } -static int -visorbus_create(struct controlvm_message *inmsg) +static int visorbus_create(struct controlvm_message *inmsg) { struct controlvm_message_packet *cmd = &inmsg->cmd; struct controlvm_message_header *pmsg_hdr = NULL; @@ -580,7 +531,7 @@ visorbus_create(struct controlvm_message *inmsg) bus_info = visorbus_get_device_by_id(bus_no, BUS_ROOT_DEVICE, NULL); if (bus_info && (bus_info->state.created == 1)) { dev_err(&chipset_dev->acpi_device->dev, - "failed visorbus_create: already exists\n"); + "failed %s: already exists\n", __func__); err = -EEXIST; goto err_respond; } @@ -595,7 +546,7 @@ visorbus_create(struct controlvm_message *inmsg) bus_info->chipset_bus_no = bus_no; bus_info->chipset_dev_no = BUS_ROOT_DEVICE; - if (uuid_le_cmp(cmd->create_bus.bus_inst_uuid, visor_siovm_uuid) == 0) { + if (guid_equal(&cmd->create_bus.bus_inst_guid, &visor_siovm_guid)) { err = save_crash_message(inmsg, CRASH_BUS); if (err) goto err_free_bus_info; @@ -615,19 +566,17 @@ visorbus_create(struct controlvm_message *inmsg) } visorchannel = visorchannel_create(cmd->create_bus.channel_addr, - cmd->create_bus.channel_bytes, GFP_KERNEL, - cmd->create_bus.bus_data_type_uuid); - + &cmd->create_bus.bus_data_type_guid); if (!visorchannel) { err = -ENOMEM; goto err_free_pending_msg; } + bus_info->visorchannel = visorchannel; - /* Response will be handled by visorchipset_bus_create */ - err = visorchipset_bus_create(bus_info); - /* If visorchipset_bus_create didn't respond, need to respond here */ + /* Response will be handled by visorbus_create_instance on success */ + err = visorbus_create_instance(bus_info); if (err) goto err_destroy_channel; @@ -648,8 +597,7 @@ err_respond: return err; } -static int -visorbus_destroy(struct controlvm_message *inmsg) +static int visorbus_destroy(struct controlvm_message *inmsg) { struct controlvm_message_packet *cmd = &inmsg->cmd; struct controlvm_message_header *pmsg_hdr = NULL; @@ -683,8 +631,8 @@ visorbus_destroy(struct controlvm_message *inmsg) bus_info->pending_msg_hdr = pmsg_hdr; } - /* Response will be handled by visorchipset_bus_destroy */ - visorchipset_bus_destroy(bus_info); + /* Response will be handled by visorbus_remove_instance */ + visorbus_remove_instance(bus_info); return 0; err_respond: @@ -693,9 +641,60 @@ err_respond: return err; } -static int -visorbus_configure(struct controlvm_message *inmsg, - struct parser_context *parser_ctx) +static const guid_t *parser_id_get(struct parser_context *ctx) +{ + return &ctx->data.id; +} + +static void *parser_string_get(struct parser_context *ctx) +{ + u8 *pscan; + unsigned long nscan; + int value_length; + void *value; + int i; + + pscan = ctx->curr; + if (!pscan) + return NULL; + nscan = ctx->bytes_remaining; + if (nscan == 0) + return NULL; + + for (i = 0, value_length = -1; i < nscan; i++) + if (pscan[i] == '\0') { + value_length = i; + break; + } + /* '\0' was not included in the length */ + if (value_length < 0) + value_length = nscan; + + value = kmalloc(value_length + 1, GFP_KERNEL); + if (!value) + return NULL; + if (value_length > 0) + memcpy(value, pscan, value_length); + ((u8 *)(value))[value_length] = '\0'; + return value; +} + +static void *parser_name_get(struct parser_context *ctx) +{ + struct visor_controlvm_parameters_header *phdr = NULL; + + phdr = &ctx->data; + + if (phdr->name_offset + phdr->name_length > ctx->param_bytes) + return NULL; + + ctx->curr = (char *)&phdr + phdr->name_offset; + ctx->bytes_remaining = phdr->name_length; + return parser_string_get(ctx); +} + +static int visorbus_configure(struct controlvm_message *inmsg, + struct parser_context *parser_ctx) { struct controlvm_message_packet *cmd = &inmsg->cmd; u32 bus_no; @@ -707,10 +706,12 @@ visorbus_configure(struct controlvm_message *inmsg, if (!bus_info) { err = -EINVAL; goto err_respond; - } else if (bus_info->state.created == 0) { + } + if (bus_info->state.created == 0) { err = -EINVAL; goto err_respond; - } else if (bus_info->pending_msg_hdr) { + } + if (bus_info->pending_msg_hdr) { err = -EIO; goto err_respond; } @@ -722,7 +723,9 @@ visorbus_configure(struct controlvm_message *inmsg, goto err_respond; if (parser_ctx) { - bus_info->partition_uuid = parser_id_get(parser_ctx); + const guid_t *partition_guid = parser_id_get(parser_ctx); + + guid_copy(&bus_info->partition_guid, partition_guid); bus_info->name = parser_name_get(parser_ctx); } @@ -732,14 +735,13 @@ visorbus_configure(struct controlvm_message *inmsg, err_respond: dev_err(&chipset_dev->acpi_device->dev, - "visorbus_configure exited with err: %d\n", err); + "%s exited with err: %d\n", __func__, err); if (inmsg->hdr.flags.response_expected == 1) controlvm_responder(inmsg->hdr.id, &inmsg->hdr, err); return err; } -static int -visorbus_device_create(struct controlvm_message *inmsg) +static int visorbus_device_create(struct controlvm_message *inmsg) { struct controlvm_message_packet *cmd = &inmsg->cmd; struct controlvm_message_header *pmsg_hdr = NULL; @@ -757,7 +759,6 @@ visorbus_device_create(struct controlvm_message *inmsg) err = -ENODEV; goto err_respond; } - if (bus_info->state.created == 0) { dev_err(&chipset_dev->acpi_device->dev, "bus not created, id: %d\n", bus_no); @@ -781,17 +782,13 @@ visorbus_device_create(struct controlvm_message *inmsg) dev_info->chipset_bus_no = bus_no; dev_info->chipset_dev_no = dev_no; - dev_info->inst = cmd->create_device.dev_inst_uuid; - - /* not sure where the best place to set the 'parent' */ + guid_copy(&dev_info->inst, &cmd->create_device.dev_inst_guid); dev_info->device.parent = &bus_info->device; visorchannel = visorchannel_create_with_lock(cmd->create_device.channel_addr, - cmd->create_device.channel_bytes, GFP_KERNEL, - cmd->create_device.data_type_uuid); - + &cmd->create_device.data_type_guid); if (!visorchannel) { dev_err(&chipset_dev->acpi_device->dev, "failed to create visorchannel: %d/%d\n", @@ -800,9 +797,8 @@ visorbus_device_create(struct controlvm_message *inmsg) goto err_free_dev_info; } dev_info->visorchannel = visorchannel; - dev_info->channel_type_guid = cmd->create_device.data_type_uuid; - if (uuid_le_cmp(cmd->create_device.data_type_uuid, - visor_vhba_channel_uuid) == 0) { + guid_copy(&dev_info->channel_type_guid, &cmd->create_device.data_type_guid); + if (guid_equal(&cmd->create_device.data_type_guid, &visor_vhba_channel_guid)) { err = save_crash_message(inmsg, CRASH_DEV); if (err) goto err_destroy_visorchannel; @@ -819,8 +815,8 @@ visorbus_device_create(struct controlvm_message *inmsg) sizeof(struct controlvm_message_header)); dev_info->pending_msg_hdr = pmsg_hdr; } - /* visorchipset_device_create will send response */ - err = visorchipset_device_create(dev_info); + /* create_visor_device will send response */ + err = create_visor_device(dev_info); if (err) goto err_destroy_visorchannel; @@ -838,8 +834,7 @@ err_respond: return err; } -static int -visorbus_device_changestate(struct controlvm_message *inmsg) +static int visorbus_device_changestate(struct controlvm_message *inmsg) { struct controlvm_message_packet *cmd = &inmsg->cmd; struct controlvm_message_header *pmsg_hdr = NULL; @@ -899,8 +894,7 @@ err_respond: return err; } -static int -visorbus_device_destroy(struct controlvm_message *inmsg) +static int visorbus_device_destroy(struct controlvm_message *inmsg) { struct controlvm_message_packet *cmd = &inmsg->cmd; struct controlvm_message_header *pmsg_hdr = NULL; @@ -918,7 +912,6 @@ visorbus_device_destroy(struct controlvm_message *inmsg) err = -EINVAL; goto err_respond; } - if (dev_info->pending_msg_hdr) { /* only non-NULL if dev is still waiting on a response */ err = -EIO; @@ -936,7 +929,8 @@ visorbus_device_destroy(struct controlvm_message *inmsg) dev_info->pending_msg_hdr = pmsg_hdr; } - visorchipset_device_destroy(dev_info); + kfree(dev_info->name); + remove_visor_device(dev_info); return 0; err_respond: @@ -954,8 +948,7 @@ err_respond: * disable the specified device. The udev script then writes to * /sys/devices/platform/visorchipset/parahotplug, which causes the * parahotplug store functions to get called, at which point the - * appropriate CONTROLVM message is retrieved from the list and responded - * to. + * appropriate CONTROLVM message is retrieved from the list and responded to. */ #define PARAHOTPLUG_TIMEOUT_MS 2000 @@ -967,8 +960,7 @@ err_respond: * * Return: a unique integer value */ -static int -parahotplug_next_id(void) +static int parahotplug_next_id(void) { static atomic_t id = ATOMIC_INIT(0); @@ -982,8 +974,7 @@ parahotplug_next_id(void) * * Return: expected expiration time (in jiffies) */ -static unsigned long -parahotplug_next_expiration(void) +static unsigned long parahotplug_next_expiration(void) { return jiffies + msecs_to_jiffies(PARAHOTPLUG_TIMEOUT_MS); } @@ -996,8 +987,8 @@ parahotplug_next_expiration(void) * * Return: the request containing the provided message */ -static struct parahotplug_request * -parahotplug_request_create(struct controlvm_message *msg) +static struct parahotplug_request *parahotplug_request_create( + struct controlvm_message *msg) { struct parahotplug_request *req; @@ -1016,14 +1007,14 @@ parahotplug_request_create(struct controlvm_message *msg) * parahotplug_request_destroy() - free a parahotplug_request * @req: the request to deallocate */ -static void -parahotplug_request_destroy(struct parahotplug_request *req) +static void parahotplug_request_destroy(struct parahotplug_request *req) { kfree(req); } static LIST_HEAD(parahotplug_request_list); -static DEFINE_SPINLOCK(parahotplug_request_list_lock); /* lock for above */ +/* lock for above */ +static DEFINE_SPINLOCK(parahotplug_request_list_lock); /* * parahotplug_request_complete() - mark request as complete @@ -1036,8 +1027,7 @@ static DEFINE_SPINLOCK(parahotplug_request_list_lock); /* lock for above */ * * Return: 0 on success or -EINVAL on failure */ -static int -parahotplug_request_complete(int id, u16 active) +static int parahotplug_request_complete(int id, u16 active) { struct list_head *pos; struct list_head *tmp; @@ -1146,7 +1136,7 @@ static struct attribute *visorchipset_parahotplug_attrs[] = { NULL }; -static struct attribute_group visorchipset_parahotplug_group = { +static const struct attribute_group visorchipset_parahotplug_group = { .name = "parahotplug", .attrs = visorchipset_parahotplug_attrs }; @@ -1164,8 +1154,7 @@ static const struct attribute_group *visorchipset_dev_groups[] = { * Cause uevent to run the user level script to do the disable/enable specified * in the parahotplug_request. */ -static int -parahotplug_request_kickoff(struct parahotplug_request *req) +static int parahotplug_request_kickoff(struct parahotplug_request *req) { struct controlvm_message_packet *cmd = &req->msg.cmd; char env_cmd[40], env_id[40], env_state[40], env_bus[40], env_dev[40], @@ -1194,14 +1183,12 @@ parahotplug_request_kickoff(struct parahotplug_request *req) * off a udev script * @inmsg: the message indicating whether to enable or disable */ -static int -parahotplug_process_message(struct controlvm_message *inmsg) +static int parahotplug_process_message(struct controlvm_message *inmsg) { struct parahotplug_request *req; int err; req = parahotplug_request_create(inmsg); - if (!req) return -ENOMEM; @@ -1220,10 +1207,9 @@ parahotplug_process_message(struct controlvm_message *inmsg) } /* - * For disable messages, add the request to the - * request list before kicking off the udev script. It - * won't get responded to until the script has - * indicated it's done. + * For disable messages, add the request to the request list before + * kicking off the udev script. It won't get responded to until the + * script has indicated it's done. */ spin_lock(¶hotplug_request_list_lock); list_add_tail(&req->list, ¶hotplug_request_list); @@ -1247,8 +1233,7 @@ err_respond: * * Return: 0 on success, negative on failure */ -static int -chipset_ready_uevent(struct controlvm_message_header *msg_hdr) +static int chipset_ready_uevent(struct controlvm_message_header *msg_hdr) { int res; @@ -1268,8 +1253,7 @@ chipset_ready_uevent(struct controlvm_message_header *msg_hdr) * * Return: 0 on success, negative on failure */ -static int -chipset_selftest_uevent(struct controlvm_message_header *msg_hdr) +static int chipset_selftest_uevent(struct controlvm_message_header *msg_hdr) { char env_selftest[20]; char *envp[] = { env_selftest, NULL }; @@ -1292,13 +1276,11 @@ chipset_selftest_uevent(struct controlvm_message_header *msg_hdr) * * Return: 0 on success, negative on failure */ -static int -chipset_notready_uevent(struct controlvm_message_header *msg_hdr) +static int chipset_notready_uevent(struct controlvm_message_header *msg_hdr) { - int res; - - res = kobject_uevent(&chipset_dev->acpi_device->dev.kobj, + int res = kobject_uevent(&chipset_dev->acpi_device->dev.kobj, KOBJ_OFFLINE); + if (msg_hdr->flags.response_expected) controlvm_respond(msg_hdr, res, NULL); @@ -1321,13 +1303,12 @@ static int unisys_vmcall(unsigned long tuple, unsigned long param) __asm__ __volatile__(".byte 0x00f, 0x001, 0x0c1" : "=a"(result) : "a"(tuple), "b"(reg_ebx), "c"(reg_ecx)); - if (result) goto error; return 0; - -error: /* Need to convert from VMCALL error codes to Linux */ +/* Need to convert from VMCALL error codes to Linux */ +error: switch (result) { case VMCALL_RESULT_INVALID_PARAM: return -EINVAL; @@ -1337,35 +1318,27 @@ error: /* Need to convert from VMCALL error codes to Linux */ return -EFAULT; } } -static unsigned int -issue_vmcall_io_controlvm_addr(u64 *control_addr, u32 *control_bytes) -{ - chipset_dev->controlvm_addr.physaddr = virt_to_phys( - &chipset_dev->controlvm_addr.params); - chipset_dev->controlvm_addr.err = unisys_vmcall(VMCALL_CONTROLVM_ADDR, - chipset_dev->controlvm_addr.physaddr); - if (chipset_dev->controlvm_addr.err) - return chipset_dev->controlvm_addr.err; - - *control_addr = chipset_dev->controlvm_addr.params.address; - *control_bytes = chipset_dev->controlvm_addr.params.channel_bytes; - - return 0; -} -static u64 controlvm_get_channel_address(void) +static int controlvm_channel_create(struct visorchipset_device *dev) { - u64 addr = 0; - u32 size = 0; - - if (issue_vmcall_io_controlvm_addr(&addr, &size)) - return 0; + struct visorchannel *chan; + u64 addr; + int err; - return addr; + err = unisys_vmcall(VMCALL_CONTROLVM_ADDR, + virt_to_phys(&dev->controlvm_params)); + if (err) + return err; + addr = dev->controlvm_params.address; + chan = visorchannel_create_with_lock(addr, GFP_KERNEL, + &visor_controlvm_channel_guid); + if (!chan) + return -ENOMEM; + dev->controlvm_channel = chan; + return 0; } -static void -setup_crash_devices_work_queue(struct work_struct *work) +static void setup_crash_devices_work_queue(struct work_struct *work) { struct controlvm_message local_crash_bus_msg; struct controlvm_message local_crash_dev_msg; @@ -1444,87 +1417,44 @@ setup_crash_devices_work_queue(struct work_struct *work) visorbus_device_create(&local_crash_dev_msg); } -void -visorbus_create_response(struct visor_device *bus_info, int response) +void visorbus_response(struct visor_device *bus_info, int response, + int controlvm_id) { - if (response >= 0) - bus_info->state.created = 1; - - controlvm_responder(CONTROLVM_BUS_CREATE, bus_info->pending_msg_hdr, - response); + controlvm_responder(controlvm_id, bus_info->pending_msg_hdr, response); kfree(bus_info->pending_msg_hdr); bus_info->pending_msg_hdr = NULL; } -void -visorbus_destroy_response(struct visor_device *bus_info, int response) -{ - controlvm_responder(CONTROLVM_BUS_DESTROY, bus_info->pending_msg_hdr, - response); - - kfree(bus_info->pending_msg_hdr); - bus_info->pending_msg_hdr = NULL; -} - -void -visorbus_device_create_response(struct visor_device *dev_info, int response) -{ - if (response >= 0) - dev_info->state.created = 1; - - controlvm_responder(CONTROLVM_DEVICE_CREATE, dev_info->pending_msg_hdr, - response); - - kfree(dev_info->pending_msg_hdr); - dev_info->pending_msg_hdr = NULL; -} - -void -visorbus_device_destroy_response(struct visor_device *dev_info, int response) -{ - controlvm_responder(CONTROLVM_DEVICE_DESTROY, dev_info->pending_msg_hdr, - response); - - kfree(dev_info->pending_msg_hdr); - dev_info->pending_msg_hdr = NULL; -} - -void -visorbus_device_pause_response(struct visor_device *dev_info, int response) +void visorbus_device_changestate_response(struct visor_device *dev_info, + int response, + struct visor_segment_state state) { device_changestate_responder(CONTROLVM_DEVICE_CHANGESTATE, - dev_info, response, - segment_state_standby); + dev_info, response, state); kfree(dev_info->pending_msg_hdr); dev_info->pending_msg_hdr = NULL; } -void -visorbus_device_resume_response(struct visor_device *dev_info, int response) +static void parser_done(struct parser_context *ctx) { - device_changestate_responder(CONTROLVM_DEVICE_CHANGESTATE, - dev_info, response, - segment_state_running); - - kfree(dev_info->pending_msg_hdr); - dev_info->pending_msg_hdr = NULL; + chipset_dev->controlvm_payload_bytes_buffered -= ctx->param_bytes; + kfree(ctx); } -static struct parser_context * -parser_init_byte_stream(u64 addr, u32 bytes, bool local, bool *retry) +static struct parser_context *parser_init_stream(u64 addr, u32 bytes, + bool *retry) { - int allocbytes = sizeof(struct parser_context) + bytes; + int allocbytes; struct parser_context *ctx; + void *mapping; *retry = false; - /* - * alloc an 0 extra byte to ensure payload is - * '\0'-terminated - */ - allocbytes++; + /* alloc an extra byte to ensure payload is \0 terminated */ + allocbytes = bytes + 1 + (sizeof(struct parser_context) - + sizeof(struct visor_controlvm_parameters_header)); if ((chipset_dev->controlvm_payload_bytes_buffered + bytes) > MAX_CONTROLVM_PAYLOAD_BYTES) { *retry = true; @@ -1538,32 +1468,18 @@ parser_init_byte_stream(u64 addr, u32 bytes, bool local, bool *retry) ctx->allocbytes = allocbytes; ctx->param_bytes = bytes; - ctx->curr = NULL; - ctx->bytes_remaining = 0; - ctx->byte_stream = false; - if (local) { - void *p; - - if (addr > virt_to_phys(high_memory - 1)) - goto err_finish_ctx; - p = __va((unsigned long)(addr)); - memcpy(ctx->data, p, bytes); - } else { - void *mapping = memremap(addr, bytes, MEMREMAP_WB); - - if (!mapping) - goto err_finish_ctx; - memcpy(ctx->data, mapping, bytes); - memunmap(mapping); - } - + mapping = memremap(addr, bytes, MEMREMAP_WB); + if (!mapping) + goto err_finish_ctx; + memcpy(&ctx->data, mapping, bytes); + memunmap(mapping); ctx->byte_stream = true; chipset_dev->controlvm_payload_bytes_buffered += ctx->param_bytes; return ctx; err_finish_ctx: - parser_done(ctx); + kfree(ctx); return NULL; } @@ -1580,19 +1496,16 @@ err_finish_ctx: * which to copy out controlvm payload data. * < 0 - error: ControlVM message was processed but an error occurred. */ -static int -handle_command(struct controlvm_message inmsg, u64 channel_addr) +static int handle_command(struct controlvm_message inmsg, u64 channel_addr) { struct controlvm_message_packet *cmd = &inmsg.cmd; u64 parm_addr; u32 parm_bytes; struct parser_context *parser_ctx = NULL; - bool local_addr; struct controlvm_message ackmsg; int err = 0; /* create parsing context if necessary */ - local_addr = (inmsg.hdr.flags.test_message == 1); parm_addr = channel_addr + inmsg.hdr.payload_vm_offset; parm_bytes = inmsg.hdr.payload_bytes; @@ -1601,25 +1514,19 @@ handle_command(struct controlvm_message inmsg, u64 channel_addr) * within our OS-controlled memory. We need to know that, because it * makes a difference in how we compute the virtual address. */ - if (parm_addr && parm_bytes) { + if (parm_bytes) { bool retry = false; - parser_ctx = - parser_init_byte_stream(parm_addr, parm_bytes, - local_addr, &retry); + parser_ctx = parser_init_stream(parm_addr, parm_bytes, &retry); if (!parser_ctx && retry) return -EAGAIN; } + controlvm_init_response(&ackmsg, &inmsg.hdr, CONTROLVM_RESP_SUCCESS); + err = visorchannel_signalinsert(chipset_dev->controlvm_channel, + CONTROLVM_QUEUE_ACK, &ackmsg); + if (err) + return err; - if (!local_addr) { - controlvm_init_response(&ackmsg, &inmsg.hdr, - CONTROLVM_RESP_SUCCESS); - err = visorchannel_signalinsert(chipset_dev->controlvm_channel, - CONTROLVM_QUEUE_ACK, - &ackmsg); - if (err) - return err; - } switch (inmsg.hdr.id) { case CONTROLVM_CHIPSET_INIT: err = chipset_init(&inmsg); @@ -1641,8 +1548,8 @@ handle_command(struct controlvm_message inmsg, u64 channel_addr) err = parahotplug_process_message(&inmsg); } else { /* - * save the hdr and cmd structures for later use - * when sending back the response to Command + * save the hdr and cmd structures for later use when + * sending back the response to Command */ err = visorbus_device_changestate(&inmsg); break; @@ -1689,12 +1596,9 @@ handle_command(struct controlvm_message inmsg, u64 channel_addr) * * Return: 0 if valid message was retrieved or -error */ -static int -read_controlvm_event(struct controlvm_message *msg) +static int read_controlvm_event(struct controlvm_message *msg) { - int err; - - err = visorchannel_signalremove(chipset_dev->controlvm_channel, + int err = visorchannel_signalremove(chipset_dev->controlvm_channel, CONTROLVM_QUEUE_EVENT, msg); if (err) return err; @@ -1710,8 +1614,7 @@ read_controlvm_event(struct controlvm_message *msg) * parahotplug_process_list() - remove any request from the list that's been on * there too long and respond with an error */ -static void -parahotplug_process_list(void) +static void parahotplug_process_list(void) { struct list_head *pos; struct list_head *tmp; @@ -1737,8 +1640,7 @@ parahotplug_process_list(void) spin_unlock(¶hotplug_request_list_lock); } -static void -controlvm_periodic_work(struct work_struct *work) +static void controlvm_periodic_work(struct work_struct *work) { struct controlvm_message inmsg; int count = 0; @@ -1756,9 +1658,8 @@ controlvm_periodic_work(struct work_struct *work) if (chipset_dev->controlvm_pending_msg_valid) { /* - * we throttled processing of a prior - * msg, so try to process it again - * rather than reading a new one + * we throttled processing of a prior msg, so try to process + * it again rather than reading a new one */ inmsg = chipset_dev->controlvm_pending_msg; chipset_dev->controlvm_pending_msg_valid = false; @@ -1793,9 +1694,8 @@ schedule_out: if (time_after(jiffies, chipset_dev->most_recent_message_jiffies + (HZ * MIN_IDLE_SECONDS))) { /* - * it's been longer than MIN_IDLE_SECONDS since we - * processed our last controlvm message; slow down the - * polling + * it's been longer than MIN_IDLE_SECONDS since we processed + * our last controlvm message; slow down the polling */ if (chipset_dev->poll_jiffies != POLLJIFFIES_CONTROLVMCHANNEL_SLOW) @@ -1812,41 +1712,36 @@ schedule_out: chipset_dev->poll_jiffies); } -static int -visorchipset_init(struct acpi_device *acpi_device) +static int visorchipset_init(struct acpi_device *acpi_device) { int err = -ENODEV; - u64 addr; - uuid_le uuid = VISOR_CONTROLVM_CHANNEL_UUID; struct visorchannel *controlvm_channel; chipset_dev = kzalloc(sizeof(*chipset_dev), GFP_KERNEL); if (!chipset_dev) goto error; - addr = controlvm_get_channel_address(); - if (!addr) - goto error; + err = controlvm_channel_create(chipset_dev); + if (err) + goto error_free_chipset_dev; acpi_device->driver_data = chipset_dev; - chipset_dev->acpi_device = acpi_device; chipset_dev->poll_jiffies = POLLJIFFIES_CONTROLVMCHANNEL_FAST; - controlvm_channel = visorchannel_create_with_lock(addr, - 0, GFP_KERNEL, uuid); - - if (!controlvm_channel) - goto error_free_chipset_dev; - - chipset_dev->controlvm_channel = controlvm_channel; err = sysfs_create_groups(&chipset_dev->acpi_device->dev.kobj, visorchipset_dev_groups); if (err < 0) goto error_destroy_channel; - if (!VISOR_CONTROLVM_CHANNEL_OK_CLIENT( - visorchannel_get_header(controlvm_channel))) + controlvm_channel = chipset_dev->controlvm_channel; + if (!visor_check_channel(visorchannel_get_header(controlvm_channel), + &chipset_dev->acpi_device->dev, + &visor_controlvm_channel_guid, + "controlvm", + sizeof(struct visor_controlvm_channel), + VISOR_CONTROLVM_CHANNEL_VERSIONID, + VISOR_CHANNEL_SIGNATURE)) goto error_delete_groups; /* if booting in a crash kernel */ @@ -1886,8 +1781,7 @@ error: return err; } -static int -visorchipset_exit(struct acpi_device *acpi_device) +static int visorchipset_exit(struct acpi_device *acpi_device) { visorbus_exit(); cancel_delayed_work_sync(&chipset_dev->periodic_controlvm_work); @@ -1928,9 +1822,8 @@ static __init int visorutil_spar_detect(void) return (ebx == UNISYS_VISOR_ID_EBX) && (ecx == UNISYS_VISOR_ID_ECX) && (edx == UNISYS_VISOR_ID_EDX); - } else { - return 0; } + return 0; } static int init_unisys(void) diff --git a/drivers/staging/unisys/visorbus/vmcallinterface.h b/drivers/staging/unisys/visorbus/vmcallinterface.h deleted file mode 100644 index cc70e1b16bda..000000000000 --- a/drivers/staging/unisys/visorbus/vmcallinterface.h +++ /dev/null @@ -1,54 +0,0 @@ -/* Copyright (C) 2010 - 2015 UNISYS CORPORATION - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - */ - -#ifndef __VMCALLINTERFACE_H__ -#define __VMCALLINTERFACE_H__ - -enum vmcall_monitor_interface_method_tuple { /* VMCALL identification tuples */ - /* Note: when a new VMCALL is added: - * - the 1st 2 hex digits correspond to one of the - * VMCALL_MONITOR_INTERFACE types and - * - the next 2 hex digits are the nth relative instance of within a - * type - * E.G. for VMCALL_VIRTPART_RECYCLE_PART, - * - the 0x02 identifies it as a VMCALL_VIRTPART type and - * - the 0x01 identifies it as the 1st instance of a VMCALL_VIRTPART - * type of VMCALL - */ - /* used by all Guests, not just IO */ - VMCALL_CONTROLVM_ADDR = 0x0501, -}; - -enum vmcall_result { - VMCALL_RESULT_SUCCESS = 0, - VMCALL_RESULT_INVALID_PARAM = 1, - VMCALL_RESULT_DATA_UNAVAILABLE = 2, - VMCALL_RESULT_FAILURE_UNAVAILABLE = 3, - VMCALL_RESULT_DEVICE_ERROR = 4, - VMCALL_RESULT_DEVICE_NOT_READY = 5 -}; - -/* Structures for IO VMCALLs */ -/* Parameters to VMCALL_CONTROLVM_ADDR interface */ -struct vmcall_io_controlvm_addr_params { - /* The Guest-relative physical address of the ControlVm channel. */ - /* This VMCall fills this in with the appropriate address. */ - u64 address; /* contents provided by this VMCALL (OUT) */ - /* the size of the ControlVm channel in bytes This VMCall fills this */ - /* in with the appropriate address. */ - u32 channel_bytes; /* contents provided by this VMCALL (OUT) */ - u8 unused[4]; /* Unused Bytes in the 64-Bit Aligned Struct */ -} __packed; - -#endif /* __VMCALLINTERFACE_H__ */ diff --git a/drivers/staging/unisys/visorhba/visorhba_main.c b/drivers/staging/unisys/visorhba/visorhba_main.c index a6e7a6bbc428..419dba89af06 100644 --- a/drivers/staging/unisys/visorhba/visorhba_main.c +++ b/drivers/staging/unisys/visorhba/visorhba_main.c @@ -1,4 +1,5 @@ -/* Copyright (c) 2012 - 2015 UNISYS CORPORATION +/* + * Copyright (c) 2012 - 2015 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify @@ -14,7 +15,6 @@ */ #include <linux/debugfs.h> -#include <linux/skbuff.h> #include <linux/kthread.h> #include <linux/idr.h> #include <linux/seq_file.h> @@ -39,16 +39,16 @@ static struct visor_channeltype_descriptor visorhba_channel_types[] = { /* Note that the only channel type we expect to be reported by the * bus driver is the VISOR_VHBA channel. */ - { VISOR_VHBA_CHANNEL_UUID, "sparvhba" }, - { NULL_UUID_LE, NULL } + { VISOR_VHBA_CHANNEL_GUID, "sparvhba" }, + {} }; MODULE_DEVICE_TABLE(visorbus, visorhba_channel_types); -MODULE_ALIAS("visorbus:" VISOR_VHBA_CHANNEL_UUID_STR); +MODULE_ALIAS("visorbus:" VISOR_VHBA_CHANNEL_GUID_STR); struct visordisk_info { + struct scsi_device *sdev; u32 valid; - u32 channel, id, lun; /* Disk Path */ atomic_t ios_threshold; atomic_t error_count; struct visordisk_info *next; @@ -56,8 +56,10 @@ struct visordisk_info { struct scsipending { struct uiscmdrsp cmdrsp; - void *sent; /* The Data being tracked */ - char cmdtype; /* Type of pointer that is being stored */ + /* The Data being tracked */ + void *sent; + /* Type of pointer that is being stored */ + char cmdtype; }; /* Each scsi_host has a host_data area that contains this struct. */ @@ -71,7 +73,8 @@ struct visorhba_devdata { struct scsipending pending[MAX_PENDING_REQUESTS]; /* Start search for next pending free slot here */ unsigned int nextinsert; - spinlock_t privlock; /* lock to protect data in devdata */ + /* lock to protect data in devdata */ + spinlock_t privlock; bool serverdown; bool serverchangingstate; unsigned long long acquire_failed_cnt; @@ -101,25 +104,19 @@ struct visorhba_devices_open { struct visorhba_devdata *devdata; }; -#define for_each_vdisk_match(iter, list, match) \ - for (iter = &list->head; iter->next; iter = iter->next) \ - if ((iter->channel == match->channel) && \ - (iter->id == match->id) && \ - (iter->lun == match->lun)) - /* - * visor_thread_start - starts a thread for the device - * @threadfn: Function the thread starts - * @thrcontext: Context to pass to the thread, i.e. devdata - * @name: string describing name of thread + * visor_thread_start - Starts a thread for the device + * @threadfn: Function the thread starts + * @thrcontext: Context to pass to the thread, i.e. devdata + * @name: String describing name of thread * - * Starts a thread for the device. + * Starts a thread for the device. * - * Return the task_struct * denoting the thread on success, - * or NULL on failure + * Return: The task_struct * denoting the thread on success, + * or NULL on failure */ -static struct task_struct *visor_thread_start -(int (*threadfn)(void *), void *thrcontext, char *name) +static struct task_struct *visor_thread_start(int (*threadfn)(void *), + void *thrcontext, char *name) { struct task_struct *task; @@ -132,27 +129,27 @@ static struct task_struct *visor_thread_start } /* - * visor_thread_stop - stops the thread if it is running + * visor_thread_stop - Stops the thread if it is running + * @task: Description of process to stop */ static void visor_thread_stop(struct task_struct *task) { - if (!task) - return; /* no thread running */ kthread_stop(task); } /* - * add_scsipending_entry - save off io command that is pending in - * Service Partition - * @devdata: Pointer to devdata - * @cmdtype: Specifies the type of command pending - * @new: The command to be saved + * add_scsipending_entry - Save off io command that is pending in + * Service Partition + * @devdata: Pointer to devdata + * @cmdtype: Specifies the type of command pending + * @new: The command to be saved * - * Saves off the io command that is being handled by the Service - * Partition so that it can be handled when it completes. If new is - * NULL it is assumed the entry refers only to the cmdrsp. - * Returns insert_location where entry was added, - * -EBUSY if it can't + * Saves off the io command that is being handled by the Service + * Partition so that it can be handled when it completes. If new is + * NULL it is assumed the entry refers only to the cmdrsp. + * + * Return: Insert_location where entry was added on success, + * -EBUSY if it can't */ static int add_scsipending_entry(struct visorhba_devdata *devdata, char cmdtype, void *new) @@ -176,7 +173,8 @@ static int add_scsipending_entry(struct visorhba_devdata *devdata, entry->cmdtype = cmdtype; if (new) entry->sent = new; - else /* wants to send cmdrsp */ + /* wants to send cmdrsp */ + else entry->sent = &entry->cmdrsp; devdata->nextinsert = (insert_location + 1) % MAX_PENDING_REQUESTS; spin_unlock_irqrestore(&devdata->privlock, flags); @@ -185,15 +183,15 @@ static int add_scsipending_entry(struct visorhba_devdata *devdata, } /* - * del_scsipending_ent - removes an entry from the pending array - * @devdata: Device holding the pending array - * @del: Entry to remove + * del_scsipending_ent - Removes an entry from the pending array + * @devdata: Device holding the pending array + * @del: Entry to remove * - * Removes the entry pointed at by del and returns it. - * Returns the scsipending entry pointed at + * Removes the entry pointed at by del and returns it. + * + * Return: The scsipending entry pointed to on success, NULL on failure */ -static void *del_scsipending_ent(struct visorhba_devdata *devdata, - int del) +static void *del_scsipending_ent(struct visorhba_devdata *devdata, int del) { unsigned long flags; void *sent; @@ -203,7 +201,6 @@ static void *del_scsipending_ent(struct visorhba_devdata *devdata, spin_lock_irqsave(&devdata->privlock, flags); sent = devdata->pending[del].sent; - devdata->pending[del].cmdtype = 0; devdata->pending[del].sent = NULL; spin_unlock_irqrestore(&devdata->privlock, flags); @@ -212,13 +209,14 @@ static void *del_scsipending_ent(struct visorhba_devdata *devdata, } /* - * get_scsipending_cmdrsp - return the cmdrsp stored in a pending entry - * @ddata: Device holding the pending array - * @ent: Entry that stores the cmdrsp + * get_scsipending_cmdrsp - Return the cmdrsp stored in a pending entry + * @ddata: Device holding the pending array + * @ent: Entry that stores the cmdrsp * - * Each scsipending entry has a cmdrsp in it. The cmdrsp is only valid - * if the "sent" field is not NULL - * Returns a pointer to the cmdrsp. + * Each scsipending entry has a cmdrsp in it. The cmdrsp is only valid + * if the "sent" field is not NULL. + * + * Return: A pointer to the cmdrsp, NULL on failure */ static struct uiscmdrsp *get_scsipending_cmdrsp(struct visorhba_devdata *ddata, int ent) @@ -230,13 +228,15 @@ static struct uiscmdrsp *get_scsipending_cmdrsp(struct visorhba_devdata *ddata, } /* - * simple_idr_get - associate a provided pointer with an int value - * 1 <= value <= INT_MAX, and return this int value; - * the pointer value can be obtained later by passing - * this int value to idr_find() - * @idrtable: the data object maintaining the pointer<-->int mappings - * @p: the pointer value to be remembered - * @lock: a spinlock used when exclusive access to idrtable is needed + * simple_idr_get - Associate a provided pointer with an int value + * 1 <= value <= INT_MAX, and return this int value; + * the pointer value can be obtained later by passing + * this int value to idr_find() + * @idrtable: The data object maintaining the pointer<-->int mappings + * @p: The pointer value to be remembered + * @lock: A spinlock used when exclusive access to idrtable is needed + * + * Return: The id number mapped to pointer 'p', 0 on failure */ static unsigned int simple_idr_get(struct idr *idrtable, void *p, spinlock_t *lock) @@ -249,16 +249,23 @@ static unsigned int simple_idr_get(struct idr *idrtable, void *p, id = idr_alloc(idrtable, p, 1, INT_MAX, GFP_NOWAIT); spin_unlock_irqrestore(lock, flags); idr_preload_end(); + /* failure */ if (id < 0) - return 0; /* failure */ - return (unsigned int)(id); /* idr_alloc() guarantees > 0 */ + return 0; + /* idr_alloc() guarantees > 0 */ + return (unsigned int)(id); } /* - * setup_scsitaskmgmt_handles - stash the necessary handles so that the - * completion processing logic for a taskmgmt - * cmd will be able to find who to wake up - * and where to stash the result + * setup_scsitaskmgmt_handles - Stash the necessary handles so that the + * completion processing logic for a taskmgmt + * cmd will be able to find who to wake up + * and where to stash the result + * @idrtable: The data object maintaining the pointer<-->int mappings + * @lock: A spinlock used when exclusive access to idrtable is needed + * @cmdrsp: Response from the IOVM + * @event: The event handle to associate with an id + * @result: The location to place the result of the event handle into */ static void setup_scsitaskmgmt_handles(struct idr *idrtable, spinlock_t *lock, struct uiscmdrsp *cmdrsp, @@ -273,8 +280,10 @@ static void setup_scsitaskmgmt_handles(struct idr *idrtable, spinlock_t *lock, } /* - * cleanup_scsitaskmgmt_handles - forget handles created by - * setup_scsitaskmgmt_handles() + * cleanup_scsitaskmgmt_handles - Forget handles created by + * setup_scsitaskmgmt_handles() + * @idrtable: The data object maintaining the pointer<-->int mappings + * @cmdrsp: Response from the IOVM */ static void cleanup_scsitaskmgmt_handles(struct idr *idrtable, struct uiscmdrsp *cmdrsp) @@ -286,20 +295,20 @@ static void cleanup_scsitaskmgmt_handles(struct idr *idrtable, } /* - * forward_taskmgmt_command - send taskmegmt command to the Service - * Partition - * @tasktype: Type of taskmgmt command - * @scsidev: Scsidev that issued command + * forward_taskmgmt_command - Send taskmegmt command to the Service + * Partition + * @tasktype: Type of taskmgmt command + * @scsidev: Scsidev that issued command * - * Create a cmdrsp packet and send it to the Serivce Partition - * that will service this request. - * Returns whether the command was queued successfully or not. + * Create a cmdrsp packet and send it to the Serivce Partition + * that will service this request. + * + * Return: Int representing whether command was queued successfully or not */ static int forward_taskmgmt_command(enum task_mgmt_types tasktype, - struct scsi_cmnd *scsicmd) + struct scsi_device *scsidev) { struct uiscmdrsp *cmdrsp; - struct scsi_device *scsidev = scsicmd->device; struct visorhba_devdata *devdata = (struct visorhba_devdata *)scsidev->host->hostdata; int notifyresult = 0xffff; @@ -347,12 +356,6 @@ static int forward_taskmgmt_command(enum task_mgmt_types tasktype, dev_dbg(&scsidev->sdev_gendev, "visorhba: taskmgmt type=%d success; result=0x%x\n", tasktype, notifyresult); - if (tasktype == TASK_MGMT_ABORT_TASK) - scsicmd->result = DID_ABORT << 16; - else - scsicmd->result = DID_RESET << 16; - - scsicmd->scsi_done(scsicmd); cleanup_scsitaskmgmt_handles(&devdata->idr, cmdrsp); return SUCCESS; @@ -365,97 +368,105 @@ err_del_scsipending_ent: } /* - * visorhba_abort_handler - Send TASK_MGMT_ABORT_TASK - * @scsicmd: The scsicmd that needs aborted - * - * Returns SUCCESS if inserted, failure otherwise + * visorhba_abort_handler - Send TASK_MGMT_ABORT_TASK + * @scsicmd: The scsicmd that needs aborted * + * Return: SUCCESS if inserted, FAILED otherwise */ static int visorhba_abort_handler(struct scsi_cmnd *scsicmd) { /* issue TASK_MGMT_ABORT_TASK */ struct scsi_device *scsidev; struct visordisk_info *vdisk; - struct visorhba_devdata *devdata; + int rtn; scsidev = scsicmd->device; - devdata = (struct visorhba_devdata *)scsidev->host->hostdata; - for_each_vdisk_match(vdisk, devdata, scsidev) { - if (atomic_read(&vdisk->error_count) < VISORHBA_ERROR_COUNT) - atomic_inc(&vdisk->error_count); - else - atomic_set(&vdisk->ios_threshold, IOS_ERROR_THRESHOLD); + vdisk = scsidev->hostdata; + if (atomic_read(&vdisk->error_count) < VISORHBA_ERROR_COUNT) + atomic_inc(&vdisk->error_count); + else + atomic_set(&vdisk->ios_threshold, IOS_ERROR_THRESHOLD); + rtn = forward_taskmgmt_command(TASK_MGMT_ABORT_TASK, scsidev); + if (rtn == SUCCESS) { + scsicmd->result = DID_ABORT << 16; + scsicmd->scsi_done(scsicmd); } - return forward_taskmgmt_command(TASK_MGMT_ABORT_TASK, scsicmd); + return rtn; } /* - * visorhba_device_reset_handler - Send TASK_MGMT_LUN_RESET - * @scsicmd: The scsicmd that needs aborted + * visorhba_device_reset_handler - Send TASK_MGMT_LUN_RESET + * @scsicmd: The scsicmd that needs aborted * - * Returns SUCCESS if inserted, failure otherwise + * Return: SUCCESS if inserted, FAILED otherwise */ static int visorhba_device_reset_handler(struct scsi_cmnd *scsicmd) { /* issue TASK_MGMT_LUN_RESET */ struct scsi_device *scsidev; struct visordisk_info *vdisk; - struct visorhba_devdata *devdata; + int rtn; scsidev = scsicmd->device; - devdata = (struct visorhba_devdata *)scsidev->host->hostdata; - for_each_vdisk_match(vdisk, devdata, scsidev) { - if (atomic_read(&vdisk->error_count) < VISORHBA_ERROR_COUNT) - atomic_inc(&vdisk->error_count); - else - atomic_set(&vdisk->ios_threshold, IOS_ERROR_THRESHOLD); + vdisk = scsidev->hostdata; + if (atomic_read(&vdisk->error_count) < VISORHBA_ERROR_COUNT) + atomic_inc(&vdisk->error_count); + else + atomic_set(&vdisk->ios_threshold, IOS_ERROR_THRESHOLD); + rtn = forward_taskmgmt_command(TASK_MGMT_LUN_RESET, scsidev); + if (rtn == SUCCESS) { + scsicmd->result = DID_RESET << 16; + scsicmd->scsi_done(scsicmd); } - return forward_taskmgmt_command(TASK_MGMT_LUN_RESET, scsicmd); + return rtn; } /* - * visorhba_bus_reset_handler - Send TASK_MGMT_TARGET_RESET for each - * target on the bus - * @scsicmd: The scsicmd that needs aborted + * visorhba_bus_reset_handler - Send TASK_MGMT_TARGET_RESET for each + * target on the bus + * @scsicmd: The scsicmd that needs aborted * - * Returns SUCCESS + * Return: SUCCESS if inserted, FAILED otherwise */ static int visorhba_bus_reset_handler(struct scsi_cmnd *scsicmd) { struct scsi_device *scsidev; struct visordisk_info *vdisk; - struct visorhba_devdata *devdata; + int rtn; scsidev = scsicmd->device; - devdata = (struct visorhba_devdata *)scsidev->host->hostdata; - for_each_vdisk_match(vdisk, devdata, scsidev) { + shost_for_each_device(scsidev, scsidev->host) { + vdisk = scsidev->hostdata; if (atomic_read(&vdisk->error_count) < VISORHBA_ERROR_COUNT) atomic_inc(&vdisk->error_count); else atomic_set(&vdisk->ios_threshold, IOS_ERROR_THRESHOLD); } - return forward_taskmgmt_command(TASK_MGMT_BUS_RESET, scsicmd); + rtn = forward_taskmgmt_command(TASK_MGMT_BUS_RESET, scsidev); + if (rtn == SUCCESS) { + scsicmd->result = DID_RESET << 16; + scsicmd->scsi_done(scsicmd); + } + return rtn; } /* - * visorhba_host_reset_handler - Not supported - * @scsicmd: The scsicmd that needs aborted + * visorhba_host_reset_handler - Not supported + * @scsicmd: The scsicmd that needs to be aborted * - * Not supported, return SUCCESS - * Returns SUCCESS + * Return: Not supported, return SUCCESS */ -static int -visorhba_host_reset_handler(struct scsi_cmnd *scsicmd) +static int visorhba_host_reset_handler(struct scsi_cmnd *scsicmd) { /* issue TASK_MGMT_TARGET_RESET for each target on each bus for host */ return SUCCESS; } /* - * visorhba_get_info - * @shp: Scsi host that is requesting information + * visorhba_get_info - Get information about SCSI device + * @shp: Scsi host that is requesting information * - * Returns string with info + * Return: String with visorhba information */ static const char *visorhba_get_info(struct Scsi_Host *shp) { @@ -464,19 +475,42 @@ static const char *visorhba_get_info(struct Scsi_Host *shp) } /* - * visorhba_queue_command_lck -- queues command to the Service Partition - * @scsicmd: Command to be queued - * @vsiorhba_cmnd_done: Done command to call when scsicmd is returned + * dma_data_dir_linux_to_spar - convert dma_data_direction value to + * Unisys-specific equivalent + * @d: dma direction value to convert * - * Queues to scsicmd to the ServicePartition after converting it to a - * uiscmdrsp structure. + * Returns the Unisys-specific dma direction value corresponding to @d + */ +static u32 dma_data_dir_linux_to_spar(enum dma_data_direction d) +{ + switch (d) { + case DMA_BIDIRECTIONAL: + return UIS_DMA_BIDIRECTIONAL; + case DMA_TO_DEVICE: + return UIS_DMA_TO_DEVICE; + case DMA_FROM_DEVICE: + return UIS_DMA_FROM_DEVICE; + case DMA_NONE: + return UIS_DMA_NONE; + default: + return UIS_DMA_NONE; + } +} + +/* + * visorhba_queue_command_lck - Queues command to the Service Partition + * @scsicmd: Command to be queued + * @vsiorhba_cmnd_done: Done command to call when scsicmd is returned * - * Returns success if queued to the Service Partition, otherwise - * failure. + * Queues to scsicmd to the ServicePartition after converting it to a + * uiscmdrsp structure. + * + * Return: 0 if successfully queued to the Service Partition, otherwise + * error code */ -static int -visorhba_queue_command_lck(struct scsi_cmnd *scsicmd, - void (*visorhba_cmnd_done)(struct scsi_cmnd *)) +static int visorhba_queue_command_lck(struct scsi_cmnd *scsicmd, + void (*visorhba_cmnd_done) + (struct scsi_cmnd *)) { struct uiscmdrsp *cmdrsp; struct scsi_device *scsidev = scsicmd->device; @@ -494,12 +528,10 @@ visorhba_queue_command_lck(struct scsi_cmnd *scsicmd, insert_location = add_scsipending_entry(devdata, CMD_SCSI_TYPE, (void *)scsicmd); - if (insert_location < 0) return SCSI_MLQUEUE_DEVICE_BUSY; cmdrsp = get_scsipending_cmdrsp(devdata, insert_location); - cmdrsp->cmdtype = CMD_SCSI_TYPE; /* save the pending insertion location. Deletion from pending * will return the scsicmd pointer for completion @@ -513,9 +545,9 @@ visorhba_queue_command_lck(struct scsi_cmnd *scsicmd, cmdrsp->scsi.vdest.id = scsidev->id; cmdrsp->scsi.vdest.lun = scsidev->lun; /* save datadir */ - cmdrsp->scsi.data_dir = scsicmd->sc_data_direction; + cmdrsp->scsi.data_dir = + dma_data_dir_linux_to_spar(scsicmd->sc_data_direction); memcpy(cmdrsp->scsi.cmnd, cdb, MAX_CMND_SIZE); - cmdrsp->scsi.bufflen = scsi_bufflen(scsicmd); /* keep track of the max buffer length so far. */ @@ -555,13 +587,13 @@ static DEF_SCSI_QCMD(visorhba_queue_command) #endif /* - * visorhba_slave_alloc - called when new disk is discovered - * @scsidev: New disk + * visorhba_slave_alloc - Called when new disk is discovered + * @scsidev: New disk * - * Create a new visordisk_info structure and add it to our - * list of vdisks. + * Create a new visordisk_info structure and add it to our + * list of vdisks. * - * Returns success when created, otherwise error. + * Return: 0 on success, -ENOMEM on failure. */ static int visorhba_slave_alloc(struct scsi_device *scsidev) { @@ -569,51 +601,41 @@ static int visorhba_slave_alloc(struct scsi_device *scsidev) * LLD can alloc any struct & do init if needed. */ struct visordisk_info *vdisk; - struct visordisk_info *tmpvdisk; struct visorhba_devdata *devdata; struct Scsi_Host *scsihost = (struct Scsi_Host *)scsidev->host; + /* already allocated return success */ + if (scsidev->hostdata) + return 0; + + /* even though we errored, treat as success */ devdata = (struct visorhba_devdata *)scsihost->hostdata; if (!devdata) - return 0; /* even though we errored, treat as success */ - - for_each_vdisk_match(vdisk, devdata, scsidev) - return 0; /* already allocated return success */ + return 0; - tmpvdisk = kzalloc(sizeof(*tmpvdisk), GFP_ATOMIC); - if (!tmpvdisk) + vdisk = kzalloc(sizeof(*vdisk), GFP_ATOMIC); + if (!vdisk) return -ENOMEM; - tmpvdisk->channel = scsidev->channel; - tmpvdisk->id = scsidev->id; - tmpvdisk->lun = scsidev->lun; - vdisk->next = tmpvdisk; + vdisk->sdev = scsidev; + scsidev->hostdata = vdisk; return 0; } /* - * visorhba_slave_destroy - disk is going away - * @scsidev: scsi device going away - * - * Disk is going away, clean up resources. - * Returns void. + * visorhba_slave_destroy - Disk is going away, clean up resources. + * @scsidev: Scsi device to destroy */ static void visorhba_slave_destroy(struct scsi_device *scsidev) { /* midlevel calls this after device has been quiesced and * before it is to be deleted. */ - struct visordisk_info *vdisk, *delvdisk; - struct visorhba_devdata *devdata; - struct Scsi_Host *scsihost = (struct Scsi_Host *)scsidev->host; + struct visordisk_info *vdisk; - devdata = (struct visorhba_devdata *)scsihost->hostdata; - for_each_vdisk_match(vdisk, devdata, scsidev) { - delvdisk = vdisk->next; - vdisk->next = delvdisk->next; - kfree(delvdisk); - return; - } + vdisk = scsidev->hostdata; + scsidev->hostdata = NULL; + kfree(vdisk); } static struct scsi_host_template visorhba_driver_template = { @@ -635,10 +657,13 @@ static struct scsi_host_template visorhba_driver_template = { }; /* - * info_debugfs_show - debugfs interface to dump visorhba states + * info_debugfs_show - Debugfs interface to dump visorhba states + * @seq: The sequence file to write information to + * @v: Unused, but needed for use with seq file single_open invocation + * + * Presents a file in the debugfs tree named: /visorhba/vbus<x>:dev<y>/info. * - * This presents a file in the debugfs tree named: - * /visorhba/vbus<x>:dev<y>/info + * Return: SUCCESS */ static int info_debugfs_show(struct seq_file *seq, void *v) { @@ -679,12 +704,13 @@ static const struct file_operations info_debugfs_fops = { }; /* - * complete_taskmgmt_command - complete task management - * @cmdrsp: Response from the IOVM + * complete_taskmgmt_command - Complete task management + * @idrtable: The data object maintaining the pointer<-->int mappings + * @cmdrsp: Response from the IOVM + * @result: The result of the task management command * - * Service Partition returned the result of the task management - * command. Wake up anyone waiting for it. - * Returns void + * Service Partition returned the result of the task management + * command. Wake up anyone waiting for it. */ static void complete_taskmgmt_command(struct idr *idrtable, struct uiscmdrsp *cmdrsp, int result) @@ -693,7 +719,6 @@ static void complete_taskmgmt_command(struct idr *idrtable, idr_find(idrtable, cmdrsp->scsitaskmgmt.notify_handle); int *scsi_result_ptr = idr_find(idrtable, cmdrsp->scsitaskmgmt.notifyresult_handle); - if (unlikely(!(wq && scsi_result_ptr))) { pr_err("visorhba: no completion context; cmd will time out\n"); return; @@ -708,13 +733,12 @@ static void complete_taskmgmt_command(struct idr *idrtable, } /* - * visorhba_serverdown_complete - Called when we are done cleaning up - * from serverdown - * @work: work structure for this serverdown request + * visorhba_serverdown_complete - Called when we are done cleaning up + * from serverdown + * @devdata: Visorhba instance on which to complete serverdown * - * Called when we are done cleanning up from serverdown, stop processing - * queue, fail pending IOs. - * Returns void when finished cleaning up + * Called when we are done cleanning up from serverdown, stop processing + * queue, fail pending IOs. */ static void visorhba_serverdown_complete(struct visorhba_devdata *devdata) { @@ -758,12 +782,13 @@ static void visorhba_serverdown_complete(struct visorhba_devdata *devdata) } /* - * visorhba_serverdown - Got notified that the IOVM is down - * @devdata: visorhba that is being serviced by downed IOVM. + * visorhba_serverdown - Got notified that the IOVM is down + * @devdata: Visorhba that is being serviced by downed IOVM * - * Something happened to the IOVM, return immediately and - * schedule work cleanup work. - * Return SUCCESS or EINVAL + * Something happened to the IOVM, return immediately and + * schedule cleanup work. + * + * Return: 0 on success, -EINVAL on failure */ static int visorhba_serverdown(struct visorhba_devdata *devdata) { @@ -777,17 +802,15 @@ static int visorhba_serverdown(struct visorhba_devdata *devdata) } /* - * do_scsi_linuxstat - scsi command returned linuxstat - * @cmdrsp: response from IOVM - * @scsicmd: Command issued. + * do_scsi_linuxstat - Scsi command returned linuxstat + * @cmdrsp: Response from IOVM + * @scsicmd: Command issued * - * Don't log errors for disk-not-present inquiries - * Returns void + * Don't log errors for disk-not-present inquiries. */ -static void -do_scsi_linuxstat(struct uiscmdrsp *cmdrsp, struct scsi_cmnd *scsicmd) +static void do_scsi_linuxstat(struct uiscmdrsp *cmdrsp, + struct scsi_cmnd *scsicmd) { - struct visorhba_devdata *devdata; struct visordisk_info *vdisk; struct scsi_device *scsidev; @@ -800,19 +823,17 @@ do_scsi_linuxstat(struct uiscmdrsp *cmdrsp, struct scsi_cmnd *scsicmd) (cmdrsp->scsi.addlstat == ADDL_SEL_TIMEOUT)) return; /* Okay see what our error_count is here.... */ - devdata = (struct visorhba_devdata *)scsidev->host->hostdata; - for_each_vdisk_match(vdisk, devdata, scsidev) { - if (atomic_read(&vdisk->error_count) < VISORHBA_ERROR_COUNT) { - atomic_inc(&vdisk->error_count); - atomic_set(&vdisk->ios_threshold, IOS_ERROR_THRESHOLD); - } + vdisk = scsidev->hostdata; + if (atomic_read(&vdisk->error_count) < VISORHBA_ERROR_COUNT) { + atomic_inc(&vdisk->error_count); + atomic_set(&vdisk->ios_threshold, IOS_ERROR_THRESHOLD); } } -static int set_no_disk_inquiry_result(unsigned char *buf, - size_t len, bool is_lun0) +static int set_no_disk_inquiry_result(unsigned char *buf, size_t len, + bool is_lun0) { - if (!buf || len < NO_DISK_INQUIRY_RESULT_LEN) + if (len < NO_DISK_INQUIRY_RESULT_LEN) return -EINVAL; memset(buf, 0, NO_DISK_INQUIRY_RESULT_LEN); buf[2] = SCSI_SPC2_VER; @@ -828,15 +849,14 @@ static int set_no_disk_inquiry_result(unsigned char *buf, } /* - * do_scsi_nolinuxstat - scsi command didn't have linuxstat - * @cmdrsp: response from IOVM - * @scsicmd: Command issued. + * do_scsi_nolinuxstat - Scsi command didn't have linuxstat + * @cmdrsp: Response from IOVM + * @scsicmd: Command issued * - * Handle response when no linuxstat was returned - * Returns void + * Handle response when no linuxstat was returned. */ -static void -do_scsi_nolinuxstat(struct uiscmdrsp *cmdrsp, struct scsi_cmnd *scsicmd) +static void do_scsi_nolinuxstat(struct uiscmdrsp *cmdrsp, + struct scsi_cmnd *scsicmd) { struct scsi_device *scsidev; unsigned char *buf; @@ -846,7 +866,6 @@ do_scsi_nolinuxstat(struct uiscmdrsp *cmdrsp, struct scsi_cmnd *scsicmd) char *this_page_orig; int bufind = 0; struct visordisk_info *vdisk; - struct visorhba_devdata *devdata; scsidev = scsicmd->device; if ((cmdrsp->scsi.cmnd[0] == INQUIRY) && @@ -883,28 +902,25 @@ do_scsi_nolinuxstat(struct uiscmdrsp *cmdrsp, struct scsi_cmnd *scsicmd) } kfree(buf); } else { - devdata = (struct visorhba_devdata *)scsidev->host->hostdata; - for_each_vdisk_match(vdisk, devdata, scsidev) { - if (atomic_read(&vdisk->ios_threshold) > 0) { - atomic_dec(&vdisk->ios_threshold); - if (atomic_read(&vdisk->ios_threshold) == 0) - atomic_set(&vdisk->error_count, 0); - } + vdisk = scsidev->hostdata; + if (atomic_read(&vdisk->ios_threshold) > 0) { + atomic_dec(&vdisk->ios_threshold); + if (atomic_read(&vdisk->ios_threshold) == 0) + atomic_set(&vdisk->error_count, 0); } } } /* - * complete_scsi_command - complete a scsi command - * @uiscmdrsp: Response from Service Partition - * @scsicmd: The scsi command + * complete_scsi_command - Complete a scsi command + * @uiscmdrsp: Response from Service Partition + * @scsicmd: The scsi command * - * Response returned by the Service Partition, finish it and send - * completion to the scsi midlayer. - * Returns void. + * Response was returned by the Service Partition. Finish it and send + * completion to the scsi midlayer. */ -static void -complete_scsi_command(struct uiscmdrsp *cmdrsp, struct scsi_cmnd *scsicmd) +static void complete_scsi_command(struct uiscmdrsp *cmdrsp, + struct scsi_cmnd *scsicmd) { /* take what we need out of cmdrsp and complete the scsicmd */ scsicmd->result = cmdrsp->scsi.linuxstat; @@ -917,24 +933,23 @@ complete_scsi_command(struct uiscmdrsp *cmdrsp, struct scsi_cmnd *scsicmd) } /* - * drain_queue - pull responses out of iochannel - * @cmdrsp: Response from the IOSP - * @devdata: device that owns this iochannel + * drain_queue - Pull responses out of iochannel + * @cmdrsp: Response from the IOSP + * @devdata: Device that owns this iochannel * - * Pulls responses out of the iochannel and process the responses. - * Restuns void + * Pulls responses out of the iochannel and process the responses. */ -static void -drain_queue(struct uiscmdrsp *cmdrsp, struct visorhba_devdata *devdata) +static void drain_queue(struct uiscmdrsp *cmdrsp, + struct visorhba_devdata *devdata) { struct scsi_cmnd *scsicmd; while (1) { + /* queue empty */ if (visorchannel_signalremove(devdata->dev->visorchannel, IOCHAN_FROM_IOPART, cmdrsp)) - break; /* queue empty */ - + break; if (cmdrsp->cmdtype == CMD_SCSI_TYPE) { /* scsicmd location is returned by the * deletion @@ -959,12 +974,14 @@ drain_queue(struct uiscmdrsp *cmdrsp, struct visorhba_devdata *devdata) } /* - * process_incoming_rsps - Process responses from IOSP - * @v: void pointer to visorhba_devdata + * process_incoming_rsps - Process responses from IOSP + * @v: Void pointer to visorhba_devdata * - * Main function for the thread that processes the responses - * from the IO Service Partition. When the queue is empty, wait - * to check to see if it is full again. + * Main function for the thread that processes the responses + * from the IO Service Partition. When the queue is empty, wait + * to check to see if it is full again. + * + * Return: 0 on success, -ENOMEM on failure */ static int process_incoming_rsps(void *v) { @@ -991,14 +1008,15 @@ static int process_incoming_rsps(void *v) } /* - * visorhba_pause - function to handle visorbus pause messages - * @dev: device that is pausing. - * @complete_func: function to call when finished + * visorhba_pause - Function to handle visorbus pause messages + * @dev: Device that is pausing + * @complete_func: Function to call when finished + * + * Something has happened to the IO Service Partition that is + * handling this device. Quiet this device and reset commands + * so that the Service Partition can be corrected. * - * Something has happened to the IO Service Partition that is - * handling this device. Quiet this device and reset commands - * so that the Service Partition can be corrected. - * Returns SUCCESS + * Return: SUCCESS */ static int visorhba_pause(struct visor_device *dev, visorbus_state_complete_func complete_func) @@ -1011,13 +1029,14 @@ static int visorhba_pause(struct visor_device *dev, } /* - * visorhba_resume - function called when the IO Service Partition is back - * @dev: device that is pausing. - * @complete_func: function to call when finished + * visorhba_resume - Function called when the IO Service Partition is back + * @dev: Device that is pausing + * @complete_func: Function to call when finished * - * Yay! The IO Service Partition is back, the channel has been wiped - * so lets re-establish connection and start processing responses. - * Returns 0 on success, error on failure. + * Yay! The IO Service Partition is back, the channel has been wiped + * so lets re-establish connection and start processing responses. + * + * Return: 0 on success, -EINVAL on failure */ static int visorhba_resume(struct visor_device *dev, visorbus_state_complete_func complete_func) @@ -1033,7 +1052,6 @@ static int visorhba_resume(struct visor_device *dev, devdata->thread = visor_thread_start(process_incoming_rsps, devdata, "vhba_incming"); - devdata->serverdown = false; devdata->serverchangingstate = false; @@ -1041,11 +1059,12 @@ static int visorhba_resume(struct visor_device *dev, } /* - * visorhba_probe - device has been discovered, do acquire - * @dev: visor_device that was discovered + * visorhba_probe - Device has been discovered; do acquire + * @dev: visor_device that was discovered * - * A new HBA was discovered, do the initial connections of it. - * Return 0 on success, otherwise error. + * A new HBA was discovered; do the initial connections of it. + * + * Return: 0 on success, otherwise error code */ static int visorhba_probe(struct visor_device *dev) { @@ -1139,11 +1158,10 @@ err_scsi_host_put: } /* - * visorhba_remove - remove a visorhba device - * @dev: Device to remove + * visorhba_remove - Remove a visorhba device + * @dev: Device to remove * - * Removes the visorhba device. - * Returns void. + * Removes the visorhba device. */ static void visorhba_remove(struct visor_device *dev) { @@ -1181,10 +1199,12 @@ static struct visor_driver visorhba_driver = { }; /* - * visorhba_init - driver init routine + * visorhba_init - Driver init routine + * + * Initialize the visorhba driver and register it with visorbus + * to handle s-Par virtual host bus adapter. * - * Initialize the visorhba driver and register it with visorbus - * to handle s-Par virtual host bus adapter. + * Return: 0 on success, error code otherwise */ static int visorhba_init(void) { @@ -1207,9 +1227,9 @@ cleanup_debugfs: } /* - * visorhba_exit - driver exit routine + * visorhba_exit - Driver exit routine * - * Unregister driver from the bus and free up memory. + * Unregister driver from the bus and free up memory. */ static void visorhba_exit(void) { diff --git a/drivers/staging/unisys/visorinput/ultrainputreport.h b/drivers/staging/unisys/visorinput/ultrainputreport.h index a4baea53c518..53975a09535f 100644 --- a/drivers/staging/unisys/visorinput/ultrainputreport.h +++ b/drivers/staging/unisys/visorinput/ultrainputreport.h @@ -1,4 +1,5 @@ -/* Copyright (C) 2010 - 2015 UNISYS CORPORATION +/* + * Copyright (C) 2010 - 2015 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify it @@ -20,44 +21,35 @@ /* These defines identify mouse and keyboard activity which is specified by the * firmware to the host using the cmsimpleinput protocol. @ingroup coretypes */ -#define INPUTACTION_XY_MOTION 1 /* only motion; arg1=x, arg2=y */ -#define INPUTACTION_MOUSE_BUTTON_DOWN 2 /* arg1: 1=left,2=center,3=right */ -#define INPUTACTION_MOUSE_BUTTON_UP 3 /* arg1: 1=left,2=center,3=right */ -#define INPUTACTION_MOUSE_BUTTON_CLICK 4 /* arg1: 1=left,2=center,3=right */ -#define INPUTACTION_MOUSE_BUTTON_DCLICK 5 /* arg1: 1=left,2=center, - * 3=right - */ -#define INPUTACTION_WHEEL_ROTATE_AWAY 6 /* arg1: wheel rotation away from - * user - */ -#define INPUTACTION_WHEEL_ROTATE_TOWARD 7 /* arg1: wheel rotation toward - * user - */ -#define INPUTACTION_KEY_DOWN 64 /* arg1: scancode, as follows: - * If arg1 <= 0xff, it's a 1-byte - * scancode and arg1 is that scancode. - * If arg1 > 0xff, it's a 2-byte - * scanecode, with the 1st byte in the - * low 8 bits, and the 2nd byte in the - * high 8 bits. E.g., the right ALT key - * would appear as x'38e0'. - */ -#define INPUTACTION_KEY_UP 65 /* arg1: scancode (in same format as - * inputaction_keyDown) - */ + /* only motion; arg1=x, arg2=y */ +#define INPUTACTION_XY_MOTION 1 +/* arg1: 1=left,2=center,3=right */ +#define INPUTACTION_MOUSE_BUTTON_DOWN 2 +/* arg1: 1=left,2=center,3=right */ +#define INPUTACTION_MOUSE_BUTTON_UP 3 +/* arg1: 1=left,2=center,3=right */ +#define INPUTACTION_MOUSE_BUTTON_CLICK 4 +/* arg1: 1=left,2=center 3=right */ +#define INPUTACTION_MOUSE_BUTTON_DCLICK 5 +/* arg1: wheel rotation away from user */ +#define INPUTACTION_WHEEL_ROTATE_AWAY 6 +/* arg1: wheel rotation toward user */ +#define INPUTACTION_WHEEL_ROTATE_TOWARD 7 +/* arg1: scancode, as follows: If arg1 <= 0xff, it's a 1-byte scancode and arg1 + * is that scancode. If arg1 > 0xff, it's a 2-byte scanecode, with the 1st + * byte in the low 8 bits, and the 2nd byte in the high 8 bits. + * E.g., the right ALT key would appear as x'38e0'. + */ +#define INPUTACTION_KEY_DOWN 64 +/* arg1: scancode (in same format as inputaction_keyDown) */ +#define INPUTACTION_KEY_UP 65 +/* arg1: scancode (in same format as inputaction_keyDown); MUST refer to one of + * the locking keys, like capslock, numlock, or scrolllock. + * arg2: 1 iff locking key should be in the LOCKED position (e.g., light is ON) + */ #define INPUTACTION_SET_LOCKING_KEY_STATE 66 - /* arg1: scancode (in same format - * as inputaction_keyDown); - * MUST refer to one of the - * locking keys, like capslock, - * numlock, or scrolllock - * arg2: 1 iff locking key should be - * in the LOCKED position - * (e.g., light is ON) - */ -#define INPUTACTION_KEY_DOWN_UP 67 /* arg1: scancode (in same format - * as inputaction_keyDown) - */ +/* arg1: scancode (in same format as inputaction_keyDown */ +#define INPUTACTION_KEY_DOWN_UP 67 struct visor_inputactivity { u16 action; diff --git a/drivers/staging/unisys/visorinput/visorinput.c b/drivers/staging/unisys/visorinput/visorinput.c index 45bc340d4e9d..9d8cbc52de8b 100644 --- a/drivers/staging/unisys/visorinput/visorinput.c +++ b/drivers/staging/unisys/visorinput/visorinput.c @@ -1,5 +1,4 @@ -/* visorinput.c - * +/* * Copyright (C) 2011 - 2015 UNISYS CORPORATION * All rights reserved. * @@ -21,11 +20,8 @@ * standard way the Linux expects for input drivers. */ -#include <linux/buffer_head.h> #include <linux/fb.h> -#include <linux/fs.h> #include <linux/input.h> -#include <linux/uaccess.h> #include <linux/kernel.h> #include <linux/uuid.h> @@ -33,16 +29,16 @@ #include "ultrainputreport.h" /* Keyboard channel {c73416d0-b0b8-44af-b304-9d2ae99f1b3d} */ -#define VISOR_KEYBOARD_CHANNEL_UUID \ - UUID_LE(0xc73416d0, 0xb0b8, 0x44af, \ - 0xb3, 0x4, 0x9d, 0x2a, 0xe9, 0x9f, 0x1b, 0x3d) -#define VISOR_KEYBOARD_CHANNEL_UUID_STR "c73416d0-b0b8-44af-b304-9d2ae99f1b3d" +#define VISOR_KEYBOARD_CHANNEL_GUID \ + GUID_INIT(0xc73416d0, 0xb0b8, 0x44af, \ + 0xb3, 0x4, 0x9d, 0x2a, 0xe9, 0x9f, 0x1b, 0x3d) +#define VISOR_KEYBOARD_CHANNEL_GUID_STR "c73416d0-b0b8-44af-b304-9d2ae99f1b3d" /* Mouse channel {addf07d4-94a9-46e2-81c3-61abcdbdbd87} */ -#define VISOR_MOUSE_CHANNEL_UUID \ - UUID_LE(0xaddf07d4, 0x94a9, 0x46e2, \ - 0x81, 0xc3, 0x61, 0xab, 0xcd, 0xbd, 0xbd, 0x87) -#define VISOR_MOUSE_CHANNEL_UUID_STR "addf07d4-94a9-46e2-81c3-61abcdbdbd87" +#define VISOR_MOUSE_CHANNEL_GUID \ + GUID_INIT(0xaddf07d4, 0x94a9, 0x46e2, \ + 0x81, 0xc3, 0x61, 0xab, 0xcd, 0xbd, 0xbd, 0x87) +#define VISOR_MOUSE_CHANNEL_GUID_STR "addf07d4-94a9-46e2-81c3-61abcdbdbd87" #define PIXELS_ACROSS_DEFAULT 800 #define PIXELS_DOWN_DEFAULT 600 @@ -60,17 +56,19 @@ enum visorinput_device_type { */ struct visorinput_devdata { struct visor_device *dev; - struct mutex lock_visor_dev; /* lock for dev */ + /* lock for dev */ + struct mutex lock_visor_dev; struct input_dev *visorinput_dev; bool paused; bool interrupts_enabled; - unsigned int keycode_table_bytes; /* size of following array */ + /* size of following array */ + unsigned int keycode_table_bytes; /* for keyboard devices: visorkbd_keycode[] + visorkbd_ext_keycode[] */ unsigned char keycode_table[0]; }; -static const uuid_le visor_keyboard_channel_uuid = VISOR_KEYBOARD_CHANNEL_UUID; -static const uuid_le visor_mouse_channel_uuid = VISOR_MOUSE_CHANNEL_UUID; +static const guid_t visor_keyboard_channel_guid = VISOR_KEYBOARD_CHANNEL_GUID; +static const guid_t visor_mouse_channel_guid = VISOR_MOUSE_CHANNEL_GUID; /* * Borrowed from drivers/input/keyboard/atakbd.c @@ -162,9 +160,8 @@ static const unsigned char visorkbd_keycode[KEYCODE_TABLE_BYTES] = { [81] = KEY_KP3, [82] = KEY_KP0, [83] = KEY_KPDOT, - [86] = KEY_102ND, /* enables UK backslash+pipe key, - * and FR lessthan+greaterthan key - */ + /* enables UK backslash+pipe key and FR lessthan+greaterthan key */ + [86] = KEY_102ND, [87] = KEY_F11, [88] = KEY_F12, [90] = KEY_KPLEFTPAREN, @@ -260,7 +257,6 @@ static void visorinput_close(struct input_dev *visorinput_dev) * interrupts should be disabled so when we resume we will * not re-enable them. */ - mutex_lock(&devdata->lock_visor_dev); devdata->interrupts_enabled = false; if (devdata->paused) @@ -276,15 +272,13 @@ out_unlock: * we can use to deliver keyboard inputs to Linux. We of course do this when * we see keyboard inputs coming in on a keyboard channel. */ -static struct input_dev * -setup_client_keyboard(void *devdata, /* opaque on purpose */ - unsigned char *keycode_table) +static struct input_dev *setup_client_keyboard(void *devdata, + unsigned char *keycode_table) { int i; - struct input_dev *visorinput_dev; + struct input_dev *visorinput_dev = input_allocate_device(); - visorinput_dev = input_allocate_device(); if (!visorinput_dev) return NULL; @@ -302,7 +296,8 @@ setup_client_keyboard(void *devdata, /* opaque on purpose */ BIT_MASK(LED_SCROLLL) | BIT_MASK(LED_NUML); visorinput_dev->keycode = keycode_table; - visorinput_dev->keycodesize = 1; /* sizeof(unsigned char) */ + /* sizeof(unsigned char) */ + visorinput_dev->keycodesize = 1; visorinput_dev->keycodemax = KEYCODE_TABLE_BYTES; for (i = 1; i < visorinput_dev->keycodemax; i++) @@ -313,19 +308,18 @@ setup_client_keyboard(void *devdata, /* opaque on purpose */ visorinput_dev->open = visorinput_open; visorinput_dev->close = visorinput_close; - input_set_drvdata(visorinput_dev, devdata); /* pre input_register! */ + /* pre input_register! */ + input_set_drvdata(visorinput_dev, devdata); return visorinput_dev; } -static struct input_dev * -setup_client_mouse(void *devdata /* opaque on purpose */) +static struct input_dev *setup_client_mouse(void *devdata) { - struct input_dev *visorinput_dev = NULL; int xres, yres; struct fb_info *fb0; + struct input_dev *visorinput_dev = input_allocate_device(); - visorinput_dev = input_allocate_device(); if (!visorinput_dev) return NULL; @@ -354,14 +348,16 @@ setup_client_mouse(void *devdata /* opaque on purpose */) visorinput_dev->open = visorinput_open; visorinput_dev->close = visorinput_close; - input_set_drvdata(visorinput_dev, devdata); /* pre input_register! */ + /* pre input_register! */ + input_set_drvdata(visorinput_dev, devdata); input_set_capability(visorinput_dev, EV_REL, REL_WHEEL); return visorinput_dev; } -static struct visorinput_devdata * -devdata_create(struct visor_device *dev, enum visorinput_device_type devtype) +static struct visorinput_devdata *devdata_create( + struct visor_device *dev, + enum visorinput_device_type devtype) { struct visorinput_devdata *devdata = NULL; unsigned int extra_bytes = 0; @@ -446,16 +442,15 @@ err_kfree_devdata: return NULL; } -static int -visorinput_probe(struct visor_device *dev) +static int visorinput_probe(struct visor_device *dev) { - uuid_le guid; + const guid_t *guid; enum visorinput_device_type devtype; - guid = visorchannel_get_uuid(dev->visorchannel); - if (uuid_le_cmp(guid, visor_mouse_channel_uuid) == 0) + guid = visorchannel_get_guid(dev->visorchannel); + if (guid_equal(guid, &visor_mouse_channel_guid)) devtype = visorinput_mouse; - else if (uuid_le_cmp(guid, visor_keyboard_channel_uuid) == 0) + else if (guid_equal(guid, &visor_keyboard_channel_guid)) devtype = visorinput_keyboard; else return -ENODEV; @@ -465,15 +460,13 @@ visorinput_probe(struct visor_device *dev) return 0; } -static void -unregister_client_input(struct input_dev *visorinput_dev) +static void unregister_client_input(struct input_dev *visorinput_dev) { if (visorinput_dev) input_unregister_device(visorinput_dev); } -static void -visorinput_remove(struct visor_device *dev) +static void visorinput_remove(struct visor_device *dev) { struct visorinput_devdata *devdata = dev_get_drvdata(&dev->device); @@ -499,9 +492,8 @@ visorinput_remove(struct visor_device *dev) * Make it so the current locking state of the locking key indicated by * <keycode> is as indicated by <desired_state> (1=locked, 0=unlocked). */ -static void -handle_locking_key(struct input_dev *visorinput_dev, - int keycode, int desired_state) +static void handle_locking_key(struct input_dev *visorinput_dev, int keycode, + int desired_state) { int led; @@ -533,17 +525,15 @@ handle_locking_key(struct input_dev *visorinput_dev, * with 0xE0 in the low byte and the extended scancode value in the next * higher byte. */ -static int -scancode_to_keycode(int scancode) +static int scancode_to_keycode(int scancode) { if (scancode > 0xff) return visorkbd_ext_keycode[(scancode >> 8) & 0xff]; - return visorkbd_keycode[scancode]; + return visorkbd_keycode[scancode]; } -static int -calc_button(int x) +static int calc_button(int x) { switch (x) { case 1: @@ -562,15 +552,13 @@ calc_button(int x) * client guest partition. It is called periodically so we can obtain inputs * from the channel, and deliver them to the guest OS. */ -static void -visorinput_channel_interrupt(struct visor_device *dev) +static void visorinput_channel_interrupt(struct visor_device *dev) { struct visor_inputreport r; int scancode, keycode; struct input_dev *visorinput_dev; int xmotion, ymotion, button; int i; - struct visorinput_devdata *devdata = dev_get_drvdata(&dev->device); if (!devdata) @@ -626,7 +614,6 @@ visorinput_channel_interrupt(struct visor_device *dev) if (button < 0) break; input_report_key(visorinput_dev, button, 1); - input_sync(visorinput_dev); input_report_key(visorinput_dev, button, 0); input_sync(visorinput_dev); @@ -657,9 +644,8 @@ visorinput_channel_interrupt(struct visor_device *dev) } } -static int -visorinput_pause(struct visor_device *dev, - visorbus_state_complete_func complete_func) +static int visorinput_pause(struct visor_device *dev, + visorbus_state_complete_func complete_func) { int rc; struct visorinput_devdata *devdata = dev_get_drvdata(&dev->device); @@ -681,7 +667,6 @@ visorinput_pause(struct visor_device *dev, * due to above, at this time no thread of execution will be * in visorinput_channel_interrupt() */ - devdata->paused = true; complete_func(dev, 0); rc = 0; @@ -691,9 +676,8 @@ out: return rc; } -static int -visorinput_resume(struct visor_device *dev, - visorbus_state_complete_func complete_func) +static int visorinput_resume(struct visor_device *dev, + visorbus_state_complete_func complete_func) { int rc; struct visorinput_devdata *devdata = dev_get_drvdata(&dev->device); @@ -727,9 +711,9 @@ out: /* GUIDS for all channel types supported by this driver. */ static struct visor_channeltype_descriptor visorinput_channel_types[] = { - { VISOR_KEYBOARD_CHANNEL_UUID, "keyboard"}, - { VISOR_MOUSE_CHANNEL_UUID, "mouse"}, - { NULL_UUID_LE, NULL } + { VISOR_KEYBOARD_CHANNEL_GUID, "keyboard"}, + { VISOR_MOUSE_CHANNEL_GUID, "mouse"}, + {} }; static struct visor_driver visorinput_driver = { @@ -743,20 +727,8 @@ static struct visor_driver visorinput_driver = { .resume = visorinput_resume, }; -static int -visorinput_init(void) -{ - return visorbus_register_visor_driver(&visorinput_driver); -} - -static void -visorinput_cleanup(void) -{ - visorbus_unregister_visor_driver(&visorinput_driver); -} - -module_init(visorinput_init); -module_exit(visorinput_cleanup); +module_driver(visorinput_driver, visorbus_register_visor_driver, + visorbus_unregister_visor_driver); MODULE_DEVICE_TABLE(visorbus, visorinput_channel_types); @@ -764,5 +736,5 @@ MODULE_AUTHOR("Unisys"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("s-Par human input driver for virtual keyboard/mouse"); -MODULE_ALIAS("visorbus:" VISOR_MOUSE_CHANNEL_UUID_STR); -MODULE_ALIAS("visorbus:" VISOR_KEYBOARD_CHANNEL_UUID_STR); +MODULE_ALIAS("visorbus:" VISOR_MOUSE_CHANNEL_GUID_STR); +MODULE_ALIAS("visorbus:" VISOR_KEYBOARD_CHANNEL_GUID_STR); diff --git a/drivers/staging/unisys/visornic/visornic_main.c b/drivers/staging/unisys/visornic/visornic_main.c index 2891622eef18..dc390eae2960 100644 --- a/drivers/staging/unisys/visornic/visornic_main.c +++ b/drivers/staging/unisys/visornic/visornic_main.c @@ -37,22 +37,28 @@ #define NAPI_WEIGHT 64 /* GUIDS for director channel type supported by this driver. */ +/* {8cd5994d-c58e-11da-95a9-00e08161165f} */ +#define VISOR_VNIC_CHANNEL_GUID \ + GUID_INIT(0x8cd5994d, 0xc58e, 0x11da, \ + 0x95, 0xa9, 0x0, 0xe0, 0x81, 0x61, 0x16, 0x5f) +#define VISOR_VNIC_CHANNEL_GUID_STR \ + "8cd5994d-c58e-11da-95a9-00e08161165f" + static struct visor_channeltype_descriptor visornic_channel_types[] = { /* Note that the only channel type we expect to be reported by the * bus driver is the VISOR_VNIC channel. */ - { VISOR_VNIC_CHANNEL_UUID, "ultravnic" }, - { NULL_UUID_LE, NULL } + { VISOR_VNIC_CHANNEL_GUID, "ultravnic" }, + {} }; MODULE_DEVICE_TABLE(visorbus, visornic_channel_types); -/* - * FIXME XXX: This next line of code must be fixed and removed before +/* FIXME XXX: This next line of code must be fixed and removed before * acceptance into the 'normal' part of the kernel. It is only here as a place * holder to get module autoloading functionality working for visorbus. Code * must be added to scripts/mode/file2alias.c, etc., to get this working * properly. */ -MODULE_ALIAS("visorbus:" VISOR_VNIC_CHANNEL_UUID_STR); +MODULE_ALIAS("visorbus:" VISOR_VNIC_CHANNEL_GUID_STR); struct chanstat { unsigned long got_rcv; @@ -68,10 +74,67 @@ struct chanstat { unsigned long extra_rcvbufs_sent; }; +/* struct visornic_devdata + * @enabled: 0 disabled 1 enabled to receive. + * @enab_dis_acked: NET_RCV_ENABLE/DISABLE acked by IOPART. + * @struct *dev: + * @struct *netdev: + * @struct net_stats: + * @interrupt_rcvd: + * @rsp_queue: + * @struct **rcvbuf: + * @incarnation_id: incarnation_id lets IOPART know about + * re-birth. + * @old_flags: flags as they were prior to + * set_multicast_list. + * @usage: count of users. + * @num_rcv_bufs: number of rcv buffers the vnic will post. + * @num_rcv_bufs_could_not_alloc: + * @num_rcvbuf_in_iovm: + * @alloc_failed_in_if_needed_cnt: + * @alloc_failed_in_repost_rtn_cnt: + * @max_outstanding_net_xmits: absolute max number of outstanding xmits + * - should never hit this. + * @upper_threshold_net_xmits: high water mark for calling + * netif_stop_queue(). + * @lower_threshold_net_xmits: high water mark for calling + * netif_wake_queue(). + * @struct xmitbufhead: xmitbufhead - head of the xmit buffer list + * sent to the IOPART end. + * @server_down_complete_func: + * @struct timeout_reset: + * @struct *cmdrsp_rcv: cmdrsp_rcv is used for posting/unposting rcv + * buffers. + * @struct *xmit_cmdrsp: xmit_cmdrsp - issues NET_XMIT - only one + * active xmit at a time. + * @server_down: IOPART is down. + * @server_change_state: Processing SERVER_CHANGESTATE msg. + * @going_away: device is being torn down. + * @struct *eth_debugfs_dir: + * @interrupts_rcvd: + * @interrupts_notme: + * @interrupts_disabled: + * @busy_cnt: + * @priv_lock: spinlock to access devdata structures. + * @flow_control_upper_hits: + * @flow_control_lower_hits: + * @n_rcv0: # rcvs of 0 buffers. + * @n_rcv1: # rcvs of 1 buffers. + * @n_rcv2: # rcvs of 2 buffers. + * @n_rcvx: # rcvs of >2 buffers. + * @found_repost_rcvbuf_cnt: # repost_rcvbuf_cnt. + * @repost_found_skb_cnt: # of found the skb. + * @n_repost_deficit: # of lost rcv buffers. + * @bad_rcv_buf: # of unknown rcv skb not freed. + * @n_rcv_packets_not_accepted: # bogs rcv packets. + * @queuefullmsg_logged: + * @struct chstat: + * @struct irq_poll_timer: + * @struct napi: + * @struct cmdrsp: + */ struct visornic_devdata { - /* 0 disabled 1 enabled to receive */ unsigned short enabled; - /* NET_RCV_ENABLE/DISABLE acked by IOPART */ unsigned short enab_dis_acked; struct visor_device *dev; @@ -80,59 +143,50 @@ struct visornic_devdata { atomic_t interrupt_rcvd; wait_queue_head_t rsp_queue; struct sk_buff **rcvbuf; - /* incarnation_id lets IOPART know about re-birth */ u64 incarnation_id; - /* flags as they were prior to set_multicast_list */ unsigned short old_flags; - atomic_t usage; /* count of users */ + atomic_t usage; - /* number of rcv buffers the vnic will post */ int num_rcv_bufs; int num_rcv_bufs_could_not_alloc; atomic_t num_rcvbuf_in_iovm; unsigned long alloc_failed_in_if_needed_cnt; unsigned long alloc_failed_in_repost_rtn_cnt; - /* absolute max number of outstanding xmits - should never hit this */ unsigned long max_outstanding_net_xmits; - /* high water mark for calling netif_stop_queue() */ unsigned long upper_threshold_net_xmits; - /* high water mark for calling netif_wake_queue() */ unsigned long lower_threshold_net_xmits; - /* xmitbufhead - head of the xmit buffer list sent to the IOPART end */ struct sk_buff_head xmitbufhead; visorbus_state_complete_func server_down_complete_func; struct work_struct timeout_reset; - /* cmdrsp_rcv is used for posting/unposting rcv buffers */ struct uiscmdrsp *cmdrsp_rcv; - /* xmit_cmdrsp - issues NET_XMIT - only one active xmit at a time */ struct uiscmdrsp *xmit_cmdrsp; - - bool server_down; /* IOPART is down */ - bool server_change_state; /* Processing SERVER_CHANGESTATE msg */ - bool going_away; /* device is being torn down */ + bool server_down; + bool server_change_state; + bool going_away; struct dentry *eth_debugfs_dir; u64 interrupts_rcvd; u64 interrupts_notme; u64 interrupts_disabled; u64 busy_cnt; - spinlock_t priv_lock; /* spinlock to access devdata structures */ + /* spinlock to access devdata structures. */ + spinlock_t priv_lock; /* flow control counter */ u64 flow_control_upper_hits; u64 flow_control_lower_hits; /* debug counters */ - unsigned long n_rcv0; /* # rcvs of 0 buffers */ - unsigned long n_rcv1; /* # rcvs of 1 buffers */ - unsigned long n_rcv2; /* # rcvs of 2 buffers */ - unsigned long n_rcvx; /* # rcvs of >2 buffers */ - unsigned long found_repost_rcvbuf_cnt; /* # repost_rcvbuf_cnt */ - unsigned long repost_found_skb_cnt; /* # of found the skb */ - unsigned long n_repost_deficit; /* # of lost rcv buffers */ - unsigned long bad_rcv_buf; /* # of unknown rcv skb not freed */ - unsigned long n_rcv_packets_not_accepted;/* # bogs rcv packets */ + unsigned long n_rcv0; + unsigned long n_rcv1; + unsigned long n_rcv2; + unsigned long n_rcvx; + unsigned long found_repost_rcvbuf_cnt; + unsigned long repost_found_skb_cnt; + unsigned long n_repost_deficit; + unsigned long bad_rcv_buf; + unsigned long n_rcv_packets_not_accepted; int queuefullmsg_logged; struct chanstat chstat; @@ -142,12 +196,11 @@ struct visornic_devdata { }; /* Returns next non-zero index on success or 0 on failure (i.e. out of room). */ -static u16 -add_physinfo_entries(u64 inp_pfn, u16 inp_off, u32 inp_len, u16 index, - u16 max_pi_arr_entries, struct phys_info pi_arr[]) +static u16 add_physinfo_entries(u64 inp_pfn, u16 inp_off, u16 inp_len, + u16 index, u16 max_pi_arr_entries, + struct phys_info pi_arr[]) { - u32 len; - u16 i, firstlen; + u16 i, len, firstlen; firstlen = PI_PAGE_SIZE - inp_off; if (inp_len <= firstlen) { @@ -171,29 +224,27 @@ add_physinfo_entries(u64 inp_pfn, u16 inp_off, u32 inp_len, u16 index, pi_arr[index].pi_len = firstlen; } else { pi_arr[index + i].pi_off = 0; - pi_arr[index + i].pi_len = - (u16)MINNUM(len, (u32)PI_PAGE_SIZE); + pi_arr[index + i].pi_len = min_t(u16, len, + PI_PAGE_SIZE); } } return index + i; } -/* - * visor_copy_fragsinfo_from_skb( - * @skb_in: skbuff that we are pulling the frags from - * @firstfraglen: length of first fragment in skb - * @frags_max: max len of frags array - * @frags: frags array filled in on output +/* visor_copy_fragsinfo_from_skb - copy fragment list in the SKB to a phys_info + * array that the IOPART understands + * @skb: Skbuff that we are pulling the frags from. + * @firstfraglen: Length of first fragment in skb. + * @frags_max: Max len of frags array. + * @frags: Frags array filled in on output. * - * Copy the fragment list in the SKB to a phys_info - * array that the IOPART understands. - * Return value indicates number of entries filled in frags - * Negative values indicate an error. + * Return: Positive integer indicating number of entries filled in frags on + * success, negative integer on error. */ -static int -visor_copy_fragsinfo_from_skb(struct sk_buff *skb, unsigned int firstfraglen, - unsigned int frags_max, - struct phys_info frags[]) +static int visor_copy_fragsinfo_from_skb(struct sk_buff *skb, + unsigned int firstfraglen, + unsigned int frags_max, + struct phys_info frags[]) { unsigned int count = 0, frag, size, offset = 0, numfrags; unsigned int total_count; @@ -239,11 +290,10 @@ visor_copy_fragsinfo_from_skb(struct sk_buff *skb, unsigned int firstfraglen, for (frag = 0; frag < numfrags; frag++) { count = add_physinfo_entries(page_to_pfn( - skb_frag_page(&skb_shinfo(skb)->frags[frag])), - skb_shinfo(skb)->frags[frag]. - page_offset, - skb_shinfo(skb)->frags[frag]. - size, count, frags_max, frags); + skb_frag_page(&skb_shinfo(skb)->frags[frag])), + skb_shinfo(skb)->frags[frag].page_offset, + skb_shinfo(skb)->frags[frag].size, count, + frags_max, frags); /* add_physinfo_entries only returns * zero if the frags array is out of room * That should never happen because we @@ -287,21 +337,15 @@ static const struct file_operations debugfs_enable_ints_fops = { .write = enable_ints_write, }; -/* - * visornic_serverdown_complete - IOPART went down, pause device - * @work: Work queue it was scheduled on +/* visornic_serverdown_complete - pause device following IOPART going down + * @devdata: Device managed by IOPART. * - * The IO partition has gone down and we need to do some cleanup - * for when it comes back. Treat the IO partition as the link - * being down. - * Returns void. + * The IO partition has gone down, and we need to do some cleanup for when it + * comes back. Treat the IO partition as the link being down. */ -static void -visornic_serverdown_complete(struct visornic_devdata *devdata) +static void visornic_serverdown_complete(struct visornic_devdata *devdata) { - struct net_device *netdev; - - netdev = devdata->netdev; + struct net_device *netdev = devdata->netdev; /* Stop polling for interrupts */ del_timer_sync(&devdata->irq_poll_timer); @@ -322,17 +366,17 @@ visornic_serverdown_complete(struct visornic_devdata *devdata) devdata->server_down_complete_func = NULL; } -/* - * visornic_serverdown - Command has notified us that IOPART is down - * @devdata: device that is being managed by IOPART +/* visornic_serverdown - Command has notified us that IOPART is down + * @devdata: Device managed by IOPART. + * @complete_func: Function to call when finished. + * + * Schedule the work needed to handle the server down request. Make sure we + * haven't already handled the server change state event. * - * Schedule the work needed to handle the server down request. Make - * sure we haven't already handled the server change state event. - * Returns 0 if we scheduled the work, -EINVAL on error. + * Return: 0 if we scheduled the work, negative integer on error. */ -static int -visornic_serverdown(struct visornic_devdata *devdata, - visorbus_state_complete_func complete_func) +static int visornic_serverdown(struct visornic_devdata *devdata, + visorbus_state_complete_func complete_func) { unsigned long flags; int err; @@ -369,16 +413,15 @@ err_unlock: return err; } -/* - * alloc_rcv_buf - alloc rcv buffer to be given to the IO Partition. - * @netdev: network adapter the rcv bufs are attached too. +/* alloc_rcv_buf - alloc rcv buffer to be given to the IO Partition + * @netdev: Network adapter the rcv bufs are attached too. * - * Create an sk_buff (rcv_buf) that will be passed to the IO Partition - * so that it can write rcv data into our memory space. - * Return pointer to sk_buff + * Create an sk_buff (rcv_buf) that will be passed to the IO Partition + * so that it can write rcv data into our memory space. + * + * Return: Pointer to sk_buff. */ -static struct sk_buff * -alloc_rcv_buf(struct net_device *netdev) +static struct sk_buff *alloc_rcv_buf(struct net_device *netdev) { struct sk_buff *skb; @@ -400,18 +443,15 @@ alloc_rcv_buf(struct net_device *netdev) return skb; } -/* - * post_skb - post a skb to the IO Partition. - * @cmdrsp: cmdrsp packet to be send to the IO Partition - * @devdata: visornic_devdata to post the skb too - * @skb: skb to give to the IO partition +/* post_skb - post a skb to the IO Partition + * @cmdrsp: Cmdrsp packet to be send to the IO Partition. + * @devdata: visornic_devdata to post the skb to. + * @skb: Skb to give to the IO partition. * - * Send the skb to the IO Partition. - * Returns 0 or error + * Return: 0 on success, negative integer on error. */ -static int -post_skb(struct uiscmdrsp *cmdrsp, - struct visornic_devdata *devdata, struct sk_buff *skb) +static int post_skb(struct uiscmdrsp *cmdrsp, struct visornic_devdata *devdata, + struct sk_buff *skb) { int err; @@ -437,23 +477,20 @@ post_skb(struct uiscmdrsp *cmdrsp, atomic_inc(&devdata->num_rcvbuf_in_iovm); devdata->chstat.sent_post++; - return 0; } -/* - * send_enbdis - send NET_RCV_ENBDIS to IO Partition - * @netdev: netdevice we are enable/disable, used as context - * return value - * @state: enable = 1/disable = 0 - * @devdata: visornic device we are enabling/disabling +/* send_enbdis - Send NET_RCV_ENBDIS to IO Partition + * @netdev: Netdevice we are enabling/disabling, used as context return value. + * @state: Enable = 1/disable = 0. + * @devdata: Visornic device we are enabling/disabling. + * + * Send the enable/disable message to the IO Partition. * - * Send the enable/disable message to the IO Partition. - * Returns 0 or error + * Return: 0 on success, negative integer on error. */ -static int -send_enbdis(struct net_device *netdev, int state, - struct visornic_devdata *devdata) +static int send_enbdis(struct net_device *netdev, int state, + struct visornic_devdata *devdata) { int err; @@ -470,19 +507,17 @@ send_enbdis(struct net_device *netdev, int state, return 0; } -/* - * visornic_disable_with_timeout - Disable network adapter - * @netdev: netdevice to disable - * @timeout: timeout to wait for disable +/* visornic_disable_with_timeout - disable network adapter + * @netdev: netdevice to disable. + * @timeout: Timeout to wait for disable. * - * Disable the network adapter and inform the IO Partition that we - * are disabled, reclaim memory from rcv bufs. - * Returns 0 on success, negative for failure of IO Partition - * responding. + * Disable the network adapter and inform the IO Partition that we are disabled. + * Reclaim memory from rcv bufs. * + * Return: 0 on success, negative integer on failure of IO Partition responding. */ -static int -visornic_disable_with_timeout(struct net_device *netdev, const int timeout) +static int visornic_disable_with_timeout(struct net_device *netdev, + const int timeout) { struct visornic_devdata *devdata = netdev_priv(netdev); int i; @@ -493,7 +528,8 @@ visornic_disable_with_timeout(struct net_device *netdev, const int timeout) /* send a msg telling the other end we are stopping incoming pkts */ spin_lock_irqsave(&devdata->priv_lock, flags); devdata->enabled = 0; - devdata->enab_dis_acked = 0; /* must wait for ack */ + /* must wait for ack */ + devdata->enab_dis_acked = 0; spin_unlock_irqrestore(&devdata->priv_lock, flags); /* send disable and wait for ack -- don't hold lock when sending @@ -560,16 +596,16 @@ visornic_disable_with_timeout(struct net_device *netdev, const int timeout) return 0; } -/* - * init_rcv_bufs -- initialize receive bufs and send them to the IO Part - * @netdev: struct netdevice - * @devdata: visornic_devdata +/* init_rcv_bufs - initialize receive buffs and send them to the IO Partition + * @netdev: struct netdevice. + * @devdata: visornic_devdata. + * + * Allocate rcv buffers and post them to the IO Partition. * - * Allocate rcv buffers and post them to the IO Partition. - * Return 0 for success, and negative for failure. + * Return: 0 on success, negative integer on failure. */ -static int -init_rcv_bufs(struct net_device *netdev, struct visornic_devdata *devdata) +static int init_rcv_bufs(struct net_device *netdev, + struct visornic_devdata *devdata) { int i, j, count, err; @@ -578,10 +614,12 @@ init_rcv_bufs(struct net_device *netdev, struct visornic_devdata *devdata) */ for (i = 0; i < devdata->num_rcv_bufs; i++) { devdata->rcvbuf[i] = alloc_rcv_buf(netdev); + /* if we failed to allocate one let us stop */ if (!devdata->rcvbuf[i]) - break; /* if we failed to allocate one let us stop */ + break; } - if (i == 0) /* couldn't even allocate one -- bail out */ + /* couldn't even allocate one -- bail out */ + if (i == 0) return -ENOMEM; count = i; @@ -624,17 +662,17 @@ init_rcv_bufs(struct net_device *netdev, struct visornic_devdata *devdata) return 0; } -/* - * visornic_enable_with_timeout - send enable to IO Part - * @netdev: struct net_device - * @timeout: Time to wait for the ACK from the enable +/* visornic_enable_with_timeout - send enable to IO Partition + * @netdev: struct net_device. + * @timeout: Time to wait for the ACK from the enable. * - * Sends enable to IOVM, inits, and posts receive buffers to IOVM - * timeout is defined in msecs (timeout of 0 specifies infinite wait) - * Return 0 for success, negative for failure. + * Sends enable to IOVM and inits, and posts receive buffers to IOVM. Timeout is + * defined in msecs (timeout of 0 specifies infinite wait). + * + * Return: 0 on success, negative integer on failure. */ -static int -visornic_enable_with_timeout(struct net_device *netdev, const int timeout) +static int visornic_enable_with_timeout(struct net_device *netdev, + const int timeout) { int err = 0; struct visornic_devdata *devdata = netdev_priv(netdev); @@ -695,20 +733,17 @@ visornic_enable_with_timeout(struct net_device *netdev, const int timeout) } netif_start_queue(netdev); - return 0; } -/* - * visornic_timeout_reset - handle xmit timeout resets - * @work work item that scheduled the work +/* visornic_timeout_reset - handle xmit timeout resets + * @work: Work item that scheduled the work. * - * Transmit Timeouts are typically handled by resetting the - * device for our virtual NIC we will send a Disable and Enable - * to the IOVM. If it doesn't respond we will trigger a serverdown. + * Transmit timeouts are typically handled by resetting the device for our + * virtual NIC; we will send a disable and enable to the IOVM. If it doesn't + * respond, we will trigger a serverdown. */ -static void -visornic_timeout_reset(struct work_struct *work) +static void visornic_timeout_reset(struct work_struct *work) { struct visornic_devdata *devdata; struct net_device *netdev; @@ -742,41 +777,36 @@ call_serverdown: rtnl_unlock(); } -/* - * visornic_open - Enable the visornic device and mark the queue started - * @netdev: netdevice to start +/* visornic_open - enable the visornic device and mark the queue started + * @netdev: netdevice to start. * - * Enable the device and start the transmit queue. - * Return 0 for success + * Enable the device and start the transmit queue. + * + * Return: 0 on success. */ -static int -visornic_open(struct net_device *netdev) +static int visornic_open(struct net_device *netdev) { visornic_enable_with_timeout(netdev, VISORNIC_INFINITE_RSP_WAIT); - return 0; } -/* - * visornic_close - Disables the visornic device and stops the queues - * @netdev: netdevice to start +/* visornic_close - disables the visornic device and stops the queues + * @netdev: netdevice to stop. * - * Disable the device and stop the transmit queue. - * Return 0 for success + * Disable the device and stop the transmit queue. + * + * Return 0 on success. */ -static int -visornic_close(struct net_device *netdev) +static int visornic_close(struct net_device *netdev) { visornic_disable_with_timeout(netdev, VISORNIC_INFINITE_RSP_WAIT); - return 0; } -/* - * devdata_xmits_outstanding - compute outstanding xmits - * @devdata: visornic_devdata for device +/* devdata_xmits_outstanding - compute outstanding xmits + * @devdata: visornic_devdata for device * - * Return value is the number of outstanding xmits. + * Return: Long integer representing the number of outstanding xmits. */ static unsigned long devdata_xmits_outstanding(struct visornic_devdata *devdata) { @@ -787,14 +817,13 @@ static unsigned long devdata_xmits_outstanding(struct visornic_devdata *devdata) + devdata->chstat.sent_xmit + 1); } -/* - * vnic_hit_high_watermark - * @devdata: indicates visornic device we are checking - * @high_watermark: max num of unacked xmits we will tolerate, - * before we will start throttling +/* vnic_hit_high_watermark + * @devdata: Indicates visornic device we are checking. + * @high_watermark: Max num of unacked xmits we will tolerate before we will + * start throttling. * - * Returns true iff the number of unacked xmits sent to - * the IO partition is >= high_watermark. + * Return: True iff the number of unacked xmits sent to the IO Partition is >= + * high_watermark. False otherwise. */ static bool vnic_hit_high_watermark(struct visornic_devdata *devdata, ulong high_watermark) @@ -802,15 +831,13 @@ static bool vnic_hit_high_watermark(struct visornic_devdata *devdata, return (devdata_xmits_outstanding(devdata) >= high_watermark); } -/* - * vnic_hit_low_watermark - * @devdata: indicates visornic device we are checking - * @low_watermark: we will wait until the num of unacked xmits - * drops to this value or lower before we start - * transmitting again +/* vnic_hit_low_watermark + * @devdata: Indicates visornic device we are checking. + * @low_watermark: We will wait until the num of unacked xmits drops to this + * value or lower before we start transmitting again. * - * Returns true iff the number of unacked xmits sent to - * the IO partition is <= low_watermark. + * Return: True iff the number of unacked xmits sent to the IO Partition is <= + * low_watermark. */ static bool vnic_hit_low_watermark(struct visornic_devdata *devdata, ulong low_watermark) @@ -818,20 +845,18 @@ static bool vnic_hit_low_watermark(struct visornic_devdata *devdata, return (devdata_xmits_outstanding(devdata) <= low_watermark); } -/* - * visornic_xmit - send a packet to the IO Partition - * @skb: Packet to be sent - * @netdev: net device the packet is being sent from +/* visornic_xmit - send a packet to the IO Partition + * @skb: Packet to be sent. + * @netdev: Net device the packet is being sent from. + * + * Convert the skb to a cmdrsp so the IO Partition can understand it, and send + * the XMIT command to the IO Partition for processing. This function is + * protected from concurrent calls by a spinlock xmit_lock in the net_device + * struct. As soon as the function returns, it can be called again. * - * Convert the skb to a cmdrsp so the IO Partition can understand it. - * Send the XMIT command to the IO Partition for processing. This - * function is protected from concurrent calls by a spinlock xmit_lock - * in the net_device struct, but as soon as the function returns it - * can be called again. - * Returns NETDEV_TX_OK. + * Return: NETDEV_TX_OK. */ -static int -visornic_xmit(struct sk_buff *skb, struct net_device *netdev) +static int visornic_xmit(struct sk_buff *skb, struct net_device *netdev) { struct visornic_devdata *devdata; int len, firstfraglen, padlen; @@ -938,6 +963,7 @@ visornic_xmit(struct sk_buff *skb, struct net_device *netdev) * - everything else will be pass in frags & DMA'ed */ memcpy(cmdrsp->net.xmt.ethhdr, skb->data, ETH_HLEN); + /* copy frags info - from skb->data we need to only provide access * beyond eth header */ @@ -991,46 +1017,39 @@ visornic_xmit(struct sk_buff *skb, struct net_device *netdev) return NETDEV_TX_OK; } -/* - * visornic_get_stats - returns net_stats of the visornic device - * @netdev: netdevice +/* visornic_get_stats - returns net_stats of the visornic device + * @netdev: netdevice. * - * Returns the net_device_stats for the device + * Return: Pointer to the net_device_stats struct for the device. */ -static struct net_device_stats * -visornic_get_stats(struct net_device *netdev) +static struct net_device_stats *visornic_get_stats(struct net_device *netdev) { struct visornic_devdata *devdata = netdev_priv(netdev); return &devdata->net_stats; } -/* - * visornic_change_mtu - changes mtu of device. - * @netdev: netdevice - * @new_mtu: value of new mtu +/* visornic_change_mtu - changes mtu of device + * @netdev: netdevice. + * @new_mtu: Value of new mtu. + * + * The device's MTU cannot be changed by system; it must be changed via a + * CONTROLVM message. All vnics and pnics in a switch have to have the same MTU + * for everything to work. Currently not supported. * - * MTU cannot be changed by system, must be changed via - * CONTROLVM message. All vnics and pnics in a switch have - * to have the same MTU for everything to work. - * Currently not supported. - * Returns EINVAL + * Return: -EINVAL. */ -static int -visornic_change_mtu(struct net_device *netdev, int new_mtu) +static int visornic_change_mtu(struct net_device *netdev, int new_mtu) { return -EINVAL; } -/* - * visornic_set_multi - changes mtu of device. - * @netdev: netdevice +/* visornic_set_multi - set visornic device flags + * @netdev: netdevice. * - * Only flag we support currently is IFF_PROMISC - * Returns void + * The only flag we currently support is IFF_PROMISC. */ -static void -visornic_set_multi(struct net_device *netdev) +static void visornic_set_multi(struct net_device *netdev) { struct uiscmdrsp *cmdrsp; struct visornic_devdata *devdata = netdev_priv(netdev); @@ -1062,16 +1081,13 @@ out_save_flags: devdata->old_flags = netdev->flags; } -/* - * visornic_xmit_timeout - request to timeout the xmit - * @netdev +/* visornic_xmit_timeout - request to timeout the xmit + * @netdev: netdevice. * - * Queue the work and return. Make sure we have not already - * been informed the IO Partition is gone, if it is gone - * we will already timeout the xmits. + * Queue the work and return. Make sure we have not already been informed that + * the IO Partition is gone; if so, we will have already timed-out the xmits. */ -static void -visornic_xmit_timeout(struct net_device *netdev) +static void visornic_xmit_timeout(struct net_device *netdev) { struct visornic_devdata *devdata = netdev_priv(netdev); unsigned long flags; @@ -1097,20 +1113,20 @@ visornic_xmit_timeout(struct net_device *netdev) spin_unlock_irqrestore(&devdata->priv_lock, flags); } -/* - * repost_return - repost rcv bufs that have come back - * @cmdrsp: io channel command struct to post - * @devdata: visornic devdata for the device - * @skb: skb - * @netdev: netdevice +/* repost_return - repost rcv bufs that have come back + * @cmdrsp: IO channel command struct to post. + * @devdata: Visornic devdata for the device. + * @skb: Socket buffer. + * @netdev: netdevice. + * + * Repost rcv buffers that have been returned to us when we are finished + * with them. * - * Repost rcv buffers that have been returned to us when - * we are finished with them. - * Returns 0 for success, -1 for error. + * Return: 0 for success, negative integer on error. */ -static int -repost_return(struct uiscmdrsp *cmdrsp, struct visornic_devdata *devdata, - struct sk_buff *skb, struct net_device *netdev) +static int repost_return(struct uiscmdrsp *cmdrsp, + struct visornic_devdata *devdata, + struct sk_buff *skb, struct net_device *netdev) { struct net_pkt_rcv copy; int i = 0, cc, numreposted; @@ -1174,16 +1190,15 @@ repost_return(struct uiscmdrsp *cmdrsp, struct visornic_devdata *devdata, return status; } -/* - * visornic_rx - Handle receive packets coming back from IO Part - * @cmdrsp: Receive packet returned from IO Part +/* visornic_rx - handle receive packets coming back from IO Partition + * @cmdrsp: Receive packet returned from IO Partition. * - * Got a receive packet back from the IO Part, handle it and send - * it up the stack. - * Returns 1 iff an skb was received, otherwise 0 + * Got a receive packet back from the IO Partition; handle it and send it up + * the stack. + + * Return: 1 iff an skb was received, otherwise 0. */ -static int -visornic_rx(struct uiscmdrsp *cmdrsp) +static int visornic_rx(struct uiscmdrsp *cmdrsp) { struct visornic_devdata *devdata; struct sk_buff *skb, *prev, *curr; @@ -1236,7 +1251,8 @@ visornic_rx(struct uiscmdrsp *cmdrsp) * firstfrag & set data_len to show rest see if we have to chain * frag_list. */ - if (skb->len > RCVPOST_BUF_SIZE) { /* do PRECAUTIONARY check */ + /* do PRECAUTIONARY check */ + if (skb->len > RCVPOST_BUF_SIZE) { if (cmdrsp->net.rcv.numrcvbufs < 2) { if (repost_return(cmdrsp, devdata, skb, netdev) < 0) dev_err(&devdata->netdev->dev, @@ -1244,23 +1260,24 @@ visornic_rx(struct uiscmdrsp *cmdrsp) return 0; } /* length rcvd is greater than firstfrag in this skb rcv buf */ - skb->tail += RCVPOST_BUF_SIZE; /* amount in skb->data */ - skb->data_len = skb->len - RCVPOST_BUF_SIZE; /* amount that - * will be in - * frag_list - */ + /* amount in skb->data */ + skb->tail += RCVPOST_BUF_SIZE; + /* amount that will be in frag_list */ + skb->data_len = skb->len - RCVPOST_BUF_SIZE; } else { /* data fits in this skb - no chaining - do * PRECAUTIONARY check */ - if (cmdrsp->net.rcv.numrcvbufs != 1) { /* should be 1 */ + /* should be 1 */ + if (cmdrsp->net.rcv.numrcvbufs != 1) { if (repost_return(cmdrsp, devdata, skb, netdev) < 0) dev_err(&devdata->netdev->dev, "repost_return failed"); return 0; } skb->tail += skb->len; - skb->data_len = 0; /* nothing rcvd in frag_list */ + /* nothing rcvd in frag_list */ + skb->data_len = 0; } off = skb_tail_pointer(skb) - skb->data; @@ -1286,7 +1303,8 @@ visornic_rx(struct uiscmdrsp *cmdrsp) cc < cmdrsp->net.rcv.numrcvbufs; cc++) { curr = (struct sk_buff *)cmdrsp->net.rcv.rcvbuf[cc]; curr->next = NULL; - if (!prev) /* start of list- set head */ + /* start of list- set head */ + if (!prev) skb_shinfo(skb)->frag_list = curr; else prev->next = curr; @@ -1314,18 +1332,18 @@ visornic_rx(struct uiscmdrsp *cmdrsp) * sets up skb->pkt_type & it also PULLS out the eth header */ skb->protocol = eth_type_trans(skb, netdev); - eth = eth_hdr(skb); - skb->csum = 0; skb->ip_summed = CHECKSUM_NONE; do { + /* accept all packets */ if (netdev->flags & IFF_PROMISC) - break; /* accept all packets */ + break; if (skb->pkt_type == PACKET_BROADCAST) { + /* accept all broadcast packets */ if (netdev->flags & IFF_BROADCAST) - break; /* accept all broadcast packets */ + break; } else if (skb->pkt_type == PACKET_MULTICAST) { if ((netdev->flags & IFF_MULTICAST) && (netdev_mc_count(netdev))) { @@ -1367,8 +1385,7 @@ visornic_rx(struct uiscmdrsp *cmdrsp) */ skb = NULL; - /* - * whether the packet got dropped or handled, the skb is freed by + /* whether the packet got dropped or handled, the skb is freed by * kernel code, so we shouldn't free it. but we should repost a * new rcv buffer. */ @@ -1376,29 +1393,25 @@ visornic_rx(struct uiscmdrsp *cmdrsp) return 1; } -/* - * devdata_initialize - Initialize devdata structure - * @devdata: visornic_devdata structure to initialize - * #dev: visorbus_deviced it belongs to +/* devdata_initialize - initialize devdata structure + * @devdata: visornic_devdata structure to initialize. + * @dev: visorbus_device it belongs to. * - * Setup initial values for the visornic based on channel and default - * values. - * Returns a pointer to the devdata structure + * Setup initial values for the visornic, based on channel and default values. + * + * Return: A pointer to the devdata structure. */ -static struct visornic_devdata * -devdata_initialize(struct visornic_devdata *devdata, struct visor_device *dev) +static struct visornic_devdata *devdata_initialize( + struct visornic_devdata *devdata, + struct visor_device *dev) { devdata->dev = dev; devdata->incarnation_id = get_jiffies_64(); return devdata; } -/* - * devdata_release - Frees up references in devdata - * @devdata: struct to clean up - * - * Frees up references in devdata. - * Returns void +/* devdata_release - free up references in devdata + * @devdata: Struct to clean up. */ static void devdata_release(struct visornic_devdata *devdata) { @@ -1570,15 +1583,10 @@ static const struct file_operations debugfs_info_fops = { .read = info_debugfs_read, }; -/* - * send_rcv_posts_if_needed - * @devdata: visornic device - * - * Send receive buffers to the IO Partition. - * Returns void +/* send_rcv_posts_if_needed - send receive buffers to the IO Partition. + * @devdata: Visornic device. */ -static int -send_rcv_posts_if_needed(struct visornic_devdata *devdata) +static void send_rcv_posts_if_needed(struct visornic_devdata *devdata) { int i; struct net_device *netdev; @@ -1588,7 +1596,7 @@ send_rcv_posts_if_needed(struct visornic_devdata *devdata) /* don't do this until vnic is marked ready */ if (!(devdata->enabled && devdata->enab_dis_acked)) - return 0; + return; netdev = devdata->netdev; rcv_bufs_allocated = 0; @@ -1617,16 +1625,14 @@ send_rcv_posts_if_needed(struct visornic_devdata *devdata) } } devdata->num_rcv_bufs_could_not_alloc -= rcv_bufs_allocated; - return 0; } -/* - * drain_resp_queue - drains and ignores all messages from the resp queue - * @cmdrsp: io channel command response message - * @devdata: visornic device to drain +/* drain_resp_queue - drains and ignores all messages from the resp queue + * @cmdrsp: IO channel command response message. + * @devdata: Visornic device to drain. */ -static void -drain_resp_queue(struct uiscmdrsp *cmdrsp, struct visornic_devdata *devdata) +static void drain_resp_queue(struct uiscmdrsp *cmdrsp, + struct visornic_devdata *devdata) { while (!visorchannel_signalremove(devdata->dev->visorchannel, IOCHAN_FROM_IOPART, @@ -1634,30 +1640,31 @@ drain_resp_queue(struct uiscmdrsp *cmdrsp, struct visornic_devdata *devdata) ; } -/* - * service_resp_queue - drains the response queue - * @cmdrsp: io channel command response message - * @devdata: visornic device to drain +/* service_resp_queue - drain the response queue + * @cmdrsp: IO channel command response message. + * @devdata: Visornic device to drain. + * @rx_work_done: + * @budget: * - * Drain the response queue of any responses from the IO partition. - * Process the responses as we get them. - * Returns when response queue is empty or when the thread stops. + * Drain the response queue of any responses from the IO Partition. Process the + * responses as we get them. */ -static void -service_resp_queue(struct uiscmdrsp *cmdrsp, struct visornic_devdata *devdata, - int *rx_work_done, int budget) +static void service_resp_queue(struct uiscmdrsp *cmdrsp, + struct visornic_devdata *devdata, + int *rx_work_done, int budget) { unsigned long flags; struct net_device *netdev; while (*rx_work_done < budget) { - /* TODO: CLIENT ACQUIRE -- Don't really need this at the - * moment - */ + /* TODO: CLIENT ACQUIRE -- Don't really need this at the + * moment + */ + /* queue empty */ if (visorchannel_signalremove(devdata->dev->visorchannel, IOCHAN_FROM_IOPART, cmdrsp)) - break; /* queue empty */ + break; switch (cmdrsp->net.type) { case NET_RCV: @@ -1740,12 +1747,8 @@ static int visornic_poll(struct napi_struct *napi, int budget) struct visornic_devdata, napi); int rx_count = 0; - int err; - - err = send_rcv_posts_if_needed(devdata); - if (err) - return err; + send_rcv_posts_if_needed(devdata); service_resp_queue(devdata->cmdrsp, devdata, &rx_count, budget); /* If there aren't any more packets to receive stop the poll */ @@ -1755,16 +1758,13 @@ static int visornic_poll(struct napi_struct *napi, int budget) return rx_count; } -/* - * poll_for_irq - Checks the status of the response queue. - * @v: void pointer to the visronic devdata +/* poll_for_irq - checks the status of the response queue + * @v: Void pointer to the visronic devdata struct. * - * Main function of the vnic_incoming thread. Periodically check the - * response queue and drain it if needed. - * Returns when thread has stopped. + * Main function of the vnic_incoming thread. Periodically check the response + * queue and drain it if needed. */ -static void -poll_for_irq(unsigned long v) +static void poll_for_irq(unsigned long v) { struct visornic_devdata *devdata = (struct visornic_devdata *)v; @@ -1778,13 +1778,13 @@ poll_for_irq(unsigned long v) mod_timer(&devdata->irq_poll_timer, msecs_to_jiffies(2)); } -/* - * visornic_probe - probe function for visornic devices - * @dev: The visor device discovered +/* visornic_probe - probe function for visornic devices + * @dev: The visor device discovered. + * + * Called when visorbus discovers a visornic device on its bus. It creates a new + * visornic ethernet adapter. * - * Called when visorbus discovers a visornic device on its - * bus. It creates a new visornic ethernet adapter. - * Returns 0 or negative for error. + * Return: 0 on success, or negative integer on error. */ static int visornic_probe(struct visor_device *dev) { @@ -1831,7 +1831,8 @@ static int visornic_probe(struct visor_device *dev) dev_set_drvdata(&dev->device, devdata); init_waitqueue_head(&devdata->rsp_queue); spin_lock_init(&devdata->priv_lock); - devdata->enabled = 0; /* not yet */ + /* not yet */ + devdata->enabled = 0; atomic_set(&devdata->usage, 1); /* Setup rcv bufs */ @@ -1852,9 +1853,10 @@ static int visornic_probe(struct visor_device *dev) goto cleanup_netdev; } - /* set the net_xmit outstanding threshold */ - /* always leave two slots open but you should have 3 at a minimum */ - /* note that max_outstanding_net_xmits must be > 0 */ + /* set the net_xmit outstanding threshold + * always leave two slots open but you should have 3 at a minimum + * note that max_outstanding_net_xmits must be > 0 + */ devdata->max_outstanding_net_xmits = max_t(unsigned long, 3, ((devdata->num_rcv_bufs / 3) - 2)); devdata->upper_threshold_net_xmits = @@ -1972,28 +1974,25 @@ cleanup_netdev: return err; } -/* - * host_side_disappeared - IO part is gone. - * @devdata: device object +/* host_side_disappeared - IO Partition is gone + * @devdata: Device object. * - * IO partition servicing this device is gone, do cleanup - * Returns void. + * IO partition servicing this device is gone; do cleanup. */ static void host_side_disappeared(struct visornic_devdata *devdata) { unsigned long flags; spin_lock_irqsave(&devdata->priv_lock, flags); - devdata->dev = NULL; /* indicate device destroyed */ + /* indicate device destroyed */ + devdata->dev = NULL; spin_unlock_irqrestore(&devdata->priv_lock, flags); } -/* - * visornic_remove - Called when visornic dev goes away - * @dev: visornic device that is being removed +/* visornic_remove - called when visornic dev goes away + * @dev: Visornic device that is being removed. * - * Called when DEVICE_DESTROY gets called to remove device. - * Returns void + * Called when DEVICE_DESTROY gets called to remove device. */ static void visornic_remove(struct visor_device *dev) { @@ -2023,8 +2022,8 @@ static void visornic_remove(struct visor_device *dev) cancel_work_sync(&devdata->timeout_reset); debugfs_remove_recursive(devdata->eth_debugfs_dir); - - unregister_netdev(netdev); /* this will call visornic_close() */ + /* this will call visornic_close() */ + unregister_netdev(netdev); del_timer_sync(&devdata->irq_poll_timer); netif_napi_del(&devdata->napi); @@ -2035,18 +2034,17 @@ static void visornic_remove(struct visor_device *dev) free_netdev(netdev); } -/* - * visornic_pause - Called when IO Part disappears - * @dev: visornic device that is being serviced - * @complete_func: call when finished. +/* visornic_pause - called when IO Part disappears + * @dev: Visornic device that is being serviced. + * @complete_func: Call when finished. + * + * Called when the IO Partition has gone down. Need to free up resources and + * wait for IO partition to come back. Mark link as down and don't attempt any + * DMA. When we have freed memory, call the complete_func so that Command knows + * we are done. If we don't call complete_func, the IO Partition will never + * come back. * - * Called when the IO Partition has gone down. Need to free - * up resources and wait for IO partition to come back. Mark - * link as down and don't attempt any DMA. When we have freed - * memory call the complete_func so that Command knows we are - * done. If we don't call complete_func, IO part will never - * come back. - * Returns 0 for success. + * Return: 0 on success. */ static int visornic_pause(struct visor_device *dev, visorbus_state_complete_func complete_func) @@ -2057,15 +2055,14 @@ static int visornic_pause(struct visor_device *dev, return 0; } -/* - * visornic_resume - Called when IO part has recovered - * @dev: visornic device that is being serviced - * @compelte_func: call when finished +/* visornic_resume - called when IO Partition has recovered + * @dev: Visornic device that is being serviced. + * @compelte_func: Call when finished. + * + * Called when the IO partition has recovered. Re-establish connection to the IO + * Partition and set the link up. Okay to do DMA again. * - * Called when the IO partition has recovered. Reestablish - * connection to the IO part and set the link up. Okay to do - * DMA again. - * Returns 0 for success. + * Returns 0 for success, negative integer on error. */ static int visornic_resume(struct visor_device *dev, visorbus_state_complete_func complete_func) @@ -2127,12 +2124,12 @@ static struct visor_driver visornic_driver = { .channel_interrupt = NULL, }; -/* - * visornic_init - Init function +/* visornic_init - init function * - * Init function for the visornic driver. Do initial driver setup - * and wait for devices. - * Returns 0 for success, negative for error. + * Init function for the visornic driver. Do initial driver setup and wait + * for devices. + * + * Return: 0 on success, negative integer on error. */ static int visornic_init(void) { @@ -2160,19 +2157,16 @@ static int visornic_init(void) cleanup_debugfs: debugfs_remove_recursive(visornic_debugfs_dir); - return err; } -/* - * visornic_cleanup - driver exit routine +/* visornic_cleanup - driver exit routine * - * Unregister driver from the bus and free up memory. + * Unregister driver from the bus and free up memory. */ static void visornic_cleanup(void) { visorbus_unregister_visor_driver(&visornic_driver); - debugfs_remove_recursive(visornic_debugfs_dir); } diff --git a/drivers/staging/vboxvideo/Kconfig b/drivers/staging/vboxvideo/Kconfig index a52746f9a670..1f4182e2e980 100644 --- a/drivers/staging/vboxvideo/Kconfig +++ b/drivers/staging/vboxvideo/Kconfig @@ -2,11 +2,14 @@ config DRM_VBOXVIDEO tristate "Virtual Box Graphics Card" depends on DRM && X86 && PCI select DRM_KMS_HELPER + select DRM_TTM + select GENERIC_ALLOCATOR help This is a KMS driver for the virtual Graphics Card used in Virtual Box virtual machines. - Although it is possible to builtin this module, it is advised - to build this driver as a module, so that it can be updated - independently of the kernel. Select M to built this driver as a - module and add support for these devices via drm/kms interfaces. + Although it is possible to build this driver built-in to the + kernel, it is advised to build it as a module, so that it can + be updated independently of the kernel. Select M to build this + driver as a module and add support for these devices via drm/kms + interfaces. diff --git a/drivers/staging/vboxvideo/TODO b/drivers/staging/vboxvideo/TODO index ce764309b079..bd381d861ab3 100644 --- a/drivers/staging/vboxvideo/TODO +++ b/drivers/staging/vboxvideo/TODO @@ -5,5 +5,5 @@ TODO: -Extend this TODO with the results of that review Please send any patches to Greg Kroah-Hartman <gregkh@linuxfoundation.org>, -Hans de Goede <hdegoede@redhat.com> and -Michael Thayer <michael.thayer@oracle.com>. +Hans de Goede <hdegoede@redhat.com>, Michael Thayer <michael.thayer@oracle.com> +and dri-devel@lists.freedesktop.org . diff --git a/drivers/staging/vboxvideo/vbox_drv.c b/drivers/staging/vboxvideo/vbox_drv.c index 6d0600c37c0c..e18642e5027e 100644 --- a/drivers/staging/vboxvideo/vbox_drv.c +++ b/drivers/staging/vboxvideo/vbox_drv.c @@ -36,7 +36,7 @@ #include "vbox_drv.h" -int vbox_modeset = -1; +static int vbox_modeset = -1; MODULE_PARM_DESC(modeset, "Disable/Enable modesetting"); module_param_named(modeset, vbox_modeset, int, 0400); diff --git a/drivers/staging/vboxvideo/vbox_fb.c b/drivers/staging/vboxvideo/vbox_fb.c index c1572843003a..8aed248db6e2 100644 --- a/drivers/staging/vboxvideo/vbox_fb.c +++ b/drivers/staging/vboxvideo/vbox_fb.c @@ -45,144 +45,20 @@ #include "vbox_drv.h" #include "vboxvideo.h" -#define VBOX_DIRTY_DELAY (HZ / 30) -/** - * Tell the host about dirty rectangles to update. - */ -static void vbox_dirty_update(struct vbox_fbdev *fbdev, - int x, int y, int width, int height) -{ - struct drm_gem_object *obj; - struct vbox_bo *bo; - int ret = -EBUSY; - bool store_for_later = false; - int x2, y2; - unsigned long flags; - struct drm_clip_rect rect; - - obj = fbdev->afb.obj; - bo = gem_to_vbox_bo(obj); - - /* - * try and reserve the BO, if we fail with busy - * then the BO is being moved and we should - * store up the damage until later. - */ - if (drm_can_sleep()) - ret = vbox_bo_reserve(bo, true); - if (ret) { - if (ret != -EBUSY) - return; - - store_for_later = true; - } - - x2 = x + width - 1; - y2 = y + height - 1; - spin_lock_irqsave(&fbdev->dirty_lock, flags); - - if (fbdev->y1 < y) - y = fbdev->y1; - if (fbdev->y2 > y2) - y2 = fbdev->y2; - if (fbdev->x1 < x) - x = fbdev->x1; - if (fbdev->x2 > x2) - x2 = fbdev->x2; - - if (store_for_later) { - fbdev->x1 = x; - fbdev->x2 = x2; - fbdev->y1 = y; - fbdev->y2 = y2; - spin_unlock_irqrestore(&fbdev->dirty_lock, flags); - return; - } - - fbdev->x1 = INT_MAX; - fbdev->y1 = INT_MAX; - fbdev->x2 = 0; - fbdev->y2 = 0; - - spin_unlock_irqrestore(&fbdev->dirty_lock, flags); - - /* - * Not sure why the original code subtracted 1 here, but I will keep - * it that way to avoid unnecessary differences. - */ - rect.x1 = x; - rect.x2 = x2 + 1; - rect.y1 = y; - rect.y2 = y2 + 1; - vbox_framebuffer_dirty_rectangles(&fbdev->afb.base, &rect, 1); - - vbox_bo_unreserve(bo); -} - -#ifdef CONFIG_FB_DEFERRED_IO -static void vbox_deferred_io(struct fb_info *info, struct list_head *pagelist) -{ - struct vbox_fbdev *fbdev = info->par; - unsigned long start, end, min, max; - struct page *page; - int y1, y2; - - min = ULONG_MAX; - max = 0; - list_for_each_entry(page, pagelist, lru) { - start = page->index << PAGE_SHIFT; - end = start + PAGE_SIZE - 1; - min = min(min, start); - max = max(max, end); - } - - if (min < max) { - y1 = min / info->fix.line_length; - y2 = (max / info->fix.line_length) + 1; - DRM_INFO("%s: Calling dirty update: 0, %d, %d, %d\n", - __func__, y1, info->var.xres, y2 - y1 - 1); - vbox_dirty_update(fbdev, 0, y1, info->var.xres, y2 - y1 - 1); - } -} - +#ifdef CONFIG_DRM_KMS_FB_HELPER static struct fb_deferred_io vbox_defio = { - .delay = VBOX_DIRTY_DELAY, - .deferred_io = vbox_deferred_io, + .delay = HZ / 30, + .deferred_io = drm_fb_helper_deferred_io, }; #endif -static void vbox_fillrect(struct fb_info *info, const struct fb_fillrect *rect) -{ - struct vbox_fbdev *fbdev = info->par; - - sys_fillrect(info, rect); - vbox_dirty_update(fbdev, rect->dx, rect->dy, rect->width, rect->height); -} - -static void vbox_copyarea(struct fb_info *info, const struct fb_copyarea *area) -{ - struct vbox_fbdev *fbdev = info->par; - - sys_copyarea(info, area); - vbox_dirty_update(fbdev, area->dx, area->dy, area->width, area->height); -} - -static void vbox_imageblit(struct fb_info *info, const struct fb_image *image) -{ - struct vbox_fbdev *fbdev = info->par; - - sys_imageblit(info, image); - vbox_dirty_update(fbdev, image->dx, image->dy, image->width, - image->height); -} - static struct fb_ops vboxfb_ops = { .owner = THIS_MODULE, .fb_check_var = drm_fb_helper_check_var, .fb_set_par = drm_fb_helper_set_par, - .fb_fillrect = vbox_fillrect, - .fb_copyarea = vbox_copyarea, - .fb_imageblit = vbox_imageblit, + .fb_fillrect = drm_fb_helper_sys_fillrect, + .fb_copyarea = drm_fb_helper_sys_copyarea, + .fb_imageblit = drm_fb_helper_sys_imageblit, .fb_pan_display = drm_fb_helper_pan_display, .fb_blank = drm_fb_helper_blank, .fb_setcmap = drm_fb_helper_setcmap, @@ -219,7 +95,6 @@ static int vboxfb_create(struct drm_fb_helper *helper, struct DRM_MODE_FB_CMD mode_cmd; struct drm_framebuffer *fb; struct fb_info *info; - struct device *device = &dev->pdev->dev; struct drm_gem_object *gobj; struct vbox_bo *bo; int size, ret; @@ -263,16 +138,16 @@ static int vboxfb_create(struct drm_fb_helper *helper, return ret; } - info = framebuffer_alloc(0, device); - if (!info) - return -ENOMEM; + info = drm_fb_helper_alloc_fbi(helper); + if (IS_ERR(info)) + return -PTR_ERR(info); + info->par = fbdev; fbdev->size = size; fb = &fbdev->afb.base; fbdev->helper.fb = fb; - fbdev->helper.fbdev = info; strcpy(info->fix.id, "vboxdrmfb"); @@ -284,17 +159,10 @@ static int vboxfb_create(struct drm_fb_helper *helper, FBINFO_MISC_ALWAYS_SETPAR; info->fbops = &vboxfb_ops; - ret = fb_alloc_cmap(&info->cmap, 256, 0); - if (ret) - return -ENOMEM; - /* * This seems to be done for safety checking that the framebuffer * is not registered twice by different drivers. */ - info->apertures = alloc_apertures(1); - if (!info->apertures) - return -ENOMEM; info->apertures->ranges[0].base = pci_resource_start(dev->pdev, 0); info->apertures->ranges[0].size = pci_resource_len(dev->pdev, 0); @@ -305,7 +173,7 @@ static int vboxfb_create(struct drm_fb_helper *helper, info->screen_base = bo->kmap.virtual; info->screen_size = size; -#ifdef CONFIG_FB_DEFERRED_IO +#ifdef CONFIG_DRM_KMS_FB_HELPER info->fbdefio = &vbox_defio; fb_deferred_io_init(info); #endif @@ -327,6 +195,11 @@ void vbox_fbdev_fini(struct drm_device *dev) struct vbox_fbdev *fbdev = vbox->fbdev; struct vbox_framebuffer *afb = &fbdev->afb; +#ifdef CONFIG_DRM_KMS_FB_HELPER + if (fbdev->helper.fbdev && fbdev->helper.fbdev->fbdefio) + fb_deferred_io_cleanup(fbdev->helper.fbdev); +#endif + drm_fb_helper_unregister_fbi(&fbdev->helper); if (afb->obj) { diff --git a/drivers/staging/vboxvideo/vbox_mode.c b/drivers/staging/vboxvideo/vbox_mode.c index e5b6383984e7..257a77830410 100644 --- a/drivers/staging/vboxvideo/vbox_mode.c +++ b/drivers/staging/vboxvideo/vbox_mode.c @@ -54,14 +54,12 @@ static void vbox_do_modeset(struct drm_crtc *crtc, struct vbox_crtc *vbox_crtc = to_vbox_crtc(crtc); struct vbox_private *vbox; int width, height, bpp, pitch; - unsigned int crtc_id; u16 flags; s32 x_offset, y_offset; vbox = crtc->dev->dev_private; width = mode->hdisplay ? mode->hdisplay : 640; height = mode->vdisplay ? mode->vdisplay : 480; - crtc_id = vbox_crtc->crtc_id; bpp = crtc->enabled ? CRTC_FB(crtc)->format->cpp[0] * 8 : 32; pitch = crtc->enabled ? CRTC_FB(crtc)->pitches[0] : width * bpp / 8; x_offset = vbox->single_framebuffer ? crtc->x : vbox_crtc->x_hint; @@ -573,9 +571,6 @@ static int vbox_mode_valid(struct drm_connector *connector, static void vbox_connector_destroy(struct drm_connector *connector) { - struct vbox_connector *vbox_connector; - - vbox_connector = to_vbox_connector(connector); drm_connector_unregister(connector); drm_connector_cleanup(connector); kfree(connector); diff --git a/drivers/staging/vboxvideo/vbox_ttm.c b/drivers/staging/vboxvideo/vbox_ttm.c index 34a905d40735..4eb410a2a1a8 100644 --- a/drivers/staging/vboxvideo/vbox_ttm.c +++ b/drivers/staging/vboxvideo/vbox_ttm.c @@ -230,7 +230,7 @@ static void vbox_ttm_tt_unpopulate(struct ttm_tt *ttm) ttm_pool_unpopulate(ttm); } -struct ttm_bo_driver vbox_bo_driver = { +static struct ttm_bo_driver vbox_bo_driver = { .ttm_tt_create = vbox_ttm_tt_create, .ttm_tt_populate = vbox_ttm_tt_populate, .ttm_tt_unpopulate = vbox_ttm_tt_unpopulate, diff --git a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c index 3637ddf909a4..94654c0c7bba 100644 --- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c +++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c @@ -20,7 +20,7 @@ #include "bcm2835.h" /* hardware definition */ -static struct snd_pcm_hardware snd_bcm2835_playback_hw = { +static const struct snd_pcm_hardware snd_bcm2835_playback_hw = { .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID), .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, @@ -36,7 +36,7 @@ static struct snd_pcm_hardware snd_bcm2835_playback_hw = { .periods_max = 128, }; -static struct snd_pcm_hardware snd_bcm2835_playback_spdif_hw = { +static const struct snd_pcm_hardware snd_bcm2835_playback_spdif_hw = { .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID), .formats = SNDRV_PCM_FMTBIT_S16_LE, @@ -438,7 +438,7 @@ static int snd_bcm2835_pcm_lib_ioctl(struct snd_pcm_substream *substream, } /* operators */ -static struct snd_pcm_ops snd_bcm2835_playback_ops = { +static const struct snd_pcm_ops snd_bcm2835_playback_ops = { .open = snd_bcm2835_playback_open, .close = snd_bcm2835_playback_close, .ioctl = snd_bcm2835_pcm_lib_ioctl, @@ -450,7 +450,7 @@ static struct snd_pcm_ops snd_bcm2835_playback_ops = { .ack = snd_bcm2835_pcm_ack, }; -static struct snd_pcm_ops snd_bcm2835_playback_spdif_ops = { +static const struct snd_pcm_ops snd_bcm2835_playback_spdif_ops = { .open = snd_bcm2835_playback_spdif_open, .close = snd_bcm2835_playback_close, .ioctl = snd_bcm2835_pcm_lib_ioctl, diff --git a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c index a11e047734f9..be936b8fe317 100644 --- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c +++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c @@ -642,7 +642,7 @@ static void bm2835_mmal_unlock(struct vb2_queue *vq) mutex_unlock(&dev->mutex); } -static struct vb2_ops bm2835_mmal_video_qops = { +static const struct vb2_ops bm2835_mmal_video_qops = { .queue_setup = queue_setup, .buf_prepare = buffer_prepare, .buf_queue = buffer_queue, @@ -1456,7 +1456,7 @@ static const struct v4l2_file_operations camera0_fops = { .mmap = vb2_fop_mmap, }; -static struct video_device vdev_template = { +static const struct video_device vdev_template = { .name = "camera0", .fops = &camera0_fops, .ioctl_ops = &camera0_ioctl_ops, diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_util.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_util.c index 7fa0310e7b9e..2e52f07bbaa9 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_util.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_util.c @@ -51,7 +51,7 @@ int vchiu_queue_init(VCHIU_QUEUE_T *queue, int size) sema_init(&queue->pop, 0); sema_init(&queue->push, 0); - queue->storage = kzalloc(size * sizeof(VCHIQ_HEADER_T *), GFP_KERNEL); + queue->storage = kcalloc(size, sizeof(VCHIQ_HEADER_T *), GFP_KERNEL); if (!queue->storage) { vchiu_queue_delete(queue); return 0; diff --git a/drivers/staging/vt6655/card.c b/drivers/staging/vt6655/card.c index f5db2b3d9045..14034e342aa6 100644 --- a/drivers/staging/vt6655/card.c +++ b/drivers/staging/vt6655/card.c @@ -649,19 +649,19 @@ static unsigned short CARDwGetOFDMControlRate(struct vnt_private *priv, pr_debug("BASIC RATE: %X\n", priv->basic_rates); if (!CARDbIsOFDMinBasicRate((void *)priv)) { - pr_debug("CARDwGetOFDMControlRate:(NO OFDM) %d\n", wRateIdx); + pr_debug("%s:(NO OFDM) %d\n", __func__, wRateIdx); if (wRateIdx > RATE_24M) wRateIdx = RATE_24M; return wRateIdx; } while (ui > RATE_11M) { if (priv->basic_rates & ((u32)0x1 << ui)) { - pr_debug("CARDwGetOFDMControlRate : %d\n", ui); + pr_debug("%s : %d\n", __func__, ui); return (unsigned short)ui; } ui--; } - pr_debug("CARDwGetOFDMControlRate: 6M\n"); + pr_debug("%s: 6M\n", __func__); return (unsigned short)RATE_24M; } diff --git a/drivers/staging/vt6655/mac.c b/drivers/staging/vt6655/mac.c index 4aaa99bafcda..f7550b215f72 100644 --- a/drivers/staging/vt6655/mac.c +++ b/drivers/staging/vt6655/mac.c @@ -809,7 +809,7 @@ void MACvSetKeyEntry(struct vnt_private *priv, unsigned short wKeyCtl, if (byLocalID <= 1) return; - pr_debug("MACvSetKeyEntry\n"); + pr_debug("%s\n", __func__); offset = MISCFIFO_KEYETRY0; offset += (uEntryIdx * MISCFIFO_KEYENTRYSIZE); diff --git a/drivers/staging/vt6656/device.h b/drivers/staging/vt6656/device.h index 4832666cc580..74715c854856 100644 --- a/drivers/staging/vt6656/device.h +++ b/drivers/staging/vt6656/device.h @@ -83,7 +83,7 @@ #define CONFIG_PATH "/etc/vntconfiguration.dat" #define MAX_UINTS 8 -#define OPTION_DEFAULT { [0 ... MAX_UINTS-1] = -1} +#define OPTION_DEFAULT { [0 ... MAX_UINTS - 1] = -1} #define DUPLICATE_RX_CACHE_LENGTH 5 diff --git a/drivers/staging/vt6656/firmware.c b/drivers/staging/vt6656/firmware.c index 282f665aacfa..093a6048bd22 100644 --- a/drivers/staging/vt6656/firmware.c +++ b/drivers/staging/vt6656/firmware.c @@ -65,7 +65,7 @@ int vnt_download_firmware(struct vnt_private *priv) status = vnt_control_out(priv, 0, - 0x1200+ii, + 0x1200 + ii, 0x0000, length, buffer); diff --git a/drivers/staging/vt6656/key.h b/drivers/staging/vt6656/key.h index 906d3454591d..cfc6c2131536 100644 --- a/drivers/staging/vt6656/key.h +++ b/drivers/staging/vt6656/key.h @@ -46,6 +46,6 @@ int vnt_key_init_table(struct vnt_private *priv); int vnt_set_keys(struct ieee80211_hw *hw, struct ieee80211_sta *sta, - struct ieee80211_vif *vif, struct ieee80211_key_conf *key); + struct ieee80211_vif *vif, struct ieee80211_key_conf *key); #endif /* __KEY_H__ */ diff --git a/drivers/staging/vt6656/main_usb.c b/drivers/staging/vt6656/main_usb.c index 095b85567306..cc6d8778fe5b 100644 --- a/drivers/staging/vt6656/main_usb.c +++ b/drivers/staging/vt6656/main_usb.c @@ -419,8 +419,7 @@ static bool vnt_alloc_bufs(struct vnt_private *priv) int ii; for (ii = 0; ii < priv->num_tx_context; ii++) { - tx_context = kmalloc(sizeof(struct vnt_usb_send_context), - GFP_KERNEL); + tx_context = kmalloc(sizeof(*tx_context), GFP_KERNEL); if (!tx_context) goto free_tx; @@ -437,7 +436,7 @@ static bool vnt_alloc_bufs(struct vnt_private *priv) } for (ii = 0; ii < priv->num_rcb; ii++) { - priv->rcb[ii] = kzalloc(sizeof(struct vnt_rcb), GFP_KERNEL); + priv->rcb[ii] = kzalloc(sizeof(*priv->rcb[ii]), GFP_KERNEL); if (!priv->rcb[ii]) { dev_err(&priv->usb->dev, "failed to allocate rcb no %d\n", ii); diff --git a/drivers/staging/vt6656/power.c b/drivers/staging/vt6656/power.c index e322b7d8c617..c466e0614bc4 100644 --- a/drivers/staging/vt6656/power.c +++ b/drivers/staging/vt6656/power.c @@ -74,16 +74,15 @@ void vnt_enable_power_saving(struct vnt_private *priv, u16 listen_interval) vnt_mac_reg_bits_on(priv, MAC_REG_PSCTL, PSCTL_GO2DOZE); if (listen_interval >= 2) { - /* clear always listen beacon */ vnt_mac_reg_bits_off(priv, MAC_REG_PSCTL, PSCTL_ALBCN); /* first time set listen next beacon */ vnt_mac_reg_bits_on(priv, MAC_REG_PSCTL, PSCTL_LNBCN); - } else - + } else { /* always listen beacon */ vnt_mac_reg_bits_on(priv, MAC_REG_PSCTL, PSCTL_ALBCN); + } dev_dbg(&priv->usb->dev, "PS:Power Saving Mode Enable...\n"); } @@ -100,7 +99,6 @@ void vnt_enable_power_saving(struct vnt_private *priv, u16 listen_interval) void vnt_disable_power_saving(struct vnt_private *priv) { - /* disable power saving hw function */ vnt_control_out(priv, MESSAGE_TYPE_DISABLE_PS, 0, 0, 0, NULL); diff --git a/drivers/staging/vt6656/rf.c b/drivers/staging/vt6656/rf.c index 23581afb4211..3a9d19a0b842 100644 --- a/drivers/staging/vt6656/rf.c +++ b/drivers/staging/vt6656/rf.c @@ -611,7 +611,7 @@ int vnt_rf_write_embedded(struct vnt_private *priv, u32 data) reg_data[3] = (u8)(data >> 24); vnt_control_out(priv, MESSAGE_TYPE_WRITE_IFRF, - 0, 0, ARRAY_SIZE(reg_data), reg_data); + 0, 0, ARRAY_SIZE(reg_data), reg_data); return true; } @@ -643,9 +643,9 @@ int vnt_rf_setpower(struct vnt_private *priv, u32 rate, u32 channel) case RATE_48M: case RATE_54M: if (channel > CB_MAX_CHANNEL_24G) - power = priv->ofdm_a_pwr_tbl[channel-15]; + power = priv->ofdm_a_pwr_tbl[channel - 15]; else - power = priv->ofdm_pwr_tbl[channel-1]; + power = priv->ofdm_pwr_tbl[channel - 1]; break; } diff --git a/drivers/staging/vt6656/usbpipe.c b/drivers/staging/vt6656/usbpipe.c index dc11a05be8c4..23eaef458556 100644 --- a/drivers/staging/vt6656/usbpipe.c +++ b/drivers/staging/vt6656/usbpipe.c @@ -44,7 +44,7 @@ #define USB_CTL_WAIT 500 /* ms */ int vnt_control_out(struct vnt_private *priv, u8 request, u16 value, - u16 index, u16 length, u8 *buffer) + u16 index, u16 length, u8 *buffer) { int status = 0; u8 *usb_buffer; @@ -82,7 +82,7 @@ void vnt_control_out_u8(struct vnt_private *priv, u8 reg, u8 reg_off, u8 data) } int vnt_control_in(struct vnt_private *priv, u8 request, u16 value, - u16 index, u16 length, u8 *buffer) + u16 index, u16 length, u8 *buffer) { int status; u8 *usb_buffer; diff --git a/drivers/staging/wilc1000/host_interface.c b/drivers/staging/wilc1000/host_interface.c index 2568dfc15181..7b620658ec38 100644 --- a/drivers/staging/wilc1000/host_interface.c +++ b/drivers/staging/wilc1000/host_interface.c @@ -1963,7 +1963,7 @@ static s32 Handle_Get_InActiveTime(struct wilc_vif *vif, wilc_get_vif_idx(vif)); if (result) { - netdev_err(vif->ndev, "Failed to SET incative time\n"); + netdev_err(vif->ndev, "Failed to SET inactive time\n"); return -EFAULT; } @@ -1976,7 +1976,7 @@ static s32 Handle_Get_InActiveTime(struct wilc_vif *vif, wilc_get_vif_idx(vif)); if (result) { - netdev_err(vif->ndev, "Failed to get incative time\n"); + netdev_err(vif->ndev, "Failed to get inactive time\n"); return -EFAULT; } diff --git a/drivers/staging/wilc1000/linux_wlan.c b/drivers/staging/wilc1000/linux_wlan.c index dbb3e24615be..119f3459b5bb 100644 --- a/drivers/staging/wilc1000/linux_wlan.c +++ b/drivers/staging/wilc1000/linux_wlan.c @@ -283,7 +283,8 @@ int wilc_wlan_get_num_conn_ifcs(struct wilc *wilc) static int linux_wlan_txq_task(void *vp) { - int ret, txq_count; + int ret; + u32 txq_count; struct wilc_vif *vif; struct wilc *wl; struct net_device *dev = vp; @@ -812,7 +813,7 @@ _fail_wilc_wlan_: wilc_wlan_cleanup(dev); _fail_locks_: wlan_deinit_locks(dev); - netdev_err(dev, "WLAN Iinitialization FAILED\n"); + netdev_err(dev, "WLAN initialization FAILED\n"); } else { netdev_dbg(dev, "wilc1000 already initialized\n"); } diff --git a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c index 68fd5b3b8b2d..ac5aaafa461c 100644 --- a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c +++ b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c @@ -214,48 +214,39 @@ static u32 get_rssi_avg(struct network_info *network_info) return rssi_v; } -static void refresh_scan(void *user_void, u8 all, bool direct_scan) +static void refresh_scan(struct wilc_priv *priv, bool direct_scan) { - struct wilc_priv *priv; - struct wiphy *wiphy; - struct cfg80211_bss *bss = NULL; + struct wiphy *wiphy = priv->dev->ieee80211_ptr->wiphy; int i; - int rssi = 0; - - priv = user_void; - wiphy = priv->dev->ieee80211_ptr->wiphy; for (i = 0; i < last_scanned_cnt; i++) { struct network_info *network_info; + s32 freq; + struct ieee80211_channel *channel; + int rssi; + struct cfg80211_bss *bss; network_info = &last_scanned_shadow[i]; - if (!network_info->found || all) { - s32 freq; - struct ieee80211_channel *channel; - - if (network_info) { - freq = ieee80211_channel_to_frequency((s32)network_info->ch, NL80211_BAND_2GHZ); - channel = ieee80211_get_channel(wiphy, freq); - - rssi = get_rssi_avg(network_info); - if (memcmp("DIRECT-", network_info->ssid, 7) || - direct_scan) { - bss = cfg80211_inform_bss(wiphy, - channel, - CFG80211_BSS_FTYPE_UNKNOWN, - network_info->bssid, - network_info->tsf_hi, - network_info->cap_info, - network_info->beacon_period, - (const u8 *)network_info->ies, - (size_t)network_info->ies_len, - (s32)rssi * 100, - GFP_KERNEL); - cfg80211_put_bss(wiphy, bss); - } - } - } + if (!memcmp("DIRECT-", network_info->ssid, 7) && !direct_scan) + continue; + + freq = ieee80211_channel_to_frequency((s32)network_info->ch, + NL80211_BAND_2GHZ); + channel = ieee80211_get_channel(wiphy, freq); + rssi = get_rssi_avg(network_info); + bss = cfg80211_inform_bss(wiphy, + channel, + CFG80211_BSS_FTYPE_UNKNOWN, + network_info->bssid, + network_info->tsf_hi, + network_info->cap_info, + network_info->beacon_period, + (const u8 *)network_info->ies, + (size_t)network_info->ies_len, + (s32)rssi * 100, + GFP_KERNEL); + cfg80211_put_bss(wiphy, bss); } } @@ -442,7 +433,7 @@ static void CfgScanResult(enum scan_event scan_event, } } } else if (scan_event == SCAN_EVENT_DONE) { - refresh_scan(priv, 1, false); + refresh_scan(priv, false); mutex_lock(&priv->scan_req_lock); @@ -466,7 +457,7 @@ static void CfgScanResult(enum scan_event scan_event, }; update_scan_time(); - refresh_scan(priv, 1, false); + refresh_scan(priv, false); cfg80211_scan_done(priv->pstrScanReq, &info); priv->bCfgScanning = false; @@ -540,7 +531,7 @@ static void CfgConnectResult(enum conn_event enuConnDisconnEvent, } if (bNeedScanRefresh) - refresh_scan(priv, 1, true); + refresh_scan(priv, true); } cfg80211_connect_result(dev, pstrConnectInfo->bssid, diff --git a/drivers/staging/wilc1000/wilc_wfi_netdevice.h b/drivers/staging/wilc1000/wilc_wfi_netdevice.h index c89bf4301096..7a36561a599e 100644 --- a/drivers/staging/wilc1000/wilc_wfi_netdevice.h +++ b/drivers/staging/wilc1000/wilc_wfi_netdevice.h @@ -227,8 +227,8 @@ int wilc1000_wlan_init(struct net_device *dev, struct wilc_vif *vif); void wilc_frmw_to_linux(struct wilc *wilc, u8 *buff, u32 size, u32 pkt_offset); void wilc_mac_indicate(struct wilc *wilc, int flag); void wilc_netdev_cleanup(struct wilc *wilc); -int wilc_netdev_init(struct wilc **wilc, struct device *, int io_type, int gpio, - const struct wilc_hif_func *ops); +int wilc_netdev_init(struct wilc **wilc, struct device *dev, int io_type, + int gpio, const struct wilc_hif_func *ops); void wilc1000_wlan_deinit(struct net_device *dev); void WILC_WFI_mgmt_rx(struct wilc *wilc, u8 *buff, u32 size); int wilc_wlan_get_firmware(struct net_device *dev); diff --git a/drivers/staging/wlan-ng/hfa384x.h b/drivers/staging/wlan-ng/hfa384x.h index 018db2299d0c..f5a3a1ce21ce 100644 --- a/drivers/staging/wlan-ng/hfa384x.h +++ b/drivers/staging/wlan-ng/hfa384x.h @@ -413,8 +413,8 @@ struct hfa384x_join_request_data { /*-- Configuration Record: authenticateStation (data portion only) --*/ struct hfa384x_authenticate_station_data { u8 address[ETH_ALEN]; - u16 status; - u16 algorithm; + __le16 status; + __le16 algorithm; } __packed; /*-- Configuration Record: WPAData (data portion only) --*/ @@ -445,9 +445,9 @@ struct hfa384x_downloadbuffer { /*-- Information Record: commsquality --*/ struct hfa384x_commsquality { - u16 cq_curr_bss; - u16 asl_curr_bss; - u16 anl_curr_fc; + __le16 cq_curr_bss; + __le16 asl_curr_bss; + __le16 anl_curr_fc; } __packed; /*-- Information Record: dmbcommsquality --*/ @@ -598,51 +598,51 @@ struct hfa384x_rx_frame { /*-- Inquiry Frame, Diagnose: Communication Tallies --*/ struct hfa384x_comm_tallies_16 { - u16 txunicastframes; - u16 txmulticastframes; - u16 txfragments; - u16 txunicastoctets; - u16 txmulticastoctets; - u16 txdeferredtrans; - u16 txsingleretryframes; - u16 txmultipleretryframes; - u16 txretrylimitexceeded; - u16 txdiscards; - u16 rxunicastframes; - u16 rxmulticastframes; - u16 rxfragments; - u16 rxunicastoctets; - u16 rxmulticastoctets; - u16 rxfcserrors; - u16 rxdiscardsnobuffer; - u16 txdiscardswrongsa; - u16 rxdiscardswepundecr; - u16 rxmsginmsgfrag; - u16 rxmsginbadmsgfrag; + __le16 txunicastframes; + __le16 txmulticastframes; + __le16 txfragments; + __le16 txunicastoctets; + __le16 txmulticastoctets; + __le16 txdeferredtrans; + __le16 txsingleretryframes; + __le16 txmultipleretryframes; + __le16 txretrylimitexceeded; + __le16 txdiscards; + __le16 rxunicastframes; + __le16 rxmulticastframes; + __le16 rxfragments; + __le16 rxunicastoctets; + __le16 rxmulticastoctets; + __le16 rxfcserrors; + __le16 rxdiscardsnobuffer; + __le16 txdiscardswrongsa; + __le16 rxdiscardswepundecr; + __le16 rxmsginmsgfrag; + __le16 rxmsginbadmsgfrag; } __packed; struct hfa384x_comm_tallies_32 { - u32 txunicastframes; - u32 txmulticastframes; - u32 txfragments; - u32 txunicastoctets; - u32 txmulticastoctets; - u32 txdeferredtrans; - u32 txsingleretryframes; - u32 txmultipleretryframes; - u32 txretrylimitexceeded; - u32 txdiscards; - u32 rxunicastframes; - u32 rxmulticastframes; - u32 rxfragments; - u32 rxunicastoctets; - u32 rxmulticastoctets; - u32 rxfcserrors; - u32 rxdiscardsnobuffer; - u32 txdiscardswrongsa; - u32 rxdiscardswepundecr; - u32 rxmsginmsgfrag; - u32 rxmsginbadmsgfrag; + __le32 txunicastframes; + __le32 txmulticastframes; + __le32 txfragments; + __le32 txunicastoctets; + __le32 txmulticastoctets; + __le32 txdeferredtrans; + __le32 txsingleretryframes; + __le32 txmultipleretryframes; + __le32 txretrylimitexceeded; + __le32 txdiscards; + __le32 rxunicastframes; + __le32 rxmulticastframes; + __le32 rxfragments; + __le32 rxunicastoctets; + __le32 rxmulticastoctets; + __le32 rxfcserrors; + __le32 rxdiscardsnobuffer; + __le32 txdiscardswrongsa; + __le32 rxdiscardswepundecr; + __le32 rxmsginmsgfrag; + __le32 rxmsginbadmsgfrag; } __packed; /*-- Inquiry Frame, Diagnose: Scan Results & Subfields--*/ @@ -711,7 +711,7 @@ struct hfa384x_hscan_result { #define HFA384x_LINK_ASSOCFAIL ((u16)6) struct hfa384x_link_status { - u16 linkstatus; + __le16 linkstatus; } __packed; /*-- Unsolicited Frame, MAC Mgmt: AssociationStatus (--*/ @@ -733,13 +733,13 @@ struct hfa384x_assoc_status { struct hfa384x_auth_request { u8 sta_addr[ETH_ALEN]; - u16 algorithm; + __le16 algorithm; } __packed; /*-- Unsolicited Frame, MAC Mgmt: PSUserCount (AP Only) --*/ struct hfa384x_ps_user_count { - u16 usercnt; + __le16 usercnt; } __packed; struct hfa384x_key_id_changed { diff --git a/drivers/staging/wlan-ng/hfa384x_usb.c b/drivers/staging/wlan-ng/hfa384x_usb.c index ee5fa86e941d..d1e8218f96fb 100644 --- a/drivers/staging/wlan-ng/hfa384x_usb.c +++ b/drivers/staging/wlan-ng/hfa384x_usb.c @@ -1344,16 +1344,14 @@ hfa384x_docmd(struct hfa384x *hw, if (result != 0) { kfree(ctlx); } else if (mode == DOWAIT) { - struct usbctlx_cmd_completor completor; + struct usbctlx_cmd_completor cmd_completor; + struct usbctlx_completor *completor; - result = - hfa384x_usbctlx_complete_sync(hw, ctlx, - init_cmd_completor(&completor, - &ctlx-> - inbuf. - cmdresp, - &cmd-> - result)); + completor = init_cmd_completor(&cmd_completor, + &ctlx->inbuf.cmdresp, + &cmd->result); + + result = hfa384x_usbctlx_complete_sync(hw, ctlx, completor); } done: diff --git a/drivers/staging/wlan-ng/p80211conv.c b/drivers/staging/wlan-ng/p80211conv.c index fc8ad33ade9f..c1b6d426bcad 100644 --- a/drivers/staging/wlan-ng/p80211conv.c +++ b/drivers/staging/wlan-ng/p80211conv.c @@ -213,6 +213,7 @@ int skb_ether_to_p80211(struct wlandevice *wlandev, u32 ethconv, netdev_warn(wlandev->netdev, "Host en-WEP failed, dropping frame (%d).\n", foo); + kfree(p80211_wep->data); return 2; } fc |= cpu_to_le16(WLAN_SET_FC_ISWEP(1)); diff --git a/drivers/staging/wlan-ng/p80211netdev.c b/drivers/staging/wlan-ng/p80211netdev.c index 021fb23ae9ba..0f503652740f 100644 --- a/drivers/staging/wlan-ng/p80211netdev.c +++ b/drivers/staging/wlan-ng/p80211netdev.c @@ -258,7 +258,7 @@ static int p80211_convert_to_ether(struct wlandevice *wlandev, return 0; } - netdev_dbg(wlandev->netdev, "p80211_convert_to_ether failed.\n"); + netdev_dbg(wlandev->netdev, "%s failed.\n", __func__); return CONV_TO_ETHER_FAILED; } diff --git a/drivers/staging/wlan-ng/prism2fw.c b/drivers/staging/wlan-ng/prism2fw.c index 1a0c786c7616..344bec8cc31b 100644 --- a/drivers/staging/wlan-ng/prism2fw.c +++ b/drivers/staging/wlan-ng/prism2fw.c @@ -1016,7 +1016,8 @@ static int writeimage(struct wlandevice *wlandev, struct imgchunk *fchunk, kfree(rstmsg); kfree(rwrmsg); netdev_err(wlandev->netdev, - "writeimage: no memory for firmware download, aborting download\n"); + "%s: no memory for firmware download, aborting download\n", + __func__); return -ENOMEM; } @@ -1058,15 +1059,15 @@ static int writeimage(struct wlandevice *wlandev, struct imgchunk *fchunk, result = prism2mgmt_ramdl_state(wlandev, rstmsg); if (result) { netdev_err(wlandev->netdev, - "writeimage state enable failed w/ result=%d, aborting download\n", - result); + "%s state enable failed w/ result=%d, aborting download\n", + __func__, result); goto free_result; } resultcode = rstmsg->resultcode.data; if (resultcode != P80211ENUM_resultcode_success) { netdev_err(wlandev->netdev, - "writeimage()->xxxdl_state msg indicates failure, w/ resultcode=%d, aborting download.\n", - resultcode); + "%s()->xxxdl_state msg indicates failure, w/ resultcode=%d, aborting download.\n", + __func__, resultcode); result = 1; goto free_result; } @@ -1102,14 +1103,14 @@ static int writeimage(struct wlandevice *wlandev, struct imgchunk *fchunk, /* Check the results */ if (result) { netdev_err(wlandev->netdev, - "writeimage chunk write failed w/ result=%d, aborting download\n", - result); + "%s chunk write failed w/ result=%d, aborting download\n", + __func__, result); goto free_result; } resultcode = rstmsg->resultcode.data; if (resultcode != P80211ENUM_resultcode_success) { - pr_err("writeimage()->xxxdl_write msg indicates failure, w/ resultcode=%d, aborting download.\n", - resultcode); + pr_err("%s()->xxxdl_write msg indicates failure, w/ resultcode=%d, aborting download.\n", + __func__, resultcode); result = 1; goto free_result; } @@ -1124,15 +1125,15 @@ static int writeimage(struct wlandevice *wlandev, struct imgchunk *fchunk, result = prism2mgmt_ramdl_state(wlandev, rstmsg); if (result) { netdev_err(wlandev->netdev, - "writeimage state disable failed w/ result=%d, aborting download\n", - result); + "%s state disable failed w/ result=%d, aborting download\n", + __func__, result); goto free_result; } resultcode = rstmsg->resultcode.data; if (resultcode != P80211ENUM_resultcode_success) { netdev_err(wlandev->netdev, - "writeimage()->xxxdl_state msg indicates failure, w/ resultcode=%d, aborting download.\n", - resultcode); + "%s()->xxxdl_state msg indicates failure, w/ resultcode=%d, aborting download.\n", + __func__, resultcode); result = 1; goto free_result; } diff --git a/drivers/staging/wlan-ng/prism2sta.c b/drivers/staging/wlan-ng/prism2sta.c index e16da34389cd..c9df45063ab3 100644 --- a/drivers/staging/wlan-ng/prism2sta.c +++ b/drivers/staging/wlan-ng/prism2sta.c @@ -991,9 +991,9 @@ static void prism2sta_inf_tallies(struct wlandevice *wlandev, struct hfa384x_inf_frame *inf) { struct hfa384x *hw = wlandev->priv; - u16 *src16; + __le16 *src16; u32 *dst; - u32 *src32; + __le32 *src32; int i; int cnt; @@ -1005,12 +1005,12 @@ static void prism2sta_inf_tallies(struct wlandevice *wlandev, cnt = sizeof(struct hfa384x_comm_tallies_32) / sizeof(u32); if (inf->framelen > 22) { dst = (u32 *)&hw->tallies; - src32 = (u32 *)&inf->info.commtallies32; + src32 = (__le32 *)&inf->info.commtallies32; for (i = 0; i < cnt; i++, dst++, src32++) *dst += le32_to_cpu(*src32); } else { dst = (u32 *)&hw->tallies; - src16 = (u16 *)&inf->info.commtallies16; + src16 = (__le16 *)&inf->info.commtallies16; for (i = 0; i < cnt; i++, dst++, src16++) *dst += le16_to_cpu(*src16); } @@ -1136,7 +1136,7 @@ static void prism2sta_inf_chinforesults(struct wlandevice *wlandev, unsigned int i, n; hw->channel_info.results.scanchannels = - le16_to_cpu(inf->info.chinforesult.scanchannels); + inf->info.chinforesult.scanchannels; for (i = 0, n = 0; i < HFA384x_CHINFORESULT_MAX; i++) { struct hfa384x_ch_info_result_sub *result; @@ -1147,16 +1147,16 @@ static void prism2sta_inf_chinforesults(struct wlandevice *wlandev, continue; result = &inf->info.chinforesult.result[n]; - chan = le16_to_cpu(result->chid) - 1; + chan = result->chid - 1; if (chan < 0 || chan >= HFA384x_CHINFORESULT_MAX) continue; chinforesult = &hw->channel_info.results.result[chan]; chinforesult->chid = chan; - chinforesult->anl = le16_to_cpu(result->anl); - chinforesult->pnl = le16_to_cpu(result->pnl); - chinforesult->active = le16_to_cpu(result->active); + chinforesult->anl = result->anl; + chinforesult->pnl = result->pnl; + chinforesult->active = result->active; pr_debug("chinfo: channel %d, %s level (avg/peak)=%d/%d dB, pcf %d\n", chan + 1, @@ -1447,7 +1447,7 @@ static void prism2sta_inf_linkstatus(struct wlandevice *wlandev, { struct hfa384x *hw = wlandev->priv; - hw->link_status_new = le16_to_cpu(inf->info.linkstatus.linkstatus); + hw->link_status_new = inf->info.linkstatus.linkstatus; schedule_work(&hw->link_bh); } @@ -1561,7 +1561,7 @@ static void prism2sta_inf_authreq_defer(struct wlandevice *wlandev, */ ether_addr_copy(rec.address, inf->info.authreq.sta_addr); - rec.status = P80211ENUM_status_unspec_failure; + rec.status = cpu_to_le16(P80211ENUM_status_unspec_failure); /* * Authenticate based on the access mode. @@ -1578,7 +1578,7 @@ static void prism2sta_inf_authreq_defer(struct wlandevice *wlandev, for (i = 0; i < hw->authlist.cnt; i++) if (ether_addr_equal(rec.address, hw->authlist.addr[i])) { - rec.status = P80211ENUM_status_successful; + rec.status = cpu_to_le16(P80211ENUM_status_successful); break; } @@ -1590,7 +1590,7 @@ static void prism2sta_inf_authreq_defer(struct wlandevice *wlandev, * Allow all authentications. */ - rec.status = P80211ENUM_status_successful; + rec.status = cpu_to_le16(P80211ENUM_status_successful); break; case WLAN_ACCESS_ALLOW: @@ -1615,7 +1615,7 @@ static void prism2sta_inf_authreq_defer(struct wlandevice *wlandev, for (i = 0; i < cnt; i++, addr += ETH_ALEN) if (ether_addr_equal(rec.address, addr)) { - rec.status = P80211ENUM_status_successful; + rec.status = cpu_to_le16(P80211ENUM_status_successful); break; } @@ -1641,11 +1641,11 @@ static void prism2sta_inf_authreq_defer(struct wlandevice *wlandev, addr = hw->deny.addr1[0]; } - rec.status = P80211ENUM_status_successful; + rec.status = cpu_to_le16(P80211ENUM_status_successful); for (i = 0; i < cnt; i++, addr += ETH_ALEN) if (ether_addr_equal(rec.address, addr)) { - rec.status = P80211ENUM_status_unspec_failure; + rec.status = cpu_to_le16(P80211ENUM_status_unspec_failure); break; } @@ -1663,7 +1663,7 @@ static void prism2sta_inf_authreq_defer(struct wlandevice *wlandev, added = 0; - if (rec.status == P80211ENUM_status_successful) { + if (rec.status == cpu_to_le16(P80211ENUM_status_successful)) { for (i = 0; i < hw->authlist.cnt; i++) if (ether_addr_equal(rec.address, hw->authlist.addr[i])) @@ -1671,7 +1671,7 @@ static void prism2sta_inf_authreq_defer(struct wlandevice *wlandev, if (i >= hw->authlist.cnt) { if (hw->authlist.cnt >= WLAN_AUTH_MAX) { - rec.status = P80211ENUM_status_ap_full; + rec.status = cpu_to_le16(P80211ENUM_status_ap_full); } else { ether_addr_copy( hw->authlist.addr[hw->authlist.cnt], @@ -1688,7 +1688,6 @@ static void prism2sta_inf_authreq_defer(struct wlandevice *wlandev, * it was added. */ - rec.status = cpu_to_le16(rec.status); rec.algorithm = inf->info.authreq.algorithm; result = hfa384x_drvr_setconfig(hw, HFA384x_RID_AUTHENTICATESTA, |